diff --git a/CMakeLists.txt b/CMakeLists.txt
index 70f369132..104dffe66 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,8 +49,7 @@ if(CMAKE_COMPILER_IS_GNUCXX)
include(cMake/ConfigureChecks.cmake)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
add_definitions(-DHAVE_CONFIG_H)
- add_definitions(-Wno-write-strings)
- add_definitions(-Wno-deprecated)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-write-strings")
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
# get linker errors as soon as possible and not at runtime e.g. for modules
if(UNIX)
@@ -271,7 +270,6 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
# -------------------------------- Eigen --------------------------------
- #find_package(Eigen2)
find_package(Eigen3)
# -------------------------------- ODE ----------------------------------
diff --git a/ChangeLog.txt b/ChangeLog.txt
index ae9473443..568dcdfa3 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,4 +1,4 @@
-Changelog you finde now here:
+Changelog you find now here:
https://sourceforge.net/apps/mantisbt/free-cad/changelog_page.php
Version: 0.12
diff --git a/README b/README
index 8ecbded40..b9a2d2f61 100644
--- a/README
+++ b/README
@@ -12,13 +12,20 @@ FreeCAD is based on OpenCasCade, a powerful geometry kernel, features an Open In
The interface is built with Qt. FreeCAD runs exactly the same way on Windows, Mac OSX, BSD and
Linux platforms.
-Home page and wiki documentation: http://free-cad.sf.net
+Home page: http://www.freecadweb.org
+Documentation wiki: http://www.freecadweb.org/wiki
Forum: http://sourceforge.net/apps/phpbb/free-cad/
Bug tracker: http://sourceforge.net/apps/mantisbt/free-cad/
-Official git link: git://free-cad.git.sourceforge.net/free-cad/free-cad
+Git repository: http://sourceforge.net/p/free-cad/code/ci/master/tree/
-Building
-========
+Installing
+==========
+
+Precompiled (installable) packages are usually available to you from several sources and are
+described on the FreeCAD download page: http://www.freecadweb.org/wiki/index.php?title=Download
+
+Compiling
+=========
Compiling FreeCAD requires to install several heavyweight libraries and their development
files such as OpenCasCADe, Coin and Qt, listed in the pages below. Once this is done,
@@ -31,12 +38,26 @@ Note that autotools build system can still be used but will be obsoleted soon.
The pages below contain up-to-date build instructions:
-For Linux: http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=CompileOnUnix
-For windows: http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=CompileOnWindows
-For Mac OSX: http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=CompileOnMac
+For Linux: http://www.freecadweb.org/wiki/index.php?title=CompileOnUnix
+For windows: http://www.freecadweb.org/wiki/index.php?title=CompileOnWindows
+For Mac OSX: http://www.freecadweb.org/wiki/index.php?title=CompileOnMac
In this folder you will also find additional README files, specific for each platform.
+Usage
+=====
+
+The FreeCAD documentation wiki contains sections for each category of users, and a manual,
+which is a compilation of the most useful articles of the wiki:
+
+For users: General FreeCAD usage: http://www.freecadweb.org/wiki/index.php?title=User_hub
+For power-users: Python scripting: http://www.freecadweb.org/wiki/index.php?title=Power_users_hub
+For developers: C++ FreeCAD development: http://www.freecadweb.org/wiki/index.php?title=Developer_hub
+
+The FreeCAD manual: http://www.freecadweb.org/wiki/index.php?title=Online_Help_Toc
+
+
+
diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp
index f777c8d2b..fb73ec4d0 100644
--- a/src/App/PropertyStandard.cpp
+++ b/src/App/PropertyStandard.cpp
@@ -467,7 +467,7 @@ void PropertyEnumeration::setPyObject(PyObject *value)
{
if (PyInt_Check(value)) {
long val = PyInt_AsLong(value);
- if(_EnumArray){
+ if (_EnumArray) {
const char** plEnums = _EnumArray;
long i=0;
while(*(plEnums++) != NULL)i++;
@@ -478,10 +478,10 @@ void PropertyEnumeration::setPyObject(PyObject *value)
}
else if (PyString_Check(value)) {
const char* str = PyString_AsString (value);
- if (isPartOf(str))
+ if (_EnumArray && isPartOf(str))
setValue(PyString_AsString (value));
else
- throw Py::ValueError("not a member of the enum");
+ throw Py::ValueError("not part of the enum");
}
else if (PyList_Check(value)) {
Py_ssize_t nSize = PyList_Size(value);
diff --git a/src/Base/Parameter.cpp b/src/Base/Parameter.cpp
index 52ae32023..031d697c6 100644
--- a/src/Base/Parameter.cpp
+++ b/src/Base/Parameter.cpp
@@ -37,6 +37,7 @@
# endif
# include
# include
+# include
# include
# include
# include
@@ -1080,7 +1081,23 @@ bool ParameterManager::LoadOrCreateDocument(const char* sFileName)
int ParameterManager::LoadDocument(const char* sFileName)
{
Base::FileInfo file(sFileName);
-
+
+ try {
+#if defined (FC_OS_WIN32)
+ LocalFileInputSource inputSource((XMLCh*)file.toStdWString().c_str());
+#else
+ LocalFileInputSource inputSource(XStr(file.filePath().c_str()).unicodeForm());
+#endif
+ return LoadDocument(inputSource);
+ }
+ catch (...) {
+ std::cerr << "An error occurred during parsing\n " << std::endl;
+ return 0;
+ }
+}
+
+int ParameterManager::LoadDocument(const XERCES_CPP_NAMESPACE_QUALIFIER InputSource& inputSource)
+{
//
// Create our parser, then attach an error handler to the parser.
// The parser will call back to methods of the ErrorHandler if it
@@ -1102,11 +1119,7 @@ int ParameterManager::LoadDocument(const char* sFileName)
//
bool errorsOccured = false;
try {
-#if defined (FC_OS_WIN32)
- parser->parse((XMLCh*)file.toStdWString().c_str());
-#else
- parser->parse(file.filePath().c_str());
-#endif
+ parser->parse(inputSource);
}
catch (const XMLException& e) {
@@ -1152,10 +1165,36 @@ int ParameterManager::LoadDocument(const char* sFileName)
}
void ParameterManager::SaveDocument(const char* sFileName) const
+{
+ Base::FileInfo file(sFileName);
+
+ try {
+ //
+ // Plug in a format target to receive the resultant
+ // XML stream from the serializer.
+ //
+ // LocalFileFormatTarget prints the resultant XML stream
+ // to a file once it receives any thing from the serializer.
+ //
+#if defined (FC_OS_WIN32)
+ XMLFormatTarget *myFormTarget = new LocalFileFormatTarget ((XMLCh*)file.toStdWString().c_str());
+#else
+ XMLFormatTarget *myFormTarget = new LocalFileFormatTarget (file.filePath().c_str());
+#endif
+ SaveDocument(myFormTarget);
+ delete myFormTarget;
+ }
+ catch (XMLException& e) {
+ std::cerr << "An error occurred during creation of output transcoder. Msg is:"
+ << std::endl
+ << StrX(e.getMessage()) << std::endl;
+ }
+}
+
+void ParameterManager::SaveDocument(XMLFormatTarget* pFormatTarget) const
{
#if (XERCES_VERSION_MAJOR == 2)
DOMPrintFilter *myFilter = 0;
- Base::FileInfo file(sFileName);
try {
// get a serializer, an instance of DOMWriter
@@ -1199,31 +1238,17 @@ void ParameterManager::SaveDocument(const char* sFileName) const
if (theSerializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint))
theSerializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint);
- //
- // Plug in a format target to receive the resultant
- // XML stream from the serializer.
- //
- // LocalFileFormatTarget prints the resultant XML stream
- // to a file once it receives any thing from the serializer.
- //
-#if defined (FC_OS_WIN32)
- XMLFormatTarget *myFormTarget = new LocalFileFormatTarget ((XMLCh*)file.toStdWString().c_str());
-#else
- XMLFormatTarget *myFormTarget = new LocalFileFormatTarget (file.filePath().c_str());
-#endif
-
//
// do the serialization through DOMWriter::writeNode();
//
- theSerializer->writeNode(myFormTarget, *_pDocument);
+ theSerializer->writeNode(pFormatTarget, *_pDocument);
delete theSerializer;
//
- // Filter, formatTarget and error handler
+ // Filter and error handler
// are NOT owned by the serializer.
//
- delete myFormTarget;
delete myErrorHandler;
if (gUseFilter)
@@ -1236,8 +1261,6 @@ void ParameterManager::SaveDocument(const char* sFileName) const
<< StrX(e.getMessage()) << std::endl;
}
#else
- Base::FileInfo file(sFileName);
-
try {
// get a serializer, an instance of DOMWriter
XMLCh tempStr[100];
@@ -1250,70 +1273,15 @@ void ParameterManager::SaveDocument(const char* sFileName) const
DOMConfiguration* config = theSerializer->getDomConfig();
config->setParameter(XStr("format-pretty-print").unicodeForm(),true);
- // plug in user's own filter
- if (gUseFilter) {
- // even we say to show attribute, but the DOMWriter
- // will not show attribute nodes to the filter as
- // the specs explicitly says that DOMWriter shall
- // NOT show attributes to DOMWriterFilter.
- //
- // so DOMNodeFilter::SHOW_ATTRIBUTE has no effect.
- // same DOMNodeFilter::SHOW_DOCUMENT_TYPE, no effect.
- //
-// myFilter = new DOMPrintFilter(DOMNodeFilter::SHOW_ELEMENT |
-// DOMNodeFilter::SHOW_ATTRIBUTE |
-// DOMNodeFilter::SHOW_DOCUMENT_TYPE
-// );
-// theSerializer->setFilter(myFilter);
- }
-
- // plug in user's own error handler
- DOMErrorHandler *myErrorHandler = new DOMPrintErrorHandler();
-// theSerializer->setErrorHandler(myErrorHandler);
-
- // set feature if the serializer supports the feature/mode
-// if (theSerializer->canSetFeature(XMLUni::fgDOMWRTSplitCdataSections, gSplitCdataSections))
-// theSerializer->setFeature(XMLUni::fgDOMWRTSplitCdataSections, gSplitCdataSections);
-
-// if (theSerializer->canSetFeature(XMLUni::fgDOMWRTDiscardDefaultContent, gDiscardDefaultContent))
-// theSerializer->setFeature(XMLUni::fgDOMWRTDiscardDefaultContent, gDiscardDefaultContent);
-
-// if (theSerializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint))
-// theSerializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint);
-
- //
- // Plug in a format target to receive the resultant
- // XML stream from the serializer.
- //
- // LocalFileFormatTarget prints the resultant XML stream
- // to a file once it receives any thing from the serializer.
- //
-#if defined (FC_OS_WIN32)
- XMLFormatTarget *myFormTarget = new LocalFileFormatTarget ((XMLCh*)file.toStdWString().c_str());
-#else
- XMLFormatTarget *myFormTarget = new LocalFileFormatTarget (file.filePath().c_str());
-#endif
-
//
// do the serialization through DOMWriter::writeNode();
//
DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
theOutput->setEncoding(gOutputEncoding);
- theOutput->setByteStream(myFormTarget);
+ theOutput->setByteStream(pFormatTarget);
theSerializer->write(_pDocument, theOutput);
delete theSerializer;
-
- //
- // Filter, formatTarget and error handler
- // are NOT owned by the serializer.
- //
- delete myFormTarget;
- delete myErrorHandler;
-
-// if (gUseFilter)
-// delete myFilter;
-
}
catch (XMLException& e) {
std::cerr << "An error occurred during creation of output transcoder. Msg is:"
@@ -1327,6 +1295,7 @@ void ParameterManager::CreateDocument(void)
{
// creating a document from screatch
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(XStr("Core").unicodeForm());
+ delete _pDocument;
_pDocument = impl->createDocument(
0, // root element namespace URI.
XStr("FCParameters").unicodeForm(), // root element name
@@ -1337,11 +1306,8 @@ void ParameterManager::CreateDocument(void)
_pGroupNode = _pDocument->createElement(XStr("FCParamGroup").unicodeForm());
((DOMElement*)_pGroupNode)->setAttribute(XStr("Name").unicodeForm(), XStr("Root").unicodeForm());
rootElem->appendChild(_pGroupNode);
-
-
}
-
void ParameterManager::CheckDocument() const
{
diff --git a/src/Base/Parameter.h b/src/Base/Parameter.h
index cb5056260..c50e1595a 100644
--- a/src/Base/Parameter.h
+++ b/src/Base/Parameter.h
@@ -60,6 +60,8 @@ XERCES_CPP_NAMESPACE_BEGIN
class DOMNode;
class DOMElement;
class DOMDocument;
+class XMLFormatTarget;
+class InputSource;
XERCES_CPP_NAMESPACE_END
class ParameterManager;
@@ -266,13 +268,11 @@ public:
static void Init(void);
int LoadDocument(const char* sFileName);
-
+ int LoadDocument(const XERCES_CPP_NAMESPACE_QUALIFIER InputSource&);
bool LoadOrCreateDocument(const char* sFileName);
-
void SaveDocument(const char* sFileName) const;
-
+ void SaveDocument(XERCES_CPP_NAMESPACE_QUALIFIER XMLFormatTarget* pFormatTarget) const;
void CreateDocument(void);
-
void CheckDocument() const;
private:
diff --git a/src/Base/PreCompiled.h b/src/Base/PreCompiled.h
index 69bdb90f7..018dbd6a4 100644
--- a/src/Base/PreCompiled.h
+++ b/src/Base/PreCompiled.h
@@ -82,6 +82,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/Base/Tools.cpp b/src/Base/Tools.cpp
index 43f845f0c..4cbab7b9d 100644
--- a/src/Base/Tools.cpp
+++ b/src/Base/Tools.cpp
@@ -24,6 +24,8 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include
+# include
+# include
#endif
# include
@@ -122,6 +124,24 @@ std::string Base::Tools::getIdentifier(const std::string& name)
return CleanName;
}
+std::wstring Base::Tools::widen(const std::string& str)
+{
+ std::wostringstream wstm;
+ const std::ctype& ctfacet = std::use_facet< std::ctype >(wstm.getloc());
+ for (size_t i=0; i& ctfacet = std::use_facet< std::ctype >(stm.getloc());
+ for (size_t i=0; i&,int d=0);
static std::string addNumber(const std::string&, unsigned int, int d=0);
static std::string getIdentifier(const std::string&);
+ static std::wstring widen(const std::string& str);
+ static std::string narrow(const std::wstring& str);
};
} // namespace Base
diff --git a/src/Base/Uuid.cpp b/src/Base/Uuid.cpp
index 2c1f44fa3..1fac7ac94 100644
--- a/src/Base/Uuid.cpp
+++ b/src/Base/Uuid.cpp
@@ -88,7 +88,7 @@ void Uuid::setValue(const char* sString)
void Uuid::setValue(const std::string &sString)
{
- setValue(sString.c_str());
+ setValue(sString.c_str());
}
const std::string& Uuid::getValue(void) const
diff --git a/src/Doc/sphinx/Document.rst b/src/Doc/sphinx/Document.rst
new file mode 100644
index 000000000..2b8a9d365
--- /dev/null
+++ b/src/Doc/sphinx/Document.rst
@@ -0,0 +1,9 @@
+The FreeCAD Document
+====================
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: DocumentObject
+
+
diff --git a/src/Doc/sphinx/DocumentObject.rst b/src/Doc/sphinx/DocumentObject.rst
new file mode 100644
index 000000000..c32918221
--- /dev/null
+++ b/src/Doc/sphinx/DocumentObject.rst
@@ -0,0 +1,18 @@
+The FreeCAD Document Object
+===========================
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: DocumentObject
+
+ .. autoclass:: DocumentObject
+ :members:
+
+ .. method:: __setstate__(value)
+
+ allows to save custom attributes of this object as strings, so they can be saved when saving the FreeCAD document
+
+ .. method:: __getstate__()
+
+ reads values previously saved with __setstate__()
diff --git a/src/Doc/sphinx/Draft.rst b/src/Doc/sphinx/Draft.rst
index 4479028b1..3ffaa5ec3 100644
--- a/src/Doc/sphinx/Draft.rst
+++ b/src/Doc/sphinx/Draft.rst
@@ -1,5 +1,5 @@
-The Draft module
-================
+Draft module
+============
The Draft module offer several convenient functions to work with simple objects.
@@ -8,19 +8,3 @@ The Draft module offer several convenient functions to work with simple objects.
.. automodule:: Draft
:members:
-
-.. automodule:: DraftSnap
- :members:
-
-The Draft module also contains two submodules, widely used throughout the Draft and Arch modules: DraftVecUtils, which contains useful methods for dealing with vectors, and DraftGeomUtils, which offers many tools for working with OpenCascade geometry.
-
-.. automodule:: DraftVecUtils
- :members:
-
-.. automodule:: DraftGeomUtils
- :members:
-
-The Draft module also features a module that contains trackers, special objects made to display 3D temporary geometry in the 3D scene, that have no real existence in the FreeCAD document.
-
-.. automodule:: DraftTrackers
- :members:
diff --git a/src/Doc/sphinx/DraftGeomUtils.rst b/src/Doc/sphinx/DraftGeomUtils.rst
new file mode 100644
index 000000000..8875a57d3
--- /dev/null
+++ b/src/Doc/sphinx/DraftGeomUtils.rst
@@ -0,0 +1,10 @@
+Draft Geometry Utilities
+========================
+
+The DraftGeomUtils module offer tools to manipulate Part geometry.
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: DraftGeomUtils
+ :members:
diff --git a/src/Doc/sphinx/DraftSnap.rst b/src/Doc/sphinx/DraftSnap.rst
new file mode 100644
index 000000000..ca9089b9d
--- /dev/null
+++ b/src/Doc/sphinx/DraftSnap.rst
@@ -0,0 +1,10 @@
+Draft Snapper
+=============
+
+The Draft Snapper manages object snapping in Draft and Arch modules.
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: DraftSnap
+ :members:
diff --git a/src/Doc/sphinx/DraftTrackers.rst b/src/Doc/sphinx/DraftTrackers.rst
new file mode 100644
index 000000000..6a0ada8c2
--- /dev/null
+++ b/src/Doc/sphinx/DraftTrackers.rst
@@ -0,0 +1,10 @@
+Draft Trackers
+==============
+
+Different trackers (temporary screen widgets) used in the Draft and Arch modules.
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: DraftTrackers
+ :members:
diff --git a/src/Doc/sphinx/DraftVecUtils.rst b/src/Doc/sphinx/DraftVecUtils.rst
new file mode 100644
index 000000000..dbf44d781
--- /dev/null
+++ b/src/Doc/sphinx/DraftVecUtils.rst
@@ -0,0 +1,10 @@
+Draft Vector Utilities
+======================
+
+The DraftVecUtils module offer several convenient utilities to deal with vectors
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: DraftVecUtils
+ :members:
diff --git a/src/Doc/sphinx/FreeCAD.rst b/src/Doc/sphinx/FreeCAD.rst
index eff8e09cf..1a280b6d5 100644
--- a/src/Doc/sphinx/FreeCAD.rst
+++ b/src/Doc/sphinx/FreeCAD.rst
@@ -7,14 +7,5 @@ The FreeCAD module
.. automodule:: FreeCAD
:members:
- .. autoclass:: Vector
- :members:
-
- .. autoclass:: Matrix
- :members:
-
- .. autoclass:: Placement
- :members:
-
.. autoclass:: Console
:members:
diff --git a/src/Doc/sphinx/Matrix.rst b/src/Doc/sphinx/Matrix.rst
new file mode 100644
index 000000000..90e4e8ba3
--- /dev/null
+++ b/src/Doc/sphinx/Matrix.rst
@@ -0,0 +1,10 @@
+The Matrix object
+=================
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: FreeCAD
+
+ .. autoclass:: Matrix
+ :members:
diff --git a/src/Doc/sphinx/Placement.rst b/src/Doc/sphinx/Placement.rst
new file mode 100644
index 000000000..56d596e98
--- /dev/null
+++ b/src/Doc/sphinx/Placement.rst
@@ -0,0 +1,10 @@
+The Placement object
+====================
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: FreeCAD
+
+ .. autoclass:: Placement
+ :members:
diff --git a/src/Doc/sphinx/Vector.rst b/src/Doc/sphinx/Vector.rst
new file mode 100644
index 000000000..f7b8d9287
--- /dev/null
+++ b/src/Doc/sphinx/Vector.rst
@@ -0,0 +1,10 @@
+The Vector object
+=================
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: FreeCAD
+
+ .. autoclass:: Vector
+ :members:
diff --git a/src/Doc/sphinx/ViewProvider.rst b/src/Doc/sphinx/ViewProvider.rst
new file mode 100644
index 000000000..675dbce69
--- /dev/null
+++ b/src/Doc/sphinx/ViewProvider.rst
@@ -0,0 +1,10 @@
+The View Provider object
+========================
+
+.. toctree::
+ :maxdepth: 4
+
+.. automodule:: DocumentObject
+
+ .. autoclass:: ViewProvider
+ :members:
diff --git a/src/Doc/sphinx/_static/freecad.css b/src/Doc/sphinx/_static/freecad.css
index e596ecb35..4f78bb38e 100644
--- a/src/Doc/sphinx/_static/freecad.css
+++ b/src/Doc/sphinx/_static/freecad.css
@@ -1,526 +1,100 @@
-/* FreeCAD CSS template by Yorik */
-
-/* general settings ******************************* */
-
-a, #bodyContent a.external {
- color: #0092E8;
- }
-
-a.new, .new a, #p-cactions .new a, #p-personal a.new {
- color: #FF1F00;
- }
-
-h1 {
- background: #0092E8;
- border: none;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- color: white;
- font-weight: bold;
- padding: 5px;
- margin: 10px 0;
- }
-
-h2 {
- font-weight: normal;
- }
-
-h4 {
- font-size: 90%;
- font-weight: bold;
- }
-
-pre {
- border: 1px solid #AAAAAA;
- background: #EEEEEE;
- }
-
-.docnav {
- background: #D3D7D9;
- padding: 3px;
- border: none;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- margin-top: 15px;
- }
-
-.languages {
- font-size: 9px;
- padding:2px 5px;
- color: #666666;
- border: none;
- border-top: 1px solid #666666;
- margin-top: 10px;
- }
-
-#bodyContent a[href^="https://"], .link-https {
- padding: 0 16px 0 0;
- }
-
-/* homepage ******************************* */
-
-body[class*='page-Main_Page'] {
- text-align: justify;
- }
-
-body[class*='page-Main_Page'] h1 {
- background: none;
- margin-bottom: 0;
- border-bottom: 1px solid #638C9C;
- padding-bottom: 15px;
- }
-
-body[class*='page-Main_Page'] h2 {
- color: #FFF;
- border-bottom: none;
- margin-bottom: 20px !important;
- }
-
-body[class*='page-Main_Page'] h3 {
- color: white;
- font-size: 105%;
- font-weight: bold;
- }
-
-body[class*='page-Main_Page'] h1 .mw-headline {
- font-size: 2em;
- letter-spacing: 20px;
- }
-
-body[class*='page-Main_Page'] #bodyContent a:visited {
- color: #0092E8;
- }
-
-body[class*='page-Main_Page'] h1.firstHeading {
- display:none;
- }
-
-body[class*='page-Main_Page'] #content {
- background: transparent;
- color: white;
- }
-
-body[class*='page-Main_Page'] #content ul {
- list-style-type: none;
- list-style-image: none;
- margin: 0;
- }
-
-/* homepage toolboxes & menus ******************************** */
-
-.main-toolbox {
- float: right;
- width: 300px;
- margin-left: 25px;
- }
-
-.main-menu {
- margin-bottom: 40px;
- }
-
-.main-menu a {
- color: #FFF !important;
- }
-
-.main-content {
- display: table;
- }
-
-#feedholder, #mantisholder, .sidebox, #fbholder {
- max-width: 300px;
- border: 1px solid #AAAAAA;
- background-color:#EEEEEE;
- padding:1.2em;
- color: black;
- margin-top: 10px;
- font-size: 0.85em;
- text-align: left;
- }
-
-#feedholder .title, #mantisholder .title, .sidebox .title {
- font-weight: bold;
- font-size: 1.2em;
- }
-
-#feedholder .title a, #mantisholder .title a, .sidebox .title a {
- float: right;
- }
-
-#fbholder {
- padding: 0;
- }
-
-.downloadbox {
- background: white url(/userapps/mediawiki/yorikvanhavre/nfs/user/y/yo/yorikvanhavre/6/65/Download.jpg) top left no-repeat;
- padding: 10px 10px 10px 80px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- text-align: left;
- margin-bottom: 15px;
- color: black;
- font-weight: bold;
- }
-
-#bodyContent .downloadbox li a.external {
- display: box;
- color: #005295;
- padding: 3px 13px 3px 3px;
- }
-
-/* wikibars ******************************** */
-
-#p-cactions {
- padding: 0 60px;
- /* top: 3px; */
- width: auto;
- z-index: 2;
- }
-
-#p-cactions li, #p-cactions li a, #p-personal li a {
- color: #0092E8;
- background: none;
- padding: 1px 5px !important;
- margin: 0 !important;
- }
-
-#globalWrapper {
- background: #171a2a url(/userapps/mediawiki/yorikvanhavre/nfs/user/y/yo/yorikvanhavre/1/1f/Background.jpg) top left no-repeat !important;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- width: auto !important;
- margin:5px;
- }
-
-.portlet {
- width: auto;
- padding-right: 5px;
- }
-
-.pBody {
- background: transparent;
- border: none;
- padding: 0 }
-
-.pBody a {
- color: white;
- padding: 1px 5px !important;
- }
-
-.portlet ul {
- margin: 0;
- }
-
-.portlet li {
- margin-left: 5px;
- list-style-position: inside;
- }
-
-#column-one {
- margin-left: 3px;
- padding-top: 160px;
- }
-
-#p-cactions li a:hover, #p-personal li a:hover, #p-cactions li.selected a, #bodyContent .downloadbox li a.external:hover {
- color: white;
- background: #0092E8;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- text-decoration: none;
- }
-
-/* content ******************************** */
-
-#column-content {
- margin:0 0 0.6em -12.2em !important;
- padding: 5px;
- width: 96%;
- }
-
-#content {
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- }
-
-#content, #p-cactions li {
- border: none;
- padding: 0.6em 1em 1em;
- }
-
-#footer {
- background: none;
- border: none;
- color: #fff;
- }
-
-/* sidebar ******************************** */
-
-.portlet h5 {
- color: #638C9C;
- text-transform: uppercase;
- font-size: 75%;
- height: 15px;
- display: block;
- margin-bottom: 5px;
- border-bottom: 1px solid #638C9C;
- padding-left: 10px;
- }
-
-#p- h5 {
- display: none;
- }
-
-#p-search, #p-Documentation, #p-tb, #p-languages, #p-Meta, #p-Feedback, #p-Manual {
- max-width: 180px;
- }
-
-#n-Basic, #n-Advanced, #n-Development, #n-Using-FreeCAD, #n-Python-Scripting {
- list-style: none;
- font-size: 12px;
- text-transform: uppercase;
- font-weight: bold;
- padding: 3px 0;
- }
-
-#n-Home {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/9/9a/Home.png);
- }
-
-#n-Features {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/5/53/Features16.png);
- }
-
-#n-Screenshots {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/e/ef/Screenshots16.png);
- }
-
-#n-Downloads {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/e/ed/Download16.png);
- }
-
-#n-Getting-Started {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/b/b4/Gettingstarted16.png);
- }
-
-#n-FAQ {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/8/86/Faq16.png);
- }
-
-#n-Forum {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/6/6a/Forum16.png);
- }
-
-#n-Tutorials {
- list-style-image: url(/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/4/46/Tutorials.png);
- }
-
-/* Commands Template******************* */
-
-.ct {
- padding: 5px;
- background: #eeeeee;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- margin: 5px 0 15px 8px;
- }
-
-.ctEven {
- background-color:#F9F9F9;
- border:1px solid #AAAAAA;
- padding: 2px;
- }
-
-.ctToc .toc {
- width: 100%;
- }
-
-.left {
- text-align: left;
- }
-
-/* API ******************************** */
-
-.api {
- margin-left: 30px;
- }
-
-.api .function, dl dt {
- padding: 3px 2px 3px 20px;
- border-radius: 3px;
- }
-
-dl.class dt {
- background: #dddddd url("http://sourceforge.net/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/0/0f/Class.png") left center no-repeat;
- }
-
-dl.function dt, dl.method dt {
- background: #dddddd url("http://sourceforge.net/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/2/20/Method.png") left center no-repeat;
- }
-
-dl.attribute dt {
- background: #dddddd url("http://sourceforge.net/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/4/47/Property.png") left center no-repeat;
- }
-
-dl dt tt {
- font-weight: bold;
- }
-
-dl dt big {
- margin: 0 3px 0 3px;
- font-size: 0.8em;
- }
-
-.api .description {
- padding-left: 30px;
- }
-
-.highlight {
- background: #ffffff !important;
- margin-bottom: 40px;
- }
-
-.highlight pre {
- margin-left: 30px;
- padding: 5px;
- }
-
-/* Screenshots ************************ */
-
-.screenthumbs {
- padding: 5px;
- background: #eeeeee;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- width: 800px;
- }
-
-/* Translations *********************** */
-
-body[class*='_it'] h1.firstHeading, body[class*='_fr'] h1.firstHeading {
- display:none;
- }
-
-h1 .editsection a:link {
- color: white;
- font-weight: normal;
- }
-
-/* Charts *********************** */
-
-.orgchart {
- margin: 10px;
- background: #EEEEEE;
- text-align: center;
- width: 800px;
- padding: 4px;
- border-radius: 5px;
- border-spacing: 0;
- }
-
-.orgheader {
- background: #9FBDE0;
- }
-
-.orgchart td {
- padding: 0;
- }
-/* Printing ************************ */
-
-@media print {
+/* FreeCAD sphinx CSS file */
body {
- font: small sans-serif;
- text-align: left;
- }
-
-a{
- color: blue;
- }
-
-h1 {
- background: none;
- border: none;
- color: black;
- font-weight: bold;
- padding: 5px;
- margin-top: 10px;
- }
-
-#globalWrapper {
- backgound: none;
- }
-
-#column-content {
- margin:0 !important;
- padding: 5px;
- width: auto;
- }
-
-.docnav, .languages, #sf_header {
- display: none;
- }
-
-.toc {
- border: none;
- }
-
-.thumbcaption {
- text-align: left;
- }
-
+ background: #191b26;
+ background-attachment: fixed;
+ background-size: cover;
+ font-family: Arial, Helvetica, sans-serif;
+ color: #eee;
+ opacity: 0.9;
+ text-align: justify;
+ /* font-size: 0.9em; */
}
-/* sphinx-specific *****************************/
-
-body {
- background: #171a2a url(http://www.sourceforge.net/userapps/mediawiki/yorikvanhavre/nfs/user/y/yo/yorikvanhavre/1/1f/Background.jpg) top left no-repeat !important;
- font-family: sans-serif;
- color: #ffffff;
+a {
+ font-weight: bold;
+ text-decoration: none;
+ color: #0F3472;
}
-.document {
- background: url(http://sourceforge.net/apps/mediawiki/free-cad/nfs/project/f/fr/free-cad/7/70/MediaWikiSidebarLogo.png) top left no-repeat;
+a img {
+ border: 0;
}
-.related h3 {
- display: none;
-}
-
-.related ul {
- float: right;
-}
-
-.related ul li {
- display: inline;
- font-size: 0.8em;
-}
-
-.documentwrapper {
- color: #000000;
- background: none repeat scroll 0 0 white;
- border-radius: 5px;
- padding: 0.6em;
- position: relative;
- z-index: 2;
- float: right;
- width: 75%
-}
-
-.sphinxsidebar {
- font-size: 0.8em;
- width: 220px;
- padding-top: 100px;
-}
-
-.clearer {
- clear: both;
+a:hover {
+ text-decoration: underline;
}
a.headerlink {
display: none;
}
-.footer {
- clear: both;
- font-size: 0.7em;
- text-align: center;
+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;
}
+
+h2 {
+ font-size: 18px;
+ margin: 30px 0 0 0;
+}
+
+.document {
+ background-color: #eee;
+ display: table;
+ width: 960px;
+ box-shadow: 0 0 5px #000;
+ padding: 10px;
+ margin: auto;
+ color: #000;
+}
+
+.related {
+ margin: auto;
+ width: 960px;
+}
+
+.related a {
+ color: #1E90FF;
+ font-size: 0.9em;
+}
+
+.related h3 {
+ display: none;
+}
+
+.related li {
+ display: inline;
+}
+
+.footer {
+ margin: auto;
+ width: 960px;
+}
+
+.descname {
+ font-weight: bold;
+}
+
+.function, .attribute, .method {
+ border-bottom: 1px solid #bbb;
+ padding: 10px;
+}
+
+@media print {
+
+.document {
+ box-shadow: none;
+}
+
+.related {
+ display: none;
+}
+
+}
+
diff --git a/src/Doc/sphinx/_templates/searchbox.html b/src/Doc/sphinx/_templates/searchbox.html
index 0c41389fc..b4be3686f 100644
--- a/src/Doc/sphinx/_templates/searchbox.html
+++ b/src/Doc/sphinx/_templates/searchbox.html
@@ -20,7 +20,7 @@
{{ _('Enter search terms or a module, class or function name.') }}
- Go back to the FreeCAD wiki
+ Go back to the FreeCAD homepage
diff --git a/src/Doc/sphinx/conf.py b/src/Doc/sphinx/conf.py
index 512f6f5fc..52c32f05d 100644
--- a/src/Doc/sphinx/conf.py
+++ b/src/Doc/sphinx/conf.py
@@ -53,6 +53,11 @@ elif commands.getstatusoutput("locate FreeCAD/lib")[0] == 0:
path = commands.getstatusoutput("locate FreeCAD/lib")[1].split()[0]
sys.path.append(path)
+# locate TemplatePyMod
+if commands.getstatusoutput("locate TemplatePyMod")[0] == 0:
+ path = commands.getstatusoutput("locate TemplatePyMod")[1].split()[0]
+ sys.path.append(path)
+
import FreeCAD, FreeCADGui
FreeCADGui.showMainWindow() # this is needed for complete import of GUI modules
@@ -86,9 +91,9 @@ copyright = u'2011, Jürgen Riegel, Werner Mayer, Yorik van Havre'
# built documents.
#
# The short X.Y version.
-version = '0.12'
+version = '0.13'
# The full version, including alpha/beta/rc tags.
-release = '0.12'
+release = '0.13'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -155,7 +160,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 = None
# 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/Doc/sphinx/index.rst b/src/Doc/sphinx/index.rst
index bcb2a9599..ff12b2634 100644
--- a/src/Doc/sphinx/index.rst
+++ b/src/Doc/sphinx/index.rst
@@ -13,11 +13,21 @@ This is the complete python API reference of the FreeCAD appication
FreeCAD.rst
FreeCADGui.rst
+ Vector.rst
+ Placement.rst
+ Matrix.rst
+ Document.rst
+ DocumentObject.rst
+ ViewProvider.rst
Mesh.rst
Part.rst
Sketch.rst
PartDesign.rst
Draft.rst
+ DraftVecUtils.rst
+ DraftGeomUtils.rst
+ DraftTrackers.rst
+ DraftSnap.rst
Arch.rst
Drawing.rst
RayTracing.rst
@@ -25,5 +35,4 @@ This is the complete python API reference of the FreeCAD appication
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
-
-* `Go back to the FreeCAD wiki `_
+* `FreeCAD homepage `_
diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp
index 960e2eb7b..7af6737fb 100644
--- a/src/Gui/Application.cpp
+++ b/src/Gui/Application.cpp
@@ -800,19 +800,19 @@ Gui::Document* Application::getDocument(const App::Document* pDoc) const
return 0;
}
-void Application::showViewProvider(App::DocumentObject* obj)
+void Application::showViewProvider(const App::DocumentObject* obj)
{
ViewProvider* vp = getViewProvider(obj);
if (vp) vp->show();
}
-void Application::hideViewProvider(App::DocumentObject* obj)
+void Application::hideViewProvider(const App::DocumentObject* obj)
{
ViewProvider* vp = getViewProvider(obj);
if (vp) vp->hide();
}
-Gui::ViewProvider* Application::getViewProvider(App::DocumentObject* obj) const
+Gui::ViewProvider* Application::getViewProvider(const App::DocumentObject* obj) const
{
App::Document* doc = obj->getDocument();
if (doc) {
diff --git a/src/Gui/Application.h b/src/Gui/Application.h
index bbbf0e923..ad70000a6 100644
--- a/src/Gui/Application.h
+++ b/src/Gui/Application.h
@@ -148,11 +148,11 @@ public:
*/
Gui::Document* getDocument(const App::Document* pDoc) const;
/// Shows the associated view provider of the given object
- void showViewProvider(App::DocumentObject*);
+ void showViewProvider(const App::DocumentObject*);
/// Hides the associated view provider of the given object
- void hideViewProvider(App::DocumentObject*);
+ void hideViewProvider(const App::DocumentObject*);
/// Get the view provider of the given object
- Gui::ViewProvider* getViewProvider(App::DocumentObject*) const;
+ Gui::ViewProvider* getViewProvider(const App::DocumentObject*) const;
//@}
/// true when the application shuting down
diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index 0a80f7b61..166dd4830 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -576,6 +576,7 @@ SOURCE_GROUP("Widget\\iisTaskPanel\\Mocs" FILES ${iis_MOC_SRCS})
# The 3d view
SET(View3D_CPP_SRCS
Flag.cpp
+ GLPainter.cpp
MouseSelection.cpp
NavigationStyle.cpp
InventorNavigationStyle.cpp
@@ -592,6 +593,7 @@ SET(View3D_CPP_SRCS
SET(View3D_SRCS
${View3D_CPP_SRCS}
Flag.h
+ GLPainter.h
MouseSelection.h
NavigationStyle.h
SplitView3DInventor.h
diff --git a/src/Gui/Command.h b/src/Gui/Command.h
index 255a7dd2f..7b77d4a4c 100644
--- a/src/Gui/Command.h
+++ b/src/Gui/Command.h
@@ -184,7 +184,7 @@ public:
/// Get pointer to the Application Window
static Application* getGuiApplication(void);
/// Get a reference to the selection
- Gui::SelectionSingleton& getSelection(void);
+ static Gui::SelectionSingleton& getSelection(void);
/// Get pointer to the active gui document
Gui::Document* getActiveGuiDocument(void) const;
/** Get pointer to the named or active App document
diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp
index 9714ec051..4b2d5b410 100644
--- a/src/Gui/CommandView.cpp
+++ b/src/Gui/CommandView.cpp
@@ -1437,10 +1437,16 @@ void StdCmdToggleNavigation::activated(int iMsg)
bool StdCmdToggleNavigation::isActive(void)
{
+ //#0001087: Inventor Navigation continues with released Mouse Button
+ //This happens because 'Esc' is also used to close the task dialog.
+ //Add also new method 'isRedirectToSceneGraphEnabled' to explicitly
+ //check if this is allowed.
+ if (Gui::Control().activeDialog())
+ return false;
Gui::MDIView* view = Gui::getMainWindow()->activeWindow();
if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer();
- return viewer->isEditing();
+ return viewer->isEditing() && viewer->isRedirectToSceneGraphEnabled();
}
return false;
}
diff --git a/src/Gui/DlgParameterImp.cpp b/src/Gui/DlgParameterImp.cpp
index 586e2c1b9..ee2ab82b8 100644
--- a/src/Gui/DlgParameterImp.cpp
+++ b/src/Gui/DlgParameterImp.cpp
@@ -82,15 +82,18 @@ DlgParameterImp::DlgParameterImp( QWidget* parent, Qt::WFlags fl )
qApp->translate( "Gui::Dialog::DlgParameterImp", "User parameter" );
#endif
- const std::map rcList = App::GetApplication().GetParameterSetList();
+ ParameterManager* sys = App::GetApplication().GetParameterSet("System parameter");
+ const std::map& rcList = App::GetApplication().GetParameterSetList();
for (std::map::const_iterator it= rcList.begin();it!=rcList.end();++it) {
- parameterSet->addItem(tr(it->first.c_str()), QVariant(QByteArray(it->first.c_str())));
+ if (it->second != sys) // for now ignore system parameters because they are nowhere used
+ parameterSet->addItem(tr(it->first.c_str()), QVariant(QByteArray(it->first.c_str())));
}
QByteArray cStr("User parameter");
parameterSet->setCurrentIndex(parameterSet->findData(cStr));
onChangeParameterSet(parameterSet->currentIndex());
- parameterSet->hide();
+ if (parameterSet->count() < 2)
+ parameterSet->hide();
connect(parameterSet, SIGNAL(activated(int)),
this, SLOT(onChangeParameterSet(int)));
@@ -238,6 +241,13 @@ void DlgParameterImp::onChangeParameterSet(int index)
if (!rcParMngr)
return;
+ if (rcParMngr == App::GetApplication().GetParameterSet("System parameter"))
+ buttonSaveToDisk->setEnabled(true);
+ else if (rcParMngr == App::GetApplication().GetParameterSet("User parameter"))
+ buttonSaveToDisk->setEnabled(true);
+ else
+ buttonSaveToDisk->setEnabled(false);
+
// remove all labels
paramGroup->clear();
paramValue->clear();
@@ -282,18 +292,19 @@ void DlgParameterImp::onChangeParameterSet(int index)
if (parent)
paramGroup->setCurrentItem(parent);
+ else if (paramGroup->topLevelItemCount() > 0)
+ paramGroup->setCurrentItem(paramGroup->topLevelItem(0));
}
void DlgParameterImp::on_buttonSaveToDisk_clicked()
{
- ParameterManager* sys = App::GetApplication().GetParameterSet("System parameter");
- if (sys) {
- sys->SaveDocument(App::Application::Config()["SystemParameter"].c_str());
- }
- ParameterManager* user = App::GetApplication().GetParameterSet("User parameter");
- if (user) {
- user->SaveDocument(App::Application::Config()["UserParameter"].c_str());
- }
+ int index = parameterSet->currentIndex();
+ ParameterManager* parmgr = App::GetApplication().GetParameterSet(parameterSet->itemData(index).toByteArray());
+ if (!parmgr) return;
+ if (parmgr == App::GetApplication().GetParameterSet("System parameter"))
+ parmgr->SaveDocument(App::Application::Config()["SystemParameter"].c_str());
+ else if (parmgr == App::GetApplication().GetParameterSet("User parameter"))
+ parmgr->SaveDocument(App::Application::Config()["UserParameter"].c_str());
}
namespace Gui {
diff --git a/src/Gui/DocumentPyImp.cpp b/src/Gui/DocumentPyImp.cpp
index 535e58dd9..450fca8bd 100644
--- a/src/Gui/DocumentPyImp.cpp
+++ b/src/Gui/DocumentPyImp.cpp
@@ -270,7 +270,7 @@ PyObject* DocumentPy::toggleTreeItem(PyObject *args)
Gui::ViewProviderDocumentObject* ActiveVp = dynamic_cast (getDocumentPtr()->getViewProvider(Object)) ;
switch(mod) {
case 0: getDocumentPtr()->signalExpandObject(*ActiveVp,Gui::Toggle); break;
- case 1: getDocumentPtr()->signalExpandObject(*ActiveVp,Gui::Collaps); break;
+ case 1: getDocumentPtr()->signalExpandObject(*ActiveVp,Gui::Collapse); break;
case 2: getDocumentPtr()->signalExpandObject(*ActiveVp,Gui::Expand); break;
}
}
@@ -278,7 +278,6 @@ PyObject* DocumentPy::toggleTreeItem(PyObject *args)
Py_Return;
}
-
Py::Object DocumentPy::getActiveObject(void) const
{
App::DocumentObject *object = getDocumentPtr()->getDocument()->getActiveObject();
diff --git a/src/Gui/Flag.cpp b/src/Gui/Flag.cpp
index bf8e4e500..7ae9c269a 100644
--- a/src/Gui/Flag.cpp
+++ b/src/Gui/Flag.cpp
@@ -27,6 +27,8 @@
# include
#endif
#include
+#include "View3DInventorViewer.h"
+#include "GLPainter.h"
#include "Flag.h"
@@ -192,7 +194,7 @@ const SbVec3f& Flag::getOrigin() const
return this->coord;
}
-void Flag::drawLine (int tox, int toy)
+void Flag::drawLine (View3DInventorViewer* v, int tox, int toy)
{
if (!isVisible())
return;
@@ -204,50 +206,17 @@ void Flag::drawLine (int tox, int toy)
int fromy = pos().y() + height()/2;
if (false) fromx += width();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho(0, view[0], 0, view[1], -1, 1);
-
- // Store GL state
- glPushAttrib(GL_ALL_ATTRIB_BITS);
- GLfloat depthrange[2];
- glGetFloatv(GL_DEPTH_RANGE, depthrange);
- GLdouble projectionmatrix[16];
- glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
-
- glDepthFunc(GL_ALWAYS);
- glDepthMask(GL_TRUE);
- glDepthRange(0,0);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
- glDisable(GL_BLEND);
-
- glColor4f(1.0, 1.0, 1.0, 0.0);
- glViewport(0, 0, view[0], view[1]);
+ GLPainter p;
+ p.begin(v);
+ p.setDrawBuffer(GL_BACK);
// the line
- glLineWidth(1.0f);
- glBegin(GL_LINE_LOOP);
- glVertex3i(fromx, view[1]-fromy, 0);
- glVertex3i(tox , view[1]-toy , 0);
- glEnd();
-
- glPointSize(3.0f);
- glBegin(GL_POINTS);
- glVertex3i(tox , view[1]-toy , 0);
- glEnd();
-
- glFlush();
-
- // Reset original state
- glDepthRange(depthrange[0], depthrange[1]);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixd(projectionmatrix);
-
- glPopAttrib();
- glPopMatrix();
+ p.setLineWidth(1.0f);
+ p.drawLine(fromx, fromy, tox, toy);
+ // the point
+ p.setPointSize(3.0f);
+ p.drawPoint(tox, toy);
+ p.end();
}
void Flag::setText(const QString& t)
diff --git a/src/Gui/Flag.h b/src/Gui/Flag.h
index 2c6d7b05e..36d196a05 100644
--- a/src/Gui/Flag.h
+++ b/src/Gui/Flag.h
@@ -31,7 +31,7 @@
#include
namespace Gui {
-
+class View3DInventorViewer;
/**
* @author Werner Mayer
*/
@@ -47,7 +47,7 @@ public:
QSize sizeHint() const;
void setOrigin(const SbVec3f&);
const SbVec3f& getOrigin() const;
- void drawLine(int tox, int toy);
+ void drawLine(Gui::View3DInventorViewer*, int tox, int toy);
void setText(const QString&);
protected:
diff --git a/src/Gui/GLPainter.cpp b/src/Gui/GLPainter.cpp
new file mode 100644
index 000000000..81bffea6c
--- /dev/null
+++ b/src/Gui/GLPainter.cpp
@@ -0,0 +1,184 @@
+/***************************************************************************
+ * 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 "GLPainter.h"
+#include "View3DInventorViewer.h"
+
+using namespace Gui;
+
+GLPainter::GLPainter() : viewer(0), logicOp(false), lineStipple(false)
+{
+}
+
+GLPainter::~GLPainter()
+{
+ end();
+}
+
+bool GLPainter::begin(View3DInventorViewer* v)
+{
+ if (viewer)
+ return false;
+ viewer = v;
+
+ // Make current context
+ SbVec2s view = viewer->getGLSize();
+ this->width = view[0];
+ this->height = view[1];
+
+ viewer->glLockNormal();
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0, this->width, 0, this->height, -1, 1);
+
+ // Store GL state
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glGetFloatv(GL_DEPTH_RANGE, this->depthrange);
+ glGetDoublev(GL_PROJECTION_MATRIX, this->projectionmatrix);
+
+ glDepthFunc(GL_ALWAYS);
+ glDepthMask(GL_TRUE);
+ glDepthRange(0,0);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glDisable(GL_BLEND);
+
+ glLineWidth(1.0f);
+ glColor4f(1.0, 1.0, 1.0, 0.0);
+ glViewport(0, 0, this->width, this->height);
+ glDrawBuffer(GL_FRONT);
+
+ return true;
+}
+
+bool GLPainter::end()
+{
+ if (!viewer)
+ return false;
+
+ glFlush();
+ if (this->logicOp) {
+ this->logicOp = false;
+ glDisable(GL_COLOR_LOGIC_OP);
+ }
+ if (this->lineStipple) {
+ this->lineStipple = false;
+ glDisable(GL_LINE_STIPPLE);
+ }
+
+ // Reset original state
+ glDepthRange(this->depthrange[0], this->depthrange[1]);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixd(this->projectionmatrix);
+
+ glPopAttrib();
+ glPopMatrix();
+
+ // Release the context
+ viewer->glUnlockNormal();
+
+ viewer = 0;
+ return true;
+}
+
+bool GLPainter::isActive() const
+{
+ return viewer != 0;
+}
+
+void GLPainter::setLineWidth(float w)
+{
+ glLineWidth(w);
+}
+
+void GLPainter::setPointSize(float s)
+{
+ glPointSize(s);
+}
+
+void GLPainter::setColor(float r, float g, float b, float a)
+{
+ glColor4f(r, g, b, a);
+}
+
+void GLPainter::setLogicOp(GLenum mode)
+{
+ glEnable(GL_COLOR_LOGIC_OP);
+ glLogicOp(mode);
+ this->logicOp = true;
+}
+
+void GLPainter::setDrawBuffer(GLenum mode)
+{
+ glDrawBuffer(mode);
+}
+
+void GLPainter::setLineStipple(GLint factor, GLushort pattern)
+{
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(factor, pattern);
+ this->lineStipple = true;
+}
+
+// Draw routines
+void GLPainter::drawRect(int x1, int y1, int x2, int y2)
+{
+ if (!viewer)
+ return;
+
+ glBegin(GL_LINE_LOOP);
+ glVertex3i(x1, this->height-y1, 0);
+ glVertex3i(x2, this->height-y1, 0);
+ glVertex3i(x2, this->height-y2, 0);
+ glVertex3i(x1, this->height-y2, 0);
+ glEnd();
+}
+
+void GLPainter::drawLine (int x1, int y1, int x2, int y2)
+{
+ if (!viewer)
+ return;
+
+ glBegin(GL_LINES);
+ glVertex3i(x1, this->height-y1, 0);
+ glVertex3i(x2, this->height-y2, 0);
+ glEnd();
+}
+
+void GLPainter::drawPoint(int x, int y)
+{
+ if (!viewer)
+ return;
+
+ glBegin(GL_POINTS);
+ glVertex3i(x, this->height-y, 0);
+ glEnd();
+}
diff --git a/src/Gui/GLPainter.h b/src/Gui/GLPainter.h
new file mode 100644
index 000000000..170ce6357
--- /dev/null
+++ b/src/Gui/GLPainter.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * 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 GUI_GLPAINTER_H
+#define GUI_GLPAINTER_H
+
+#ifdef FC_OS_WIN32
+#include
+#endif
+#ifdef FC_OS_MACOSX
+#include
+#else
+#include
+#endif
+
+namespace Gui {
+class View3DInventorViewer;
+class GuiExport GLPainter
+{
+public:
+ GLPainter();
+ virtual ~GLPainter();
+
+ bool begin(View3DInventorViewer*);
+ bool end();
+ bool isActive() const;
+
+ /** @name Setter methods */
+ //@{
+ void setLineWidth(float);
+ void setPointSize(float);
+ void setColor(float, float, float, float=0);
+ void setLogicOp(GLenum);
+ void setDrawBuffer(GLenum);
+ void setLineStipple(GLint factor, GLushort pattern);
+ //@}
+
+ /** @name Draw routines */
+ //@{
+ void drawRect (int x, int y, int w, int h);
+ void drawLine (int x1, int y1, int x2, int y2);
+ void drawPoint(int x, int y);
+ //@}
+
+private:
+ View3DInventorViewer* viewer;
+ GLfloat depthrange[2];
+ GLdouble projectionmatrix[16];
+ GLint width, height;
+ bool logicOp;
+ bool lineStipple;
+};
+
+} // namespace Gui
+
+#endif // GUI_GLPAINTER_H
+
diff --git a/src/Gui/MDIView.cpp b/src/Gui/MDIView.cpp
index c47e628f8..895d4ec4e 100644
--- a/src/Gui/MDIView.cpp
+++ b/src/Gui/MDIView.cpp
@@ -85,6 +85,14 @@ void MDIView::deleteSelf()
delete this;
}
+void MDIView::setOverrideCursor(const QCursor& c)
+{
+}
+
+void MDIView::restoreOverrideCursor()
+{
+}
+
void MDIView::onRelabel(Gui::Document *pDoc)
{
if (!bIsPassive) {
diff --git a/src/Gui/MDIView.h b/src/Gui/MDIView.h
index e96f7e172..eb086c53b 100644
--- a/src/Gui/MDIView.h
+++ b/src/Gui/MDIView.h
@@ -104,6 +104,10 @@ public:
virtual void setCurrentViewMode(ViewMode mode);
ViewMode currentViewMode() const { return currentMode; }
+public Q_SLOTS:
+ virtual void setOverrideCursor(const QCursor&);
+ virtual void restoreOverrideCursor();
+
Q_SIGNALS:
void message(const QString&, int);
diff --git a/src/Gui/MouseSelection.cpp b/src/Gui/MouseSelection.cpp
index a4733b545..dccf87142 100644
--- a/src/Gui/MouseSelection.cpp
+++ b/src/Gui/MouseSelection.cpp
@@ -41,6 +41,7 @@
#include "MouseSelection.h"
#include "View3DInventor.h"
#include "View3DInventorViewer.h"
+#include "GLPainter.h"
using namespace Gui;
@@ -263,10 +264,15 @@ void PolyPickerSelection::draw ()
if (mustRedraw){
if (_cNodeVector.size() > 1) {
QPoint start = _cNodeVector.front();
+ GLPainter p;
+ p.begin(_pcView3D);
+ p.setColor(1.0f,1.0f,1.0f);
+ p.setLogicOp(GL_XOR);
for (std::vector::iterator it = _cNodeVector.begin()+1; it != _cNodeVector.end(); ++it) {
- _pcView3D->drawLine(start.x(),start.y(),it->x(), it->y() );
+ p.drawLine(start.x(),start.y(),it->x(), it->y());
start = *it;
}
+ p.end();
}
// recursive call, but no infinite loop
@@ -279,15 +285,25 @@ void PolyPickerSelection::draw ()
if (_cNodeVector.size() > 2) {
QPoint start = _cNodeVector.front();
- _pcView3D->drawLine(m_iXnew,m_iYnew,start.x(), start.y() );
+ GLPainter p;
+ p.begin(_pcView3D);
+ p.setColor(1.0f,1.0f,1.0f);
+ p.setLogicOp(GL_XOR);
+ p.drawLine(m_iXnew,m_iYnew,start.x(), start.y());
+ p.end();
}
}
else {
- _pcView3D->drawLine(m_iXnew,m_iYnew,m_iXold,m_iYold);
+ GLPainter p;
+ p.begin(_pcView3D);
+ p.setColor(1.0f,1.0f,1.0f);
+ p.setLogicOp(GL_XOR);
+ p.drawLine(m_iXnew,m_iYnew,m_iXold,m_iYold);
if (_cNodeVector.size() > 1) {
QPoint start = _cNodeVector.front();
- _pcView3D->drawLine(m_iXnew,m_iYnew,start.x(), start.y());
+ p.drawLine(m_iXnew,m_iYnew,start.x(), start.y());
}
+ p.end();
}
}
}
@@ -458,6 +474,201 @@ int PolyClipSelection::popupMenu()
// -----------------------------------------------------------------------------------
+BrushSelection::BrushSelection()
+ : r(1.0f), g(0.0f), b(0.0f), a(0.0f), l(2.0f)
+{
+ m_iNodes = 0;
+ m_bWorking = false;
+}
+
+void BrushSelection::initialize()
+{
+ QPixmap p(cursor_cut_scissors);
+ QCursor cursor(p, 4, 4);
+ _pcView3D->getWidget()->setCursor(cursor);
+}
+
+void BrushSelection::terminate()
+{
+}
+
+void BrushSelection::setColor(float r, float g, float b, float a)
+{
+ this->r = r;
+ this->g = g;
+ this->b = b;
+ this->a = a;
+}
+
+void BrushSelection::setLineWidth(float l)
+{
+ this->l = l;
+}
+
+void BrushSelection::draw ()
+{
+ if (mustRedraw){
+ if (_cNodeVector.size() > 1) {
+ QPoint start = _cNodeVector.front();
+ GLPainter p;
+ p.begin(_pcView3D);
+ p.setLineWidth(this->l);
+ p.setColor(this->r, this->g, this->b, this->a);
+ for (std::vector::iterator it = _cNodeVector.begin()+1; it != _cNodeVector.end(); ++it) {
+ p.drawLine(start.x(),start.y(),it->x(), it->y());
+ start = *it;
+ }
+ p.end();
+ }
+
+ // recursive call, but no infinite loop
+ mustRedraw = false;
+ draw();
+ }
+ if (m_bWorking) {
+ GLPainter p;
+ p.begin(_pcView3D);
+ p.setLineWidth(this->l);
+ p.setColor(this->r, this->g, this->b, this->a);
+ p.drawLine(m_iXnew, m_iYnew, m_iXold, m_iYold);
+ p.end();
+ }
+}
+
+BrushSelection::~BrushSelection()
+{
+}
+
+int BrushSelection::popupMenu()
+{
+ QMenu menu;
+ QAction* fi = menu.addAction(QObject::tr("Finish"));
+ menu.addAction(QObject::tr("Clear"));
+ QAction* ca = menu.addAction(QObject::tr("Cancel"));
+ if (getPositions().size() < 3)
+ fi->setEnabled(false);
+ QAction* id = menu.exec(QCursor::pos());
+ if (id == fi)
+ return Finish;
+ else if (id == ca)
+ return Cancel;
+ else
+ return Restart;
+}
+
+int BrushSelection::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoint& pos)
+{
+ const int button = e->getButton();
+ const SbBool press = e->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
+
+ if (press) {
+ switch (button)
+ {
+ case SoMouseButtonEvent::BUTTON1:
+ {
+ // start working from now on
+ if (!m_bWorking) {
+ m_bWorking = true;
+ // clear the old polygon
+ _cNodeVector.clear();
+ _pcView3D->getGLWidget()->update();
+
+ _cNodeVector.push_back(pos);
+
+ m_iXnew = pos.x(); m_iYnew = pos.y();
+ m_iXold = pos.x(); m_iYold = pos.y();
+ }
+ } break;
+ case SoMouseButtonEvent::BUTTON2:
+ {
+ if (_cNodeVector.size() > 0) {
+ if (_cNodeVector.back() != pos)
+ _cNodeVector.push_back(pos);
+ m_iXnew = pos.x(); m_iYnew = pos.y();
+ m_iXold = pos.x(); m_iYold = pos.y();
+ }
+ } break;
+ default:
+ {
+ } break;
+ }
+ }
+ // release
+ else {
+ switch (button)
+ {
+ case SoMouseButtonEvent::BUTTON1:
+ return Finish;
+ case SoMouseButtonEvent::BUTTON2:
+ {
+ QCursor cur = _pcView3D->getWidget()->cursor();
+ _pcView3D->getWidget()->setCursor(m_cPrevCursor);
+
+ // The pop-up menu should be shown when releasing mouse button because
+ // otherwise the navigation style doesn't get the UP event and gets into
+ // an inconsistent state.
+ int id = popupMenu();
+ if (id == Finish || id == Cancel) {
+ releaseMouseModel();
+ }
+ else if (id == Restart) {
+ m_bWorking = false;
+ m_iNodes = 0;
+ _pcView3D->getWidget()->setCursor(cur);
+ }
+ return id;
+ } break;
+ default:
+ {
+ } break;
+ }
+ }
+
+ return Continue;
+}
+
+int BrushSelection::locationEvent(const SoLocation2Event * const e, const QPoint& pos)
+{
+ // do all the drawing stuff for us
+ QPoint clPoint = pos;
+
+ if (m_bWorking) {
+ // check the position
+ QRect r = _pcView3D->getGLWidget()->rect();
+ if (!r.contains(clPoint)) {
+ if (clPoint.x() < r.left())
+ clPoint.setX( r.left());
+ if (clPoint.x() > r.right())
+ clPoint.setX(r.right());
+ if (clPoint.y() < r.top())
+ clPoint.setY(r.top());
+ if (clPoint.y() > r.bottom())
+ clPoint.setY(r.bottom());
+ }
+
+ SbVec2s last = _clPoly.back();
+ SbVec2s curr = e->getPosition();
+ if (abs(last[0]-curr[0]) > 20 || abs(last[1]-curr[1]) > 20)
+ _clPoly.push_back(curr);
+ _cNodeVector.push_back(clPoint);
+ }
+
+ m_iXnew = clPoint.x();
+ m_iYnew = clPoint.y();
+ draw();
+ m_iXold = clPoint.x();
+ m_iYold = clPoint.y();
+
+ return Continue;
+}
+
+int BrushSelection::keyboardEvent( const SoKeyboardEvent * const e )
+{
+ return Continue;
+}
+
+// -----------------------------------------------------------------------------------
+
RectangleSelection::RectangleSelection()
{
m_bWorking = false;
@@ -477,8 +688,16 @@ void RectangleSelection::terminate()
void RectangleSelection::draw ()
{
- if (m_bWorking)
- _pcView3D->drawRect(m_iXold, m_iYold, m_iXnew, m_iYnew);
+ if (m_bWorking) {
+ GLPainter p;
+ p.begin(_pcView3D);
+ p.setColor(1.0, 1.0, 0.0, 0.0);
+ p.setLogicOp(GL_XOR);
+ p.setLineWidth(3.0f);
+ p.setLineStipple(2, 0x3F3F);
+ p.drawRect(m_iXold, m_iYold, m_iXnew, m_iYnew);
+ p.end();
+ }
}
int RectangleSelection::mouseButtonEvent( const SoMouseButtonEvent * const e, const QPoint& pos )
diff --git a/src/Gui/MouseSelection.h b/src/Gui/MouseSelection.h
index fd8716e72..b26cdea30 100644
--- a/src/Gui/MouseSelection.h
+++ b/src/Gui/MouseSelection.h
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
// forwards
class QMouseEvent;
@@ -156,6 +157,45 @@ protected:
// -----------------------------------------------------------------------------------
+/**
+ * The brush selection class
+ * \author Werner Mayer
+ */
+class GuiExport BrushSelection : public BaseMouseSelection
+{
+public:
+ BrushSelection();
+ virtual ~BrushSelection();
+
+ /// set the new mouse cursor
+ virtual void initialize();
+ /// do nothing
+ virtual void terminate();
+
+ // Settings
+ void setColor(float r, float g, float b, float a=0);
+ void setLineWidth(float);
+
+protected:
+ virtual int mouseButtonEvent( const SoMouseButtonEvent * const e, const QPoint& pos );
+ virtual int locationEvent ( const SoLocation2Event * const e, const QPoint& pos );
+ virtual int keyboardEvent ( const SoKeyboardEvent * const e );
+
+ /// draw the polygon
+ virtual void draw ();
+ virtual int popupMenu();
+
+protected:
+ std::vector _cNodeVector;
+ int m_iNodes;
+ bool m_bWorking;
+
+private:
+ float r,g,b,a,l;
+};
+
+// -----------------------------------------------------------------------------------
+
/**
* The selection mouse model class
* Draws a rectangle for selection
diff --git a/src/Gui/Selection.cpp b/src/Gui/Selection.cpp
index ad67904fd..a42da3a64 100644
--- a/src/Gui/Selection.cpp
+++ b/src/Gui/Selection.cpp
@@ -465,32 +465,30 @@ bool SelectionSingleton::setPreselect(const char* pDocName, const char* pObjectN
if (DocName != "")
rmvPreselect();
- if(ActiveGate)
- {
+ if (ActiveGate) {
App::Document* pDoc = getDocument(pDocName);
-
if (pDoc) {
- if(pObjectName){
+ if (pObjectName) {
App::DocumentObject* pObject = pDoc->getObject(pObjectName);
- if(! ActiveGate->allow(pDoc,pObject,pSubName)){
+ if (!ActiveGate->allow(pDoc,pObject,pSubName)) {
snprintf(buf,512,"Not allowed: %s.%s.%s ",pDocName
,pObjectName
,pSubName
);
- if (getMainWindow()){
+ if (getMainWindow()) {
getMainWindow()->showMessage(QString::fromAscii(buf),3000);
Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
- if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
- static_cast(mdi)->setCursor(Qt::ForbiddenCursor);
- }
+ mdi->setOverrideCursor(QCursor(Qt::ForbiddenCursor));
}
return false;
}
- }else
+ }
+ else
return ActiveGate->allow(pDoc,0,0);
- }else
+ }
+ else
return false;
}
@@ -520,13 +518,13 @@ bool SelectionSingleton::setPreselect(const char* pDocName, const char* pObjectN
,Chng.pSubName
,x,y,z);
- if (getMainWindow()){
- getMainWindow()->showMessage(QString::fromAscii(buf),3000);
- Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
- if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
- static_cast(mdi)->setCursor(Qt::ArrowCursor);
- }
- }
+ //FIXME: We shouldn't replace the possibly defined edit cursor
+ //with the arrow cursor. But it seems that we don't even have to.
+ //if (getMainWindow()){
+ // getMainWindow()->showMessage(QString::fromAscii(buf),3000);
+ // Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
+ // mdi->restoreOverrideCursor();
+ //}
Notify(Chng);
signalSelectionChanged(Chng);
@@ -587,11 +585,9 @@ void SelectionSingleton::rmvPreselect()
hy = 0;
hz = 0;
- if (getMainWindow()){
+ if (ActiveGate && getMainWindow()) {
Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
- if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
- static_cast(mdi)->setCursor(Qt::ArrowCursor);
- }
+ mdi->restoreOverrideCursor();
}
//Base::Console().Log("Sel : Rmv preselect \n");
@@ -605,7 +601,7 @@ const SelectionChanges &SelectionSingleton::getPreselection(void) const
// add a SelectionGate to control what is selectable
void SelectionSingleton::addSelectionGate(Gui::SelectionGate *gate)
{
- if(ActiveGate)
+ if (ActiveGate)
rmvSelectionGate();
ActiveGate = gate;
@@ -621,9 +617,7 @@ void SelectionSingleton::rmvSelectionGate(void)
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (doc) {
Gui::MDIView* mdi = doc->getActiveView();
- if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
- static_cast(mdi)->setCursor(Qt::ArrowCursor);
- }
+ mdi->restoreOverrideCursor();
}
}
}
@@ -654,15 +648,12 @@ bool SelectionSingleton::addSelection(const char* pDocName, const char* pObjectN
temp.pObject = 0;
// check for a Selection Gate
- if(ActiveGate)
- {
- if(! ActiveGate->allow(temp.pDoc,temp.pObject,pSubName)){
- if (getMainWindow()){
+ if (ActiveGate) {
+ if (!ActiveGate->allow(temp.pDoc,temp.pObject,pSubName)) {
+ if (getMainWindow()) {
getMainWindow()->showMessage(QString::fromAscii("Selection not allowed by filter"),5000);
Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
- if (mdi && mdi->isDerivedFrom(View3DInventor::getClassTypeId())) {
- static_cast(mdi)->setCursor(Qt::ForbiddenCursor);
- }
+ mdi->setOverrideCursor(Qt::ForbiddenCursor);
}
QApplication::beep();
return false;
diff --git a/src/Gui/SelectionObjectPyImp.cpp b/src/Gui/SelectionObjectPyImp.cpp
index 5cd52a9f3..34200b241 100644
--- a/src/Gui/SelectionObjectPyImp.cpp
+++ b/src/Gui/SelectionObjectPyImp.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (c) 2009 Juergen Riegel (FreeCAD@juergen-riegel.net) *
+ * Copyright (c) 2009 Juergen Riegel (FreeCAD@juergen-riegel.net) *
* *
* This file is part of the FreeCAD CAx development system. *
* *
diff --git a/src/Gui/SoAxisCrossKit.h b/src/Gui/SoAxisCrossKit.h
index 488c51ee8..644cd6452 100644
--- a/src/Gui/SoAxisCrossKit.h
+++ b/src/Gui/SoAxisCrossKit.h
@@ -26,6 +26,7 @@
#include
#include
+#include
#include
#include
#include
diff --git a/src/Gui/SplitView3DInventor.cpp b/src/Gui/SplitView3DInventor.cpp
index 5ea8d3fa0..33879ffb2 100644
--- a/src/Gui/SplitView3DInventor.cpp
+++ b/src/Gui/SplitView3DInventor.cpp
@@ -204,7 +204,7 @@ void AbstractSplitView::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp
}
else if (strcmp(Reason,"Gradient") == 0) {
for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it)
- (*it)->setGradientBackgroud((rGrp.GetBool("Gradient",true)));
+ (*it)->setGradientBackground((rGrp.GetBool("Gradient",true)));
}
else if (strcmp(Reason,"UseAntialiasing") == 0) {
for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it)
@@ -238,9 +238,9 @@ void AbstractSplitView::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp
for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) {
(*it)->setBackgroundColor(SbColor(r1, g1, b1));
if (rGrp.GetBool("UseBackgroundColorMid",false) == false)
- (*it)->setGradientBackgroudColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3));
+ (*it)->setGradientBackgroundColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3));
else
- (*it)->setGradientBackgroudColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3), SbColor(r4, g4, b4));
+ (*it)->setGradientBackgroundColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3), SbColor(r4, g4, b4));
}
}
}
@@ -354,7 +354,7 @@ bool AbstractSplitView::onHasMsg(const char* pMsg) const
return false;
}
-void AbstractSplitView::setCursor(const QCursor& aCursor)
+void AbstractSplitView::setOverrideCursor(const QCursor& aCursor)
{
//_viewer->getWidget()->setCursor(aCursor);
}
diff --git a/src/Gui/SplitView3DInventor.h b/src/Gui/SplitView3DInventor.h
index de7254ec4..2131f93a1 100644
--- a/src/Gui/SplitView3DInventor.h
+++ b/src/Gui/SplitView3DInventor.h
@@ -54,7 +54,7 @@ public:
View3DInventorViewer *getViewer(unsigned int) const;
- void setCursor(const QCursor&);
+ void setOverrideCursor(const QCursor&);
protected:
void setupSettings();
diff --git a/src/Gui/TaskView/TaskView.cpp b/src/Gui/TaskView/TaskView.cpp
index d5f647809..aa52c86e7 100644
--- a/src/Gui/TaskView/TaskView.cpp
+++ b/src/Gui/TaskView/TaskView.cpp
@@ -61,7 +61,72 @@ TaskWidget::~TaskWidget()
{
}
+//**************************************************************************
+//**************************************************************************
+// TaskGroup
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+TaskGroup::TaskGroup(QWidget *parent)
+ : iisTaskGroup(parent, false)
+{
+ setScheme(iisFreeCADTaskPanelScheme::defaultScheme());
+}
+
+TaskGroup::~TaskGroup()
+{
+}
+
+namespace Gui { namespace TaskView {
+class TaskIconLabel : public iisIconLabel {
+public:
+ TaskIconLabel(const QIcon &icon,
+ const QString &title,
+ QWidget *parent = 0)
+ : iisIconLabel(icon, title, parent) {
+ // do not allow to get the focus because when hiding the task box
+ // it could cause to activate another MDI view.
+ setFocusPolicy(Qt::NoFocus);
+ }
+ void setTitle(const QString &text) {
+ myText = text;
+ update();
+ }
+};
+}
+}
+
+void TaskGroup::actionEvent (QActionEvent* e)
+{
+ QAction *action = e->action();
+ switch (e->type()) {
+ case QEvent::ActionAdded:
+ {
+ TaskIconLabel *label = new TaskIconLabel(
+ action->icon(), action->text(), this);
+ this->addIconLabel(label);
+ connect(label,SIGNAL(clicked()),action,SIGNAL(triggered()));
+ break;
+ }
+ case QEvent::ActionChanged:
+ {
+ // update label when action changes
+ QBoxLayout* bl = this->groupLayout();
+ int index = this->actions().indexOf(action);
+ if (index < 0) break;
+ QWidgetItem* item = static_cast(bl->itemAt(index));
+ TaskIconLabel* label = static_cast(item->widget());
+ label->setTitle(action->text());
+ break;
+ }
+ case QEvent::ActionRemoved:
+ {
+ // cannot change anything
+ break;
+ }
+ default:
+ break;
+ }
+}
//**************************************************************************
//**************************************************************************
@@ -125,25 +190,6 @@ void TaskBox::hideGroupBox()
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
}
-namespace Gui { namespace TaskView {
-class TaskIconLabel : public iisIconLabel {
-public:
- TaskIconLabel(const QIcon &icon,
- const QString &title,
- QWidget *parent = 0)
- : iisIconLabel(icon, title, parent) {
- // do not allow to get the focus because when hiding the task box
- // it could cause to activate another MDI view.
- setFocusPolicy(Qt::NoFocus);
- }
- void setTitle(const QString &text) {
- myText = text;
- update();
- }
-};
-}
-}
-
void TaskBox::actionEvent (QActionEvent* e)
{
QAction *action = e->action();
diff --git a/src/Gui/TaskView/TaskView.h b/src/Gui/TaskView/TaskView.h
index 9b388d5a2..72b8100f7 100644
--- a/src/Gui/TaskView/TaskView.h
+++ b/src/Gui/TaskView/TaskView.h
@@ -57,6 +57,18 @@ public:
//~TaskContent();
};
+class GuiExport TaskGroup : public iisTaskGroup, public TaskContent
+{
+ Q_OBJECT
+
+public:
+ TaskGroup(QWidget *parent = 0);
+ ~TaskGroup();
+
+protected:
+ void actionEvent (QActionEvent*);
+};
+
/// Father class of content with header and Icon
class GuiExport TaskBox : public iisTaskBox, public TaskContent
{
diff --git a/src/Gui/Thumbnail.cpp b/src/Gui/Thumbnail.cpp
index df5cbdf3a..aeb0a594a 100644
--- a/src/Gui/Thumbnail.cpp
+++ b/src/Gui/Thumbnail.cpp
@@ -87,6 +87,19 @@ void Thumbnail::SaveDocFile (Base::Writer &writer) const
QImage img;
try {
this->viewer->savePicture(this->size, this->size, View3DInventorViewer::Current, img);
+ // Alternative way of off-screen rendering
+#if 0
+ QGLFramebufferObject fbo(this->size, this->size,QGLFramebufferObject::Depth);
+ fbo.bind();
+ glEnable(GL_DEPTH_TEST);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glDepthRange(0.1,1.0);
+ glEnable(GL_LINE_SMOOTH);
+ SoGLRenderAction gl(SbViewportRegion(this->size,this->size));
+ gl.apply(this->viewer->getSceneManager()->getSceneGraph());
+ fbo.release();
+ img = fbo.toImage();
+#endif
}
catch (...) {
return; // offscreen rendering failed
diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp
index 67190c4fe..4faa227fd 100644
--- a/src/Gui/Tree.cpp
+++ b/src/Gui/Tree.cpp
@@ -893,7 +893,6 @@ void DocumentItem::slotActiveObject(const Gui::ViewProviderDocumentObject& obj)
void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& obj,const Gui::HighlightMode& high,bool set)
{
-
std::string objectName = obj.getObject()->getNameInDocument();
std::map::iterator jt = ObjectMap.find(objectName);
if (jt == ObjectMap.end())
@@ -915,27 +914,26 @@ void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& o
// not defined enum
assert(0);
}
+
jt->second->setFont(0,f);
-
}
void DocumentItem::slotExpandObject (const Gui::ViewProviderDocumentObject& obj,const Gui::TreeItemMode& mode)
{
-
std::string objectName = obj.getObject()->getNameInDocument();
std::map::iterator jt = ObjectMap.find(objectName);
if (jt == ObjectMap.end())
return; // signal is emitted before the item gets created
switch (mode) {
- case Gui::Expand:
+ case Gui::Expand:
jt->second->setExpanded(true);
break;
- case Gui::Collaps:
+ case Gui::Collapse:
jt->second->setExpanded(false);
break;
- case Gui::Toggle:
- if(jt->second->isExpanded())
+ case Gui::Toggle:
+ if (jt->second->isExpanded())
jt->second->setExpanded(false);
else
jt->second->setExpanded(true);
@@ -945,10 +943,8 @@ void DocumentItem::slotExpandObject (const Gui::ViewProviderDocumentObject& obj,
// not defined enum
assert(0);
}
-
}
-
const Gui::Document* DocumentItem::document() const
{
return this->pDocument;
diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h
index 4e616daa5..be1126d6e 100644
--- a/src/Gui/Tree.h
+++ b/src/Gui/Tree.h
@@ -49,8 +49,8 @@ enum HighlightMode { Underlined,
/// highlight modes for the tree items
enum TreeItemMode { Expand,
- Collaps,
- Toggle
+ Collapse,
+ Toggle
};
diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp
index 6c9c207f4..01e5fa115 100644
--- a/src/Gui/View3DInventor.cpp
+++ b/src/Gui/View3DInventor.cpp
@@ -307,7 +307,7 @@ void View3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M
_viewer->setAnimationEnabled(rGrp.GetBool("UseAutoRotation",true));
}
else if (strcmp(Reason,"Gradient") == 0) {
- _viewer->setGradientBackgroud((rGrp.GetBool("Gradient",true)));
+ _viewer->setGradientBackground((rGrp.GetBool("Gradient",true)));
}
else if (strcmp(Reason,"UseAntialiasing") == 0) {
_viewer->getGLRenderAction()->setSmoothing(rGrp.GetBool("UseAntialiasing",false));
@@ -357,9 +357,9 @@ void View3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M
r4 = ((col4 >> 24) & 0xff) / 255.0; g4 = ((col4 >> 16) & 0xff) / 255.0; b4 = ((col4 >> 8) & 0xff) / 255.0;
_viewer->setBackgroundColor(SbColor(r1, g1, b1));
if (rGrp.GetBool("UseBackgroundColorMid",false) == false)
- _viewer->setGradientBackgroudColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3));
+ _viewer->setGradientBackgroundColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3));
else
- _viewer->setGradientBackgroudColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3), SbColor(r4, g4, b4));
+ _viewer->setGradientBackgroundColor(SbColor(r2, g2, b2), SbColor(r3, g3, b3), SbColor(r4, g4, b4));
}
}
@@ -772,12 +772,9 @@ bool View3DInventor::hasClippingPlane() const
return _viewer->hasClippingPlane();
}
-void View3DInventor::setOverlayWidget(GLOverlayWidget* widget)
+void View3DInventor::setOverlayWidget(QWidget* widget)
{
removeOverlayWidget();
- QGLWidget* w = static_cast(_viewer->getGLWidget());
- QImage img = w->grabFrameBuffer();
- widget->setImage(img);
stack->addWidget(widget);
stack->setCurrentIndex(1);
}
@@ -789,14 +786,14 @@ void View3DInventor::removeOverlayWidget()
if (overlay) stack->removeWidget(overlay);
}
-void View3DInventor::setCursor(const QCursor& aCursor)
+void View3DInventor::setOverrideCursor(const QCursor& aCursor)
{
_viewer->getWidget()->setCursor(aCursor);
}
-void View3DInventor::setCursor(Qt::CursorShape aCursor)
+void View3DInventor::restoreOverrideCursor()
{
- _viewer->getWidget()->setCursor(aCursor);
+ _viewer->getWidget()->setCursor(QCursor(Qt::ArrowCursor));
}
void View3DInventor::dump(const char* filename)
diff --git a/src/Gui/View3DInventor.h b/src/Gui/View3DInventor.h
index cfc1f9253..de3bc9249 100644
--- a/src/Gui/View3DInventor.h
+++ b/src/Gui/View3DInventor.h
@@ -100,15 +100,15 @@ public:
void toggleClippingPlane();
bool hasClippingPlane() const;
- void setOverlayWidget(GLOverlayWidget*);
+ void setOverlayWidget(QWidget*);
void removeOverlayWidget();
View3DInventorViewer *getViewer(void) const {return _viewer;}
public Q_SLOTS:
/// override the cursor in this view
- void setCursor(const QCursor&);
- void setCursor(Qt::CursorShape s);
+ void setOverrideCursor(const QCursor&);
+ void restoreOverrideCursor();
void dump(const char* filename);
diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp
index 5e1963687..c53e8b566 100644
--- a/src/Gui/View3DInventorViewer.cpp
+++ b/src/Gui/View3DInventorViewer.cpp
@@ -138,7 +138,7 @@ SOQT_OBJECT_ABSTRACT_SOURCE(View3DInventorViewer);
View3DInventorViewer::View3DInventorViewer (QWidget *parent, const char *name,
SbBool embed, Type type, SbBool build)
: inherited (parent, name, embed, type, build), editViewProvider(0),navigation(0),
- editing(FALSE), redirected(FALSE)
+ editing(FALSE), redirected(FALSE), allowredir(FALSE)
{
Gui::Selection().Attach(this);
@@ -258,7 +258,7 @@ View3DInventorViewer::View3DInventorViewer (QWidget *parent, const char *name,
setViewing(false);
setBackgroundColor(SbColor(0.1f, 0.1f, 0.1f));
- setGradientBackgroud(true);
+ setGradientBackground(true);
// set some callback functions for user interaction
addStartCallback(interactionStartCB);
@@ -420,7 +420,7 @@ void View3DInventorViewer::handleEventCB(void * ud, SoEventCallback * n)
SoGLWidgetElement::set(action->getState(), qobject_cast(that->getGLWidget()));
}
-void View3DInventorViewer::setGradientBackgroud(bool on)
+void View3DInventorViewer::setGradientBackground(bool on)
{
if (on && backgroundroot->findChild(pcBackGround) == -1)
backgroundroot->addChild(pcBackGround);
@@ -428,15 +428,15 @@ void View3DInventorViewer::setGradientBackgroud(bool on)
backgroundroot->removeChild(pcBackGround);
}
-void View3DInventorViewer::setGradientBackgroudColor(const SbColor& fromColor,
- const SbColor& toColor)
+void View3DInventorViewer::setGradientBackgroundColor(const SbColor& fromColor,
+ const SbColor& toColor)
{
pcBackGround->setColorGradient(fromColor, toColor);
}
-void View3DInventorViewer::setGradientBackgroudColor(const SbColor& fromColor,
- const SbColor& toColor,
- const SbColor& midColor)
+void View3DInventorViewer::setGradientBackgroundColor(const SbColor& fromColor,
+ const SbColor& toColor,
+ const SbColor& midColor)
{
pcBackGround->setColorGradient(fromColor, toColor, midColor);
}
@@ -948,7 +948,7 @@ void View3DInventorViewer::actualRedraw(void)
vv.projectToScreen(pt, pt);
int tox = (int)(pt[0] * size[0]);
int toy = (int)((1.0f-pt[1]) * size[1]);
- flag->drawLine(tox, toy);
+ flag->drawLine(this, tox, toy);
}
}
}
@@ -1506,120 +1506,6 @@ void View3DInventorViewer::viewSelection()
root->unref();
}
-// Draw routines
-void View3DInventorViewer::drawRect(int x1, int y1, int x2, int y2)
-{
- // Make current context
- SbVec2s view = this->getGLSize();
- this->glLockNormal();
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho(0, view[0], 0, view[1], -1, 1);
-
- // Store GL state
- glPushAttrib(GL_ALL_ATTRIB_BITS);
- GLfloat depthrange[2];
- glGetFloatv(GL_DEPTH_RANGE, depthrange);
- GLdouble projectionmatrix[16];
- glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
-
- glDepthFunc(GL_ALWAYS);
- glDepthMask(GL_TRUE);
- glDepthRange(0,0);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
- glDisable(GL_BLEND);
-
- glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_XOR);
- glDrawBuffer(GL_FRONT);
- glLineWidth(3.0f);
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(2, 0x3F3F);
- glColor4f(1.0, 1.0, 0.0, 0.0);
- glViewport(0, 0, view[0], view[1]);
-
- glBegin(GL_LINE_LOOP);
- glVertex3i(x1, view[1]-y1, 0);
- glVertex3i(x2, view[1]-y1, 0);
- glVertex3i(x2, view[1]-y2, 0);
- glVertex3i(x1, view[1]-y2, 0);
- glEnd();
-
- glFlush();
- glDisable(GL_LINE_STIPPLE);
- glDisable(GL_COLOR_LOGIC_OP);
-
- // Reset original state
- glDepthRange(depthrange[0], depthrange[1]);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixd(projectionmatrix);
-
- glPopAttrib();
- glPopMatrix();
-
- // Release the context
- this->glUnlockNormal();
-}
-
-void View3DInventorViewer::drawLine (int x1, int y1, int x2, int y2)
-{
- // Make current context
- SbVec2s view = this->getGLSize();
- this->glLockNormal();
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho(0, view[0], 0, view[1], -1, 1);
-
- // Store GL state
- glPushAttrib(GL_ALL_ATTRIB_BITS);
- GLfloat depthrange[2];
- glGetFloatv(GL_DEPTH_RANGE, depthrange);
- GLdouble projectionmatrix[16];
- glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
-
- glDepthFunc(GL_ALWAYS);
- glDepthMask(GL_TRUE);
- glDepthRange(0,0);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
- glDisable(GL_BLEND);
-
- glLineWidth(1.0f);
- glColor4f(1.0, 1.0, 1.0, 0.0);
- glViewport(0, 0, view[0], view[1]);
-
- glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_XOR);
- glDrawBuffer(GL_FRONT);
-
- glBegin(GL_LINES);
- glVertex3i(x1, view[1]-y1, 0);
- glVertex3i(x2, view[1]-y2, 0);
- glEnd();
-
- glFlush();
- glLogicOp(GL_COPY);
- glDisable(GL_COLOR_LOGIC_OP);
-
- // Reset original state
- glDepthRange(depthrange[0], depthrange[1]);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixd(projectionmatrix);
-
- glPopAttrib();
- glPopMatrix();
-
- // Release the context
- this->glUnlockNormal();
-}
-
/*!
Decide if it should be possible to start a spin animation of the
model in the viewer by releasing the mouse button while dragging.
diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h
index 47cb11de9..8b2e295fb 100644
--- a/src/Gui/View3DInventorViewer.h
+++ b/src/Gui/View3DInventorViewer.h
@@ -182,6 +182,8 @@ public:
void setEditingCursor (const QCursor& cursor);
void setRedirectToSceneGraph(SbBool redirect) { this->redirected = redirect; }
SbBool isRedirectedToSceneGraph() const { return this->redirected; }
+ void setRedirectToSceneGraphEnabled(SbBool enable) { this->allowredir = enable; }
+ SbBool isRedirectToSceneGraphEnabled(void) const { return this->allowredir; }
//@}
/** @name Pick actions */
@@ -252,18 +254,12 @@ public:
*/
void viewSelection();
- /** @name Draw routines */
- //@{
- void drawRect (int x, int y, int w, int h);
- void drawLine (int x1, int y1, int x2, int y2);
- //@}
-
- void setGradientBackgroud(bool b);
- void setGradientBackgroudColor(const SbColor& fromColor,
- const SbColor& toColor);
- void setGradientBackgroudColor(const SbColor& fromColor,
- const SbColor& toColor,
- const SbColor& midColor);
+ void setGradientBackground(bool b);
+ void setGradientBackgroundColor(const SbColor& fromColor,
+ const SbColor& toColor);
+ void setGradientBackgroundColor(const SbColor& fromColor,
+ const SbColor& toColor,
+ const SbColor& midColor);
void setEnabledFPSCounter(bool b);
void setNavigationType(Base::Type);
NavigationStyle* navigationStyle() const;
@@ -317,6 +313,7 @@ private:
SbBool editing;
QCursor editCursor;
SbBool redirected;
+ SbBool allowredir;
void setCursorRepresentation(int mode);
@@ -328,6 +325,7 @@ private:
// friends
friend class NavigationStyle;
+ friend class GLPainter;
};
} // namespace Gui
diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py
index 63b5055b6..52cf96397 100644
--- a/src/Mod/Arch/ArchCommands.py
+++ b/src/Mod/Arch/ArchCommands.py
@@ -165,6 +165,9 @@ def removeComponents(objectsList,host=None):
s.remove(o)
h.Subtractions = s
o.ViewObject.show()
+ elif o == s.Base:
+ s.Base = None
+ o.ViewObject.show()
elif tp in ["SectionPlane"]:
a = h.Objects
if o in a:
@@ -569,7 +572,7 @@ class _CommandRemove:
def Activated(self):
sel = FreeCADGui.Selection.getSelection()
FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Ungrouping")))
- if Draft.getType(sel[-1]) in ["Wall","Structure"]:
+ if (Draft.getType(sel[-1]) in ["Wall","Structure"]) and (len(sel) > 1):
host = sel.pop()
ss = "["
for o in sel:
@@ -581,7 +584,7 @@ class _CommandRemove:
FreeCADGui.doCommand("Arch.removeComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")")
else:
FreeCADGui.doCommand("import Arch")
- FreeCADGui.doCommand("Arch.removeComponents("+ss+")")
+ 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 e614a2db2..aa5a30064 100644
--- a/src/Mod/Arch/ArchComponent.py
+++ b/src/Mod/Arch/ArchComponent.py
@@ -25,7 +25,7 @@ __title__="FreeCAD Arch Component"
__author__ = "Yorik van Havre"
__url__ = "http://free-cad.sourceforge.net"
-import FreeCAD,FreeCADGui
+import FreeCAD,FreeCADGui,Draft
from PyQt4 import QtGui,QtCore
from DraftTools import translate
@@ -101,7 +101,8 @@ def removeFromComponent(compobject,subobject):
l = compobject.Subtractions
l.append(subobject)
compobject.Subtractions = l
- subobject.ViewObject.hide()
+ if Draft.getType(subobject) != "Window":
+ subobject.ViewObject.hide()
class ComponentTaskPanel:
@@ -306,7 +307,8 @@ class Component:
if prop in ["Additions","Subtractions"]:
if hasattr(obj,prop):
for o in getattr(obj,prop):
- o.ViewObject.hide()
+ if Draft.getType(o) != "Window":
+ o.ViewObject.hide()
def processSubShapes(self,obj,base):
"Adds additions and subtractions to a base shape"
diff --git a/src/Mod/Arch/ArchFloor.py b/src/Mod/Arch/ArchFloor.py
index f7eb0c75c..bdbcb8b59 100644
--- a/src/Mod/Arch/ArchFloor.py
+++ b/src/Mod/Arch/ArchFloor.py
@@ -78,6 +78,8 @@ class _Floor:
def __init__(self,obj):
obj.addProperty("App::PropertyLength","Height","Base",
str(translate("Arch","The height of this floor")))
+ obj.addProperty("App::PropertyPlacement","Placement","Base",
+ str(translate("Arch","The placement of this group")))
self.Type = "Floor"
obj.Proxy = self
self.Object = obj
@@ -90,10 +92,18 @@ class _Floor:
self.Type = state
def execute(self,obj):
- pass
+ if hasattr(obj,"Placement"):
+ self.OldPlacement = obj.Placement.copy()
def onChanged(self,obj,prop):
self.Object = obj
+ if prop == "Placement":
+ if hasattr(self,"OldPlacement"):
+ delta = obj.Placement.Base.sub(self.OldPlacement.Base)
+ for o in obj.Group:
+ if hasattr(o,"Placement"):
+ o.Placement.move(delta)
+ self.OldPlacement = FreeCAD.Placement(obj.Placement)
def addObject(self,child):
if hasattr(self,"Object"):
diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py
index 7b6c5ff6a..14a9a3f80 100644
--- a/src/Mod/Arch/ArchStructure.py
+++ b/src/Mod/Arch/ArchStructure.py
@@ -68,10 +68,19 @@ class _CommandStructure:
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Structure","Creates a structure object from scratch or from a selected object (sketch, wire, face or solid)")}
def Activated(self):
- FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Structure")))
- FreeCADGui.doCommand("import Arch")
+
+ global QtGui, QtCore
+ from PyQt4 import QtGui, QtCore
+
+ self.Length = 0.5
+ self.Width = 0.2
+ self.Height = 1
+ self.continueCmd = False
sel = FreeCADGui.Selection.getSelection()
if sel:
+ # direct creation
+ FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Structure")))
+ FreeCADGui.doCommand("import Arch")
# if selection contains structs and axes, make a system
st = Draft.getObjectsOfType(sel,"Structure")
ax = Draft.getObjectsOfType(sel,"Axis")
@@ -81,10 +90,90 @@ class _CommandStructure:
# else, do normal structs
for obj in sel:
FreeCADGui.doCommand("Arch.makeStructure(FreeCAD.ActiveDocument." + obj.Name + ")")
+ FreeCAD.ActiveDocument.commitTransaction()
+ FreeCAD.ActiveDocument.recompute()
else:
- FreeCADGui.doCommand("Arch.makeStructure()")
+ # interactive mode
+ import DraftTrackers
+ self.points = []
+ self.tracker = DraftTrackers.boxTracker()
+ self.tracker.on()
+ FreeCADGui.Snapper.getPoint(callback=self.getPoint,movecallback=self.update,extradlg=self.taskbox())
+
+ def getPoint(self,point=None,obj=None):
+ "this function is called by the snapper when it has a 3D point"
+ self.tracker.finalize()
+ if point == None:
+ 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)+')')
+ FreeCADGui.doCommand('s.Placement.Base = '+DraftVecUtils.toString(point))
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
+ if self.continueCmd:
+ self.Activated()
+
+ def taskbox(self):
+ "sets up a taskbox widget"
+ w = QtGui.QWidget()
+ w.setWindowTitle(str(translate("Arch","Structure options")))
+ lay0 = QtGui.QVBoxLayout(w)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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(value4,QtCore.SIGNAL("stateChanged(int)"),self.setContinue)
+ return w
+
+ def update(self,point):
+ "this function is called by the Snapper when the mouse is moved"
+ self.tracker.pos(point)
+
+ def setWidth(self,d):
+ self.Width = d
+ self.tracker.width(d)
+
+ def setHeight(self,d):
+ self.Height = d
+ self.tracker.height(d)
+
+ def setLength(self,d):
+ self.Length = d
+ self.tracker.length(d)
+
+ def setContinue(self,i):
+ self.continueCmd = bool(i)
class _Structure(ArchComponent.Component):
"The Structure object"
diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py
index 5af1c7481..91d3f26f6 100644
--- a/src/Mod/Arch/ArchWall.py
+++ b/src/Mod/Arch/ArchWall.py
@@ -335,6 +335,19 @@ class _Wall(ArchComponent.Component):
self.hideSubobjects(obj,prop)
if prop in ["Base","Height","Width","Align","Additions","Subtractions"]:
self.createGeometry(obj)
+ # propagate movements to children windows
+ if prop == "Placement":
+ if obj.Shape:
+ if not obj.Shape.isNull():
+ vo = obj.Shape.Placement.Base
+ vn = obj.Placement.Base
+ if not DraftVecUtils.equals(vo,vn):
+ delta = vn.sub(vo)
+ for o in obj.OutList:
+ if (Draft.getType(o) == "Window") or Draft.isClone(o,"Window"):
+ o.Placement.move(delta)
+
+
def getDefaultValues(self,obj):
"returns normal,width,height values from this wall"
@@ -472,6 +485,10 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent):
def getIcon(self):
import Arch_rc
+ if hasattr(self,"Object"):
+ for o in self.Object.OutList:
+ if Draft.getType(o) == "Wall":
+ return ":/icons/Arch_Wall_Tree_Assembly.svg"
return ":/icons/Arch_Wall_Tree.svg"
def getDisplayModes(self,vobj):
diff --git a/src/Mod/Arch/Arch_rc.py b/src/Mod/Arch/Arch_rc.py
index ea96da63c..2bc77e48c 100644
--- a/src/Mod/Arch/Arch_rc.py
+++ b/src/Mod/Arch/Arch_rc.py
@@ -2,7 +2,7 @@
# Resource object code
#
-# Created: Sun Mar 24 15:50:46 2013
+# Created: Wed Apr 17 16:59:58 2013
# by: The Resource Compiler for PyQt (Qt v4.8.2)
#
# WARNING! All changes made in this file will be lost!
@@ -27968,6 +27968,163 @@ qt_resource_data = "\
\xba\x70\x69\x20\x5a\xa2\xbd\xe0\xab\x69\x8b\x99\x5e\x5b\x43\xe6\
\xc8\x70\xb7\x67\xbb\xbc\x3a\xbb\x70\x5b\x40\x57\x67\xff\x01\xbd\
\xf5\xc0\x77\
+\x00\x00\x09\xaf\
+\x00\
+\x00\x5c\xa6\x78\x9c\xed\x5c\x6d\x6f\xdb\x38\x12\xfe\x9e\x5f\xa1\
+\x73\xbf\xec\xe2\x2c\x9a\xef\x2f\x6e\x92\xc5\xe1\x8a\x05\x16\xb8\
+\xfb\xb2\xdb\xc3\x7e\x2c\x64\x89\x76\xb4\x95\x25\x43\x92\xe3\xa4\
+\xbf\xfe\x86\xb2\x2c\x4b\xb6\xeb\xa4\x75\x92\x26\x6b\xb9\x48\x13\
+\x91\x43\x8a\x1c\x3e\x9c\x79\x66\xc8\xe4\xf2\x97\xbb\x79\xe2\xdd\
+\xda\xbc\x88\xb3\xf4\x6a\x40\x10\x1e\x78\x36\x0d\xb3\x28\x4e\x67\
+\x57\x83\xff\x7d\xfc\xd5\xd7\x03\xaf\x28\x83\x34\x0a\x92\x2c\xb5\
+\x57\x83\x34\x1b\xfc\x72\x7d\x71\xf9\x0f\xdf\xf7\xfe\x9d\xdb\xa0\
+\xb4\x91\xb7\x8a\xcb\x1b\xef\xb7\xf4\x73\x11\x06\x0b\xeb\xfd\x74\
+\x53\x96\x8b\xf1\x68\xb4\x5a\xad\x50\x5c\x17\xa2\x2c\x9f\x8d\x7e\
+\xf6\x7c\xff\xfa\xe2\xe2\xb2\xb8\x9d\x5d\x78\x9e\x07\xef\x4d\x8b\
+\x71\x14\x5e\x0d\xea\x06\x8b\x65\x9e\x54\x82\x51\x38\xb2\x89\x9d\
+\xdb\xb4\x2c\x46\x04\x91\xd1\x60\x2b\x1e\x6e\xc5\x43\xf7\xf6\xf8\
+\xd6\x86\xd9\x7c\x9e\xa5\x45\xd5\x32\x2d\xde\xb5\x84\xf3\x68\xda\
+\x48\xbb\xd1\xac\x58\x25\x44\x8c\x31\x23\x4c\x47\x94\xfa\x20\xe1\
+\x17\xf7\x69\x19\xdc\xf9\xdd\xa6\x30\xc6\x43\x4d\x29\xc6\x78\x04\
+\x75\x5b\xc9\xc7\x49\x8d\x0b\x50\xe8\x02\xbe\x1a\xf1\x4d\x01\x2a\
+\xb2\x65\x1e\xda\x29\xb4\xb3\x28\xb5\xe5\xe8\xc3\xc7\x0f\x4d\xa5\
+\x8f\x51\x54\x46\xad\x6e\x36\xfa\xec\xbc\xb5\xa3\xe4\x34\x98\xdb\
+\x62\x11\x84\xb6\x18\x6d\xca\xab\xf6\xab\x38\x2a\x6f\xae\x06\x92\
+\x2f\xee\xaa\xe7\x1b\x1b\xcf\x6e\xca\x56\x41\x1c\x5d\x0d\x60\xcc\
+\x54\x13\x59\x3d\xb7\x20\x41\xd6\x02\x75\x77\xe3\xa6\x06\x23\xae\
+\x11\x43\xc4\xcb\x8d\xd6\xeb\x56\x9b\x91\x8f\xa3\x2c\x74\x43\xb9\
+\x1a\xfc\x2b\x0f\x6f\x3e\xfd\x19\x24\xc9\xa7\x8f\xb9\xb5\xc8\xa9\
+\xe5\x1a\x24\x2f\x23\x3b\x2d\x5c\x8b\xf5\x9b\xdd\x13\xbc\x5a\x57\
+\x75\x50\xdb\xbc\x6c\x01\x2f\x5b\xd8\xd0\x2d\xf4\x5a\xba\xf5\x8e\
+\xf2\xde\x69\xa2\x2b\xca\xd6\xea\xf2\x3a\x03\x5e\x7c\xba\x83\xd1\
+\x7a\x63\x8f\x51\xf8\x8f\x1c\x94\xb8\x5f\x4b\x10\x58\x3b\xf8\x86\
+\x0f\xca\x7c\x71\xfa\x3a\xd2\x4d\x3d\x02\x3f\xcb\xe3\x59\x0c\x0a\
+\xaa\xe4\x28\x41\xac\xfa\x74\xdb\xc0\xa4\x5b\x73\xa3\x9a\xf2\x81\
+\x37\x7a\xc4\xec\x77\x1a\x32\x49\xe9\xc3\x03\xc1\x48\xb8\x49\xd5\
+\x03\xd9\x1d\x4a\x77\x86\xa4\x92\x14\x27\x29\xaa\x56\xf7\x6e\x37\
+\x0f\xad\xdc\xf7\x2a\xc0\x37\x67\xae\x02\xc1\xce\x5c\x01\x4a\x9c\
+\xb9\x02\x8c\x3a\x6f\x05\x28\x7a\x60\x0c\x67\xa5\x00\x7e\xe6\x7e\
+\x40\x49\x7e\xe6\x0a\xd0\x67\x6e\x04\x35\x96\x67\xaf\x00\xff\xcc\
+\x99\x80\x66\x7f\xb7\x4d\x70\x39\x72\xc1\x51\xf5\x53\xd3\xc0\x85\
+\x56\xd1\x6d\x6c\x57\xdb\x08\x6a\x12\x14\xb6\xee\x79\x11\xcc\x20\
+\x2a\x4e\xb2\xfc\x6a\xf0\x6e\x5a\x7d\xea\x8a\x49\x96\x47\x36\xdf\
+\x54\xc9\xea\xd3\xa9\xca\x20\x72\x8c\xcb\xfb\x75\x1e\xe0\x62\x47\
+\x89\xd0\x6b\x53\x8f\x0f\xd7\x17\x37\x41\x94\xad\xae\x06\x74\xb7\
+\xf2\x4b\x96\xcd\xa1\x57\xb2\x5b\x1e\x82\x6a\x88\x44\x04\x2b\x2e\
+\xcc\x5e\x25\xbc\x88\x31\x44\x89\x62\x8d\x69\xdb\x56\x2e\xf3\xdc\
+\xa6\xa5\x9f\x04\xf7\x16\x66\x53\x7d\xdb\x74\x5f\xdc\x64\xab\x59\
+\xee\xb4\x52\xe6\x4b\xbb\xdb\x12\x42\xd3\xa5\x4b\x2e\xf8\xcb\x34\
+\x2e\x21\x80\xaf\x03\xe0\x96\x84\x6b\xeb\x4f\x26\xd9\xdd\xe1\x0e\
+\x8a\x34\x58\x1c\xa9\x76\x35\xfe\x22\x28\x6f\x8a\x23\xf5\x69\x16\
+\xd9\xaf\xd4\x37\xdd\xfb\x36\x9a\x59\x7f\x1e\x47\x8b\x2c\x4e\xcb\
+\x07\xa5\x1f\x10\xcc\x26\x7f\xc1\x1e\x39\x36\xb0\x5a\xe2\xc8\xd0\
+\x56\x71\x0a\xeb\xeb\xd7\xc9\x04\x62\xe8\x1e\x0a\x6a\x89\x4d\x7a\
+\x81\x60\xa1\xbe\x22\xe2\x36\xc5\x57\xaa\xee\xbf\x5e\x35\x0f\xee\
+\xe2\x79\xfc\xc5\xc2\xda\xee\x81\xa9\x52\x45\x3d\xfa\x69\x90\x14\
+\x87\x75\x35\x4b\xb2\x49\x90\x6c\x24\xea\x3d\x36\xb7\x65\x10\x05\
+\x65\xb0\xdd\x4f\x9b\x12\x88\xcc\xc9\x26\x2b\x91\x47\xd3\xf1\xef\
+\x1f\x7e\xbd\xae\x37\xf0\x65\x18\x8e\xff\xcc\xf2\xcf\x9b\xfd\xec\
+\x79\x4e\x20\x98\x64\x4b\x98\xf9\xe0\xba\x29\xbe\x8c\xc2\xf1\x34\
+\xcb\xe7\x41\x79\x1d\xcf\x61\x97\xb8\xdc\xd0\x3f\xef\xe6\x09\xec\
+\xec\xa6\xa2\x23\xec\xec\xc1\xb6\xd3\x75\xb7\xb9\x5d\x67\x8a\x0e\
+\xa6\xcb\xa2\x70\x1e\xbb\x46\xa3\x3f\xca\x38\x49\x7e\x73\x2f\x69\
+\xcc\x67\xd3\x69\x5c\x26\xf6\xba\x7a\xe7\xfa\xc7\xcd\x2c\x46\xf5\
+\x34\xea\x49\x8e\x5a\xb3\xbc\x1c\x6d\xd4\x50\x3d\xcd\xb6\xea\xe9\
+\xec\xb7\x46\xc1\x49\x30\xb1\xa0\xda\xff\xb8\x4a\x6f\xaf\x76\x96\
+\x67\xcb\xc5\x1c\xd6\xa7\x6e\xde\xa8\x15\x50\xd7\xd8\xc4\xf2\x3e\
+\x81\xfa\xca\x46\x8d\xdf\xe1\xea\xf3\x7e\x0a\x93\x1a\xbf\x53\x81\
+\xfb\x57\x3d\xf8\xb5\x21\x1a\x93\xf5\x63\xbe\x4c\xec\xd8\xde\x5a\
+\x58\xfc\xe8\x7d\x51\xe6\xd9\x67\xdb\x34\x5e\x3f\xae\x31\x3b\x26\
+\xc8\x68\x0a\x56\x8f\x8a\x4d\x79\x12\xa7\x16\x46\x37\x9e\x2c\xcb\
+\xb2\x5d\xf6\x17\x6c\xa5\x31\x0c\x38\xdd\x74\x08\xfb\xab\xb4\x79\
+\x02\xe8\x2b\xc7\x7c\x53\xb6\x1d\x47\x5d\x10\x05\x60\x03\xf3\x3c\
+\xb8\x1f\xa7\x59\x6a\xdb\xa5\xd9\x74\x5a\xd8\x72\x8c\xdf\xcf\x83\
+\xfc\xb3\xcd\xd7\xf5\xb7\x71\x11\x4f\xe2\xc4\x75\x51\xfd\x98\xd8\
+\xf7\x51\x5c\x2c\x40\x3d\xe3\x38\x75\xc3\x78\x9f\xdd\xda\x7c\x9a\
+\x64\xab\xa6\xde\xa6\x01\x7c\xf3\x27\x41\xf8\x79\x56\x8d\x6f\x1c\
+\x84\x60\xd0\x96\x49\x50\xda\xad\xf7\x81\x25\x72\x6a\xa5\x9a\x63\
+\x9f\xf9\xdc\xc7\xbe\xf6\xb7\x9e\xb1\xde\xc0\x1a\x69\x23\x0d\xa3\
+\x5b\xda\xd4\xa4\x05\x11\x27\x42\x6a\xbc\xa5\xd4\xb0\x5d\x05\x58\
+\x7d\x8a\x25\xd1\x4d\x21\x6c\x54\x8d\x91\x26\x9a\xc8\x6d\x0a\xa6\
+\xcc\x83\xb4\x70\xb0\x86\x4d\x14\x94\x79\x7c\xf7\x13\x88\x60\x86\
+\x15\x36\x72\xe8\x83\x13\x34\x42\x6b\xc6\xc9\x10\x0f\xdd\x17\xfe\
+\x79\xeb\xe9\x1f\x89\x84\xb5\x53\x3b\x15\x09\x1a\xe6\xc2\x89\x31\
+\x67\x84\x04\xb5\x8b\x00\xc2\x11\xd1\x9a\x72\x7d\x00\x01\x4c\x02\
+\x32\x74\x07\x01\x54\x21\x63\x08\x26\xac\x8d\x00\xa6\x11\xc5\x84\
+\x6a\x79\x14\x01\x46\x50\x26\x25\x83\x15\x47\x0c\x73\x23\x24\xef\
+\xd7\xff\xc5\xd7\xdf\xf8\xf2\x44\x04\x70\x86\x04\xa1\x42\xec\x00\
+\x80\x18\x00\x05\x3d\x1d\x00\x8e\x9d\x3c\x02\x00\xa1\x72\xff\x4e\
+\x05\x80\x52\x52\x09\x82\xf9\xdf\x1b\x00\x8e\xcb\x78\x40\xa3\x35\
+\xa6\x42\x8a\x21\x27\x88\x33\xa1\x0c\xf3\x48\xb5\x94\x1c\x9b\x21\
+\x47\xb0\xce\xca\x48\xcf\x57\x88\x70\xae\xa5\x1e\x0a\x58\x24\x22\
+\x98\xf0\xfc\xad\x98\x5f\xcb\x29\xaf\x11\xf3\x6b\x39\xee\x7d\xf9\
+\x9a\xef\x11\xd5\xd7\x36\x30\xda\x06\x31\xc0\x04\x1c\x69\x01\xb6\
+\x16\xba\xcf\x7e\xe8\x14\x66\x29\xac\x48\x99\xe5\x3e\xb0\xfd\xdb\
+\xa0\x5c\xe6\xd6\x31\xc3\x1e\x2d\xcf\x8c\x16\xae\x91\xd0\x5c\x09\
+\x40\x8b\x8b\xcd\x84\x24\x7c\x1f\x2d\x6a\x1f\x2d\xfc\x69\xd0\xf2\
+\x2c\x58\xe9\x49\xe6\x4b\x90\x4c\xb1\xef\x60\xbe\x91\x64\x82\x7d\
+\x32\xc2\x28\x61\xda\x1e\x46\x3a\x5f\x24\x31\x16\x3d\xc9\x7c\x0b\
+\x48\xa0\x27\x92\x0c\xa6\x10\xc6\x5c\xd1\x2e\xcd\x84\x45\x65\x4c\
+\x60\xf6\x62\x34\xb3\xb7\x05\x27\xd8\x82\x53\x83\x4d\xa9\x11\xa7\
+\x4a\xea\x8e\x1d\x30\x12\x09\xac\xb5\x7c\x49\x3b\xd0\xa3\xe0\x24\
+\x8f\xb0\x17\x72\x7e\x2b\x0e\x30\x52\x04\xe3\x8e\x29\xd0\x14\x81\
+\xc9\x68\x1f\xf7\x9c\x00\x83\x9e\x44\x3e\x13\x89\xa4\x88\x69\x69\
+\x88\x19\x32\x58\x58\xc9\x99\xa6\xc7\x48\xa4\x7a\x1c\x89\x54\x8f\
+\x23\x91\xf4\xb9\xc3\x8d\x87\x1a\xf5\x88\x7a\x96\x20\xd6\x70\xc1\
+\xb4\x1a\xba\x70\x16\x48\x95\x22\x9e\x74\xd6\x84\x70\x39\x04\x93\
+\xc0\x09\x93\xe6\x60\x54\xd2\x48\xf9\xb5\x98\x3e\x06\x1e\xee\x1f\
+\x38\xa3\xdb\x83\x4f\xcf\x27\x5f\xcc\x8f\xec\xc5\x14\x1c\xc1\xfa\
+\x6a\xd1\xba\xf1\xd1\xe2\x93\x4a\x77\x2e\x45\xba\xc4\x35\x45\x0a\
+\x53\x2e\xd4\x0e\x9f\x94\x94\x51\x72\x3c\x71\xdd\xf3\xc9\x57\x81\
+\x80\x2a\xb6\x3c\x9d\x51\x52\x05\x9b\xbf\xc3\x28\x35\x74\x42\x25\
+\x7e\x1a\x46\xd9\x3b\x88\x1f\xeb\x20\x84\x42\x0c\x5c\x00\xe1\x2e\
+\xcb\x09\x7e\x42\x48\xe9\x71\x24\xa1\x88\xb1\x21\x41\xe0\x3b\x04\
+\x3f\xe8\x1f\x6a\x21\x3e\xf4\xd7\x52\xcc\x1c\xf5\x0f\xdf\xe2\x1d\
+\x7a\x4c\xfc\x60\xd2\x40\x91\x10\x8a\x4a\x3a\x24\xb0\xb6\xc0\x1f\
+\x04\xf1\x0c\xa2\x58\x70\xe0\x11\xe0\x17\x60\x51\x09\x90\x06\x42\
+\x11\x81\x7d\x6d\xd4\x50\x23\x77\x96\x01\x52\x7e\x23\xe6\x37\x72\
+\x47\xf3\x96\xa4\x75\xf9\xea\xe9\x78\x43\xef\x35\x4e\xf1\x1a\xc0\
+\xe5\x60\x6d\xc8\xae\xeb\x20\x02\x61\x89\xdb\x8c\x60\xe3\x3a\x34\
+\xe0\xc0\x18\xae\xba\x27\xdf\xcc\x79\x7f\x21\x3a\x27\xdf\x92\x23\
+\xc1\x01\x28\x7d\x2e\xe2\x4d\x61\x81\x9f\x88\x05\x2e\x20\x9a\xc5\
+\x58\x76\xb0\x20\xa0\x0f\xae\x0c\xe5\x3d\x18\xde\x0e\x18\x4e\x04\
+\x02\x83\xa8\x52\xb2\x4e\x62\x0a\xb0\x01\x51\x26\xe1\x7d\x7e\xf2\
+\xad\xc0\xc0\xd7\x27\x67\x28\xb9\x41\x46\x61\x4e\x3b\x77\x22\xa4\
+\x40\x82\x11\xfa\xa2\x99\xea\x3e\xc3\xf0\x9d\x48\x38\xf5\xbc\xca\
+\x5d\x8b\x72\x11\x45\x07\x01\x94\x22\x03\xc4\x13\xbf\x5c\x7e\xa1\
+\x5f\xff\xef\xbe\x16\x75\x2a\x02\x38\x43\x5c\x61\xda\x4a\x3b\xd5\
+\x08\x00\xaa\x20\x9e\xe0\xc4\xb2\x8f\x22\x7f\x78\xea\x59\x49\x4a\
+\x05\x1f\x52\x89\x88\xd2\x60\xb8\x1f\x75\x23\x66\x7b\x7f\x8a\xec\
+\x9f\x65\x98\xe6\x2c\x43\x3c\x74\x7d\xea\x9b\x12\xd2\x3d\x58\x7e\
+\xf0\xc9\x97\x86\xc0\x10\x3e\x6c\xc8\xc0\xc5\xc3\x42\xd3\xa3\xd7\
+\xa7\xd4\xe3\x2e\xdb\xa9\xc7\xa2\xe5\x39\x0e\x2f\x7a\x92\x79\x52\
+\xac\x71\x7a\xe6\x9a\x29\x05\xbe\xa1\x93\xb9\x26\x88\x52\xd2\xfa\
+\xbd\xef\x9e\x60\xbe\x5a\x14\xd0\x93\x6f\xde\xbb\xfc\x24\x66\x86\
+\xef\x51\x4c\xa0\x0e\x54\xf7\x04\xe3\x0d\x23\xa5\xf2\x19\x44\x23\
+\xa9\x80\x60\xa8\xa1\xfb\x7b\x31\x42\x18\xa9\x5f\x96\x60\xb4\x8e\
+\xd7\xfa\x33\xef\xd7\x60\x30\x0e\x9d\x77\x12\xc5\x05\x69\xb9\x81\
+\xad\xc9\x70\x8b\xac\xb8\x6a\x9b\x0c\xea\xd2\x53\x94\x28\xd9\x31\
+\x19\xcc\x41\xc3\xe8\x3e\x26\x79\xcb\x58\x59\x9b\x0c\x8c\x20\xb6\
+\x14\x44\x0f\xc1\x78\x30\x41\x9d\xc9\x50\x48\x62\xc6\x88\x19\x52\
+\x77\x51\x52\x12\x71\xd0\x62\xac\xa5\x28\x26\xee\x64\xab\x96\x7b\
+\xd8\x3e\xf4\xb7\x62\x5e\x93\x85\x60\x60\x23\x0e\x65\xb0\x15\x11\
+\x10\x7c\x1c\xb0\x10\x50\x21\x0d\x21\x1d\x52\x61\x10\x15\x44\x31\
+\xde\xb6\x10\x10\xb3\x30\x6a\xf8\x53\x58\x88\x1e\x03\xcf\x8f\x81\
+\xfd\x5f\xe8\x13\xee\xef\x5a\x28\x7a\x00\x02\x40\x2b\x78\x3b\x1d\
+\xb5\x76\x12\x20\x8d\xb1\xde\x81\x80\xd6\x44\xf3\xe3\xa7\x59\x3d\
+\x04\x5e\x01\x04\x54\xeb\xce\xc1\x77\x47\x16\x60\x18\x34\xe9\x1a\
+\x01\x77\x57\x4a\x52\xd9\x23\xe0\xd5\x23\xa0\xa2\x8a\xfb\x09\x6c\
+\x83\x08\x35\x58\x99\x7d\x14\x08\xa4\x09\xb0\x06\x46\xbb\x76\x40\
+\x1a\x4c\x88\x22\x3b\x28\xd0\x8c\x4b\xfc\xc4\xbf\xd8\xdb\x93\xc5\
+\x97\x26\x8b\xff\xf5\x38\x30\x03\xa9\x18\xa6\x43\x82\xa4\x06\x2e\
+\x60\x84\x27\x38\x32\x8a\x2a\xed\xe2\x4b\xae\x60\xf1\xb5\x74\xb7\
+\xf6\x35\x61\xda\x80\x1c\x43\xe0\x45\x04\x73\xb9\x6f\x89\x01\x69\
+\x7c\x08\x8c\x53\x68\x2d\x08\x79\xf0\x1e\x54\x7f\x13\xea\x35\x99\
+\x88\xed\xed\x97\x27\xb8\x07\x45\xa8\xc2\x9d\x90\xb2\xba\xf4\x80\
+\xa5\x3e\x6e\x25\xfa\x4b\x0f\xaf\x0c\x0a\xfb\x29\x49\x09\xe6\x40\
+\xb8\x7b\x8e\x07\xc0\xc0\xb5\xc0\x82\x76\xa2\x07\xe9\xee\xd8\x1a\
+\xa2\x3a\xf7\xa9\xc1\xa6\x28\x0c\x2e\xe3\xf4\x5b\x71\x97\xa3\xd9\
+\xf5\xc5\xa5\xfb\x5b\x49\xd7\x17\xff\x07\x1e\x03\x47\xa2\
\x00\x00\x08\x6a\
\x00\
\x00\x47\x9a\x78\x9c\xed\x5a\xdd\x6f\xe3\x36\x12\x7f\xcf\x5f\xa1\
@@ -33045,6 +33202,11 @@ qt_resource_name = "\
\x00\x41\
\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x43\x00\x65\x00\x6c\x00\x6c\x00\x5f\x00\x54\x00\x72\x00\x65\x00\x65\x00\x2e\x00\x73\x00\x76\
\x00\x67\
+\x00\x1b\
+\x08\x25\x0d\x47\
+\x00\x41\
+\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x57\x00\x61\x00\x6c\x00\x6c\x00\x5f\x00\x54\x00\x72\x00\x65\x00\x65\x00\x5f\x00\x41\x00\x73\
+\x00\x73\x00\x65\x00\x6d\x00\x62\x00\x6c\x00\x79\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x0d\
\x09\x3c\x92\x47\
\x00\x41\
@@ -33179,8 +33341,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\x39\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1e\x00\x00\x00\x1b\
+\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x3a\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1f\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\
@@ -33205,35 +33367,36 @@ 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\x06\x5a\x00\x01\x00\x00\x00\x01\x00\x07\xa2\x92\
-\x00\x00\x05\x3a\x00\x00\x00\x00\x00\x01\x00\x07\x59\x96\
-\x00\x00\x03\xd6\x00\x00\x00\x00\x00\x01\x00\x06\xfb\x9a\
-\x00\x00\x07\x8a\x00\x01\x00\x00\x00\x01\x00\x07\xfa\x67\
-\x00\x00\x06\x2c\x00\x01\x00\x00\x00\x01\x00\x07\x9b\xbd\
-\x00\x00\x04\x10\x00\x01\x00\x00\x00\x01\x00\x07\x0a\x09\
-\x00\x00\x04\x62\x00\x01\x00\x00\x00\x01\x00\x07\x1d\x90\
-\x00\x00\x03\x7a\x00\x01\x00\x00\x00\x01\x00\x06\xe0\xf8\
-\x00\x00\x07\x24\x00\x00\x00\x00\x00\x01\x00\x07\xd7\x23\
-\x00\x00\x05\x7a\x00\x00\x00\x00\x00\x01\x00\x07\x73\x70\
-\x00\x00\x05\x1a\x00\x01\x00\x00\x00\x01\x00\x07\x51\xce\
-\x00\x00\x03\x58\x00\x01\x00\x00\x00\x01\x00\x06\xd7\xff\
-\x00\x00\x06\x00\x00\x01\x00\x00\x00\x01\x00\x07\x90\x93\
-\x00\x00\x06\xfa\x00\x01\x00\x00\x00\x01\x00\x07\xcf\x8e\
-\x00\x00\x04\x3e\x00\x01\x00\x00\x00\x01\x00\x07\x13\x61\
-\x00\x00\x03\x0e\x00\x01\x00\x00\x00\x01\x00\x06\xc5\xe9\
+\x00\x00\x06\x96\x00\x01\x00\x00\x00\x01\x00\x07\xac\x45\
+\x00\x00\x05\x76\x00\x00\x00\x00\x00\x01\x00\x07\x63\x49\
+\x00\x00\x04\x12\x00\x00\x00\x00\x00\x01\x00\x07\x05\x4d\
+\x00\x00\x07\xc6\x00\x01\x00\x00\x00\x01\x00\x08\x04\x1a\
+\x00\x00\x06\x68\x00\x01\x00\x00\x00\x01\x00\x07\xa5\x70\
+\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x07\x13\xbc\
+\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x07\x27\x43\
+\x00\x00\x03\xb6\x00\x01\x00\x00\x00\x01\x00\x06\xea\xab\
+\x00\x00\x07\x60\x00\x00\x00\x00\x00\x01\x00\x07\xe0\xd6\
+\x00\x00\x05\xb6\x00\x00\x00\x00\x00\x01\x00\x07\x7d\x23\
+\x00\x00\x05\x56\x00\x01\x00\x00\x00\x01\x00\x07\x5b\x81\
+\x00\x00\x03\x94\x00\x01\x00\x00\x00\x01\x00\x06\xe1\xb2\
+\x00\x00\x06\x3c\x00\x01\x00\x00\x00\x01\x00\x07\x9a\x46\
\x00\x00\x03\x38\x00\x01\x00\x00\x00\x01\x00\x06\xcf\x91\
-\x00\x00\x05\xaa\x00\x01\x00\x00\x00\x01\x00\x07\x82\xde\
-\x00\x00\x04\xce\x00\x00\x00\x00\x00\x01\x00\x07\x39\x8b\
-\x00\x00\x05\xd8\x00\x01\x00\x00\x00\x01\x00\x07\x88\x2e\
-\x00\x00\x04\xf8\x00\x01\x00\x00\x00\x01\x00\x07\x4a\x0c\
-\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x07\xaa\xd7\
-\x00\x00\x04\x86\x00\x01\x00\x00\x00\x01\x00\x07\x22\xa7\
-\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x07\xc7\x14\
-\x00\x00\x06\xae\x00\x01\x00\x00\x00\x01\x00\x07\xbc\xda\
-\x00\x00\x05\x5a\x00\x01\x00\x00\x00\x01\x00\x07\x6d\x58\
-\x00\x00\x07\x50\x00\x00\x00\x00\x00\x01\x00\x07\xe8\xf2\
-\x00\x00\x03\xac\x00\x00\x00\x00\x00\x01\x00\x06\xe9\x3a\
-\x00\x00\x04\xb0\x00\x00\x00\x00\x00\x01\x00\x07\x2a\x8f\
+\x00\x00\x07\x36\x00\x01\x00\x00\x00\x01\x00\x07\xd9\x41\
+\x00\x00\x04\x7a\x00\x01\x00\x00\x00\x01\x00\x07\x1d\x14\
+\x00\x00\x03\x0e\x00\x01\x00\x00\x00\x01\x00\x06\xc5\xe9\
+\x00\x00\x03\x74\x00\x01\x00\x00\x00\x01\x00\x06\xd9\x44\
+\x00\x00\x05\xe6\x00\x01\x00\x00\x00\x01\x00\x07\x8c\x91\
+\x00\x00\x05\x0a\x00\x00\x00\x00\x00\x01\x00\x07\x43\x3e\
+\x00\x00\x06\x14\x00\x01\x00\x00\x00\x01\x00\x07\x91\xe1\
+\x00\x00\x05\x34\x00\x01\x00\x00\x00\x01\x00\x07\x53\xbf\
+\x00\x00\x06\xc0\x00\x00\x00\x00\x00\x01\x00\x07\xb4\x8a\
+\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x07\x2c\x5a\
+\x00\x00\x07\x0a\x00\x01\x00\x00\x00\x01\x00\x07\xd0\xc7\
+\x00\x00\x06\xea\x00\x01\x00\x00\x00\x01\x00\x07\xc6\x8d\
+\x00\x00\x05\x96\x00\x01\x00\x00\x00\x01\x00\x07\x77\x0b\
+\x00\x00\x07\x8c\x00\x00\x00\x00\x00\x01\x00\x07\xf2\xa5\
+\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x01\x00\x06\xf2\xed\
+\x00\x00\x04\xec\x00\x00\x00\x00\x00\x01\x00\x07\x34\x42\
\x00\x00\x02\xda\x00\x01\x00\x00\x00\x01\x00\x06\xbe\x99\
\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 fcfd728bb..28f691455 100644
--- a/src/Mod/Arch/CMakeLists.txt
+++ b/src/Mod/Arch/CMakeLists.txt
@@ -21,6 +21,7 @@ SET(Arch_SRCS
ArchAxis.py
ArchVRM.py
ArchRoof.py
+ importWebGL.py
)
SOURCE_GROUP("" FILES ${Arch_SRCS})
diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py
index ddba892dc..1f5f2386d 100644
--- a/src/Mod/Arch/InitGui.py
+++ b/src/Mod/Arch/InitGui.py
@@ -129,6 +129,7 @@ class ArchWorkbench(Workbench):
FreeCADGui.addWorkbench(ArchWorkbench)
FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC")
FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ")
+FreeCAD.addExportType("WebGL file (*.html)","importWebGL")
# check for pycollada
try:
import collada
diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc
index 452ecf5b5..8197a7a2c 100644
--- a/src/Mod/Arch/Resources/Arch.qrc
+++ b/src/Mod/Arch/Resources/Arch.qrc
@@ -30,6 +30,7 @@
icons/Arch_Check.svg
icons/Arch_SelectNonManifold.svg
icons/Arch_MergeWalls.svg
+ icons/Arch_Wall_Tree_Assembly.svg
ui/archprefs-base.ui
translations/Arch_af.qm
translations/Arch_de.qm
diff --git a/src/Mod/Arch/Resources/icons/Arch_Wall_Tree_Assembly.svg b/src/Mod/Arch/Resources/icons/Arch_Wall_Tree_Assembly.svg
new file mode 100644
index 000000000..57db4d808
--- /dev/null
+++ b/src/Mod/Arch/Resources/icons/Arch_Wall_Tree_Assembly.svg
@@ -0,0 +1,415 @@
+
+
+
+
diff --git a/src/Mod/Arch/importWebGL.py b/src/Mod/Arch/importWebGL.py
new file mode 100644
index 000000000..1e5d76858
--- /dev/null
+++ b/src/Mod/Arch/importWebGL.py
@@ -0,0 +1,228 @@
+#***************************************************************************
+#* *
+#* 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 *
+#* *
+#***************************************************************************
+
+"FreeCAD webgl exporter"
+
+import FreeCAD,Draft,Part,DraftGeomUtils
+from DraftTools import translate
+
+if FreeCAD.GuiUp:
+ import FreeCADGui
+else:
+ FreeCADGui = None
+
+tab = " "
+addWireframe = False
+
+if open.__module__ == '__builtin__':
+ pythonopen = open
+
+def export(exportList,filename):
+ "exports the given objects to a .html file"
+
+ html = getHTML(exportList)
+ outfile = pythonopen(filename,"wb")
+ outfile.write(html)
+ outfile.close()
+ FreeCAD.Console.PrintMessage(str(translate("Arch","successfully written "))+filename)
+
+def getHTML(objectsList):
+ "returns the complete HTML code of a viewer for the given objects"
+
+ # get objects data
+ objectsData = ''
+ for obj in objectsList:
+ objectsData += getObjectData(obj)
+ template = getTemplate()
+ template = template.replace("$CameraData",getCameraData())
+ template = template.replace("$ObjectsData",objectsData)
+ return template
+
+def getCameraData():
+ "returns the position and direction of the camera as three.js snippet"
+
+ result = ""
+ if FreeCADGui:
+ # getting camera position
+ pos = FreeCADGui.ActiveDocument.ActiveView.viewPosition().Base
+ result += "camera.position.set( "
+ result += str(pos.x) + ", "
+ result += str(pos.y) + ", "
+ result += str(pos.z) + " );\n"
+ else:
+ result += "camera.position.set(0,0,1000);\n"
+ result += tab+"camera.lookAt( scene.position );\n"+tab
+ # print result
+ return result
+
+def getObjectData(obj,wireframeMode="faceloop"):
+ """returns the geometry data of an object as three.js snippet. wireframeMode
+ can be multimaterial, faceloop or None"""
+
+ result = ""
+ wires = []
+
+ if obj.isDerivedFrom("Part::Feature"):
+ fcmesh = obj.Shape.tessellate(0.1)
+ result = "var geom = new THREE.Geometry();\n"
+ # adding vertices data
+ for i in range(len(fcmesh[0])):
+ v = fcmesh[0][i]
+ result += tab+"var v"+str(i)+" = new THREE.Vector3("+str(v.x)+","+str(v.y)+","+str(v.z)+");\n"
+ result += tab+"console.log(geom.vertices)\n"
+ for i in range(len(fcmesh[0])):
+ result += tab+"geom.vertices.push(v"+str(i)+");\n"
+ # adding facets data
+ for f in fcmesh[1]:
+ result += tab+"geom.faces.push( new THREE.Face3"+str(f)+" );\n"
+ for f in obj.Shape.Faces:
+ for w in f.Wires:
+ wo = Part.Wire(DraftGeomUtils.sortEdges(w.Edges))
+ p = []
+ for v in wo.Vertexes:
+ p.append(v.Point)
+ p.append(wo.Vertexes[0].Point)
+ wires.append(p)
+
+ elif obj.isDerivedFrom("Mesh::Feature"):
+ mesh = obj.Mesh
+ result = "var geom = new THREE.Geometry();\n"
+ # adding vertices data
+ for p in mesh.Points:
+ v = p.Vector
+ i = p.Index
+ result += tab+"var v"+str(i)+" = new THREE.Vector3("+str(v.x)+","+str(v.y)+","+str(v.z)+");\n"
+ result += tab+"console.log(geom.vertices)\n"
+ for p in mesh.Points:
+ result += tab+"geom.vertices.push(v"+str(p.Index)+");\n"
+ # adding facets data
+ for f in mesh.Facets:
+ result += tab+"geom.faces.push( new THREE.Face3"+str(f.PointIndices)+" );\n"
+
+ if result:
+ # adding a base material
+ if FreeCADGui:
+ col = obj.ViewObject.ShapeColor
+ rgb = Draft.getrgb(col,testbw=False)
+ else:
+ rgb = "#888888" # test color
+ result += tab+"var basematerial = new THREE.MeshBasicMaterial( { color: 0x"+str(rgb)[1:]+" } );\n"
+ #result += tab+"var basematerial = new THREE.MeshLambertMaterial( { color: 0x"+str(rgb)[1:]+" } );\n"
+
+ if wireframeMode == "faceloop":
+ # adding the mesh to the scene with a wireframe copy
+ result += tab+"var mesh = new THREE.Mesh( geom, basematerial );\n"
+ result += tab+"scene.add( mesh );\n"
+ result += tab+"var linematerial = new THREE.LineBasicMaterial({color: 0x000000,});\n"
+ for w in wires:
+ result += tab+"var wire = new THREE.Geometry();\n"
+ for p in w:
+ result += tab+"wire.vertices.push(new THREE.Vector3("
+ result += str(p.x)+", "+str(p.y)+", "+str(p.z)+"));\n"
+ result += tab+"var line = new THREE.Line(wire, linematerial);\n"
+ result += tab+"scene.add(line);\n"
+
+ elif wireframeMode == "multimaterial":
+ # adding a wireframe material
+ result += tab+"var wireframe = new THREE.MeshBasicMaterial( { color: "
+ result += "0x000000, wireframe: true, transparent: true } );\n"
+ result += tab+"var material = [ basematerial, wireframe ];\n"
+ result += tab+"var mesh = new THREE.SceneUtils.createMultiMaterialObject( geom, material );\n"
+ result += tab+"scene.add( mesh );\n"+tab
+
+ else:
+ # adding the mesh to the scene with simple material
+ result += tab+"var mesh = new THREE.Mesh( geom, basematerial );\n"
+ result += tab+"scene.add( mesh );\n"+tab
+
+ return result
+
+def getTemplate():
+ "returns a html template"
+
+ result = """
+
+
+ FreeCAD model
+
+
+
+
+
+ """
+
+ return result
+
diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt
index 3d1288561..0b0822a83 100644
--- a/src/Mod/Draft/CMakeLists.txt
+++ b/src/Mod/Draft/CMakeLists.txt
@@ -13,6 +13,7 @@ SET(Draft_SRCS
importDXF.py
importOCA.py
importSVG.py
+ importDWG.py
importAirfoilDAT.py
macros.py
Draft_rc.py
diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py
index 8a30efe50..cd9adf39a 100644
--- a/src/Mod/Draft/Draft.py
+++ b/src/Mod/Draft/Draft.py
@@ -101,7 +101,7 @@ def getParamType(param):
"modalt"]:
return "int"
elif param in ["constructiongroupname","textfont","patternFile","template","maxSnapEdges",
- "snapModes"]:
+ "snapModes","FontFile"]:
return "string"
elif param in ["textheight","tolerance","gridSpacing"]:
return "float"
@@ -142,6 +142,11 @@ def precision():
def tolerance():
"tolerance(): returns the tolerance value from Draft user settings"
return getParam("tolerance")
+
+def epsilon():
+ ''' epsilon(): returns a small number based on Draft.tolerance() for use in
+ floating point comparisons. Use with caution. '''
+ return (1.0/(10.0**tolerance()))
def getRealName(name):
"getRealName(string): strips the trailing numbers from a string name"
@@ -803,17 +808,24 @@ def makeArray(baseobject,arg1,arg2,arg3,arg4=None):
select(obj)
return obj
-def makeEllipse(majradius,minradius,placement=None):
- '''makeEllipse(majradius,minradius,[placement]): makes
+def makeEllipse(majradius,minradius,placement=None,face=True,support=None):
+ '''makeEllipse(majradius,minradius,[placement],[face],[support]): makes
an ellipse with the given major and minor radius, and optionally
a placement.'''
- import Part
- e = Part.Ellipse(FreeCAD.Vector(0,0,0),majradius,minradius)
- newobj = FreeCAD.ActiveDocument.addObject("Part::Feature","Ellipse")
- newobj.Shape = e.toShape()
- if placement: newobj.Placement = placement
- FreeCAD.ActiveDocument.recompute()
- return newobj
+ obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Ellipse")
+ _Ellipse(obj)
+ obj.MajorRadius = majradius
+ obj.MinorRadius = minradius
+ obj.Support = support
+ if placement:
+ obj.Placement = placement
+ if gui:
+ _ViewProviderDraft(obj.ViewObject)
+ if not face:
+ obj.ViewObject.DisplayMode = "Wireframe"
+ formatObject(obj)
+ select(obj)
+ return obj
def extrude(obj,vector):
'''makeExtrusion(object,vector): extrudes the given object
@@ -1283,18 +1295,6 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct
return "0.02,0.02"
return "none"
- def getrgb(color):
- "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)
- col = "#"+r+g+b
- if col == "#ffffff":
- print getParam('SvgLinesBlack')
- if getParam('SvgLinesBlack'):
- col = "#000000"
- return col
-
def getProj(vec):
if not plane: return vec
nx = DraftVecUtils.project(vec,plane.u)
@@ -1520,6 +1520,20 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct
else:
svg = getCircle(obj.Shape.Edges[0])
return svg
+
+def getrgb(color,testbw=True):
+ """getRGB(color,[testbw]): returns a rgb value #000000 from a freecad color
+ if testwb = True (default), pure white will be converted into pure black"""
+ 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)
+ col = "#"+r+g+b
+ if testbw:
+ if col == "#ffffff":
+ #print getParam('SvgLinesBlack')
+ if getParam('SvgLinesBlack'):
+ col = "#000000"
+ return col
def makeDrawingView(obj,page,lwmod=None,tmod=None):
'''
@@ -1680,6 +1694,34 @@ def makePoint(X=0, Y=0, Z=0,color=None,name = "Point", point_size= 5):
FreeCAD.ActiveDocument.recompute()
return obj
+def makeShapeString(String,FontFile,Size = 100,Tracking = 0):
+ '''ShapeString(Text,FontFile,Height,Track): Turns a text string
+ into a Compound Shape'''
+
+ # temporary code
+ import platform
+ if not (platform.system() == 'Linux'):
+# if (platform.system() == 'Linux'):
+ FreeCAD.Console.PrintWarning("Sorry, ShapeString is not yet implemented for your platform.\n")
+ return (None)
+ # temporary code
+
+ obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","ShapeString")
+ _ShapeString(obj)
+ obj.String = String
+ obj.FontFile = FontFile
+ obj.Size = Size
+ obj.Tracking = Tracking
+
+ if gui:
+ _ViewProviderDraft(obj.ViewObject)
+ formatObject(obj)
+ obrep = obj.ViewObject
+ if "PointSize" in obrep.PropertiesList: obrep.PointSize = 1 # hide the segment end points
+ select(obj)
+ FreeCAD.ActiveDocument.recompute()
+ return obj
+
def clone(obj,delta=None):
'''clone(obj,[delta]): makes a clone of the given object(s). The clone is an exact,
linked copy of the given object. If the original object changes, the final object
@@ -2998,6 +3040,36 @@ class _Circle(_DraftObject):
shape = Part.Face(shape)
fp.Shape = shape
fp.Placement = plm
+
+class _Ellipse(_DraftObject):
+ "The Circle object"
+
+ def __init__(self, obj):
+ _DraftObject.__init__(self,obj,"Ellipse")
+ obj.addProperty("App::PropertyDistance","MinorRadius","Base",
+ "The minor radius of the ellipse")
+ obj.addProperty("App::PropertyDistance","MajorRadius","Base",
+ "The major radius of the ellipse")
+
+ def execute(self, fp):
+ self.createGeometry(fp)
+
+ def onChanged(self, fp, prop):
+ if prop in ["MinorRadius","MajorRadius"]:
+ self.createGeometry(fp)
+
+ def createGeometry(self,fp):
+ import Part
+ plm = fp.Placement
+ if fp.MajorRadius < fp.MinorRadius:
+ msg(translate("Error: Major radius is smaller than the minor radius"))
+ return
+ if fp.MajorRadius and fp.MinorRadius:
+ shape = Part.Ellipse(Vector(0,0,0),fp.MajorRadius,fp.MinorRadius).toShape()
+ shape = Part.Wire(shape)
+ shape = Part.Face(shape)
+ fp.Shape = shape
+ fp.Placement = plm
class _Wire(_DraftObject):
"The Wire object"
@@ -3369,45 +3441,9 @@ class _Shape2DView(_DraftObject):
if prop in ["Projection","Base","ProjectionMode","FaceNumbers"]:
self.createGeometry(obj)
- def clean(self,shape):
- "returns a valid compound of edges, by recreating them"
- # this is because the projection algorithm somehow creates wrong shapes.
- # they dispay fine, but on loading the file the shape is invalid
- import Part,DraftGeomUtils
- oldedges = shape.Edges
- newedges = []
- for e in oldedges:
- try:
- if DraftGeomUtils.geomType(e) == "Line":
- newedges.append(e.Curve.toShape())
- elif DraftGeomUtils.geomType(e) == "Circle":
- if len(e.Vertexes) > 1:
- mp = DraftGeomUtils.findMidpoint(e)
- a = Part.Arc(e.Vertexes[0].Point,mp,e.Vertexes[-1].Point).toShape()
- newedges.append(a)
- else:
- newedges.append(e.Curve.toShape())
- elif DraftGeomUtils.geomType(e) == "Ellipse":
- if len(e.Vertexes) > 1:
- a = Part.Arc(e.Curve,e.FirstParameter,e.LastParameter).toShape()
- newedges.append(a)
- else:
- newedges.append(e.Curve.toShape())
- elif DraftGeomUtils.geomType(e) == "BSplineCurve":
- if DraftGeomUtils.isLine(e.Curve):
- l = Part.Line(e.Vertexes[0].Point,e.Vertexes[-1].Point).toShape()
- newedges.append(l)
- else:
- newedges.append(e.Curve.toShape())
- else:
- newedges.append(e)
- except:
- print "Debug: error cleaning edge ",e
- return Part.makeCompound(newedges)
-
def getProjected(self,obj,shape,direction):
"returns projected edges from a shape and a direction"
- import Part,Drawing
+ import Part,Drawing,DraftGeomUtils
edges = []
groups = Drawing.projectEx(shape,direction)
for g in groups[0:5]:
@@ -3418,7 +3454,7 @@ class _Shape2DView(_DraftObject):
for g in groups[5:]:
edges.append(g)
#return Part.makeCompound(edges)
- return self.clean(Part.makeCompound(edges))
+ return DraftGeomUtils.cleanProjection(Part.makeCompound(edges))
def createGeometry(self,obj):
import DraftGeomUtils
@@ -3691,6 +3727,91 @@ class _ViewProviderClone(_ViewProviderDraftAlt):
def getIcon(self):
return ":/icons/Draft_Clone.svg"
+
+class _ShapeString(_DraftObject):
+ "The ShapeString object"
+
+ def __init__(self, obj):
+ _DraftObject.__init__(self,obj,"ShapeString")
+ obj.addProperty("App::PropertyString","String","Base","Text string")
+ obj.addProperty("App::PropertyString","FontFile","Base","Font file name")
+ obj.addProperty("App::PropertyFloat","Size","Base","Height of text")
+ obj.addProperty("App::PropertyInteger","Tracking","Base",
+ "Inter-character spacing")
+
+ def execute(self, fp):
+ self.createGeometry(fp)
+
+ def onChanged(self, fp, prop):
+ pass
+
+ def createGeometry(self,fp):
+ import Part
+# import OpenSCAD2Dgeom
+ import os
+ if fp.String and fp.FontFile:
+ if fp.Placement:
+ plm = fp.Placement
+ # TODO: os.path.splitunc() for Win/Samba net files?
+ head, tail = os.path.splitdrive(fp.FontFile) # os.path.splitdrive() for Win
+ head, tail = os.path.split(tail)
+ head = head + '/' # os.split drops last '/' from head
+ CharList = Part.makeWireString(fp.String,
+ head,
+ tail,
+ fp.Size,
+ fp.Tracking)
+ SSChars = []
+ for char in CharList:
+ CharFaces = []
+ for CWire in char:
+ f = Part.Face(CWire)
+ if f:
+ CharFaces.append(f)
+ # whitespace (ex: ' ') has no faces. This breaks OpenSCAD2Dgeom...
+ if CharFaces:
+# s = OpenSCAD2Dgeom.Overlappingfaces(CharFaces).makeshape()
+ s = self.makeGlyph(CharFaces)
+ SSChars.append(s)
+ shape = Part.Compound(SSChars)
+ fp.Shape = shape
+ if plm:
+ fp.Placement = plm
+
+ def makeGlyph(self, facelist):
+ ''' turn list of simple contour faces into a compound shape representing a glyph '''
+ ''' remove cuts, fuse overlapping contours, retain islands '''
+ import Part
+ if len(facelist) == 1:
+ return(facelist[0])
+
+ sortedfaces = sorted(facelist,key=(lambda shape: shape.Area),reverse=True)
+
+ biggest = sortedfaces[0]
+ result = biggest
+ islands =[]
+ for face in sortedfaces[1:]:
+ bcfA = biggest.common(face).Area
+ fA = face.Area
+ difA = abs(bcfA - fA)
+ eps = epsilon()
+# if biggest.common(face).Area == face.Area:
+ if difA <= eps: # close enough to zero
+ # biggest completely overlaps current face ==> cut
+ result = result.cut(face)
+# elif biggest.common(face).Area == 0:
+ elif bcfA <= eps:
+ # island
+ islands.append(face)
+ else:
+ # partial overlap - (font designer error?)
+ result = result.fuse(face)
+ glyphfaces = [result]
+ glyphfaces.extend(islands)
+ ret = Part.Compound(glyphfaces) # should we fuse these instead of making compound?
+ return ret
+
+#----End of Python Features Definitions----#
if gui:
if not hasattr(FreeCADGui,"Snapper"):
diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py
index c5fb3e9a0..1ae0d693f 100755
--- a/src/Mod/Draft/DraftGeomUtils.py
+++ b/src/Mod/Draft/DraftGeomUtils.py
@@ -195,30 +195,13 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F
returns a list containing the intersection point(s) of 2 edges.
You can also feed 4 points instead of edge1 and edge2'''
- pt1 = None
-
- if isinstance(edge1,FreeCAD.Vector) and isinstance(edge2,FreeCAD.Vector):
- # we got points directly
- pt1 = edge1
- pt2 = edge2
- pt3 = infinite1
- pt4 = infinite2
- infinite1 = ex1
- infinite2 = ex2
-
- elif (geomType(edge1) == "Line") and (geomType(edge2) == "Line") :
- # we have 2 straight lines
- pt1, pt2, pt3, pt4 = [edge1.Vertexes[0].Point,
- edge1.Vertexes[1].Point,
- edge2.Vertexes[0].Point,
- edge2.Vertexes[1].Point]
-
+ def getLineIntersections(pt1,pt2,pt3,pt4,infinite1,infinite2):
if pt1:
- # first check if we don't already have coincident endpoints
- if (pt1 in [pt3,pt4]):
- return [pt1]
- elif (pt2 in [pt3,pt4]):
- return [pt2]
+ # first check if we don't already have coincident endpoints
+ if (pt1 in [pt3,pt4]):
+ return [pt1]
+ elif (pt2 in [pt3,pt4]):
+ return [pt2]
norm1 = pt2.sub(pt1).cross(pt3.sub(pt1))
norm2 = pt2.sub(pt4).cross(pt3.sub(pt4))
if not DraftVecUtils.isNull(norm1):
@@ -250,6 +233,26 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F
return [] # Lines have same direction
else :
return [] # Lines aren't on same plane
+
+ pt1 = None
+
+ if isinstance(edge1,FreeCAD.Vector) and isinstance(edge2,FreeCAD.Vector):
+ # we got points directly
+ pt1 = edge1
+ pt2 = edge2
+ pt3 = infinite1
+ pt4 = infinite2
+ infinite1 = ex1
+ infinite2 = ex2
+ return getLineIntersections(pt1,pt2,pt3,pt4,infinite1,infinite2)
+
+ elif (geomType(edge1) == "Line") and (geomType(edge2) == "Line") :
+ # we have 2 straight lines
+ pt1, pt2, pt3, pt4 = [edge1.Vertexes[0].Point,
+ edge1.Vertexes[1].Point,
+ edge2.Vertexes[0].Point,
+ edge2.Vertexes[1].Point]
+ return getLineIntersections(pt1,pt2,pt3,pt4,infinite1,infinite2)
elif (geomType(edge1) == "Circle") and (geomType(edge2) == "Line") \
or (geomType(edge1) == "Line") and (geomType(edge2) == "Circle") :
@@ -419,7 +422,7 @@ def mirror (point, edge):
else:
return None
-def isClockwise(edge):
+def isClockwise(edge,ref=None):
"""Returns True if a circle-based edge has a clockwise direction"""
if not geomType(edge) == "Circle":
return True
@@ -429,11 +432,26 @@ def isClockwise(edge):
# we take an arbitrary other point on the edge that has little chances to be aligned with the first one...
v2 = edge.Curve.tangent(edge.ParameterRange[0]+0.01)[0]
n = edge.Curve.Axis
+ # if that axis points "the wrong way" from the reference, we invert it
+ if not ref:
+ ref = Vector(0,0,1)
+ if n.getAngle(ref) > math.pi/2:
+ n = DraftVecUtils.neg(n)
if DraftVecUtils.angle(v1,v2,n) < 0:
return False
if n.z < 0:
return False
return True
+
+def isWideAngle(edge):
+ """returns True if the given edge is an arc with angle > 180 degrees"""
+ if geomType(edge) != "Circle":
+ return False
+ r = edge.Curve.Radius
+ total = 2*r*math.pi
+ if edge.Length > total/2:
+ return True
+ return False
def findClosest(basepoint,pointslist):
'''
@@ -1652,6 +1670,71 @@ def filletWire(aWire,r,chamfer=False):
filEdges[-1:] = result[0:2]
filEdges[0] = result[2]
return Part.Wire(filEdges)
+
+def getCircleFromSpline(edge):
+ "returns a circle-based edge from a bspline-based edge"
+ if geomType(edge) != "BSplineCurve":
+ return None
+ if len(edge.Vertexes) != 1:
+ return None
+ # get 2 points
+ p1 = edge.Curve.value(0)
+ p2 = edge.Curve.value(math.pi/2)
+ # get 2 tangents
+ t1 = edge.Curve.tangent(0)[0]
+ t2 = edge.Curve.tangent(math.pi/2)[0]
+ # get normal
+ n = p1.cross(p2)
+ if DraftVecUtils.isNull(n):
+ return None
+ # get rays
+ r1 = DraftVecUtils.rotate(t1,math.pi/2,n)
+ r2 = DraftVecUtils.rotate(t2,math.pi/2,n)
+ # get center (intersection of rays)
+ i = findIntersection(p1,p1.add(r1),p2,p2.add(r2),True,True)
+ if not i:
+ return None
+ c = i[0]
+ r = (p1.sub(c)).Length
+ circle = Part.makeCircle(r,c,n)
+ #print circle.Curve
+ return circle
+
+def cleanProjection(shape):
+ "returns a valid compound of edges, by recreating them"
+ # this is because the projection algorithm somehow creates wrong shapes.
+ # they dispay fine, but on loading the file the shape is invalid
+ oldedges = shape.Edges
+ newedges = []
+ for e in oldedges:
+ try:
+ if geomType(e) == "Line":
+ newedges.append(e.Curve.toShape())
+ elif geomType(e) == "Circle":
+ if len(e.Vertexes) > 1:
+ mp = findMidpoint(e)
+ a = Part.Arc(e.Vertexes[0].Point,mp,e.Vertexes[-1].Point).toShape()
+ newedges.append(a)
+ else:
+ newedges.append(e.Curve.toShape())
+ elif geomType(e) == "Ellipse":
+ if len(e.Vertexes) > 1:
+ a = Part.Arc(e.Curve,e.FirstParameter,e.LastParameter).toShape()
+ newedges.append(a)
+ else:
+ newedges.append(e.Curve.toShape())
+ elif geomType(e) == "BSplineCurve":
+ if isLine(e.Curve):
+ l = Part.Line(e.Vertexes[0].Point,e.Vertexes[-1].Point).toShape()
+ newedges.append(l)
+ else:
+ newedges.append(e.Curve.toShape())
+ else:
+ newedges.append(e)
+ except:
+ print "Debug: error cleaning edge ",e
+ return Part.makeCompound(newedges)
+
# circle functions *********************************************************
diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py
index 3352f0512..1ea342253 100644
--- a/src/Mod/Draft/DraftGui.py
+++ b/src/Mod/Draft/DraftGui.py
@@ -313,8 +313,29 @@ class DraftToolBar:
self.zValue.setText("0.00")
self.textValue = self._lineedit("textValue", self.layout)
+ # shapestring
+
+ self.labelSSize = self._label("labelSize", self.layout)
+ self.SSizeValue = self._lineedit("SSizeValue", self.layout, width=60)
+ self.SSizeValue.setText("200.0")
+ self.labelSTrack = self._label("labelTracking", self.layout)
+ self.STrackValue = self._lineedit("STrackValue", self.layout, width=60)
+ self.STrackValue.setText("0")
+ self.labelSString = self._label("labelString", self.layout)
+ self.SStringValue = self._lineedit("SStringValue", self.layout)
+ self.SStringValue.setText("")
+ self.labelFFile = self._label("labelFFile", self.layout)
+ self.FFileValue = self._lineedit("FFileValue", self.layout)
+ defFile = Draft.getParam("FontFile")
+ if defFile:
+ self.FFileValue.setText(defFile)
+ else:
+ self.FFileValue.setText("")
+ self.chooserButton = self._pushbutton("chooserButton", self.layout, width=26)
+ self.chooserButton.setText("...")
+
# options
-
+
self.numFaces = self._spinbox("numFaces", self.layout, 3)
self.offsetLabel = self._label("offsetlabel", self.layout)
self.offsetValue = self._lineedit("offsetValue", self.layout, width=60)
@@ -386,7 +407,20 @@ class DraftToolBar:
QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("escaped()"),self.escape)
QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("resized()"),self.relocate)
QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("retranslate()"),self.retranslateUi)
+ QtCore.QObject.connect(self.SSizeValue,QtCore.SIGNAL("returnPressed()"),self.validateSNumeric)
+ QtCore.QObject.connect(self.SSizeValue,QtCore.SIGNAL("escaped()"),self.escape)
+ QtCore.QObject.connect(self.STrackValue,QtCore.SIGNAL("returnPressed()"),self.validateSNumeric)
+ QtCore.QObject.connect(self.STrackValue,QtCore.SIGNAL("escaped()"),self.escape)
+ QtCore.QObject.connect(self.SStringValue,QtCore.SIGNAL("returnPressed()"),self.validateSString)
+ QtCore.QObject.connect(self.SStringValue,QtCore.SIGNAL("escaped()"),self.escape)
+ QtCore.QObject.connect(self.chooserButton,QtCore.SIGNAL("pressed()"),self.pickFile)
+ QtCore.QObject.connect(self.FFileValue,QtCore.SIGNAL("returnPressed()"),self.validateFile)
+ QtCore.QObject.connect(self.FFileValue,QtCore.SIGNAL("escaped()"),self.escape)
+# if Ui changed to have Size & Track visible at same time, use this
+# QtCore.QObject.connect(self.SSizeValue,QtCore.SIGNAL("returnPressed()"),self.checkSSize)
+# QtCore.QObject.connect(self.STrackValue,QtCore.SIGNAL("returnPressed()"),self.checkSTrack)
+
def setupTray(self):
"sets draft tray buttons up"
@@ -478,6 +512,15 @@ class DraftToolBar:
self.resetPlaneButton.setToolTip(translate("draft", "Do not project points to a drawing plane"))
self.isCopy.setText(translate("draft", "&Copy"))
self.isCopy.setToolTip(translate("draft", "If checked, objects will be copied instead of moved (C)"))
+ self.SStringValue.setToolTip(translate("draft", "Text string to draw"))
+ self.labelSString.setText(translate("draft", "String"))
+ self.SSizeValue.setToolTip(translate("draft", "Height of text"))
+ self.labelSSize.setText(translate("draft", "Height"))
+ self.STrackValue.setToolTip(translate("draft", "Intercharacter spacing"))
+ self.labelSTrack.setText(translate("draft", "Tracking"))
+ self.labelFFile.setText(translate("draft", "Pick a font file"))
+ self.chooserButton.setToolTip(translate("draft", "Open a FileChooser for font file"))
+
if (not self.taskmode) or self.tray:
self.wplabel.setToolTip(translate("draft", "Set/unset a working plane"))
self.colorButton.setToolTip(translate("draft", "Line Color"))
@@ -528,6 +571,15 @@ class DraftToolBar:
self.offsetLabel.show()
self.offsetValue.show()
+ def hideXYZ(self):
+ ''' turn off all the point entry widgets '''
+ self.labelx.hide()
+ self.labely.hide()
+ self.labelz.hide()
+ self.xValue.hide()
+ self.yValue.hide()
+ self.zValue.hide()
+
def lineUi(self,title=None):
if title:
self.pointUi(title,icon="Draft_Line")
@@ -606,12 +658,7 @@ class DraftToolBar:
else:
self.setTitle(translate("draft", "None"))
self.labelx.setText(translate("draft", "X"))
- self.labelx.hide()
- self.labely.hide()
- self.labelz.hide()
- self.xValue.hide()
- self.yValue.hide()
- self.zValue.hide()
+ self.hideXYZ()
self.numFaces.hide()
self.isRelative.hide()
self.hasFill.hide()
@@ -634,6 +681,15 @@ class DraftToolBar:
self.textValue.hide()
self.continueCmd.hide()
self.occOffset.hide()
+ self.labelSString.hide()
+ self.SStringValue.hide()
+ self.labelSSize.hide()
+ self.SSizeValue.hide()
+ self.labelSTrack.hide()
+ self.STrackValue.hide()
+ self.labelFFile.hide()
+ self.FFileValue.hide()
+ self.chooserButton.hide()
def trimUi(self,title=translate("draft","Trim")):
self.taskUi(title)
@@ -643,29 +699,56 @@ class DraftToolBar:
self.radiusValue.selectAll()
def radiusUi(self):
- self.labelx.hide()
- self.labely.hide()
- self.labelz.hide()
- self.xValue.hide()
- self.yValue.hide()
- self.zValue.hide()
+ self.hideXYZ()
self.labelRadius.setText(translate("draft", "Radius"))
self.labelRadius.show()
self.radiusValue.show()
def textUi(self):
- self.labelx.hide()
- self.labely.hide()
- self.labelz.hide()
- self.xValue.hide()
- self.yValue.hide()
- self.zValue.hide()
+ self.hideXYZ()
self.textValue.show()
self.textValue.setText('')
self.textValue.setFocus()
self.textbuffer=[]
self.textline=0
self.continueCmd.show()
+
+ def SSUi(self):
+ ''' set up ui for ShapeString text entry '''
+ self.hideXYZ()
+ self.labelSString.show()
+ self.SStringValue.show()
+ self.SStringValue.setText('')
+ self.SStringValue.setFocus()
+ self.continueCmd.hide()
+
+ def SSizeUi(self):
+ ''' set up ui for ShapeString size entry '''
+ self.labelSString.hide()
+ self.SStringValue.hide()
+ self.continueCmd.hide()
+ self.labelSSize.show()
+ self.SSizeValue.setText('200.0')
+ self.SSizeValue.show()
+ self.SSizeValue.setFocus()
+
+ def STrackUi(self):
+ ''' set up ui for ShapeString tracking entry '''
+ self.labelSSize.hide()
+ self.SSizeValue.hide()
+ self.labelSTrack.show()
+ self.STrackValue.setText('0')
+ self.STrackValue.show()
+ self.STrackValue.setFocus()
+
+ def SFileUi(self):
+ ''' set up UI for ShapeString font file selection '''
+ self.labelSTrack.hide()
+ self.STrackValue.hide()
+ self.labelFFile.show()
+ self.FFileValue.show()
+ self.chooserButton.show()
+ self.FFileValue.setFocus()
def switchUi(self,store=True):
if store:
@@ -676,12 +759,7 @@ class DraftToolBar:
self.state.append(self.xValue.isVisible())
self.state.append(self.yValue.isVisible())
self.state.append(self.zValue.isVisible())
- self.labelx.hide()
- self.labely.hide()
- self.labelz.hide()
- self.xValue.hide()
- self.yValue.hide()
- self.zValue.hide()
+ self.hideXYZ()
else:
if self.state:
if self.state[0]:self.labelx.show()
@@ -707,12 +785,7 @@ class DraftToolBar:
def editUi(self):
self.taskUi(translate("draft", "Edit"))
- self.labelx.hide()
- self.labely.hide()
- self.labelz.hide()
- self.xValue.hide()
- self.yValue.hide()
- self.zValue.hide()
+ self.hideXYZ()
self.numFaces.hide()
self.isRelative.hide()
self.hasFill.hide()
@@ -902,6 +975,74 @@ class DraftToolBar:
numz = last.z + v.z
self.sourceCmd.numericInput(numx,numy,numz)
+ def validateSNumeric(self):
+ ''' send valid numeric parameters to ShapeString '''
+ if self.sourceCmd:
+ if (self.labelSSize.isVisible()):
+ try:
+ SSize=float(self.SSizeValue.text())
+ except ValueError:
+ FreeCAD.Console.PrintMessage(translate("draft", "Invalid Size value. Using 200.0."))
+ self.sourceCmd.numericSSize(unicode("200.0"))
+ else:
+ self.sourceCmd.numericSSize(unicode(SSize))
+ elif (self.labelSTrack.isVisible()):
+ try:
+ track=int(self.STrackValue.text())
+ except ValueError:
+ FreeCAD.Console.PrintMessage(translate("draft", "Invalid Tracking value. Using 0."))
+ self.sourceCmd.numericSTrack(unicode("0"))
+ else:
+ self.sourceCmd.numericSTrack(unicode(track))
+
+ def validateSString(self):
+ ''' send a valid text string to ShapeString as unicode '''
+ if self.sourceCmd:
+ if (self.labelSString.isVisible()):
+ if self.SStringValue.text():
+# print "debug: D_G DraftToolBar.validateSString type(SStringValue.text): " str(type(self.SStringValue.text))
+ self.sourceCmd.validSString(str(self.SStringValue.text().toUtf8())) # QString to QByteArray to PyString
+ else:
+ FreeCAD.Console.PrintMessage(translate("draft", "Please enter a text string."))
+
+
+ def pickFile(self):
+ ''' invoke a font file chooser dialog and send result to ShapeString to'''
+ if self.sourceCmd:
+ if (self.chooserButton.isVisible()):
+ try:
+ dialogCaption = translate("draft", "Select a Font file")
+ dialogDir = os.path.dirname(Draft.getParam("FontFile"))
+ if not dialogDir:
+ dialogDir = os.getcwd() # reasonable default?
+ dialogFilter = "Fonts (*.ttf *.pfb *.otf);;All files (*.*)"
+ fname = QtGui.QFileDialog.getOpenFileName(self.baseWidget,
+ dialogCaption,
+ dialogDir,
+ dialogFilter)
+ fname = str(fname.toUtf8()) # QString to PyString
+# print "debug: D_G DraftToolBar.pickFile type(fname): " str(type(fname))
+
+ except Exception as e:
+ FreeCAD.Console.PrintMessage("DraftGui.pickFile: unable to select a font file.")
+ print type(e)
+ print e.args
+ else:
+ if fname:
+ self.sourceCmd.validFFile(fname)
+ else:
+ FreeCAD.Console.PrintMessage("DraftGui.pickFile: no file selected.") # can this happen?
+
+ def validateFile(self):
+ ''' check and send font file parameter to ShapeString as unicode'''
+ if self.sourceCmd:
+ if (self.labelFFile.isVisible()):
+ if self.FFileValue.text():
+ self.sourceCmd.validFFile(str(self.FFileValue.text().toUtf8())) #QString to PyString
+ else:
+ FreeCAD.Console.PrintMessage(translate("draft", "Please enter a font file."))
+
+
def finish(self):
"finish button action"
if self.sourceCmd:
@@ -1222,7 +1363,8 @@ class DraftToolBar:
self.commands = ["Draft_Line","Draft_Wire",
"Draft_Rectangle","Draft_Arc",
"Draft_Circle","Draft_BSpline",
- "Draft_Text","Draft_Dimension"]
+ "Draft_Text","Draft_Dimension",
+ "Draft_ShapeString"]
self.title = "Create objects"
def shouldShow(self):
return (FreeCAD.ActiveDocument != None) and (not FreeCADGui.Selection.getSelection())
diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py
index 58ee1d06b..bedb71f13 100644
--- a/src/Mod/Draft/DraftSnap.py
+++ b/src/Mod/Draft/DraftSnap.py
@@ -104,13 +104,14 @@ class Snapper:
'ortho':':/icons/Snap_Ortho.svg',
'intersection':':/icons/Snap_Intersection.svg'}
- def snap(self,screenpos,lastpoint=None,active=True,constrain=False):
- """snap(screenpos,lastpoint=None,active=True,constrain=False): returns a snapped
+ def snap(self,screenpos,lastpoint=None,active=True,constrain=False,noTracker=False):
+ """snap(screenpos,lastpoint=None,active=True,constrain=False,noTracker=False): returns a snapped
point from the given (x,y) screenpos (the position of the mouse cursor), active is to
activate active point snapping or not (passive), lastpoint is an optional
other point used to draw an imaginary segment and get additional snap locations. Constrain can
be True to constrain the point against the closest working plane axis.
- Screenpos can be a list, a tuple or a coin.SbVec2s object."""
+ Screenpos can be a list, a tuple or a coin.SbVec2s object. If noTracker is True,
+ the tracking line is not displayed."""
global Part, DraftGeomUtils
import Part, DraftGeomUtils
@@ -196,7 +197,7 @@ class Snapper:
if active:
point = self.snapToGrid(point)
fp = cstr(point)
- if self.trackLine and lastpoint:
+ if self.trackLine and lastpoint and (not noTracker):
self.trackLine.p2(fp)
self.trackLine.on()
return fp
diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py
index fbff806a5..33fb5d6ca 100644
--- a/src/Mod/Draft/DraftTools.py
+++ b/src/Mod/Draft/DraftTools.py
@@ -121,14 +121,15 @@ def selectObject(arg):
FreeCAD.activeDraftCommand.component=snapped['Component']
FreeCAD.activeDraftCommand.proceed()
-def getPoint(target,args,mobile=False,sym=False,workingplane=True):
+def getPoint(target,args,mobile=False,sym=False,workingplane=True,noTracker=False):
'''
Function used by the Draft Tools.
returns a constrained 3d point and its original point.
if mobile=True, the constraining occurs from the location of
mouse cursor when Shift is pressed, otherwise from last entered
point. If sym=True, x and y values stay always equal. If workingplane=False,
- the point wont be projected on the Working Plane.
+ the point wont be projected on the Working Plane. if noTracker is True, the
+ tracking line will not be displayed
'''
ui = FreeCADGui.draftToolBar
@@ -141,7 +142,7 @@ def getPoint(target,args,mobile=False,sym=False,workingplane=True):
last = None
amod = hasMod(args,MODSNAP)
cmod = hasMod(args,MODCONSTRAIN)
- point = FreeCADGui.Snapper.snap(args["Position"],lastpoint=last,active=amod,constrain=cmod)
+ point = FreeCADGui.Snapper.snap(args["Position"],lastpoint=last,active=amod,constrain=cmod,noTracker=noTracker)
info = FreeCADGui.Snapper.snapInfo
ctrlPoint = Vector(point)
mask = FreeCADGui.Snapper.affinity
@@ -606,7 +607,7 @@ class BSpline(Line):
if arg["Key"] == "ESCAPE":
self.finish()
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
- self.point,ctrlPoint,info = getPoint(self,arg)
+ self.point,ctrlPoint,info = getPoint(self,arg,noTracker=True)
self.bsplinetrack.update(self.node + [self.point])
elif arg["Type"] == "SoMouseButtonEvent":
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
@@ -813,7 +814,7 @@ class Rectangle(Creator):
if arg["Key"] == "ESCAPE":
self.finish()
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
- self.point,ctrlPoint,info = getPoint(self,arg,mobile=True)
+ self.point,ctrlPoint,info = getPoint(self,arg,mobile=True,noTracker=True)
self.rect.update(self.point)
elif arg["Type"] == "SoMouseButtonEvent":
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
@@ -1394,7 +1395,7 @@ class Ellipse(Creator):
'pl = FreeCAD.Placement()',
'pl.Rotation.Q='+rot,
'pl.Base = '+DraftVecUtils.toString(center),
- 'Draft.makeEllipse('+str(r1)+','+str(r2)+',placement=pl)'])
+ 'Draft.makeEllipse('+str(r1)+','+str(r2)+',placement=pl,face='+fil+',support='+sup+')'])
except:
print "Draft: Error: Unable to create object."
self.finish(cont=True)
@@ -1405,7 +1406,7 @@ class Ellipse(Creator):
if arg["Key"] == "ESCAPE":
self.finish()
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
- self.point,ctrlPoint,info = getPoint(self,arg,mobile=True)
+ self.point,ctrlPoint,info = getPoint(self,arg,mobile=True,noTracker=True)
self.rect.update(self.point)
elif arg["Type"] == "SoMouseButtonEvent":
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
@@ -1616,8 +1617,9 @@ class Dimension(Creator):
if arg["Key"] == "ESCAPE":
self.finish()
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
+ import DraftGeomUtils
shift = hasMod(arg,MODCONSTRAIN)
- self.point,ctrlPoint,self.info = getPoint(self,arg)
+ self.point,ctrlPoint,self.info = getPoint(self,arg,noTracker=(len(self.node)>0))
if self.arcmode or self.point2:
setMod(arg,MODCONSTRAIN,False)
if hasMod(arg,MODALT) and (len(self.node)<3):
@@ -1696,6 +1698,7 @@ class Dimension(Creator):
self.dimtrack.update(self.node+[self.point]+[self.cont])
elif arg["Type"] == "SoMouseButtonEvent":
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
+ import DraftGeomUtils
if self.point:
if (not self.node) and (not self.support):
self.support = getSupport(arg)
@@ -1721,7 +1724,6 @@ class Dimension(Creator):
self.node = [v1,v2]
self.link = [ob,i1,i2]
self.edges.append(ed)
- import DraftGeomUtils
if DraftGeomUtils.geomType(ed) == "Circle":
# snapped edge is an arc
self.arcmode = "diameter"
@@ -1736,6 +1738,7 @@ class Dimension(Creator):
self.node[3],
True,True)
if c:
+ print "centers:",c
self.center = c[0]
self.arctrack.setCenter(self.center)
self.arctrack.on()
@@ -1786,6 +1789,118 @@ class Dimension(Creator):
self.createObject()
if not self.cont: self.finish()
+class ShapeString(Creator):
+ "This class creates a shapestring feature."
+
+ def GetResources(self):
+ return {'Pixmap' : 'Draft_ShapeString',
+ 'Accel' : "S, S",
+ 'MenuShapeString': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", "ShapeString"),
+ 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_ShapeString", "Creates text string in shapes.")}
+
+ def Activated(self):
+ name = str(translate("draft","ShapeString"))
+ Creator.Activated(self,name)
+ if self.ui:
+ self.ui.sourceCmd = self
+ self.dialog = None
+ self.text = ''
+ self.ui.sourceCmd = self
+ self.ui.pointUi(name)
+ self.call = self.view.addEventCallback("SoEvent",self.action)
+ self.ui.xValue.setFocus()
+ self.ui.xValue.selectAll()
+ msg(translate("draft", "Pick ShapeString location point:\n"))
+ FreeCADGui.draftToolBar.show()
+
+ def createObject(self):
+ "creates object in the current doc"
+# print "debug: D_T ShapeString.createObject type(self.SString): " str(type(self.SString))
+ # temporary code
+ import platform
+ if not (platform.system() == 'Linux'):
+# if (platform.system() == 'Linux'):
+ FreeCAD.Console.PrintWarning("Sorry, ShapeString is not yet fully implemented for your platform.\n")
+ self.finish()
+ return
+ # temporary code
+
+ dquote = '"'
+ String = dquote + self.SString + dquote
+ Size = str(self.SSSize) # numbers are ascii so this should always work
+ Tracking = str(self.SSTrack) # numbers are ascii so this should always work
+ FFile = dquote + self.FFile + dquote
+# print "debug: D_T ShapeString.createObject type(String): " str(type(String))
+# print "debug: D_T ShapeString.createObject type(FFile): " str(type(FFile))
+
+ try:
+ qr,sup,points,fil = self.getStrings()
+ self.commit(translate("draft","Create ShapeString"),
+ ['import Draft',
+ 'ss=Draft.makeShapeString(String='+String+',FontFile='+FFile+',Size='+Size+',Tracking='+Tracking+')',
+ 'plm=FreeCAD.Placement()',
+ 'plm.Base='+DraftVecUtils.toString(self.point),
+ 'plm.Rotation.Q='+qr,
+ 'ss.Placement=plm',
+ 'ss.Support='+sup])
+ except Exception as e:
+ msg("Draft_ShapeString: error delaying commit", "error")
+ print type(e)
+ print e.args
+ self.finish()
+
+ def action(self,arg):
+ "scene event handler"
+ if arg["Type"] == "SoKeyboardEvent":
+ if arg["Key"] == "ESCAPE":
+ self.finish()
+ elif arg["Type"] == "SoLocation2Event": #mouse movement detection
+ 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.ui.SSUi()
+
+ def numericInput(self,numx,numy,numz):
+ '''this function gets called by the toolbar when valid
+ x, y, and z have been entered there'''
+ self.point = Vector(numx,numy,numz)
+ self.node.append(self.point)
+ self.ui.SSUi() #move on to next step in parameter entry
+
+ def numericSSize(self,ssize):
+ '''this function is called by the toolbar when valid size parameter
+ has been entered. '''
+ self.SSSize = ssize
+ self.ui.STrackUi()
+
+ def numericSTrack(self,strack):
+ '''this function is called by the toolbar when valid size parameter
+ has been entered. ?'''
+ self.SSTrack = strack
+ self.ui.SFileUi()
+
+ def validSString(self,sstring):
+ '''this function is called by the toolbar when a ?valid? string parameter
+ has been entered. '''
+ self.SString = sstring
+ self.ui.SSizeUi()
+
+ def validFFile(self,FFile):
+ '''this function is called by the toolbar when a ?valid? font file parameter
+ has been entered. '''
+ self.FFile = FFile
+ # last step in ShapeString parm capture, create object
+ self.createObject()
+
+ def finish(self, finishbool=False):
+ "terminates the operation"
+ Creator.finish(self)
+ if self.ui:
+# del self.dialog # what does this do??
+ if self.ui.continueMode:
+ self.Activated()
#---------------------------------------------------------------------------
# Modifier functions
@@ -1821,7 +1936,14 @@ class Move(Modifier):
def proceed(self):
if self.call: self.view.removeEventCallback("SoEvent",self.call)
self.sel = Draft.getSelection()
- self.sel = Draft.getGroupContents(self.sel)
+ # testing for special case: only Arch groups in selection
+ onlyarchgroups = True
+ for o in self.sel:
+ if not(Draft.getType(o) in ["Floor","Building","Site"]):
+ onlyarchgroups = False
+ if not onlyarchgroups:
+ # arch groups can be moved, no need to add their children
+ self.sel = Draft.getGroupContents(self.sel)
self.ui.pointUi(self.name)
self.ui.modUi()
self.ui.xValue.setFocus()
@@ -2972,7 +3094,8 @@ class Edit(Modifier):
Modifier.finish(self)
plane.restore()
self.running = False
- FreeCADGui.ActiveDocument.resetEdit()
+ # following line causes crash
+ # FreeCADGui.ActiveDocument.resetEdit()
def action(self,arg):
"scene event handler"
@@ -3584,6 +3707,7 @@ FreeCADGui.addCommand('Draft_Polygon',Polygon())
FreeCADGui.addCommand('Draft_BSpline',BSpline())
FreeCADGui.addCommand('Draft_Point',Point())
FreeCADGui.addCommand('Draft_Ellipse',Ellipse())
+FreeCADGui.addCommand('Draft_ShapeString',ShapeString())
# modification commands
FreeCADGui.addCommand('Draft_Move',Move())
diff --git a/src/Mod/Draft/Draft_rc.py b/src/Mod/Draft/Draft_rc.py
index 37e3e5fc2..b521dbd33 100644
--- a/src/Mod/Draft/Draft_rc.py
+++ b/src/Mod/Draft/Draft_rc.py
@@ -2,8 +2,8 @@
# Resource object code
#
-# Created: Tue Apr 2 18:58:00 2013
-# by: The Resource Compiler for PyQt (Qt v4.8.2)
+# Created: Mon Apr 15 12:19:38 2013
+# by: The Resource Compiler for PyQt (Qt v4.8.1)
#
# WARNING! All changes made in this file will be lost!
@@ -41254,214 +41254,219 @@ 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\x69\
+\x00\x00\x09\xb5\
\x00\
-\x00\x48\x24\x78\x9c\xed\x5c\x5b\x73\xdb\xb6\x12\x7e\xf7\xaf\xc0\
-\xe8\xe1\x9c\xb4\xe3\x5a\x92\xaf\x49\x8e\xac\x4e\x62\xd7\x49\x3a\
-\xc9\x69\x5a\xb9\x49\xdf\x3c\x10\x09\x89\xa8\x49\x42\x05\x40\x4b\
-\xea\xaf\xef\x2e\x00\x8a\x14\x45\xdd\x2d\xc9\x71\x35\xe3\x19\x8b\
-\x00\x88\x5d\x2c\xbe\x5d\xec\x2e\x56\x6a\xfc\x38\x88\x42\xf2\xc0\
-\xa4\xe2\x22\xbe\xac\xd4\x8f\x6a\x15\xc2\x62\x4f\xf8\x3c\xee\x5e\
-\x56\x7e\xbf\xbd\xf9\xe1\x65\xe5\xc7\xe6\x41\x23\xe1\xd9\xa0\x53\
-\x18\xd4\x3c\x20\x0d\x2f\xa4\x4a\x35\xdf\x25\xfc\xf5\xeb\x6b\x4e\
-\x43\xd1\x85\xff\x61\xb7\xc5\xb4\x86\x97\xd5\xb5\xa4\x1d\xdd\xa8\
-\xda\x41\x30\xba\xcf\xfd\x2e\xd3\xc4\x3c\x5f\x56\x7e\xfd\x6a\x1e\
-\x2b\x24\xa6\x11\xbb\xac\xcc\x9c\x04\x89\x91\x46\x4f\x8a\x1e\x93\
-\x7a\xe8\xde\xe8\x32\x11\x31\x2d\x87\xa6\x93\x34\x24\xf3\xb4\xf9\
-\x44\x1a\x83\x66\xad\x51\x1d\xb8\x87\x21\x3e\x0c\xdd\x03\xb0\xa0\
-\x83\xe6\xd9\xc5\x59\xa3\x6a\x3f\xda\xe6\x80\xf1\x6e\xa0\x9b\xe7\
-\xc7\xaf\x1a\x55\xf7\xd9\xcc\x59\x4d\x27\x6d\x54\x53\xe2\x65\x9c\
-\xf4\x79\xec\x8b\xfe\x2d\xd7\x21\x73\xcc\x28\x2d\x81\xf9\xe6\x87\
-\xa8\x27\xa4\xae\xfe\x34\xc0\x7f\x8d\xaa\x6b\x9d\x9c\x2f\xa4\x43\
-\x91\x64\x92\xf9\xf2\x56\x0c\x3e\x9a\x26\x37\x5d\x81\x9e\xea\x51\
-\x0f\x26\xaa\x38\xee\xe3\x24\x6a\x33\xd9\x3c\x6f\x54\xdd\x27\xcb\
-\x7b\x9e\xc2\xc4\x14\x11\x95\x5d\x1e\x17\x66\x78\x35\x73\x06\xae\
-\x59\x94\x89\x31\xbf\x93\xef\xa4\x48\x7a\xc0\xf3\x68\x2f\xdd\x73\
-\xfd\xd8\x11\x98\x20\xaf\x33\x59\xe5\xc4\x75\xfd\xc7\x0d\xe9\x08\
-\x19\x51\x4d\x44\x4f\x03\xd2\x54\x5e\x66\x93\x2c\xcd\x97\xdc\x5c\
-\xe1\x4d\x95\x5f\x19\xb5\xd9\x52\x9c\x2a\xc8\xf2\xa9\x32\x71\x96\
-\xac\xe3\xfd\xe4\x3a\x16\x58\xc9\x8c\xb5\x94\xb1\x30\x7f\x3d\xd9\
-\x84\xb5\x05\x27\x1c\x5b\xd5\x24\x52\x3e\xd2\x36\x0b\x53\x98\x68\
-\x36\xd0\xa6\xa1\x7e\x77\x92\xa7\x39\x89\x16\x18\x38\x36\xa0\xa0\
-\x60\x44\xe9\x61\xc8\x0a\x58\x99\xca\x23\x31\xba\x0f\x5c\xe5\x97\
-\x32\xce\xf7\x9c\x65\x18\x5b\xf5\x59\xb2\xce\x95\x88\xda\x22\x07\
-\xfc\x2e\x76\xf4\xa0\xc3\xc3\x8e\x36\x74\xcc\x5c\x96\x10\xe1\x2d\
-\xef\x95\xaf\xec\x36\xe0\x8a\xc0\x9f\x0e\x18\x01\x33\x17\x08\x9f\
-\x78\x81\x10\x8a\xf9\xa8\x22\x84\x9b\x85\xc3\x40\x02\x0f\x5a\xd2\
-\x58\x85\xd4\x3c\xa2\x0e\x89\xf6\x9f\x60\xb7\x88\x27\x42\x1c\x19\
-\x6b\x41\x6e\x24\x63\x57\x6f\xae\x8f\xc8\xc1\x87\x8e\x6b\x8f\x68\
-\xaf\x87\x2f\x00\x0d\x37\xf1\x21\x01\xc0\x91\x28\x51\xda\xb5\x10\
-\x5a\x18\xdb\xe1\x21\x83\xa6\x58\x53\x1e\xe3\x33\xcd\x48\x8b\x98\
-\x68\xda\x86\x6e\x1d\x80\xfa\xf6\x79\x18\xe2\x40\x38\x31\x1c\x1f\
-\xca\x32\x12\xf2\x98\x19\xcb\xab\x8e\x0e\x16\xde\xb0\x09\xc9\x79\
-\x89\x94\x2c\xd6\x1f\x62\x9f\x0d\x0a\xe2\x9b\x8e\xd7\x45\x27\xc7\
-\xfd\xfb\x29\xc6\x83\x05\x70\xe5\x2b\xa6\x2f\x2b\xb5\x02\x11\xcf\
-\x31\xee\x0f\x3a\x0e\x7a\xde\xaa\x4b\x41\x6a\x9f\xa9\x0e\xe6\x13\
-\xfb\x24\xfc\x6a\x7a\xa4\x2e\x4c\xad\x00\xe4\x45\x74\x6b\x04\xc1\
-\xff\x8b\x98\x91\x17\x1d\xaa\x34\x53\xfa\xbb\xb2\xdd\x9a\x46\xb5\
-\x5a\x24\xbb\x16\x1f\xbf\x03\x12\x7d\xd6\xa1\x49\x98\x62\x9a\xc6\
-\x7e\x86\xa4\xdd\x31\xf6\x8b\xe4\x60\x2e\x69\xf8\xb4\xb8\xba\x1a\
-\xa9\x2c\xd8\x8a\xbc\xca\xed\x90\x25\xc9\xa8\x66\xa4\x47\x25\x45\
-\x97\x8d\x7b\xce\x44\x15\xcf\xf7\xed\xb3\xd4\xba\x67\xda\x0b\xd8\
-\x5a\x8c\xcc\x3d\x4f\x1a\x55\x7b\xbc\x67\xde\x40\xbe\x7b\x61\x4f\
-\xc0\x2d\x2a\x10\x92\xff\x8d\x36\x38\x9c\xf4\x10\x96\x39\x7e\x43\
-\x7c\xb8\xbb\x58\xf1\xe4\xfd\x44\x07\xa4\xd5\x43\x6c\x91\x16\xeb\
-\x46\x60\x8d\x77\x70\xfe\xb6\xe0\x54\x2a\x3b\x7e\x15\xb4\xc3\xe9\
-\x7b\x77\x3c\x73\x71\x11\x1d\xf0\x28\x89\x5a\xfc\x6f\x56\x5c\x23\
-\x34\x15\x60\x63\xc3\x85\xf3\xda\x58\xe0\x30\xea\x75\x41\x43\xfd\
-\xfc\xe2\xe2\xe2\xb8\x7e\x36\x16\x45\x64\x8b\x2c\x4e\xbb\xd8\x09\
-\x31\xd3\x4d\xf8\x1a\xb0\x98\xb0\x41\xea\x0c\x28\xb3\x23\x0a\xd5\
-\x1e\x1c\x81\x43\xf4\x1e\x86\x84\x4a\x66\xcf\x69\xf4\xad\xc1\x26\
-\xf0\x98\xf4\x44\x38\x34\x23\x8f\x88\x71\x34\x1e\x68\x98\xb0\x91\
-\xbb\x61\xe5\x42\x42\x16\x77\x75\x40\x44\x87\x30\xea\x99\xff\xd8\
-\x9b\xbe\x4a\x94\xdd\x76\x98\x02\x7c\x8a\x9a\xa1\x15\x9b\x11\xfd\
-\x40\x80\x1f\x60\x59\x31\x73\x1a\x55\xf3\x09\x55\xe0\x30\x00\xdf\
-\x14\x45\x93\xbe\x7e\xb4\xba\x17\x60\x98\x2e\x3f\xfe\xcf\xb6\x72\
-\xfc\x83\xa0\x9c\xc0\x53\x0d\x78\x9a\x6e\xc0\x8e\x0d\xd4\x98\x77\
-\xbf\xbc\x89\x5a\xd1\x40\x5d\x4d\x78\xae\x3b\x30\x50\x37\x40\xf6\
-\xca\xf8\xd2\x72\xc2\x48\x21\x4b\x9e\xeb\x9b\x69\xa6\xc0\xd7\x5e\
-\xd2\x4c\x9d\xd4\x66\xdb\xa9\xda\xf6\x0c\xd4\x6d\xc0\xca\x82\x88\
-\x4e\x21\x6c\x01\x4f\x7a\x4a\x9c\xb0\xba\x7d\x58\xce\x91\x77\xec\
-\x59\xa0\xec\xf5\xb8\x4c\x8f\x2f\x16\xd7\xe3\x2c\x44\x0e\x98\x77\
-\x5f\x1a\x22\x63\xc7\xfc\x43\x7a\x26\xb8\x38\x1e\x49\x36\x4e\x4e\
-\x62\x33\x21\x46\xb1\x68\x13\x54\x35\x32\xff\x48\x5f\xc4\xff\xd5\
-\xa4\xcd\x5c\xc4\xcc\xfc\xd5\xf1\x34\x37\x0d\x61\x29\x62\x18\xe0\
-\x73\x38\x0f\x54\x49\x06\x6b\x49\x28\x2d\x0e\x5f\xa4\xbd\xc7\x6d\
-\x39\x6e\x8f\x37\x82\xdb\x39\x39\xab\x05\x71\x3b\x42\x6d\x8f\xc2\
-\xeb\x04\x73\x7a\x2c\x8d\x8e\x6c\x1a\x25\x87\x5d\xf0\xeb\xc4\x06\
-\xf1\x6b\x25\xbb\x35\xc8\x5a\x72\x7b\xd0\x96\x83\xf6\x74\x23\xa0\
-\x9d\x13\xee\xcd\x02\xad\x99\xdc\xe1\xb6\x63\x52\x85\x7d\x1a\x6b\
-\xe3\xf1\xc7\x22\xfe\x01\x67\xf0\x49\x3b\x14\xde\xbd\x22\x2f\xda\
-\xac\xcb\x63\x93\x23\xec\x73\x88\x21\x28\xf9\xfe\x3b\x0c\x4a\xb6\
-\x87\xe5\xef\x2d\x27\xdb\xc2\xb2\xd2\x54\xa6\x14\xf7\x78\x2e\xc3\
-\xf3\xcb\x8d\xe0\xf9\xec\x71\x8d\x70\x6a\x78\x3b\x52\x44\x06\xd9\
-\x0a\xe6\x41\xbb\xc8\x64\x66\x8d\xff\x14\xe0\x9c\xfa\xd6\x4f\x35\
-\x9b\x40\xde\x9a\x9d\x07\xcf\x23\x91\x06\xf3\xf8\xa6\xcf\x21\x36\
-\xa4\x43\x62\xf2\xa7\xf2\x90\xb4\x41\x5c\x11\xbd\x77\xdd\x18\x5d\
-\x2b\x05\x81\xb5\xe2\xe1\x90\x30\x9f\x9b\xe4\xf9\x26\xf4\xc1\x5c\
-\xc6\xa5\x4b\x30\x3c\x6f\x51\x33\xba\x48\xfc\xa3\xa1\xbd\xd7\x8b\
-\x72\xbd\x38\xdb\x88\x5e\xbc\x5a\x5d\x2f\xf0\x86\x28\xd5\x87\x8e\
-\x64\xcc\xa3\xbe\x85\x3e\xec\x38\xda\x70\x84\x3f\x26\xe2\x79\xec\
-\x71\x9f\xc1\xc7\x54\x69\x0c\xb8\xfa\x5c\x62\x56\xe9\x2d\xeb\x53\
-\xc9\x0e\xad\x86\x79\x14\x2f\x87\xee\xf1\x3e\xa9\x1f\x40\x7c\x75\
-\x74\xb4\x46\xd6\x67\x3a\xd2\x7f\x06\x96\x48\x5a\x15\xb0\x15\x78\
-\xa3\x28\x32\x82\x7b\x7c\x97\xe1\xfb\x7c\x13\xf8\x5e\x0b\xdd\x13\
-\x56\x9f\x02\xb8\x53\x10\xe7\x6e\x37\x3b\xe0\x8a\x67\x56\xdf\x26\
-\x59\x6d\x1a\xf3\xc4\x37\x69\x50\x33\x60\x13\x48\xb6\x05\x23\xe4\
-\xe4\x7a\xc4\x16\x10\x4d\x29\x92\x88\xa9\x29\x37\x16\x1b\xc9\x8b\
-\x00\xb5\x3d\xb6\xcb\xb1\x5d\xaf\x6f\xc4\x78\xbf\x7c\x5c\x78\x67\
-\x1e\xb7\xcd\x88\x20\xa0\x91\x31\xe3\xdf\x68\x1a\xfb\x54\xfa\xce\
-\x91\xc1\x11\x04\xb3\x80\xf0\x56\x0c\x7e\x0b\x98\x7e\x97\xf6\xc7\
-\x46\x7b\x9d\x10\xd0\x07\x86\x77\x08\xd8\x8a\xd5\x06\xbe\xf0\x92\
-\xa5\xee\x7f\x96\x50\x04\xbc\xfa\x1d\xb1\xd8\x01\xd1\x5b\x3e\x4c\
-\xf6\x10\x17\xb3\x2d\x25\x68\x69\x1f\xf3\xaf\x7b\x3d\x98\xa2\x07\
-\x9b\xc9\xb0\xd4\x6b\x8f\xab\x08\x01\x35\x77\xbd\x23\x93\xee\x0a\
-\x54\x52\x5f\x5e\x81\xa2\x84\xcc\x7a\x30\x1b\x8c\x4c\x0d\x17\xa4\
-\x2d\x12\x44\x35\x67\xc6\xb6\xaf\x49\x73\x09\x30\x5b\x63\x70\x3d\
-\xe8\xbc\xa7\xee\xe2\x7b\x0f\xe9\x52\x48\x2f\x71\x69\xb5\x0c\xa4\
-\xeb\x8f\x0b\xe9\x3e\x5e\xba\x8e\x6e\x73\xad\x6d\x06\x2f\x1b\x6f\
-\x4e\xb0\x66\x06\x03\x55\x77\x0b\x9c\x82\x5e\xb2\xd8\x67\xd2\xfa\
-\x31\x5e\x68\x0a\xca\x0c\xfa\x6c\xa2\x46\x9b\xeb\x1a\x89\x75\xaf\
-\x64\x6a\xd1\xc8\xba\x8a\xf0\x9b\x61\x21\xc7\xb6\x21\xbd\x26\xb9\
-\x25\x74\xc0\x8a\xe0\xb3\x23\xff\xd5\xd2\x7d\x8e\x6a\x30\xde\x39\
-\x36\x57\x6e\xdc\x4a\x95\xbd\x77\x4b\xd6\xf6\xb6\xbe\xbc\x7b\xbc\
-\xda\x5e\x47\x29\x97\x82\xff\xd6\xab\x7c\xd3\x15\x8d\x65\x7d\x9f\
-\x6f\xbd\xef\x9c\xb4\xdd\xce\xeb\x7d\xcd\x35\x8c\x9c\x38\x1b\x5a\
-\xa6\x79\x2c\xa4\x9d\xe4\x1e\x46\x83\x37\x6c\x4a\x62\x0b\x8b\x60\
-\x20\xd2\xe6\xaf\xfa\xf5\xeb\xf7\xa3\x19\x1b\x55\xd3\xb8\xb4\xd1\
-\x41\x37\xf8\x3d\x78\x2d\xd3\x8d\xce\xd4\xe2\x80\xd3\xd9\xb5\x01\
-\xc7\x6b\x15\x07\xc0\x30\x23\xa3\x25\x64\xbd\x6a\x6d\xf5\x3a\x17\
-\x70\x0b\x57\x57\xa3\xd9\x9a\x5e\x4e\xfd\xed\x57\x30\xab\x87\xee\
-\xbe\x82\x79\xe3\xc5\xa6\xff\xba\x0a\xe6\x5d\x7b\xef\xaf\x16\x77\
-\xde\xcb\x8a\x62\xe7\x94\xa4\xcc\xcb\xdb\xb5\x9e\xc8\xd7\x51\x40\
-\xb9\xef\x6c\xda\xf2\xce\x28\xf9\xdd\xfa\x5f\x4b\x31\x4b\xc3\x9c\
-\x90\xf1\xe7\xb0\x92\x0b\x73\xfe\x12\x18\xb4\xa1\x48\x56\x8a\x4a\
-\x5d\x6d\xf5\xf3\x30\x92\x63\x72\x7c\x9e\xc6\xf2\xd6\x95\xe3\xc1\
-\x19\xf8\x02\x0f\xc1\x9e\xc4\x7b\x9e\xff\xd0\xa8\xf7\xbf\xf4\x32\
-\x73\x87\x26\xf4\x37\xda\xb7\x6c\x5d\xbd\xf9\xb4\x16\x1b\xbb\x36\
-\x4d\x63\x49\xad\xc7\x4b\x2c\xcc\xf6\x49\x97\xa9\x21\x47\xcd\x7e\
-\xe0\xac\xaf\x0e\xf1\xbe\x9a\x99\xdb\x91\x7e\x80\x1a\x6e\x8e\x06\
-\x21\xef\x09\x7e\xb7\x84\xa2\x2f\x44\xda\x21\xf5\xee\x0f\x8d\xd3\
-\xd4\x66\x5a\x83\xcf\x2c\x19\xf5\x69\x9b\x87\x1c\x88\xd3\x2e\xc5\
-\x34\xb2\x7b\xbd\x0d\x43\xf1\x42\x38\xf6\x37\x92\x5e\x1b\xe1\x37\
-\xc7\xad\x3b\xd7\xcc\xa5\x37\x50\x5f\xc3\x14\xd9\x84\x4b\x81\x72\
-\x1b\xc4\xda\xd4\x32\x01\x8b\x60\x3e\x6e\xd2\x08\xb5\x1e\xba\x1f\
-\x31\x59\xf2\xd6\x2e\xe4\x69\x5a\xa0\xa7\x9b\xae\x18\x05\x0b\x8b\
-\xa5\x2b\x7e\xb9\x7a\xf3\xf8\xe9\x8a\x4c\x47\x9f\x4b\xba\x62\xac\
-\x22\xf8\x9b\x4f\x57\x2c\x61\x6e\x4f\x57\x37\xb7\x33\xea\xe8\x28\
-\x18\x4f\x45\x5e\x9c\x5c\xdb\xbb\xe7\xb2\x92\xb9\x8d\x54\x4e\xb8\
-\xb4\x0a\x82\xde\xb0\xb0\x95\x2c\xac\xf0\xa8\x23\xb6\xb7\x65\x66\
-\x2f\xf2\x39\x27\xbc\x97\xe2\x5e\x9a\x71\x9a\x66\xbb\xca\x52\x4d\
-\x59\x96\xe9\x8b\x9b\x63\x2c\xc7\x34\x69\xb7\x96\xc8\x2c\x8d\x27\
-\x95\x5c\x3e\xe9\x78\x22\x9f\x94\xa6\x92\x4e\x27\x52\x49\x63\x59\
-\xa4\x22\x2b\x63\xb9\xa3\x4c\x48\x39\x49\xe6\xc4\xe8\x8c\x53\x1a\
-\x55\x3b\x63\x73\x59\x39\xaf\x10\x6b\x26\x2e\x2b\xf5\x7a\xa5\x8a\
-\x23\x7b\x7c\x10\xd1\x5e\x27\x89\x3d\x14\x54\xf3\xaf\xcf\xe6\xf9\
-\x46\x8a\xe8\x13\x8f\x58\x4b\x24\xd2\x83\x03\xbc\x30\x0a\x7f\xdd\
-\x24\x51\x5a\x44\x96\xa2\x32\x9c\xe4\x5b\x2c\x97\xb9\x5f\x40\xc9\
-\x7d\xd7\x27\xfb\xd1\x13\xdc\x8f\x81\x66\xe0\xf2\x34\xdd\x0f\x9e\
-\xc0\x6e\xb8\x86\x03\x2b\x2a\xea\xc3\x92\x61\x86\x2a\x4e\x60\x7f\
-\x01\xe5\x28\x40\xc1\x99\x0e\x23\x80\x22\xdd\xd9\x8c\x14\xbe\x78\
-\x54\xca\xcc\x24\xc7\xd3\xb8\xc2\xd9\x2c\xe7\x6a\x7d\xb6\xdc\x17\
-\x36\xcb\xe5\x33\xea\xdc\x0a\x2b\xa9\x8d\x2f\xe7\x25\xeb\xdd\x0e\
-\x33\x2e\x72\x9f\xc2\xcc\xa8\x77\x7d\x66\xc6\x1b\xcc\xef\xf2\x48\
-\xa6\x8c\x0e\x28\xa3\x2d\x9e\x88\x63\x66\x74\x00\x9f\x1b\xd5\x84\
-\x37\x0f\xfe\x01\xbd\x89\x17\xfc\
-\x00\x00\x10\x85\
+\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\
-\x00\xa9\x59\x78\x9c\xed\x1d\x6b\x6f\xdb\x38\xf2\x7b\x7e\x05\x91\
-\x0f\xbd\x1e\xd0\x8d\x63\xe7\xdd\x3a\x3e\xb4\xe9\x13\x68\x77\xd3\
-\x3a\x6d\x6f\xef\xcb\x82\x96\x68\x9b\x57\x59\xf2\x92\x74\x12\x2f\
-\xee\xc7\xdf\x0c\x49\x59\x8f\xc8\x72\x64\x59\x96\xbd\x75\x51\x20\
+\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\x6f\xde\xfe\x72\xbe\xff\xaf\xce\x5e\x7b\xc2\xa3\x46\
-\xc7\xd0\xa8\xb3\x47\xda\x8e\x47\xa5\xec\xbc\x9b\xf0\xe7\xcf\x5f\
-\x73\xea\x05\x03\xf8\xeb\x0d\xba\x4c\x29\x78\x59\xbe\x16\xb4\xaf\
-\xda\x0d\xd3\x08\x5a\xdf\x71\x77\xc0\x14\xd1\xcf\x97\xfb\x9f\xbf\
-\xeb\xc7\x7d\xe2\xd3\x11\xbb\xdc\xcf\xed\x04\x07\x23\xed\xb1\x08\
+\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\xc9\x05\x14\x99\x9f\xa6\x78\xc8\xf8\x60\xa8\
-\x3a\xa7\x47\xad\x76\xc3\xfe\xd6\x7d\x36\xc2\x4e\xdb\x8d\x70\xf0\
+\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\xef\x98\xcf\x04\xf5\x88\xb4\x93\x69\x37\x6c\xc5\xc3\x2e\x3d\
-\x3a\x0d\x26\x11\x72\xbe\xbd\x0a\xee\x3f\xea\x22\xdb\x63\x6a\x48\
+\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\x77\x22\x98\x8c\x01\xe6\x70\
+\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\x8f\x56\x34\x70\x34\xa3\x8c\x8e\xde\x3f\xe8\x68\x18\x08\xfe\
-\x57\xe0\xab\x59\x57\xcd\x8b\x59\x5f\xe9\xde\x1e\x20\x49\x93\xf8\
-\xb5\x60\xfd\xab\x21\x73\x7e\xc4\x91\x85\x15\x63\xa8\x70\xb0\xa2\
-\x17\xdc\xff\xd1\x6c\xc5\xba\xcd\xc0\x5e\x10\x78\x37\x7c\x9c\x68\
-\x33\x43\xe2\x87\x3e\x51\x43\x2e\x09\xfc\xd7\xfd\x31\xf7\x19\x14\
-\x30\x8b\xd4\xbb\x40\xfc\xe8\x01\x7f\x0f\xe1\x97\xff\x0f\x45\xe8\
-\x78\xcc\xa8\x38\x20\x5f\x25\xeb\x4f\x80\x52\xb9\xef\x30\x42\x3d\
+\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\
-\x4b\xa1\xbb\xb1\x1d\x1e\xa4\xd6\x29\x7b\xb1\xb2\xe7\xc3\xee\x55\
-\xf6\x64\xde\x73\xf7\x01\xe4\xcb\x8f\x83\x38\x7e\xe3\xa3\xcc\x20\
+\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\x8f\x86\x75\xca\x8c\x7b\x4d\xd5\x70\xf1\xb0\x9f\x02\xb7\x11\
+\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\x3f\xd2\x1e\xf3\x42\x62\xf4\xf0\x21\x49\xd7\x45\x16\xcc\
+\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\xac\x9e\x3f\x7f\x89\xf5\x5f\
-\x50\x60\xff\x6f\xf6\x78\x23\x28\xf7\x60\xb4\xa8\xe4\xdb\x15\x43\
+\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\x7e\xd0\x68\
+\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\xfe\x48\xf6\x33\x91\x4c\x8f\xfc\
-\x56\x30\x76\xf5\xf2\x35\xb9\x81\x16\xb7\x9c\xdd\x11\x39\x95\x80\
+\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\xf9\x27\x4d\x8d\x9b\xc9\xc7\x0f\xe8\xea\x31\x6c\
+\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\x4d\x94\x0a\
+\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\
@@ -41479,201 +41484,204 @@ qt_resource_data = "\
\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\xfc\x60\xd3\xb5\xf8\x55\x60\x40\x27\x04\x60\x53\
+\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\x9f\xf5\xd8\x6e\xe8\xc2\xc2\xa4\x2a\xf9\x5f\xec\x3d\xf7\
-\xd5\x7c\x52\xc5\x16\x29\x74\x9a\x88\xe3\x71\x32\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\x83\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\x97\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\
-\x8f\xdc\x67\x6f\x5c\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\xe7\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\x1a\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\x15\x00\xf1\x5b\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\xbe\x7c\xac\x84\x29\x5e\x26\
-\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\x5f\x0c\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\x19\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\x31\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\xaf\xe8\xdf\xf7\x98\x4d\x01\xa2\x5d\xf6\
-\x08\x5c\xec\xb6\x11\x19\x27\x56\xe3\x97\x9d\xc8\x12\x51\x8f\x82\
-\x57\x8f\x6c\xfb\x62\x56\x1d\xa1\x28\x70\x52\xbf\xc8\xb5\x3b\x0b\
-\x32\x9d\xf3\xa4\x1d\x8f\x49\x3b\x4a\x2c\x08\x76\x97\xa5\x5d\x27\
-\xc3\x28\x94\x8c\x37\x71\x60\xd9\xd8\xa3\x3e\x23\x31\x43\xda\x5e\
-\xc7\x23\x89\x3b\xc1\x4e\x43\x0f\x2d\x41\x30\x74\x83\x6a\xb6\x67\
-\x28\x10\xbf\x5b\x98\xae\x35\x4c\x4a\x50\x98\x4a\x09\x99\x58\x50\
-\x78\xe9\x51\x6f\xc2\x41\x77\x44\x9f\x45\xf4\xd5\x44\xe5\x4a\xe4\
-\xc1\x67\xb9\x24\x12\xb1\x34\x43\xcd\x98\xa4\xd1\x87\x47\xd8\x24\
-\x44\xe9\x1a\x07\xe4\xb7\x30\xb2\xad\xad\x83\x69\xfa\x8d\x3b\x0e\
-\x50\x8a\x22\xe9\x5a\x05\x28\xfe\x2d\x8e\x35\x3b\xea\x3b\x2d\x9f\
-\x43\x52\x80\xdc\x11\x15\xbb\xe8\xf3\x7c\x32\x2f\x70\xa3\x5a\xa6\
-\xdb\xbb\xec\x2d\x2c\x09\xe1\xbc\x91\x99\xcf\xf9\x33\x2c\x40\x8a\
-\x96\xec\xbf\x5f\x6f\x2a\x2d\x96\xcb\x9b\xfd\x35\xc8\x5e\xc0\xf5\
-\x64\xed\xfe\xfb\x77\xf2\xf4\x26\x18\x67\x46\x3f\xd6\x04\xc1\x7f\
-\xc8\xd3\xb7\x02\x78\xab\x46\x18\x7e\x07\x18\xba\x60\xd0\x96\x02\
-\xa1\x6e\x91\xd4\xac\x26\xa3\xac\xdc\x25\x8f\x31\x6b\x73\x20\xb8\
-\x9b\xd0\x9f\x3a\x5c\x6f\x8d\xc7\x2a\xf4\xe7\x57\xd8\xa2\xe3\xa0\
-\x5b\xed\xcc\x37\x13\xd8\x4c\xc1\xb7\xf2\xe8\x7b\xbe\x1f\x67\xe7\
-\xcb\x2f\xe3\xcb\x2f\xb2\xc3\xcc\x3f\xcb\x50\x8b\x8b\x3f\xed\xa7\
-\x33\x0e\x90\x98\x4c\x31\x49\x39\x3d\x46\x6e\xb9\xe4\x98\x86\xa3\
-\xc5\x4b\xd6\x9d\xb2\xb0\x13\xc0\xfb\x1c\x6f\x59\xcc\xbc\x8f\x25\
-\x10\x4d\x74\xf6\x10\x0d\x53\x59\xab\xcc\x20\x82\x3d\xe5\x5a\xac\
-\x79\x9b\xc8\x03\xc3\xbd\xfb\x7b\x89\x93\x47\x58\xda\xf9\x19\xd1\
-\x95\xd1\xf2\xfc\x1c\x65\x24\x59\x7b\x33\x76\x0d\x86\xfb\xeb\x60\
-\x02\x13\x9e\x17\x1d\x72\x75\x6d\x18\x23\xda\xc0\x48\x9f\x3e\xd5\
-\x6e\x90\x07\xbc\xae\xee\x18\x30\x2c\xa3\xc0\xd4\x5a\x12\xe0\x99\
-\x87\xe5\x19\xca\x65\x0e\x1f\x01\xe4\xd9\x51\xa4\x12\x41\xa4\xec\
-\xa8\x97\xc1\x35\x46\xbd\x2e\x0e\x2e\xce\x2f\x66\xff\xce\xce\x5b\
-\xed\x86\xad\x2c\x3c\x54\x56\x18\xcc\xf6\xd5\x3c\x38\x4c\xfe\x5b\
-\x7e\x94\x82\xf6\x4b\x37\xa4\xf6\x9f\x49\xee\xd4\x13\x60\xcd\x0b\
-\x4d\x73\x5f\x33\x88\x24\x18\xc4\x7a\xfc\xc1\xba\xf5\xc5\xa4\xf3\
-\x13\x8f\x6a\xca\x2c\xe0\xbe\x41\x5a\x18\x0b\x34\xb7\xed\xa9\x21\
-\x47\x2f\xf0\x01\xe9\x62\xa6\x61\x7f\x4a\xc0\x8e\x60\x04\x5d\xd4\
-\x60\x33\x4c\x89\xfc\x73\x42\x05\x93\x33\x11\x35\x0a\xbb\x29\x91\
-\x90\x9c\x13\xe1\x6e\x1e\xae\x25\xc2\x8d\xbc\xfc\xc6\xd0\xce\x96\
-\x72\x72\xd5\x5b\xf0\x92\x77\x87\x2d\xc8\xb4\x9f\xcb\xdb\x1f\xf0\
-\x8e\x72\x1f\xf3\x5d\x05\x50\x23\x9e\xf2\x23\x1e\x30\x79\xe6\x69\
-\xf0\x9a\x79\x3c\xdf\xa6\xb0\x9a\xb2\x0b\x3b\xa2\xc7\xee\xba\x4e\
-\xf3\x77\x5d\xcd\xd3\xb3\xb3\xb3\x56\xf3\xa4\xcc\xde\xab\xb8\x89\
-\x12\xe5\xff\x84\x46\x05\x1e\x7f\xe3\xe1\x32\x39\x41\x20\x5c\xee\
-\x53\xc5\x64\x2c\x6a\x46\x9e\x62\x7a\x12\xbb\x3f\x20\x47\xe4\x92\
-\x1c\x82\xba\x6e\x96\xc8\x4a\xce\x11\x17\xa7\x6b\x91\x16\x33\x5a\
-\xdc\x5a\x69\x51\xd4\x7d\x91\xaf\xbf\x76\xee\x8b\x95\x1f\x1e\x58\
-\x56\x5e\xbe\xe6\x23\xe6\xeb\xc3\xd0\x5b\x20\x31\xf3\x37\xb0\xb9\
-\x19\x75\xe7\xd5\xe4\xd3\xad\x45\x7c\xb8\x7c\x74\xbd\xf5\x12\xa4\
-\x6a\x7b\xa3\xc0\x81\xbf\x2c\x06\x5a\x90\x37\x37\x97\x7f\x6e\x02\
-\x0f\x94\x96\xef\x54\x1a\x79\xcc\x97\xb5\xf9\xac\xbf\x93\xb5\x2b\
-\x71\x15\x17\x70\x16\xfd\x04\x66\x5d\x74\x81\x8d\x16\x8e\x98\x6a\
-\xe7\x62\x5e\x46\x7f\xe2\x3b\xc6\x80\x53\x43\xaa\x74\x66\x28\x25\
-\x2a\x64\x91\x83\xbd\x6f\xd8\xda\x9e\x6f\x71\x79\xbf\x0f\x3b\x45\
-\x28\xc7\xcd\xa1\x07\xfb\x45\x9d\x9c\x62\x3a\x0c\xb7\x98\x4a\x30\
-\x7d\xe8\x85\x4a\x22\x01\xb0\x12\x7b\xc6\x9c\x53\x5c\x8d\x65\x08\
-\xde\x1f\x00\x39\x28\x96\x46\x91\xf5\x23\x81\xc9\xda\x5c\x91\x87\
-\x29\xc7\x8f\x05\xa3\x9c\xac\xdf\x8f\xa5\x22\x91\xb7\xd3\x45\x59\
-\xba\xe8\xb4\x9c\x2a\x5a\x90\xe1\xb5\x30\x21\x06\x5b\x10\x23\x0b\
-\x36\xdc\xab\x9e\x1f\x50\xff\x3b\x88\xca\x70\x4d\xcc\x78\xfa\xd0\
-\x0d\x2e\x8f\xd4\xf7\x12\xb9\x33\xdb\x7b\xb5\x7b\xdb\x99\x74\x68\
-\xd5\xe0\xe5\xc6\xe9\x85\xc4\xb7\xa5\xe2\xa1\xa8\x01\x96\xef\xc8\
-\xd9\x19\x60\xab\xde\xec\x2e\xb8\xd9\xe9\x71\x02\xb2\x0f\xf8\xde\
-\xc4\x9b\x05\x97\xcf\x31\xca\xba\x57\x10\x67\xa9\xdf\x9d\x7d\xcd\
-\xd1\x7e\x20\x36\x43\x08\x1d\xec\x7d\x00\x78\xa9\x8f\x76\x17\x8d\
-\xbd\x29\x27\xce\x10\x0d\xb0\x27\x7f\x4e\x02\xf5\xe2\xa5\xe0\xd4\
-\x33\x3f\x31\x95\x29\x1c\x48\xaa\xa9\x97\x6e\x2a\xa9\x2f\xc3\x96\
-\xb6\x84\x09\xde\x37\x3f\xf7\x00\x1e\xf3\x6b\x14\xf8\x41\xd8\x0c\
-\x81\x24\x7d\x3a\xe2\xde\x34\x6b\xdc\x67\xef\x99\x77\xcb\xf0\xdb\
-\xc0\xcf\xa2\xce\xcd\x4b\x1a\x54\x6d\x58\x52\x03\xcc\x5e\xc6\xfb\
-\xcf\x5f\x05\x9e\x6b\x9e\x2b\x49\x66\xc0\x31\xb6\xea\xeb\xa9\x65\
-\x25\xbd\xe1\xa2\x2d\x95\xf3\x55\xbb\x24\x0a\x9c\xf0\xcb\xf4\xe9\
-\x2d\x7b\x8f\x7f\x24\xe7\x46\x63\x0f\x3f\x05\x2b\x87\x8c\x55\x2a\
-\xec\xf2\xf5\xe3\x82\x89\xec\x14\xe4\x4a\x3c\x14\x6f\xb9\xc7\xae\
-\x86\x41\x00\x32\xf6\x81\x72\xe9\x43\x9d\x63\xea\x16\x19\xdd\xdc\
-\x2f\x6a\x74\x1f\x1d\xe6\x23\xa8\x14\x7e\x8a\x07\x9c\xdc\x34\xf5\
-\xdb\xfb\x49\x75\x46\x9b\x83\xfe\x04\x93\xd4\x86\xdf\xb0\x0a\xcf\
-\x6b\x15\x63\x90\x72\x42\xd3\x40\xb5\x13\x9a\xd9\x42\xb3\x55\xd1\
-\x49\xc1\x12\x97\x19\x7e\x37\xd9\x93\xa9\x83\x53\x51\x3a\x25\xbe\
-\x6c\x93\x22\x34\x79\x31\x72\x8d\x97\x7c\x8e\x05\x1f\x71\xcc\xad\
-\x94\xe1\xbd\x84\x18\x04\x35\xaf\xcc\xee\x41\xd4\x44\x49\x6f\x41\
-\x87\x63\x46\x47\x25\x77\xb4\x61\xee\xb7\x06\xe8\x7a\x06\xd0\x7a\
-\xbe\xde\x2d\x19\x0e\x1b\x1f\x75\x47\xf2\x99\x76\x42\x81\x6b\x9e\
-\x33\xec\x84\xf2\x81\xbf\x27\x74\x34\x7e\x41\x3e\x02\x85\x82\x0e\
-\xa7\x42\x04\x77\xc6\x82\xde\xc4\xc3\x54\x2b\x3b\x4a\xc5\x47\xe6\
-\x53\xbc\x9b\x4a\x95\xe5\x8e\xf1\xbc\x0e\x14\x39\xa9\xef\x14\x11\
-\x0e\x7f\x56\xef\xf0\x17\xf5\x0d\x7f\xc5\x85\x03\x9b\xe1\x1a\xf1\
-\x6f\x21\xa8\x71\x09\x2c\x04\x35\xae\x42\x17\x44\xcb\xb0\xce\x45\
-\x30\x00\xd4\xb8\x06\x06\x80\x1a\x97\xe0\x15\x75\x7e\xc8\xba\x97\
-\x21\x02\xa2\xc6\xa5\x88\x80\x28\xb5\x1c\xb5\x9b\x2a\x25\x43\x5b\
-\xcd\xfc\xbc\xb0\xf9\xd6\xca\x37\x68\xc5\x1d\xea\xc5\xdc\x95\xc6\
-\x8d\x1b\x73\x1e\x6c\xa2\xb9\xb2\xaa\x0f\x9f\xc7\xef\x1c\x09\xfa\
-\xc6\xc5\x1b\x62\xc2\x3a\x73\xed\x21\x2f\xd8\xe3\xc7\x91\x44\x05\
-\x23\xb7\x16\x79\x07\x24\xf4\x0c\x41\xaf\x1e\xeb\x2b\xdc\x7f\x70\
-\x73\x0c\x0c\x7b\xfc\xd0\xfd\x0d\x3f\x50\xe0\xbb\x54\x94\xb9\x43\
-\xbd\x98\x15\x96\x58\xc0\xbf\xa3\x29\xf6\x11\x10\x4d\x9e\xc6\x71\
-\x5b\xe3\xf1\xee\x2f\xf3\xa2\xc2\x5b\x22\x81\x4a\x8a\x9f\x65\x3f\
-\xf3\xfe\xd2\xd3\xe9\xca\xb0\xb5\xef\x7e\x7b\x07\xbb\x69\x85\x8f\
-\xc0\x43\x81\x53\xb9\xe4\x59\xe0\x5a\xcd\x3f\x9f\xba\x73\xad\xae\
-\xd5\xb5\xba\x20\xa3\x7f\xab\x5d\xab\xef\xf1\x54\x0f\x5e\xf7\x87\
-\x11\x42\x69\x8f\xfa\x50\x50\x35\x82\x39\x2a\x10\x53\xbc\x5b\x54\
-\xd9\x2f\x9a\x23\x93\x20\x5e\x64\xbc\xf0\x89\xa7\x5e\x8c\x0d\xe7\
-\x3c\x19\xa8\x17\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\x9c\x4c\x4e\x56\x26\
-\xfa\x8a\xda\xc5\x1a\xc5\x5a\x58\xf9\x3d\x8b\x01\x9b\xc3\x8d\x97\
-\xfb\xa7\xfb\x64\x44\xc5\x80\xfb\x97\xfb\xcd\xe6\x3e\xa6\xd7\xb5\
-\xc7\xfc\x7e\x44\xc7\x61\x7e\x60\xe7\xcf\x6b\xfd\xfc\x56\x04\xa3\
-\x4f\x60\xac\x74\x83\x89\xc0\x7c\xb2\x54\x2b\x78\xcf\x99\x48\x15\
-\x8c\xcc\x88\x52\x43\x12\x2f\x31\x50\x6a\x76\xed\x68\x6e\x8d\x71\
-\x2a\xe0\x4f\x97\xeb\x26\x20\xd9\x99\xef\xca\xce\xe7\xef\xfa\x3d\
-\x10\x75\xb6\x60\xcf\x70\x13\xba\xbe\xb0\x87\x06\x76\xf0\x9a\x53\
-\x2f\x18\x1c\x0c\x91\xb9\x74\x85\x46\x40\x7a\xdc\x7c\x40\xae\xf0\
-\xeb\x63\xaf\x26\x4a\x69\xb3\x26\x03\x90\xeb\x89\x1c\x86\xf5\xf3\
-\x80\x31\xc0\xca\x72\x90\xa4\x04\x58\x26\x34\x0f\x71\x37\x0f\x24\
-\xec\x6d\x65\x60\xd9\x2c\xb1\x6c\x04\xcd\x2a\xd7\x02\xca\xa2\xf5\
-\x7a\xb8\xa8\xeb\x01\xcb\x46\x36\xb2\x51\x14\xd5\xae\x09\x47\x66\
-\xb7\x33\x07\x98\x59\xed\x5a\x80\x09\x13\x69\xb2\x81\x89\x6a\xd7\
-\x02\x4c\x22\xe9\x31\x1b\xa2\x54\x93\xf2\x60\x25\x0b\xb0\xa7\xb6\
-\x60\x52\x0b\x52\xa9\x45\x2e\xe8\x5e\x9f\x99\x74\x6c\x33\x8b\xd9\
-\xb3\x19\x55\x02\x00\xd0\x77\xc6\x3d\x47\x98\x3b\xe2\xdb\x71\xd1\
-\x3a\x19\xf8\xd4\xeb\x38\x1e\x9e\xf3\x75\x9f\xe2\xd1\x62\xdc\xc1\
-\x98\x52\xdd\x02\x4c\x00\xc6\x6f\xe3\x7d\xa5\x6e\x4f\x68\x37\x66\
-\x4d\x4c\x97\x5e\xa0\x3a\xa0\x06\xdf\x98\x83\xcc\xb3\x3e\xb1\xd8\
-\x60\x04\x3f\x56\x62\x35\x12\xfe\x26\x6a\x3a\x46\x53\x53\x4f\x2f\
-\x11\xf6\x68\xdf\x77\x2e\x00\xe0\xfb\xf0\x71\xda\x39\x3a\xbb\x68\
-\x37\xa6\xa1\x3a\xc3\xb7\x1f\x76\xe4\x32\xfc\xc0\x92\x36\x8c\xd3\
-\xbd\x1d\x37\xcf\x92\xdd\x9d\x37\xb3\xba\x33\x3f\xa5\x5d\x9a\x04\
-\x6a\xd7\x8a\xe9\xd9\x89\xf1\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\x25\x85\x8a\x31\xdb\x5a\x29\x66\x9b\xa7\x6b\xc3\xec\xf2\x12\
-\x22\xbc\xf4\xa7\x5a\xcc\x9e\x9c\x27\x19\xf9\xf4\xa4\x0c\x66\x8f\
-\x4e\x8e\xb7\x40\xf6\x86\xd7\x9a\x54\x8b\xd9\xa3\xa3\x14\x66\xcf\
-\x56\x49\xb3\x55\x62\xf6\xac\xbc\xc4\x8d\xae\x86\xaf\x16\xc9\xcd\
-\x14\xfd\xb6\x2e\x4a\x49\x86\x63\xf4\xd7\x24\xba\xcb\x54\x93\x9b\
-\x62\x3b\xc4\xae\xb9\xab\xd8\x7a\x48\x5b\x68\xa5\xa4\x44\xab\x75\
-\xfa\x18\x63\x64\x3e\x96\xe3\x8f\x50\xdf\x6e\x4c\x78\x67\xef\xff\
-\x40\xba\x52\xd7\
+\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\x00\x07\xb5\
\x00\
\x00\x1a\x6e\x78\x9c\xed\x58\x5d\x6f\xe3\xb8\x15\x7d\xcf\xaf\x50\
@@ -47969,6 +47977,304 @@ qt_resource_data = "\
\xd8\xee\x88\x05\x36\x62\x1e\x73\xd8\x05\xd9\xfd\xc8\xa6\x16\xbb\
\x60\xfb\xff\x13\xdb\xc4\xf6\x10\x20\x00\x07\xd7\xda\x76\xd2\xe2\
\xf0\x1a\x0c\x5f\x13\xf5\xb6\x7e\x7b\xf5\x17\x93\x56\xec\x3d\
+\x00\x00\x12\x80\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
+\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\
+\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\
+\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\
+\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\
+\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\
+\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\
+\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\
+\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\
+\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\
+\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\
+\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\
+\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
+\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\
+\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\
+\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\
+\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
+\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\
+\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\
+\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\
+\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\
+\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\
+\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\
+\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\
+\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\
+\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
+\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\
+\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\
+\x70\x78\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\
+\x34\x70\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x34\
+\x35\x39\x34\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\
+\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\
+\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\
+\x69\x6f\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x33\x2e\x31\x20\x72\x39\
+\x38\x38\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\
+\x3a\x64\x6f\x63\x6e\x61\x6d\x65\x3d\x22\x44\x72\x61\x66\x74\x5f\
+\x53\x68\x61\x70\x65\x53\x74\x72\x69\x6e\x67\x2e\x73\x76\x67\x22\
+\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6f\x75\x74\
+\x70\x75\x74\x5f\x65\x78\x74\x65\x6e\x73\x69\x6f\x6e\x3d\x22\x6f\
+\x72\x67\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x75\x74\x70\
+\x75\x74\x2e\x73\x76\x67\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x22\
+\x0a\x20\x20\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\
+\x69\x64\x3d\x22\x64\x65\x66\x73\x34\x35\x39\x36\x22\x3e\x0a\x20\
+\x20\x20\x20\x3c\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\
+\x73\x70\x65\x63\x74\x69\x76\x65\x0a\x20\x20\x20\x20\x20\x20\x20\
+\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\x65\x3d\x22\x69\
+\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x33\x64\x22\
+\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\
+\x3a\x76\x70\x5f\x78\x3d\x22\x30\x20\x3a\x20\x33\x32\x20\x3a\x20\
+\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x3a\x76\x70\x5f\x79\x3d\x22\x30\x20\x3a\x20\x31\x30\x30\
+\x30\x20\x3a\x20\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\
+\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x7a\x3d\x22\x36\x34\x20\
+\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\
+\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x33\
+\x64\x2d\x6f\x72\x69\x67\x69\x6e\x3d\x22\x33\x32\x20\x3a\x20\x32\
+\x31\x2e\x33\x33\x33\x33\x33\x33\x20\x3a\x20\x31\x22\x0a\x20\x20\
+\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x65\x72\x73\x70\x65\x63\
+\x74\x69\x76\x65\x34\x36\x30\x32\x22\x20\x2f\x3e\x0a\x20\x20\x3c\
+\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\
+\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\
+\x20\x20\x69\x64\x3d\x22\x62\x61\x73\x65\x22\x0a\x20\x20\x20\x20\
+\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\
+\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\
+\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\
+\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\
+\x74\x79\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\
+\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\
+\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\
+\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\
+\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\
+\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x35\x2e\x36\x35\x36\x38\
+\x35\x34\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x3a\x63\x78\x3d\x22\x31\x36\x2e\x37\x32\x34\x37\x31\x38\
+\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
+\x63\x79\x3d\x22\x32\x34\x2e\x38\x33\x31\x39\x30\x37\x22\x0a\x20\
+\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\
+\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x6c\x61\x79\x65\
+\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\x72\x69\
+\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\
+\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\
+\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\x20\x20\x20\x20\
+\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x69\x64\x2d\x62\x62\
+\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x69\
+\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x77\
+\x69\x64\x74\x68\x3d\x22\x31\x33\x36\x36\x22\x0a\x20\x20\x20\x20\
+\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\
+\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x39\x35\x22\x0a\x20\x20\
+\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\
+\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\
+\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\
+\x22\x32\x34\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\
+\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x6d\x65\
+\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
+\x6d\x65\x74\x61\x64\x61\x74\x61\x34\x35\x39\x39\x22\x3e\x0a\x20\
+\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x20\
+\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\x20\x20\
+\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\x3d\x22\
+\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x66\
+\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\x67\x2b\
+\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x0a\
+\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\x70\x65\
+\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\
+\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\
+\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\x63\x6d\
+\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\x67\x65\
+\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\
+\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\
+\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\
+\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\
+\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\
+\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\x22\x4c\x61\
+\x79\x65\x72\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
+\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\x65\x3d\x22\
+\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\x20\x20\x20\x3c\x74\x65\x78\
+\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6d\x6c\x3a\x73\x70\x61\
+\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x0a\x20\x20\
+\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x6f\x6e\x74\
+\x2d\x73\x69\x7a\x65\x3a\x34\x30\x70\x78\x3b\x66\x6f\x6e\x74\x2d\
+\x73\x74\x79\x6c\x65\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\x66\x6f\x6e\
+\x74\x2d\x77\x65\x69\x67\x68\x74\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\
+\x6c\x69\x6e\x65\x2d\x68\x65\x69\x67\x68\x74\x3a\x31\x32\x35\x25\
+\x3b\x6c\x65\x74\x74\x65\x72\x2d\x73\x70\x61\x63\x69\x6e\x67\x3a\
+\x30\x70\x78\x3b\x77\x6f\x72\x64\x2d\x73\x70\x61\x63\x69\x6e\x67\
+\x3a\x30\x70\x78\x3b\x66\x69\x6c\x6c\x3a\x23\x30\x30\x30\x30\x30\
+\x30\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\
+\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x6e\x6f\x6e\x65\x3b\x66\x6f\x6e\
+\x74\x2d\x66\x61\x6d\x69\x6c\x79\x3a\x53\x61\x6e\x73\x22\x0a\x20\
+\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x31\x35\x2e\x36\x38\x34\x39\
+\x31\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x31\x39\
+\x2e\x37\x37\x33\x36\x38\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\
+\x69\x64\x3d\x22\x74\x65\x78\x74\x33\x30\x39\x37\x22\x0a\x20\x20\
+\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6c\x69\
+\x6e\x65\x73\x70\x61\x63\x69\x6e\x67\x3d\x22\x31\x32\x35\x25\x22\
+\x3e\x3c\x74\x73\x70\x61\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\
+\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x72\x6f\x6c\x65\x3d\x22\
+\x6c\x69\x6e\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\
+\x64\x3d\x22\x74\x73\x70\x61\x6e\x33\x30\x39\x39\x22\x0a\x20\x20\
+\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x31\x35\x2e\x36\x38\x34\
+\x39\x31\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x3d\
+\x22\x31\x39\x2e\x37\x37\x33\x36\x38\x34\x22\x20\x2f\x3e\x3c\x2f\
+\x74\x65\x78\x74\x3e\x0a\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\
+\x20\x20\x20\x20\x69\x64\x3d\x22\x67\x34\x30\x36\x31\x22\x3e\x0a\
+\x20\x20\x20\x20\x20\x20\x3c\x74\x65\x78\x74\x0a\x20\x20\x20\x20\
+\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\
+\x73\x63\x61\x6c\x65\x28\x31\x2e\x32\x36\x33\x30\x37\x37\x33\x2c\
+\x30\x2e\x37\x39\x31\x37\x31\x37\x31\x39\x29\x22\x0a\x20\x20\x20\
+\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6c\
+\x69\x6e\x65\x73\x70\x61\x63\x69\x6e\x67\x3d\x22\x31\x32\x35\x25\
+\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x74\
+\x65\x78\x74\x33\x38\x39\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\
+\x20\x20\x79\x3d\x22\x36\x39\x2e\x35\x30\x38\x33\x38\x35\x22\x0a\
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x35\x2e\x34\x36\
+\x35\x34\x32\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\
+\x74\x79\x6c\x65\x3d\x22\x66\x6f\x6e\x74\x2d\x73\x69\x7a\x65\x3a\
+\x37\x37\x2e\x33\x39\x35\x34\x36\x32\x30\x33\x39\x39\x39\x39\x39\
+\x39\x38\x31\x38\x70\x78\x3b\x66\x6f\x6e\x74\x2d\x73\x74\x79\x6c\
+\x65\x3a\x69\x74\x61\x6c\x69\x63\x3b\x66\x6f\x6e\x74\x2d\x76\x61\
+\x72\x69\x61\x6e\x74\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\x66\x6f\x6e\
+\x74\x2d\x77\x65\x69\x67\x68\x74\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\
+\x66\x6f\x6e\x74\x2d\x73\x74\x72\x65\x74\x63\x68\x3a\x6e\x6f\x72\
+\x6d\x61\x6c\x3b\x74\x65\x78\x74\x2d\x61\x6c\x69\x67\x6e\x3a\x73\
+\x74\x61\x72\x74\x3b\x6c\x69\x6e\x65\x2d\x68\x65\x69\x67\x68\x74\
+\x3a\x31\x32\x35\x25\x3b\x6c\x65\x74\x74\x65\x72\x2d\x73\x70\x61\
+\x63\x69\x6e\x67\x3a\x30\x70\x78\x3b\x77\x6f\x72\x64\x2d\x73\x70\
+\x61\x63\x69\x6e\x67\x3a\x30\x70\x78\x3b\x77\x72\x69\x74\x69\x6e\
+\x67\x2d\x6d\x6f\x64\x65\x3a\x6c\x72\x2d\x74\x62\x3b\x74\x65\x78\
+\x74\x2d\x61\x6e\x63\x68\x6f\x72\x3a\x73\x74\x61\x72\x74\x3b\x6f\
+\x70\x61\x63\x69\x74\x79\x3a\x30\x2e\x36\x32\x37\x31\x31\x38\x36\
+\x33\x39\x39\x39\x39\x39\x39\x39\x39\x35\x3b\x63\x6f\x6c\x6f\x72\
+\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x30\
+\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\
+\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\
+\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\
+\x30\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\
+\x74\x68\x3a\x33\x2e\x31\x39\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\
+\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\
+\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x6d\x69\x74\
+\x65\x72\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\
+\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\
+\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\
+\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\
+\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\
+\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\
+\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\
+\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\
+\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\
+\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\
+\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\x65\x3b\x66\x6f\
+\x6e\x74\x2d\x66\x61\x6d\x69\x6c\x79\x3a\x54\x69\x6d\x65\x73\x20\
+\x4e\x65\x77\x20\x52\x6f\x6d\x61\x6e\x3b\x2d\x69\x6e\x6b\x73\x63\
+\x61\x70\x65\x2d\x66\x6f\x6e\x74\x2d\x73\x70\x65\x63\x69\x66\x69\
+\x63\x61\x74\x69\x6f\x6e\x3a\x27\x54\x69\x6d\x65\x73\x20\x4e\x65\
+\x77\x20\x52\x6f\x6d\x61\x6e\x2c\x20\x49\x74\x61\x6c\x69\x63\x27\
+\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x78\x6d\x6c\x3a\x73\
+\x70\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\
+\x3c\x74\x73\x70\x61\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\
+\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x72\x6f\x6b\x65\x2d\
+\x77\x69\x64\x74\x68\x3a\x33\x2e\x31\x39\x31\x3b\x73\x74\x72\x6f\
+\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\
+\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\
+\x3a\x6e\x6f\x6e\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\
+\x20\x20\x79\x3d\x22\x36\x39\x2e\x35\x30\x38\x33\x38\x35\x22\x0a\
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x35\x2e\
+\x34\x36\x35\x34\x32\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\
+\x20\x20\x20\x69\x64\x3d\x22\x74\x73\x70\x61\x6e\x33\x38\x39\x34\
+\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\
+\x69\x70\x6f\x64\x69\x3a\x72\x6f\x6c\x65\x3d\x22\x6c\x69\x6e\x65\
+\x22\x3e\x53\x3c\x2f\x74\x73\x70\x61\x6e\x3e\x3c\x74\x73\x70\x61\
+\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\
+\x6c\x65\x3d\x22\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\
+\x3a\x33\x2e\x31\x39\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\
+\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\
+\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\
+\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\
+\x22\x74\x73\x70\x61\x6e\x33\x38\x39\x36\x22\x0a\x20\x20\x20\x20\
+\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x31\x36\x36\x2e\x32\x35\
+\x32\x37\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
+\x78\x3d\x22\x35\x2e\x34\x36\x35\x34\x32\x35\x22\x0a\x20\x20\x20\
+\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\
+\x3a\x72\x6f\x6c\x65\x3d\x22\x6c\x69\x6e\x65\x22\x20\x2f\x3e\x3c\
+\x2f\x74\x65\x78\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x74\x65\
+\x78\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
+\x63\x61\x70\x65\x3a\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x2d\x63\
+\x65\x6e\x74\x65\x72\x2d\x79\x3d\x22\x31\x37\x2e\x36\x34\x36\x37\
+\x39\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\
+\x73\x63\x61\x70\x65\x3a\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x2d\
+\x63\x65\x6e\x74\x65\x72\x2d\x78\x3d\x22\x31\x2e\x39\x38\x35\x39\
+\x39\x32\x33\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x74\x72\
+\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x73\x63\x61\x6c\x65\x28\x31\
+\x2e\x32\x35\x38\x36\x38\x35\x2c\x30\x2e\x37\x39\x34\x34\x37\x39\
+\x39\x36\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\
+\x64\x69\x70\x6f\x64\x69\x3a\x6c\x69\x6e\x65\x73\x70\x61\x63\x69\
+\x6e\x67\x3d\x22\x31\x32\x35\x25\x22\x0a\x20\x20\x20\x20\x20\x20\
+\x20\x20\x20\x69\x64\x3d\x22\x74\x65\x78\x74\x33\x31\x30\x33\x22\
+\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x36\x35\x2e\
+\x32\x32\x35\x36\x33\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\
+\x20\x78\x3d\x22\x32\x2e\x31\x37\x37\x34\x36\x36\x39\x22\x0a\x20\
+\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\
+\x6f\x6e\x74\x2d\x73\x69\x7a\x65\x3a\x38\x30\x2e\x30\x36\x37\x31\
+\x33\x31\x30\x34\x70\x78\x3b\x66\x6f\x6e\x74\x2d\x73\x74\x79\x6c\
+\x65\x3a\x69\x74\x61\x6c\x69\x63\x3b\x66\x6f\x6e\x74\x2d\x76\x61\
+\x72\x69\x61\x6e\x74\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\x66\x6f\x6e\
+\x74\x2d\x77\x65\x69\x67\x68\x74\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\
+\x66\x6f\x6e\x74\x2d\x73\x74\x72\x65\x74\x63\x68\x3a\x6e\x6f\x72\
+\x6d\x61\x6c\x3b\x74\x65\x78\x74\x2d\x61\x6c\x69\x67\x6e\x3a\x73\
+\x74\x61\x72\x74\x3b\x6c\x69\x6e\x65\x2d\x68\x65\x69\x67\x68\x74\
+\x3a\x31\x32\x35\x25\x3b\x6c\x65\x74\x74\x65\x72\x2d\x73\x70\x61\
+\x63\x69\x6e\x67\x3a\x30\x70\x78\x3b\x77\x6f\x72\x64\x2d\x73\x70\
+\x61\x63\x69\x6e\x67\x3a\x30\x70\x78\x3b\x77\x72\x69\x74\x69\x6e\
+\x67\x2d\x6d\x6f\x64\x65\x3a\x6c\x72\x2d\x74\x62\x3b\x74\x65\x78\
+\x74\x2d\x61\x6e\x63\x68\x6f\x72\x3a\x73\x74\x61\x72\x74\x3b\x63\
+\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\
+\x6c\x3a\x23\x66\x66\x64\x61\x30\x34\x3b\x66\x69\x6c\x6c\x2d\x6f\
+\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\
+\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\
+\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\
+\x2d\x77\x69\x64\x74\x68\x3a\x31\x2e\x35\x37\x33\x33\x33\x31\x35\
+\x39\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\
+\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\
+\x65\x6a\x6f\x69\x6e\x3a\x6d\x69\x74\x65\x72\x3b\x73\x74\x72\x6f\
+\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\
+\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\
+\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\
+\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\
+\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\
+\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\
+\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\
+\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\
+\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\
+\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\
+\x6d\x75\x6c\x61\x74\x65\x3b\x66\x6f\x6e\x74\x2d\x66\x61\x6d\x69\
+\x6c\x79\x3a\x54\x69\x6d\x65\x73\x20\x4e\x65\x77\x20\x52\x6f\x6d\
+\x61\x6e\x3b\x2d\x69\x6e\x6b\x73\x63\x61\x70\x65\x2d\x66\x6f\x6e\
+\x74\x2d\x73\x70\x65\x63\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x3a\
+\x27\x54\x69\x6d\x65\x73\x20\x4e\x65\x77\x20\x52\x6f\x6d\x61\x6e\
+\x2c\x20\x49\x74\x61\x6c\x69\x63\x27\x22\x0a\x20\x20\x20\x20\x20\
+\x20\x20\x20\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\
+\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x3c\x74\x73\x70\x61\x6e\x0a\
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\
+\x3d\x22\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x31\
+\x2e\x35\x37\x33\x33\x33\x31\x35\x39\x22\x0a\x20\x20\x20\x20\x20\
+\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x36\x35\x2e\x32\x32\x35\x36\
+\x33\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x78\
+\x3d\x22\x32\x2e\x31\x37\x37\x34\x36\x36\x39\x22\x0a\x20\x20\x20\
+\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x74\x73\x70\x61\
+\x6e\x33\x31\x30\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\
+\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x72\x6f\x6c\x65\x3d\
+\x22\x6c\x69\x6e\x65\x22\x3e\x53\x3c\x2f\x74\x73\x70\x61\x6e\x3e\
+\x3c\x2f\x74\x65\x78\x74\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\
+\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
\x00\x00\x0f\xd2\
\x00\
\x00\x52\x9a\x78\x9c\xe5\x5c\x5b\x6f\xe3\xb8\x15\x7e\x9f\x5f\xa1\
@@ -52985,6 +53291,11 @@ qt_resource_name = "\
\x07\x2c\x24\xc7\
\x00\x53\
\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x41\x00\x6e\x00\x67\x00\x6c\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
+\x00\x15\
+\x03\xf8\x76\x47\
+\x00\x44\
+\x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x53\x00\x68\x00\x61\x00\x70\x00\x65\x00\x53\x00\x74\x00\x72\x00\x69\x00\x6e\x00\x67\
+\x00\x2e\x00\x73\x00\x76\x00\x67\
\x00\x11\
\x0d\x13\x54\x07\
\x00\x44\
@@ -53087,8 +53398,8 @@ 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\x58\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x37\x00\x00\x00\x21\
+\x00\x00\x00\x10\x00\x02\x00\x00\x00\x02\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\
\x00\x00\x01\xb4\x00\x01\x00\x00\x00\x01\x00\x04\x04\x86\
@@ -53119,63 +53430,64 @@ qt_resource_struct = "\
\x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x01\x64\
\x00\x00\x00\x96\x00\x00\x00\x00\x00\x01\x00\x00\x04\xc4\
\x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x03\x12\
-\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x0a\xf8\x2f\
-\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0a\x55\x18\
-\x00\x00\x09\x04\x00\x01\x00\x00\x00\x01\x00\x0b\xbc\xa1\
-\x00\x00\x0b\x94\x00\x01\x00\x00\x00\x01\x00\x0c\x98\xac\
-\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x0a\x94\xc3\
-\x00\x00\x07\x16\x00\x00\x00\x00\x00\x01\x00\x0b\x15\x79\
-\x00\x00\x08\x2a\x00\x01\x00\x00\x00\x01\x00\x0b\x7e\x27\
-\x00\x00\x0a\xf6\x00\x01\x00\x00\x00\x01\x00\x0c\x6f\x69\
-\x00\x00\x07\x8a\x00\x00\x00\x00\x00\x01\x00\x0b\x3f\x48\
-\x00\x00\x09\x9e\x00\x01\x00\x00\x00\x01\x00\x0b\xfd\x42\
-\x00\x00\x0b\xe4\x00\x01\x00\x00\x00\x01\x00\x0c\xb4\xd0\
-\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x0a\x6e\x3a\
-\x00\x00\x08\x50\x00\x01\x00\x00\x00\x01\x00\x0b\x83\xeb\
-\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x0b\x02\xe3\
-\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x0a\x73\xb9\
-\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x0b\x2e\x3e\
-\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x0a\x63\xce\
-\x00\x00\x0b\x1e\x00\x00\x00\x00\x00\x01\x00\x0c\x7a\xd8\
-\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x0a\x2f\x86\
-\x00\x00\x05\xd6\x00\x01\x00\x00\x00\x01\x00\x0a\xaf\xe2\
-\x00\x00\x0a\xae\x00\x01\x00\x00\x00\x01\x00\x0c\x58\x3a\
-\x00\x00\x0a\xd0\x00\x01\x00\x00\x00\x01\x00\x0c\x65\xd5\
-\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x0a\x9d\xc9\
-\x00\x00\x03\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x27\xcd\
-\x00\x00\x08\xba\x00\x01\x00\x00\x00\x01\x00\x0b\xa5\x77\
-\x00\x00\x09\xf8\x00\x00\x00\x00\x00\x01\x00\x0c\x0d\x8a\
-\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x0a\xc1\x52\
-\x00\x00\x0a\x1c\x00\x00\x00\x00\x00\x01\x00\x0c\x24\x3d\
-\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0b\x56\xfb\
-\x00\x00\x05\x38\x00\x01\x00\x00\x00\x01\x00\x0a\x83\xb9\
-\x00\x00\x0b\xb4\x00\x00\x00\x00\x00\x01\x00\x0c\xa3\x5a\
-\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xd8\x91\
-\x00\x00\x04\x28\x00\x00\x00\x00\x00\x01\x00\x0a\x37\x8d\
-\x00\x00\x0c\x14\x00\x00\x00\x00\x00\x01\x00\x0c\xc0\xa9\
-\x00\x00\x0a\x64\x00\x00\x00\x00\x00\x01\x00\x0c\x41\xc4\
-\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x0a\x4c\xad\
-\x00\x00\x0a\x8c\x00\x01\x00\x00\x00\x01\x00\x0c\x50\xeb\
-\x00\x00\x09\x26\x00\x01\x00\x00\x00\x01\x00\x0b\xc5\x4a\
-\x00\x00\x0b\x44\x00\x01\x00\x00\x00\x01\x00\x0c\x83\x65\
-\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x0a\xea\xd0\
-\x00\x00\x07\xbc\x00\x01\x00\x00\x00\x01\x00\x0b\x4d\x4a\
-\x00\x00\x09\x7c\x00\x00\x00\x00\x00\x01\x00\x0b\xe8\xb1\
-\x00\x00\x05\x5c\x00\x01\x00\x00\x00\x01\x00\x0a\x8a\x82\
-\x00\x00\x08\x0a\x00\x00\x00\x00\x00\x01\x00\x0b\x68\xb3\
-\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x0a\xbb\xd3\
-\x00\x00\x09\xc8\x00\x01\x00\x00\x00\x01\x00\x0c\x03\xb7\
-\x00\x00\x08\x92\x00\x01\x00\x00\x00\x01\x00\x0b\x9a\x05\
-\x00\x00\x08\xdc\x00\x01\x00\x00\x00\x01\x00\x0b\xac\xcb\
-\x00\x00\x0b\x6a\x00\x01\x00\x00\x00\x01\x00\x0c\x8e\x2a\
-\x00\x00\x0a\x40\x00\x01\x00\x00\x00\x01\x00\x0c\x37\x14\
-\x00\x00\x05\x08\x00\x01\x00\x00\x00\x01\x00\x0a\x7b\x97\
-\x00\x00\x08\x72\x00\x00\x00\x00\x00\x01\x00\x0b\x8a\x33\
-\x00\x00\x06\x58\x00\x00\x00\x00\x00\x01\x00\x0a\xc9\x37\
-\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x0b\x24\xca\
-\x00\x00\x09\x4a\x00\x00\x00\x00\x00\x01\x00\x0b\xcc\x9b\
+\x00\x00\x06\xce\x00\x01\x00\x00\x00\x01\x00\x0a\xf8\xb6\
+\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0a\x55\x9f\
+\x00\x00\x09\x34\x00\x01\x00\x00\x00\x01\x00\x0b\xcf\xac\
+\x00\x00\x0b\xc4\x00\x01\x00\x00\x00\x01\x00\x0c\xab\xb7\
+\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x0a\x95\x4a\
+\x00\x00\x07\x16\x00\x00\x00\x00\x00\x01\x00\x0b\x16\x00\
+\x00\x00\x08\x2a\x00\x01\x00\x00\x00\x01\x00\x0b\x7e\xae\
+\x00\x00\x0b\x26\x00\x01\x00\x00\x00\x01\x00\x0c\x82\x74\
+\x00\x00\x07\x8a\x00\x00\x00\x00\x00\x01\x00\x0b\x3f\xcf\
+\x00\x00\x09\xce\x00\x01\x00\x00\x00\x01\x00\x0c\x10\x4d\
+\x00\x00\x0c\x14\x00\x01\x00\x00\x00\x01\x00\x0c\xc7\xdb\
+\x00\x00\x04\xc2\x00\x01\x00\x00\x00\x01\x00\x0a\x6e\xc1\
+\x00\x00\x08\xdc\x00\x00\x00\x00\x00\x01\x00\x0b\xad\x52\
+\x00\x00\x08\x50\x00\x01\x00\x00\x00\x01\x00\x0b\x84\x72\
+\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x0b\x03\x6a\
+\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x0a\x74\x40\
+\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x0b\x2e\xc5\
+\x00\x00\x04\x9e\x00\x01\x00\x00\x00\x01\x00\x0a\x64\x55\
+\x00\x00\x0b\x4e\x00\x00\x00\x00\x00\x01\x00\x0c\x8d\xe3\
+\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x0a\x30\x0d\
+\x00\x00\x05\xd6\x00\x01\x00\x00\x00\x01\x00\x0a\xb0\x69\
+\x00\x00\x0a\xde\x00\x01\x00\x00\x00\x01\x00\x0c\x6b\x45\
+\x00\x00\x0b\x00\x00\x01\x00\x00\x00\x01\x00\x0c\x78\xe0\
+\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x0a\x9e\x50\
+\x00\x00\x03\xca\x00\x01\x00\x00\x00\x01\x00\x0a\x28\x54\
+\x00\x00\x08\xba\x00\x01\x00\x00\x00\x01\x00\x0b\xa5\xfe\
+\x00\x00\x0a\x28\x00\x00\x00\x00\x00\x01\x00\x0c\x20\x95\
+\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x0a\xc1\xd9\
+\x00\x00\x0a\x4c\x00\x00\x00\x00\x00\x01\x00\x0c\x37\x48\
+\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0b\x57\x82\
+\x00\x00\x05\x38\x00\x01\x00\x00\x00\x01\x00\x0a\x84\x40\
+\x00\x00\x0b\xe4\x00\x00\x00\x00\x00\x01\x00\x0c\xb6\x65\
+\x00\x00\x06\x84\x00\x00\x00\x00\x00\x01\x00\x0a\xd9\x18\
+\x00\x00\x04\x28\x00\x00\x00\x00\x00\x01\x00\x0a\x38\x14\
+\x00\x00\x0c\x44\x00\x00\x00\x00\x00\x01\x00\x0c\xd3\xb4\
+\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x0c\x54\xcf\
+\x00\x00\x04\x4c\x00\x01\x00\x00\x00\x01\x00\x0a\x4d\x34\
+\x00\x00\x0a\xbc\x00\x01\x00\x00\x00\x01\x00\x0c\x63\xf6\
+\x00\x00\x09\x56\x00\x01\x00\x00\x00\x01\x00\x0b\xd8\x55\
+\x00\x00\x0b\x74\x00\x01\x00\x00\x00\x01\x00\x0c\x96\x70\
+\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x0a\xeb\x57\
+\x00\x00\x07\xbc\x00\x01\x00\x00\x00\x01\x00\x0b\x4d\xd1\
+\x00\x00\x09\xac\x00\x00\x00\x00\x00\x01\x00\x0b\xfb\xbc\
+\x00\x00\x05\x5c\x00\x01\x00\x00\x00\x01\x00\x0a\x8b\x09\
+\x00\x00\x08\x0a\x00\x00\x00\x00\x00\x01\x00\x0b\x69\x3a\
+\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x0a\xbc\x5a\
+\x00\x00\x09\xf8\x00\x01\x00\x00\x00\x01\x00\x0c\x16\xc2\
+\x00\x00\x08\x92\x00\x01\x00\x00\x00\x01\x00\x0b\x9a\x8c\
+\x00\x00\x09\x0c\x00\x01\x00\x00\x00\x01\x00\x0b\xbf\xd6\
+\x00\x00\x0b\x9a\x00\x01\x00\x00\x00\x01\x00\x0c\xa1\x35\
+\x00\x00\x0a\x70\x00\x01\x00\x00\x00\x01\x00\x0c\x4a\x1f\
+\x00\x00\x05\x08\x00\x01\x00\x00\x00\x01\x00\x0a\x7c\x1e\
+\x00\x00\x08\x72\x00\x00\x00\x00\x00\x01\x00\x0b\x8a\xba\
+\x00\x00\x06\x58\x00\x00\x00\x00\x00\x01\x00\x0a\xc9\xbe\
+\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x0b\x25\x51\
+\x00\x00\x09\x7a\x00\x00\x00\x00\x00\x01\x00\x0b\xdf\xa6\
\x00\x00\x03\x76\x00\x01\x00\x00\x00\x01\x00\x0a\x0d\xd7\
-\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x17\x44\
+\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x0a\x17\x90\
"
def qInitResources():
diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py
index 92ab01df7..add28732a 100644
--- a/src/Mod/Draft/InitGui.py
+++ b/src/Mod/Draft/InitGui.py
@@ -104,7 +104,8 @@ class DraftWorkbench (Workbench):
pass
self.cmdList = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc","Draft_Ellipse",
"Draft_Polygon","Draft_Rectangle", "Draft_Text",
- "Draft_Dimension", "Draft_BSpline","Draft_Point"]
+ "Draft_Dimension", "Draft_BSpline","Draft_Point",
+ "Draft_ShapeString"]
self.modList = ["Draft_Move","Draft_Rotate","Draft_Offset",
"Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
"Draft_Drawing","Draft_Edit","Draft_WireToBSpline","Draft_AddPoint",
@@ -161,3 +162,12 @@ App.addExportType("Autodesk DXF (*.dxf)","importDXF")
App.addExportType("Flattened SVG (*.svg)","importSVG")
App.addExportType("Open CAD Format (*.oca)","importOCA")
+# 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")))
+
diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc
index d2a211e29..2ab449808 100644
--- a/src/Mod/Draft/Resources/Draft.qrc
+++ b/src/Mod/Draft/Resources/Draft.qrc
@@ -55,6 +55,7 @@
icons/Draft_Clone.svg
icons/Draft_Heal.svg
icons/Draft_Ellipse.svg
+ icons/Draft_ShapeString.svg
patterns/concrete.svg
patterns/cross.svg
patterns/line.svg
diff --git a/src/Mod/Draft/Resources/icons/Draft_ShapeString.svg b/src/Mod/Draft/Resources/icons/Draft_ShapeString.svg
new file mode 100644
index 000000000..53b09f83c
--- /dev/null
+++ b/src/Mod/Draft/Resources/icons/Draft_ShapeString.svg
@@ -0,0 +1,112 @@
+
+
+
+
diff --git a/src/Mod/Draft/Resources/ui/userprefs-base.ui b/src/Mod/Draft/Resources/ui/userprefs-base.ui
index d64f95ecd..f373dda63 100755
--- a/src/Mod/Draft/Resources/ui/userprefs-base.ui
+++ b/src/Mod/Draft/Resources/ui/userprefs-base.ui
@@ -6,8 +6,8 @@
0
0
- 590
- 632
+ 718
+ 808
@@ -1199,6 +1199,49 @@ such as "Arial:Bold"
+ -
+
+
-
+
+
+ Default ShapeString Font File
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 300
+ 0
+
+
+
+ Select a font file
+
+
+ FontFile
+
+
+ Mod/Draft
+
+
+
+
+
diff --git a/src/Mod/Draft/Resources/ui/userprefs-import.ui b/src/Mod/Draft/Resources/ui/userprefs-import.ui
index a14084d3b..95b64c308 100755
--- a/src/Mod/Draft/Resources/ui/userprefs-import.ui
+++ b/src/Mod/Draft/Resources/ui/userprefs-import.ui
@@ -280,6 +280,26 @@ If color mapping is choosed, you must choose a color mapping file containing a t
+ -
+
+
-
+
+
+ If this is checked, the exported objects will be projected to reflect the current view direction
+
+
+ Project exported objects along current view direction
+
+
+ dxfproject
+
+
+ Mod/Draft
+
+
+
+
+
-
-
diff --git a/src/Mod/Draft/importDWG.py b/src/Mod/Draft/importDWG.py
new file mode 100644
index 000000000..bbfc947a0
--- /dev/null
+++ b/src/Mod/Draft/importDWG.py
@@ -0,0 +1,94 @@
+# -*- coding: utf8 -*-
+
+#***************************************************************************
+#* *
+#* Copyright (c) 2009 Yorik van Havre *
+#* *
+#* This program is free software; you can redistribute it and/or modify *
+#* it under the terms of the GNU Lesser General Public License (GPL) *
+#* as published by the Free Software Foundation; either version 2 of *
+#* the License, or (at your option) any later version. *
+#* for detail see the LICENCE text file. *
+#* *
+#* This program is distributed in the hope that it will be useful, *
+#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+#* GNU Library General Public License for more details. *
+#* *
+#* You should have received a copy of the GNU Library General Public *
+#* License along with this program; if not, write to the Free Software *
+#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+#* USA *
+#* *
+#***************************************************************************
+
+"FreeCAD Draft Workbench - DWG importer/exporter"
+
+if open.__module__ == '__builtin__':
+ pythonopen = open # to distinguish python built-in open function from the one declared here
+
+def open(filename):
+ "called when freecad opens a file."
+ dxf = convertToDxf(filename)
+ import importDXF
+ doc = importDXF.open(dxf)
+ return doc
+
+def insert(filename,docname):
+ "called when freecad imports a file"
+ dxf = convertToDxf(filemname)
+ import importDXF
+ doc = importDXF.insert(dxf,docname)
+ return doc
+
+def export(objectslist,filename):
+ "called when freecad exports a file"
+ import importDXF,os,tempfile
+ outdir = tempfile.mkdtemp()
+ dxf = outdir + os.sep + os.path.splitext(os.path.basename(filename))[0] + ".dxf"
+ importDXF.export(objectslist,dxf)
+ convertToDwg(dxf,filename)
+ return filename
+
+def getTeighaConverter():
+ "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
+ if teigha:
+ if os.path.exists(teigha):
+ return teigha
+ 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"
+
+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
diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py
index 1a9a34865..7c19cc0a5 100644
--- a/src/Mod/Draft/importDXF.py
+++ b/src/Mod/Draft/importDXF.py
@@ -1190,18 +1190,31 @@ def insert(filename,docname):
# EXPORT ########################################################################
+def projectShape(shape,direction):
+ import Drawing
+ edges = []
+ try:
+ groups = Drawing.projectEx(shape,direction)
+ except:
+ print "unable to project shape"
+ return shape
+ else:
+ for g in groups[0:5]:
+ if g:
+ edges.append(g)
+ return DraftGeomUtils.cleanProjection(Part.makeCompound(edges))
+
def getArcData(edge):
"returns center, radius, start and end angles of a circle-based edge"
ce = edge.Curve.Center
radius = edge.Curve.Radius
if len(edge.Vertexes) == 1:
# closed circle
- return ce, radius, 0, 0
+ return DraftVecUtils.tup(ce), radius, 0, 0
else:
- # find direction of arc
- tang1 = edge.Curve.tangent(edge.ParameterRange[0])
- tang2 = edge.Curve.tangent(edge.ParameterRange[1])
-
+ # method 1 - find direction of arc from tangents - not reliable
+ #tang1 = edge.Curve.tangent(edge.ParameterRange[0])
+ #tang2 = edge.Curve.tangent(edge.ParameterRange[1])
# following code doesn't seem to give right result?
# cross1 = Vector.cross(Vector(tang1[0][0],tang1[0][1],tang1[0][2]),Vector(tang2[0][0],tang2[0][1],tang2[0][2]))
# if cross1[2] > 0: # >0 ccw <0 cw
@@ -1211,15 +1224,31 @@ def getArcData(edge):
# ve1 = edge.Vertexes[-1].Point
# ve2 = edge.Vertexes[0].Point
- # check the midpoint seems more reliable
+ # method 3 - recreate an arc and check if the length is the same
ve1 = edge.Vertexes[0].Point
ve2 = edge.Vertexes[-1].Point
ang1 = -math.degrees(DraftVecUtils.angle(ve1.sub(ce)))
ang2 = -math.degrees(DraftVecUtils.angle(ve2.sub(ce)))
- ve3 = DraftGeomUtils.findMidpoint(edge)
- ang3 = -math.degrees(DraftVecUtils.angle(ve3.sub(ce)))
- if (ang3 < ang1) and (ang2 < ang3):
+
+ a1 = -DraftVecUtils.angle(ve1.sub(ce))
+ a2 = -DraftVecUtils.angle(ve2.sub(ce))
+ pseudoarc = Part.ArcOfCircle(edge.Curve,a1,a2).toShape()
+ if round(pseudoarc.Length,Draft.precision()) != round(edge.Length,Draft.precision()):
ang1, ang2 = ang2, ang1
+
+ # method 2 - check the midpoint - not reliable either
+ #ve3 = DraftGeomUtils.findMidpoint(edge)
+ #ang3 = -math.degrees(DraftVecUtils.angle(ve3.sub(ce)))
+ #print "edge ",edge.hashCode()," data ",ang1, " , ",ang2," , ", ang3
+ #if (ang3 < ang1) and (ang2 < ang3):
+ # print "inverting, case1"
+ # ang1, ang2 = ang2, ang1
+ #elif (ang3 > ang1) and (ang3 > ang2):
+ # print "inverting, case2"
+ # ang1, ang2 = ang2, ang1
+ #elif (ang3 < ang1) and (ang3 < ang2):
+ # print "inverting, case3"
+ # ang1, ang2 = ang2, ang1
return DraftVecUtils.tup(ce), radius, ang1, ang2
def getSplineSegs(edge):
@@ -1246,6 +1275,7 @@ def getWire(wire,nospline=False):
"returns an array of dxf-ready points and bulges from a wire"
edges = DraftGeomUtils.sortEdges(wire.Edges)
points = []
+ # print "processing wire ",wire.Edges
for edge in edges:
v1 = edge.Vertexes[0].Point
if len(edge.Vertexes) < 2:
@@ -1255,6 +1285,9 @@ def getWire(wire,nospline=False):
v2 = edge.Vertexes[-1].Point
c = edge.Curve.Center
angle = abs(DraftVecUtils.angle(v1.sub(c),v2.sub(c)))
+ if DraftGeomUtils.isWideAngle(edge):
+ if angle < math.pi:
+ angle = math.pi*2 - angle
# if (DraftVecUtils.angle(v2.sub(c)) < DraftVecUtils.angle(v1.sub(c))):
# angle = -angle
# polyline bulge -> negative makes the arc go clockwise
@@ -1291,16 +1324,16 @@ def getWire(wire,nospline=False):
# print "wire verts: ",points
return points
-def getBlock(obj):
+def getBlock(sh,obj):
"returns a dxf block with the contents of the object"
block = dxfLibrary.Block(name=obj.Name,layer=getGroup(obj,exportList))
- writeShape(obj,block)
+ writeShape(sh,obj,block)
return block
-def writeShape(ob,dxfobject,nospline=False):
+def writeShape(sh,ob,dxfobject,nospline=False):
"writes the object's shape contents in the given dxf object"
processededges = []
- for wire in ob.Shape.Wires: # polylines
+ for wire in sh.Wires: # polylines
for e in wire.Edges:
processededges.append(e.hashCode())
if (len(wire.Edges) == 1) and (DraftGeomUtils.geomType(wire.Edges[0]) == "Circle"):
@@ -1317,22 +1350,32 @@ def writeShape(ob,dxfobject,nospline=False):
dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline), [0.0,0.0,0.0],
int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob),
layer=getGroup(ob,exportList)))
- if len(processededges) < len(ob.Shape.Edges): # lone edges
+ if len(processededges) < len(sh.Edges): # lone edges
loneedges = []
- for e in ob.Shape.Edges:
+ for e in sh.Edges:
if not(e.hashCode() in processededges): loneedges.append(e)
# print "lone edges ",loneedges
for edge in loneedges:
if (DraftGeomUtils.geomType(edge) == "BSplineCurve") and ((not nospline) or (len(edge.Vertexes) == 1)): # splines
- points = []
- spline = getSplineSegs(edge)
- for p in spline:
- points.append((p.x,p.y,p.z,None,None,0.0))
- dxfobject.append(dxfLibrary.PolyLine(points, [0.0,0.0,0.0],
- 0, color=getACI(ob),
- layer=getGroup(ob,exportList)))
+ if (len(edge.Vertexes) == 1) and (edge.Curve.isClosed()):
+ # special case: 1-vert closed spline, approximate as a circle
+ c = DraftGeomUtils.getCircleFromSpline(edge)
+ if c:
+ dxfobject.append(dxfLibrary.Circle(DraftVecUtils.tup(c.Curve.Center), c.Curve.Radius,
+ color=getACI(ob),
+ layer=getGroup(ob,exportList)))
+ else:
+ points = []
+ spline = getSplineSegs(edge)
+ for p in spline:
+ points.append((p.x,p.y,p.z,None,None,0.0))
+ dxfobject.append(dxfLibrary.PolyLine(points, [0.0,0.0,0.0],
+ 0, color=getACI(ob),
+ layer=getGroup(ob,exportList)))
elif DraftGeomUtils.geomType(edge) == "Circle": # curves
center, radius, ang1, ang2 = getArcData(edge)
+ if not isinstance(center,tuple):
+ center = DraftVecUtils.tup(center)
if len(edge.Vertexes) == 1: # circles
dxfobject.append(dxfLibrary.Circle(center, radius,
color=getACI(ob),
@@ -1387,27 +1430,37 @@ def export(objectslist,filename,nospline=False):
for ob in exportList:
print "processing ",ob.Name
if ob.isDerivedFrom("Part::Feature"):
- if not ob.Shape.isNull():
- if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"):
+ if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"):
+ sh = None
+ if not ob.Shape.isNull():
writeMesh(ob,dxf)
+ elif FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfproject"):
+ direction = FreeCADGui.ActiveDocument.ActiveView.getViewDirection()
+ sh = projectShape(ob.Shape,direction)
+ else:
+ if ob.Shape.Volume > 0:
+ sh = projectShape(ob.Shape,Vector(0,0,1))
else:
- if ob.Shape.ShapeType == 'Compound':
- if (len(ob.Shape.Wires) == 1):
+ sh = ob.Shape
+ if sh:
+ if not sh.isNull():
+ if sh.ShapeType == 'Compound':
+ if (len(sh.Wires) == 1):
# only one wire in this compound, no lone edge -> polyline
- if (len(ob.Shape.Wires[0].Edges) == len(ob.Shape.Edges)):
- writeShape(ob,dxf,nospline)
+ if (len(sh.Wires[0].Edges) == len(sh.Edges)):
+ writeShape(sh,ob,dxf,nospline)
else:
# 1 wire + lone edges -> block
- block = getBlock(ob)
+ block = getBlock(sh,ob)
dxf.blocks.append(block)
dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
else:
# all other cases: block
- block = getBlock(ob)
+ block = getBlock(sh,ob)
dxf.blocks.append(block)
dxf.append(dxfLibrary.Insert(name=ob.Name.upper()))
else:
- writeShape(ob,dxf,nospline)
+ writeShape(sh,ob,dxf,nospline)
elif Draft.getType(ob) == "Annotation":
# texts
diff --git a/src/Mod/Drawing/Gui/ViewProviderPage.h b/src/Mod/Drawing/Gui/ViewProviderPage.h
index 356ff6507..350471652 100644
--- a/src/Mod/Drawing/Gui/ViewProviderPage.h
+++ b/src/Mod/Drawing/Gui/ViewProviderPage.h
@@ -53,6 +53,7 @@ public:
virtual void attach(App::DocumentObject *);
virtual void setDisplayMode(const char* ModeName);
+ virtual bool useNewSelectionModel(void) const {return false;}
/// returns a list of all possible modes
virtual std::vector getDisplayModes(void) const;
diff --git a/src/Mod/Drawing/Gui/ViewProviderView.h b/src/Mod/Drawing/Gui/ViewProviderView.h
index 0307f5845..0969d8870 100644
--- a/src/Mod/Drawing/Gui/ViewProviderView.h
+++ b/src/Mod/Drawing/Gui/ViewProviderView.h
@@ -43,6 +43,7 @@ public:
virtual void attach(App::DocumentObject *);
virtual void setDisplayMode(const char* ModeName);
+ virtual bool useNewSelectionModel(void) const {return false;}
/// returns a list of all possible modes
virtual std::vector getDisplayModes(void) const;
virtual void updateData(const App::Property*);
diff --git a/src/Mod/Image/App/ImageBase.cpp b/src/Mod/Image/App/ImageBase.cpp
index fa078faf9..d3177a180 100644
--- a/src/Mod/Image/App/ImageBase.cpp
+++ b/src/Mod/Image/App/ImageBase.cpp
@@ -123,7 +123,7 @@ void ImageBase::clear()
_setColorFormat(IB_CF_GREY8, 8);
}
-// Sets the color format and the dependant parameters
+// Sets the color format and the dependent parameters
// Returns 0 for OK, -1 for invalid color format
int ImageBase::_setColorFormat(int format, unsigned short numSigBitsPerSample)
{
@@ -235,7 +235,7 @@ int ImageBase::createCopy(void* pSrcPixelData, unsigned long width, unsigned lon
// Clear any existing data
clear();
- // Set the color format and the dependant parameters
+ // Set the color format and the dependent parameters
if (_setColorFormat(format, numSigBitsPerSample) != 0)
return -1;
@@ -273,7 +273,7 @@ int ImageBase::pointTo(void* pSrcPixelData, unsigned long width, unsigned long h
// Clear any existing data
clear();
- // Set the color format and the dependant parameters
+ // Set the color format and the dependent parameters
if (_setColorFormat(format, numSigBitsPerSample) != 0)
return -1;
@@ -324,15 +324,15 @@ int ImageBase::getSample(int x, int y, unsigned short sampleIndex, double &value
case IB_CF_RGBA64:
case IB_CF_BGRA64:
{
- unsigned short* pPix16 = (unsigned short *)_pPixelData;
- unsigned short* pSample = pPix16 + _numSamples * (y * _width + x) + sampleIndex;
+ uint16_t* pPix16 = (uint16_t *)_pPixelData;
+ uint16_t* pSample = pPix16 + _numSamples * (y * _width + x) + sampleIndex;
value = (double)(*pSample);
}
break;
case IB_CF_GREY32:
{
- unsigned long* pPix32 = (unsigned long *)_pPixelData;
- unsigned long* pSample = pPix32 + y * _width + x;
+ uint32_t* pPix32 = (uint32_t *)_pPixelData;
+ uint32_t* pSample = pPix32 + y * _width + x;
value = (double)(*pSample);
}
break;
diff --git a/src/Mod/Image/App/ImageBase.h b/src/Mod/Image/App/ImageBase.h
index 44b061c11..144699c71 100644
--- a/src/Mod/Image/App/ImageBase.h
+++ b/src/Mod/Image/App/ImageBase.h
@@ -71,7 +71,7 @@ protected:
int _format; // colour format of the pixel data
unsigned short _numSigBitsPerSample;// number of significant bits per sample (always <= _numBitsPerSample)
- // Dependant parameters
+ // Dependent parameters
unsigned short _numSamples; // number of samples per pixel (e.g. 1 for grey, 3 for rgb, 4 for rgba)
unsigned short _numBitsPerSample; // number of bits per sample (e.g. 8 for Grey8)
unsigned short _numBytesPerPixel; // number of bytes per pixel (e.g. 1 for Grey8)
diff --git a/src/Mod/Image/Gui/GLImageBox.cpp b/src/Mod/Image/Gui/GLImageBox.cpp
index bfb54eec0..e29c400cf 100644
--- a/src/Mod/Image/Gui/GLImageBox.cpp
+++ b/src/Mod/Image/Gui/GLImageBox.cpp
@@ -45,6 +45,8 @@ using namespace ImageGui;
#pragma warning(disable:4305) // init: truncation from const double to float
#endif
+bool GLImageBox::haveMesa = false;
+
/* TRANSLATOR ImageGui::GLImageBox */
// Constructor
@@ -81,7 +83,13 @@ GLImageBox::~GLImageBox()
// Set up the OpenGL rendering state
void GLImageBox::initializeGL()
{
- qglClearColor( Qt::black ); // Let OpenGL clear to black
+ qglClearColor( Qt::black ); // Let OpenGL clear to black
+ static bool init = false;
+ if (!init) {
+ init = true;
+ std::string ver = (const char*)(glGetString(GL_VERSION));
+ haveMesa = (ver.find("Mesa") != std::string::npos);
+ }
}
@@ -170,7 +178,7 @@ void GLImageBox::drawImage()
// Load the color map if present
if (_pColorMap != 0)
{
- glPixelTransferf(GL_MAP_COLOR, 1.0);
+ if (!haveMesa) glPixelTransferf(GL_MAP_COLOR, 1.0);
glPixelMapfv(GL_PIXEL_MAP_R_TO_R, _numMapEntries, _pColorMap);
glPixelMapfv(GL_PIXEL_MAP_G_TO_G, _numMapEntries, _pColorMap + _numMapEntries);
glPixelMapfv(GL_PIXEL_MAP_B_TO_B, _numMapEntries, _pColorMap + _numMapEntries * 2);
diff --git a/src/Mod/Image/Gui/GLImageBox.h b/src/Mod/Image/Gui/GLImageBox.h
index 91b6ca9dc..0aeb5121b 100644
--- a/src/Mod/Image/Gui/GLImageBox.h
+++ b/src/Mod/Image/Gui/GLImageBox.h
@@ -105,6 +105,7 @@ private:
float* _pColorMap; // a RGBA color map (to alter the intensity or colors)
int _numMapEntries; // number of entries in color map
+ static bool haveMesa;
};
diff --git a/src/Mod/Image/Gui/Workbench.cpp b/src/Mod/Image/Gui/Workbench.cpp
index c07043da9..ed972cecd 100644
--- a/src/Mod/Image/Gui/Workbench.cpp
+++ b/src/Mod/Image/Gui/Workbench.cpp
@@ -58,7 +58,6 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
Gui::ToolBarItem* Workbench::setupCommandBars() const
{
- // Part tools
Gui::ToolBarItem* root = new Gui::ToolBarItem;
Gui::ToolBarItem* img = new Gui::ToolBarItem(root);
img->setCommand("Image");
diff --git a/src/Mod/Inspection/Gui/Command.cpp b/src/Mod/Inspection/Gui/Command.cpp
index 8176bdf40..75915160f 100644
--- a/src/Mod/Inspection/Gui/Command.cpp
+++ b/src/Mod/Inspection/Gui/Command.cpp
@@ -87,6 +87,7 @@ void CmdInspectElement::activated(int iMsg)
if (view) {
Gui::View3DInventorViewer* viewer = view->getViewer();
viewer->setEditing(true);
+ viewer->setRedirectToSceneGraphEnabled(true);
viewer->setRedirectToSceneGraph(true);
viewer->setEditingCursor(QCursor(Gui::BitmapFactory().pixmap("mesh_pipette"),4,29));
viewer->addEventCallback(SoButtonEvent::getClassTypeId(),
diff --git a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp
index dc6f246ed..1783b6380 100644
--- a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp
+++ b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp
@@ -436,6 +436,7 @@ void ViewProviderInspection::inspectCallback(void * ud, SoEventCallback * n)
view->setEditing(false);
view->getWidget()->setCursor(QCursor(Qt::ArrowCursor));
view->setRedirectToSceneGraph(false);
+ view->setRedirectToSceneGraphEnabled(false);
view->removeEventCallback(SoButtonEvent::getClassTypeId(), inspectCallback);
}
}
diff --git a/src/Mod/Mesh/App/Core/Approximation.cpp b/src/Mod/Mesh/App/Core/Approximation.cpp
index 0cc23d404..2c1731e26 100644
--- a/src/Mod/Mesh/App/Core/Approximation.cpp
+++ b/src/Mod/Mesh/App/Core/Approximation.cpp
@@ -452,8 +452,8 @@ void QuadraticFit::CalcEigenValues(double &dLambda1, double &dLambda2, double &d
*/
Wm4::Matrix3 akMat(_fCoeff[4], _fCoeff[7]/2.0f, _fCoeff[8]/2.0f,
- _fCoeff[7]/2.0f, _fCoeff[5], _fCoeff[9]/2.0f,
- _fCoeff[8]/2.0f, _fCoeff[9]/2.0f, _fCoeff[6] );
+ _fCoeff[7]/2.0f, _fCoeff[5], _fCoeff[9]/2.0f,
+ _fCoeff[8]/2.0f, _fCoeff[9]/2.0f, _fCoeff[6] );
Wm4::Matrix3 rkRot, rkDiag;
akMat.EigenDecomposition( rkRot, rkDiag );
@@ -476,9 +476,9 @@ void QuadraticFit::CalcZValues( double x, double y, double &dZ1, double &dZ2 ) c
assert( _bIsFitted );
double dDisk = _fCoeff[3]*_fCoeff[3]+2*_fCoeff[3]*_fCoeff[8]*x+2*_fCoeff[3]*_fCoeff[9]*y+
- _fCoeff[8]*_fCoeff[8]*x*x+2*_fCoeff[8]*x*_fCoeff[9]*y+_fCoeff[9]*_fCoeff[9]*y*y-
- 4*_fCoeff[6]*_fCoeff[0]-4*_fCoeff[6]*_fCoeff[1]*x-4*_fCoeff[6]*_fCoeff[2]*y-
- 4*_fCoeff[6]*_fCoeff[7]*x*y-4*_fCoeff[6]*_fCoeff[4]*x*x-4*_fCoeff[6]*_fCoeff[5]*y*y;
+ _fCoeff[8]*_fCoeff[8]*x*x+2*_fCoeff[8]*x*_fCoeff[9]*y+_fCoeff[9]*_fCoeff[9]*y*y-
+ 4*_fCoeff[6]*_fCoeff[0]-4*_fCoeff[6]*_fCoeff[1]*x-4*_fCoeff[6]*_fCoeff[2]*y-
+ 4*_fCoeff[6]*_fCoeff[7]*x*y-4*_fCoeff[6]*_fCoeff[4]*x*x-4*_fCoeff[6]*_fCoeff[5]*y*y;
if (fabs( _fCoeff[6] ) < 0.000005) {
dZ1 = FLOAT_MAX;
diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp
index 909c664f5..684df06d6 100644
--- a/src/Mod/Mesh/App/Core/MeshIO.cpp
+++ b/src/Mod/Mesh/App/Core/MeshIO.cpp
@@ -795,17 +795,17 @@ bool MeshInput::LoadPLY (std::istream &inp)
}
}
else {
- for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) {
- if (boost::regex_match(line.c_str(), what, rx_p)) {
- pt.x = (float)std::atof(what[1].first);
- pt.y = (float)std::atof(what[4].first);
- pt.z = (float)std::atof(what[7].first);
- meshPoints.push_back(pt);
+ for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) {
+ if (boost::regex_match(line.c_str(), what, rx_p)) {
+ pt.x = (float)std::atof(what[1].first);
+ pt.y = (float)std::atof(what[4].first);
+ pt.z = (float)std::atof(what[7].first);
+ meshPoints.push_back(pt);
+ }
+ else {
+ return false;
+ }
}
- else {
- return false;
- }
- }
}
int f1, f2, f3;
for (std::size_t i = 0; i < f_count && std::getline(inp, line); i++) {
diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp
index 9a13a27a8..fb5084b64 100644
--- a/src/Mod/Mesh/App/Mesh.cpp
+++ b/src/Mod/Mesh/App/Mesh.cpp
@@ -587,6 +587,23 @@ void MeshObject::getPointsFromSelection(std::vector& inds) const
MeshCore::MeshAlgorithm(this->_kernel).GetPointsFlag(inds, MeshCore::MeshPoint::SELECTED);
}
+bool MeshObject::hasSelectedFacets() const
+{
+ unsigned long ct = MeshCore::MeshAlgorithm(this->_kernel).CountFacetFlag(MeshCore::MeshFacet::SELECTED);
+ return ct > 0;
+}
+
+bool MeshObject::hasSelectedPoints() const
+{
+ unsigned long ct = MeshCore::MeshAlgorithm(this->_kernel).CountPointFlag(MeshCore::MeshPoint::SELECTED);
+ return ct > 0;
+}
+
+std::vector MeshObject::getPointsFromFacets(const std::vector& facets) const
+{
+ return _kernel.GetFacetPoints(facets);
+}
+
void MeshObject::updateMesh(const std::vector& facets)
{
std::vector points;
diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h
index 441db4de3..a88a06ec3 100644
--- a/src/Mod/Mesh/App/Mesh.h
+++ b/src/Mod/Mesh/App/Mesh.h
@@ -124,6 +124,7 @@ public:
double getVolume() const;
void getFaces(std::vector &Points,std::vector &Topo,
float Accuracy, uint16_t flags=0) const;
+ std::vector getPointsFromFacets(const std::vector& facets) const;
//@}
void setKernel(const MeshCore::MeshKernel& m);
@@ -211,6 +212,8 @@ public:
void addPointsToSelection(const std::vector&) const;
void removeFacetsFromSelection(const std::vector&) const;
void removePointsFromSelection(const std::vector&) const;
+ bool hasSelectedFacets() const;
+ bool hasSelectedPoints() const;
void getFacetsFromSelection(std::vector&) const;
void getPointsFromSelection(std::vector&) const;
void clearFacetSelection() const;
diff --git a/src/Mod/Mesh/Gui/AppMeshGui.cpp b/src/Mod/Mesh/Gui/AppMeshGui.cpp
index a3ff09cc6..624d56972 100644
--- a/src/Mod/Mesh/Gui/AppMeshGui.cpp
+++ b/src/Mod/Mesh/Gui/AppMeshGui.cpp
@@ -41,6 +41,7 @@
#include "DlgSettingsMeshView.h"
#include "SoFCMeshObject.h"
#include "SoFCIndexedFaceSet.h"
+#include "SoPolygon.h"
#include "ViewProvider.h"
#include "ViewProviderMeshFaceSet.h"
#include "ViewProviderCurvature.h"
@@ -111,6 +112,7 @@ void MeshGuiExport initMeshGui()
MeshGui::SoFCIndexedFaceSet ::initClass();
MeshGui::SoFCMeshPickNode ::initClass();
MeshGui::SoFCMeshGridNode ::initClass();
+ MeshGui::SoPolygon ::initClass();
MeshGui::PropertyMeshKernelItem ::init();
MeshGui::ViewProviderMesh ::init();
MeshGui::ViewProviderMeshObject ::init();
diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt
index ae4701a0f..cafca6c7c 100644
--- a/src/Mod/Mesh/Gui/CMakeLists.txt
+++ b/src/Mod/Mesh/Gui/CMakeLists.txt
@@ -24,6 +24,7 @@ set(Mesh_MOC_HDRS
MeshEditor.h
PropertyEditorMesh.h
RemoveComponents.h
+ Selection.h
)
fc_wrap_cpp(Mesh_MOC_SRCS ${Mesh_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${Mesh_MOC_SRCS})
@@ -35,6 +36,7 @@ set(Dialogs_UIC_SRCS
DlgSmoothing.ui
RemoveComponents.ui
Segmentation.ui
+ Selection.ui
)
qt4_wrap_ui(Dialogs_UIC_HDRS ${Dialogs_UIC_SRCS})
SET(Dialogs_SRCS
@@ -57,6 +59,9 @@ SET(Dialogs_SRCS
Segmentation.ui
Segmentation.cpp
Segmentation.h
+ Selection.ui
+ Selection.cpp
+ Selection.h
)
SOURCE_GROUP("Dialogs" FILES ${Dialogs_SRCS})
@@ -65,6 +70,8 @@ SET(Inventor_SRCS
SoFCIndexedFaceSet.h
SoFCMeshObject.cpp
SoFCMeshObject.h
+ SoPolygon.cpp
+ SoPolygon.h
)
SOURCE_GROUP("Inventor" FILES ${Inventor_SRCS})
@@ -105,6 +112,8 @@ SET(MeshGui_SRCS
PreCompiled.h
MeshEditor.cpp
MeshEditor.h
+ MeshSelection.cpp
+ MeshSelection.h
PropertyEditorMesh.cpp
PropertyEditorMesh.h
Workbench.cpp
diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp
index cc83bdaa0..2e71e4ed9 100644
--- a/src/Mod/Mesh/Gui/Command.cpp
+++ b/src/Mod/Mesh/Gui/Command.cpp
@@ -1019,9 +1019,19 @@ bool CmdMeshRemoveComponents::isActive(void)
{
// Check for the selected mesh feature (all Mesh types)
App::Document* doc = getDocument();
- return (doc && doc->countObjectsOfType
- (Mesh::Feature::getClassTypeId()) > 0
- && !Gui::Control().activeDialog());
+ if (!(doc && doc->countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0))
+ return false;
+ Gui::Document* viewDoc = Gui::Application::Instance->getDocument(doc);
+ Gui::View3DInventor* view = dynamic_cast(viewDoc->getActiveView());
+ if (view) {
+ Gui::View3DInventorViewer* viewer = view->getViewer();
+ if (viewer->isEditing())
+ return false;
+ }
+ if (Gui::Control().activeDialog())
+ return false;
+
+ return true;
}
//--------------------------------------------------------------------------------------
@@ -1046,7 +1056,7 @@ void CmdMeshRemoveCompByHand::activated(int iMsg)
if (view) {
Gui::View3DInventorViewer* viewer = view->getViewer();
viewer->setEditing(true);
- //viewer->setEditingCursor(QCursor(Gui::BitmapFactory().pixmap("mesh_pipette"),4,29));
+ viewer->setEditingCursor(QCursor(Qt::OpenHandCursor));
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), MeshGui::ViewProviderMeshFaceSet::markPartCallback);
}
}
@@ -1120,7 +1130,8 @@ CmdMeshSmoothing::CmdMeshSmoothing()
void CmdMeshSmoothing::activated(int iMsg)
{
- MeshGui::DlgSmoothing dlg(Gui::getMainWindow());
+#if 0
+ MeshGui::SmoothingDialog dlg(Gui::getMainWindow());
if (dlg.exec() == QDialog::Accepted) {
Gui::WaitCursor wc;
openCommand("Mesh Smoothing");
@@ -1149,10 +1160,17 @@ void CmdMeshSmoothing::activated(int iMsg)
}
commitCommand();
}
+#else
+ Gui::Control().showDialog(new MeshGui::TaskSmoothing());
+#endif
}
bool CmdMeshSmoothing::isActive(void)
{
+#if 1
+ if (Gui::Control().activeDialog())
+ return false;
+#endif
// Check for the selected mesh feature (all Mesh types)
return getSelection().countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0;
}
diff --git a/src/Mod/Mesh/Gui/DlgSmoothing.cpp b/src/Mod/Mesh/Gui/DlgSmoothing.cpp
index 9efebc9ea..4541d83e7 100644
--- a/src/Mod/Mesh/Gui/DlgSmoothing.cpp
+++ b/src/Mod/Mesh/Gui/DlgSmoothing.cpp
@@ -23,17 +23,25 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include
+# include
#endif
#include "DlgSmoothing.h"
#include "ui_DlgSmoothing.h"
+#include "Selection.h"
+
+#include
+#include
+#include
+#include
+#include
using namespace MeshGui;
/* TRANSLATOR MeshGui::DlgSmoothing */
-DlgSmoothing::DlgSmoothing(QWidget* parent, Qt::WFlags fl)
- : QDialog(parent, fl), ui(new Ui_DlgSmoothing())
+DlgSmoothing::DlgSmoothing(QWidget* parent)
+ : QWidget(parent), ui(new Ui_DlgSmoothing())
{
ui->setupUi(this);
bg = new QButtonGroup(this);
@@ -92,4 +100,130 @@ DlgSmoothing::Smooth DlgSmoothing::method() const
return DlgSmoothing::None;
}
+bool DlgSmoothing::smoothSelection() const
+{
+ return ui->checkBoxSelection->isChecked();
+}
+
+void DlgSmoothing::on_checkBoxSelection_toggled(bool on)
+{
+ /*emit*/ toggledSelection(on);
+}
+
+// ------------------------------------------------
+
+SmoothingDialog::SmoothingDialog(QWidget* parent, Qt::WFlags fl)
+ : QDialog(parent, fl)
+{
+ widget = new DlgSmoothing(this);
+ this->setWindowTitle(widget->windowTitle());
+
+ QVBoxLayout* hboxLayout = new QVBoxLayout(this);
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
+ buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+
+ connect(buttonBox, SIGNAL(accepted()),
+ this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()),
+ this, SLOT(reject()));
+
+ hboxLayout->addWidget(widget);
+ hboxLayout->addWidget(buttonBox);
+}
+
+SmoothingDialog::~SmoothingDialog()
+{
+}
+
+// ---------------------------------------
+
+/* TRANSLATOR MeshGui::TaskSmoothing */
+
+TaskSmoothing::TaskSmoothing()
+{
+ widget = new DlgSmoothing();
+ Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox(
+ QPixmap(), widget->windowTitle(), false, 0);
+ taskbox->groupLayout()->addWidget(widget);
+ Content.push_back(taskbox);
+
+ selection = new Selection();
+ selection->setObjects(Gui::Selection().getSelectionEx(0, Mesh::Feature::getClassTypeId()));
+ Gui::TaskView::TaskGroup* tasksel = new Gui::TaskView::TaskGroup();
+ tasksel->groupLayout()->addWidget(selection);
+ tasksel->hide();
+ Content.push_back(tasksel);
+
+ connect(widget, SIGNAL(toggledSelection(bool)),
+ tasksel, SLOT(setVisible(bool)));
+}
+
+TaskSmoothing::~TaskSmoothing()
+{
+ // automatically deleted in the sub-class
+}
+
+bool TaskSmoothing::accept()
+{
+ std::vector meshes = selection->getObjects();
+ if (meshes.empty())
+ return true;
+
+ Gui::WaitCursor wc;
+ Gui::Command::openCommand("Mesh Smoothing");
+
+ bool hasSelection = false;
+ for (std::vector::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
+ Mesh::Feature* mesh = static_cast(*it);
+ std::vector selection;
+ if (widget->smoothSelection()) {
+ // clear the selection before editing the mesh to avoid
+ // to have coloured triangles when doing an 'undo'
+ const Mesh::MeshObject* mm = mesh->Mesh.getValuePtr();
+ mm->getFacetsFromSelection(selection);
+ selection = mm->getPointsFromFacets(selection);
+ mm->clearFacetSelection();
+ if (!selection.empty())
+ hasSelection = true;
+ }
+ Mesh::MeshObject* mm = mesh->Mesh.startEditing();
+ switch (widget->method()) {
+ case MeshGui::DlgSmoothing::Taubin:
+ {
+ MeshCore::TaubinSmoothing s(mm->getKernel());
+ s.SetLambda(widget->lambdaStep());
+ s.SetMicro(widget->microStep());
+ if (widget->smoothSelection()) {
+ s.SmoothPoints(widget->iterations(), selection);
+ }
+ else {
+ s.Smooth(widget->iterations());
+ }
+ } break;
+ case MeshGui::DlgSmoothing::Laplace:
+ {
+ MeshCore::LaplaceSmoothing s(mm->getKernel());
+ s.SetLambda(widget->lambdaStep());
+ if (widget->smoothSelection()) {
+ s.SmoothPoints(widget->iterations(), selection);
+ }
+ else {
+ s.Smooth(widget->iterations());
+ }
+ } break;
+ default:
+ break;
+ }
+ mesh->Mesh.finishEditing();
+ }
+
+ if (widget->smoothSelection() && !hasSelection) {
+ Gui::Command::abortCommand();
+ return false;
+ }
+
+ Gui::Command::commitCommand();
+ return true;
+}
+
#include "moc_DlgSmoothing.cpp"
diff --git a/src/Mod/Mesh/Gui/DlgSmoothing.h b/src/Mod/Mesh/Gui/DlgSmoothing.h
index e3bf61d54..fafccd3e1 100644
--- a/src/Mod/Mesh/Gui/DlgSmoothing.h
+++ b/src/Mod/Mesh/Gui/DlgSmoothing.h
@@ -25,13 +25,16 @@
#define MESHGUI_DLGSMOOTHING_H
#include
+#include
+#include
class QButtonGroup;
namespace MeshGui {
+class Selection;
class Ui_DlgSmoothing;
-class DlgSmoothing : public QDialog
+class DlgSmoothing : public QWidget
{
Q_OBJECT
@@ -42,21 +45,76 @@ public:
Laplace
};
- DlgSmoothing(QWidget* parent = 0, Qt::WFlags fl = 0);
+ DlgSmoothing(QWidget* parent = 0);
~DlgSmoothing();
int iterations() const;
double lambdaStep() const;
double microStep() const;
Smooth method() const;
+ bool smoothSelection() const;
private Q_SLOTS:
void method_clicked(int);
+ void on_checkBoxSelection_toggled(bool);
+
+Q_SIGNALS:
+ void toggledSelection(bool);
private:
Ui_DlgSmoothing* ui;
QButtonGroup* bg;
};
+/**
+ * Embed the panel into a dialog.
+ */
+class MeshGuiExport SmoothingDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ SmoothingDialog(QWidget* parent = 0, Qt::WFlags fl = 0);
+ ~SmoothingDialog();
+
+ int iterations() const
+ { return widget->iterations(); }
+ double lambdaStep() const
+ { return widget->lambdaStep(); }
+ double microStep() const
+ { return widget->microStep(); }
+ DlgSmoothing::Smooth method() const
+ { return widget->method(); }
+ bool smoothSelection() const
+ { return widget->smoothSelection(); }
+
+private:
+ DlgSmoothing* widget;
+};
+
+/**
+ * Embed the panel into a task dialog.
+ */
+class TaskSmoothing : public Gui::TaskView::TaskDialog
+{
+ Q_OBJECT
+
+public:
+ TaskSmoothing();
+ ~TaskSmoothing();
+
+public:
+ bool accept();
+
+ virtual QDialogButtonBox::StandardButtons getStandardButtons() const
+ { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; }
+ virtual bool isAllowedAlterDocument(void) const
+ { return true; }
+
+private:
+ DlgSmoothing* widget;
+ Selection* selection;
+};
+
}
#endif // MESHGUI_DLGSMOOTHING_H
diff --git a/src/Mod/Mesh/Gui/DlgSmoothing.ui b/src/Mod/Mesh/Gui/DlgSmoothing.ui
index 691484639..69844eec0 100644
--- a/src/Mod/Mesh/Gui/DlgSmoothing.ui
+++ b/src/Mod/Mesh/Gui/DlgSmoothing.ui
@@ -1,172 +1,130 @@
MeshGui::DlgSmoothing
-
+
0
0
- 242
- 251
+ 210
+ 227
Smoothing
-
+
true
-
+
-
-
+
-
+ Method
-
+
-
-
-
- Method
+
+
+ Taubin
+
+
+ true
-
-
-
-
-
- Taubin
-
-
- true
-
-
-
- -
-
-
- Laplace
-
-
-
-
- -
-
-
- Parameter
+
-
+
+
+ Laplace
-
-
-
-
-
- Iterations:
-
-
-
- -
-
-
- 1
-
-
- 4
-
-
-
- -
-
-
- Lambda:
-
-
-
- -
-
-
- 4
-
-
- 1.000000000000000
-
-
- 0.001000000000000
-
-
- 0.630700000000000
-
-
-
- -
-
-
- Mu:
-
-
-
- -
-
-
- 4
-
-
- 1.000000000000000
-
-
- 0.001000000000000
-
-
- 0.042400000000000
-
-
-
-
-
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+ Parameter
+
+
-
+
+
+ Iterations:
+
+
+
+ -
+
+
+ 1
+
+
+ 4
+
+
+
+ -
+
+
+ Lambda:
+
+
+
+ -
+
+
+ 4
+
+
+ 1.000000000000000
+
+
+ 0.001000000000000
+
+
+ 0.630700000000000
+
+
+
+ -
+
+
+ Mu:
+
+
+
+ -
+
+
+ 4
+
+
+ 1.000000000000000
+
+
+ 0.001000000000000
+
+
+ 0.042400000000000
+
+
+
+ -
+
+
+ Only selection
+
+
+
+
-
-
- buttonBox
- accepted()
- MeshGui::DlgSmoothing
- accept()
-
-
- 94
- 191
-
-
- -3
- 193
-
-
-
-
- buttonBox
- rejected()
- MeshGui::DlgSmoothing
- reject()
-
-
- 190
- 193
-
-
- 219
- 151
-
-
-
-
+
diff --git a/src/Mod/Mesh/Gui/MeshEditor.cpp b/src/Mod/Mesh/Gui/MeshEditor.cpp
index 2f819554e..11c2a2c20 100644
--- a/src/Mod/Mesh/Gui/MeshEditor.cpp
+++ b/src/Mod/Mesh/Gui/MeshEditor.cpp
@@ -40,15 +40,21 @@
# include
# include
# include
+# include
# include
# include
+# include
#endif
#include "MeshEditor.h"
#include "SoFCMeshObject.h"
+#include "SoPolygon.h"
#include
#include
+#include
+#include
#include
+#include
#include
#include
@@ -278,8 +284,19 @@ void MeshFaceAddition::showMarker(SoPickedPoint* pp)
return;
// is a border facet picked?
MeshCore::MeshFacet f = facets[face_index];
- if (!f.HasOpenEdge())
- return;
+ if (!f.HasOpenEdge()) {
+ // check if a neighbour facet is at the border
+ bool ok=false;
+ for (int i=0; i<3; i++) {
+ if (facets[f._aulNeighbours[i]].HasOpenEdge()) {
+ f = facets[f._aulNeighbours[i]];
+ ok = true;
+ break;
+ }
+ }
+ if (!ok)
+ return;
+ }
int point_index = -1;
float distance = FLT_MAX;
@@ -372,4 +389,326 @@ void MeshFaceAddition::addFacetCallback(void * ud, SoEventCallback * n)
}
}
+// ----------------------------------------------------------------------
+
+namespace MeshGui {
+ // for sorting of elements
+ struct NofFacetsCompare : public std::binary_function&,
+ const std::vector&, bool>
+ {
+ bool operator () (const std::vector &rclC1,
+ const std::vector &rclC2)
+ {
+ return rclC1.size() < rclC2.size();
+ }
+ };
+}
+
+/* TRANSLATOR MeshGui::MeshFillHole */
+
+MeshFillHole::MeshFillHole(MeshHoleFiller& hf, Gui::View3DInventor* parent)
+ : QObject(parent), myMesh(0), myNumPoints(0), myHoleFiller(hf)
+{
+ myBoundariesRoot = new SoSeparator;
+ myBoundariesRoot->ref();
+ myBoundaryRoot = new SoSeparator;
+ myBoundaryRoot->ref();
+ myBoundariesGroup = new SoSeparator();
+ myBoundariesGroup->ref();
+ myBridgeRoot = new SoSeparator;
+ myBridgeRoot->ref();
+
+ SoDrawStyle* pointStyle = new SoDrawStyle();
+ pointStyle->style = SoDrawStyle::POINTS;
+ pointStyle->pointSize = 8.0f;
+ myBridgeRoot->addChild(pointStyle);
+
+ SoBaseColor * markcol = new SoBaseColor;
+ markcol->rgb.setValue(1.0f, 1.0f, 0.0f);
+ SoPointSet* marker = new SoPointSet();
+ myBridgeRoot->addChild(markcol);
+
+ myVertex = new SoCoordinate3();
+ myBridgeRoot->addChild(myVertex);
+ myBridgeRoot->addChild(new SoPointSet);
+}
+
+MeshFillHole::~MeshFillHole()
+{
+ myBoundariesRoot->unref();
+ myBoundariesGroup->unref();
+ myBoundaryRoot->unref();
+ myBridgeRoot->unref();
+}
+
+void MeshFillHole::startEditing(MeshGui::ViewProviderMesh* vp)
+{
+ this->myMesh = static_cast(vp->getObject());
+
+ Gui::View3DInventor* view = static_cast(parent());
+ Gui::View3DInventorViewer* viewer = view->getViewer();
+ viewer->setEditing(true);
+ //viewer->setRedirectToSceneGraph(true);
+ viewer->addEventCallback(SoEvent::getClassTypeId(),
+ MeshFillHole::fileHoleCallback, this);
+ myConnection = App::GetApplication().signalChangedObject.connect(
+ boost::bind(&MeshFillHole::slotChangedObject, this, _1, _2));
+
+ myBoundariesRoot->removeAllChildren();
+ myBoundariesRoot->addChild(viewer->getHeadlight());
+ myBoundariesRoot->addChild(viewer->getCamera());
+ myBoundariesRoot->addChild(myBoundariesGroup);
+ myBoundaryRoot->removeAllChildren();
+ myBoundaryRoot->addChild(viewer->getHeadlight());
+ myBoundaryRoot->addChild(viewer->getCamera());
+ createPolygons();
+ static_cast(viewer->getSceneGraph())->addChild(myBridgeRoot);
+}
+
+void MeshFillHole::finishEditing()
+{
+ Gui::View3DInventor* view = static_cast(parent());
+ Gui::View3DInventorViewer* viewer = view->getViewer();
+ viewer->setEditing(false);
+ //viewer->setRedirectToSceneGraph(false);
+ viewer->removeEventCallback(SoEvent::getClassTypeId(),
+ MeshFillHole::fileHoleCallback, this);
+ myConnection.disconnect();
+ this->deleteLater();
+ static_cast(viewer->getSceneGraph())->removeChild(myBridgeRoot);
+}
+
+void MeshFillHole::closeBridge()
+{
+ // Do the hole-filling
+ Gui::WaitCursor wc;
+ TBoundary::iterator it = std::find(myPolygon.begin(), myPolygon.end(), myVertex1);
+ TBoundary::iterator jt = std::find(myPolygon.begin(), myPolygon.end(), myVertex2);
+ if (it != myPolygon.end() && jt != myPolygon.end()) {
+ // which iterator comes first
+ if (jt < it)
+ std::swap(it, jt);
+ // split the boundary into two loops and take the shorter one
+ std::list bounds;
+ TBoundary loop1, loop2;
+ loop1.insert(loop1.end(), myPolygon.begin(), it);
+ loop1.insert(loop1.end(), jt, myPolygon.end());
+ loop2.insert(loop2.end(), it, jt);
+ // this happens when myVertex1 == myVertex2
+ if (loop2.empty())
+ bounds.push_back(loop1);
+ else if (loop1.size() < loop2.size())
+ bounds.push_back(loop1);
+ else
+ bounds.push_back(loop2);
+
+ App::Document* doc = myMesh->getDocument();
+ doc->openTransaction("Bridge && Fill hole");
+ Mesh::MeshObject* pMesh = myMesh->Mesh.startEditing();
+ bool ok = myHoleFiller.fillHoles(*pMesh, bounds, myVertex1, myVertex2);
+ myMesh->Mesh.finishEditing();
+ if (ok)
+ doc->commitTransaction();
+ else
+ doc->abortTransaction();
+ }
+}
+
+void MeshFillHole::slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop)
+{
+ if (&Obj == myMesh && strcmp(Prop.getName(),"Mesh") == 0) {
+ myBoundariesGroup->removeAllChildren();
+ myVertex->point.setNum(0);
+ myNumPoints = 0;
+ myPolygon.clear();
+
+ createPolygons();
+ }
+}
+
+void MeshFillHole::createPolygons()
+{
+ Gui::WaitCursor wc;
+ myPolygons.clear();
+
+ SoPickStyle* pickStyle = new SoPickStyle();
+ pickStyle->style = SoPickStyle::BOUNDING_BOX;
+ myBoundariesGroup->addChild(pickStyle);
+ myBoundaryRoot->addChild(pickStyle);
+
+ // get mesh kernel
+ const MeshCore::MeshKernel & rMesh = this->myMesh->Mesh.getValue().getKernel();
+
+ // get the mesh boundaries as an array of point indices
+ std::list > borders;
+ MeshCore::MeshAlgorithm cAlgo(rMesh);
+ MeshCore::MeshPointIterator p_iter(rMesh);
+ cAlgo.GetMeshBorders(borders);
+ cAlgo.SplitBoundaryLoops(borders);
+
+ // sort the borders in ascending order of the number of edges
+ borders.sort(NofFacetsCompare());
+
+ int32_t count=0;
+ for (std::list >::iterator it =
+ borders.begin(); it != borders.end(); ++it) {
+ if (it->front() == it->back())
+ it->pop_back();
+ count += it->size();
+ }
+
+ SoCoordinate3* coords = new SoCoordinate3();
+ myBoundariesGroup->addChild(coords);
+ myBoundaryRoot->addChild(coords);
+
+ coords->point.setNum(count);
+ int32_t index = 0;
+ for (std::list >::iterator it =
+ borders.begin(); it != borders.end(); ++it) {
+ SoPolygon* polygon = new SoPolygon();
+ polygon->startIndex = index;
+ polygon->numVertices = it->size();
+ myBoundariesGroup->addChild(polygon);
+ myPolygons[polygon] = *it;
+ for (std::vector::iterator jt = it->begin();
+ jt != it->end(); ++jt) {
+ p_iter.Set(*jt);
+ coords->point.set1Value(index++,p_iter->x,p_iter->y,p_iter->z);
+ }
+ }
+}
+
+SoNode* MeshFillHole::getPickedPolygon(const SoRayPickAction& action/*SoNode* root, const SbVec2s& pos, const SoQtViewer* viewer*/) const
+{
+ SoPolygon* poly = 0;
+ const SoPickedPointList & points = action.getPickedPointList();
+ for (int i=0; i < points.getLength(); i++) {
+ const SoPickedPoint * point = points[i];
+ if (point && point->getPath()->getTail()->getTypeId() == MeshGui::SoPolygon::getClassTypeId()) {
+ // we have something picked, now check if it was an SoPolygon node
+ SoPolygon* node = static_cast(point->getPath()->getTail());
+ if (!poly) {
+ poly = node;
+ }
+ // check which polygon has less edges
+ else if (node->numVertices.getValue() < poly->numVertices.getValue()) {
+ poly = node;
+ }
+ }
+ }
+
+ return poly;
+}
+
+float MeshFillHole::findClosestPoint(const SbLine& ray, const TBoundary& polygon,
+ unsigned long& vertex_index, SbVec3f& closestPoint) const
+{
+ // now check which vertex of the polygon is closest to the ray
+ float minDist = FLT_MAX;
+ vertex_index = ULONG_MAX;
+
+ const MeshCore::MeshKernel & rMesh = myMesh->Mesh.getValue().getKernel();
+ const MeshCore::MeshPointArray& pts = rMesh.GetPoints();
+ for (TBoundary::const_iterator it = polygon.begin(); it != polygon.end(); ++it) {
+ SbVec3f vertex;
+ const Base::Vector3f& v = pts[*it];
+ vertex.setValue(v.x,v.y,v.z);
+ SbVec3f point = ray.getClosestPoint(vertex);
+ float distance = (vertex-point).sqrLength();
+ if (distance < minDist) {
+ minDist = distance;
+ vertex_index = *it;
+ closestPoint = vertex;
+ }
+ }
+
+ return minDist;
+}
+
+void MeshFillHole::fileHoleCallback(void * ud, SoEventCallback * n)
+{
+ MeshFillHole* self = reinterpret_cast(ud);
+ Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData());
+
+ const SoEvent* ev = n->getEvent();
+ if (ev->getTypeId() == SoLocation2Event::getClassTypeId()) {
+ n->setHandled();
+ SoRayPickAction rp(view->getViewportRegion());
+ rp.setPoint(ev->getPosition());
+ rp.setPickAll(true);
+ if (self->myNumPoints == 0)
+ rp.apply(self->myBoundariesRoot);
+ else
+ rp.apply(self->myBoundaryRoot);
+ SoNode* node = self->getPickedPolygon(rp);
+ if (node) {
+ std::map::iterator it = self->myPolygons.find(node);
+ if (it != self->myPolygons.end()) {
+ // now check which vertex of the polygon is closest to the ray
+ unsigned long vertex_index;
+ SbVec3f closestPoint;
+ float minDist = self->findClosestPoint(rp.getLine(), it->second, vertex_index, closestPoint);
+ if (minDist < 1.0f) {
+ if (self->myNumPoints == 0)
+ self->myVertex->point.set1Value(0, closestPoint);
+ else
+ self->myVertex->point.set1Value(1, closestPoint);
+ }
+ }
+ }
+ }
+ else if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
+ n->setHandled();
+ const SoMouseButtonEvent * mbe = static_cast(ev);
+ if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
+ }
+ else if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::UP) {
+ if (self->myNumPoints > 1)
+ return;
+ SoRayPickAction rp(view->getViewportRegion());
+ rp.setPoint(ev->getPosition());
+ rp.setPickAll(true);
+ if (self->myNumPoints == 0)
+ rp.apply(self->myBoundariesRoot);
+ else
+ rp.apply(self->myBoundaryRoot);
+ SoNode* node = self->getPickedPolygon(rp);
+ if (node) {
+ std::map::iterator it = self->myPolygons.find(node);
+ if (it != self->myPolygons.end()) {
+ // now check which vertex of the polygon is closest to the ray
+ unsigned long vertex_index;
+ SbVec3f closestPoint;
+ float minDist = self->findClosestPoint(rp.getLine(), it->second, vertex_index, closestPoint);
+ if (minDist < 1.0f) {
+ if (self->myNumPoints == 0) {
+ self->myBoundaryRoot->addChild(node);
+ self->myVertex->point.set1Value(0, closestPoint);
+ self->myNumPoints = 1;
+ self->myVertex1 = vertex_index;
+ }
+ else {
+ // myVertex2 can be equal to myVertex1 which does a full hole-filling
+ self->myBoundaryRoot->removeChild(node);
+ self->myVertex->point.set1Value(1, closestPoint);
+ self->myNumPoints = 2;
+ self->myVertex2 = vertex_index;
+ self->myPolygon = it->second;
+ QTimer::singleShot(300, self, SLOT(closeBridge()));
+ }
+ }
+ }
+ }
+ }
+ else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) {
+ QMenu menu;
+ QAction* fin = menu.addAction(MeshFillHole::tr("Finish"));
+ QAction* act = menu.exec(QCursor::pos());
+ if (act == fin) {
+ QTimer::singleShot(300, self, SLOT(finishEditing()));
+ }
+ }
+ }
+}
+
#include "moc_MeshEditor.cpp"
diff --git a/src/Mod/Mesh/Gui/MeshEditor.h b/src/Mod/Mesh/Gui/MeshEditor.h
index c10a39470..c7fb12f4d 100644
--- a/src/Mod/Mesh/Gui/MeshEditor.h
+++ b/src/Mod/Mesh/Gui/MeshEditor.h
@@ -25,15 +25,22 @@
#include
#include
+#include
class SoCoordinate3;
class SoFaceSet;
class SoEventCallback;
class SoPickedPoint;
class SoQtViewer;
+class SoGroup;
+class SoSeparator;
+class SoRayPickAction;
+class SbLine;
+class SbVec3f;
namespace Gui { class View3DInventor; }
-
+namespace Mesh { class MeshObject; }
+namespace Mesh { class Feature; }
namespace MeshGui {
class SoFCMeshPickNode;
@@ -95,6 +102,69 @@ private:
ViewProviderFace* faceView;
};
+class MeshGuiExport MeshHoleFiller
+{
+public:
+ MeshHoleFiller()
+ {
+ }
+ virtual ~MeshHoleFiller()
+ {
+ }
+ virtual bool fillHoles(Mesh::MeshObject& mesh, const std::list >& boundaries,
+ unsigned long v1, unsigned long v2)
+ {
+ return false;
+ }
+};
+
+/**
+ * Display data of a mesh kernel.
+ * \author Werner Mayer
+ */
+class MeshGuiExport MeshFillHole : public QObject
+{
+ Q_OBJECT
+
+public:
+ MeshFillHole(MeshHoleFiller& hf, Gui::View3DInventor* parent);
+ virtual ~MeshFillHole();
+
+ void startEditing(ViewProviderMesh*);
+
+public Q_SLOTS:
+ void finishEditing();
+
+private Q_SLOTS:
+ void closeBridge();
+
+private:
+ typedef std::vector TBoundary;
+ typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection;
+
+ static void fileHoleCallback(void * ud, SoEventCallback * n);
+ void createPolygons();
+ SoNode* getPickedPolygon(const SoRayPickAction& action) const;
+ float findClosestPoint(const SbLine& ray, const TBoundary& polygon,
+ unsigned long&, SbVec3f&) const;
+ void slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop);
+
+private:
+ SoSeparator* myBoundariesRoot;
+ SoGroup* myBoundariesGroup;
+ SoSeparator* myBoundaryRoot;
+ SoSeparator* myBridgeRoot;
+ SoCoordinate3* myVertex;
+ std::map myPolygons;
+ Mesh::Feature* myMesh;
+ int myNumPoints;
+ unsigned long myVertex1;
+ unsigned long myVertex2;
+ TBoundary myPolygon;
+ MeshHoleFiller& myHoleFiller;
+ Connection myConnection;
+};
+
} // namespace MeshGui
diff --git a/src/Mod/Mesh/Gui/MeshSelection.cpp b/src/Mod/Mesh/Gui/MeshSelection.cpp
new file mode 100644
index 000000000..a724f96ce
--- /dev/null
+++ b/src/Mod/Mesh/Gui/MeshSelection.cpp
@@ -0,0 +1,467 @@
+/***************************************************************************
+ * 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
+# include
+# include
+#endif
+
+#include "MeshSelection.h"
+#include "ViewProvider.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace MeshGui;
+
+#define CROSS_WIDTH 16
+#define CROSS_HEIGHT 16
+#define CROSS_HOT_X 7
+#define CROSS_HOT_Y 7
+
+unsigned char MeshSelection::cross_bitmap[] = {
+ 0xc0, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
+ 0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x01, 0x80,
+ 0x01, 0x80, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02,
+ 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xc0, 0x03
+};
+
+unsigned char MeshSelection::cross_mask_bitmap[] = {
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03,
+ 0xc0, 0x03, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xc0, 0x03,
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03
+};
+
+MeshSelection::MeshSelection()
+ : onlyPointToUserTriangles(false), onlyVisibleTriangles(false), _activeCB(0)
+{
+}
+
+MeshSelection::~MeshSelection()
+{
+ if (_activeCB) {
+ Gui::View3DInventorViewer* viewer = this->getViewer();
+ if (viewer)
+ stopInteractiveCallback(viewer);
+ }
+}
+
+void MeshSelection::setObjects(const std::vector& obj)
+{
+ meshObjects = obj;
+}
+
+std::vector MeshSelection::getObjects() const
+{
+ std::vector objs;
+ if (!meshObjects.empty()) {
+ for (std::vector::iterator it = meshObjects.begin(); it != meshObjects.end(); ++it) {
+ App::DocumentObject* obj = it->getObject();
+ if (obj) {
+ objs.push_back(obj);
+ }
+ }
+ }
+ // get all objects of the active document
+ else {
+ App::Document* doc = App::GetApplication().getActiveDocument();
+ if (doc)
+ objs = doc->getObjectsOfType(Mesh::Feature::getClassTypeId());
+ }
+
+ return objs;
+}
+
+std::list MeshSelection::getViewProviders() const
+{
+ std::vector objs = getObjects();
+ std::list vps;
+ for (std::vector::iterator it = objs.begin(); it != objs.end(); ++it) {
+ if ((*it)->isDerivedFrom(Mesh::Feature::getClassTypeId())) {
+ Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(*it);
+ if (vp->isVisible())
+ vps.push_back(static_cast(vp));
+ }
+ }
+
+ return vps;
+}
+
+Gui::View3DInventorViewer* MeshSelection::getViewer() const
+{
+ Gui::Document* doc = Gui::Application::Instance->activeDocument();
+ if (!doc) return 0;
+ Gui::MDIView* view = doc->getActiveView();
+ if (view && view->getTypeId().isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
+ Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer();
+ return viewer;
+ }
+
+ return 0;
+}
+
+void MeshSelection::startInteractiveCallback(Gui::View3DInventorViewer* viewer,SoEventCallbackCB *cb)
+{
+ if (this->_activeCB)
+ return;
+ viewer->setEditing(true);
+ viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), cb, this);
+ this->_activeCB = cb;
+}
+
+void MeshSelection::stopInteractiveCallback(Gui::View3DInventorViewer* viewer)
+{
+ if (!this->_activeCB)
+ return;
+ if (viewer->isEditing()) {
+ viewer->setEditing(false);
+ viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), this->_activeCB, this);
+ this->_activeCB = 0;
+ }
+}
+
+void MeshSelection::prepareBrushSelection(bool add)
+{
+ // a rubberband to select a rectangle area of the meshes
+ Gui::View3DInventorViewer* viewer = this->getViewer();
+ if (viewer) {
+ stopInteractiveCallback(viewer);
+ startInteractiveCallback(viewer, selectGLCallback);
+ // set cross cursor
+ Gui::BrushSelection* brush = new Gui::BrushSelection();
+ brush->setColor(1.0f,0.0f,0.0f);
+ brush->setLineWidth(3.0f);
+ viewer->navigationStyle()->startSelection(brush);
+ SoQtCursor::CustomCursor custom;
+ custom.dim.setValue(CROSS_WIDTH, CROSS_HEIGHT);
+ custom.hotspot.setValue(CROSS_HOT_X, CROSS_HOT_Y);
+ custom.bitmap = cross_bitmap;
+ custom.mask = cross_mask_bitmap;
+ viewer->setComponentCursor(SoQtCursor(&custom));
+ this->addToSelection = add;
+ }
+}
+
+void MeshSelection::startSelection()
+{
+ prepareBrushSelection(true);
+}
+
+void MeshSelection::startDeselection()
+{
+ prepareBrushSelection(false);
+}
+
+void MeshSelection::fullSelection()
+{
+ // select the complete meshes
+ std::list views = getViewProviders();
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ Mesh::Feature* mf = static_cast((*it)->getObject());
+ const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
+ std::vector faces(mo->countFacets());
+ std::generate(faces.begin(), faces.end(), Base::iotaGen(0));
+ (*it)->addSelection(faces);
+ }
+}
+
+void MeshSelection::clearSelection()
+{
+ std::list views = getViewProviders();
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ (*it)->clearSelection();
+ }
+}
+
+bool MeshSelection::deleteSelection()
+{
+ // delete all selected faces
+ bool selected = false;
+ std::list views = getViewProviders();
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ Mesh::Feature* mf = static_cast((*it)->getObject());
+ unsigned long ct = MeshCore::MeshAlgorithm(mf->Mesh.getValue().getKernel()).
+ CountFacetFlag(MeshCore::MeshFacet::SELECTED);
+ if (ct > 0) {
+ selected = true;
+ break;
+ }
+ }
+ if (!selected)
+ return false; // nothing todo
+
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ (*it)->deleteSelection();
+ }
+
+ return true;
+}
+
+void MeshSelection::invertSelection()
+{
+ std::list views = getViewProviders();
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ Mesh::Feature* mf = static_cast((*it)->getObject());
+ const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
+ const MeshCore::MeshFacetArray& faces = mo->getKernel().GetFacets();
+ unsigned long num_notsel = std::count_if(faces.begin(), faces.end(),
+ std::bind2nd(MeshCore::MeshIsNotFlag(),
+ MeshCore::MeshFacet::SELECTED));
+ std::vector notselect;
+ notselect.reserve(num_notsel);
+ MeshCore::MeshFacetArray::_TConstIterator beg = faces.begin();
+ MeshCore::MeshFacetArray::_TConstIterator end = faces.end();
+ for (MeshCore::MeshFacetArray::_TConstIterator jt = beg; jt != end; ++jt) {
+ if (!jt->IsFlag(MeshCore::MeshFacet::SELECTED))
+ notselect.push_back(jt-beg);
+ }
+ (*it)->setSelection(notselect);
+ }
+}
+
+void MeshSelection::selectComponent(int size)
+{
+ std::list views = getViewProviders();
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ Mesh::Feature* mf = static_cast((*it)->getObject());
+ const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
+
+ std::vector > segm;
+ MeshCore::MeshComponents comp(mo->getKernel());
+ comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm);
+
+ std::vector faces;
+ for (std::vector >::iterator jt = segm.begin(); jt != segm.end(); ++jt) {
+ if (jt->size() < (unsigned long)size)
+ faces.insert(faces.end(), jt->begin(), jt->end());
+ }
+
+ (*it)->addSelection(faces);
+ }
+}
+
+void MeshSelection::deselectComponent(int size)
+{
+ std::list views = getViewProviders();
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ Mesh::Feature* mf = static_cast((*it)->getObject());
+ const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
+
+ std::vector > segm;
+ MeshCore::MeshComponents comp(mo->getKernel());
+ comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm);
+
+ std::vector faces;
+ for (std::vector >::iterator jt = segm.begin(); jt != segm.end(); ++jt) {
+ if (jt->size() > (unsigned long)size)
+ faces.insert(faces.end(), jt->begin(), jt->end());
+ }
+
+ (*it)->removeSelection(faces);
+ }
+}
+
+void MeshSelection::selectTriangle()
+{
+ this->addToSelection = true;
+
+ Gui::View3DInventorViewer* viewer = this->getViewer();
+ if (viewer) {
+ viewer->setEditingCursor(QCursor(Qt::OpenHandCursor));
+ stopInteractiveCallback(viewer);
+ startInteractiveCallback(viewer, pickFaceCallback);
+ }
+}
+
+void MeshSelection::deselectTriangle()
+{
+ this->addToSelection = false;
+
+ Gui::View3DInventorViewer* viewer = this->getViewer();
+ if (viewer) {
+ viewer->setEditingCursor(QCursor(Qt::OpenHandCursor));
+ stopInteractiveCallback(viewer);
+ startInteractiveCallback(viewer, pickFaceCallback);
+ }
+}
+
+void MeshSelection::setCheckOnlyPointToUserTriangles(bool on)
+{
+ onlyPointToUserTriangles = on;
+}
+
+void MeshSelection::setCheckOnlyVisibleTriangles(bool on)
+{
+ onlyVisibleTriangles = on;
+}
+
+void MeshSelection::setAddComponentOnClick(bool on)
+{
+ addComponent = on;
+}
+
+void MeshSelection::setRemoveComponentOnClick(bool on)
+{
+ removeComponent = on;
+}
+
+void MeshSelection::selectGLCallback(void * ud, SoEventCallback * n)
+{
+ // When this callback function is invoked we must leave the edit mode
+ Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData());
+ MeshSelection* self = reinterpret_cast(ud);
+ self->stopInteractiveCallback(view);
+ n->setHandled();
+ std::vector polygon = view->getGLPolygon();
+ if (polygon.size() < 3)
+ return;
+ if (polygon.front() != polygon.back())
+ polygon.push_back(polygon.front());
+
+ SbVec3f pnt, dir;
+ view->getNearPlane(pnt, dir);
+ Base::Vector3f point (pnt[0],pnt[1],pnt[2]);
+ Base::Vector3f normal(dir[0],dir[1],dir[2]);
+
+ std::list views = self->getViewProviders();
+ for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
+ ViewProviderMesh* vp = static_cast(*it);
+
+ std::vector faces;
+ const Mesh::MeshObject& mesh = static_cast((*it)->getObject())->Mesh.getValue();
+ const MeshCore::MeshKernel& kernel = mesh.getKernel();
+
+ // simply get all triangles under the polygon
+ vp->getFacetsFromPolygon(polygon, *view, true, faces);
+ if (self->onlyVisibleTriangles) {
+ const SbVec2s& sz = view->getViewportRegion().getWindowSize();
+ short width,height; sz.getValue(width,height);
+ std::vector pixelPoly = view->getPolygon();
+ SbBox2s rect;
+ for (std::vector::iterator it = pixelPoly.begin(); it != pixelPoly.end(); ++it) {
+ const SbVec2s& p = *it;
+ rect.extendBy(SbVec2s(p[0],height-p[1]));
+ }
+ std::vector rf; rf.swap(faces);
+ std::vector vf = vp->getVisibleFacetsAfterZoom
+ (rect, view->getViewportRegion(), view->getCamera());
+
+ // get common facets of the viewport and the visible one
+ std::sort(vf.begin(), vf.end());
+ std::sort(rf.begin(), rf.end());
+ std::back_insert_iterator > biit(faces);
+ std::set_intersection(vf.begin(), vf.end(), rf.begin(), rf.end(), biit);
+ }
+
+ // if set filter out all triangles which do not point into user direction
+ if (self->onlyPointToUserTriangles) {
+ std::vector screen;
+ screen.reserve(faces.size());
+ MeshCore::MeshFacetIterator it_f(kernel);
+ for (std::vector::iterator it = faces.begin(); it != faces.end(); ++it) {
+ it_f.Set(*it);
+ if (it_f->GetNormal() * normal > 0.0f) {
+ screen.push_back(*it);
+ }
+ }
+
+ faces.swap(screen);
+ }
+
+ if (self->addToSelection)
+ vp->addSelection(faces);
+ else
+ vp->removeSelection(faces);
+ }
+
+ view->render();
+}
+
+void MeshSelection::pickFaceCallback(void * ud, SoEventCallback * n)
+{
+ // handle only mouse button events
+ if (n->getEvent()->isOfType(SoMouseButtonEvent::getClassTypeId())) {
+ const SoMouseButtonEvent * mbe = static_cast(n->getEvent());
+ Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData());
+
+ // Mark all incoming mouse button events as handled, especially, to deactivate the selection node
+ n->getAction()->setHandled();
+ if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
+ const SoPickedPoint * point = n->getPickedPoint();
+ if (point == NULL) {
+ Base::Console().Message("No facet picked.\n");
+ return;
+ }
+
+ n->setHandled();
+
+ // By specifying the indexed mesh node 'pcFaceSet' we make sure that the picked point is
+ // really from the mesh we render and not from any other geometry
+ Gui::ViewProvider* vp = static_cast(view->getViewProviderByPath(point->getPath()));
+ if (!vp || !vp->getTypeId().isDerivedFrom(ViewProviderMesh::getClassTypeId()))
+ return;
+ ViewProviderMesh* mesh = static_cast(vp);
+ MeshSelection* self = reinterpret_cast(ud);
+ std::list views = self->getViewProviders();
+ if (std::find(views.begin(), views.end(), mesh) == views.end())
+ return;
+ const SoDetail* detail = point->getDetail(/*mesh->getShapeNode()*/);
+ if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
+ // get the boundary to the picked facet
+ unsigned long uFacet = static_cast(detail)->getFaceIndex();
+ if (self->addToSelection) {
+ if (self->addComponent)
+ mesh->selectComponent(uFacet);
+ else
+ mesh->selectFacet(uFacet);
+ }
+ else {
+ if (self->removeComponent)
+ mesh->deselectComponent(uFacet);
+ else
+ mesh->deselectFacet(uFacet);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Mod/Mesh/Gui/MeshSelection.h b/src/Mod/Mesh/Gui/MeshSelection.h
new file mode 100644
index 000000000..e2857ba02
--- /dev/null
+++ b/src/Mod/Mesh/Gui/MeshSelection.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * 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 MESHGUI_MESHSELECTION_H
+#define MESHGUI_MESHSELECTION_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Gui {
+ class View3DInventorViewer;
+}
+
+namespace MeshGui {
+
+class ViewProviderMesh;
+
+class MeshGuiExport MeshSelection
+{
+public:
+ MeshSelection();
+ ~MeshSelection();
+
+ void startSelection();
+ void startDeselection();
+ bool deleteSelection();
+ void fullSelection();
+ void clearSelection();
+ void invertSelection();
+
+ void selectComponent(int);
+ void deselectComponent(int);
+ void selectTriangle();
+ void deselectTriangle();
+
+ void setCheckOnlyPointToUserTriangles(bool);
+ void setCheckOnlyVisibleTriangles(bool);
+ void setAddComponentOnClick(bool);
+ void setRemoveComponentOnClick(bool);
+ void setObjects(const std::vector&);
+ std::vector getObjects() const;
+
+private:
+ std::list getViewProviders() const;
+ Gui::View3DInventorViewer* getViewer() const;
+ void startInteractiveCallback(Gui::View3DInventorViewer* viewer,SoEventCallbackCB *cb);
+ void stopInteractiveCallback(Gui::View3DInventorViewer* viewer);
+ void prepareBrushSelection(bool);
+
+ static void selectGLCallback(void * ud, SoEventCallback * n);
+ static void pickFaceCallback(void * ud, SoEventCallback * n);
+
+private:
+ bool onlyPointToUserTriangles, onlyVisibleTriangles;
+ bool addToSelection, addComponent, removeComponent;
+ SoEventCallbackCB *_activeCB;
+ mutable std::vector meshObjects;
+
+ static unsigned char cross_bitmap[];
+ static unsigned char cross_mask_bitmap[];
+};
+
+}
+
+#endif // MESHGUI_MESHSELECTION_H
diff --git a/src/Mod/Mesh/Gui/RemoveComponents.cpp b/src/Mod/Mesh/Gui/RemoveComponents.cpp
index 708eb8b4e..a66e3f500 100644
--- a/src/Mod/Mesh/Gui/RemoveComponents.cpp
+++ b/src/Mod/Mesh/Gui/RemoveComponents.cpp
@@ -27,12 +27,19 @@
# include
# include
# include
+# include
+# include
# include
# include
# include
# include
+# include
# include
+# include
# include
+# include
+# include
+# include
#endif
#include "RemoveComponents.h"
@@ -42,9 +49,12 @@
#include
#include
#include
+#include
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -56,26 +66,9 @@
using namespace MeshGui;
-#define CROSS_WIDTH 16
-#define CROSS_HEIGHT 16
-#define CROSS_HOT_X 7
-#define CROSS_HOT_Y 7
-
-static unsigned char cross_bitmap[] = {
- 0xc0, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
- 0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x01, 0x80,
- 0x01, 0x80, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02,
- 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xc0, 0x03
-};
-
-static unsigned char cross_mask_bitmap[] = {
- 0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,0xc0,0x03,
- 0xc0,0x03
-};
RemoveComponents::RemoveComponents(QWidget* parent, Qt::WFlags fl)
- : QWidget(parent, fl), _interactiveMode(0)
+ : QWidget(parent, fl)
{
ui = new Ui_RemoveComponents;
ui->setupUi(this);
@@ -83,6 +76,9 @@ RemoveComponents::RemoveComponents(QWidget* parent, Qt::WFlags fl)
ui->spSelectComp->setValue(10);
ui->spDeselectComp->setRange(1, INT_MAX);
ui->spDeselectComp->setValue(10);
+
+ meshSel.setCheckOnlyVisibleTriangles(ui->visibleTriangles->isChecked());
+ meshSel.setCheckOnlyPointToUserTriangles(ui->screenTriangles->isChecked());
}
RemoveComponents::~RemoveComponents()
@@ -101,372 +97,266 @@ void RemoveComponents::changeEvent(QEvent *e)
void RemoveComponents::on_selectRegion_clicked()
{
- // a rubberband to select a rectangle area of the meshes
- this->selectRegion = true;
- Gui::View3DInventorViewer* viewer = this->getViewer();
- if (viewer) {
- stopInteractiveCallback(viewer);
- startInteractiveCallback(viewer, selectGLCallback);
- // set cross cursor
- viewer->startSelection(Gui::View3DInventorViewer::Lasso);
- SoQtCursor::CustomCursor custom;
- custom.dim.setValue(CROSS_WIDTH, CROSS_HEIGHT);
- custom.hotspot.setValue(CROSS_HOT_X, CROSS_HOT_Y);
- custom.bitmap = cross_bitmap;
- custom.mask = cross_mask_bitmap;
- viewer->setComponentCursor(SoQtCursor(&custom));
- }
+ meshSel.startSelection();
}
void RemoveComponents::on_deselectRegion_clicked()
{
- // a rubberband to deselect a rectangle area of the meshes
- this->selectRegion = false;
- Gui::View3DInventorViewer* viewer = this->getViewer();
- if (viewer) {
- stopInteractiveCallback(viewer);
- startInteractiveCallback(viewer, selectGLCallback);
- // set cross cursor
- viewer->startSelection(Gui::View3DInventorViewer::Lasso);
- SoQtCursor::CustomCursor custom;
- custom.dim.setValue(CROSS_WIDTH, CROSS_HEIGHT);
- custom.hotspot.setValue(CROSS_HOT_X, CROSS_HOT_Y);
- custom.bitmap = cross_bitmap;
- custom.mask = cross_mask_bitmap;
- viewer->setComponentCursor(SoQtCursor(&custom));
- }
+ meshSel.startDeselection();
}
void RemoveComponents::on_selectAll_clicked()
{
// select the complete meshes
- Gui::Document* doc = Gui::Application::Instance->activeDocument();
- if (!doc) return;
- std::list views = getViewProviders(doc);
- for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
- Mesh::Feature* mf = static_cast((*it)->getObject());
- const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
- std::vector faces(mo->countFacets());
- std::generate(faces.begin(), faces.end(), Base::iotaGen(0));
- (*it)->addSelection(faces);
- }
+ meshSel.fullSelection();
}
void RemoveComponents::on_deselectAll_clicked()
{
// deselect all meshes
- Gui::Document* doc = Gui::Application::Instance->activeDocument();
- if (!doc) return;
- std::list views = getViewProviders(doc);
- for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
- (*it)->clearSelection();
- }
+ meshSel.clearSelection();
}
void RemoveComponents::on_selectComponents_clicked()
{
// select components upto a certain size
int size = ui->spSelectComp->value();
- Gui::Document* doc = Gui::Application::Instance->activeDocument();
- if (!doc) return;
- std::list views = getViewProviders(doc);
- for (std::list::iterator it = views.begin(); it != views.end(); ++it) {
- Mesh::Feature* mf = static_cast((*it)->getObject());
- const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
-
- std::vector > segm;
- MeshCore::MeshComponents comp(mo->getKernel());
- comp.SearchForComponents(MeshCore::MeshComponents::OverEdge,segm);
-
- std::vector