Merge branch 'master' of ssh://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad into sanguinariojoe-ship

This commit is contained in:
Jose Luis Cercós pita 2012-07-06 10:48:48 +02:00
commit 91599cf603
55 changed files with 1035 additions and 489 deletions

View File

@ -206,7 +206,7 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
if( ${OCE_FOUND} )
message("-- OpenCASCADE Community Edition has been found.")
add_definitions ( -DHAVE_CONFIG_H )
set( OCC_LIBRARIES "TKFillet;TKMesh;TKernel;TKG2d;TKG3d;TKMath;TKIGES;TKSTL;TKShHealing;TKXSBase;TKBool;TKBO;TKBRep;TKTopAlgo;TKGeomAlgo;TKGeomBase;TKOffset;TKPrim;TKSTEP;TKSTEPBase;TKSTEPAttr;TKHLR" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake
set( OCC_LIBRARIES "TKFeat;TKFillet;TKMesh;TKernel;TKG2d;TKG3d;TKMath;TKIGES;TKSTL;TKShHealing;TKXSBase;TKBool;TKBO;TKBRep;TKTopAlgo;TKGeomAlgo;TKGeomBase;TKOffset;TKPrim;TKSTEP;TKSTEPBase;TKSTEPAttr;TKHLR" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake
set( OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS} )
set( OCC_FOUND ${OCE_FOUND} )
else() #look for OpenCASCADE
@ -219,12 +219,6 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
ENDIF()
endif()
# -------------------------------- f2c ----------------------------------
IF(OCC_FOUND)
find_package(F2C REQUIRED)
ENDIF(OCC_FOUND)
# -------------------------------- Salome SMESH --------------------------
# Salome SMESH sources are under src/3rdParty now
@ -268,7 +262,7 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
# -------------------------------- ODE ----------------------------------
find_package(ODE)
# find_package(ODE)
# -------------------------------- Qt --------------------------------
@ -439,7 +433,7 @@ if(FREECAD_MAINTAINERS_BUILD AND NOT WIN32)
set(PKG_ARCH amd64)
ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 4 )
set(CPACK_DEBIAN_PACKAGE_SECTION "science")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python, oce | opencascade, libqtgui4, libcoin60, libode1, libsoqt4-20, libxerces-c3.1, libgts-0.7-5, zlib1g, libboost-dev, libeigen2-dev")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python, oce | opencascade, libqtgui4, libcoin60, libsoqt4-20, libxerces-c3.1, zlib1g, libboost-dev, libeigen2-dev")
set(CPACK_PACKAGE_CONTACT "<root@localhost>")
set(CPACK_PACKAGE_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}_${PKG_ARCH}")

View File

@ -78,6 +78,7 @@ IF(OCC_LIBRARY)
TKSTEPBase
TKSTEPAttr
TKHLR
TKFeat
)
ENDIF(OCC_LIBRARY)

View File

@ -7,8 +7,8 @@ by the authors who actually wrote it.
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
51 Franklin Street - Fifth Floor
Boston, MA 02110-1301, USA.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

View File

@ -173,7 +173,7 @@ FILE(GLOB StdMeshers_source_files src/StdMeshers/*.cpp src/MEFISTO2/*.cpp src/ME
INCLUDE_DIRECTORIES(src/StdMeshers)
ADD_LIBRARY(StdMeshers SHARED ${StdMeshers_source_files})
TARGET_LINK_LIBRARIES(StdMeshers SMESH TKernel TKMath TKAdvTools f2c gfortran)
TARGET_LINK_LIBRARIES(StdMeshers SMESH TKernel TKMath TKAdvTools gfortran)
SET(StdMeshers_CFLAGS "")
IF(WIN32)
SET(StdMeshers_CFLAGS "-DSTDMESHERS_EXPORTS -DMEFISTO2D_EXPORTS")

View File

@ -1188,13 +1188,13 @@ void Application::processCmdLineFiles(void)
Application::_pcSingleton->openDocument(File.filePath().c_str());
}
else if (File.hasExtension("fcscript")||File.hasExtension("fcmacro")) {
Base::Interpreter().runFile(File.filePath().c_str(), false);
Base::Interpreter().runFile(File.filePath().c_str(), true);
}
else if (File.hasExtension("py")) {
//FIXME: Does this make any sense? I think we should do the ame as for
// fcmacro or fcscript.
//Base::Interpreter().loadModule(File.fileNamePure().c_str());
Base::Interpreter().runFile(File.filePath().c_str(), false);
Base::Interpreter().runFile(File.filePath().c_str(), true);
}
else {
std::vector<std::string> mods = App::GetApplication().getImportModules(Ext.c_str());
@ -1210,8 +1210,7 @@ void Application::processCmdLineFiles(void)
}
}
catch (const Base::SystemExitException&) {
Base::PyGILStateLocker locker;
Base::Interpreter().systemExit();
throw; // re-throw to main() function
}
catch (const Base::Exception& e) {
Console().Error("Exception while processing file: %s [%s]\n", File.filePath().c_str(), e.what());
@ -1523,20 +1522,23 @@ void Application::ParseOptions(int ac, char ** av)
notify(vm);
}
catch (const std::exception& e) {
cerr << e.what() << endl << endl << visible << endl;
exit(1);
std::stringstream str;
str << e.what() << endl << endl << visible << endl;
throw UnknownProgramOption(str.str());
}
catch (...) {
cerr << "Wrong or unknown option, bailing out!" << endl << endl << visible << endl;
exit(1);
std::stringstream str;
str << "Wrong or unknown option, bailing out!" << endl << endl << visible << endl;
throw UnknownProgramOption(str.str());
}
if (vm.count("help")) {
cout << mConfig["ExeName"] << endl << endl;
cout << "For detailed descripton see http://free-cad.sf.net" << endl<<endl;
cout << "Usage: " << mConfig["ExeName"] << " [options] File1 File2 ..." << endl << endl;
cout << visible << endl;
exit(0);
std::stringstream str;
str << mConfig["ExeName"] << endl << endl;
str << "For detailed descripton see http://free-cad.sf.net" << endl<<endl;
str << "Usage: " << mConfig["ExeName"] << " [options] File1 File2 ..." << endl << endl;
str << visible << endl;
throw Base::ProgramInformation(str.str());
}
if (vm.count("response-file")) {
@ -1544,9 +1546,10 @@ void Application::ParseOptions(int ac, char ** av)
std::ifstream ifs(vm["response-file"].as<string>().c_str());
if (!ifs) {
Base::Console().Error("Could no open the response file\n");
cerr << "Could no open the response file: '"
<< vm["response-file"].as<string>() << "'" << endl;
exit(1);
std::stringstream str;
str << "Could no open the response file: '"
<< vm["response-file"].as<string>() << "'" << endl;
throw Base::UnknownProgramOption(str.str());
}
// Read the whole file into a string
stringstream ss;
@ -1562,9 +1565,10 @@ void Application::ParseOptions(int ac, char ** av)
}
if (vm.count("version")) {
std::cout << mConfig["ExeName"] << " " << mConfig["ExeVersion"]
<< " Revision: " << mConfig["BuildRevision"] << std::endl;
exit(0);
std::stringstream str;
str << mConfig["ExeName"] << " " << mConfig["ExeVersion"]
<< " Revision: " << mConfig["BuildRevision"] << std::endl;
throw Base::ProgramInformation(str.str());
}
if (vm.count("console")) {

View File

@ -35,6 +35,7 @@
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <iostream>
#include <boost/regex.hpp>
using namespace App;
@ -82,10 +83,20 @@ std::string PropertyPythonObject::toString() const
std::string repr;
Base::PyGILStateLocker lock;
try {
Py::Module pickle(PyImport_ImportModule("cPickle"),true);
Py::Module pickle(PyImport_ImportModule("json"),true);
Py::Callable method(pickle.getAttr(std::string("dumps")));
Py::Object dump;
if (this->object.hasAttr("__getstate__")) {
Py::Tuple args(0);
Py::Callable state(this->object.getAttr("__getstate__"));
dump = state.apply(args);
}
else if (this->object.hasAttr("__dict__")) {
dump = this->object.getAttr("__dict__");
}
Py::Tuple args(1);
args.setItem(0, this->object);
args.setItem(0, dump);
Py::Object res = method.apply(args);
Py::String str(res);
repr = str.as_std_string();
@ -102,12 +113,21 @@ void PropertyPythonObject::fromString(const std::string& repr)
{
Base::PyGILStateLocker lock;
try {
Py::Module pickle(PyImport_ImportModule("cPickle"),true);
Py::Module pickle(PyImport_ImportModule("json"),true);
Py::Callable method(pickle.getAttr(std::string("loads")));
Py::Tuple args(1);
args.setItem(0, Py::String(repr));
Py::Object res = method.apply(args);
this->object = res;
if (this->object.hasAttr("__setstate__")) {
Py::Tuple args(1);
args.setItem(0, res);
Py::Callable state(this->object.getAttr("__setstate__"));
state.apply(args);
}
else {
this->object.setAttr("__dict__", res);
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@ -115,6 +135,32 @@ void PropertyPythonObject::fromString(const std::string& repr)
}
}
void PropertyPythonObject::loadPickle(const std::string& str)
{
// find the custom attributes and restore them
Base::PyGILStateLocker lock;
try {
std::string buffer = str;
boost::regex pickle("S'(\\w+)'.+S'(\\w+)'\\n");
boost::match_results<std::string::const_iterator> what;
std::string::const_iterator start, end;
start = buffer.begin();
end = buffer.end();
while (boost::regex_search(start, end, what, pickle)) {
std::string key = std::string(what[1].first, what[1].second);
std::string val = std::string(what[2].first, what[2].second);
this->object.setAttr(key, Py::String(val));
buffer = std::string(what[2].second, end);
start = buffer.begin();
end = buffer.end();
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::Console().Warning("PropertyPythonObject::loadPickle: %s\n", e.what());
}
}
std::string PropertyPythonObject::encodeValue(const std::string& str) const
{
std::string tmp;
@ -210,7 +256,25 @@ void PropertyPythonObject::Save (Base::Writer &writer) const
repr = Base::base64_encode((const unsigned char*)repr.c_str(), repr.size());
std::string val = /*encodeValue*/(repr);
writer.Stream() << writer.ind() << "<Python value=\"" << val
<<"\" encoded=\"yes\"";
<< "\" encoded=\"yes\"";
Base::PyGILStateLocker lock;
try {
if (this->object.hasAttr("__module__") && this->object.hasAttr("__class__")) {
Py::String mod(this->object.getAttr("__module__"));
Py::Object cls(this->object.getAttr("__class__"));
if (cls.hasAttr("__name__")) {
Py::String name(cls.getAttr("__name__"));
writer.Stream() << " module=\"" << (std::string)mod << "\""
<< " class=\"" << (std::string)name << "\"";
}
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::Console().Warning("PropertyPythonObject::Save: %s\n", e.what());
}
saveObject(writer);
writer.Stream() << "/>" << std::endl;
//}
@ -228,6 +292,8 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader)
reader.addFile(file.c_str(),this);
}
else {
bool load_json=false;
bool load_pickle=false;
std::string buffer = reader.getAttribute("value");
if (reader.hasAttribute("encoded") &&
strcmp(reader.getAttribute("encoded"),"yes") == 0) {
@ -237,8 +303,39 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader)
buffer = decodeValue(buffer);
}
Base::PyGILStateLocker lock;
try {
boost::regex pickle("^\\(i(\\w+)\\n(\\w+)\\n");
boost::match_results<std::string::const_iterator> what;
std::string::const_iterator start, end;
start = buffer.begin();
end = buffer.end();
if (reader.hasAttribute("module") && reader.hasAttribute("class")) {
Py::Module mod(PyImport_ImportModule(reader.getAttribute("module")),true);
this->object = PyInstance_NewRaw(mod.getAttr(reader.getAttribute("class")).ptr(), 0);
load_json = true;
}
else if (boost::regex_search(start, end, what, pickle)) {
std::string nam = std::string(what[1].first, what[1].second);
std::string cls = std::string(what[2].first, what[2].second);
Py::Module mod(PyImport_ImportModule(nam.c_str()),true);
this->object = PyInstance_NewRaw(mod.getAttr(cls).ptr(), 0);
load_pickle = true;
buffer = std::string(what[2].second, end);
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::Console().Warning("PropertyPythonObject::Restore: %s\n", e.what());
}
aboutToSetValue();
this->fromString(buffer);
if (load_json)
this->fromString(buffer);
else if (load_pickle)
this->loadPickle(buffer);
else
Base::Console().Warning("PropertyPythonObject::Restore: unsupported serialisation: %s\n", buffer.c_str());
restoreObject(reader);
hasSetValue();
}

View File

@ -77,6 +77,7 @@ private:
void restoreObject(Base::XMLReader &reader);
std::string encodeValue(const std::string& str) const;
std::string decodeValue(const std::string& str) const;
void loadPickle(const std::string& str);
Py::Object object;
};

View File

@ -202,6 +202,40 @@ AbnormalProgramTermination::AbnormalProgramTermination(const AbnormalProgramTerm
// ---------------------------------------------------------
UnknownProgramOption::UnknownProgramOption(const char * sMessage)
: Exception(sMessage)
{
}
UnknownProgramOption::UnknownProgramOption(const std::string& sMessage)
: Exception(sMessage)
{
}
UnknownProgramOption::UnknownProgramOption(const UnknownProgramOption &inst)
: Exception(inst)
{
}
// ---------------------------------------------------------
ProgramInformation::ProgramInformation(const char * sMessage)
: Exception(sMessage)
{
}
ProgramInformation::ProgramInformation(const std::string& sMessage)
: Exception(sMessage)
{
}
ProgramInformation::ProgramInformation(const ProgramInformation &inst)
: Exception(inst)
{
}
// ---------------------------------------------------------
#if defined(__GNUC__) && defined (FC_OS_LINUX)
#include <stdexcept>
#include <iostream>

View File

@ -174,6 +174,38 @@ public:
virtual ~AbnormalProgramTermination() throw() {}
};
/**
* The UnknownProgramOption can be used to indicate an unknown program option.
* @author Werner Mayer
*/
class BaseExport UnknownProgramOption : public Exception
{
public:
/// Construction
UnknownProgramOption(const char * sMessage);
UnknownProgramOption(const std::string& sMessage);
/// Construction
UnknownProgramOption(const UnknownProgramOption &inst);
/// Destruction
virtual ~UnknownProgramOption() throw() {}
};
/**
* The ProgramInformation can be used to show information about the program.
* @author Werner Mayer
*/
class BaseExport ProgramInformation : public Exception
{
public:
/// Construction
ProgramInformation(const char * sMessage);
ProgramInformation(const std::string& sMessage);
/// Construction
ProgramInformation(const ProgramInformation &inst);
/// Destruction
virtual ~ProgramInformation() throw() {}
};
inline void Exception::setMessage(const char * sMessage)
{

View File

@ -190,7 +190,6 @@ void InterpreterSingleton::runInteractiveString(const char *sCmd)
presult = PyRun_String(sCmd, Py_single_input, dict, dict); /* eval direct */
if (!presult) {
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
//systemExit();
throw SystemExitException();
}
/* get latest python exception information */

View File

@ -1545,8 +1545,16 @@ void Application::runApplication(void)
int argc = App::Application::GetARGC();
GUIApplication mainApp(argc, App::Application::GetARGV());
// set application icon and window title
const std::map<std::string,std::string>& cfg = App::Application::Config();
std::map<std::string,std::string>::const_iterator it;
it = cfg.find("Application");
if (it != cfg.end()) {
mainApp.setApplicationName(QString::fromUtf8(it->second.c_str()));
}
else {
mainApp.setApplicationName(QString::fromUtf8(App::GetApplication().getExecutableName()));
}
mainApp.setWindowIcon(Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str()));
mainApp.setApplicationName(QString::fromAscii(App::GetApplication().getExecutableName()));
QString plugin;
plugin = QString::fromUtf8(App::GetApplication().GetHomePath());
plugin += QLatin1String("/plugins");
@ -1606,8 +1614,6 @@ void Application::runApplication(void)
QString home = QString::fromUtf8(App::GetApplication().GetHomePath());
const std::map<std::string,std::string>& cfg = App::Application::Config();
std::map<std::string,std::string>::const_iterator it;
it = cfg.find("WindowTitle");
if (it != cfg.end()) {
QString title = QString::fromUtf8(it->second.c_str());

View File

@ -292,7 +292,7 @@ StdCmdMergeProjects::StdCmdMergeProjects()
void StdCmdMergeProjects::activated(int iMsg)
{
QString exe = QString::fromUtf8(App::GetApplication().getExecutableName());
QString exe = qApp->applicationName();
QString project = QFileDialog::getOpenFileName(Gui::getMainWindow(),
QString::fromUtf8(QT_TR_NOOP("Merge project")), QDir::homePath(),
QString::fromUtf8(QT_TR_NOOP("%1 document (*.fcstd)")).arg(exe));

View File

@ -193,13 +193,7 @@ Action * StdCmdAbout::createAction(void)
{
Action *pcAction;
QString exe;
std::map<std::string,std::string>& cfg = App::Application::Config();
std::map<std::string,std::string>::iterator it = cfg.find("Application");
if (it != cfg.end())
exe = QString::fromUtf8(it->second.c_str());
else
exe = QString::fromUtf8(App::GetApplication().getExecutableName());
QString exe = qApp->applicationName();
pcAction = new Action(this,getMainWindow());
pcAction->setText(QCoreApplication::translate(
this->className(), sMenuText, 0,
@ -235,13 +229,7 @@ void StdCmdAbout::activated(int iMsg)
void StdCmdAbout::languageChange()
{
if (_pcAction) {
QString exe;
std::map<std::string,std::string>& cfg = App::Application::Config();
std::map<std::string,std::string>::iterator it = cfg.find("Application");
if (it != cfg.end())
exe = QString::fromUtf8(it->second.c_str());
else
exe = QString::fromUtf8(App::GetApplication().getExecutableName());
QString exe = qApp->applicationName();
_pcAction->setText(QCoreApplication::translate(
this->className(), sMenuText, 0,
QCoreApplication::CodecForTr).arg(exe));

View File

@ -1,45 +1,62 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Gui::Dialog::DlgSettingsMacro</class>
<widget class="QWidget" name="Gui::Dialog::DlgSettingsMacro" >
<property name="geometry" >
<widget class="QWidget" name="Gui::Dialog::DlgSettingsMacro">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>384</width>
<height>388</height>
<width>391</width>
<height>407</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Macro</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="QGroupBox" name="GroupBox6" >
<property name="title" >
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>General macro settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="Gui::PrefCheckBox" name="PrefCheckBox_LocalEnv">
<property name="text">
<string>Run macros in local environment</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>LocalEnvironment</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Macro</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="GroupBox6">
<property name="title">
<string>Macro recording settings</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="margin">
<number>9</number>
</property>
<property name="spacing" >
<property name="spacing">
<number>6</number>
</property>
<item row="3" column="0" >
<item row="3" column="0">
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
@ -47,56 +64,56 @@
</property>
</spacer>
</item>
<item row="2" column="0" >
<widget class="QGroupBox" name="groupBox4" >
<property name="title" >
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox4">
<property name="title">
<string>Logging Commands</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>11</number>
</property>
<property name="spacing" >
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>11</number>
</property>
<item>
<widget class="Gui::PrefCheckBox" name="PConsoleCheckBox" >
<property name="text" >
<widget class="Gui::PrefCheckBox" name="PConsoleCheckBox">
<property name="text">
<string>Show script commands in python console</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0" >
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ScriptToPyConsole</cstring>
</property>
<property name="prefPath" stdset="0" >
<property name="prefPath" stdset="0">
<cstring>Macro</cstring>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="FileLogCheckBox" >
<property name="text" >
<widget class="Gui::PrefCheckBox" name="FileLogCheckBox">
<property name="text">
<string>Log all commands issued by menus to file:</string>
</property>
<property name="prefEntry" stdset="0" >
<property name="prefEntry" stdset="0">
<cstring>ScriptToFile</cstring>
</property>
<property name="prefPath" stdset="0" >
<property name="prefPath" stdset="0">
<cstring>Macro</cstring>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefFileChooser" name="MacroPath_2" >
<property name="fileName" >
<widget class="Gui::PrefFileChooser" name="MacroPath_2">
<property name="fileName">
<string>FullScript.FCScript</string>
</property>
<property name="prefEntry" stdset="0" >
<property name="prefEntry" stdset="0">
<cstring>ScriptFile</cstring>
</property>
<property name="prefPath" stdset="0" >
<property name="prefPath" stdset="0">
<cstring>Macro</cstring>
</property>
</widget>
@ -104,46 +121,46 @@
</layout>
</widget>
</item>
<item row="1" column="0" >
<widget class="QGroupBox" name="GroupBox7" >
<property name="title" >
<item row="1" column="0">
<widget class="QGroupBox" name="GroupBox7">
<property name="title">
<string>Gui commands</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="margin">
<number>11</number>
</property>
<property name="spacing" >
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="Gui::PrefCheckBox" name="PrefCheckBox_RecordGui" >
<property name="text" >
<item row="0" column="0">
<widget class="Gui::PrefCheckBox" name="PrefCheckBox_RecordGui">
<property name="text">
<string>Recording GUI commands</string>
</property>
<property name="checked" >
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0" >
<property name="prefEntry" stdset="0">
<cstring>RecordGui</cstring>
</property>
<property name="prefPath" stdset="0" >
<property name="prefPath" stdset="0">
<cstring>Macro</cstring>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="Gui::PrefCheckBox" name="PrefCheckBox_GuiAsComment" >
<property name="text" >
<item row="1" column="0">
<widget class="Gui::PrefCheckBox" name="PrefCheckBox_GuiAsComment">
<property name="text">
<string>Record as comment</string>
</property>
<property name="checked" >
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0" >
<property name="prefEntry" stdset="0">
<cstring>GuiAsComment</cstring>
</property>
<property name="prefPath" stdset="0" >
<property name="prefPath" stdset="0">
<cstring>Macro</cstring>
</property>
</widget>
@ -151,27 +168,27 @@
</layout>
</widget>
</item>
<item row="0" column="0" >
<widget class="QGroupBox" name="GroupBox8" >
<property name="title" >
<item row="0" column="0">
<widget class="QGroupBox" name="GroupBox8">
<property name="title">
<string>Macro path</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="margin">
<number>11</number>
</property>
<property name="spacing" >
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="Gui::PrefFileChooser" name="MacroPath" >
<property name="mode" >
<item row="0" column="0">
<widget class="Gui::PrefFileChooser" name="MacroPath">
<property name="mode">
<enum>Gui::FileChooser::Directory</enum>
</property>
<property name="prefEntry" stdset="0" >
<property name="prefEntry" stdset="0">
<cstring>MacroPath</cstring>
</property>
<property name="prefPath" stdset="0" >
<property name="prefPath" stdset="0">
<cstring>Macro</cstring>
</property>
</widget>
@ -184,21 +201,22 @@
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11" />
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
<container>0</container>
<pixmap></pixmap>
<class>Gui::FileChooser</class>
<extends>QWidget</extends>
<header>Gui/FileDialog.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefFileChooser</class>
<extends>Gui::FileChooser</extends>
<header>Gui/PrefWidgets.h</header>
<container>0</container>
<pixmap></pixmap>
</customwidget>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
@ -209,11 +227,11 @@
<receiver>PrefCheckBox_GuiAsComment</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>

View File

@ -54,6 +54,7 @@ DlgSettingsMacroImp::~DlgSettingsMacroImp()
void DlgSettingsMacroImp::saveSettings()
{
PrefCheckBox_LocalEnv->onSave();
MacroPath->onSave();
PrefCheckBox_RecordGui->onSave();
PrefCheckBox_GuiAsComment->onSave();
@ -64,6 +65,7 @@ void DlgSettingsMacroImp::saveSettings()
void DlgSettingsMacroImp::loadSettings()
{
PrefCheckBox_LocalEnv->onRestore();
MacroPath->onRestore();
PrefCheckBox_RecordGui->onRestore();
PrefCheckBox_GuiAsComment->onRestore();

View File

@ -504,7 +504,7 @@ bool Document::saveAs(void)
{
getMainWindow()->statusBar()->showMessage(QObject::tr("Save document under new filename..."));
QString exe = QString::fromUtf8(App::GetApplication().getExecutableName());
QString exe = qApp->applicationName();
QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe),
FileDialog::getWorkingDirectory(), QObject::tr("%1 document (*.FCStd)").arg(exe));
if (!fn.isEmpty()) {

View File

@ -15,8 +15,8 @@
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
* Fifth Floor, Boston, MA 02110-1301, USA *
* *
***************************************************************************/

View File

@ -26,6 +26,7 @@
#ifndef _PreComp_
# include <assert.h>
# include <stdio.h>
# include <QApplication>
# include <QFile>
# include <QTextStream>
#endif
@ -71,6 +72,7 @@ void MacroManager::OnChange(Base::Subject<const char*> &rCaller, const char * sR
this->recordGui = this->params->GetBool("RecordGui", true);
this->guiAsComment = this->params->GetBool("GuiAsComment", true);
this->scriptToPyConsole = this->params->GetBool("ScriptToPyConsole", true);
this->localEnv = this->params->GetBool("LocalEnvironment", true);
}
void MacroManager::open(MacroType eType,const char *sName)
@ -228,12 +230,10 @@ void MacroManager::run(MacroType eType,const char *sName)
PythonRedirector std_out("stdout",pyout);
PythonRedirector std_err("stderr",pyerr);
//The given path name is expected to be Utf-8
Base::Interpreter().runFile(sName, true);
Base::Interpreter().runFile(sName, this->localEnv);
}
catch (const Base::SystemExitException&) {
Base::PyGILStateLocker lock;
PyErr_Clear();
Base::Interpreter().systemExit();
qApp->quit();
}
catch (const Base::PyException& e) {
Base::Console().Error("%s%s: %s\n",

View File

@ -98,6 +98,7 @@ protected:
bool recordGui;
bool guiAsComment;
bool scriptToPyConsole;
bool localEnv;
PythonConsole* pyConsole; // link to the python console
PythonDebugger* pyDebugger;
Base::Reference<ParameterGrp> params; // link to the Macro parameter group

View File

@ -52,6 +52,7 @@
#include <Base/Parameter.h>
#include <Base/Exception.h>
#include <Base/FileInfo.h>
#include <Base/Interpreter.h>
#include <Base/Persistence.h>
#include <Base/Stream.h>
#include <Base/Reader.h>
@ -1152,7 +1153,13 @@ void MainWindow::showMainWindow()
void MainWindow::delayedStartup()
{
// processing all command line files
App::Application::processCmdLineFiles();
try {
App::Application::processCmdLineFiles();
}
catch (const Base::SystemExitException&) {
QApplication::quit();
return;
}
const std::map<std::string,std::string>& cfg = App::Application::Config();
std::map<std::string,std::string>::const_iterator it = cfg.find("StartHidden");
@ -1318,10 +1325,7 @@ QPixmap MainWindow::splashImage() const
// include application name and version number
std::map<std::string,std::string>::const_iterator tc = App::Application::Config().find("SplashInfoColor");
if (tc != App::Application::Config().end()) {
QString title = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
std::map<std::string,std::string>::iterator it = App::Application::Config().find("Application");
if (it != App::Application::Config().end())
title = QString::fromUtf8(it->second.c_str());
QString title = qApp->applicationName();
QString major = QString::fromAscii(App::Application::Config()["BuildVersionMajor"].c_str());
QString minor = QString::fromAscii(App::Application::Config()["BuildVersionMinor"].c_str());
QString version = QString::fromAscii("%1.%2").arg(major).arg(minor);

View File

@ -1118,11 +1118,13 @@ SbBool NavigationStyle::processEvent(const SoEvent * const ev)
pcPolygon = mouseSelection->getPositions();
clipInner = mouseSelection->isInner();
delete mouseSelection; mouseSelection = 0;
syncWithEvent(ev);
return NavigationStyle::processSoEvent(ev);
}
else if (hd==AbstractMouseSelection::Cancel) {
pcPolygon.clear();
delete mouseSelection; mouseSelection = 0;
syncWithEvent(ev);
return NavigationStyle::processSoEvent(ev);
}
}
@ -1150,6 +1152,72 @@ SbBool NavigationStyle::processSoEvent(const SoEvent * const ev)
return viewer->processSoEventBase(ev);
}
void NavigationStyle::syncWithEvent(const SoEvent * const ev)
{
// Events when in "ready-to-seek" mode are ignored, except those
// which influence the seek mode itself -- these are handled further
// up the inheritance hierarchy.
if (this->isSeekMode()) { return; }
const SoType type(ev->getTypeId());
// Mismatches in state of the modifier keys happens if the user
// presses or releases them outside the viewer window.
if (this->ctrldown != ev->wasCtrlDown()) {
this->ctrldown = ev->wasCtrlDown();
}
if (this->shiftdown != ev->wasShiftDown()) {
this->shiftdown = ev->wasShiftDown();
}
if (this->altdown != ev->wasAltDown()) {
this->altdown = ev->wasAltDown();
}
// Keyboard handling
if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
switch (event->getKey()) {
case SoKeyboardEvent::LEFT_CONTROL:
case SoKeyboardEvent::RIGHT_CONTROL:
this->ctrldown = press;
break;
case SoKeyboardEvent::LEFT_SHIFT:
case SoKeyboardEvent::RIGHT_SHIFT:
this->shiftdown = press;
break;
case SoKeyboardEvent::LEFT_ALT:
case SoKeyboardEvent::RIGHT_ALT:
this->altdown = press;
break;
default:
break;
}
}
// Mouse Button / Spaceball Button handling
if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
const int button = event->getButton();
const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
// SoDebugError::postInfo("processSoEvent", "button = %d", button);
switch (button) {
case SoMouseButtonEvent::BUTTON1:
this->button1down = press;
break;
case SoMouseButtonEvent::BUTTON2:
this->button2down = press;
break;
case SoMouseButtonEvent::BUTTON3:
this->button3down = press;
break;
default:
break;
}
}
}
SbBool NavigationStyle::processMotionEvent(const SoMotion3Event * const ev)
{
SoCamera * const camera = viewer->getCamera();

View File

@ -175,6 +175,7 @@ protected:
SbBool handleEventInForeground(const SoEvent* const e);
virtual SbBool processSoEvent(const SoEvent * const ev);
void syncWithEvent(const SoEvent * const ev);
virtual void openPopupMenu(const SbVec2s& position);
void clearLog(void);

View File

@ -23,6 +23,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QApplication>
# include <QClipboard>
# include <QDockWidget>
# include <QGridLayout>
@ -700,12 +701,13 @@ void PythonConsole::runSource(const QString& line)
catch (const Base::SystemExitException&) {
ParameterGrp::handle hPrefGrp = getWindowParameter();
bool check = hPrefGrp->GetBool("CheckSystemExit",true);
if (!check) Base::Interpreter().systemExit();
if (!check) qApp->quit();
int ret = QMessageBox::question(this, tr("System exit"), tr("The application is still running.\nDo you want to exit without saving your data?"),
QMessageBox::Yes, QMessageBox::No|QMessageBox::Escape|QMessageBox::Default);
if (ret == QMessageBox::Yes) {
Base::Interpreter().systemExit();
} else {
qApp->quit();
}
else {
PyErr_Clear();
}
}

View File

@ -88,23 +88,31 @@ public:
textColor = col;
}
}
virtual ~SplashObserver()
{
Base::Console().DetachObserver(this);
}
const char* Name()
{
return "SplashObserver";
}
void Warning(const char * s)
{
#ifdef FC_DEBUG
Log(s);
#endif
}
void Message(const char * s)
{
#ifdef FC_DEBUG
Log(s);
#endif
}
void Error (const char * s)
{
#ifdef FC_DEBUG
Log(s);
#endif
}
void Log (const char * s)
{
@ -267,11 +275,9 @@ static QString getPlatform()
void AboutDialog::setupLabels()
{
QString exeName = qApp->applicationName();
std::map<std::string, std::string>& config = App::Application::Config();
QString exeName = QString::fromAscii(config["ExeName"].c_str());
std::map<std::string,std::string>::iterator it = config.find("WindowTitle");
if (it != config.end())
exeName = QString::fromUtf8(it->second.c_str());
std::map<std::string,std::string>::iterator it;
QString banner = QString::fromUtf8(config["CopyrightInfo"].c_str());
banner = banner.left( banner.indexOf(QLatin1Char('\n')) );
QString major = QString::fromAscii(config["BuildVersionMajor"].c_str());

View File

@ -24,6 +24,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QApplication>
# include <QBuffer>
# include <QByteArray>
# include <QDateTime>
@ -97,7 +98,7 @@ void Thumbnail::SaveDocFile (Base::Writer &writer) const
// according to specification add some meta-information to the image
uint mt = QDateTime::currentDateTime().toTime_t();
QString mtime = QString::fromAscii("%1").arg(mt);
img.setText(QLatin1String("Software"), QString::fromUtf8(App::GetApplication().getExecutableName()));
img.setText(QLatin1String("Software"), qApp->applicationName());
img.setText(QLatin1String("Thumb::Mimetype"), QLatin1String("application/x-extension-fcstd"));
img.setText(QLatin1String("Thumb::MTime"), mtime);
img.setText(QLatin1String("Thumb::URI"), this->uri.toString());

View File

@ -311,7 +311,7 @@ void LightManip(SoSeparator * root)
in.setBuffer((void *)scenegraph, std::strlen(scenegraph));
SoSeparator * _root = SoDB::readAll( &in );
root->addChild(_root);
if ( root == NULL ) exit( 1 ); // Shouldn't happen.
if ( root == NULL ) return; // Shouldn't happen.
root->ref();
const char * pointlightnames[3] = { "RedLight", "GreenLight", "BlueLight" };
@ -323,7 +323,7 @@ void LightManip(SoSeparator * root)
sa.setSearchingAll( FALSE );
sa.apply( root );
SoPath * path = sa.getPath();
if ( path == NULL) exit( 1 ); // Shouldn't happen.
if ( path == NULL) return; // Shouldn't happen.
SoPointLightManip * manip = new SoPointLightManip;
manip->replaceNode( path );
@ -446,7 +446,7 @@ void AnimationTexture(SoSeparator * root)
texturetimer->schedule();
// Scene graph
if ( root == NULL ) exit( 1 ); // Shouldn't happen.
if ( root == NULL ) return; // Shouldn't happen.
root->ref(); // prevent from being deleted because of the still running timer sensor
// SoSeparator * root = new SoSeparator;
// root->ref();

View File

@ -37,6 +37,7 @@
#include <stdio.h>
#include <sstream>
#include <iostream>
// FreeCAD Base header
#include <Base/Console.h>
@ -89,6 +90,14 @@ int main( int argc, char ** argv )
// Inits the Application
App::Application::init(argc,argv);
}
catch (const Base::UnknownProgramOption& e) {
std::cerr << e.what();
exit(1);
}
catch (const Base::ProgramInformation& e) {
std::cout << e.what();
exit(0);
}
catch (const Base::Exception& e) {
std::string appName = App::Application::Config()["ExeName"];
std::stringstream msg;

View File

@ -161,83 +161,6 @@ private:
QDomDocument domDocument;
};
class ProgramOptions
{
public:
ProgramOptions()
{
newcout = new ProgramOptionsStream(out);
oldcout = std::cout.rdbuf(newcout);
out.reserve(80);
newcerr = new ProgramOptionsStream(err);
oldcerr = std::cerr.rdbuf(newcerr);
err.reserve(80);
error = true;
::atexit(ProgramOptions::failure);
}
~ProgramOptions()
{
std::cout.rdbuf(oldcout);
delete newcout;
std::cerr.rdbuf(oldcerr);
delete newcerr;
error = false;
}
static void failure()
{
if (error) {
int argc=0;
QApplication app(argc,0);
QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
if (!err.empty()) {
QString msg = QString::fromAscii(err.c_str());
QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");
QMessageBox::critical(0, appName, s);
}
else if (!out.empty()) {
QString msg = QString::fromAscii(out.c_str());
QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");
QMessageBox::information(0, appName, s);
}
}
}
private:
class ProgramOptionsStream : public std::streambuf
{
public:
ProgramOptionsStream(std::string& s) : buf(s)
{
}
int overflow(int c = EOF)
{
if (c != EOF)
buf.push_back((char)c);
return c;
}
int sync()
{
return 0;
}
private:
std::string& buf;
};
private:
friend class ProgramOptionsStream;
std::streambuf* oldcout;
std::streambuf* newcout;
std::streambuf* oldcerr;
std::streambuf* newcerr;
static std::string out, err;
static bool error;
};
bool ProgramOptions::error = false;
std::string ProgramOptions::out;
std::string ProgramOptions::err;
#if defined (FC_OS_LINUX) || defined(FC_OS_BSD)
QString myDecoderFunc(const QByteArray &localFileName)
{
@ -300,10 +223,25 @@ int main( int argc, char ** argv )
App::Application::Config()["RunMode"] = "Gui";
// Inits the Application
ProgramOptions po;
App::Application::init(argc,argv);
Gui::Application::initApplication();
}
catch (const Base::UnknownProgramOption& e) {
QApplication app(argc,argv);
QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
QString msg = QString::fromAscii(e.what());
QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");
QMessageBox::critical(0, appName, s);
exit(1);
}
catch (const Base::ProgramInformation& e) {
QApplication app(argc,argv);
QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
QString msg = QString::fromAscii(e.what());
QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");
QMessageBox::information(0, appName, s);
exit(0);
}
catch (const Base::Exception& e) {
// Popup an own dialog box instead of that one of Windows
QApplication app(argc,argv);

View File

@ -154,31 +154,36 @@ def splitMesh(obj,mark=True):
def makeFace(wires,method=2,cleanup=False):
'''makeFace(wires): makes a face from a list of wires, finding which ones are holes'''
#print "makeFace: start:", wires
import Part
if not isinstance(wires,list):
if len(wires.Vertexes) < 3:
raise
return Part.Face(wires)
elif len(wires) == 1:
#import Draft;Draft.printShape(wires[0])
if len(wires[0].Vertexes) < 3:
raise
return Part.Face(wires[0])
wires = wires[:]
print "inner wires found"
#print "makeFace: inner wires found"
ext = None
max_length = 0
# cleaning up rubbish in wires
if cleanup:
for i in range(len(wires)):
wires[i] = DraftGeomUtils.removeInterVertices(wires[i])
print "garbage removed"
#print "makeFace: garbage removed"
for w in wires:
# we assume that the exterior boundary is that one with
# the biggest bounding box
if w.BoundBox.DiagonalLength > max_length:
max_length = w.BoundBox.DiagonalLength
ext = w
print "exterior wire",ext
#print "makeFace: exterior wire",ext
wires.remove(ext)
if method == 1:
@ -186,23 +191,22 @@ def makeFace(wires,method=2,cleanup=False):
# all interior wires mark a hole and must reverse
# their orientation, otherwise Part.Face fails
for w in wires:
print "reversing",w
#print "makeFace: reversing",w
w.reverse()
print "reversed"
# make sure that the exterior wires comes as first in the list
wires.insert(0, ext)
print "done sorting", wires
#print "makeFace: done sorting", wires
if wires:
return Part.Face(wires)
else:
# method 2: use the cut method
mf = Part.Face(ext)
print "external face:",mf
#print "makeFace: external face:",mf
for w in wires:
f = Part.Face(w)
print "internal face:",f
#print "makeFace: internal face:",f
mf = mf.cut(f)
print "final face:",mf.Faces
#print "makeFace: final face:",mf.Faces
return mf.Faces[0]
def meshToShape(obj,mark=True):

View File

@ -62,7 +62,8 @@ def addToComponent(compobject,addobject,mod=None):
l = getattr(compobject,mod)
l.append(addobject)
setattr(compobject,mod,l)
addobject.ViewObject.hide()
if mod != "Objects":
addobject.ViewObject.hide()
else:
for a in attribs[:3]:
if hasattr(compobject,a):

View File

@ -21,7 +21,7 @@
#* *
#***************************************************************************
import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,math,Draft,ArchCommands, DraftVecUtils
import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,math,Draft,ArchCommands,DraftVecUtils
from FreeCAD import Vector
from PyQt4 import QtCore
from pivy import coin
@ -215,7 +215,7 @@ class _ArchDrawingView:
import ArchVRM
render = ArchVRM.Renderer()
render.setWorkingPlane(obj.Source.Placement)
render.addObjects(objs)
render.addObjects(Draft.getGroupContents(objs,walls=True))
render.cut(obj.Source.Shape)
svg += render.getViewSVG(linewidth=linewidth)
svg += render.getSectionSVG(linewidth=linewidth*2)

View File

@ -145,12 +145,14 @@ class Renderer:
def reorient(self):
"reorients the faces on the WP"
#print "VRM: start reorient"
if not self.faces:
return
self.faces = [self.projectFace(f) for f in self.faces]
if self.sections:
self.sections = [self.projectFace(f) for f in self.sections]
self.oriented = True
#print "VRM: end reorient"
def removeHidden(self):
"removes faces pointing outwards"
@ -166,17 +168,24 @@ class Renderer:
def projectFace(self,face):
"projects a single face on the WP"
#print "VRM: projectFace start: ",len(face[0].Vertexes)," verts, ",len(face[0].Edges)," edges"
wires = []
if not face[0].Wires:
if DEBUG: print "Error: Unable to project face on the WP"
return None
norm = face[0].normalAt(0,0)
for w in face[0].Wires:
verts = []
edges = DraftGeomUtils.sortEdges(w.Edges)
#print len(edges)," edges after sorting"
for e in edges:
v = e.Vertexes[0].Point
#print v
v = self.wp.getLocalCoords(v)
verts.append(v)
verts.append(verts[0])
if len(verts) > 2:
#print "new wire with ",len(verts)
wires.append(Part.makePolygon(verts))
try:
sh = ArchCommands.makeFace(wires)
@ -188,6 +197,7 @@ class Renderer:
vnorm = self.wp.getLocalCoords(norm)
if vnorm.getAngle(sh.normalAt(0,0)) > 1:
sh.reverse()
#print "VRM: projectFace end: ",len(sh.Vertexes)," verts"
return [sh]+face[1:]
def flattenFace(self,face):
@ -211,6 +221,7 @@ class Renderer:
def cut(self,cutplane):
"Cuts through the shapes with a given cut plane and builds section faces"
if DEBUG: print "\n\n======> Starting cut\n\n"
if self.iscut:
return
if not self.shapes:
@ -262,12 +273,10 @@ class Renderer:
shapes.append([c]+sh[1:])
for f in c.Faces:
faces.append([f]+sh[1:])
sec = sol.section(cutface)
if sec.Edges:
wires = DraftGeomUtils.findWires(sec.Edges)
for w in wires:
sec = Part.Face(w)
sections.append([sec,fill])
print "iscoplanar:",f.Vertexes[0].Point,f.normalAt(0,0),cutface.Vertexes[0].Point,cutface.normalAt(0,0)
if DraftGeomUtils.isCoplanar([f,cutface]):
print "COPLANAR"
sections.append([f,fill])
self.shapes = shapes
self.faces = faces
self.sections = sections
@ -277,6 +286,7 @@ class Renderer:
self.trimmed = False
self.sorted = False
self.joined = False
if DEBUG: print "\n\n======> Finished cut\n\n"
def isInside(self,vert,face):
"Returns True if the vert is inside the face in Z projection"
@ -319,6 +329,15 @@ class Renderer:
def compare(self,face1,face2):
"zsorts two faces. Returns 1 if face1 is closer, 2 if face2 is closer, 0 otherwise"
#print face1,face2
if not face1:
if DEBUG: print "Warning, undefined face!"
return 31
elif not face2:
if DEBUG: print "Warning, undefined face!"
return 32
# theory from
# http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm
# and practical application http://vrm.ao2.it/ (blender vector renderer)
@ -456,14 +475,17 @@ class Renderer:
def sort(self):
"projects a shape on the WP"
if DEBUG: print "\n\n======> Starting sort\n\n"
if len(self.faces) <= 1:
return
if not self.trimmed:
self.removeHidden()
if DEBUG: print "Done hidden face removal"
if len(self.faces) == 1:
return
if not self.oriented:
self.reorient()
if DEBUG: print "Done reorientation"
faces = self.faces[:]
if DEBUG: print "sorting ",len(self.faces)," faces"
sfaces = []
@ -492,6 +514,7 @@ class Renderer:
for f2 in faces[1:]:
if DEBUG: print "comparing face",str(self.faces.index(f1))," with face",str(self.faces.index(f2))
r = self.compare(f1,f2)
print "comparison result:",r
if r == 1:
faces.remove(f2)
sfaces.append(f2)
@ -506,6 +529,10 @@ class Renderer:
sfaces.append(f2)
notfoundstack = 0
break
elif r == 31:
faces.remove(f1)
elif r == 32:
faces.remove(f2)
else:
# nothing found, move the face to the end of the pile
faces.remove(f1)
@ -518,6 +545,7 @@ class Renderer:
if DEBUG: print "done Z sorting. ", len(sfaces), " faces retained, ", len(self.faces)-len(sfaces), " faces lost."
self.faces = sfaces
self.sorted = True
if DEBUG: print "\n\n======> Finished sort\n\n"
def buildDummy(self):
"Builds a dummy object with faces spaced on the Z axis, for visual check"
@ -544,19 +572,21 @@ class Renderer:
def getPathData(self,w):
"Returns a SVG path data string from a 2D wire"
def tostr(val):
return str(round(val,DraftVecUtils.precision()))
edges = DraftGeomUtils.sortEdges(w.Edges)
v = edges[0].Vertexes[0].Point
svg = 'M '+ str(v.x) +' '+ str(v.y) + ' '
svg = 'M '+ tostr(v.x) +' '+ tostr(v.y) + ' '
for e in edges:
if isinstance(e.Curve,Part.Line) or isinstance(e.Curve,Part.BSplineCurve):
v = e.Vertexes[-1].Point
svg += 'L '+ str(v.x) +' '+ str(v.y) + ' '
svg += 'L '+ tostr(v.x) +' '+ tostr(v.y) + ' '
elif isinstance(e.Curve,Part.Circle):
r = e.Curve.Radius
v = e.Vertexes[-1].Point
svg += 'A '+ str(r) + ' '+ str(r) +' 0 0 1 '+ str(v.x) +' '
svg += str(v.y) + ' '
svg += 'z '
svg += 'A '+ tostr(r) + ' '+ tostr(r) +' 0 0 1 '+ tostr(v.x) +' '
svg += tostr(v.y) + ' '
svg += 'Z '
return svg
def getViewSVG(self,linewidth=0.01):
@ -566,44 +596,47 @@ class Renderer:
self.sort()
svg = ''
for f in self.faces:
fill = self.getFill(f[1])
svg +='<path '
svg += 'd="'
for w in f[0].Wires:
svg += self.getPathData(w)
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;'
svg += 'fill:' + fill + ';'
svg += 'fill-rule: evenodd'
svg += '"/>\n'
if f:
fill = self.getFill(f[1])
svg +='<path '
svg += 'd="'
for w in f[0].Wires:
svg += self.getPathData(w)
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;'
svg += 'fill:' + fill + ';'
svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg
def getSectionSVG(self,linewidth=0.02):
"Returns a SVG fragment from cut faces"
if DEBUG: print "Printing ", len(self.sections), " cutfaces"
if DEBUG: print "Printing ", len(self.sections), " sections"
if not self.oriented:
self.reorient()
svg = ''
for f in self.sections:
fill = self.getFill(f[1])
svg +='<path '
svg += 'd="'
for w in f[0].Wires:
svg += self.getPathData(w)
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;'
svg += 'fill:' + fill + ';'
svg += 'fill-rule: evenodd'
svg += '"/>\n'
if f:
fill = self.getFill(f[1])
svg +='<path '
svg += 'd="'
for w in f[0].Wires:
#print "wire with ",len(w.Vertexes)," verts"
svg += self.getPathData(w)
svg += '" '
svg += 'stroke="#000000" '
svg += 'stroke-width="' + str(linewidth) + '" '
svg += 'style="stroke-width:' + str(linewidth) + ';'
svg += 'stroke-miterlimit:1;'
svg += 'stroke-linejoin:round;'
svg += 'stroke-dasharray:none;'
svg += 'fill:' + fill + ';'
svg += 'fill-rule: evenodd'
svg += '"/>\n'
return svg

View File

@ -72,7 +72,7 @@ How it works / how to extend:
'''
# import FreeCAD modules
import FreeCAD, math, sys, os, DraftVecUtils
import FreeCAD, math, sys, os, DraftVecUtils, Draft_rc
from FreeCAD import Vector
from pivy import coin
@ -253,17 +253,43 @@ def shapify(obj):
FreeCAD.ActiveDocument.recompute()
return newobj
def getGroupContents(objectslist):
def getGroupContents(objectslist,walls=False):
'''getGroupContents(objectlist): if any object of the given list
is a group, its content is appened to the list, which is returned'''
newlist = []
for obj in objectslist:
if obj.Type == "App::DocumentObjectGroup":
if obj.isDerivedFrom("App::DocumentObjectGroup"):
newlist.extend(getGroupContents(obj.Group))
else:
newlist.append(obj)
if walls:
if getType(obj) == "Wall":
for o in obj.OutList:
if (getType(o) == "Window") or isClone(o,"Window"):
newlist.append(o)
return newlist
def printShape(shape):
"""prints detailed information of a shape"""
print "solids: ", len(shape.Solids)
print "faces: ", len(shape.Faces)
print "wires: ", len(shape.Wires)
print "edges: ", len(shape.Edges)
print "verts: ", len(shape.Vertexes)
if shape.Faces:
for f in range(len(shape.Faces)):
print "face ",f,":"
for v in shape.Faces[f].Vertexes:
print " ",v.Point
elif shape.Wires:
for w in range(len(shape.Wires)):
print "wire ",w,":"
for v in shape.Wires[w].Vertexes:
print " ",v.Point
else:
for v in shape.Vertexes:
print " ",v.Point
def formatObject(target,origin=None):
'''
formatObject(targetObject,[originObject]): This function applies
@ -1514,7 +1540,7 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"):
ok = False
tp = getType(obj)
if tp == "BSpline":
pass
print "makeSketch: BSplines not supported"
elif tp == "Circle":
if obj.FirstAngle == obj.LastAngle:
nobj.addGeometry(obj.Shape.Edges[0].Curve)
@ -1560,32 +1586,16 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"):
nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint))
ok = True
if (not ok) and obj.isDerivedFrom("Part::Feature"):
if DraftGeomUtils.hasOnlyWires(obj.Shape):
for w in obj.Shape.Wires:
for edge in DraftGeomUtils.sortEdges(w.Edges):
g = DraftGeomUtils.geom(edge)
if g:
nobj.addGeometry(g)
if autoconstraints:
last = nobj.GeometryCount
segs = range(last-len(w.Edges),last-1)
for seg in segs:
nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint))
if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"):
nobj.addConstraint(Constraint("Vertical",seg))
elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"):
nobj.addConstraint(Constraint("Horizontal",seg))
if w.isClosed:
nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint))
else:
for edge in obj.Shape.Edges:
nobj.addGeometry(DraftGeomUtils.geom(edge))
if autoconstraints:
last = nobj.GeometryCount - 1
if DraftGeomUtils.isAligned(nobj.Geometry[last],"x"):
nobj.addConstraint(Constraint("Vertical",last))
elif DraftGeomUtils.isAligned(nobj.Geometry[last],"y"):
nobj.addConstraint(Constraint("Horizontal",last))
if not DraftGeomUtils.isPlanar(obj.Shape):
print "Error: The given object is not planar and cannot be converted into a sketch."
return None
if not addTo:
nobj.Placement.Rotation = DraftGeomUtils.calculatePlacement(obj.Shape).Rotation
edges = []
for e in obj.Shape.Edges:
g = (DraftGeomUtils.geom(e,nobj.Placement))
if g:
nobj.addGeometry(g)
ok = True
if ok:
FreeCAD.ActiveDocument.removeObject(obj.Name)
@ -1945,7 +1955,7 @@ class _ViewProviderDimension:
[p2.x,p2.y,p2.z],
[p3.x,p3.y,p3.z],
[p4.x,p4.y,p4.z]])
self.line.numVertices.setValues([4])
self.line.numVertices.setValue(4)
else:
ts = (len(text)*obj.ViewObject.FontSize)/4
rm = ((p3.sub(p2)).Length/2)-ts
@ -2714,29 +2724,35 @@ class _Array:
obj.addProperty("App::PropertyEnumeration","ArrayType","Base",
"The type of array to create")
obj.addProperty("App::PropertyVector","Axis","Base",
"The axis direction for polar arrays")
"The axis direction")
obj.addProperty("App::PropertyInteger","NumberX","Base",
"Number of copies in X direction (ortho arrays)")
"Number of copies in X direction")
obj.addProperty("App::PropertyInteger","NumberY","Base",
"Number of copies in Y direction (ortho arrays)")
"Number of copies in Y direction")
obj.addProperty("App::PropertyInteger","NumberZ","Base",
"Number of copies in Z direction")
obj.addProperty("App::PropertyInteger","NumberPolar","Base",
"Number of copies (polar arrays)")
"Number of copies")
obj.addProperty("App::PropertyVector","IntervalX","Base",
"Distance and orientation of intervals in X direction (ortho arrays)")
"Distance and orientation of intervals in X direction")
obj.addProperty("App::PropertyVector","IntervalY","Base",
"Distance and orientation of intervals in Y direction (ortho arrays)")
"Distance and orientation of intervals in Y direction")
obj.addProperty("App::PropertyVector","IntervalZ","Base",
"Distance and orientation of intervals in Z direction")
obj.addProperty("App::PropertyVector","Center","Base",
"Center point (polar arrays)")
"Center point")
obj.addProperty("App::PropertyAngle","Angle","Base",
"Angle to cover with copies (polar arrays)")
"Angle to cover with copies")
obj.Proxy = self
self.Type = "Array"
obj.ArrayType = ['ortho','polar']
obj.NumberX = 1
obj.NumberY = 1
obj.NumberZ = 1
obj.NumberPolar = 1
obj.IntervalX = Vector(1,0,0)
obj.IntervalY = Vector(0,1,0)
obj.IntervalZ = Vector(0,0,1)
obj.Angle = 360
obj.Axis = Vector(0,0,1)
@ -2744,7 +2760,32 @@ class _Array:
self.createGeometry(obj)
def onChanged(self,obj,prop):
if prop in ["ArrayType","NumberX","NumberY","NumberPolar","IntervalX","IntervalY","Angle","Center","Axis"]:
if prop == "ArrayType":
if obj.ViewObject:
if obj.ArrayType == "ortho":
obj.ViewObject.setEditorMode('Axis',2)
obj.ViewObject.setEditorMode('NumberPolar',2)
obj.ViewObject.setEditorMode('Center',2)
obj.ViewObject.setEditorMode('Angle',2)
obj.ViewObject.setEditorMode('NumberX',0)
obj.ViewObject.setEditorMode('NumberY',0)
obj.ViewObject.setEditorMode('NumberZ',0)
obj.ViewObject.setEditorMode('IntervalX',0)
obj.ViewObject.setEditorMode('IntervalY',0)
obj.ViewObject.setEditorMode('IntervalZ',0)
else:
obj.ViewObject.setEditorMode('Axis',0)
obj.ViewObject.setEditorMode('NumberPolar',0)
obj.ViewObject.setEditorMode('Center',0)
obj.ViewObject.setEditorMode('Angle',0)
obj.ViewObject.setEditorMode('NumberX',2)
obj.ViewObject.setEditorMode('NumberY',2)
obj.ViewObject.setEditorMode('NumberY',2)
obj.ViewObject.setEditorMode('IntervalX',2)
obj.ViewObject.setEditorMode('IntervalY',2)
obj.ViewObject.setEditorMode('IntervalZ',2)
if prop in ["ArrayType","NumberX","NumberY","NumberZ","NumberPolar",
"IntervalX","IntervalY","IntervalZ","Angle","Center","Axis"]:
self.createGeometry(obj)
def createGeometry(self,obj):
@ -2752,14 +2793,15 @@ class _Array:
if obj.Base:
pl = obj.Placement
if obj.ArrayType == "ortho":
sh = self.rectArray(obj.Base.Shape,obj.IntervalX,obj.IntervalY,obj.NumberX,obj.NumberY)
sh = self.rectArray(obj.Base.Shape,obj.IntervalX,obj.IntervalY,
obj.IntervalZ,obj.NumberX,obj.NumberY,obj.NumberZ)
else:
sh = self.polarArray(obj.Base.Shape,obj.Center,obj.Angle,obj.NumberPolar,obj.Axis)
obj.Shape = sh
if not DraftGeomUtils.isNull(pl):
obj.Placement = pl
def rectArray(self,shape,xvector,yvector,xnum,ynum):
def rectArray(self,shape,xvector,yvector,zvector,xnum,ynum,znum):
import Part
base = [shape.copy()]
for xcount in range(xnum):
@ -2769,12 +2811,19 @@ class _Array:
nshape.translate(currentxvector)
base.append(nshape)
for ycount in range(ynum):
currentxvector=FreeCAD.Vector(currentxvector)
currentyvector=currentxvector.add(DraftVecUtils.scale(yvector,ycount))
currentyvector=FreeCAD.Vector(currentxvector)
currentyvector=currentyvector.add(DraftVecUtils.scale(yvector,ycount))
if not ycount==0:
nshape = shape.copy()
nshape.translate(currentyvector)
base.append(nshape)
for zcount in range(znum):
currentzvector=FreeCAD.Vector(currentyvector)
currentzvector=currentzvector.add(DraftVecUtils.scale(zvector,zcount))
if not zcount==0:
nshape = shape.copy()
nshape.translate(currentzvector)
base.append(nshape)
return Part.makeCompound(base)
def polarArray(self,shape,center,angle,num,axis):

View File

@ -355,27 +355,33 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F
else :
print "fcgeo: Unsupported curve type: (" + str(edge1.Curve) + ", " + str(edge2.Curve) + ")"
def geom(edge):
"returns a Line, ArcOfCircle or Circle geom from the given edge"
if isinstance(edge.Curve,Part.Line):
return edge.Curve
elif isinstance(edge.Curve,Part.Circle):
if len(edge.Vertexes) == 1:
return Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius)
else:
ref = edge.Placement.multVec(Vector(1,0,0))
ref = ref.sub(edge.Placement.Base) # we only want the orientation
v1 = edge.Vertexes[0].Point
v2 = edge.Vertexes[-1].Point
c = edge.Curve.Center
cu = Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius)
a1 = -DraftVecUtils.angle(v1.sub(c),ref,edge.Curve.Axis)
a2 = -DraftVecUtils.angle(v2.sub(c),ref,edge.Curve.Axis)
print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)"
p= Part.ArcOfCircle(cu,a1,a2)
return p
def geom(edge,plac=FreeCAD.Placement()):
"returns a Line, ArcOfCircle or Circle geom from the given edge, according to the given placement"
if isinstance(edge.Curve,Part.Line):
return edge.Curve
elif isinstance(edge.Curve,Part.Circle):
if len(edge.Vertexes) == 1:
return Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius)
else:
return edge.Curve
# reorienting the arc along the correct normal
normal = plac.Rotation.multVec(FreeCAD.Vector(0,0,1))
v1 = edge.Vertexes[0].Point
v2 = edge.Vertexes[-1].Point
c = edge.Curve.Center
cu = Part.Circle(edge.Curve.Center,normal,edge.Curve.Radius)
ref = plac.Rotation.multVec(Vector(1,0,0))
a1 = math.pi + DraftVecUtils.angle(v1.sub(c),ref,normal)
a2 = DraftVecUtils.angle(v2.sub(c),ref,normal)
# direction check
if a1 > a2:
a1,a2 = a2,a1
#print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)"
p= Part.ArcOfCircle(cu,a1,a2)
return p
else:
return edge.Curve
def mirror (point, edge):
"finds mirror point relative to an edge"
@ -445,98 +451,91 @@ def isLine(bsp):
return True
def sortEdges(lEdges, aVertex=None):
"an alternative, more accurate version of Part.__sortEdges__"
"an alternative, more accurate version of Part.__sortEdges__"
#There is no reason to limit this to lines only because every non-closed edge always
#has exactly two vertices (wmayer)
#for e in lEdges:
# if not isinstance(e.Curve,Part.Line):
# print "Warning: sortedges cannot treat wired containing curves yet."
# return lEdges
def isSameVertex(V1, V2):
''' Test if vertexes have same coordinates with precision 10E(-precision)'''
if round(V1.X-V2.X,1)==0 and round(V1.Y-V2.Y,1)==0 and round(V1.Z-V2.Z,1)==0 :
return True
else :
return False
def lookfor(aVertex, inEdges):
''' Look for (aVertex, inEdges) returns count, the position of the instance
the position in the instance and the instance of the Edge'''
count = 0
linstances = [] #lists the instances of aVertex
for i in range(len(inEdges)) :
for j in range(2) :
if isSameVertex(aVertex,inEdges[i].Vertexes[j-1]):
instance = inEdges[i]
count += 1
linstances += [i,j-1,instance]
return [count]+linstances
if (len(lEdges) < 2):
if aVertex == None:
return lEdges
#There is no reason to limit this to lines only because every non-closed edge always
#has exactly two vertices (wmayer)
#for e in lEdges:
# if not isinstance(e.Curve,Part.Line):
# print "Warning: sortedges cannot treat wired containing curves yet."
# return lEdges
def lookfor(aVertex, inEdges):
''' Look for (aVertex, inEdges) returns count, the position of the instance
the position in the instance and the instance of the Edge'''
count = 0
linstances = [] #lists the instances of aVertex
for i in range(len(inEdges)) :
for j in range(2) :
if aVertex.Point == inEdges[i].Vertexes[j-1].Point:
instance = inEdges[i]
count += 1
linstances += [i,j-1,instance]
return [count]+linstances
if (len(lEdges) < 2):
if aVertex == None:
return lEdges
else:
result = lookfor(aVertex,lEdges)
if result[0] != 0:
if aVertex.Point == result[3].Vertexes[0].Point:
return lEdges
else:
result = lookfor(aVertex,lEdges)
if result[0] != 0:
if isSameVertex(aVertex,result[3].Vertexes[0]):
return lEdges
else:
if isinstance(result[3].Curve,Part.Line):
return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()]
elif isinstance(result[3].Curve,Part.Circle):
mp = findMidpoint(result[3])
return [Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape()]
elif isinstance(result[3].Curve,Part.BSplineCurve):
if isLine(result[3].Curve):
return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()]
else:
return lEdges
else:
return lEdges
olEdges = [] # ol stands for ordered list
if aVertex == None:
for i in range(len(lEdges)*2) :
if len(lEdges[i/2].Vertexes) > 1:
result = lookfor(lEdges[i/2].Vertexes[i%2],lEdges)
if result[0] == 1 : # Have we found an end ?
olEdges = sortEdges(lEdges, result[3].Vertexes[result[2]])
return olEdges
# if the wire is closed there is no end so choose 1st Vertex
#print "closed wire, starting from ",lEdges[0].Vertexes[0].Point
return sortEdges(lEdges, lEdges[0].Vertexes[0])
else :
#print "looking ",aVertex.Point
result = lookfor(aVertex,lEdges)
if result[0] != 0 :
del lEdges[result[1]]
next = sortEdges(lEdges, result[3].Vertexes[-((-result[2])^1)])
#print "result ",result[3].Vertexes[0].Point," ",result[3].Vertexes[1].Point, " compared to ",aVertex.Point
if isSameVertex(aVertex,result[3].Vertexes[0]):
#print "keeping"
olEdges += [result[3]] + next
if isinstance(result[3].Curve,Part.Line):
return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()]
elif isinstance(result[3].Curve,Part.Circle):
mp = findMidpoint(result[3])
return [Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape()]
elif isinstance(result[3].Curve,Part.BSplineCurve):
if isLine(result[3].Curve):
return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()]
else:
#print "inverting", result[3].Curve
if isinstance(result[3].Curve,Part.Line):
newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()
olEdges += [newedge] + next
elif isinstance(result[3].Curve,Part.Circle):
mp = findMidpoint(result[3])
newedge = Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape()
olEdges += [newedge] + next
elif isinstance(result[3].Curve,Part.BSplineCurve):
if isLine(result[3].Curve):
newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()
olEdges += [newedge] + next
else:
olEdges += [result[3]] + next
else:
olEdges += [result[3]] + next
return olEdges
else :
return []
return lEdges
else:
return lEdges
olEdges = [] # ol stands for ordered list
if aVertex == None:
for i in range(len(lEdges)*2) :
if len(lEdges[i/2].Vertexes) > 1:
result = lookfor(lEdges[i/2].Vertexes[i%2],lEdges)
if result[0] == 1 : # Have we found an end ?
olEdges = sortEdges(lEdges, result[3].Vertexes[result[2]])
return olEdges
# if the wire is closed there is no end so choose 1st Vertex
# print "closed wire, starting from ",lEdges[0].Vertexes[0].Point
return sortEdges(lEdges, lEdges[0].Vertexes[0])
else :
#print "looking ",aVertex.Point
result = lookfor(aVertex,lEdges)
if result[0] != 0 :
del lEdges[result[1]]
next = sortEdges(lEdges, result[3].Vertexes[-((-result[2])^1)])
#print "result ",result[3].Vertexes[0].Point," ",result[3].Vertexes[1].Point, " compared to ",aVertex.Point
if aVertex.Point == result[3].Vertexes[0].Point:
#print "keeping"
olEdges += [result[3]] + next
else:
#print "inverting", result[3].Curve
if isinstance(result[3].Curve,Part.Line):
newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()
olEdges += [newedge] + next
elif isinstance(result[3].Curve,Part.Circle):
mp = findMidpoint(result[3])
newedge = Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape()
olEdges += [newedge] + next
elif isinstance(result[3].Curve,Part.BSplineCurve):
if isLine(result[3].Curve):
newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()
olEdges += [newedge] + next
else:
olEdges += [result[3]] + next
else:
olEdges += [result[3]] + next
return olEdges
else :
return []
def findWires(edgeslist):
@ -787,6 +786,31 @@ def getNormal(shape):
if n.getAngle(vdir) < 0.78: n = DraftVecUtils.neg(n)
return n
def getRotation(v1,v2=FreeCAD.Vector(0,0,1)):
'''Get the rotation Quaternion between 2 vectors'''
if (v1.dot(v2) > 0.999999) or (v1.dot(v2) < -0.999999):
# vectors are opposite
return None
axis = v1.cross(v2)
axis.normalize()
angle = math.degrees(math.sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + v1.dot(v2))
return FreeCAD.Rotation(axis,angle)
def calculatePlacement(shape):
'''calculatePlacement(shape): if the given shape is planar, this function
returns a placement located at the center of gravity of the shape, and oriented
towards the shape's normal. Otherwise, it returns a null placement.'''
if not isPlanar(shape):
return FreeCAD.Placement()
pos = shape.BoundBox.Center
norm = getNormal(shape)
pla = FreeCAD.Placement()
pla.Base = pos
r = getRotation(norm)
if r:
pla.Rotation = r
return pla
def offsetWire(wire,dvec,bind=False,occ=False):
'''
offsetWire(wire,vector,[bind]): offsets the given wire along the
@ -982,11 +1006,13 @@ def isCoplanar(faces):
"checks if all faces in the given list are coplanar"
if len(faces) < 2:
return True
base =faces[0].normalAt(.5,.5)
base =faces[0].normalAt(0,0)
for i in range(1,len(faces)):
normal = faces[i].normalAt(.5,.5)
if (normal.getAngle(base) > .0001) and (normal.getAngle(base) < 3.1415):
return False
for v in faces[i].Vertexes:
chord = v.Point.sub(faces[0].Vertexes[0].Point)
dist = DraftVecUtils.project(chord,base)
if round(dist.Length,DraftVecUtils.precision()) > 0:
return False
return True
def isPlanar(shape):

View File

@ -51,8 +51,8 @@ if open.__module__ == '__builtin__':
pythonopen = open
svgcolors = {
'Pink': (255, 192, 203),
'Blue': (0, 0, 255),
'Pink': (255, 192, 203),
'Blue': (0, 0, 255),
'Honeydew': (240, 255, 240),
'Purple': (128, 0, 128),
'Fuchsia': (255, 0, 255),
@ -269,7 +269,7 @@ def makewire(path,checkclosed=False,donttry=False):
#ToDo Do not catch all exceptions
if not donttry:
try:
sh = Part.Wire(DraftGeomUtils.sortEdges(path))
sh = Part.Wire(DraftGeomUtils.sortEdges(path))
#sh = Part.Wire(path)
isok = (not checkclosed) or sh.isClosed()
except:# BRep_API:command not done
@ -448,8 +448,7 @@ class svgHandler(xml.sax.ContentHandler):
abh = getsize(h,unitmode)
sx=abw/vbw
sy=abh/vbh
preservearstr=data.get('preserveAspectRatio',\
'').lower()
preservearstr=' '.join(data.get('preserveAspectRatio',[])).lower()
uniformscaling = round(sx/sy,5) == 1
if uniformscaling:
m.scale(Vector(sx,sy,1))
@ -534,7 +533,8 @@ class svgHandler(xml.sax.ContentHandler):
if path:
#sh = Part.Wire(path)
sh = makewire(path)
if self.fill: sh = Part.Face(sh)
if self.fill and sh.isClosed():
sh = Part.Face(sh)
sh = self.applyTrans(sh)
obj = self.doc.addObject("Part::Feature",pathname)
obj.Shape = sh
@ -624,7 +624,8 @@ class svgHandler(xml.sax.ContentHandler):
if sweepflag:
#angledelta=-(-angledelta % (math.pi *2)) # Step4
#angledelta=(-angledelta % (math.pi *2)) # Step4
angle1 = angle1-angledelta
angle1 = angle1+angledelta
angledelta = -angledelta
#angle1 = math.pi - angle1
e1a = Part.Arc(e1,angle1-swapaxis*math.radians(90),\
@ -750,7 +751,8 @@ class svgHandler(xml.sax.ContentHandler):
if path:
sh=makewire(path,checkclosed=False)
#sh = Part.Wire(path)
if self.fill: sh = Part.Face(sh)
if self.fill and sh.isClosed():
sh = Part.Face(sh)
sh = self.applyTrans(sh)
obj = self.doc.addObject("Part::Feature",pathname)
obj.Shape = sh
@ -828,7 +830,6 @@ class svgHandler(xml.sax.ContentHandler):
obj = self.doc.addObject("Part::Feature",pathname)
obj.Shape = sh
self.format(obj)
# processing lines
if name == "line":
@ -864,7 +865,8 @@ class svgHandler(xml.sax.ContentHandler):
path.append(seg)
if path:
sh = Part.Wire(path)
if self.fill: sh = Part.Face(sh)
if self.fill and sh.isClosed():
sh = Part.Face(sh)
sh = self.applyTrans(sh)
obj = self.doc.addObject("Part::Feature",pathname)
obj.Shape = sh

View File

@ -677,5 +677,10 @@
<UserDocu>Returns a reparametrized copy of this surface</UserDocu>
</Documentation>
</Methode>
<Methode Name="interpolate">
<Documentation>
<UserDocu>Replaces this B-Spline surface by interpolating a set of points.</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

View File

@ -31,6 +31,8 @@
# include <TColStd_Array1OfInteger.hxx>
# include <TColgp_Array1OfPnt.hxx>
# include <TColgp_Array2OfPnt.hxx>
# include <Precision.hxx>
# include <GeomAPI_PointsToBSplineSurface.hxx>
#endif
#include <Base/GeometryPyCXX.h>
@ -1242,6 +1244,55 @@ PyObject* BSplineSurfacePy::reparametrize(PyObject * args)
}
}
PyObject* BSplineSurfacePy::interpolate(PyObject *args)
{
PyObject* obj;
double tol3d = Precision::Approximation();
PyObject* closed = Py_False;
PyObject* t1=0; PyObject* t2=0;
if (!PyArg_ParseTuple(args, "O!",&(PyList_Type), &obj))
return 0;
try {
Py::List list(obj);
Standard_Integer lu = list.size();
Py::List col(list.getItem(0));
Standard_Integer lv = col.size();
TColgp_Array2OfPnt interpolationPoints(1, lu, 1, lv);
Standard_Integer index1 = 0;
Standard_Integer index2 = 0;
for (Py::List::iterator it1 = list.begin(); it1 != list.end(); ++it1) {
index1++;
index2=0;
Py::List row(*it1);
for (Py::List::iterator it2 = row.begin(); it2 != row.end(); ++it2) {
index2++;
Py::Vector v(*it2);
Base::Vector3d pnt = v.toVector();
gp_Pnt newPoint(pnt.x,pnt.y,pnt.z);
interpolationPoints.SetValue(index1, index2, newPoint);
}
}
if (interpolationPoints.RowLength() < 2 || interpolationPoints.ColLength() < 2) {
Standard_Failure::Raise("not enough points given");
}
GeomAPI_PointsToBSplineSurface surInterpolation;
surInterpolation.Interpolate (interpolationPoints);
Handle_Geom_BSplineSurface sur(surInterpolation.Surface());
this->getGeomBSplineSurfacePtr()->setHandle(sur);
Py_Return;
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
std::string err = e->GetMessageString();
if (err.empty()) err = e->DynamicType()->Name();
PyErr_SetString(PyExc_Exception, err.c_str());
return 0;
}
}
Py::Int BSplineSurfacePy::getUDegree(void) const
{
Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast

View File

@ -1362,6 +1362,11 @@ GeomBSplineSurface::~GeomBSplineSurface()
{
}
void GeomBSplineSurface::setHandle(const Handle_Geom_BSplineSurface& s)
{
mySurface = Handle_Geom_BSplineSurface::DownCast(s->Copy());
}
const Handle_Geom_Geometry& GeomBSplineSurface::handle() const
{
return mySurface;

View File

@ -448,6 +448,7 @@ public:
// Base implementer ----------------------------
virtual PyObject *getPyObject(void);
void setHandle(const Handle_Geom_BSplineSurface&);
const Handle_Geom_Geometry& handle() const;
private:

View File

@ -726,6 +726,11 @@ void TopoShape::exportBrep(const char *filename) const
throw Base::Exception("Writing of BREP failed");
}
void TopoShape::exportBrep(std::ostream& out)
{
BRepTools::Write(this->_Shape, out);
}
void TopoShape::exportStl(const char *filename) const
{
StlAPI_Writer writer;

View File

@ -126,6 +126,7 @@ public:
void exportIges(const char *FileName) const;
void exportStep(const char *FileName) const;
void exportBrep(const char *FileName) const;
void exportBrep(std::ostream&);
void exportStl (const char *FileName) const;
void exportFaceSet(double, double, std::ostream&) const;
void exportLineSet(std::ostream&) const;

View File

@ -88,11 +88,23 @@
</Attribute>
<Attribute Name="ParameterRange" ReadOnly="true">
<Documentation>
<UserDocu>Returns a 4 tuple with the parameter range</UserDocu>
<UserDocu>Returns a 2 tuple with the parameter range</UserDocu>
</Documentation>
<Parameter Name="ParameterRange" Type="Tuple"/>
</Attribute>
<Attribute Name="Curve" ReadOnly="true">
<Attribute Name="FirstParameter" ReadOnly="true">
<Documentation>
<UserDocu>Returns the start value of the parameter range</UserDocu>
</Documentation>
<Parameter Name="FirstParameter" Type="Float"/>
</Attribute>
<Attribute Name="LastParameter" ReadOnly="true">
<Documentation>
<UserDocu>Returns the end value of the parameter range</UserDocu>
</Documentation>
<Parameter Name="LastParameter" Type="Float"/>
</Attribute>
<Attribute Name="Curve" ReadOnly="true">
<Documentation>
<UserDocu>Returns the 3D curve of the edge</UserDocu>
</Documentation>

View File

@ -660,6 +660,22 @@ Py::Tuple TopoShapeEdgePy::getParameterRange(void) const
return t;
}
Py::Float TopoShapeEdgePy::getFirstParameter(void) const
{
const TopoDS_Edge& e = TopoDS::Edge(getTopoShapePtr()->_Shape);
BRepAdaptor_Curve adapt(e);
double t = adapt.FirstParameter();
return Py::Float(t);
}
Py::Float TopoShapeEdgePy::getLastParameter(void) const
{
const TopoDS_Edge& e = TopoDS::Edge(getTopoShapePtr()->_Shape);
BRepAdaptor_Curve adapt(e);
double t = adapt.LastParameter();
return Py::Float(t);
}
Py::Object TopoShapeEdgePy::getCenterOfMass(void) const
{
GProp_GProps props;

View File

@ -43,6 +43,11 @@ Sub-elements such as vertices, edges or faces are accessible as:
<UserDocu>Export the content of this shape to an BREP file. BREP is a CasCade native format.</UserDocu>
</Documentation>
</Methode>
<Methode Name="exportBrepToString" Const="true">
<Documentation>
<UserDocu>Export the content of this shape to a string in BREP format. BREP is a CasCade native format.</UserDocu>
</Documentation>
</Methode>
<Methode Name="exportStl" Const="true">
<Documentation>
<UserDocu>Export the content of this shape to an STL mesh file.</UserDocu>
@ -53,6 +58,11 @@ Sub-elements such as vertices, edges or faces are accessible as:
<UserDocu>Import the content to this shape of a string in BREP format.</UserDocu>
</Documentation>
</Methode>
<Methode Name="importBrepFromString">
<Documentation>
<UserDocu>Import the content to this shape from a string in BREP format.</UserDocu>
</Documentation>
</Methode>
<Methode Name="extrude" Const="true">
<Documentation>
<UserDocu>Extrude the shape along a direction.</UserDocu>

View File

@ -311,6 +311,32 @@ PyObject* TopoShapePy::exportBrep(PyObject *args)
Py_Return;
}
PyObject* TopoShapePy::exportBrepToString(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
try {
// write brep file
std::stringstream str;
getTopoShapePtr()->exportBrep(str);
return Py::new_reference_to(Py::String(str.str()));
}
catch (const Base::Exception& e) {
PyErr_SetString(PyExc_Exception,e.what());
return NULL;
}
catch (const std::exception& e) {
PyErr_SetString(PyExc_Exception,e.what());
return NULL;
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
PyErr_SetString(PyExc_Exception, e->GetMessageString());
return 0;
}
}
PyObject* TopoShapePy::importBrep(PyObject *args)
{
PyObject* input;
@ -335,6 +361,34 @@ PyObject* TopoShapePy::importBrep(PyObject *args)
Py_Return;
}
PyObject* TopoShapePy::importBrepFromString(PyObject *args)
{
char* input;
if (!PyArg_ParseTuple(args, "s", &input))
return NULL;
try {
// read brep
std::stringstream str(input);
getTopoShapePtr()->importBrep(str);
}
catch (const Base::Exception& e) {
PyErr_SetString(PyExc_Exception,e.what());
return NULL;
}
catch (const std::exception& e) {
PyErr_SetString(PyExc_Exception,e.what());
return NULL;
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
PyErr_SetString(PyExc_Exception, e->GetMessageString());
return 0;
}
Py_Return;
}
PyObject* TopoShapePy::exportStl(PyObject *args)
{
char* filename;

View File

@ -47,6 +47,7 @@
#include <Gui/Command.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/SoFCUnifiedSelection.h>
#include <Gui/TaskView/TaskView.h>
#include <Mod/Part/App/Tools.h>
@ -270,6 +271,9 @@ DlgPrimitives::~DlgPrimitives()
void DlgPrimitives::pickCallback(void * ud, SoEventCallback * n)
{
const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent*>(n->getEvent());
Picker* pick = reinterpret_cast<Picker*>(ud);
if (pick->exitCode >= 0)
pick->loop.exit(pick->exitCode);
// Mark all incoming mouse button events as handled, especially, to deactivate the selection node
n->setHandled();
@ -277,16 +281,14 @@ void DlgPrimitives::pickCallback(void * ud, SoEventCallback * n)
if (mbe->getState() == SoButtonEvent::DOWN) {
const SoPickedPoint * point = n->getPickedPoint();
if (point) {
Picker* pick = reinterpret_cast<Picker*>(ud);
if (pick->pickedPoint(point)) {
pick->loop.exit(0);
pick->exitCode = 0;
}
}
}
}
else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2) {
if (mbe->getState() == SoButtonEvent::UP) {
Picker* pick = reinterpret_cast<Picker*>(ud);
pick->loop.exit(1);
}
}
@ -305,9 +307,17 @@ void DlgPrimitives::executeCallback(Picker* p)
if (!viewer->isEditing()) {
viewer->setEditing(true);
viewer->setRedirectToSceneGraph(true);
SoNode* root = viewer->getSceneGraph();
int mode;
if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) {
mode = static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.getValue();
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(Gui::SoFCUnifiedSelection::OFF);
}
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, p);
this->setDisabled(true);
int ret = p->loop.exec();
if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId()))
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(mode);
this->setEnabled(true);
viewer->setEditing(false);
viewer->setRedirectToSceneGraph(false);
@ -587,6 +597,9 @@ Location::~Location()
viewer->setEditing(false);
viewer->setRedirectToSceneGraph(false);
viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,this);
SoNode* root = viewer->getSceneGraph();
if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId()))
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(this->mode);
}
}
@ -605,6 +618,11 @@ void Location::on_viewPositionButton_clicked()
viewer->setEditing(true);
viewer->setRedirectToSceneGraph(true);
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, this);
SoNode* root = viewer->getSceneGraph();
if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) {
this->mode = static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.getValue();
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(Gui::SoFCUnifiedSelection::OFF);
}
}
}
}
@ -617,15 +635,7 @@ void Location::pickCallback(void * ud, SoEventCallback * n)
// Mark all incoming mouse button events as handled, especially, to deactivate the selection node
n->getAction()->setHandled();
if (mbe->getButton() == SoMouseButtonEvent::BUTTON1) {
if (mbe->getState() == SoButtonEvent::UP) {
n->setHandled();
view->setEditing(false);
view->setRedirectToSceneGraph(false);
Location* dlg = reinterpret_cast<Location*>(ud);
dlg->activeView = 0;
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,ud);
}
else if (mbe->getState() == SoButtonEvent::DOWN) {
if (mbe->getState() == SoButtonEvent::DOWN) {
const SoPickedPoint * point = n->getPickedPoint();
if (point) {
SbVec3f pnt = point->getPoint();
@ -637,6 +647,19 @@ void Location::pickCallback(void * ud, SoEventCallback * n)
}
}
}
else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2) {
if (mbe->getState() == SoButtonEvent::UP) {
n->setHandled();
view->setEditing(false);
view->setRedirectToSceneGraph(false);
Location* dlg = reinterpret_cast<Location*>(ud);
dlg->activeView = 0;
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,ud);
SoNode* root = view->getSceneGraph();
if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId()))
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(static_cast<Location*>(ud)->mode);
}
}
}
QString Location::toPlacement() const

View File

@ -39,7 +39,7 @@ namespace PartGui {
class Picker
{
public:
Picker()
Picker() : exitCode(-1)
{
}
virtual ~Picker()
@ -51,6 +51,7 @@ public:
void createPrimitive(QWidget* widget, const QString&, Gui::Document*);
QString toPlacement(const gp_Ax2&) const;
int exitCode;
QEventLoop loop;
};
@ -88,6 +89,7 @@ private Q_SLOTS:
private:
static void pickCallback(void * ud, SoEventCallback * n);
int mode;
QPointer<QWidget> activeView;
Ui_Location ui;
};

View File

@ -71,7 +71,7 @@
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Model refinement</string>
<string>Model settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">

View File

@ -15,6 +15,7 @@ include_directories(
link_directories(${OCC_LIBRARY_DIR})
set(PartDesign_LIBS
${OCC_LIBRARIES}
Part
FreeCADApp
)

View File

@ -102,8 +102,6 @@ void CmdRaytracingWriteCamera::activated(int iMsg)
SoInput in;
in.setBuffer((void*)ppReturn,std::strlen(ppReturn));
//if (!in.openFile(filename)) { exit(1); }
SoNode* rootNode;
SoDB::read(&in,rootNode);

View File

@ -731,9 +731,8 @@ public:
virtual void mouseMove(Base::Vector2D onSketchPos)
{
setPositionText(onSketchPos);
if (Mode==STATUS_SEEK_First) {
setPositionText(onSketchPos);
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr1);
return;
@ -750,6 +749,16 @@ public:
EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - dx, EditCurve[0].fY - dy);
}
EditCurve[33] = EditCurve[1];
// Display radius and start angle
float radius = (onSketchPos - EditCurve[0]).Length();
float angle = atan2f(dy_ , dx_) * 180 / M_PI;
char buf[40];
sprintf( buf, " (R%.1f,%.1f)", radius, angle);
std::string text = buf;
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr2);
@ -767,6 +776,15 @@ public:
float dy = rx * sin(angle) + ry * cos(angle);
EditCurve[i] = Base::Vector2D(CenterPoint.fX + dx, CenterPoint.fY + dy);
}
// Display radius and end angle
float radius = (onSketchPos - EditCurve[0]).Length();
char buf[40];
sprintf( buf, " (R%.1f,%.1f)", radius, arcAngle * 180 / M_PI);
std::string text = buf;
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr3);
@ -950,8 +968,8 @@ public:
virtual void mouseMove(Base::Vector2D onSketchPos)
{
setPositionText(onSketchPos);
if (Mode==STATUS_SEEK_First) {
setPositionText(onSketchPos);
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr1);
return;
@ -968,6 +986,15 @@ public:
EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry);
}
EditCurve[33] = EditCurve[1];
// Display radius for user
float radius = (onSketchPos - EditCurve[0]).Length();
char buf[40];
sprintf( buf, "R%.1f", radius);
std::string text = buf;
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), CURVE)) {
renderSuggestConstraintsCursor(sugConstr2);

View File

@ -385,6 +385,12 @@ void DrawSketchHandler::renderSuggestConstraintsCursor(std::vector<AutoConstrain
applyCursor(newCursor);
}
void DrawSketchHandler::setPositionText(const Base::Vector2D &Pos, const std::string &text)
{
sketchgui->setPositionText(Pos, text);
}
void DrawSketchHandler::setPositionText(const Base::Vector2D &Pos)
{
sketchgui->setPositionText(Pos);

View File

@ -87,6 +87,7 @@ public:
void createAutoConstraints(const std::vector<AutoConstraint> &autoConstrs,
int geoId, Sketcher::PointPos pointPos=Sketcher::none);
void setPositionText(const Base::Vector2D &Pos, const std::string &text);
void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);
void renderSuggestConstraintsCursor(std::vector<AutoConstraint> &suggestedConstraints);

View File

@ -3026,6 +3026,12 @@ void ViewProviderSketch::unsetEditViewer(Gui::View3DInventorViewer* viewer)
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(TRUE);
}
void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos, const std::string &text)
{
edit->textX->string = text.c_str();
edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText);
}
void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos)
{
char buf[40];

View File

@ -200,6 +200,7 @@ protected:
/// build up the visual of the constraints
void rebuildConstraintsVisual(void);
void setPositionText(const Base::Vector2D &Pos, const std::string &txt);
void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);