diff --git a/.gitignore b/.gitignore index 761f4120f..a850113c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ # file types to ignore *.pyc +*~ +CMakeFiles/ +*qrc.depends +qrc_*.cpp +ui_*.h +moc_*.cpp +Makefile +CMakeCache.txt +config.h +install_manifest.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 91d447c10..a3867b17a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,13 @@ endif(WIN32) SET(CMAKE_INSTALL_DATADIR data CACHE PATH "Output directory for data and resource files") SET(CMAKE_INSTALL_INCLUDEDIR include CACHE PATH "Output directory for header files") SET(CMAKE_INSTALL_DOCDIR doc CACHE PATH "Output directory for documentation and license files") + +SET(PYCXX_INCLUDE_DIR + "${CMAKE_SOURCE_DIR}/src" CACHE PATH + "Path to the directory containing PyCXX's CXX/Config.hxx include file") +SET(PYCXX_SOURCE_DIR + "${CMAKE_SOURCE_DIR}/src/CXX" CACHE PATH + "Path to the directory containing PyCXX's cxxextensions.c source file") # used as compiler defines SET(RESOURCEDIR "${CMAKE_INSTALL_DATADIR}") @@ -152,6 +159,10 @@ if(FREECAD_LIBPACK_USE) message(SEND_ERROR "Could not find neither LibPack 6.x nor 7.x in specified location:" ${FREECAD_LIBPACK_DIR}) ENDIF(FREECAD_LIBPACK_CHECKFILE6X) +# -------------------------------- PyCXX -------------------------------- + + find_package(PyCXX REQUIRED) + # -------------------------------- Swig ---------------------------------- find_package(SWIG) @@ -204,6 +215,10 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) find_package(ZLIB REQUIRED) +# -------------------------------- PyCXX -------------------------------- + + find_package(PyCXX REQUIRED) + # -------------------------------- OpenCasCade -------------------------------- #first, look for OpenCASCADE Community Edition (OCE) diff --git a/cMake/FindPyCXX.cmake b/cMake/FindPyCXX.cmake new file mode 100644 index 000000000..37d1f8147 --- /dev/null +++ b/cMake/FindPyCXX.cmake @@ -0,0 +1,108 @@ +# Locate PyCXX headers and source files + +# This module defines +# PYCXX_INCLUDE_DIR +# PYCXX_SOURCE_DIR +# PYCXX_FOUND +# PYCXX_SOURCES +# +# The PYCXX_*_DIR variables can be set to tell this module where +# the files are. + + +# There's no standard location for PyCXX. +# +# The authors' example is to put it in "~\" [sic]. +# +# Ubuntu puts the includes into /usr/include/python2.7/CXX and sources into +# /usr/share/python2.7/CXX. +# +# The Zultron Fedora RPM does the same as Ubuntu. + +set(PYCXX_FOUND "YES") + +# find the header directory +if(PYCXX_INCLUDE_DIR) + # headers better be in there + if(NOT EXISTS "${PYCXX_INCLUDE_DIR}/CXX/Config.hxx") + if(PyCXX_FIND_REQUIRED) + MESSAGE(FATAL_ERROR + "PyCXX: could not find CXX/Config.hxx in PYCXX_INCLUDE_DIR " + "${PYCXX_INCLUDE_DIR}") + else(PyCXX_FIND_REQUIRED) + MESSAGE(WARNING + "PyCXX: could not find CXX/Config.hxx in PYCXX_INCLUDE_DIR " + "${PYCXX_INCLUDE_DIR}") + unset(PYCXX_FOUND) + endif(PyCXX_FIND_REQUIRED) + endif(NOT EXISTS "${PYCXX_INCLUDE_DIR}/CXX/Config.hxx") +else(PYCXX_INCLUDE_DIR) + # check in 'standard' places + find_path(PYCXX_INCLUDE_DIR CXX/Config.hxx + ${PYTHON_INCLUDE_DIR} + "${CMAKE_CURRENT_LIST_DIR}/..") + if(NOT PYCXX_INCLUDE_DIR) + if(PyCXX_FIND_REQUIRED) + MESSAGE(FATAL_ERROR + "PyCXX not found; please set PYCXX_INCLUDE_DIR to " + "the location of CXX/Config.hxx") + else(PyCXX_FIND_REQUIRED) + MESSAGE(STATUS "PyCXX not found") + unset(PYCXX_FOUND) + endif(PyCXX_FIND_REQUIRED) + endif(NOT PYCXX_INCLUDE_DIR) +endif(PYCXX_INCLUDE_DIR) + +# find the sources directory +if(PYCXX_SOURCE_DIR) + # source directory specified, they'd better be there + if(NOT EXISTS "${PYCXX_SOURCE_DIR}/cxxextensions.c") + if(PyCXX_FIND_REQUIRED) + MESSAGE(FATAL_ERROR + "PyCXX: cxxextensions.c not found in PYCXX_INCLUDE_DIR " + "${PYCXX_INCLUDE_DIR}") + else(PyCXX_FIND_REQUIRED) + MESSAGE(WARNING + "PyCXX: cxxextensions.c not found in PYCXX_INCLUDE_DIR " + "${PYCXX_INCLUDE_DIR}") + unset(PYCXX_FOUND) + endif(PyCXX_FIND_REQUIRED) + endif(NOT EXISTS "${PYCXX_SOURCE_DIR}/cxxextensions.c") +else(PYCXX_SOURCE_DIR) + # check in 'standard' places + find_path(PYCXX_SOURCE_DIR cxxextensions.c + "${PYCXX_INCLUDE_DIR}/CXX" + "${PYCXX_INCLUDE_DIR}/Src" + "${PYTHON_INCLUDE_DIR}/CXX" + "${PYTHON_INCLUDE_DIR}/Src" + "${CMAKE_CURRENT_LIST_DIR}/../Src" + "${CMAKE_CURRENT_LIST_DIR}/../CXX") + if(NOT PYCXX_SOURCE_DIR) + if(PyCXX_FIND_REQUIRED) + MESSAGE(FATAL_ERROR + "PyCXX not found; please set PYCXX_SOURCE_DIR to " + "the location of cxxextensions.c") + else(PyCXX_FIND_REQUIRED) + MESSAGE(STATUS "PyCXX not found") + unset(PYCXX_FOUND) + endif(PyCXX_FIND_REQUIRED) + endif(NOT PYCXX_SOURCE_DIR) +endif(PYCXX_SOURCE_DIR) + +# see what we've got +if(PYCXX_FOUND) + MESSAGE(STATUS "PyCXX found:") + MESSAGE(STATUS " Headers: ${PYCXX_INCLUDE_DIR}") + MESSAGE(STATUS " Sources: ${PYCXX_SOURCE_DIR}") + + # Build the list of sources for convenience + set(PYCXX_SOURCES + ${PYCXX_SOURCE_DIR}/cxxextensions.c + ${PYCXX_SOURCE_DIR}/cxx_extensions.cxx + ${PYCXX_SOURCE_DIR}/cxxsupport.cxx + ${PYCXX_SOURCE_DIR}/IndirectPythonInterface.cxx + ) +else(PYCXX_FOUND) + MESSAGE(STATUS "PyCXX not found") +endif(PYCXX_FOUND) + diff --git a/src/3rdParty/salomesmesh/CMakeLists.txt b/src/3rdParty/salomesmesh/CMakeLists.txt index 21e321308..79381c68c 100644 --- a/src/3rdParty/salomesmesh/CMakeLists.txt +++ b/src/3rdParty/salomesmesh/CMakeLists.txt @@ -140,13 +140,13 @@ if(MSVC) elseif(MINGW) set_target_properties(SMDS PROPERTIES COMPILE_FLAGS "-DSMDS_EXPORTS") set_target_properties(SMDS PROPERTIES OUTPUT_NAME "SMDS") - set_target_properties(SMDS PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(SMDS PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(SMDS PROPERTIES PREFIX "") else(MSVC) set_target_properties(SMDS PROPERTIES OUTPUT_NAME "SMDS") - set_target_properties(SMDS PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(SMDS PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(SMDS PROPERTIES PREFIX "") - set_target_properties(SMDS PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(SMDS PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) ########## @@ -165,13 +165,13 @@ if(MSVC) elseif(MINGW) set_target_properties(Driver PROPERTIES COMPILE_FLAGS "-DMESHDRIVER_EXPORTS") set_target_properties(Driver PROPERTIES OUTPUT_NAME "Driver") - set_target_properties(Driver PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(Driver PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(Driver PROPERTIES PREFIX "") else(MSVC) set_target_properties(Driver PROPERTIES OUTPUT_NAME "Driver") - set_target_properties(Driver PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(Driver PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(Driver PROPERTIES PREFIX "") - set_target_properties(Driver PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(Driver PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) @@ -199,13 +199,13 @@ if(MSVC) elseif(MINGW) set_target_properties(DriverSTL PROPERTIES COMPILE_FLAGS "-DMESHDRIVERSTL_EXPORTS") set_target_properties(DriverSTL PROPERTIES OUTPUT_NAME "DriverSTL") - set_target_properties(DriverSTL PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(DriverSTL PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(DriverSTL PROPERTIES PREFIX "") else(MSVC) set_target_properties(DriverSTL PROPERTIES OUTPUT_NAME "DriverSTL") - set_target_properties(DriverSTL PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(DriverSTL PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(DriverSTL PROPERTIES PREFIX "") - set_target_properties(DriverSTL PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(DriverSTL PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) @@ -233,13 +233,13 @@ if(MSVC) elseif(MINGW) set_target_properties(DriverDAT PROPERTIES COMPILE_FLAGS "-DMESHDRIVERDAT_EXPORTS") set_target_properties(DriverDAT PROPERTIES OUTPUT_NAME "DriverDAT") - set_target_properties(DriverDAT PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(DriverDAT PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(DriverDAT PROPERTIES PREFIX "") else(MSVC) set_target_properties(DriverDAT PROPERTIES OUTPUT_NAME "DriverDAT") - set_target_properties(DriverDAT PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(DriverDAT PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(DriverDAT PROPERTIES PREFIX "") - set_target_properties(DriverDAT PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(DriverDAT PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) @@ -267,13 +267,13 @@ if(MSVC) elseif(MINGW) set_target_properties(DriverUNV PROPERTIES COMPILE_FLAGS "-DMESHDRIVERUNV_EXPORTS") set_target_properties(DriverUNV PROPERTIES OUTPUT_NAME "DriverUNV") - set_target_properties(DriverUNV PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(DriverUNV PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(DriverUNV PROPERTIES PREFIX "") else(MSVC) set_target_properties(DriverUNV PROPERTIES OUTPUT_NAME "DriverUNV") - set_target_properties(DriverUNV PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(DriverUNV PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(DriverUNV PROPERTIES PREFIX "") - set_target_properties(DriverUNV PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(DriverUNV PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) @@ -299,13 +299,13 @@ if(MSVC) set_target_properties(SMESHDS PROPERTIES PREFIX "../") elseif(MINGW) set_target_properties(SMESHDS PROPERTIES OUTPUT_NAME "SMESHDS") - set_target_properties(SMESHDS PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(SMESHDS PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(SMESHDS PROPERTIES PREFIX "") else(MSVC) set_target_properties(SMESHDS PROPERTIES OUTPUT_NAME "SMESHDS") - set_target_properties(SMESHDS PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(SMESHDS PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(SMESHDS PROPERTIES PREFIX "") - set_target_properties(SMESHDS PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(SMESHDS PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) @@ -330,12 +330,13 @@ if(MSVC) elseif(MINGW) set_target_properties(SMESH PROPERTIES COMPILE_FLAGS "-DSMESH_EXPORTS -DSMESHCONTROLS_EXPORTS -DSMESHimpl_EXPORTS") set_target_properties(SMESH PROPERTIES OUTPUT_NAME "SMESH") - set_target_properties(SMESH PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(SMESH PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(SMESH PROPERTIES PREFIX "") else(MSVC) set_target_properties(SMESH PROPERTIES OUTPUT_NAME "SMESH") + set_target_properties(SMESH PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(SMESH PROPERTIES PREFIX "") - set_target_properties(SMESH PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(SMESH PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) @@ -379,14 +380,15 @@ elseif(MINGW) TARGET_LINK_LIBRARIES(MEFISTO2 ${SMESH_LIBS} gfortran) set_target_properties(MEFISTO2 PROPERTIES COMPILE_FLAGS "-DMEFISTO2D_EXPORTS") set_target_properties(MEFISTO2 PROPERTIES OUTPUT_NAME "MEFISTO2") - set_target_properties(MEFISTO2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(MEFISTO2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(MEFISTO2 PROPERTIES PREFIX "") else(MSVC) TARGET_LINK_LIBRARIES(MEFISTO2 ${SMESH_LIBS} gfortran) set_target_properties(MEFISTO2 PROPERTIES COMPILE_FLAGS "${MEFISTO2_CFLAGS}") set_target_properties(MEFISTO2 PROPERTIES OUTPUT_NAME "MEFISTO2") + set_target_properties(MEFISTO2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(MEFISTO2 PROPERTIES PREFIX "") - set_target_properties(MEFISTO2 PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(MEFISTO2 PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) @@ -407,7 +409,7 @@ elseif(MINGW) TARGET_LINK_LIBRARIES(StdMeshers SMESH ${SMESH_LIBS} MEFISTO2) set_target_properties(StdMeshers PROPERTIES COMPILE_FLAGS "-DSTDMESHERS_EXPORTS") set_target_properties(StdMeshers PROPERTIES OUTPUT_NAME "StdMeshers") - set_target_properties(StdMeshers PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(StdMeshers PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(StdMeshers PROPERTIES PREFIX "") else(MSVC) TARGET_LINK_LIBRARIES(StdMeshers SMESH ${SMESH_LIBS} MEFISTO2) @@ -419,8 +421,9 @@ else(MSVC) ENDIF(${CMAKE_SIZEOF_VOID_P} MATCHES "8") set_target_properties(StdMeshers PROPERTIES COMPILE_FLAGS "${StdMeshers_CFLAGS}") set_target_properties(StdMeshers PROPERTIES OUTPUT_NAME "StdMeshers") + set_target_properties(StdMeshers PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(StdMeshers PROPERTIES PREFIX "") - set_target_properties(StdMeshers PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(StdMeshers PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) #SET(StdMeshers_CFLAGS "") @@ -450,12 +453,13 @@ if(MSVC) elseif(MINGW) set_target_properties(NETGENPlugin PROPERTIES COMPILE_FLAGS "-DNETGENPLUGIN_EXPORTS -DNO_PARALLEL_THREADS -DOCCGEOMETRY") set_target_properties(NETGENPlugin PROPERTIES OUTPUT_NAME "NETGENPlugin") - set_target_properties(NETGENPlugin PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_target_properties(NETGENPlugin PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(NETGENPlugin PROPERTIES PREFIX "") else(MSVC) set_target_properties(NETGENPlugin PROPERTIES OUTPUT_NAME "NETGENPlugin") + set_target_properties(NETGENPlugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set_target_properties(NETGENPlugin PROPERTIES PREFIX "") - set_target_properties(NETGENPlugin PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin) + set_target_properties(NETGENPlugin PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) endif(MSVC) endif (FREECAD_BUILD_FEM_NETGEN) @@ -468,4 +472,27 @@ endif (FREECAD_BUILD_FEM_NETGEN) #ENDIF(MINGW) +if(WIN32) + INSTALL(TARGETS SMDS Driver DriverSTL DriverDAT DriverUNV SMESHDS SMESH MEFISTO2 StdMeshers + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ) +else(WIN32) + INSTALL(TARGETS SMDS Driver DriverSTL DriverDAT DriverUNV SMESHDS SMESH MEFISTO2 StdMeshers + LIBRARY DESTINATION lib + ) +endif(WIN32) + +if (FREECAD_BUILD_FEM_NETGEN) + if(WIN32) + INSTALL(TARGETS NETGENPlugin + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ) + else(WIN32) + INSTALL(TARGETS NETGENPlugin + LIBRARY DESTINATION lib + ) + endif(WIN32) +endif (FREECAD_BUILD_FEM_NETGEN) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index f1b526f56..db242cddb 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1385,6 +1385,10 @@ namespace boost { namespace filesystem { pair customSyntax(const string& s) { +#if defined(FC_OS_MACOSX) + if (s.find("-psn_") == 0) + return make_pair(string("psn"), s.substr(5)); +#endif if (s.find("-display") == 0) return make_pair(string("display"), string("null")); else if (s.find("-style") == 0) @@ -1493,6 +1497,9 @@ void Application::ParseOptions(int ac, char ** av) ("visual", boost::program_options::value< string >(), "set the X-Window to color scema") ("ncols", boost::program_options::value< int >(), "set the X-Window to color scema") ("cmap", "set the X-Window to color scema") +#if defined(FC_OS_MACOSX) + ("psn", boost::program_options::value< string >(), "process serial number") +#endif ; // Ignored options, will be savely ignored. Mostly uses by underlaying libs. diff --git a/src/App/Document.cpp b/src/App/Document.cpp index ee92e46da..5f476c04c 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -229,8 +229,8 @@ bool Document::undo(void) if (d->iUndoMode) { if (d->activeUndoTransaction) commitTransaction(); - else - assert(mUndoTransactions.size()!=0); + else if (mUndoTransactions.empty()) + return false; // redo d->activeUndoTransaction = new Transaction(); @@ -313,12 +313,21 @@ void Document::openTransaction(const char* name) } } -void Document::_checkTransaction(void) +void Document::_checkTransaction(DocumentObject* pcObject) { // if the undo is active but no transaction open, open one! if (d->iUndoMode) { - if (!d->activeUndoTransaction) - openTransaction(); + if (!d->activeUndoTransaction) { + // When the object is going to be deleted we have to check if it has already been added to + // the undo transactions + std::list::iterator it; + for (it = mUndoTransactions.begin(); it != mUndoTransactions.end(); ++it) { + if ((*it)->hasObject(pcObject)) { + openTransaction(); + break; + } + } + } } } @@ -1440,14 +1449,14 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName) /// Remove an object out of the document void Document::remObject(const char* sName) { - _checkTransaction(); - std::map::iterator pos = d->objectMap.find(sName); // name not found? if (pos == d->objectMap.end()) return; + _checkTransaction(pos->second); + if (d->activeObject == pos->second) d->activeObject = 0; @@ -1499,7 +1508,7 @@ void Document::remObject(const char* sName) /// Remove an object out of the document (internal) void Document::_remObject(DocumentObject* pcObject) { - _checkTransaction(); + _checkTransaction(pcObject); std::map::iterator pos = d->objectMap.find(pcObject->getNameInDocument()); diff --git a/src/App/Document.h b/src/App/Document.h index 3ab0cb639..f192244e8 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -293,7 +293,7 @@ protected: DocumentObject* _copyObject(DocumentObject* obj, std::map&, bool recursive=false, bool keepdigitsatend=false); /// checks if a valid transaction is open - void _checkTransaction(void); + void _checkTransaction(DocumentObject* pcObject); void breakDependency(DocumentObject* pcObject, bool clear); std::vector readObjects(Base::XMLReader& reader); void writeObjects(const std::vector&, Base::Writer &writer) const; diff --git a/src/App/Transactions.cpp b/src/App/Transactions.cpp index f61b97be9..d52376370 100644 --- a/src/App/Transactions.cpp +++ b/src/App/Transactions.cpp @@ -102,6 +102,12 @@ int Transaction::getPos(void) const return iPos; } +bool Transaction::hasObject(DocumentObject *Obj) const +{ + std::map::const_iterator it; + it = _Objects.find(Obj); + return (it != _Objects.end()); +} //************************************************************************** // separator for other implemetation aspects diff --git a/src/App/Transactions.h b/src/App/Transactions.h index d9657ed3c..5c66fa6f2 100644 --- a/src/App/Transactions.h +++ b/src/App/Transactions.h @@ -93,6 +93,8 @@ public: /// get the position in the transaction history int getPos(void) const; + /// check if this object is used in a transaction + bool hasObject(DocumentObject *Obj) const; friend class Document; diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index 4b5a06170..fca1e2784 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -14,6 +14,7 @@ include_directories( ${XERCESC_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} + ${PYCXX_INCLUDE_DIR} ) if(MSVC) @@ -62,6 +63,8 @@ generate_from_xml(MatrixPy) generate_from_xml(RotationPy) generate_from_xml(PlacementPy) generate_from_xml(AxisPy) +generate_from_xml(UnitPy) +generate_from_xml(QuantityPy) if(SWIG_FOUND) execute_process(COMMAND ${SWIG_EXECUTABLE} -python -external-runtime ${CMAKE_CURRENT_BINARY_DIR}/swigpyrun.h) @@ -124,20 +127,7 @@ SET(zipios_SRCS SOURCE_GROUP("zipios" FILES ${zipios_SRCS}) endif () -SET(pycxx_SRCS - ../CXX/Config.hxx - ../CXX/cxxextensions.c - ../CXX/cxx_extensions.cxx - ../CXX/cxxsupport.cxx - ../CXX/Exception.hxx - ../CXX/Extensions.hxx - ../CXX/IndirectPythonInterface.cxx - ../CXX/IndirectPythonInterface.hxx - ../CXX/Objects.hxx - ../CXX/Version.hxx - ../CXX/WrapPython.h -) -SOURCE_GROUP("pycxx" FILES ${pycxx_SRCS}) +SOURCE_GROUP("pycxx" FILES ${PYCXX_SOURCES}) SET(FreeCADBase_XML_SRCS AxisPy.xml @@ -148,6 +138,8 @@ SET(FreeCADBase_XML_SRCS PlacementPy.xml RotationPy.xml VectorPy.xml + QuantityPy.xml + UnitPy.xml ) SOURCE_GROUP("XML" FILES ${FreeCADBase_XML_SRCS}) @@ -171,6 +163,15 @@ SET(FreeCADBase_UNITAPI_SRCS UnitsSchemaImperial1.cpp UnitsApi.y UnitsApi.l + Quantity.h + Quantity.cpp + QuantityPyImp.cpp + QuantityParser.l + QuantityParser.y + Unit.h + Unit.cpp + UnitPyImp.cpp + ) SOURCE_GROUP("Units" FILES ${FreeCADBase_UNITAPI_SRCS}) @@ -279,7 +280,7 @@ SET(FreeCADBase_HPP_SRCS ) SET(FreeCADBase_SRCS - ${pycxx_SRCS} + ${PYCXX_SOURCES} ${FreeCADBase_CPP_SRCS} ${FreeCADBase_HPP_SRCS} ${FreeCADBase_XML_SRCS} diff --git a/src/Base/Console.cpp b/src/Base/Console.cpp index 7c5c82535..197594364 100644 --- a/src/Base/Console.cpp +++ b/src/Base/Console.cpp @@ -133,6 +133,28 @@ ConsoleMsgFlags ConsoleSingleton::SetEnabledMsgType(const char* sObs, ConsoleMsg } } +bool ConsoleSingleton::IsMsgTypeEnabled(const char* sObs, FreeCAD_ConsoleMsgType type) const +{ + ConsoleObserver* pObs = Get(sObs); + if (pObs) { + switch (type) { + case MsgType_Txt: + return pObs->bMsg; + case MsgType_Log: + return pObs->bLog; + case MsgType_Wrn: + return pObs->bWrn; + case MsgType_Err: + return pObs->bErr; + default: + return false; + } + } + else { + return false; + } +} + /** Prints a Message * This method issues a Message. * Messages are used show some non vital information. That means in the @@ -207,7 +229,7 @@ void ConsoleSingleton::Error( const char *pMsg, ... ) /** Prints a Message * this method is more for devlopment and tracking purpos. - * It can be used to track execution of algorithems and functions + * It can be used to track execution of algorithms and functions * and put it in files. The normal user dont need to see it, its more * for developers and experinced users. So in normal user modes the * logging is switched of. @@ -282,37 +304,40 @@ void ConsoleSingleton::DetachObserver(ConsoleObserver *pcObserver) void ConsoleSingleton::NotifyMessage(const char *sMsg) { - for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) + for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) { if((*Iter)->bMsg) (*Iter)->Message(sMsg); // send string to the listener + } } void ConsoleSingleton::NotifyWarning(const char *sMsg) { - for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) + for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) { if((*Iter)->bWrn) (*Iter)->Warning(sMsg); // send string to the listener + } } void ConsoleSingleton::NotifyError(const char *sMsg) { - for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) + for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) { if((*Iter)->bErr) (*Iter)->Error(sMsg); // send string to the listener + } } void ConsoleSingleton::NotifyLog(const char *sMsg) { - for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) + for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) { if((*Iter)->bLog) (*Iter)->Log(sMsg); // send string to the listener + } } -ConsoleObserver *ConsoleSingleton::Get(const char *Name) +ConsoleObserver *ConsoleSingleton::Get(const char *Name) const { const char* OName; - for(std::set::iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) - { + for(std::set::const_iterator Iter=_aclObservers.begin();Iter!=_aclObservers.end();Iter++) { OName = (*Iter)->Name(); // get the name if(OName && strcmp(OName,Name) == 0) return *Iter; @@ -539,13 +564,13 @@ PyObject *ConsoleSingleton::sPySetStatus(PyObject * /*self*/, PyObject *args, Py if(pObs) { if(strcmp(pstr2,"Log") == 0) - pObs->bLog = (Bool==0)?false:true; + pObs->bLog = (Bool==0)?false:true; else if(strcmp(pstr2,"Wrn") == 0) - pObs->bWrn = (Bool==0)?false:true; + pObs->bWrn = (Bool==0)?false:true; else if(strcmp(pstr2,"Msg") == 0) - pObs->bMsg = (Bool==0)?false:true; + pObs->bMsg = (Bool==0)?false:true; else if(strcmp(pstr2,"Err") == 0) - pObs->bErr = (Bool==0)?false:true; + pObs->bErr = (Bool==0)?false:true; else Py_Error(PyExc_Exception,"Unknown Message Type (use Log,Err,Msg or Wrn)"); diff --git a/src/Base/Console.h b/src/Base/Console.h index b51183b13..8b2e04eac 100644 --- a/src/Base/Console.h +++ b/src/Base/Console.h @@ -56,7 +56,7 @@ class ConsoleSingleton; typedef Base::ConsoleSingleton ConsoleMsgType; typedef unsigned int ConsoleMsgFlags; - + namespace Base { /** The console observer class @@ -141,12 +141,14 @@ public: void UnsetMode(ConsoleMode m); /// Enables or disables message types of a cetain console observer ConsoleMsgFlags SetEnabledMsgType(const char* sObs, ConsoleMsgFlags type, bool b); + /// Enables or disables message types of a cetain console observer + bool IsMsgTypeEnabled(const char* sObs, FreeCAD_ConsoleMsgType type) const; /// singleton static ConsoleSingleton &Instance(void); // retrieval of an observer by name - ConsoleObserver *Get(const char *Name); + ConsoleObserver *Get(const char *Name) const; static PyMethodDef Methods[]; diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp index 548265d98..812b7c625 100644 --- a/src/Base/Interpreter.cpp +++ b/src/Base/Interpreter.cpp @@ -71,12 +71,16 @@ PyException::PyException(void) _stackTrace = PP_last_error_trace; /* exception traceback text */ + + // This should be done in the constructor because when doing + // in the destructor it's not always clear when it is called + // and thus may clear a Python exception when it should not. + PyGILStateLocker locker; + PyErr_Clear(); // must be called to keep Python interpreter in a valid state (Werner) } PyException::~PyException() throw() { - PyGILStateLocker locker; - PyErr_Clear(); // must be called to keep Python interpreter in a valid state (Werner) } void PyException::ReportException (void) const diff --git a/src/Base/Matrix.cpp b/src/Base/Matrix.cpp index 18072b6b0..65968afcc 100644 --- a/src/Base/Matrix.cpp +++ b/src/Base/Matrix.cpp @@ -23,8 +23,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ -# include -# include +# include +# include # include #endif @@ -80,6 +80,14 @@ void Matrix4D::setToUnity (void) dMtrx4D[3][0] = 0.0; dMtrx4D[3][1] = 0.0; dMtrx4D[3][2] = 0.0; dMtrx4D[3][3] = 1.0; } +void Matrix4D::nullify(void) +{ + dMtrx4D[0][0] = 0.0; dMtrx4D[0][1] = 0.0; dMtrx4D[0][2] = 0.0; dMtrx4D[0][3] = 0.0; + dMtrx4D[1][0] = 0.0; dMtrx4D[1][1] = 0.0; dMtrx4D[1][2] = 0.0; dMtrx4D[1][3] = 0.0; + dMtrx4D[2][0] = 0.0; dMtrx4D[2][1] = 0.0; dMtrx4D[2][2] = 0.0; dMtrx4D[2][3] = 0.0; + dMtrx4D[3][0] = 0.0; dMtrx4D[3][1] = 0.0; dMtrx4D[3][2] = 0.0; dMtrx4D[3][3] = 0.0; +} + double Matrix4D::determinant() const { double fA0 = dMtrx4D[0][0]*dMtrx4D[1][1] - dMtrx4D[0][1]*dMtrx4D[1][0]; @@ -701,8 +709,8 @@ void Matrix4D::fromString(const std::string &str) input >> dMtrx4D[i][j]; } } - -// Analyse the a transformation Matrix and describe the transformation + +// Analyse the a transformation Matrix and describe the transformation std::string Matrix4D::analyse(void) const { const double eps=1.0e-06; @@ -723,22 +731,22 @@ std::string Matrix4D::analyse(void) const } else //translation and affine { - if (dMtrx4D[0][1] == 0.0 && dMtrx4D[0][2] == 0.0 && - dMtrx4D[1][0] == 0.0 && dMtrx4D[1][2] == 0.0 && + if (dMtrx4D[0][1] == 0.0 && dMtrx4D[0][2] == 0.0 && + dMtrx4D[1][0] == 0.0 && dMtrx4D[1][2] == 0.0 && dMtrx4D[2][0] == 0.0 && dMtrx4D[2][1] == 0.0) //scaling { - std::ostringstream stringStream; - stringStream << "Scale [" << dMtrx4D[0][0] << ", " << + std::ostringstream stringStream; + stringStream << "Scale [" << dMtrx4D[0][0] << ", " << dMtrx4D[1][1] << ", " << dMtrx4D[2][2] << "]"; - text = stringStream.str(); + text = stringStream.str(); } else { Base::Matrix4D sub; - sub[0][0] = dMtrx4D[0][0]; sub[0][1] = dMtrx4D[0][1]; - sub[0][2] = dMtrx4D[0][2]; sub[1][0] = dMtrx4D[1][0]; + sub[0][0] = dMtrx4D[0][0]; sub[0][1] = dMtrx4D[0][1]; + sub[0][2] = dMtrx4D[0][2]; sub[1][0] = dMtrx4D[1][0]; sub[1][1] = dMtrx4D[1][1]; sub[1][2] = dMtrx4D[1][2]; - sub[2][0] = dMtrx4D[2][0]; sub[2][1] = dMtrx4D[2][1]; + sub[2][0] = dMtrx4D[2][0]; sub[2][1] = dMtrx4D[2][1]; sub[2][2] = dMtrx4D[2][2]; Base::Matrix4D trp = sub; @@ -771,23 +779,23 @@ std::string Matrix4D::analyse(void) const } else //scaling with rotation { - std::ostringstream stringStream; - stringStream << "Scale and Rotate "; + std::ostringstream stringStream; + stringStream << "Scale and Rotate "; if (determinant<0.0 ) - stringStream << "and Invert "; - stringStream << "[ " << - sqrt(trp[0][0]) << ", " << sqrt(trp[1][1]) << ", " << + stringStream << "and Invert "; + stringStream << "[ " << + sqrt(trp[0][0]) << ", " << sqrt(trp[1][1]) << ", " << sqrt(trp[2][2]) << "]"; - text = stringStream.str(); + text = stringStream.str(); } } } else { - std::ostringstream stringStream; - stringStream << "Affine with det= " << + std::ostringstream stringStream; + stringStream << "Affine with det= " << determinant; - text = stringStream.str(); + text = stringStream.str(); } } } @@ -795,4 +803,4 @@ std::string Matrix4D::analyse(void) const text += " with Translation"; } return text; -} +} diff --git a/src/Base/Matrix.h b/src/Base/Matrix.h index 36444c667..f53019a4a 100644 --- a/src/Base/Matrix.h +++ b/src/Base/Matrix.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "Vector3D.h" @@ -104,7 +104,9 @@ public: /** @name Manipulation */ //@{ /// Makes unity matrix - void setToUnity (void); + void setToUnity(void); + /// Makes a null matrix + void nullify(void); /// moves the coordinatesystem for the x,y,z value void move (float x, float y, float z) { move(Vector3f(x,y,z)); } diff --git a/src/Base/Parser.bat b/src/Base/Parser.bat new file mode 100644 index 000000000..8d9394cf2 --- /dev/null +++ b/src/Base/Parser.bat @@ -0,0 +1,2 @@ +C:\Tools\GnuWin32\bin\flex.exe -oQuantityLexer.c QuantityParser.l +C:\Tools\GnuWin32\bin\bison -oQuantityParser.c QuantityParser.y \ No newline at end of file diff --git a/src/Base/Quantity.cpp b/src/Base/Quantity.cpp new file mode 100644 index 000000000..29e6e4bfb --- /dev/null +++ b/src/Base/Quantity.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + * Copyright (c) 2013 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 "Quantity.h" +#include "Exception.h" + +using namespace Base; + +Quantity::Quantity() +{ + this->_Value = 0.0; +} + +Quantity::Quantity(const Quantity& that) +{ + *this = that ; +} + +Quantity::Quantity(double Value, const Unit& unit) +{ + this->_Unit = unit; + this->_Value = Value; +} + + +bool Quantity::operator ==(const Quantity& that) const +{ + return (this->_Value == that._Value) && (this->_Unit == that._Unit) ; +} + + +Quantity Quantity::operator *(const Quantity &p) const +{ + return Quantity(this->_Value * p._Value,this->_Unit * p._Unit); +} +Quantity Quantity::operator /(const Quantity &p) const +{ + return Quantity(this->_Value / p._Value,this->_Unit / p._Unit); +} + +Quantity Quantity::pow(const Quantity &p) const +{ + if(!p._Unit.isEmpty()) + throw Base::Exception("Quantity::pow(): exponent must not have a unit"); + return Quantity( + std::pow(this->_Value, p._Value), + this->_Unit.pow((short)p._Value) + ); +} + + +Quantity Quantity::operator +(const Quantity &p) const +{ + if(this->_Unit != p._Unit) + throw Base::Exception("Quantity::operator +(): Unit missmatch in plus operation"); + return Quantity(this->_Value + p._Value,this->_Unit); +} +Quantity Quantity::operator -(const Quantity &p) const +{ + if(this->_Unit != p._Unit) + throw Base::Exception("Quantity::operator +(): Unit missmatch in plus operation"); + return Quantity(this->_Value - p._Value,this->_Unit); +} + +Quantity Quantity::operator -(void) const +{ + return Quantity(-(this->_Value),this->_Unit); +} + +Quantity& Quantity::operator = (const Quantity &New) +{ + this->_Value = New._Value; + this->_Unit = New._Unit; + return *this; +} + +// === Parser & Scanner stuff =============================================== + +// include the Scanner and the Parser for the Quantitys + +Quantity QuantResult; + +#ifndef DOUBLE_MAX +# define DOUBLE_MAX 1.7976931348623157E+308 /* max decimal value of a "double"*/ +#endif +#ifndef DOUBLE_MIN +# define DOUBLE_MIN 2.2250738585072014E-308 /* min decimal value of a "double"*/ +#endif + + +// error func +void Quantity_yyerror(char *errorinfo) +{ + throw Base::Exception(errorinfo); +} + + +// for VC9 (isatty and fileno not supported anymore) +//#ifdef _MSC_VER +//int isatty (int i) {return _isatty(i);} +//int fileno(FILE *stream) {return _fileno(stream);} +//#endif + +namespace QuantityParser { + +// show the parser the lexer method +#define yylex QuantityLexer +int QuantityLexer(void); + +// Parser, defined in QuantityParser.y +#include "QuantityParser.c" + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +// Scanner, defined in QuantityParser.l +#include "QuantityLexer.c" +#endif // DOXYGEN_SHOULD_SKIP_THIS +} + +Quantity Quantity::parse(const char* buffer) +{ + // parse from buffer + QuantityParser::YY_BUFFER_STATE my_string_buffer = QuantityParser::yy_scan_string (buffer); + // set the global return variables + QuantResult = Quantity(DOUBLE_MIN); + // run the parser + QuantityParser::yyparse (); + // free the scan buffer + QuantityParser::yy_delete_buffer (my_string_buffer); + + if (QuantResult == Quantity(DOUBLE_MIN)) + throw Base::Exception("Unknown error in Quantity expression"); + return QuantResult; +} diff --git a/src/Base/Quantity.h b/src/Base/Quantity.h new file mode 100644 index 000000000..8f5646cd9 --- /dev/null +++ b/src/Base/Quantity.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (c) 2013 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 BASE_Quantity_H +#define BASE_Quantity_H + +#include "Unit.h" + +namespace Base { + +/** + * The Quantity class. + */ +class BaseExport Quantity +{ +public: + /// default constructor + Quantity(void); + Quantity(const Quantity&); + Quantity(double Value, const Unit& unit=Unit()); + /// Destruction + ~Quantity () {}; + + /** Operators. */ + //@{ + Quantity operator *(const Quantity &p) const; + Quantity operator +(const Quantity &p) const; + Quantity operator -(const Quantity &p) const; + Quantity operator -(void) const; + Quantity operator /(const Quantity &p) const; + bool operator ==(const Quantity&) const; + Quantity& operator =(const Quantity&); + Quantity pow(const Quantity&)const; + //@} + +protected: + double _Value; + Unit _Unit; + + static Quantity parse(const char* buffer); +}; + +} // namespace Base + +#endif // BASE_Quantity_H diff --git a/src/Base/QuantityLexer.c b/src/Base/QuantityLexer.c new file mode 100644 index 000000000..3ed01975a --- /dev/null +++ b/src/Base/QuantityLexer.c @@ -0,0 +1,1743 @@ +#line 2 "QuantityLexer.c" +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + + +#define yywrap() 1 +#define YY_SKIP_YYWRAP +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 40 +#define YY_END_OF_BUFFER 41 +static yyconst short int yy_accept[63] = + { 0, + 0, 0, 41, 40, 1, 2, 10, 12, 3, 37, + 29, 30, 40, 40, 39, 40, 16, 28, 40, 40, + 35, 5, 40, 40, 40, 26, 18, 40, 2, 36, + 37, 31, 6, 0, 0, 7, 11, 0, 9, 15, + 8, 19, 17, 0, 34, 4, 0, 20, 38, 0, + 21, 13, 33, 14, 36, 22, 23, 25, 27, 32, + 24, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 1, 1, 1, 1, 5, 6, + 6, 6, 6, 1, 6, 7, 6, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, + 6, 1, 1, 1, 9, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 10, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6, 1, 1, 11, 12, 13, 14, + + 15, 16, 17, 18, 19, 1, 20, 21, 22, 23, + 24, 25, 1, 26, 27, 28, 1, 1, 29, 1, + 30, 31, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[32] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1 + } ; + +static yyconst short int yy_base[63] = + { 0, + 0, 0, 69, 70, 70, 65, 70, 70, 70, 25, + 70, 70, 20, 21, 70, 43, 42, 70, 42, 18, + 52, 33, 32, 43, 50, 32, 41, 18, 55, 48, + 30, 70, 70, 25, 34, 70, 70, 25, 70, 70, + 70, 70, 70, 24, 70, 70, 25, 70, 70, 31, + 70, 70, 70, 70, 33, 70, 70, 70, 70, 70, + 70, 70 + } ; + +static yyconst short int yy_def[63] = + { 0, + 62, 1, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 0 + } ; + +static yyconst short int yy_nxt[102] = + { 0, + 4, 5, 6, 7, 8, 9, 4, 10, 11, 12, + 4, 4, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 4, 23, 24, 25, 26, 27, 4, 28, + 4, 30, 31, 32, 40, 35, 30, 31, 53, 41, + 55, 33, 36, 54, 61, 60, 59, 58, 34, 43, + 57, 44, 56, 45, 46, 55, 47, 29, 52, 51, + 50, 49, 48, 42, 39, 38, 37, 29, 62, 3, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + + 62 + } ; + +static yyconst short int yy_chk[102] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 10, 10, 13, 20, 14, 31, 31, 28, 20, + 55, 13, 14, 28, 50, 47, 44, 38, 13, 22, + 35, 22, 34, 22, 22, 30, 22, 29, 27, 26, + 25, 24, 23, 21, 19, 17, 16, 6, 3, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + + 62 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "QuantityParser.l" +#define INITIAL 0 +#line 2 "QuantityParser.l" +/* Lexer for the FreeCAD Units language */ +/* (c) 2013 Juergen Riegel LGPL */ + + +/* This disables inclusion of unistd.h, which is not available under Visual C++ + * on Win32. The C++ scanner uses STL streams instead. */ +#define YY_NO_UNISTD_H + +/*** Flex Declarations and Options ***/ +/* the manual says "somewhat more optimized" */ +#define YY_NEVER_INTERACTIVE 1 +/* no support for include files is planned */ +#define YY_NO_UNPUT 1 +#line 424 "QuantityLexer.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 27 "QuantityParser.l" + + + +#line 579 "QuantityLexer.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 63 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 62 ); + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 30 "QuantityParser.l" +; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 31 "QuantityParser.l" +; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 33 "QuantityParser.l" +{ return *yytext; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 35 "QuantityParser.l" +yylval = 1.0; return UNIT; // millimeter (internal standard length) + YY_BREAK +case 5: +YY_RULE_SETUP +#line 36 "QuantityParser.l" +yylval = 1000.0; return UNIT; // meter + YY_BREAK +case 6: +YY_RULE_SETUP +#line 37 "QuantityParser.l" +yylval = 10.0; return UNIT; // centimeter + YY_BREAK +case 7: +YY_RULE_SETUP +#line 38 "QuantityParser.l" +yylval = 100.0; return UNIT; // decimeter + YY_BREAK +case 8: +YY_RULE_SETUP +#line 39 "QuantityParser.l" +yylval = 1000000.0; return UNIT; // kilometer + YY_BREAK +case 9: +YY_RULE_SETUP +#line 41 "QuantityParser.l" +yylval = 25.4; return UNIT; // inch + YY_BREAK +case 10: +YY_RULE_SETUP +#line 42 "QuantityParser.l" +yylval = 25.4; return UNIT; // inch + YY_BREAK +case 11: +YY_RULE_SETUP +#line 43 "QuantityParser.l" +yylval = 304.8; return UNIT; // foot + YY_BREAK +case 12: +YY_RULE_SETUP +#line 44 "QuantityParser.l" +yylval = 304.8; return UNIT; // foot + YY_BREAK +case 13: +YY_RULE_SETUP +#line 45 "QuantityParser.l" +yylval = 0.0254; return UNIT; // thou + YY_BREAK +case 14: +YY_RULE_SETUP +#line 46 "QuantityParser.l" +yylval = 914.4; return UNIT; // yard + YY_BREAK +case 15: +YY_RULE_SETUP +#line 48 "QuantityParser.l" +yylval = 1.0; return UNIT; // kilogram (internal standard mass) + YY_BREAK +case 16: +YY_RULE_SETUP +#line 49 "QuantityParser.l" +yylval = 0.001; return UNIT; // gram + YY_BREAK +case 17: +YY_RULE_SETUP +#line 50 "QuantityParser.l" +yylval = 0.000001; return UNIT; // milligram + YY_BREAK +case 18: +YY_RULE_SETUP +#line 51 "QuantityParser.l" +yylval = 1000.0; return UNIT; // ton + YY_BREAK +case 19: +YY_RULE_SETUP +#line 53 "QuantityParser.l" +yylval = 0.45359237; return UNIT; // pound + YY_BREAK +case 20: +YY_RULE_SETUP +#line 54 "QuantityParser.l" +yylval = 0.45359237; return UNIT; // ounce + YY_BREAK +case 21: +YY_RULE_SETUP +#line 55 "QuantityParser.l" +yylval = 6.35029318; return UNIT; // Stone + YY_BREAK +case 22: +YY_RULE_SETUP +#line 56 "QuantityParser.l" +yylval = 50.80234544;return UNIT; // hundredweights + YY_BREAK +case 23: +YY_RULE_SETUP +#line 58 "QuantityParser.l" +yylval = 1.0; return UNIT; // degree (internal standard angle) + YY_BREAK +case 24: +YY_RULE_SETUP +#line 59 "QuantityParser.l" +yylval = 180/M_PI; return UNIT; // radian + YY_BREAK +case 25: +YY_RULE_SETUP +#line 60 "QuantityParser.l" +yylval = 360.0/400.0;return UNIT; // gon + YY_BREAK +case 26: +YY_RULE_SETUP +#line 62 "QuantityParser.l" +yylval = 1.0; return UNIT; // second (internal standard time) + YY_BREAK +case 27: +YY_RULE_SETUP +#line 63 "QuantityParser.l" +yylval = 60.0; return UNIT; // minute + YY_BREAK +case 28: +YY_RULE_SETUP +#line 64 "QuantityParser.l" +yylval = 3600.0; return UNIT; // hour + YY_BREAK +case 29: +YY_RULE_SETUP +#line 66 "QuantityParser.l" +yylval = 1.0; return UNIT; // Ampere (internal standard electric current) + YY_BREAK +case 30: +YY_RULE_SETUP +#line 67 "QuantityParser.l" +yylval = 1.0; return UNIT; // Kelvin (internal standard thermodynamic temperature) + YY_BREAK +case 31: +YY_RULE_SETUP +#line 68 "QuantityParser.l" +yylval = 1.0; return UNIT; // Candela (internal standard luminous intensity) + YY_BREAK +case 32: +YY_RULE_SETUP +#line 69 "QuantityParser.l" +yylval = 1.0; return UNIT; // Mole (internal standard amount of substance) + YY_BREAK +case 33: +YY_RULE_SETUP +#line 71 "QuantityParser.l" +yylval = 1.0; return UNIT; // microliter mm^3(derived standard volume) + YY_BREAK +case 34: +YY_RULE_SETUP +#line 72 "QuantityParser.l" +yylval = 1000.0; return UNIT; // milliliter cm^3 + YY_BREAK +case 35: +YY_RULE_SETUP +#line 73 "QuantityParser.l" +yylval = 1000000.0; return UNIT; // Liter dm^3 + YY_BREAK +case 36: +YY_RULE_SETUP +#line 78 "QuantityParser.l" +{yylval = atof( yytext ); return NUM;} + YY_BREAK +case 37: +YY_RULE_SETUP +#line 79 "QuantityParser.l" +{yylval = atof( yytext ); return NUM;} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 81 "QuantityParser.l" +{yylval = M_PI ; return NUM;} // constant pi + YY_BREAK +case 39: +YY_RULE_SETUP +#line 82 "QuantityParser.l" +{yylval = M_E ; return NUM;} // constant e + YY_BREAK +case 40: +YY_RULE_SETUP +#line 86 "QuantityParser.l" +ECHO; + YY_BREAK +#line 858 "QuantityLexer.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 63 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 63 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 62); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 86 "QuantityParser.l" diff --git a/src/Base/QuantityParser.c b/src/Base/QuantityParser.c new file mode 100644 index 000000000..0410baa6c --- /dev/null +++ b/src/Base/QuantityParser.c @@ -0,0 +1,1615 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 6 "QuantityParser.y" + + #define YYSTYPE Quantity + #define yyparse Quantity_yyparse + #define yyerror Quantity_yyerror + + +/* Line 189 of yacc.c */ +#line 80 "QuantityParser.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + UNIT = 258, + NUM = 259, + NEG = 260 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 127 "QuantityParser.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 10 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 30 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 13 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 3 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 12 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 22 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 260 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 11, 12, 7, 6, 2, 5, 2, 8, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 9 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 7, 9, 12, 16, 20, 24, + 28, 31, 35 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 14, 0, -1, 15, -1, 4, -1, 3, -1, 4, + 3, -1, 15, 6, 15, -1, 15, 5, 15, -1, + 15, 7, 15, -1, 15, 8, 15, -1, 5, 15, + -1, 15, 10, 4, -1, 11, 15, 12, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 25, 25, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "UNIT", "NUM", "'-'", "'+'", "'*'", + "'/'", "NEG", "'^'", "'('", "')'", "$accept", "input", "exp", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 45, 43, 42, 47, 260, + 94, 40, 41 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 13, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 2, 3, 3, 3, 3, + 2, 3, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 4, 3, 0, 0, 0, 2, 5, 10, 0, + 1, 0, 0, 0, 0, 0, 12, 7, 6, 8, + 9, 11 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 5, 6 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -4 +static const yytype_int8 yypact[] = +{ + 1, -4, -1, 1, 1, 3, 16, -4, 7, 8, + -4, 1, 1, 1, 1, 15, -4, 20, 20, 7, + 7, -4 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -4, -4, -3 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 8, 9, 7, 10, 1, 2, 3, 0, 17, 18, + 19, 20, 4, 11, 12, 13, 14, 15, 15, 21, + 16, 11, 12, 13, 14, 0, 15, 13, 14, 0, + 15 +}; + +static const yytype_int8 yycheck[] = +{ + 3, 4, 3, 0, 3, 4, 5, -1, 11, 12, + 13, 14, 11, 5, 6, 7, 8, 10, 10, 4, + 12, 5, 6, 7, 8, -1, 10, 7, 8, -1, + 10 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 11, 14, 15, 3, 15, 15, + 0, 5, 6, 7, 8, 10, 12, 15, 15, 15, + 15, 4 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1455 of yacc.c */ +#line 25 "QuantityParser.y" + { QuantResult = (yyvsp[(1) - (1)]) ; ;} + break; + + case 3: + +/* Line 1455 of yacc.c */ +#line 28 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (1)]); ;} + break; + + case 4: + +/* Line 1455 of yacc.c */ +#line 29 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (1)]); ;} + break; + + case 5: + +/* Line 1455 of yacc.c */ +#line 30 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (2)])*(yyvsp[(2) - (2)]); ;} + break; + + case 6: + +/* Line 1455 of yacc.c */ +#line 31 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (3)]) + (yyvsp[(3) - (3)]); ;} + break; + + case 7: + +/* Line 1455 of yacc.c */ +#line 32 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (3)]) - (yyvsp[(3) - (3)]); ;} + break; + + case 8: + +/* Line 1455 of yacc.c */ +#line 33 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (3)]) * (yyvsp[(3) - (3)]); ;} + break; + + case 9: + +/* Line 1455 of yacc.c */ +#line 34 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (3)]) / (yyvsp[(3) - (3)]); ;} + break; + + case 10: + +/* Line 1455 of yacc.c */ +#line 35 "QuantityParser.y" + { (yyval) = -(yyvsp[(2) - (2)]); ;} + break; + + case 11: + +/* Line 1455 of yacc.c */ +#line 36 "QuantityParser.y" + { (yyval) = (yyvsp[(1) - (3)]).pow((yyvsp[(3) - (3)])); ;} + break; + + case 12: + +/* Line 1455 of yacc.c */ +#line 37 "QuantityParser.y" + { (yyval) = (yyvsp[(2) - (3)]); ;} + break; + + + +/* Line 1455 of yacc.c */ +#line 1402 "QuantityParser.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 41 "QuantityParser.y" + + diff --git a/src/Base/QuantityParser.l b/src/Base/QuantityParser.l new file mode 100644 index 000000000..07434bac3 --- /dev/null +++ b/src/Base/QuantityParser.l @@ -0,0 +1,85 @@ +%{ +/* Lexer for the FreeCAD Units language */ +/* (c) 2013 Juergen Riegel LGPL */ + + +/* This disables inclusion of unistd.h, which is not available under Visual C++ + * on Win32. The C++ scanner uses STL streams instead. */ +#define YY_NO_UNISTD_H + +%} + +/*** Flex Declarations and Options ***/ + + +/* the manual says "somewhat more optimized" */ +%option batch +%option never-interactive + + +/* no support for include files is planned */ +%option noyywrap nounput + +DIGIT [0-9] +ID [a-z][a-z0-9]* + + +%% /*** Filter language Part ***/ + + +[ \t] ; +[\n]+ ; + +[-+()=/*^] { return *yytext; } + +"mm" yylval = 1.0; return UNIT; // millimeter (internal standard length) +"m" yylval = 1000.0; return UNIT; // meter +"cm" yylval = 10.0; return UNIT; // centimeter +"dm" yylval = 100.0; return UNIT; // decimeter +"km" yylval = 1000000.0; return UNIT; // kilometer + +"in" yylval = 25.4; return UNIT; // inch +"\"" yylval = 25.4; return UNIT; // inch +"fo" yylval = 304.8; return UNIT; // foot +"'" yylval = 304.8; return UNIT; // foot +"th" yylval = 0.0254; return UNIT; // thou +"yr" yylval = 914.4; return UNIT; // yard + +"kg" yylval = 1.0; return UNIT; // kilogram (internal standard mass) +"g" yylval = 0.001; return UNIT; // gram +"mg" yylval = 0.000001; return UNIT; // milligram +"t" yylval = 1000.0; return UNIT; // ton + +"lb" yylval = 0.45359237; return UNIT; // pound +"oz" yylval = 0.45359237; return UNIT; // ounce +"st" yylval = 6.35029318; return UNIT; // Stone +"cwt" yylval = 50.80234544;return UNIT; // hundredweights + +"deg" yylval = 1.0; return UNIT; // degree (internal standard angle) +"rad" yylval = 180/M_PI; return UNIT; // radian +"gon" yylval = 360.0/400.0;return UNIT; // gon + +"s" yylval = 1.0; return UNIT; // second (internal standard time) +"min" yylval = 60.0; return UNIT; // minute +"h" yylval = 3600.0; return UNIT; // hour + +"A" yylval = 1.0; return UNIT; // Ampere (internal standard electric current) +"K" yylval = 1.0; return UNIT; // Kelvin (internal standard thermodynamic temperature) +"cd" yylval = 1.0; return UNIT; // Candela (internal standard luminous intensity) +"mol" yylval = 1.0; return UNIT; // Mole (internal standard amount of substance) + +"yl" yylval = 1.0; return UNIT; // microliter mm^3(derived standard volume) +"ml" yylval = 1000.0; return UNIT; // milliliter cm^3 +"l" yylval = 1000000.0; return UNIT; // Liter dm^3 + + + + +{DIGIT}+"."{DIGIT}* {yylval = atof( yytext ); return NUM;} +{DIGIT}+ {yylval = atof( yytext ); return NUM;} + +"pi" {yylval = M_PI ; return NUM;} // constant pi +"e" {yylval = M_E ; return NUM;} // constant e + + + diff --git a/src/Base/QuantityParser.y b/src/Base/QuantityParser.y new file mode 100644 index 000000000..5ab6b1723 --- /dev/null +++ b/src/Base/QuantityParser.y @@ -0,0 +1,41 @@ +/* Parser for the FreeCAD Units language */ +/* (c) 2013 Juergen Riegel LGPL */ + + +/* Represents the many different ways we can access our data */ +%{ + #define YYSTYPE Quantity + #define yyparse Quantity_yyparse + #define yyerror Quantity_yyerror +%} + + /* Bison declarations. */ + %token UNIT NUM + %left '-' '+' + %left '*' '/' + %left NEG /* negation--unary minus */ + %right '^' /* exponentiation */ + + + +%start input + +%% + + input: exp { QuantResult = $1 ; } + ; + + exp: NUM { $$ = $1; } + | UNIT { $$ = $1; } + | NUM UNIT { $$ = $1*$2; } + | exp '+' exp { $$ = $1 + $3; } + | exp '-' exp { $$ = $1 - $3; } + | exp '*' exp { $$ = $1 * $3; } + | exp '/' exp { $$ = $1 / $3; } + | '-' exp %prec NEG { $$ = -$2; } + | exp '^' NUM { $$ = $1.pow($3); } + | '(' exp ')' { $$ = $2; } +; + + +%% diff --git a/src/Base/QuantityPy.xml b/src/Base/QuantityPy.xml new file mode 100644 index 000000000..5f12089fe --- /dev/null +++ b/src/Base/QuantityPy.xml @@ -0,0 +1,48 @@ + + + + + + Quantity +defined by a value and a unit. + +The following constructors are supported: +Quantity() -- empty constructor +Quantity(Value) -- empty constructor +Quantity(Value,Unit) -- empty constructor +Quantity(Quantity) -- copy constructor +Quantity(string) -- arbitrary mixture of numbers and chars defining a Quantity + + Quantity + + + + + multiply two quantities + + + + + + Vector to the Base position of the Quantity + + + + + + Direction vector of the Quantity + + + + + diff --git a/src/Base/QuantityPyImp.cpp b/src/Base/QuantityPyImp.cpp new file mode 100644 index 000000000..26240ce6d --- /dev/null +++ b/src/Base/QuantityPyImp.cpp @@ -0,0 +1,73 @@ + +#include "PreCompiled.h" + +#include "Base/Quantity.h" + +// inclusion of the generated files (generated out of QuantityPy.xml) +#include "QuantityPy.h" +#include "QuantityPy.cpp" + +using namespace Base; + +// returns a string which represents the object e.g. when printed in python +std::string QuantityPy::representation(void) const +{ + return std::string(""); +} + +PyObject *QuantityPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper +{ + // create a new instance of QuantityPy and the Twin object + return new QuantityPy(new Quantity); +} + +// constructor method +int QuantityPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) +{ + return 0; +} + + +PyObject* QuantityPy::multiply(PyObject * /*args*/) +{ + PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented"); + return 0; +} + + + + + +Py::Float QuantityPy::getValue(void) const +{ + //return Py::Float(); + throw Py::AttributeError("Not yet implemented"); +} + +void QuantityPy::setValue(Py::Float /*arg*/) +{ + throw Py::AttributeError("Not yet implemented"); +} + +Py::Object QuantityPy::getUnit(void) const +{ + //return Py::Object(); + throw Py::AttributeError("Not yet implemented"); +} + +void QuantityPy::setUnit(Py::Object /*arg*/) +{ + throw Py::AttributeError("Not yet implemented"); +} + +PyObject *QuantityPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int QuantityPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Base/Unit.cpp b/src/Base/Unit.cpp new file mode 100644 index 000000000..cc2d37847 --- /dev/null +++ b/src/Base/Unit.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + * 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 "Unit.h" + +using namespace Base; + + +Unit::Unit(int8_t Length, + int8_t Mass, + int8_t Time, + int8_t ElectricCurrent, + int8_t ThermodynamicTemperature, + int8_t AmountOfSubstance, + int8_t LuminoseIntensity, + int8_t Angle) +{ + Sig.Length = Length; + Sig.Mass = Mass; + Sig.Time = Time; + Sig.ElectricCurrent = ElectricCurrent; + Sig.ThermodynamicTemperature = ThermodynamicTemperature; + Sig.AmountOfSubstance = AmountOfSubstance; + Sig.LuminoseIntensity = LuminoseIntensity; + Sig.Angle = Angle; +} + + +Unit::Unit() +{ + +} + +Unit::Unit(const Unit& that) +{ + this->Sig = that.Sig; +} + +Unit::Unit(const std::string& Pars) +{ + +} + + +Unit Unit::pow(char exp)const +{ + Unit result; + result.Sig.Length = Sig.Length * exp; + result.Sig.Mass = Sig.Mass * exp; + result.Sig.Time = Sig.Time * exp; + result.Sig.ElectricCurrent = Sig.ElectricCurrent * exp; + result.Sig.ThermodynamicTemperature = Sig.ThermodynamicTemperature * exp; + result.Sig.AmountOfSubstance = Sig.AmountOfSubstance * exp; + result.Sig.LuminoseIntensity = Sig.LuminoseIntensity * exp; + result.Sig.Angle = Sig.Angle * exp; + + return result; + +} + +bool Unit::isEmpty(void)const +{ + return (this->Sig.Length == 0) + && (this->Sig.Mass == 0) + && (this->Sig.Time == 0) + && (this->Sig.ElectricCurrent == 0) + && (this->Sig.ThermodynamicTemperature == 0) + && (this->Sig.AmountOfSubstance == 0) + && (this->Sig.LuminoseIntensity == 0) + && (this->Sig.Angle == 0); +} + +bool Unit::operator ==(const Unit& that) const +{ + return (this->Sig.Length == that.Sig.Length) + && (this->Sig.Mass == that.Sig.Mass) + && (this->Sig.Time == that.Sig.Time) + && (this->Sig.ElectricCurrent == that.Sig.ElectricCurrent) + && (this->Sig.ThermodynamicTemperature == that.Sig.ThermodynamicTemperature) + && (this->Sig.AmountOfSubstance == that.Sig.AmountOfSubstance) + && (this->Sig.LuminoseIntensity == that.Sig.LuminoseIntensity) + && (this->Sig.Angle == that.Sig.Angle); +} + + +Unit Unit::operator *(const Unit &right) const +{ + Unit result; + result.Sig.Length = Sig.Length + right.Sig.Length; + result.Sig.Mass = Sig.Mass + right.Sig.Mass; + result.Sig.Time = Sig.Time + right.Sig.Time; + result.Sig.ElectricCurrent = Sig.ElectricCurrent + right.Sig.ElectricCurrent; + result.Sig.ThermodynamicTemperature = Sig.ThermodynamicTemperature + right.Sig.ThermodynamicTemperature; + result.Sig.AmountOfSubstance = Sig.AmountOfSubstance + right.Sig.AmountOfSubstance; + result.Sig.LuminoseIntensity = Sig.LuminoseIntensity + right.Sig.LuminoseIntensity; + result.Sig.Angle = Sig.Angle + right.Sig.Angle; + + return result; +} + +Unit Unit::operator /(const Unit &right) const +{ + Unit result; + result.Sig.Length = Sig.Length - right.Sig.Length; + result.Sig.Mass = Sig.Mass - right.Sig.Mass; + result.Sig.Time = Sig.Time - right.Sig.Time; + result.Sig.ElectricCurrent = Sig.ElectricCurrent - right.Sig.ElectricCurrent; + result.Sig.ThermodynamicTemperature = Sig.ThermodynamicTemperature - right.Sig.ThermodynamicTemperature; + result.Sig.AmountOfSubstance = Sig.AmountOfSubstance - right.Sig.AmountOfSubstance; + result.Sig.LuminoseIntensity = Sig.LuminoseIntensity - right.Sig.LuminoseIntensity; + result.Sig.Angle = Sig.Angle - right.Sig.Angle; + + return result; +} + +Unit& Unit::operator = (const Unit &New) +{ + Sig.Length = New.Sig.Length; + Sig.Mass = New.Sig.Mass ; + Sig.Time = New.Sig.Time ; + Sig.ElectricCurrent = New.Sig.ElectricCurrent ; + Sig.ThermodynamicTemperature = New.Sig.ThermodynamicTemperature; + Sig.AmountOfSubstance = New.Sig.AmountOfSubstance ; + Sig.LuminoseIntensity = New.Sig.LuminoseIntensity ; + Sig.Angle = New.Sig.Angle ; + + return *this; +} \ No newline at end of file diff --git a/src/Base/Unit.h b/src/Base/Unit.h new file mode 100644 index 000000000..8c1f92701 --- /dev/null +++ b/src/Base/Unit.h @@ -0,0 +1,95 @@ +/*************************************************************************** + * 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 BASE_Unit_H +#define BASE_Unit_H + +#ifdef _MSC_VER +# include +#else +# include +#endif +#include + +namespace Base { + + +struct UnitSignature{ + int32_t Length:4; + int32_t Mass:4; + int32_t Time:4; + int32_t ElectricCurrent:4; + int32_t ThermodynamicTemperature:4; + int32_t AmountOfSubstance:4; + int32_t LuminoseIntensity:4; + int32_t Angle:4; +}; +/** + * The Unit class. + */ +class BaseExport Unit +{ +public: + /// default constructor + Unit(int8_t Length,int8_t Mass=0,int8_t Time=0,int8_t ElectricCurrent=0,int8_t ThermodynamicTemperature=0,int8_t AmountOfSubstance=0,int8_t LuminoseIntensity=0,int8_t Angle=0); + Unit(void); + Unit(const Unit&); + Unit(const std::string& Pars); + /// Destruction + ~Unit () {}; + + + /** Operators. */ + //@{ + inline Unit& operator *=(const Unit& that); + inline Unit& operator /=(const Unit& that); + Unit operator *(const Unit&) const; + Unit operator /(const Unit&) const; + bool operator ==(const Unit&) const; + bool operator !=(const Unit&that) const {return !(*this == that);} + Unit& operator =(const Unit&); + Unit pow(char exp)const; + //@} + + bool isEmpty(void)const; + char getLengthDimension(void){return Sig.Length;} + +protected: + UnitSignature Sig; +}; + +inline Unit& Unit::operator *=(const Unit& that) +{ + *this = *this * that; + return *this; +} + +inline Unit& Unit::operator /=(const Unit& that) +{ + *this = *this / that; + return *this; +} + +} // namespace Base + +#endif // BASE_Unit_H diff --git a/src/Base/UnitPy.xml b/src/Base/UnitPy.xml new file mode 100644 index 000000000..5ba7fcc65 --- /dev/null +++ b/src/Base/UnitPy.xml @@ -0,0 +1,48 @@ + + + + + + Unit +defines a unit type and calculate and compare. + +The following constructors are supported: +Unit() -- empty constructor +Unit(Unit) -- copy constructor +Unit(string) -- parse the string for units + + Unit + + + + + multiply(Placement) + Multiply this axis with a placement + + + + + + + get the type of the unit as string + + + + + + get the dimension as a vector with 8 fields + + + + + diff --git a/src/Base/UnitPyImp.cpp b/src/Base/UnitPyImp.cpp new file mode 100644 index 000000000..aaabc2cf8 --- /dev/null +++ b/src/Base/UnitPyImp.cpp @@ -0,0 +1,68 @@ + +#include "PreCompiled.h" + +#include "Base/Unit.h" + +// inclusion of the generated files (generated out of UnitPy.xml) +#include "UnitPy.h" +#include "UnitPy.cpp" + +using namespace Base; + +// returns a string which represents the object e.g. when printed in python +std::string UnitPy::representation(void) const +{ + return std::string(""); +} + +PyObject *UnitPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper +{ + // create a new instance of UnitPy and the Twin object + return new UnitPy(new Unit); +} + +// constructor method +int UnitPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) +{ + return 0; +} + + +PyObject* UnitPy::multiply(PyObject * /*args*/) +{ + PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented"); + return 0; +} + +PyObject* UnitPy::getType(PyObject * /*args*/) +{ + PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented"); + return 0; +} + + + + + +Py::Object UnitPy::getDimensions(void) const +{ + //return Py::Object(); + throw Py::AttributeError("Not yet implemented"); +} + +void UnitPy::setDimensions(Py::Object /*arg*/) +{ + throw Py::AttributeError("Not yet implemented"); +} + +PyObject *UnitPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int UnitPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Base/VectorPy.xml b/src/Base/VectorPy.xml index 6286e4b27..2549c5bfb 100644 --- a/src/Base/VectorPy.xml +++ b/src/Base/VectorPy.xml @@ -32,6 +32,13 @@ + + + negative() + returns the negative (opposite) of this vector + + + scale(Float,Float,Float) @@ -88,6 +95,14 @@ + + + + distanceToPoint(Vector) + returns the distance to another point + + + distanceToLine(Vector,Vector) diff --git a/src/Base/VectorPyImp.cpp b/src/Base/VectorPyImp.cpp index 4a1bae849..c86902c68 100644 --- a/src/Base/VectorPyImp.cpp +++ b/src/Base/VectorPyImp.cpp @@ -215,6 +215,16 @@ PyObject* VectorPy::sub(PyObject *args) return new VectorPy(v); } +PyObject* VectorPy::negative(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + + VectorPy::PointerType this_ptr = reinterpret_cast(_pcTwinPointer); + Base::Vector3d v = -(*this_ptr); + return new VectorPy(v); +} + PyObject* VectorPy::richCompare(PyObject *v, PyObject *w, int op) { if (PyObject_TypeCheck(v, &(VectorPy::Type)) && @@ -380,6 +390,20 @@ PyObject* VectorPy::projectToPlane(PyObject *args) return Py::new_reference_to(this); } +PyObject* VectorPy::distanceToPoint(PyObject *args) +{ + PyObject *pnt; + if (!PyArg_ParseTuple(args, "O!",&(VectorPy::Type),&pnt)) + return 0; + + VectorPy* base_vec = static_cast(pnt); + VectorPy::PointerType this_ptr = reinterpret_cast(_pcTwinPointer); + VectorPy::PointerType base_ptr = reinterpret_cast(base_vec->_pcTwinPointer); + + Py::Float dist(Base::Distance(*this_ptr, *base_ptr)); + return Py::new_reference_to(dist); +} + PyObject* VectorPy::distanceToLine(PyObject *args) { PyObject *base, *line; diff --git a/src/Doc/sphinx/Document.rst b/src/Doc/sphinx/Document.rst index 2b8a9d365..86f096883 100644 --- a/src/Doc/sphinx/Document.rst +++ b/src/Doc/sphinx/Document.rst @@ -1,9 +1,12 @@ The FreeCAD Document ==================== +.. currentmodule:: FreeCAD + .. toctree:: :maxdepth: 4 -.. automodule:: DocumentObject +.. autoclass:: ActiveDocument + :members: diff --git a/src/Doc/sphinx/_static/favicon.ico b/src/Doc/sphinx/_static/favicon.ico new file mode 100644 index 000000000..dcefbc956 Binary files /dev/null and b/src/Doc/sphinx/_static/favicon.ico differ diff --git a/src/Doc/sphinx/_static/freecad.css b/src/Doc/sphinx/_static/freecad.css index 4f78bb38e..f7a7e94a7 100644 --- a/src/Doc/sphinx/_static/freecad.css +++ b/src/Doc/sphinx/_static/freecad.css @@ -1,5 +1,7 @@ /* FreeCAD sphinx CSS file */ +@import url("/freecad.css"); + body { background: #191b26; background-attachment: fixed; @@ -31,12 +33,8 @@ a.headerlink { h1 { font-size: 24px; - font-weight: bold; - margin: 0; - background: url("/images/freecad.png") top left no-repeat; - color: #000; - padding-left: 40px; - border-bottom: 1px solid #444; + letter-spacing: 1px; + border-bottom: 1px solid #888; } h2 { @@ -44,6 +42,10 @@ h2 { margin: 30px 0 0 0; } +ul { + margin: 0px 0px 0px; +} + .document { background-color: #eee; display: table; @@ -86,6 +88,11 @@ h2 { padding: 10px; } +.footer { + background: transparent; + color: #aaa; +} + @media print { .document { diff --git a/src/Doc/sphinx/conf.py b/src/Doc/sphinx/conf.py index 52c32f05d..6146780a8 100644 --- a/src/Doc/sphinx/conf.py +++ b/src/Doc/sphinx/conf.py @@ -60,6 +60,7 @@ if commands.getstatusoutput("locate TemplatePyMod")[0] == 0: import FreeCAD, FreeCADGui FreeCADGui.showMainWindow() # this is needed for complete import of GUI modules +doc = FreeCAD.newDocument("doc") # -- General configuration ----------------------------------------------------- @@ -84,16 +85,16 @@ master_doc = 'index' # General information about the project. project = u'FreeCAD' -copyright = u'2011, Jürgen Riegel, Werner Mayer, Yorik van Havre' +copyright = u'2013, Jürgen Riegel, Werner Mayer, Yorik van Havre' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.13' +version = '0.14' # The full version, including alpha/beta/rc tags. -release = '0.13' +release = '0.14' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -160,7 +161,7 @@ html_title = "FreeCAD API documentation" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = None +html_favicon = "favicon.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/src/Gui/CommandStd.cpp b/src/Gui/CommandStd.cpp index 4bb0148a2..5ba4beddd 100644 --- a/src/Gui/CommandStd.cpp +++ b/src/Gui/CommandStd.cpp @@ -277,7 +277,7 @@ StdCmdWhatsThis::StdCmdWhatsThis() sToolTipText = QT_TR_NOOP("What's This"); sWhatsThis = "Std_WhatsThis"; sStatusTip = QT_TR_NOOP("What's This"); - sAccel = keySequenceToAccel(QKeySequence::WhatsThis); + sAccel = keySequenceToAccel(QKeySequence::WhatsThis); sPixmap = "WhatsThis"; eType = 0; } @@ -421,7 +421,7 @@ StdCmdOnlineHelp::StdCmdOnlineHelp() sWhatsThis = "Std_OnlineHelp"; sStatusTip = QT_TR_NOOP("Help"); sPixmap = "help-browser"; - sAccel = keySequenceToAccel(QKeySequence::HelpContents); + sAccel = keySequenceToAccel(QKeySequence::HelpContents); eType = 0; } @@ -449,9 +449,9 @@ StdCmdOnlineHelpWebsite::StdCmdOnlineHelpWebsite() void StdCmdOnlineHelpWebsite::activated(int iMsg) { - ParameterGrp::handle hURLGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/OnlineHelp"); - std::string url = hURLGrp->GetASCII("DownloadURL", "http://apps.sourceforge.net/mediawiki/free-cad/index.php?title=Online_Help_Toc"); - OpenURLInBrowser(url.c_str()); + ParameterGrp::handle hURLGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/OnlineHelp"); + std::string url = hURLGrp->GetASCII("DownloadURL", "http://www.freecadweb.org/wiki/index.php?title=Online_Help_Toc"); + OpenURLInBrowser(url.c_str()); } //=========================================================================== @@ -468,12 +468,105 @@ StdCmdFreeCADWebsite::StdCmdFreeCADWebsite() sToolTipText = QT_TR_NOOP("The FreeCAD website"); sWhatsThis = "Std_FreeCADWebsite"; sStatusTip = QT_TR_NOOP("FreeCAD Website"); + sPixmap = "internet-web-browser"; eType = 0; } void StdCmdFreeCADWebsite::activated(int iMsg) { - OpenURLInBrowser("http://apps.sourceforge.net/mediawiki/free-cad/index.php?title=Main_Page"); + OpenURLInBrowser("http://www.freecadweb.org"); +} + +//=========================================================================== +// Std_FreeCADUserHub +//=========================================================================== + +DEF_STD_CMD(StdCmdFreeCADUserHub); + +StdCmdFreeCADUserHub::StdCmdFreeCADUserHub() + :Command("Std_FreeCADUserHub") +{ + sGroup = QT_TR_NOOP("Help"); + sMenuText = QT_TR_NOOP("Users documentation"); + sToolTipText = QT_TR_NOOP("Documentation for users on the FreeCAD website"); + sWhatsThis = "Std_FreeCADUserHub"; + sStatusTip = QT_TR_NOOP("Users documentation"); + sPixmap = "internet-web-browser"; + eType = 0; +} + +void StdCmdFreeCADUserHub::activated(int iMsg) +{ + OpenURLInBrowser("http://www.freecadweb.org/wiki/index.php?title=User_hub"); +} + +//=========================================================================== +// Std_FreeCADPowerUserHub +//=========================================================================== + +DEF_STD_CMD(StdCmdFreeCADPowerUserHub); + +StdCmdFreeCADPowerUserHub::StdCmdFreeCADPowerUserHub() + :Command("Std_FreeCADPowerUserHub") +{ + sGroup = QT_TR_NOOP("Help"); + sMenuText = QT_TR_NOOP("Python scripting documentation"); + sToolTipText = QT_TR_NOOP("Python scripting documentation on the FreeCAD website"); + sWhatsThis = "Std_FreeCADPowerUserHub"; + sStatusTip = QT_TR_NOOP("PowerUsers documentation"); + sPixmap = "internet-web-browser"; + eType = 0; +} + +void StdCmdFreeCADPowerUserHub::activated(int iMsg) +{ + OpenURLInBrowser("http://www.freecadweb.org/wiki/index.php?title=Power_users_hub"); +} + +//=========================================================================== +// Std_FreeCADForum +//=========================================================================== + +DEF_STD_CMD(StdCmdFreeCADForum); + +StdCmdFreeCADForum::StdCmdFreeCADForum() + :Command("Std_FreeCADForum") +{ + sGroup = QT_TR_NOOP("Help"); + sMenuText = QT_TR_NOOP("FreeCAD Forum"); + sToolTipText = QT_TR_NOOP("The FreeCAD forum, where you can find help from other users"); + sWhatsThis = "Std_FreeCADForum"; + sStatusTip = QT_TR_NOOP("The FreeCAD Forum"); + sPixmap = "internet-web-browser"; + eType = 0; +} + +void StdCmdFreeCADForum::activated(int iMsg) +{ + OpenURLInBrowser("http://sourceforge.net/apps/phpbb/free-cad"); +} + +//=========================================================================== +// Std_FreeCADFAQ +//=========================================================================== + +DEF_STD_CMD(StdCmdFreeCADFAQ); + +StdCmdFreeCADFAQ::StdCmdFreeCADFAQ() + :Command("Std_FreeCADFAQ") +{ + sGroup = QT_TR_NOOP("Help"); + sMenuText = QT_TR_NOOP("FreeCAD FAQ"); + sToolTipText = QT_TR_NOOP("Frequently Asked Questions on the FreeCAD website"); + sWhatsThis = "Std_FreeCADFAQ"; + sStatusTip = QT_TR_NOOP("Frequently Asked Questions"); + sPixmap = "internet-web-browser"; + eType = 0; +} + +void StdCmdFreeCADFAQ::activated(int iMsg) +{ + OpenURLInBrowser("http://www.freecadweb.org/wiki/index.php?title=FAQ"); } //=========================================================================== @@ -490,13 +583,13 @@ StdCmdPythonWebsite::StdCmdPythonWebsite() sToolTipText = QT_TR_NOOP("The official Python website"); sWhatsThis = "Std_PythonWebsite"; sStatusTip = QT_TR_NOOP("Python Website"); - sPixmap = "python"; + sPixmap = "applications-python"; eType = 0; } void StdCmdPythonWebsite::activated(int iMsg) { - OpenURLInBrowser("http://python.org"); + OpenURLInBrowser("http://python.org"); } //=========================================================================== @@ -575,6 +668,10 @@ void CreateStdCommands(void) rcCmdMgr.addCommand(new StdCmdOnlineHelp()); rcCmdMgr.addCommand(new StdCmdOnlineHelpWebsite()); rcCmdMgr.addCommand(new StdCmdFreeCADWebsite()); + rcCmdMgr.addCommand(new StdCmdFreeCADUserHub()); + rcCmdMgr.addCommand(new StdCmdFreeCADPowerUserHub()); + rcCmdMgr.addCommand(new StdCmdFreeCADForum()); + rcCmdMgr.addCommand(new StdCmdFreeCADFAQ()); rcCmdMgr.addCommand(new StdCmdPythonWebsite()); //rcCmdMgr.addCommand(new StdCmdMeasurementSimple()); //rcCmdMgr.addCommand(new StdCmdDownloadOnlineHelp()); diff --git a/src/Gui/DlgProjectInformation.ui b/src/Gui/DlgProjectInformation.ui index f080e6233..df33f5517 100644 --- a/src/Gui/DlgProjectInformation.ui +++ b/src/Gui/DlgProjectInformation.ui @@ -1,10 +1,8 @@ - - - - + + Gui::Dialog::DlgProjectInformation - - + + 0 0 @@ -12,220 +10,148 @@ 540 - + Project information - + true - + true - - + + 9 - + 6 - - - + + + Information - - + + 9 - + 6 - - - - &Name: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - lineEditName - - - - - - - - 0 - 25 - - - - true - - - - - - - Path: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 25 - - - - true - - - - - - - UUID: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 25 - - - - true - - - - - - - Created &by: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - lineEditCreator - - - - - - - - 0 - 25 - - - - - - - - Creation &date: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - lineEditDate - - - - - - - - 0 - 25 - - - - true - - - - - - - &Last modified by: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - lineEditLastMod - - - - - - - - 0 - 25 - - - - - - - + + + Last &modification date: - + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + lineEditLastModDate - - - + + + + &Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lineEditName + + + + + + 0 25 - + true - - - - Com&pany: + + + + Commen&t: - + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - lineEditCompany + + textEditComment - - - + + + + Path: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 25 + + + + true + + + + + + + UUID: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 25 + + + + true + + + + + + + Created &by: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lineEditCreator + + + + + + 0 25 @@ -233,31 +159,103 @@ - - - - Commen&t: + + + + Creation &date: - + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - textEditComment + + lineEditDate - - + + + + + 0 + 25 + + + + true + + - + + + + &Last modified by: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lineEditLastMod + + + + + + + + 0 + 25 + + + + + + + + + 0 + 25 + + + + true + + + + + + + Com&pany: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lineEditCompany + + + + + + + + 0 + 25 + + + + + + + + - + Qt::Vertical - + QSizePolicy::Expanding - + 91 240 @@ -265,26 +263,63 @@ + + + + License information: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + License URL + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + Open in browser + + + + + - - - - 0 - - + + + 6 + + 0 + - + Qt::Horizontal - + QSizePolicy::Expanding - + 20 20 @@ -293,30 +328,30 @@ - - + + &OK - + - + true - + true - - + + &Cancel - + - + true @@ -325,9 +360,7 @@ - - - + @@ -336,11 +369,11 @@ Gui::Dialog::DlgProjectInformation accept() - + 20 20 - + 20 20 @@ -352,11 +385,11 @@ Gui::Dialog::DlgProjectInformation reject() - + 20 20 - + 20 20 diff --git a/src/Gui/DlgProjectInformationImp.cpp b/src/Gui/DlgProjectInformationImp.cpp index c5f878693..fd58c674d 100644 --- a/src/Gui/DlgProjectInformationImp.cpp +++ b/src/Gui/DlgProjectInformationImp.cpp @@ -28,6 +28,8 @@ #include "DlgProjectInformationImp.h" #include "Document.h" +#include +#include using namespace Gui::Dialog; @@ -52,6 +54,8 @@ DlgProjectInformationImp::DlgProjectInformationImp( App::Document* doc, QWidget* lineEditLastMod->setText(QString::fromUtf8(doc->LastModifiedBy.getValue())); lineEditLastModDate->setText(QString::fromUtf8(doc->LastModifiedDate.getValue())); lineEditCompany->setText(QString::fromUtf8(doc->Company.getValue())); + lineEditLicense->setText(QString::fromUtf8(doc->License.getValue())); + lineEditLicenseURL->setText(QString::fromUtf8(doc->LicenseURL.getValue())); // When saving the text to XML the newlines get lost. So we store also the newlines as '\n'. // See also accept(). @@ -59,6 +63,7 @@ DlgProjectInformationImp::DlgProjectInformationImp( App::Document* doc, QWidget* QStringList lines = comment.split(QLatin1String("\\n"), QString::KeepEmptyParts); QString text = lines.join(QLatin1String("\n")); textEditComment->setPlainText( text ); + connect(pushButtonOpenURL, SIGNAL(clicked()),this, SLOT(open_url())); } /** @@ -77,6 +82,8 @@ void DlgProjectInformationImp::accept() _doc->CreatedBy.setValue(lineEditCreator->text().toUtf8()); _doc->LastModifiedBy.setValue(lineEditCreator->text().toUtf8()); _doc->Company.setValue(lineEditCompany->text().toUtf8()); + _doc->License.setValue(lineEditLicense->text().toUtf8()); + _doc->LicenseURL.setValue(lineEditLicenseURL->text().toUtf8()); // Replace newline escape sequence trough '\\n' string QStringList lines = textEditComment->toPlainText().split @@ -87,3 +94,11 @@ void DlgProjectInformationImp::accept() QDialog::accept(); } +/** + * Opens the text in the LicenseURL property in external browser. + */ +void DlgProjectInformationImp::open_url() +{ + QString url = QString::fromUtf8(_doc->LicenseURL.getValue()); + QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); +} diff --git a/src/Gui/DlgProjectInformationImp.h b/src/Gui/DlgProjectInformationImp.h index e7f3b7903..cda120e7c 100644 --- a/src/Gui/DlgProjectInformationImp.h +++ b/src/Gui/DlgProjectInformationImp.h @@ -42,6 +42,7 @@ public: protected: void accept(); + void open_url(); App::Document* _doc; }; diff --git a/src/Gui/DlgSettingsMacroImp.cpp b/src/Gui/DlgSettingsMacroImp.cpp index ce79fba28..afc9fb7e3 100644 --- a/src/Gui/DlgSettingsMacroImp.cpp +++ b/src/Gui/DlgSettingsMacroImp.cpp @@ -39,8 +39,8 @@ DlgSettingsMacroImp::DlgSettingsMacroImp( QWidget* parent ) { this->setupUi(this); if (MacroPath->fileName().isEmpty()) { - QDir d(QString::fromUtf8(App::GetApplication().GetHomePath())); - MacroPath->setFileName( d.path() ); + QDir d(QString::fromUtf8(App::GetApplication().getUserAppDataDir().c_str())); + MacroPath->setFileName(d.path()); } } diff --git a/src/Gui/DlgSettingsViewColor.cpp b/src/Gui/DlgSettingsViewColor.cpp index bf8f3e216..28fcee439 100644 --- a/src/Gui/DlgSettingsViewColor.cpp +++ b/src/Gui/DlgSettingsViewColor.cpp @@ -66,15 +66,6 @@ void DlgSettingsViewColor::saveSettings() checkBoxSelection->onSave(); HighlightColor->onSave(); SelectionColor->onSave(); - CursorTextColor->onSave(); - EditedEdgeColor->onSave(); - EditedVertexColor->onSave(); - ConstructionColor->onSave(); - FullyConstrainedColor->onSave(); - BoundingBoxColor->onSave(); - DefaultShapeColor->onSave(); - DefaultShapeLineColor->onSave(); - DefaultShapeLineWidth->onSave(); } void DlgSettingsViewColor::loadSettings() @@ -90,15 +81,6 @@ void DlgSettingsViewColor::loadSettings() checkBoxSelection->onRestore(); HighlightColor->onRestore(); SelectionColor->onRestore(); - CursorTextColor->onRestore(); - EditedEdgeColor->onRestore(); - EditedVertexColor->onRestore(); - ConstructionColor->onRestore(); - FullyConstrainedColor->onRestore(); - BoundingBoxColor->onRestore(); - DefaultShapeColor->onRestore(); - DefaultShapeLineColor->onRestore(); - DefaultShapeLineWidth->onRestore(); } /** diff --git a/src/Gui/DlgSettingsViewColor.ui b/src/Gui/DlgSettingsViewColor.ui index 8a7d92e6f..9b2f5301e 100644 --- a/src/Gui/DlgSettingsViewColor.ui +++ b/src/Gui/DlgSettingsViewColor.ui @@ -148,7 +148,7 @@ - + Background color @@ -342,7 +342,7 @@ - + Qt::Vertical @@ -355,296 +355,6 @@ - - - - Default colors - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 0 - - - 6 - - - - - - 240 - 0 - - - - Edited edge color - - - - - - - Edited vertex color - - - - - - - Construction geometry - - - - - - - Fully constrained geometry - - - - - - - The color of construction geometry in edit mode - - - - 0 - 0 - 220 - - - - ConstructionColor - - - View - - - - - - - The color of fully constrained geometry in edit mode - - - - 0 - 255 - 0 - - - - FullyConstrainedColor - - - View - - - - - - - The color of vertices being edited - - - - 255 - 38 - 0 - - - - EditedVertexColor - - - View - - - - - - - The color of edges being edited - - - - 255 - 255 - 255 - - - - EditedEdgeColor - - - View - - - - - - - Cursor text color - - - - - - - - 0 - 0 - 255 - - - - CursorTextColor - - - View - - - - - - - Bounding box color - - - - - - - The color of bounding boxes in the 3D view - - - - 255 - 255 - 255 - - - - BoundingBoxColor - - - View - - - - - - - - - - - - 240 - 0 - - - - Default shape color - - - - - - - The default color for new shapes - - - - 204 - 204 - 204 - - - - DefaultShapeColor - - - View - - - - - - - - - - - - 182 - 0 - - - - Default line width and color - - - - - - - The default line color for new shapes - - - - 25 - 25 - 25 - - - - DefaultShapeLineColor - - - View - - - - - - - The default line thickness for new shapes - - - px - - - 2 - - - DefaultShapeLineWidth - - - View - - - - - - - - @@ -653,11 +363,6 @@ QPushButton
Gui/Widgets.h
- - Gui::PrefSpinBox - QSpinBox -
Gui/PrefWidgets.h
-
Gui::PrefColorButton Gui::ColorButton @@ -679,15 +384,6 @@ checkBoxSelection HighlightColor SelectionColor - DefaultShapeColor - DefaultShapeLineWidth - DefaultShapeLineColor - CursorTextColor - EditedEdgeColor - EditedVertexColor - ConstructionColor - FullyConstrainedColor - BoundingBoxColor radioButtonSimple SelectionColor_Background radioButtonGradient diff --git a/src/Gui/Icons/applications-python.svg b/src/Gui/Icons/applications-python.svg new file mode 100644 index 000000000..d782f8dde --- /dev/null +++ b/src/Gui/Icons/applications-python.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/Gui/Icons/internet-web-browser.svg b/src/Gui/Icons/internet-web-browser.svg new file mode 100644 index 000000000..d2366a9dc --- /dev/null +++ b/src/Gui/Icons/internet-web-browser.svg @@ -0,0 +1,982 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Globe + + + Jakub Steiner + + + + + Tuomas Kuosmanen + + + + http://jimmac.musichall.cz + + + globe + international + web + www + internet + network + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc index e27da77af..bb248ed5e 100644 --- a/src/Gui/Icons/resource.qrc +++ b/src/Gui/Icons/resource.qrc @@ -53,7 +53,9 @@ window-new.svg camera-photo.svg applications-accessories.svg + applications-python.svg accessories-text-editor.svg + internet-web-browser.svg view-unselectable.svg view-refresh.svg view-fullscreen.svg diff --git a/src/Gui/OnlineDocumentation.cpp b/src/Gui/OnlineDocumentation.cpp index 985b9c0d1..8f932b262 100644 --- a/src/Gui/OnlineDocumentation.cpp +++ b/src/Gui/OnlineDocumentation.cpp @@ -407,10 +407,11 @@ StdCmdPythonHelp::StdCmdPythonHelp() : Command("Std_PythonHelp"), server(0) { sGroup = QT_TR_NOOP("Tools"); - sMenuText = QT_TR_NOOP("Python Modules"); - sToolTipText = QT_TR_NOOP("Opens a browser to show the Python modules"); - sWhatsThis = QT_TR_NOOP("Opens a browser to show the Python modules"); - sStatusTip = QT_TR_NOOP("Opens a browser to show the Python modules"); + sMenuText = QT_TR_NOOP("Automatic python modules documentation"); + sToolTipText = QT_TR_NOOP("Opens a browser to show the Python modules documentation"); + sWhatsThis = QT_TR_NOOP("Opens a browser to show the Python modules documentation"); + sStatusTip = QT_TR_NOOP("Opens a browser to show the Python modules documentation"); + sPixmap = "applications-python"; } StdCmdPythonHelp::~StdCmdPythonHelp() diff --git a/src/Gui/TouchpadNavigationStyle.cpp b/src/Gui/TouchpadNavigationStyle.cpp index a8552ac79..f7fecdb25 100644 --- a/src/Gui/TouchpadNavigationStyle.cpp +++ b/src/Gui/TouchpadNavigationStyle.cpp @@ -71,7 +71,7 @@ const char* TouchpadNavigationStyle::mouseButtons(ViewerMode mode) case NavigationStyle::DRAGGING: return QT_TR_NOOP("Press ALT button"); case NavigationStyle::ZOOMING: - return QT_TR_NOOP("Press PgUp/PgDown button"); + return QT_TR_NOOP("Press CTRL and SHIFT buttons"); default: return "No description"; } @@ -310,12 +310,12 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) newmode = NavigationStyle::PANNING; break; case ALTDOWN: - case CTRLDOWN|SHIFTDOWN: if (newmode != NavigationStyle::DRAGGING) { saveCursorPosition(ev); } newmode = NavigationStyle::DRAGGING; break; + case CTRLDOWN|SHIFTDOWN: case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN: newmode = NavigationStyle::ZOOMING; break; diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 72d31f318..30b13e21e 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -681,10 +681,14 @@ bool View3DInventor::onHasMsg(const char* pMsg) const return true; else if (strcmp("SaveAs",pMsg) == 0) return true; - else if (strcmp("Undo",pMsg) == 0) - return getAppDocument() && getAppDocument()->getAvailableUndos() > 0; - else if (strcmp("Redo",pMsg) == 0) - return getAppDocument() && getAppDocument()->getAvailableRedos() > 0; + else if (strcmp("Undo",pMsg) == 0) { + App::Document* doc = getAppDocument(); + return doc && doc->getAvailableUndos() > 0; + } + else if (strcmp("Redo",pMsg) == 0) { + App::Document* doc = getAppDocument(); + return doc && doc->getAvailableRedos() > 0; + } else if (strcmp("Print",pMsg) == 0) return true; else if (strcmp("PrintPreview",pMsg) == 0) diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index f3580a814..13ee7d523 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -449,9 +449,9 @@ MenuItem* StdWorkbench::setupMenuBar() const MenuItem* stdviews = new MenuItem; stdviews->setCommand("Standard views"); *stdviews << "Std_ViewFitAll" << "Std_ViewFitSelection" << "Std_ViewAxo" - << "Separator" << "Std_ViewFront" << "Std_ViewRight" - << "Std_ViewTop" << "Separator" << "Std_ViewRear" - << "Std_ViewLeft" << "Std_ViewBottom" + << "Separator" << "Std_ViewFront" << "Std_ViewTop" + << "Std_ViewRight" << "Separator" << "Std_ViewRear" + << "Std_ViewBottom" << "Std_ViewLeft" << "Separator" << "Std_ViewRotateLeft" << "Std_ViewRotateRight"; // stereo @@ -514,15 +514,12 @@ MenuItem* StdWorkbench::setupMenuBar() const sep->setCommand( "Separator" ); // Help - MenuItem* helpWebsites = new MenuItem; - helpWebsites->setCommand("&On-line help"); - *helpWebsites << "Std_OnlineHelpWebsite" << "Std_FreeCADWebsite" << "Std_PythonWebsite"; - MenuItem* help = new MenuItem( menuBar ); help->setCommand("&Help"); - *help << "Std_OnlineHelp" << "Std_PythonHelp" - << helpWebsites << "Separator" << "Std_About" - << "Std_AboutQt" << "Separator" << "Std_WhatsThis"; + *help << "Std_OnlineHelp" << "Std_FreeCADWebsite" + << "Std_FreeCADUserHub" << "Std_FreeCADPowerUserHub" + << "Std_PythonHelp" << "Std_FreeCADForum" + << "Std_FreeCADFAQ" << "Std_About" << "Std_WhatsThis"; return menuBar; } @@ -547,9 +544,9 @@ ToolBarItem* StdWorkbench::setupToolBars() const // View ToolBarItem* view = new ToolBarItem( root ); view->setCommand("View"); - *view << "Std_ViewFitAll" << "Separator" << "Std_ViewAxo" << "Separator" << "Std_ViewFront" - << "Std_ViewRight" << "Std_ViewTop" << "Separator" << "Std_ViewRear" << "Std_ViewLeft" - << "Std_ViewBottom" << "Separator" << "Std_MeasureDistance" ; + *view << "Std_ViewFitAll" << "Separator" << "Std_ViewAxo" << "Separator" << "Std_ViewFront" + << "Std_ViewTop" << "Std_ViewRight" << "Separator" << "Std_ViewRear" << "Std_ViewBottom" + << "Std_ViewLeft" << "Separator" << "Std_MeasureDistance" ; return root; } diff --git a/src/Gui/propertyeditor/PropertyItemDelegate.cpp b/src/Gui/propertyeditor/PropertyItemDelegate.cpp index 2b79de29c..f6ca91506 100644 --- a/src/Gui/propertyeditor/PropertyItemDelegate.cpp +++ b/src/Gui/propertyeditor/PropertyItemDelegate.cpp @@ -36,7 +36,7 @@ using namespace Gui::PropertyEditor; PropertyItemDelegate::PropertyItemDelegate(QObject* parent) - : QItemDelegate(parent) + : QItemDelegate(parent), pressed(false) { } @@ -89,6 +89,16 @@ void PropertyItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & painter->setPen(savedPen); } +bool PropertyItemDelegate::editorEvent (QEvent * event, QAbstractItemModel* model, + const QStyleOptionViewItem& option, const QModelIndex& index) +{ + if (event && event->type() == QEvent::MouseButtonPress) + this->pressed = true; + else + this->pressed = false; + return QItemDelegate::editorEvent(event, model, option, index); +} + QWidget * PropertyItemDelegate::createEditor (QWidget * parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & index ) const { @@ -101,6 +111,9 @@ QWidget * PropertyItemDelegate::createEditor (QWidget * parent, const QStyleOpti QWidget* editor = childItem->createEditor(parent, this, SLOT(valueChanged())); if (editor && childItem->isReadOnly()) editor->setDisabled(true); + else if (editor && this->pressed) + editor->setFocus(); + this->pressed = false; return editor; } diff --git a/src/Gui/propertyeditor/PropertyItemDelegate.h b/src/Gui/propertyeditor/PropertyItemDelegate.h index b3086f65e..236020bd2 100644 --- a/src/Gui/propertyeditor/PropertyItemDelegate.h +++ b/src/Gui/propertyeditor/PropertyItemDelegate.h @@ -42,9 +42,14 @@ public: virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index ) const; virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const; + virtual bool editorEvent (QEvent *event, QAbstractItemModel *model, + const QStyleOptionViewItem& option, const QModelIndex& index); public Q_SLOTS: void valueChanged(); + +private: + mutable bool pressed; }; } // namespace PropertyEditor diff --git a/src/Mod/Arch/Arch.py b/src/Mod/Arch/Arch.py index 77c0b9534..0a32f924b 100644 --- a/src/Mod/Arch/Arch.py +++ b/src/Mod/Arch/Arch.py @@ -39,3 +39,4 @@ from ArchSectionPlane import * from ArchWindow import * from ArchAxis import * from ArchRoof import * +from ArchSpace import * diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 8212772fa..63dd4e159 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -67,25 +67,24 @@ def addComponents(objectsList,host): example to add windows to a wall, or to add walls to a cell or floor.''' if not isinstance(objectsList,list): objectsList = [objectsList] - tp = Draft.getType(host) - 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"]: + hostType = Draft.getType(host) + if hostType 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","Window","Roof"]: + elif hostType in ["Wall","Structure","Window","Roof"]: + import DraftGeomUtils a = host.Additions if hasattr(host,"Axes"): x = host.Axes for o in objectsList: - if Draft.getType(o) == "Axis": + if DraftGeomUtils.isValidPath(o.Shape) and (hostType == "Structure"): + if o.Support == host: + o.Support = None + host.Tool = o + elif Draft.getType(o) == "Axis": if not o in x: x.append(o) elif not o in a: @@ -94,7 +93,7 @@ def addComponents(objectsList,host): host.Additions = a if hasattr(host,"Axes"): host.Axes = x - elif tp in ["SectionPlane"]: + elif hostType in ["SectionPlane"]: a = host.Objects for o in objectsList: if not o in a: @@ -117,6 +116,9 @@ def removeComponents(objectsList,host=None): objectsList = [objectsList] if host: if Draft.getType(host) in ["Wall","Structure"]: + if hasattr(host,"Tool"): + if objectsList[0] == host.Tool: + host.Tool = None if hasattr(host,"Axes"): a = host.Axes for o in objectsList[:]: @@ -150,7 +152,7 @@ def removeComponents(objectsList,host=None): if o.InList: h = o.InList[0] tp = Draft.getType(h) - if tp in ["Cell","Floor","Building","Site"]: + if tp in ["Floor","Building","Site"]: c = h.Components if o in c: c.remove(o) @@ -271,8 +273,8 @@ def makeFace(wires,method=2,cleanup=False): #print "makeFace: reversing",w w.reverse() # make sure that the exterior wires comes as first in the list - wires.insert(0, ext) - #print "makeFace: done sorting", wires + wires.insert(0, ext) + #print "makeFace: done sorting", wires if wires: return Part.Face(wires) else: @@ -317,17 +319,29 @@ def getCutVolume(cutplane,shapes): """getCutVolume(cutplane,shapes): returns a cut face and a cut volume from the given shapes and the given cutting plane""" import Part - placement = FreeCAD.Placement(cutplane.Placement) + if not isinstance(shapes,list): + shapes = [shapes] # building boundbox - bb = shapes[0].BoundBox + bb = shapes[0].BoundBox for sh in shapes[1:]: bb.add(sh.BoundBox) bb.enlarge(1) + # building cutplane space + placement = None um = vm = wm = 0 - ax = placement.Rotation.multVec(FreeCAD.Vector(0,0,1)) - u = placement.Rotation.multVec(FreeCAD.Vector(1,0,0)) - v = placement.Rotation.multVec(FreeCAD.Vector(0,1,0)) - if not bb.isCutPlane(placement.Base,ax): + try: + if hasattr(cutplane,"Shape"): + p = cutplane.Shape.copy().Faces[0] + else: + p = cutplane.copy().Faces[0] + except: + FreeCAD.Console.PrintMessage(str(translate("Arch","Invalid cutplane"))) + return None,None,None + ce = p.CenterOfMass + ax = p.normalAt(0,0) + u = p.Vertexes[1].Point.sub(p.Vertexes[0].Point).normalize() + v = u.cross(ax) + if not bb.isCutPlane(ce,ax): FreeCAD.Console.PrintMessage(str(translate("Arch","No objects are cut by the plane"))) return None,None,None else: @@ -340,23 +354,26 @@ def getCutVolume(cutplane,shapes): 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) + dv = c.sub(ce) um1 = DraftVecUtils.project(dv,u).Length um = max(um,um1) vm1 = DraftVecUtils.project(dv,v).Length vm = max(vm,vm1) wm1 = DraftVecUtils.project(dv,ax).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) + vu = DraftVecUtils.scaleTo(u,um) + vui = vu.negative() + vv = DraftVecUtils.scaleTo(v,vm) + vvi = vv.negative() + p1 = ce.add(vu.add(vvi)) + p2 = ce.add(vu.add(vv)) + p3 = ce.add(vui.add(vv)) + p4 = ce.add(vui.add(vvi)) cutface = Part.makePolygon([p1,p2,p3,p4,p1]) cutface = Part.Face(cutface) - cutface.Placement = placement cutnormal = DraftVecUtils.scaleTo(ax,wm) cutvolume = cutface.extrude(cutnormal) - cutnormal = DraftVecUtils.neg(cutnormal) + cutnormal = cutnormal.negative() invcutvolume = cutface.extrude(cutnormal) return cutface,cutvolume,invcutvolume @@ -442,7 +459,7 @@ def removeShape(objs,mark=True): length = dims[1] width = dims[2] v1 = Vector(length/2,0,0) - v2 = DraftVecUtils.neg(v1) + v2 = v1.negative() v1 = dims[0].multVec(v1) v2 = dims[0].multVec(v2) line = Draft.makeLine(v1,v2) @@ -556,17 +573,22 @@ class _CommandAdd: def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Grouping"))) - if not mergeCells(sel): - host = sel.pop() - ss = "[" - for o in sel: - if len(ss) > 1: - ss += "," - ss += "FreeCAD.ActiveDocument."+o.Name - ss += "]" + if Draft.getType(sel[-1]) == "Space": + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Add space boundary"))) FreeCADGui.doCommand("import Arch") - FreeCADGui.doCommand("Arch.addComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")") + FreeCADGui.doCommand("Arch.addSpaceBoundaries( FreeCAD.ActiveDocument."+sel[-1].Name+", FreeCADGui.Selection.getSelectionEx() )") + else: + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Grouping"))) + if not mergeCells(sel): + host = sel.pop() + 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() @@ -586,20 +608,25 @@ class _CommandRemove: def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Ungrouping"))) - if (Draft.getType(sel[-1]) in ["Wall","Structure"]) and (len(sel) > 1): - host = sel.pop() - ss = "[" - for o in sel: - if len(ss) > 1: - ss += "," - ss += "FreeCAD.ActiveDocument."+o.Name - ss += "]" + if Draft.getType(sel[-1]) == "Space": + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Remove space boundary"))) FreeCADGui.doCommand("import Arch") - FreeCADGui.doCommand("Arch.removeComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")") + FreeCADGui.doCommand("Arch.removeSpaceBoundaries( FreeCAD.ActiveDocument."+sel[-1].Name+", FreeCADGui.Selection.getSelection() )") else: - FreeCADGui.doCommand("import Arch") - FreeCADGui.doCommand("Arch.removeComponents(Arch.ActiveDocument."+sel[-1].Name+")") + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Ungrouping"))) + if (Draft.getType(sel[-1]) in ["Wall","Structure"]) and (len(sel) > 1): + host = sel.pop() + 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: + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.removeComponents(Arch.ActiveDocument."+sel[-1].Name+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index 786f48914..f6bc68143 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -26,6 +26,7 @@ __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" import FreeCAD,FreeCADGui,Draft +from FreeCAD import Vector from PyQt4 import QtGui,QtCore from DraftTools import translate @@ -104,6 +105,22 @@ def removeFromComponent(compobject,subobject): compobject.Subtractions = l if Draft.getType(subobject) != "Window": subobject.ViewObject.hide() + + +class SelectionTaskPanel: + """A temp taks panel to wait for a selection""" + def __init__(self): + self.form = QtGui.QLabel() + self.form.setText(QtGui.QApplication.translate("Arch", "Please select a base object", None, QtGui.QApplication.UnicodeUTF8)) + + def getStandardButtons(self): + return int(QtGui.QDialogButtonBox.Cancel) + + def reject(self): + if hasattr(FreeCAD,"ArchObserver"): + FreeCADGui.Selection.removeObserver(FreeCAD.ArchObserver) + del FreeCAD.ArchObserver + return True class ComponentTaskPanel: @@ -270,11 +287,12 @@ class Component: self.Type = "Component" self.Subvolume = None + def execute(self,obj): + return def __getstate__(self): return self.Type - def __setstate__(self,state): if state: self.Type = state @@ -307,8 +325,8 @@ class Component: n = f.normalAt(0,0) v1 = DraftVecUtils.scaleTo(n,width*1.1) # we extrude a little more to avoid face-on-face f.translate(v1) - v2 = DraftVecUtils.neg(v1) - v2 = DraftVecUtils.scale(v1,-2) + v2 = v1.negative() + v2 = Vector(v1).multiply(-2) f = f.extrude(v2) if plac: f.Placement = plac @@ -408,7 +426,7 @@ class ViewProviderComponent: vobj.Proxy = self self.Object = vobj.Object - def updateData(self,vobj,prop): + def updateData(self,obj,prop): return def onChanged(self,vobj,prop): @@ -443,10 +461,15 @@ class ViewProviderComponent: return None def claimChildren(self): - c = [self.Object.Base]+self.Object.Additions+self.Object.Subtractions - if hasattr(self.Object,"Fixtures"): - c.extend(self.Object.Fixtures) - return c + if hasattr(self,"Object"): + c = [self.Object.Base]+self.Object.Additions+self.Object.Subtractions + if hasattr(self.Object,"Fixtures"): + c.extend(self.Object.Fixtures) + if hasattr(self.Object,"Tool"): + if self.Object.Tool: + c.append(self.Object.Tool) + return c + return [] def setEdit(self,vobj,mode): taskd = ComponentTaskPanel() @@ -460,18 +483,32 @@ class ViewProviderComponent: return False class ArchSelectionObserver: - def __init__(self,origin,watched,hide=True,nextCommand=None): + """ArchSelectionObserver([origin,watched,hide,nextCommand]): The ArchSelectionObserver + object can be added as a selection observer to the FreeCAD Gui. If watched is given (a + document object), the observer will be triggered only when that object is selected/unselected. + If hide is True, the watched object will be hidden. If origin is given (a document + object), that object will have its visibility/selectability restored. If nextCommand + is given (a FreeCAD command), it will be executed on leave.""" + + def __init__(self,origin=None,watched=None,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 self.watched: + FreeCADGui.Selection.removeObserver(FreeCAD.ArchObserver) + if self.nextCommand: + FreeCADGui.runCommand(self.nextCommand) + del FreeCAD.ArchObserver + elif object == self.watched.Name: if not element: FreeCAD.Console.PrintMessage(str(translate("Arch","closing Sketch edit"))) if self.hide: - self.origin.ViewObject.Transparency = 0 - self.origin.ViewObject.Selectable = True + if self.origin: + self.origin.ViewObject.Transparency = 0 + self.origin.ViewObject.Selectable = True self.watched.ViewObject.hide() FreeCADGui.activateWorkbench("ArchWorkbench") FreeCADGui.Selection.removeObserver(FreeCAD.ArchObserver) diff --git a/src/Mod/Arch/ArchRoof.py b/src/Mod/Arch/ArchRoof.py index 8b20daf5a..505a0a915 100644 --- a/src/Mod/Arch/ArchRoof.py +++ b/src/Mod/Arch/ArchRoof.py @@ -52,17 +52,12 @@ class _CommandRoof: '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 + FreeCADGui.Control.closeDialog() if sel.HasSubObjects: if "Face" in sel.SubElementNames[0]: idx = int(sel.SubElementNames[0][4:]) @@ -83,7 +78,10 @@ class _CommandRoof: else: FreeCAD.Console.PrintMessage(str(translate("Arch","Unable to create a roof"))) else: - FreeCAD.Console.PrintMessage(str(translate("Arch","No object selected"))) + FreeCAD.Console.PrintMessage(str(translate("Arch","Please select a base object\n"))) + FreeCADGui.Control.showDialog(ArchComponent.SelectionTaskPanel()) + FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(nextCommand="Arch_Roof") + FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver) class _Roof(ArchComponent.Component): "The Roof object" diff --git a/src/Mod/Arch/ArchSpace.py b/src/Mod/Arch/ArchSpace.py new file mode 100644 index 000000000..d3161e555 --- /dev/null +++ b/src/Mod/Arch/ArchSpace.py @@ -0,0 +1,288 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2013 * +#* 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,ArchComponent,ArchCommands,math,Draft +from DraftTools import translate +from PyQt4 import QtCore + +def makeSpace(objects=None): + """makeSpace([objects]): Creates a space object from the given objects. Objects can be one + document object, in which case it becomes the base shape of the space object, or a list of + selection objects as got from getSelectionEx(), or a list of tuples (object, subobjectname)""" + obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Space") + _Space(obj) + _ViewProviderSpace(obj.ViewObject) + if objects: + if not isinstance(objects,list): + objects = [objects] + if len(objects) == 1: + obj.Base = objects[0] + objects[0].ViewObject.hide() + else: + obj.Proxy.addSubobjects(obj,objects) + +def addSpaceBoundaries(space,subobjects): + """addSpaceBoundaries(space,subobjects): adds the given subobjects to the given space""" + import Draft + if Draft.getType(space) == "Space": + space.Proxy.addSubobjects(space,subobjects) + +def removeSpaceBoundaries(space,objects): + """removeSpaceBoundaries(space,objects): removes the given objects from the given spaces boundaries""" + import Draft + if Draft.getType(space) == "Space": + bounds = space.Boundaries + for o in objects: + for b in bounds: + if o.Name == b[0].Name: + bounds.remove(b) + break + space.Boundaries = bounds + +class _CommandSpace: + "the Arch Space command definition" + def GetResources(self): + return {'Pixmap' : 'Arch_Space', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Space","Space"), + 'Accel': "S, P", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Space","Creates a space object from selected boundary objects")} + + def Activated(self): + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Space"))) + FreeCADGui.doCommand("import Arch") + sel = FreeCADGui.Selection.getSelection() + if sel: + FreeCADGui.Control.closeDialog() + if len(sel) == 1: + FreeCADGui.doCommand("Arch.makeSpace(FreeCADGui.Selection.getSelection())") + else: + FreeCADGui.doCommand("Arch.makeSpace(FreeCADGui.Selection.getSelectionEx())") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + else: + FreeCAD.Console.PrintMessage(str(translate("Arch","Please select a base object\n"))) + FreeCADGui.Control.showDialog(ArchComponent.SelectionTaskPanel()) + FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(nextCommand="Arch_Space") + FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver) + + +class _Space(ArchComponent.Component): + "A space object" + def __init__(self,obj): + obj.Proxy = self + obj.addProperty("App::PropertyLink","Base","Base", + str(translate("Arch","A base shape defining this space"))) + obj.addProperty("App::PropertyLinkSubList","Boundaries","Base", + str(translate("Arch","The objects that make the boundaries of this space object"))) + self.Type = "Space" + + def execute(self,obj): + self.getShape(obj) + + def onChanged(self,obj,prop): + if prop in ["Boundaries","Base"]: + self.getShape(obj) + + def addSubobjects(self,obj,subobjects): + "adds subobjects to this space" + objs = obj.Boundaries + for o in subobjects: + if isinstance(o,tuple) or isinstance(o,list): + if o[0].Name != obj.Name: + objs.append(tuple(o)) + else: + for el in o.SubElementNames: + if "Face" in el: + if o.Object.Name != obj.Name: + objs.append((o.Object,el)) + obj.Boundaries = objs + + def getShape(self,obj): + "computes a shape from a base shape and/or bounday faces" + import Part + shape = None + faces = [] + + #print "starting compute" + # 1: if we have a base shape, we use it + + if obj.Base: + if obj.Base.isDerivedFrom("Part::Feature"): + if obj.Base.Shape.Solids: + shape = obj.Base.Shape.Solids[0].copy() + + # 2: if not, add all bounding boxes of considered objects and build a first shape + if shape: + #print "got shape from base object" + bb = shape.BoundBox + else: + bb = None + for b in obj.Boundaries: + if b[0].isDerivedFrom("Part::Feature"): + if not bb: + bb = b[0].Shape.BoundBox + else: + bb.add(b[0].Shape.BoundBox) + if not bb: + return + shape = Part.makeBox(bb.XLength,bb.YLength,bb.ZLength,FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin)) + #print "created shape from boundbox" + + # 3: identifing boundary faces + goodfaces = [] + for b in obj.Boundaries: + if b[0].isDerivedFrom("Part::Feature"): + if "Face" in b[1]: + fn = int(b[1][4:])-1 + faces.append(b[0].Shape.Faces[fn]) + #print "adding face ",fn," of object ",b[0].Name + + #print "total: ", len(faces), " faces" + + # 4: get cutvolumes from faces + cutvolumes = [] + for f in faces: + f = f.copy() + f.reverse() + cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(f,shape) + if cutvolume: + #print "generated 1 cutvolume" + cutvolumes.append(cutvolume.copy()) + #Part.show(cutvolume) + for v in cutvolumes: + #print "cutting" + shape = shape.cut(v) + + # 5: get the final shape + if shape: + if shape.Solids: + #print "setting objects shape" + shape = shape.Solids[0] + obj.Shape = shape + return + + print "Arch: error computing space boundary" + + def getArea(self,obj): + "returns the horizontal area at the center of the space" + import Part,DraftGeomUtils + try: + pl = Part.makePlane(1,1) + sh = obj.Shape.copy() + cutplane,v1,v2 = ArchCommands.getCutVolume(pl,sh) + e = sh.section(cutplane) + e = DraftGeomUtils.sortEdges(e.Edges) + w = Part.Wire(e) + f = Part.Face(w) + return round(f.Area,Draft.getParam("dimPrecision")) + except: + return 0 + + +class _ViewProviderSpace(ArchComponent.ViewProviderComponent): + "A View Provider for Section Planes" + def __init__(self,vobj): + vobj.Transparency = 85 + vobj.LineWidth = 1 + vobj.LineColor = (1.0,0.0,0.0,1.0) + vobj.DrawStyle = "Dotted" + vobj.addProperty("App::PropertyString","Override","Base", + "Text override. Use $area to insert the area") + vobj.addProperty("App::PropertyColor","TextColor","Base", + "The color of the area text") + vobj.TextColor = (1.0,0.0,0.0,1.0) + vobj.Override = "$area m2" + ArchComponent.ViewProviderComponent.__init__(self,vobj) + + def getIcon(self): + import Arch_rc + return ":/icons/Arch_Space_Tree.svg" + + def claimChildren(self): + if self.Object.Base: + return [self.Object.Base] + else: + return [] + + def setDisplayMode(self,mode): + if mode == "Detailed": + self.setAnnotation(True) + return "Flat Lines" + else: + self.setAnnotation(False) + return mode + + def getArea(self,obj): + "returns a formatted area text" + area = str(obj.Proxy.getArea(obj)) + if obj.ViewObject.Override: + text = obj.ViewObject.Override + area = text.replace("$area",str(area)) + return str(area) + + def setAnnotation(self,recreate=True): + if hasattr(self,"Object"): + if hasattr(self,"area"): + if self.area: + self.Object.ViewObject.Annotation.removeChild(self.area) + self.area = None + self.coords = None + self.anno = None + if recreate: + area = self.getArea(self.Object) + if area: + from pivy import coin + import SketcherGui + self.area = coin.SoSeparator() + self.coords = coin.SoTransform() + if self.Object.Shape: + if not self.Object.Shape.isNull(): + c = self.Object.Shape.CenterOfMass + self.coords.translation.setValue([c.x,c.y,c.z]) + self.anno = coin.SoType.fromName("SoDatumLabel").createInstance() + self.anno.string.setValue(area) + self.anno.datumtype.setValue(6) + color = coin.SbVec3f(self.Object.ViewObject.TextColor[:3]) + self.anno.textColor.setValue(color) + self.area.addChild(self.coords) + self.area.addChild(self.anno) + self.Object.ViewObject.Annotation.addChild(self.area) + + def updateData(self,obj,prop): + if prop == "Shape": + if hasattr(self,"area"): + if self.area: + area = self.getArea(obj) + self.anno.string.setValue(area) + if not obj.Shape.isNull(): + c = obj.Shape.CenterOfMass + self.coords.translation.setValue([c.x,c.y,c.z]) + + def onChanged(self,vobj,prop): + if prop in ["Override","TextColor"]: + if vobj.DisplayMode == "Detailed": + self.setAnnotation(True) + return + + +FreeCADGui.addCommand('Arch_Space',_CommandSpace()) diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index 379730903..677205ec3 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -30,7 +30,80 @@ __title__="FreeCAD Structure" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeStructure(baseobj=None,length=1,width=1,height=1,name=str(translate("Arch","Structure"))): +# Make some strings picked by the translator +QtCore.QT_TRANSLATE_NOOP("Arch","Wood") +QtCore.QT_TRANSLATE_NOOP("Arch","Steel") + +# Presets in the form: Class, Name, Width, Height, [Web thickness, Flange thickness] +Presets = [None, + + # wood sections + + ["Wood","1x2in",19,28], + ["Wood","1x3in",19,64], + ["Wood","1x4in",19,89], + ["Wood","1x6in",19,89], + ["Wood","1x8in",19,140], + ["Wood","1x10in",19,184], + ["Wood","1x12in",19,286], + + ["Wood","2x2in",38,38], + ["Wood","2x3in",38,64], + ["Wood","2x4in",38,89], + ["Wood","2x6in",38,140], + ["Wood","2x8in",38,184], + ["Wood","2x10in",38,235], + ["Wood","2x12in",38,286], + + ["Wood","4x4in",89,89], + ["Wood","4x6in",89,140], + ["Wood","6x6in",140,140], + ["Wood","8x8in",184,184], + + # IPE beams + + ["Steel","IPE90",46,80,3.8,5.2], + ["Steel","IPE100",55,100,4.1,5.7], + ["Steel","IPE120",64,120,4.4,6.3], + ["Steel","IPE140",73,140,4.7,6.9], + ["Steel","IPE160",82,160,5,7.4], + ["Steel","IPE180",91,180,5.3,8], + ["Steel","IPE200",100,200,5.6,8.5], + ["Steel","IPE220",110,220,5.9,9.2], + ["Steel","IPE240",120,240,6.2,9.8], + ["Steel","IPE270",135,270,6.6,10.2], + ["Steel","IPE300",150,300,7.1,10.7], + ["Steel","IPE330",160,330,7.5,11.5], + ["Steel","IPE360",170,360,8,12.7], + ["Steel","IPE400",180,400,8.6,13.5], + ["Steel","IPE450",190,450,9.4,14.6], + ["Steel","IPE500",200,500,10.2,16], + ["Steel","IPE550",210,550,11.1,17.2], + ["Steel","IPE600",220,600,12,19], + + # INP beams + + ["Steel","INP80",42,80,3.9,5.9], + ["Steel","INP100",50,100,4.5,6.8], + ["Steel","INP120",58,120,5.1,7.7], + ["Steel","INP140",66,140,5.7,8.6], + ["Steel","INP160",74,160,6.3,9.5], + ["Steel","INP180",82,180,6.9,10.4], + ["Steel","INP200",90,200,7.5,11.3], + ["Steel","INP220",98,220,8.1,12.2], + ["Steel","INP240",106,240,8.7,13.1], + ["Steel","INP260",113,260,9.4,14.1], + ["Steel","INP280",119,280,10.1,15.2], + ["Steel","INP300",125,300,10.8,16.2], + ["Steel","INP320",131,320,11.5,17.3], + ["Steel","INP340",137,340,12.2,18.3], + ["Steel","INP360",143,360,13,19.5], + ["Steel","INP380",149,380,13.7,20.5], + ["Steel","INP400",155,400,14.4,21.6] + + ] + +def makeStructure(baseobj=None,length=0,width=0,height=0,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 @@ -41,9 +114,12 @@ def makeStructure(baseobj=None,length=1,width=1,height=1,name=str(translate("Arc if baseobj: obj.Base = baseobj obj.Base.ViewObject.hide() - obj.Width = width - obj.Height = height - obj.Length = length + if width: + obj.Width = width + if height: + obj.Height = height + if length: + obj.Length = length obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Structure") return obj @@ -58,6 +134,21 @@ def makeStructuralSystem(objects,axes): result.append(s) FreeCAD.ActiveDocument.recompute() return result + +def makeProfile(W=46,H=80,tw=3.8,tf=5.2): + '''makeProfile(W,H,tw,tf): returns a shape with one face describing + the profile of a steel beam (IPE, IPN, HE, etc...) based on the following + dimensions: W = total width, H = total height, tw = web thickness + tw = flange thickness (see http://en.wikipedia.org/wiki/I-beam for + reference)''' + obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Profile") + _Profile(obj) + obj.Width = W + obj.Height = H + obj.WebThickness = tw + obj.FlangeThickness = tf + Draft._ViewProviderDraft(obj.ViewObject) + return obj class _CommandStructure: "the Arch Structure command definition" @@ -72,9 +163,11 @@ class _CommandStructure: global QtGui, QtCore from PyQt4 import QtGui, QtCore - self.Length = 0.5 - self.Width = 0.2 - self.Height = 1 + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") + self.Length = p.GetFloat("StructureLength",100) + self.Width = p.GetFloat("StructureWidth",100) + self.Height = p.GetFloat("StructureHeight",1000) + self.Profile = 0 self.continueCmd = False sel = FreeCADGui.Selection.getSelection() if sel: @@ -94,6 +187,8 @@ class _CommandStructure: FreeCAD.ActiveDocument.recompute() else: # interactive mode + if hasattr(FreeCAD,"DraftWorkingPlane"): + FreeCAD.DraftWorkingPlane.setup() import DraftTrackers self.points = [] self.tracker = DraftTrackers.boxTracker() @@ -110,7 +205,18 @@ class _CommandStructure: return FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Structure"))) FreeCADGui.doCommand('import Arch') - FreeCADGui.doCommand('s = Arch.makeStructure(length='+str(self.Length)+',width='+str(self.Width)+',height='+str(self.Height)+')') + if self.Profile: + pr = Presets[self.Profile] + FreeCADGui.doCommand('p = Arch.makeProfile('+str(pr[2])+','+str(pr[3])+','+str(pr[4])+','+str(pr[5])+')') + if self.Length == pr[2]: + # vertical + FreeCADGui.doCommand('s = Arch.makeStructure(p,height='+str(self.Height)+')') + else: + # horizontal + FreeCADGui.doCommand('s = Arch.makeStructure(p,height='+str(self.Length)+')') + FreeCADGui.doCommand('s.Placement.Rotation = FreeCAD.Rotation(-0.5,0.5,-0.5,0.5)') + else: + FreeCADGui.doCommand('s = Arch.makeStructure(length='+str(self.Length)+',width='+str(self.Width)+',height='+str(self.Height)+')') FreeCADGui.doCommand('s.Placement.Base = '+DraftVecUtils.toString(point)) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() @@ -123,45 +229,74 @@ class _CommandStructure: w.setWindowTitle(str(translate("Arch","Structure options"))) lay0 = QtGui.QVBoxLayout(w) + # presets box + layp = QtGui.QHBoxLayout() + lay0.addLayout(layp) + labelp = QtGui.QLabel(str(translate("Arch","Preset"))) + layp.addWidget(labelp) + valuep = QtGui.QComboBox() + fpresets = [" "] + for p in Presets[1:]: + fpresets.append(str(translate("Arch",p[0]))+" "+p[1]+" ("+str(p[2])+"x"+str(p[3])+"mm)") + valuep.addItems(fpresets) + layp.addWidget(valuep) + + # length lay1 = QtGui.QHBoxLayout() lay0.addLayout(lay1) label1 = QtGui.QLabel(str(translate("Arch","Length"))) lay1.addWidget(label1) - value1 = QtGui.QDoubleSpinBox() - value1.setDecimals(2) - value1.setValue(self.Length) - lay1.addWidget(value1) + self.vLength = QtGui.QDoubleSpinBox() + self.vLength.setDecimals(2) + self.vLength.setMaximum(99999.99) + self.vLength.setValue(self.Length) + lay1.addWidget(self.vLength) + # width lay2 = QtGui.QHBoxLayout() lay0.addLayout(lay2) label2 = QtGui.QLabel(str(translate("Arch","Width"))) lay2.addWidget(label2) - value2 = QtGui.QDoubleSpinBox() - value2.setDecimals(2) - value2.setValue(self.Width) - lay2.addWidget(value2) + self.vWidth = QtGui.QDoubleSpinBox() + self.vWidth.setDecimals(2) + self.vWidth.setMaximum(99999.99) + self.vWidth.setValue(self.Width) + lay2.addWidget(self.vWidth) + # height lay3 = QtGui.QHBoxLayout() lay0.addLayout(lay3) label3 = QtGui.QLabel(str(translate("Arch","Height"))) lay3.addWidget(label3) - value3 = QtGui.QDoubleSpinBox() - value3.setDecimals(2) - value3.setValue(self.Height) - lay3.addWidget(value3) + self.vHeight = QtGui.QDoubleSpinBox() + self.vHeight.setDecimals(2) + self.vHeight.setMaximum(99999.99) + self.vHeight.setValue(self.Height) + lay3.addWidget(self.vHeight) + + # horizontal button + value5 = QtGui.QPushButton(str(translate("Arch","Rotate"))) + lay0.addWidget(value5) + # continue button value4 = QtGui.QCheckBox(str(translate("Arch","Continue"))) lay0.addWidget(value4) - QtCore.QObject.connect(value1,QtCore.SIGNAL("valueChanged(double)"),self.setLength) - QtCore.QObject.connect(value2,QtCore.SIGNAL("valueChanged(double)"),self.setWidth) - QtCore.QObject.connect(value3,QtCore.SIGNAL("valueChanged(double)"),self.setHeight) + QtCore.QObject.connect(valuep,QtCore.SIGNAL("currentIndexChanged(int)"),self.setPreset) + QtCore.QObject.connect(self.vLength,QtCore.SIGNAL("valueChanged(double)"),self.setLength) + QtCore.QObject.connect(self.vWidth,QtCore.SIGNAL("valueChanged(double)"),self.setWidth) + QtCore.QObject.connect(self.vHeight,QtCore.SIGNAL("valueChanged(double)"),self.setHeight) QtCore.QObject.connect(value4,QtCore.SIGNAL("stateChanged(int)"),self.setContinue) + QtCore.QObject.connect(value5,QtCore.SIGNAL("pressed()"),self.rotate) return w def update(self,point): "this function is called by the Snapper when the mouse is moved" - self.tracker.pos(point) + if self.Height >= self.Length: + delta = Vector(0,0,self.Height/2) + else: + delta = Vector(self.Length/2,0,0) + self.tracker.pos(point.add(delta)) def setWidth(self,d): self.Width = d @@ -177,11 +312,30 @@ class _CommandStructure: def setContinue(self,i): self.continueCmd = bool(i) + + def setPreset(self,i): + if i > 0: + self.vLength.setValue(float(Presets[i][2])) + self.vWidth.setValue(float(Presets[i][3])) + if len(Presets[i]) == 6: + self.Profile = i + else: + self.Profile = 0 + + def rotate(self): + l = self.Length + w = self.Width + h = self.Height + self.vLength.setValue(h) + self.vHeight.setValue(w) + self.vWidth.setValue(l) class _Structure(ArchComponent.Component): "The Structure object" def __init__(self,obj): ArchComponent.Component.__init__(self,obj) + obj.addProperty("App::PropertyLink","Tool","Base", + "An optional extrusion path for this element") obj.addProperty("App::PropertyLength","Length","Base", str(translate("Arch","The length of this element, if not based on a profile"))) obj.addProperty("App::PropertyLength","Width","Base", @@ -195,13 +349,16 @@ class _Structure(ArchComponent.Component): obj.addProperty("App::PropertyIntegerList","Exclude","Base", str(translate("Arch","The element numbers to exclude when this structure is based on axes"))) self.Type = "Structure" + obj.Length = 1 + obj.Width = 1 + obj.Height = 1 def execute(self,obj): self.createGeometry(obj) def onChanged(self,obj,prop): self.hideSubobjects(obj,prop) - if prop in ["Base","Length","Width","Height","Normal","Additions","Subtractions","Axes"]: + if prop in ["Base","Tool","Length","Width","Height","Normal","Additions","Subtractions","Axes"]: self.createGeometry(obj) def getAxisPoints(self,obj): @@ -245,21 +402,30 @@ class _Structure(ArchComponent.Component): base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): - if obj.Normal == Vector(0,0,0): - p = FreeCAD.Placement(obj.Base.Placement) - normal = p.Rotation.multVec(Vector(0,0,1)) - else: - normal = Vector(obj.Normal) - normal = normal.multiply(height) - base = obj.Base.Shape.copy() - if base.Solids: - pass - elif base.Faces: - base = base.extrude(normal) - elif (len(base.Wires) == 1): - if base.Wires[0].isClosed(): - base = Part.Face(base.Wires[0]) + if hasattr(obj,"Tool"): + if obj.Tool: + try: + base = obj.Tool.Shape.copy().makePipe(obj.Base.Shape.copy()) + except: + FreeCAD.Console.PrintError(str(translate("Arch","Error: The base shape couldn't be extruded along this tool object"))) + return + if not base: + if obj.Normal == Vector(0,0,0): + p = FreeCAD.Placement(obj.Base.Placement) + normal = p.Rotation.multVec(Vector(0,0,1)) + else: + normal = Vector(obj.Normal) + normal = normal.multiply(height) + base = obj.Base.Shape.copy() + if base.Solids: + pass + elif base.Faces: base = base.extrude(normal) + elif (len(base.Wires) == 1): + if base.Wires[0].isClosed(): + base = Part.Face(base.Wires[0]) + base = base.extrude(normal) + elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: @@ -310,13 +476,14 @@ class _Structure(ArchComponent.Component): if base.Volume < 0: base.reverse() if base.Volume < 0: - FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute the wall shape"))) + FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute a shape"))) return 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" @@ -327,4 +494,43 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent): import Arch_rc return ":/icons/Arch_Structure_Tree.svg" + +class _Profile(Draft._DraftObject): + "A parametric beam profile object" + + def __init__(self,obj): + obj.addProperty("App::PropertyDistance","Width","Base","Width of the beam").Width = 10 + obj.addProperty("App::PropertyDistance","Height","Base","Height of the beam").Height = 30 + obj.addProperty("App::PropertyDistance","WebThickness","Base","Thickness of the webs").WebThickness = 3 + obj.addProperty("App::PropertyDistance","FlangeThickness","Base","Thickness of the flange").FlangeThickness = 2 + Draft._DraftObject.__init__(self,obj,"Profile") + + def execute(self,obj): + self.createGeometry(obj) + + def onChanged(self,obj,prop): + if prop in ["Width","Height","WebThickness","FlangeThickness"]: + self.createGeometry(obj) + + def createGeometry(self,obj): + import Part + pl = obj.Placement + p1 = Vector(-obj.Width/2,-obj.Height/2,0) + p2 = Vector(obj.Width/2,-obj.Height/2,0) + p3 = Vector(obj.Width/2,(-obj.Height/2)+obj.FlangeThickness,0) + p4 = Vector(obj.WebThickness/2,(-obj.Height/2)+obj.FlangeThickness,0) + p5 = Vector(obj.WebThickness/2,obj.Height/2-obj.FlangeThickness,0) + p6 = Vector(obj.Width/2,obj.Height/2-obj.FlangeThickness,0) + p7 = Vector(obj.Width/2,obj.Height/2,0) + p8 = Vector(-obj.Width/2,obj.Height/2,0) + p9 = Vector(-obj.Width/2,obj.Height/2-obj.FlangeThickness,0) + p10 = Vector(-obj.WebThickness/2,obj.Height/2-obj.FlangeThickness,0) + p11 = Vector(-obj.WebThickness/2,(-obj.Height/2)+obj.FlangeThickness,0) + p12 = Vector(-obj.Width/2,(-obj.Height/2)+obj.FlangeThickness,0) + p = Part.makePolygon([p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p1]) + p = Part.Face(p) + obj.Shape = p + obj.Placement = pl + + FreeCADGui.addCommand('Arch_Structure',_CommandStructure()) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 5f0ca5cb0..8de79cc5c 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -30,15 +30,18 @@ __title__="FreeCAD Wall" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeWall(baseobj=None,width=None,height=None,align="Center",name=str(translate("Arch","Wall"))): - '''makeWall(obj,[width],[height],[align],[name]): creates a wall based on the - given object, which can be a sketch, a draft object, a face or a solid. align +def makeWall(baseobj=None,length=None,width=None,height=None,align="Center",name=str(translate("Arch","Wall"))): + '''makeWall([obj],[length],[width],[height],[align],[name]): creates a wall based on the + given object, which can be a sketch, a draft object, a face or a solid, or no object at + all, then you must provide length, width and height. Align can be "Center","Left" or "Right"''' obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) _Wall(obj) _ViewProviderWall(obj.ViewObject) if baseobj: obj.Base = baseobj + if length: + obj.Length = length if width: obj.Width = width if height: @@ -95,7 +98,7 @@ def mergeShapes(w1,w2): w = DraftGeomUtils.findWires(eds) if len(w) == 1: print "found common wire" - normal,width,height = w1.Proxy.getDefaultValues(w1) + normal,length,width,height = w1.Proxy.getDefaultValues(w1) print w[0].Edges sh = w1.Proxy.getBase(w1,w[0],normal,width,height) print sh @@ -133,12 +136,12 @@ class _CommandWall: global QtGui, QtCore from PyQt4 import QtGui, QtCore - self.Width = 0.1 - self.Height = 1 self.Align = "Center" self.Length = None self.continueCmd = False p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") + self.Width = p.GetFloat("WallWidth",200) + self.Height = p.GetFloat("WallHeight",3000) self.JOIN_WALLS = p.GetBool("joinWallSketches") sel = FreeCADGui.Selection.getSelection() done = False @@ -157,6 +160,8 @@ class _CommandWall: import DraftTrackers self.points = [] self.tracker = DraftTrackers.boxTracker() + if hasattr(FreeCAD,"DraftWorkingPlane"): + FreeCAD.DraftWorkingPlane.setup() FreeCADGui.Snapper.getPoint(callback=self.getPoint,extradlg=self.taskbox()) def getPoint(self,point=None,obj=None): @@ -222,7 +227,7 @@ class _CommandWall: elif self.Align == "Left": self.tracker.update([b.add(dv),point.add(dv)]) else: - dv = DraftVecUtils.neg(dv) + dv = dv.negative() self.tracker.update([b.add(dv),point.add(dv)]) if self.Length: self.Length.setValue(bv.Length) @@ -328,6 +333,8 @@ class _Wall(ArchComponent.Component): "The Wall object" def __init__(self,obj): ArchComponent.Component.__init__(self,obj) + obj.addProperty("App::PropertyLength","Length","Base", + str(translate("Arch","The length of this wall. Not used if this wall is based on an underlying object"))) obj.addProperty("App::PropertyLength","Width","Base", str(translate("Arch","The width of this wall. Not used if this wall is based on a face"))) obj.addProperty("App::PropertyLength","Height","Base", @@ -341,8 +348,9 @@ class _Wall(ArchComponent.Component): obj.Align = ['Left','Right','Center'] obj.ForceWire = False self.Type = "Wall" - obj.Width = 0.1 - obj.Height = 0 + obj.Width = 1 + obj.Height = 1 + obj.Length = 1 def execute(self,obj): self.createGeometry(obj) @@ -366,7 +374,11 @@ class _Wall(ArchComponent.Component): def getDefaultValues(self,obj): "returns normal,width,height values from this wall" - width = 1.0 + length = 1 + if hasattr(obj,"Length"): + if obj.Length: + length = obj.Length + width = 1 if hasattr(obj,"Width"): if obj.Width: width = obj.Width @@ -379,7 +391,7 @@ class _Wall(ArchComponent.Component): if Draft.getType(p) == "Floor": height = p.Height if not height: - height = 1.0 + height = 1 if hasattr(obj,"Normal"): if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) @@ -387,7 +399,7 @@ class _Wall(ArchComponent.Component): normal = Vector(obj.Normal) else: normal = Vector(0,0,1) - return normal,width,height + return normal,length,width,height def getBase(self,obj,wire,normal,width,height): "returns a full shape from a base wire" @@ -399,20 +411,20 @@ class _Wall(ArchComponent.Component): if not DraftVecUtils.isNull(dvec): dvec.normalize() if obj.Align == "Left": - dvec = dvec.multiply(width) + 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(width) - dvec = DraftVecUtils.neg(dvec) + dvec.multiply(width) + dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": - dvec = dvec.multiply(width/2) + dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) - dvec = DraftVecUtils.neg(dvec) + dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) # fixing self-intersections @@ -425,54 +437,58 @@ class _Wall(ArchComponent.Component): def createGeometry(self,obj): "builds the wall shape" - if not obj.Base: - return - import Part, DraftGeomUtils - pl = obj.Placement - normal,width,height = self.getDefaultValues(obj) - - # computing shape + normal,length,width,height = self.getDefaultValues(obj) base = None - if obj.Base.isDerivedFrom("Part::Feature"): - if not obj.Base.Shape.isNull(): - if obj.Base.Shape.isValid(): - base = obj.Base.Shape.copy() - if base.Solids: - pass - elif (len(base.Faces) == 1) and (not obj.ForceWire): - if height: - norm = normal.multiply(height) - base = base.extrude(norm) - elif len(base.Wires) >= 1: - temp = None - for wire in obj.Base.Shape.Wires: - sh = self.getBase(obj,wire,normal,width,height) - if temp: - temp = temp.fuse(sh) - else: - temp = sh - base = temp - elif base.Edges: - wire = Part.Wire(base.Edges) - if wire: - sh = self.getBase(obj,wire,normal,width,height) - if sh: - base = sh - else: - base = None - FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object"))) - - elif obj.Base.isDerivedFrom("Mesh::Feature"): - if obj.Base.Mesh.isSolid(): - if obj.Base.Mesh.countComponents() == 1: - sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) - if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()): - base = sh - else: - FreeCAD.Console.PrintWarning(str(translate("Arch","This mesh is an invalid solid"))) - obj.Base.ViewObject.show() + + # computing a shape from scratch + if not obj.Base: + if length and width and height: + base = Part.makeBox(length,width,height) + else: + FreeCAD.Console.PrintError(str(translate("Arch","Error: Unable to compute a base shape"))) + return + else: + # computing a shape from a base object + if obj.Base.isDerivedFrom("Part::Feature"): + if not obj.Base.Shape.isNull(): + if obj.Base.Shape.isValid(): + base = obj.Base.Shape.copy() + if base.Solids: + pass + elif (len(base.Faces) == 1) and (not obj.ForceWire): + if height: + normal.multiply(height) + base = base.extrude(normal) + elif len(base.Wires) >= 1: + temp = None + for wire in obj.Base.Shape.Wires: + sh = self.getBase(obj,wire,normal,width,height) + if temp: + temp = temp.fuse(sh) + else: + temp = sh + base = temp + elif base.Edges: + wire = Part.Wire(base.Edges) + if wire: + sh = self.getBase(obj,wire,normal,width,height) + if sh: + base = sh + else: + base = None + FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object"))) + + elif obj.Base.isDerivedFrom("Mesh::Feature"): + if obj.Base.Mesh.isSolid(): + if obj.Base.Mesh.countComponents() == 1: + sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) + if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()): + base = sh + else: + FreeCAD.Console.PrintWarning(str(translate("Arch","This mesh is an invalid solid"))) + obj.Base.ViewObject.show() base = self.processSubShapes(obj,base) diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index c3d72f30a..ab58b74a9 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -51,7 +51,7 @@ def makeWindow(baseobj=None,width=None,name=str(translate("Arch","Window"))): if obj.Base: obj.Base.ViewObject.DisplayMode = "Wireframe" obj.Base.ViewObject.hide() - obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Window") + #obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Window") return obj def makeDefaultWindowPart(obj): @@ -77,38 +77,40 @@ class _CommandWindow: 'Accel': "W, N", '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() if sel: - if Draft.getType(sel[0]) == "Wall": + obj = sel[0] + if Draft.getType(obj) == "Wall": FreeCADGui.activateWorkbench("SketcherWorkbench") FreeCADGui.runCommand("Sketcher_NewSketch") - FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(sel[0],FreeCAD.ActiveDocument.Objects[-1],hide=False,nextCommand="Arch_Window") + FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(obj,FreeCAD.ActiveDocument.Objects[-1],hide=False,nextCommand="Arch_Window") FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver) else: + FreeCADGui.Control.closeDialog() 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(obj,"Window"): - if obj.Objects[0].Inlist: - FreeCADGui.doCommand("Arch.removeComponents(FreeCAD.ActiveDocument."+obj.Name+",host=FreeCAD.ActiveDocument."+obj.Objects[0].Inlist[0].Name+")") + 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(obj,"Window"): + if obj.Objects[0].Inlist: + FreeCADGui.doCommand("Arch.removeComponents(FreeCAD.ActiveDocument."+obj.Name+",host=FreeCAD.ActiveDocument."+obj.Objects[0].Inlist[0].Name+")") FreeCAD.ActiveDocument.commitTransaction() - + FreeCAD.ActiveDocument.recompute() + else: + FreeCAD.Console.PrintMessage(str(translate("Arch","Please select a base object\n"))) + FreeCADGui.Control.showDialog(ArchComponent.SelectionTaskPanel()) + FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(nextCommand="Arch_Window") + FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver) + + class _Window(ArchComponent.Component): "The Window object" def __init__(self,obj): @@ -122,6 +124,7 @@ class _Window(ArchComponent.Component): self.createGeometry(obj) def onChanged(self,obj,prop): + print prop self.hideSubobjects(obj,prop) if prop in ["Base","WindowParts"]: self.createGeometry(obj) @@ -170,6 +173,11 @@ class _Window(ArchComponent.Component): base = Part.makeCompound(shapes) if not DraftGeomUtils.isNull(pl): base.Placement = pl + elif not obj.WindowParts: + # create default parts + obj.WindowParts = makeDefaultWindowPart(obj.Base) + else: + print "Arch: Bad formatting of window parts definitions" base = self.processSubShapes(obj,base) if base: @@ -188,12 +196,16 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent): def updateData(self,obj,prop): if (prop in ["WindowParts","Shape"]) and obj.ViewObject: - self.colorize(obj) + if obj.Shape: + if not obj.Shape.isNull(): + self.colorize(obj) def onChanged(self,vobj,prop): if (prop == "DiffuseColor") and vobj.Object: if len(vobj.DiffuseColor) < 2: - self.colorize(vobj.Object) + if vobj.Object.Shape: + if not vobj.Object.Shape.isNull(): + self.colorize(vobj.Object) def setEdit(self,vobj,mode): taskd = _ArchWindowTaskPanel() @@ -217,20 +229,22 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent): def colorize(self,obj): "setting different part colors" - print "Colorizing ", obj.Shape.Solids + solids = obj.Shape.copy().Solids + #print "Colorizing ", solids colors = [] base = obj.ViewObject.ShapeColor - for i in range(len(obj.Shape.Solids)): + for i in range(len(solids)): ccol = base typeidx = (i*5)+1 if typeidx < len(obj.WindowParts): typ = obj.WindowParts[typeidx] if typ == WindowPartTypes[2]: # transparent parts ccol = ArchCommands.getDefaultColor("WindowGlass") - for f in obj.Shape.Solids[i].Faces: + for f in solids[i].Faces: colors.append(ccol) - print "colors: ",colors - obj.ViewObject.DiffuseColor = colors + #print "colors: ",colors + if colors: + obj.ViewObject.DiffuseColor = colors class _ArchWindowTaskPanel: '''The TaskPanel for Arch Windows''' diff --git a/src/Mod/Arch/Arch_rc.py b/src/Mod/Arch/Arch_rc.py index 37b7e01be..28b593b4c 100644 --- a/src/Mod/Arch/Arch_rc.py +++ b/src/Mod/Arch/Arch_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Sun Jul 7 11:06:17 2013 -# by: The Resource Compiler for PyQt (Qt v4.8.4) +# Created: Fri Aug 16 18:34:56 2013 +# by: The Resource Compiler for PyQt (Qt v4.8.5) # # WARNING! All changes made in this file will be lost! @@ -27568,133 +27568,143 @@ qt_resource_data = "\ \x6c\x6c\x61\x64\x61\x20\x73\x75\x70\x70\x6f\x72\x74\x20\x77\x69\ \x6c\x6c\x20\x62\x65\x20\x64\x69\x73\x61\x62\x6c\x65\x64\x2e\x0a\ \x07\x00\x00\x00\x04\x61\x72\x63\x68\x01\ -\x00\x00\x07\xcc\ +\x00\x00\x08\x6e\ \x00\ -\x00\x3d\x0e\x78\x9c\xed\x5b\x6d\x6f\xdb\x36\x10\xfe\xde\x5f\x41\ -\xf8\xd3\x06\x74\xb5\x9d\xb7\x26\x81\xe2\x61\x6d\x9a\x36\x43\xbb\ -\xa5\x73\xd6\x7e\x1c\x68\xe9\x6c\x71\xa1\x48\x8d\xa4\x62\xbb\xbf\ -\x7e\x47\x4a\xb2\x2c\x5b\x52\xe2\xf8\x25\x40\xe0\xa2\x45\x25\x1e\ -\x7d\x77\x3c\xdd\x3d\x77\x47\x4a\xde\xaf\x93\x88\x93\x7b\x50\x9a\ -\x49\x71\xd1\xea\xbe\xe9\xb4\x08\x08\x5f\x06\x4c\x8c\x2e\x5a\x7f\ -\xdf\x5e\xfd\x72\xda\xfa\xb5\xf7\xca\x4b\x58\x31\xe9\x08\x27\xf5\ -\x5e\x11\xcf\xe7\x54\xeb\xde\xc7\x84\x9d\x9f\x5f\x32\xca\xe5\x08\ -\xff\xe7\xa3\x3e\x18\x83\x3f\xd6\xbf\x29\x3f\xf4\xda\xe9\x1c\x9c\ -\x3c\x66\xc1\x08\x0c\x71\xf7\x17\xad\xaf\xdf\xdd\x6d\x8b\x08\x1a\ -\xc1\x45\xab\x89\x87\x15\x45\xbc\x58\xc9\x18\x94\x99\x66\x3f\x18\ -\x81\x8c\xc0\xa8\xa9\x23\x12\x4f\x81\x6f\xdc\x15\xf1\x26\xbd\x8e\ -\xd7\x9e\x64\x37\x53\x7b\x33\xcd\x6e\x50\x03\x13\xf6\x8e\xdf\x1e\ -\x7b\xed\xf4\x32\x1d\x0e\x81\x8d\x42\xd3\x3b\x39\x38\xf3\xda\xd9\ -\xb5\xe3\xd9\xce\x99\x7a\xed\x5c\x78\x95\x26\x63\x26\x02\x39\xbe\ -\x65\x86\x43\xa6\x8c\x36\x0a\x75\xef\x7d\x04\x01\x8a\x72\xa2\xb3\ -\xb5\x78\xed\x8c\xb0\xcc\x92\xd3\xa9\x4c\x0a\xdb\x7c\x7b\x27\x27\ -\x9f\xdd\x50\xc6\x71\x41\xa4\x8e\xa9\x8f\x8c\x5a\xd9\x02\x44\x12\ -\x0d\x40\xf5\x4e\xbc\x76\x76\x95\xaa\x3f\x2f\x61\x89\x45\x44\xd5\ -\x88\x89\x05\x0e\x67\x8d\x1c\x98\x81\xa8\xb0\xe4\xfc\xb3\xfc\xa8\ -\x64\x12\xa3\xce\xf9\xd3\x1c\xe5\xf7\xe9\xf4\x25\xe1\xa6\x30\x56\ -\x85\xbd\xec\x33\x27\xfd\x0a\xa3\x2d\xeb\xd4\x68\xba\x4c\x18\x7a\ -\xad\x61\x3e\xe5\xe9\xe8\x3f\x07\x85\xdc\x62\x41\x15\x8c\x3e\x2d\ -\x31\x0a\xa5\x62\x3f\xa4\x30\x15\xac\x16\x99\x2d\x9b\xe8\x33\x1d\ -\x00\xcf\x39\x71\x7b\x53\xfa\x79\x85\x8d\x60\x62\x4a\x13\x66\x76\ -\xba\x84\x21\x4d\x38\xb2\x96\x5c\x2a\x32\xc4\x7f\x63\xca\xf9\xa2\ -\xa5\xaa\xcd\x95\x0e\xa6\xba\xcd\x29\xdf\x2e\x6b\xbf\xb4\x18\xeb\ -\x70\xa0\x96\xec\xd0\x77\xc3\x8d\xcb\xc0\xb9\x80\x53\x0d\xe2\xc6\ -\xc2\x6a\x00\x5d\xad\xf7\xd5\x9c\x9f\x7f\x9a\xf1\xf3\xda\x6e\xf0\ -\xa1\x05\x2c\xc7\x03\xfb\x01\x9f\x98\xc0\x27\xa5\x4d\x80\xe1\x76\ -\xd1\xea\x2c\x9a\x0e\x67\x94\x46\x72\x34\x38\xea\x94\xc0\x60\x46\ -\xcd\x80\xe0\xa0\x53\xc2\x84\x42\xad\x45\x86\x35\x96\x4e\x0d\xb7\ -\x82\xa5\xcb\x6e\xe3\x60\xf1\x46\xc1\xf0\xbd\x7d\xd6\xef\x12\x63\ -\xd0\x8c\x79\x90\x59\x5a\x8c\x34\xe7\x07\x83\x94\xd6\xe8\x51\x52\ -\xf2\x5b\x16\x57\x3b\xd5\x6d\xc8\x34\xc1\xbf\x26\x04\x12\x2c\x39\ -\x98\x80\x31\xf9\x8e\x4e\x46\xe4\xe0\x5f\x04\xc5\xc7\xfb\xda\x92\ -\x12\x8e\xe7\x82\x0a\x6e\x6c\xc1\xfe\x0a\x82\xde\x41\xf7\xc8\x82\ -\x70\xb0\x40\x1a\x29\x00\x91\x12\xd3\xcb\x32\x79\xc0\x13\x48\xa9\ -\xee\xaa\xfc\xd8\x96\x44\x3d\x4e\x6b\x6b\xe6\x0f\xc2\xa6\x9b\x5a\ -\x0f\xf3\x33\x8b\x58\x33\xb9\xa7\x85\xc2\x9e\x6a\x24\x2b\xee\x86\ -\x9a\xf0\x61\x69\x5f\x64\xd0\xce\xf2\xec\xa6\xa2\xdf\x6b\xa7\x48\ -\x38\x83\xc9\x12\x79\x5d\xd0\x5c\x0b\x32\x37\x06\x98\x48\x48\x7c\ -\x93\x28\x78\x3e\xd4\x7c\x00\xfe\xf7\xb8\xb9\x4b\xdc\x7c\x28\x17\ -\xaf\x87\x9c\xfd\xdc\xdb\x76\x0b\x9f\xdd\xe3\x4e\x3d\x7c\x76\x4f\ -\xce\x1a\xe0\xb3\x7b\x7a\xf2\x4c\xf0\x39\xb3\xd5\x1e\x43\xeb\x0b\ -\xcf\x93\xf5\x0a\xcf\xe3\xcd\x15\x9e\xae\xf7\x79\x46\x10\x3d\xda\ -\x83\x68\xbd\xad\x77\x0d\xa2\x87\x8d\x0f\x63\x15\xe8\x3a\x3c\xac\ -\x47\xae\xa3\xe3\x06\xe0\x3a\x79\x2e\xdc\xfa\xee\x22\x61\x0f\x5a\ -\xf5\xa0\xd5\x3d\x5a\x0f\xb5\x4e\x36\x8c\x5a\x64\x64\x65\x3d\x1f\ -\x74\x35\xa3\xf0\x1e\xba\x76\x0a\x5d\xcd\x79\x64\x15\xe8\x3a\x6b\ -\x80\xae\xee\xe9\x61\x53\xcf\xda\x39\x7c\x56\xf0\xfa\x68\x6d\xb7\ -\x47\xb0\x06\x04\xeb\x3c\x1e\xc1\x0a\x0f\x0c\xc1\xbf\x9b\xdf\x1b\ -\x9d\xb9\x9f\x25\x0c\xe4\xe4\x9f\xd3\xa7\xf7\x1e\xd7\x43\x6c\x3b\ -\xd2\xf6\xc3\xb1\x83\xe0\x35\x19\x87\x20\xc8\x01\xd1\x2c\x62\x9c\ -\x66\x7b\x83\x84\x62\xf3\x31\x00\xfc\x09\xc2\xa0\x10\xd8\x83\xd8\ -\x99\xd8\xb1\x30\x45\x12\x11\x80\xe2\x53\x4b\xd3\x77\x60\x90\x8f\ -\x46\x84\xe4\x1c\xe7\x93\x7f\x25\x13\x10\x10\x84\x08\x49\xa4\x80\ -\xd7\x84\x8a\xc0\x35\x3a\x66\x2c\x33\xce\xd9\x54\x5f\x46\x60\xa7\ -\x3c\xbd\xb5\xa9\x47\xf0\xdf\x51\x8b\x4c\xda\x80\x6a\x98\x53\xd3\ -\x2e\x35\x96\x5a\xb3\x01\x5f\x43\xf2\x0a\x91\x62\x0d\x62\x77\x78\ -\xfa\x99\x0a\x2f\x32\x52\xca\xc4\x12\xaf\xb9\x79\x4f\x38\x0f\x28\ -\xda\xec\xc7\x9d\x08\x5c\x5f\xbd\x27\x2c\x8a\xa5\x32\x9b\x3e\x06\ -\xd8\xdc\x21\xc0\xd9\x56\x30\xe1\x81\x16\xad\x09\x13\x1c\xf3\x14\ -\x16\x30\x6a\x03\xa6\x63\x5c\x14\x09\x60\x90\x8c\x48\x04\x5a\xd3\ -\x91\x8b\x1c\xc6\x21\xb3\xad\x8d\x7c\x6b\xe9\x21\x0e\xad\xb1\x35\ -\x51\x1f\xbf\xfd\x10\xab\xad\xb2\x02\x3b\x09\x56\x36\xf4\x2f\xad\ -\xd4\x17\x19\xa4\xeb\x7b\xee\xf1\x36\x3c\x77\xb3\xb9\x6c\xe6\x96\ -\x69\x9a\xa1\x7c\x4c\xa7\xda\x26\xa6\xd4\x73\x31\x35\x8d\x99\x09\ -\x5d\x46\xc2\x1c\x05\x4a\x50\x4e\xe2\xa9\x09\x25\xa6\x05\xaa\x34\ -\xa8\xd7\x04\xee\x31\x47\xb0\x21\xb9\x1e\xfa\x7f\xc6\x20\xfa\x21\ -\x20\x23\x2b\x46\x68\x34\x05\x87\x60\x1b\x1e\x7f\x25\x95\x0f\x65\ -\x4d\x76\xe2\xf1\x43\x2b\x17\x57\x7a\xe3\x24\xdf\x64\x82\xf7\xde\ -\x5f\xe1\xfd\x87\x5b\xc1\xed\x35\xf6\x91\xdf\x2b\xa0\x06\x3d\xdd\ -\x25\x4b\xed\x1a\x55\xa0\x7e\x98\x1e\x87\xa7\x1b\xc7\xc4\x4c\xe3\ -\xad\x54\x58\x2e\x61\x63\x69\x88\x51\x25\xb0\xed\xc4\x10\x9b\x3a\ -\x59\xbb\xc1\x69\xdf\xad\x1c\xdd\xd6\xa9\xf1\x32\x6b\xaa\xf5\x1d\ -\x76\x85\xed\x93\x15\x1c\xb6\x79\xcf\xae\xde\x63\xae\x1d\x00\x93\ -\x61\xa2\x04\x73\x47\x1b\x3f\xf9\x54\x90\x88\xde\x81\x43\xe3\x48\ -\x06\xc0\x49\x08\xf4\x7e\xfa\xf3\x6e\x72\xbd\xd3\x07\x7d\xe8\x2a\ -\xd7\x68\xef\x46\xd5\x4d\x6c\x77\x2b\x7e\xf4\xc0\xee\xdc\xaa\x89\ -\x1f\x7f\x2d\xec\xeb\x3f\xb3\x4e\x74\x96\xf0\xa9\x26\x3a\x19\x18\ -\x45\x7d\xbb\x37\xa6\x71\x2a\xfa\x9b\x1a\x33\xec\x0b\x6d\x8b\x48\ -\x74\x48\xe3\xa2\x5e\x40\x64\x09\xa6\x24\xa4\xf7\x90\x75\xbb\x33\ -\xc6\x39\x93\xed\x14\x00\x7d\xc0\xac\x8f\xa0\x36\x93\xb7\xab\x82\ -\x37\x17\xfc\xe7\x4c\xee\x3e\x0a\xaa\xa2\x60\x85\x77\xb7\x56\x88\ -\x82\xb7\x1b\x8e\x82\x34\xeb\xdb\x5f\x17\x91\x60\x05\xb2\xc9\x7c\ -\xe9\x6b\xab\xe4\xeb\x4b\x92\xbe\xba\xb7\x0d\x6f\xbe\x71\x22\x67\ -\x7a\xa0\xd8\x0d\x88\x5b\xcd\xaf\x53\x15\xfe\x70\x32\xf7\x4e\x5d\ -\xe3\xd4\x2b\xd4\xb4\x55\x27\x2c\xcd\x9b\xe0\xf5\xee\xf1\x61\xe2\ -\xf3\x24\x00\xc2\x99\x36\xe7\x64\x9b\x27\x2a\x35\x81\xf9\x99\x09\ -\xf8\x10\x30\xb3\x14\x98\x1c\x09\x60\x09\x4f\x0e\xcb\xdf\x6c\x55\ -\x1c\xd1\x5f\x74\x86\xab\x81\x5b\x25\x91\xae\xa1\x24\x58\x2b\x33\ -\xc3\xc0\xed\xb4\x40\x66\x85\xa1\x92\x51\xf5\xae\x55\xbd\x29\x1e\ -\x6f\xec\xf6\x13\x5c\x9e\x53\x1f\x42\xc9\x03\x50\xb7\xf5\xf5\x1c\ -\xa6\x0e\x7b\xe6\xf2\x1a\x2f\xde\x25\x8c\xdb\xd7\xbf\x3f\x70\x88\ -\x70\x85\x37\x4a\x4e\xa6\x76\xfc\x8a\xcb\xf1\x2d\xa8\x88\x09\x7b\ -\xe4\xb4\xa3\x7c\x76\xc7\xe2\x17\x19\xee\xdb\xdb\x64\x9d\xa1\xc0\ -\xe3\x36\x59\x0f\x2e\x89\x02\x7b\x06\x80\x37\x1b\x7f\xdb\xba\x40\ -\xa4\xb5\xd1\xed\xed\x56\x32\xf6\x03\x98\xd7\x04\x0d\x73\xdb\x9a\ -\x4c\x60\xbb\x1e\xb9\xd3\x5a\x12\x24\x96\x4a\x1a\xcc\xba\x82\xff\ -\x3e\xb0\xa9\x9a\x4a\x00\xf5\x1c\xbb\xab\x56\x81\x6f\x7f\x7d\xd9\ -\xef\xb0\xd6\xbb\xec\xe9\x7a\xf9\xf8\xa9\xbd\xf9\x7b\xd4\x92\x62\ -\xe7\xa3\x89\xcd\x7f\xb6\xac\xf4\xef\x04\xba\x06\x51\xd6\x43\x9f\ -\xef\x8d\x87\xe6\xf5\xec\xdf\x78\xd8\xc8\x1b\x0f\x97\x32\x19\x70\ -\xe8\xc7\x4c\x54\xe1\x5e\xe0\xa8\x1a\xa9\x6b\xed\xd5\xf7\x63\xf0\ -\xd9\xd0\x16\x3e\x16\x85\x22\x2a\xa6\xc4\x30\xdb\x1c\xd8\x76\xe4\ -\x9e\xc1\xd8\xd5\x49\x25\xdf\x8b\x12\x2c\x9b\xb0\x7d\xa1\x71\xcc\ -\x19\x92\xb1\x62\xf2\xd1\x4f\xed\xac\x35\xf0\xea\x9e\xf2\x04\x16\ -\x74\x4c\xd7\xd8\x3b\x78\xd3\x29\xff\xf1\xda\x19\x65\x9b\xa8\x88\ -\xb1\x67\xab\xd1\xdb\x7c\xdd\x2f\x12\x19\x57\xaf\x5d\x4a\xc0\x90\ -\xd7\x08\xe5\xcf\x87\x1e\x83\x07\x05\x14\x7c\xcb\x78\x94\x80\x60\ -\xb9\x5e\x59\x21\xfc\xcb\x91\x9f\x05\xfd\xc1\x52\xd0\xe7\xf1\x7e\ -\xb4\x14\xef\xa5\x50\x5f\x54\xa5\x14\xe0\x85\x91\xe6\x2c\x39\x67\ -\xc6\x2c\xd5\xe4\x6f\x93\x67\x9f\xfb\x5d\xb4\x4e\x5a\x24\xfd\x6e\ -\xef\xa2\xd5\xed\xb6\x6c\x2b\xe0\xc5\x6c\x12\xd1\x78\x98\x08\xb7\ -\x1d\xd6\xfb\xef\xc6\xdd\x5f\x61\x0f\xf2\x05\x03\xb2\x2f\x13\xe5\ -\x03\xea\x52\x9e\x65\x3f\xdd\xc4\x70\x94\x51\x2a\x51\x3b\x4d\xe6\ -\x47\x52\x2d\xe7\x3e\xef\x9c\x7b\x8f\xaa\xf8\xa4\xd3\x3e\x8f\x89\ -\xc1\x12\x44\xf7\xbe\xde\x24\x3a\xcc\xe9\xf9\xe0\xab\xd4\x5c\x14\ -\x4b\x14\xcb\xa5\x9d\x7e\xf2\xa9\xdf\x84\xd6\x72\x6e\xd4\x59\x60\ -\x51\x70\xb3\x26\x0b\x6f\x75\x55\x6a\xb3\xac\x72\x9d\x4a\x96\xdb\ -\xe6\xd4\xca\xaa\xcd\x6a\x0b\x15\xd4\x9d\x28\x93\xf7\xc4\xd5\xca\ -\x14\xd4\x9d\x28\x53\x4a\x4a\xd5\x1a\x2d\x4c\x59\x5f\xad\xf2\x80\ -\xfb\x04\x59\x81\x76\x01\xa1\x5d\xe8\x64\x6f\x42\xd9\x5d\x64\xbc\ -\xf7\xda\x09\xeb\xbd\xfa\x1f\x60\x53\xb8\xc3\ +\x00\x4d\x6d\x78\x9c\xed\x5c\xeb\x73\xd3\x38\x10\xff\xce\x5f\xa1\ +\xc9\x67\x20\x8f\x3e\x68\x3a\x6e\x18\xa0\x14\xb8\x81\xbb\x72\xed\ +\x71\x1f\x6f\x14\x7b\x13\xeb\x90\x2d\x9f\x24\x37\x09\x7f\xfd\xad\ +\x64\xe7\x61\xc7\x71\x1a\xe7\x45\x4a\x32\x30\xb5\x25\x79\x77\xb5\ +\xfe\xed\x4b\x96\xed\xbc\x1e\x06\x9c\x3c\x80\x54\x4c\x84\x57\xb5\ +\xe6\xcb\x46\x8d\x40\xe8\x0a\x8f\x85\xfd\xab\xda\x5f\xf7\x37\x2f\ +\x2e\x6a\xaf\x3b\xcf\x9c\x98\x4d\x07\x9d\xe2\xa0\xce\x33\xe2\xb8\ +\x9c\x2a\xd5\xf9\x10\xb3\xcb\xcb\x6b\x46\xb9\xe8\xe3\x5f\xde\xbf\ +\x03\xad\xf1\x62\xf5\x46\xba\xbe\x53\x4f\xc6\xe0\xe0\x01\xf3\xfa\ +\xa0\x89\x3d\xbf\xaa\x7d\xfd\xdb\x9e\xd6\x48\x48\x03\xb8\xaa\x95\ +\xd1\x30\xac\x88\x13\x49\x11\x81\xd4\xa3\xf4\x82\x3e\x88\x00\xb4\ +\x1c\xd9\x4e\xe2\x48\x70\xb5\x3d\x22\xce\xb0\xd3\x70\xea\xc3\xf4\ +\x64\x64\x4e\x46\xe9\x09\x4a\xa0\xfd\xce\xd9\xab\x33\xa7\x9e\x1c\ +\x26\xcd\x3e\xb0\xbe\xaf\x3b\xe7\xad\xb6\x53\x4f\x8f\x2d\xcd\xfa\ +\x98\xa8\x53\x1f\x33\x2f\x92\x64\xc0\x42\x4f\x0c\xee\x99\xe6\x90\ +\x0a\xa3\xb4\x44\xd9\x3b\x1f\x20\x04\x49\x39\x51\xe9\x5c\x9c\x7a\ +\xda\x31\x4f\x92\xd3\x91\x88\xa7\xba\xf9\xf6\x56\x0c\x3f\xdb\xa6\ +\x94\x62\x8e\xa5\x8a\xa8\x8b\x84\x6a\xe9\x04\xc2\x38\xe8\x82\xec\ +\x9c\x3b\xf5\xf4\x28\x11\x7f\x96\xc3\x1c\x89\x80\xca\x3e\x0b\x73\ +\x14\xda\xa5\x14\x98\x86\x60\xaa\xc9\xd9\x7b\xf9\x41\x8a\x38\x42\ +\x99\xc7\x77\xb3\x3f\x3e\x4f\x86\xcf\x31\xd7\x53\x65\xcd\xe8\xeb\ +\x1a\x7a\x34\xe6\xba\x50\x5f\xf3\xe2\x94\x6a\x2d\xe5\x83\x80\xd5\ +\xcc\xa5\x3c\x69\xfd\xa7\x35\x65\x39\x9d\x4b\x01\xa1\x8f\x73\x84\ +\x7c\x21\xd9\x0f\x11\xea\x02\x52\x79\x62\xf3\xda\xf9\x4c\xbb\xc0\ +\xc7\x94\xb8\x39\xc9\x5c\x5e\xa0\x1e\x18\xea\xcc\x80\x89\x8a\xfe\ +\xa6\x9c\xe7\xd4\x52\xac\x9b\xa4\x31\x11\x64\x46\xd2\x7a\x56\xd4\ +\x39\xc9\x0d\xb0\x40\xce\x4d\xfa\xce\x36\x97\xca\x8c\x63\x01\x87\ +\x6a\xf4\x0f\x39\xd1\x01\x21\xd5\xf9\xaa\x2f\x2f\x3f\x4e\xe8\x39\ +\x75\xdb\xb8\x6c\x02\xf3\xb8\x67\x3f\xe0\x23\x0b\xf1\xb6\x28\xed\ +\x21\x4c\xae\x6a\x8d\xbc\x9e\x70\x44\xa6\x65\x6c\xf5\xa7\x8d\x8c\ +\xd1\x4f\x7a\x53\x83\x6f\x35\x32\xb6\x3f\x15\x2b\x4f\x70\x81\xa6\ +\x13\xc5\xad\xa0\xe9\xe5\x18\x69\x36\xaa\x82\xc4\x4c\xf3\x72\x9b\ +\x30\xc9\x0a\x6f\x7d\xf7\xad\x84\xde\xb5\x88\xbb\x1c\xee\x22\x16\ +\xce\xfa\x02\xd3\x1b\x61\xaf\x67\x7b\x15\xf6\x76\xc5\x70\x89\x05\ +\x04\x74\xc8\x82\x38\xc8\xcd\x2f\xa1\xd0\x69\xe3\xef\x65\xfb\xa2\ +\x3d\xf9\xbd\xba\x68\x39\xf5\xb4\x73\x65\x4c\x3d\x50\x1e\x43\x31\ +\xa3\x56\xa3\xf1\xb2\x91\xfd\x55\xe7\x63\x54\xf0\x3e\x34\x11\x6b\ +\x21\x78\xdd\x19\x2b\xb7\x37\x11\xa3\xe7\x23\x6f\x62\x21\xbb\x5b\ +\xaa\xfd\xe5\xdc\xbe\x08\xaf\x9e\x86\xea\x5d\x21\xa6\x08\xee\x17\ +\x15\xd1\xfe\xd1\x5a\xed\xcf\x0e\xf7\x93\x03\x80\xfb\x49\x63\x8f\ +\x78\x4f\x6e\xe3\xaf\x04\xf8\x76\x45\xc0\xbf\x13\x5c\xc8\x7d\xe0\ +\xdd\x32\x7e\x1b\x6b\x8d\x21\x3e\x8f\x76\xd7\xf4\x75\x93\xbe\xd2\ +\x69\x09\xc1\xef\x59\x54\x3c\xb3\x7b\x9f\x29\x82\xff\xb4\x0f\xc4\ +\x4b\x93\x41\x4b\x98\xf4\xf0\x7f\x08\x03\x62\x90\x42\x44\xf7\x5f\ +\x4c\xcc\xf3\xe9\xe1\x0a\x50\xb1\x34\xf3\xe0\x30\x6d\xb9\xdc\x40\ +\x82\xd7\x69\x35\x4f\x4d\x21\xe0\xe5\xba\xfa\x12\x20\x4c\x3a\x93\ +\xc3\x6c\x77\x17\x8d\x2c\xe9\xb5\x47\xd9\x94\x62\x8e\xd5\x56\x0c\ +\xca\xde\xad\x43\xb5\x27\xa7\x9e\xa4\xe4\x93\x7c\x3d\xd3\xbd\x6e\ +\xf6\xbe\x56\xee\x5e\xd1\x6a\xef\xb4\x8c\x5d\x1d\x4b\xd8\x5b\xfa\ +\xbe\x24\xe5\x3a\x26\xf0\x1b\x4f\xe0\xab\x56\x79\x9f\x21\xec\xff\ +\xfc\x19\xfc\xe9\x01\xa4\x34\xcd\x3d\x65\x34\x13\x6b\x4f\x6e\xe5\ +\xa1\xba\xe1\x4a\xa8\x2f\x4f\x75\x0f\xbc\x6c\x3d\x3b\x82\x7e\x39\ +\xe8\x7f\xb9\xda\xb5\x59\xee\x0b\x0f\xbd\x78\x3d\x3f\x0c\xd0\xef\ +\x19\xf5\xbf\x5e\x05\xdb\x6c\x3e\xd1\x12\x76\xd9\xfa\xfc\x7a\x45\ +\xec\x04\x31\xbb\xad\x64\x9b\x67\x8d\xc5\x95\x6c\xf3\xbc\x5d\x52\ +\xc9\x36\x2f\xce\xf7\x54\xc9\x4e\x74\x75\x2c\x67\x17\x3f\x8c\x9a\ +\xf5\xcf\x15\xcc\xb8\x3c\xa7\x29\x4b\xd8\xcc\x83\xcf\xfd\xd5\xb3\ +\xe5\x41\xf7\x58\xcf\x6e\xba\x9e\x2d\x4f\x03\x16\xe3\xe4\x46\xe2\ +\x80\xc4\x07\xfe\xcc\x3e\xbf\xbc\x6e\x59\xc5\xd3\x9e\x9c\x2c\x76\ +\xb4\xa7\x67\x25\x7e\xf6\x7c\x5f\x6e\x36\x31\xe5\x83\xf6\xb1\x95\ +\x12\x98\xaa\xae\xef\x83\xa1\xf9\xf3\x43\xba\xdc\x43\xae\x02\xe9\ +\x76\x09\xa4\x9b\x17\x27\x65\xab\xe0\x8d\x93\xbd\x82\xda\xde\xaa\ +\x83\x46\xf6\x96\xb3\x87\xcc\x3e\x83\x47\x23\xd0\x07\xf7\x7b\x51\ +\xe5\xe8\x9a\x0e\x53\x34\x2e\x79\x9e\x5b\x96\x42\x7f\xea\x61\xf6\ +\x9c\x64\xd1\x96\x1c\x78\xcf\xc9\xc0\x87\x90\xb4\x88\x62\x01\xe3\ +\x54\x92\x01\xe5\x5c\x11\x8a\x39\x74\x17\xf0\x12\x34\xc5\x30\xc4\ +\x54\xda\x8c\xc4\xc4\x9b\x49\x12\x87\x1e\x48\x3e\x32\x7d\xea\x3b\ +\x68\xa4\xa3\xc8\x80\x71\x8e\xe3\xc9\xbf\x82\x85\xe0\x11\x8c\xdb\ +\x82\x88\x10\x9e\x13\x1a\x7a\x36\x5f\xd7\x03\x91\x52\x4e\x87\xba\ +\x02\x23\x17\x0e\xa9\x9e\xa1\x2f\xf6\x21\xbf\xa1\x14\x29\xb7\x2e\ +\x55\x30\x23\xa6\x99\x6a\x24\x94\x62\x58\xbb\x56\xe7\xbc\x82\xa5\ +\x18\x85\x98\x67\x46\x77\xa9\x08\x4f\xd2\x52\xb2\x9d\x19\x5a\x33\ +\xe3\x2a\xec\x72\x9b\x56\x8b\x8f\xdb\xe7\xf6\xe9\xe6\x1d\x61\x41\ +\x24\xa4\xde\xf4\x0e\xb7\xcd\xed\x6f\x6b\x6f\xc5\x27\x2c\x09\xb7\ +\x65\x3e\xc1\x12\x4f\xdc\x02\x5a\xad\xc7\x54\x84\x93\xc2\x02\xbb\ +\x1b\xf7\x49\x00\x4a\xd1\xbe\xb5\x1c\xc6\x21\xd5\xad\xb1\x7c\xa3\ +\xe9\x1e\x36\xad\x51\x61\x97\x3c\xd1\xf3\xc5\x20\x27\xc0\x4e\x8c\ +\x95\xf5\xdc\x6b\xc3\xf5\x49\x1a\xe9\xfa\xc8\x3d\xdb\x06\x72\x37\ +\x1b\xcb\x26\xb0\x4c\xc2\x0c\xe5\x03\x3a\x52\x26\x30\x25\xc8\xc5\ +\xd0\x34\x60\xda\xb7\x11\x09\x63\x14\xc8\x90\x72\x12\x8d\xb4\x2f\ +\x30\x2c\x50\xa9\x40\x3e\x27\xf0\x80\x31\x82\xf5\xc8\xa7\x9e\xfb\ +\x47\x04\xe1\x9d\x0f\x48\xc8\xb0\x09\x15\xaa\x82\x83\xb7\x0d\xc4\ +\xdf\x08\xe9\x42\x56\x92\x9d\x20\xbe\x67\xf8\xe2\x4c\x6f\x2d\xe7\ +\xdb\x94\xf1\x11\xfd\x05\xe8\x3f\xd9\x8a\xdf\x5e\x63\x39\xf4\x9d\ +\x04\xaa\x11\xe9\x36\x58\x2a\xbb\x06\x0a\xd4\xf5\x89\x51\x6b\xba\ +\xfe\x49\xf4\x28\xda\x4a\x86\x65\x03\x36\xa6\x86\x68\x55\x21\x84\ +\x1a\x4d\x6c\x64\x79\xed\xc6\x4f\xbb\x76\xe6\x08\x5b\x2b\xc6\xd3\ +\xcc\xa9\x36\x50\x7d\x34\xb7\x82\xd8\x25\x6b\x55\xab\x7a\x6c\xbc\ +\x3a\x34\xaf\x24\x4c\x4a\x88\x89\xa7\xa6\x8a\xa8\xb8\xab\x25\x75\ +\xcd\x4a\xa3\xc2\xa1\xe8\xb6\xe5\x80\x61\x42\x6f\x72\x7b\xa2\x7c\ +\x1a\x4d\x1d\x3d\x42\xc2\x1b\x11\x9f\x3e\x40\x5a\xa6\x4c\x08\x8f\ +\x89\x6c\xc7\x73\xdf\x01\xba\x6b\x44\xe3\x84\xdf\xae\x32\x95\x31\ +\xe3\x3f\x26\x7c\x8f\x56\x50\x64\x05\x2b\xbc\x4f\xb2\x82\x15\xbc\ +\xda\xb0\x15\x24\xee\xda\x5c\x3d\xb5\x04\xc3\x90\x0d\x67\x73\x16\ +\x93\xde\x7c\xba\x26\xc9\x9b\x44\xdb\x40\xf3\xad\x65\x39\x91\x03\ +\xd9\x6e\x80\xdd\x6a\xb8\x4e\x44\xf8\xdd\xf2\x3c\x82\x7a\x01\xa8\ +\x57\x48\x46\x8a\x56\x67\xab\x6e\xaa\x78\x3f\x74\x79\xec\x01\xe1\ +\x4c\xe9\x4b\xb2\x87\xe5\xd9\xcf\x2c\x84\xf7\x1e\xd3\x73\x86\xc9\ +\xb1\x03\x4c\x47\x65\xb3\x7c\x63\xd2\x99\x80\xbe\x50\xa9\x5f\xf5\ +\xec\x2c\x89\xb0\x95\x00\xc1\x24\x87\x69\x06\xb6\x44\x86\x54\x0b\ +\x3d\x29\x82\xe2\xe5\x86\xc5\xaa\x78\xbc\xb2\xeb\x15\x20\xcf\xa9\ +\x0b\xbe\xe0\x1e\xc8\xfb\x85\xf7\x10\x67\x63\x9f\xf2\x3d\xc7\x83\ +\xb7\x31\xe3\xe6\x6d\xd4\xf7\x1c\x02\x9c\xe1\xad\x14\xc3\x91\x69\ +\xbf\xe1\x62\x70\x0f\x32\x60\x58\x1f\xd9\xf3\x58\x86\x4c\xf9\xd3\ +\x91\x3b\x0b\x72\xdf\x59\x74\xf4\x01\xc5\x3e\x60\xcd\x67\xd3\x4b\ +\x22\xd8\x62\xfc\x58\xc0\x9b\xec\x0c\x63\x84\x0f\x6a\x1f\x4f\x69\ +\x96\xba\x81\x75\xea\xaa\x12\x47\x80\xe1\xd7\x56\x39\x18\x8c\xa9\ +\x26\x41\x8c\xcd\xb9\x8c\x35\xd1\xc9\x1a\xe6\xf1\x48\x13\xde\x9b\ +\x45\xbe\x51\x5f\x70\x8a\x4f\xd2\x26\xb7\xb7\x8c\x3d\x09\xd7\x8f\ +\x5b\xc6\x6e\x5d\x13\x09\xe6\x29\x0b\x9e\x6c\xfc\x55\xed\x69\xea\ +\xb0\xb6\x0b\x7a\xb5\x95\xd4\x7a\x49\x72\x52\x66\xba\x33\x0b\xc7\ +\x2c\xec\x09\x19\xd8\x4d\x2a\xc4\x8b\x4d\x2f\x29\x51\xeb\x0a\xf8\ +\x5d\xb2\x6c\x9d\x70\x00\xb9\x8f\xf5\x6b\x23\xc0\xb7\x3f\xbf\x1c\ +\xd7\xb0\x17\x43\xf6\x62\xbd\xa0\x59\x75\x07\xfe\x3b\x94\x92\x4a\ +\xc0\x00\x61\x22\x94\xa9\xff\xdc\xef\x21\x42\x83\x48\x83\xd0\xfd\ +\x6d\xf4\x2a\x9f\xcf\x71\xa3\xd7\x3a\x1b\xbd\xaa\x6c\x08\x5f\xc3\ +\xf5\x45\xe0\xb2\x9e\xa9\x50\x8c\x17\x0a\x68\x38\x22\x9a\x05\x90\ +\xec\x96\x7d\x60\x30\xb0\x79\x4c\x06\x7b\xe3\xfc\x85\x46\x11\x67\ +\xd8\x8d\xa5\x8d\x8b\x38\x35\xa3\xd6\xf0\x57\x65\x6f\xfd\xef\x65\ +\x1b\x39\xda\x9e\xc9\x17\xef\xc7\xf3\xfe\x25\x3c\x63\xc6\xec\xc7\ +\x19\xc0\xdc\xc7\x46\x1e\x69\xf0\x53\x73\xff\x96\x52\xca\x1b\x7b\ +\xd1\x8c\x56\x34\xf4\x39\x33\x4f\x8d\xbc\x55\x64\xe4\x63\x13\x3f\ +\x2d\x32\xf1\xbc\x81\x17\x08\x97\x37\xee\xd5\xf3\xc0\x99\x41\x33\ +\x23\xd2\x88\x34\xde\x9d\x9e\x7e\x4d\xe8\xaa\x76\x5e\x23\xc9\x67\ +\x81\xae\x6a\xcd\x66\xcd\x94\xf6\x4e\xc4\x86\x01\x8d\x7a\x71\x68\ +\x97\xb7\x3b\xff\xdd\xda\xf3\x1b\x29\x82\x2f\x68\xb7\x77\x22\x96\ +\x2e\xa0\xe4\xd9\x51\xe6\xcb\x50\x68\xb5\x22\x48\x38\x2a\x2b\xc9\ +\x6c\x4b\x22\xe5\xcc\xd7\xa3\x66\x36\xb4\x4d\xbf\x18\x65\x6e\xe9\ +\x50\x63\xa6\xa2\x3a\x5f\x6f\x63\xe5\x8f\xfb\xc7\x8d\xcf\x12\x15\ +\x53\xcc\x64\x0c\x95\x7a\xf2\x45\x29\xf5\xd2\x37\xda\xb6\xad\x56\ +\x03\x79\xc6\xe5\x92\xe4\xb6\xd7\x15\x4a\x33\x2f\xf2\x22\x91\x0c\ +\xb5\xcd\x89\x95\x26\xa5\xc5\x1a\x9a\xf6\xee\x44\x98\x71\x71\x5b\ +\x2c\xcc\xb4\x77\x27\xc2\x64\x62\x57\xb1\x44\xb9\x21\xeb\x8b\x95\ +\x6d\xb0\x5f\x38\x93\xa0\xac\x41\x28\x6b\x3a\xe9\x96\x34\xf3\x54\ +\x08\xcf\x9d\x7a\xcc\x3a\xcf\xfe\x07\xb7\xee\x27\xe9\ \x00\x00\x07\x4c\ \x00\ \x00\x29\xd1\x78\x9c\xed\x59\x5b\x8f\xe2\x46\x16\x7e\xef\x5f\xe1\ @@ -31365,6 +31375,116 @@ qt_resource_data = "\ \x55\x4c\x69\x8a\x07\xe9\x7b\x88\xe6\x87\xfa\x1b\xc0\x5e\xa3\xb6\ \x8e\x99\x2c\x6e\xae\xae\x6d\x7d\x71\x73\xf5\x1f\x81\x50\x39\x69\ \ +\x00\x00\x06\xbf\ +\x00\ +\x00\x19\x91\x78\x9c\xed\x57\xdd\x6f\xe3\x44\x10\x7f\xef\x5f\x61\ +\x7c\x2f\x20\x62\x7b\xbf\x6c\xef\xba\x49\x11\xe2\x04\x42\x02\x21\ +\xc1\x9d\x78\x3c\x6d\xec\x4d\x62\xea\xd8\xd1\xda\x69\x92\xfe\xf5\ +\xcc\xfa\xdb\x8d\xdb\xde\x01\xc7\x0b\x38\x6a\x13\xcf\xc7\xce\xce\ +\xcc\x6f\x66\x67\x97\xdf\x9c\xf7\x99\xf5\xa0\x74\x99\x16\xf9\xca\ +\xc6\x2e\xb2\x2d\x95\xc7\x45\x92\xe6\xdb\x95\xfd\xfe\xdd\xf7\x0e\ +\xb7\xad\xb2\x92\x79\x22\xb3\x22\x57\x2b\x3b\x2f\xec\x6f\xee\x6e\ +\x96\x5f\x38\x8e\xf5\x9d\x56\xb2\x52\x89\x75\x4a\xab\x9d\xf5\x63\ +\x7e\x5f\xc6\xf2\xa0\xac\x2f\x77\x55\x75\x88\x3c\xef\x74\x3a\xb9\ +\x69\x4b\x74\x0b\xbd\xf5\xbe\xb2\x1c\xe7\xee\xe6\x66\x59\x3e\x6c\ +\x6f\x2c\xcb\x02\xbb\x79\x19\x25\xf1\xca\x6e\x15\x0e\x47\x9d\xd5\ +\x82\x49\xec\xa9\x4c\xed\x55\x5e\x95\x1e\x76\xb1\x67\x0f\xe2\xf1\ +\x20\x1e\x1b\xeb\xe9\x83\x8a\x8b\xfd\xbe\xc8\xcb\x5a\x33\x2f\xdf\ +\x8c\x84\x75\xb2\xe9\xa5\xcd\x6e\x4e\xb4\x16\xc2\x42\x08\x0f\x11\ +\x8f\x10\x07\x24\x9c\xf2\x92\x57\xf2\xec\x4c\x55\x61\x8f\x73\xaa\ +\x04\x21\xe4\x01\x6f\x90\xfc\x38\xa9\xe8\x9c\x41\x28\x9e\xdd\x4c\ +\xcd\x1d\x5b\x87\xf0\x1f\xe0\xaf\x57\xe8\x08\x6e\x59\x1c\x75\xac\ +\x36\xa0\xa9\xdc\x5c\x55\xde\xdb\x77\x6f\x7b\xa6\x83\xdc\xa4\x4a\ +\x46\xcb\x74\xd1\x9f\xd8\x9d\xa4\x24\x97\x7b\x55\x1e\x64\xac\x4a\ +\xaf\xa3\xd7\xfa\xa7\x34\xa9\x76\x2b\x3b\x60\x87\x73\xfd\xbe\x53\ +\xe9\x76\x57\x8d\x08\x69\xb2\xb2\xc1\x43\xc2\x03\x54\xbf\x77\x7b\ +\x88\x7a\x24\x21\x97\x92\x46\xb4\x5d\x78\xcc\x62\xdc\x65\x96\x16\ +\x82\x8a\xa9\x76\x52\xc4\x66\x4b\x2b\xfb\x5b\x1d\xef\x3e\xfc\x66\ +\x76\xe6\x76\x81\xec\xd7\x29\x8e\xd5\xe1\x58\x7d\x50\xe7\x4a\xe5\ +\xcd\x82\xe0\xca\xc8\xaf\x9a\x6d\xd4\xdc\x89\x4f\x23\x8c\x63\xfb\ +\x0e\x28\xcb\x44\x6d\x4a\xc3\x69\xdc\x31\x6f\xe0\x0f\xa9\x79\xc0\ +\x85\x9c\x28\xa9\x7f\xd0\x32\x49\x01\x89\x8d\x5c\x23\x39\xe5\x50\ +\x1a\x86\xad\x0e\x68\x95\x55\x71\xe8\x64\xdb\x30\x01\x05\x64\x1a\ +\x4f\x9b\xa7\xd8\x6c\x4a\x05\xe1\x44\x23\x5a\x59\x5d\x32\xd5\x48\ +\x3b\x71\x91\x15\x3a\x7a\xb3\x91\x9b\x0d\x59\xdf\xd6\xa4\x02\x62\ +\x91\x56\x97\x08\xdf\xda\x96\xf7\xaa\x35\x8e\x67\xac\xe1\x57\xac\ +\x6d\xa4\x44\xe8\x59\x6b\x4b\x6f\xea\x76\x4b\xed\xb3\x72\x80\xf0\ +\x1e\x54\x6c\x2a\xb2\x33\xd3\xa7\xb5\xba\x18\x10\x4e\x45\x69\xd2\ +\x6f\x67\x40\xc8\xe1\xc3\x19\xa2\x62\x45\x16\x25\xf0\x0f\xcf\x4a\ +\x5c\x1a\x09\x0c\x45\x06\x5f\x68\x56\xe6\xd1\x40\xf5\x85\x65\xda\ +\x1d\x38\x85\x4e\xb7\x29\x40\xa2\x96\x23\xd8\xa5\xf5\x33\xd5\x81\ +\xa0\x8e\x7c\x03\x84\xf0\x21\x26\x26\x16\x32\xbb\xc2\x48\x67\x06\ +\x22\x9b\x81\xda\xca\x96\xd9\x49\x5e\xca\x7e\xcd\xba\xde\xa3\x9d\ +\x56\xd0\x9f\xde\x5c\xa3\xc9\x99\x5a\x9f\x1a\xa1\x48\xf8\x4e\xd0\ +\x0b\x6c\x5b\xf2\xfb\x3c\xad\xa0\x19\x1d\x4b\xa5\xeb\xb2\xf9\x25\ +\x7f\x5f\xaa\x2b\xa9\x77\x5a\xe6\x25\x74\x8f\xfd\xca\xde\xcb\x4a\ +\xa7\xe7\x2f\xa1\xe1\x53\x9f\x84\xdc\x5f\x20\x97\x50\x81\x21\xac\ +\x7c\x01\x9d\x84\x09\x4c\xa0\x37\xd1\x05\x71\x31\x09\x38\x23\x6c\ +\xe1\x70\xea\x22\x82\xfc\x20\x58\x38\x04\x23\x17\x0b\x5f\xf8\x5f\ +\xf5\x36\x62\x48\x1d\xa6\xbe\x4b\x39\x84\x70\xa0\x42\xba\x44\xe8\ +\xd2\x40\xf8\x10\xb8\x8e\xba\x99\x95\xdd\xcc\xca\x6a\x10\x15\x2e\ +\x0b\x42\x46\x83\x21\xf2\x9f\x52\x9d\x0e\xfe\x98\xfa\x74\xe6\x6a\ +\xe6\x33\x56\xa8\x83\xfe\xad\x1a\xfd\x0c\x28\xc5\x8c\xbd\x80\x51\ +\x86\x11\xff\xe7\x10\xba\x40\xe6\xe3\x06\x82\xfb\x44\x30\xf8\x4d\ +\x10\x71\x39\x14\x22\x9d\x82\x8f\x10\xdf\x25\x01\x43\x64\x02\xbe\ +\x20\x24\x6e\x28\x42\x1a\x4c\xc0\x77\x2d\xbb\x99\x95\x05\xf0\x51\ +\xe6\x52\xe6\x63\xce\x5f\x05\xdf\x6b\x01\x9d\x41\xa7\x89\xe3\x33\ +\x58\x99\x4d\xbf\x79\xae\xd2\xff\x32\x6c\x7b\xcc\x61\x16\x3c\x8f\ +\xcc\x8f\xb4\x86\xe6\xac\xe1\x79\x6b\xfc\xaf\xe1\x72\x12\xf2\x97\ +\xb3\x33\x9f\xc9\xf9\xac\xcf\x23\xe4\x6f\xc2\xee\xe3\xb0\x3d\x57\ +\x20\x94\x7d\x7a\x9d\x3d\x87\xaf\x26\xcc\x4b\xcf\x4c\x30\xf5\xaf\ +\xfe\xe0\x35\xc3\x54\xf2\x90\xaa\xd3\x30\xe6\xac\x65\xbf\xb3\x83\ +\xdc\xaa\x3a\xd7\x60\xb7\x49\x76\xcb\x58\x17\x3a\x51\xba\x63\x05\ +\xf5\x33\x61\xb5\x70\x68\xee\x0b\x37\xd3\xdd\x99\x55\x7b\x3e\x9a\ +\xe7\x97\x3b\x99\x14\x27\x48\xc8\x53\xe6\x63\x51\x40\x0a\xa8\xcb\ +\xb9\x40\x3c\xa4\x4f\xd9\x75\x12\xa9\x1b\xc0\x98\x46\xaf\x74\x4d\ +\xde\x71\x00\xc7\x52\x88\xc4\x35\xf3\xa8\x35\x04\xd4\xc9\xe4\x45\ +\x81\x53\xf5\x57\x87\xdb\x72\x57\x9c\xb6\xda\x04\xa7\xd2\x47\xf5\ +\x54\x13\x66\xd2\xa3\xb9\x8b\x38\xc7\x26\xc9\xed\x04\x3c\x92\x30\ +\xba\xce\x7a\x5d\x9c\xe7\x17\x38\xa5\x39\x38\xeb\xb4\x33\x35\x16\ +\xe4\x2a\x24\xad\x44\x37\x65\x63\xe4\x87\xcf\x88\x9c\x87\xda\x7e\ +\xca\xba\xcc\xb0\x8a\xf5\x1f\x00\x14\xe7\x20\xab\x1d\xec\x7c\x23\ +\xb3\xf2\x6a\x77\x65\x2e\x0f\x4e\x5e\x24\xaa\x9c\xdf\x7d\xbb\xc4\ +\x0b\x12\xad\xfd\xbd\x3c\xa7\xfb\xf4\x51\x25\xa6\x21\xb4\x90\xdc\ +\xab\x4a\x26\xb2\x92\x03\xfc\x3a\x0a\xd4\x91\xdf\x4d\xda\x70\x0b\ +\x8b\x7e\x7d\xfb\x7d\xdf\x99\xe2\x38\xfa\xbd\xd0\xf7\x43\x53\x31\ +\x02\x72\x0d\x83\xfd\xca\xee\xbb\xa5\x99\xdf\xe3\xc8\x94\xac\xac\ +\xee\xd2\x3d\x80\xca\x5c\xb9\xbe\x86\x9b\x0f\x14\x42\xcf\x98\x08\ +\x9b\x31\x74\x58\xb4\x59\x56\xab\xe6\x4a\x35\x7b\x0b\x4d\xe2\x7d\ +\x6a\x94\xbc\xdf\xaa\x34\xcb\x7e\x34\x46\x46\x1d\xb4\x5d\x34\xad\ +\x32\x75\x57\xdb\x6c\x7e\x76\x5e\x78\xad\x1b\x5d\x0b\x1c\x79\xb9\ +\xf4\xba\x30\xd4\x6f\xdb\x21\x3c\x13\x5c\xf6\x11\xce\xe4\x5a\x65\ +\x2b\xfb\x27\xc3\xb4\xae\xb8\x5b\x5d\x1c\x0f\x7b\xc8\x4f\xab\xde\ +\x85\xd5\x64\xbd\x1f\xc5\x9b\xf6\xde\x76\x76\x54\x3f\xb7\x1b\x70\ +\x6a\xd4\xe6\x75\x71\xaf\xa2\x37\xdc\x37\x9f\xf6\xb5\x01\x6d\xc4\ +\xba\x57\xd3\x9d\xc0\x66\xb4\x3e\x56\xd5\x98\xf6\x47\x91\xe6\x11\ +\x6c\x23\x4f\x3a\x2a\x04\x4e\xe9\x0c\x00\x51\x0d\xda\xc3\x91\xd5\ +\x12\x12\x09\x8d\x40\x6b\x79\x89\xf8\x82\x8d\x89\xcd\xc9\x02\xa7\ +\xcd\x5e\xea\x7b\xa5\xa3\xbc\xc8\xd5\xed\x43\x5a\xa6\xeb\x34\x33\ +\x2b\xd4\x3f\x33\x75\x9b\xa4\xe5\x01\x7c\x86\x9b\xae\xd9\xc5\x6d\ +\x01\x77\xbc\x4d\x56\x9c\x7a\xbe\xca\x25\x7c\x39\x6b\x19\xdf\x6f\ +\xeb\xed\x45\x32\x86\x6a\x3e\x66\xb2\x52\xb5\xfb\xc3\xc1\xe6\x9a\ +\xa1\x05\xe6\x5f\x8e\xda\x67\x38\x24\x20\x2f\x3f\x5b\x04\x06\x53\ +\x1c\x08\x1a\x2c\x18\x34\x20\xc4\x18\x66\x16\x73\x91\x2f\x04\x47\ +\x78\xe1\xfb\x30\x26\x23\x1c\xf2\x49\xd3\x37\x19\xa0\x02\xd1\xb9\ +\x16\x9e\x43\x24\xab\x42\x3b\xd0\x98\x1e\x64\x75\xd4\xca\x94\x6f\ +\x7f\x60\x8e\x73\xf7\x9a\xd2\xd5\x75\xcb\xd4\xaa\x81\x2d\xd4\x6b\ +\x6c\x9e\xe9\x41\x04\x2b\xc0\xc4\x8f\x46\xe3\x67\xe7\x1f\x0b\x84\ +\x08\xc3\x85\xef\x42\xbb\x0f\x11\x62\x96\x2f\x5c\x81\x42\xce\x17\ +\xdc\xcc\xdf\x84\xf3\x9a\x04\xb7\x84\x00\xae\x03\xe6\x0e\xcf\x45\ +\xe0\xf3\xd9\xd0\x3c\xda\x4f\xa0\xf7\x3f\xd8\x5e\x06\xdb\xe7\x49\ +\xfd\x7c\xf2\xaf\xa1\x7d\x95\x7a\xe6\x12\x02\xd0\x16\xfe\x02\x03\ +\xca\x79\x88\x42\x66\x51\x80\x03\x48\x61\xb1\xc0\xdc\x15\x3e\x25\ +\x38\xb4\x18\x72\xfd\x80\xf9\x22\x58\x04\x30\x0b\x04\x70\x72\xd1\ +\x59\x8c\x04\x30\x09\xc0\xca\x3e\x01\x2c\xe1\x00\x11\x16\xfa\xaf\ +\x60\xe4\xb5\x88\xfd\xf7\x40\xf4\x6f\xb6\x87\x31\x42\xf6\xf3\x68\ +\x08\x5c\x4a\x59\x80\x02\x7f\xc1\x60\xe8\x42\x08\x73\x0b\x2d\x18\ +\xcc\xdd\x9c\x32\x8e\x2d\x07\x04\x7c\xc4\x02\xec\x8b\x85\xe3\xbb\ +\x82\x21\x2a\x66\x72\xfe\xc2\x91\xf4\x2a\x02\x6a\x01\x7d\xcc\x94\ +\x09\xf7\x23\x8c\xa5\xff\x63\xe2\xd3\x30\xd1\x1f\x52\xfe\xe8\xa6\ +\x54\xf7\x04\xa8\x6b\x22\x10\x09\x4c\xa9\x53\x22\xe0\xde\x33\x73\ +\x1a\xfc\xbd\xfa\x1d\xb2\xa7\x1e\x14\x80\x32\xf9\xcf\x66\x6f\xe9\ +\x6d\xef\x6e\x96\x66\x7e\xbd\xbb\xf9\x13\xf5\x97\x97\x20\ \x00\x00\x0b\x26\ \x00\ \x00\x5f\x19\x78\x9c\xed\x5c\xdb\x72\xe3\x36\x12\x7d\xf7\x57\x70\ @@ -31546,6 +31666,151 @@ qt_resource_data = "\ \xd6\x3c\x7b\x1b\x0c\x34\xd1\xc5\x5a\x70\x62\x48\x7c\x18\x6c\xc7\ \xb1\x5f\x18\x9d\x9e\xf6\x47\xe7\x27\xa7\xfe\x9b\xbd\xce\x4f\xfe\ \x06\xf2\x9a\xfe\xf0\ +\x00\x00\x08\xea\ +\x00\ +\x00\x21\x8a\x78\x9c\xe5\x59\x6d\x8f\xa3\x38\x12\xfe\xde\xbf\x82\ +\xcb\x7c\x99\xd6\x05\xe3\x17\x6c\x70\xa6\xd3\x2b\xdd\x8d\xf6\xb4\ +\xd2\x9e\x76\x75\x3b\xa3\xfb\x38\x72\xc0\x49\xb3\x4d\x20\x02\xd2\ +\x49\xe6\xd7\x5f\x99\x17\x07\x1a\x92\xee\x7d\x99\xd6\x49\xcb\x68\ +\x26\xe0\x2a\x53\x76\xd5\x53\x8f\xab\x98\xbb\xef\x8e\xdb\xd4\x79\ +\xd2\x45\x99\xe4\xd9\x72\x46\x10\x9e\x39\x3a\x8b\xf2\x38\xc9\x36\ +\xcb\xd9\xe7\x4f\xdf\xbb\xe1\xcc\x29\x2b\x95\xc5\x2a\xcd\x33\xbd\ +\x9c\x65\xf9\xec\xbb\xfb\x9b\xbb\xbf\xb9\xae\xf3\xcf\x42\xab\x4a\ +\xc7\xce\x21\xa9\x1e\x9c\x1f\xb2\xc7\x32\x52\x3b\xed\xbc\x7f\xa8\ +\xaa\xdd\xc2\xf3\x0e\x87\x03\x4a\xda\x41\x94\x17\x1b\xef\xd6\x71\ +\xdd\xfb\x9b\x9b\xbb\xf2\x69\x73\xe3\x38\x0e\xd8\xcd\xca\x45\x1c\ +\x2d\x67\xed\x84\xdd\xbe\x48\x6b\xc5\x38\xf2\x74\xaa\xb7\x3a\xab\ +\x4a\x8f\x20\xe2\xcd\xce\xea\xd1\x59\x3d\x32\xd6\x93\x27\x1d\xe5\ +\xdb\x6d\x9e\x95\xf5\xcc\xac\x7c\xd7\x53\x2e\xe2\xb5\xd5\x36\xab\ +\x39\xb0\x5a\x89\x48\x29\x3d\x4c\x3d\x4a\x5d\xd0\x70\xcb\x53\x56\ +\xa9\xa3\x3b\x9c\x0a\x6b\x9c\x9a\x4a\x31\xc6\x1e\xc8\xce\x9a\xaf\ +\xd3\x5a\x1c\x53\x70\xc5\xc5\xc5\xd4\xd2\xbe\x75\x70\xff\x0e\xfe\ +\xda\x09\xdd\x00\x2a\xf3\x7d\x11\xe9\x35\xcc\xd4\x28\xd3\x95\xf7\ +\xf1\xd3\x47\x2b\x74\x31\x8a\xab\xb8\xf7\x9a\xce\xfb\x03\xbb\x83\ +\x90\x64\x6a\xab\xcb\x9d\x8a\x74\xe9\x75\xe3\xf5\xfc\x43\x12\x57\ +\x0f\xcb\x99\xf0\x77\xc7\xfa\xf9\x41\x27\x9b\x87\xaa\x37\x90\xc4\ +\xcb\x19\xec\x90\x86\x02\xd7\xcf\xdd\x1a\x16\x16\x49\x18\x31\xda\ +\xa8\xb6\x2f\xee\x8b\xfc\x10\xf9\x4e\x21\x25\x93\xc3\xd9\x71\x1e\ +\x99\x25\x2d\x67\x3f\xab\xa2\xfa\xf2\x8f\xfc\x88\x3a\x37\xda\xb7\ +\xe4\xfb\x6a\xb7\xaf\xbe\xe8\x63\xa5\xb3\xe6\x75\xb0\x91\xde\xae\ +\x6a\xb1\x99\x86\x06\x3b\xea\x21\x9c\xcc\xee\x61\xe4\x2e\xd6\xeb\ +\xd2\x48\x9a\xcd\x98\x27\xd8\x0d\xad\x65\x20\x85\x88\x68\x55\xfc\ +\xab\x50\x71\x02\x38\x6c\xf4\x1a\xcd\xa1\x84\xb1\x20\x68\xe7\xc0\ +\xac\xb2\xca\x77\x9d\x6e\xeb\x24\x18\x01\x9d\x66\x9f\xcd\x95\xaf\ +\xd7\xa5\x06\x67\xe2\xde\x58\x59\x9d\x52\xdd\x68\xbb\x51\x9e\xe6\ +\xc5\xe2\xdd\x5a\xad\xd7\x74\xf5\xa1\x1e\xca\x21\x46\x49\x75\x5a\ +\x90\x0f\x33\xc7\x7b\xd1\x5a\x48\x26\xac\x91\x17\xac\xad\x95\xc2\ +\xf8\xa2\xb5\x3b\x6f\xb8\xed\x76\xd4\x46\x65\x07\xee\xdd\xe9\xc8\ +\xe4\x63\x67\xc6\x06\xb5\x3a\x19\x08\x0e\x55\x59\x6c\x97\x73\xc6\ +\xc7\xee\xcb\x11\xbc\xe2\x2c\x1c\x46\xe1\x1f\x32\xa9\x71\x6a\x34\ +\x08\xa4\x18\xfc\xe0\x49\x9d\xaf\x06\xa8\x57\x5e\xd3\xae\xc0\xcd\ +\x8b\x64\x93\x00\x24\x6a\x3d\x4a\x10\xab\xaf\xe1\x1c\x70\x6a\x6f\ +\x6f\x80\x90\xf0\xec\x13\xe3\x0b\x95\x8e\x30\xd2\x99\x01\xcf\xa6\ +\x30\x6d\x39\x53\xe9\x41\x9d\x4a\xfb\xce\x3a\xdb\x17\x0f\x85\x06\ +\x76\x7a\x37\x81\xa6\xbe\xed\xa1\x09\x86\x25\xb5\xe2\x4d\x3b\xf8\ +\x39\x4b\x2a\xa0\xa1\x7d\xa9\x8b\x5f\x4c\x2a\xff\x94\x7d\x2e\xb5\ +\xd5\x8a\xc0\xa5\x3e\x47\x61\xc8\x18\x3d\xbf\x3a\x02\x37\xd2\x10\ +\x85\x42\x72\xd8\x50\x37\xba\x9e\xd4\x5d\x4f\xea\x16\x80\x28\x89\ +\x7c\x11\xf8\x4c\x8c\x96\xf4\xa9\x50\x59\x09\x24\xb5\x5d\xce\xb6\ +\xaa\x2a\x92\xe3\x7b\x38\x57\x04\xe5\x8c\xf2\x39\x86\x3f\xe7\x27\ +\x97\x30\x1f\x71\x1f\x13\x31\x77\x03\x1f\x11\xc9\xb0\x4f\x6f\xbf\ +\xb5\x8b\x5d\x72\xdd\xc9\xdc\x1d\xef\xe9\xba\x9b\xaf\xee\x9c\x71\ +\x1a\x84\xb0\x73\x44\x99\x24\x80\xdc\x70\x0e\x54\xed\x4b\x42\x81\ +\xfc\xd9\x9c\x22\x42\x45\xe8\x53\x7f\xee\x86\x0c\x61\x8a\xb9\x00\ +\x67\x50\x82\xc1\x1b\x5c\xf2\xdb\x41\x28\x09\xe3\x88\x41\x7c\xd8\ +\x20\x94\x32\x40\x6c\x1c\xca\xb1\xee\x7a\x52\x77\x10\x4a\xeb\xf9\ +\xdf\x42\x80\x2e\x79\x0d\x05\xba\x53\xb4\xf4\x0d\x49\xd0\xc5\x6f\ +\x45\x83\xdf\x00\xa5\xc4\xf7\xaf\x60\xd4\x27\x38\xfc\xf3\x10\x5a\ +\xe7\x24\x46\x42\x86\x9c\x4a\x1f\xee\x29\xa6\x28\x04\xae\x63\x43\ +\xf0\x51\xca\x11\x15\x3e\xa6\x03\xf0\x89\x80\xa2\x40\x06\x3d\x1a\ +\x58\x4f\xea\xae\x27\x75\x01\x7c\xc0\x00\xcc\xe7\x24\x0c\x5f\x04\ +\xdf\x4b\x0e\x9d\x40\xa7\xf1\xe3\x05\xac\x4c\x86\xdf\x5c\xa3\xf0\ +\x5f\x87\xad\xc5\x1c\xf1\xc5\x65\x64\xbe\xd2\x1a\x9e\xb2\x46\xa6\ +\xad\x85\xbf\x0f\x97\x03\x97\x5f\x8f\xce\x74\x24\xa7\xa3\x3e\x8d\ +\x90\x3f\x08\xbb\xd7\x61\x7b\x2a\x41\x98\xff\xdb\xf3\xec\x12\xbe\ +\x1a\x37\xdf\x79\xa6\x48\xac\xef\x6c\x6d\x63\xaa\xd5\xf8\x29\xd1\ +\x87\x73\x25\xb9\x52\x76\x65\x3b\xb5\xd1\x75\xac\xc1\x6e\x13\xec\ +\x56\xb0\xca\x8b\x58\x17\x9d\x48\xd4\xd7\x40\xd4\xc2\xa1\x69\xc8\ +\x6e\x86\xab\x33\x6f\xb5\x72\x3c\x2d\x2f\x1f\x54\x9c\x1f\x20\x20\ +\xcf\x85\x5f\xf3\x1c\x42\xc0\x11\x7f\x2e\x30\xe1\xe3\x12\x51\x0e\ +\xb8\x92\x23\x21\x58\x62\x50\xd1\xcb\x80\xe3\xf1\xcc\x7d\x51\x80\ +\x2b\xdd\x54\x9d\x34\x6c\xa7\xfe\xe9\x10\x5b\x3e\xe4\x87\x4d\x61\ +\xdc\x52\x15\x7b\xfd\x7c\x26\x94\xfb\x7b\xd3\xe6\xb9\xfb\x26\xbc\ +\x6d\x73\xd1\xd3\x30\x73\xdd\xd5\x2a\x3f\x4e\xbf\xe0\x90\x64\xb0\ +\x4d\xb7\x6d\x57\x88\xa4\x23\x67\xb4\x1a\x5d\x03\x43\x30\x0f\x2e\ +\xa8\x1c\xcf\x59\xfd\x5c\x74\x9a\x10\xe5\xab\x5f\x01\x22\xee\x4e\ +\x55\x0f\xb0\xf2\xb5\x4a\xcb\xd1\xea\xca\x4c\xed\xdc\x2c\x8f\x75\ +\x39\xbd\xfa\xf6\x15\x57\x34\x5a\xfb\x5b\x75\x4c\xb6\xc9\x57\x1d\ +\x1b\x2a\x68\xc1\xb8\xd5\x95\x8a\x55\xa5\xce\xc0\xeb\x46\x20\x83\ +\x78\xd7\xc6\x40\x83\xbb\xf8\xcf\xc7\xef\x2d\x27\x45\xd1\xe2\xbf\ +\x79\xf1\x78\xa6\x13\xa3\xa0\x56\xd0\x35\x2d\x67\x96\x27\x4d\x73\ +\x14\x2d\x4c\xb2\xaa\xea\x3e\xd9\x02\x9c\x4c\x37\xfb\x77\x68\x2a\ +\x21\x05\xac\x60\xa0\x6c\x6a\xfc\xf3\x4b\x9b\xd7\x16\xba\xe9\x56\ +\x27\x1b\xfc\x38\xda\x26\x66\x92\xf7\x4b\x95\xa4\xe9\x0f\xc6\x48\ +\x8f\x3b\xdb\x97\x26\x55\xaa\xef\x6b\x9b\xcd\x6d\xb7\x0b\xaf\xdd\ +\x46\x47\x7e\xbd\x5d\xde\x79\x9d\x1b\xea\xa7\xcd\xd9\x3d\x03\x5c\ +\x5a\x0f\xa7\x6a\xa5\xd3\xe5\xec\x47\x23\x74\x46\xd2\x4d\x91\xef\ +\x77\x5b\x88\x4f\x3b\xbd\x73\xab\x89\xba\xed\x73\x1a\x62\x5f\xc3\ +\x36\x16\x59\x9e\x69\xe0\xf3\x22\x7f\xd4\x86\xde\x57\xac\xae\x25\ +\xcc\x63\x83\xd1\x05\x85\x26\x23\xec\x86\x0c\x15\x81\x99\xc5\x6a\ +\x5f\x55\xfd\xb1\x5f\xf3\x24\x5b\x80\xe5\x2c\xee\x46\xcf\x67\x51\ +\x7b\x74\xe0\xfa\xea\xc4\xe0\x4a\x5d\xa4\x00\x91\x6a\xe1\x77\x63\ +\xb1\x02\x0e\x28\x0a\x75\x5a\xf8\x48\x04\x62\x3e\xb0\x6c\x84\xcd\ +\xe1\x02\x07\xce\x56\x15\x8f\xba\x68\xd6\xfe\x94\x94\xc9\x2a\x49\ +\x8d\xad\xfa\x36\xd5\x1f\xe2\xa4\xdc\xc1\xe6\x17\x49\x66\xd6\xf6\ +\x21\x87\x4e\x7a\x9d\xe6\x07\x2b\xd7\x99\x82\x1f\x77\xa5\xa2\xc7\ +\x4d\xbd\xe8\x85\x8a\x20\xad\xf7\xa9\xaa\xce\x0c\x0d\xfe\xff\xb7\ +\x43\x03\x14\x08\xc6\x49\x30\xf7\x29\x82\x53\x02\x8a\x61\x47\x00\ +\xff\xfb\x42\x12\x36\xe7\x50\xfc\x06\x8c\x12\x3e\xa0\x75\xe3\x69\ +\x26\x31\x9b\x22\xe9\x0c\xdc\x57\xe5\x85\x0b\x04\xf4\xa4\xaa\x7d\ +\xa1\x4d\x9a\xda\x23\xb1\x1f\xa3\x97\x26\x8d\x7a\x56\x93\x93\x06\ +\x9e\x90\x97\x91\xb9\x86\x47\x0d\xbc\x01\x6a\x7a\xdc\x2b\x30\xbb\ +\xfd\x49\x4c\xa1\x95\x09\x11\x0d\x28\x17\x9c\x38\x3c\x40\x34\x0c\ +\x89\xcf\xe7\x50\xcf\x87\x58\x0a\xe1\x70\x01\x87\x1c\xf6\x05\x99\ +\xfb\x01\xf4\x41\x02\x9a\x83\x49\xcf\x7c\x9d\xbd\x25\xc2\xa6\x20\ +\x74\x46\xdd\xff\x15\xa6\x6c\x84\x37\xfd\xa0\x6c\x18\x11\xe7\x78\ +\x54\xa3\x72\x03\x5a\x2e\x22\x28\x86\xea\x22\x30\xed\x17\xc6\x4c\ +\x84\xa6\x1d\xb5\x77\x7d\x05\x01\xc5\x0d\x0b\x70\xe0\xcf\x09\x04\ +\xc4\x67\x92\x89\xdb\x31\x02\xf5\x71\x97\x17\x95\x0b\x71\xd1\xcd\ +\x57\x2b\xef\x21\xdf\x6a\xef\x94\x17\xc9\xa3\xf7\xb1\x3d\xdb\x4a\ +\xef\x47\xb5\xf2\x3e\x16\x6a\x5d\x79\x09\xc0\xaf\xac\x4b\x35\xb4\ +\xcb\x36\x17\x5f\x78\x8c\x77\xc9\x72\x06\xe0\x08\xa0\x43\xe4\x13\ +\x1f\x30\x5a\xbd\xd3\x33\x3d\xcb\x8f\x7d\xe8\xd7\xd8\xdc\x3a\x14\ +\x1a\xfb\x00\x36\x13\xce\x05\x87\x1a\x0d\x1a\x6d\x27\x72\xa0\xe4\ +\x32\x60\xe4\x54\x38\xd0\x70\xa2\x00\x40\x09\x08\x0c\x11\x07\x4d\ +\xe6\xb8\xdd\x5d\x6f\xa8\xd3\x9f\xe3\x9e\xd8\xce\xed\x8f\xd9\x39\ +\x78\x6e\x67\x39\xd6\xc8\x59\x3c\x31\xa3\x67\xc4\x4a\xad\x89\xf1\ +\xa2\xce\x89\xd2\x4b\xe0\x02\xce\xec\x4e\x63\x52\x7e\xbc\x2e\xaf\ +\x6b\xdc\xd6\x53\x93\x72\xd3\x60\x43\x2f\x6d\x5c\xca\x7b\x0a\x96\ +\xb3\x00\x4b\xe3\x56\xb3\x4e\x61\xd3\x64\x4a\x48\x5b\xf3\xd0\xcb\ +\xb1\xfa\xb1\xd8\xa7\xda\x64\xcd\x57\x28\x01\x6d\x9a\x0f\xc9\xbe\ +\x49\x73\x0e\x6c\x62\x2e\x22\x5f\x95\xeb\x75\x7a\xff\xce\x5c\xef\ +\x51\xce\xdb\x1f\x1c\xa3\xef\x88\xaa\x88\xfa\x4d\xd6\x10\xea\xe3\ +\xb4\x07\xd6\xe5\x84\x61\xca\x4c\x7e\x73\xea\x8b\x80\x43\xab\xd1\ +\xbb\xb3\x62\xa0\x32\x38\x8b\x84\xa4\x80\xb5\xfa\x4b\x14\x0d\x6f\ +\x67\xcf\xb3\x08\x2a\x64\x81\x25\x25\x73\xdb\xff\xd4\x69\x44\x18\ +\xa2\xbe\x84\x9c\x72\x09\x47\x2c\x10\x21\x70\x23\x43\x12\x68\x1c\ +\x86\xda\x66\x4b\xf6\x86\x48\x88\xa4\x08\x19\x35\x69\x64\xc5\x2e\ +\x1c\x11\x81\x4f\x68\x7f\xc8\x4e\xc1\xe6\x53\x59\x6b\xa4\xb5\x11\ +\x58\x31\x75\x46\x33\xa8\xd3\xda\x60\x60\xc3\x4a\x1b\x0b\x44\x3a\ +\xcf\xd7\x44\x2f\x67\x51\xa7\x71\x31\x8d\xc6\xcd\xe4\xf3\x3c\x1a\ +\xf5\x8a\xcf\x12\x69\xdc\x36\x0e\x12\xc9\xbf\x90\x48\x50\x4e\xbe\ +\x7f\x37\xee\xfb\x6e\x9f\x67\x56\x9b\x47\x06\xa7\xaf\xc3\xd5\x9d\ +\xb7\xf9\x16\x45\xc4\x74\x19\x41\x5f\x2c\x22\x80\x0e\xfd\x30\xc0\ +\x00\x57\x88\x3c\x30\x47\x80\x21\x80\x75\xab\x06\xb8\xa5\xd0\x96\ +\x61\x98\xe1\xa4\x0e\xc0\x9a\x30\x0e\xd4\x08\x48\x86\x92\x43\x84\ +\xa1\x43\xe0\x74\xe0\xe6\x0e\xe0\x43\x10\x83\x52\x24\x24\xa0\x27\ +\x08\x31\x43\x4c\x20\xce\x38\xa6\x17\x6a\x0d\x53\x5f\x48\x4b\x3c\ +\x57\xca\x0d\xdc\xbf\xde\xa8\xf8\xe8\x9b\x04\x6f\x39\x57\x16\xf2\ +\x56\xa4\x35\xc4\x1d\x46\xe6\x2b\x9d\x24\x58\xbe\x65\x4d\xda\x07\ +\xd3\x76\x1a\x39\x14\x49\x28\x95\x4c\xfd\xc6\x20\x2d\x79\x08\xdc\ +\x02\x80\x09\x78\x48\xa4\x04\xee\x31\x65\x38\x38\xcf\x1c\xd2\xe6\ +\xfb\x31\xf1\x25\xfb\x33\xf0\x21\x6c\xac\xfe\xba\xf8\x18\x36\x6f\ +\x93\x68\x21\x54\x76\xd7\xb8\x22\xf8\x63\x40\xb2\x8c\xca\x7b\x4c\ +\x5c\x73\x0e\x90\x09\x87\x7a\xc5\x0f\xe6\x44\xc2\x01\x01\x25\x0d\ +\x9b\xe8\x5c\x26\x31\x30\xc1\xc1\xe6\x7f\xa9\x46\x1c\x7c\xde\x8b\ +\x7e\xd2\x80\xe4\xf8\x65\xd4\xfc\x05\x9a\x98\xfa\xa0\xb9\x33\x5f\ +\x57\xee\x6f\xfe\x07\xcd\x1d\xa1\x65\ \x00\x00\x06\xd1\ \x00\ \x00\x27\xd8\x78\x9c\xed\x59\x5b\x6f\xe3\xb6\x12\x7e\xcf\xaf\xd0\ @@ -33405,10 +33670,19 @@ qt_resource_name = "\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x42\x00\x75\x00\x69\x00\x6c\x00\x64\x00\x69\x00\x6e\x00\x67\x00\x2e\x00\x73\x00\x76\x00\x67\ \ \x00\x13\ +\x06\x64\xa3\x67\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x53\x00\x70\x00\x61\x00\x63\x00\x65\x00\x5f\x00\x54\x00\x72\x00\x65\x00\x65\x00\x2e\x00\x73\ +\x00\x76\x00\x67\ +\x00\x13\ \x08\x0a\x92\x67\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x4d\x00\x65\x00\x72\x00\x67\x00\x65\x00\x57\x00\x61\x00\x6c\x00\x6c\x00\x73\x00\x2e\x00\x73\ \x00\x76\x00\x67\ +\x00\x0e\ +\x06\xac\xdc\x27\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x53\x00\x70\x00\x61\x00\x63\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x14\ \x03\x50\x84\x07\ \x00\x70\ @@ -33457,8 +33731,8 @@ 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\x3b\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x20\x00\x00\x00\x1b\ +\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x3d\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x22\x00\x00\x00\x1b\ \x00\x00\x00\x1a\x00\x02\x00\x00\x00\x17\x00\x00\x00\x04\ \x00\x00\x01\x2e\x00\x00\x00\x00\x00\x01\x00\x02\x9d\x23\ \x00\x00\x02\x92\x00\x00\x00\x00\x00\x01\x00\x06\x6c\x9e\ @@ -33483,38 +33757,40 @@ qt_resource_struct = "\ \x00\x00\x01\x14\x00\x00\x00\x00\x00\x01\x00\x02\x52\xbc\ \x00\x00\x00\xe0\x00\x00\x00\x00\x00\x01\x00\x01\xbc\xaa\ \x00\x00\x02\x3e\x00\x00\x00\x00\x00\x01\x00\x05\x84\xf1\ -\x00\x00\x05\x56\x00\x01\x00\x00\x00\x01\x00\x07\x5b\xb5\ -\x00\x00\x06\xbc\x00\x01\x00\x00\x00\x01\x00\x07\xb3\x28\ -\x00\x00\x05\x9c\x00\x00\x00\x00\x00\x01\x00\x07\x6a\x2c\ -\x00\x00\x04\x12\x00\x00\x00\x00\x00\x01\x00\x07\x05\x81\ -\x00\x00\x07\xec\x00\x01\x00\x00\x00\x01\x00\x08\x0a\xfd\ -\x00\x00\x06\x8e\x00\x01\x00\x00\x00\x01\x00\x07\xac\x53\ -\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x07\x13\xf0\ -\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x07\x27\x77\ -\x00\x00\x03\xb6\x00\x01\x00\x00\x00\x01\x00\x06\xea\xdf\ -\x00\x00\x07\x86\x00\x00\x00\x00\x00\x01\x00\x07\xe7\xb9\ -\x00\x00\x05\xdc\x00\x00\x00\x00\x00\x01\x00\x07\x84\x06\ -\x00\x00\x05\x7c\x00\x01\x00\x00\x00\x01\x00\x07\x62\x64\ -\x00\x00\x03\x94\x00\x01\x00\x00\x00\x01\x00\x06\xe1\xe6\ -\x00\x00\x06\x62\x00\x01\x00\x00\x00\x01\x00\x07\xa1\x29\ -\x00\x00\x03\x38\x00\x01\x00\x00\x00\x01\x00\x06\xcf\xc5\ -\x00\x00\x07\x5c\x00\x01\x00\x00\x00\x01\x00\x07\xe0\x24\ -\x00\x00\x04\x7a\x00\x01\x00\x00\x00\x01\x00\x07\x1d\x48\ -\x00\x00\x03\x0e\x00\x01\x00\x00\x00\x01\x00\x06\xc6\x1d\ -\x00\x00\x03\x74\x00\x01\x00\x00\x00\x01\x00\x06\xd9\x78\ -\x00\x00\x06\x0c\x00\x01\x00\x00\x00\x01\x00\x07\x93\x74\ -\x00\x00\x05\x0a\x00\x00\x00\x00\x00\x01\x00\x07\x43\x72\ -\x00\x00\x06\x3a\x00\x01\x00\x00\x00\x01\x00\x07\x98\xc4\ -\x00\x00\x05\x34\x00\x01\x00\x00\x00\x01\x00\x07\x53\xf3\ -\x00\x00\x06\xe6\x00\x00\x00\x00\x00\x01\x00\x07\xbb\x6d\ -\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x07\x2c\x8e\ -\x00\x00\x07\x30\x00\x01\x00\x00\x00\x01\x00\x07\xd7\xaa\ -\x00\x00\x07\x10\x00\x01\x00\x00\x00\x01\x00\x07\xcd\x70\ -\x00\x00\x05\xbc\x00\x01\x00\x00\x00\x01\x00\x07\x7d\xee\ -\x00\x00\x07\xb2\x00\x00\x00\x00\x00\x01\x00\x07\xf9\x88\ -\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x01\x00\x06\xf3\x21\ -\x00\x00\x04\xec\x00\x00\x00\x00\x00\x01\x00\x07\x34\x76\ -\x00\x00\x02\xda\x00\x01\x00\x00\x00\x01\x00\x06\xbe\xcd\ +\x00\x00\x05\x56\x00\x01\x00\x00\x00\x01\x00\x07\x5c\x57\ +\x00\x00\x07\x0a\x00\x01\x00\x00\x00\x01\x00\x07\xc3\x7b\ +\x00\x00\x05\x9c\x00\x00\x00\x00\x00\x01\x00\x07\x6a\xce\ +\x00\x00\x04\x12\x00\x00\x00\x00\x00\x01\x00\x07\x06\x23\ +\x00\x00\x08\x3a\x00\x01\x00\x00\x00\x01\x00\x08\x1b\x50\ +\x00\x00\x06\xdc\x00\x01\x00\x00\x00\x01\x00\x07\xbc\xa6\ +\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x07\x14\x92\ +\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x07\x28\x19\ +\x00\x00\x03\xb6\x00\x01\x00\x00\x00\x01\x00\x06\xeb\x81\ +\x00\x00\x07\xd4\x00\x00\x00\x00\x00\x01\x00\x07\xf8\x0c\ +\x00\x00\x06\x62\x00\x01\x00\x00\x00\x01\x00\x07\xa1\xcb\ +\x00\x00\x06\xba\x00\x01\x00\x00\x00\x01\x00\x07\xb3\xb8\ +\x00\x00\x05\xdc\x00\x00\x00\x00\x00\x01\x00\x07\x84\xa8\ +\x00\x00\x05\x7c\x00\x01\x00\x00\x00\x01\x00\x07\x63\x06\ +\x00\x00\x03\x94\x00\x01\x00\x00\x00\x01\x00\x06\xe2\x88\ +\x00\x00\x06\x8e\x00\x01\x00\x00\x00\x01\x00\x07\xa8\x8e\ +\x00\x00\x03\x38\x00\x01\x00\x00\x00\x01\x00\x06\xd0\x67\ +\x00\x00\x07\xaa\x00\x01\x00\x00\x00\x01\x00\x07\xf0\x77\ +\x00\x00\x04\x7a\x00\x01\x00\x00\x00\x01\x00\x07\x1d\xea\ +\x00\x00\x03\x0e\x00\x01\x00\x00\x00\x01\x00\x06\xc6\xbf\ +\x00\x00\x03\x74\x00\x01\x00\x00\x00\x01\x00\x06\xda\x1a\ +\x00\x00\x06\x0c\x00\x01\x00\x00\x00\x01\x00\x07\x94\x16\ +\x00\x00\x05\x0a\x00\x00\x00\x00\x00\x01\x00\x07\x44\x14\ +\x00\x00\x06\x3a\x00\x01\x00\x00\x00\x01\x00\x07\x99\x66\ +\x00\x00\x05\x34\x00\x01\x00\x00\x00\x01\x00\x07\x54\x95\ +\x00\x00\x07\x34\x00\x00\x00\x00\x00\x01\x00\x07\xcb\xc0\ +\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x07\x2d\x30\ +\x00\x00\x07\x7e\x00\x01\x00\x00\x00\x01\x00\x07\xe7\xfd\ +\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x07\xdd\xc3\ +\x00\x00\x05\xbc\x00\x01\x00\x00\x00\x01\x00\x07\x7e\x90\ +\x00\x00\x08\x00\x00\x00\x00\x00\x00\x01\x00\x08\x09\xdb\ +\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x01\x00\x06\xf3\xc3\ +\x00\x00\x04\xec\x00\x00\x00\x00\x00\x01\x00\x07\x35\x18\ +\x00\x00\x02\xda\x00\x01\x00\x00\x00\x01\x00\x06\xbf\x6f\ \x00\x00\x02\xb2\x00\x01\x00\x00\x00\x01\x00\x06\xb6\xfd\ " diff --git a/src/Mod/Arch/CMakeLists.txt b/src/Mod/Arch/CMakeLists.txt index 76d09e80d..e55bf558f 100644 --- a/src/Mod/Arch/CMakeLists.txt +++ b/src/Mod/Arch/CMakeLists.txt @@ -21,6 +21,8 @@ SET(Arch_SRCS ArchVRM.py ArchRoof.py importWebGL.py + ArchSpace.py + TestArch.py ) SOURCE_GROUP("" FILES ${Arch_SRCS}) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 7d7fd9f5e..ccd46e51d 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -72,8 +72,8 @@ class ArchWorkbench(Workbench): self.archtools = ["Arch_Wall","Arch_Structure", "Arch_Floor","Arch_Building","Arch_Site", "Arch_Window","Arch_Roof","Arch_Axis", - "Arch_SectionPlane","Arch_Add","Arch_Remove", - "Arch_Fixture"] + "Arch_SectionPlane","Arch_Space","Arch_Add", + "Arch_Remove","Arch_Fixture"] self.meshtools = ["Arch_SplitMesh","Arch_MeshToShape", "Arch_SelectNonSolidMeshes","Arch_RemoveShape", "Arch_CloseHoles","Arch_MergeWalls"] @@ -85,13 +85,14 @@ class ArchWorkbench(Workbench): "Draft_Dimension", "Draft_BSpline","Draft_Point"] self.draftmodtools = ["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_Clone","Draft_Heal"] + "Draft_Drawing","Draft_Edit","Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array", + "Draft_Clone"] + self.extramodtools = ["Draft_WireToBSpline","Draft_AddPoint","Draft_DelPoint"] self.draftcontexttools = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup", - "Draft_SelectGroup","Draft_SelectPlane","Draft_ToggleSnap", + "Draft_SelectGroup","Draft_SelectPlane", "Draft_ShowSnapBar","Draft_ToggleGrid","Draft_UndoLine", "Draft_FinishLine","Draft_CloseLine"] + self.draftutils = ["Draft_Heal"] self.snapList = ['Draft_Snap_Lock','Draft_Snap_Midpoint','Draft_Snap_Perpendicular', 'Draft_Snap_Grid','Draft_Snap_Intersection','Draft_Snap_Parallel', 'Draft_Snap_Endpoint','Draft_Snap_Angle','Draft_Snap_Center', @@ -103,8 +104,9 @@ class ArchWorkbench(Workbench): self.appendMenu([str(translate("arch","&Architecture")),str(translate("arch","Conversion Tools"))],self.meshtools) self.appendMenu([str(translate("arch","&Architecture")),str(translate("arch","Calculation Tools"))],self.calctools) self.appendMenu(str(translate("arch","&Architecture")),self.archtools) - self.appendMenu(str(translate("arch","&Draft")),self.drafttools+self.draftmodtools) + self.appendMenu(str(translate("arch","&Draft")),self.drafttools+self.draftmodtools+self.extramodtools) self.appendMenu([str(translate("arch","&Draft")),str(translate("arch","Context Tools"))],self.draftcontexttools) + self.appendMenu([str(translate("arch","&Draft")),str(translate("arch","Utilities"))],self.draftutils) self.appendMenu([str(translate("arch","&Draft")),str(translate("arch","Snapping"))],self.snapList) FreeCADGui.addIconPath(":/icons") FreeCADGui.addLanguagePath(":/translations") @@ -112,6 +114,7 @@ class ArchWorkbench(Workbench): if hasattr(FreeCADGui,"draftToolBar"): if not hasattr(FreeCADGui.draftToolBar,"loadedPreferences"): FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") + FreeCADGui.addPreferencePage(":/ui/userprefs-visual.ui","Draft") FreeCADGui.addPreferencePage(":/ui/userprefs-import.ui","Draft") FreeCADGui.draftToolBar.loadedPreferences = True Log ('Loading Arch module... done\n') @@ -142,14 +145,7 @@ FreeCADGui.addWorkbench(ArchWorkbench) FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC") FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ") FreeCAD.addExportType("WebGL file (*.html)","importWebGL") +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/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index 4aafc08b0..304c659ae 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -32,6 +32,8 @@ icons/Arch_MergeWalls.svg icons/Arch_Wall_Tree_Assembly.svg icons/Arch_Fixture.svg + icons/Arch_Space.svg + icons/Arch_Space_Tree.svg ui/archprefs-base.ui translations/Arch_af.qm translations/Arch_de.qm diff --git a/src/Mod/Arch/Resources/icons/Arch_Space.svg b/src/Mod/Arch/Resources/icons/Arch_Space.svg new file mode 100644 index 000000000..1e302c4dd --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Space.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Arch/Resources/icons/Arch_Space_Tree.svg b/src/Mod/Arch/Resources/icons/Arch_Space_Tree.svg new file mode 100644 index 000000000..65ca3cf5e --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Space_Tree.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Arch/Resources/ui/archprefs-base.ui b/src/Mod/Arch/Resources/ui/archprefs-base.ui index 4741046ae..8093699d0 100644 --- a/src/Mod/Arch/Resources/ui/archprefs-base.ui +++ b/src/Mod/Arch/Resources/ui/archprefs-base.ui @@ -23,7 +23,7 @@ - General Arch Settings + Default settings @@ -31,7 +31,7 @@ - Default color for walls + Wall @@ -48,6 +48,59 @@ + + + + Width: + + + + + + + 9999.989999999999782 + + + 200.000000000000000 + + + WallWidth + + + Mod/Arch + + + + + + + Height: + + + + + + + 9999.989999999999782 + + + 3000.000000000000000 + + + WallHeight + + + Mod/Arch + + + + + + + Color: + + + @@ -75,7 +128,7 @@ - Default color for structures + Structure @@ -92,6 +145,82 @@ + + + + Length: + + + + + + + 9999.989999999999782 + + + 100.000000000000000 + + + StructureLength + + + Mod/Arch + + + + + + + Width: + + + + + + + 9999.989999999999782 + + + 100.000000000000000 + + + StructureWidth + + + Mod/Arch + + + + + + + Height: + + + + + + + 9999.989999999999782 + + + 1000.000000000000000 + + + StructureHeight + + + Mod/Arch + + + + + + + Color: + + + @@ -119,7 +248,7 @@ - Default color for windows + Window @@ -136,6 +265,13 @@ + + + + Frame color: + + + @@ -153,30 +289,13 @@ - - - - - + - Default color for window glass + Glass color: - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -285,23 +404,6 @@ - - - - - - Import furniture (can make the model heavy) - - - importIfcFurniture - - - Mod/Arch - - - - - @@ -360,7 +462,7 @@ - IfcSpace,IfcBuildingElementProxy,IfcFlowTerminal + IfcSpace,IfcBuildingElementProxy,IfcFlowTerminal,IfcFurnishingElement ifcSkip @@ -372,6 +474,33 @@ + + + + + + Import as meshes: + + + + + + + A comma-separated list of IFC types that must be imported as meshes + + + IfcFurnishingElement + + + ifcAsMesh + + + Mod/Arch + + + + + @@ -441,22 +570,22 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/src/Mod/Arch/TestArch.py b/src/Mod/Arch/TestArch.py new file mode 100644 index 000000000..7f86153e4 --- /dev/null +++ b/src/Mod/Arch/TestArch.py @@ -0,0 +1,53 @@ +# Unit test for the Arch module + +#*************************************************************************** +#* (c) Yorik van Havre 2013 * +#* * +#* This file is part of the FreeCAD CAx development system. * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* FreeCAD is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with FreeCAD; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#***************************************************************************/ + +import FreeCAD, os, unittest, FreeCADGui, Arch, Draft + +class ArchTest(unittest.TestCase): + + def setUp(self): + # setting a new document to hold the tests + if FreeCAD.ActiveDocument: + if FreeCAD.ActiveDocument.Name != "ArchTest": + FreeCAD.newDocument("ArchTest") + else: + FreeCAD.newDocument("ArchTest") + FreeCAD.setActiveDocument("ArchTest") + + def testWall(self): + FreeCAD.Console.PrintLog ('Checking Arch Wall...\n') + l=Draft.makeLine(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-2,0,0)) + w = Arch.makeWall(l) + self.failUnless(w,"Arch Wall failed") + + def testStructure(self): + FreeCAD.Console.PrintLog ('Checking Arch Structure...\n') + s = Arch.makeStructure(length=2,width=3,hright=5) + self.failUnless(s,"Arch Structure failed") + + def tearDown(self): + FreeCAD.closeDocument("ArchTest") + pass + diff --git a/src/Mod/Arch/importDAE.py b/src/Mod/Arch/importDAE.py index 4ffa2bde6..94ad0cd1b 100644 --- a/src/Mod/Arch/importDAE.py +++ b/src/Mod/Arch/importDAE.py @@ -37,14 +37,15 @@ def checkCollada(): try: import collada except: - FreeCAD.Console.PrintError(str(translate("Arch","pycollada not found, no collada support.\n"))) + FreeCAD.Console.PrintError(str(translate("Arch","pycollada not found, collada support is disabled.\n"))) return False else: return True def open(filename): "called when freecad wants to open a file" - if not checkCollada(): return + if not checkCollada(): + return docname = os.path.splitext(os.path.basename(filename))[0] doc = FreeCAD.newDocument(docname) doc.Label = decode(docname) @@ -54,7 +55,8 @@ def open(filename): def insert(filename,docname): "called when freecad wants to import a file" - if not checkCollada(): return + if not checkCollada(): + return try: doc = FreeCAD.getDocument(docname) except: diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 140119ed0..313050fbd 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -59,17 +59,17 @@ def insert(filename,docname): def getConfig(): "Gets Arch IFC import preferences" - global CREATE_IFC_GROUPS, IMPORT_IFC_FURNITURE, DEBUG, SKIP, PREFIX_NUMBERS, FORCE_PYTHON_PARSER, SEPARATE_OPENINGS + global CREATE_IFC_GROUPS, ASMESH, DEBUG, SKIP, PREFIX_NUMBERS, FORCE_PYTHON_PARSER, SEPARATE_OPENINGS CREATE_IFC_GROUPS = False IMPORT_IFC_FURNITURE = False DEBUG = False - SKIP = ["IfcSpace","IfcBuildingElementProxy","IfcFlowTerminal"] + SKIP = ["IfcBuildingElementProxy","IfcFlowTerminal","IfcFurnishingElement"] + ASMESH = ["IfcFurnishingElement"] PREFIX_NUMBERS = False FORCE_PYTHON_PARSER = False SEPARATE_OPENINGS = False p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") CREATE_IFC_GROUPS = p.GetBool("createIfcGroups") - IMPORT_IFC_FURNITURE = p.GetBool("importIfcFurniture") FORCE_PYTHON_PARSER = p.GetBool("forceIfcPythonParser") DEBUG = p.GetBool("ifcDebug") SEPARATE_OPENINGS = p.GetBool("ifcSeparateOpenings") @@ -77,7 +77,9 @@ def getConfig(): skiplist = p.GetString("ifcSkip") if skiplist: SKIP = skiplist.split(",") - + asmeshlist = p.GetString("ifcAsMesh") + if asmeshlist: + ASMESH = asmeshlist.split(",") def getIfcOpenShell(): "locates and imports ifcopenshell" @@ -104,8 +106,6 @@ def read(filename): if DEBUG: global ifcObjects,ifcParents ifcObjects = {} # a table to relate ifc id with freecad object ifcParents = {} # a table to relate ifc id with parent id - if not IMPORT_IFC_FURNITURE: - SKIP.append("IfcFurnishingElement") if hasattr(IfcImport,"DISABLE_OPENING_SUBTRACTIONS") and SEPARATE_OPENINGS: IfcImport.Settings(IfcImport.DISABLE_OPENING_SUBTRACTIONS,True) else: @@ -123,7 +123,6 @@ def read(filename): obj = IfcImport.Get() if DEBUG: print "["+str(int((float(obj.id)/num_lines)*100))+"%] parsing ",obj.id,": ",obj.name," of type ",obj.type - meshdata = [] # retrieving name n = getName(obj) @@ -164,6 +163,10 @@ def read(filename): elif obj.type in ["IfcSite"]: nobj = makeSite(obj.id,shape,n) + # spaces + elif obj.type in ["IfcSpace"]: + nobj = makeSpace(obj.id,shape,n) + elif shape: # treat as dumb parts #if DEBUG: print "Fixme: Shape-containing object not handled: ",obj.id, " ", obj.type @@ -185,7 +188,7 @@ def read(filename): if not IfcImport.Next(): break - + # processing non-geometry and relationships parents_temp = dict(ifcParents) import ArchCommands @@ -239,7 +242,7 @@ def read(filename): ArchCommands.addComponents(ifcObjects[id],parent) else: ArchCommands.removeComponents(ifcObjects[id],parent) - + IfcImport.CleanUp() else: @@ -282,7 +285,7 @@ def read(filename): for s in ifc.getEnt("IfcSite"): group(s,ifc,"Site") - if DEBUG: print "done parsing. Recomputing..." + if DEBUG: print "done parsing. Recomputing..." FreeCAD.ActiveDocument.recompute() t3 = time.time() if DEBUG: print "done processing IFC file in %s s" % ((t3-t1)) @@ -306,8 +309,12 @@ def makeWall(entity,shape=None,name="Wall"): try: if shape: # use ifcopenshell - body = FreeCAD.ActiveDocument.addObject("Part::Feature","WallBody") - body.Shape = shape + if isinstance(shape,Part.Shape): + body = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body") + body.Shape = shape + else: + body = FreeCAD.ActiveDocument.addObject("Mesh::Feature",name+"_body") + body.Mesh = shape wall = Arch.makeWall(body,name=name) wall.Label = name if DEBUG: print "made wall object ",entity,":",wall @@ -352,11 +359,12 @@ def makeWindow(entity,shape=None,name="Window"): try: if shape: # use ifcopenshell - window = Arch.makeWindow(name=name) - window.Shape = shape - window.Label = name - if DEBUG: print "made window object ",entity,":",window - return window + if isinstance(shape,Part.Shape): + window = Arch.makeWindow(name=name) + window.Shape = shape + window.Label = name + if DEBUG: print "made window object ",entity,":",window + return window # use internal parser if DEBUG: print "=====> making window",entity.id @@ -386,9 +394,13 @@ def makeStructure(entity,shape=None,name="Structure"): try: if shape: # use ifcopenshell - sh = FreeCAD.ActiveDocument.addObject("Part::Feature","StructureBody") - sh.Shape = shape - structure = Arch.makeStructure(sh,name=name) + if isinstance(shape,Part.Shape): + body = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body") + body.Shape = shape + else: + body = FreeCAD.ActiveDocument.addObject("Mesh::Feature",name+"_body") + body.Mesh = shape + structure = Arch.makeStructure(body,name=name) structure.Label = name if DEBUG: print "made structure object ",entity,":",structure return structure @@ -419,15 +431,37 @@ def makeStructure(entity,shape=None,name="Structure"): def makeSite(entity,shape=None,name="Site"): "makes a site in the freecad document" try: + body = None if shape: # use ifcopenshell - site = Arch.makeSite(name=name) - site.Label = name - body = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body") - body.Shape = shape + if isinstance(shape,Part.Shape): + body = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body") + body.Shape = shape + else: + body = FreeCAD.ActiveDocument.addObject("Mesh::Feature",name+"_body") + body.Mesh = shape + site = Arch.makeSite(name=name) + site.Label = name + if body: site.Terrain = body - if DEBUG: print "made site object ",entity,":",site - return site + if DEBUG: print "made site object ",entity,":",site + return site + except: + return None + +def makeSpace(entity,shape=None,name="Space"): + "makes a space in the freecad document" + try: + if shape: + # use ifcopenshell + if isinstance(shape,Part.Shape): + space = Arch.makeSpace(name=name) + space.Label = name + body = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body") + body.Shape = shape + space.Base = body + if DEBUG: print "made space object ",entity,":",space + return site except: return None @@ -437,11 +471,12 @@ def makeRoof(entity,shape=None,name="Roof"): try: if shape: # use ifcopenshell - roof = Arch.makeRoof(name=name) - roof.Label = name - roof.Shape = shape - if DEBUG: print "made roof object ",entity,":",roof - return roof + if isinstance(shape,Part.Shape): + roof = Arch.makeRoof(name=name) + roof.Label = name + roof.Shape = shape + if DEBUG: print "made roof object ",entity,":",roof + return roof except: return None @@ -450,6 +485,9 @@ def makeRoof(entity,shape=None,name="Roof"): def getMesh(obj): "gets mesh and placement from an IfcOpenShell object" import Mesh + meshdata = [] + print obj.mesh.faces + print obj.mesh.verts f = obj.mesh.faces v = obj.mesh.verts for i in range(0, len(f), 3): @@ -458,6 +496,7 @@ def getMesh(obj): vi = f[i+j]*3 face.append([v[vi],v[vi+1],v[vi+2]]) meshdata.append(face) + print meshdata me = Mesh.Mesh(meshdata) # get transformation matrix m = obj.matrix @@ -470,9 +509,15 @@ def getMesh(obj): def getShape(obj): "gets a shape from an IfcOpenShell object" - import StringIO,Part + #print "retrieving shape from obj ",obj.id + import Part sh=Part.Shape() - sh.importBrep(StringIO.StringIO(obj.mesh.brep_data)) + try: + sh.importBrepFromString(obj.mesh.brep_data) + #sh = Part.makeBox(2,2,2) + except: + print "Error: malformed shape" + return None if not sh.Solids: # try to extract a solid shape if sh.Faces: @@ -494,6 +539,8 @@ def getShape(obj): 0, 0, 0, 1) sh.Placement = FreeCAD.Placement(mat) # if DEBUG: print "getting Shape from ",obj + #print "getting shape: ",sh,sh.Solids,sh.Volume,sh.isValid(),sh.isNull() + #for v in sh.Vertexes: print v.Point return sh # below is only used by the internal parser ######################################### diff --git a/src/Mod/CMakeLists.txt b/src/Mod/CMakeLists.txt index b63fac633..99ba91dd5 100644 --- a/src/Mod/CMakeLists.txt +++ b/src/Mod/CMakeLists.txt @@ -51,5 +51,7 @@ add_subdirectory(OpenSCAD) add_subdirectory(Plot) +add_subdirectory(Spreadsheet) + diff --git a/src/Mod/Complete/App/AppComplete.cpp b/src/Mod/Complete/App/AppComplete.cpp index 057e8296e..2385ff17b 100644 --- a/src/Mod/Complete/App/AppComplete.cpp +++ b/src/Mod/Complete/App/AppComplete.cpp @@ -60,7 +60,7 @@ void AppCompleteExport initComplete() try { Base::Interpreter().loadModule("Draft"); } - catch (const Base::PyException& e) { + catch (const Base::Exception& e) { // If called from console then issue a message but don't stop with an error PySys_WriteStdout("Import error: %s\n", e.what()); } diff --git a/src/Mod/Complete/Gui/Workbench.cpp b/src/Mod/Complete/Gui/Workbench.cpp index 6ccb6b12b..ebc9b06b7 100644 --- a/src/Mod/Complete/Gui/Workbench.cpp +++ b/src/Mod/Complete/Gui/Workbench.cpp @@ -140,9 +140,9 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* stdviews = new Gui::MenuItem; stdviews->setCommand("Standard views"); *stdviews << "Std_ViewFitAll" << "Std_ViewFitSelection" << "Std_ViewAxo" - << "Separator" << "Std_ViewFront" << "Std_ViewRight" - << "Std_ViewTop" << "Separator" << "Std_ViewRear" - << "Std_ViewLeft" << "Std_ViewBottom"; + << "Separator" << "Std_ViewFront" << "Std_ViewTop" + << "Std_ViewRight" << "Separator" << "Std_ViewRear" + << "Std_ViewBottom" << "Std_ViewLeft"; // stereo Gui::MenuItem* view3d = new Gui::MenuItem; @@ -209,7 +209,6 @@ Gui::MenuItem* Workbench::setupMenuBar() const mesh->setCommand("&Meshes"); *mesh << "Mesh_Import" << "Mesh_Export" - << "Mesh_FromGeometry" << "MeshPart_Mesher" << "Separator" << analyze @@ -470,8 +469,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* view = new Gui::ToolBarItem( root ); view->setCommand("View"); *view << "Std_ViewFitAll" << "Separator" << "Std_ViewAxo" << "Separator" << "Std_ViewFront" - << "Std_ViewRight" << "Std_ViewTop" << "Separator" << "Std_ViewRear" << "Std_ViewLeft" - << "Std_ViewBottom" << "Separator" << "Std_MeasureDistance"; + << "Std_ViewTop" << "Std_ViewRight" << "Separator" << "Std_ViewRear" << "Std_ViewBottom" + << "Std_ViewLeft" << "Separator" << "Std_MeasureDistance"; // Part Design Gui::ToolBarItem* part_design = new Gui::ToolBarItem( root ); diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index e380eb193..95a21c33f 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -17,6 +17,7 @@ SET(Draft_SRCS importAirfoilDAT.py macros.py Draft_rc.py + TestDraft.py ) SOURCE_GROUP("" FILES ${Draft_SRCS}) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 9f9379d50..9b8161a3e 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -1,3 +1,5 @@ +# -*- coding: utf8 -*- + #*************************************************************************** #* * #* Copyright (c) 2009, 2010 * @@ -98,7 +100,7 @@ def typecheck (args_and_types, name="?"): def getParamType(param): if param in ["dimsymbol","dimPrecision","dimorientation","precision","defaultWP", "snapRange","gridEvery","linewidth","UiMode","modconstrain","modsnap", - "modalt"]: + "modalt","HatchPatternResolution"]: return "int" elif param in ["constructiongroupname","textfont","patternFile","template","maxSnapEdges", "snapModes","FontFile"]: @@ -278,7 +280,11 @@ def getGroupContents(objectslist,walls=False): newlist = [] for obj in objectslist: if obj.isDerivedFrom("App::DocumentObjectGroup"): - newlist.extend(getGroupContents(obj.Group)) + if obj.isDerivedFrom("Drawing::FeaturePage"): + # skip if the grou is a page + newlist.append(obj) + else: + newlist.extend(getGroupContents(obj.Group)) else: newlist.append(obj) if walls: @@ -414,10 +420,13 @@ def loadSvgPatterns(): # getting default patterns patfiles = QtCore.QDir(":/patterns").entryList() for fn in patfiles: - f = QtCore.QFile(":/patterns/"+str(fn)) + fn = ":/patterns/"+str(fn) + f = QtCore.QFile(fn) f.open(QtCore.QIODevice.ReadOnly) p = importSVG.getContents(str(f.readAll()),'pattern',True) if p: + for k in p: + p[k] = [p[k],fn] FreeCAD.svgpatterns.update(p) # looking for user patterns altpat = getParam("patternFile") @@ -426,7 +435,19 @@ def loadSvgPatterns(): if f[-4:].upper() == ".SVG": p = importSVG.getContents(altpat+os.sep+f,'pattern') if p: + for k in p: + p[k] = [p[k],fn] FreeCAD.svgpatterns.update(p) + +def svgpatterns(): + """svgpatterns(): returns a dictionnary with installed SVG patterns""" + if hasattr(FreeCAD,"svgpatterns"): + return FreeCAD.svgpatterns + else: + loadSvgPatterns() + if hasattr(FreeCAD,"svgpatterns"): + return FreeCAD.svgpatterns + return {} def loadTexture(filename,size=None): """loadTexture(filename,[size]): returns a SoSFImage from a file. If size @@ -437,11 +458,11 @@ def loadTexture(filename,size=None): from PyQt4 import QtGui,QtSvg try: if size and (".svg" in filename.lower()): - # we need to resize + # this is a pattern, not a texture if isinstance(size,int): size = (size,size) svgr = QtSvg.QSvgRenderer(filename) - p = QtGui.QImage(size[0],size[1],QtGui.QImage.Format_ARGB32_Premultiplied) + p = QtGui.QImage(size[0],size[1],QtGui.QImage.Format_ARGB32) pa = QtGui.QPainter() pa.begin(p) svgr.render(pa) @@ -495,7 +516,11 @@ def makeCircle(radius, placement=None, face=True, startangle=None, endangle=None is passed, its Curve must be a Part.Circle''' import Part, DraftGeomUtils if placement: typecheck([(placement,FreeCAD.Placement)], "makeCircle") - obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Circle") + if startangle != endangle: + n = "Arc" + else: + n = "Circle" + obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",n) _Circle(obj) if isinstance(radius,Part.Edge): edge = radius @@ -587,10 +612,10 @@ def makeDimension(p1,p2,p3=None,p4=None): obj.Base = p1 if p3 == "radius": obj.LinkedVertices = [p2,1,1] - obj.ViewObject.Override = "Rdim" + obj.ViewObject.Override = "R$dim" elif p3 == "diameter": obj.LinkedVertices = [p2,2,1] - obj.ViewObject.Override = "Ddim" + obj.ViewObject.Override = "Ø$dim" p3 = p4 if not p3: p3 = obj.Base.Shape.Edges[0].Curve.Center.add(Vector(1,0,0)) @@ -637,8 +662,8 @@ def makeWire(pointslist,closed=False,placement=None,face=True,support=None): if DraftGeomUtils.isReallyClosed(pointslist): closed = True pointslist = nlist - print pointslist - print closed + #print pointslist + #print closed if placement: typecheck([(placement,FreeCAD.Placement)], "makeWire") if len(pointslist) == 2: fname = "Line" else: fname = "DWire" @@ -708,7 +733,7 @@ def makeBSpline(pointslist,closed=False,placement=None,face=True,support=None): obj.Support = support if placement: obj.Placement = placement if gui: - _ViewProviderBSpline(obj.ViewObject) + _ViewProviderWire(obj.ViewObject) if not face: obj.ViewObject.DisplayMode = "Wireframe" formatObject(obj) select(obj) @@ -724,7 +749,9 @@ def makeText(stringslist,point=Vector(0,0,0),screen=False): typecheck([(point,Vector)], "makeText") if not isinstance(stringslist,list): stringslist = [stringslist] textbuffer = [] - for l in stringslist: textbuffer.append(unicode(l).encode('utf-8')) + for l in stringslist: + #textbuffer.append(l.decode("utf8").encode('latin1')) + textbuffer.append(str(l)) obj=FreeCAD.ActiveDocument.addObject("App::Annotation","Text") obj.LabelText=textbuffer obj.Position=point @@ -769,12 +796,15 @@ def makeCopy(obj,force=None,reparent=False): newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _BSpline(newobj) if gui: - _ViewProviderBSpline(newobj.ViewObject) + _ViewProviderWire(newobj.ViewObject) elif (getType(obj) == "Block") or (force == "BSpline"): newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) _Block(newobj) if gui: _ViewProviderDraftPart(newobj.ViewObject) + elif (getType(obj) == "DrawingView") or (force == "DrawingView"): + newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) + _DrawingView(newobj) elif (getType(obj) == "Structure") or (force == "Structure"): import ArchStructure newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) @@ -793,12 +823,6 @@ def makeCopy(obj,force=None,reparent=False): ArchWindow._Window(newobj) if gui: Archwindow._ViewProviderWindow(newobj.ViewObject) - elif (getType(obj) == "Cell") or (force == "Cell"): - import ArchCell - newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name)) - ArchCell._Cell(newobj) - 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: @@ -819,7 +843,7 @@ def makeCopy(obj,force=None,reparent=False): parents = obj.InList if parents: for par in parents: - if par.TypeId == "App::DocumentObjectGroup": + if par.isDerivedFrom("App::DocumentObjectGroup"): par.addObject(newobj) else: for prop in par.PropertiesList: @@ -875,6 +899,8 @@ def makeEllipse(majradius,minradius,placement=None,face=True,support=None): a placement.''' obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Ellipse") _Ellipse(obj) + if minradius > majradius: + majradius,minradius = minradius,majradius obj.MajorRadius = majradius obj.MinorRadius = minradius obj.Support = support @@ -1009,12 +1035,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=DraftVecUtils.scale(xvector,xcount) + currentxvector=Vector(xvector).multiply(xcount) if not xcount==0: move(objectslist,currentxvector,True) for ycount in range(ynum): currentxvector=FreeCAD.Base.Vector(currentxvector) - currentyvector=currentxvector.add(DraftVecUtils.scale(yvector,ycount)) + currentyvector=currentxvector.add(Vector(yvector).multiply(ycount)) if not ycount==0: move(objectslist,currentyvector,True) def polarArray(objectslist,center,angle,num): @@ -1102,7 +1128,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 = DraftVecUtils.neg(corr.sub(center)) + corr = (corr.sub(center)).negative() sh.translate(corr) if getType(obj) == "Rectangle": p = [] @@ -1146,7 +1172,7 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy obj.Scale = delta corr = Vector(center.x,center.y,center.z) corr.scale(delta.x,delta.y,delta.z) - corr = DraftVecUtils.neg(corr.sub(center)) + corr = (corr.sub(center)).negative() p = obj.Placement p.move(corr) obj.Placement = p @@ -1203,8 +1229,8 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): pass else: if sym: - d1 = delta.multiply(0.5) - d2 = DraftVecUtils.neg(d1) + d1 = Vector(delta).multiply(0.5) + d2 = d1.negative() n1 = DraftGeomUtils.offsetWire(obj.Shape,d1) n2 = DraftGeomUtils.offsetWire(obj.Shape,d2) else: @@ -1265,9 +1291,9 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): obj.Tool = None obj.Points = p elif getType(obj) == "BSpline": - print delta + #print delta obj.Points = delta - print "done" + #print "done" elif getType(obj) == "Rectangle": length,height,plac = getRect(p,obj) obj.Placement = plac @@ -1323,8 +1349,8 @@ def draftify(objectslist,makeblock=False,delete=True): return newobjlist[0] return newobjlist -def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direction=None): - '''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction]): +def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direction=None,linestyle=None): + '''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction],[linestyle]): 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 @@ -1339,22 +1365,18 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct if isinstance(direction,FreeCAD.Vector): if direction != Vector(0,0,0): plane = WorkingPlane.plane() - plane.alignToPointAndAxis(Vector(0,0,0),DraftVecUtils.neg(direction),0) + plane.alignToPointAndAxis(Vector(0,0,0),direction.negative(),0) elif isinstance(direction,WorkingPlane.plane): plane = direction - def getLineStyle(obj): - "returns a linestyle pattern for a given object" - if gui: - 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" + def getLineStyle(): + "returns a linestyle" + if linestyle == "Dashed": + return "0.09,0.05" + elif linestyle == "Dashdot": + return "0.09,0.05,0.02,0.05" + elif linestyle == "Dotted": + return "0.02,0.02" return "none" def getProj(vec): @@ -1368,44 +1390,51 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct return Vector(lx,ly,0) def getPattern(pat): - if not hasattr(FreeCAD,"svgpatterns"): - loadSvgPatterns() - if pat in FreeCAD.svgpatterns: - return FreeCAD.svgpatterns[pat] + if pat in svgpatterns(): + return svgpatterns()[pat][0] return '' - def getPath(edges): + def getPath(edges=[],wires=[]): import DraftGeomUtils svg =' 1 - flag_sweep = e.Curve.Axis * drawing_plane_normal >= 0 - v = getProj(e.Vertexes[-1].Point) - svg += 'A ' + str(r) + ' ' + str(r) + ' ' - svg += '0 ' + str(int(flag_large_arc)) + ' ' + str(int(flag_sweep)) + ' ' - svg += str(v.x) + ' ' + str(v.y) + ' ' - if fill != 'none': svg += 'Z' + svg += 'd="' + if not wires: + egroups = [edges] + else: + egroups = [] + for w in wires: + egroups.append(w.Edges) + for g in egroups: + edges = DraftGeomUtils.sortEdges(g) + v = getProj(edges[0].Vertexes[0].Point) + svg += 'M '+ str(v.x) +' '+ str(v.y) + ' ' + for e in edges: + if DraftGeomUtils.geomType(e) == "Circle": + if len(e.Vertexes) == 1: + # complete circle + svg = getCircle(e) + return svg + r = e.Curve.Radius + drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis + if plane: drawing_plane_normal = plane.axis + flag_large_arc = (((e.ParameterRange[1] - e.ParameterRange[0]) / math.pi) % 2) > 1 + flag_sweep = e.Curve.Axis * drawing_plane_normal >= 0 + v = getProj(e.Vertexes[-1].Point) + svg += 'A ' + str(r) + ' ' + str(r) + ' ' + svg += '0 ' + str(int(flag_large_arc)) + ' ' + str(int(flag_sweep)) + ' ' + svg += str(v.x) + ' ' + str(v.y) + ' ' + else: + v = getProj(e.Vertexes[-1].Point) + svg += 'L '+ str(v.x) +' '+ str(v.y) + ' ' + if fill != 'none': svg += 'Z ' svg += '" ' svg += 'stroke="' + stroke + '" ' svg += 'stroke-width="' + str(linewidth) + ' px" ' svg += 'style="stroke-width:'+ str(linewidth) svg += ';stroke-miterlimit:4' svg += ';stroke-dasharray:' + lstyle - svg += ';fill:' + fill + '"' + svg += ';fill:' + fill + svg += ';fill-rule: evenodd "' svg += '/>\n' return svg @@ -1428,84 +1457,91 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct pass elif getType(obj) == "Dimension": - p1,p2,p3,p4,tbase,norm,rot = obj.ViewObject.Proxy.calcGeom(obj) - dimText = getParam("dimPrecision") - dimText = "%."+str(dimText)+"f" - p1 = getProj(p1) - p2 = getProj(p2) - p3 = getProj(p3) - p4 = getProj(p4) - tbase = getProj(tbase) - svg = '\n' + for i in range(len(obj.LabelText)): + if i == 0: + svg += '' + else: + svg += '' + svg += obj.LabelText[i]+'\n' svg += '\n' + #print svg elif getType(obj) == "Axis": "returns the SVG representation of an Arch Axis system" color = getrgb(obj.ViewObject.LineColor) - lorig = getLineStyle(obj) + lorig = getLineStyle() name = obj.Name stroke = getrgb(obj.ViewObject.LineColor) fill = 'none' @@ -1573,13 +1614,16 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct fill = "#888888" else: fill = 'none' - lstyle = getLineStyle(obj) + lstyle = getLineStyle() name = obj.Name if gui: - if obj.ViewObject.DisplayMode == "Shaded": - stroke = "none" - else: - stroke = getrgb(obj.ViewObject.LineColor) + try: + if obj.ViewObject.DisplayMode == "Shaded": + stroke = "none" + else: + stroke = getrgb(obj.ViewObject.LineColor) + except: + stroke = "#000000" else: stroke = "#000000" @@ -1587,7 +1631,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct wiredEdges = [] if obj.Shape.Faces: for f in obj.Shape.Faces: - svg += getPath(f.Edges) + svg += getPath(wires=f.Wires) wiredEdges.extend(f.Edges) else: for w in obj.Shape.Wires: @@ -1638,6 +1682,11 @@ def makeDrawingView(obj,page,lwmod=None,tmod=None): viewobj.Source = obj if lwmod: viewobj.LineweightModifier = lwmod if tmod: viewobj.TextModifier = tmod + if hasattr(obj.ViewObject,"Pattern"): + if str(obj.ViewObject.Pattern) in svgpatterns().keys(): + viewobj.FillStyle = str(obj.ViewObject.Pattern) + if hasattr(obj.ViewObject,"DrawStyle"): + viewobj.LineStyle = obj.ViewObject.DrawStyle return viewobj def makeShape2DView(baseobj,projectionVector=None,facenumbers=[]): @@ -1819,10 +1868,15 @@ def heal(objlist=None,delete=True,reparent=True): the damaged objects are deleted (default). If ran without arguments, all the objects in the document will be healed if they are damaged. If reparent is True (default), new objects go at the very same place in the tree than their original.''' + + auto = False if not objlist: objlist = FreeCAD.ActiveDocument.Objects - print "Healing whole document..." + print "Automatic mode: Healing whole document..." + auto = True + else: + print "Manual mode: Force-healing selected objects..." if not isinstance(objlist,list): objlist = [objlist] @@ -1833,8 +1887,12 @@ def heal(objlist=None,delete=True,reparent=True): for obj in objlist: dtype = getType(obj) ftype = obj.TypeId - if ftype in ["Part::FeaturePython","App::FeaturePython","Part::Part2DObjectPython"]: - if obj.ViewObject.Proxy == 1 and dtype in ["Unknown","Part"]: + if ftype in ["Part::FeaturePython","App::FeaturePython","Part::Part2DObjectPython","Drawing::FeatureViewPython"]: + proxy = obj.Proxy + if hasattr(obj,"ViewObject"): + if hasattr(obj.ViewObject,"Proxy"): + proxy = obj.ViewObject.Proxy + if (proxy == 1) or (dtype in ["Unknown","Part"]) or (not auto): got = True dellist.append(obj.Name) props = obj.PropertiesList @@ -1857,6 +1915,8 @@ def heal(objlist=None,delete=True,reparent=True): elif ("DrawMode" in props) and ("FacesNumber" in props): print "Healing " + obj.Name + " of type Polygon" nobj = makeCopy(obj,force="Polygon",reparent=reparent) + elif ("FillStyle" in props) and ("FontSize" in props): + nobj = makeCopy(obj,force="DrawingView",reparent=reparent) else: dellist.pop() print "Object " + obj.Name + " is not healable" @@ -2165,7 +2225,7 @@ def upgrade(objects,delete=False,force=None): elif wires and (not faces) and (not openwires): # we have a sketch: Extract a face - if (len(objects) == 1) and objects[0].isDerivedFrom("Sketcher::SketchObject") and (not curves): + if (len(objects) == 1) and objects[0].isDerivedFrom("Sketcher::SketchObject"): result = makeSketchFace(objects[0]) if result: msg(translate("draft", "Found 1 closed sketch object: making a face from it\n")) @@ -2410,41 +2470,100 @@ class _DraftObject: class _ViewProviderDraft: "The base class for Draft Viewproviders" - def __init__(self, obj): - obj.Proxy = self - self.Object = obj.Object + def __init__(self, vobj): + from DraftTools import translate + vobj.Proxy = self + self.Object = vobj.Object + vobj.addProperty("App::PropertyEnumeration","Pattern", + "Pattern","Defines a hatch pattern") + vobj.addProperty("App::PropertyFloat","PatternSize", + "Pattern","Sets the size of the pattern") + vobj.Pattern = [str(translate("draft","None"))]+svgpatterns().keys() + vobj.PatternSize = 1 def __getstate__(self): return None - def __setstate__(self,state): + def __setstate__(self, state): return None - def attach(self, obj): - self.Object = obj.Object + def attach(self,vobj): + self.texture = None + self.texcoords = None + self.Object = vobj.Object return - def updateData(self, fp, prop): + def updateData(self, obj, prop): return - def getDisplayModes(self,obj): + def getDisplayModes(self, vobj): modes=[] return modes - def setDisplayMode(self,mode): + def setDisplayMode(self, mode): return mode - def onChanged(self, vp, prop): + def onChanged(self, vobj, prop): + # treatment of patterns and image textures + if prop in ["TextureImage","Pattern"]: + if hasattr(self.Object,"Shape"): + if self.Object.Shape.Faces: + from pivy import coin + from PyQt4 import QtCore + path = None + if hasattr(vobj,"TextureImage"): + if vobj.TextureImage: + path = vobj.TextureImage + if not path: + if str(vobj.Pattern) in svgpatterns().keys(): + path = svgpatterns()[vobj.Pattern][1] + if path: + r = vobj.RootNode.getChild(2).getChild(0).getChild(2) + i = QtCore.QFileInfo(path) + if self.texture: + r.removeChild(self.texture) + self.texture = None + if self.texcoords: + r.removeChild(self.texcoords) + self.texcoords = None + if i.exists(): + size = None + if ":/patterns" in path: + size = getParam("HatchPAtternResolution") + if not size: + size = 128 + im = loadTexture(path, size) + if im: + self.texture = coin.SoTexture2() + self.texture.image = im + r.insertChild(self.texture,1) + if size: + s =1 + if hasattr(vobj,"PatternSize"): + if vobj.PatternSize: + s = vobj.PatternSize + self.texcoords = coin.SoTextureCoordinatePlane() + self.texcoords.directionS.setValue(s,0,0) + self.texcoords.directionT.setValue(0,s,0) + r.insertChild(self.texcoords,2) + elif prop == "PatternSize": + if hasattr(self,"texcoords"): + if self.texcoords: + s = 1 + if vobj.PatternSize: + s = vobj.PatternSize + self.texcoords.directionS.setValue(s,0,0) + self.texcoords.directionT.setValue(0,s,0) return - def execute(self,obj): + def execute(self,vobj): return - def setEdit(self,vp,mode): + def setEdit(self,vobj,mode): FreeCADGui.runCommand("Draft_Edit") return True - def unsetEdit(self,vp,mode): + def unsetEdit(self,vobj,mode): if FreeCAD.activeDraftCommand: FreeCAD.activeDraftCommand.finish() FreeCADGui.Control.closeDialog() @@ -2467,7 +2586,8 @@ class _ViewProviderDraftAlt(_ViewProviderDraft): "a view provider that doesn't swallow its base object" def __init__(self,vobj): - _ViewProviderDraft.__init__(self,vobj) + vobj.Proxy = self + self.Object = vobj.Object def claimChildren(self): return [] @@ -2476,7 +2596,8 @@ class _ViewProviderDraftPart(_ViewProviderDraftAlt): "a view provider that displays a Part icon instead of a Draft icon" def __init__(self,vobj): - _ViewProviderDraftAlt.__init__(self,vobj) + vobj.Proxy = self + self.Object = vobj.Object def getIcon(self): return ":/icons/Tree_Part.svg" @@ -2517,7 +2638,7 @@ class _ViewProviderDimension(_ViewProviderDraft): obj.addProperty("App::PropertyColor","LineColor","Base","Line color") obj.addProperty("App::PropertyLength","ExtLines","Base","Ext lines") obj.addProperty("App::PropertyVector","TextPosition","Base","The position of the text. Leave (0,0,0) for automatic position") - obj.addProperty("App::PropertyString","Override","Base","Text override. Use 'dim' to insert the dimension length") + obj.addProperty("App::PropertyString","Override","Base","Text override. Use $dim to insert the dimension length") obj.FontSize=getParam("textheight") obj.FontName=getParam("textfont") obj.ExtLines=0.3 @@ -2535,35 +2656,35 @@ class _ViewProviderDimension(_ViewProviderDraft): p2 = p1 p3 = p4 else: - p2 = p1.add(DraftVecUtils.neg(proj)) - p3 = p4.add(DraftVecUtils.neg(proj)) + p2 = p1.add(proj.negative()) + p3 = p4.add(proj.negative()) dmax = obj.ViewObject.ExtLines if dmax and (proj.Length > dmax): p1 = p2.add(DraftVecUtils.scaleTo(proj,dmax)) p4 = p3.add(DraftVecUtils.scaleTo(proj,dmax)) - midpoint = p2.add(DraftVecUtils.scale(p3.sub(p2),0.5)) + midpoint = p2.add((p3.sub(p2).multiply(0.5))) if not proj: ed = DraftGeomUtils.vec(base) proj = ed.cross(Vector(0,0,1)) if not proj: norm = Vector(0,0,1) - else: norm = DraftVecUtils.neg(p3.sub(p2).cross(proj)) + else: norm = (p3.sub(p2).cross(proj)).negative() if not DraftVecUtils.isNull(norm): norm.normalize() va = get3DView().getViewDirection() if va.getAngle(norm) < math.pi/2: - norm = DraftVecUtils.neg(norm) + norm = norm.negative() u = p3.sub(p2) u.normalize() 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 = DraftVecUtils.neg(u) + if ru.getAngle(u) > math.pi/2: u = u.negative() v = norm.cross(u) offset = DraftVecUtils.scaleTo(v,obj.ViewObject.FontSize*.2) if obj.ViewObject: if hasattr(obj.ViewObject,"DisplayMode"): if obj.ViewObject.DisplayMode == "3D": - offset = DraftVecUtils.neg(offset) + offset = offset.negative() if hasattr(obj.ViewObject,"TextPosition"): if obj.ViewObject.TextPosition == Vector(0,0,0): tbase = midpoint.add(offset) @@ -2644,7 +2765,7 @@ class _ViewProviderDimension(_ViewProviderDraft): self.onChanged(obj,"FontName") def updateData(self, obj, prop): - if not prop in ["Start","End","Dimline"]: + if not prop in ["Start","End","Dimline","DisplayMode","ExtLines","FontSize","Override"]: return from pivy import coin try: @@ -2662,7 +2783,7 @@ class _ViewProviderDimension(_ViewProviderDraft): if obj.LinkedVertices[1] == 1: v1 = c else: - v1 = c.add(DraftVecUtils.neg(bray)) + v1 = c.add(bray.negative()) v2 = c.add(bray) else: # linear linked dimension @@ -2673,12 +2794,12 @@ class _ViewProviderDimension(_ViewProviderDraft): p1,p2,p3,p4,tbase,norm,rot = self.calcGeom(obj) # print p1,p2,p3,p4,tbase,norm,rot if 'Override' in obj.ViewObject.PropertiesList: - text = str(obj.ViewObject.Override) + text = unicode(obj.ViewObject.Override).encode("latin1") dtext = getParam("dimPrecision") dtext = "%."+str(dtext)+"f" dtext = (dtext % p3.sub(p2).Length) if text: - text = text.replace("dim",dtext) + text = text.replace("$dim",dtext) else: text = dtext if hasattr(self,"text"): @@ -2717,6 +2838,7 @@ class _ViewProviderDimension(_ViewProviderDraft): self.font.size = vp.FontSize if hasattr(self,"font3d"): self.font3d.size = vp.FontSize*100 + self.updateData(vp.Object, prop) elif prop == "FontName": if hasattr(self,"font") and hasattr(self,"font3d"): self.font.name = self.font3d.name = str(vp.FontName) @@ -2730,7 +2852,7 @@ class _ViewProviderDimension(_ViewProviderDraft): else: if hasattr(self,"drawstyle"): self.drawstyle.lineWidth = vp.LineWidth - self.updateData(vp.Object, None) + self.updateData(vp.Object, prop) def getDisplayModes(self,obj): return ["2D","3D"] @@ -2944,7 +3066,7 @@ class _ViewProviderAngularDimension(_ViewProviderDraft): self.arc = arc self.selnode.addChild(self.arc) if 'Override' in obj.ViewObject.PropertiesList: - text = str(obj.ViewObject.Override) + text = unicode(obj.ViewObject.Override).encode("latin1") dtext = getParam("dimPrecision") dtext = "%."+str(dtext)+"f" if obj.LastAngle > obj.FirstAngle: @@ -3058,37 +3180,11 @@ class _Rectangle(_DraftObject): fp.Placement = plm class _ViewProviderRectangle(_ViewProviderDraft): - "A View Provider for the Rectangle object" - def __init__(self, vobj): + def __init__(self,vobj): _ViewProviderDraft.__init__(self,vobj) vobj.addProperty("App::PropertyFile","TextureImage", - "Base","Uses an image as a texture map") + "Pattern","Defines a texture image (overrides hatch patterns)") - def attach(self,vobj): - self.texture = None - self.Object = vobj.Object - - def onChanged(self, vp, prop): - from pivy import coin - from PyQt4 import QtCore - if prop == "TextureImage": - r = vp.RootNode - i = QtCore.QFileInfo(vp.TextureImage) - if i.exists(): - size = None - if ":/patterns" in vp.TextureImage: - size = 128 - im = loadTexture(vp.TextureImage, size) - if im: - self.texture = coin.SoTexture2() - self.texture.image = im - r.insertChild(self.texture,1) - else: - if self.texture: - r.removeChild(self.texture) - self.texture = None - return - class _Circle(_DraftObject): "The Circle object" @@ -3220,9 +3316,6 @@ class _Wire(_DraftObject): if fp.Base.Shape.isClosed(): shape = Part.Face(shape) fp.Shape = shape - p = [] - for v in shape.Vertexes: p.append(v.Point) - if fp.Points != p: fp.Points = p elif fp.Base and fp.Tool: if fp.Base.isDerivedFrom("Part::Feature") and fp.Tool.isDerivedFrom("Part::Feature"): if (not fp.Base.Shape.isNull()) and (not fp.Tool.Shape.isNull()): @@ -3290,6 +3383,7 @@ class _ViewProviderWire(_ViewProviderDraft): self.pt.addChild(col) self.pt.addChild(self.coords) self.pt.addChild(dimSymbol()) + _ViewProviderDraft.attach(self,obj) def updateData(self, obj, prop): if prop == "Points": @@ -3305,10 +3399,13 @@ class _ViewProviderWire(_ViewProviderDraft): rn.addChild(self.pt) else: rn.removeChild(self.pt) + _ViewProviderDraft.onChanged(self,vp,prop) return def claimChildren(self): - return [self.Object.Base,self.Object.Tool] + if hasattr(self.Object,"Base"): + return [self.Object.Base,self.Object.Tool] + return [] class _Polygon(_DraftObject): "The Polygon object" @@ -3365,16 +3462,13 @@ class _DrawingView(_DraftObject): def __init__(self, obj): _DraftObject.__init__(self,obj,"DrawingView") 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::PropertyFloat","LineWidth","View Style","The width of the lines inside this object") + obj.addProperty("App::PropertyFloat","FontSize","View Style","The size of the texts inside this object") obj.addProperty("App::PropertyLink","Source","Base","The linked object") - obj.addProperty("App::PropertyEnumeration","FillStyle","Drawing View","Shape Fill Style") - fills = ['shape color'] - if not hasattr(FreeCAD,"svgpatterns"): - loadSvgPatterns() - for f in FreeCAD.svgpatterns.keys(): - fills.append(f) - obj.FillStyle = fills + obj.addProperty("App::PropertyEnumeration","FillStyle","View Style","Shape Fill Style") + obj.addProperty("App::PropertyEnumeration","LineStyle","View Style","Line Style") + obj.FillStyle = ['shape color'] + svgpatterns().keys() + obj.LineStyle = ['Solid','Dashed','Dotted','Dashdot'] obj.LineWidth = 0.35 obj.FontSize = 12 @@ -3383,21 +3477,35 @@ class _DrawingView(_DraftObject): obj.ViewResult = self.updateSVG(obj) def onChanged(self, obj, prop): - if prop in ["X","Y","Scale","LineWidth","FontSize","FillStyle","Direction"]: + if prop in ["X","Y","Scale","LineWidth","FontSize","FillStyle","Direction","LineStyle"]: obj.ViewResult = self.updateSVG(obj) def updateSVG(self, obj): "encapsulates a svg fragment into a transformation node" - svg = getSVG(obj.Source,obj.Scale,obj.LineWidth,obj.FontSize,obj.FillStyle,obj.Direction) - result = '' - result += ' 1: + return False + if shape.Wires: + if shape.Wires[0].isClosed(): + return False + if shape.isClosed(): + return False + return True # edge functions ***************************************************************** @@ -400,8 +413,8 @@ def geom(edge,plac=FreeCAD.Placement()): c = edge.Curve.Center cu = Part.Circle(edge.Curve.Center,normal,edge.Curve.Radius) ref = plac.Rotation.multVec(Vector(1,0,0)) - a1 = DraftVecUtils.angle(v1.sub(c),ref,DraftVecUtils.neg(normal)) - a2 = DraftVecUtils.angle(v2.sub(c),ref,DraftVecUtils.neg(normal)) + a1 = DraftVecUtils.angle(v1.sub(c),ref,normal.negative()) + a2 = DraftVecUtils.angle(v2.sub(c),ref,normal.negative()) # direction check if edge.Curve.Axis.getAngle(normal) > 1: @@ -418,7 +431,7 @@ def mirror (point, edge): normPoint = point.add(findDistance(point, edge, False)) if normPoint: normPoint_point = Vector.sub(point, normPoint) - normPoint_refl = DraftVecUtils.neg(normPoint_point) + normPoint_refl = normPoint_point.negative() refl = Vector.add(normPoint, normPoint_refl) return refl else: @@ -438,7 +451,7 @@ def isClockwise(edge,ref=None): if not ref: ref = Vector(0,0,1) if n.getAngle(ref) > math.pi/2: - n = DraftVecUtils.neg(n) + n = n.negative() if DraftVecUtils.angle(v1,v2,n) < 0: return False if n.z < 0: @@ -721,7 +734,7 @@ def findMidpoint(edge): if len(edge.Vertexes) == 1: # Circle dv = first.sub(center) - dv = DraftVecUtils.neg(dv) + dv = dv.negative() return center.add(dv) axis = edge.Curve.Axis chord = last.sub(first) @@ -730,12 +743,12 @@ def findMidpoint(edge): ray = first.sub(center) apothem = ray.dot(perp) sagitta = radius - apothem - startpoint = Vector.add(first, DraftVecUtils.scale(chord,0.5)) + startpoint = Vector.add(first, chord.multiply(0.5)) endpoint = DraftVecUtils.scaleTo(perp,sagitta) return Vector.add(startpoint,endpoint) elif geomType(edge) == "Line": - halfedge = DraftVecUtils.scale(last.sub(first),.5) + halfedge = (last.sub(first)).multiply(.5) return Vector.add(first,halfedge) else: @@ -850,7 +863,8 @@ def getNormal(shape): if FreeCAD.GuiUp: import Draft vdir = Draft.get3DView().getViewDirection() - if n.getAngle(vdir) < 0.78: n = DraftVecUtils.neg(n) + if n.getAngle(vdir) < 0.78: + n = n.negative() return n def getRotation(v1,v2=FreeCAD.Vector(0,0,1)): @@ -1003,7 +1017,7 @@ def findDistance(point,edge,strict=False): center = edge.Curve.Center segment = center.sub(point) ratio = (segment.Length - edge.Curve.Radius) / segment.Length - dist = DraftVecUtils.scale(segment,ratio) + dist = segment.multiply(ratio) newpoint = Vector.add(point, dist) if (dist.Length == 0): return None @@ -1053,7 +1067,7 @@ def angleBisection(edge1, edge2): return Part.Line(origin,origin.add(dir)).toShape() else: diff = p3.sub(p1) - origin = p1.add(DraftVecUtils.scale(diff, 0.5)) + origin = p1.add(diff.multiply(0.5)) dir = p2.sub(p1); dir.normalize() return Part.Line(origin,origin.add(dir)).toShape() else: @@ -1857,8 +1871,8 @@ def circlefrom1Line2Points(edge, p1, p2): v2 = p2.sub(s) projectedDist = math.sqrt(abs(v1.dot(v2))) edgeDir = vec(edge); edgeDir.normalize() - projectedCen1 = Vector.add(s, DraftVecUtils.scale(edgeDir, projectedDist)) - projectedCen2 = Vector.add(s, DraftVecUtils.scale(edgeDir, -projectedDist)) + projectedCen1 = Vector.add(s, Vector(edgeDir).multiply(projectedDist)) + projectedCen2 = Vector.add(s, Vector(edgeDir).multiply(-projectedDist)) perpEdgeDir = edgeDir.cross(Vector(0,0,1)) perpCen1 = Vector.add(projectedCen1, perpEdgeDir) perpCen2 = Vector.add(projectedCen2, perpEdgeDir) @@ -1890,13 +1904,13 @@ def circleFrom2LinesRadius (edge1, edge2, radius): dist12 = radius / math.sin(ang12 * 0.5) dist21 = radius / math.sin(ang21 * 0.5) circles = [] - cen = Vector.add(int, DraftVecUtils.scale(vec(bis12), dist12)) + cen = Vector.add(int, vec(bis12).multiply(dist12)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, DraftVecUtils.scale(vec(bis12), -dist12)) + cen = Vector.add(int, vec(bis12).multiply(-dist12)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, DraftVecUtils.scale(vec(bis21), dist21)) + cen = Vector.add(int, vec(bis21).multiply(dist21)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, DraftVecUtils.scale(vec(bis21), -dist21)) + cen = Vector.add(int, vec(bis21).multiply(-dist21)) circles.append(Part.Circle(cen, NORM, radius)) return circles @@ -1954,15 +1968,15 @@ def circleFromPointLineRadius (point, edge, radius): if dist.Length == 0: segment = vec(edge) perpVec = DraftVecUtils.crossproduct(segment); perpVec.normalize() - normPoint_c1 = DraftVecUtils.scale(perpVec, radius) - normPoint_c2 = DraftVecUtils.scale(perpVec, -radius) + normPoint_c1 = Vector(perpVec).multiply(radius) + normPoint_c2 = Vector(perpVec).multiply(-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 = DraftVecUtils.scale(normPoint.sub(point), 0.5) + dummy = (normPoint.sub(point)).multiply(0.5) cen = point.add(dummy) circ = Part.Circle(cen, NORM, radius) if circ: @@ -1975,8 +1989,8 @@ def circleFromPointLineRadius (point, edge, radius): dist = math.sqrt(radius**2 - (radius - normDist)**2) centerNormVec = DraftVecUtils.scaleTo(point.sub(normPoint), radius) edgeDir = edge.Vertexes[0].Point.sub(normPoint); edgeDir.normalize() - center1 = centerNormVec.add(normPoint.add(DraftVecUtils.scale(edgeDir, dist))) - center2 = centerNormVec.add(normPoint.add(DraftVecUtils.scale(edgeDir, -dist))) + center1 = centerNormVec.add(normPoint.add(Vector(edgeDir).multiply(dist))) + center2 = centerNormVec.add(normPoint.add(Vector(edgeDir).multiply(-dist))) circles = [] if center1: circ = Part.Circle(center1, NORM, radius) @@ -2006,8 +2020,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, DraftVecUtils.scale(perpDir, dist)) - cen2 = Vector.add(mid, DraftVecUtils.scale(perpDir, -dist)) + cen1 = Vector.add(mid, Vector(perpDir).multiply(dist)) + cen2 = Vector.add(mid, Vector(perpDir).multiply(-dist)) circles = [] if cen1: circles.append(Part.Circle(cen1, norm, radius)) if cen2: circles.append(Part.Circle(cen2, norm, radius)) @@ -2252,12 +2266,12 @@ def findHomotheticCenterOfCircles(circle1, circle2): perpCenDir = cenDir.cross(Vector(0,0,1)); perpCenDir.normalize() # Get point on first circle - p1 = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, circle1.Curve.Radius)) + p1 = Vector.add(circle1.Curve.Center, Vector(perpCenDir).multiply(circle1.Curve.Radius)) centers = [] # Calculate inner homothetic center # Get point on second circle - p2_inner = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, -circle1.Curve.Radius)) + p2_inner = Vector.add(circle1.Curve.Center, Vector(perpCenDir).multiply(-circle1.Curve.Radius)) hCenterInner = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_inner, True, True) if hCenterInner: centers.append(hCenterInner) @@ -2265,7 +2279,7 @@ def findHomotheticCenterOfCircles(circle1, circle2): # 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, DraftVecUtils.scale(perpCenDir, circle1.Curve.Radius)) + p2_outer = Vector.add(circle1.Curve.Center, Vector(perpCenDir).multiply(circle1.Curve.Radius)) hCenterOuter = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_outer, True, True) if hCenterOuter: centers.append(hCenterOuter) @@ -2315,7 +2329,7 @@ def findRadicalAxis(circle1, circle2): k1 = (dist + (r1^2 - r2^2) / dist) / 2.0 #k2 = dist - k1 - K = Vector.add(cen1, DraftVecUtils.scale(cenDir, k1)) + K = Vector.add(cen1, cenDir.multiply(k1)) # K_ .. A point somewhere between K and J (actually with a distance of 1 unit from K). K_ = Vector,add(K, perpCenDir) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index ff4d9e0da..45d816428 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -978,13 +978,13 @@ class DraftToolBar: last = self.sourceCmd.node[0] else: last = self.sourceCmd.node[-1] - print "last:",last + #print "last:",last v = FreeCAD.Vector(numx,numy,numz) - print "orig:",v + #print "orig:",v if FreeCAD.DraftWorkingPlane: v = FreeCAD.Vector(numx,numy,numz) v = FreeCAD.DraftWorkingPlane.getGlobalRot(v) - print "rotated:",v + #print "rotated:",v numx = last.x + v.x numy = last.y + v.y numz = last.z + v.z @@ -1418,7 +1418,7 @@ class DraftToolBar: def changeEvent(self, event): if event.type() == QtCore.QEvent.LanguageChange: - print "Language changed!" + #print "Language changed!" self.ui.retranslateUi(self) def Activated(self): diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 9f5d98202..b8c0fe03a 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -258,7 +258,7 @@ class Snapper: elif (Draft.getType(obj) == "Structure") and not oldActive: # special snapping for struct: only to its base point (except when CTRL is pressed) if obj.Base: - for edge in o.Base.Shape.Edges: + for edge in obj.Base.Shape.Edges: snaps.extend(self.snapToEndpoints(edge)) snaps.extend(self.snapToMidpoint(edge)) snaps.extend(self.snapToPerpendicular(edge,lastpoint)) @@ -466,13 +466,13 @@ class Snapper: 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])]) + vecs.extend([ax[0],ax[0].negative()]) + vecs.extend([ax[1],ax[1].negative()]) else: v = DraftVecUtils.rotate(ax[0],math.radians(a),ax[2]) - vecs.extend([v,DraftVecUtils.neg(v)]) + vecs.extend([v,v.negative()]) v = DraftVecUtils.rotate(ax[1],math.radians(a),ax[2]) - vecs.extend([v,DraftVecUtils.neg(v)]) + vecs.extend([v,v.negative()]) for v in vecs: de = Part.Line(last,last.add(v)).toShape() np = self.getPerpendicular(de,point) @@ -1054,5 +1054,5 @@ if not hasattr(FreeCADGui,"Snapper"): if not hasattr(FreeCAD,"DraftWorkingPlane"): import WorkingPlane, Draft_rc FreeCAD.DraftWorkingPlane = WorkingPlane.plane() - print FreeCAD.DraftWorkingPlane + #print FreeCAD.DraftWorkingPlane FreeCADGui.addIconPath(":/icons") diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index fe67b50f9..089d80e63 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -232,12 +232,7 @@ class DraftTool: self.ui.sourceCmd = self self.ui.setTitle(name) self.ui.show() - try: - 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) - except: - pass + plane.setup() self.node = [] self.pos = [] self.constrain = None @@ -382,7 +377,7 @@ class SelectPlane(DraftTool): self.display('side') self.finish() elif arg == "currentView": - viewDirection = DraftVecUtils.neg(self.view.getViewDirection()) + viewDirection = self.view.getViewDirection().negative() plane.alignToPointAndAxis(Vector(0,0,0), viewDirection, self.offset) self.display(viewDirection) self.finish() @@ -780,10 +775,10 @@ class Rectangle(Creator): base = p1 if length < 0: length = -length - base = base.add(DraftVecUtils.neg(p1.sub(p4))) + base = base.add((p1.sub(p4)).negative()) if height < 0: height = -height - base = base.add(DraftVecUtils.neg(p1.sub(p2))) + base = base.add((p1.sub(p2)).negative()) self.commit(translate("draft","Create Plane"), ['plane = FreeCAD.ActiveDocument.addObject("Part::Plane","Plane")', 'plane.Length = '+str(length), @@ -915,7 +910,7 @@ class Arc(Creator): if self.center and DraftVecUtils.dist(self.point,self.center) > 0: viewdelta = DraftVecUtils.project(self.point.sub(self.center), plane.axis) if not DraftVecUtils.isNull(viewdelta): - self.point = self.point.add(DraftVecUtils.neg(viewdelta)) + self.point = self.point.add(viewdelta.negative()) if (self.step == 0): # choose center if hasMod(arg,MODALT): if not self.altdown: @@ -1202,7 +1197,7 @@ class Polygon(Creator): if self.center and DraftVecUtils.dist(self.point,self.center) > 0: viewdelta = DraftVecUtils.project(self.point.sub(self.center), plane.axis) if not DraftVecUtils.isNull(viewdelta): - self.point = self.point.add(DraftVecUtils.neg(viewdelta)) + self.point = self.point.add(viewdelta.negative()) if (self.step == 0): # choose center if hasMod(arg,MODALT): if not self.altdown: @@ -1356,7 +1351,7 @@ class Ellipse(Creator): p1 = self.node[0] p3 = self.node[-1] diagonal = p3.sub(p1) - halfdiag = DraftVecUtils.scale(diagonal,0.5) + halfdiag = Vector(diagonal).multiply(0.5) center = p1.add(halfdiag) p2 = p1.add(DraftVecUtils.project(diagonal, plane.v)) p4 = p1.add(DraftVecUtils.project(diagonal, plane.u)) @@ -1452,6 +1447,7 @@ class Text(Creator): self.ui.sourceCmd = self self.ui.pointUi(name) self.call = self.view.addEventCallback("SoEvent",self.action) + self.active = True self.ui.xValue.setFocus() self.ui.xValue.selectAll() msg(translate("draft", "Pick location point:\n")) @@ -1471,7 +1467,7 @@ class Text(Creator): for l in self.text: if len(tx) > 1: tx += ',' - tx += '"'+str(l)+'"' + tx += '"'+str(unicode(l).encode("utf8"))+'"' tx += ']' self.commit(translate("draft","Create Text"), ['import Draft', @@ -1485,10 +1481,13 @@ class Text(Creator): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection - self.point,ctrlPoint,info = getPoint(self,arg) + if self.active: + self.point,ctrlPoint,info = getPoint(self,arg) elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): if self.point: + self.active = False + FreeCADGui.Snapper.off() self.node.append(self.point) self.ui.textUi() self.ui.textValue.setFocus() @@ -1660,7 +1659,7 @@ class Dimension(Creator): rad = self.edges[0].Curve.Radius baseray = self.point.sub(cen) v2 = DraftVecUtils.scaleTo(baseray,rad) - v1 = DraftVecUtils.neg(v2) + v1 = v2.negative() if shift: self.node = [cen,cen.add(v2)] self.arcmode = "radius" @@ -1701,7 +1700,7 @@ class Dimension(Creator): if (not self.node) and (not self.support): self.support = getSupport(arg) if hasMod(arg,MODALT) and (len(self.node)<3): - print "snapped: ",self.info + #print "snapped: ",self.info if self.info: ob = self.doc.getObject(self.info['Object']) if 'Edge' in self.info['Component']: @@ -1736,7 +1735,7 @@ class Dimension(Creator): self.node[3], True,True) if c: - print "centers:",c + #print "centers:",c self.center = c[0] self.arctrack.setCenter(self.center) self.arctrack.on() @@ -1766,7 +1765,7 @@ class Dimension(Creator): # for unlinked arc mode: # if self.arcmode: # v = self.node[1].sub(self.node[0]) - # v = DraftVecUtils.scale(v,0.5) + # v.multiply(0.5) # cen = self.node[0].add(v) # self.node = [self.node[0],self.node[1],cen] self.createObject() @@ -1805,6 +1804,7 @@ class ShapeString(Creator): self.text = '' self.ui.sourceCmd = self self.ui.pointUi(name) + self.active = True self.call = self.view.addEventCallback("SoEvent",self.action) self.ui.xValue.setFocus() self.ui.xValue.selectAll() @@ -1813,7 +1813,7 @@ class ShapeString(Creator): def createObject(self): "creates object in the current doc" -# print "debug: D_T ShapeString.createObject type(self.SString): " str(type(self.SString)) + #print "debug: D_T ShapeString.createObject type(self.SString): " str(type(self.SString)) # temporary code #import platform #if not (platform.system() == 'Linux'): @@ -1842,8 +1842,8 @@ class ShapeString(Creator): 'ss.Support='+sup]) except Exception as e: msg("Draft_ShapeString: error delaying commit", "error") - print type(e) - print e.args + #print type(e) + #print e.args self.finish() def action(self,arg): @@ -1852,11 +1852,14 @@ class ShapeString(Creator): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection - self.point,ctrlPoint,info = getPoint(self,arg) + if self.active: + self.point,ctrlPoint,info = getPoint(self,arg) elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): if self.point: self.node.append(self.point) + self.active = False + FreeCADGui.Snapper.off() self.ui.SSUi() def numericInput(self,numx,numy,numz): @@ -2148,7 +2151,7 @@ class Rotate(Modifier): if self.center and DraftVecUtils.dist(self.point,self.center): viewdelta = DraftVecUtils.project(self.point.sub(self.center), plane.axis) if not DraftVecUtils.isNull(viewdelta): - self.point = self.point.add(DraftVecUtils.neg(viewdelta)) + self.point = self.point.add(viewdelta.negative()) if self.extendedCopy: if not hasMod(arg,MODALT): self.step = 3 @@ -2327,7 +2330,7 @@ class Offset(Modifier): if dist: self.ghost.on() if self.mode == "Wire": - d = DraftVecUtils.neg(dist[0]) + d = dist[0].negative() v1 = DraftGeomUtils.getTangent(self.shape.Edges[0],self.point) v2 = DraftGeomUtils.getTangent(self.shape.Edges[dist[1]],self.point) a = -DraftVecUtils.angle(v1,v2) @@ -2335,7 +2338,7 @@ class Offset(Modifier): occmode = self.ui.occOffset.isChecked() self.ghost.update(DraftGeomUtils.offsetWire(self.shape,self.dvec,occ=occmode),forceclosed=occmode) elif self.mode == "BSpline": - d = DraftVecUtils.neg(dist[0]) + d = dist[0].negative() e = self.shape.Edges[0] basetan = DraftGeomUtils.getTangent(e,self.point) self.npts = [] @@ -2370,7 +2373,7 @@ 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 + #print "offset:npts=",self.npts self.commit(translate("draft","Offset"), ['import Draft', 'Draft.offset(FreeCAD.ActiveDocument.'+self.sel.Name+','+DraftVecUtils.toString(self.ntps)+',copy='+str(copymode)+')']) @@ -2661,7 +2664,7 @@ class Trimex(Modifier): if real: if self.force: ray = self.newpoint.sub(v1) - ray = DraftVecUtils.scale(ray,self.force/ray.Length) + ray.multiply(self.force/ray.Length) self.newpoint = Vector.add(v1,ray) newedges.append(Part.Line(self.newpoint,v2).toShape()) else: @@ -2673,7 +2676,7 @@ class Trimex(Modifier): self.ui.labelRadius.setText("Angle") dist = math.degrees(-ang2) # if ang1 > ang2: ang1,ang2 = ang2,ang1 - print "last calculated:",math.degrees(-ang1),math.degrees(-ang2) + #print "last calculated:",math.degrees(-ang1),math.degrees(-ang2) ghost.setEndAngle(-ang2) ghost.setStartAngle(-ang1) ghost.setCenter(center) @@ -2718,7 +2721,7 @@ class Trimex(Modifier): "trims the actual object" if self.extrudeMode: delta = self.extrude(self.shift,real=True) - print "delta",delta + #print "delta",delta self.doc.openTransaction("Extrude") obj = Draft.extrude(self.obj,delta) self.doc.commitTransaction() @@ -2764,8 +2767,8 @@ class Trimex(Modifier): self.obj.Z1 = p[0].z elif Draft.getType(self.obj) == "Circle": angles = self.ghost[0].getAngles() - print "original",self.obj.FirstAngle," ",self.obj.LastAngle - print "new",angles + #print "original",self.obj.FirstAngle," ",self.obj.LastAngle + #print "new",angles if angles[0] > angles[1]: angles = (angles[1],angles[0]) self.obj.FirstAngle = angles[0] self.obj.LastAngle = angles[1] @@ -2870,7 +2873,7 @@ class Scale(Modifier): # calculate a correction factor depending on the scaling center corr = Vector(self.node[0].x,self.node[0].y,self.node[0].z) corr.scale(delta.x,delta.y,delta.z) - corr = DraftVecUtils.neg(corr.sub(self.node[0])) + corr = (corr.sub(self.node[0])).negative() self.ghost.move(corr) self.ghost.on() if self.extendedCopy: @@ -2948,14 +2951,19 @@ class Drawing(Modifier): 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Drawing", "Drawing"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Drawing", "Puts the selected objects on a Drawing sheet.")} - def IsActive(self): - if Draft.getSelection(): - return True - else: - return False - def Activated(self): Modifier.Activated(self,"Drawing") + if not Draft.getSelection(): + self.ghost = None + self.ui.selectUi() + msg(translate("draft", "Select an object to project\n")) + self.call = self.view.addEventCallback("SoEvent",selectObject) + else: + self.proceed() + + def proceed(self): + if self.call: + self.view.removeEventCallback("SoEvent",self.call) sel = Draft.getSelection() if not sel: self.page = self.createDefaultPage() @@ -3030,19 +3038,25 @@ class Edit(Modifier): 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Edit", "Edit"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Edit", "Edits the active object")} - def IsActive(self): - if Draft.getSelection(): - self.selection = Draft.getSelection() - if "Proxy" in self.selection[0].PropertiesList: - if hasattr(self.selection[0].Proxy,"Type"): - return True - return False - def Activated(self): if self.running: self.finish() else: Modifier.Activated(self,"Edit") + if Draft.getSelection(): + self.selection = Draft.getSelection() + if "Proxy" in self.selection[0].PropertiesList: + if hasattr(self.selection[0].Proxy,"Type"): + self.proceed() + return + self.ghost = None + self.ui.selectUi() + msg(translate("draft", "Select a Draft object to edit\n")) + self.call = self.view.addEventCallback("SoEvent",selectObject) + + def proceed(self): + if self.call: + self.view.removeEventCallback("SoEvent",self.call) self.ui.editUi() if self.doc: self.obj = Draft.getSelection() @@ -3075,9 +3089,11 @@ 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 = DraftVecUtils.neg(self.bx) + if self.obj.Length < 0: + self.bx = self.bx.negative() self.by = v[2].Point.sub(v[1].Point) - if self.obj.Height < 0: self.by = DraftVecUtils.neg(self.by) + if self.obj.Height < 0: + self.by = self.by.negative() elif Draft.getType(self.obj) == "Polygon": self.editpoints.append(self.obj.Placement.Base) self.editpoints.append(self.obj.Shape.Vertexes[0].Point) @@ -3442,8 +3458,6 @@ class WireToBSpline(Modifier): Draft.formatObject(n,self.selection[0]) else: self.finish() - def finish(self): - Modifier.finish(self) class SelectGroup(): @@ -3478,20 +3492,27 @@ class SelectGroup(): FreeCADGui.Selection.addSelection(child) -class Shape2DView(): +class Shape2DView(Modifier): "The Shape2DView FreeCAD command definition" + def GetResources(self): return {'Pixmap' : 'Draft_2DShapeView', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Shape2DView", "Shape 2D view"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Shape2DView", "Creates Shape 2D views of selected objects")} - - def IsActive(self): - if FreeCADGui.Selection.getSelection(): - return True - else: - return False def Activated(self): + Modifier.Activated(self) + if not Draft.getSelection(): + if self.ui: + self.ui.selectUi() + msg(translate("draft", "Select an object to project\n")) + self.call = self.view.addEventCallback("SoEvent",selectObject) + else: + self.proceed() + + def proceed(self): + if self.call: + self.view.removeEventCallback("SoEvent",self.call) faces = [] objs = [] sel = FreeCADGui.Selection.getSelectionEx() @@ -3500,28 +3521,37 @@ class Shape2DView(): for e in s.SubElementNames: if "Face" in e: faces.append(int(e[4:])-1) - print objs,faces + #print objs,faces if len(objs) == 1: if faces: Draft.makeShape2DView(objs[0],facenumbers=faces) return for o in objs: Draft.makeShape2DView(o) + self.finish() -class Draft2Sketch(): + +class Draft2Sketch(Modifier): "The Draft2Sketch FreeCAD command definition" + def GetResources(self): return {'Pixmap' : 'Draft_Draft2Sketch', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Draft2Sketch", "Draft to Sketch"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Shape2DView", "Convert bidirectionally between Draft and Sketch objects")} - def IsActive(self): - if Draft.getSelection(): - return True - else: - return False - def Activated(self): + Modifier.Activated(self) + if not Draft.getSelection(): + if self.ui: + self.ui.selectUi() + msg(translate("draft", "Select an object to convert\n")) + self.call = self.view.addEventCallback("SoEvent",selectObject) + else: + self.proceed() + + def proceed(self): + if self.call: + self.view.removeEventCallback("SoEvent",self.call) sel = Draft.getSelection() allSketches = True allDraft = True @@ -3554,26 +3584,37 @@ class Draft2Sketch(): if (len(obj.Shape.Wires) == 1) or (len(obj.Shape.Edges) == 1): Draft.makeSketch(obj,autoconstraints=False) FreeCAD.ActiveDocument.commitTransaction() + self.finish() - -class Array(): + +class Array(Modifier): "The Shape2DView FreeCAD command definition" + def GetResources(self): return {'Pixmap' : 'Draft_Array', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Array", "Array"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Array", "Creates a polar or rectangular array from a selected object")} - def IsActive(self): - if len(Draft.getSelection()) == 1: - return True - else: - return False - def Activated(self): - obj = Draft.getSelection()[0] - FreeCAD.ActiveDocument.openTransaction("Array") - Draft.makeArray(obj,Vector(1,0,0),Vector(0,1,0),2,2) - FreeCAD.ActiveDocument.commitTransaction() + Modifier.Activated(self) + if not Draft.getSelection(): + if self.ui: + self.ui.selectUi() + msg(translate("draft", "Select an object to array\n")) + self.call = self.view.addEventCallback("SoEvent",selectObject) + else: + self.proceed() + + def proceed(self): + if self.call: + self.view.removeEventCallback("SoEvent",self.call) + if Draft.getSelection(): + obj = Draft.getSelection()[0] + FreeCAD.ActiveDocument.openTransaction("Array") + Draft.makeArray(obj,Vector(1,0,0),Vector(0,1,0),2,2) + FreeCAD.ActiveDocument.commitTransaction() + self.finish() + class Point: "this class will create a vertex after the user clicks a point on the screen" @@ -3594,7 +3635,7 @@ class Point: self.stack = [] 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) + plane.setup(self.view.getViewDirection().negative(), Vector(0,0,0), upv) self.point = None # adding 2 callback functions self.callbackClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.click) @@ -3630,19 +3671,6 @@ class Point: todo.delayCommit(commitlist) FreeCADGui.Snapper.off() -class ToggleSnap(): - "The ToggleSnap FreeCAD command definition" - - def GetResources(self): - 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.toggle() - class ShowSnapBar(): "The ShowSnapBar FreeCAD command definition" @@ -3655,7 +3683,7 @@ class ShowSnapBar(): FreeCADGui.Snapper.show() -class Draft_Clone(): +class Draft_Clone(Modifier): "The Draft Clone command definition" def GetResources(self): @@ -3665,17 +3693,24 @@ class Draft_Clone(): 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Clone", "Clones the selected object(s)")} def Activated(self): + Modifier.Activated(self) + if not Draft.getSelection(): + if self.ui: + self.ui.selectUi() + msg(translate("draft", "Select an object to clone\n")) + self.call = self.view.addEventCallback("SoEvent",selectObject) + else: + self.proceed() + + def proceed(self): + if self.call: + self.view.removeEventCallback("SoEvent",self.call) 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 + self.finish() class ToggleGrid(): @@ -3723,12 +3758,12 @@ class Heal(): class Draft_Snap_Lock(): def GetResources(self): return {'Pixmap' : 'Snap_Lock', + 'Accel' : "Shift+S", 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Lock", "Toggle On/Off"), 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Snap_Lock", "Activates/deactivates all snap tools at once")} def Activated(self): if hasattr(FreeCADGui,"Snapper"): if hasattr(FreeCADGui.Snapper,"masterbutton"): - print FreeCADGui.Snapper.masterbutton FreeCADGui.Snapper.masterbutton.toggle() class Draft_Snap_Midpoint(): @@ -3911,7 +3946,6 @@ FreeCADGui.addCommand('Draft_ToggleDisplayMode',ToggleDisplayMode()) 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()) diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index 960f281d2..7bbb7882a 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -272,8 +272,8 @@ class dimTracker(Tracker): p2 = p1 p3 = p4 else: - p2 = p1.add(DraftVecUtils.neg(proj)) - p3 = p4.add(DraftVecUtils.neg(proj)) + p2 = p1.add(proj.negative()) + p3 = p4.add(proj.negative()) points = [DraftVecUtils.tup(p1),DraftVecUtils.tup(p2),DraftVecUtils.tup(p3),DraftVecUtils.tup(p4)] self.coords.point.setValues(0,4,points) @@ -743,7 +743,7 @@ 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(DraftVecUtils.scale(lvec,0.5)) + bp = bp.add(lvec.multiply(0.5)) bp = bp.add(DraftVecUtils.scaleTo(normal,self.cube.depth.getValue()/2)) self.pos(bp) diff --git a/src/Mod/Draft/Draft_rc.py b/src/Mod/Draft/Draft_rc.py index 7375cb072..53977b3cf 100644 --- a/src/Mod/Draft/Draft_rc.py +++ b/src/Mod/Draft/Draft_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Sat Jul 6 16:32:11 2013 -# by: The Resource Compiler for PyQt (Qt v4.8.4) +# Created: Sat Aug 24 18:47:43 2013 +# by: The Resource Compiler for PyQt (Qt v4.8.5) # # WARNING! All changes made in this file will be lost! @@ -41485,434 +41485,515 @@ qt_resource_data = "\ \x00\x6c\x00\x6b\x00\x79\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\x09\xb5\ +\x00\x00\x0b\x42\ \x00\ -\x00\x4b\x27\x78\x9c\xed\x5c\x5b\x73\xdb\xb6\x12\x7e\xf7\xaf\xc0\ -\xe8\xe1\x34\xed\xb8\x96\xe5\x6b\x92\x23\xab\x93\xd8\x71\x92\x4e\ -\xd2\xba\x95\x9b\x9c\x37\x0f\x44\x42\x22\x6a\x92\x50\x01\xd0\x92\ -\xfa\xeb\xcf\x2e\x00\x8a\x14\x49\xdd\x2d\xd9\xc9\x68\xc6\x33\x16\ -\x01\x10\xbb\x58\x7e\xbb\xd8\x5d\x2c\xd9\xfc\x65\x18\x85\xe4\x81\ -\x49\xc5\x45\x7c\x51\x6b\x1c\x1c\xd6\x08\x8b\x3d\xe1\xf3\xb8\x77\ -\x51\xfb\xeb\xf6\xfa\xe7\x97\xb5\x5f\x5a\x7b\xcd\x84\x67\x83\x4e\ -\x60\x50\x6b\x8f\x34\xbd\x90\x2a\xd5\x7a\x9f\xf0\xd7\xaf\xaf\x38\ -\x0d\x45\x0f\xfe\x87\xbd\x36\xd3\x1a\x6e\x56\x57\x92\x76\x75\xb3\ -\x6e\x07\xc1\xe8\x01\xf7\x7b\x4c\x13\x73\x7d\x51\xfb\xe3\xab\xb9\ -\xac\x91\x98\x46\xec\xa2\x36\x73\x12\x24\x46\x9a\x7d\x29\xfa\x4c\ -\xea\x91\xbb\xa3\xc7\x44\xc4\xb4\x1c\x99\x4e\xd2\x94\xcc\xd3\xe6\ -\x17\x69\x0e\x5b\x87\xcd\xfa\xd0\x5d\x8c\xf0\x62\xe4\x2e\x80\x05\ -\x1d\xb4\x4e\xcf\x4f\x9b\x75\xfb\xd3\x36\x07\x8c\xf7\x02\xdd\x3a\ -\x3b\x7a\xd5\xac\xbb\xdf\x66\xce\x7a\x3a\x69\xb3\x9e\x12\xaf\xe2\ -\x64\xc0\x63\x5f\x0c\x6e\xb9\x0e\x99\x63\x46\x69\x09\xcc\xb7\x3e\ -\x46\x7d\x21\x75\xfd\xdd\x10\xff\x35\xeb\xae\xb5\x3c\x5f\x48\x47\ -\x22\xc9\x24\xf3\xe5\xad\x18\x7e\x32\x4d\x6e\xba\x02\x3d\xd5\xa7\ -\x1e\x4c\x54\x73\xdc\xc7\x49\xd4\x61\xb2\x75\xd6\xac\xbb\x5f\x96\ -\xf7\x3c\x85\xd2\x14\x11\x95\x3d\x1e\x17\x66\x78\x35\x73\x06\xae\ -\x59\x94\x89\x31\xff\x24\xdf\x4b\x91\xf4\x81\xe7\xf1\xb3\x74\xd7\ -\x8d\x23\x47\xa0\x44\x5e\x67\xb2\xca\x89\xeb\xea\x7f\xd7\xa4\x2b\ -\x64\x44\x35\x11\x7d\x0d\x48\x53\x79\x99\x95\x59\x9a\x2f\xb9\xb9\ -\xc2\x9b\x2a\xbf\x2a\x6a\xb3\xa5\x38\x55\x90\xd5\x53\x65\xe2\xac\ -\x58\xc7\x87\xf2\x3a\x16\x58\xc9\x8c\xb5\x54\xb1\x30\x7f\x3d\xd9\ -\x84\x87\x0b\x4e\x38\xb1\xaa\x32\x52\x3e\xd1\x0e\x0b\x53\x98\x68\ -\x36\xd4\xa6\xa1\x71\x77\x9c\xa7\x59\x46\x0b\x0c\x9c\x18\x50\x50\ -\x30\xa2\xf4\x28\x64\x05\xac\x4c\xe5\x91\x18\xdd\x07\xae\xf2\x4b\ -\x99\xe4\x7b\xce\x32\x8c\xad\xba\x91\xac\x7b\x29\xa2\x8e\xc8\x01\ -\xbf\x87\x1d\x7d\xe8\xf0\xb0\xa3\x03\x1d\x33\x97\x25\x44\x78\xcb\ -\xfb\xd5\x2b\xbb\x0d\xb8\x22\xf0\xa7\x03\x46\xc0\xcc\x05\xc2\x27\ -\x5e\x20\x84\x62\x3e\xaa\x08\xe1\x66\xe1\x30\x90\xc0\x85\x96\x34\ -\x56\x21\x35\x97\xa8\x43\xa2\xf3\x37\xd8\x2d\xe2\x89\x10\x47\xc6\ -\x5a\x90\x6b\xc9\xd8\xe5\x9b\xab\x03\xb2\xf7\xb1\xeb\xda\x23\xda\ -\xef\xe3\x0d\x40\xc3\x4d\xbc\x4f\x00\x70\x24\x4a\x94\x76\x2d\x84\ -\x16\xc6\x76\x79\xc8\xa0\x29\xd6\x94\xc7\x78\x4d\x33\xd2\x22\x26\ -\x9a\x76\xa0\x5b\x07\xa0\xbe\x03\x1e\x86\x38\x10\x76\x0c\xc7\x87\ -\xb2\x8c\x84\x3c\x66\xc6\xf2\xaa\x83\xbd\x85\x1f\x58\x49\x72\x5e\ -\x22\x25\x8b\xf5\xc7\xd8\x67\xc3\x82\xf8\xa6\xe3\x75\xd1\xc9\xf1\ -\xf9\xbd\x8b\x71\x63\x01\x5c\xf9\x8a\xe9\x8b\xda\x61\x81\x88\xe7\ -\x18\xf7\x87\x5d\x07\x3d\x6f\xd5\xa5\x20\xb5\x1b\xaa\x83\xf9\xc4\ -\x3e\x0b\xbf\x9e\x6e\xa9\x0b\x53\x2b\x00\x79\x11\xdd\x1a\x43\xf0\ -\x37\x11\x33\xf2\xa2\x4b\x95\x66\x4a\xff\x58\xf5\xb4\xa6\x51\xad\ -\x17\xc9\xae\xc5\xc7\x5f\x80\x44\x9f\x75\x69\x12\xa6\x98\xa6\xb1\ -\x9f\x21\xe9\xe9\x18\xfb\x5d\x72\x30\x97\x34\x7c\x5e\x5c\x5d\x8e\ -\x55\x16\x6c\x45\x5e\xe5\x9e\x90\x25\xc9\xa8\x66\xa4\x4f\x25\x45\ -\x97\x8d\x7b\xce\x44\x15\xf7\xf7\xed\xb3\xd4\xbe\x67\xda\x0b\xd8\ -\x5a\x8c\xcc\xdd\x4f\x9a\x75\xbb\xbd\x67\xde\x40\xbe\x7b\x61\x4f\ -\xc0\x2d\x2a\x10\x92\xff\x8b\x36\x38\x2c\x7b\x08\xcb\x6c\xbf\x21\ -\x5e\xdc\x9d\xaf\xb8\xf3\x7e\xa6\x43\xd2\xee\x23\xb6\x48\x9b\xf5\ -\x22\xb0\xc6\x4f\xb0\xff\xb6\x61\x57\xaa\xda\x7e\x15\xb4\xc3\xee\ -\x7b\x77\x34\x73\x71\x11\x1d\xf2\x28\x89\xda\xfc\x5f\x56\x5c\x23\ -\x34\x15\x60\x63\xc3\x85\xb3\xc3\x89\xc0\x61\xdc\xeb\x82\x86\xc6\ -\xd9\xf9\xf9\xf9\x51\xe3\x74\x22\x8a\xc8\x16\x59\x9c\x76\xb1\x1d\ -\x62\xa6\x9b\xf0\x35\x60\x31\x61\xc3\xd4\x19\x50\xe6\x89\x28\x54\ -\x7b\x70\x04\xf6\xd1\x7b\x18\x11\x2a\x99\xdd\xa7\xd1\xb7\x06\x9b\ -\xc0\x63\xd2\x17\xe1\xc8\x8c\x3c\x20\xc6\xd1\x78\xa0\x61\xc2\xc6\ -\xee\x86\x95\x0b\x09\x59\xdc\xd3\x01\x11\x5d\xc2\xa8\x67\xfe\x63\ -\x6f\x7a\x2b\x51\xf6\xb1\xc3\x14\xe0\x53\x1c\x1a\x5a\xb1\x19\x31\ -\x08\x04\xf8\x01\x96\x15\x33\xa7\x51\x35\x9f\x50\x05\x0e\x03\xf0\ -\x4d\x51\x34\xe9\xed\x07\xab\x7b\x01\x86\xe9\xea\xed\xff\x74\x2b\ -\xdb\x3f\x08\xca\x09\x3c\xd5\x80\xe7\xe9\x06\x3c\xb1\x81\x9a\xf0\ -\xee\x97\x37\x51\x2b\x1a\xa8\xcb\x92\xe7\xfa\x04\x06\xea\x1a\xc8\ -\x5e\x1a\x5f\x5a\x96\x8c\x14\xb2\xe4\xb9\xbe\x99\x66\x0a\x7c\xed\ -\x25\xcd\xd4\xf1\xe1\x6c\x3b\x75\xb8\x3d\x03\x75\x1b\xb0\xaa\x20\ -\xa2\x5b\x08\x5b\xc0\x93\x9e\x12\x27\xac\x6e\x1f\x96\x73\xe4\x1d\ -\x7b\x16\x28\x3b\x3d\xae\xd2\xe3\xf3\xc5\xf5\x38\x0b\x91\x03\xe6\ -\xdd\x57\x86\xc8\xd8\x31\x7f\x93\x9e\x09\x2e\x8e\x5b\x92\x8d\x93\ -\x93\xd8\x4c\x88\x51\x2c\xda\x04\x55\x8f\xcc\x3f\x32\x10\xf1\x0f\ -\x9a\x74\x98\x8b\x98\x99\xbf\x3a\x9e\xe6\xa6\x21\x2c\x45\x0c\x03\ -\x7c\x0e\xfb\x81\xaa\xc8\x60\x2d\x09\xa5\xc5\xe1\x8b\xb4\x77\xb8\ -\xad\xc6\xed\xd1\x46\x70\x3b\x27\x67\xb5\x20\x6e\xc7\xa8\xed\x53\ -\xb8\x9d\x60\x4e\x8f\xa5\xd1\x91\x4d\xa3\xe4\xb0\x0b\x7e\x9d\xd8\ -\x20\x7e\xad\x64\xb7\x06\x59\x4b\x6e\x07\xda\x6a\xd0\x9e\x6c\x04\ -\xb4\x73\xc2\xbd\x59\xa0\x35\x93\x3b\xdc\x76\x4d\xaa\x70\x40\x63\ -\x6d\x3c\xfe\x58\xc4\x3f\xe3\x0c\x3e\xe9\x84\xc2\xbb\x57\xe4\x45\ -\x87\xf5\x78\x6c\x72\x84\x03\x0e\x31\x04\x25\x3f\xfd\x88\x41\xc9\ -\xf6\xb0\xfc\x93\xe5\x64\x5b\x58\x56\x9a\xca\x94\xe2\x0e\xcf\x55\ -\x78\x7e\xb9\x11\x3c\x9f\x3e\xae\x11\x4e\x0d\x6f\x57\x8a\xc8\x20\ -\x5b\xc1\x3c\x68\x17\x99\xcc\xac\xf1\xdf\x02\x9c\x53\xdf\xfa\xa9\ -\xe6\x21\x90\xb7\xe6\xc9\x83\xe7\x91\x48\x83\x79\xbc\xd3\xe7\x10\ -\x1b\xd2\x11\x31\xf9\x53\xb9\x4f\x3a\x20\xae\x88\xde\xbb\x6e\x8c\ -\xae\x95\x82\xc0\x5a\xf1\x70\x44\x98\xcf\x4d\xf2\x7c\x13\xfa\x60\ -\x0e\xe3\xd2\x25\x18\x9e\xb7\xa8\x19\x3d\x24\xfe\xc9\xd0\xde\xe9\ -\x45\xb5\x5e\x9c\x6e\x44\x2f\x5e\xad\xae\x17\x78\x42\x94\xea\x43\ -\x57\x32\xe6\x51\xdf\x42\x1f\x9e\x38\xda\x70\x84\x3f\x26\xe2\x79\ -\xec\x71\x9f\xc1\xcf\x54\x69\x0c\xb8\x06\x5c\x62\x56\xe9\x2d\x1b\ -\x50\xc9\xf6\xad\x86\x79\x14\x0f\x87\xee\xf1\x3c\x69\x10\x40\x7c\ -\x75\x70\xb0\x46\xd6\x67\x3a\xd2\x7f\x05\x96\x48\x5a\x15\xb0\x15\ -\x78\xa3\x28\x32\x82\x3b\x7c\x57\xe1\xfb\x6c\x13\xf8\x5e\x0b\xdd\ -\x25\xab\x4f\x01\xdc\x29\x88\x73\xa7\x9b\x5d\x70\xc5\x33\xab\x6f\ -\x93\xac\x36\x8d\x79\xec\x9b\x34\xa8\x19\xb0\x09\x24\xdb\x82\x11\ -\x72\x7c\x35\x66\x0b\x88\xa6\x14\x49\xc4\xd4\x94\x13\x8b\x8d\xe4\ -\x45\x80\xda\x0e\xdb\xd5\xd8\x6e\x6c\xc6\x49\x6f\xac\x91\x12\xa9\ -\xc2\x37\xba\x23\x63\xf8\x16\x63\x4b\x98\x1c\x1b\xec\x59\x21\x70\ -\x11\x62\xe9\x00\xde\xe1\x0e\xd9\xc9\x03\x67\x03\xf0\x66\xb0\x14\ -\x8a\x8b\x78\x13\x70\xbf\xb1\x2c\x94\x79\xa4\xa1\x00\x3d\x7c\x6c\ -\x46\x96\xc3\xbf\x93\xcf\x4e\x05\xa6\xa8\x40\x63\x23\x2a\xf0\xf2\ -\x71\x35\x20\x0b\x3a\x6d\x52\x10\xb1\x8f\x8c\x19\x17\x5f\xd3\xd8\ -\xa7\xd2\x77\xbe\x3c\x8e\x20\x98\x08\x87\xbb\x62\x70\xdd\xc1\xfb\ -\x71\x27\x5f\xd8\x68\x4f\xd4\x02\xfa\xc0\xf0\x18\x0d\x5b\xb1\xe0\ -\xc6\x17\x5e\xb2\xd4\x11\xe8\x12\xca\x81\xd5\x0f\x63\x16\xbb\x20\ -\x7a\xcb\x87\x49\xa0\xe3\x62\xb6\xa5\x07\x6d\xed\xe3\x11\xc4\x4e\ -\x0f\xa6\xe8\xc1\x66\x92\x8c\x8d\xc3\xc7\x55\x84\x80\x9a\x72\x87\ -\xb1\xf5\x77\x35\x5a\x69\x38\xab\x40\x51\x42\x66\x9d\xf8\x0d\x26\ -\x67\x0c\x17\xa4\x23\x12\x44\x35\x67\xc6\xbd\x59\x93\xe6\x12\x60\ -\xb6\xc6\xe0\x6a\xd8\xfd\x40\x5d\xed\xc7\x0e\xd2\x95\x90\x5e\xe2\ -\xdc\x76\x19\x48\x37\x1e\x17\xd2\x03\xac\x3b\x18\x17\x34\x58\xdb\ -\x0c\x81\x26\x1e\x1e\x62\xd9\x18\xe6\x6a\x5c\x21\x44\x0a\x7a\xf0\ -\x26\x7c\x26\xad\x2b\xef\x85\xa6\xa6\xd2\xa0\xcf\xe6\x2a\x8d\xef\ -\x23\x24\xba\x19\x64\x6a\xdd\xd4\xba\x8a\xf0\xa7\x61\x21\xc7\xb6\ -\x21\xbd\x26\xb9\x25\x74\xc0\x8a\xe0\xc6\x91\xff\x6a\xe9\x7e\x8f\ -\x6a\x30\xd9\x39\x31\x57\x6e\xdc\x4a\xc5\xed\x77\x4b\x96\xb7\xb7\ -\xbf\xbc\x7f\xbc\xf2\x76\x47\x29\x77\x0a\xf5\xad\x17\xba\xa7\x2b\ -\x9a\x88\xa9\xe6\xad\x69\xc6\xaa\xaa\xe1\xf4\x6c\x4a\xde\xe7\x64\ -\xae\x9f\xbc\xe4\xdd\x9c\x44\xca\xd2\xde\xd0\x36\xcd\x13\x59\x9d\ -\x32\xf7\x30\x1a\xbc\x61\x53\x15\x5e\x58\x04\x03\x91\xb6\xfe\xd0\ -\xaf\x5f\x7f\x18\xcf\xd8\xac\x9b\xc6\xa5\x8d\x0e\xba\xc1\x1f\xc0\ -\x6b\x99\x6e\x74\xa6\xd6\xc7\x9c\xcc\x2e\x8f\x39\x5a\xab\x3e\x06\ -\x86\x19\x19\x2d\x21\xeb\x55\x5f\x2f\x58\xe7\x0c\x7a\xe1\x17\x0c\ -\xd0\x6c\x4d\x7f\xa3\xe0\xdb\x2f\xe2\x57\x0f\xbd\x5d\x11\xff\x02\ -\x65\xce\xbb\x22\xfe\xa5\xb8\x7a\x6a\xef\xfd\xd5\xe2\xce\x7b\x55\ -\x5d\xf8\x9c\x14\xe4\xbc\xd4\x75\xfb\x99\xbc\x91\x05\xca\x7d\x67\ -\xd3\x8a\x77\x46\xc9\xef\xd6\x7f\x33\xcb\x2c\x0d\x73\x42\xc6\x9f\ -\xc3\x62\x46\x3c\xf6\x92\xc0\xa0\x0d\x45\xb2\x6a\x6c\xea\x5e\x2f\ -\xf8\x3e\x8c\xe4\x84\x1c\xbf\x4f\x63\x79\xeb\x2a\x52\x61\x0f\x7c\ -\x81\x9b\x60\x5f\xe2\x51\xe7\x7f\x68\xd4\xff\x6f\x7a\x9e\xff\x84\ -\x26\xf4\x4f\x3a\xb0\x6c\x5d\xbe\xf9\xbc\x16\x1b\x4f\x6d\x9a\x26\ -\x92\x5a\x8f\x97\x58\x98\xed\x93\x2e\xf3\x1a\x05\x6a\x36\x9e\x36\ -\xa8\x7d\x2c\xd9\x60\xe6\x80\x70\x10\xa0\x86\x9b\xad\x41\xc8\x7b\ -\x82\xaf\x57\x51\xf4\x85\x48\x27\xa4\xde\xfd\xbe\x71\x9a\x3a\x4c\ -\x6b\xf0\x99\x25\xa3\x3e\xed\xf0\x90\x03\x71\xda\xa3\x98\x46\x76\ -\xb7\x77\x60\x28\xd6\x44\xc4\xfe\x46\xd2\x6b\x63\xfc\xe6\xb8\x75\ -\xfb\x9a\xa9\xfb\x00\xea\x6b\x98\x22\x9b\x70\x29\x50\xee\x80\x58\ -\x5b\x5a\x26\x60\x11\xcc\xcf\x4d\x1a\xa1\xf6\x43\xef\x13\x26\x4b\ -\xde\xda\x85\x3c\x4f\x0b\xf4\x7c\xd3\x15\xe3\x60\x61\xb1\x74\xc5\ -\xef\x97\x6f\x1e\x3f\x5d\x91\xe9\xe8\xf7\x92\xae\x98\x28\x8a\xff\ -\xe6\xd3\x15\x4b\x98\xdb\x93\xd5\xcd\xed\x8c\x52\x52\x0a\xc6\x53\ -\x91\x17\xc7\x57\xb6\xfc\xa2\xaa\x6a\x74\x23\xc5\x43\x2e\xad\x82\ -\xa0\x37\x2c\x6c\x25\x0b\x2b\x3c\xea\x88\xed\x6c\x99\x79\x16\xf9\ -\x9c\x13\x9e\x4b\x71\x2f\xcd\x38\x4d\xb3\x5d\x55\xa9\xa6\x2c\xcb\ -\xf4\xc5\xcd\x31\x91\x63\x2a\xdb\xad\x25\x32\x4b\x93\x49\x25\x97\ -\x4f\x3a\x2a\xe5\x93\xd2\x54\xd2\x49\x29\x95\x34\x91\x45\x2a\xb2\ -\x32\x91\x3b\xca\x84\x94\x93\x64\x4e\x8c\xce\x38\xa5\x51\xb5\x33\ -\x36\x17\xb5\xb3\x1a\xb1\x66\xe2\xa2\xd6\x68\xd4\xea\x38\xb2\xcf\ -\x87\x11\xed\x77\x93\xd8\x94\x4e\xb4\xfe\xb9\x31\xd7\xd7\x52\x44\ -\x9f\x79\xc4\xda\x22\x91\x1e\x6c\xe0\x85\x51\xf8\x81\x9f\x44\x69\ -\x11\x59\x8a\xca\x70\x92\x6f\xb1\x5c\xe6\x3e\x02\x94\x7b\xdd\x2d\ -\xfb\xee\x0f\x3e\x8f\xa1\x66\xe0\xf2\xb4\xdc\x37\x7f\xe0\x69\xb8\ -\x86\x3d\x2b\x2a\xea\xc3\x92\x61\x86\x3a\x4e\x60\x3f\x02\x74\x10\ -\xa0\xe0\x4c\x87\x11\x40\x91\xee\x6c\x46\x0a\xef\xde\x55\x32\x53\ -\xe6\x78\x1a\x57\x38\x9b\xe5\x5c\xad\xcf\x96\x7b\x67\xb9\x5a\x3e\ -\xe3\xce\xad\xb0\x92\xda\xf8\x6a\x5e\xb2\xde\xed\x30\xe3\x22\xf7\ -\x29\xcc\x8c\x7b\xd7\x67\x66\xb2\xc1\x7c\x9a\x4a\x32\x65\x74\x40\ -\x19\x6d\xf1\x44\x1c\xdb\x22\x23\xbc\x6e\xd6\x13\xde\xda\xfb\x3f\ -\x76\xfc\xff\x17\ -\x00\x00\x10\xc0\ +\x00\x6a\x6f\x78\x9c\xed\x5d\x5b\x93\xda\xb8\x12\x7e\x9f\x5f\xa1\ +\xe2\x21\xb5\xa7\x2a\x67\xb8\xcc\x85\x99\x84\x61\x2b\xf7\x49\x55\ +\x52\x9b\x0d\xb3\xd9\xc7\x2d\x61\x0b\xd0\x59\xdb\x22\x92\x3c\xc0\ +\xd6\xf9\xf1\xa7\x75\x31\xbe\x60\x0c\xc6\x80\x93\x39\xa4\x2a\x35\ +\xb6\x24\xb7\xda\xad\xee\x4f\xdd\x2d\xc9\xf4\x7e\x9d\xfb\x1e\x7a\ +\x24\x5c\x50\x16\xdc\x35\xda\xe7\xad\x06\x22\x81\xc3\x5c\x1a\x8c\ +\xef\x1a\x7f\x3c\xbc\xff\xf7\x4d\xe3\xd7\xfe\x59\x2f\xa4\x71\xa3\ +\x4b\x68\xd4\x3f\x43\x3d\xc7\xc3\x42\xf4\x3f\x84\xf4\xc5\x8b\xb7\ +\x14\x7b\x6c\x0c\x7f\xbd\xf1\x80\x48\x09\x0f\x8b\xb7\x1c\x8f\x64\ +\xaf\x69\x1a\x41\xeb\x19\x75\xc7\x44\x22\x7d\x7f\xd7\xf8\xfd\x4f\ +\x7d\xdb\x40\x01\xf6\xc9\x5d\xa3\x90\x88\xea\x0c\xf5\xa6\x9c\x4d\ +\x09\x97\x0b\xfb\xc4\x98\x30\x9f\x48\xbe\xd0\x95\xa8\xc7\x89\x23\ +\xf5\x15\xea\xcd\xfb\xad\x5e\x73\x6e\x6f\x16\xea\x66\x61\x6f\x80\ +\x05\x39\xe9\x77\xdb\x37\xbd\xa6\xb9\x34\xc5\x13\x42\xc7\x13\xd9\ +\xbf\x69\x41\xb9\xbd\xd6\x34\x9b\x11\xd1\x5e\x33\xea\x3c\x8f\x93\ +\x19\x0d\x5c\x36\x7b\xa0\xd2\x23\x96\x19\x21\x39\x30\xdf\xff\x46\ +\x45\x88\x3d\x24\xec\xbb\xf4\x9a\xb6\x7c\x95\xa2\x87\x17\x2c\x8c\ +\x65\xf3\xed\x35\x9b\x7f\xd2\x45\x96\x60\xa6\x47\x31\xc5\x0e\x10\ +\x6a\x58\xfe\x83\xd0\x1f\x12\xde\xbf\xee\x35\xed\x95\xe1\x3e\xd9\ +\xc3\x0a\x09\x1f\xf3\x31\x0d\x32\x14\x6e\x0b\x29\x50\x49\xfc\x58\ +\x90\xc9\xb1\xfc\xc0\x59\x38\x05\x9e\xa3\xd1\x1c\x47\xf7\xa6\xf9\ +\x4a\xe7\x32\x96\xd5\xaa\xb8\x06\x39\xe2\x5a\xe5\xa6\x50\x68\xb6\ +\x1b\x50\x58\x49\x1d\xec\x99\xd2\xbf\x3a\x71\x8f\xf1\xab\xe4\x10\ +\xba\x5f\x21\x34\x61\x9c\xfe\xc3\x02\x99\x43\x2a\x4b\x6c\x55\x38\ +\x9f\xf0\x90\x78\x11\x25\x4f\xdd\xa4\x1e\xcf\x91\x0e\x99\xcb\x54\ +\x83\xa5\x84\xde\x92\x11\x0e\x3d\x89\x3c\x1a\x10\xe4\x30\x8f\xf1\ +\x8c\x90\xf2\x25\x65\x0a\x0d\x5b\x09\xbe\x9b\x69\xc6\x57\xde\x43\ +\x69\x19\xe1\x2b\x22\x18\xe8\xe2\xc2\x37\x80\xb6\x04\x9a\x4a\x40\ +\x8b\xcc\x8b\x10\xd0\xaf\xfe\xef\xf2\xc5\x8b\xfb\x25\xbd\x5e\x53\ +\x17\x6e\x7a\x81\x55\x23\xa0\xff\x90\x7b\x1a\xc0\x20\x09\xe9\x82\ +\x8d\xdd\x35\x5a\x59\xa9\x41\x8b\x54\x49\x84\x00\x97\xad\x14\x00\ +\x2c\x6b\xad\xf1\x77\x5a\x29\x1c\x88\xd9\xca\x12\x5c\x23\x69\x23\ +\xb8\x12\x92\x4e\x6b\x8c\xc6\xc2\x2f\x9c\x8c\xde\xa8\x11\x7e\x1d\ +\x4a\x09\x62\x8c\x2c\x4b\xd5\x4d\xa1\x4e\x8f\xfe\xd0\xd4\x15\x2a\ +\x13\x63\xde\x03\x9d\xe6\xeb\x93\x9c\x10\xe4\x5a\x9d\xd2\x04\xd1\ +\x08\xfe\x07\x64\x86\xd8\xf0\x3f\x80\x7d\x59\x1b\x2c\x31\x3a\x9a\ +\x5c\xa6\x57\x5d\x96\x11\x39\x27\xae\x42\x68\xf5\x27\x5d\x31\xe6\ +\x84\x04\xaa\xca\x5c\xa4\x2b\x87\x5e\x48\x54\x9d\xfe\x9b\x1e\xa3\ +\x95\x4e\xb6\xe3\x57\xc9\xf4\x5d\xa0\xe6\x93\xb5\xea\xe4\x58\x59\ +\x58\xc3\x73\x76\x15\x8d\xea\xea\x0b\x96\x93\xcd\x3d\x7d\x66\x6e\ +\x33\x9a\x46\xf7\x65\xe7\xbd\xa6\x81\xbb\x25\x16\xa6\xaa\x2b\x23\ +\x63\xb7\x1a\x32\x5e\xec\x03\x19\xb5\x69\xd7\x86\x8c\x1b\xd0\xfd\ +\x84\x8d\x7b\xc1\xc6\xc1\x94\x06\x49\x8f\x23\xc2\x45\x01\xe5\xc3\ +\xd8\xf3\xc8\x95\xce\xd6\x98\xa8\xb4\x49\xcb\x62\x7f\xb8\xf8\x88\ +\x01\xb2\x32\x3d\x5b\x9f\xab\x93\xf2\xbe\x4a\x51\x2d\x81\x5e\xcb\ +\x77\x3a\x21\x58\x3e\x82\x5d\x54\x43\xb0\xcb\x1d\x11\x6c\x10\xe0\ +\x29\x12\x0b\x7f\xc8\x3c\x51\xb3\x6f\xb7\xe1\x1d\x4e\x08\x76\x4c\ +\xef\x6e\x53\xb0\x50\xde\xbf\x13\x09\x4d\x3b\x39\x78\x49\xf6\xad\ +\x2c\x94\x80\x4e\x4e\x5e\x01\x44\x5e\x6e\x0f\x91\xb1\xba\x4f\x88\ +\xf3\x77\xde\x8c\xed\xa8\x8a\x4a\x53\xb6\xa6\x80\xe4\x84\x0a\x44\ +\x47\x08\x38\x44\x33\x1c\x48\x24\x19\x0a\x05\x41\xca\x08\xf4\x68\ +\x36\x13\xd3\x39\x67\xbe\xae\x50\x74\x87\x98\x23\x2c\x22\x43\xd9\ +\xdd\x22\x0a\xb0\x1d\x3f\x02\x0f\x21\xe7\x80\x9b\xd6\x10\x71\xe0\ +\x26\xdc\x0b\xec\x70\x26\x04\x12\x44\xa8\x0c\x5b\x05\xab\x2c\xa3\ +\xe5\xc0\x14\x0b\xc8\x9c\x96\x50\xbc\xff\x2f\x35\x6f\x97\x48\xf3\ +\x6c\xaf\xe7\x7f\xb5\xdb\xbb\xab\x3a\xe8\xb7\xa6\x43\xdc\xe7\x08\ +\x23\xcb\x02\x0d\x5c\xea\x60\x95\x34\x33\xca\x6e\x15\x6d\xc6\xf8\ +\xdf\xaa\x6c\xea\x61\x08\x8a\x12\xb3\x36\xc2\xd3\x29\xc1\x1c\x54\ +\x3e\x54\x44\x91\xcb\xf1\x4c\xfd\x55\x6c\xe8\x06\x15\x14\xb0\xc0\ +\x08\x26\x6c\x86\xfe\xb4\x3c\x7d\xd1\x3c\x49\x8e\xe1\x55\xb6\x77\ +\x74\x2a\xa9\x3b\x74\xaf\x7b\x7d\x88\x3a\x3d\x29\x7d\x9e\xd2\xdf\ +\x1c\x44\xe7\xaf\x77\x57\xf9\x8f\x23\x0b\xed\x22\x56\x7d\x1b\x86\ +\x81\x01\x78\x9e\xd5\x66\x05\xe1\x23\xb8\x25\x6e\x02\xcc\xcf\xd1\ +\x6f\x60\x11\x7c\x46\x05\x79\xae\x6c\x63\x91\x7d\x62\x46\x81\x4b\ +\x0e\x4c\x1c\x42\xe3\xdf\xab\xbe\x22\x56\x87\x8b\xea\x33\x4c\x09\ +\x75\x57\xa2\xf0\x99\x4b\x4e\x6a\xbe\x06\xdb\xdb\xd5\xc2\xbc\x4d\ +\x20\xbe\x31\x53\x05\x3d\x02\x30\x4b\x82\xc4\x84\x90\xed\x75\x62\ +\xef\xb1\xde\x86\x17\x39\x05\x7b\x7b\x09\xf6\x00\x0a\xc8\x9b\x09\ +\x63\x82\xf0\x15\x90\x04\x53\x25\x8e\xa9\xdb\x10\xec\xf9\x34\xa0\ +\x7e\xe8\x0f\x80\xf7\x6d\xe5\x73\xd1\x2a\x16\x50\x25\xf9\x94\x03\ +\xf2\x87\x44\x34\xba\xd4\x7e\xeb\xa4\xcf\x26\x24\x40\x0e\x27\xc6\ +\x8b\xc1\x3a\xd7\x16\xb9\x25\xe5\x0c\xa4\x0a\x68\x46\x5c\x9d\x40\ +\x33\x17\x34\x2b\x22\xe6\xae\xb9\xfd\x57\x9e\x24\x3c\x50\xca\x32\ +\xf8\xf6\x01\x81\x70\xd5\xad\x40\x1e\x73\x34\x2c\xd5\x08\x9d\xad\ +\x13\x74\xae\x17\xf6\xb1\xa1\xb3\x58\xbd\x7e\x6e\xe8\xbc\x27\x9c\ +\xe8\xc4\x86\x83\x03\x24\xa6\xc4\xa1\xa3\x05\xa0\xa4\x4b\xd5\x0e\ +\x15\xc6\x17\xc8\x51\x4a\x04\xaf\x08\x70\xa9\x8c\x44\xc9\x45\x24\ +\x0b\x9f\x79\xf2\xe5\xd4\x58\xce\xb3\xb1\x7c\xa9\x70\x18\x2a\x74\ +\xac\x07\x7e\x31\x96\x9a\xf0\x90\x20\xec\xba\xe0\x40\x03\x28\xab\ +\x40\x52\x48\x1c\xb8\x98\xbb\x48\xc3\x14\x82\x66\xce\x04\x59\x2a\ +\xc7\xc9\x51\xd8\xce\x94\x0a\x9c\x30\x79\x8d\x23\x5b\x22\x60\xcb\ +\x83\xe5\xee\x8e\xa8\x7c\x9f\xd2\x06\xc4\x89\x60\x5e\x58\x33\x1e\ +\x9f\x56\x5e\x0b\x84\x7d\xa4\x95\xd7\x4d\x2e\x2c\x9e\x2b\x1c\xce\ +\x5f\x01\xbd\x6a\x57\x58\x03\x2d\x58\x59\x6d\x77\x6e\x8e\xb2\xb6\ +\xaa\x6d\xc2\x3a\x28\x5f\x13\x06\xf1\x14\x91\x2b\x5d\x99\xa2\x95\ +\x68\xb7\xc3\xa6\xc1\x78\x22\xdf\x6e\xdb\xe0\x07\x4e\xdd\xbd\xef\ +\x15\x8c\x9d\x89\xea\x00\x5d\x62\x4b\x4c\x89\x8c\x5a\x85\x65\xc1\ +\x8f\xa9\x24\xf2\x18\xe4\x97\x4a\x8b\xe9\x58\xcc\x06\x5f\x87\x48\ +\x8b\xfd\x01\xf1\xde\x78\x75\xd0\x4a\xd0\xb6\xdc\x67\xc8\x0f\xe1\ +\x9d\xfb\x23\xec\x09\xf0\x15\xf4\xf5\x21\x4d\xdd\xbc\xc0\x53\x34\ +\xec\x3d\x68\xfc\xd5\x61\xd6\x4d\x8a\xc3\x2d\x12\xe0\xa1\x77\x00\ +\xa5\xd8\xda\x94\x94\xcb\x6c\x3c\xe5\x84\x49\x79\x33\xbc\x10\xca\ +\xb3\x7e\xa4\x82\x02\x7f\xc6\xba\xe2\xa6\x6a\x91\x66\x48\x02\x70\ +\xa5\xa8\x40\xd8\x91\xf4\x91\x24\x92\xd6\x88\x05\xde\xc2\x3c\x12\ +\x0a\x93\x19\x71\x98\xef\x83\x5b\x7e\x08\xc3\x7c\x65\x98\x55\x2b\ +\x25\x9a\xc3\x6a\x46\x5a\xc2\x98\x8c\x94\xd4\x02\xd1\x87\x93\x59\ +\xad\x37\xab\x56\x35\x4f\x3f\x65\x96\x47\xb4\x9f\xb5\xfa\xa6\x06\ +\x1b\xd9\xb3\x0c\xf5\x45\x0d\xc5\x01\xd0\x29\x68\xd8\x4b\xd0\xf0\ +\x96\x85\xa0\x5c\xeb\x42\x07\x57\xd7\x46\x01\x44\x71\x22\xa7\x16\ +\x98\x57\xa9\x6b\xab\xa8\x80\xe5\x72\x46\x00\x90\x09\x06\xd0\xd6\ +\x48\xaf\xf6\x71\xec\x8e\x93\x2e\x71\xa8\x0f\x9c\xe7\x87\x2e\x97\ +\xbb\x07\x2e\xf9\xa1\x96\x91\x75\xff\x16\xfe\x9d\xdf\xde\xdc\x2e\ +\xff\x75\x6f\x20\xf6\xb2\x95\x7b\x89\xbd\x2c\xad\xf6\x79\x2b\xfd\ +\x6f\xf7\x5e\x4a\xba\x67\x83\x08\x59\x4e\xd3\x49\xee\x74\x52\x71\ +\xa3\x6b\xbb\x78\x4d\xff\xf8\xd3\xc9\x67\x4c\x03\x6d\x8b\x02\x11\ +\x08\xe7\x16\xf5\x4d\x29\x37\xa7\x29\x65\xbd\xac\x8f\x95\x87\x2a\ +\xde\xc4\x5c\xcb\x34\xa2\x34\xd4\x28\xa8\x0e\x0e\x20\x2a\x50\x61\ +\xb6\x0a\x07\xa8\xda\x92\x74\x8e\x06\x36\xb5\x3f\x51\xf9\x7e\xe5\ +\x86\x83\xab\xbf\x40\xe2\x7b\x88\x39\x11\xcb\x99\xc7\x8f\xc8\x9c\ +\x1f\xe4\x1c\x42\xbb\x75\x94\x64\x99\x82\xe8\x77\xc6\x4e\x9f\x22\ +\x40\x1f\x2e\x3f\xb6\xcc\xfc\x6c\x97\x1f\x7b\x00\xc0\x14\x7a\xbf\ +\xa9\x4b\x7d\x12\xe4\x6d\x30\xad\x9c\x2f\xdb\x5f\xb6\xec\xba\xda\ +\xa4\xb4\x61\x9f\xd9\x16\xbb\x72\xe6\x12\x19\x74\xab\x6f\xfa\x28\ +\x7e\x89\xd3\xf4\x71\xf4\x88\x64\xab\x25\x8d\x32\x4b\xcb\xd7\xc5\ +\x32\x6a\x5f\x77\xbb\xdd\x4e\xfb\xea\x78\x0b\xcc\x91\xfe\x9b\xfe\ +\xf4\x31\x11\xb9\x19\x37\x4a\xf4\x5e\x10\x21\xb4\xce\x3b\x35\x44\ +\x08\xea\xf5\x22\x43\x7f\x8a\xf3\x4f\x75\x28\xbe\xad\x06\xc5\xc5\ +\xd9\xa6\x2d\xa1\x78\x04\x0c\xd5\x07\xc4\xc5\x99\x88\x13\x10\xef\ +\x05\x88\x3f\x81\x27\xfb\xce\xa5\x72\x05\x83\x95\x8b\x4b\x54\xc5\ +\xce\xa8\xf6\x60\xf7\x8d\x27\xcf\xc1\x29\x8d\xd2\xcf\x6a\x90\xc3\ +\xe0\x86\x9b\x44\x7c\x1e\xdc\x9d\x9f\x7d\x8c\x77\xc6\x24\x9e\x14\ +\xa1\x33\x51\xbb\xc7\x9f\x7d\x0f\x99\x7c\xf9\x8a\x53\xec\x99\x4b\ +\xb5\x9e\x16\x75\x24\xe4\xc2\xcb\x36\x15\x38\x10\x51\x4b\x5b\x42\ +\x38\x1d\x99\xcb\x33\xe0\xc7\x5c\xf9\x2c\x60\x51\x33\xc5\x24\x1a\ +\x61\x9f\x7a\x8b\xbc\x7e\x9f\xdf\x13\xef\x91\x28\x57\xec\x79\x4c\ +\xdc\x3c\xa4\x59\x9d\x51\x75\xbc\xc8\x30\x73\x96\xf3\xfc\x8b\xd7\ +\xcc\x73\xcd\xfd\x41\x96\x14\x54\x1f\xbb\x13\xc6\x1e\x1d\x07\x30\ +\x1a\x2b\xd4\xc1\xc8\x95\x7d\xbd\x52\xf5\x5f\x95\x0e\xff\x77\x79\ +\xfb\xc0\x31\x05\xd5\x19\xc7\x25\xdf\xde\x00\x05\x7d\xcc\x84\xc8\ +\xf2\x3c\x94\x9c\x53\x0c\x62\x9d\x66\x94\xdc\x94\x53\x89\x83\x83\ +\x39\x53\xca\xae\x13\xca\xd2\x9e\xd1\x33\xec\x4f\x5f\xa2\x4f\x04\ +\xbb\x00\xfa\x98\x73\x88\xb0\xb5\x65\x1c\x72\x8a\x59\x7b\xfc\xd7\ +\x1f\xb2\xdc\xf5\x4e\x55\xb1\xe9\x3c\x64\x09\xa5\x04\x38\x33\x87\ +\x7d\x7f\x54\xad\x5c\x11\xd9\x36\x83\x1b\x8f\x2e\x93\xe8\x2a\x6f\ +\xfc\xd6\x75\xd6\xcc\xf6\x56\xb9\xfb\x6e\xbd\xdd\xdf\xd6\xd7\xfd\ +\x1b\xca\x1d\x98\xe4\x6a\x94\xbf\xe5\xa0\xc6\x21\xb0\x1c\xd4\x38\ +\x0a\x03\x80\x96\x49\x9d\x83\x60\x18\xa8\x71\x0c\x0c\x03\x35\x0e\ +\xc1\x6b\xec\xfc\x2d\xea\x1e\x86\x98\x89\x1a\x87\x22\x66\xa2\xd2\ +\x70\xd4\xee\xaa\x54\x4c\x44\xb6\x8b\x97\x1f\xd6\x7b\x2b\xdf\x6c\ +\x62\x35\x11\x86\x98\x50\x38\x11\x6e\xfe\x88\xee\xca\xa6\x4f\x77\ +\x6d\x1b\xa7\x25\xcf\xa9\xb3\x91\x09\xdd\x22\x49\xd8\x20\xcd\x6e\ +\xa1\x62\x82\x24\x85\x84\x39\x41\x51\x56\xfa\x1c\x45\x59\x04\xa0\ +\xea\x91\x91\x7c\x0e\x0f\x51\xb3\xc9\x4a\x51\xfc\x38\xf8\x6d\x79\ +\xba\xa1\xc2\x22\x4a\x39\x2f\x2c\x35\x80\x4f\xd1\x15\xfb\x04\x82\ +\x46\xbf\x24\x65\xfb\xaf\xfa\x70\xe8\xeb\xba\x1c\xfe\xcf\x82\x40\ +\x9d\x8a\xeb\xf3\x9d\x5d\x11\x28\x32\x9d\xc1\x04\x4f\xc9\x40\x97\ +\xa1\xf7\x2a\xf7\x61\x8e\xe1\xd4\x95\x8c\xbb\x2d\x7c\x9d\x53\x32\ +\xee\x98\x87\xed\x9e\xf0\x51\xbb\x01\x81\xb7\x94\x51\xba\x6f\x54\ +\x46\xe5\xab\xcc\x0f\xca\xc0\x9e\xee\x31\xb7\xf2\x8b\xe1\x29\x2c\ +\x88\xa6\xf5\xf4\xa7\x87\xb7\x81\x80\xd8\xfa\x23\xbf\x2a\x65\xfb\ +\xab\x0b\xdf\x25\x2c\x3e\xad\xce\x56\x93\x3b\x2b\x8a\x1c\xe9\xf0\ +\xe5\x8a\x12\xa7\xf4\x37\xcb\x4a\xca\xa6\x63\x21\x25\x24\x99\x10\ +\xa3\x9d\x5e\x96\xa9\x67\xb3\xf3\xed\xae\x71\xdd\x40\xe6\x43\xdf\ +\x77\x8d\x76\xbb\xd1\x54\x2d\xa7\x74\xee\xe3\xe9\x28\x0c\x1c\x25\ +\xa8\xfe\xf7\x2f\xfa\xfe\x3d\x67\xfe\x67\xf0\xa5\x06\x2c\xe4\x0e\ +\x28\x61\xa6\x95\xfa\xd8\x7b\x28\x24\xf3\x4d\x8f\x42\x73\x92\x2c\ +\x31\x5c\x26\x3e\x08\x9f\x00\x92\xf8\x1b\xf0\x6a\x3c\xe6\x92\x04\ +\xae\xe8\xdb\xef\xbf\xc3\x68\xd8\x82\x33\x23\x2a\x95\x99\x53\x14\ +\x9a\x8a\x80\xf9\x20\xfc\xf9\x44\x09\x4e\x57\x68\x01\x64\xfb\x2d\ +\x66\x24\xf1\x99\xbd\x7c\x46\xbe\x84\x62\x12\xd5\xaf\x63\xc6\x30\ +\x2b\xaa\x71\x92\xc1\xd7\x5c\x6e\x56\x65\xb7\x8e\x25\x45\x6d\x6f\ +\x6c\xd9\x65\xf0\x7c\x01\x2d\x2b\x8f\xc2\xca\xa6\xf1\x5a\x1d\xd4\ +\xe3\xb0\x65\x8f\xa7\xe4\x8b\x28\xae\x3d\x92\x8c\x4c\x30\xb6\x86\ +\x99\x65\xed\x51\x98\x89\xd6\xef\xf2\x99\x89\x6b\x8f\xc2\x4c\x6a\ +\x57\x47\x3e\x47\x99\x26\xd5\xd9\x4a\x17\xe8\xdf\xba\x50\xa7\xa1\ +\x15\x90\x0a\x0d\xb9\x0e\x0b\x02\xa2\x81\xd4\x02\xe7\xf2\xde\xf4\ +\x2a\x80\x01\xa0\x9d\x73\xc6\x4f\x2d\x59\x05\x6e\x34\x09\x08\x3a\ +\x0e\xb0\xd7\x77\x3c\xb5\x5b\xd0\xfd\x45\x6d\x50\x54\x01\x96\x29\ +\xd5\x2d\x38\x71\x08\x7d\x4c\xd2\xca\x6c\xad\xd7\xbf\x69\x61\x9a\ +\x18\x92\x1e\x93\x7d\x98\xd7\xde\x99\xed\x90\x4b\x9a\xaa\xd8\x48\ +\x04\x26\x3f\x61\x67\x24\x75\x8d\xe4\x62\xaa\xe6\x45\xfd\x7a\xa9\ +\x55\x99\xde\xbc\x7f\xdb\x59\xfe\xf0\x86\xfa\xe5\x8d\x8b\xee\x6d\ +\xfc\xdb\x1b\x4d\xf5\xf4\x2a\x21\x97\x08\x49\x03\x3d\x69\x67\xa9\ +\x5d\xb6\xbb\x69\x72\x37\xed\x3c\x72\xe6\x52\xd8\xa1\x49\x89\xf6\ +\xa8\x92\x5e\xee\x3b\x3d\xac\x8c\x95\x4c\x53\x32\xbe\xa8\x22\xe3\ +\xab\x6e\x3b\x43\xee\xf2\x07\x94\x71\x74\x7e\xe9\xb0\x92\xbd\xba\ +\x49\x8b\xe2\xfa\xaa\x8a\x64\x2f\xae\x2e\x7f\x02\xed\x8d\xb6\xf2\ +\x1f\x56\xb2\x17\x17\x19\xc9\x76\x2b\xe9\xac\x62\xf7\x87\x97\x6c\ +\xde\xf9\xd5\x03\x23\x43\x16\x7d\x2b\xe9\x6f\xa7\x73\xbd\x0d\xd0\ +\xac\x97\x72\xf2\x16\xea\x7b\xcd\x90\xf6\xcf\xfe\x07\xa5\x05\x6e\ +\x26\ +\x00\x00\x0a\x1d\ \x00\ -\x00\xae\x67\x78\x9c\xed\x1d\x6b\x6f\xdb\x38\xf2\x7b\x7e\x05\x91\ -\x0f\xbd\x1e\xd0\x8d\x63\xe7\xdd\x75\x7c\x68\xd3\x27\xd0\xee\xa6\ -\x75\xda\xde\xde\x97\x05\x2d\xd1\x36\xaf\xb2\xe4\x25\xe9\x24\x5e\ -\xdc\x8f\xbf\x19\x92\xb2\x1e\x91\xe5\xc8\xb2\x2c\xbb\x75\x51\x20\ -\x16\x49\x91\xc3\xe1\xbc\x38\x33\xa4\xda\xff\xba\x1f\x79\xe4\x96\ -\x09\xc9\x03\xff\x72\xbf\x79\x70\xb8\x4f\x98\xef\x04\x2e\xf7\x07\ -\x97\xfb\x5f\x6e\xde\xfc\x72\xbe\xff\xaf\xce\x5e\x7b\xc2\xa3\x46\ -\xc7\xd0\xa8\xb3\x47\xda\x8e\x47\xa5\xec\xbc\x9d\xf0\xe7\xcf\x5f\ -\x71\xea\x05\x03\xf8\xeb\x0d\xba\x4c\x29\x78\x59\xbe\x12\xb4\xaf\ -\xda\x0d\xd3\x08\x5a\xdf\x71\x77\xc0\x14\xd1\xcf\x97\xfb\x9f\xbe\ -\xe9\xc7\x7d\xe2\xd3\x11\xbb\xdc\xcf\xed\x04\x07\x23\xed\xb1\x08\ -\xc6\x4c\xa8\xa9\x7d\x63\xc0\x82\x11\x53\x62\xaa\x2b\x49\x5b\x30\ -\x47\xe9\x5f\xa4\x7d\xdf\x39\x6c\x37\xee\xed\xc3\x14\x1f\xa6\xf6\ -\x01\x40\x50\xc3\xce\x59\xf3\xbc\xdd\x30\x3f\x4d\xf1\x90\xf1\xc1\ -\x50\x75\xce\x0f\xa1\xdc\xfe\xd6\x7d\x36\xc2\x4e\xdb\x8d\x70\xf0\ -\x2c\x48\xee\xb8\xef\x06\x77\x37\x5c\x79\xcc\x02\x23\x95\x00\xe0\ -\x3b\x6f\x99\xcf\x04\xf5\x88\xb4\x93\x69\x37\x6c\xc5\xc3\x2e\x3d\ -\x3a\x0d\x26\x11\x72\xbe\xbe\x0c\xee\x3f\xe8\x22\xdb\x63\x6a\x48\ -\x39\xa6\x0e\x74\xb4\x6f\x27\xe0\x4f\x46\x3d\x26\x3a\xa7\xed\x86\ -\xfd\x65\xc0\x8f\x8f\xf0\xa0\x8b\x11\x15\x03\xee\xa7\x7a\xb8\xc8\ -\xed\x81\x2b\x36\x8a\x30\x19\x5f\xcc\xb7\x22\x98\x8c\x01\xe6\x70\ -\x39\x07\xe1\xb3\x69\xfe\x60\x70\x15\x21\x2b\x03\x5f\x7a\xd1\x49\ -\x37\x03\x6b\x0f\x81\xca\xc5\x9d\x1d\x0d\x08\x57\x71\x87\x7a\xa6\ -\xf4\xcf\x56\x34\x70\x34\xa3\x8c\x8e\xde\x3d\xe8\x68\x18\x08\xfe\ -\x77\xe0\xab\x59\x57\xcd\x8b\x59\x5f\xe9\xde\x1e\x20\x49\x93\xf8\ -\xb5\x60\xfd\xab\x21\x73\xbe\xc7\x91\x85\x15\x63\xa8\x70\xb0\xa2\ -\x17\xdc\xff\xd9\x6c\xc5\xba\xcd\xc0\x5e\x10\x78\x37\x7c\x9c\x68\ -\x33\x43\xe2\xfb\x3e\x51\x43\x2e\x09\xfc\xd7\xfd\x31\xf7\x19\x14\ -\x30\x8b\xd4\xbb\x40\x7c\xef\x01\x7f\x0f\xe1\x97\xff\x0f\x45\xe8\ -\x78\xcc\xa8\x38\x20\x5f\x24\xeb\x4f\x80\x52\xb9\xef\x30\x42\x3d\ -\x8f\x04\xfd\xd8\x5b\x38\xa0\x24\x54\x60\x95\x0c\x08\xf7\x75\xdd\ -\x0b\xa1\xbb\xb1\x1d\x1e\xa4\xd6\x29\x7b\xb1\xb2\xe7\xc3\xee\x55\ -\xf6\x64\xde\x71\xf7\x01\xe4\xcb\x8f\x83\x38\x7e\xed\xa3\xcc\x20\ -\x52\xb9\xc0\x95\x97\xfb\x87\xa9\x71\x1d\xdb\xf7\x10\x06\xd6\xe3\ -\x7e\x8b\x86\x75\xca\x8c\x7b\x4d\xd5\x70\xf1\xb0\x1f\x03\xb7\x11\ -\xca\xcd\x47\x8e\xa6\x45\x19\x90\x59\x8c\x0e\x1b\x49\x42\x5c\x40\ -\x97\x9f\x3e\xd0\x1e\xf3\x42\x62\xf4\xf0\x21\x49\xd7\x45\x16\xcc\ -\xac\x15\xf7\x15\x13\x7d\x0a\xa4\x34\x0a\x5c\xb6\xfc\x82\x51\x8f\ -\x0f\xfc\x11\xf3\x1f\x0c\x06\xd3\xfd\xa4\x9e\x3f\x7f\x81\xf5\x9f\ -\x51\x60\xff\x6f\xf6\x78\x23\x28\xf7\x60\xb4\xa8\xe4\xeb\x15\x43\ -\x78\x00\x8c\x38\x96\xaa\x42\x67\xc4\xe6\xc1\xa8\x17\x64\xb2\x39\ -\x56\x20\x9b\x1f\x2f\xcf\xe5\x37\x96\xc5\x91\x0f\xbf\xbc\xd7\x68\ -\x46\xb6\xbc\x1b\x72\xe0\xc9\x88\x71\xa1\x7c\xe2\x31\x72\xc7\x81\ -\xa3\x91\x81\x9e\x93\x1b\xe8\xb5\x47\x85\x79\x43\x97\x8f\x3d\x6a\ -\x79\xde\xbc\x13\x6a\x2b\xec\x8f\xc2\xd3\x98\x0a\xaa\x98\x96\x01\ -\xf0\xe2\x33\x1c\x03\xba\x54\x54\x7e\x4f\xf6\x33\x91\x4c\x8f\xfc\ -\x46\x30\x76\xf5\xe2\x15\xb9\x81\x16\xb7\x9c\xdd\x11\x39\x95\x80\ -\x31\xd2\x0f\x84\x1e\x85\x2b\x89\x6d\x85\xa1\x12\xea\x28\xb0\x29\ -\xd6\xc2\xd3\x5f\xf8\x47\x4d\x8d\x9b\xc9\xc7\x0f\xe8\xea\x31\x6c\ -\x17\xd1\x83\x59\x9d\x2c\x3c\xce\x1b\xae\x91\x1e\xaf\x1c\x00\x76\ -\xb5\xcb\x40\xb0\x90\xf7\xda\x0d\xa3\xa2\x67\xfa\x3b\x51\x5d\x5a\ -\x9b\xb7\x1e\xaf\xcc\xb3\x84\xe6\x02\xa5\x3d\x5f\x66\xb2\x3e\x9d\ -\x78\xd0\x75\xe0\x05\x99\x2b\x58\xb9\xa0\x82\x71\x5f\x4e\x94\x0a\ -\xfc\x0c\x59\x05\x75\x3d\x53\xb7\xb4\xb0\x42\xa9\xe0\xc6\x27\xa9\ -\x65\x81\x0f\xa2\x21\xe8\xfd\x17\x4c\xec\xb4\x89\x97\x47\x33\xa9\ -\x71\x75\x77\x69\x26\xc4\xb2\x14\x95\x0a\xe6\xe2\x46\x00\xff\x24\ -\x2b\x06\x20\xad\x7c\xac\x32\x3f\x92\x95\x3d\x6f\xc2\xb0\x4e\xff\ -\x4d\x12\xf4\x83\x41\x56\x2e\xae\x2c\x39\x6c\xa6\xb4\xaa\xc4\xea\ -\x58\xa0\x0f\xe7\x32\x50\xd7\xa7\xe3\x4d\xe7\x9e\x45\xd2\xa1\x38\ -\xff\x48\x9c\xb5\x9c\x82\x2d\xe1\xed\x18\x28\x01\xbe\xc5\x05\x22\ -\xe8\xe7\x63\xa2\x65\x2d\xf7\xab\xc0\x87\x5f\x13\x6d\x8e\x6d\x3c\ -\x33\x1d\xad\xc6\x72\x7e\xc8\x54\x56\x21\x91\x1e\x83\xb6\xc4\x15\ -\xf4\xce\xb7\x06\x2f\x47\xac\xc4\x50\x84\x86\x6f\x89\x3d\x6f\x11\ -\xbe\x3b\x3e\x9e\xcf\x78\xcd\xd6\x49\x0e\xeb\xb5\x4e\x4e\x6a\xd3\ -\x5e\x11\xae\x7e\x3e\x26\x5c\x40\x9f\x0b\x4d\x41\xd8\xc0\x32\xed\ -\xa1\xac\x81\x07\xbb\x63\xee\x67\x6d\x5b\x25\x94\xf7\x22\x97\x5e\ -\xf6\xcc\x1e\xab\xc6\x66\x13\x5c\x9d\x29\x78\x4b\x81\xce\x53\x23\ -\x5b\x67\x66\x2b\xe1\xd6\x2c\xd4\x6b\x01\x92\x8f\x2d\xda\x96\x92\ -\x7a\xc5\xfb\xab\xa3\x92\xfb\xab\xc3\x52\xaa\x8d\x72\x2d\xb4\x6b\ -\xd1\x6a\x8b\x3c\x41\x27\x65\xf4\x19\x23\xb3\x09\xa2\xd2\x82\x39\ -\xf2\x3e\x67\x82\x7c\x67\xd3\xb5\xf8\x55\x60\x40\x27\x04\x60\x53\ -\x49\xbf\x9c\x73\x43\x0e\x39\x0e\x56\x97\x6f\xc5\x51\xc2\xab\x6f\ -\x74\xea\x95\x9a\xfa\x12\x6c\x84\xd1\x2d\xa0\xdf\xb4\x14\xe9\xea\ -\xe2\x05\xbc\x02\xad\x19\x34\x46\xb3\x23\x45\x3d\x0c\x54\x80\xf6\ -\x1a\xbf\x9b\xf5\xd8\x6e\xe8\xc2\xc2\xa4\x2a\xf9\xdf\xec\x1d\xf7\ -\xd5\x7c\x52\xc5\x16\x29\x74\x9a\x88\xe3\xf1\x61\x22\xf6\x38\xab\ -\xb5\x71\xc7\xd6\x61\x22\x04\x19\x81\x95\xee\x70\x8e\xc8\x32\xa8\ -\x5b\xa9\x2d\xd3\x6a\x96\xd9\x96\x6f\xaa\xc4\x3d\x2d\x27\x71\xa5\ -\x9d\xdb\x0a\x24\xad\x33\x11\x02\x48\xf6\xbd\xef\xb2\xfb\x6c\xf3\ -\xa5\xb9\x16\xf3\x05\x66\x83\xb3\xda\x49\x70\x53\xba\x93\xe0\x51\ -\xc1\x8a\x25\x78\x3e\xef\xed\x24\xf8\xca\x25\xf8\xb2\x91\x89\x17\ -\x9e\xda\x58\x01\x7e\x56\x4e\x80\x53\x33\xb5\xb5\xc8\xef\xf5\x6c\ -\x3f\x61\x36\x9a\xd1\x77\xe2\x7b\x27\xbe\x37\x29\xaa\xda\x8c\x53\ -\xd1\x32\xb9\x28\xe5\xb6\xfd\xd6\x5d\xab\x33\xd2\xf4\x2b\x35\x48\ -\xb3\x0f\xdc\x67\xaf\x5d\xae\x1e\x48\x33\x74\x19\x31\xa8\x28\x13\ -\x1d\xca\x72\x68\x47\xb3\xd5\xfe\xb5\x84\xe3\x3a\x4c\x9c\xac\x22\ -\x5f\x2b\x8e\xf2\xb5\xf8\x1e\xe2\x33\xd3\x93\x36\x2b\xbc\x99\x32\ -\xb0\x6e\x4e\x3c\x7e\x3c\x23\x3e\x3e\x59\x71\x79\xc2\xd5\x3d\xd8\ -\x64\xc5\x3e\x01\x08\xc9\x1d\xf5\x31\xd9\x70\x96\x4a\xa4\x03\x07\ -\x8d\x98\xaf\x58\x04\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\ -\x88\x40\x4a\x22\x99\xc4\xc4\xe8\x12\xbe\xeb\x22\x51\x4d\x00\x2a\ -\xf0\xd9\x3d\xdf\x58\x55\x5f\x37\x99\x9f\x55\x41\xe6\x65\x5c\xb4\ -\x59\x29\xb9\x4e\x30\x9e\xc6\x92\xe7\x7a\x0c\x8c\xd0\xb1\x0a\x29\ -\x0a\xac\xdc\x11\x90\xda\x33\x12\x00\xb5\x8b\x3b\x2e\x59\x58\x24\ -\x4d\x7b\xea\xdd\xd1\x29\x50\x9e\xa2\x02\xd3\x2d\x89\x1f\xfc\x32\ -\xeb\xb1\x0a\x56\x78\xeb\x05\x3d\xea\x91\x15\x8c\x61\x31\x90\x1a\ -\xa6\x07\xf8\xeb\x80\x20\x87\x8e\xf5\xcf\x6a\x75\xc6\x78\x3a\xda\ -\xe0\x4c\xc0\xba\xf9\xa7\x79\x5e\x09\x03\x95\x88\xd9\xff\x16\x88\ -\x11\xf5\xbc\xe9\x33\x02\x88\x64\x42\x93\x21\x86\x3a\x6c\xcc\xf0\ -\x99\x55\x16\x63\xce\x24\x41\xe0\x24\xf3\xa0\x9c\xb9\x07\x24\x64\ -\xbd\x60\xac\x6d\x9f\x74\x52\x7c\x8f\x02\x67\x85\x31\xff\x90\x11\ -\xc3\xb7\x81\xaf\xa4\x62\xd4\xad\x24\xb3\xbd\xab\x07\x49\x02\x90\ -\x98\xdc\x7a\x94\x89\x86\xe2\x25\x00\xf1\x7b\x18\x7e\xdd\xf1\x44\ -\x16\x4f\x9c\x54\xc2\x12\xe7\xab\xd5\x29\xda\x84\x8a\x6b\x07\x74\ -\x52\x83\x39\x05\xc6\x82\x54\x31\x7e\xb1\x19\x2d\x98\xdd\x02\xa5\ -\x9a\x49\xfc\x40\xc5\xde\xef\x19\x07\xf7\x58\xbf\xe3\x7b\x53\x78\ -\x81\xf9\x04\x40\x07\x3b\x07\x8a\xae\x6e\x3e\x7f\xa8\x84\x29\x5e\ -\x24\xe1\x0e\xc1\x7d\xea\x72\x49\x7b\x5e\xe4\x75\x47\x87\xcd\x3f\ -\xb7\x59\x05\x99\x05\xea\x6e\xb0\xbb\x7d\xe5\x4e\xdf\xfc\x1d\xee\ -\xce\xe9\xbb\x6a\xa7\x6f\xb3\xa4\x83\x54\x50\x97\x4f\xe4\x2c\xd3\ -\x54\xcb\x02\xe0\x49\x39\x66\x0e\x07\x4b\x70\x1c\x00\x22\xe5\x01\ -\x9e\xd2\xc3\xe2\x43\x93\xc7\x13\x10\x60\x55\x45\xf1\x10\xd9\x53\ -\xee\xf7\xb9\x0f\x70\x97\x60\xd4\x05\xb1\x45\x41\xfd\x41\x1d\xee\ -\x9c\x05\x19\x52\x0b\x48\x5d\x4e\xfa\x7d\x9e\xf6\x14\xdb\x39\x8c\ -\xef\xd7\xa3\xf6\x01\x7b\x9f\x0d\xf2\xb6\x54\xfa\x54\x7d\x12\xa4\ -\x80\xcf\xb2\x80\xbe\x2f\x71\xe0\x2b\x4b\xdf\xcf\xf8\x52\x2b\x6d\ -\x50\xe1\x24\x70\x9c\x89\x20\x74\x40\xd1\x74\x8d\x19\xb6\x6a\x08\ -\x6a\x53\xa0\x53\x85\x9a\xb3\x9b\xdc\x77\xb9\x43\xd1\xc8\x35\x91\ -\x09\x3c\xef\xc9\x60\x56\x25\x7c\x18\x8b\x12\x01\xe8\x3d\x1f\x4d\ -\x46\x95\x68\xed\x3e\xf5\xe4\x3a\xd4\x36\xcc\xe1\x67\xd2\xd9\x3b\ -\x8d\x3d\x1f\xd3\x55\x84\x69\xf3\x77\xc8\xcc\x47\x1b\x78\xf5\xf4\ -\x9f\x2b\x76\x3e\x1a\xae\x4d\x4b\x09\x54\xf9\x3d\xa6\xe3\x0a\xdc\ -\x65\x02\xc4\x48\xdc\x4e\xa8\x42\x86\xcc\x01\x64\x03\xb5\x7f\x7e\ -\x76\x43\x55\xab\x68\xc5\x6b\x76\x00\xfa\xe2\xe2\x62\xf9\x10\x74\ -\x5e\x5e\xf5\xf1\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\x81\x3e\x61\xc3\x7c\x76\x0b\x6c\ -\x8d\x1e\x08\x0c\xfe\x54\x29\x49\xba\x30\x64\x78\xc5\x48\x0c\xa4\ -\x6d\x76\x27\x20\x16\x71\x2e\x2f\xe9\x8f\x7b\xcc\xa6\x00\xd1\x2e\ -\x7b\x04\x2e\x76\xdb\x88\x8c\x13\xab\xf1\xcb\x4e\x64\x89\xa8\x47\ -\xc1\xab\x47\xb6\x7d\x31\xab\x8e\x50\x14\x38\xa9\x5f\xe4\xda\x9d\ -\x05\x99\xce\x79\xd2\x8e\xc7\xa4\x1d\x25\x16\x04\xbb\xcb\xd2\xae\ -\x93\x61\x14\x4a\xc6\x9b\x38\xb0\x6c\xec\x51\x9f\x91\x98\x21\x6d\ -\xaf\xe3\x91\xc4\x9d\x60\xa7\xa1\x87\x96\x20\x18\xba\x41\x35\xdb\ -\x33\x14\x88\xdf\x2c\x4c\xd7\x1a\x26\x25\x28\x4c\xa5\x84\x4c\x2c\ -\x28\xbc\xf4\xa8\x37\xe1\xa0\x3b\xa2\xcf\x22\xfa\x6a\xa2\x72\x25\ -\xf2\xe0\xb3\x5c\x12\x89\x58\x9a\xa1\x66\x4c\xd2\xe8\xc3\x23\x6c\ -\x12\xa2\x74\x8d\x03\xf2\x7b\x18\xd9\xd6\xd6\xc1\x34\xfd\xc6\x1d\ -\x07\x28\x45\x91\x74\xad\x02\x14\xff\x06\xc7\x9a\x1d\xf5\x9d\x96\ -\xcf\x21\x29\x40\xee\x88\x8a\x5d\xf4\x79\x3e\x99\x17\xb8\x51\x2d\ -\xd3\xed\x5d\xf6\x16\x96\x84\x70\xde\xc8\xcc\xe7\xfc\x19\x16\x20\ -\x45\x4b\xf6\xdf\xae\x37\x95\x16\xcb\xe5\xcd\xfe\x16\x64\x2f\xe0\ -\x7a\xb2\x76\xff\xfd\x07\x79\x7a\x13\x8c\x33\xa3\x1f\x6b\x82\xe0\ -\x3f\xe4\xe9\x1b\x01\xbc\x55\x23\x0c\x7f\x00\x0c\x5d\x30\x68\x4b\ -\x81\x50\xb7\x48\x6a\x56\x93\x51\x56\xee\x92\xc7\x98\xb5\x39\x10\ -\xdc\x4d\xe8\x4f\x1d\xae\xb7\xc6\x63\x15\xfa\xf3\x0b\x6c\xd1\x71\ -\xd0\xad\x76\xe6\x9b\x09\x6c\xa6\xe0\x5b\x79\xf4\x3d\xdf\x8f\xb3\ -\xf3\xe5\x97\xf1\xe5\x17\xd9\x61\xe6\x9f\x65\xa8\xc5\xc5\x9f\xf6\ -\xd3\x19\x07\x48\x4c\xa6\x98\xa4\x9c\x1e\x23\xb7\x5c\x72\x4c\xc3\ -\xd1\xe2\x25\xeb\x4e\x59\xd8\x09\xe0\x7d\x8e\xb7\x2c\x66\xde\xc7\ -\x12\x88\x26\x3a\x7b\x88\x86\xa9\xac\x55\x66\x10\xc1\x9e\x72\x2d\ -\xd6\xbc\x4d\xe4\x81\xe1\xde\xfe\x58\xe2\xe4\x11\x96\x76\x7e\x46\ -\x74\x65\xb4\x3c\x3f\x47\x19\x49\xd6\xde\x8c\x5d\x83\xe1\xfe\x2a\ -\x98\xc0\x84\xe7\x45\x87\x5c\x5d\x1b\xc6\x88\x36\x30\xd2\xa7\x4f\ -\xb5\x1b\xe4\x01\xaf\xab\x3b\x06\x0c\xcb\x28\x30\xb5\x96\x04\x78\ -\xe6\x61\x79\x86\x72\x99\xc3\x47\x00\x79\x76\x14\xa9\x44\x10\x29\ -\x3b\xea\x65\x70\x8d\x51\xaf\x8b\x83\x8b\xf3\x8b\xd9\xbf\xb3\xf3\ -\x56\xbb\x61\x2b\x0b\x0f\x95\x15\x06\xb3\x7d\x35\x0f\x0e\x93\xff\ -\x96\x1f\xa5\xa0\xfd\xd2\x0d\xa9\xfd\x67\x92\x3b\xf5\x04\x58\xf3\ -\x42\xd3\xdc\xd7\x0c\x22\x09\x06\xb1\x1e\x7f\xb0\x6e\x7d\x31\xe9\ -\xfc\xc4\xa3\x9a\x32\x0b\xb8\x6f\x90\x16\xc6\x02\xcd\x6d\x7b\x6a\ -\xc8\xd1\x0b\x7c\x40\xba\x98\x69\xd8\x9f\x12\xb0\x23\x18\x41\x17\ -\x35\xd8\x0c\x53\x22\xff\x9a\x50\xc1\xe4\x4c\x44\x8d\xc2\x6e\x4a\ -\x24\x24\xe7\x44\xb8\x9b\x87\x6b\x89\x70\x23\x2f\xbf\x36\xb4\xb3\ -\xa5\x9c\x5c\xf5\x16\xbc\xe4\xdd\x61\x0b\x32\xed\xe7\xf2\xf6\x7b\ -\xbc\xa3\xdc\xc7\x7c\x57\x01\xd4\x88\xa7\xfc\x88\x07\x4c\x9e\x79\ -\x1a\xbc\x66\x1e\xcf\xb7\x29\xac\xa6\xec\xc2\x8e\xe8\xb1\xbb\xae\ -\xd3\xfc\x5d\x57\xf3\xf4\xec\xec\xac\xd5\x3c\x29\xb3\xf7\x2a\x6e\ -\xa2\x44\xf9\x3f\xa1\x51\x81\xc7\xdf\x78\xb8\x4c\x4e\x10\x08\x97\ -\xfb\x54\x31\x19\x8b\x9a\x91\xa7\x98\x9e\xc4\xee\x0f\xc8\x11\xb9\ -\x24\x87\xa0\xae\x9b\x25\xb2\x92\x73\xc4\xc5\xe9\x5a\xa4\xc5\x8c\ -\x16\xb7\x56\x5a\x14\x75\x5f\xe4\xeb\xaf\x9d\xfb\x62\xe5\x87\x07\ -\x96\x95\x97\xaf\xf8\x88\xf9\xfa\x30\xf4\x16\x48\xcc\xfc\x0d\x6c\ -\x6e\x46\xdd\x79\x35\xf9\x74\x6b\x11\x1f\x2e\x1f\x5d\x6f\xbd\x04\ -\xa9\xda\xde\x28\x70\xe0\x2f\x8b\x81\x16\xe4\xcd\xcd\xe5\x9f\x9b\ -\xc0\x03\xa5\xe5\x3b\x95\x46\x1e\xf3\x65\x6d\x3e\xeb\xef\x64\xed\ -\x4a\x5c\xc5\x05\x9c\x45\x3f\x81\x59\x17\x5d\x60\xa3\x85\x23\xa6\ -\xda\xb9\x98\x97\xd1\x9f\xf8\x8e\x31\xe0\xd4\x90\x2a\x9d\x19\x4a\ -\x89\x0a\x59\xe4\x60\xef\x2b\xb6\xb6\xe7\x5b\x5c\xde\xef\xc3\x4e\ -\x11\xca\x71\x73\xe8\xc1\x7e\x51\x27\xa7\x98\x0e\xc3\x2d\xa6\x12\ -\x4c\x1f\x7a\xa1\x92\x48\x00\xac\xc4\x9e\x31\xe7\x14\x57\x63\x19\ -\x82\xf7\x07\x40\x0e\x8a\xa5\x51\x64\xfd\x48\x60\xb2\x36\x57\xe4\ -\x61\xca\xf1\x63\xc1\x28\x27\xeb\xf7\x63\xa9\x48\xe4\xed\x74\x51\ -\x96\x2e\x3a\x2d\xa7\x8a\x16\x64\x78\x2d\x4c\x88\xc1\x16\xc4\xc8\ -\x82\x0d\xf7\xaa\xe7\x07\xd4\x7f\x04\x51\x19\xae\x89\x19\x4f\x1f\ -\xba\xc1\xe5\x91\xfa\x5e\x22\x77\x66\x7b\xaf\x76\x6f\x3b\x93\x0e\ -\xad\x1a\xbc\xdc\x38\xbd\x90\xf8\xb6\x54\x3c\x14\x35\xc0\xf2\x1d\ -\x39\x3b\x03\x6c\xd5\x9b\xdd\x05\x37\x3b\x3d\x4e\x40\xf6\x01\xdf\ -\x9b\x78\xb3\xe0\xf2\x39\x46\x59\xf7\x0a\xe2\x2c\xf5\xbb\xb3\xaf\ -\x39\xda\x0f\xc4\x66\x08\xa1\x83\xbd\xf7\x00\x2f\xf5\xd1\xee\xa2\ -\xb1\x37\xe5\xc4\x19\xa2\x01\xf6\xe4\xaf\x49\xa0\x7e\x7d\x21\x38\ -\xf5\xcc\x4f\x4c\x65\x0a\x07\x92\x6a\xea\xa5\x9b\x4a\xea\xcb\xb0\ -\xa5\x2d\x61\x82\xf7\xcd\xcf\x3d\x80\xc7\xfc\x1a\x05\x7e\x10\x36\ -\x43\x20\x49\x9f\x8e\xb8\x37\xcd\x1a\xf7\xd9\x3b\xe6\xdd\x32\xfc\ -\x36\xf0\xb3\xa8\x73\xf3\x92\x06\x55\x1b\x96\xd4\x00\xb3\x97\xf1\ -\xfe\xf3\x97\x81\xe7\x9a\xe7\x4a\x92\x19\x70\x8c\xad\xfa\x7a\x6a\ -\x59\x49\x6f\xb8\x68\x4b\xe5\x7c\xd5\x2e\x89\x02\x27\xfc\x32\x7d\ -\x7a\xcb\xde\xe3\x1f\xc9\xb9\xd1\xd8\xc3\x4f\xc1\xca\x21\x63\x95\ -\x0a\xbb\x7c\xfd\xb8\x60\x22\x3b\x05\xb9\x12\x0f\xc5\x1b\xee\xb1\ -\xab\x61\x10\x80\x8c\x7d\xa0\x5c\xfa\x50\xe7\x98\xba\x45\x46\x37\ -\xf7\x8b\x1a\xdd\x47\x87\xf9\x08\x2a\x85\x9f\xe2\x01\x27\x37\x4d\ -\xfd\xf6\x7e\x52\x9d\xd1\xe6\xa0\x3f\xc1\x24\xb5\xe1\x37\xac\xc2\ -\xf3\x5a\xc5\x18\xa4\x9c\xd0\x34\x50\xed\x84\x66\xb6\xd0\x6c\x55\ -\x74\x52\xb0\xc4\x65\x86\xdf\x4c\xf6\x64\xea\xe0\x54\x94\x4e\x89\ -\x2f\xdb\xa4\x08\x4d\x5e\x8c\x5c\xe3\x25\x9f\x63\xc1\x47\x1c\x73\ -\x2b\x65\x78\x2f\x21\x06\x41\xcd\x2b\xb3\x7b\x10\x35\x51\xd2\x5b\ -\xd0\xe1\x98\xd1\x51\xc9\x1d\x6d\x98\xfb\xad\x01\xba\x9e\x01\xb4\ -\x9e\xaf\x77\x4b\x86\xc3\xc6\x47\xdd\x91\x7c\xa6\x9d\x50\xe0\x9a\ -\xe7\x0c\x3b\xa1\x7c\xe0\xef\x09\x1d\x8d\x7f\x25\x1f\x80\x42\x41\ -\x87\x53\x21\x82\x3b\x63\x41\x6f\xe2\x61\xaa\x95\x1d\xa5\xe2\x23\ -\xf3\x29\xde\x4d\xa5\xca\x72\xc7\x78\x5e\x05\x8a\x9c\xd4\x77\x8a\ -\x08\x87\x3f\xab\x77\xf8\x8b\xfa\x86\xbf\xe2\xc2\x81\xcd\x70\x8d\ -\xf8\xb7\x10\xd4\xb8\x04\x16\x82\x1a\x57\xa1\x0b\xa2\x65\x58\xe7\ -\x22\x18\x00\x6a\x5c\x03\x03\x40\x8d\x4b\xf0\x92\x3a\xdf\x65\xdd\ -\xcb\x10\x01\x51\xe3\x52\x44\x40\x94\x5a\x8e\xda\x4d\x95\x92\xa1\ -\xad\x66\x7e\x5e\xd8\x7c\x6b\xe5\x2b\xb4\xe2\x0e\xf5\x62\xee\x4a\ -\xe3\xc6\x8d\x39\x0f\x36\xd1\x5c\x59\xd5\x87\xcf\xe3\x77\x8e\x04\ -\x7d\xe3\xe2\x0d\x31\x61\x9d\xb9\xf6\x90\x17\xec\xf1\xe3\x48\xa2\ -\x82\x91\x5b\x8b\xbc\x03\x12\x7a\x86\xa0\x57\x8f\xf5\x15\xee\x3f\ -\xb8\x39\x06\x86\x3d\xbe\xef\xfe\x8e\x1f\x28\xf0\x5d\x2a\xca\xdc\ -\xa1\x5e\xcc\x0a\x4b\x2c\xe0\x8f\x68\x8a\x7d\x00\x44\x93\xa7\x71\ -\xdc\xd6\x78\xbc\xfb\xf3\xbc\xa8\xf0\x96\x48\xa0\x92\xe2\x67\xd9\ -\xcf\xbc\xbf\xf0\x74\xba\x32\x6c\xed\xbb\x5f\xdf\xc2\x6e\x5a\xe1\ -\x23\xf0\x50\xe0\x54\x2e\x79\x16\xb8\x56\xf3\xcf\xa7\xee\x5c\xab\ -\x6b\x75\xad\x2e\xc8\xe8\xdf\x6a\xd7\xea\x3b\x3c\xd5\x83\xd7\xfd\ -\x61\x84\x50\xda\xa3\x3e\x14\x54\x8d\x60\x8e\x0a\xc4\x14\xef\x16\ -\x55\xf6\x8b\xe6\xc8\x24\x88\x17\x19\x2f\x7c\xe2\xa9\x5f\xc7\x86\ -\x73\x9e\x0c\xd4\xaf\xe8\xa7\xc5\xeb\xc6\xa3\x6c\xb1\x30\xf4\xe8\ -\xba\xcc\x45\xa7\x2d\xaa\xa4\x50\x64\x5a\xbf\x19\x34\x03\x75\x65\ -\x7b\x59\x8f\x1b\xcb\x0e\x86\x24\xb0\xa9\xfa\xa9\x6e\xab\xb0\x55\ -\xf2\xac\x4f\x6b\x59\xab\x30\x34\x67\xba\x43\x3a\x66\x5d\x5d\x46\ -\xde\x60\xdc\xda\xac\x56\x5d\x42\x39\xff\x3a\xc3\x9d\x4c\x5e\xa7\ -\x4c\xfe\x81\x25\xb2\xfd\x22\x91\x4d\xd5\xe8\x17\x21\xf9\x32\x02\ -\x11\x19\xec\xc7\x95\x86\xc9\xca\x44\x5f\x51\xbb\x58\xa3\x58\x0b\ -\x2b\x39\x67\x19\x31\xe6\xa8\xf7\xe5\xfe\xe9\x3e\x19\x51\x31\xe0\ -\xfe\xe5\x7e\xb3\xb9\x8f\xc9\xc6\xed\x31\xbf\x1f\xd1\x71\x98\x2d\ -\xdd\xf9\xeb\x5a\x3f\xbf\x11\xc1\xe8\x23\x6c\xdd\xba\xc1\x44\x60\ -\x76\x6d\xaa\x15\xbc\xe7\x4c\xa4\x0a\x46\x66\x44\xa9\x21\x89\x97\ -\x18\x28\x35\xa3\x74\x34\x9f\xc4\x78\x04\xf0\xa7\xcb\x75\x13\x10\ -\xa8\xcc\x77\x65\xe7\xd3\x37\xfd\x1e\x08\x19\x5b\xb0\x67\x28\x19\ -\x03\x01\xd8\x43\x03\x3b\x78\xc5\xa9\x17\x0c\x0e\x86\x48\xd8\xba\ -\x42\x23\x20\x3d\x6e\x3e\x20\x57\xf8\x2d\xc6\x97\x13\xa5\xf4\x26\ -\x2f\x03\x90\xeb\x89\x1c\x86\xf5\xf3\x80\x31\xc0\xca\x72\x90\xa4\ -\x44\x47\x26\x34\x0f\x71\x37\x0f\x24\xec\x6d\x65\x60\xd9\x9c\xd9\ -\x6c\x04\xcd\x2a\xd7\x02\xca\xa2\xf5\x7a\xb8\xa8\xeb\x01\xcb\xc6\ -\x79\xb3\x51\x14\xd5\xae\x09\x47\xc6\xf7\x33\x07\x98\x59\xed\x5a\ -\x80\x09\xd3\x0a\xb3\x81\x89\x6a\xd7\x02\x4c\x22\x05\x3c\x1b\xa2\ -\x54\x93\xf2\x60\x25\x0b\xb0\xa7\xb6\x60\x52\x0b\x52\xa9\x45\x2e\ -\xec\x44\x7c\x66\x0e\xa7\x98\x59\xcc\x9e\xcd\xa8\x12\x00\x80\xbe\ -\x33\x6e\x7d\xc3\x4c\x3a\xdf\x8e\x8b\x96\xc1\xc0\xa7\x5e\xc7\xf1\ -\xf0\xd6\x03\xf7\x29\x5e\xb4\x80\xfe\x1c\x53\xaa\x5b\xc0\x86\x88\ -\xf1\xdb\x78\x5f\xa9\xbb\x64\xda\x8d\x59\x13\xd3\xa5\x17\xa8\x0e\ -\xa8\xc1\xd7\xe6\x5a\x87\x59\x9f\x58\x6c\x30\x82\x9f\x6e\xb2\x1a\ -\x09\x7f\x13\x35\x1d\xa3\x91\xa7\xa7\x97\x08\x02\xb7\xef\x3b\x17\ -\x00\xf0\x7d\xf8\x38\xed\x1c\x9d\x5d\xb4\x1b\xd3\x50\x9d\xe1\xdb\ -\x0f\x3b\x72\x19\x7e\x6e\x4e\x9b\xa4\xe9\xde\x8e\x9b\x67\xc9\xee\ -\xce\x9b\x59\xdd\x99\x9f\xd2\x2e\x4d\x02\xb5\x6b\xc5\xf4\xec\xfe\ -\x8c\x6a\x71\x8c\x38\x4d\xe0\xf8\xa8\x0c\x8e\x4f\xce\x9a\xa9\xee\ -\x8e\x2b\xc3\xf1\xf1\xea\x70\x7c\x5a\x2d\x8e\x4f\x93\x84\xd7\x3a\ -\x3b\x5c\x25\x8e\x5b\x67\xad\x0d\xc4\x71\xf8\x5d\x99\x8a\x31\xdb\ -\x5a\x29\x66\x9b\xa7\x6b\xc3\xec\xf2\x12\x22\xbc\x02\xad\x5a\xcc\ -\x9e\x9c\x27\x19\xf9\xf4\xa4\x0c\x66\x8f\x4e\x8e\xb7\x40\xf6\x86\ -\x97\x3c\x55\x8b\xd9\xa3\xa3\x14\x66\xcf\x56\x49\xb3\x55\x62\xf6\ -\xac\xbc\xc4\x8d\x3e\x94\x51\x2d\x92\x9b\x29\xfa\x6d\x5d\x94\x92\ -\x0c\xc7\xe8\x2b\x49\x74\x97\xa9\x26\x37\xc5\x76\x88\x5d\xfa\x59\ -\xb1\xf5\x90\xb6\xd0\x4a\x49\x89\x56\xeb\xf4\x31\xc6\xc8\x7c\x2c\ -\xc7\x1f\xa1\xbe\xdd\x98\xf0\xce\xde\xff\x01\xff\x94\xb5\x4d\ +\x00\x50\xcd\x78\x9c\xed\x1c\x6b\x73\xdb\x36\xf2\xbb\x7f\x05\x46\ +\x1f\xee\xd2\x8e\x6b\x59\x7e\xe5\x71\xb2\x3a\x89\x5d\x27\xb9\x49\ +\xae\x6e\xe5\x26\xfd\xe6\x81\x48\x48\x44\x4d\x12\x2c\x08\x5a\x52\ +\x7f\xfd\xed\x02\xa0\x48\x91\xd4\x83\xa6\x25\x3b\x19\xcd\x78\xc6\ +\x22\x00\x62\x17\x8b\x7d\x2f\xc0\xee\xcf\x93\xc0\x27\xf7\x4c\xc6\ +\x5c\x84\xe7\xad\xce\xc1\x61\x8b\xb0\xd0\x11\x2e\x0f\x47\xe7\xad\ +\x3f\x6e\xae\x7e\x7a\xd5\xfa\xb9\xb7\xd7\x4d\x78\x36\xe8\x04\x06\ +\xf5\xf6\x48\xd7\xf1\x69\x1c\xf7\xde\x27\xfc\xcd\x9b\x4b\x4e\x7d\ +\x31\x82\xff\xfe\xa8\xcf\x94\x82\x97\xe3\x4b\x49\x87\xaa\xdb\x36\ +\x83\x60\xf4\x98\xbb\x23\xa6\x88\x7e\x3e\x6f\xfd\xf6\x55\x3f\xb6\ +\x48\x48\x03\x76\xde\x5a\x3a\x09\x02\x23\xdd\x48\x8a\x88\x49\x35\ +\xb5\x6f\x8c\x98\x08\x98\x92\x53\xdd\x49\xba\x92\x39\x4a\xff\x22\ +\xdd\x49\xef\xb0\xdb\x9e\xd8\x87\x29\x3e\x4c\xed\x03\xa0\xa0\xbc\ +\xde\xe9\xcb\xd3\x6e\xdb\xfc\x34\xcd\x1e\xe3\x23\x4f\xf5\xce\xce\ +\xce\xba\x6d\xfb\x5b\xcf\xd9\x4e\x27\xed\xb6\x53\xe0\x55\x98\x8c\ +\x79\xe8\x8a\xf1\x0d\x57\x3e\xb3\xc8\xc4\x4a\x02\xf2\xbd\x8f\x41\ +\x24\xa4\x6a\xff\x32\xc1\x7f\xdd\xb6\x6d\x2d\xcf\xe7\xd3\xa9\x48\ +\x32\xca\x7c\x79\x27\x26\x9f\x74\x93\x9d\xae\x00\x2f\x8e\xa8\x03\ +\x13\xb5\x2c\xf6\x61\x12\x0c\x98\xec\x01\xee\xf6\x97\xc1\x3d\x0f\ +\xa1\x34\x45\x40\xe5\x88\x87\x85\x19\x5e\x2f\x9d\x81\x2b\x16\x64\ +\x64\xcc\xef\xe4\x7b\x29\x92\x08\x70\x9e\xed\xa5\x7d\xee\x1c\x59\ +\x00\x25\xf0\x2a\xa3\x55\x8e\x5c\x97\x7f\x5e\x91\xa1\x90\x01\x55\ +\x44\x44\x0a\x38\x2d\xce\xd3\xac\x8c\xd2\x6a\xca\xad\x24\xde\x42\ +\xfa\x55\x41\x5b\x4e\xc5\x85\x84\xac\x9e\x2a\x23\x67\xc5\x3a\x3e\ +\x94\xd7\xb1\xc6\x4a\x96\xac\xa5\x0a\x85\xd5\xeb\xc9\x26\x3c\x5c\ +\x73\xc2\xb9\x55\x95\x39\xe5\x13\x1d\x30\x3f\x65\x13\xc5\x26\x4a\ +\x37\x74\x6e\x8f\xf3\x30\xcb\xdc\x02\x03\xe7\x06\x14\x04\x8c\xc4\ +\x6a\xea\xb3\x02\xaf\x2c\xc4\x91\x68\xd9\x07\xac\xf2\x4b\x99\xc7\ +\x7b\xc5\x32\xb4\xae\xba\x96\x6c\x78\x21\x82\x81\xc8\x31\xfe\x08\ +\x3b\x22\xe8\x70\xb0\x63\x00\x1d\x4b\x97\x25\x84\x7f\xc3\xa3\xea\ +\x95\xdd\x78\x3c\x26\xf0\xa7\x3c\x46\x40\xcd\x79\xc2\x25\x8e\x27\ +\x44\xcc\x5c\x14\x11\xc2\xf5\xc2\x61\x20\x81\x07\x25\x69\x18\xfb\ +\x54\x3f\xa2\x0c\x89\xc1\x5f\xa0\xb7\x88\x23\x7c\x1c\x19\x2a\x41\ +\xae\x24\x63\x17\x6f\x2f\x0f\xc8\xde\xc7\xa1\x6d\x0f\x68\x14\xe1\ +\x0b\x00\xc3\x4e\xbc\x4f\x80\xe1\x48\x90\xc4\xca\xb6\x10\x5a\x18\ +\x3b\xe4\x3e\x83\xa6\x50\x51\x1e\xe2\x33\xcd\x40\x8b\x90\x28\x3a\ +\x80\x6e\xe5\x81\xf8\x8e\xb9\xef\xe3\x40\xb0\x18\x16\x8f\xd8\x20\ +\xe2\xf3\x90\x69\xcd\x1b\x1f\xec\xad\xbd\x61\x25\xca\x39\x89\x94\ +\x2c\x54\x1f\x43\x97\x4d\x0a\xe4\x5b\xcc\xaf\xeb\x4e\x8e\xfb\xf7\ +\x4b\x88\x86\x05\xf8\xca\x8d\x99\x3a\x6f\x1d\x16\x80\x38\x16\x71\ +\x77\x32\xb4\xac\xe7\x3c\x74\x29\x08\xed\x9a\x2a\x6f\x35\xb0\xcf\ +\xc2\x6d\xa7\x26\x75\x6d\x68\x05\x46\x5e\x47\xb6\x66\x2c\xf8\x3f\ +\x11\x32\xf2\x62\x48\x63\xc5\x62\xf5\x43\xd5\x6e\x2d\x82\xda\x2e\ +\x82\x6d\x84\xc7\x1f\xc0\x89\x2e\x1b\xd2\xc4\x4f\x79\x9a\x86\x6e\ +\xc6\x49\x4f\x87\xd8\xaf\x92\x83\xba\xa4\xfe\xf3\xc2\xea\x62\x26\ +\xb2\xa0\x2b\xf2\x22\xf7\x84\x28\x49\x46\x15\x23\x11\x95\x14\x5d\ +\x36\xee\x58\x15\x55\xb4\xef\xdb\x47\xa9\x7f\xc7\x94\xe3\xb1\x46\ +\x88\xac\xb4\x27\xdd\xb6\x31\xef\x99\x37\x90\xef\x5e\xdb\x13\xb0\ +\x8b\xf2\x84\xe4\xff\xa0\x0e\xf6\x4d\xfb\xed\xcb\xbc\x8f\x50\xc7\ +\x00\xfb\xf8\xd0\xd0\xf6\x3e\x85\xd5\xf5\x98\x73\x57\x69\x75\xb1\ +\x03\xac\xee\xed\xd1\xc3\xed\x2e\x1f\x82\x05\x33\xa6\x37\x09\xf5\ +\x84\x68\x18\x91\x0a\x71\x3b\xd0\xff\xc8\x58\x84\xff\x56\x64\xc0\ +\xac\x11\x66\xee\xc3\x0d\xd9\x62\xea\x1a\x50\xa8\x52\x5c\x1e\xb0\ +\x30\xae\xf0\x86\x6b\xc0\xa9\x67\xd3\x10\xf6\x73\x35\x69\xdb\x64\ +\xa3\xce\x43\x45\x23\x12\xe0\xec\x6c\x6d\xbb\x8c\x20\x5e\x5b\x98\ +\xbb\x6d\x5b\xb1\x6b\x6b\x4a\xff\x4c\xf6\x23\x0a\xaf\x13\x0c\xb6\ +\x58\x6a\xb6\x8c\x7f\x9b\xd3\x00\x60\x67\xc5\x26\xb4\x80\x31\x06\ +\x5b\xe3\x24\x03\x6e\xc7\x43\x93\x39\x9b\x5a\x93\x87\xf4\xe4\x96\ +\x8d\x86\x3a\xa4\x1a\xd3\x50\xe9\x40\x2e\x14\xe1\x4f\x38\x83\x4b\ +\x06\xbe\x70\xee\x62\xf2\x62\xc0\xc0\x83\xd4\xb1\xd4\x98\x2b\x0f\ +\x02\xaa\x1f\x7f\x40\x9f\x6d\x0b\xac\xf5\xa3\x41\x61\x5b\xac\x15\ +\x2b\x2a\x53\x88\xdf\x28\x7b\x6d\xd6\x8d\x6b\xe6\xc4\xad\xe0\xd7\ +\x85\x5c\xf0\x99\x4e\x48\x3f\xc2\x10\x81\xf4\xd9\x08\x1c\x8d\xa7\ +\x70\xe8\xfa\x11\x0f\xab\xa4\x31\x86\xf6\xd5\xee\x5c\x40\x27\x3c\ +\x48\x82\x3e\xff\x87\x15\xd7\x08\x4d\x05\xef\xdf\x64\x7d\xcf\x0e\ +\xe7\xf2\xbf\xb3\x5e\x9b\xfb\xed\x9c\xbd\x7c\xf9\xf2\xa8\x73\x3a\ +\x97\x0c\xce\x16\x59\x9c\x76\x4d\x49\x5c\xa6\x33\xbe\x7a\x2c\x24\ +\x6c\x92\xe6\x74\x62\xbd\x23\x31\x6a\x82\xcb\x3f\xaf\xf6\x51\x77\ +\x4c\x09\x95\xcc\xa4\x5b\x30\x45\x0a\x7a\x81\x87\x24\x12\xfe\x54\ +\x8f\x3c\x20\x3a\x5f\x74\x4f\xfd\x84\xcd\xb2\x46\x86\x2e\xc4\x67\ +\xe1\x08\x54\x8b\x18\x12\x46\x1d\xfd\x1f\x7b\xd3\x57\x49\x6c\xb6\ +\x1d\xa6\xf8\x38\x24\x87\x1a\x56\xa8\x47\x8c\x3d\xe1\x33\x8b\x8a\ +\x9e\x53\x47\x4c\x2e\xa1\xe0\x96\x82\xfc\x49\x8a\xa4\x49\x5f\x3f\ +\x78\xb8\x1e\xd1\x48\x57\x67\x71\x4e\xb7\x92\xc5\x01\x42\x59\x82\ +\xa7\x12\xb0\x53\x50\x55\x71\xe6\x71\x23\x15\xf5\x40\x05\x75\x51\ +\x4a\x40\x3e\x81\x82\xba\x02\xb0\x17\x3a\x25\x2a\x4b\x4a\x0a\x51\ +\x72\x6c\xdf\x52\x35\xc5\xc3\xba\x6a\xea\xf8\x70\xb9\x9e\x3a\xdc\ +\x9e\x82\xba\xf1\x58\x55\x2e\x78\x58\xc8\x3e\x83\xa1\x5f\x90\xee\ +\xdd\x96\x9f\x61\xd1\x33\x8c\xb2\x93\xe3\x2a\x39\x7e\xb5\xbe\x1c\ +\xd7\xf0\x98\x4f\x1f\x37\xea\x4a\x23\xad\xa1\x14\x81\x36\x47\x31\ +\xcc\x43\x60\xb1\x4c\x66\xe1\xd7\x5f\x10\xf3\x6a\x4b\x88\x86\x12\ +\x37\x81\xbc\xd3\x2e\x26\x58\xb1\x44\x6a\xaf\x1a\xdf\x74\x39\xa8\ +\x77\x3a\x25\x3a\x93\x2d\xf7\xc9\x00\xc8\x15\xd0\x3b\xdb\x8d\x06\ +\x32\x8e\xc1\x36\xc6\xdc\x9f\x12\xe6\x72\x5d\xc6\xd8\x84\xc7\xad\ +\xcb\xa2\xe9\x12\x34\xce\x5b\x74\xc1\x47\x08\xfc\x93\x86\xbd\x93\ +\x8b\x6a\xb9\x38\xdd\x88\x5c\xbc\x7e\xb8\x5c\x60\xad\x2e\x95\x87\ +\xa1\x64\xcc\xa1\xae\x61\x7d\xd8\x71\xf4\x0d\x91\xfd\xb1\x24\xc2\ +\x43\x87\xbb\xe0\xb8\xcc\x84\x46\x33\xd7\x98\x4b\x74\x0c\xdf\xb1\ +\x31\x78\x8e\xfb\x46\xc2\x1c\x8a\x65\xba\x3b\xac\xec\x8d\x3d\x50\ +\x91\x07\x07\x0d\x1c\xb7\xc5\x9c\xfe\x5f\x40\x89\xa4\xe7\x33\xb6\ +\xc2\xde\x48\x8a\x0c\xe0\x8e\xbf\xab\xf8\xfb\x6c\x13\xfc\xdd\x88\ +\xbb\x4b\x5a\x9f\x02\x73\xa7\x4c\x9c\xab\x33\x0f\xa9\xc3\x32\xad\ +\x6f\xe2\x24\x13\x89\x1c\xbb\x3a\x92\xd1\x03\x36\xc1\xc9\xe6\xe8\ +\x0e\x39\xbe\x9c\xa1\x05\x40\x53\x88\x24\x60\xf1\x82\xda\xd1\x46\ +\x5c\x1b\x80\xb6\xe3\xed\x6a\xde\xee\x9c\x6c\x44\x79\x77\x1a\x54\ +\x92\xaa\xf8\x1b\xdd\x91\x19\xfb\x16\x93\xc9\x30\x39\x36\x98\xaa\ +\x2d\x60\xe1\xe3\x21\x0e\x7c\xc3\x1e\x77\x20\xf7\x9c\x8d\xc1\x9b\ +\xc1\x43\x69\x5c\x84\x9b\x60\xf7\x6b\x83\x42\x19\x47\xea\x0b\x90\ +\xc3\xc7\x46\xa4\x1e\xff\x5b\xfa\xec\x44\x60\x81\x08\x74\x36\x22\ +\x02\xaf\x1e\x57\x02\xb2\xb4\xb6\xa9\xa5\x22\xef\x23\x62\xda\xc5\ +\x57\x34\x74\xa9\x74\xad\x2f\x8f\x23\x08\xc6\xb2\xf0\x56\x08\xae\ +\x3b\x78\x3f\x36\x79\x85\x8d\x26\x29\xe6\xd1\x7b\x86\x99\x30\x6c\ +\xc5\xa3\x4f\xae\x70\x92\x5a\x59\xcc\x1a\xc2\x81\xe7\x50\x66\x28\ +\x0e\x81\xf4\x06\x0f\x1d\x03\xe3\x62\xb6\x25\x07\x7d\xe5\x62\x16\ +\x61\x27\x07\x0b\xe4\xe0\x68\x33\xa6\xe0\xf0\x71\x05\xc1\xa3\xfa\ +\xe0\xc9\x4c\xfb\xdb\xd3\x72\x69\x38\x1b\x83\xa0\xf8\xcc\x38\xf1\ +\x9b\x60\x66\x7b\x72\x52\x63\x41\x06\x22\x41\xae\xe6\x4c\xbb\x37\ +\x0d\x61\xd6\x60\x66\xa3\x0c\x2e\x27\xc3\x0f\xd4\x9e\xc2\xd9\xb1\ +\x74\x25\x4b\xd7\x48\xbd\xd6\x61\xe9\xce\xe3\xb2\xf4\x18\x4b\x07\ +\xb3\x9a\x84\xd1\xcd\x10\x68\x62\xfe\x0f\x0f\xf0\x61\xae\xc6\xd6\ +\x32\x52\xa6\x07\x6f\xc2\x65\xd2\xb8\xf2\x8e\xaf\x4f\xb7\x6a\xee\ +\x33\xd5\x50\xed\xfb\x08\x89\x6e\x06\x59\x78\x82\xad\xa9\x20\xfc\ +\xae\x51\xc8\xa1\xad\x41\x37\x04\x57\x43\x06\x0c\x09\xae\x2d\xf8\ +\xaf\x06\xee\xf7\x28\x06\xf3\x9d\x73\x73\xe5\xc6\xd5\xb8\x66\x30\ +\x4a\x9f\x53\x00\xc5\x3d\xaf\xbe\x64\xf0\xf5\xfd\xe3\x5d\x32\x48\ +\x4b\x58\x30\x9a\x3b\xa5\x4a\x6e\x63\xb9\xaf\x11\xd4\x54\x15\x85\ +\x4f\x96\x8b\xf7\xe2\x28\x80\xa2\xf0\x09\x72\x83\xc5\x05\x4a\xb0\ +\xfa\x41\x2e\xac\x79\x92\xcf\xb7\xfc\xd2\xe4\xd8\x1f\xd6\x37\x22\ +\xbb\x6c\x20\xbd\xac\x5e\x3b\xc4\x45\xcc\x49\x1a\x26\x88\x6b\xe8\ +\x06\x83\x84\x5e\x7e\x46\xfe\x9d\x6e\x28\xb3\xca\x92\x2b\x48\xb7\ +\x35\x2f\x21\xf5\xbf\x3c\xbe\x7e\xc8\x95\x4e\xbf\xf5\xeb\x48\xe9\ +\x8a\xe6\x54\xd3\xaa\x35\x2d\x59\x55\x35\x3b\x3d\x9b\x8b\x49\x2b\ +\xaa\x5a\x4f\x7e\x31\x49\x1f\x4b\x94\x25\xfb\xd1\xd7\xcd\x73\x19\ +\xdf\x32\xf6\x30\x1a\x22\x65\x7d\x77\xa7\xb0\x08\x06\x24\xed\xfd\ +\xa6\xde\xbc\xf9\x30\x9b\xb1\xdb\xd6\x8d\xb5\x95\x0e\x86\xc8\x1f\ +\x20\xa2\x59\xac\x74\x16\x96\xbf\x4f\x96\x57\xbf\x8f\x1a\x95\xbf\ +\x61\x98\xa6\x51\x73\xeb\xb4\xf2\x12\x58\x93\x03\xa9\x6b\x5f\x03\ +\x43\xb5\xb5\xf8\xde\xd7\xb7\x7f\xd5\x2a\xbe\x1f\xed\xae\x5a\x55\ +\x40\xdd\x5d\xb5\x6a\x84\xd5\x53\x47\xf6\xaf\x9b\x79\xf8\x2b\x3c\ +\xde\x55\x65\xad\xfe\x33\xb9\x37\x0b\xc2\x7d\x6b\x4a\x0e\xb7\x5a\ +\xc8\x6f\x9b\xdf\x9f\xd5\x4b\xc3\x7c\xb1\xf6\xe7\xd0\x8b\xc7\x92\ +\xb8\x04\x04\x4d\x9a\x22\x3b\x6c\x49\xed\x25\xb0\xef\x43\x49\xce\ +\xd1\xf1\xfb\x54\x96\x37\xf6\xc0\x19\xd8\xc0\x17\x68\x04\x23\x89\ +\xc7\x20\xfe\x45\x83\xe8\x3f\xe9\x59\x9f\x27\x54\xa1\xbf\xd3\xb1\ +\x41\xeb\xe2\xed\xe7\x46\x68\x3c\xb5\x6a\x9a\x4b\x78\x3f\x5e\xd2\ +\x71\xb9\x4f\x5a\xe7\x94\x34\x4a\x36\x56\x22\xe3\x7d\x3c\xce\xc5\ +\xf4\xe1\x81\xb1\x87\x12\xae\x4d\x83\x90\x77\x04\x2f\xc1\x52\xf4\ +\x85\xc8\xc0\xa7\xce\xdd\xbe\x76\x9a\x06\x4c\x61\x2c\x2f\x19\x75\ +\xe9\x80\xfb\x1c\x80\xd3\x11\xc5\x12\x93\x7d\x7d\x00\x43\x31\xb9\ +\x14\xba\x1b\x49\xbd\xcf\xf8\x37\x87\xad\xb5\x6b\xfa\x4c\x18\x40\ +\x6f\xa0\x8a\x4c\x32\xb6\x00\x79\x00\x64\xed\x29\x99\x80\x46\xd0\ +\x3f\x37\xa9\x84\xfa\xf7\xa3\x4f\x98\x48\x7d\x67\x16\xf2\x3c\x35\ +\xd0\xf3\x4d\x57\xcc\x82\x85\xf5\xd2\x15\xbf\x5e\xbc\x7d\xfc\x74\ +\x45\x26\xa3\xdf\x4b\xba\x62\xee\x8e\xf4\x37\x9f\xae\xa8\xa1\x6e\ +\x57\xe4\x80\x1f\x78\x91\x8d\x82\xf2\x8c\xc9\x8b\xe3\x4b\x73\x34\ +\xab\xea\xce\xda\x46\x0e\x16\xda\xb4\x0a\x32\xbd\x46\x61\x2b\x59\ +\x58\xe1\x50\x0b\x6c\xa7\xcb\xf4\x5e\xe4\x73\x4e\x69\xe9\xc3\x64\ +\x9c\x16\xe9\xae\xaa\x54\x53\x96\x65\xfa\x62\xe7\x98\xcb\x31\x95\ +\xf5\x56\x8d\xcc\xd2\x7c\x52\xc9\xe6\x93\x8e\x4a\xf9\xa4\x34\x95\ +\x74\x52\x4a\x25\xcd\x65\x91\x8a\xa8\xcc\xe5\x8e\x32\x22\xe5\x28\ +\x99\x23\xa3\x55\x4e\x69\x54\x6d\x95\xcd\x79\xeb\xac\x45\x8c\x9a\ +\x38\x6f\x75\x3a\xad\x36\x8e\x8c\xf8\x24\xa0\xd1\x30\x09\xf5\xb1\ +\xaa\xde\xdf\xd7\xfa\xf9\x4a\x8a\xe0\x33\x0f\x58\x5f\x24\xd2\x01\ +\x03\x5e\x18\x85\x9f\x61\x4b\x62\x25\x02\x03\x31\xd6\x98\xe4\x5b\ +\x0c\x96\xb9\x4f\xb5\xe5\xca\x29\xd9\xd7\xd9\x70\x3f\x26\x8a\x81\ +\xcb\xd3\xb3\x5f\x66\x83\xdd\xb0\x0d\x7b\x86\x54\xd4\x85\x25\xc3\ +\x0c\x6d\x9c\xc0\x7c\xaa\xed\xc0\x43\xc2\xe9\x0e\x4d\x80\x22\xdc\ +\xe5\x88\x14\x6a\x3b\x95\xc8\x94\x31\x5e\x84\x15\xce\x66\x30\x8f\ +\x9b\xa3\x65\xaf\x24\x56\xd3\x67\xd6\xb9\x15\x54\x52\x1d\x5f\x8d\ +\x4b\xd6\xbb\x1d\x64\x6c\xe4\xbe\x00\x99\x59\x6f\x73\x64\xe6\x1b\ +\xf4\x07\x04\x25\x8b\xb5\x0c\xc4\x5a\x5a\x1c\x11\x86\xe6\x00\x22\ +\x3e\x77\xdb\x09\xef\xed\xfd\x1f\x9d\xcd\x9d\x8f\ +\x00\x00\x09\xfb\ +\x00\ +\x00\x57\x7d\x78\x9c\xed\x5c\x5b\x6f\xdb\x3a\x12\x7e\xcf\xaf\x20\ +\xfc\xb2\x5d\xa0\x27\xbe\xe4\xda\xc0\xf1\x41\xdb\xf4\x12\xa0\x3d\ +\x9b\xc2\x49\xbb\x67\x5f\x02\x5a\xa2\x6d\x6e\x24\x51\x4b\x52\xb1\ +\x5d\xec\x8f\xdf\xe1\x45\xd6\xd5\x8e\x6d\x39\x72\xb6\xc7\x45\x80\ +\x4a\x24\x3d\x33\x1c\xce\x7c\x43\x0e\x49\x75\x7f\x9f\xfa\x1e\x7a\ +\x24\x5c\x50\x16\x5c\x36\xda\x87\xad\x06\x22\x81\xc3\x5c\x1a\x8c\ +\x2e\x1b\x77\xb7\x1f\x7f\x3b\x6f\xfc\xde\x3b\xe8\x46\x34\x69\x74\ +\x0c\x8d\x7a\x07\xa8\xeb\x78\x58\x88\xde\xa7\x88\x5e\x5c\x5c\x51\ +\xec\xb1\x11\xfc\xef\x8d\xfa\x44\x4a\xf8\xb1\xb8\xe2\x78\x28\xbb\ +\x4d\xd3\x08\x5a\x4f\xa8\x3b\x22\x12\xe9\xf7\xcb\xc6\xb7\x1f\xfa\ +\xb5\x81\x02\xec\x93\xcb\xc6\x52\x22\x8a\x19\xea\x86\x9c\x85\x84\ +\xcb\x99\xfd\xc5\x88\x30\x9f\x48\x3e\xd3\x95\xa8\xcb\x89\x23\xf5\ +\x13\xea\x4e\x7b\xad\x6e\x73\x6a\x5f\x66\xea\x65\x66\x5f\x40\x04\ +\x39\xee\x9d\xb5\xcf\xbb\x4d\xf3\x68\x8a\xc7\x84\x8e\xc6\xb2\x77\ +\xde\x82\x72\xfb\xac\x69\x36\x63\xa2\xdd\x66\xcc\xbc\x4c\x92\x09\ +\x0d\x5c\x36\xb9\xa5\xd2\x23\x56\x18\x21\x39\x08\xdf\xfb\x44\x02\ +\xc2\xb1\x87\x84\xed\x4c\xb7\x69\x2b\x8a\x24\x3d\x3c\x63\x51\xa2\ +\x9c\xef\xef\xd8\xf4\x8b\x2e\xb2\x14\x73\x2c\x45\x88\x1d\x20\xd4\ +\xb0\x1d\x08\x22\x7f\x40\x78\xef\xb4\xdb\xb4\x4f\x46\xfc\x34\x87\ +\x02\x09\x1f\xf3\x11\x0d\x72\x14\xde\x2c\xa5\x40\x25\xf1\x13\x4d\ +\xa6\x07\xf3\x13\x67\x51\x08\x32\xc7\xc3\x39\x8a\xdf\x4d\xf3\x02\ +\x73\x99\x28\xab\x44\x5f\x7a\xd0\x51\xbf\x44\x6b\x45\xa1\x96\xea\ +\xce\x72\x03\xc3\x95\xd4\xc1\x9e\x29\xbd\xef\x24\x8c\x93\x1e\x95\ +\x10\xfa\x5c\x20\x34\x66\x9c\xfe\x64\x81\x9c\x93\x6a\xbf\x99\xd3\ +\xca\x53\x2b\x28\x49\x9b\xf8\x0d\x27\xc3\xf7\x63\xe2\x3c\xa4\x95\ +\xa5\x2a\x42\xa8\x70\x54\xc5\x80\x4d\xef\xdb\x9d\x14\xd9\x12\xed\ +\x31\xe6\xdd\xd2\x30\xd3\x66\xae\xc4\xeb\x21\x92\x63\x2a\x10\xfc\ +\x69\x7a\xc4\x7d\x0d\x05\xc4\x2a\x75\xc2\xf8\xc3\x00\xfc\x7b\x0c\ +\x4f\xc1\xdf\x24\xc2\x61\x48\x30\x3f\x44\x77\x82\x0c\x23\xb0\x54\ +\x1a\x38\x04\x61\xcf\x43\x6c\x98\xfa\x95\x62\x28\x10\xe6\xaa\x4a\ +\x30\x44\x03\x5d\xf7\x96\x6b\x32\x96\xe0\x61\x6e\x9c\xca\x07\xab\ +\xbc\x3f\x64\x2a\xcb\x3b\xf3\x99\xba\x05\xc9\x37\xe7\xa3\x74\xfc\ +\x21\x50\x98\x81\x84\x74\xc1\x2b\x2f\x1b\xad\x1c\x5f\xc7\xd2\x1e\ +\x03\x63\xcd\xf7\x47\xc2\xd6\xa9\xc2\xf7\x06\xcb\xf1\xd3\x6c\xbf\ +\x32\xb7\x19\xe3\xe6\x8a\xdc\x34\x94\x81\x99\xa5\xec\xb0\x99\x35\ +\xeb\xa6\xb1\xeb\xb9\xd1\x67\xaa\xab\xba\xc0\xea\xf6\xff\xed\x0b\ +\x1e\x10\x2f\xa6\xe3\xa9\x97\xac\xff\xac\x63\x18\xc6\x26\x68\x20\ +\x09\x1f\x62\x30\x59\x9f\xb9\x64\x73\xc3\xc0\x1e\x1d\x05\x3e\x09\ +\x0a\xcc\x40\xad\xdf\xe4\xc5\xc5\x5b\x55\xff\x85\x60\x15\x14\xff\ +\x9b\x2a\x18\xca\xe4\xed\xfb\x7b\xa2\xa4\x01\x21\xd2\x63\xb1\xe9\ +\xa0\x15\x95\xa9\x20\x9f\xf0\xc2\x28\xf4\x75\xf1\xfd\xf1\x52\x3d\ +\x42\x6b\x10\x0e\x4b\x88\xde\xb9\x1e\x12\x80\x7b\xdd\xc5\xcf\x73\ +\x8a\xdd\xa6\x2e\x5c\x5b\x89\x82\xfe\x24\x9f\x61\x44\x16\x5b\xb9\ +\x6a\x91\x29\x89\x23\xf2\x71\x2b\x13\x90\xe7\xb5\x36\x18\x77\x5a\ +\x99\xb8\x9c\x88\x95\x27\xb8\x40\xd7\x46\x75\x6b\xe8\x7a\x11\x70\ +\x33\x7f\xc0\x4a\x81\x5b\x55\x28\xe0\x5e\x3e\x0c\x4b\x71\xfb\xd6\ +\x82\xb6\x42\xd6\xbb\x6b\x6d\xd0\x0a\x68\x27\x63\x0a\x28\x9b\x40\ +\x31\x94\x47\x1e\x41\x13\x0a\x18\xad\x20\xf1\x02\xdd\x02\xd5\x01\ +\xe6\xe6\x17\xba\x3c\xf4\xb0\x45\x71\xf3\x9b\x78\xfe\xa1\xe8\x61\ +\x78\x0b\x31\xc7\x92\x68\x54\x87\x1f\xbe\x56\x3c\x80\xa4\xc4\xe2\ +\x21\x4b\x27\x12\x44\x73\xfe\xc8\x09\x79\xff\xf6\x0a\xdd\x42\x8b\ +\x47\x4a\x26\x48\xcc\x04\x68\x0c\x0d\x19\xd7\x5c\xa8\x14\xaa\x2d\ +\x37\xfe\x88\x1d\x65\x67\xb5\xa0\xf4\x1d\xfd\xaa\xfd\xfe\x65\x22\ +\x73\xc1\xae\x56\x01\xb8\xc4\x1e\xcc\xe8\x94\xe9\x71\x11\xbb\x66\ +\x9e\x5f\x35\x01\xec\x68\x57\x91\x60\xc7\xc1\xe9\xfe\xec\x59\xa6\ +\x67\x27\xdb\x9d\x9d\x39\x2c\x9c\xa5\xbc\x6e\x40\xd0\x03\x09\x61\ +\x6a\xe6\x70\x26\xa0\x19\xf3\x7d\x1c\x40\x33\x06\xae\xc8\x27\x14\ +\x7c\xd2\x16\x09\xd3\x1e\x7b\x13\x3c\x13\x60\xc0\x98\xab\x88\x88\ +\x02\xf6\xdb\x9c\xe2\x73\xcc\xc9\x3e\x79\x6c\x00\x93\xf4\x2d\xf0\ +\xb0\x1a\xc8\xb1\x19\x80\xfe\x7a\x92\x47\x40\x58\x3f\x3e\x27\x80\ +\xa8\x4e\xf8\x2f\x18\x42\x76\xed\x3f\xed\xf3\x67\x71\xa0\xa3\xcd\ +\x1d\xe8\x0f\xc6\x7d\x88\x39\xb3\xd7\x08\x14\x09\x21\x47\x8d\x20\ +\x94\x23\x36\xf8\x37\x2c\xd6\x85\x59\xeb\x40\x21\x25\x02\x29\xe1\ +\x04\xf1\xa0\x9c\xb8\x87\x28\x76\x3d\x16\xaa\xf8\x54\x58\x1f\x0d\ +\x30\x78\x96\xa5\x32\x77\xc4\xf8\xd7\xe0\x57\x10\xf1\xb0\xfb\x2c\ +\x8b\x9c\xbe\x66\x92\x15\x20\xd3\xb9\x5a\x62\xa9\xe9\xea\x3b\x10\ +\xe2\x1f\x46\x86\xbd\x4f\x94\xfb\xc4\x1a\x4b\xfe\xd2\x25\xcf\x13\ +\x6b\xfb\xc5\x4b\x1e\x32\xc4\x91\x67\x16\xc2\xca\xe2\x61\x96\x17\ +\xac\x0e\xbe\x5b\x5f\x71\x9c\xed\x57\x1c\x8b\x75\x5d\xdf\x8a\x63\ +\xb9\x35\xad\xe1\xff\xae\x31\xaf\x1f\x37\x2f\xd5\xef\xab\xcd\x66\ +\xff\x60\xe5\xce\x52\xcf\x5c\xfa\x9f\x7f\xa2\x57\xb7\x2c\xfc\xfb\ +\x0e\x25\xf8\x17\x7a\xf5\x91\x83\xbb\xed\x50\x86\x3f\x41\x86\x3e\ +\x75\x49\x25\x11\x76\x0d\xff\xed\xa3\x6a\xf8\x7f\xbe\x21\xfc\x5f\ +\xab\xb5\x75\x00\x13\x6f\x70\x32\x87\xaa\x8d\x18\xe4\x91\x47\xe2\ +\xed\x2c\x02\xec\xf1\x7f\xb1\xa6\xb7\x85\xff\xfd\x90\x06\x65\xf0\ +\x2f\xa0\xfc\xe9\x89\xb4\x8f\xa7\xd4\x8f\xfc\x3e\xc8\xbc\xaa\x5e\ +\x4e\x97\xeb\xa5\x7d\x7a\x76\x76\xd6\x69\x9f\x54\xd1\xce\xba\x69\ +\x31\x82\xcc\x96\x94\xda\x92\x70\xc1\xf4\x61\xfa\xaf\x33\x59\x34\ +\x76\x08\x87\x31\xee\xd2\x00\x4b\xa2\x26\xf7\x84\x6b\xab\x13\xe8\ +\x95\x4a\x4f\x91\xe9\x21\x3a\x42\x97\xa8\x75\xd8\x6a\xb5\x4b\x71\ +\x67\x35\x19\x1f\xb1\x17\xe5\x95\x58\xba\xeb\xb6\x16\xd5\x35\xc2\ +\xf3\xdc\xeb\x5f\x6a\x78\xde\x35\x2e\x77\x2a\x4e\xcb\x37\xc5\xe5\ +\x2b\xea\x93\x40\x68\x8b\x7b\x29\xc8\xfc\xc4\xa4\x70\x8f\xcd\xb5\ +\x60\xf3\xf2\x2c\xa1\xc5\xe6\x72\x48\x39\xdf\x1c\x52\x96\x00\x55\ +\xa7\x16\xa0\x72\xa9\x7f\xb3\xc7\xaa\x27\xe6\x90\x27\xd5\xc0\x6a\ +\xf9\xda\x7b\x31\x56\xdd\x32\x0f\xc2\x63\xe0\xec\x30\x6d\xb0\x1c\ +\x66\xf7\xd0\xb4\x15\x68\xba\x62\xd1\xc0\x23\x8b\x00\xca\xd5\xb5\ +\x16\xa6\xfe\x02\x13\xc8\x64\x5f\x55\x83\xa3\xda\xaa\x74\xd1\x60\ +\x86\x86\x51\xe0\x98\xa9\xa2\x1c\x63\xa9\x77\x3b\x31\x92\xb1\x8b\ +\x1c\x1e\x7c\x57\xad\x55\x2e\x58\x8e\x91\x4b\x87\x43\xc2\x09\x94\ +\x0b\x04\x1e\xc8\x26\x26\x97\x6c\x08\xc6\xd9\x62\xc9\x09\x56\xc9\ +\x62\x2c\x90\x00\xc1\x2a\x24\x8b\x45\x34\x1c\xd2\x69\x69\x87\x9a\ +\x9b\x18\x7c\x30\x02\x73\x90\x24\xaf\x22\x63\x09\x3d\x98\x1c\xb7\ +\x5b\xe9\x7f\xdd\xa6\xad\xd9\x4a\xf8\x49\xb8\x9c\x6c\x89\xcb\x1a\ +\xe1\x48\x26\x90\xb7\x8f\x45\xa5\xf3\xe6\x35\x26\xce\xeb\x1c\x61\ +\xab\xb0\xc7\xf3\x63\x4c\x82\x65\x87\xd8\xcc\x71\x34\xed\x75\x8e\ +\x76\x39\x74\xa3\xf6\x3e\x43\x4e\x7d\x2a\xe9\x23\x11\xf1\x76\x8d\ +\x5a\x32\x9a\x9f\xcc\xb7\x87\x26\x8a\x36\x7e\xc4\x14\x22\xa9\x57\ +\xc5\x45\x17\x47\xd9\x3b\x61\x05\xba\x49\x04\xca\xb2\xad\xe7\x70\ +\x84\x20\x4a\x8a\x44\x88\x5f\xd3\x03\xb2\x95\x19\x5a\xa9\x76\x1b\ +\x9c\x5d\x4d\x56\x51\xab\x9d\x5e\xed\x07\x38\x0c\x8b\xbb\x75\x95\ +\xcf\xab\x6e\xef\xb4\x6a\xc5\xcc\x65\xa7\xb5\xe1\xb4\xf3\x3d\xc4\ +\x58\xc9\x31\x0d\xd4\x79\x81\xdd\x4d\x3d\x97\x2f\xc8\xf6\x53\xcf\ +\x9a\x76\xac\x2a\x9c\x9e\x51\xc9\xc0\xb9\x31\xa9\x3d\x50\xb0\x27\ +\x3a\xa4\x30\xe4\x0f\x64\x56\x0b\xa8\x02\x43\x27\x16\xe0\xa5\xe2\ +\x69\xb5\x4d\x1a\x31\xa6\x8a\xd9\xae\xf6\x88\x1c\xc9\x4b\x13\x67\ +\xf5\x70\xc7\x5e\xa5\xae\xef\x7a\x2e\x77\x5c\x11\xe0\xdb\x1b\x02\ +\xbc\x0a\x7d\xbb\xc5\xf6\xe5\xb3\xcd\x3d\xb6\xd7\x84\xed\xa7\xd5\ +\xb0\x5d\x58\x3b\xda\x02\xa6\x3b\x11\x87\xe5\xba\xbc\x0e\x5c\x92\ +\x5f\x47\xdb\x24\x68\xbb\x96\x74\x28\xf4\x46\xf5\x6a\x1f\x2b\x4c\ +\xe9\x3e\x56\x24\x05\xbb\x8d\x15\x15\x53\xd0\x9d\x4d\x8f\xb1\xbd\ +\xf5\xe4\x6e\x43\xc5\x72\x8c\xda\x87\x8a\x9a\x42\xc5\x13\x7b\x18\ +\x4f\x85\x0a\x6c\xcc\xa8\x96\x48\x51\xcf\xc6\x19\xf4\x46\x43\xca\ +\x3e\x50\xec\x03\xc5\x4b\x0a\x14\x99\x55\xc1\xf6\x12\xc4\x15\xfc\ +\xff\x7a\x98\xcd\x0a\xeb\xe5\x87\xbd\xcd\x96\x1c\xdd\x1f\xb3\x49\ +\xa0\xf3\xae\xe4\x11\x20\x02\xba\xa2\x77\x78\x44\x79\x96\x6e\xd9\ +\x80\xac\xbe\x0c\x02\x96\xf1\xe5\xf5\x94\x48\xff\xcf\x17\x64\x94\ +\x16\x55\x5f\xde\xa9\x6e\xbc\x4c\x64\xda\xb5\x7f\x9c\x3e\x8b\x7b\ +\x6c\x7a\x31\x3a\x75\x63\x5e\xa4\xdd\xc2\x5c\x28\x01\x0f\xa8\xed\ +\xfa\xfc\x2f\x6d\x36\xb9\xca\xee\x4f\xc6\x5d\x98\x1f\x74\x9b\xf6\ +\xa1\x4a\x71\xde\xc2\xcc\x97\x52\xee\x8f\xd6\x6b\x7e\xbc\x5e\xf3\ +\x93\x6c\xf3\x6d\xee\xa3\xcc\x73\x33\xab\xed\xa3\x98\x04\x6f\xa4\ +\xb7\xe6\x51\xfc\x95\x97\xad\x7f\x04\x24\x49\x18\x55\x3f\xcd\xd3\ +\xaa\xb6\x94\x6a\x57\xdb\x57\x89\x35\xa5\xd4\xad\x7f\xf2\x9c\x4b\ +\xab\x05\x78\xf6\x85\x06\xe4\x83\x4b\x65\x01\xcf\x3c\xa8\x20\x50\ +\xf1\xc4\x91\xc4\x95\x4f\x70\xd8\x5b\x2a\xa9\xde\xea\x5b\xe8\xce\ +\x0a\x36\xb3\x58\x0f\x1b\xaa\xbc\x16\x24\x4d\xf7\x4c\x77\xda\x8c\ +\xf0\xaf\x88\xa9\xd5\x3d\x71\x8d\xdb\xaa\x65\x8e\xb8\x69\xcc\x2d\ +\x45\x2c\xb0\x49\x8f\xad\x3e\xf7\xdb\x7a\x9a\x63\x79\x67\xf6\x69\ +\x8e\x2d\xa5\x39\x60\x8c\xdf\x45\x52\x82\x1a\x8b\x99\x0e\xa8\x1b\ +\xe8\xba\x2a\x17\x9e\xcb\xd0\x4f\x93\xd6\xc0\x17\xdf\x17\x1e\x10\ +\xb5\x1d\xea\x72\xac\xd7\x3c\xea\x73\x1e\x34\xc8\xa2\xa2\xba\xe6\ +\x5e\xe1\xb8\x8b\x66\x99\x47\x0a\x55\x96\x1b\x20\x4e\xdc\xde\xf1\ +\xb1\xfa\x74\x9a\x9b\xab\x19\x71\x42\x82\x5e\xbb\x03\x33\x0d\xf3\ +\x98\xad\x1e\x78\x11\xe9\x75\x4e\xa0\x56\x3f\x65\x87\xb5\xc0\xe9\ +\x59\x71\xd6\x7a\xee\x5f\x01\x63\x33\x18\x12\x4f\x91\x0a\xf7\xbb\ +\x56\x44\x8f\x04\x3b\xbe\x5b\x4a\x79\xe4\x28\xeb\xd1\x9a\xa8\x51\ +\xc0\x0c\x8b\x18\x9d\x32\xc4\x88\xf1\xe2\xb8\x0c\x2f\xf2\x68\x51\ +\x22\x5c\x1e\x29\xd6\x3f\x79\x94\x6a\x94\x6a\x61\x63\x5b\xec\xcf\ +\xf6\x73\x7e\x97\x8d\xd3\x06\x32\xdf\xe5\xbb\x6c\xb4\xdb\x0d\x75\ +\xd4\xb3\x1b\xd2\xa9\x8f\xc3\xf8\xac\x6a\xef\x3f\x37\xfa\xfd\x23\ +\x67\xfe\x57\xea\x93\x3e\x8b\xb8\x3a\xdb\x98\x6b\xa5\x3e\xce\x18\ +\x09\xc9\x7c\xc3\x51\x68\x49\xd2\x25\x46\xca\xd4\x07\x1c\x53\x48\ +\x96\x7c\xb3\x51\x0d\xe9\x54\x92\xc0\x15\xbd\x6f\x37\x91\x18\xc7\ +\xf5\x71\xe1\x81\x51\x31\x56\xcb\x06\xa0\xd2\x34\x6b\x09\x71\x38\ +\x56\xda\xc6\x76\x31\x01\xe4\x72\x8c\x97\x4b\x92\xba\x5b\x51\x2e\ +\xc9\xbc\x72\x91\x18\x8a\xc2\xd6\x44\x79\x4a\x31\x45\xed\xd5\x23\ +\x96\xcd\x20\x94\xab\x28\xa9\xad\x49\x47\x26\xdb\xbf\x40\x98\x79\ +\x6d\x2d\xc2\xc4\x6b\x91\x72\x61\x92\xda\x5a\x84\xc9\x9c\xc4\x2f\ +\x97\x28\xd7\xa4\xba\x58\xd9\x02\xfd\xed\x55\x4e\x84\x06\x0a\xa1\ +\x21\x05\x62\x5d\x40\xcc\xd1\x77\xd3\x8b\xf9\xbb\xe1\x2a\x40\x00\ +\xa0\x5d\x92\xb3\x55\x5f\xb7\x0b\xe2\x24\x01\x20\xf1\x28\xc0\x5e\ +\xcf\xf1\xa8\xca\x52\xbe\x52\xc9\x48\x75\xc5\xd2\x94\xea\x16\x9c\ +\x38\x84\x3e\x96\xd2\x7a\xa3\x3f\xaf\x6a\x6a\x0d\x35\x8f\xc9\x1e\ +\xe0\xfd\x87\x40\x1d\x91\x4d\xc8\xa9\x62\xa3\x0c\x08\x0a\xc2\x82\ +\xad\x7a\x46\x72\x16\xaa\x78\xa1\x7b\xa6\x67\xf0\xf3\x44\xc3\xb4\ +\xd7\x3e\x39\x9f\x7f\x04\x56\x7d\x05\xb6\xf3\x26\xf5\x1d\xd8\xa6\ +\xfa\x79\x91\x92\x4b\x84\x54\xf7\x48\x41\x11\x79\x72\xc7\xad\x56\ +\x8e\xdc\x51\x19\x39\xf3\x28\xec\xb0\xa4\xd5\x9a\x7e\x85\xfa\x6e\ +\x33\xa2\xbd\x83\xff\x01\x47\x37\x00\x13\ \x00\x00\x07\xb5\ \x00\ \x00\x1a\x6e\x78\x9c\xed\x58\x5d\x6f\xe3\xb8\x15\x7d\xcf\xaf\x50\ @@ -53366,6 +53447,11 @@ qt_resource_name = "\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x63\x00\x73\x00\x2e\x00\x71\x00\x6d\ \x00\x13\ +\x0f\x69\x32\x79\ +\x00\x75\ +\x00\x73\x00\x65\x00\x72\x00\x70\x00\x72\x00\x65\x00\x66\x00\x73\x00\x2d\x00\x76\x00\x69\x00\x73\x00\x75\x00\x61\x00\x6c\x00\x2e\ +\x00\x75\x00\x69\ +\x00\x13\ \x02\xb7\x50\xf9\ \x00\x75\ \x00\x73\x00\x65\x00\x72\x00\x70\x00\x72\x00\x65\x00\x66\x00\x73\x00\x2d\x00\x69\x00\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x2e\ @@ -53629,7 +53715,7 @@ qt_resource_name = "\ 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\x59\ +\x00\x00\x00\x10\x00\x02\x00\x00\x00\x03\x00\x00\x00\x59\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x38\x00\x00\x00\x21\ \x00\x00\x00\x38\x00\x02\x00\x00\x00\x05\x00\x00\x00\x1c\ \x00\x00\x00\x1a\x00\x02\x00\x00\x00\x17\x00\x00\x00\x05\ @@ -53661,64 +53747,65 @@ qt_resource_struct = "\ \x00\x00\x00\x64\x00\x01\x00\x00\x00\x01\x00\x00\x0a\xf1\ \x00\x00\x00\x96\x00\x01\x00\x00\x00\x01\x00\x00\x13\x00\ \x00\x00\x00\x7c\x00\x01\x00\x00\x00\x01\x00\x00\x0f\x23\ -\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x0b\x07\x34\ -\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0a\x64\x1d\ -\x00\x00\x09\x34\x00\x01\x00\x00\x00\x01\x00\x0b\xde\x2a\ -\x00\x00\x0b\xc4\x00\x01\x00\x00\x00\x01\x00\x0c\xba\x35\ -\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x0a\xa3\xc8\ -\x00\x00\x07\x16\x00\x00\x00\x00\x00\x01\x00\x0b\x24\x7e\ -\x00\x00\x08\x2a\x00\x01\x00\x00\x00\x01\x00\x0b\x8d\x2c\ -\x00\x00\x0b\x26\x00\x01\x00\x00\x00\x01\x00\x0c\x90\xf2\ -\x00\x00\x07\x8a\x00\x00\x00\x00\x00\x01\x00\x0b\x4e\x4d\ -\x00\x00\x09\xce\x00\x01\x00\x00\x00\x01\x00\x0c\x1e\xcb\ -\x00\x00\x0c\x14\x00\x01\x00\x00\x00\x01\x00\x0c\xd6\x59\ -\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x0a\x7d\x3f\ -\x00\x00\x08\xdc\x00\x00\x00\x00\x00\x01\x00\x0b\xbb\xd0\ -\x00\x00\x08\x50\x00\x01\x00\x00\x00\x01\x00\x0b\x92\xf0\ -\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x0b\x11\xe8\ -\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x0a\x82\xbe\ -\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x0b\x3d\x43\ -\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x0a\x72\xd3\ -\x00\x00\x0b\x4e\x00\x00\x00\x00\x00\x01\x00\x0c\x9c\x61\ -\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x0a\x3e\x8b\ -\x00\x00\x05\xd6\x00\x01\x00\x00\x00\x01\x00\x0a\xbe\xe7\ -\x00\x00\x0a\xde\x00\x01\x00\x00\x00\x01\x00\x0c\x79\xc3\ -\x00\x00\x0b\x00\x00\x01\x00\x00\x00\x01\x00\x0c\x87\x5e\ -\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x0a\xac\xce\ -\x00\x00\x03\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x36\xd2\ -\x00\x00\x08\xba\x00\x01\x00\x00\x00\x01\x00\x0b\xb4\x7c\ -\x00\x00\x0a\x28\x00\x00\x00\x00\x00\x01\x00\x0c\x2f\x13\ -\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x0a\xd0\x57\ -\x00\x00\x0a\x4c\x00\x00\x00\x00\x00\x01\x00\x0c\x45\xc6\ -\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0b\x66\x00\ -\x00\x00\x05\x38\x00\x01\x00\x00\x00\x01\x00\x0a\x92\xbe\ -\x00\x00\x0b\xe4\x00\x00\x00\x00\x00\x01\x00\x0c\xc4\xe3\ -\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xe7\x96\ -\x00\x00\x04\x28\x00\x00\x00\x00\x00\x01\x00\x0a\x46\x92\ -\x00\x00\x0c\x44\x00\x00\x00\x00\x00\x01\x00\x0c\xe2\x32\ -\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x0c\x63\x4d\ -\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x0a\x5b\xb2\ -\x00\x00\x0a\xbc\x00\x01\x00\x00\x00\x01\x00\x0c\x72\x74\ -\x00\x00\x09\x56\x00\x01\x00\x00\x00\x01\x00\x0b\xe6\xd3\ -\x00\x00\x0b\x74\x00\x01\x00\x00\x00\x01\x00\x0c\xa4\xee\ -\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x0a\xf9\xd5\ -\x00\x00\x07\xbc\x00\x01\x00\x00\x00\x01\x00\x0b\x5c\x4f\ -\x00\x00\x09\xac\x00\x00\x00\x00\x00\x01\x00\x0c\x0a\x3a\ -\x00\x00\x05\x5c\x00\x01\x00\x00\x00\x01\x00\x0a\x99\x87\ -\x00\x00\x08\x0a\x00\x00\x00\x00\x00\x01\x00\x0b\x77\xb8\ -\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x0a\xca\xd8\ -\x00\x00\x09\xf8\x00\x01\x00\x00\x00\x01\x00\x0c\x25\x40\ -\x00\x00\x08\x92\x00\x01\x00\x00\x00\x01\x00\x0b\xa9\x0a\ -\x00\x00\x09\x0c\x00\x01\x00\x00\x00\x01\x00\x0b\xce\x54\ -\x00\x00\x0b\x9a\x00\x01\x00\x00\x00\x01\x00\x0c\xaf\xb3\ -\x00\x00\x0a\x70\x00\x01\x00\x00\x00\x01\x00\x0c\x58\x9d\ -\x00\x00\x05\x08\x00\x01\x00\x00\x00\x01\x00\x0a\x8a\x9c\ -\x00\x00\x08\x72\x00\x00\x00\x00\x00\x01\x00\x0b\x99\x38\ -\x00\x00\x06\x58\x00\x00\x00\x00\x00\x01\x00\x0a\xd8\x3c\ -\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x0b\x33\xcf\ -\x00\x00\x09\x7a\x00\x00\x00\x00\x00\x01\x00\x0b\xee\x24\ +\x00\x00\x06\xfa\x00\x01\x00\x00\x00\x01\x00\x0b\x0c\x1d\ +\x00\x00\x04\xa8\x00\x00\x00\x00\x00\x01\x00\x0a\x69\x06\ +\x00\x00\x09\x60\x00\x01\x00\x00\x00\x01\x00\x0b\xe3\x13\ +\x00\x00\x0b\xf0\x00\x01\x00\x00\x00\x01\x00\x0c\xbf\x1e\ +\x00\x00\x05\xb2\x00\x01\x00\x00\x00\x01\x00\x0a\xa8\xb1\ +\x00\x00\x07\x42\x00\x00\x00\x00\x00\x01\x00\x0b\x29\x67\ +\x00\x00\x08\x56\x00\x01\x00\x00\x00\x01\x00\x0b\x92\x15\ +\x00\x00\x0b\x52\x00\x01\x00\x00\x00\x01\x00\x0c\x95\xdb\ +\x00\x00\x07\xb6\x00\x00\x00\x00\x00\x01\x00\x0b\x53\x36\ +\x00\x00\x09\xfa\x00\x01\x00\x00\x00\x01\x00\x0c\x23\xb4\ +\x00\x00\x0c\x40\x00\x01\x00\x00\x00\x01\x00\x0c\xdb\x42\ +\x00\x00\x04\xee\x00\x01\x00\x00\x00\x01\x00\x0a\x82\x28\ +\x00\x00\x09\x08\x00\x00\x00\x00\x00\x01\x00\x0b\xc0\xb9\ +\x00\x00\x08\x7c\x00\x01\x00\x00\x00\x01\x00\x0b\x97\xd9\ +\x00\x00\x07\x1c\x00\x00\x00\x00\x00\x01\x00\x0b\x16\xd1\ +\x00\x00\x05\x12\x00\x01\x00\x00\x00\x01\x00\x0a\x87\xa7\ +\x00\x00\x07\x8a\x00\x01\x00\x00\x00\x01\x00\x0b\x42\x2c\ +\x00\x00\x04\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x77\xbc\ +\x00\x00\x0b\x7a\x00\x00\x00\x00\x00\x01\x00\x0c\xa1\x4a\ +\x00\x00\x04\x28\x00\x01\x00\x00\x00\x01\x00\x0a\x43\x74\ +\x00\x00\x06\x02\x00\x01\x00\x00\x00\x01\x00\x0a\xc3\xd0\ +\x00\x00\x0b\x0a\x00\x01\x00\x00\x00\x01\x00\x0c\x7e\xac\ +\x00\x00\x0b\x2c\x00\x01\x00\x00\x00\x01\x00\x0c\x8c\x47\ +\x00\x00\x05\xe0\x00\x00\x00\x00\x00\x01\x00\x0a\xb1\xb7\ +\x00\x00\x03\xf6\x00\x01\x00\x00\x00\x01\x00\x0a\x3b\xbb\ +\x00\x00\x08\xe6\x00\x01\x00\x00\x00\x01\x00\x0b\xb9\x65\ +\x00\x00\x0a\x54\x00\x00\x00\x00\x00\x01\x00\x0c\x33\xfc\ +\x00\x00\x06\x56\x00\x01\x00\x00\x00\x01\x00\x0a\xd5\x40\ +\x00\x00\x0a\x78\x00\x00\x00\x00\x00\x01\x00\x0c\x4a\xaf\ +\x00\x00\x08\x10\x00\x00\x00\x00\x00\x01\x00\x0b\x6a\xe9\ +\x00\x00\x05\x64\x00\x01\x00\x00\x00\x01\x00\x0a\x97\xa7\ +\x00\x00\x0c\x10\x00\x00\x00\x00\x00\x01\x00\x0c\xc9\xcc\ +\x00\x00\x06\xb0\x00\x00\x00\x00\x00\x01\x00\x0a\xec\x7f\ +\x00\x00\x04\x54\x00\x00\x00\x00\x00\x01\x00\x0a\x4b\x7b\ +\x00\x00\x0c\x70\x00\x00\x00\x00\x00\x01\x00\x0c\xe7\x1b\ +\x00\x00\x0a\xc0\x00\x00\x00\x00\x00\x01\x00\x0c\x68\x36\ +\x00\x00\x04\x78\x00\x01\x00\x00\x00\x01\x00\x0a\x60\x9b\ +\x00\x00\x0a\xe8\x00\x01\x00\x00\x00\x01\x00\x0c\x77\x5d\ +\x00\x00\x09\x82\x00\x01\x00\x00\x00\x01\x00\x0b\xeb\xbc\ +\x00\x00\x0b\xa0\x00\x01\x00\x00\x00\x01\x00\x0c\xa9\xd7\ +\x00\x00\x06\xd8\x00\x01\x00\x00\x00\x01\x00\x0a\xfe\xbe\ +\x00\x00\x07\xe8\x00\x01\x00\x00\x00\x01\x00\x0b\x61\x38\ +\x00\x00\x09\xd8\x00\x00\x00\x00\x00\x01\x00\x0c\x0f\x23\ +\x00\x00\x05\x88\x00\x01\x00\x00\x00\x01\x00\x0a\x9e\x70\ +\x00\x00\x08\x36\x00\x00\x00\x00\x00\x01\x00\x0b\x7c\xa1\ +\x00\x00\x06\x36\x00\x01\x00\x00\x00\x01\x00\x0a\xcf\xc1\ +\x00\x00\x0a\x24\x00\x01\x00\x00\x00\x01\x00\x0c\x2a\x29\ +\x00\x00\x08\xbe\x00\x01\x00\x00\x00\x01\x00\x0b\xad\xf3\ +\x00\x00\x09\x38\x00\x01\x00\x00\x00\x01\x00\x0b\xd3\x3d\ +\x00\x00\x0b\xc6\x00\x01\x00\x00\x00\x01\x00\x0c\xb4\x9c\ +\x00\x00\x0a\x9c\x00\x01\x00\x00\x00\x01\x00\x0c\x5d\x86\ +\x00\x00\x05\x34\x00\x01\x00\x00\x00\x01\x00\x0a\x8f\x85\ +\x00\x00\x08\x9e\x00\x00\x00\x00\x00\x01\x00\x0b\x9e\x21\ +\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xdd\x25\ +\x00\x00\x07\x6a\x00\x01\x00\x00\x00\x01\x00\x0b\x38\xb8\ +\x00\x00\x09\xa6\x00\x00\x00\x00\x00\x01\x00\x0b\xf3\x0d\ +\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x27\x9b\ +\x00\x00\x03\xce\x00\x01\x00\x00\x00\x01\x00\x0a\x31\xbc\ \x00\x00\x03\x76\x00\x01\x00\x00\x00\x01\x00\x0a\x1c\x55\ -\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x26\x0e\ " def qInitResources(): diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index f1ae9612c..938680e59 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -112,11 +112,12 @@ class DraftWorkbench (Workbench): "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_Clone","Draft_Heal"] + "Draft_Clone"] self.treecmdList = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup", - "Draft_SelectGroup","Draft_SelectPlane","Draft_ToggleSnap", + "Draft_SelectGroup","Draft_SelectPlane", "Draft_ShowSnapBar","Draft_ToggleGrid"] self.lineList = ["Draft_UndoLine","Draft_FinishLine","Draft_CloseLine"] + self.utils = ["Draft_Heal"] self.snapList = ['Draft_Snap_Lock','Draft_Snap_Midpoint','Draft_Snap_Perpendicular', 'Draft_Snap_Grid','Draft_Snap_Intersection','Draft_Snap_Parallel', 'Draft_Snap_Endpoint','Draft_Snap_Angle','Draft_Snap_Center', @@ -125,11 +126,13 @@ class DraftWorkbench (Workbench): self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Draft modification tools"),self.modList) self.appendMenu(str(translate("draft","&Draft")),self.cmdList+self.modList) self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Context tools"))],self.treecmdList) + self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Utilities"))],self.utils) self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Wire tools"))],self.lineList) self.appendMenu([str(translate("draft","&Draft")),str(translate("draft","Snapping"))],self.snapList) if hasattr(FreeCADGui,"draftToolBar"): if not hasattr(FreeCADGui.draftToolBar,"loadedPreferences"): FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") + FreeCADGui.addPreferencePage(":/ui/userprefs-visual.ui","Draft") FreeCADGui.addPreferencePage(":/ui/userprefs-import.ui","Draft") FreeCADGui.draftToolBar.loadedPreferences = True Log ('Loading Draft module...done\n') @@ -178,13 +181,5 @@ App.addImportType("Common airfoil data (*.dat)","importAirfoilDAT") App.addExportType("Autodesk DXF (*.dxf)","importDXF") App.addExportType("Flattened SVG (*.svg)","importSVG") App.addExportType("Open CAD Format (*.oca)","importOCA") - -# add DWG support -import importDWG -if importDWG.getTeighaConverter(): - App.addImportType("Autodesk DWG (*.dwg)","importDWG") - App.addExportType("Autodesk DWG (*.dwg)","importDWG") -else: - from DraftTools import translate - FreeCAD.Console.PrintMessage(str(translate("draft","Teigha File Converter not found, DWG support will be disabled.\n"))) - +App.addImportType("Autodesk DWG (*.dwg)","importDWG") +App.addExportType("Autodesk DWG (*.dwg)","importDWG") diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index 2ab449808..62d171766 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -86,5 +86,6 @@ translations/Draft_pt-PT.qm ui/userprefs-base.ui ui/userprefs-import.ui + ui/userprefs-visual.ui diff --git a/src/Mod/Draft/Resources/ui/userprefs-base.ui b/src/Mod/Draft/Resources/ui/userprefs-base.ui index f373dda63..7a4e56e0c 100755 --- a/src/Mod/Draft/Resources/ui/userprefs-base.ui +++ b/src/Mod/Draft/Resources/ui/userprefs-base.ui @@ -44,16 +44,33 @@ + + + + Draft interface mode - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -79,302 +96,6 @@ - - - - - - Default color - - - - - - - the default color for new objects - - - - 0 - 0 - 0 - - - - color - - - Mod/Draft - - - - - - - Snap color - - - - - - - the default color for snap symbols - - - - 0 - 0 - 0 - - - - snapcolor - - - Mod/Draft - - - - - - - Construction color - - - - - - - This is the default color for objects being drawn while in construction mode. - - - - 44 - 125 - 255 - - - - constructioncolor - - - Mod/Draft - - - - - - - Default linewidth - - - - - - - the default linewidth for new objects - - - 2 - - - linewidth - - - Mod/Draft - - - - - - - - - - - Constrain mod - - - - - - - The Constraining modifier key - - - modconstrain - - - Mod/Draft - - - - shift - - - - - ctrl - - - - - alt - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Snap mod - - - - - - - The snap modifier key - - - 1 - - - modsnap - - - Mod/Draft - - - - shift - - - - - ctrl - - - - - alt - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Alt mod - - - - - - - The alt modifier key - - - 2 - - - modalt - - - Mod/Draft - - - - shift - - - - - ctrl - - - - - alt - - - - - - - - - - - - Construction group name - - - - - - - This is the default group name for construction geometry - - - Construction - - - constructiongroupname - - - Mod/Draft - - - - - - - - - - - check this if you want to use the color/linewidth from the toolbar as default - - - Save current color and linewidth across sessions - - - saveonexit - - - Mod/Draft - - - - - @@ -418,209 +139,6 @@ - - - - - - If this is checked, you will always snap to existing objects while drawing. If not, you will be snapping only when pressing CTRL. - - - Always snap to objects (disable snap mod key) - - - true - - - alwaysSnap - - - Mod/Draft - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - The radius for snapping to special points. Set to 0 for no distance (infinite) - - - Snap range - - - - - - - px - - - snapRange - - - Mod/Draft - - - - - - - - - - - If this is checked, snapping will not occur against objects with more than the indicated number of edges - - - Snap maximum - - - false - - - maxSnap - - - Mod/Draft - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - Maximum number of edges to be considered for snapping - - - Maximum number of edges - - - - - - - false - - - 999 - - - 24 - - - maxSnapEdges - - - Mod/Draft - - - - - - - - - - - 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 - - - - - - - - - - - If this is checked, objects will appear as filled as default. Otherwise, they will appear as wireframe - - - Fill objects by default - - - fillmode - - - Mod/Draft - - - - - @@ -630,6 +148,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -663,28 +194,16 @@ - + - - - If checked, a grid will appear when drawing - + - Use grid - - - false - - - grid - - - Mod/Draft + Internal precision level - + Qt::Horizontal @@ -696,100 +215,6 @@ - - - - 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 - - - - - - - false - - - The spacing between each grid line - - - 4 - - - 9999.989999999999782 - - - 1.000000000000000 - - - gridSpacing - - - Mod/Draft - - - - - - - false - - - Main lines every - - - - - - - false - - - Mainlines will be drawn thicker. Specify here how many squares between mainlines. - - - 10 - - - gridEvery - - - Mod/Draft - - - - - - - - - - - Internal precision level - - - @@ -812,8 +237,19 @@ + + + + - + + + Dimensions precision level + + + + + Qt::Horizontal @@ -825,13 +261,6 @@ - - - - Dimensions precision level - - - @@ -904,34 +333,93 @@ Values with differences below this value will be treated as same.
- + - + + + When this is checked, the Draft tools will create Part primitives instead of Draft objects, when available. + - Default text height + Use Part Primitives when available + + + UsePartPrimitives + + + Mod/Draft + + + + + + + + + + + + Snapping + + + + + + + + Constrain mod - - + + + Qt::Horizontal + + - 60 - 16777215 + 40 + 20 + + + + - Default height for texts and dimensions - - - 0.200000000000000 + The Constraining modifier key - textheight + modconstrain Mod/Draft + + + shift + + + + + ctrl + + + + + alt + + + + + + + + + + + + Snap mod + @@ -948,47 +436,49 @@ Values with differences below this value will be treated as same.
- - - Default text font - - - - - + - This is the default font name for all Draft texts and dimensions. -It can be a font name such as "Arial", a default style such as "sans", "serif" -or "mono", or a family such as "Arial,Helvetica,sans" or a name with a style -such as "Arial:Bold" + The snap modifier key - - Arial - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 1 - textfont + modsnap Mod/Draft + + + shift + + + + + ctrl + + + + + alt + + - + - + - Default template sheet + Alt mod - + Qt::Horizontal @@ -1001,38 +491,53 @@ such as "Arial:Bold" - - - - 300 - 0 - - + - The default template to use when creating a new drawing sheet + The alt modifier key + + + 2 - template + modalt Mod/Draft + + + shift + + + + + ctrl + + + + + alt + + - + - + - When this is checked, the Draft tools will create Part primitives instead of Draft objects, when available. + If checked, the Snap toolbar will be shown whenever you use snapping - Use Part Primitives + Show Draft Snap toolbar + + + true - UsePartPrimitives + showSnapBar Mod/Draft @@ -1042,155 +547,56 @@ such as "Arial:Bold" - + - + - Dimensions & Leader arrow style + Hide Draft snap toolbar after use - - - - - dimsymbol + hideSnapBar Mod/Draft - - - Dot 5 - - - - - Dot 7 - - - - - Dot 9 - - - - - Circle 5 - - - - - Circle 7 - - - - - Circle 9 - - - - - Slash 5 - - - - - Slash 7 - - - - - Slash 9 - - - - - Backslash 5 - - - - - Backslash 7 - - - - - Backslash 9 - - + + + + + horizontalLayoutWidget_3 + horizontalLayoutWidget_4 + horizontalLayoutWidget_5 + + + + + + Construction geometry + + - + - + - Vertical dimensions text orientation + Construction group name - + - This is the orientation of the dimension texts when those dimensions are vertical. Default is left, which is the ISO standard. + This is the default group name for construction geometry - - dimorientation - - - Mod/Draft - - - - Left (ISO standard) - - - - - Right - - - - - - - - - - - Alternate SVG Patterns location - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 300 - 0 - - - - Here you can specify a directory containing SVG files containing <pattern> definitions that can be added to the standard Draft hatch patterns + Construction - patternFile + constructiongroupname Mod/Draft @@ -1200,11 +606,11 @@ such as "Arial:Bold" - + - + - Default ShapeString Font File + Construction geometry color @@ -1222,18 +628,19 @@ such as "Arial:Bold" - - - - 300 - 0 - - + - Select a font file + This is the default color for objects being drawn while in construction mode. + + + + 44 + 125 + 255 + - FontFile + constructioncolor Mod/Draft @@ -1242,6 +649,19 @@ such as "Arial:Bold" + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -1250,21 +670,11 @@ such as "Arial:Bold" qPixmapFromMimeSource - - Gui::FileChooser - QWidget -
Gui/FileDialog.h
-
Gui::ColorButton QPushButton
Gui/Widgets.h
- - Gui::PrefFileChooser - Gui::FileChooser -
Gui/PrefWidgets.h
-
Gui::PrefSpinBox QSpinBox @@ -1298,102 +708,6 @@ such as "Arial:Bold"
- - gui::prefcheckbox_2 - clicked(bool) - gui::prefdoublespinbox_3 - setEnabled(bool) - - - 92 - 379 - - - 417 - 381 - - - - - gui::prefcheckbox_2 - clicked(bool) - gui::prefspinbox_4 - setEnabled(bool) - - - 79 - 373 - - - 571 - 374 - - - - - gui::prefcheckbox_4 - clicked(bool) - gui::prefspinbox_6 - setEnabled(bool) - - - 67 - 270 - - - 571 - 272 - - - - - gui::prefcheckbox_4 - clicked(bool) - label_23 - setEnabled(bool) - - - 62 - 270 - - - 516 - 272 - - - - - gui::prefcheckbox_2 - clicked(bool) - label_15 - setEnabled(bool) - - - 58 - 365 - - - 354 - 381 - - - - - gui::prefcheckbox_2 - clicked(bool) - label_16 - setEnabled(bool) - - - 33 - 367 - - - 516 - 381 - - - gui::prefcheckbox_7 clicked(bool) @@ -1410,21 +724,5 @@ such as "Arial:Bold" - - 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 95b64c308..20ebbe7cd 100755 --- a/src/Mod/Draft/Resources/ui/userprefs-import.ui +++ b/src/Mod/Draft/Resources/ui/userprefs-import.ui @@ -7,7 +7,7 @@ 0 0 575 - 629 + 666 @@ -97,6 +97,78 @@ If color mapping is choosed, you must choose a color mapping file containing a t + + + + + + Import + + + + + + + if this is unchecked, texts/mtexts won't be imported + + + texts and dimensions + + + dxftext + + + Mod/Draft + + + + + + + points + + + dxfImportPoints + + + Mod/Draft + + + + + + + if this is checked, paper space objects will be imported too + + + layouts + + + dxflayout + + + Mod/Draft + + + + + + + Check this if you want the non-named blocks (beginning with a *) to be imported too + + + *blocks + + + dxfstarblocks + + + Mod/Draft + + + + + @@ -160,66 +232,6 @@ If color mapping is choosed, you must choose a color mapping file containing a t - - - - - - if this is unchecked, texts/mtexts won't be imported - - - Import texts and dimensions - - - dxftext - - - Mod/Draft - - - - - - - - - - - if this is checked, paper space objects will be imported too - - - Import layouts - - - dxflayout - - - Mod/Draft - - - - - - - - - - - Check this if you want the non-named blocks (beginning with a *) to be imported too - - - Import *blocks - - - dxfstarblocks - - - Mod/Draft - - - - - @@ -363,6 +375,39 @@ If color mapping is choosed, you must choose a color mapping file containing a t + + + + DWG format options + + + + + + + + Path to Teigha File Converter + + + + + + + The path to your Teigha File Converter executable + + + TeighaFileConverter + + + Mod/Draft + + + + + + + + diff --git a/src/Mod/Draft/Resources/ui/userprefs-visual.ui b/src/Mod/Draft/Resources/ui/userprefs-visual.ui new file mode 100644 index 000000000..dca4dd81a --- /dev/null +++ b/src/Mod/Draft/Resources/ui/userprefs-visual.ui @@ -0,0 +1,905 @@ + + + Gui::Dialog::DlgSettingsDraft + + + + 0 + 0 + 718 + 808 + + + + Visual settings + + + + 6 + + + 9 + + + + + Visual Settings + + + + + + + + Default line color + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + the default color for new objects + + + + 0 + 0 + 0 + + + + color + + + Mod/Draft + + + + + + + + + + + Default line width + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + the default linewidth for new objects + + + 2 + + + linewidth + + + Mod/Draft + + + + + + + + + + + Snap symbols color + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + the default color for snap symbols + + + + 0 + 0 + 0 + + + + snapcolor + + + Mod/Draft + + + + + + + + + + + check this if you want to use the color/linewidth from the toolbar as default + + + Save current color and linewidth across sessions + + + saveonexit + + + Mod/Draft + + + + + + + + + + + if checked, a widget indicating the current working plane orientation appears during drawing operations + + + Show Working Plane tracker + + + showPlaneTracker + + + Mod/Draft + + + + + + + + + + + If this is checked, objects will appear as filled as default. Otherwise, they will appear as wireframe + + + Fill objects by default + + + fillmode + + + Mod/Draft + + + + + + + + + + + Default template sheet + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 300 + 0 + + + + The default template to use when creating a new drawing sheet + + + template + + + Mod/Draft + + + + + + + + + + + Alternate SVG Patterns location + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 300 + 0 + + + + Here you can specify a directory containing SVG files containing <pattern> definitions that can be added to the standard Draft hatch patterns + + + patternFile + + + Mod/Draft + + + + + + + + + + + Hatch patterns resolution + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 512 + + + 128 + + + HatchPatternResolution + + + Mod/Draft + + + + + + + + + + + + Grid + + + + + + + + If checked, a grid will appear when drawing + + + Use grid + + + false + + + grid + + + Mod/Draft + + + + + + + + + + + false + + + If checked, the Draft grid will always be visible when the Draft workbench is active. Otherwise only when using a command + + + Always show the grid + + + alwaysShowGrid + + + Mod/Draft + + + + + + + + + + + false + + + Grid spacing + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + The spacing between each grid line + + + 4 + + + 9999.989999999999782 + + + 1.000000000000000 + + + gridSpacing + + + Mod/Draft + + + + + + + + + + + false + + + Main lines every + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Mainlines will be drawn thicker. Specify here how many squares between mainlines. + + + 10 + + + gridEvery + + + Mod/Draft + + + + + + + + + + + + Texts and dimensions + + + + + + + + Default text height + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 16777215 + + + + Default height for texts and dimensions + + + 0.200000000000000 + + + textheight + + + Mod/Draft + + + + + + + + + + + Default text font + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + This is the default font name for all Draft texts and dimensions. +It can be a font name such as "Arial", a default style such as "sans", "serif" +or "mono", or a family such as "Arial,Helvetica,sans" or a name with a style +such as "Arial:Bold" + + + Arial + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + textfont + + + Mod/Draft + + + + + + + + + + + Dimensions & Leader arrow style + + + + + + + dimsymbol + + + Mod/Draft + + + + Dot 5 + + + + + Dot 7 + + + + + Dot 9 + + + + + Circle 5 + + + + + Circle 7 + + + + + Circle 9 + + + + + Slash 5 + + + + + Slash 7 + + + + + Slash 9 + + + + + Backslash 5 + + + + + Backslash 7 + + + + + Backslash 9 + + + + + + + + + + + + Vertical dimensions text orientation + + + + + + + This is the orientation of the dimension texts when those dimensions are vertical. Default is left, which is the ISO standard. + + + dimorientation + + + Mod/Draft + + + + Left (ISO standard) + + + + + Right + + + + + + + + + + + + Default ShapeString Font File + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 300 + 0 + + + + Select a font file + + + FontFile + + + Mod/Draft + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + qPixmapFromMimeSource + + + Gui::FileChooser + QWidget +
Gui/FileDialog.h
+
+ + Gui::ColorButton + QPushButton +
Gui/Widgets.h
+
+ + Gui::PrefFileChooser + Gui::FileChooser +
Gui/PrefWidgets.h
+
+ + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
+ + Gui::PrefColorButton + Gui::ColorButton +
Gui/PrefWidgets.h
+
+ + Gui::PrefCheckBox + QCheckBox +
Gui/PrefWidgets.h
+
+ + Gui::PrefComboBox + QComboBox +
Gui/PrefWidgets.h
+
+ + Gui::PrefLineEdit + QLineEdit +
Gui/PrefWidgets.h
+
+ + Gui::PrefDoubleSpinBox + QDoubleSpinBox +
Gui/PrefWidgets.h
+
+
+ + + + gui::prefcheckbox_2 + clicked(bool) + gui::prefdoublespinbox_3 + setEnabled(bool) + + + 92 + 379 + + + 417 + 381 + + + + + gui::prefcheckbox_2 + clicked(bool) + gui::prefspinbox_4 + setEnabled(bool) + + + 79 + 373 + + + 571 + 374 + + + + + gui::prefcheckbox_2 + clicked(bool) + label_15 + setEnabled(bool) + + + 58 + 365 + + + 354 + 381 + + + + + gui::prefcheckbox_2 + clicked(bool) + label_16 + setEnabled(bool) + + + 33 + 367 + + + 516 + 381 + + + + + gui::prefcheckbox_2 + clicked(bool) + gui::prefcheckbox_10 + setEnabled(bool) + + + 72 + 375 + + + 226 + 373 + + + + +
diff --git a/src/Mod/Draft/TestDraft.py b/src/Mod/Draft/TestDraft.py new file mode 100644 index 000000000..6c2f613bc --- /dev/null +++ b/src/Mod/Draft/TestDraft.py @@ -0,0 +1,142 @@ +# Unit test for the Draft module + +#*************************************************************************** +#* (c) Yorik van Havre 2013 * +#* * +#* This file is part of the FreeCAD CAx development system. * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* FreeCAD is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with FreeCAD; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#***************************************************************************/ + +import FreeCAD, os, unittest, FreeCADGui, Draft + +class DraftTest(unittest.TestCase): + + def setUp(self): + # setting a new document to hold the tests + if FreeCAD.ActiveDocument: + if FreeCAD.ActiveDocument.Name != "DraftTest": + FreeCAD.newDocument("DraftTest") + else: + FreeCAD.newDocument("DraftTest") + FreeCAD.setActiveDocument("DraftTest") + + def testPivy(self): + FreeCAD.Console.PrintLog ('Checking Pivy...\n') + from pivy import coin + c = coin.SoCube() + FreeCADGui.ActiveDocument.ActiveView.getSceneGraph().addChild(c) + self.failUnless(c,"Pivy is not working properly") + + # creation tools + + def testLine(self): + FreeCAD.Console.PrintLog ('Checking Draft Line...\n') + Draft.makeLine(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-2,0,0)) + self.failUnless(FreeCAD.ActiveDocument.getObject("Line"),"Draft Line failed") + + def testWire(self): + FreeCAD.Console.PrintLog ('Checking Draft Wire...\n') + Draft.makeWire([FreeCAD.Vector(0,0,0),FreeCAD.Vector(2,0,0),FreeCAD.Vector(2,2,0)]) + self.failUnless(FreeCAD.ActiveDocument.getObject("DWire"),"Draft Wire failed") + + def testBSpline(self): + FreeCAD.Console.PrintLog ('Checking Draft BSpline...\n') + Draft.makeBSpline([FreeCAD.Vector(0,0,0),FreeCAD.Vector(2,0,0),FreeCAD.Vector(2,2,0)]) + self.failUnless(FreeCAD.ActiveDocument.getObject("BSpline"),"Draft BSpline failed") + + def testRectangle(self): + FreeCAD.Console.PrintLog ('Checking Draft Rectangle...\n') + Draft.makeRectangle(4,2) + self.failUnless(FreeCAD.ActiveDocument.getObject("Rectangle"),"Draft Rectangle failed") + + def testArc(self): + FreeCAD.Console.PrintLog ('Checking Draft Arc...\n') + Draft.makeCircle(2, startangle=0, endangle=90) + self.failUnless(FreeCAD.ActiveDocument.getObject("Arc"),"Draft Arc failed") + + def testCircle(self): + FreeCAD.Console.PrintLog ('Checking Draft Circle...\n') + Draft.makeCircle(3) + self.failUnless(FreeCAD.ActiveDocument.getObject("Circle"),"Draft Circle failed") + + def testPolygon(self): + FreeCAD.Console.PrintLog ('Checking Draft Polygon...\n') + Draft.makePolygon(5,5) + self.failUnless(FreeCAD.ActiveDocument.getObject("Polygon"),"Draft Polygon failed") + + def testEllipse(self): + FreeCAD.Console.PrintLog ('Checking Draft Ellipse...\n') + Draft.makeEllipse(5,3) + self.failUnless(FreeCAD.ActiveDocument.getObject("Ellipse"),"Draft Ellipse failed") + + def testPoint(self): + FreeCAD.Console.PrintLog ('Checking Draft Point...\n') + Draft.makePoint(5,3,2) + self.failUnless(FreeCAD.ActiveDocument.getObject("Point"),"Draft Point failed") + + def testText(self): + FreeCAD.Console.PrintLog ('Checking Draft Text...\n') + Draft.makeText("Testing Draft") + self.failUnless(FreeCAD.ActiveDocument.getObject("Text"),"Draft Text failed") + + #def testShapeString(self): + # not working ATM because it needs a font file + # FreeCAD.Console.PrintLog ('Checking Draft ShapeString...\n') + # Draft.makeShapeString("Testing Draft") + # self.failUnless(FreeCAD.ActiveDocument.getObject("ShapeString"),"Draft ShapeString failed") + + def testDimension(self): + FreeCAD.Console.PrintLog ('Checking Draft Dimension...\n') + Draft.makeDimension(FreeCAD.Vector(0,0,0),FreeCAD.Vector(2,0,0),FreeCAD.Vector(1,-1,0)) + self.failUnless(FreeCAD.ActiveDocument.getObject("Dimension"),"Draft Dimension failed") + + # modification tools + + def testMove(self): + FreeCAD.Console.PrintLog ('Checking Draft Move...\n') + l = Draft.makeLine(FreeCAD.Vector(0,0,0),FreeCAD.Vector(-2,0,0)) + Draft.move(l,FreeCAD.Vector(2,0,0)) + self.failUnless(l.Start == FreeCAD.Vector(2,0,0),"Draft Move failed") + + def testCopy(self): + FreeCAD.Console.PrintLog ('Checking Draft Move with copy...\n') + l = Draft.makeLine(FreeCAD.Vector(0,0,0),FreeCAD.Vector(2,0,0)) + l2 = Draft.move(l,FreeCAD.Vector(2,0,0),copy=True) + self.failUnless(l2,"Draft Move with copy failed") + + def testRotate(self): + FreeCAD.Console.PrintLog ('Checking Draft Rotate...\n') + l = Draft.makeLine(FreeCAD.Vector(2,0,0),FreeCAD.Vector(4,0,0)) + Draft.rotate(l,90) + self.failUnless(l.Start == FreeCAD.Vector(0,2,0),"Draft Rotate failed") + + def testOffset(self): + FreeCAD.Console.PrintLog ('Checking Draft Offset...\n') + r = Draft.makeRectangle(4,2) + r2 = Draft.offset(r,FreeCAD.Vector(-1,-1,0),copy=True) + self.failUnless(r2,"Draft Offset failed") + + # modification tools + + def tearDown(self): + FreeCAD.closeDocument("DraftTest") + pass + + + diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index a0057df5e..7a0274d0b 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -92,7 +92,7 @@ class plane: gp = self.getGlobalCoords(Vector(lp.x,lp.y,0)) a = direction.getAngle(gp.sub(p)) if a > math.pi/2: - direction = DraftVecUtils.neg(direction) + direction = direction.negative() a = math.pi - a ld = self.getLocalRot(direction) gd = self.getGlobalRot(Vector(ld.x,ld.y,0)) @@ -158,7 +158,7 @@ class plane: v1.normalize() v2.normalize() v3.normalize() - print v1,v2,v3 + #print v1,v2,v3 self.u = v1 self.v = v2 self.axis = v3 @@ -187,10 +187,20 @@ class plane: # len(sex) > 2, look for point and line, three points, etc. return False - def setup(self, direction, point, upvec=None): + def setup(self, direction=None, point=None, upvec=None): '''If working plane is undefined, define it!''' if self.weak: - self.alignToPointAndAxis(point, direction, 0, upvec) + if direction and point: + self.alignToPointAndAxis(point, direction, 0, upvec) + else: + try: + from pivy import coin + rot = FreeCADGui.ActiveDocument.ActiveView.getCameraNode().getField("orientation").getValue() + upvec = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) + vdir = FreeCADGui.ActiveDocument.ActiveView.getViewDirection() + self.alignToPointAndAxis(Vector(0,0,0), vdir.negative(), 0, upvec) + except: + print "Draft: Unable to align the working plane to the current view" self.weak = True def reset(self): @@ -251,9 +261,9 @@ class plane: def getGlobalCoords(self,point): "returns the global coordinates of the given point, taken relatively to this working plane" - vx = DraftVecUtils.scale(self.u,point.x) - vy = DraftVecUtils.scale(self.v,point.y) - vz = DraftVecUtils.scale(self.axis,point.z) + vx = Vector(self.u).multiply(point.x) + vy = Vector(self.v).multiply(point.y) + vz = Vector(self.axis).multiply(point.z) pt = (vx.add(vy)).add(vz) return pt.add(self.position) @@ -275,9 +285,9 @@ class plane: 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) + vx = Vector(self.u).multiply(point.x) + vy = Vector(self.v).multiply(point.y) + vz = Vector(self.axis).multiply(point.z) pt = (vx.add(vy)).add(vz) return pt @@ -286,9 +296,9 @@ class plane: ax = point.getAngle(self.u) ay = point.getAngle(self.v) az = point.getAngle(self.axis) - bx = point.getAngle(DraftVecUtils.neg(self.u)) - by = point.getAngle(DraftVecUtils.neg(self.v)) - bz = point.getAngle(DraftVecUtils.neg(self.axis)) + bx = point.getAngle(self.u.negative()) + by = point.getAngle(self.v.negative()) + bz = point.getAngle(self.axis.negative()) b = min(ax,ay,az,bx,by,bz) if b in [ax,bx]: return "x" diff --git a/src/Mod/Draft/importDWG.py b/src/Mod/Draft/importDWG.py index f976b1a01..f0f39b35a 100644 --- a/src/Mod/Draft/importDWG.py +++ b/src/Mod/Draft/importDWG.py @@ -30,16 +30,20 @@ if open.__module__ == '__builtin__': def open(filename): "called when freecad opens a file." dxf = convertToDxf(filename) - import importDXF - doc = importDXF.open(dxf) - return doc + if dxf: + import importDXF + doc = importDXF.open(dxf) + return doc + return def insert(filename,docname): "called when freecad imports a file" dxf = convertToDxf(filemname) - import importDXF - doc = importDXF.insert(dxf,docname) - return doc + if dxf: + import importDXF + doc = importDXF.insert(dxf,docname) + return doc + return def export(objectslist,filename): "called when freecad exports a file" @@ -51,44 +55,64 @@ def export(objectslist,filename): return filename def getTeighaConverter(): + import FreeCAD,os,platform "finds the Teigha Converter executable" - import os,platform - teigha = None - if platform.system() == "Linux": - teigha = "/usr/bin/TeighaFileConverter" - elif platform.system() == "Windows": - odadir = "C:\Program Files\ODA" - if os.path.exists(odadir): - subdirs = os.walk(odadir).next()[1] - for sub in subdirs: - t = odadir + os.sep + sub + os.sep + "TeighaFileConverter.exe" - if os.path.exists(t): - teigha = t + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + p = p.GetString("TeighaFileConverter") + if p: + # path set manually + teigha = p + else: + # try to find teigha + teigha = None + if platform.system() == "Linux": + teigha = "/usr/bin/TeighaFileConverter" + elif platform.system() == "Windows": + odadir = "C:\Program Files\ODA" + if os.path.exists(odadir): + subdirs = os.walk(odadir).next()[1] + for sub in subdirs: + t = odadir + os.sep + sub + os.sep + "TeighaFileConverter.exe" + if os.path.exists(t): + teigha = t if teigha: if os.path.exists(teigha): return teigha + from DraftTools import translate + FreeCAD.Console.PrintMessage(str(translate("draft","Teigha File Converter not found, DWG support is disabled.\n"))) return None def convertToDxf(dwgfilename): "converts a DWG file to DXF" import os,tempfile teigha = getTeighaConverter() - indir = os.path.dirname(dwgfilename) - outdir = tempfile.mkdtemp() - basename = os.path.basename(dwgfilename) - cmdline = teigha + ' "' + indir + '" "' + outdir + '" "ACAD2010" "DXF" "0" "1" "' + basename + '"' - print "converting " + cmdline - os.system(cmdline) - return outdir + os.sep + os.path.splitext(basename)[0] + ".dxf" + if teigha: + indir = os.path.dirname(dwgfilename) + outdir = tempfile.mkdtemp() + basename = os.path.basename(dwgfilename) + cmdline = teigha + ' "' + indir + '" "' + outdir + '" "ACAD2010" "DXF" "0" "1" "' + basename + '"' + print "Converting: " + cmdline + os.system(cmdline) + result = outdir + os.sep + os.path.splitext(basename)[0] + ".dxf" + if os.path.exists(result): + print "Conversion successful" + return result + else: + print "Error during DWG to DXF conversion. Try moving the DWG file to a directory path" + print "without spaces and non-english characters, or try saving to a lower DWG version" + return None def convertToDwg(dxffilename,dwgfilename): "converts a DXF file to DWG" import os teigha = getTeighaConverter() - indir = os.path.dirname(dxffilename) - outdir = os.path.dirname(dwgfilename) - basename = os.path.basename(dxffilename) - cmdline = teigha + ' "' + indir + '" "' + outdir + '" "ACAD2010" "DWG" "0" "1" "' + basename + '"' - print "converting " + cmdline - os.system(cmdline) - return dwgfilename + if teigha: + indir = os.path.dirname(dxffilename) + outdir = os.path.dirname(dwgfilename) + basename = os.path.basename(dxffilename) + cmdline = teigha + ' "' + indir + '" "' + outdir + '" "ACAD2010" "DWG" "0" "1" "' + basename + '"' + print "converting " + cmdline + os.system(cmdline) + return dwgfilename + return None + diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 494c5166e..467e8d9a1 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -39,6 +39,8 @@ lines, polylines, lwpolylines, circles, arcs, texts, colors,layers (from groups) ''' +TEXTSCALING = 1.35 # scaling factor between autocad font sizes and coin font sizes + import sys, FreeCAD, os, Part, math, re, string, Mesh, Draft, DraftVecUtils, DraftGeomUtils from Draft import _Dimension, _ViewProviderDimension from FreeCAD import Vector @@ -86,34 +88,24 @@ def deformat(text): "removes weird formats in texts and wipes UTF characters" # remove ACAD string formatation #t = re.sub('{([^!}]([^}]|\n)*)}', '', text) + print "input text: ",text t = text.strip("{}") t = re.sub("\\\.*?;","",t) - # replace UTF codes - t = re.sub("\\\\U\+00e9","e",t) - t = re.sub("\\\\U\+00e1","a",t) - t = re.sub("\\\\U\+00e7","c",t) - t = re.sub("\\\\U\+00e3","a",t) - t = re.sub("\\\\U\+00e0","a",t) - t = re.sub("\\\\U\+00c1","A",t) - t = re.sub("\\\\U\+00ea","e",t) - # replace non-UTF chars - t = re.sub("ã","a",t) - t = re.sub("ç","c",t) - t = re.sub("õ","o",t) - t = re.sub("à","a",t) - t = re.sub("á","a",t) - t = re.sub("â","a",t) - t = re.sub("é","e",t) - t = re.sub("è","e",t) - t = re.sub("ê","e",t) - t = re.sub("í","i",t) - t = re.sub("Ã","A",t) - t = re.sub("À","A",t) - t = re.sub("É","E",t) - t = re.sub("È","E",t) + # replace UTF codes by utf chars + sts = re.split("\\\\(U\+....)",t) + ns = u"" + for ss in sts: + print ss, type(ss) + if ss.startswith("U+"): + ucode = "0x"+ss[2:] + ns += unichr(eval(ucode)) + else: + ns += ss.decode("utf8") + t = ns # replace degrees, diameters chars t = re.sub('%%d','°',t) t = re.sub('%%c','Ø',t) + print "output text: ",t return t def locateLayer(wantedLayer): @@ -145,10 +137,10 @@ def calcBulge(v1,bulge,v2): ''' chord = v2.sub(v1) sagitta = (bulge * chord.Length)/2 - startpoint = v1.add(DraftVecUtils.scale(chord,0.5)) perp = chord.cross(Vector(0,0,1)) + startpoint = v1.add(chord.multiply(0.5)) if not DraftVecUtils.isNull(perp): perp.normalize() - endpoint = DraftVecUtils.scale(perp,sagitta) + endpoint = perp.multiply(sagitta) return startpoint.add(endpoint) def getGroup(ob): @@ -215,6 +207,7 @@ class fcformat: self.stdSize = params.GetBool("dxfStdSize") self.importDxfHatches = params.GetBool("importDxfHatches") self.renderPolylineWidth = params.GetBool("renderPolylineWidth") + self.importPoints = params.GetBool("dxfImportPoints") bparams = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View") if self.paramstyle > 1: @@ -231,7 +224,7 @@ class fcformat: v1 = FreeCAD.Vector(r1,g1,b1) v2 = FreeCAD.Vector(r2,g2,b2) v = v2.sub(v1) - v = DraftVecUtils.scale(v,0.5) + v.multiply(0.5) cv = v1.add(v) else: c1 = bparams.GetUnsigned("BackgroundColor") @@ -260,13 +253,13 @@ class fcformat: if self.paramstyle == 3: parammappingfile = params.GetString("dxfmappingfile") self.table = self.buildTable(parammappingfile) - + def buildTable(self,tablefile): "builds a table for converting colors into linewidths" try: f = pythonopen(tablefile) except ValueError: - print "error: ",tablefile, " not found" - return None + print "error: ",tablefile, " not found" + return None table = {} header = len(f.readline().split("\t")) if header == 15: @@ -300,13 +293,12 @@ class fcformat: table = None print table return table - + def formatObject(self,obj,dxfobj=None): "applies color and linetype to objects" - if self.paramstyle == 0: - if hasattr(obj.ViewObject,"TextColor"): - obj.ViewObject.TextColor = (0.0,0.0,0.0) - elif self.paramstyle == 1: + if hasattr(obj.ViewObject,"TextColor"): + obj.ViewObject.TextColor = (0.0,0.0,0.0) + if self.paramstyle == 1: if hasattr(obj.ViewObject,"TextColor"): obj.ViewObject.TextColor = self.col else: @@ -479,6 +471,38 @@ def drawCircle(circle,shapemode=False): except: warn(circle) return None + +def drawEllipse(ellipse): + "returns a Part shape from a dxf arc" + + try: + c = vec(ellipse.loc) + start = round(ellipse.start_angle,prec()) + end = round(ellipse.end_angle,prec()) + majv = vec(ellipse.major) + majr = majv.Length + minr = majr*ellipse.ratio + el = Part.Ellipse(vec((0,0,0)),majr,minr) + x = majv.normalize() + z = vec(ellipse.extrusion).normalize() + y = z.cross(x) + m = DraftVecUtils.getPlaneRotation(x,y,z) + pl = FreeCAD.Placement(m) + pl.move(c) + if (fmt.paramstyle >= 4) and (not shapemode): + if (start != 0.0) or ((end != 0.0) or (end != round(math.pi/2,prec()))): + shape = el.toShape(start,end) + shape.Placement = pl + return shape + else: + return Draft.makeEllipse(majr,minr,pl) + else: + shape = el.toShape(start,end) + shape.Placement = pl + return shape + except: + warn(arc) + return None def drawFace(face): "returns a Part face from a list of points" @@ -605,7 +629,7 @@ def drawSpline(spline,shapemode=False): warn(spline) return None -def drawBlock(blockref,num=None): +def drawBlock(blockref,num=None,createObject=False): "returns a shape from a dxf block reference" if not fmt.paramstarblocks: if blockref.name[0] == '*': @@ -650,31 +674,52 @@ def drawBlock(blockref,num=None): except: warn(blockref) if shape: blockshapes[blockref.name]=shape + if createObject: + newob=doc.addObject("Part::Feature",blockref.name) + newob.Shape = shape + blockobjects[blockref.name] = newob + return newob return shape return None -def drawInsert(insert,num=None): - if blockshapes.has_key(insert): - shape = blockshapes[insert.block].copy() - else: - shape = None - for b in drawing.blocks.data: - if b.name == insert.block: - shape = drawBlock(b,num) +def drawInsert(insert,num=None,clone=False): if fmt.paramtext: attrs = attribs(insert) for a in attrs: addText(a,attrib=True) - if shape: - pos = vec(insert.loc) - rot = math.radians(insert.rotation) - scale = insert.scale - tsf = FreeCAD.Matrix() - tsf.scale(scale[0],scale[1],0) # for some reason z must be 0 to work - tsf.rotateZ(rot) - shape = shape.transformGeometry(tsf) - shape.translate(pos) - return shape + if clone: + if blockobjects.has_key(insert.block): + newob = Draft.clone(blockobjects[insert.block]) + tsf = FreeCAD.Matrix() + rot = math.radians(insert.rotation) + pos = vec(insert.loc) + tsf.move(pos) + tsf.rotateZ(rot) + sc = insert.scale + sc = FreeCAD.Vector(sc[0],sc[1],0) + newob.Placement = FreeCAD.Placement(tsf) + newob.Scale = sc + return newob + else: + shape = None + else: + if blockshapes.has_key(insert): + shape = blockshapes[insert.block].copy() + else: + shape = None + for b in drawing.blocks.data: + if b.name == insert.block: + shape = drawBlock(b,num) + if shape: + pos = vec(insert.loc) + rot = math.radians(insert.rotation) + scale = insert.scale + tsf = FreeCAD.Matrix() + tsf.scale(scale[0],scale[1],0) # for some reason z must be 0 to work + tsf.rotateZ(rot) + shape = shape.transformGeometry(tsf) + shape.translate(pos) + return shape return None def drawLayerBlock(objlist): @@ -743,28 +788,54 @@ def addText(text,attrib=False): newob = doc.addObject("App::Annotation","Text") lay.addObject(newob) val = deformat(val) - #val = val.decode("Latin1").encode("Latin1") + # the following stores text as Latin1 in annotations, which + # displays ok in coin texts, but causes errors later on. + # better store as utf8 always. + #try: + # val = val.decode("utf8").encode("Latin1") + #except: + # try: + # val = val.encode("latin1") + # except: + # pass rx = rawValue(text,11) ry = rawValue(text,21) rz = rawValue(text,31) + xv = Vector(1,0,0) + ax = Vector(0,0,1) if rx or ry or rz: xv = Vector(rx,ry,rz) if not DraftVecUtils.isNull(xv): - ax = DraftVecUtils.neg(xv.cross(Vector(1,0,0))) + ax = (xv.cross(Vector(1,0,0))).negative() if DraftVecUtils.isNull(ax): ax = Vector(0,0,1) ang = -math.degrees(DraftVecUtils.angle(xv,Vector(1,0,0),ax)) Draft.rotate(newob,ang,axis=ax) + if ax == Vector(0,0,-1): ax = Vector(0,0,1) elif hasattr(text,"rotation"): if text.rotation: Draft.rotate(newob,text.rotation) + if attrib: + attrot = rawValue(text,50) + if attrot: + Draft.rotate(newob,attrot) newob.LabelText = val.split("\n") + if gui and fmt.stdSize: + fsize = FreeCADGui.draftToolBar.fontsize + else: + fsize = float(hgt)*TEXTSCALING + if hasattr(text,"alignment"): + yv = ax.cross(xv) + if text.alignment in [1,2,3]: + sup = DraftVecUtils.scaleTo(yv,fsize/TEXTSCALING).negative() + print ax,sup + pos = pos.add(sup) + elif text.alignment in [4,5,6]: + sup = DraftVecUtils.scaleTo(yv,fsize/(2*TEXTSCALING)).negative() + pos = pos.add(sup) newob.Position = pos if gui: - if fmt.stdSize: - newob.ViewObject.FontSize = FreeCADGui.draftToolBar.fontsize - else: - newob.ViewObject.FontSize = float(hgt) + newob.ViewObject.FontSize = fsize if hasattr(text,"alignment"): if text.alignment in [2,5,8]: newob.ViewObject.Justification = "Center" @@ -791,6 +862,8 @@ def processdxf(document,filename): doc = document global blockshapes blockshapes = {} + global blockobjects + blockobjects = {} global badobjects badobjects = [] global layerBlocks @@ -830,7 +903,7 @@ def processdxf(document,filename): else: newob = addObject(shape,"Line",line.layer) if gui: fmt.formatObject(newob,line) - + # drawing polylines pls = drawing.entities.get_type("lwpolyline") @@ -876,7 +949,7 @@ def processdxf(document,filename): newob = addObject(shape,"Polyline",polyline.layer) if gui: fmt.formatObject(newob,polyline) num += 1 - + # drawing arcs arcs = drawing.entities.get_type("arc") @@ -968,6 +1041,21 @@ def processdxf(document,filename): else: newob = addObject(shape,"Spline",lay) if gui: fmt.formatObject(newob,spline) + + # drawing ellipses + + ellipses = drawing.entities.get_type("ellipse") + if ellipses: FreeCAD.Console.PrintMessage("drawing "+str(len(ellipses))+" ellipses...\n") + for ellipse in ellipses: + lay = rawValue(ellipse,8) + if fmt.dxflayout or (not rawValue(ellipse,67)): + shape = drawEllipse(ellipse) + if shape: + if fmt.makeBlocks: + addToBlock(shape,lay) + else: + newob = addObject(shape,"Ellipse",lay) + if gui: fmt.formatObject(newob,ellipse) # drawing texts @@ -979,7 +1067,7 @@ def processdxf(document,filename): for text in texts: if fmt.dxflayout or (not rawValue(text,67)): addText(text) - + else: FreeCAD.Console.PrintMessage("skipping texts...\n") # drawing 3D objects @@ -1032,6 +1120,12 @@ def processdxf(document,filename): pt = FreeCAD.Vector(x1,y1,z1) p1 = FreeCAD.Vector(x2,y2,z2) p2 = FreeCAD.Vector(x3,y3,z3) + if align >= 128: + align -= 128 + elif align >= 64: + align -= 64 + elif align >= 32: + align -= 32 if align == 0: if angle in [0,180]: p2 = FreeCAD.Vector(x3,y2,z2) @@ -1052,29 +1146,32 @@ def processdxf(document,filename): newob.ViewObject.FontSize = FreeCADGui.draftToolBar.fontsize else: st = rawValue(dim,3) - newob.ViewObject.FontSize = float(getdimheight(st)) - - else: FreeCAD.Console.PrintMessage("skipping dimensions...\n") + newob.ViewObject.FontSize = float(getdimheight(st))*TEXTSCALING + else: + FreeCAD.Console.PrintMessage("skipping dimensions...\n") # drawing points - points = drawing.entities.get_type("point") - if points: FreeCAD.Console.PrintMessage("drawing "+str(len(points))+" points...\n") - for point in points: - x = rawValue(point,10) - y = rawValue(point,20) - z = rawValue(point,30) - lay = rawValue(point,8) - if fmt.dxflayout or (not rawValue(point,67)): - if fmt.makeBlocks: - shape = Part.Vertex(x,y,z) - addToBlock(shape,lay) - else: - newob = Draft.makePoint(x,y,z) - lay = locateLayer(lay) - lay.addObject(newob) - if gui: - fmt.formatObject(newob,point) + if fmt.importPoints: + points = drawing.entities.get_type("point") + if points: FreeCAD.Console.PrintMessage("drawing "+str(len(points))+" points...\n") + for point in points: + x = rawValue(point,10) + y = rawValue(point,20) + z = rawValue(point,30) + lay = rawValue(point,8) + if fmt.dxflayout or (not rawValue(point,67)): + if fmt.makeBlocks: + shape = Part.Vertex(x,y,z) + addToBlock(shape,lay) + else: + newob = Draft.makePoint(x,y,z) + lay = locateLayer(lay) + lay.addObject(newob) + if gui: + fmt.formatObject(newob,point) + else: + FreeCAD.Console.PrintMessage("skipping points...\n") # drawing leaders @@ -1139,10 +1236,16 @@ def processdxf(document,filename): FreeCAD.Console.PrintMessage("drawing "+str(len(inserts))+" blocks...\n") blockrefs = drawing.blocks.data for ref in blockrefs: - drawBlock(ref) + if fmt.paramstyle >= 4: + drawBlock(ref,createObject=True) + else: + drawBlock(ref,createObject=False) num = 0 for insert in inserts: - shape = drawInsert(insert,num) + if (fmt.paramstyle >= 4) and not(fmt.makeBlocks): + shape = drawInsert(insert,num,clone=True) + else: + shape = drawInsert(insert,num) if shape: if fmt.makeBlocks: addToBlock(shape,insert.layer) @@ -1160,7 +1263,14 @@ def processdxf(document,filename): if shape: newob = addObject(shape,k) del layerBlocks - + + # hide block objects, if any + + for k,o in blockobjects.iteritems(): + if o.ViewObject: + o.ViewObject.hide() + del blockobjects + # finishing print "done processing" @@ -1396,6 +1506,22 @@ def writeShape(sh,ob,dxfobject,nospline=False): dxfobject.append(dxfLibrary.Arc(center, radius, ang1, ang2, color=getACI(ob), layer=getGroup(ob))) + elif DraftGeomUtils.geomType(edge) == "Ellipse": # ellipses: + if hasattr(dxfLibrary,"Ellipse"): + center = DraftVecUtils.tup(edge.Curve.Center) + norm = DraftVecUtils.tup(edge.Curve.Axis) + start = edge.FirstParameter + end = edge.LastParameter + ax = edge.Curve.Focus1.sub(edge.Curve.Center) + major = DraftVecUtils.tup(DraftVecUtils.scaleTo(ax,edge.Curve.MajorRadius)) + minor = edge.Curve.MinorRadius/edge.Curve.MajorRadius + dxfobject.append(dxfLibrary.Ellipse(center=center,majorAxis=major,normalAxis=norm, + minorAxisRatio=minor,startParameter=start, + endParameter=end, + color=getACI(ob), + layer=getGroup(ob))) + else: + FreeCAD.Console.PrintWarning("Ellipses support not found. Please delete dxfLibrary.py from your FreeCAD user directory to force auto-update\n") else: # anything else is treated as lines if len(edge.Vertexes) > 1: ve1=edge.Vertexes[0].Point @@ -1424,7 +1550,11 @@ def export(objectslist,filename,nospline=False): global exportList exportList = objectslist + print exportList + exportList = Draft.getGroupContents(exportList) + + print exportList if (len(exportList) == 1) and (Draft.getType(exportList[0]) == "ArchSectionView"): # arch view: export it "as is" @@ -1500,7 +1630,7 @@ def export(objectslist,filename,nospline=False): if not proj: pbase = DraftVecUtils.tup(ob.End) else: - pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj))) + pbase = DraftVecUtils.tup(ob.End.add(proj.negative())) dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob), layer=getGroup(ob))) diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index 4eb5f3752..0b011e6a7 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -320,7 +320,7 @@ def arcend2center(lastvec,currentvec,rx,ry,xrotation=0.0,correction=False): rx = float(rx) ry = float(ry) v0 = lastvec.sub(currentvec) - v0 = v0.multiply(0.5) + v0.multiply(0.5) m1=FreeCAD.Matrix() m1.rotateZ(-xrotation) #Formular 6.5.1 v1=m1.multiply(v0) @@ -335,19 +335,19 @@ def arcend2center(lastvec,currentvec,rx,ry,xrotation=0.0,correction=False): results=[] if abs(numer/denom) < 10**(-1*(Draft.precision())): scalefacpos = 0 - else: - try: - scalefacpos = math.sqrt(numer/denom) - except ValueError: + else: + try: + scalefacpos = math.sqrt(numer/denom) + except ValueError: FreeCAD.Console.PrintMessage('sqrt(%f/%f)\n' % (numer,denom)) - scalefacpos = 0 + scalefacpos = 0 for scalefacsign in (1,-1): scalefac = scalefacpos * scalefacsign vcx1 = Vector(v1.y*rx/ry,-v1.x*ry/rx,0).multiply(scalefac) # Step2 F.6.5.2 m2=FreeCAD.Matrix() m2.rotateZ(xrotation) centeroff = currentvec.add(lastvec) - centeroff = DraftVecUtils.scale(centeroff,.5) + centeroff.multiply(.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 @@ -359,19 +359,19 @@ def arcend2center(lastvec,currentvec,rx,ry,xrotation=0.0,correction=False): def getrgb(color): - "returns a rgb value #000000 from a freecad color" - r = str(hex(int(color[0]*255)))[2:].zfill(2) - g = str(hex(int(color[1]*255)))[2:].zfill(2) - b = str(hex(int(color[2]*255)))[2:].zfill(2) - return "#"+r+g+b + "returns a rgb value #000000 from a freecad color" + r = str(hex(int(color[0]*255)))[2:].zfill(2) + g = str(hex(int(color[1]*255)))[2:].zfill(2) + b = str(hex(int(color[2]*255)))[2:].zfill(2) + return "#"+r+g+b class svgHandler(xml.sax.ContentHandler): - "this handler parses the svg files and creates freecad objects" + "this handler parses the svg files and creates freecad objects" - def __init__(self): - "retrieving Draft parameters" - params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") - self.style = params.GetInt("svgstyle") + def __init__(self): + "retrieving Draft parameters" + params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + self.style = params.GetInt("svgstyle") self.count = 0 self.transform = None self.grouptransform = [] @@ -380,42 +380,44 @@ class svgHandler(xml.sax.ContentHandler): global Part import Part - - if gui and draftui: - r = float(draftui.color.red()/255.0) - g = float(draftui.color.green()/255.0) - b = float(draftui.color.blue()/255.0) - self.lw = float(draftui.linewidth) - else: - self.lw = float(params.GetInt("linewidth")) - c = params.GetUnsigned("color") - r = float(((c>>24)&0xFF)/255) - g = float(((c>>16)&0xFF)/255) - b = float(((c>>8)&0xFF)/255) - self.col = (r,g,b,0.0) + + if gui and draftui: + r = float(draftui.color.red()/255.0) + g = float(draftui.color.green()/255.0) + b = float(draftui.color.blue()/255.0) + self.lw = float(draftui.linewidth) + else: + self.lw = float(params.GetInt("linewidth")) + c = params.GetUnsigned("color") + r = float(((c>>24)&0xFF)/255) + g = float(((c>>16)&0xFF)/255) + b = float(((c>>8)&0xFF)/255) + self.col = (r,g,b,0.0) - def format(self,obj): - "applies styles to passed object" - if self.style and gui: - v = obj.ViewObject - if self.color: v.LineColor = self.color - if self.width: v.LineWidth = self.width - if self.fill: v.ShapeColor = self.fill - - def startElement(self, name, attrs): + def format(self,obj): + "applies styles to passed object" + if self.style and gui: + v = obj.ViewObject + if self.color: v.LineColor = self.color + if self.width: v.LineWidth = self.width + if self.fill: v.ShapeColor = self.fill + + def startElement(self, name, attrs): - # reorganizing data into a nice clean dictionary + # reorganizing data into a nice clean dictionary self.count += 1 FreeCAD.Console.PrintMessage('processing element %d: %s\n'%(self.count,name)) FreeCAD.Console.PrintMessage('existing group transform: %s\n'%(str(self.grouptransform))) - - data = {} - for (keyword,content) in attrs.items(): - content = content.replace(',',' ') - content = content.split() - data[keyword]=content + + data = {} + for (keyword,content) in attrs.items(): + #print keyword,content + content = content.replace(',',' ') + content = content.split() + #print keyword,content + data[keyword]=content if 'style' in data: if not data['style']: @@ -425,24 +427,27 @@ class svgHandler(xml.sax.ContentHandler): content = content.split(';') for i in content: pair = i.split(':') - if len(pair)>1: data[pair[0]]=pair[1] + if len(pair)>1: data[pair[0]]=pair[1] - for k in ['x','y','x1','y1','x2','y2','r','rx','ry','cx','cy','width','height']: - if k in data: - data[k] = getsize(data[k][0],'css') + for k in ['x','y','x1','y1','x2','y2','r','rx','ry','cx','cy','width','height']: + if k in data: + data[k] = getsize(data[k][0],'css') - for k in ['fill','stroke','stroke-width','font-size']: - if k in data: - if isinstance(data[k],list): - data[k]=data[k][0] + for k in ['fill','stroke','stroke-width','font-size']: + if k in data: + if isinstance(data[k],list): + if data[k][0].lower().startswith("rgb("): + data[k] = ",".join(data[k]) + else: + data[k]=data[k][0] - # extracting style info - - self.fill = None - self.color = None - self.width = None - self.text = None - + # extracting style info + + self.fill = None + self.color = None + self.width = None + self.text = None + if name == 'svg': m=FreeCAD.Matrix() if 'width' in data and 'height' in data and \ @@ -481,16 +486,16 @@ class svgHandler(xml.sax.ContentHandler): #fallback to 90 dpi m.scale(Vector(25.4/90.0,25.4/90.0,1)) self.grouptransform.append(m) - if 'fill' in data: - if data['fill'][0] != 'none': - self.fill = getcolor(data['fill']) - if 'stroke' in data: - if data['stroke'][0] != 'none': - self.color = getcolor(data['stroke']) - if 'stroke-width' in data: - if data['stroke-width'] != 'none': - self.width = getsize(data['stroke-width'],'css') - if 'transform' in data: + if 'fill' in data: + if data['fill'][0] != 'none': + self.fill = getcolor(data['fill']) + if 'stroke' in data: + if data['stroke'][0] != 'none': + self.color = getcolor(data['stroke']) + if 'stroke-width' in data: + if data['stroke-width'] != 'none': + self.width = getsize(data['stroke-width'],'css') + if 'transform' in data: m = self.getMatrix(attrs.getValue('transform')) if name == "g": self.grouptransform.append(m) @@ -500,29 +505,29 @@ class svgHandler(xml.sax.ContentHandler): if name == "g": self.grouptransform.append(FreeCAD.Matrix()) - if (self.style == 1): - self.color = self.col - self.width = self.lw + if (self.style == 1): + self.color = self.col + self.width = self.lw pathname = None if 'id' in data: pathname = data['id'][0] FreeCAD.Console.PrintMessage('name: %s\n'%pathname) - # processing paths + # processing paths - if name == "path": + if name == "path": FreeCAD.Console.PrintMessage('data: %s\n'%str(data)) if not pathname: pathname = 'Path' - path = [] - point = [] - lastvec = Vector(0,0,0) - lastpole = None - command = None - relative = False - firstvec = None + path = [] + point = [] + lastvec = Vector(0,0,0) + lastpole = None + command = None + relative = False + firstvec = None if "freecad:basepoint1" in data: p1 = data["freecad:basepoint1"] @@ -616,11 +621,11 @@ class svgHandler(xml.sax.ContentHandler): else: # anticlockwise perp = DraftVecUtils.rotate2D(chord,math.pi/2) - chord = DraftVecUtils.scale(chord,.5) + chord.multiply(.5) if chord.Length > rx: a = 0 else: a = math.sqrt(rx**2-chord.Length**2) s = rx - a - perp = DraftVecUtils.scale(perp,s/perp.Length) + perp.multiply(s/perp.Length) midpoint = lastvec.add(chord.add(perp)) seg = Part.Arc(lastvec,midpoint,currentvec).toShape() else:# big arc or elliptical arc @@ -748,7 +753,11 @@ class svgHandler(xml.sax.ContentHandler): path.append(seg) elif (d == "Z") or (d == "z"): if not DraftVecUtils.equals(lastvec,firstvec): + try: seg = Part.Line(lastvec,firstvec).toShape() + except: + pass + else: path.append(seg) if path: #the path should be closed by now #sh=makewire(path,True) @@ -774,9 +783,9 @@ class svgHandler(xml.sax.ContentHandler): self.format(obj) - # processing rects + # processing rects - if name == "rect": + if name == "rect": if not pathname: pathname = 'Rectangle' edges = [] if ('rx' not in data or data['rx'] < 10**(-1*Draft.precision())) and \ @@ -847,37 +856,37 @@ class svgHandler(xml.sax.ContentHandler): self.format(obj) # processing lines - if name == "line": + if name == "line": if not pathname: pathname = 'Line' - p1 = Vector(data['x1'],-data['y1'],0) - p2 = Vector(data['x2'],-data['y2'],0) - sh = Part.Line(p1,p2).toShape() + p1 = Vector(data['x1'],-data['y1'],0) + p2 = Vector(data['x2'],-data['y2'],0) + sh = Part.Line(p1,p2).toShape() sh = self.applyTrans(sh) - obj = self.doc.addObject("Part::Feature",pathname) - obj.Shape = sh - self.format(obj) + obj = self.doc.addObject("Part::Feature",pathname) + obj.Shape = sh + self.format(obj) # processing polylines and polygons - if name == "polyline" or name == "polygon": - '''a simpler implementation would be sh = Part.makePolygon([Vector(svgx,-svgy,0) for svgx,svgy in zip(points[0::2],points[1::2])]) - but there would be more difficlult to search for duplicate points beforehand.''' - if not pathname: pathname = 'Polyline' - points=[float(d) for d in data['points']] + if name == "polyline" or name == "polygon": + '''a simpler implementation would be sh = Part.makePolygon([Vector(svgx,-svgy,0) for svgx,svgy in zip(points[0::2],points[1::2])]) + but there would be more difficlult to search for duplicate points beforehand.''' + if not pathname: pathname = 'Polyline' + points=[float(d) for d in data['points']] FreeCAD.Console.PrintMessage('points %s\n'%str(points)) - lenpoints=len(points) - if lenpoints>=4 and lenpoints % 2 == 0: - lastvec = Vector(points[0],-points[1],0) - path=[] + lenpoints=len(points) + if lenpoints>=4 and lenpoints % 2 == 0: + lastvec = Vector(points[0],-points[1],0) + path=[] if name == 'polygon': points=points+points[:2] # emulate closepath - for svgx,svgy in zip(points[2::2],points[3::2]): - currentvec = Vector(svgx,-svgy,0) - if not DraftVecUtils.equals(lastvec,currentvec): - seg = Part.Line(lastvec,currentvec).toShape() - #print "polyline seg ",lastvec,currentvec - lastvec = currentvec - path.append(seg) + for svgx,svgy in zip(points[2::2],points[3::2]): + currentvec = Vector(svgx,-svgy,0) + if not DraftVecUtils.equals(lastvec,currentvec): + seg = Part.Line(lastvec,currentvec).toShape() + #print "polyline seg ",lastvec,currentvec + lastvec = currentvec + path.append(seg) if path: sh = Part.Wire(path) if self.fill and sh.isClosed(): @@ -908,9 +917,9 @@ class svgHandler(xml.sax.ContentHandler): sh = Part.Wire([sh]) sh = Part.Face(sh) sh = self.applyTrans(sh) - obj = self.doc.addObject("Part::Feature",pathname) - obj.Shape = sh - self.format(obj) + obj = self.doc.addObject("Part::Feature",pathname) + obj.Shape = sh + self.format(obj) # processing circles @@ -925,13 +934,13 @@ class svgHandler(xml.sax.ContentHandler): sh = Part.Face(sh) sh.translate(c) sh = self.applyTrans(sh) - obj = self.doc.addObject("Part::Feature",pathname) - obj.Shape = sh - self.format(obj) + obj = self.doc.addObject("Part::Feature",pathname) + obj.Shape = sh + self.format(obj) # processing texts - if name in ["text","tspan"]: + if name in ["text","tspan"]: if not("freecad:skip" in data): FreeCAD.Console.PrintMessage("processing a text\n") if 'x' in data: @@ -953,12 +962,12 @@ class svgHandler(xml.sax.ContentHandler): FreeCAD.Console.PrintMessage("done processing element %d\n"%self.count) - def characters(self,content): - if self.text: + def characters(self,content): + if self.text: FreeCAD.Console.PrintMessage("reading characters %s\n" % str(content)) - obj=self.doc.addObject("App::Annotation",'Text') - obj.LabelText = content.encode('latin1') - vec = Vector(self.x,-self.y,0) + obj=self.doc.addObject("App::Annotation",'Text') + obj.LabelText = content.encode('latin1') + vec = Vector(self.x,-self.y,0) if self.transform: vec = self.translateVec(vec,self.transform) #print "own transform: ",self.transform, vec @@ -967,10 +976,10 @@ class svgHandler(xml.sax.ContentHandler): vec = transform.multiply(vec) #print "applying vector: ",vec obj.Position = vec - if gui: - obj.ViewObject.FontSize = int(self.text) - if self.fill: obj.ViewObject.TextColor = self.fill - else: obj.ViewObject.TextColor = (0.0,0.0,0.0,0.0) + if gui: + obj.ViewObject.FontSize = int(self.text) + if self.fill: obj.ViewObject.TextColor = self.fill + else: obj.ViewObject.TextColor = (0.0,0.0,0.0,0.0) def endElement(self, name): if not name in ["tspan"]: @@ -1010,41 +1019,41 @@ class svgHandler(xml.sax.ContentHandler): def getMatrix(self,tr): "returns a FreeCAD matrix from a svg transform attribute" - transformre=re.compile('(matrix|translate|scale|rotate|skewX|skewY)\s*?\((.*?)\)',re.DOTALL) + transformre=re.compile('(matrix|translate|scale|rotate|skewX|skewY)\s*?\((.*?)\)',re.DOTALL) m = FreeCAD.Matrix() for transformation, arguments in transformre.findall(tr): - argsplit=[float(arg) for arg in arguments.replace(',',' ').split()] + argsplit=[float(arg) for arg in arguments.replace(',',' ').split()] #m.multiply(FreeCAD.Matrix (1,0,0,0,0,-1)) #print '%s:%s %s %d' % (transformation, arguments,argsplit,len(argsplit)) - if transformation == 'translate': - tx = argsplit[0] - ty = argsplit[1] if len(argsplit) > 1 else 0.0 - m.move(Vector(tx,-ty,0)) - elif transformation == 'scale': - sx = argsplit[0] - sy = argsplit[1] if len(argsplit) > 1 else sx - m.scale(Vector(sx,sy,1)) - elif transformation == 'rotate': - angle = argsplit[0] - if len(argsplit) >= 3: - cx = argsplit[1] - cy = argsplit[2] - m.move(Vector(cx,-cy,0)) + if transformation == 'translate': + tx = argsplit[0] + ty = argsplit[1] if len(argsplit) > 1 else 0.0 + m.move(Vector(tx,-ty,0)) + elif transformation == 'scale': + sx = argsplit[0] + sy = argsplit[1] if len(argsplit) > 1 else sx + m.scale(Vector(sx,sy,1)) + elif transformation == 'rotate': + angle = argsplit[0] + if len(argsplit) >= 3: + cx = argsplit[1] + cy = argsplit[2] + m.move(Vector(cx,-cy,0)) m.rotateZ(math.radians(-angle)) #mirroring one axis equals changing the direction of rotaion - if len(argsplit) >= 3: - m.move(Vector(-cx,cy,0)) - elif transformation == 'skewX': - m=m.multiply(FreeCAD.Matrix(1,-math.tan(math.radians(argsplit[0])))) - elif transformation == 'skewY': - m=m.multiply(FreeCAD.Matrix(1,0,0,0,-math.tan(math.radians(argsplit[0])))) - elif transformation == 'matrix': + if len(argsplit) >= 3: + m.move(Vector(-cx,cy,0)) + elif transformation == 'skewX': + m=m.multiply(FreeCAD.Matrix(1,-math.tan(math.radians(argsplit[0])))) + elif transformation == 'skewY': + m=m.multiply(FreeCAD.Matrix(1,0,0,0,-math.tan(math.radians(argsplit[0])))) + elif transformation == 'matrix': # '''transformation matrix: # FreeCAD SVG # (+A -C +0 +E) (A C 0 E) # (-B +D -0 -F) = (-Y) * (B D 0 F) *(-Y) # (+0 -0 +1 +0) (0 0 1 0) # (+0 -0 +0 +1) (0 0 0 1)''' - m=m.multiply(FreeCAD.Matrix(argsplit[0],-argsplit[2],0,argsplit[4],-argsplit[1],argsplit[3],0,-argsplit[5])) + m=m.multiply(FreeCAD.Matrix(argsplit[0],-argsplit[2],0,argsplit[4],-argsplit[1],argsplit[3],0,-argsplit[5])) #else: #print 'SKIPPED %s' % transformation #print "m= ",m @@ -1052,17 +1061,17 @@ class svgHandler(xml.sax.ContentHandler): return m def decodeName(name): - "decodes encoded strings" - try: - decodedName = (name.decode("utf8")) - except UnicodeDecodeError: - try: - decodedName = (name.decode("latin1")) - except UnicodeDecodeError: - FreeCAD.Console.PrintError("svg: error: couldn't determine character encoding\n") + "decodes encoded strings" + try: + decodedName = (name.decode("utf8")) + except UnicodeDecodeError: + try: + decodedName = (name.decode("latin1")) + except UnicodeDecodeError: + FreeCAD.Console.PrintError("svg: error: couldn't determine character encoding\n") - decodedName = name - return decodedName + decodedName = name + return decodedName def getContents(filename,tag,stringmode=False): "gets the contents of all the occurences of the given tag in the given file" @@ -1087,50 +1096,50 @@ def getContents(filename,tag,stringmode=False): return result def open(filename): - docname=os.path.split(filename)[1] - doc=FreeCAD.newDocument(docname) - doc.Label = decodeName(docname[:-4]) - parser = xml.sax.make_parser() - parser.setContentHandler(svgHandler()) - parser._cont_handler.doc = doc + docname=os.path.split(filename)[1] + doc=FreeCAD.newDocument(docname) + doc.Label = decodeName(docname[:-4]) + parser = xml.sax.make_parser() + parser.setContentHandler(svgHandler()) + parser._cont_handler.doc = doc f = pythonopen(filename) - parser.parse(f) + parser.parse(f) f.close() - doc.recompute() + doc.recompute() return doc def insert(filename,docname): - try: - doc=FreeCAD.getDocument(docname) - except: - doc=FreeCAD.newDocument(docname) - FreeCAD.ActiveDocument = doc - parser = xml.sax.make_parser() - parser.setContentHandler(svgHandler()) - parser._cont_handler.doc = doc - parser.parse(pythonopen(filename)) - doc.recompute() + try: + doc=FreeCAD.getDocument(docname) + except: + doc=FreeCAD.newDocument(docname) + FreeCAD.ActiveDocument = doc + parser = xml.sax.make_parser() + parser.setContentHandler(svgHandler()) + parser._cont_handler.doc = doc + parser.parse(pythonopen(filename)) + doc.recompute() def export(exportList,filename): - "called when freecad exports a file" + "called when freecad exports a file" svg_export_style = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetInt("svg_export_style") if svg_export_style != 0 and svg_export_style != 1: FreeCAD.Console.PrintMessage("unknown svg export style, switching to Translated\n") svg_export_style = 0 - # finding sheet size - minx = 10000 - miny = 10000 - maxx = 0 - maxy = 0 - for ob in exportList: - if ob.isDerivedFrom("Part::Feature"): - for v in ob.Shape.Vertexes: - if v.Point.x < minx: minx = v.Point.x - if v.Point.x > maxx: maxx = v.Point.x - if v.Point.y < miny: miny = v.Point.y - if v.Point.y > maxy: maxy = v.Point.y + # finding sheet size + minx = 10000 + miny = 10000 + maxx = 0 + maxy = 0 + for ob in exportList: + if ob.isDerivedFrom("Part::Feature"): + for v in ob.Shape.Vertexes: + if v.Point.x < minx: minx = v.Point.x + if v.Point.x > maxx: maxx = v.Point.x + if v.Point.y < miny: miny = v.Point.y + if v.Point.y > maxy: maxy = v.Point.y if svg_export_style == 0: # translated-style exports get a bit of a margin margin = (maxx-minx)*.01 @@ -1138,23 +1147,23 @@ def export(exportList,filename): # raw-style exports get no margin margin = 0 - minx -= margin - maxx += margin - miny -= margin - maxy += margin - sizex = maxx-minx - sizey = maxy-miny - miny += margin + minx -= margin + maxx += margin + miny -= margin + maxy += margin + sizex = maxx-minx + sizey = maxy-miny + miny += margin - # writing header + # writing header # we specify the svg width and height in FreeCAD's physical units (mm), # and specify the viewBox so that user units maps one-to-one to mm - svg = pythonopen(filename,'wb') - svg.write('\n') - svg.write('\n') - svg.write('\n') + svg.write('\n') + svg.write('\n') + svg.write(' xmlns="http://www.w3.org/2000/svg" version="1.1"') + svg.write('>\n') - # writing paths - for ob in exportList: + # writing paths + for ob in exportList: if svg_export_style == 0: # translated-style exports have the entire sketch translated to fit in the X>0, Y>0 quadrant svg.write('\n') @@ -1177,6 +1186,6 @@ def export(exportList,filename): svg.write(Draft.getSVG(ob)) svg.write('\n') - # closing - svg.write('') - svg.close() + # closing + svg.write('') + svg.close() diff --git a/src/Mod/Import/App/AppImport.cpp b/src/Mod/Import/App/AppImport.cpp index 77b44caa4..c21b306b2 100644 --- a/src/Mod/Import/App/AppImport.cpp +++ b/src/Mod/Import/App/AppImport.cpp @@ -25,47 +25,29 @@ #include "PreCompiled.h" #ifndef _PreComp_ -# include -# if defined (_POSIX_C_SOURCE) -# undef _POSIX_C_SOURCE -# endif // (re-)defined in pyconfig.h -# include #endif #include #include -#include -#include - -#include "FeatureImportStep.h" -#include "FeatureImportIges.h" - /* registration table */ -extern struct PyMethodDef Import_methods[]; +extern struct PyMethodDef Import_Import_methods[]; - -// python entry -#ifdef FC_OS_WIN32 -# define ModuleExport __declspec(dllexport) -#else -# define ModuleExport -#endif extern "C" { -void ModuleExport initImport() { +void ImportExport initImport() +{ + (void) Py_InitModule("Import", Import_Import_methods); /* mod name, table ptr */ - (void) Py_InitModule("Import", Import_methods); /* mod name, table ptr */ + try { + Base::Interpreter().loadModule("Part"); + } + catch(const Base::Exception& e) { + PyErr_SetString(PyExc_ImportError, e.what()); + return; + } - // load dependend module - Base::Interpreter().loadModule("Part"); - - App::AbstractFeatureFactory().AddProducer("ImportStep",new App::AbstractFeatureProducer); - App::AbstractFeatureFactory().AddProducer("ImportIges",new App::AbstractFeatureProducer); - - Base::Console().Log("Import loaded\n"); - - return; + Base::Console().Log("Loading Import module... done\n"); } diff --git a/src/Mod/Import/App/AppImportPy.cpp b/src/Mod/Import/App/AppImportPy.cpp index da82ca508..4399f17ba 100644 --- a/src/Mod/Import/App/AppImportPy.cpp +++ b/src/Mod/Import/App/AppImportPy.cpp @@ -1,118 +1,264 @@ /*************************************************************************** - * (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * Copyright (c) 2013 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Library General Public License (LGPL) * - * as published by the Free Software Foundation; either version 2 of * - * the License, or (at your option) any later version. * - * for detail see the LICENCE text file. * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * * * - * FreeCAD is distributed in the hope that it will be useful, * + * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * - * License along with FreeCAD; if not, write to the Free Software * - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * - * USA * + * 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 * * * - * Juergen Riegel 2002 * ***************************************************************************/ #include "PreCompiled.h" +#if defined(__MINGW32__) +# define WNT // avoid conflict with GUID +#endif #ifndef _PreComp_ -# include -# if defined (_POSIX_C_SOURCE) -# undef _POSIX_C_SOURCE -# endif // (re-)defined in pyconfig.h -# include -# include -# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include #endif +#include "ImportOCAF.h" +#include #include -#include - #include #include -#include -#include -#include +#include +#include +#include +#include +#include /* module functions */ -static PyObject * -open(PyObject *self, PyObject *args) + +static PyObject * importer(PyObject *self, PyObject *args) { - const char* Name; - if (! PyArg_ParseTuple(args, "s",&Name)) - return NULL; + char* Name; + char* DocName=0; + if (!PyArg_ParseTuple(args, "s|s",&Name,&DocName)) + return 0; - Base::Console().Log("Open in Import with %s",Name); + PY_TRY { + //Base::Console().Log("Insert in Part with %s",Name); + Base::FileInfo file(Name); - // extract ending - std::string cEnding(Name); - unsigned int pos = cEnding.find_last_of('.'); - if(pos == cEnding.size()) - Py_Error(PyExc_Exception,"no file ending"); - cEnding.erase(0,pos+1); + App::Document *pcDoc = 0; + if (DocName) { + pcDoc = App::GetApplication().getDocument(DocName); + } + if (!pcDoc) { + pcDoc = App::GetApplication().newDocument("Unnamed"); + } - if(cEnding == "stp" || cEnding == "step") - { - // create new document and add Import feature - App::Document *pcDoc = App::GetApplication().newDocument(); - App::AbstractFeature *pcFeature = pcDoc->addFeature("ImportStep","Step Import"); - pcFeature->setPropertyString (Name,"FileName"); - pcFeature->TouchProperty("FileName"); - pcDoc->recompute(); + Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication(); + Handle(TDocStd_Document) hDoc; + hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); - }else if(cEnding == "igs" || cEnding == "iges") - { - // create new document and add Import feature - App::Document *pcDoc = App::GetApplication().newDocument(); - App::AbstractFeature *pcFeature = pcDoc->addFeature("ImportIges","Iges Import"); -assert(0); -// pcFeature->GetProperty("FileName").Set(Name); - pcFeature->TouchProperty("FileName"); - pcDoc->recompute(); + if (file.hasExtension("stp") || file.hasExtension("step")) { + try { + STEPCAFControl_Reader aReader; + aReader.SetColorMode(true); + aReader.SetNameMode(true); + aReader.SetLayerMode(true); + if (aReader.ReadFile((Standard_CString)Name) != IFSelect_RetDone) { + PyErr_SetString(PyExc_Exception, "cannot read STEP file"); + return 0; + } - }else + Handle_Message_ProgressIndicator pi = new Part::ProgressIndicator(100); + aReader.Reader().WS()->MapReader()->SetProgress(pi); + pi->NewScope(100, "Reading STEP file..."); + pi->Show(); + aReader.Transfer(hDoc); + pi->EndScope(); + } + catch (OSD_Exception) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + Base::Console().Error("%s\n", e->GetMessageString()); + Base::Console().Message("Try to load STEP file without colors...\n"); - Py_Error(PyExc_Exception,"unknown file ending"); + Part::ImportStepParts(pcDoc,Name); + pcDoc->recompute(); + } + } + else if (file.hasExtension("igs") || file.hasExtension("iges")) { + try { + IGESControl_Controller::Init(); + Interface_Static::SetIVal("read.surfacecurve.mode",3); + IGESCAFControl_Reader aReader; + aReader.SetColorMode(true); + aReader.SetNameMode(true); + aReader.SetLayerMode(true); + if (aReader.ReadFile((Standard_CString)Name) != IFSelect_RetDone) { + PyErr_SetString(PyExc_Exception, "cannot read IGES file"); + return 0; + } + Handle_Message_ProgressIndicator pi = new Part::ProgressIndicator(100); + aReader.WS()->MapReader()->SetProgress(pi); + pi->NewScope(100, "Reading IGES file..."); + pi->Show(); + aReader.Transfer(hDoc); + pi->EndScope(); + } + catch (OSD_Exception) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + Base::Console().Error("%s\n", e->GetMessageString()); + Base::Console().Message("Try to load IGES file without colors...\n"); - Py_Return; + Part::ImportIgesParts(pcDoc,Name); + pcDoc->recompute(); + } + } + else { + PyErr_SetString(PyExc_Exception, "no supported file format"); + return 0; + } + +#if 1 + Import::ImportOCAF ocaf(hDoc, pcDoc, file.fileNamePure()); + ocaf.loadShapes(); +#else + Import::ImportXCAF xcaf(hDoc, pcDoc, file.fileNamePure()); + xcaf.loadShapes(); +#endif + pcDoc->recompute(); + + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + PY_CATCH + + Py_Return; } -/* module functions */ -static PyObject * -save(PyObject *self, PyObject *args) +static PyObject * open(PyObject *self, PyObject *args) { - char* str; + return importer(self, args); +} - if (! PyArg_ParseTuple(args, "s",&str)) +static PyObject * exporter(PyObject *self, PyObject *args) +{ + PyObject* object; + const char* filename; + if (!PyArg_ParseTuple(args, "Os",&object,&filename)) return NULL; - TopoDS_Shape ResultShape; - BRep_Builder aBuilder; + PY_TRY { + Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication(); + Handle(TDocStd_Document) hDoc; + hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); + Import::ExportOCAF ocaf(hDoc); - BRepTools::Read(ResultShape,(const Standard_CString)str,aBuilder); + Py::List list(object); + for (Py::List::iterator it = list.begin(); it != list.end(); ++it) { + PyObject* item = (*it).ptr(); + if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { + App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); + if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* part = static_cast(obj); + std::vector colors; + ocaf.saveShape(part, colors); + } + else { + Base::Console().Message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue()); + } + } + else if (PyTuple_Check(item) && PyTuple_Size(item) == 2) { + Py::Tuple tuple(*it); + Py::Object item0 = tuple.getItem(0); + Py::Object item1 = tuple.getItem(1); + if (PyObject_TypeCheck(item0.ptr(), &(App::DocumentObjectPy::Type))) { + App::DocumentObject* obj = static_cast(item0.ptr())->getDocumentObjectPtr(); + if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* part = static_cast(obj); + App::PropertyColorList colors; + colors.setPyObject(item1.ptr()); + ocaf.saveShape(part, colors.getValues()); + } + else { + Base::Console().Message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue()); + } + } + } + } - return new Part::TopoShapePy(ResultShape); /* convert C -> Python */ + Base::FileInfo file(filename); + if (file.hasExtension("stp") || file.hasExtension("step")) { + //Interface_Static::SetCVal("write.step.schema", "AP214IS"); + STEPCAFControl_Writer writer; + writer.Transfer(hDoc, STEPControl_AsIs); + // edit STEP header +#if OCC_VERSION_HEX >= 0x060500 + APIHeaderSection_MakeHeader makeHeader(writer.ChangeWriter().Model()); +#else + APIHeaderSection_MakeHeader makeHeader(writer.Writer().Model()); +#endif + makeHeader.SetName(new TCollection_HAsciiString((const Standard_CString)filename)); + makeHeader.SetAuthorValue (1, new TCollection_HAsciiString("FreeCAD")); + makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString("FreeCAD")); + makeHeader.SetOriginatingSystem(new TCollection_HAsciiString("FreeCAD")); + makeHeader.SetDescriptionValue(1, new TCollection_HAsciiString("FreeCAD Model")); + writer.Write(filename); + } + else if (file.hasExtension("igs") || file.hasExtension("iges")) { + IGESControl_Controller::Init(); + IGESCAFControl_Writer writer; + writer.Transfer(hDoc); + writer.Write(filename); + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + PY_CATCH + + Py_Return; } - - /* registration table */ -struct PyMethodDef Import_methods[] = { - {"open", open, 1}, /* method name, C func ptr, always-tuple */ - {"save", save, 1}, - +struct PyMethodDef Import_Import_methods[] = { + {"open" ,open ,METH_VARARGS, + "open(string) -- Open the file and create a new document."}, + {"insert" ,importer ,METH_VARARGS, + "insert(string,string) -- Insert the file into the given document."}, + {"export" ,exporter ,METH_VARARGS, + "export(list,string) -- Export a list of objects into a single file."}, {NULL, NULL} /* end of table marker */ }; diff --git a/src/Mod/Import/App/CMakeLists.txt b/src/Mod/Import/App/CMakeLists.txt index 1ac7c717a..e89a76a2d 100644 --- a/src/Mod/Import/App/CMakeLists.txt +++ b/src/Mod/Import/App/CMakeLists.txt @@ -1,49 +1,55 @@ -add_definitions(-DFCAppImport -DFC_DEBUG) +if(MSVC) + add_definitions(-DFCAppImport -DHAVE_ACOSH -DHAVE_ASINH -DHAVE_ATANH) +else(MSVC) + add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) +endif(MSVC) + include_directories( -# ${CMAKE_SOURCE_DIR}/src -# ${OPENCV_INCLUDE_DIR} - ${OCC_INCLUDE_DIR} -# ${PYTHON_INCLUDE_PATH} - ${ZLIB_INCLUDE_DIR} - ${XERCES_INCLUDE_DIR}) - -if(WIN32) - set(Import_LIBS -# ${OPENCV_LIBRARIES} -# -lTKIGES \ -# -lTKSTEP \ - Part - FreeCADApp) -else(WIN32) - set(Import_LIBS -# -lTKIGES \ -# -lTKSTEP \ -# -lFreeCADBase \ -# -lFreeCADApp \ -# -lPart + ${CMAKE_CURRENT_BINARY_DIR} + ${Boost_INCLUDE_DIRS} + ${OCC_INCLUDE_DIR} + ${ZLIB_INCLUDE_DIR} + ${PYTHON_INCLUDE_PATH} + ${XERCESC_INCLUDE_DIR} ) -endif(WIN32) -set(Import_SRCS - AppImport.cpp - AppImportPy.cpp - FeatureImportIges.cpp - FeatureImportIges.h - FeatureImportStep.cpp - FeatureImportStep.h - PreCompiled.cpp - PreCompiled.h +link_directories(${OCC_LIBRARY_DIR}) + +set(Import_LIBS + Part + ${OCC_OCAF_LIBRARIES} + ${OCC_OCAF_DEBUG_LIBRARIES} +) + +SET(Import_SRCS + AppImport.cpp + AppImportPy.cpp + ImportOCAF.cpp + ImportOCAF.h + PreCompiled.cpp + PreCompiled.h ) add_library(Import SHARED ${Import_SRCS}) - target_link_libraries(Import ${Import_LIBS}) -set_target_properties(Import PROPERTIES SUFFIX ".pyd") - -if(UNIX) +if(MSVC) + set_target_properties(Import PROPERTIES SUFFIX ".pyd") + set_target_properties(Import PROPERTIES DEBUG_OUTPUT_NAME "Import_d") + set_target_properties(Import PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/Import) + set_target_properties(Import PROPERTIES PREFIX "../") + # Set special compiler flag to convert a SIGSEV into an exception + set_target_properties(Import PROPERTIES COMPILE_FLAGS "/EHa") +elseif(MINGW) + set_target_properties(Import PROPERTIES SUFFIX ".pyd") + set_target_properties(Import PROPERTIES DEBUG_OUTPUT_NAME "Import_d") + set_target_properties(Import PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/Import) + set_target_properties(Import PROPERTIES PREFIX "") +else(MSVC) + set_target_properties(Import PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/Import) + set_target_properties(Import PROPERTIES PREFIX "") set_target_properties(Import PROPERTIES INSTALL_RPATH ${INSTALL_RPATH}) -endif(UNIX) +endif(MSVC) -install(TARGETS Import DESTINATION lib) +INSTALL(TARGETS Import DESTINATION lib) diff --git a/src/Mod/Import/App/ImportOCAF.cpp b/src/Mod/Import/App/ImportOCAF.cpp new file mode 100644 index 000000000..ace94ec0c --- /dev/null +++ b/src/Mod/Import/App/ImportOCAF.cpp @@ -0,0 +1,548 @@ +/*************************************************************************** + * Copyright (c) 2013 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" +#if defined(__MINGW32__) +# define WNT // avoid conflict with GUID +#endif +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#if OCC_VERSION_HEX >= 0x060500 +# include +# else +# include +# endif +#endif + +#include "ImportOCAF.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace Import; + + +ImportOCAF::ImportOCAF(Handle_TDocStd_Document h, App::Document* d, const std::string& name) + : pDoc(h), doc(d), default_name(name) +{ + aShapeTool = XCAFDoc_DocumentTool::ShapeTool (pDoc->Main()); + aColorTool = XCAFDoc_DocumentTool::ColorTool(pDoc->Main()); +} + +ImportOCAF::~ImportOCAF() +{ +} + +void ImportOCAF::loadShapes() +{ + myRefShapes.clear(); + loadShapes(pDoc->Main(), TopLoc_Location(), default_name, "", false); +} + +void ImportOCAF::loadShapes(const TDF_Label& label, const TopLoc_Location& loc, const std::string& defaultname, const std::string& assembly, bool isRef) +{ + int hash = 0; + TopoDS_Shape aShape; + if (aShapeTool->GetShape(label,aShape)) { + hash = aShape.HashCode(HashUpper); + } + + Handle(TDataStd_Name) name; + std::string part_name = defaultname; + if (label.FindAttribute(TDataStd_Name::GetID(),name)) { + TCollection_ExtendedString extstr = name->Get(); + char* str = new char[extstr.LengthOfCString()+1]; + extstr.ToUTF8CString(str); + part_name = str; + delete [] str; + if (part_name.empty()) { + part_name = defaultname; + } + else { + bool ws=true; + for (std::string::iterator it = part_name.begin(); it != part_name.end(); ++it) { + if (*it != ' ') { + ws = false; + break; + } + } + if (ws) + part_name = defaultname; + } + } + + TopLoc_Location part_loc = loc; + Handle(XCAFDoc_Location) hLoc; + if (label.FindAttribute(XCAFDoc_Location::GetID(), hLoc)) { + if (isRef) + part_loc = part_loc * hLoc->Get(); + else + part_loc = hLoc->Get(); + } + +#ifdef FC_DEBUG + Base::Console().Message("H:%d, N:%s, T:%d, A:%d, S:%d, C:%d, SS:%d, F:%d, R:%d, C:%d, SS:%d\n", + hash, + part_name.c_str(), + aShapeTool->IsTopLevel(label), + aShapeTool->IsAssembly(label), + aShapeTool->IsShape(label), + aShapeTool->IsCompound(label), + aShapeTool->IsSimpleShape(label), + aShapeTool->IsFree(label), + aShapeTool->IsReference(label), + aShapeTool->IsComponent(label), + aShapeTool->IsSubShape(label) + ); +#endif + + std::string asm_name = assembly; + if (aShapeTool->IsAssembly(label)) { + asm_name = part_name; + } + + TDF_Label ref; + if (aShapeTool->IsReference(label) && aShapeTool->GetReferredShape(label, ref)) { + loadShapes(ref, part_loc, part_name, asm_name, true); + } + + if (isRef || myRefShapes.find(hash) == myRefShapes.end()) { + TopoDS_Shape aShape; + if (isRef && aShapeTool->GetShape(label, aShape)) + myRefShapes.insert(aShape.HashCode(HashUpper)); + + if (aShapeTool->IsSimpleShape(label) && (isRef || aShapeTool->IsFree(label))) { + if (!asm_name.empty()) + part_name = asm_name; + if (isRef) + createShape(label, loc, part_name); + else + createShape(label, part_loc, part_name); + } + else { + for (TDF_ChildIterator it(label); it.More(); it.Next()) { + loadShapes(it.Value(), part_loc, part_name, asm_name, isRef); + } + } + } +} + +void ImportOCAF::createShape(const TDF_Label& label, const TopLoc_Location& loc, const std::string& name) +{ + const TopoDS_Shape& aShape = aShapeTool->GetShape(label); + if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND) { + TopExp_Explorer xp; + int ctSolids = 0, ctShells = 0; + for (xp.Init(aShape, TopAbs_SOLID); xp.More(); xp.Next(), ctSolids++) + createShape(xp.Current(), loc, name); + for (xp.Init(aShape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next(), ctShells++) + createShape(xp.Current(), loc, name); + if (ctSolids > 0 || ctShells > 0) + return; + } + + createShape(aShape, loc, name); +} + +void ImportOCAF::createShape(const TopoDS_Shape& aShape, const TopLoc_Location& loc, const std::string& name) +{ + Part::Feature* part = static_cast(doc->addObject("Part::Feature")); + if (!loc.IsIdentity()) + part->Shape.setValue(aShape.Moved(loc)); + else + part->Shape.setValue(aShape); + part->Label.setValue(name); + + Quantity_Color aColor; + App::Color color(0.8f,0.8f,0.8f); + if (aColorTool->GetColor(aShape, XCAFDoc_ColorGen, aColor) || + aColorTool->GetColor(aShape, XCAFDoc_ColorSurf, aColor) || + aColorTool->GetColor(aShape, XCAFDoc_ColorCurv, aColor)) { + color.r = aColor.Red(); + color.g = aColor.Green(); + color.b = aColor.Blue(); + std::vector colors; + colors.push_back(color); + applyColors(part, colors); +#if 0//TODO + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); + if (vp && vp->isDerivedFrom(PartGui::ViewProviderPart::getClassTypeId())) { + color.r = aColor.Red(); + color.g = aColor.Green(); + color.b = aColor.Blue(); + static_cast(vp)->ShapeColor.setValue(color); + } +#endif + } + + TopTools_IndexedMapOfShape faces; + TopExp_Explorer xp(aShape,TopAbs_FACE); + while (xp.More()) { + faces.Add(xp.Current()); + xp.Next(); + } + bool found_face_color = false; + std::vector faceColors; + faceColors.resize(faces.Extent(), color); + xp.Init(aShape,TopAbs_FACE); + while (xp.More()) { + if (aColorTool->GetColor(xp.Current(), XCAFDoc_ColorGen, aColor) || + aColorTool->GetColor(xp.Current(), XCAFDoc_ColorSurf, aColor) || + aColorTool->GetColor(xp.Current(), XCAFDoc_ColorCurv, aColor)) { + int index = faces.FindIndex(xp.Current()); + color.r = aColor.Red(); + color.g = aColor.Green(); + color.b = aColor.Blue(); + faceColors[index-1] = color; + found_face_color = true; + } + xp.Next(); + } + + if (found_face_color) { + applyColors(part, faceColors); +#if 0//TODO + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); + if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { + static_cast(vp)->DiffuseColor.setValues(faceColors); + } +#endif + } +} + +// ---------------------------------------------------------------------------- + +ExportOCAF::ExportOCAF(Handle_TDocStd_Document h) + : pDoc(h) +{ + aShapeTool = XCAFDoc_DocumentTool::ShapeTool(pDoc->Main()); + aColorTool = XCAFDoc_DocumentTool::ColorTool(pDoc->Main()); + rootLabel = TDF_TagSource::NewChild(pDoc->Main()); +} + +void ExportOCAF::saveShape(Part::Feature* part, const std::vector& colors) +{ + const TopoDS_Shape& shape = part->Shape.getValue(); + + // Add shape and name + //TDF_Label shapeLabel = hShapeTool->AddShape(shape, Standard_False); + TDF_Label shapeLabel= TDF_TagSource::NewChild(rootLabel); +#if OCC_VERSION_HEX >= 0x060500 + TDataXtd_Shape::Set(shapeLabel, shape); +#else + TDataStd_Shape::Set(shapeLabel, shape); +#endif + TDataStd_Name::Set(shapeLabel, TCollection_ExtendedString(part->Label.getValue(), 1)); + + // Add color information + Quantity_Color col; + + std::set face_index; + TopTools_IndexedMapOfShape faces; + TopExp_Explorer xp(shape,TopAbs_FACE); + while (xp.More()) { + face_index.insert(faces.Add(xp.Current())); + xp.Next(); + } + + // define color per face? + if (colors.size() == face_index.size()) { + xp.Init(shape,TopAbs_FACE); + while (xp.More()) { + int index = faces.FindIndex(xp.Current()); + if (face_index.find(index) != face_index.end()) { + face_index.erase(index); + TDF_Label faceLabel= TDF_TagSource::NewChild(shapeLabel); +#if OCC_VERSION_HEX >= 0x060500 + TDataXtd_Shape::Set(faceLabel, xp.Current()); +#else + TDataStd_Shape::Set(faceLabel, xp.Current()); +#endif + const App::Color& color = colors[index-1]; + Quantity_Parameter mat[3]; + mat[0] = color.r; + mat[1] = color.g; + mat[2] = color.b; + col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB); + aColorTool->SetColor(faceLabel, col, XCAFDoc_ColorSurf); + } + xp.Next(); + } + } + else if (!colors.empty()) { + App::Color color = colors.front(); + Quantity_Parameter mat[3]; + mat[0] = color.r; + mat[1] = color.g; + mat[2] = color.b; + col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB); + aColorTool->SetColor(shapeLabel, col, XCAFDoc_ColorGen); + } +} + +// ---------------------------------------------------------------------------- + +ImportXCAF::ImportXCAF(Handle_TDocStd_Document h, App::Document* d, const std::string& name) + : hdoc(h), doc(d), default_name(name) +{ + aShapeTool = XCAFDoc_DocumentTool::ShapeTool (hdoc->Main()); + hColors = XCAFDoc_DocumentTool::ColorTool(hdoc->Main()); +} + +ImportXCAF::~ImportXCAF() +{ +} + +void ImportXCAF::loadShapes() +{ + // collect sequence of labels to display + TDF_LabelSequence shapeLabels, colorLabels; + aShapeTool->GetFreeShapes (shapeLabels); + hColors->GetColors(colorLabels); + + // set presentations and show + for (Standard_Integer i=1; i <= shapeLabels.Length(); i++ ) { + // get the shapes and attributes + const TDF_Label& label = shapeLabels.Value(i); + loadShapes(label); + } + std::map::iterator it; + // go through solids + for (it = mySolids.begin(); it != mySolids.end(); ++it) { + createShape(it->second, true, true); + } + // go through shells + for (it = myShells.begin(); it != myShells.end(); ++it) { + createShape(it->second, true, true); + } + // go through compounds + for (it = myCompds.begin(); it != myCompds.end(); ++it) { + createShape(it->second, true, true); + } + // do the rest + if (!myShapes.empty()) { + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + for (it = myShapes.begin(); it != myShapes.end(); ++it) { + builder.Add(comp, it->second); + } + createShape(comp, true, false); + } +} + +void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setname) const +{ + Part::Feature* part; + part = static_cast(doc->addObject("Part::Feature", default_name.c_str())); + part->Shape.setValue(shape); + std::map::const_iterator jt; + jt = myColorMap.find(shape.HashCode(INT_MAX)); + + App::Color partColor(0.8f,0.8f,0.8f); +#if 0//TODO + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); + if (vp && vp->isDerivedFrom(PartGui::ViewProviderPart::getClassTypeId())) { + if (jt != myColorMap.end()) { + App::Color color; + color.r = jt->second.Red(); + color.g = jt->second.Green(); + color.b = jt->second.Blue(); + static_cast(vp)->ShapeColor.setValue(color); + } + + partColor = static_cast(vp)->ShapeColor.getValue(); + } +#endif + + // set label name if defined + if (setname && !myNameMap.empty()) { + std::map::const_iterator jt; + jt = myNameMap.find(shape.HashCode(INT_MAX)); + if (jt != myNameMap.end()) { + part->Label.setValue(jt->second); + } + } + + // check for colors per face + if (perface && !myColorMap.empty()) { + TopTools_IndexedMapOfShape faces; + TopExp_Explorer xp(shape,TopAbs_FACE); + while (xp.More()) { + faces.Add(xp.Current()); + xp.Next(); + } + + bool found_face_color = false; + std::vector faceColors; + faceColors.resize(faces.Extent(), partColor); + xp.Init(shape,TopAbs_FACE); + while (xp.More()) { + jt = myColorMap.find(xp.Current().HashCode(INT_MAX)); + if (jt != myColorMap.end()) { + int index = faces.FindIndex(xp.Current()); + App::Color color; + color.r = jt->second.Red(); + color.g = jt->second.Green(); + color.b = jt->second.Blue(); + faceColors[index-1] = color; + found_face_color = true; + } + xp.Next(); + } + + if (found_face_color) { +#if 0//TODO + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); + if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { + static_cast(vp)->DiffuseColor.setValues(faceColors); + } +#endif + } + } +} + +void ImportXCAF::loadShapes(const TDF_Label& label) +{ + TopoDS_Shape aShape; + if (aShapeTool->GetShape(label,aShape)) { + //if (aShapeTool->IsReference(label)) { + // TDF_Label reflabel; + // if (aShapeTool->GetReferredShape(label, reflabel)) { + // loadShapes(reflabel); + // } + //} + if (aShapeTool->IsTopLevel(label)) { + int ctSolids = 0, ctShells = 0, ctComps = 0; + // add the shapes + TopExp_Explorer xp; + for (xp.Init(aShape, TopAbs_SOLID); xp.More(); xp.Next(), ctSolids++) + this->mySolids[xp.Current().HashCode(INT_MAX)] = (xp.Current()); + for (xp.Init(aShape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next(), ctShells++) + this->myShells[xp.Current().HashCode(INT_MAX)] = (xp.Current()); + // if no solids and no shells were found then go for compounds + if (ctSolids == 0 && ctShells == 0) { + for (xp.Init(aShape, TopAbs_COMPOUND); xp.More(); xp.Next(), ctComps++) + this->myCompds[xp.Current().HashCode(INT_MAX)] = (xp.Current()); + } + if (ctComps == 0) { + for (xp.Init(aShape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) + this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); + for (xp.Init(aShape, TopAbs_WIRE, TopAbs_FACE); xp.More(); xp.Next()) + this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); + for (xp.Init(aShape, TopAbs_EDGE, TopAbs_WIRE); xp.More(); xp.Next()) + this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); + for (xp.Init(aShape, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) + this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); + } + } + + // getting color + Quantity_Color col; + if (hColors->GetColor(label, XCAFDoc_ColorGen, col) || + hColors->GetColor(label, XCAFDoc_ColorSurf, col) || + hColors->GetColor(label, XCAFDoc_ColorCurv, col)) { + // add defined color + myColorMap[aShape.HashCode(INT_MAX)] = col; + } + else { + // http://www.opencascade.org/org/forum/thread_17107/ + TopoDS_Iterator it; + for (it.Initialize(aShape);it.More(); it.Next()) { + if (hColors->GetColor(it.Value(), XCAFDoc_ColorGen, col) || + hColors->GetColor(it.Value(), XCAFDoc_ColorSurf, col) || + hColors->GetColor(it.Value(), XCAFDoc_ColorCurv, col)) { + // add defined color + myColorMap[it.Value().HashCode(INT_MAX)] = col; + } + } + } + + // getting names + Handle(TDataStd_Name) name; + if (label.FindAttribute(TDataStd_Name::GetID(),name)) { + TCollection_ExtendedString extstr = name->Get(); + char* str = new char[extstr.LengthOfCString()+1]; + extstr.ToUTF8CString(str); + std::string label(str); + if (!label.empty()) + myNameMap[aShape.HashCode(INT_MAX)] = label; + delete [] str; + } + +#if 0 + // http://www.opencascade.org/org/forum/thread_15174/ + if (aShapeTool->IsAssembly(label)) { + TDF_LabelSequence shapeLabels; + aShapeTool->GetComponents(label, shapeLabels); + Standard_Integer nbShapes = shapeLabels.Length(); + for (Standard_Integer i = 1; i <= nbShapes; i++) { + loadShapes(shapeLabels.Value(i)); + } + } +#endif + + if (label.HasChild()) { + TDF_ChildIterator it; + for (it.Initialize(label); it.More(); it.Next()) { + loadShapes(it.Value()); + } + } + } +} diff --git a/src/Mod/Import/App/ImportOCAF.h b/src/Mod/Import/App/ImportOCAF.h new file mode 100644 index 000000000..50b91bdf8 --- /dev/null +++ b/src/Mod/Import/App/ImportOCAF.h @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright (c) 2013 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 IMPORT_IMPORTOCAF_H +#define IMPORT_IMPORTOCAF_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class TDF_Label; +class TopLoc_Location; + +namespace App { +class Document; +class DocumentObject; +} +namespace Part { +class Feature; +} + +namespace Import { + +class ImportExport ImportOCAF +{ +public: + ImportOCAF(Handle_TDocStd_Document h, App::Document* d, const std::string& name); + virtual ~ImportOCAF(); + void loadShapes(); + +private: + void loadShapes(const TDF_Label& label, const TopLoc_Location&, const std::string& partname, const std::string& assembly, bool isRef); + void createShape(const TDF_Label& label, const TopLoc_Location&, const std::string&); + void createShape(const TopoDS_Shape& label, const TopLoc_Location&, const std::string&); + virtual void applyColors(Part::Feature*, const std::vector&){} + +private: + Handle_TDocStd_Document pDoc; + App::Document* doc; + Handle_XCAFDoc_ShapeTool aShapeTool; + Handle_XCAFDoc_ColorTool aColorTool; + std::string default_name; + std::set myRefShapes; + static const int HashUpper = INT_MAX; +}; + +class ImportExport ExportOCAF +{ +public: + ExportOCAF(Handle_TDocStd_Document h); + void saveShape(Part::Feature* part, const std::vector&); + +private: + Handle_TDocStd_Document pDoc; + Handle_XCAFDoc_ShapeTool aShapeTool; + Handle_XCAFDoc_ColorTool aColorTool; + TDF_Label rootLabel; +}; + + +class ImportXCAF +{ +public: + ImportXCAF(Handle_TDocStd_Document h, App::Document* d, const std::string& name); + virtual ~ImportXCAF(); + void loadShapes(); + +private: + void createShape(const TopoDS_Shape& shape, bool perface=false, bool setname=false) const; + void loadShapes(const TDF_Label& label); + virtual void applyColors(Part::Feature*, const std::vector&){} + +private: + Handle_TDocStd_Document hdoc; + App::Document* doc; + Handle_XCAFDoc_ShapeTool aShapeTool; + Handle_XCAFDoc_ColorTool hColors; + std::string default_name; + std::map mySolids; + std::map myShells; + std::map myCompds; + std::map myShapes; + std::map myColorMap; + std::map myNameMap; +}; + +} + +#endif //IMPORT_IMPORTOCAF_H diff --git a/src/Mod/Import/App/PreCompiled.h b/src/Mod/Import/App/PreCompiled.h index b1b36952f..894037712 100644 --- a/src/Mod/Import/App/PreCompiled.h +++ b/src/Mod/Import/App/PreCompiled.h @@ -25,25 +25,32 @@ #define __PRECOMPILED__ #include -#ifdef _PreComp_ - -/// here get the warnings of to long specifieres disabled (needet for VC6) -#ifdef _MSC_VER -# pragma warning( disable : 4251 ) -# pragma warning( disable : 4503 ) -# pragma warning( disable : 4786 ) // specifier longer then 255 chars -#endif - // Importing of App classes - #ifdef FC_OS_WIN32 +# define ImportExport __declspec(dllexport) +# define PartExport __declspec(dllimport) # define AppPartExport __declspec(dllimport) #else // for Linux +# define ImportExport +# define PartExport # define AppPartExport #endif +/// here get the warnings of to long specifieres disabled (needet for VC6) +#ifdef _MSC_VER +# pragma warning( disable : 4251 ) +# pragma warning( disable : 4503 ) +# pragma warning( disable : 4786 ) // specifier longer then 255 chars +#endif + + +#ifdef _PreComp_ + +// Python +#include + // standard #include #include @@ -60,188 +67,8 @@ // OpenCasCade ===================================================================================== // Base -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -// OCAF -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// OCAF -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// IO -#include -#include -#include -#include -#include - +#include "OpenCascadeAll.h" #endif //_PreComp_ - #endif diff --git a/src/Mod/Import/CMakeLists.txt b/src/Mod/Import/CMakeLists.txt index ec05f46d1..c5d848810 100644 --- a/src/Mod/Import/CMakeLists.txt +++ b/src/Mod/Import/CMakeLists.txt @@ -1,5 +1,5 @@ -#add_subdirectory(App) +add_subdirectory(App) if(FREECAD_BUILD_GUI) add_subdirectory(Gui) endif(FREECAD_BUILD_GUI) diff --git a/src/Mod/Import/Gui/AppImportGuiPy.cpp b/src/Mod/Import/Gui/AppImportGuiPy.cpp index d5cef5a02..65e8af25f 100644 --- a/src/Mod/Import/Gui/AppImportGuiPy.cpp +++ b/src/Mod/Import/Gui/AppImportGuiPy.cpp @@ -77,411 +77,26 @@ #include #include #include +#include -class ImportOCAF +class ImportOCAFExt : public Import::ImportOCAF { public: - ImportOCAF(Handle_TDocStd_Document h, App::Document* d, const std::string& name) - : pDoc(h), doc(d), default_name(name) + ImportOCAFExt(Handle_TDocStd_Document h, App::Document* d, const std::string& name) + : ImportOCAF(h, d, name) { - aShapeTool = XCAFDoc_DocumentTool::ShapeTool (pDoc->Main()); - aColorTool = XCAFDoc_DocumentTool::ColorTool(pDoc->Main()); } - void loadShapes(); - private: - void loadShapes(const TDF_Label& label, const TopLoc_Location&, const std::string& partname, bool isRef); - void createShape(const TDF_Label& label, const TopLoc_Location&, const std::string&); - void createShape(const TopoDS_Shape& label, const TopLoc_Location&, const std::string&); - -private: - Handle_TDocStd_Document pDoc; - App::Document* doc; - Handle_XCAFDoc_ShapeTool aShapeTool; - Handle_XCAFDoc_ColorTool aColorTool; - std::string default_name; - std::set myRefShapes; - static const int HashUpper = INT_MAX; -}; - -void ImportOCAF::loadShapes() -{ - myRefShapes.clear(); - loadShapes(pDoc->Main(), TopLoc_Location(), default_name, false); -} - -void ImportOCAF::loadShapes(const TDF_Label& label, const TopLoc_Location& loc, const std::string& defaultname, bool isRef) -{ - int hash = 0; - TopoDS_Shape aShape; - if (aShapeTool->GetShape(label,aShape)) { - hash = aShape.HashCode(HashUpper); - } - - Handle(TDataStd_Name) name; - std::string part_name = defaultname; - if (label.FindAttribute(TDataStd_Name::GetID(),name)) { - TCollection_ExtendedString extstr = name->Get(); - char* str = new char[extstr.LengthOfCString()+1]; - extstr.ToUTF8CString(str); - part_name = str; - delete [] str; - if (part_name.empty()) { - part_name = defaultname; - } - else { - bool ws=true; - for (std::string::iterator it = part_name.begin(); it != part_name.end(); ++it) { - if (*it != ' ') { - ws = false; - break; - } - } - if (ws) - part_name = defaultname; - } - } - - TopLoc_Location part_loc = loc; - Handle(XCAFDoc_Location) hLoc; - if (label.FindAttribute(XCAFDoc_Location::GetID(), hLoc)) { - if (isRef) - part_loc = part_loc * hLoc->Get(); - else - part_loc = hLoc->Get(); - } - -#ifdef FC_DEBUG - Base::Console().Message("H:%d, N:%s, T:%d, A:%d, S:%d, C:%d, SS:%d, F:%d, R:%d, C:%d, SS:%d\n", - hash, - part_name.c_str(), - aShapeTool->IsTopLevel(label), - aShapeTool->IsAssembly(label), - aShapeTool->IsShape(label), - aShapeTool->IsCompound(label), - aShapeTool->IsSimpleShape(label), - aShapeTool->IsFree(label), - aShapeTool->IsReference(label), - aShapeTool->IsComponent(label), - aShapeTool->IsSubShape(label) - ); -#endif - - TDF_Label ref; - if (aShapeTool->IsReference(label) && aShapeTool->GetReferredShape(label, ref)) { - loadShapes(ref, part_loc, part_name, true); - } - - if (isRef || myRefShapes.find(hash) == myRefShapes.end()) { - TopoDS_Shape aShape; - if (isRef && aShapeTool->GetShape(label, aShape)) - myRefShapes.insert(aShape.HashCode(HashUpper)); - - if (aShapeTool->IsSimpleShape(label) && (isRef || aShapeTool->IsFree(label))) { - if (isRef) - createShape(label, loc, part_name); - else - createShape(label, part_loc, part_name); - } - else { - for (TDF_ChildIterator it(label); it.More(); it.Next()) { - loadShapes(it.Value(), part_loc, part_name, isRef); - } - } - } -} - -void ImportOCAF::createShape(const TDF_Label& label, const TopLoc_Location& loc, const std::string& name) -{ - const TopoDS_Shape& aShape = aShapeTool->GetShape(label); - if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND) { - TopExp_Explorer xp; - int ctSolids = 0, ctShells = 0; - for (xp.Init(aShape, TopAbs_SOLID); xp.More(); xp.Next(), ctSolids++) - createShape(xp.Current(), loc, name); - for (xp.Init(aShape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next(), ctShells++) - createShape(xp.Current(), loc, name); - if (ctSolids > 0 || ctShells > 0) - return; - } - - createShape(aShape, loc, name); -} - -void ImportOCAF::createShape(const TopoDS_Shape& aShape, const TopLoc_Location& loc, const std::string& name) -{ - Part::Feature* part = static_cast(doc->addObject("Part::Feature")); - if (!loc.IsIdentity()) - part->Shape.setValue(aShape.Moved(loc)); - else - part->Shape.setValue(aShape); - part->Label.setValue(name); - - Quantity_Color aColor; - App::Color color(0.8f,0.8f,0.8f); - if (aColorTool->GetColor(aShape, XCAFDoc_ColorGen, aColor) || - aColorTool->GetColor(aShape, XCAFDoc_ColorSurf, aColor) || - aColorTool->GetColor(aShape, XCAFDoc_ColorCurv, aColor)) { - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); - if (vp && vp->isDerivedFrom(PartGui::ViewProviderPart::getClassTypeId())) { - color.r = aColor.Red(); - color.g = aColor.Green(); - color.b = aColor.Blue(); - static_cast(vp)->ShapeColor.setValue(color); - } - } - - TopTools_IndexedMapOfShape faces; - TopExp_Explorer xp(aShape,TopAbs_FACE); - while (xp.More()) { - faces.Add(xp.Current()); - xp.Next(); - } - bool found_face_color = false; - std::vector faceColors; - faceColors.resize(faces.Extent(), color); - xp.Init(aShape,TopAbs_FACE); - while (xp.More()) { - if (aColorTool->GetColor(xp.Current(), XCAFDoc_ColorGen, aColor) || - aColorTool->GetColor(xp.Current(), XCAFDoc_ColorSurf, aColor) || - aColorTool->GetColor(xp.Current(), XCAFDoc_ColorCurv, aColor)) { - int index = faces.FindIndex(xp.Current()); - color.r = aColor.Red(); - color.g = aColor.Green(); - color.b = aColor.Blue(); - faceColors[index-1] = color; - found_face_color = true; - } - xp.Next(); - } - - if (found_face_color) { + void applyColors(Part::Feature* part, const std::vector& colors) + { Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - static_cast(vp)->DiffuseColor.setValues(faceColors); + static_cast(vp)->DiffuseColor.setValues(colors); } } -} - -class ImportXCAF -{ -public: - ImportXCAF(Handle_TDocStd_Document h, App::Document* d, const std::string& name) - : hdoc(h), doc(d), default_name(name) - { - aShapeTool = XCAFDoc_DocumentTool::ShapeTool (hdoc->Main()); - hColors = XCAFDoc_DocumentTool::ColorTool(hdoc->Main()); - } - - void loadShapes() - { - // collect sequence of labels to display - TDF_LabelSequence shapeLabels, colorLabels; - aShapeTool->GetFreeShapes (shapeLabels); - hColors->GetColors(colorLabels); - - // set presentations and show - for (Standard_Integer i=1; i <= shapeLabels.Length(); i++ ) { - // get the shapes and attributes - const TDF_Label& label = shapeLabels.Value(i); - loadShapes(label); - } - std::map::iterator it; - // go through solids - for (it = mySolids.begin(); it != mySolids.end(); ++it) { - createShape(it->second, true, true); - } - // go through shells - for (it = myShells.begin(); it != myShells.end(); ++it) { - createShape(it->second, true, true); - } - // go through compounds - for (it = myCompds.begin(); it != myCompds.end(); ++it) { - createShape(it->second, true, true); - } - // do the rest - if (!myShapes.empty()) { - BRep_Builder builder; - TopoDS_Compound comp; - builder.MakeCompound(comp); - for (it = myShapes.begin(); it != myShapes.end(); ++it) { - builder.Add(comp, it->second); - } - createShape(comp, true, false); - } - } - -private: - void createShape(const TopoDS_Shape& shape, bool perface=false, bool setname=false) const - { - Part::Feature* part; - part = static_cast(doc->addObject("Part::Feature", default_name.c_str())); - part->Shape.setValue(shape); - std::map::const_iterator jt; - jt = myColorMap.find(shape.HashCode(INT_MAX)); - - App::Color partColor(0.8f,0.8f,0.8f); - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); - if (vp && vp->isDerivedFrom(PartGui::ViewProviderPart::getClassTypeId())) { - if (jt != myColorMap.end()) { - App::Color color; - color.r = jt->second.Red(); - color.g = jt->second.Green(); - color.b = jt->second.Blue(); - static_cast(vp)->ShapeColor.setValue(color); - } - - partColor = static_cast(vp)->ShapeColor.getValue(); - } - - // set label name if defined - if (setname && !myNameMap.empty()) { - std::map::const_iterator jt; - jt = myNameMap.find(shape.HashCode(INT_MAX)); - if (jt != myNameMap.end()) { - part->Label.setValue(jt->second); - } - } - - // check for colors per face - if (perface && !myColorMap.empty()) { - TopTools_IndexedMapOfShape faces; - TopExp_Explorer xp(shape,TopAbs_FACE); - while (xp.More()) { - faces.Add(xp.Current()); - xp.Next(); - } - - bool found_face_color = false; - std::vector faceColors; - faceColors.resize(faces.Extent(), partColor); - xp.Init(shape,TopAbs_FACE); - while (xp.More()) { - jt = myColorMap.find(xp.Current().HashCode(INT_MAX)); - if (jt != myColorMap.end()) { - int index = faces.FindIndex(xp.Current()); - App::Color color; - color.r = jt->second.Red(); - color.g = jt->second.Green(); - color.b = jt->second.Blue(); - faceColors[index-1] = color; - found_face_color = true; - } - xp.Next(); - } - - if (found_face_color) { - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); - if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - static_cast(vp)->DiffuseColor.setValues(faceColors); - } - } - } - } - void loadShapes(const TDF_Label& label) - { - TopoDS_Shape aShape; - if (aShapeTool->GetShape(label,aShape)) { - //if (aShapeTool->IsReference(label)) { - // TDF_Label reflabel; - // if (aShapeTool->GetReferredShape(label, reflabel)) { - // loadShapes(reflabel); - // } - //} - if (aShapeTool->IsTopLevel(label)) { - int ctSolids = 0, ctShells = 0, ctComps = 0; - // add the shapes - TopExp_Explorer xp; - for (xp.Init(aShape, TopAbs_SOLID); xp.More(); xp.Next(), ctSolids++) - this->mySolids[xp.Current().HashCode(INT_MAX)] = (xp.Current()); - for (xp.Init(aShape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next(), ctShells++) - this->myShells[xp.Current().HashCode(INT_MAX)] = (xp.Current()); - // if no solids and no shells were found then go for compounds - if (ctSolids == 0 && ctShells == 0) { - for (xp.Init(aShape, TopAbs_COMPOUND); xp.More(); xp.Next(), ctComps++) - this->myCompds[xp.Current().HashCode(INT_MAX)] = (xp.Current()); - } - if (ctComps == 0) { - for (xp.Init(aShape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) - this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); - for (xp.Init(aShape, TopAbs_WIRE, TopAbs_FACE); xp.More(); xp.Next()) - this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); - for (xp.Init(aShape, TopAbs_EDGE, TopAbs_WIRE); xp.More(); xp.Next()) - this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); - for (xp.Init(aShape, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) - this->myShapes[xp.Current().HashCode(INT_MAX)] = (xp.Current()); - } - } - - // getting color - Quantity_Color col; - if (hColors->GetColor(label, XCAFDoc_ColorGen, col) || - hColors->GetColor(label, XCAFDoc_ColorSurf, col) || - hColors->GetColor(label, XCAFDoc_ColorCurv, col)) { - // add defined color - myColorMap[aShape.HashCode(INT_MAX)] = col; - } - else { - // http://www.opencascade.org/org/forum/thread_17107/ - TopoDS_Iterator it; - for (it.Initialize(aShape);it.More(); it.Next()) { - if (hColors->GetColor(it.Value(), XCAFDoc_ColorGen, col) || - hColors->GetColor(it.Value(), XCAFDoc_ColorSurf, col) || - hColors->GetColor(it.Value(), XCAFDoc_ColorCurv, col)) { - // add defined color - myColorMap[it.Value().HashCode(INT_MAX)] = col; - } - } - } - - // getting names - Handle(TDataStd_Name) name; - if (label.FindAttribute(TDataStd_Name::GetID(),name)) { - TCollection_ExtendedString extstr = name->Get(); - char* str = new char[extstr.LengthOfCString()+1]; - extstr.ToUTF8CString(str); - std::string label(str); - if (!label.empty()) - myNameMap[aShape.HashCode(INT_MAX)] = label; - delete [] str; - } - -#if 0 - // http://www.opencascade.org/org/forum/thread_15174/ - if (aShapeTool->IsAssembly(label)) { - TDF_LabelSequence shapeLabels; - aShapeTool->GetComponents(label, shapeLabels); - Standard_Integer nbShapes = shapeLabels.Length(); - for (Standard_Integer i = 1; i <= nbShapes; i++) { - loadShapes(shapeLabels.Value(i)); - } - } -#endif - - if (label.HasChild()) { - TDF_ChildIterator it; - for (it.Initialize(label); it.More(); it.Next()) { - loadShapes(it.Value()); - } - } - } - } - -private: - Handle_TDocStd_Document hdoc; - App::Document* doc; - Handle_XCAFDoc_ShapeTool aShapeTool; - Handle_XCAFDoc_ColorTool hColors; - std::string default_name; - std::map mySolids; - std::map myShells; - std::map myCompds; - std::map myShapes; - std::map myColorMap; - std::map myNameMap; }; /* module functions */ @@ -570,15 +185,9 @@ static PyObject * importer(PyObject *self, PyObject *args) return 0; } -#if 1 - ImportOCAF ocaf(hDoc, pcDoc, file.fileNamePure()); + ImportOCAFExt ocaf(hDoc, pcDoc, file.fileNamePure()); ocaf.loadShapes(); -#else - ImportXCAF xcaf(hDoc, pcDoc, file.fileNamePure()); - xcaf.loadShapes(); -#endif pcDoc->recompute(); - } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); @@ -606,10 +215,7 @@ static PyObject * exporter(PyObject *self, PyObject *args) Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication(); Handle(TDocStd_Document) hDoc; hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc); - Handle_XCAFDoc_ShapeTool hShapeTool = XCAFDoc_DocumentTool::ShapeTool(hDoc->Main()); - Handle_XCAFDoc_ColorTool hColors = XCAFDoc_DocumentTool::ColorTool(hDoc->Main()); - - TDF_Label rootLabel= TDF_TagSource::NewChild(hDoc->Main()); + Import::ExportOCAF ocaf(hDoc); Py::List list(object); for (Py::List::iterator it = list.begin(); it != list.end(); ++it) { @@ -618,68 +224,14 @@ static PyObject * exporter(PyObject *self, PyObject *args) App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { Part::Feature* part = static_cast(obj); - const TopoDS_Shape& shape = part->Shape.getValue(); - - // Add shape and name - //TDF_Label shapeLabel = hShapeTool->AddShape(shape, Standard_False); - TDF_Label shapeLabel= TDF_TagSource::NewChild(rootLabel); -#if OCC_VERSION_HEX >= 0x060500 - TDataXtd_Shape::Set(shapeLabel, shape); -#else - TDataStd_Shape::Set(shapeLabel, shape); -#endif - TDataStd_Name::Set(shapeLabel, TCollection_ExtendedString(part->Label.getValue(), 1)); - - // Add color information - Quantity_Color col; + std::vector colors; Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); - bool per_face = false; if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - const std::vector& c = static_cast - (vp)->DiffuseColor.getValues(); - // define color per face - if (c.size() > 1) { - per_face = true; - std::set face_index; - TopTools_IndexedMapOfShape faces; - TopExp_Explorer xp(shape,TopAbs_FACE); - while (xp.More()) { - face_index.insert(faces.Add(xp.Current())); - xp.Next(); - } - - xp.Init(shape,TopAbs_FACE); - while (xp.More()) { - int index = faces.FindIndex(xp.Current()); - if (face_index.find(index) != face_index.end()) { - face_index.erase(index); - TDF_Label faceLabel= TDF_TagSource::NewChild(shapeLabel); -#if OCC_VERSION_HEX >= 0x060500 - TDataXtd_Shape::Set(faceLabel, xp.Current()); -#else - TDataStd_Shape::Set(faceLabel, xp.Current()); -#endif - const App::Color& color = c[index-1]; - Quantity_Parameter mat[3]; - mat[0] = color.r; - mat[1] = color.g; - mat[2] = color.b; - col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB); - hColors->SetColor(faceLabel, col, XCAFDoc_ColorSurf); - } - xp.Next(); - } - } - } - if (!per_face && vp && vp->isDerivedFrom(PartGui::ViewProviderPart::getClassTypeId())) { - App::Color color = static_cast(vp)->ShapeColor.getValue(); - Quantity_Parameter mat[3]; - mat[0] = color.r; - mat[1] = color.g; - mat[2] = color.b; - col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB); - hColors->SetColor(shapeLabel, col, XCAFDoc_ColorGen); + colors = static_cast(vp)->DiffuseColor.getValues(); + if (colors.empty()) + colors.push_back(static_cast(vp)->ShapeColor.getValue()); } + ocaf.saveShape(part, colors); } else { Base::Console().Message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue()); diff --git a/src/Mod/Import/Gui/CMakeLists.txt b/src/Mod/Import/Gui/CMakeLists.txt index 39193982c..412682401 100644 --- a/src/Mod/Import/Gui/CMakeLists.txt +++ b/src/Mod/Import/Gui/CMakeLists.txt @@ -22,6 +22,7 @@ link_directories(${OCC_LIBRARY_DIR}) set(ImportGui_LIBS FreeCADGui PartGui + Import ${OCC_OCAF_LIBRARIES} ${OCC_OCAF_DEBUG_LIBRARIES} ) diff --git a/src/Mod/Import/Gui/PreCompiled.h b/src/Mod/Import/Gui/PreCompiled.h index a1aa90f32..98ea64a5b 100644 --- a/src/Mod/Import/Gui/PreCompiled.h +++ b/src/Mod/Import/Gui/PreCompiled.h @@ -28,11 +28,13 @@ // Importing of App classes #ifdef FC_OS_WIN32 -# define ImportGuiExport __declspec(dllexport) +# define ImportGuiExport __declspec(dllexport) +# define ImportExport __declspec(dllimport) # define PartExport __declspec(dllimport) # define PartGuiExport __declspec(dllimport) #else // for Linux # define ImportGuiExport +# define ImportExport # define PartExport # define PartGuiExport #endif diff --git a/src/Mod/Mesh/App/Core/Elements.h b/src/Mod/Mesh/App/Core/Elements.h index fbea5359e..64f53c479 100644 --- a/src/Mod/Mesh/App/Core/Elements.h +++ b/src/Mod/Mesh/App/Core/Elements.h @@ -70,6 +70,14 @@ public: /** MeshEdge just a pair of two point indices */ typedef std::pair MeshEdge; +struct MeshExport EdgeCollapse +{ + unsigned long _fromPoint; + unsigned long _toPoint; + std::vector _removeFacets; + std::vector _changeFacets; +}; + /** * The MeshPoint class represents a point in the mesh data structure. The class inherits from * Vector3f and provides some additional information such as flag state and property value. @@ -250,6 +258,10 @@ public: * Decrement the index for each corner point that is higher than \a ulIndex. */ inline void Decrement (unsigned long ulIndex); + /** + * Checks if the facets references the given point index. + */ + inline bool HasPoint(unsigned long) const; /** * Replaces the index of the neighbour facet that is equal to \a ulOrig * by \a ulNew. If the facet does not have a neighbourt with this index @@ -826,6 +838,17 @@ inline void MeshFacet::Decrement (unsigned long ulIndex) if (_aulPoints[2] > ulIndex) _aulPoints[2]--; } +inline bool MeshFacet::HasPoint(unsigned long ulIndex) const +{ + if (_aulPoints[0] == ulIndex) + return true; + if (_aulPoints[1] == ulIndex) + return true; + if (_aulPoints[2] == ulIndex) + return true; + return false; +} + inline void MeshFacet::ReplaceNeighbour (unsigned long ulOrig, unsigned long ulNew) { if (_aulNeighbours[0] == ulOrig) diff --git a/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp b/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp index 11ff5c764..c0aa18656 100644 --- a/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp +++ b/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp @@ -25,8 +25,8 @@ #ifndef _PreComp_ # include -# include -# include +# include +# include #endif #include @@ -235,102 +235,102 @@ void MeshTopoAlgorithm::OptimizeTopology(float fMaxAngle) } } } - -// Cosine of the maximum angle in triangle (v1,v2,v3) -static float cos_maxangle(const Base::Vector3f &v1, - const Base::Vector3f &v2, - const Base::Vector3f &v3) -{ - float a = Base::Distance(v2,v3); - float b = Base::Distance(v3,v1); - float c = Base::Distance(v1,v2); - float A = a * (b*b + c*c - a*a); - float B = b * (c*c + a*a - b*b); - float C = c * (a*a + b*b - c*c); - return 0.5f * std::min(std::min(A,B),C) / (a*b*c); // min cosine == max angle -} - -static float swap_benefit(const Base::Vector3f &v1, const Base::Vector3f &v2, - const Base::Vector3f &v3, const Base::Vector3f &v4) -{ - Base::Vector3f n124 = (v4 - v2) % (v1 - v2); - Base::Vector3f n234 = (v3 - v2) % (v4 - v2); - if ((n124 * n234) <= 0.0f) - return 0.0f; // avoid normal flip - - return std::max(-cos_maxangle(v1,v2,v3), -cos_maxangle(v1,v3,v4)) - - std::max(-cos_maxangle(v1,v2,v4), -cos_maxangle(v2,v3,v4)); -} - -float MeshTopoAlgorithm::SwapEdgeBenefit(unsigned long f, int e) const -{ - const MeshFacetArray& faces = _rclMesh.GetFacets(); - const MeshPointArray& vertices = _rclMesh.GetPoints(); - - unsigned long n = faces[f]._aulNeighbours[e]; - if (n == ULONG_MAX) - return 0.0f; // border edge - - unsigned long v1 = faces[f]._aulPoints[e]; - unsigned long v2 = faces[f]._aulPoints[(e+1)%3]; - unsigned long v3 = faces[f]._aulPoints[(e+2)%3]; - unsigned short s = faces[n].Side(faces[f]); - if (s == USHRT_MAX) { - std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: error in neighbourhood " - << "of faces " << f << " and " << n << std::endl; - return 0.0f; // topological error - } - unsigned long v4 = faces[n]._aulPoints[(s+2)%3]; - if (v3 == v4) { - std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: duplicate faces " - << f << " and " << n << std::endl; - return 0.0f; // duplicate faces - } - return swap_benefit(vertices[v2], vertices[v3], - vertices[v1], vertices[v4]); -} -typedef std::pair FaceEdge; // (face, edge) pair -typedef std::pair FaceEdgePriority; +// Cosine of the maximum angle in triangle (v1,v2,v3) +static float cos_maxangle(const Base::Vector3f &v1, + const Base::Vector3f &v2, + const Base::Vector3f &v3) +{ + float a = Base::Distance(v2,v3); + float b = Base::Distance(v3,v1); + float c = Base::Distance(v1,v2); + float A = a * (b*b + c*c - a*a); + float B = b * (c*c + a*a - b*b); + float C = c * (a*a + b*b - c*c); + return 0.5f * std::min(std::min(A,B),C) / (a*b*c); // min cosine == max angle +} + +static float swap_benefit(const Base::Vector3f &v1, const Base::Vector3f &v2, + const Base::Vector3f &v3, const Base::Vector3f &v4) +{ + Base::Vector3f n124 = (v4 - v2) % (v1 - v2); + Base::Vector3f n234 = (v3 - v2) % (v4 - v2); + if ((n124 * n234) <= 0.0f) + return 0.0f; // avoid normal flip + + return std::max(-cos_maxangle(v1,v2,v3), -cos_maxangle(v1,v3,v4)) - + std::max(-cos_maxangle(v1,v2,v4), -cos_maxangle(v2,v3,v4)); +} + +float MeshTopoAlgorithm::SwapEdgeBenefit(unsigned long f, int e) const +{ + const MeshFacetArray& faces = _rclMesh.GetFacets(); + const MeshPointArray& vertices = _rclMesh.GetPoints(); + + unsigned long n = faces[f]._aulNeighbours[e]; + if (n == ULONG_MAX) + return 0.0f; // border edge + + unsigned long v1 = faces[f]._aulPoints[e]; + unsigned long v2 = faces[f]._aulPoints[(e+1)%3]; + unsigned long v3 = faces[f]._aulPoints[(e+2)%3]; + unsigned short s = faces[n].Side(faces[f]); + if (s == USHRT_MAX) { + std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: error in neighbourhood " + << "of faces " << f << " and " << n << std::endl; + return 0.0f; // topological error + } + unsigned long v4 = faces[n]._aulPoints[(s+2)%3]; + if (v3 == v4) { + std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: duplicate faces " + << f << " and " << n << std::endl; + return 0.0f; // duplicate faces + } + return swap_benefit(vertices[v2], vertices[v3], + vertices[v1], vertices[v4]); +} + +typedef std::pair FaceEdge; // (face, edge) pair +typedef std::pair FaceEdgePriority; void MeshTopoAlgorithm::OptimizeTopology() { - // Find all edges that can be swapped and insert them into a - // priority queue - const MeshFacetArray& faces = _rclMesh.GetFacets(); - unsigned long nf = _rclMesh.CountFacets(); - std::priority_queue todo; - for (unsigned long i = 0; i < nf; i++) { - for (int j = 0; j < 3; j++) { - float b = SwapEdgeBenefit(i, j); - if (b > 0.0f) - todo.push(std::make_pair(b, std::make_pair(i, j))); - } - } - - // Edges are sorted in decreasing order with respect to their benefit - while (!todo.empty()) { - unsigned long f = todo.top().second.first; - int e = todo.top().second.second; - todo.pop(); - // Check again if the swap should still be done - if (SwapEdgeBenefit(f, e) <= 0.0f) - continue; - // OK, swap the edge - unsigned long f2 = faces[f]._aulNeighbours[e]; - SwapEdge(f, f2); - // Insert new edges into queue, if necessary - for (int j = 0; j < 3; j++) { - float b = SwapEdgeBenefit(f, j); - if (b > 0.0f) - todo.push(std::make_pair(b, std::make_pair(f, j))); - } - for (int j = 0; j < 3; j++) { - float b = SwapEdgeBenefit(f2, j); - if (b > 0.0f) - todo.push(std::make_pair(b, std::make_pair(f2, j))); - } - } + // Find all edges that can be swapped and insert them into a + // priority queue + const MeshFacetArray& faces = _rclMesh.GetFacets(); + unsigned long nf = _rclMesh.CountFacets(); + std::priority_queue todo; + for (unsigned long i = 0; i < nf; i++) { + for (int j = 0; j < 3; j++) { + float b = SwapEdgeBenefit(i, j); + if (b > 0.0f) + todo.push(std::make_pair(b, std::make_pair(i, j))); + } + } + + // Edges are sorted in decreasing order with respect to their benefit + while (!todo.empty()) { + unsigned long f = todo.top().second.first; + int e = todo.top().second.second; + todo.pop(); + // Check again if the swap should still be done + if (SwapEdgeBenefit(f, e) <= 0.0f) + continue; + // OK, swap the edge + unsigned long f2 = faces[f]._aulNeighbours[e]; + SwapEdge(f, f2); + // Insert new edges into queue, if necessary + for (int j = 0; j < 3; j++) { + float b = SwapEdgeBenefit(f, j); + if (b > 0.0f) + todo.push(std::make_pair(b, std::make_pair(f, j))); + } + for (int j = 0; j < 3; j++) { + float b = SwapEdgeBenefit(f2, j); + if (b > 0.0f) + todo.push(std::make_pair(b, std::make_pair(f2, j))); + } + } } void MeshTopoAlgorithm::DelaunayFlip(float fMaxAngle) @@ -891,6 +891,27 @@ bool MeshTopoAlgorithm::CollapseEdge(unsigned long ulFacetPos, unsigned long ulN return true; } +bool MeshTopoAlgorithm::CollapseEdge(const EdgeCollapse& ec) +{ + std::vector::const_iterator it; + for (it = ec._removeFacets.begin(); it != ec._removeFacets.end(); ++it) { + MeshFacet& f = _rclMesh._aclFacetArray[*it]; + f.SetInvalid(); + } + + for (it = ec._changeFacets.begin(); it != ec._changeFacets.end(); ++it) { + MeshFacet& f = _rclMesh._aclFacetArray[*it]; + + // The neighbourhood might be broken from now on!!! + f.Transpose(ec._fromPoint, ec._toPoint); + } + + _rclMesh._aclPointArray[ec._fromPoint].SetInvalid(); + + _needsCleanup = true; + return true; +} + bool MeshTopoAlgorithm::CollapseFacet(unsigned long ulFacetPos) { MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos]; diff --git a/src/Mod/Mesh/App/Core/TopoAlgorithm.h b/src/Mod/Mesh/App/Core/TopoAlgorithm.h index b0262d5f7..598804de9 100644 --- a/src/Mod/Mesh/App/Core/TopoAlgorithm.h +++ b/src/Mod/Mesh/App/Core/TopoAlgorithm.h @@ -40,6 +40,8 @@ namespace MeshCore { class AbstractPolygonTriangulator; +struct EdgeCollapse; + /** * The MeshTopoAlgorithm class provides several algorithms to manipulate a mesh. * It supports various mesh operations like inserting a new vertex, swapping the @@ -113,11 +115,11 @@ public: * Collapses the common edge of two adjacent facets. This operation removes * one common point of the collapsed edge and the facets \a ulFacetPos and * \a ulNeighbour from the data structure. - * @note If \a ulNeighbour is the neighbour facet on the i-th side then the - * i-th point is removed whereat i is 0, 1 or 2. If the other common point - * should be removed then CollapseEdge() should be invoked with transposed - * arguments of \a ulFacetPos and \a ulNeighbour, i.e. CollapseEdge - * ( \a ulNeighbour, \a ulFacetPos ). + * @note If \a ulNeighbour is the neighbour facet on the i-th side of + * \a ulFacetPos then the i-th point is removed whereas i is 0, 1 or 2. + * If the other common point should be removed then CollapseEdge() + * should be invoked with swapped arguments of \a ulFacetPos and + * \a ulNeighbour, i.e. CollapseEdge( \a ulNeighbour, \a ulFacetPos ). * * @note The client programmer must make sure that this is a legal operation. * @@ -132,6 +134,10 @@ public: * must take care not to use such elements. */ bool CollapseEdge(unsigned long ulFacetPos, unsigned long ulNeighbour); + /** + * Convenience function that passes already all needed information. + */ + bool CollapseEdge(const EdgeCollapse& ec); /** * Removes the facet with index \a ulFacetPos and all its neighbour facets. * The three vertices that are referenced by this facet are replaced by its @@ -144,7 +150,7 @@ public: * inconsistent stage. To make the structure consistent again Cleanup() should * be called. * The reason why this cannot be done automatically is that it would become - * quite slow if a lot of edges should be collapsed. + * quite slow if a lot of facets should be collapsed. * * @note While the mesh structure has invalid elements the client programmer * must take care not to use such elements. diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 4c32b1e07..b07baf9d8 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -425,7 +425,7 @@ void CmdMeshFromGeometry::activated(int iMsg) (*it)->getPropertyMap(Map); Mesh::MeshObject mesh; for (std::map::iterator jt = Map.begin(); jt != Map.end(); ++jt) { - if (jt->second->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) { + if (jt->first == "Shape" && jt->second->getTypeId().isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) { std::vector aPoints; std::vector aTopo; static_cast(jt->second)->getFaces(aPoints, aTopo,(float)tol); diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index b5005b98d..227122213 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -185,7 +185,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const *boolean << "Mesh_Union" << "Mesh_Intersection" << "Mesh_Difference"; mesh->setCommand("&Meshes"); - *mesh << "Mesh_Import" << "Mesh_Export" << "Mesh_FromGeometry" << "Separator" + *mesh << "Mesh_Import" << "Mesh_Export" << "MeshPart_Mesher" << "Separator" << analyze << "Mesh_HarmonizeNormals" << "Mesh_FlipNormals" << "Separator" << "Mesh_FillupHoles" << "Mesh_FillInteractiveHole" << "Mesh_RemoveComponents" << "Mesh_RemoveCompByHand" << "Mesh_AddFacet" << "Mesh_Smoothing" << "Separator" diff --git a/src/Mod/Mesh/InitGui.py b/src/Mod/Mesh/InitGui.py index 83be29aa5..9994159af 100644 --- a/src/Mod/Mesh/InitGui.py +++ b/src/Mod/Mesh/InitGui.py @@ -69,6 +69,10 @@ class MeshWorkbench ( Workbench ): def Initialize(self): # load the module import MeshGui + try: + import MeshPartGui + except: + pass def GetClassName(self): return "MeshGui::Workbench" diff --git a/src/Mod/MeshPart/Gui/Tessellation.cpp b/src/Mod/MeshPart/Gui/Tessellation.cpp index f1b50c396..5e7924bf6 100644 --- a/src/Mod/MeshPart/Gui/Tessellation.cpp +++ b/src/Mod/MeshPart/Gui/Tessellation.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,7 @@ Tessellation::Tessellation(QWidget* parent) : QWidget(parent), ui(new Ui_Tessellation) { ui->setupUi(this); - Gui::Command::doCommand(Gui::Command::Doc, "import MeshPart"); + Gui::Command::doCommand(Gui::Command::Doc, "import Mesh, MeshPart"); findShapes(); } @@ -56,6 +57,20 @@ Tessellation::~Tessellation() { } +void Tessellation::on_checkSimpleMethod_toggled(bool on) +{ + if (!on) { + if (ui->checkMaxEdgeLength->isChecked()) { + ui->checkMaxEdgeLength->setEnabled(true); + ui->spinMaxEdgeLength->setEnabled(true); + } + } + else { + ui->checkMaxEdgeLength->setEnabled(false); + ui->spinMaxEdgeLength->setEnabled(false); + } +} + void Tessellation::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { @@ -74,6 +89,8 @@ void Tessellation::findShapes() this->document = QString::fromAscii(activeDoc->getName()); std::vector objs = activeDoc->getObjectsOfType(); + double edgeLen = 0; + bool foundSelection = false; for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { const TopoDS_Shape& shape = (*it)->Shape.getValue(); if (shape.IsNull()) continue; @@ -85,6 +102,10 @@ void Tessellation::findShapes() } if (hasfaces) { + Base::BoundBox3d bbox = (*it)->Shape.getBoundingBox(); + edgeLen = std::max(edgeLen, bbox.LengthX()); + edgeLen = std::max(edgeLen, bbox.LengthY()); + edgeLen = std::max(edgeLen, bbox.LengthZ()); QString label = QString::fromUtf8((*it)->Label.getValue()); QString name = QString::fromAscii((*it)->getNameInDocument()); @@ -95,8 +116,16 @@ void Tessellation::findShapes() Gui::ViewProvider* vp = activeGui->getViewProvider(*it); if (vp) child->setIcon(0, vp->getIcon()); ui->treeWidget->addTopLevelItem(child); + if (Gui::Selection().isSelected(*it)) { + child->setSelected(true); + foundSelection = true; + } } } + + ui->spinMaxEdgeLength->setValue(edgeLen/10); + if (foundSelection) + ui->treeWidget->hide(); } bool Tessellation::accept() @@ -117,7 +146,19 @@ bool Tessellation::accept() try { QString shape, label; Gui::WaitCursor wc; - + + bool simple = ui->checkSimpleMethod->isChecked(); + double devFace = ui->spinDeviation->value(); + if (!ui->spinDeviation->isEnabled()) { + if (simple) + devFace = 0.1; + else + devFace = 0; + } + double maxEdge = ui->spinMaxEdgeLength->value(); + if (!ui->spinMaxEdgeLength->isEnabled()) + maxEdge = 0; + activeDoc->openTransaction("Meshing"); QList items = ui->treeWidget->selectedItems(); std::vector shapes = Gui::Selection().getObjectsOfType(); @@ -125,17 +166,32 @@ bool Tessellation::accept() shape = (*it)->data(0, Qt::UserRole).toString(); label = (*it)->text(0); - QString cmd = QString::fromAscii( - "__doc__=FreeCAD.getDocument(\"%1\")\n" - "__mesh__=__doc__.addObject(\"Mesh::Feature\",\"Mesh\")\n" - "__mesh__.Mesh=MeshPart.meshFromShape(__doc__.getObject(\"%2\").Shape,%3,0,0,%4)\n" - "__mesh__.Label=\"%5 (Meshed)\"\n" - "del __doc__, __mesh__\n") - .arg(this->document) - .arg(shape) - .arg(ui->spinMaxEdgeLength->value()) - .arg(ui->spinDeviation->value()) - .arg(label); + QString cmd; + if (simple) { + cmd = QString::fromAscii( + "__doc__=FreeCAD.getDocument(\"%1\")\n" + "__mesh__=__doc__.addObject(\"Mesh::Feature\",\"Mesh\")\n" + "__mesh__.Mesh=Mesh.Mesh(__doc__.getObject(\"%2\").Shape.tessellate(%3))\n" + "__mesh__.Label=\"%4 (Meshed)\"\n" + "del __doc__, __mesh__\n") + .arg(this->document) + .arg(shape) + .arg(devFace) + .arg(label); + } + else { + cmd = QString::fromAscii( + "__doc__=FreeCAD.getDocument(\"%1\")\n" + "__mesh__=__doc__.addObject(\"Mesh::Feature\",\"Mesh\")\n" + "__mesh__.Mesh=MeshPart.meshFromShape(__doc__.getObject(\"%2\").Shape,%3,0,0,%4)\n" + "__mesh__.Label=\"%5 (Meshed)\"\n" + "del __doc__, __mesh__\n") + .arg(this->document) + .arg(shape) + .arg(maxEdge) + .arg(devFace) + .arg(label); + } Gui::Command::doCommand(Gui::Command::Doc, (const char*)cmd.toAscii()); } activeDoc->commitTransaction(); diff --git a/src/Mod/MeshPart/Gui/Tessellation.h b/src/Mod/MeshPart/Gui/Tessellation.h index f3c092740..81e2627d4 100644 --- a/src/Mod/MeshPart/Gui/Tessellation.h +++ b/src/Mod/MeshPart/Gui/Tessellation.h @@ -47,6 +47,9 @@ protected: private: void findShapes(); +private Q_SLOTS: + void on_checkSimpleMethod_toggled(bool); + private: QString document; std::auto_ptr ui; diff --git a/src/Mod/MeshPart/Gui/Tessellation.ui b/src/Mod/MeshPart/Gui/Tessellation.ui index 6f0158b41..12e8c01a9 100644 --- a/src/Mod/MeshPart/Gui/Tessellation.ui +++ b/src/Mod/MeshPart/Gui/Tessellation.ui @@ -31,58 +31,69 @@ Settings - + - - - Surface deviation: - - - true - - - - - - - 3 - - - 0.001000000000000 - - - 0.100000000000000 - - - 0.100000000000000 - - - - - - - Max. edge length: - - - true - - - - - - - 3 - - - 0.001000000000000 - - - 0.100000000000000 - - - 1.000000000000000 - - + + + + + Surface deviation: + + + true + + + + + + + 3 + + + 0.001000000000000 + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Use simplified mesh generation method + + + + + + + Max. edge length: + + + true + + + + + + + 3 + + + 0.001000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + +
@@ -93,6 +104,7 @@ treeWidget checkDeviation spinDeviation + checkSimpleMethod checkMaxEdgeLength spinMaxEdgeLength @@ -105,12 +117,12 @@ setEnabled(bool) - 84 - 375 + 104 + 359 - 219 - 380 + 308 + 360 diff --git a/src/Mod/OpenSCAD/Init.py b/src/Mod/OpenSCAD/Init.py index 8b077b6e5..da643fbf0 100644 --- a/src/Mod/OpenSCAD/Init.py +++ b/src/Mod/OpenSCAD/Init.py @@ -32,3 +32,6 @@ openscadfilename = param.GetString('openscadexecutable') openscadbin = openscadfilename and os.path.isfile(openscadfilename) if openscadbin: FreeCAD.addImportType("OpenSCAD Format (*.scad)","importCSG") +FreeCAD.addExportType("OpenSCAD CSG Format (*.csg)","exportCSG") +FreeCAD.addExportType("OpenSCAD Format (*.scad)","exportCSG") + diff --git a/src/Mod/OpenSCAD/InitGui.py b/src/Mod/OpenSCAD/InitGui.py index 4e91d66db..ec4417489 100644 --- a/src/Mod/OpenSCAD/InitGui.py +++ b/src/Mod/OpenSCAD/InitGui.py @@ -107,9 +107,19 @@ static char * openscadlogo_xpm[] = { param = FreeCAD.ParamGet(\ "User parameter:BaseApp/Preferences/Mod/OpenSCAD") openscadfilename = param.GetString('openscadexecutable') + if not openscadfilename: + + import OpenSCADUtils + openscadfilename = OpenSCADUtils.searchforopenscadexe() + if openscadfilename: #automatic search was succsessful + FreeCAD.addImportType("OpenSCAD Format (*.scad)","importCSG") + param.SetString('openscadexecutable',openscadfilename) #save the result if openscadfilename: commands.extend(['OpenSCAD_AddOpenSCADElement']) toolbarcommands.extend(['OpenSCAD_AddOpenSCADElement']) + else: + FreeCAD.Console.PrintWarning('OpenSCAD executable not found\n') + self.appendToolbar("OpenSCADTools",toolbarcommands) self.appendMenu('OpenSCAD',commands) self.appendToolbar('OpenSCAD Part tools',parttoolbarcommands) @@ -124,5 +134,3 @@ static char * openscadlogo_xpm[] = { Gui.addWorkbench(OpenSCADWorkbench()) -App.addExportType("OpenSCAD CSG Format (*.csg)","exportCSG") -App.addExportType("OpenSCAD Format (*.scad)","exportCSG") diff --git a/src/Mod/OpenSCAD/OpenSCADCommands.py b/src/Mod/OpenSCAD/OpenSCADCommands.py index 0637640f0..9b3a97143 100644 --- a/src/Mod/OpenSCAD/OpenSCADCommands.py +++ b/src/Mod/OpenSCAD/OpenSCADCommands.py @@ -215,8 +215,8 @@ class AddSCADTask: asmesh=self.form.checkboxmesh.checkState() import OpenSCADUtils, os extension= 'stl' if asmesh else 'csg' - tmpfilename=OpenSCADUtils.callopenscadstring(scadstr,extension) - if tmpfilename: + try: + tmpfilename=OpenSCADUtils.callopenscadstring(scadstr,extension) doc=FreeCAD.activeDocument() or FreeCAD.newDocument() if asmesh: import Mesh @@ -225,8 +225,8 @@ class AddSCADTask: import importCSG importCSG.insert(tmpfilename,doc.Name) os.unlink(tmpfilename) - else: - FreeCAD.Console.PrintError(unicode(translate('OpenSCAD','Running OpenSCAD failed'))+u'\n') + except OpenSCADUtils.OpenSCADError, e: + FreeCAD.Console.PrintError(e.value) class AddOpenSCADElement: def IsActive(self): diff --git a/src/Mod/OpenSCAD/OpenSCADFeatures.py b/src/Mod/OpenSCAD/OpenSCADFeatures.py index 6248f8bb8..869039efe 100644 --- a/src/Mod/OpenSCAD/OpenSCADFeatures.py +++ b/src/Mod/OpenSCAD/OpenSCADFeatures.py @@ -274,10 +274,7 @@ class RefineShape: def execute(self, fp): if fp.Base and fp.Base.Shape.isValid(): sh=fp.Base.Shape.removeSplitter() - if sh.Placement.isNull(): - fp.Shape=sh - else: - fp.Shape=sh.transformGeometry(sh.Placement.toMatrix()) + fp.Shape=sh class GetWire: '''return the first wire from a given shape''' diff --git a/src/Mod/OpenSCAD/OpenSCADUtils.py b/src/Mod/OpenSCAD/OpenSCADUtils.py index f8fc17553..c42cf7456 100644 --- a/src/Mod/OpenSCAD/OpenSCADUtils.py +++ b/src/Mod/OpenSCAD/OpenSCADUtils.py @@ -28,22 +28,90 @@ __url__ = ["http://free-cad.sourceforge.net"] This Script includes various pyhton helper functions that are shared across the module ''' + +class OpenSCADError(Exception): + def __init__(self,value): + self.value= value + #def __repr__(self): + # return self.msg + def __str__(self): + return repr(self.value) + +def searchforopenscadexe(): + import os,sys,subprocess + if sys.platform == 'win32': + testpaths = [os.path.join(os.environ.get('Programfiles(x86)','C:'),\ + 'OpenSCAD\\openscad.exe')] + if 'ProgramW6432' in os.environ: + testpaths.append(os.path.join(os.environ.get('ProgramW6432','C:')\ + ,'OpenSCAD\\openscad.exe')) + for testpath in testpaths: + if os.path.isfile(testpath): + return testpath + else: #unix + p1=subprocess.Popen(['which','openscad'],stdout=subprocess.PIPE) + if p1.wait() == 0: + opath=p1.stdout.read().split('\n')[0] + return opath + +def workaroundforissue128needed(): + '''sets the import path depending on the OpenSCAD Verion + for versions <= 2012.06.23 to the current working dir + for versions above to the inputfile dir + see https://github.com/openscad/openscad/issues/128''' + vdate=getopenscadversion().split(' ')[2].split('.') + year,mon=int(vdate[0]),int(vdate[1]) + return (year<2012 or (year==2012 and (mon <6 or (mon == 6 and \ + (len(vdate)<3 or int(vdate[2]) <=23))))) + #ifdate=int(vdate[0])+(int(vdate[1])-1)/12.0 + #if len(vdate)>2: + # fdate+=int((vdate[2])-1)/12.0/31.0 + #return fdate < 2012.4759 + +def getopenscadversion(osfilename=None): + import os,subprocess,tempfile,time + if not osfilename: + import FreeCAD + osfilename = FreeCAD.ParamGet(\ + "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ + GetString('openscadexecutable') + if osfilename and os.path.isfile(osfilename): + p=subprocess.Popen([osfilename,'-v'],\ + stdout=subprocess.PIPE,universal_newlines=True) + p.wait() + return p.stdout.read().strip() + def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=False): '''call the open scad binary returns the filename of the result (or None), please delete the file afterwards''' import FreeCAD,os,subprocess,tempfile,time - osfilename = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ + def check_output2(*args,**kwargs): + kwargs.update({'stdout':subprocess.PIPE}) + p=subprocess.Popen(*args,**kwargs) + stdoutd,stderrd = p.communicate() + if p.returncode != 0: + raise OpenSCADError('%s\n' % stdoutd.strip()) + #raise Exception,'stdout %s\n stderr%s' %(stdoutd,stderrd) + if stdoutd.strip(): + FreeCAD.Console.PrintWarning(stdoutd+u'\n') + return stdoutd + + osfilename = FreeCAD.ParamGet(\ + "User parameter:BaseApp/Preferences/Mod/OpenSCAD").\ GetString('openscadexecutable') if osfilename and os.path.isfile(osfilename): if not outputfilename: dir1=tempfile.gettempdir() if keepname: - outputfilename=os.path.join(dir1,'%s.%s' % (os.path.split(inputfilename)[1].rsplit('.',1)[0],outputext)) + outputfilename=os.path.join(dir1,'%s.%s' % (os.path.split(\ + inputfilename)[1].rsplit('.',1)[0],outputext)) else: - outputfilename=os.path.join(dir1,'output-%d.%s' % (int(time.time()*10) % 1000000,outputext)) - if subprocess.call([osfilename,'-o',outputfilename,inputfilename]) == 0: - return outputfilename + outputfilename=os.path.join(dir1,'output-%d.%s' % \ + (int(time.time()*100) % 1000000,outputext)) + check_output2([osfilename,'-o',outputfilename, inputfilename],\ + stderr=subprocess.STDOUT) + return outputfilename def callopenscadstring(scadstr,outputext='csg'): '''create a tempfile and call the open scad binary @@ -51,11 +119,13 @@ def callopenscadstring(scadstr,outputext='csg'): please delete the file afterwards''' import os,tempfile,time dir1=tempfile.gettempdir() - inputfilename=os.path.join(dir1,'input-%d.scad' % (int(time.time()*10) % 1000000)) + inputfilename=os.path.join(dir1,'input-%d.scad' % \ + (int(time.time()*10) % 1000000)) inputfile = open(inputfilename,'w') inputfile.write(scadstr) inputfile.close() - outputfilename = callopenscad(inputfilename,outputext=outputext,keepname=True) + outputfilename = callopenscad(inputfilename,outputext=outputext,\ + keepname=True) os.unlink(inputfilename) return outputfilename diff --git a/src/Mod/OpenSCAD/exportCSG.py b/src/Mod/OpenSCAD/exportCSG.py index 625d5bb4e..aa3ad720b 100644 --- a/src/Mod/OpenSCAD/exportCSG.py +++ b/src/Mod/OpenSCAD/exportCSG.py @@ -104,32 +104,32 @@ def process_object(csg,ob): print "axis : "+str(ob.Placement.Rotation.Axis) print "angle : "+str(ob.Placement.Rotation.Angle) - if ob.Type == "Part::Sphere" : + if ob.TypeId == "Part::Sphere" : print "Sphere Radius : "+str(ob.Radius) check_multmatrix(csg,ob,0,0,0) csg.write("sphere($fn = 0, "+fafs+", r = "+str(ob.Radius)+");\n") - elif ob.Type == "Part::Box" : + elif ob.TypeId == "Part::Box" : print "cube : ("+ str(ob.Length)+","+str(ob.Width)+","+str(ob.Height)+")" mm = check_multmatrix(csg,ob,-ob.Length/2,-ob.Width/2,-ob.Height/2) csg.write("cube (size = ["+str(ob.Length)+", "+str(ob.Width)+", "+str(ob.Height)+"], center = "+center(mm)+");\n") if mm == 1 : csg.write("}\n") - elif ob.Type == "Part::Cylinder" : + elif ob.TypeId == "Part::Cylinder" : print "cylinder : Height "+str(ob.Height)+ " Radius "+str(ob.Radius) mm = check_multmatrix(csg,ob,0,0,-ob.Height/2) csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height)+ ", r1 = "+str(ob.Radius)+\ ", r2 = " + str(ob.Radius) + ", center = "+center(mm)+");\n") if mm == 1 : csg.write("}\n") - elif ob.Type == "Part::Cone" : + elif ob.TypeId == "Part::Cone" : print "cone : Height "+str(ob.Height)+ " Radius1 "+str(ob.Radius1)+" Radius2 "+str(ob.Radius2) mm = check_multmatrix(csg,ob,0,0,-ob.Height/2) csg.write("cylinder($fn = 0, "+fafs+", h = "+str(ob.Height)+ ", r1 = "+str(ob.Radius1)+\ ", r2 = "+str(ob.Radius2)+", center = "+center(mm)+");\n") if mm == 1 : csg.write("}\n") - elif ob.Type == "Part::Torus" : + elif ob.TypeId == "Part::Torus" : print "Torus" print ob.Radius1 print ob.Radius2 @@ -142,76 +142,82 @@ def process_object(csg,ob): else : # Cannot convert to rotate extrude so best effort is polyhedron csg.write('%s\n' % shape2polyhedron(ob.Shape)) - elif ob.Type == "Part::Extrusion" : + elif ob.TypeId == "Part::Extrusion" : print "Extrusion" print ob.Base print ob.Base.Name - #if ( ob.Base == "Part::FeaturePython" and ob.Base.Name == "Polygon") : - if ob.Base.Name.startswith("Polygon") : - f = str(ob.Base.FacesNumber) - r = str(ob.Base.Radius) - h = str(ob.Dir[2]) - print "Faces : " + f - print "Radius : " + r - print "Height : " + h - mm = check_multmatrix(csg,ob,0,0,-float(h)/2) - csg.write("cylinder($fn = "+f+", "+fafs+", h = "+h+", r1 = "+r+\ - ", r2 = "+r+", center = "+center(mm)+");\n") - if mm == 1: csg.write("}\n") + if ob.Base.isDerivedFrom('Part::Part2DObjectPython') and \ + hasattr(ob.Base,'Proxy') and hasattr(ob.Base.Proxy,'TypeId'): + ptype=ob.Base.Proxy.TypeId + if ptype == "Polygon" : + f = str(ob.Base.FacesNumber) + r = str(ob.Base.Radius) + h = str(ob.Dir[2]) + print "Faces : " + f + print "Radius : " + r + print "Height : " + h + mm = check_multmatrix(csg,ob,0,0,-float(h)/2) + csg.write("cylinder($fn = "+f+", "+fafs+", h = "+h+", r1 = "+r+\ + ", r2 = "+r+", center = "+center(mm)+");\n") + if mm == 1: csg.write("}\n") - elif ob.Base.Name.startswith("circle") : - r = str(ob.Base.Radius) - h = str(ob.Dir[2]) - print "Radius : " + r - print "Height : " + h - mm = check_multmatrix(csg,ob,0,0,-float(h)/2) - csg.write("cylinder($fn = 0, "+fafs+", h = "+h+", r1 = "+r+\ - ", r2 = "+r+", center = "+center(mm)+");\n") - if mm == 1: csg.write("}\n") - - elif ob.Base.Name.startswith("Wire") : - print "Wire extrusion" - print ob.Base - mm = check_multmatrix(csg,ob,0,0,0) - csg.write("linear_extrude(height = "+str(ob.Dir[2])+", center = "+center(mm)+", "+convexity+", twist = 0, slices = 2, $fn = 0, "+fafs+")\n{\n") - csg.write(vertexs2polygon(ob.Base.Shape.Vertexes)) - if mm == 1: csg.write("}\n") + elif ptype == "Circle" : + r = str(ob.Base.Radius) + h = str(ob.Dir[2]) + print "Radius : " + r + print "Height : " + h + mm = check_multmatrix(csg,ob,0,0,-float(h)/2) + csg.write("cylinder($fn = 0, "+fafs+", h = "+h+", r1 = "+r+\ + ", r2 = "+r+", center = "+center(mm)+");\n") + if mm == 1: csg.write("}\n") - elif ob.Base.Name.startswith("square") : + elif ptype == "Wire" : + print "Wire extrusion" + print ob.Base + mm = check_multmatrix(csg,ob,0,0,0) + csg.write("linear_extrude(height = "+str(ob.Dir[2])+", center = "+center(mm)+", "+convexity+", twist = 0, slices = 2, $fn = 0, "+fafs+")\n{\n") + csg.write(vertexs2polygon(ob.Base.Shape.Vertexes)) + if mm == 1: csg.write("}\n") + + elif ob.Base.isDerivedFrom('Part::Plane'): mm = check_multmatrix(csg,ob,0,0,0) csg.write("linear_extrude(height = "+str(ob.Dir[2])+", center = true, "+convexity+", twist = 0, slices = 2, $fn = 0, "+fafs+")\n{\n") csg.write("square (size = ["+str(ob.Base.Length)+", "+str(ob.Base.Width)+"],center = "+center(mm)+";\n}\n") if mm == 1: csg.write("}\n") - - elif ob.Type == "Part::Cut" : + elif ob.Base.Name.startswith('this_is_a_bad_idea'): + pass + else: + pass #There should be a fallback solution + + elif ob.TypeId == "Part::Cut" : print "Cut" csg.write("difference() {\n") process_object(csg,ob.Base) process_object(csg,ob.Tool) csg.write("}\n") - elif ob.Type == "Part::Fuse" : + elif ob.TypeId == "Part::Fuse" : print "union" csg.write("union() {\n") process_object(csg,ob.Base) process_object(csg,ob.Tool) csg.write("}\n") - elif ob.Type == "Part::Common" : + elif ob.TypeId == "Part::Common" : print "intersection" csg.write("intersection() {\n") process_object(csg,ob.Base) process_object(csg,ob.Tool) csg.write("}\n") - elif ob.Type == "Part::MultiFuse" : + elif ob.TypeId == "Part::MultiFuse" : print "Multi Fuse / union" csg.write("union() {\n") for subobj in ob.Shapes: process_object(csg,subobj) csg.write("}\n") - elif ob.Type == "Part::Common" : + elif ob.TypeId == "Part::Common" : print "Multi Common / intersection" csg.write("intersection() {\n") for subobj in ob.Shapes: @@ -241,7 +247,7 @@ def export(exportList,filename): for ob in exportList: print ob print "Name : "+ob.Name - print "Type : "+ob.Type + print "Type : "+ob.TypeId print "Shape : " print ob.Shape process_object(csg,ob) diff --git a/src/Mod/OpenSCAD/importCSG.py b/src/Mod/OpenSCAD/importCSG.py index 4891e4a1d..623650fd9 100644 --- a/src/Mod/OpenSCAD/importCSG.py +++ b/src/Mod/OpenSCAD/importCSG.py @@ -73,10 +73,16 @@ def open(filename): doc = FreeCAD.newDocument(docname) if filename.lower().endswith('.scad'): tmpfile=callopenscad(filename) - pathName = '' #https://github.com/openscad/openscad/issues/128 - #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128 + if workaroundforissue128needed(): + pathName = '' #https://github.com/openscad/openscad/issues/128 + #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128 + else: + pathName = os.path.dirname(os.path.normpath(filename)) processcsg(tmpfile) - os.unlink(tmpfile) + try: + os.unlink(tmpfile) + except OSError: + pass else: pathName = os.path.dirname(os.path.normpath(filename)) processcsg(filename) @@ -94,10 +100,16 @@ def insert(filename,docname): importgroup = doc.addObject("App::DocumentObjectGroup",groupname) if filename.lower().endswith('.scad'): tmpfile=callopenscad(filename) - pathName = '' #https://github.com/openscad/openscad/issues/128 - #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128 + if workaroundforissue128needed(): + pathName = '' #https://github.com/openscad/openscad/issues/128 + #pathName = os.getcwd() #https://github.com/openscad/openscad/issues/128 + else: + pathName = os.path.dirname(os.path.normpath(filename)) processcsg(tmpfile) - os.unlink(tmpfile) + try: + os.unlink(tmpfile) + except OSError: + pass else: pathName = os.path.dirname(os.path.normpath(filename)) processcsg(filename) @@ -477,7 +489,7 @@ def process_rotate_extrude(obj): ViewProviderTree(newobj.ViewObject) else: newobj.ViewObject.Proxy = 0 - myrev.ViewObject.hide() + myrev.ViewObject.hide() return(newobj) def p_rotate_extrude_action(p): diff --git a/src/Mod/OpenSCAD/prototype.py b/src/Mod/OpenSCAD/prototype.py index f43d1629d..0f9062605 100644 --- a/src/Mod/OpenSCAD/prototype.py +++ b/src/Mod/OpenSCAD/prototype.py @@ -659,14 +659,18 @@ def readfile(filename): isopenscad = relname.lower().endswith('.scad') if isopenscad: tmpfile=callopenscad(filename) - lastimportpath = os.getcwd() #https://github.com/openscad/openscad/issues/128 + if OpenSCADUtils.workaroundforissue128needed(): + lastimportpath = os.getcwd() #https://github.com/openscad/openscad/issues/128 f = pythonopen(tmpfile) else: f = pythonopen(filename) rootnode=parsenode(f.read())[0] f.close() - if isopenscad: - os.unlink(tmpfile) + if isopenscad and tmpfile: + try: + os.unlink(tmpfile) + except OSError: + pass return rootnode.flattengroups() def open(filename): diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index 76ed19154..cd3bb4149 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -13,6 +13,8 @@ #ifndef _PreComp_ # include # include +# include +# include # include # include #endif @@ -38,6 +40,7 @@ #include "FeaturePartPolygon.h" #include "FeatureGeometrySet.h" #include "FeatureChamfer.h" +#include "FeatureCompound.h" #include "FeatureExtrusion.h" #include "FeatureFillet.h" #include "FeatureMirroring.h" @@ -171,6 +174,7 @@ void PartExport initPart() Part::FilletBase ::init(); Part::Fillet ::init(); Part::Chamfer ::init(); + Part::Compound ::init(); Part::Extrusion ::init(); Part::Revolution ::init(); Part::Mirroring ::init(); @@ -228,6 +232,8 @@ void PartExport initPart() Part::GeomSurfaceOfExtrusion ::init(); + IGESControl_Controller::Init(); + STEPControl_Controller::Init(); // set the user-defined units Base::Reference hGrp = App::GetApplication().GetUserParameter() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part"); diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index e9286a326..ffcf4ec16 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -58,6 +58,7 @@ # include # include # include +# include # include # include # include @@ -1250,6 +1251,34 @@ static PyObject * makeLoft(PyObject *self, PyObject *args) #endif } +static PyObject * exportUnits(PyObject *self, PyObject *args) +{ + char* unit=0; + if (!PyArg_ParseTuple(args, "|s", &unit)) + return NULL; + if (unit) { + if (strcmp(unit,"M") == 0 || strcmp(unit,"MM") == 0 || strcmp(unit,"IN") == 0) { + if (!Interface_Static::SetCVal("write.iges.unit",unit)) { + PyErr_SetString(PyExc_RuntimeError, "Failed to set 'write.iges.unit'"); + return 0; + } + if (!Interface_Static::SetCVal("write.step.unit",unit)) { + PyErr_SetString(PyExc_RuntimeError, "Failed to set 'write.step.unit'"); + return 0; + } + } + else { + PyErr_SetString(PyExc_ValueError, "Wrong unit"); + return 0; + } + } + + Py::Dict dict; + dict.setItem("write.iges.unit", Py::String(Interface_Static::CVal("write.iges.unit"))); + dict.setItem("write.step.unit", Py::String(Interface_Static::CVal("write.step.unit"))); + return Py::new_reference_to(dict); +} + static PyObject * toPythonOCC(PyObject *self, PyObject *args) { PyObject *pcObj; @@ -1587,10 +1616,13 @@ struct PyMethodDef Part_methods[] = { {"makeLoft" ,makeLoft,METH_VARARGS, "makeLoft(list of wires) -- Create a loft shape."}, - + {"makeWireString" ,makeWireString ,METH_VARARGS, "makeWireString(string,fontdir,fontfile,height,[track]) -- Make list of wires in the form of a string's characters."}, + {"exportUnits" ,exportUnits ,METH_VARARGS, + "exportUnits([string=MM|M|IN]) -- Set units for exporting STEP/IGES files and returns the units."}, + {"cast_to_shape" ,cast_to_shape,METH_VARARGS, "cast_to_shape(shape) -- Cast to the actual shape type"}, diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 391bb6023..31eb00219 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -102,6 +102,8 @@ SET(Features_SRCS FeaturePartSection.h FeatureChamfer.cpp FeatureChamfer.h + FeatureCompound.cpp + FeatureCompound.h FeatureExtrusion.cpp FeatureExtrusion.h FeatureFillet.cpp diff --git a/src/Mod/Part/App/CrossSection.cpp b/src/Mod/Part/App/CrossSection.cpp index c58cb370c..28af55320 100644 --- a/src/Mod/Part/App/CrossSection.cpp +++ b/src/Mod/Part/App/CrossSection.cpp @@ -23,10 +23,22 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include # include +# include # include +# include +# include # include +# include +# include +# include +# include # include +# include +# include # include # include # include @@ -42,10 +54,28 @@ CrossSection::CrossSection(double a, double b, double c, const TopoDS_Shape& s) { } -std::list CrossSection::section(double d) const +std::list CrossSection::slice(double d) const { std::list wires; - BRepAlgoAPI_Section cs(s, gp_Pln(a,b,c,-d)); + // Fixes: 0001228: Cross section of Torus in Part Workbench fails or give wrong results + // Fixes: 0001137: Incomplete slices when using Part.slice on a torus + TopExp_Explorer xp; + for (xp.Init(s, TopAbs_SOLID); xp.More(); xp.Next()) { + sliceSolid(d, xp.Current(), wires); + } + for (xp.Init(s, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next()) { + sliceNonSolid(d, xp.Current(), wires); + } + for (xp.Init(s, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) { + sliceNonSolid(d, xp.Current(), wires); + } + + return wires; +} + +void CrossSection::sliceNonSolid(double d, const TopoDS_Shape& shape, std::list& wires) const +{ + BRepAlgoAPI_Section cs(shape, gp_Pln(a,b,c,-d)); if (cs.IsDone()) { std::list edges; TopExp_Explorer xp; @@ -53,12 +83,54 @@ std::list CrossSection::section(double d) const edges.push_back(TopoDS::Edge(xp.Current())); connectEdges(edges, wires); } +} - return wires; +void CrossSection::sliceSolid(double d, const TopoDS_Shape& shape, std::list& wires) const +{ +#if 0 + gp_Pln slicePlane(a,b,c,-d); + BRepBuilderAPI_MakeFace mkFace(slicePlane); + TopoDS_Face face = mkFace.Face(); + BRepAlgoAPI_Common mkInt(shape, face); + + if (mkInt.IsDone()) { + // sort and repair the wires + TopTools_IndexedMapOfShape mapOfWires; + TopExp::MapShapes(mkInt.Shape(), TopAbs_WIRE, mapOfWires); + connectWires(mapOfWires, wires); + } +#else + gp_Pln slicePlane(a,b,c,-d); + BRepBuilderAPI_MakeFace mkFace(slicePlane); + TopoDS_Face face = mkFace.Face(); + BRepPrimAPI_MakeHalfSpace mkSolid(face, gp_Pnt(0,0,d-1)); + TopoDS_Solid solid = mkSolid.Solid(); + BRepAlgoAPI_Cut mkCut(shape, solid); + + if (mkCut.IsDone()) { + TopTools_IndexedMapOfShape mapOfFaces; + TopExp::MapShapes(mkCut.Shape(), TopAbs_FACE, mapOfFaces); + for (int i=1; i<=mapOfFaces.Extent(); i++) { + const TopoDS_Face& face = TopoDS::Face(mapOfFaces.FindKey(i)); + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() == GeomAbs_Plane) { + gp_Pln plane = adapt.Plane(); + if (plane.Axis().IsParallel(slicePlane.Axis(), Precision::Confusion()) && + plane.Distance(slicePlane.Location()) < Precision::Confusion()) { + // sort and repair the wires + TopTools_IndexedMapOfShape mapOfWires; + TopExp::MapShapes(face, TopAbs_WIRE, mapOfWires); + connectWires(mapOfWires, wires); + } + } + } + } +#endif } void CrossSection::connectEdges (const std::list& edges, std::list& wires) const { + // FIXME: Use ShapeAnalysis_FreeBounds::ConnectEdgesToWires() as an alternative std::list edge_list = edges; while (edge_list.size() > 0) { BRepBuilderAPI_MakeWire mkWire; @@ -84,6 +156,38 @@ void CrossSection::connectEdges (const std::list& edges, std::list< } } while (found); - wires.push_back(new_wire); + + // Fix any topological issues of the wire + ShapeFix_Wire aFix; + aFix.SetPrecision(Precision::Confusion()); + aFix.Load(new_wire); + aFix.FixReorder(); + aFix.FixConnected(); + aFix.FixClosed(); + wires.push_back(aFix.Wire()); + } +} + +void CrossSection::connectWires (const TopTools_IndexedMapOfShape& wireMap, std::list& wires) const +{ + Handle(TopTools_HSequenceOfShape) hWires = new TopTools_HSequenceOfShape(); + for (int i=1; i<=wireMap.Extent(); i++) { + const TopoDS_Shape& wire = wireMap.FindKey(i); + hWires->Append(wire); + } + + Handle(TopTools_HSequenceOfShape) hSorted = new TopTools_HSequenceOfShape(); + ShapeAnalysis_FreeBounds::ConnectWiresToWires(hWires, Precision::Confusion(), false, hSorted); + + for (int i=1; i<=hSorted->Length(); i++) { + const TopoDS_Wire& new_wire = TopoDS::Wire(hSorted->Value(i)); + // Fix any topological issues of the wire + ShapeFix_Wire aFix; + aFix.SetPrecision(Precision::Confusion()); + aFix.Load(new_wire); + aFix.FixReorder(); + aFix.FixConnected(); + aFix.FixClosed(); + wires.push_back(aFix.Wire()); } } diff --git a/src/Mod/Part/App/CrossSection.h b/src/Mod/Part/App/CrossSection.h index a8a141ca0..56fc90fdd 100644 --- a/src/Mod/Part/App/CrossSection.h +++ b/src/Mod/Part/App/CrossSection.h @@ -28,6 +28,7 @@ class TopoDS_Shape; class TopoDS_Wire; +class TopTools_IndexedMapOfShape; namespace Part { @@ -35,8 +36,13 @@ class PartExport CrossSection { public: CrossSection(double a, double b, double c, const TopoDS_Shape& s); - std::list section(double d) const; + std::list slice(double d) const; + +private: + void sliceNonSolid(double d, const TopoDS_Shape&, std::list& wires) const; + void sliceSolid(double d, const TopoDS_Shape&, std::list& wires) const; void connectEdges (const std::list& edges, std::list& wires) const; + void connectWires (const TopTools_IndexedMapOfShape& wireMap, std::list& wires) const; private: double a,b,c; diff --git a/src/Mod/Part/App/FeatureCompound.cpp b/src/Mod/Part/App/FeatureCompound.cpp new file mode 100644 index 000000000..7715b5fb5 --- /dev/null +++ b/src/Mod/Part/App/FeatureCompound.cpp @@ -0,0 +1,99 @@ +/*************************************************************************** + * Copyright (c) 2013 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 +#endif + + +#include "FeatureCompound.h" + + +using namespace Part; + + +PROPERTY_SOURCE(Part::Compound, Part::Feature) + +Compound::Compound() +{ + ADD_PROPERTY(Links,(0)); + Links.setSize(0); +} + +Compound::~Compound() +{ +} + +short Compound::mustExecute() const +{ + if (Links.isTouched()) + return 1; + return 0; +} + +App::DocumentObjectExecReturn *Compound::execute(void) +{ + try { + std::vector history; + int countFaces = 0; + + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + + const std::vector& links = Links.getValues(); + for (std::vector::const_iterator it = links.begin(); it != links.end(); ++it) { + if (*it && (*it)->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* fea = static_cast(*it); + const TopoDS_Shape& sh = fea->Shape.getValue(); + if (!sh.IsNull()) { + builder.Add(comp, sh); + TopTools_IndexedMapOfShape faceMap; + TopExp::MapShapes(sh, TopAbs_FACE, faceMap); + ShapeHistory hist; + hist.type = TopAbs_FACE; + for (int i=1; i<=faceMap.Extent(); i++) { + hist.shapeMap[i-1].push_back(countFaces++); + } + history.push_back(hist); + } + } + } + + this->Shape.setValue(comp); + PropertyShapeHistory prop; + prop.setContainer(this); + prop.setValues(history); + 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/FeatureCompound.h b/src/Mod/Part/App/FeatureCompound.h new file mode 100644 index 000000000..1caaeabc9 --- /dev/null +++ b/src/Mod/Part/App/FeatureCompound.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2013 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 PART_FEATURECOMPOUND_H +#define PART_FEATURECOMPOUND_H + +#include +#include "PartFeature.h" + +namespace Part +{ + +class Compound : public Part::Feature +{ + PROPERTY_HEADER(Part::Compound); + +public: + Compound(); + virtual ~Compound(); + + App::PropertyLinkList Links; + + /** @name methods override feature */ + //@{ + short mustExecute() const; + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "PartGui::ViewProviderCompound"; + } + //@} +}; + +} //namespace Part + + +#endif // PART_FEATURECOMPOUND_H + diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 2f8450d3a..9e68d83f0 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -707,7 +707,13 @@ void GeomArcOfCircle::getRange(double& u, double& v) const void GeomArcOfCircle::setRange(double u, double v) { - myCurve->SetTrim(u, v); + try { + myCurve->SetTrim(u, v); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } } // Persistence implementer diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index dc239da90..82476c494 100644 --- a/src/Mod/Part/App/PartFeatures.cpp +++ b/src/Mod/Part/App/PartFeatures.cpp @@ -414,6 +414,9 @@ App::DocumentObjectExecReturn *Sweep::execute(void) Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } + catch (...) { + return new App::DocumentObjectExecReturn("A fatal error occurred when making the sweep"); + } } // ---------------------------------------------------------------------------- diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index bd3746a26..85fc2ca18 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -1306,7 +1306,7 @@ TopoDS_Shape TopoShape::section(TopoDS_Shape shape) const std::list TopoShape::slice(const Base::Vector3d& dir, double d) const { CrossSection cs(dir.x, dir.y, dir.z, this->_Shape); - return cs.section(d); + return cs.slice(d); } TopoDS_Compound TopoShape::slices(const Base::Vector3d& dir, const std::vector& d) const @@ -1314,7 +1314,7 @@ TopoDS_Compound TopoShape::slices(const Base::Vector3d& dir, const std::vector > wire_list; CrossSection cs(dir.x, dir.y, dir.z, this->_Shape); for (std::vector::const_iterator jt = d.begin(); jt != d.end(); ++jt) { - wire_list.push_back(cs.section(*jt)); + wire_list.push_back(cs.slice(*jt)); } std::vector< std::list >::const_iterator ft; @@ -1845,7 +1845,7 @@ TopoDS_Shape TopoShape::transformGShape(const Base::Matrix4D& rclTrf) const return mkTrf.Shape(); } -void TopoShape::transformShape(const Base::Matrix4D& rclTrf) +void TopoShape::transformShape(const Base::Matrix4D& rclTrf, bool copy) { // There is a strange behaviour of the gp_Trsf class if rclTrf has // a negative determinant. @@ -1864,7 +1864,7 @@ void TopoShape::transformShape(const Base::Matrix4D& rclTrf) } // location transformation - BRepBuilderAPI_Transform mkTrf(this->_Shape, mat); + BRepBuilderAPI_Transform mkTrf(this->_Shape, mat, copy ? Standard_True : Standard_False); this->_Shape = mkTrf.Shape(); } @@ -1970,7 +1970,7 @@ TopoDS_Shape TopoShape::removeSplitter() const if (_Shape.ShapeType() == TopAbs_SOLID) { const TopoDS_Solid &solid = TopoDS::Solid(_Shape); - BRepTools_ReShape reshape; + BRepBuilderAPI_MakeSolid mkSolid; TopExp_Explorer it; for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); @@ -1978,7 +1978,10 @@ TopoDS_Shape TopoShape::removeSplitter() const if (uniter.process()) { if (uniter.isModified()) { const TopoDS_Shell &newShell = uniter.getShell(); - reshape.Replace(currentShell, newShell); + mkSolid.Add(newShell); + } + else { + mkSolid.Add(currentShell); } } else { @@ -1986,7 +1989,7 @@ TopoDS_Shape TopoShape::removeSplitter() const return _Shape; } } - return reshape.Apply(solid); + return mkSolid.Solid(); } else if (_Shape.ShapeType() == TopAbs_SHELL) { const TopoDS_Shell& shell = TopoDS::Shell(_Shape); diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 0369682ff..9e7ecd9a1 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -179,7 +179,7 @@ public: //@{ void transformGeometry(const Base::Matrix4D &rclMat); TopoDS_Shape transformGShape(const Base::Matrix4D&) const; - void transformShape(const Base::Matrix4D&); + void transformShape(const Base::Matrix4D&, bool copy); TopoDS_Shape mirror(const gp_Ax2&) const; TopoDS_Shape toNurbs() const; TopoDS_Shape replaceShape(const std::vector< std::pair >& s) const; diff --git a/src/Mod/Part/App/TopoShapePy.xml b/src/Mod/Part/App/TopoShapePy.xml index bf4dffa9c..92b56f50f 100644 --- a/src/Mod/Part/App/TopoShapePy.xml +++ b/src/Mod/Part/App/TopoShapePy.xml @@ -156,7 +156,8 @@ underlying geometry then use the methods translate or rotate. Apply transformation on a shape without changing -the underlying geometry. +the underlying geometry. +transformShape(Matrix,[boolean copy=False]) @@ -222,14 +223,25 @@ As a result, this shape becomes null. Checks if the shape is closed. + + + Checks if both shapes share the same geometry. + Placement and orientation may differ. + + + - Checks if both shapes share the same geometry. + Checks if both shapes share the same geometry + and placement. Orientation may differ. + - Checks if both shapes are equal. + Checks if both shapes are equal. + This means geometry, placement and orientation are equal. + diff --git a/src/Mod/Part/App/TopoShapePyImp.cpp b/src/Mod/Part/App/TopoShapePyImp.cpp index 24f26d832..537e58ec0 100644 --- a/src/Mod/Part/App/TopoShapePyImp.cpp +++ b/src/Mod/Part/App/TopoShapePyImp.cpp @@ -787,12 +787,13 @@ PyObject* TopoShapePy::transformGeometry(PyObject *args) PyObject* TopoShapePy::transformShape(PyObject *args) { PyObject *obj; - if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type),&obj)) + PyObject *copy = Py_False; + if (!PyArg_ParseTuple(args, "O!|O!", &(Base::MatrixPy::Type),&obj,&(PyBool_Type), ©)) return NULL; Base::Matrix4D mat = static_cast(obj)->value(); try { - this->getTopoShapePtr()->transformShape(mat); + this->getTopoShapePtr()->transformShape(mat, PyObject_IsTrue(copy) ? true : false); Py_Return; } catch (Standard_Failure) { @@ -1142,7 +1143,7 @@ PyObject* TopoShapePy::isEqual(PyObject *args) return NULL; TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->_Shape; - Standard_Boolean test = (getTopoShapePtr()->_Shape == shape); + Standard_Boolean test = (getTopoShapePtr()->_Shape.IsEqual(shape)); return Py_BuildValue("O", (test ? Py_True : Py_False)); } @@ -1157,6 +1158,17 @@ PyObject* TopoShapePy::isSame(PyObject *args) return Py_BuildValue("O", (test ? Py_True : Py_False)); } +PyObject* TopoShapePy::isPartner(PyObject *args) +{ + PyObject *pcObj; + if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &pcObj)) + return NULL; + + TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->_Shape; + Standard_Boolean test = getTopoShapePtr()->_Shape.IsPartner(shape); + return Py_BuildValue("O", (test ? Py_True : Py_False)); +} + PyObject* TopoShapePy::isValid(PyObject *args) { if (!PyArg_ParseTuple(args, "")) diff --git a/src/Mod/Part/App/modelRefine.cpp b/src/Mod/Part/App/modelRefine.cpp index 21170523f..851b21194 100644 --- a/src/Mod/Part/App/modelRefine.cpp +++ b/src/Mod/Part/App/modelRefine.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -698,7 +699,7 @@ void Part::BRepBuilderAPI_RefineModel::Build() if (myShape.ShapeType() == TopAbs_SOLID) { const TopoDS_Solid &solid = TopoDS::Solid(myShape); - BRepTools_ReShape reshape; + BRepBuilderAPI_MakeSolid mkSolid; TopExp_Explorer it; for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); @@ -706,15 +707,18 @@ void Part::BRepBuilderAPI_RefineModel::Build() if (uniter.process()) { if (uniter.isModified()) { const TopoDS_Shell &newShell = uniter.getShell(); - reshape.Replace(currentShell, newShell); + mkSolid.Add(newShell); LogModifications(uniter); } + else { + mkSolid.Add(currentShell); + } } else { Standard_Failure::Raise("Removing splitter failed"); } } - myShape = reshape.Apply(solid); + myShape = mkSolid.Solid(); } else if (myShape.ShapeType() == TopAbs_SHELL) { const TopoDS_Shell& shell = TopoDS::Shell(myShape); diff --git a/src/Mod/Part/Gui/AppPartGui.cpp b/src/Mod/Part/Gui/AppPartGui.cpp index 8a368bf64..6c2c04ed3 100644 --- a/src/Mod/Part/Gui/AppPartGui.cpp +++ b/src/Mod/Part/Gui/AppPartGui.cpp @@ -37,6 +37,7 @@ #include "ViewProvider2DObject.h" #include "ViewProviderMirror.h" #include "ViewProviderBoolean.h" +#include "ViewProviderCompound.h" #include "ViewProviderCircleParametric.h" #include "ViewProviderLineParametric.h" #include "ViewProviderPointParametric.h" @@ -50,6 +51,7 @@ #include "ViewProviderRuledSurface.h" #include "DlgSettingsGeneral.h" +#include "DlgSettingsObjectColor.h" #include "DlgSettings3DViewPartImp.h" #include "Workbench.h" @@ -124,6 +126,7 @@ void PartGuiExport initPartGui() PartGui::ViewProviderBoolean ::init(); PartGui::ViewProviderMultiFuse ::init(); PartGui::ViewProviderMultiCommon ::init(); + PartGui::ViewProviderCompound ::init(); PartGui::ViewProviderCircleParametric ::init(); PartGui::ViewProviderLineParametric ::init(); PartGui::ViewProviderPointParametric ::init(); @@ -146,6 +149,7 @@ void PartGuiExport initPartGui() // register preferences pages (void)new Gui::PrefPageProducer ( QT_TRANSLATE_NOOP("QObject","Part design") ); (void)new Gui::PrefPageProducer ( QT_TRANSLATE_NOOP("QObject","Part design") ); + (void)new Gui::PrefPageProducer ( QT_TRANSLATE_NOOP("QObject","Display") ); Gui::ViewProviderBuilder::add( Part::PropertyPartShape::getClassTypeId(), PartGui::ViewProviderPart::getClassTypeId()); diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index c2d457ba2..ef5922aa6 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -38,6 +38,7 @@ set(PartGui_MOC_HDRS DlgRevolution.h DlgSettings3DViewPartImp.h DlgSettingsGeneral.h + DlgSettingsObjectColor.h TaskFaceColors.h TaskShapeBuilder.h TaskLoft.h @@ -66,6 +67,7 @@ set(PartGui_UIC_SRCS DlgRevolution.ui DlgSettings3DViewPart.ui DlgSettingsGeneral.ui + DlgSettingsObjectColor.ui TaskFaceColors.ui TaskShapeBuilder.ui TaskLoft.ui @@ -121,6 +123,9 @@ SET(PartGui_SRCS DlgSettingsGeneral.cpp DlgSettingsGeneral.h DlgSettingsGeneral.ui + DlgSettingsObjectColor.cpp + DlgSettingsObjectColor.h + DlgSettingsObjectColor.ui Resources/Part.qrc PreCompiled.cpp PreCompiled.h @@ -138,6 +143,8 @@ SET(PartGui_SRCS ViewProviderReference.h ViewProviderBox.cpp ViewProviderBox.h + ViewProviderCompound.cpp + ViewProviderCompound.h ViewProviderCircleParametric.cpp ViewProviderCircleParametric.h ViewProviderLineParametric.cpp diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index b23bca966..7b33b1be8 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -379,6 +379,55 @@ bool CmdPartFuse::isActive(void) return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=2; } +//=========================================================================== +// Part_Compound +//=========================================================================== +DEF_STD_CMD_A(CmdPartCompound); + +CmdPartCompound::CmdPartCompound() + :Command("Part_Compound") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Make compound"); + sToolTipText = QT_TR_NOOP("Make a compound of several shapes"); + sWhatsThis = "Part_Compound"; + sStatusTip = sToolTipText; +} + +void CmdPartCompound::activated(int iMsg) +{ + unsigned int n = getSelection().countObjectsOfType(Part::Feature::getClassTypeId()); + if (n < 2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select two shapes or more, please.")); + return; + } + + std::string FeatName = getUniqueObjectName("Compound"); + + std::vector Sel = getSelection().getSelection(); + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Links = ["; + for (std::vector::iterator it = Sel.begin(); it != Sel.end(); ++it){ + str << "App.activeDocument()." << it->FeatName << ","; + tempSelNames.push_back(it->FeatName); + } + str << "]"; + + openCommand("Compound"); + doCommand(Doc,"App.activeDocument().addObject(\"Part::Compound\",\"%s\")",FeatName.c_str()); + runCommand(Doc,str.str().c_str()); + updateActive(); + commitCommand(); +} + +bool CmdPartCompound::isActive(void) +{ + return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=2; +} + //=========================================================================== // Part_Section //=========================================================================== @@ -1416,6 +1465,7 @@ void CreatePartCommands(void) rcCmdMgr.addCommand(new CmdPartCommon()); rcCmdMgr.addCommand(new CmdPartCut()); rcCmdMgr.addCommand(new CmdPartFuse()); + rcCmdMgr.addCommand(new CmdPartCompound()); rcCmdMgr.addCommand(new CmdPartSection()); //rcCmdMgr.addCommand(new CmdPartBox2()); //rcCmdMgr.addCommand(new CmdPartBox3()); diff --git a/src/Mod/Part/Gui/DlgFilletEdges.cpp b/src/Mod/Part/Gui/DlgFilletEdges.cpp index f53fc7445..f6ea3929f 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.cpp +++ b/src/Mod/Part/Gui/DlgFilletEdges.cpp @@ -169,12 +169,13 @@ namespace PartGui { return element.substr(0,4) == "Face"; } }; - class DlgFilletEdgesP + class DlgFilletEdges::Private { public: App::DocumentObject* object; EdgeFaceSelection* selection; Part::FilletBase* fillet; + FilletType filletType; std::vector edge_ids; TopTools_IndexedMapOfShape all_edges; TopTools_IndexedMapOfShape all_faces; @@ -186,8 +187,8 @@ namespace PartGui { /* TRANSLATOR PartGui::DlgFilletEdges */ -DlgFilletEdges::DlgFilletEdges(Part::FilletBase* fillet, QWidget* parent, Qt::WFlags fl) - : QWidget(parent, fl), ui(new Ui_DlgFilletEdges()), d(new DlgFilletEdgesP()) +DlgFilletEdges::DlgFilletEdges(FilletType type, Part::FilletBase* fillet, QWidget* parent, Qt::WFlags fl) + : QWidget(parent, fl), ui(new Ui_DlgFilletEdges()), d(new Private()) { ui->setupUi(this); @@ -205,9 +206,22 @@ DlgFilletEdges::DlgFilletEdges(Part::FilletBase* fillet, QWidget* parent, Qt::WF connect(model, SIGNAL(toggleCheckState(const QModelIndex&)), this, SLOT(toggleCheckState(const QModelIndex&))); model->insertColumns(0,3); - model->setHeaderData(0, Qt::Horizontal, tr("Edges to fillet"), Qt::DisplayRole); - model->setHeaderData(1, Qt::Horizontal, tr("Start radius"), Qt::DisplayRole); - model->setHeaderData(2, Qt::Horizontal, tr("End radius"), Qt::DisplayRole); + + d->filletType = type; + if (d->filletType == DlgFilletEdges::CHAMFER) { + ui->labelRadius->setText(tr("Length:")); + ui->filletType->setItemText(0, tr("Constant Length")); + ui->filletType->setItemText(1, tr("Variable Length")); + + model->setHeaderData(0, Qt::Horizontal, tr("Edges to chamfer"), Qt::DisplayRole); + model->setHeaderData(1, Qt::Horizontal, tr("Start length"), Qt::DisplayRole); + model->setHeaderData(2, Qt::Horizontal, tr("End length"), Qt::DisplayRole); + } + else { + model->setHeaderData(0, Qt::Horizontal, tr("Edges to fillet"), Qt::DisplayRole); + model->setHeaderData(1, Qt::Horizontal, tr("Start radius"), Qt::DisplayRole); + model->setHeaderData(2, Qt::Horizontal, tr("End radius"), Qt::DisplayRole); + } ui->treeView->setRootIsDecorated(false); ui->treeView->setItemDelegate(new FilletRadiusDelegate(this)); ui->treeView->setModel(model); @@ -657,12 +671,18 @@ void DlgFilletEdges::on_filletType_activated(int index) { QStandardItemModel *model = qobject_cast(ui->treeView->model()); if (index == 0) { - model->setHeaderData(1, Qt::Horizontal, tr("Radius"), Qt::DisplayRole); + if (d->filletType == DlgFilletEdges::CHAMFER) + model->setHeaderData(1, Qt::Horizontal, tr("Length"), Qt::DisplayRole); + else + model->setHeaderData(1, Qt::Horizontal, tr("Radius"), Qt::DisplayRole); ui->treeView->hideColumn(2); ui->filletEndRadius->hide(); } else { - model->setHeaderData(1, Qt::Horizontal, tr("Start radius"), Qt::DisplayRole); + if (d->filletType == DlgFilletEdges::CHAMFER) + model->setHeaderData(1, Qt::Horizontal, tr("Start length"), Qt::DisplayRole); + else + model->setHeaderData(1, Qt::Horizontal, tr("Start radius"), Qt::DisplayRole); ui->treeView->showColumn(2); ui->filletEndRadius->show(); } @@ -790,10 +810,10 @@ bool DlgFilletEdges::accept() // --------------------------------------- -FilletEdgesDialog::FilletEdgesDialog(Part::FilletBase* fillet, QWidget* parent, Qt::WFlags fl) +FilletEdgesDialog::FilletEdgesDialog(DlgFilletEdges::FilletType type, Part::FilletBase* fillet, QWidget* parent, Qt::WFlags fl) : QDialog(parent, fl) { - widget = new DlgFilletEdges(fillet, this); + widget = new DlgFilletEdges(type, fillet, this); this->setWindowTitle(widget->windowTitle()); QVBoxLayout* hboxLayout = new QVBoxLayout(this); @@ -821,7 +841,7 @@ void FilletEdgesDialog::accept() TaskFilletEdges::TaskFilletEdges(Part::Fillet* fillet) { - widget = new DlgFilletEdges(fillet); + widget = new DlgFilletEdges(DlgFilletEdges::FILLET, fillet); taskbox = new Gui::TaskView::TaskBox( Gui::BitmapFactory().pixmap("Part_Fillet"), widget->windowTitle(), true, 0); @@ -861,7 +881,7 @@ bool TaskFilletEdges::reject() /* TRANSLATOR PartGui::DlgChamferEdges */ DlgChamferEdges::DlgChamferEdges(Part::FilletBase* chamfer, QWidget* parent, Qt::WFlags fl) - : DlgFilletEdges(chamfer, parent, fl) + : DlgFilletEdges(DlgFilletEdges::CHAMFER, chamfer, parent, fl) { this->setWindowTitle(tr("Chamfer Edges")); } diff --git a/src/Mod/Part/Gui/DlgFilletEdges.h b/src/Mod/Part/Gui/DlgFilletEdges.h index 0fab0dbeb..ac376dcd6 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.h +++ b/src/Mod/Part/Gui/DlgFilletEdges.h @@ -70,13 +70,14 @@ Q_SIGNALS: void toggleCheckState(const QModelIndex&); }; -class DlgFilletEdgesP; class DlgFilletEdges : public QWidget, public Gui::SelectionObserver { Q_OBJECT public: - DlgFilletEdges(Part::FilletBase*, QWidget* parent = 0, Qt::WFlags fl = 0); + enum FilletType { FILLET, CHAMFER }; + + DlgFilletEdges(FilletType type, Part::FilletBase*, QWidget* parent = 0, Qt::WFlags fl = 0); ~DlgFilletEdges(); bool accept(); @@ -107,7 +108,8 @@ private Q_SLOTS: private: std::auto_ptr ui; - std::auto_ptr d; + class Private; + std::auto_ptr d; }; class FilletEdgesDialog : public QDialog @@ -115,7 +117,7 @@ class FilletEdgesDialog : public QDialog Q_OBJECT public: - FilletEdgesDialog(Part::FilletBase* fillet, QWidget* parent = 0, Qt::WFlags fl = 0); + FilletEdgesDialog(DlgFilletEdges::FilletType type, Part::FilletBase* fillet, QWidget* parent = 0, Qt::WFlags fl = 0); ~FilletEdgesDialog(); void accept(); diff --git a/src/Mod/Part/Gui/DlgFilletEdges.ui b/src/Mod/Part/Gui/DlgFilletEdges.ui index 9f2e4606a..0ad96ceac 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.ui +++ b/src/Mod/Part/Gui/DlgFilletEdges.ui @@ -91,7 +91,7 @@ 0
- + Radius: diff --git a/src/Mod/Part/Gui/DlgSettingsObjectColor.cpp b/src/Mod/Part/Gui/DlgSettingsObjectColor.cpp new file mode 100644 index 000000000..1ce9eb555 --- /dev/null +++ b/src/Mod/Part/Gui/DlgSettingsObjectColor.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (c) 2013 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_ +#endif + +#include "DlgSettingsObjectColor.h" +#include + +using namespace PartGui; + +/* TRANSLATOR PartGui::DlgSettingsObjectColor */ + +/** + * Constructs a DlgSettingsObjectColor which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + */ +DlgSettingsObjectColor::DlgSettingsObjectColor(QWidget* parent) + : PreferencePage(parent) +{ + this->setupUi(this); +} + +/** + * Destroys the object and frees any allocated resources + */ +DlgSettingsObjectColor::~DlgSettingsObjectColor() +{ + // no need to delete child widgets, Qt does it all for us +} + +void DlgSettingsObjectColor::saveSettings() +{ + CursorTextColor->onSave(); + EditedEdgeColor->onSave(); + EditedVertexColor->onSave(); + ConstructionColor->onSave(); + FullyConstrainedColor->onSave(); + BoundingBoxColor->onSave(); + DefaultShapeColor->onSave(); + DefaultShapeLineColor->onSave(); + DefaultShapeLineWidth->onSave(); +} + +void DlgSettingsObjectColor::loadSettings() +{ + CursorTextColor->onRestore(); + EditedEdgeColor->onRestore(); + EditedVertexColor->onRestore(); + ConstructionColor->onRestore(); + FullyConstrainedColor->onRestore(); + BoundingBoxColor->onRestore(); + DefaultShapeColor->onRestore(); + DefaultShapeLineColor->onRestore(); + DefaultShapeLineWidth->onRestore(); +} + +/** + * Sets the strings of the subwidgets using the current language. + */ +void DlgSettingsObjectColor::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + retranslateUi(this); + } + else { + QWidget::changeEvent(e); + } +} + +#include "moc_DlgSettingsObjectColor.cpp" + diff --git a/src/Mod/Part/Gui/DlgSettingsObjectColor.h b/src/Mod/Part/Gui/DlgSettingsObjectColor.h new file mode 100644 index 000000000..5d327eb7f --- /dev/null +++ b/src/Mod/Part/Gui/DlgSettingsObjectColor.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (c) 2013 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_DIALOG_DLGSETTINGSOBJECTCOLOR_H +#define PARTGUI_DIALOG_DLGSETTINGSOBJECTCOLOR_H + +#include "ui_DlgSettingsObjectColor.h" +#include + +namespace PartGui { + +/** + * The DlgSettingsObjectColor class implements a preference page to change color settings + * for data objects. + * @author Werner Mayer + */ +class DlgSettingsObjectColor : public Gui::Dialog::PreferencePage, public Ui_DlgSettingsObjectColor +{ + Q_OBJECT + +public: + DlgSettingsObjectColor(QWidget* parent = 0); + ~DlgSettingsObjectColor(); + + void saveSettings(); + void loadSettings(); + +protected: + void changeEvent(QEvent *e); +}; + +} // namespace Gui + +#endif // PARTGUI_DIALOG_DLGSETTINGSOBJECTCOLOR_H diff --git a/src/Mod/Part/Gui/DlgSettingsObjectColor.ui b/src/Mod/Part/Gui/DlgSettingsObjectColor.ui new file mode 100644 index 000000000..7913af994 --- /dev/null +++ b/src/Mod/Part/Gui/DlgSettingsObjectColor.ui @@ -0,0 +1,358 @@ + + + PartGui::DlgSettingsObjectColor + + + + 0 + 0 + 601 + 598 + + + + Object Colors + + + + 9 + + + 6 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Default colors + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + 6 + + + + + + 240 + 0 + + + + Edited edge color + + + + + + + Edited vertex color + + + + + + + Construction geometry + + + + + + + Fully constrained geometry + + + + + + + The color of construction geometry in edit mode + + + + 0 + 0 + 220 + + + + ConstructionColor + + + View + + + + + + + The color of fully constrained geometry in edit mode + + + + 0 + 255 + 0 + + + + FullyConstrainedColor + + + View + + + + + + + The color of vertices being edited + + + + 255 + 38 + 0 + + + + EditedVertexColor + + + View + + + + + + + The color of edges being edited + + + + 255 + 255 + 255 + + + + EditedEdgeColor + + + View + + + + + + + Cursor text color + + + + + + + + 0 + 0 + 255 + + + + CursorTextColor + + + View + + + + + + + Bounding box color + + + + + + + The color of bounding boxes in the 3D view + + + + 255 + 255 + 255 + + + + BoundingBoxColor + + + View + + + + + + + + + + + + 240 + 0 + + + + Default shape color + + + + + + + The default color for new shapes + + + + 204 + 204 + 204 + + + + DefaultShapeColor + + + View + + + + + + + + + + + + 182 + 0 + + + + Default line width and color + + + + + + + The default line color for new shapes + + + + 25 + 25 + 25 + + + + DefaultShapeLineColor + + + View + + + + + + + The default line thickness for new shapes + + + px + + + 2 + + + DefaultShapeLineWidth + + + View + + + + + + + + + + + + + Gui::ColorButton + QPushButton +
Gui/Widgets.h
+
+ + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
+ + Gui::PrefColorButton + Gui::ColorButton +
Gui/PrefWidgets.h
+
+
+ + DefaultShapeColor + DefaultShapeLineWidth + DefaultShapeLineColor + CursorTextColor + EditedEdgeColor + EditedVertexColor + ConstructionColor + FullyConstrainedColor + BoundingBoxColor + + + +
diff --git a/src/Mod/Part/Gui/TaskLoft.cpp b/src/Mod/Part/Gui/TaskLoft.cpp index 9fd33b247..6f4b5371e 100644 --- a/src/Mod/Part/Gui/TaskLoft.cpp +++ b/src/Mod/Part/Gui/TaskLoft.cpp @@ -133,7 +133,7 @@ bool LoftWidget::accept() int count = d->ui.selector->selectedTreeWidget()->topLevelItemCount(); if (count < 2) { - QMessageBox::critical(this, tr("Too few elements"), tr("At least two vertices, edges, wires or Faces are required.")); + QMessageBox::critical(this, tr("Too few elements"), tr("At least two vertices, edges, wires or faces are required.")); return false; } for (int i=0; iopenCommand("Loft"); Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); - doc->commitCommand(); doc->getDocument()->recompute(); + App::DocumentObject* obj = doc->getDocument()->getActiveObject(); + if (obj && !obj->isValid()) { + std::string msg = obj->getStatusString(); + doc->abortCommand(); + throw Base::Exception(msg); + } + doc->commitCommand(); } catch (const Base::Exception& e) { - Base::Console().Error("%s\n", e.what()); + QMessageBox::warning(this, tr("Input error"), QString::fromAscii(e.what())); return false; } diff --git a/src/Mod/Part/Gui/TaskSweep.cpp b/src/Mod/Part/Gui/TaskSweep.cpp index 9d0141ef3..fb1c899ab 100644 --- a/src/Mod/Part/Gui/TaskSweep.cpp +++ b/src/Mod/Part/Gui/TaskSweep.cpp @@ -182,11 +182,17 @@ bool SweepWidget::accept() 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(); + App::DocumentObject* obj = doc->getDocument()->getActiveObject(); + if (obj && !obj->isValid()) { + std::string msg = obj->getStatusString(); + doc->abortCommand(); + throw Base::Exception(msg); + } + doc->commitCommand(); } catch (const Base::Exception& e) { - Base::Console().Error("%s\n", e.what()); + QMessageBox::warning(this, tr("Input error"), QString::fromAscii(e.what())); return false; } diff --git a/src/Mod/Part/Gui/ViewProviderCompound.cpp b/src/Mod/Part/Gui/ViewProviderCompound.cpp new file mode 100644 index 000000000..3fccded18 --- /dev/null +++ b/src/Mod/Part/Gui/ViewProviderCompound.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (c) 2013 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 "ViewProviderCompound.h" +#include +#include + + +using namespace PartGui; + +PROPERTY_SOURCE(PartGui::ViewProviderCompound,PartGui::ViewProviderPart) + +ViewProviderCompound::ViewProviderCompound() +{ +} + +ViewProviderCompound::~ViewProviderCompound() +{ +} + +std::vector ViewProviderCompound::claimChildren(void) const +{ + return static_cast(getObject())->Links.getValues(); +} + +bool ViewProviderCompound::onDelete(const std::vector &) +{ + // get the input shapes + Part::Compound* pComp = static_cast(getObject()); + std::vector pLinks = pComp->Links.getValues(); + for (std::vector::iterator it = pLinks.begin(); it != pLinks.end(); ++it) { + if (*it) + Gui::Application::Instance->showViewProvider(*it); + } + + return true; +} + +void ViewProviderCompound::updateData(const App::Property* prop) +{ + PartGui::ViewProviderPart::updateData(prop); + if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) { + const std::vector& hist = static_cast + (prop)->getValues(); + Part::Compound* objComp = dynamic_cast(getObject()); + std::vector sources = objComp->Links.getValues(); + if (hist.size() != sources.size()) + return; + + const TopoDS_Shape& compShape = objComp->Shape.getValue(); + TopTools_IndexedMapOfShape compMap; + TopExp::MapShapes(compShape, TopAbs_FACE, compMap); + + std::vector compCol; + compCol.resize(compMap.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 baseCol = static_cast(vpBase)->DiffuseColor.getValues(); + if (baseCol.size() == baseMap.Extent()) { + applyColor(hist[index], baseCol, compCol); + setColor = true; + } + else if (!baseCol.empty() && baseCol[0] != this->ShapeColor.getValue()) { + baseCol.resize(baseMap.Extent(), baseCol[0]); + applyColor(hist[index], baseCol, compCol); + setColor = true; + } + } + + if (setColor) + this->DiffuseColor.setValues(compCol); + } + else if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) { + const std::vector& pBases = static_cast(prop)->getValues(); + for (std::vector::const_iterator it = pBases.begin(); it != pBases.end(); ++it) { + if (*it) Gui::Application::Instance->hideViewProvider(*it); + } + } +} diff --git a/src/Mod/Part/Gui/ViewProviderCompound.h b/src/Mod/Part/Gui/ViewProviderCompound.h new file mode 100644 index 000000000..1ec37b628 --- /dev/null +++ b/src/Mod/Part/Gui/ViewProviderCompound.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (c) 2013 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_VIEWPROVIDERCOMPOUND_H +#define PARTGUI_VIEWPROVIDERCOMPOUND_H + +#include "ViewProvider.h" + + +namespace PartGui { + +class PartGuiExport ViewProviderCompound : public ViewProviderPart +{ + PROPERTY_HEADER(PartGui::ViewProviderCompound); + +public: + /// constructor + ViewProviderCompound(); + /// destructor + virtual ~ViewProviderCompound(); + std::vector claimChildren() const; + bool onDelete(const std::vector &); + +protected: + void updateData(const App::Property*); +}; + +} // namespace PartGui + + +#endif // PARTGUI_VIEWPROVIDERCOMPOUND_H diff --git a/src/Mod/Part/Gui/Workbench.cpp b/src/Mod/Part/Gui/Workbench.cpp index 9d95ac40a..e827fe420 100644 --- a/src/Mod/Part/Gui/Workbench.cpp +++ b/src/Mod/Part/Gui/Workbench.cpp @@ -63,14 +63,19 @@ Gui::MenuItem* Workbench::setupMenuBar() const *prim << "Part_Box" << "Part_Cylinder" << "Part_Sphere" << "Part_Cone" << "Part_Torus"; + Gui::MenuItem* bop = new Gui::MenuItem; + bop->setCommand("Boolean"); + *bop << "Part_Boolean" << "Part_Cut" << "Part_Fuse" << "Part_Common"; + Gui::MenuItem* part = new Gui::MenuItem; root->insertItem(item, part); part->setCommand("&Part"); *part << "Part_Import" << "Part_Export" << "Separator"; *part << prim << "Part_Primitives" << "Part_Builder" << "Separator" << "Part_ShapeFromMesh" << "Part_MakeSolid" << "Part_ReverseShape" - << "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry" << "Separator" - << "Part_Boolean" << "Part_CrossSections" << "Part_Extrude" + << "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry" + << "Separator" << bop << "Separator" + << "Part_CrossSections" << "Part_Compound" << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer" << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" << "Part_Offset" << "Part_Thickness"; diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 0e2027160..e903537a5 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include @@ -70,7 +71,8 @@ using namespace PartDesign; // sort bounding boxes according to diagonal length -class SketchBased::Wire_Compare { +class SketchBased::Wire_Compare : public std::binary_function { public: bool operator() (const TopoDS_Wire& w1, const TopoDS_Wire& w2) { @@ -315,7 +317,11 @@ TopoDS_Face SketchBased::validateFace(const TopoDS_Face& face) const fix.Perform(); fix.FixWireTool()->Perform(); fix.FixFaceTool()->Perform(); - return TopoDS::Face(fix.Shape()); + TopoDS_Face fixedFace = TopoDS::Face(fix.Shape()); + aChecker.Init(fixedFace); + if (!aChecker.IsValid()) + Standard_Failure::Raise("Failed to validate broken face"); + return fixedFace; } return mkFace.Face(); } @@ -362,10 +368,28 @@ TopoDS_Shape SketchBased::makeFace(const std::vector& w) const //FIXME: Need a safe method to sort wire that the outermost one comes last // Currently it's done with the diagonal lengths of the bounding boxes +#if 1 std::vector wires = w; std::sort(wires.begin(), wires.end(), Wire_Compare()); std::list wire_list; wire_list.insert(wire_list.begin(), wires.rbegin(), wires.rend()); +#else + //bug #0001133: try alternative sort algorithm + std::list unsorted_wire_list; + unsorted_wire_list.insert(unsorted_wire_list.begin(), w.begin(), w.end()); + std::list wire_list; + Wire_Compare wc; + while (!unsorted_wire_list.empty()) { + std::list::iterator w_ref = unsorted_wire_list.begin(); + std::list::iterator w_it = unsorted_wire_list.begin(); + for (++w_it; w_it != unsorted_wire_list.end(); ++w_it) { + if (wc(*w_ref, *w_it)) + w_ref = w_it; + } + wire_list.push_back(*w_ref); + unsorted_wire_list.erase(w_ref); + } +#endif // separate the wires into several independent faces std::list< std::list > sep_wire_list; diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 0588b2785..26060a3bb 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include +# include #endif #include "ui_TaskLinearPatternParameters.h" @@ -93,6 +94,12 @@ TaskLinearPatternParameters::TaskLinearPatternParameters(TaskMultiTransformParam void TaskLinearPatternParameters::setupUI() { + updateViewTimer = new QTimer(this); + updateViewTimer->setSingleShot(true); + updateViewTimer->setInterval(getUpdateViewTimeout()); + + connect(updateViewTimer, SIGNAL(timeout()), + this, SLOT(onUpdateViewTimer())); connect(ui->comboDirection, SIGNAL(activated(int)), this, SLOT(onDirectionChanged(int))); connect(ui->checkReverse, SIGNAL(toggled(bool)), @@ -188,6 +195,16 @@ void TaskLinearPatternParameters::updateUI() blockUpdate = false; } +void TaskLinearPatternParameters::onUpdateViewTimer() +{ + recomputeFeature(); +} + +void TaskLinearPatternParameters::kickUpdateViewTimer() const +{ + updateViewTimer->start(); +} + void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { @@ -237,8 +254,7 @@ void TaskLinearPatternParameters::onCheckReverse(const bool on) { pcLinearPattern->Reversed.setValue(on); exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskLinearPatternParameters::onLength(const double l) { @@ -248,8 +264,7 @@ void TaskLinearPatternParameters::onLength(const double l) { pcLinearPattern->Length.setValue(l); exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskLinearPatternParameters::onOccurrences(const int n) { @@ -259,8 +274,7 @@ void TaskLinearPatternParameters::onOccurrences(const int n) { pcLinearPattern->Occurrences.setValue(n); exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskLinearPatternParameters::onDirectionChanged(int num) { @@ -297,8 +311,7 @@ void TaskLinearPatternParameters::onDirectionChanged(int num) { else if (num == maxcount) exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskLinearPatternParameters::onUpdateView(bool on) diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h index a76e94668..ae964d12f 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h @@ -31,6 +31,7 @@ #include "TaskTransformedParameters.h" #include "ViewProviderLinearPattern.h" +class QTimer; class Ui_TaskLinearPatternParameters; namespace App { @@ -62,6 +63,7 @@ public: const unsigned getOccurrences(void) const; private Q_SLOTS: + void onUpdateViewTimer(); void onDirectionChanged(int num); void onCheckReverse(const bool on); void onLength(const double l); @@ -75,9 +77,11 @@ protected: private: void setupUI(); void updateUI(); + void kickUpdateViewTimer() const; private: Ui_TaskLinearPatternParameters* ui; + QTimer* updateViewTimer; }; diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index 59fda6d98..a2b2ff1c2 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -245,7 +245,6 @@ void TaskMirroredParameters::onPlaneChanged(int num) { else if (num == maxcount) exitSelectionMode(); - updateUI(); recomputeFeature(); } diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index e63051a7b..170a74540 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include +# include #endif #include "ui_TaskPolarPatternParameters.h" @@ -93,6 +94,12 @@ TaskPolarPatternParameters::TaskPolarPatternParameters(TaskMultiTransformParamet void TaskPolarPatternParameters::setupUI() { + updateViewTimer = new QTimer(this); + updateViewTimer->setSingleShot(true); + updateViewTimer->setInterval(getUpdateViewTimeout()); + + connect(updateViewTimer, SIGNAL(timeout()), + this, SLOT(onUpdateViewTimer())); connect(ui->comboAxis, SIGNAL(activated(int)), this, SLOT(onAxisChanged(int))); connect(ui->checkReverse, SIGNAL(toggled(bool)), @@ -169,6 +176,16 @@ void TaskPolarPatternParameters::updateUI() blockUpdate = false; } +void TaskPolarPatternParameters::onUpdateViewTimer() +{ + recomputeFeature(); +} + +void TaskPolarPatternParameters::kickUpdateViewTimer() const +{ + updateViewTimer->start(); +} + void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { @@ -213,8 +230,7 @@ void TaskPolarPatternParameters::onCheckReverse(const bool on) { pcPolarPattern->Reversed.setValue(on); exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskPolarPatternParameters::onAngle(const double a) { @@ -224,8 +240,7 @@ void TaskPolarPatternParameters::onAngle(const double a) { pcPolarPattern->Angle.setValue(a); exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskPolarPatternParameters::onOccurrences(const int n) { @@ -235,8 +250,7 @@ void TaskPolarPatternParameters::onOccurrences(const int n) { pcPolarPattern->Occurrences.setValue(n); exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskPolarPatternParameters::onAxisChanged(int num) { @@ -259,8 +273,7 @@ void TaskPolarPatternParameters::onAxisChanged(int num) { else if (num == 1) exitSelectionMode(); - updateUI(); - recomputeFeature(); + kickUpdateViewTimer(); } void TaskPolarPatternParameters::onUpdateView(bool on) diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h index 9d23bebff..1fb90e03a 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h @@ -31,6 +31,7 @@ #include "TaskTransformedParameters.h" #include "ViewProviderPolarPattern.h" +class QTimer; class Ui_TaskPolarPatternParameters; namespace App { @@ -63,6 +64,7 @@ public: const unsigned getOccurrences(void) const; private Q_SLOTS: + void onUpdateViewTimer(); void onAxisChanged(int num); void onCheckReverse(const bool on); void onAngle(const double a); @@ -76,9 +78,11 @@ protected: private: void setupUI(); void updateUI(); + void kickUpdateViewTimer() const; private: Ui_TaskPolarPatternParameters* ui; + QTimer* updateViewTimer; }; diff --git a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp index 81caea3dc..db44d0186 100644 --- a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp @@ -147,7 +147,6 @@ void TaskScaledParameters::onFactor(const double f) { return; PartDesign::Scaled* pcScaled = static_cast(getObject()); pcScaled->Factor.setValue(f); - updateUI(); recomputeFeature(); } @@ -156,7 +155,6 @@ void TaskScaledParameters::onOccurrences(const int n) { return; PartDesign::Scaled* pcScaled = static_cast(getObject()); pcScaled->Occurrences.setValue(n); - updateUI(); recomputeFeature(); } diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index 0be5b37f8..f525bbac0 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -82,6 +82,16 @@ TaskTransformedParameters::~TaskTransformedParameters() Gui::Selection().rmvSelectionGate(); } +bool TaskTransformedParameters::isViewUpdated() const +{ + return (blockUpdate == false); +} + +int TaskTransformedParameters::getUpdateViewTimeout() const +{ + return 500; +} + const bool TaskTransformedParameters::originalSelected(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection && originalSelectionMode) { diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index 2dad89efb..b6c01ba8c 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -85,6 +85,9 @@ protected: void showOriginals(); void addReferenceSelectionGate(bool edge, bool face); + bool isViewUpdated() const; + int getUpdateViewTimeout() const; + protected: virtual void changeEvent(QEvent *e) = 0; virtual void onSelectionChanged(const Gui::SelectionChanges& msg) = 0; diff --git a/src/Mod/Points/App/PointsAlgos.h b/src/Mod/Points/App/PointsAlgos.h index 5c82b65f6..119f96bbd 100644 --- a/src/Mod/Points/App/PointsAlgos.h +++ b/src/Mod/Points/App/PointsAlgos.h @@ -29,7 +29,7 @@ namespace Points { -/** The Points algorithems container class +/** The Points algorithms container class */ class PointsExport PointsAlgos { diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 7ed811a76..1429d08ef 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -24,6 +24,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include +# include # include #endif @@ -1922,6 +1924,8 @@ TopoShape Sketch::toShape(void) const } } + // FIXME: Use ShapeAnalysis_FreeBounds::ConnectEdgesToWires() as an alternative + // // sort them together to wires while (edge_list.size() > 0) { BRepBuilderAPI_MakeWire mkWire; @@ -1947,7 +1951,15 @@ TopoShape Sketch::toShape(void) const } } while (found); - wires.push_back(new_wire); + + // Fix any topological issues of the wire + ShapeFix_Wire aFix; + aFix.SetPrecision(Precision::Confusion()); + aFix.Load(new_wire); + aFix.FixReorder(); + aFix.FixConnected(); + aFix.FixClosed(); + wires.push_back(aFix.Wire()); } if (wires.size() == 1) result = *wires.begin(); diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index a5c3e6f19..851cb2443 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -80,6 +80,8 @@ public: /// get the geometry as python objects Py::Tuple getPyGeometry(void) const; + /// retrieves the index of a point + int getPointId(int geoId, PointPos pos) const; /// retrieves a point Base::Vector3d getPoint(int geoId, PointPos pos); @@ -220,8 +222,6 @@ protected: bool isFine; private: - /// retrieves the index of a point - int getPointId(int geoId, PointPos pos) const; bool updateGeometry(void); diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 2e972531e..d7b299d9b 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -1393,12 +1393,12 @@ void SketchObject::rebuildVertexIndex(void) VertexId2GeoId.push_back(i); VertexId2PosId.push_back(mid); } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { - VertexId2GeoId.push_back(i); - VertexId2PosId.push_back(mid); VertexId2GeoId.push_back(i); VertexId2PosId.push_back(start); VertexId2GeoId.push_back(i); VertexId2PosId.push_back(end); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); } } } diff --git a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp index cad8b9e76..c6e55e5ad 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.cpp @@ -53,6 +53,10 @@ TaskSketcherGeneral::TaskSketcherGeneral(ViewProviderSketch *sketchView) this->groupLayout()->addWidget(proxy); // connecting the needed signals + QObject::connect( + ui->checkBoxShowGrid, SIGNAL(toggled(bool)), + this , SLOT(toggleGridView(bool)) + ); QObject::connect( ui->checkBoxGridSnap, SIGNAL(stateChanged(int)), this , SLOT (toggleGridSnap(int)) @@ -69,14 +73,29 @@ TaskSketcherGeneral::TaskSketcherGeneral(ViewProviderSketch *sketchView) ); Gui::Selection().Attach(this); + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Sketcher/General"); + ui->checkBoxShowGrid->setChecked(hGrp->GetBool("ShowGrid", true)); } TaskSketcherGeneral::~TaskSketcherGeneral() { + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Sketcher/General"); + hGrp->SetBool("ShowGrid", ui->checkBoxShowGrid->isChecked()); delete ui; Gui::Selection().Detach(this); } +void TaskSketcherGeneral::toggleGridView(bool on) +{ + ui->label->setEnabled(on); + ui->comboBoxGridSize->setEnabled(on); + ui->checkBoxGridSnap->setEnabled(on); + sketchView->ShowGrid.setValue(on); +} + void TaskSketcherGeneral::setGridSize(const QString& val) { float gridSize = (float) Base::UnitsApi::translateUnit(val); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.h b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.h index 57d9f60a8..b9528c9ba 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.h @@ -52,6 +52,7 @@ Q_SIGNALS: void setGridSnap(int Type); public Q_SLOTS: + void toggleGridView(bool on); void setGridSize(const QString& val); void toggleGridSnap(int state); void toggleAutoconstraints(int state); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.ui b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.ui index 75bb39595..2d375613b 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherGeneral.ui +++ b/src/Mod/Sketcher/Gui/TaskSketcherGeneral.ui @@ -7,13 +7,23 @@ 0 0 153 - 88 + 112 Form + + + + Show grid + + + true + + + diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 1d415ec10..a4c3ccbfb 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -129,6 +129,7 @@ SbVec2s ViewProviderSketch::newCursorPos; struct EditData { EditData(): sketchHandler(0), + editDatumDialog(false), DragPoint(-1), DragCurve(-1), DragConstraint(-1), @@ -150,6 +151,7 @@ struct EditData { // pointer to the active handler for new sketch objects DrawSketchHandler *sketchHandler; + bool editDatumDialog; // dragged point int DragPoint; @@ -289,6 +291,37 @@ bool ViewProviderSketch::keyPressed(bool pressed, int key) edit->sketchHandler->quit(); return true; } + if (edit && edit->editDatumDialog) { + edit->editDatumDialog = false; + return true; + } + if (edit && edit->DragConstraint >= 0) { + if (!pressed) { + edit->DragConstraint = -1; + } + return true; + } + if (edit && edit->DragCurve >= 0) { + if (!pressed) { + getSketchObject()->movePoint(edit->DragCurve, Sketcher::none, Base::Vector3d(0,0,0), true); + edit->DragCurve = -1; + resetPositionText(); + Mode = STATUS_NONE; + } + return true; + } + if (edit && edit->DragPoint >= 0) { + if (!pressed) { + int GeoId; + Sketcher::PointPos PosId; + getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId); + getSketchObject()->movePoint(GeoId, PosId, Base::Vector3d(0,0,0), true); + edit->DragPoint = -1; + resetPositionText(); + Mode = STATUS_NONE; + } + return true; + } return false; } default: @@ -798,6 +831,7 @@ void ViewProviderSketch::editDoubleClicked(void) EditDatumDialog * editDatumDialog = new EditDatumDialog(this, edit->PreselectConstraint); SoIdleSensor* sensor = new SoIdleSensor(EditDatumDialog::run, editDatumDialog); sensor->schedule(); + edit->editDatumDialog = true; // avoid to double handle "ESC" } } } @@ -1589,9 +1623,9 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & // Check if arc lies inside box selection const Part::GeomArcOfCircle *aoc = dynamic_cast(*it); - pnt0 = aoc->getCenter(); - pnt1 = aoc->getStartPoint(); - pnt2 = aoc->getEndPoint(); + pnt0 = aoc->getStartPoint(); + pnt1 = aoc->getEndPoint(); + pnt2 = aoc->getCenter(); VertexId += 3; Plm.multVec(pnt0, pnt0); @@ -1601,7 +1635,8 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & pnt1 = proj(pnt1); pnt2 = proj(pnt2); - if (polygon.Contains(Base::Vector2D(pnt0.x, pnt0.y))) { + bool pnt0Inside = polygon.Contains(Base::Vector2D(pnt0.x, pnt0.y)); + if (pnt0Inside) { std::stringstream ss; ss << "Vertex" << VertexId - 2; Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); @@ -1614,14 +1649,13 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); } - bool pnt2Inside = polygon.Contains(Base::Vector2D(pnt2.x, pnt2.y)); - if (pnt2Inside) { + if (polygon.Contains(Base::Vector2D(pnt2.x, pnt2.y))) { std::stringstream ss; ss << "Vertex" << VertexId; Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); } - if (pnt1Inside && pnt2Inside) { + if (pnt0Inside && pnt1Inside) { double startangle, endangle; aoc->getRange(startangle, endangle); if (startangle > endangle) // if arc is reversed @@ -1736,41 +1770,52 @@ void ViewProviderSketch::updateColor(void) SoSeparator *s = dynamic_cast(edit->constrGroup->getChild(i)); // Check Constraint Type - ConstraintType type = getSketchObject()->Constraints.getValues()[i]->Type; + Sketcher::Constraint* constraint = getSketchObject()->Constraints.getValues()[i]; + ConstraintType type = constraint->Type; bool hasDatumLabel = (type == Sketcher::Angle || type == Sketcher::Radius || type == Sketcher::Symmetric || type == Sketcher::Distance || - type == Sketcher::DistanceX || type == Sketcher::DistanceY); + type == Sketcher::DistanceX || + type == Sketcher::DistanceY); // Non DatumLabel Nodes will have a material excluding coincident bool hasMaterial = false; SoMaterial *m; if (!hasDatumLabel && type != Sketcher::Coincident) { - hasMaterial = true; - m = dynamic_cast(s->getChild(0)); + hasMaterial = true; + m = dynamic_cast(s->getChild(0)); } if (edit->SelConstraintSet.find(i) != edit->SelConstraintSet.end()) { if (hasDatumLabel) { SoDatumLabel *l = dynamic_cast(s->getChild(0)); l->textColor = SelectColor; - } else if (hasMaterial) - m->diffuseColor = SelectColor; + } else if (hasMaterial) { + m->diffuseColor = SelectColor; + } else if (type == Sketcher::Coincident) { + int index; + index = edit->ActSketch.getPointId(constraint->First, constraint->FirstPos) + 1; + if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; + index = edit->ActSketch.getPointId(constraint->Second, constraint->SecondPos) + 1; + if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; + } } else if (edit->PreselectConstraint == i) { if (hasDatumLabel) { SoDatumLabel *l = dynamic_cast(s->getChild(0)); l->textColor = PreselectColor; - } else if (hasMaterial) - m->diffuseColor = PreselectColor; + } else if (hasMaterial) { + m->diffuseColor = PreselectColor; + } } else { if (hasDatumLabel) { SoDatumLabel *l = dynamic_cast(s->getChild(0)); l->textColor = ConstrDimColor; - } else if (hasMaterial) - m->diffuseColor = ConstrDimColor; + } else if (hasMaterial) { + m->diffuseColor = ConstrDimColor; + } } } @@ -2027,9 +2072,9 @@ void ViewProviderSketch::draw(bool temp) Index.push_back(countSegments+1); edit->CurvIdToGeoId.push_back(GeoId); - Points.push_back(center); Points.push_back(start); Points.push_back(end); + Points.push_back(center); } else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline const Part::GeomBSplineCurve *spline = dynamic_cast(*it); diff --git a/src/Mod/Spreadsheet/CMakeLists.txt b/src/Mod/Spreadsheet/CMakeLists.txt new file mode 100644 index 000000000..1a5068574 --- /dev/null +++ b/src/Mod/Spreadsheet/CMakeLists.txt @@ -0,0 +1,21 @@ + +SET(Spreadsheet_SRCS + Init.py + InitGui.py + Spreadsheet.py + Spreadsheet_rc.py +) +SOURCE_GROUP("" FILES ${Spreadsheet_SRCS}) + +SET(all_files ${Spreadsheet_SRCS}) + +ADD_CUSTOM_TARGET(Spreadsheet ALL + SOURCES ${all_files} +) + +fc_copy_sources(Spreadsheet "${CMAKE_BINARY_DIR}/Mod/Spreadsheet" ${all_files}) + +INSTALL( + FILES ${Spreadsheet_SRCS} + DESTINATION Mod/Spreadsheet +) diff --git a/src/Mod/Spreadsheet/Init.py b/src/Mod/Spreadsheet/Init.py new file mode 100644 index 000000000..2963cfb51 --- /dev/null +++ b/src/Mod/Spreadsheet/Init.py @@ -0,0 +1,32 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2013 - 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 * +#* * +#*************************************************************************** + +# Get the Parameter Group of this module +ParGrp = App.ParamGet("System parameter:Modules").GetGroup("Spreadsheet") + +# Set the needed information +ParGrp.SetString("HelpIndex","http://free-cad.sf.net") + +# Supported file types +FreeCAD.addImportType("Spreadsheet (*.csv)","Spreadsheet") +FreeCAD.addExportType("Spreadsheet (*.csv)","Spreadsheet") + diff --git a/src/Mod/Spreadsheet/InitGui.py b/src/Mod/Spreadsheet/InitGui.py new file mode 100644 index 000000000..7bd9f8109 --- /dev/null +++ b/src/Mod/Spreadsheet/InitGui.py @@ -0,0 +1,75 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2013 - 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 * +#* * +#*************************************************************************** + +class SpreadsheetWorkbench(Workbench): + "Spreadsheet workbench object" + Icon = """ + /* XPM */ + static char * Spreadsheet_xpm[] = { + "16 16 5 1", + " c None", + ". c #151614", + "+ c #575956", + "@ c #969895", + "# c #F7F9F6", + " ", + " ", + " ...............", + ".@##@+########@.", + ".+@@+.@@@@@@@@+.", + "..+++.+++++++++.", + ".@##@+########@.", + ".+@@+.@@@@@@@@+.", + "..+++.+++++++++.", + ".@##@+########@.", + ".+@@+.@@@@@@@@+.", + "..+++.+++++++++.", + ".@##@+########@.", + "..+++.+++++++++.", + " ", + " "};""" + + MenuText = "Spreadsheet" + ToolTip = "Spreadsheet workbench" + + def Initialize(self): + import Spreadsheet,Spreadsheet_rc + from DraftTools import translate + commands = ["Spreadsheet_Create","Spreadsheet_Controller"] + self.appendToolbar(str(translate("Spreadsheet","Spreadsheet tools")),commands) + self.appendMenu(str(translate("Spreadsheet","&Spreadsheet")),commands) + FreeCADGui.addIconPath(":/icons") + FreeCADGui.addLanguagePath(":/translations") + Log ('Loading Spreadsheet module... done\n') + + def Activated(self): + Msg("Spreadsheet workbench activated\n") + + def Deactivated(self): + Msg("Spreadsheet workbench deactivated\n") + + def GetClassName(self): + return "Gui::PythonWorkbench" + +FreeCADGui.addWorkbench(SpreadsheetWorkbench) + + diff --git a/src/Mod/Spreadsheet/Resources/Spreadsheet.qrc b/src/Mod/Spreadsheet/Resources/Spreadsheet.qrc new file mode 100644 index 000000000..1ef25a0d4 --- /dev/null +++ b/src/Mod/Spreadsheet/Resources/Spreadsheet.qrc @@ -0,0 +1,6 @@ + + + icons/Spreadsheet.svg + icons/SpreadsheetController.svg + + diff --git a/src/Mod/Spreadsheet/Resources/icons/Spreadsheet.svg b/src/Mod/Spreadsheet/Resources/icons/Spreadsheet.svg new file mode 100644 index 000000000..9249d108a --- /dev/null +++ b/src/Mod/Spreadsheet/Resources/icons/Spreadsheet.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/Mod/Spreadsheet/Resources/icons/SpreadsheetController.svg b/src/Mod/Spreadsheet/Resources/icons/SpreadsheetController.svg new file mode 100644 index 000000000..b0170884b --- /dev/null +++ b/src/Mod/Spreadsheet/Resources/icons/SpreadsheetController.svg @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Spreadsheet/Spreadsheet.py b/src/Mod/Spreadsheet/Spreadsheet.py new file mode 100644 index 000000000..bf2c054e8 --- /dev/null +++ b/src/Mod/Spreadsheet/Spreadsheet.py @@ -0,0 +1,873 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2013 - 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 re, math, FreeCAD, FreeCADGui +from PyQt4 import QtCore,QtGui +DEBUG = True # set to True to show debug messages + +if open.__module__ == '__builtin__': + pyopen = open # because we'll redefine open below + +class MathParser: + "A math expression parser" + # code adapted from http://www.nerdparadise.com/tech/python/parsemath/ + def __init__(self, string, vars={}): + self.string = string + self.index = 0 + self.vars = { + 'pi' : math.pi, + 'e' : math.e + } + for var in vars.keys(): + if self.vars.get(var) != None: + raise Exception("Cannot redefine the value of " + var) + self.vars[var] = vars[var] + + def getValue(self): + value = self.parseExpression() + self.skipWhitespace() + if self.hasNext(): + raise Exception( + "Unexpected character found: '" + + self.peek() + + "' at index " + + str(self.index)) + return value + + def peek(self): + return self.string[self.index:self.index + 1] + + def hasNext(self): + return self.index < len(self.string) + + def skipWhitespace(self): + while self.hasNext(): + if self.peek() in ' \t\n\r': + self.index += 1 + else: + return + + def parseExpression(self): + return self.parseAddition() + + def parseAddition(self): + values = [self.parseMultiplication()] + while True: + self.skipWhitespace() + char = self.peek() + if char == '+': + self.index += 1 + values.append(self.parseMultiplication()) + elif char == '-': + self.index += 1 + values.append(-1 * self.parseMultiplication()) + else: + break + return sum(values) + + def parseMultiplication(self): + values = [self.parseParenthesis()] + while True: + self.skipWhitespace() + char = self.peek() + if char == '*': + self.index += 1 + values.append(self.parseParenthesis()) + elif char == '/': + div_index = self.index + self.index += 1 + denominator = self.parseParenthesis() + if denominator == 0: + raise Exception( + "Division by 0 kills baby whales (occured at index " + + str(div_index) + + ")") + values.append(1.0 / denominator) + else: + break + value = 1.0 + for factor in values: + value *= factor + return value + + def parseParenthesis(self): + self.skipWhitespace() + char = self.peek() + if char == '(': + self.index += 1 + value = self.parseExpression() + self.skipWhitespace() + if self.peek() != ')': + raise Exception( + "No closing parenthesis found at character " + + str(self.index)) + self.index += 1 + return value + else: + return self.parseNegative() + + def parseNegative(self): + self.skipWhitespace() + char = self.peek() + if char == '-': + self.index += 1 + return -1 * self.parseParenthesis() + else: + return self.parseValue() + + def parseValue(self): + self.skipWhitespace() + char = self.peek() + if char in '0123456789.': + return self.parseNumber() + else: + return self.parseVariable() + + def parseVariable(self): + self.skipWhitespace() + var = '' + while self.hasNext(): + char = self.peek() + if char.lower() in '_abcdefghijklmnopqrstuvwxyz0123456789': + var += char + self.index += 1 + else: + break + + value = self.vars.get(var, None) + if value == None: + raise Exception( + "Unrecognized variable: '" + + var + + "'") + return float(value) + + def parseNumber(self): + self.skipWhitespace() + strValue = '' + decimal_found = False + char = '' + + while self.hasNext(): + char = self.peek() + if char == '.': + if decimal_found: + raise Exception( + "Found an extra period in a number at character " + + str(self.index) + + ". Are you European?") + decimal_found = True + strValue += '.' + elif char in '0123456789': + strValue += char + else: + break + self.index += 1 + + if len(strValue) == 0: + if char == '': + raise Exception("Unexpected end found") + else: + raise Exception( + "I was expecting to find a number at character " + + str(self.index) + + " but instead I found a '" + + char + + "'. What's up with that?") + + return float(strValue) + +class Spreadsheet: + """An object representing a spreadsheet. Can be used as a + FreeCAD object or as a standalone python object. + Cells of the spreadsheet can be got/set as arguments, as: + + myspreadsheet = Spreadsheet() + myspreadsheet.a1 = 54 + print(myspreadsheet.a1) + myspreadsheet.a2 = "My text" + myspreadsheet.b1 = "=a1*3" + print(myspreadsheet.b1) + + The cell names are case-insensitive (a1 = A1) + """ + + def __init__(self,obj=None): + if obj: + obj.Proxy = self + obj.addProperty("App::PropertyLinkList","Controllers","Base","Cell controllers of this object") + self._cells = {} # this stores cell contents + self._relations = {} # this stores relations - currently not used + self.cols = [] # this stores filled columns + self.rows = [] # this stores filed rows + self.Type = "Spreadsheet" + + def __repr__(self): + return "Spreadsheet object containing " + str(len(self._cells)) + " cells" + + def __setattr__(self, key, value): + if self.isKey(key): + key = key.lower() + if DEBUG: print "Setting key ",key," to value ",value + if (value == "") or (value == None): + # remove cell + if key in self._cells.keys(): + del self._cells[key] + else: + # add cell + self._cells[key] = value + if value: + if self.isFunction(value): + self._updateDependencies(key,value) + c,r = self.splitKey(key) + if not c in self.cols: + self.cols.append(c) + self.cols.sort() + if not r in self.rows: + self.rows.append(r) + self.rows.sort() + else: + self.__dict__.__setitem__(key,value) + + def __getattr__(self, key): + if key.lower() in self._cells: + key = key.lower() + if self.isFunction(self._cells[key]): + try: + e = self.evaluate(key) + except: + print "Spreadsheet: Error evaluating formula" + return None + else: + return e + else: + return self._cells[key] + else: + return self.__dict__.__getitem__(key) + + def __getstate__(self): + self._cells["Type"] = self.Type + return self._cells + + def __setstate__(self,state): + if state: + self._cells = state + # extracting Type + if "Type" in self._cells.keys(): + self.Type = self._cells["Type"] + del self._cells["Type"] + # updating relation tables + self.rows = [] + self.cols = [] + self._relations = {} + for key in self._cells.keys(): + c,r = self.splitKey(key) + if not r in self.rows: + self.rows.append(r) + self.rows.sort() + if not c in self.cols: + self.cols.append(c) + self.cols.sort() + if self.isFunction(key): + self._updateDependencies(key) + + def _updateDependencies(self,key,value=None): + "search for ancestors in the value and updates the table" + ancestors = [] + if not value: + value = self._cells[key] + for v in re.findall(r"[\w']+",value): + if self.isKey(v): + ancestors.append(v) + for a in ancestors: + if a in self._relations: + if not key in self._relations[a]: + self._relations[a].append(key) + else: + self._relations[a] = [key] + + def execute(self,obj): + self.setControlledCells(obj) + + def isFunction(self,key): + "isFunction(cell): returns True if the given cell or value is a function" + if str(key).lower() in self._cells: + key = key.lower() + if str(self._cells[key])[0] == "=": + return True + elif str(key)[0] == "=": + return True + else: + return False + + def isNumeric(self,key): + "isNumeric(cell): returns True if the given cell returns a number" + key = key.lower() + if self.isFunction(key): + res = self.evaluate(key) + else: + res = self._cells[key] + if isinstance(res,float) or isinstance(res,int): + return True + else: + return False + + def isKey(self,value): + "isKey(val): returns True if the given value is a valid cell number" + allowMoreThanOneLetter = False + al = False + nu = False + for v in value: + if not v.isalnum(): + return False + elif not al: + if v.isalpha(): + al = True + else: + return False + else: + if not nu: + # forbidden to set items at row 0 + if v == "0": + return False + if v.isalpha(): + if not allowMoreThanOneLetter: + return False + elif nu: + return False + elif v.isdigit(): + nu = True + if not nu: + return False + return True + + def splitKey(self,key): + "splitKey(cell): splits a key between column and row" + c = '' + r = '' + for ch in key: + if ch.isalpha(): + c += ch + else: + r += ch + return c,r + + def getFunction(self,key): + "getFunction(cell): returns the function contained in the given cell, instead of the value" + key = key.lower() + if key in self._cells: + return self._cells[key] + else: + return None + + def getSize(self): + "getSize(): returns a tuple with number of columns and rows of this spreadsheet" + return (len(self.columns),len(self.rows)) + + def getCells(self,index): + "getCells(index): returns the cells from the given column of row number" + cells = {} + for k in self._cells.keys(): + c,r = self.splitKey(k) + if index in [c,r]: + cells[k] = self._cells[k] + return cells + + def evaluate(self,key): + "evaluate(key): evaluates the given formula" + key = key.lower() + elts = re.split(r'(\W+)',self._cells[key][1:]) + result = "" + for e in elts: + if self.isKey(e): + if self.isFunction(e): + if self.isNumeric(e): + result += str(self.evaluate(e)) + else: + print "Spreadsheet: Error evaluating formula" + return + elif self.isNumeric(e): + result += str(self._cells[e.lower()]) + else: + result += e + if DEBUG: print "Evaluating ",result + try: + p = MathParser(result) + result = p.getValue() + except Exception as (ex): + msg = ex.message + raise Exception(msg) + return result + + def setControlledCells(self,obj): + "Fills the cells that are controlled by a controller" + if obj: + if hasattr(obj,"Controllers"): + for co in obj.Controllers: + co.Proxy.setCells(co,obj) + + def getControlledCells(self,obj): + "returns a list of cells managed by controllers" + cells = [] + if hasattr(obj,"Controllers"): + for c in obj.Controllers: + cells.extend(c.Proxy.getCells(c,obj)) + return cells + + +class ViewProviderSpreadsheet(object): + def __init__(self, vobj): + vobj.Proxy = self + + def getIcon(self): + import Spreadsheet_rc + return ":/icons/Spreadsheet.svg" + + def attach(self,vobj): + self.Object = vobj.Object + + def setEdit(self,vobj,mode): + if hasattr(self,"editor"): + pass + else: + self.editor = SpreadsheetView(vobj.Object) + addSpreadsheetView(self.editor) + return True + + def unsetEdit(self,vobj,mode): + return False + + def claimChildren(self): + if hasattr(self,"Object"): + if hasattr(self.Object,"Controllers"): + return self.Object.Controllers + + def __getstate__(self): + return None + + def __setstate__(self,state): + return None + + +class SpreadsheetController: + "A spreadsheet cell controller object" + def __init__(self,obj): + obj.Proxy = self + self.Type = "SpreadsheetController" + obj.addProperty("App::PropertyEnumeration","FilterType","Filter","The type of filter to apply to the scene objects") + obj.addProperty("App::PropertyString","Filter","Filter","The filter to apply to the scene objects") + obj.addProperty("App::PropertyEnumeration","DataType","Data","The type of data to extract from the objects") + obj.addProperty("App::PropertyString","Data","Data","The data to extract from the objects") + obj.addProperty("App::PropertyString","BaseCell","Base","The starting cell of this controller") + obj.addProperty("App::PropertyEnumeration","Direction","Base","The cells direction of this controller") + obj.FilterType = ["Object Type","Object Name"] + obj.DataType = ["Get Property","Count"] + obj.Direction = ["Horizontal","Vertical"] + + def execute(self,obj): + pass + + def __getstate__(self): + return self.Type + + def __setstate__(self,state): + if state: + self.Type = state + + def onChanged(self,obj,prop): + if prop == "DataType": + if obj.DataType == "Count": + obj.setEditorMode('Data',1) + else: + obj.setEditorMode('Data',0) + + def getDataSet(self,obj): + "returns a list of objects to be considered by this controller" + result = [] + if hasattr(obj,"FilterType"): + import Draft + baseset = FreeCAD.ActiveDocument.Objects + if obj.FilterType == "Object Type": + for o in baseset: + t = Draft.getType(o) + if t == "Part": + t = obj.TypeId + if obj.Filter: + if obj.Filter in t: + result.append(obj) + else: + result.append(obj) + elif obj.FilterType == "Object Name": + for o in baseset: + if obj.Filter: + if obj.Filter in obl.Label: + result.append(obj) + else: + result.append(obj) + return result + + def getCells(self,obj,spreadsheet): + "returns a list of cells controlled by this controller" + cells = [] + if obj.BaseCell: + if obj.DataType == "Count": + return obj.BaseCell + for i in range(len(self.getDataSet())): + # get the correct cell key + c,r = spreadsheet.Proxy.splitKey(obj.BaseCell) + if obj.Direction == "Horizontal": + c = "abcdefghijklmnopqrstuvwxyz".index(c) + c += i + c = "abcdefghijklmnopqrstuvwxyz"[c] + else: + r = int(r) + i + cells.append(c+str(r)) + return cells + + def setCells(self,obj,spreadsheet): + "Fills the controlled cells of the given spreadsheet" + if obj.BaseCell: + dataset = self.getDataSet() + if obj.DataType == "Count": + if spreadsheet.Proxy.isKey(obj.BaseCell): + try: + setattr(spreadsheet.Proxy,obj.BaseCell,len(dataset)) + except: + print "Spreadsheet: Error counting objects" + elif obj.Data: + for i in range(len(dataset)): + # get the correct cell key + c,r = spreadsheet.Proxy.splitKey(obj.BaseCell) + if obj.Direction == "Horizontal": + c = "abcdefghijklmnopqrstuvwxyz".index(c) + c += i + c = "abcdefghijklmnopqrstuvwxyz"[c] + else: + r = int(r) + i + cell = c+str(r) + if DEBUG: print "auto setting cell ",cell + if spreadsheet.Proxy.isKey(cell): + # get the contents + args = obj.Data.split(".") + value = dataset[i] + for arg in args: + if hasattr(value,arg): + value = getattr(value,arg) + try: + setattr(spreadsheet.Proxy,cell,value) + if DEBUG: print "setting cell ",cell," to value ",value + except: + print "Spreadsheet: Error retrieving property "+obj.Data+" from object "+dataset[i].Name + + +class ViewProviderSpreadsheetController: + "A view provider for the spreadsheet cell controller" + def __init__(self,vobj): + vobj.Proxy = self + + def getIcon(self): + import Spreadsheet_rc + return ":/icons/SpreadsheetController.svg" + + +class SpreadsheetView(QtGui.QWidget): + "A spreadsheet viewer for FreeCAD" + + def __init__(self,spreadsheet=None): + from DraftTools import translate + QtGui.QWidget.__init__(self) + + self.setWindowTitle(str(translate("Spreadsheet","Spreadsheet"))) + self.setObjectName("Spreadsheet viewer") + self.verticalLayout = QtGui.QVBoxLayout(self) + self.doNotChange = False + + # add editor line + self.horizontalLayout = QtGui.QHBoxLayout() + self.label = QtGui.QLabel(self) + self.label.setMinimumSize(QtCore.QSize(82, 0)) + self.label.setText(str(translate("Spreadsheet","Cell"))+" A1 :") + self.horizontalLayout.addWidget(self.label) + self.lineEdit = QtGui.QLineEdit(self) + self.horizontalLayout.addWidget(self.lineEdit) + self.verticalLayout.addLayout(self.horizontalLayout) + + # add table + self.table = QtGui.QTableWidget(30,26,self) + for i in range(26): + ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i] + self.table.setHorizontalHeaderItem(i, QtGui.QTableWidgetItem(ch)) + self.verticalLayout.addWidget(self.table) + self.table.setCurrentCell(0,0) + self.spreadsheet = spreadsheet + self.update() + + QtCore.QObject.connect(self.table, QtCore.SIGNAL("cellChanged(int,int)"), self.changeCell) + QtCore.QObject.connect(self.table, QtCore.SIGNAL("currentCellChanged(int,int,int,int)"), self.setEditLine) + QtCore.QObject.connect(self.lineEdit, QtCore.SIGNAL("returnPressed()"), self.getEditLine) + QtCore.QObject.connect(self, QtCore.SIGNAL("destroyed()"), self.destroy) + + def destroy(self): + if DEBUG: print "Closing spreadsheet view" + if self.spreadsheet: + # before deleting this view, we remove the reference to it in the object + if hasattr(self.spreadsheet,"ViewObject"): + if self.spreadsheet.ViewObject: + if hasattr(self.spreadsheet.ViewObject.Proxy,"editor"): + del self.spreadsheet.ViewObject.Proxy.editor + if FreeCADGui: + if FreeCADGui.ActiveDocument: + FreeCADGui.ActiveDocument.resetEdit() + + def update(self): + "updates the cells with the contents of the spreadsheet" + if self.spreadsheet: + controlled = self.spreadsheet.Proxy.getControlledCells(self.spreadsheet) + for cell in self.spreadsheet.Proxy._cells.keys(): + if cell != "Type": + c,r = self.spreadsheet.Proxy.splitKey(cell) + c = "abcdefghijklmnopqrstuvwxyz".index(c) + r = int(str(r))-1 + content = getattr(self.spreadsheet.Proxy,cell) + if self.spreadsheet.Proxy.isFunction(cell): + self.doNotChange = True + if content == None: + content = "" + if DEBUG: print "Updating ",cell," to ",content + if self.table.item(r,c): + self.table.item(r,c).setText(str(content)) + else: + self.table.setItem(r,c,QtGui.QTableWidgetItem(str(content))) + if cell in controlled: + brush = QtGui.QBrush(QtGui.QColor(255, 0, 0)) + brush.setStyle(QtCore.Qt.Dense6Pattern) + self.table.item(r,c).setBackground(brush) + + def changeCell(self,r,c,value=None): + "changes the contens of a cell" + if self.doNotChange: + if DEBUG: print "DoNotChange flag is set" + self.doNotChange = False + elif self.spreadsheet: + key = "abcdefghijklmnopqrstuvwxyz"[c]+str(r+1) + if not value: + value = self.table.item(r,c).text() + if DEBUG: print "Changing "+key+" to "+value + # store the entry as best as possible + try: + v = int(value) + except: + try: + v = float(value) + except: + try: + v = v = str(value) + except: + v = value + setattr(self.spreadsheet.Proxy,key,v) + self.update() + # TODO do not update the whole spreadsheet when only one cell has changed: + # use the _relations table and recursively update only cells based on this one + self.setEditLine(r,c) + + def setEditLine(self,r,c,orr=None,orc=None): + "copies the contents of the active cell to the edit line" + if self.spreadsheet: + c = "abcdefghijklmnopqrstuvwxyz"[c] + r = r+1 + if DEBUG: print "Active cell "+c+str(r) + from DraftTools import translate + self.label.setText(str(translate("Spreadsheet","Cell"))+" "+c.upper()+str(r)+" :") + content = self.spreadsheet.Proxy.getFunction(c+str(r)) + if content == None: + content = "" + self.lineEdit.setText(str(content)) + + def getEditLine(self): + "called when something has been entered in the edit line" + txt = str(self.lineEdit.text()) + if DEBUG: print "Text edited ",txt + if txt: + r = self.table.currentRow() + c = self.table.currentColumn() + self.changeCell(r,c,txt) + + +class _Command_Spreadsheet_Create: + "the Spreadsheet_Create FreeCAD command" + def GetResources(self): + return {'Pixmap' : 'Spreadsheet', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_Create","Spreadsheet"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_Create","Adds a spreadsheet object to the active document")} + + def Activated(self): + from DraftTools import translate + FreeCAD.ActiveDocument.openTransaction(str(translate("Spreadsheet","Create Spreadsheet"))) + FreeCADGui.doCommand("import Spreadsheet") + FreeCADGui.doCommand("Spreadsheet.makeSpreadsheet()") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + + +class _Command_Spreadsheet_Controller: + "the Spreadsheet_Controller FreeCAD command" + def GetResources(self): + return {'Pixmap' : 'SpreadsheetController', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_Controller","Add controller"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_Controller","Adds a cell controller to a selected spreadsheet")} + + def IsActive(self): + if FreeCADGui.Selection.getSelection(): + return True + else: + return False + + def Activated(self): + import Draft + if Draft.getType(FreeCADGui.Selection.getSelection()[0]) == "Spreadsheet": + from DraftTools import translate + n = FreeCADGui.Selection.getSelection()[0].Name + FreeCAD.ActiveDocument.openTransaction(str(translate("Spreadsheet","Add controller"))) + FreeCADGui.doCommand("import Spreadsheet") + FreeCADGui.doCommand("Spreadsheet.makeSpreadsheetController(FreeCAD.ActiveDocument."+n+")") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + + +def makeSpreadsheet(): + "makeSpreadsheet(): adds a spreadsheet object to the active document" + obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Spreadsheet") + Spreadsheet(obj) + if FreeCAD.GuiUp: + ViewProviderSpreadsheet(obj.ViewObject) + return obj + + +def makeSpreadsheetController(spreadsheet,cell=None,direction=None): + """makeSpreadsheetController(spreadsheet,[cell,direction]): adds a + controller to the given spreadsheet. Call can be a starting cell such as "A5", + and direction can be "Horizontal" or "Vertical".""" + obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","CellController") + SpreadsheetController(obj) + if FreeCAD.GuiUp: + ViewProviderSpreadsheetController(obj.ViewObject) + conts = spreadsheet.Controllers + conts.append(obj) + spreadsheet.Controllers = conts + if cell: + obj.BaseCell = cell + if direction: + obj.Direction = direction + return obj + + +def addSpreadsheetView(view): + "addSpreadsheetView(view): adds the given spreadsheet view to the FreeCAD MDI area" + if FreeCAD.GuiUp: + import Spreadsheet_rc + mw = FreeCADGui.getMainWindow() + mdi = mw.findChild(QtGui.QMdiArea) + sw = mdi.addSubWindow(view) + sw.setWindowIcon(QtGui.QIcon(":/icons/Spreadsheet.svg")) + sw.show() + mdi.setActiveSubWindow(sw) + + +def open(filename): + "called when freecad opens a csv file" + import os + docname = os.path.splitext(os.path.basename(filename))[0] + doc = FreeCAD.newDocument(docname) + FreeCAD.ActiveDocument = doc + read(filename) + doc.recompute() + return doc + + +def insert(filename,docname): + "called when freecad wants to import a csv file" + try: + doc = FreeCAD.getDocument(docname) + except: + doc = FreeCAD.newDocument(docname) + FreeCAD.ActiveDocument = doc + read(filename) + doc.recompute() + return doc + + +def read(filename): + "creates a spreadsheet with the contents of a csv file" + sp = makeSpreadsheet() + import csv + with pyopen(filename, 'rb') as csvfile: + csvfile = csv.reader(csvfile) + rn = 1 + for row in csvfile: + cn = 0 + for c in row[:26]: + cl = "abcdefghijklmnopqrstuvwxyz"[cn] + #print "setting ",cl+str(rn)," ",c + try: + c = int(c) + except: + try: + c = float(c) + except: + c = str(c) + setattr(sp.Proxy,cl+str(rn),c) + cn += 1 + rn += 1 + print "successfully imported ",filename + + +def export(exportList,filename): + "called when freecad exports a csv file" + import csv, Draft + if not exportList: + print "Spreadsheet: Nothing to export" + return + obj = exportList[0] + if Draft.getType(obj) != "Spreadsheet": + print "Spreadhseet: The selected object is not a spreadsheet" + return + if not obj.Proxy._cells: + print "Spreadsheet: The selected spreadsheet contains no cell" + return + numcols = ("abcdefghijklmnopqrstuvwxyz".index(str(obj.Proxy.cols[-1])))+1 + numrows = int(obj.Proxy.rows[-1]) + with pyopen(filename, 'wb') as csvfile: + csvfile = csv.writer(csvfile) + for i in range(numrows): + r = [] + for j in range(numcols): + key = "abcdefghijklmnopqrstuvwxyz"[j]+str(i+1) + if key in obj.Proxy._cells.keys(): + r.append(str(obj.Proxy.getFunction(key))) + else: + r.append("") + csvfile.writerow(r) + print "successfully exported ",filename + + +FreeCADGui.addCommand('Spreadsheet_Create',_Command_Spreadsheet_Create()) +FreeCADGui.addCommand('Spreadsheet_Controller',_Command_Spreadsheet_Controller()) diff --git a/src/Mod/Spreadsheet/Spreadsheet_rc.py b/src/Mod/Spreadsheet/Spreadsheet_rc.py new file mode 100644 index 000000000..fa794a071 --- /dev/null +++ b/src/Mod/Spreadsheet/Spreadsheet_rc.py @@ -0,0 +1,245 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created: Tue Aug 6 17:48:51 2013 +# by: The Resource Compiler for PyQt (Qt v4.8.4) +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore + +qt_resource_data = "\ +\x00\x00\x06\x62\ +\x00\ +\x00\x18\x53\x78\x9c\xe5\x57\xdb\x6e\xdb\x46\x10\x7d\xf7\x57\xb0\ +\xcc\x4b\x82\x8a\xe4\x5e\x78\xb7\xa4\x3c\x34\x48\x11\xa0\x45\x81\ +\x26\x41\x1f\x83\x15\xb9\x94\x58\x53\x24\xb1\x5c\x59\x92\xbf\xbe\ +\xb3\xbc\x53\xa2\x13\x3b\x45\x90\x06\x95\x60\x8b\x3b\x33\x7b\x99\ +\x33\x67\x66\x96\xcb\xd7\xa7\x7d\xa6\xdd\x73\x51\xa5\x45\xbe\xd2\ +\xb1\x89\x74\x8d\xe7\x51\x11\xa7\xf9\x76\xa5\x7f\xfc\xf0\xd6\xf0\ +\x75\xad\x92\x2c\x8f\x59\x56\xe4\x7c\xa5\xe7\x85\xfe\x7a\x7d\xb3\ +\xfc\xc9\x30\xb4\x5f\x04\x67\x92\xc7\xda\x31\x95\x3b\xed\x5d\x7e\ +\x57\x45\xac\xe4\xda\xcb\x9d\x94\x65\x68\x59\xc7\xe3\xd1\x4c\x5b\ +\xa1\x59\x88\xad\xf5\x4a\x33\x8c\xf5\xcd\xcd\xb2\xba\xdf\xde\x68\ +\x9a\x06\xfb\xe6\x55\x18\x47\x2b\xbd\x9d\x50\x1e\x44\x56\x1b\xc6\ +\x91\xc5\x33\xbe\xe7\xb9\xac\x2c\x6c\x62\x4b\x1f\xcc\xa3\xc1\x3c\ +\x52\xbb\xa7\xf7\x3c\x2a\xf6\xfb\x22\xaf\xea\x99\x79\xf5\x62\x64\ +\x2c\xe2\xa4\xb7\x56\xa7\x39\xd2\xda\x08\x07\x41\x60\x21\x62\x11\ +\x62\x80\x85\x51\x9d\x73\xc9\x4e\xc6\x74\x2a\x9c\x71\x6e\x2a\x41\ +\x08\x59\xa0\x1b\x2c\x9f\x66\x15\x9e\x32\x80\xe2\xd1\xc3\xd4\xda\ +\xf1\xee\x00\x7f\x09\x7f\xfd\x84\x4e\x60\x56\xc5\x41\x44\x3c\x81\ +\x99\xdc\xcc\xb9\xb4\xde\x7c\x78\xd3\x2b\x0d\x64\xc6\x32\x1e\x2d\ +\xd3\xa1\x3f\xd9\x77\x12\x92\x9c\xed\x79\x55\xb2\x88\x57\x56\x27\ +\xaf\xe7\x1f\xd3\x58\xee\x56\xba\x6b\x97\xa7\x7a\xbc\xe3\xe9\x76\ +\x27\x47\x82\x34\x5e\xe9\xe0\x21\xf1\x5d\x54\x8f\xbb\x33\x84\x3d\ +\x93\x90\x49\x49\x63\xda\x2e\x3c\x56\xd9\xbe\x69\x6b\x22\x08\x68\ +\x30\x9d\x1d\x17\x91\x3a\xd2\x4a\x7f\x5f\x42\x74\xe3\x6a\xc7\xb9\ +\x34\x3b\x24\xfb\x85\x8a\x83\x2c\x0f\xf2\x13\x3f\x49\x9e\x37\x2b\ +\x82\x2f\x23\xc7\x6a\xb5\x9a\x66\x4e\x9c\x1a\x91\x1c\xeb\x6b\x90\ +\x2c\x63\x9e\x54\x4a\xd3\xf8\xa3\x46\xe0\x10\xa9\x75\xa0\x15\x2c\ +\x4e\x59\xf6\xab\xfa\x01\x2a\x36\x76\xa3\x53\x44\x45\x96\xf1\x08\ +\x40\x61\xd9\x91\x9d\x2b\xbd\x33\xa8\x83\x19\xee\x04\x07\xf2\xbd\ +\x80\x67\xce\x44\xb7\x06\xa5\x9e\xd7\xdb\xa9\x2d\xa7\x5b\x50\x37\ +\x20\xbd\x3a\x3a\xad\x74\xdb\x31\x7d\x9f\x52\x32\x4c\x8a\xce\x2b\ +\x9d\xf8\xa6\xef\x06\x8e\xeb\xf7\xd2\x64\xd6\x36\x99\xb5\x15\xe0\ +\x7f\x60\xda\xae\x67\x53\xb7\x17\x6e\xdb\x13\x7c\xcc\x53\x09\x94\ +\x3e\x54\x5c\xbc\x57\xb4\xf8\x23\xff\x58\x71\x5d\xb3\xbe\x1b\x22\ +\x1e\xa2\x4f\x3c\xe4\x18\x37\x4c\x1d\x93\x02\x18\x74\x82\x5b\xe0\ +\x99\xf4\x1a\xb7\x6b\xdb\x64\xd6\xf6\xb3\xb8\x7d\x10\x2c\xaf\x20\ +\x2b\xf7\x2b\x7d\xcf\xa4\x48\x4f\x2f\x91\x19\x80\xa5\xb3\x40\x26\ +\x21\x0e\xa2\x5e\xb0\x80\xf4\xb4\x5d\x42\x31\x72\x16\xc4\x44\x08\ +\xbb\x1e\xf1\x17\x2a\x11\x7c\xcf\x71\xec\x85\x81\x89\x67\x06\x01\ +\xc4\xf0\xd5\x00\xf8\x14\xac\x31\x4e\x33\x30\xae\x5b\xfd\xb2\x92\ +\x45\xd9\xd9\xb6\xa9\x0a\x12\xb0\x09\xf4\x41\x5c\x24\x49\xc5\x21\ +\x56\x68\x24\xab\xe4\x39\xe3\x8d\xb5\x01\xc1\x2c\x44\xf8\x22\x61\ +\x49\x42\x36\xb7\xb5\xa8\x00\xb4\x53\x79\x0e\xf1\x6d\x7f\xc2\xcf\ +\xec\xe6\xe3\x99\xdd\xf0\x17\x76\x4b\x18\x43\xe8\xd1\xdd\x96\xd6\ +\xd4\xed\xef\x48\x4b\xe7\x6b\x68\x09\xd1\xf6\xaf\x68\xe9\xe3\xb9\ +\x74\xbe\xb6\x4d\x66\x6d\x9f\x49\x4b\x0c\x5c\x77\x88\xe3\xfb\x8a\ +\x8e\xc8\xc1\xd4\xf5\x7c\x0a\x24\x45\xca\x25\x97\x04\xf0\x08\x0d\ +\x89\x62\x4a\x16\x86\x0b\x25\x3c\x20\x36\xa2\x0b\xcf\xf4\x90\x8d\ +\x6c\xea\x8f\xa8\xd9\xc3\x5b\x42\x59\x2d\x01\x5f\x68\xc5\xdd\xfe\ +\x7d\x3d\x97\x67\xd5\x7d\xa6\xa6\x34\xd6\xaf\x42\x74\x5f\x7e\x02\ +\x9f\x91\x16\x6a\x94\xc0\x3f\x3c\x6b\x71\x6e\x2c\x30\x74\x57\xf8\ +\x41\xb3\x36\x0f\xaa\x47\x7d\x66\x99\xf6\x04\x46\x21\xd2\x6d\x0a\ +\xad\xa0\xb6\x23\x80\x4a\xfd\x99\xce\x81\xb0\x8f\x7c\x83\xce\xe0\ +\xb7\xde\x2f\x2d\xd5\x2a\xea\xa7\xde\x53\xd5\xb6\xe2\xfb\x94\x1f\ +\x87\x7e\xb2\x61\x7d\xfc\x4b\xb6\xe5\x35\xc5\x81\x69\x49\xfd\x69\ +\x15\x9b\x42\xc4\x5c\x74\x2a\xb7\xfe\x4c\x54\x6d\x16\x34\x37\xb3\ +\x9b\x0b\x67\x60\xd5\x5e\x8f\xe6\xf5\xd5\x8e\xc5\xc5\x11\x1a\xc1\ +\xa5\xf2\xa1\x28\x80\x16\x8e\xe9\x5c\x2a\xea\xc6\x83\x4d\xd7\xc7\ +\x2e\xc1\x57\x4a\xd8\x89\x02\x09\x3d\x8f\xda\xde\x95\xf2\x20\x04\ +\xb0\xce\xc8\xd8\x99\x83\x3b\xf5\x4f\xb7\x42\xb5\x2b\x8e\x5b\xa1\ +\x60\x91\xe2\xc0\x2f\x67\x42\xdf\x3f\xa8\xfb\x9e\x71\x68\x92\xa8\ +\xbd\x65\x8c\x2c\xd4\x5c\x63\xb3\x29\x4e\xf3\x0b\x1c\xd3\x1c\xdc\ +\x34\xda\x7b\x0b\x0e\xc8\x15\x18\xad\x45\x77\x93\x81\x32\x4c\x1f\ +\x31\x39\x0d\x45\xf1\x52\x75\x7e\x5c\xb5\x67\xa7\x74\x9f\x3e\xf0\ +\x58\x15\xb9\x96\x27\x7b\x2e\x59\xcc\x24\x1b\x38\xd1\x49\x80\x4d\ +\x4e\x7f\xcf\x88\x93\xf0\xcf\x37\x6f\xfb\x82\x1a\x45\xe1\x5f\x85\ +\xb8\x1b\x0a\xa5\x32\x60\x1b\xb8\xd6\xac\xf4\xbe\xc8\xab\xdb\x4b\ +\x14\xaa\xdc\x66\x72\x9d\xee\x21\xd2\xea\xc6\xf9\x33\x5c\xfc\x80\ +\x9d\xbd\x62\x62\xac\x92\x71\x58\xb4\x59\x56\xf0\xe6\x46\x39\x7b\ +\x09\x8f\xa3\x7d\xaa\x26\x59\xef\x65\x9a\x65\xef\xd4\x26\xa3\xc2\ +\xdf\x2e\x9a\xca\x8c\xaf\xeb\x3d\x9b\xc7\xce\x0b\xab\x75\xa3\xab\ +\xdc\x23\x2f\x97\x56\x07\x43\x3d\xda\x0e\xf0\x4c\x28\xd3\x23\x9c\ +\xb1\x0d\xcf\x56\xfa\x6f\x4a\xa9\x5d\x69\xb7\xa2\x38\x94\xfb\x22\ +\xe6\xed\xf4\x1e\x56\xc8\xdb\xbe\x20\x35\xad\xa6\xed\x32\xa8\xfe\ +\xdc\x26\xe0\x54\xd8\xa6\x63\x3d\x18\xb5\x9c\x7a\x28\x0e\x19\x0f\ +\xf3\x22\x7f\x80\x34\x84\x9e\x24\x8a\xbb\x7a\xc8\xdb\xe7\x86\x6d\ +\xa1\xdd\x0d\x55\x0b\x81\x13\x85\x9b\x83\x94\x63\xd9\xdf\x45\x9a\ +\x87\x70\xc8\x3c\xee\xa4\x00\x2b\x17\x19\xd0\x45\x0e\xb3\x87\xbd\ +\x5b\x41\xcc\x20\x77\x85\x60\xe7\xc9\x9e\x4a\xda\x34\xd3\x10\xdd\ +\xee\x99\xb8\xe3\xa2\xd1\xdf\xa7\x55\xba\x49\x33\xb5\x44\xfd\x98\ +\xf1\xdb\x38\xad\x4a\x80\x04\xde\x03\xd4\x31\x6e\x0b\xb8\x00\x27\ +\x59\x71\xec\xf5\x3c\x67\xf0\x63\x6c\x58\x74\xb7\xad\xcf\x17\xb2\ +\x08\xf2\xf0\x90\xc1\x5b\xdd\xb4\xfb\x01\x94\x14\xa1\xe1\x72\xda\ +\xe6\x99\xe3\x9a\xd8\xc7\xfe\x20\xef\xb2\xcb\x76\x4d\xc7\x86\xef\ +\xd0\x92\x54\x51\xe9\x07\xea\x82\x65\x12\x0f\xbe\xfe\xe8\x72\xf9\ +\xa4\x78\xd5\xbe\x3e\x35\x58\xdd\xcc\xff\x6b\xbc\x8c\xe0\x9b\x46\ +\xac\x64\x72\x77\x11\xb1\x21\x46\xff\x3e\x04\x35\xea\x8f\xc2\x3d\ +\x17\x93\x69\x08\xfa\xc3\xab\xba\xab\xd9\x0b\x82\x1a\x17\x1d\xcd\ +\x71\x4c\x97\xc2\xd7\x5e\xa0\x69\xbb\x07\x87\xe0\x96\x3c\x73\xb5\ +\x88\x8a\x1c\x4e\x2a\x0b\x61\x40\x93\xbb\x67\xf2\x20\xb8\x6a\x05\ +\x3f\x22\x14\xbf\x6b\x00\x44\x80\xe0\x8b\x17\x41\x83\x03\x75\x47\ +\xb2\x11\x05\x46\x98\x90\xff\x36\x26\x5f\x91\xa1\x53\x7a\x10\x13\ +\x6e\xbf\x90\x33\xde\x82\x12\xd3\x26\x81\x8f\xb1\x86\xe1\x25\x90\ +\xda\xd4\xa3\x74\x9e\x27\xf6\xf3\x31\x79\x72\x53\x1a\xa1\x32\xdb\ +\x73\xbe\x61\x29\x99\x96\x57\x78\x6b\xc5\xd8\x76\x7c\x6a\x5f\x97\ +\x18\xcf\xc3\x97\x05\x86\x06\xa6\xa2\x11\xf2\xaf\x2a\x0c\xa1\x0d\ +\xc3\xc6\x05\x86\xe0\x71\x85\x01\x0e\x36\x69\xf9\x83\x72\xc8\x5e\ +\xd8\x36\xbc\xce\x53\x04\xaf\x20\x5f\x28\x31\xee\xb7\xa2\xce\xf3\ +\xfa\x63\x3c\x83\x9c\xfb\x4d\xb9\xf5\xf5\x35\x6c\xbe\x45\xcf\x91\ +\x92\xce\x90\xf2\xa2\xb9\xf5\xa4\xb4\x27\x74\x44\xa6\x57\x37\xb9\ +\x0b\x56\x36\x35\xf2\x99\xac\x9c\xc3\xf6\xbb\x54\x36\x62\x22\x8c\ +\x02\x3b\x18\x55\x36\x0a\x6f\xf4\x20\xc3\xde\x23\x85\xcd\x78\x6e\ +\x0b\x5c\x5a\xdb\xf5\xcd\x52\xbd\x82\xac\x6f\xfe\x01\x67\xd0\x48\ +\x57\ +\x00\x00\x05\xda\ +\x00\ +\x00\x14\x77\x78\x9c\xe5\x57\x59\x8f\xdb\x36\x10\x7e\xdf\x5f\xa1\ +\x2a\x2f\x29\x6a\x49\x14\xa9\x7b\x6d\x07\x68\x83\x14\x01\x5a\xb4\ +\x68\x12\xf4\x31\xa0\x25\xca\x56\x57\x16\x0d\x8a\x5e\xdb\xfb\xeb\ +\x3b\xa4\xee\xb5\x36\x57\x51\xa4\x87\x85\x5d\x8b\x73\x70\x38\xdf\ +\xcc\x70\xc6\xcb\x17\xe7\x7d\x69\xdc\x33\x51\x17\xbc\x5a\x99\xae\ +\x8d\x4c\x83\x55\x29\xcf\x8a\x6a\xbb\x32\xdf\xbd\x7d\x65\x45\xa6\ +\x51\x4b\x5a\x65\xb4\xe4\x15\x5b\x99\x15\x37\x5f\xac\x6f\x96\xdf\ +\x58\x96\xf1\x83\x60\x54\xb2\xcc\x38\x15\x72\x67\xbc\xae\xee\xea\ +\x94\x1e\x98\xf1\x7c\x27\xe5\x21\x71\x9c\xd3\xe9\x64\x17\x2d\xd1\ +\xe6\x62\xeb\x7c\x6b\x58\xd6\xfa\xe6\x66\x59\xdf\x6f\x6f\x0c\xc3\ +\x00\xbb\x55\x9d\x64\xe9\xca\x6c\x15\x0e\x47\x51\x6a\xc1\x2c\x75\ +\x58\xc9\xf6\xac\x92\xb5\xe3\xda\xae\x63\x0e\xe2\xe9\x20\x9e\x2a\ +\xeb\xc5\x3d\x4b\xf9\x7e\xcf\xab\x5a\x6b\x56\xf5\xb3\x91\xb0\xc8\ +\xf2\x5e\x5a\x9d\xe6\x44\xb4\x90\x1b\xc7\xb1\x83\xb0\x83\xb1\x05\ +\x12\x56\x7d\xa9\x24\x3d\x5b\x53\x55\x38\xe3\x9c\x2a\x46\x08\x39\ +\xc0\x1b\x24\x3f\x4d\x2a\x39\x97\x00\xc5\x93\x87\xd1\xdc\xb1\x75\ +\x80\xff\x00\x7f\xbd\x42\x47\xb0\x6b\x7e\x14\x29\xcb\x41\x93\xd9\ +\x15\x93\xce\xcb\xb7\x2f\x7b\xa6\x85\xec\x4c\x66\xa3\x6d\x3a\xf4\ +\x27\x76\x27\x21\xa9\xe8\x9e\xd5\x07\x9a\xb2\xda\xe9\xe8\x5a\xff\ +\x54\x64\x72\xb7\x32\x03\xef\x70\xd6\xeb\x1d\x2b\xb6\x3b\x39\x22\ +\x14\xd9\xca\x04\x0f\x71\x14\x20\xbd\xee\xce\x90\xf4\x99\x84\x6c\ +\x82\x1b\xd1\x76\xe3\x31\xcb\x8b\x6c\xcf\x10\x71\x4c\xe2\xa9\x76\ +\xc6\x53\x75\xa4\x95\xf9\x2b\x15\xf2\xfd\xf7\xfc\x6c\x77\x30\xf6\ +\xbb\xf0\xa3\x3c\x1c\xe5\x7b\x76\x96\xac\x6a\xb6\x03\x47\x46\x5e\ +\x69\xb6\x52\xb3\x27\x1e\x8d\x32\xdc\x35\xd7\x40\x59\x66\x2c\xaf\ +\x15\xa7\x71\x46\xad\xc0\x1b\xac\x79\xc0\x15\x34\x2b\x68\xf9\xa3\ +\xfa\x82\x3c\x6c\xe4\x46\xa7\x48\x79\x59\xb2\x14\x10\xa1\xe5\x89\ +\x5e\x6a\xb3\x13\xd0\x91\x4c\x76\x82\x41\xe6\x3d\x83\x77\x46\x45\ +\xb7\x07\x21\x61\xd8\xcb\x29\x93\x53\x13\x24\x88\x71\xcf\x4e\xcf\ +\x2b\xd3\xf3\xed\x28\x22\x04\x0f\x4a\xe9\x65\x65\xe2\xc8\x8e\x82\ +\xd8\x0f\xa2\x9e\x9a\xcf\xca\xe6\xb3\xb2\x02\xfc\x8f\x6d\x2f\x08\ +\x3d\x12\xf4\xc4\x6d\x7b\x82\x77\x55\x21\x21\x9f\x8f\x35\x13\x6f\ +\x54\x4e\xfc\x52\xbd\xab\x99\x69\x38\x5f\x0d\x91\x10\x91\x4f\x3c\ +\xe4\x18\x37\x97\xf8\x36\x01\x30\xc8\x04\xb7\x38\xb4\xc9\x35\x6e\ +\xd7\xb2\xf9\xac\xec\x07\x71\x7b\x2b\x68\x55\x43\x49\xee\x57\xe6\ +\x9e\x4a\x51\x9c\x9f\x23\x3b\x06\x49\x7f\x81\x6c\x8c\x7d\x44\xc2\ +\x78\x01\xb5\xe9\x05\x98\xb8\xc8\x5f\x60\x1b\x21\x37\x08\x71\xb4\ +\x50\x55\x10\x85\xbe\xef\x2d\x2c\x17\x87\x76\x1c\x43\x0c\xbf\x1d\ +\x00\x9f\x82\x35\xc6\x69\x06\xc6\x75\xcb\x5f\xd6\x92\x1f\x3a\xd9\ +\xb6\x4e\x81\x02\x32\xb1\x39\x90\x79\x9e\xd7\x0c\x62\x85\x46\xb4\ +\x5a\x5e\x4a\xd6\x48\x5b\x10\x4c\x2e\x92\x67\x39\xcd\x73\xbc\xb9\ +\xd5\x24\x0e\x68\x17\xf2\x92\xb8\xb7\xfd\x09\x3f\x60\x2d\x72\x67\ +\xac\xb9\x1f\xb1\x96\x53\x8a\xd0\x93\xd6\x96\xce\xd4\xed\xaf\x98\ +\x96\xfe\x97\xa4\x25\x44\x3b\xba\x4a\xcb\xc8\x9d\x2b\xe7\x6b\xd9\ +\x7c\x56\xf6\x33\xd3\xd2\x85\x5c\xf7\xb1\x1f\x45\x2a\x1d\x91\xef\ +\x92\x20\x8c\x08\x24\x29\x52\x2e\x05\x38\x86\x57\xe8\x46\xc4\x25\ +\x78\x61\x05\x70\x7f\xc7\xd8\x43\x64\x11\xda\x21\xf2\x90\x47\xa2\ +\x51\x6a\xf6\xf0\x1e\xe0\x5a\x3d\x00\xbe\xd0\x87\x3b\xfb\xfd\x65\ +\x2e\x2f\xaa\xf5\x4c\x45\x49\x66\x5e\x85\xe8\xfe\xf0\x1e\x7c\x46\ +\x46\x62\x10\x0c\xff\xdc\x59\x89\x4b\x23\xe1\x42\x6b\x85\x2f\x34\ +\x2b\xf3\xa0\x1a\xd4\x07\xb6\x69\x4f\x60\x71\x51\x6c\x0b\x68\x05\ +\x5a\x0e\x03\x2a\xfa\x33\xd5\x81\xb0\x8f\x7c\x83\xce\x10\xb5\xde\ +\x2f\x1d\xd5\x2a\xf4\x5b\xef\xa9\xea\x59\xd9\x7d\xc1\x4e\x43\x3f\ +\xd9\xd0\x3e\xfe\x07\xba\x65\x3a\xc5\x21\xd3\x72\xfd\x69\x19\x1b\ +\x2e\x32\x26\x3a\x56\xa0\x3f\x13\x56\x5b\x05\xcd\x58\x76\xf3\xc8\ +\x19\xd8\xb5\xe7\xa3\x79\x7e\xbd\xa3\x19\x3f\x41\x23\x78\xcc\x7c\ +\xe0\x1c\xd2\xc2\xb7\xfd\xc7\x0c\x9d\xa9\xc8\x0e\xfc\xc8\x77\xbd\ +\x2b\x26\x58\x82\x0b\x13\xfb\x61\x48\xa2\x2b\xe6\x51\x08\xc8\x3a\ +\xab\xa4\x17\x06\xee\xe8\xaf\x0e\xcf\x7a\xc7\x4f\x5b\xa1\x60\x91\ +\xe2\xc8\x1e\x6b\x42\xd3\x3f\xaa\x61\xcf\x3a\x36\x45\xd4\x8e\x18\ +\x23\x09\xa5\x6b\x6d\x36\xfc\x3c\xbf\xc1\xa9\xa8\xc0\x4d\xab\x1d\ +\x5a\xdc\x18\x5f\x81\xd1\x4a\x74\x63\x0c\x5c\xc3\xe4\x09\x91\xf3\ +\x70\x29\x3e\x66\x5d\x9e\x66\xed\xe9\xb9\xd8\x17\x0f\x2c\x53\x97\ +\x5c\x9b\x27\x7b\x26\x69\x46\x25\x1d\x72\xa2\xa3\x40\x36\xf9\xfd\ +\x9c\x91\xe5\xc9\x6f\x2f\x5f\xf5\x17\x6a\x9a\x26\xbf\x73\x71\x37\ +\x5c\x94\x4a\x80\x6e\x60\xac\x59\x99\xfd\x25\xaf\xa6\x97\x34\x51\ +\xb5\x4d\xe5\xba\xd8\x43\xa4\xd5\xb8\xf9\x1d\x4c\x7d\x90\x9d\x3d\ +\x63\x22\xac\x8a\x71\xd8\xb4\xd9\x56\xb0\x66\x9c\x9c\x9d\xc0\xb3\ +\x74\x5f\x28\x25\xe7\x8d\x2c\xca\xf2\xb5\x32\x32\xba\xf8\xdb\x4d\ +\x0b\x59\xb2\xb5\xb6\xd9\xbc\x76\x5e\x38\xad\x1b\xdd\xcd\x3d\xf2\ +\x72\xe9\x74\x30\xe8\xd5\x76\x80\x67\x92\x32\x3d\xc2\x25\xdd\xb0\ +\x72\x65\xfe\xa4\x98\xc6\x15\x77\x2b\xf8\xf1\xb0\xe7\x19\x6b\xd5\ +\x7b\x58\xa1\x6e\xfb\x0b\xa9\x69\x35\x6d\x97\x41\xfa\x73\x9b\x83\ +\x53\x49\x5b\x8e\x7a\x31\x6a\x39\x7a\x29\x8e\x25\x4b\x2a\x5e\x3d\ +\x40\x19\x42\x4f\x12\xfc\x4e\x2f\x59\xfb\xde\x64\x5b\xe2\x75\x4b\ +\xd5\x42\xe0\x44\xc9\xe6\x28\xe5\x98\xf6\x07\x2f\xaa\x04\x0e\x59\ +\x65\x1d\x15\x60\x65\xa2\x84\x74\x91\x83\xf6\x60\xbb\x25\x64\x14\ +\x6a\x57\x08\x7a\x99\xd8\x54\xd4\xa6\x99\x26\xe8\x76\x4f\xc5\x1d\ +\x13\x0d\xff\xbe\xa8\x8b\x4d\x51\xaa\x2d\xf4\x6b\xc9\x6e\xb3\xa2\ +\x3e\x00\x24\xf0\x23\x40\x1d\xe3\x96\xc3\x00\x9c\x97\xfc\xd4\xf3\ +\x59\x45\xe1\xcb\xda\xd0\xf4\x6e\xab\xcf\x97\xd0\x14\xea\xf0\x58\ +\xc2\x4f\xba\x69\xf7\x03\x28\x09\x42\xc3\x70\xda\xd6\x99\x1f\xd8\ +\x6e\xe4\x46\x03\xbd\xab\x2e\x2f\xb0\x7d\x0f\x9e\xa1\x25\xa9\x09\ +\xb5\x5f\xa8\x01\xcb\xc6\x21\x3c\xd1\x68\xb8\xfc\xa4\x78\x69\x5f\ +\x3f\x35\x58\x9d\xe6\xff\x35\x5e\x56\xfc\xb7\x46\xec\x40\xe5\xee\ +\x51\xc4\x86\x18\xfd\xf5\x10\x68\xd4\x9f\x84\x7b\x2e\x26\xd3\x10\ +\xf4\x87\x57\xf7\xae\xe1\x2d\x30\x6a\x5c\xf4\x0d\xdf\xb7\x03\x02\ +\x8f\xb7\x40\xd3\x76\x0f\x0e\xc1\x94\x3c\x33\x5a\xa4\xbc\x82\x93\ +\x4a\x2e\x2c\x68\x72\xf7\x54\x1e\x05\x53\xad\xe0\xdf\x08\xc5\xcf\ +\x06\x00\x11\x23\x78\xdc\x45\xdc\xe0\x40\x82\x11\x6d\x94\x02\x23\ +\x4c\xf0\x3f\x1b\x93\x2f\xa8\xd0\xc7\xe9\x41\xb0\xed\xe1\x38\x72\ +\x5d\x95\x1e\x48\x83\x31\x9f\x1e\xde\x7f\x1e\x0a\xcf\x83\x5f\xa5\ +\x04\xc1\x24\xfd\x91\x4a\x09\x3e\x13\x8a\xa5\xb3\x5d\xdf\x2c\xd5\ +\xa4\xb2\xbe\xf9\x13\x2d\x67\x17\x7f\ +" + +qt_resource_name = "\ +\x00\x05\ +\x00\x6f\xa6\x53\ +\x00\x69\ +\x00\x63\x00\x6f\x00\x6e\x00\x73\ +\x00\x19\ +\x02\x18\xed\xa7\ +\x00\x53\ +\x00\x70\x00\x72\x00\x65\x00\x61\x00\x64\x00\x73\x00\x68\x00\x65\x00\x65\x00\x74\x00\x43\x00\x6f\x00\x6e\x00\x74\x00\x72\x00\x6f\ +\x00\x6c\x00\x6c\x00\x65\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x0f\ +\x0a\xa9\x40\xe7\ +\x00\x53\ +\x00\x70\x00\x72\x00\x65\x00\x61\x00\x64\x00\x73\x00\x68\x00\x65\x00\x65\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\ +" + +qt_resource_struct = "\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x02\ +\x00\x00\x00\x10\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x00\x48\x00\x01\x00\x00\x00\x01\x00\x00\x06\x66\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/src/Mod/TemplatePyMod/FeaturePython.py b/src/Mod/TemplatePyMod/FeaturePython.py index 552ff62ba..3d1f1c990 100644 --- a/src/Mod/TemplatePyMod/FeaturePython.py +++ b/src/Mod/TemplatePyMod/FeaturePython.py @@ -1,28 +1,6 @@ """ Examples for a feature class and its view provider. - -*************************************************************************** -* Copyright (c) 2009 Werner Mayer * -* * -* This file is part of the FreeCAD CAx development system. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License (GPL) * -* as published by the Free Software Foundation; either version 2 of * -* the License, or (at your option) any later version. * -* for detail see the LICENCE text file. * -* * -* FreeCAD is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU Library General Public License for more details. * -* * -* You should have received a copy of the GNU Library General Public * -* License along with FreeCAD; if not, write to the Free Software * -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -* USA * -* * -*************************************************************************** +(c) 2009 Werner Mayer LGPL """ __author__ = "Werner Mayer " diff --git a/src/Mod/TemplatePyMod/PythonQt.py b/src/Mod/TemplatePyMod/PythonQt.py index 058abb107..db02384ee 100644 --- a/src/Mod/TemplatePyMod/PythonQt.py +++ b/src/Mod/TemplatePyMod/PythonQt.py @@ -1,28 +1,6 @@ """ Examples for customizing the FreeCAD application with PyQt facilities. - -*************************************************************************** -* Copyright (c) 2007 Werner Mayer * -* * -* This file is part of the FreeCAD CAx development system. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License (GPL) * -* as published by the Free Software Foundation; either version 2 of * -* the License, or (at your option) any later version. * -* for detail see the LICENCE text file. * -* * -* FreeCAD is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU Library General Public License for more details. * -* * -* You should have received a copy of the GNU Library General Public * -* License along with FreeCAD; if not, write to the Free Software * -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -* USA * -* * -*************************************************************************** +(c) 2007 Werner Mayer LGPL """ __author__ = "Werner Mayer " diff --git a/src/Mod/Test/TestApp.py b/src/Mod/Test/TestApp.py index 2eab8fe40..cf58c99f5 100644 --- a/src/Mod/Test/TestApp.py +++ b/src/Mod/Test/TestApp.py @@ -51,6 +51,8 @@ def All(): suite.addTest(unittest.defaultTestLoader.loadTestsFromName("TestSketcherGui") ) suite.addTest(unittest.defaultTestLoader.loadTestsFromName("TestPartGui") ) suite.addTest(unittest.defaultTestLoader.loadTestsFromName("TestPartDesignGui") ) + suite.addTest(unittest.defaultTestLoader.loadTestsFromName("TestDraft") ) + suite.addTest(unittest.defaultTestLoader.loadTestsFromName("TestArch") ) return suite diff --git a/src/WindowsInstaller/FreeCAD.wxs b/src/WindowsInstaller/FreeCAD.wxs index fd8e9e758..7d270448c 100644 --- a/src/WindowsInstaller/FreeCAD.wxs +++ b/src/WindowsInstaller/FreeCAD.wxs @@ -143,7 +143,6 @@ - diff --git a/src/WindowsInstaller/ModArch.wxi b/src/WindowsInstaller/ModArch.wxi index 7e28c9302..ea5c0c71d 100644 --- a/src/WindowsInstaller/ModArch.wxi +++ b/src/WindowsInstaller/ModArch.wxi @@ -45,6 +45,8 @@ + + diff --git a/src/WindowsInstaller/ModDraft.wxi b/src/WindowsInstaller/ModDraft.wxi index 2a212d379..a80dd345e 100644 --- a/src/WindowsInstaller/ModDraft.wxi +++ b/src/WindowsInstaller/ModDraft.wxi @@ -41,6 +41,7 @@ + diff --git a/src/WindowsInstaller/Version.wxi.in b/src/WindowsInstaller/Version.wxi.in index 9d49f2aaa..d2cfcd6e5 100644 --- a/src/WindowsInstaller/Version.wxi.in +++ b/src/WindowsInstaller/Version.wxi.in @@ -1,5 +1,5 @@ - +