Merge branch 'refs/heads/master' into jriegel/develop-fem

Conflicts:
	src/Mod/Fem/App/FemMeshShapeNetgenObject.cpp
	src/Mod/Fem/App/FemMeshShapeNetgenObject.h
	src/Mod/Fem/Gui/AppFemGuiPy.cpp
	src/Mod/Fem/Gui/Command.cpp
	src/Mod/Fem/Gui/TaskDlgMeshShapeNetgen.cpp
	src/Mod/Fem/Gui/TaskDlgMeshShapeNetgen.h
	src/Mod/Fem/Gui/TaskTetParameter.cpp
	src/Mod/Fem/Gui/TaskTetParameter.h
	src/Mod/Fem/Gui/TaskTetParameter.ui
	src/Mod/Fem/Gui/ViewProviderAnalysis.cpp
	src/Mod/Fem/Gui/ViewProviderAnalysis.h
	src/Mod/Fem/Gui/ViewProviderFemMeshShapeNetgen.cpp
	src/Mod/Fem/Gui/ViewProviderFemMeshShapeNetgen.h
This commit is contained in:
jriegel 2013-06-26 19:02:15 +02:00
commit 83b956e908
123 changed files with 6137 additions and 2296 deletions

View File

@ -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 ----------------------------------

View File

@ -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

35
README
View File

@ -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

View File

@ -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);

View File

@ -37,6 +37,7 @@
# endif
# include <xercesc/framework/StdOutFormatTarget.hpp>
# include <xercesc/framework/LocalFileFormatTarget.hpp>
# include <xercesc/framework/LocalFileInputSource.hpp>
# include <xercesc/parsers/XercesDOMParser.hpp>
# include <xercesc/util/XMLUni.hpp>
# include <xercesc/util/XMLUniDefs.hpp>
@ -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
{

View File

@ -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:

View File

@ -82,6 +82,7 @@
#include <xercesc/dom/DOMText.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/XMLUniDefs.hpp>

View File

@ -24,6 +24,8 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
# include <locale>
# include <iostream>
#endif
# include <QTime>
@ -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<wchar_t>& ctfacet = std::use_facet< std::ctype<wchar_t> >(wstm.getloc());
for (size_t i=0; i<str.size(); ++i)
wstm << ctfacet.widen(str[i]);
return wstm.str();
}
std::string Base::Tools::narrow(const std::wstring& str)
{
std::ostringstream stm;
const std::ctype<char>& ctfacet = std::use_facet< std::ctype<char> >(stm.getloc());
for (size_t i=0; i<str.size(); ++i)
stm << ctfacet.narrow(str[i], 0);
return stm.str();
}
// ----------------------------------------------------------------------------
using namespace Base;

View File

@ -151,6 +151,8 @@ struct BaseExport Tools
static std::string getUniqueName(const std::string&, const std::vector<std::string>&,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

View File

@ -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

View File

@ -0,0 +1,9 @@
The FreeCAD Document
====================
.. toctree::
:maxdepth: 4
.. automodule:: DocumentObject

View File

@ -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__()

View File

@ -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:

View File

@ -0,0 +1,10 @@
Draft Geometry Utilities
========================
The DraftGeomUtils module offer tools to manipulate Part geometry.
.. toctree::
:maxdepth: 4
.. automodule:: DraftGeomUtils
:members:

View File

@ -0,0 +1,10 @@
Draft Snapper
=============
The Draft Snapper manages object snapping in Draft and Arch modules.
.. toctree::
:maxdepth: 4
.. automodule:: DraftSnap
:members:

View File

@ -0,0 +1,10 @@
Draft Trackers
==============
Different trackers (temporary screen widgets) used in the Draft and Arch modules.
.. toctree::
:maxdepth: 4
.. automodule:: DraftTrackers
:members:

View File

@ -0,0 +1,10 @@
Draft Vector Utilities
======================
The DraftVecUtils module offer several convenient utilities to deal with vectors
.. toctree::
:maxdepth: 4
.. automodule:: DraftVecUtils
:members:

View File

@ -7,14 +7,5 @@ The FreeCAD module
.. automodule:: FreeCAD
:members:
.. autoclass:: Vector
:members:
.. autoclass:: Matrix
:members:
.. autoclass:: Placement
:members:
.. autoclass:: Console
:members:

10
src/Doc/sphinx/Matrix.rst Normal file
View File

@ -0,0 +1,10 @@
The Matrix object
=================
.. toctree::
:maxdepth: 4
.. automodule:: FreeCAD
.. autoclass:: Matrix
:members:

View File

@ -0,0 +1,10 @@
The Placement object
====================
.. toctree::
:maxdepth: 4
.. automodule:: FreeCAD
.. autoclass:: Placement
:members:

10
src/Doc/sphinx/Vector.rst Normal file
View File

@ -0,0 +1,10 @@
The Vector object
=================
.. toctree::
:maxdepth: 4
.. automodule:: FreeCAD
.. autoclass:: Vector
:members:

View File

@ -0,0 +1,10 @@
The View Provider object
========================
.. toctree::
:maxdepth: 4
.. automodule:: DocumentObject
.. autoclass:: ViewProvider
:members:

View File

@ -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;
}
}

View File

@ -20,7 +20,7 @@
{{ _('Enter search terms or a module, class or function name.') }}
</p>
<p>
<a href="http://free-cad.sf.net">Go back to the FreeCAD wiki</a>
<a href="http://www.freecadweb.org">Go back to the FreeCAD homepage</a>
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>

View File

@ -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,

View File

@ -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 <http://free-cad.sf.net>`_
* `FreeCAD homepage <http://www.freecadweb.org>`_

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<Gui::View3DInventor*>(view)->getViewer();
return viewer->isEditing();
return viewer->isEditing() && viewer->isRedirectToSceneGraphEnabled();
}
return false;
}

View File

@ -82,15 +82,18 @@ DlgParameterImp::DlgParameterImp( QWidget* parent, Qt::WFlags fl )
qApp->translate( "Gui::Dialog::DlgParameterImp", "User parameter" );
#endif
const std::map<std::string,ParameterManager *> rcList = App::GetApplication().GetParameterSetList();
ParameterManager* sys = App::GetApplication().GetParameterSet("System parameter");
const std::map<std::string,ParameterManager *>& rcList = App::GetApplication().GetParameterSetList();
for (std::map<std::string,ParameterManager *>::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 {

View File

@ -270,7 +270,7 @@ PyObject* DocumentPy::toggleTreeItem(PyObject *args)
Gui::ViewProviderDocumentObject* ActiveVp = dynamic_cast<Gui::ViewProviderDocumentObject*> (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();

View File

@ -27,6 +27,8 @@
# include <QMouseEvent>
#endif
#include <Inventor/SbVec2s.h>
#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)

View File

@ -31,7 +31,7 @@
#include <Inventor/SbVec3f.h>
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:

184
src/Gui/GLPainter.cpp Normal file
View File

@ -0,0 +1,184 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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();
}

77
src/Gui/GLPainter.h Normal file
View File

@ -0,0 +1,77 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 <windows.h>
#endif
#ifdef FC_OS_MACOSX
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#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

View File

@ -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) {

View File

@ -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);

View File

@ -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<QPoint>::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<QPoint>::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 )

View File

@ -27,6 +27,7 @@
#include <vector>
#include <Inventor/SbLinear.h>
#include <Inventor/SbVec2f.h>
#include <QCursor>
// 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<QPoint> _cNodeVector;
int m_iNodes;
bool m_bWorking;
private:
float r,g,b,a,l;
};
// -----------------------------------------------------------------------------------
/**
* The selection mouse model class
* Draws a rectangle for selection

View File

@ -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<View3DInventor*>(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<View3DInventor*>(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<View3DInventor*>(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<View3DInventor*>(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<View3DInventor*>(mdi)->setCursor(Qt::ForbiddenCursor);
}
mdi->setOverrideCursor(Qt::ForbiddenCursor);
}
QApplication::beep();
return false;

View File

@ -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. *
* *

View File

@ -26,6 +26,7 @@
#include <Inventor/nodekits/SoSubKit.h>
#include <Inventor/nodekits/SoBaseKit.h>
#include <Inventor/nodes/SoShape.h>
#include <Inventor/fields/SoSFFloat.h>
#include <Inventor/fields/SoSFColor.h>
#include <Inventor/fields/SoSFString.h>

View File

@ -204,7 +204,7 @@ void AbstractSplitView::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp
}
else if (strcmp(Reason,"Gradient") == 0) {
for (std::vector<View3DInventorViewer*>::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<View3DInventorViewer*>::iterator it = _viewer.begin(); it != _viewer.end(); ++it)
@ -238,9 +238,9 @@ void AbstractSplitView::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp
for (std::vector<View3DInventorViewer*>::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);
}

View File

@ -54,7 +54,7 @@ public:
View3DInventorViewer *getViewer(unsigned int) const;
void setCursor(const QCursor&);
void setOverrideCursor(const QCursor&);
protected:
void setupSettings();

View File

@ -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<QWidgetItem*>(bl->itemAt(index));
TaskIconLabel* label = static_cast<TaskIconLabel*>(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();

View File

@ -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
{

View File

@ -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

View File

@ -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<std::string, DocumentObjectItem*>::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<std::string, DocumentObjectItem*>::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;

View File

@ -49,8 +49,8 @@ enum HighlightMode { Underlined,
/// highlight modes for the tree items
enum TreeItemMode { Expand,
Collaps,
Toggle
Collapse,
Toggle
};

View File

@ -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<QGLWidget*>(_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)

View File

@ -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);

View File

@ -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<QGLWidget*>(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.

View File

@ -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

View File

@ -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()

View File

@ -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"

View File

@ -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"):

View File

@ -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"

View File

@ -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):

View File

@ -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\
"

View File

@ -21,6 +21,7 @@ SET(Arch_SRCS
ArchAxis.py
ArchVRM.py
ArchRoof.py
importWebGL.py
)
SOURCE_GROUP("" FILES ${Arch_SRCS})

View File

@ -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

View File

@ -30,6 +30,7 @@
<file>icons/Arch_Check.svg</file>
<file>icons/Arch_SelectNonManifold.svg</file>
<file>icons/Arch_MergeWalls.svg</file>
<file>icons/Arch_Wall_Tree_Assembly.svg</file>
<file>ui/archprefs-base.ui</file>
<file>translations/Arch_af.qm</file>
<file>translations/Arch_de.qm</file>

View File

@ -0,0 +1,415 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2816"
version="1.1"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Arch_Wall_Tree.svg">
<defs
id="defs2818">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2824" />
<inkscape:perspective
id="perspective3622"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3622-9"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3653"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3675"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3697"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3720"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3742"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3764"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3785"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3806-3"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3835"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11"
inkscape:cx="16.107459"
inkscape:cy="33.217385"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:object-nodes="true"
inkscape:window-width="1920"
inkscape:window-height="1057"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-nodes="false"
inkscape:snap-global="false" />
<metadata
id="metadata2821">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-0-8-5"
width="8.8969326"
height="6.4156804"
x="50.020618"
y="80.818169"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-7"
width="14.188248"
height="6.3632684"
x="27.991013"
y="38.201286"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-9-6"
width="14.188248"
height="6.3632684"
x="43.51255"
y="38.190132"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<path
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 33.802565,41.435793 13.512409,4.326796 -7.144868,5.301535 -13.512409,-4.326797 7.144868,-5.301534 z"
id="rect2840-3-5-3-5-0"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 48.584755,46.105614 13.512409,4.326797 -7.144868,5.301534 -13.512409,-4.326797 7.144868,-5.301534 z"
id="rect2840-3-5-3-0"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-0-5-6"
width="8.8969326"
height="6.4156804"
x="41.959759"
y="66.366005"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-2"
width="14.188248"
height="6.3632684"
x="37.004723"
y="30.533503"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-5"
width="8.8969326"
height="6.4156804"
x="68.427689"
y="96.508865"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-0-7"
width="8.8969326"
height="6.4156804"
x="60.71003"
y="82.268806"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<path
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 42.386919,36.464382 13.512409,4.326797 -7.144867,5.301534 -13.512409,-4.326797 7.144867,-5.301534 z"
id="rect2840-3-5-2"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 33.945387,33.819971 6.896146,2.241369 -7.144868,5.301534 -6.896146,-2.241368 z"
id="rect2840-3-5-4-1"
sodipodi:nodetypes="ccccc" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-6"
width="4.8688564"
height="6.3783622"
x="52.702457"
y="30.623219"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-0-5"
width="8.8969326"
height="6.4156804"
x="68.274139"
y="88.826065"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 57.336914,41.387566 4.636933,1.45354 -7.144868,5.301534 -4.636934,-1.453539 z"
id="rect2840-3-5-4"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 32.557262,11.494551 9.205487,2.784019 -12.158897,8.901351 -9.205487,-2.784019 z"
id="rect2840-3-5-3-1-3"
sodipodi:nodetypes="ccccc" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-04-1-5-1"
width="15.060457"
height="8.1599474"
x="53.304558"
y="64.54351"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-04-1-5-4"
width="15.060457"
height="8.1599474"
x="45.460068"
y="55.047924"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-04-1"
width="15.060457"
height="8.1599474"
x="36.8633"
y="45.146145"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-0-8-7"
width="8.8969326"
height="6.4156804"
x="49.970425"
y="65.531265"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-2"
width="14.188248"
height="6.3632684"
x="27.948685"
y="22.957209"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-9-2"
width="14.188248"
height="6.3632684"
x="43.470222"
y="22.946053"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 33.762254,26.178803 13.512409,4.326797 -7.144868,5.301535 -13.51241,-4.326797 7.144869,-5.301535 z"
id="rect2840-3-5-3-5-1"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 48.544443,30.848624 13.512409,4.326797 -7.144867,5.301535 -13.512409,-4.326797 7.144867,-5.301535 z"
id="rect2840-3-5-3-1"
sodipodi:nodetypes="ccccc" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-04"
width="8.8969326"
height="6.4156804"
x="68.377495"
y="81.22197"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-2-7"
width="14.188248"
height="6.3632684"
x="12.103945"
y="22.966328"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 18.672257,21.355968 13.512409,4.326797 -7.144868,5.301535 -13.51241,-4.326797 7.144869,-5.301535 z"
id="rect2840-3-5-3-5-1-5"
sodipodi:nodetypes="ccccc" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-2-7-5"
width="8.1745195"
height="6.0153747"
x="2.8632176"
y="23.144983"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 10.053518,18.352968 7.603319,2.508615 -7.144868,5.301535 -7.6033201,-2.508615 z"
id="rect2840-3-5-3-5-1-5-1"
sodipodi:nodetypes="ccccc" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-2-1"
width="15.715544"
height="6.7156911"
x="19.251734"
y="30.329483"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-2-6"
width="15.33372"
height="6.5594053"
x="2.8333008"
y="30.881844"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-7-3"
width="14.188248"
height="6.3632684"
x="12.569814"
y="38.276264"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.82064199;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-2-7-5-2"
width="9.1290798"
height="5.8151832"
x="2.6901171"
y="38.834602"
transform="matrix(0.95236631,0.3049564,0,1,0,0)" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c7c7c7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.77675104;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 45.767302,1.6871595 54.972789,4.4711786 42.813892,13.37253 33.608404,10.588511 z"
id="rect2840-3-5-3-1-3-3"
sodipodi:nodetypes="ccccc" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-04-1-5"
width="15.060457"
height="8.1599474"
x="53.312706"
y="45.140682"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
<rect
style="color:#000000;fill:#7a7a7a;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.98266625;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2840-3-4-04-1-5-7"
width="6.9758401"
height="8.4850521"
x="61.389179"
y="54.704601"
transform="matrix(0.80307096,-0.59588341,0,1,0,0)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

228
src/Mod/Arch/importWebGL.py Normal file
View File

@ -0,0 +1,228 @@
#***************************************************************************
#* *
#* Copyright (c) 2013 *
#* Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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 = """<!DOCTYPE html>
<html>
<head>
<title>FreeCAD model</title>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/three.js/r50/three.min.js"></script>
<script>
var camera, controls, scene, renderer;
window.onload = function() {
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 35, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
renderer = new THREE.WebGLRenderer();
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
VIEW_ANGLE, // Field of view
ASPECT, // Aspect ratio
NEAR, // Near plane
FAR // Far plane
);
$CameraData // placeholder for the FreeCAD camera
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
$ObjectsData // placeholder for the FreeCAD objects
var light = new THREE.PointLight( 0xFFFF00 );
light.position.set( -10000, -10000, 10000 );
scene.add( light );
renderer.render( scene, camera );
animate();
};
function animate(){
requestAnimationFrame( animate );
render();
};
function render(){
controls.update();
renderer.render( scene, camera );
};
</script>
</head>
<body></body>
</html>"""
return result

View File

@ -13,6 +13,7 @@ SET(Draft_SRCS
importDXF.py
importOCA.py
importSVG.py
importDWG.py
importAirfoilDAT.py
macros.py
Draft_rc.py

View File

@ -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"):

View File

@ -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 *********************************************************

View File

@ -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())

View File

@ -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

View File

@ -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())

File diff suppressed because it is too large Load Diff

View File

@ -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")))

View File

@ -55,6 +55,7 @@
<file>icons/Draft_Clone.svg</file>
<file>icons/Draft_Heal.svg</file>
<file>icons/Draft_Ellipse.svg</file>
<file>icons/Draft_ShapeString.svg</file>
<file>patterns/concrete.svg</file>
<file>patterns/cross.svg</file>
<file>patterns/line.svg</file>

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg4594"
sodipodi:version="0.32"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Draft_ShapeString.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs4596">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective4602" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6568542"
inkscape:cx="16.724718"
inkscape:cy="24.831907"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1366"
inkscape:window-height="695"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata4599">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<text
xml:space="preserve"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="15.684914"
y="19.773684"
id="text3097"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3099"
x="15.684914"
y="19.773684" /></text>
<g
id="g4061">
<text
transform="scale(1.2630773,0.79171719)"
sodipodi:linespacing="125%"
id="text3892"
y="69.508385"
x="5.465425"
style="font-size:77.39546203999999818px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:0.62711863999999995;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.191;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman, Italic'"
xml:space="preserve"><tspan
style="stroke-width:3.191;stroke-miterlimit:4;stroke-dasharray:none"
y="69.508385"
x="5.465425"
id="tspan3894"
sodipodi:role="line">S</tspan><tspan
style="stroke-width:3.191;stroke-miterlimit:4;stroke-dasharray:none"
id="tspan3896"
y="166.25272"
x="5.465425"
sodipodi:role="line" /></text>
<text
inkscape:transform-center-y="17.646795"
inkscape:transform-center-x="1.9859923"
transform="scale(1.258685,0.79447996)"
sodipodi:linespacing="125%"
id="text3103"
y="65.225639"
x="2.1774669"
style="font-size:80.06713104px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#ffda04;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.57333159;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman, Italic'"
xml:space="preserve"><tspan
style="stroke-width:1.57333159"
y="65.225639"
x="2.1774669"
id="tspan3105"
sodipodi:role="line">S</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>590</width>
<height>632</height>
<width>718</width>
<height>808</height>
</rect>
</property>
<property name="windowTitle">
@ -1199,6 +1199,49 @@ such as &quot;Arial:Bold&quot;</string>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_23">
<item>
<widget class="QLabel" name="label_24">
<property name="text">
<string>Default ShapeString Font File</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Select a font file</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>FontFile</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Draft</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -280,6 +280,26 @@ If color mapping is choosed, you must choose a color mapping file containing a t
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
<widget class="Gui::PrefCheckBox" name="gui::prefcheckbox_12">
<property name="toolTip">
<string>If this is checked, the exported objects will be projected to reflect the current view direction</string>
</property>
<property name="text">
<string>Project exported objects along current view direction</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>dxfproject</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Draft</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>

View File

@ -0,0 +1,94 @@
# -*- coding: utf8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2009 Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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

View File

@ -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

View File

@ -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<std::string> getDisplayModes(void) const;

View File

@ -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<std::string> getDisplayModes(void) const;
virtual void updateData(const App::Property*);

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;
};

View File

@ -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");

View File

@ -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(),

View File

@ -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);
}
}

View File

@ -452,8 +452,8 @@ void QuadraticFit::CalcEigenValues(double &dLambda1, double &dLambda2, double &d
*/
Wm4::Matrix3<double> 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<double> 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;

View File

@ -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++) {

View File

@ -587,6 +587,23 @@ void MeshObject::getPointsFromSelection(std::vector<unsigned long>& 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<unsigned long> MeshObject::getPointsFromFacets(const std::vector<unsigned long>& facets) const
{
return _kernel.GetFacetPoints(facets);
}
void MeshObject::updateMesh(const std::vector<unsigned long>& facets)
{
std::vector<unsigned long> points;

View File

@ -124,6 +124,7 @@ public:
double getVolume() const;
void getFaces(std::vector<Base::Vector3d> &Points,std::vector<Facet> &Topo,
float Accuracy, uint16_t flags=0) const;
std::vector<unsigned long> getPointsFromFacets(const std::vector<unsigned long>& facets) const;
//@}
void setKernel(const MeshCore::MeshKernel& m);
@ -211,6 +212,8 @@ public:
void addPointsToSelection(const std::vector<unsigned long>&) const;
void removeFacetsFromSelection(const std::vector<unsigned long>&) const;
void removePointsFromSelection(const std::vector<unsigned long>&) const;
bool hasSelectedFacets() const;
bool hasSelectedPoints() const;
void getFacetsFromSelection(std::vector<unsigned long>&) const;
void getPointsFromSelection(std::vector<unsigned long>&) const;
void clearFacetSelection() const;

View File

@ -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();

View File

@ -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

View File

@ -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<Gui::View3DInventor*>(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;
}

View File

@ -23,17 +23,25 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QButtonGroup>
# include <QDialogButtonBox>
#endif
#include "DlgSmoothing.h"
#include "ui_DlgSmoothing.h"
#include "Selection.h"
#include <Gui/WaitCursor.h>
#include <Gui/Command.h>
#include <Gui/Selection.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/App/Core/Smoothing.h>
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<App::DocumentObject*> meshes = selection->getObjects();
if (meshes.empty())
return true;
Gui::WaitCursor wc;
Gui::Command::openCommand("Mesh Smoothing");
bool hasSelection = false;
for (std::vector<App::DocumentObject*>::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
Mesh::Feature* mesh = static_cast<Mesh::Feature*>(*it);
std::vector<unsigned long> 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"

View File

@ -25,13 +25,16 @@
#define MESHGUI_DLGSMOOTHING_H
#include <QDialog>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/TaskView/TaskView.h>
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

View File

@ -1,172 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MeshGui::DlgSmoothing</class>
<widget class="QDialog" name="MeshGui::DlgSmoothing">
<widget class="QWidget" name="MeshGui::DlgSmoothing">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>242</width>
<height>251</height>
<width>210</width>
<height>227</height>
</rect>
</property>
<property name="windowTitle">
<string>Smoothing</string>
</property>
<property name="sizeGripEnabled">
<property name="sizeGripEnabled" stdset="0">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string/>
<string>Method</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Method</string>
<widget class="QRadioButton" name="radioButtonTaubin">
<property name="text">
<string>Taubin</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="radioButtonTaubin">
<property name="text">
<string>Taubin</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="radioButtonLaplace">
<property name="text">
<string>Laplace</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Parameter</string>
<item row="0" column="1">
<widget class="QRadioButton" name="radioButtonLaplace">
<property name="text">
<string>Laplace</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Iterations:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="iterations">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelLambda">
<property name="text">
<string>Lambda:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="spinLambda">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.630700000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelMu">
<property name="text">
<string>Mu:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="spinMicro">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.042400000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Parameter</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Iterations:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="iterations">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelLambda">
<property name="text">
<string>Lambda:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="spinLambda">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.630700000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelMu">
<property name="text">
<string>Mu:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="spinMicro">
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.042400000000000</double>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="checkBoxSelection">
<property name="text">
<string>Only selection</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MeshGui::DlgSmoothing</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>94</x>
<y>191</y>
</hint>
<hint type="destinationlabel">
<x>-3</x>
<y>193</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MeshGui::DlgSmoothing</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>190</x>
<y>193</y>
</hint>
<hint type="destinationlabel">
<x>219</x>
<y>151</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

View File

@ -40,15 +40,21 @@
# include <Inventor/nodes/SoFaceSet.h>
# include <Inventor/nodes/SoLineSet.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoShapeHints.h>
# include <boost/bind.hpp>
#endif
#include "MeshEditor.h"
#include "SoFCMeshObject.h"
#include "SoPolygon.h"
#include <App/Document.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/App/Core/Algorithm.h>
#include <Mod/Mesh/App/Core/Triangulation.h>
#include <Gui/Application.h>
#include <Gui/WaitCursor.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
@ -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<unsigned long>&,
const std::vector<unsigned long>&, bool>
{
bool operator () (const std::vector<unsigned long> &rclC1,
const std::vector<unsigned long> &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<Mesh::Feature*>(vp->getObject());
Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(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<SoGroup*>(viewer->getSceneGraph())->addChild(myBridgeRoot);
}
void MeshFillHole::finishEditing()
{
Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(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<SoGroup*>(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<TBoundary> 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<std::vector<unsigned long> > 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<std::vector<unsigned long> >::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<std::vector<unsigned long> >::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<unsigned long>::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<SoPolygon*>(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<MeshFillHole*>(ud);
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(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<SoNode*, TBoundary>::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<const SoMouseButtonEvent *>(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<SoNode*, TBoundary>::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"

Some files were not shown because too many files have changed in this diff Show More