Merge branch 'master' into logari81/sketcher

This commit is contained in:
logari81 2012-07-17 10:15:51 +02:00
commit b3284357d2
65 changed files with 2198 additions and 496 deletions

View File

@ -104,6 +104,11 @@ OPTION(FREECAD_BUILD_TEMPLATE "Build the FreeCAD template module which is only f
OPTION(FREECAD_BUILD_DEBIAN "Prepare for a build of a Debian package" OFF)
OPTION(FREECAD_USE_EXTERNAL_ZIPIOS "Use system installed zipios++ instead of the bundled." OFF)
OPTION(FREECAD_USE_EXTERNAL_PIVY "Use system installed python-pivy instead of the bundled." OFF)
if(MSVC)
OPTION(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON)
else(MSVC)
set(FREECAD_USE_3DCONNEXION OFF)
endif(MSVC)
# if this is set override some options
if (FREECAD_BUILD_DEBIAN)
@ -206,7 +211,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 +224,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 +267,7 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
# -------------------------------- ODE ----------------------------------
find_package(ODE)
# find_package(ODE)
# -------------------------------- Qt --------------------------------
@ -439,7 +438,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

@ -329,6 +329,7 @@ set(OCC_LIBRARIES
TKSTEPBase
TKSTEPAttr
TKHLR
TKFeat
)
set(OCC_LIBRARY_DIR
${FREECAD_LIBPACK_DIR}/lib

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

@ -0,0 +1,718 @@
/*
Development tools and related technology provided under license from 3Dconnexion.
(c) 1992 - 2012 3Dconnexion. All rights reserved
*/
/*
Support for Qt added by David Dibben at
http://www.codegardening.com/2011/02/using-3dconnexion-mouse-with-qt.html
*/
/*
See also:
http://www.3dconnexion.com/forum/viewtopic.php?f=19&t=4968&sid=72c018bdcf0e6edc99a6effb5c0c48d9
*/
#include "PreCompiled.h"
#include <QGlobalStatic>
#include <QMainWindow>
#include <QWidget>
#include <FCConfig.h>
#include <Base/Console.h>
#include "GuiApplicationNativeEventAware.h"
#include "SpaceballEvent.h"
// Windows dependencies, enumerators and global variables
#ifdef _USE_3DCONNEXION_SDK
#include <QApplication>
#include <windows.h>
#include <math.h>
#define LOGITECH_VENDOR_ID 0x46d
#define _CONSTANT_INPUT_PERIOD 0
#ifndef RIDEV_DEVNOTIFY
#define RIDEV_DEVNOTIFY 0x00002000
#endif
#define _TRACE_WM_INPUT_PERIOD 0
#define _TRACE_RI_TYPE 0
#define _TRACE_RIDI_DEVICENAME 0
#define _TRACE_RIDI_DEVICEINFO 0
#define _TRACE_RI_RAWDATA 0
#define _TRACE_3DINPUT_PERIOD 0
#ifdef _WIN64
typedef unsigned __int64 QWORD;
#endif // _WIN64
static const int kTimeToLive = 5;
enum e3dconnexion_pid {
eSpacePilot = 0xc625,
eSpaceNavigator = 0xc626,
eSpaceExplorer = 0xc627,
eSpaceNavigatorForNotebooks = 0xc628,
eSpacePilotPRO = 0xc629
};
enum e3dmouse_virtual_key
{
V3DK_INVALID=0
, V3DK_MENU=1, V3DK_FIT
, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_BOTTOM, V3DK_BACK
, V3DK_CW, V3DK_CCW
, V3DK_ISO1, V3DK_ISO2
, V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6, V3DK_7, V3DK_8, V3DK_9, V3DK_10
, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL
, V3DK_ROTATE, V3DK_PANZOOM, V3DK_DOMINANT
, V3DK_PLUS, V3DK_MINUS
};
struct tag_VirtualKeys
{
e3dconnexion_pid pid;
size_t nKeys;
e3dmouse_virtual_key *vkeys;
};
static const e3dmouse_virtual_key SpaceExplorerKeys [] =
{
V3DK_INVALID // there is no button 0
, V3DK_1, V3DK_2
, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT
, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL
, V3DK_FIT, V3DK_MENU
, V3DK_PLUS, V3DK_MINUS
, V3DK_ROTATE
};
static const e3dmouse_virtual_key SpacePilotKeys [] =
{
V3DK_INVALID
, V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6
, V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT
, V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL
, V3DK_FIT, V3DK_MENU
, V3DK_PLUS, V3DK_MINUS
, V3DK_DOMINANT, V3DK_ROTATE
};
static const struct tag_VirtualKeys _3dmouseVirtualKeys[]=
{
eSpacePilot
, sizeof(SpacePilotKeys)/sizeof(SpacePilotKeys[0])
, const_cast<e3dmouse_virtual_key *>(SpacePilotKeys),
eSpaceExplorer
, sizeof(SpaceExplorerKeys)/sizeof(SpaceExplorerKeys[0])
, const_cast<e3dmouse_virtual_key *>(SpaceExplorerKeys)
};
// Methods for windows events
/*!
Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device to the standard 3d mouse virtual key definition.
\a pid USB Product ID (PID) of 3D mouse device
\a hidKeyCode Hid keycode as retrieved from a Raw Input packet
\return The standard 3d mouse virtual key (button identifier) or zero if an error occurs.
Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device
to the standard 3d mouse virtual key definition.
*/
unsigned short HidToVirtualKey(unsigned long pid, unsigned short hidKeyCode)
{
unsigned short virtualkey=hidKeyCode;
for (size_t i=0; i<sizeof(_3dmouseVirtualKeys)/sizeof(_3dmouseVirtualKeys[0]); ++i)
{
if (pid == _3dmouseVirtualKeys[i].pid)
{
if (hidKeyCode < _3dmouseVirtualKeys[i].nKeys)
virtualkey = _3dmouseVirtualKeys[i].vkeys[hidKeyCode];
else
virtualkey = V3DK_INVALID;
break;
}
}
// Remaining devices are unchanged
return virtualkey;
}
bool Gui::GUIApplicationNativeEventAware::RawInputEventFilter(void* msg, long* result)
{
if (gMouseInput == 0) return false;
MSG* message = (MSG*)(msg);
if (message->message == WM_INPUT) {
HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(message->lParam);
gMouseInput->OnRawInput(RIM_INPUT,hRawInput);
if (result != 0) {
result = 0;
}
return true;
}
return false;
}
/*!
Access the mouse parameters structure
*/
I3dMouseParam& Gui::GUIApplicationNativeEventAware::MouseParams()
{
return f3dMouseParams;
}
/*!
Access the mouse parameters structure
*/
const I3dMouseParam& Gui::GUIApplicationNativeEventAware::MouseParams() const
{
return f3dMouseParams;
}
/*!
Called with the processed motion data when a 3D mouse event is received
The default implementation emits a Move3d signal with the motion data
*/
void Gui::GUIApplicationNativeEventAware::Move3d(HANDLE device, std::vector<float>& motionData)
{
Q_UNUSED(device);
QWidget *currentWidget = this->focusWidget();
if (!currentWidget)
currentWidget = mainWindow;
int x, y, z, rx, ry, rz;
x = ceil(motionData[0])*(-1);
y = ceil(motionData[1]);
z = ceil(motionData[2]);
rx = ceil(motionData[3])*(-1);
ry = ceil(motionData[4]);
rz = ceil(motionData[5]);
Spaceball::MotionEvent *motionEvent = new Spaceball::MotionEvent();
motionEvent->setTranslations(x, y, z);
motionEvent->setRotations(rx, ry, rz);
this->postEvent(currentWidget, motionEvent);
}
/*!
Called when a 3D mouse key is pressed
The default implementation emits a On3dmouseKeyDown signal with the key code.
*/
void Gui::GUIApplicationNativeEventAware::On3dmouseKeyDown(HANDLE device, int virtualKeyCode)
{
Q_UNUSED(device);
QWidget *currentWidget = this->focusWidget();
if (!currentWidget)
currentWidget = mainWindow;
Spaceball::ButtonEvent *buttonEvent = new Spaceball::ButtonEvent();
buttonEvent->setButtonNumber(virtualKeyCode - 1);
buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED);
this->postEvent(currentWidget, buttonEvent);
}
/*!
Called when a 3D mouse key is released
The default implementation emits a On3dmouseKeyUp signal with the key code.
*/
void Gui::GUIApplicationNativeEventAware::On3dmouseKeyUp(HANDLE device, int virtualKeyCode)
{
Q_UNUSED(device);
QWidget *currentWidget = this->focusWidget();
if (!currentWidget)
currentWidget = mainWindow;
Spaceball::ButtonEvent *buttonEvent = new Spaceball::ButtonEvent();
buttonEvent->setButtonNumber(virtualKeyCode - 1);
buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED);
this->postEvent(currentWidget, buttonEvent);
}
/*!
Get an initialized array of PRAWINPUTDEVICE for the 3D devices
pNumDevices returns the number of devices to register. Currently this is always 1.
*/
static PRAWINPUTDEVICE GetDevicesToRegister(unsigned int* pNumDevices)
{
// Array of raw input devices to register
static RAWINPUTDEVICE sRawInputDevices[] = {
{0x01, 0x08, 0x00, 0x00} // Usage Page = 0x01 Generic Desktop Page, Usage Id= 0x08 Multi-axis Controller
};
if (pNumDevices) {
*pNumDevices = sizeof(sRawInputDevices) / sizeof(sRawInputDevices[0]);
}
return sRawInputDevices;
}
/*!
Detect the 3D mouse
*/
bool Gui::GUIApplicationNativeEventAware::Is3dmouseAttached()
{
unsigned int numDevicesOfInterest = 0;
PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevicesOfInterest);
unsigned int nDevices = 0;
if (::GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) {
return false;
}
if (nDevices == 0) return false;
std::vector<RAWINPUTDEVICELIST> rawInputDeviceList(nDevices);
if (::GetRawInputDeviceList(&rawInputDeviceList[0], &nDevices, sizeof(RAWINPUTDEVICELIST)) == static_cast<unsigned int>(-1)) {
return false;
}
for (unsigned int i = 0; i < nDevices; ++i) {
RID_DEVICE_INFO rdi = {sizeof(rdi)};
unsigned int cbSize = sizeof(rdi);
if (GetRawInputDeviceInfo(rawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) > 0) {
//skip non HID and non logitec (3DConnexion) devices
if (rdi.dwType != RIM_TYPEHID || rdi.hid.dwVendorId != LOGITECH_VENDOR_ID) {
continue;
}
//check if devices matches Multi-axis Controller
for (unsigned int j = 0; j < numDevicesOfInterest; ++j) {
if (devicesToRegister[j].usUsage == rdi.hid.usUsage
&& devicesToRegister[j].usUsagePage == rdi.hid.usUsagePage) {
return true;
}
}
}
}
return false;
}
/*!
Initialize the window to recieve raw-input messages
This needs to be called initially so that Windows will send the messages from the 3D mouse to the window.
*/
bool Gui::GUIApplicationNativeEventAware::InitializeRawInput(HWND hwndTarget)
{
fWindow = hwndTarget;
// Simply fail if there is no window
if (!hwndTarget) return false;
unsigned int numDevices = 0;
PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevices);
if (numDevices == 0) return false;
// Get OS version.
OSVERSIONINFO osvi = {sizeof(OSVERSIONINFO),0};
::GetVersionEx(&osvi);
unsigned int cbSize = sizeof (devicesToRegister[0]);
for (size_t i = 0; i < numDevices; i++) {
// Set the target window to use
//devicesToRegister[i].hwndTarget = hwndTarget;
// If Vista or newer, enable receiving the WM_INPUT_DEVICE_CHANGE message.
if (osvi.dwMajorVersion >= 6) {
devicesToRegister[i].dwFlags |= RIDEV_DEVNOTIFY;
}
}
return (::RegisterRawInputDevices(devicesToRegister, numDevices, cbSize) != FALSE);
}
/*!
Get the raw input data from Windows
Includes workaround for incorrect alignment of the RAWINPUT structure on x64 os
when running as Wow64 (copied directly from 3DConnexion code)
*/
UINT Gui::GUIApplicationNativeEventAware::GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
{
#ifdef _WIN64
return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
#else
BOOL bIsWow64 = FALSE;
::IsWow64Process(GetCurrentProcess(), &bIsWow64);
if (!bIsWow64 || pData==NULL) {
return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
} else {
HWND hwndTarget = fWindow; //fParent->winId();
size_t cbDataSize=0;
UINT nCount=0;
PRAWINPUT pri = pData;
MSG msg;
while (PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_NOREMOVE)) {
HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(msg.lParam);
size_t cbSize = *pcbSize - cbDataSize;
if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast<UINT>(-1)) {
if (nCount==0) {
return static_cast<UINT>(-1);
} else {
break;
}
}
++nCount;
// Remove the message for the data just read
PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_REMOVE);
pri = NEXTRAWINPUTBLOCK(pri);
cbDataSize = reinterpret_cast<ULONG_PTR>(pri) - reinterpret_cast<ULONG_PTR>(pData);
if (cbDataSize >= *pcbSize) {
cbDataSize = *pcbSize;
break;
}
}
return nCount;
}
#endif
}
/*!
Process the raw input device data
On3dmouseInput() does all the preprocessing of the rawinput device data before
finally calling the Move3d method.
*/
void Gui::GUIApplicationNativeEventAware::On3dmouseInput()
{
// Don't do any data processing in background
bool bIsForeground = (::GetActiveWindow() != NULL);
if (!bIsForeground) {
// set all cached data to zero so that a zero event is seen and the cached data deleted
for (std::map<HANDLE, TInputData>::iterator it = fDevice2Data.begin(); it != fDevice2Data.end(); it++) {
it->second.fAxes.assign(6, .0);
it->second.fIsDirty = true;
}
}
DWORD dwNow = ::GetTickCount(); // Current time;
DWORD dwElapsedTime; // Elapsed time since we were last here
if (0 == fLast3dmouseInputTime) {
dwElapsedTime = 10; // System timer resolution
} else {
dwElapsedTime = dwNow - fLast3dmouseInputTime;
if (fLast3dmouseInputTime > dwNow) {
dwElapsedTime = ~dwElapsedTime+1;
}
if (dwElapsedTime<1) {
dwElapsedTime=1;
} else if (dwElapsedTime > 500) {
// Check for wild numbers because the device was removed while sending data
dwElapsedTime = 10;
}
}
#if _TRACE_3DINPUT_PERIOD
qDebug("On3DmouseInput() period is %dms\n", dwElapsedTime);
#endif
float mouseData2Rotation;
// v = w * r, we don't know r yet so lets assume r=1.)
float mouseData2PanZoom;
// Grab the I3dmouseParam interface
I3dMouseParam& i3dmouseParam = f3dMouseParams;
// Take a look at the users preferred speed setting and adjust the sensitivity accordingly
I3dMouseSensor::ESpeed speedSetting = i3dmouseParam.GetSpeed();
// See "Programming for the 3D Mouse", Section 5.1.3
float speed = (speedSetting == I3dMouseSensor::kLowSpeed ? 0.25f : speedSetting == I3dMouseSensor::kHighSpeed ? 4.f : 1.f);
// Multiplying by the following will convert the 3d mouse data to real world units
mouseData2PanZoom = speed;
mouseData2Rotation = speed;
std::map<HANDLE, TInputData>::iterator iterator=fDevice2Data.begin();
while (iterator != fDevice2Data.end()) {
// If we have not received data for a while send a zero event
if ((--(iterator->second.fTimeToLive)) == 0) {
iterator->second.fAxes.assign(6, .0);
} else if (/*!t_bPoll3dmouse &&*/ !iterator->second.fIsDirty) {
// If we are not polling then only handle the data that was actually received
++iterator;
continue;
}
iterator->second.fIsDirty=false;
// get a copy of the device
HANDLE hdevice = iterator->first;
// get a copy of the motion vectors and apply the user filters
std::vector<float> motionData = iterator->second.fAxes;
// apply the user filters
// Pan Zoom filter
// See "Programming for the 3D Mouse", Section 5.1.2
if (!i3dmouseParam.IsPanZoom()) {
// Pan zoom is switched off so set the translation vector values to zero
motionData[0] = motionData[1] = motionData[2] = 0.;
}
// Rotate filter
// See "Programming for the 3D Mouse", Section 5.1.1
if (!i3dmouseParam.IsRotate()) {
// Rotate is switched off so set the rotation vector values to zero
motionData[3] = motionData[4] = motionData[5] = 0.;
}
// convert the translation vector into physical data
for (int axis = 0; axis < 3; axis++) {
motionData[axis] *= mouseData2PanZoom;
}
// convert the directed Rotate vector into physical data
// See "Programming for the 3D Mouse", Section 7.2.2
for (int axis = 3; axis < 6; axis++) {
motionData[axis] *= mouseData2Rotation;
}
// Now that the data has had the filters and sensitivty settings applied
// calculate the displacements since the last view update
for (int axis = 0; axis < 6; axis++) {
motionData[axis] *= dwElapsedTime;
}
// Now a bit of book keeping before passing on the data
if (iterator->second.IsZero()) {
iterator = fDevice2Data.erase(iterator);
} else {
++iterator;
}
// Work out which will be the next device
HANDLE hNextDevice = 0;
if (iterator != fDevice2Data.end()) {
hNextDevice = iterator->first;
}
// Pass the 3dmouse input to the view controller
Move3d(hdevice, motionData);
// Because we don't know what happened in the previous call, the cache might have
// changed so reload the iterator
iterator = fDevice2Data.find(hNextDevice);
}
if (!fDevice2Data.empty()) {
fLast3dmouseInputTime = dwNow;
} else {
fLast3dmouseInputTime = 0;
}
}
/*!
Called when new raw input data is available
*/
void Gui::GUIApplicationNativeEventAware::OnRawInput(UINT nInputCode, HRAWINPUT hRawInput)
{
const size_t cbSizeOfBuffer=1024;
BYTE pBuffer[cbSizeOfBuffer];
PRAWINPUT pRawInput = reinterpret_cast<PRAWINPUT>(pBuffer);
UINT cbSize = cbSizeOfBuffer;
if (::GetRawInputData(hRawInput, RID_INPUT, pRawInput, &cbSize, sizeof(RAWINPUTHEADER)) == static_cast<UINT>(-1)) {
return;
}
bool b3dmouseInput = TranslateRawInputData(nInputCode, pRawInput);
::DefRawInputProc(&pRawInput, 1, sizeof(RAWINPUTHEADER));
// Check for any buffered messages
cbSize = cbSizeOfBuffer;
UINT nCount = this->GetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER));
if (nCount == (UINT)-1) {
qDebug ("GetRawInputBuffer returned error %d\n", GetLastError());
}
while (nCount>0 && nCount != static_cast<UINT>(-1)) {
PRAWINPUT pri = pRawInput;
UINT nInput;
for (nInput=0; nInput<nCount; ++nInput) {
b3dmouseInput |= TranslateRawInputData(nInputCode, pri);
// clean the buffer
::DefRawInputProc(&pri, 1, sizeof(RAWINPUTHEADER));
pri = NEXTRAWINPUTBLOCK(pri);
}
cbSize = cbSizeOfBuffer;
nCount = this->GetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER));
}
// If we have mouse input data for the app then tell tha app about it
if (b3dmouseInput) {
On3dmouseInput();
}
}
bool Gui::GUIApplicationNativeEventAware::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInput)
{
bool bIsForeground = (nInputCode == RIM_INPUT);
#if _TRACE_RI_TYPE
qDebug("Rawinput.header.dwType=0x%x\n", pRawInput->header.dwType);
#endif
// We are not interested in keyboard or mouse data received via raw input
if (pRawInput->header.dwType != RIM_TYPEHID) return false;
#if _TRACE_RIDI_DEVICENAME
UINT dwSize=0;
if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, NULL, &dwSize) == 0) {
std::vector<wchar_t> szDeviceName(dwSize+1);
if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, &szDeviceName[0], &dwSize) >0) {
qDebug("Device Name = %s\nDevice handle = 0x%x\n", &szDeviceName[0], pRawInput->header.hDevice);
}
}
#endif
RID_DEVICE_INFO sRidDeviceInfo;
sRidDeviceInfo.cbSize = sizeof(RID_DEVICE_INFO);
UINT cbSize = sizeof(RID_DEVICE_INFO);
if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &sRidDeviceInfo, &cbSize) == cbSize) {
#if _TRACE_RIDI_DEVICEINFO
switch (sRidDeviceInfo.dwType) {
case RIM_TYPEMOUSE:
qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEMOUSE\n");
break;
case RIM_TYPEKEYBOARD:
qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEKEYBOARD\n");
break;
case RIM_TYPEHID:
qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEHID\n");
qDebug("\tVendor=0x%x\n\tProduct=0x%x\n\tUsagePage=0x%x\n\tUsage=0x%x\n",
sRidDeviceInfo.hid.dwVendorId,
sRidDeviceInfo.hid.dwProductId,
sRidDeviceInfo.hid.usUsagePage,
sRidDeviceInfo.hid.usUsage);
break;
}
#endif
if (sRidDeviceInfo.hid.dwVendorId == LOGITECH_VENDOR_ID) {
if (pRawInput->data.hid.bRawData[0] == 0x01) { // Translation vector
TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice];
deviceData.fTimeToLive = kTimeToLive;
if (bIsForeground) {
short* pnRawData = reinterpret_cast<short*>(&pRawInput->data.hid.bRawData[1]);
// Cache the pan zoom data
deviceData.fAxes[0] = static_cast<float>(pnRawData[0]);
deviceData.fAxes[1] = static_cast<float>(pnRawData[1]);
deviceData.fAxes[2] = static_cast<float>(pnRawData[2]);
#if _TRACE_RI_RAWDATA
qDebug("Pan/Zoom RI Data =\t0x%x,\t0x%x,\t0x%x\n",
pnRawData[0], pnRawData[1], pnRawData[2]);
#endif
if (pRawInput->data.hid.dwSizeHid >= 13) {// Highspeed package
// Cache the rotation data
deviceData.fAxes[3] = static_cast<float>(pnRawData[3]);
deviceData.fAxes[4] = static_cast<float>(pnRawData[4]);
deviceData.fAxes[5] = static_cast<float>(pnRawData[5]);
deviceData.fIsDirty = true;
#if _TRACE_RI_RAWDATA
qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n",
pnRawData[3], pnRawData[4], pnRawData[5]);
#endif
return true;
}
} else { // Zero out the data if the app is not in forground
deviceData.fAxes.assign(6, 0.f);
}
} else if (pRawInput->data.hid.bRawData[0] == 0x02) { // Rotation vector
// If we are not in foreground do nothing
// The rotation vector was zeroed out with the translation vector in the previous message
if (bIsForeground) {
TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice];
deviceData.fTimeToLive = kTimeToLive;
short* pnRawData = reinterpret_cast<short*>(&pRawInput->data.hid.bRawData[1]);
// Cache the rotation data
deviceData.fAxes[3] = static_cast<float>(pnRawData[0]);
deviceData.fAxes[4] = static_cast<float>(pnRawData[1]);
deviceData.fAxes[5] = static_cast<float>(pnRawData[2]);
deviceData.fIsDirty = true;
#if _TRACE_RI_RAWDATA
qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n",
pnRawData[0], pnRawData[1], pnRawData[2]);
#endif
return true;
}
} else if (pRawInput->data.hid.bRawData[0] == 0x03) { // Keystate change
// this is a package that contains 3d mouse keystate information
// bit0=key1, bit=key2 etc.
unsigned long dwKeystate = *reinterpret_cast<unsigned long*>(&pRawInput->data.hid.bRawData[1]);
#if _TRACE_RI_RAWDATA
qDebug("ButtonData =0x%x\n", dwKeystate);
#endif
// Log the keystate changes
unsigned long dwOldKeystate = fDevice2Keystate[pRawInput->header.hDevice];
if (dwKeystate != 0) {
fDevice2Keystate[pRawInput->header.hDevice] = dwKeystate;
} else {
fDevice2Keystate.erase(pRawInput->header.hDevice);
}
// Only call the keystate change handlers if the app is in foreground
if (bIsForeground) {
unsigned long dwChange = dwKeystate ^ dwOldKeystate;
for (int nKeycode=1; nKeycode<33; nKeycode++) {
if (dwChange & 0x01) {
int nVirtualKeyCode = HidToVirtualKey(sRidDeviceInfo.hid.dwProductId, nKeycode);
if (nVirtualKeyCode) {
if (dwKeystate&0x01) {
On3dmouseKeyDown(pRawInput->header.hDevice, nVirtualKeyCode);
} else {
On3dmouseKeyUp(pRawInput->header.hDevice, nVirtualKeyCode);
}
}
}
dwChange >>=1;
dwKeystate >>=1;
}
}
}
}
}
return false;
}
#endif // _USE_3DCONNEXION_SDK

View File

@ -0,0 +1,91 @@
/*
Development tools and related technology provided under license from 3Dconnexion.
(c) 1992 - 2012 3Dconnexion. All rights reserved
*/
#ifndef I3D_MOUSE_PARAMS_H
#define I3D_MOUSE_PARAMS_H
/*
Parameters for the 3D mouse based on the SDK from 3Dconnexion
*/
class I3dMouseSensor
{
public:
enum ESpeed {
kLowSpeed = 0,
kMidSpeed,
kHighSpeed
};
virtual bool IsPanZoom() const = 0;
virtual bool IsRotate() const = 0;
virtual ESpeed GetSpeed() const = 0;
virtual void SetPanZoom(bool isPanZoom) = 0;
virtual void SetRotate(bool isRotate) = 0;
virtual void SetSpeed(ESpeed speed) = 0;
protected:
virtual ~I3dMouseSensor() {}
};
class I3dMouseNavigation
{
public:
enum EPivot {
kManualPivot = 0,
kAutoPivot,
kAutoPivotOverride
};
enum ENavigation {
kObjectMode = 0,
kCameraMode,
kFlyMode,
kWalkMode,
kHelicopterMode
};
enum EPivotVisibility {
kHidePivot = 0,
kShowPivot,
kShowMovingPivot
};
virtual ENavigation GetNavigationMode() const = 0;
virtual EPivot GetPivotMode() const = 0;
virtual EPivotVisibility GetPivotVisibility() const = 0;
virtual bool IsLockHorizon() const = 0;
virtual void SetLockHorizon(bool bOn) = 0;
virtual void SetNavigationMode(ENavigation navigation) = 0;
virtual void SetPivotMode(EPivot pivot) = 0;
virtual void SetPivotVisibility(EPivotVisibility visibility) = 0;
protected:
virtual ~I3dMouseNavigation(){}
};
class I3dMouseParam : public I3dMouseSensor, public I3dMouseNavigation
{
public:
virtual ~I3dMouseParam() {}
};
#endif // I3D_MOUSE_PARAMS_H

View File

@ -0,0 +1,95 @@
/*
Development tools and related technology provided under license from 3Dconnexion.
(c) 1992 - 2012 3Dconnexion. All rights reserved
*/
#include "PreCompiled.h"
#include "MouseParameters.h"
MouseParameters::MouseParameters(): fNavigation(kObjectMode)
, fPivot(kAutoPivot)
, fPivotVisibility(kShowPivot)
, fIsLockHorizon(true)
, fIsPanZoom(true)
, fIsRotate(true)
, fSpeed(kLowSpeed)
{
}
MouseParameters::~MouseParameters()
{
}
bool MouseParameters::IsPanZoom() const
{
return fIsPanZoom;
}
bool MouseParameters::IsRotate() const
{
return fIsRotate;
}
MouseParameters::ESpeed MouseParameters::GetSpeed() const
{
return fSpeed;
}
void MouseParameters::SetPanZoom(bool isPanZoom)
{
fIsPanZoom=isPanZoom;
}
void MouseParameters::SetRotate(bool isRotate)
{
fIsRotate=isRotate;
}
void MouseParameters::SetSpeed(ESpeed speed)
{
fSpeed=speed;
}
MouseParameters::ENavigation MouseParameters::GetNavigationMode() const
{
return fNavigation;
}
MouseParameters::EPivot MouseParameters::GetPivotMode() const
{
return fPivot;
}
MouseParameters::EPivotVisibility MouseParameters::GetPivotVisibility() const
{
return fPivotVisibility;
}
bool MouseParameters::IsLockHorizon() const
{
return fIsLockHorizon;
}
void MouseParameters::SetLockHorizon(bool bOn)
{
fIsLockHorizon=bOn;
}
void MouseParameters::SetNavigationMode(ENavigation navigation)
{
fNavigation=navigation;
}
void MouseParameters::SetPivotMode(EPivot pivot)
{
if (fPivot!=kManualPivot || pivot!=kAutoPivotOverride)
fPivot = pivot;
}
void MouseParameters::SetPivotVisibility(EPivotVisibility visibility)
{
fPivotVisibility = visibility;
}

View File

@ -0,0 +1,56 @@
/*
Development tools and related technology provided under license from 3Dconnexion.
(c) 1992 - 2012 3Dconnexion. All rights reserved
*/
#ifndef T3D_MOUSE_PARAMS_H
#define T3D_MOUSE_PARAMS_H
#include "I3dMouseParams.h"
class MouseParameters : public I3dMouseParam
{
public:
MouseParameters();
~MouseParameters();
// I3dmouseSensor interface
bool IsPanZoom() const;
bool IsRotate() const;
ESpeed GetSpeed() const;
void SetPanZoom(bool isPanZoom);
void SetRotate(bool isRotate);
void SetSpeed(ESpeed speed);
// I3dmouseNavigation interface
ENavigation GetNavigationMode() const;
EPivot GetPivotMode() const;
EPivotVisibility GetPivotVisibility() const;
bool IsLockHorizon() const;
void SetLockHorizon(bool bOn);
void SetNavigationMode(ENavigation navigation);
void SetPivotMode(EPivot pivot);
void SetPivotVisibility(EPivotVisibility visibility);
private:
MouseParameters (const MouseParameters&);
const MouseParameters& operator =(const MouseParameters&);
ENavigation fNavigation;
EPivot fPivot;
EPivotVisibility fPivotVisibility;
bool fIsLockHorizon;
bool fIsPanZoom;
bool fIsRotate;
ESpeed fSpeed;
};
#endif // T3D_MOUSE_PARAMS_H

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

@ -181,6 +181,7 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
else if (press && (this->currentmode == NavigationStyle::PANNING ||
this->currentmode == NavigationStyle::ZOOMING)) {
newmode = NavigationStyle::DRAGGING;
saveCursorPosition(ev);
this->centerTime = ev->getTime();
processed = TRUE;
}
@ -221,6 +222,7 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
if (press && (this->currentmode == NavigationStyle::PANNING ||
this->currentmode == NavigationStyle::ZOOMING)) {
newmode = NavigationStyle::DRAGGING;
saveCursorPosition(ev);
this->centerTime = ev->getTime();
processed = TRUE;
}
@ -285,6 +287,7 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
else if (this->currentmode == NavigationStyle::DRAGGING) {
this->addToLog(event->getPosition(), event->getTime());
this->spin(posn);
moveCursorPosition();
processed = TRUE;
}
}
@ -338,6 +341,9 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
newmode = NavigationStyle::PANNING;
break;
case BUTTON3DOWN:
if (newmode != NavigationStyle::DRAGGING) {
saveCursorPosition(ev);
}
newmode = NavigationStyle::DRAGGING;
break;
case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:

View File

@ -210,6 +210,7 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev)
else if (press && (this->currentmode == NavigationStyle::PANNING ||
this->currentmode == NavigationStyle::ZOOMING)) {
newmode = NavigationStyle::DRAGGING;
saveCursorPosition(ev);
this->centerTime = ev->getTime();
processed = TRUE;
}
@ -250,6 +251,7 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev)
if (press && (this->currentmode == NavigationStyle::PANNING ||
this->currentmode == NavigationStyle::ZOOMING)) {
newmode = NavigationStyle::DRAGGING;
saveCursorPosition(ev);
this->centerTime = ev->getTime();
processed = TRUE;
}
@ -314,6 +316,7 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev)
else if (this->currentmode == NavigationStyle::DRAGGING) {
this->addToLog(event->getPosition(), event->getTime());
this->spin(posn);
moveCursorPosition();
processed = TRUE;
}
}
@ -379,6 +382,9 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev)
newmode = NavigationStyle::PANNING;
break;
case SHIFTDOWN|BUTTON2DOWN:
if (newmode != NavigationStyle::DRAGGING) {
saveCursorPosition(ev);
}
newmode = NavigationStyle::DRAGGING;
break;
case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:

View File

@ -3,6 +3,9 @@
if(WIN32)
add_definitions(-DFCGui -DQIIS_MAKEDLL)
endif(WIN32)
if (FREECAD_USE_3DCONNEXION)
add_definitions(-D_USE_3DCONNEXION_SDK)
endif(FREECAD_USE_3DCONNEXION)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
@ -78,6 +81,17 @@ SET(FreeCADGui_XML_SRCS
)
SOURCE_GROUP("XML" FILES ${FreeCADApp_XML_SRCS})
# The 3D Connexion SDK files
if(FREECAD_USE_3DCONNEXION)
SET(FreeCADGui_SDK_SRCS
3Dconnexion/I3dMouseParams.h
3Dconnexion/MouseParameters.cpp
3Dconnexion/MouseParameters.h
3Dconnexion/GuiApplicationNativeEventAwareWin32.cpp
)
SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS})
endif(FREECAD_USE_3DCONNEXION)
set(Gui_MOC_HDRS
Action.h
CallTips.h
@ -769,6 +783,7 @@ SET(FreeCADGui_SRCS
)
SET(FreeCADGui_SRCS
${FreeCADGui_SDK_SRCS}
${FreeCADGui_CPP_SRCS}
${FreeCADGui_XML_SRCS}
${iis_MOC_SRCS}

View File

@ -33,6 +33,7 @@
# include <QPointer>
# include <QProcess>
# include <sstream>
# include <Inventor/nodes/SoCamera.h>
#endif
#include <algorithm>
@ -292,7 +293,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));
@ -1176,16 +1177,27 @@ void StdCmdAlignment::activated(int iMsg)
model.addGroups(groupMap);
align->setModel(model);
Base::Type style = Base::Type::fromName("Gui::CADNavigationStyle");
Base::Vector3d upDir(0,1,0), viewDir(0,0,-1);
Gui::Document* doc = Application::Instance->activeDocument();
if (doc) {
View3DInventor* mdi = qobject_cast<View3DInventor*>(doc->getActiveView());
if (mdi) {
style = mdi->getViewer()->navigationStyle()->getTypeId();
View3DInventorViewer* viewer = mdi->getViewer();
SoCamera* camera = viewer->getCamera();
if (camera) {
SbVec3f up(0,1,0), dir(0,0,-1);
camera->orientation.getValue().multVec(dir, dir);
viewDir.Set(dir[0],dir[1],dir[2]);
camera->orientation.getValue().multVec(up, up);
upDir.Set(up[0],up[1],up[2]);
}
style = viewer->navigationStyle()->getTypeId();
}
}
align->setMinPoints(1);
align->startAlignment(style);
align->setViewingDirections(viewDir,upDir, viewDir,upDir);
Gui::Selection().clearSelection();
}

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

@ -405,6 +405,9 @@ void Document::slotDeletedObject(const App::DocumentObject& Obj)
// cycling to all views of the document
ViewProvider* viewProvider = getViewProvider(&Obj);
#if 0 // With this we can show child objects again if this method was called by undo
viewProvider->onDelete(std::vector<std::string>());
#endif
if (viewProvider && viewProvider->getTypeId().isDerivedFrom
(ViewProviderDocumentObject::getClassTypeId())) {
// go through the views
@ -504,7 +507,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()) {
@ -927,13 +930,16 @@ bool Document::canClose ()
return false;
}
else if (!Gui::Control().isAllowedAlterDocument()) {
QMessageBox::warning(getActiveView(),
QObject::tr("Document not closable"),
QObject::tr("The document is in editing mode and thus cannot be closed for the moment.\n"
"You either have to finish or cancel the editing in the task panel."));
Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
if (dlg) Gui::Control().showDialog(dlg);
return false;
std::string name = Gui::Control().activeDialog()->getDocumentName();
if (name == this->getDocument()->getName()) {
QMessageBox::warning(getActiveView(),
QObject::tr("Document not closable"),
QObject::tr("The document is in editing mode and thus cannot be closed for the moment.\n"
"You either have to finish or cancel the editing in the task panel."));
Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
if (dlg) Gui::Control().showDialog(dlg);
return false;
}
}
if (!isModified())

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

@ -40,11 +40,10 @@
#endif
#endif
#ifdef Q_WS_WIN
#include <windows.h>
#ifdef _USE_3DCONNEXION_SDK
Gui::GUIApplicationNativeEventAware* Gui::GUIApplicationNativeEventAware::gMouseInput = 0;
#endif
Gui::GUIApplicationNativeEventAware::GUIApplicationNativeEventAware(int &argc, char *argv[]) :
QApplication (argc, argv), spaceballPresent(false)
{
@ -59,11 +58,18 @@ Gui::GUIApplicationNativeEventAware::~GUIApplicationNativeEventAware()
else
Base::Console().Log("Disconnected from spacenav daemon\n");
#endif
#ifdef _USE_3DCONNEXION_SDK
if (gMouseInput == this) {
gMouseInput = 0;
}
#endif
}
void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window)
{
mainWindow = window;
#ifdef SPNAV_FOUND
if (spnav_x11_open(QX11Info::display(), window->winId()) == -1)
Base::Console().Log("Couldn't connect to spacenav daemon\n");
@ -74,6 +80,19 @@ void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window)
}
#endif
#ifdef _USE_3DCONNEXION_SDK
spaceballPresent = Is3dmouseAttached();
if (spaceballPresent) {
fLast3dmouseInputTime = 0;
if (InitializeRawInput(mainWindow->winId())){
gMouseInput = this;
qApp->setEventFilter(Gui::GUIApplicationNativeEventAware::RawInputEventFilter);
}
}
#endif // _USE_3DCONNEXION_SDK
Spaceball::MotionEvent::MotionEventType = QEvent::registerEventType();
Spaceball::ButtonEvent::ButtonEventType = QEvent::registerEventType();
}
@ -146,15 +165,8 @@ bool Gui::GUIApplicationNativeEventAware::x11EventFilter(XEvent *event)
return true;
#else
return false;
#endif
#endif // SPNAV_FOUND
}
#endif
#ifdef Q_WS_WIN
bool Gui::GUIApplicationNativeEventAware::winEventFilter(MSG *msg, long *result)
{
return false;
}
#endif
#endif // Q_WS_X11
#include "moc_GuiApplicationNativeEventAware.cpp"

View File

@ -29,6 +29,19 @@
class QMainWindow;
#ifdef _USE_3DCONNEXION_SDK
#include "3Dconnexion/MouseParameters.h"
#include <vector>
#include <map>
// #define _WIN32_WINNT 0x0501 //target at least windows XP
#include <Windows.h>
#endif // _USE_3DCONNEXION_SDK
namespace Gui
{
class GUIApplicationNativeEventAware : public QApplication
@ -38,18 +51,65 @@ namespace Gui
GUIApplicationNativeEventAware(int &argc, char *argv[]);
~GUIApplicationNativeEventAware();
void initSpaceball(QMainWindow *window);
bool isSpaceballPresent() const {return spaceballPresent;}
bool processSpaceballEvent(QObject *object, QEvent *event);
#ifdef Q_WS_X11
bool x11EventFilter(XEvent *event);
#endif
#ifdef Q_WS_WIN
bool winEventFilter(MSG *msg, long *result);
#endif
bool isSpaceballPresent(){return spaceballPresent;}
private:
bool spaceballPresent;
QMainWindow *mainWindow;
// For X11
#ifdef Q_WS_X11
public:
bool x11EventFilter(XEvent *event);
#endif // Q_WS_X11
// For Windows
#ifdef _USE_3DCONNEXION_SDK
public:
static bool Is3dmouseAttached();
I3dMouseParam& MouseParams();
const I3dMouseParam& MouseParams() const;
virtual void Move3d(HANDLE device, std::vector<float>& motionData);
virtual void On3dmouseKeyDown(HANDLE device, int virtualKeyCode);
virtual void On3dmouseKeyUp(HANDLE device, int virtualKeyCode);
private:
bool InitializeRawInput(HWND hwndTarget);
static bool RawInputEventFilter(void* msg, long* result);
void OnRawInput(UINT nInputCode, HRAWINPUT hRawInput);
UINT GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader);
bool TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInput);
void On3dmouseInput();
class TInputData
{
public:
TInputData() : fAxes(6) {}
bool IsZero() {
return (0.==fAxes[0] && 0.==fAxes[1] && 0.==fAxes[2] &&
0.==fAxes[3] && 0.==fAxes[4] && 0.==fAxes[5]);
}
int fTimeToLive; // For telling if the device was unplugged while sending data
bool fIsDirty;
std::vector<float> fAxes;
};
HWND fWindow;
// Data cache to handle multiple rawinput devices
std::map< HANDLE, TInputData> fDevice2Data;
std::map< HANDLE, unsigned long> fDevice2Keystate;
// 3dmouse parameters
MouseParameters f3dMouseParams; // Rotate, Pan Zoom etc.
// use to calculate distance traveled since last event
DWORD fLast3dmouseInputTime;
static Gui::GUIApplicationNativeEventAware* gMouseInput;
#endif // _USE_3DCONNEXION_SDK
};
}
#endif // GUIAPPLICATIONNATIVEEVENTAWARE_H

View File

@ -279,6 +279,7 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev)
else if (this->currentmode == NavigationStyle::DRAGGING) {
this->addToLog(event->getPosition(), event->getTime());
this->spin(posn);
moveCursorPosition();
processed = TRUE;
}
}
@ -316,6 +317,9 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev)
}
break;
case BUTTON1DOWN:
if (newmode != NavigationStyle::DRAGGING) {
saveCursorPosition(ev);
}
newmode = NavigationStyle::DRAGGING;
break;
case BUTTON3DOWN:

View File

@ -26,6 +26,7 @@
#ifndef _PreComp_
# include <assert.h>
# include <stdio.h>
# include <QApplication>
# include <QFile>
# include <QTextStream>
#endif
@ -232,9 +233,7 @@ void MacroManager::run(MacroType eType,const char *sName)
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

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

@ -54,10 +54,14 @@ struct NavigationStyleP {
SbVec3f focal1, focal2;
SbRotation endRotation;
SoTimerSensor * animsensor;
float sensitivity;
SbBool resetcursorpos;
NavigationStyleP()
{
this->animationsteps = 0;
this->sensitivity = 2.0f;
this->resetcursorpos = FALSE;
}
static void viewAnimationCB(void * data, SoSensor * sensor);
};
@ -372,7 +376,7 @@ void NavigationStyle::lookAtPoint(const SbVec3f& pos)
}
}
void NavigationStyle::setCameraOrientation(const SbRotation& rot)
void NavigationStyle::setCameraOrientation(const SbRotation& rot, SbBool moveToCenter)
{
SoCamera* cam = viewer->getCamera();
if (cam == 0) return;
@ -383,16 +387,18 @@ void NavigationStyle::setCameraOrientation(const SbRotation& rot)
PRIVATE(this)->focal1 = cam->position.getValue() +
cam->focalDistance.getValue() * direction;
PRIVATE(this)->focal2 = PRIVATE(this)->focal1;
SoGetBoundingBoxAction action(viewer->getViewportRegion());
action.apply(viewer->getSceneGraph());
SbBox3f box = action.getBoundingBox();
if (!box.isEmpty()) {
rot.multVec(SbVec3f(0, 0, -1), direction);
//float s = (this->focal1 - box.getCenter()).dot(direction);
//this->focal2 = box.getCenter() + s * direction;
// setting the center of the overall bounding box as the future focal point
// seems to be a satisfactory solution
PRIVATE(this)->focal2 = box.getCenter();
if (moveToCenter) {
SoGetBoundingBoxAction action(viewer->getViewportRegion());
action.apply(viewer->getSceneGraph());
SbBox3f box = action.getBoundingBox();
if (!box.isEmpty()) {
rot.multVec(SbVec3f(0, 0, -1), direction);
//float s = (this->focal1 - box.getCenter()).dot(direction);
//this->focal2 = box.getCenter() + s * direction;
// setting the center of the overall bounding box as the future focal point
// seems to be a satisfactory solution
PRIVATE(this)->focal2 = box.getCenter();
}
}
// avoid to interfere with spinning (fixes #3101462)
@ -780,6 +786,14 @@ void NavigationStyle::spin(const SbVec2f & pointerpos)
this->spinprojector->project(lastpos);
SbRotation r;
this->spinprojector->projectAndGetRotation(pointerpos, r);
float sensitivity = getSensitivity();
if (sensitivity > 1.0f) {
SbVec3f axis;
float radians;
r.getValue(axis, radians);
radians = sensitivity * radians;
r.setValue(axis, radians);
}
r.invert();
this->reorientCamera(viewer->getCamera(), r);
@ -834,6 +848,25 @@ SbBool NavigationStyle::doSpin()
return FALSE;
}
void NavigationStyle::saveCursorPosition(const SoEvent * const ev)
{
this->globalPos.setValue(QCursor::pos().x(), QCursor::pos().y());
this->localPos = ev->getPosition();
}
void NavigationStyle::moveCursorPosition()
{
if (!isResetCursorPosition())
return;
QPoint cpos = QCursor::pos();
if (abs(cpos.x()-globalPos[0]) > 10 ||
abs(cpos.y()-globalPos[1]) > 10) {
QCursor::setPos(globalPos[0], globalPos[1]-1);
this->log.position[0] = localPos;
}
}
void NavigationStyle::updateAnimation()
{
SbTime now = SbTime::getTimeOfDay();
@ -923,6 +956,26 @@ void NavigationStyle::stopAnimating(void)
NavigationStyle::IDLE : NavigationStyle::INTERACT);
}
void NavigationStyle::setSensitivity(float val)
{
PRIVATE(this)->sensitivity = val;
}
float NavigationStyle::getSensitivity() const
{
return PRIVATE(this)->sensitivity;
}
void NavigationStyle::setResetCursorPosition(SbBool on)
{
PRIVATE(this)->resetcursorpos = on;
}
SbBool NavigationStyle::isResetCursorPosition() const
{
return PRIVATE(this)->resetcursorpos;
}
void NavigationStyle::setZoomInverted(SbBool on)
{
this->invertZoom = on;

View File

@ -110,6 +110,12 @@ public:
void stopAnimating(void);
SbBool isAnimating(void) const;
void setSensitivity(float);
float getSensitivity() const;
void setResetCursorPosition(SbBool);
SbBool isResetCursorPosition() const;
void setZoomInverted(SbBool);
SbBool isZoomInverted() const;
void setZoomStep(float);
@ -121,7 +127,7 @@ public:
void updateAnimation();
void redraw();
void setCameraOrientation(const SbRotation& rot);
void setCameraOrientation(const SbRotation& rot, SbBool moveTocenter=false);
void lookAtPoint(const SbVec3f&);
void boxZoom(const SbBox2s& box);
virtual void viewAll();
@ -172,6 +178,8 @@ protected:
void doZoom(SoCamera * camera, SbBool forward, const SbVec2f& pos);
void spin(const SbVec2f & pointerpos);
SbBool doSpin();
void moveCursorPosition();
void saveCursorPosition(const SoEvent * const ev);
SbBool handleEventInForeground(const SoEvent* const e);
virtual SbBool processSoEvent(const SoEvent * const ev);
@ -192,6 +200,8 @@ protected:
View3DInventorViewer* viewer;
ViewerMode currentmode;
SbVec2f lastmouseposition;
SbVec2s globalPos;
SbVec2s localPos;
SbPlane panningplane;
SbTime prevRedrawTime;
SbTime centerTime;

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

@ -180,21 +180,21 @@ public:
PythonSyntaxHighlighterP()
{
keywords << QLatin1String("and") << QLatin1String("as")
<< QLatin1String("assert")
<< QLatin1String("break") << QLatin1String("class")
<< QLatin1String("continue") << QLatin1String("def")
<< QLatin1String("del") << QLatin1String("elif")
<< QLatin1String("else") << QLatin1String("except")
<< QLatin1String("exec") << QLatin1String("finally")
<< QLatin1String("for") << QLatin1String("from")
<< QLatin1String("global") << QLatin1String("if")
<< QLatin1String("import") << QLatin1String("in")
<< QLatin1String("is") << QLatin1String("lambda")
<< QLatin1String("None") << QLatin1String("not")
<< QLatin1String("or") << QLatin1String("pass")
<< QLatin1String("print") << QLatin1String("raise")
<< QLatin1String("return") << QLatin1String("try")
<< QLatin1String("while") << QLatin1String("yield");
<< QLatin1String("assert") << QLatin1String("break")
<< QLatin1String("class") << QLatin1String("continue")
<< QLatin1String("def") << QLatin1String("del")
<< QLatin1String("elif") << QLatin1String("else")
<< QLatin1String("except") << QLatin1String("exec")
<< QLatin1String("finally") << QLatin1String("for")
<< QLatin1String("from") << QLatin1String("global")
<< QLatin1String("if") << QLatin1String("import")
<< QLatin1String("in") << QLatin1String("is")
<< QLatin1String("lambda") << QLatin1String("None")
<< QLatin1String("not") << QLatin1String("or")
<< QLatin1String("pass") << QLatin1String("print")
<< QLatin1String("raise") << QLatin1String("return")
<< QLatin1String("try") << QLatin1String("while")
<< QLatin1String("with") << QLatin1String("yield");
}
QStringList keywords;

View File

@ -26,6 +26,7 @@
# include <Python.h>
# include <QApplication>
# include <QClipboard>
# include <QDialogButtonBox>
# include <QMutex>
# include <QProcess>
# include <QSysInfo>
@ -88,23 +89,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)
{
@ -174,7 +183,11 @@ AboutDialogFactory::~AboutDialogFactory()
QDialog *AboutDialogFactory::create(QWidget *parent) const
{
#ifdef _USE_3DCONNEXION_SDK
return new AboutDialog(true, parent);
#else
return new AboutDialog(false, parent);
#endif
}
const AboutDialogFactory *AboutDialogFactory::defaultFactory()
@ -267,11 +280,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());
@ -328,8 +339,54 @@ void AboutDialog::setupLabels()
}
}
namespace Gui {
namespace Dialog {
class GuiExport LicenseDialog : public QDialog
{
public:
LicenseDialog(QWidget *parent = 0) : QDialog(parent, Qt::FramelessWindowHint)
{
QString info;
#ifdef _USE_3DCONNEXION_SDK
info = QString::fromAscii(
"3D Mouse Support:\n"
"Development tools and related technology provided under license from 3Dconnexion.\n"
"(c) 1992 - 2012 3Dconnexion. All rights reserved");
#endif
statusLabel = new QLabel(info);
buttonBox = new QDialogButtonBox;
buttonBox->setStandardButtons(QDialogButtonBox::Ok);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
QHBoxLayout *topLayout = new QHBoxLayout;
topLayout->addWidget(statusLabel);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(topLayout);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Copyright"));
}
~LicenseDialog()
{
}
private:
QLabel *statusLabel;
QDialogButtonBox *buttonBox;
};
} // namespace Dialog
} // namespace Gui
void AboutDialog::on_licenseButton_clicked()
{
#ifdef _USE_3DCONNEXION_SDK
LicenseDialog dlg(this);
dlg.exec();
#endif
}
void AboutDialog::on_copyButton_clicked()

View File

@ -67,6 +67,8 @@ public:
virtual void modifyStandardButtons(QDialogButtonBox*)
{}
const std::string& getDocumentName() const
{ return documentName; }
virtual bool isAllowedAlterDocument(void) const
{ return false; }
virtual bool isAllowedAlterView(void) const
@ -92,6 +94,7 @@ protected:
/// List of TaskBoxes of that dialog
std::vector<QWidget*> Content;
ButtonPosition pos;
std::string documentName;
};
} //namespace TaskView

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

@ -185,6 +185,7 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev)
else if (press && (this->currentmode == NavigationStyle::PANNING ||
this->currentmode == NavigationStyle::ZOOMING)) {
newmode = NavigationStyle::DRAGGING;
saveCursorPosition(ev);
this->centerTime = ev->getTime();
processed = TRUE;
}
@ -225,6 +226,7 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev)
if (press && (this->currentmode == NavigationStyle::PANNING ||
this->currentmode == NavigationStyle::ZOOMING)) {
newmode = NavigationStyle::DRAGGING;
saveCursorPosition(ev);
this->centerTime = ev->getTime();
processed = TRUE;
}
@ -259,6 +261,7 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev)
else if (this->currentmode == NavigationStyle::DRAGGING) {
this->addToLog(event->getPosition(), event->getTime());
this->spin(posn);
moveCursorPosition();
processed = TRUE;
}
}
@ -305,6 +308,9 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev)
break;
case ALTDOWN:
case CTRLDOWN|SHIFTDOWN:
if (newmode != NavigationStyle::DRAGGING) {
saveCursorPosition(ev);
}
newmode = NavigationStyle::DRAGGING;
break;
case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN:

View File

@ -140,6 +140,8 @@ View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent, Qt::W
OnChange(*hGrp,"BacklightIntensity");
OnChange(*hGrp,"NavigationStyle");
OnChange(*hGrp,"OrbitStyle");
OnChange(*hGrp,"Sensitivity");
OnChange(*hGrp,"ResetCursorPosition");
stopSpinTimer = new QTimer(this);
connect(stopSpinTimer, SIGNAL(timeout()), this, SLOT(stopAnimating()));
@ -274,6 +276,14 @@ void View3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M
int style = rGrp.GetInt("OrbitStyle",1);
_viewer->navigationStyle()->setOrbitStyle(NavigationStyle::OrbitStyle(style));
}
else if (strcmp(Reason,"Sensitivity") == 0) {
float val = rGrp.GetFloat("Sensitivity",2.0f);
_viewer->navigationStyle()->setSensitivity(val);
}
else if (strcmp(Reason,"ResetCursorPosition") == 0) {
bool on = rGrp.GetBool("ResetCursorPosition",false);
_viewer->navigationStyle()->setResetCursorPosition(on);
}
else if (strcmp(Reason,"InvertZoom") == 0) {
bool on = rGrp.GetBool("InvertZoom", false);
_viewer->navigationStyle()->setZoomInverted(on);

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

@ -1309,9 +1309,9 @@ void View3DInventorViewer::pubSeekToPoint(const SbVec3f& pos)
this->seekToPoint(pos);
}
void View3DInventorViewer::setCameraOrientation(const SbRotation& rot)
void View3DInventorViewer::setCameraOrientation(const SbRotation& rot, SbBool moveTocenter)
{
navigation->setCameraOrientation(rot);
navigation->setCameraOrientation(rot, moveTocenter);
}
void View3DInventorViewer::setCameraType(SoType t)

View File

@ -231,7 +231,7 @@ public:
* \a TRUE the reorientation is animated, otherwise its directly
* set.
*/
void setCameraOrientation(const SbRotation& rot);
void setCameraOrientation(const SbRotation& rot, SbBool moveTocenter=false);
void setCameraType(SoType t);
void moveCameraTo(const SbRotation& rot, const SbVec3f& pos, int steps, int ms);
/**

View File

@ -464,7 +464,8 @@ Py::Object View3DInventorPy::viewRotateRight(const Py::Tuple& args)
Py::Object View3DInventorPy::setCameraOrientation(const Py::Tuple& args)
{
PyObject* o;
if (!PyArg_ParseTuple(args.ptr(), "O!", &PyTuple_Type, &o))
PyObject* m=0;
if (!PyArg_ParseTuple(args.ptr(), "O!|O!", &PyTuple_Type, &o, &PyBool_Type, &m))
throw Py::Exception();
try {
@ -473,7 +474,7 @@ Py::Object View3DInventorPy::setCameraOrientation(const Py::Tuple& args)
float q1 = (float)Py::Float(tuple[1]);
float q2 = (float)Py::Float(tuple[2]);
float q3 = (float)Py::Float(tuple[3]);
_view->getViewer()->setCameraOrientation(SbRotation(q0, q1, q2, q3));
_view->getViewer()->setCameraOrientation(SbRotation(q0, q1, q2, q3), m==Py_True);
}
catch (const Base::Exception& e) {
throw Py::Exception(e.what());

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

@ -75,6 +75,14 @@ def removeComponents(objectsList,host=None):
objectsList = [objectsList]
if host:
if Draft.getType(host) in ["Wall","Structure"]:
if hasattr(host,"Axes"):
a = host.Axes
print a
for o in objectsList[:]:
print o.Name
if o in a:
a.remove(o)
objectsList.remove(o)
s = host.Subtractions
for o in objectsList:
if not o in s:
@ -154,31 +162,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 +199,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):
@ -79,7 +80,7 @@ def removeFromComponent(compobject,subobject):
it is added as a subtraction.'''
if compobject == subobject: return
found = False
attribs = ["Additions","Subtractions","Objects","Components","Base"]
attribs = ["Additions","Subtractions","Objects","Components","Base","Axes"]
for a in attribs:
if hasattr(compobject,a):
if a == "Base":

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

@ -86,6 +86,8 @@ class _Structure(ArchComponent.Component):
str(translate("Arch","Axes systems this structure is built on")))
obj.addProperty("App::PropertyVector","Normal","Base",
str(translate("Arch","The normal extrusion direction of this object (keep (0,0,0) for automatic normal)")))
obj.addProperty("App::PropertyIntegerList","Exclude","Base",
str(translate("Arch","The element numbers to exclude when this structure is based on axes")))
self.Type = "Structure"
def execute(self,obj):
@ -110,6 +112,12 @@ class _Structure(ArchComponent.Component):
pts.extend(DraftGeomUtils.findIntersection(e1,e2))
return pts
def getAxisPlacement(self,obj):
"returns an axis placement"
if obj.Axes:
return obj.Axes[0].Placement
return None
def createGeometry(self,obj):
import Part, DraftGeomUtils
@ -174,22 +182,32 @@ class _Structure(ArchComponent.Component):
if not hole.Shape.isNull():
base = base.cut(hole.Shape)
hole.ViewObject.hide() # to be removed
# applying axes
pts = self.getAxisPoints(obj)
apl = self.getAxisPlacement(obj)
if pts:
fsh = []
for p in pts:
for i in range(len(pts)):
if hasattr(obj,"Exclude"):
if i in obj.Exclude:
continue
sh = base.copy()
sh.translate(p)
if apl:
sh.Placement.Rotation = apl.Rotation
sh.translate(pts[i])
fsh.append(sh)
obj.Shape = Part.makeCompound(fsh)
# finalizing
else:
if base:
if not base.isNull():
base = base.removeSplitter()
obj.Shape = base
if not DraftGeomUtils.isNull(pl):
obj.Placement = pl
if not DraftGeomUtils.isNull(pl):
obj.Placement = pl
class _ViewProviderStructure(ArchComponent.ViewProviderComponent):
"A View Provider for the Structure object"

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

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

@ -288,11 +288,13 @@ class Snapper:
origin = Vector(self.snapInfo['x'],self.snapInfo['y'],self.snapInfo['z'])
winner = [Vector(0,0,0),None,Vector(0,0,0)]
for snap in snaps:
# if snap[0] == None: print "debug: Snapper: 'i[0]' is 'None'"
delta = snap[0].sub(origin)
if delta.Length < shortest:
shortest = delta.Length
winner = snap
if snap[0] == None:
print "debug: Snapper: snap point = ",snap
else:
delta = snap[0].sub(origin)
if delta.Length < shortest:
shortest = delta.Length
winner = snap
# see if we are out of the max radius, if any
if self.radius:

View File

@ -565,7 +565,8 @@ bool MeshInput::LoadOFF (std::istream &rstrIn)
meshPoints.reserve(numPoints);
meshFacets.reserve(numFaces);
for (int i=0; i<numPoints; i++) {
int cntPoints = 0;
while (cntPoints < numPoints) {
if (!std::getline(rstrIn, line))
break;
if (boost::regex_match(line.c_str(), what, rx_p)) {
@ -573,9 +574,12 @@ bool MeshInput::LoadOFF (std::istream &rstrIn)
fY = (float)std::atof(what[4].first);
fZ = (float)std::atof(what[7].first);
meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
cntPoints++;
}
}
for (int i=0; i<numFaces; i++) {
int cntFaces = 0;
while (cntFaces < numFaces) {
if (!std::getline(rstrIn, line))
break;
if (boost::regex_match(line.c_str(), what, rx_f3)) {
@ -586,6 +590,7 @@ bool MeshInput::LoadOFF (std::istream &rstrIn)
i3 = std::atoi(what[4].first);
item.SetVertices(i1,i2,i3);
meshFacets.push_back(item);
cntFaces++;
}
}
else if (boost::regex_match(line.c_str(), what, rx_f4)) {
@ -601,6 +606,7 @@ bool MeshInput::LoadOFF (std::istream &rstrIn)
item.SetVertices(i3,i4,i1);
meshFacets.push_back(item);
cntFaces++;
}
}
}

View File

@ -677,9 +677,33 @@
<UserDocu>Returns a reparametrized copy of this surface</UserDocu>
</Documentation>
</Methode>
<Methode Name="approximate">
<Documentation>
<UserDocu>
approximate(points, degMin, degMax, continuity, tol)
approximate(zPoints, degMin, degMax, continuity, tol, X0, dX, Y0, dY)
Replaces this B-Spline surface by approximating a set of points.
continuity is an integer between 0 and 3
</UserDocu>
</Documentation>
</Methode>
<Methode Name="interpolate">
<Documentation>
<UserDocu>Replaces this B-Spline surface by interpolating a set of points.</UserDocu>
<UserDocu>
interpolate(points)
interpolate(zpoints, X0, dX, Y0, dY)
Replaces this B-Spline surface by interpolating a set of points.
The resulting surface is of degree 3 and continuity C2.
Arguments:
a 2 dimensional array of vectors, that the surface passes through
or
a 2 dimensional array of floats with the z values,
the x starting point X0 (float),
the x increment dX (float),
the y starting point Y0 and increment dY
</UserDocu>
</Documentation>
</Methode>
</PythonExport>

View File

@ -33,6 +33,7 @@
# include <TColgp_Array2OfPnt.hxx>
# include <Precision.hxx>
# include <GeomAPI_PointsToBSplineSurface.hxx>
# include <GeomAbs_Shape.hxx>
#endif
#include <Base/GeometryPyCXX.h>
@ -43,6 +44,7 @@
#include "BSplineSurfacePy.h"
#include "BSplineSurfacePy.cpp"
using namespace Part;
// returns a string which represents the object e.g. when printed in python
@ -1244,13 +1246,21 @@ PyObject* BSplineSurfacePy::reparametrize(PyObject * args)
}
}
PyObject* BSplineSurfacePy::interpolate(PyObject *args)
PyObject* BSplineSurfacePy::approximate(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))
Standard_Integer degMin=0;
Standard_Integer degMax=0;
Standard_Integer continuity=0;
Standard_Real tol3d = Precision::Approximation();
Standard_Real X0=0;
Standard_Real dX=0;
Standard_Real Y0=0;
Standard_Real dY=0;
int len = PyTuple_GET_SIZE(args);
if (!PyArg_ParseTuple(args, "O!iiid|dddd",&(PyList_Type), &obj, &degMin, &degMax, &continuity, &tol3d, &X0, &dX, &Y0, &dY))
return 0;
try {
Py::List list(obj);
@ -1258,6 +1268,8 @@ PyObject* BSplineSurfacePy::interpolate(PyObject *args)
Py::List col(list.getItem(0));
Standard_Integer lv = col.size();
TColgp_Array2OfPnt interpolationPoints(1, lu, 1, lv);
TColStd_Array2OfReal zPoints(1, lu, 1, lv);
//Base::Console().Message("lu=%d, lv=%d\n", lu, lv);
Standard_Integer index1 = 0;
Standard_Integer index2 = 0;
@ -1267,10 +1279,97 @@ PyObject* BSplineSurfacePy::interpolate(PyObject *args)
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(len == 5){
Py::Vector v(*it2);
Base::Vector3d pnt = v.toVector();
gp_Pnt newPoint(pnt.x,pnt.y,pnt.z);
interpolationPoints.SetValue(index1, index2, newPoint);
}
else {
Standard_Real val = PyFloat_AsDouble((*it2).ptr());
zPoints.SetValue(index1, index2, val);
}
}
}
if(continuity<0 || continuity>3){
Standard_Failure::Raise("continuity must be between 0 and 3");
}
GeomAbs_Shape c;
switch(continuity){
case 0:
c = GeomAbs_C0;
case 1:
c = GeomAbs_C1;
case 2:
c = GeomAbs_C2;
case 3:
c = GeomAbs_C3;
}
if (interpolationPoints.RowLength() < 2 || interpolationPoints.ColLength() < 2) {
Standard_Failure::Raise("not enough points given");
}
GeomAPI_PointsToBSplineSurface surInterpolation;
if(len == 5){
surInterpolation.Init(interpolationPoints, degMin, degMax, c, tol3d);
}
else {
surInterpolation.Init(zPoints, X0, dX, Y0, dY, degMin, degMax, c, tol3d);
}
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;
}
}
PyObject* BSplineSurfacePy::interpolate(PyObject *args)
{
PyObject* obj;
Standard_Real tol3d = Precision::Approximation();
Standard_Real X0=0;
Standard_Real dX=0;
Standard_Real Y0=0;
Standard_Real dY=0;
int len = PyTuple_GET_SIZE(args);
if (!PyArg_ParseTuple(args, "O!|dddd",&(PyList_Type), &obj, &X0, &dX, &Y0, &dY))
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);
TColStd_Array2OfReal zPoints(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++;
if(len == 1){
Py::Vector v(*it2);
Base::Vector3d pnt = v.toVector();
gp_Pnt newPoint(pnt.x,pnt.y,pnt.z);
interpolationPoints.SetValue(index1, index2, newPoint);
}
else {
Standard_Real val = PyFloat_AsDouble((*it2).ptr());
zPoints.SetValue(index1, index2, val);
}
}
}
@ -1279,7 +1378,12 @@ PyObject* BSplineSurfacePy::interpolate(PyObject *args)
}
GeomAPI_PointsToBSplineSurface surInterpolation;
surInterpolation.Interpolate (interpolationPoints);
if(len == 1){
surInterpolation.Interpolate (interpolationPoints);
}
else {
surInterpolation.Interpolate(zPoints, X0, dX, Y0, dY);
}
Handle_Geom_BSplineSurface sur(surInterpolation.Surface());
this->getGeomBSplineSurfacePtr()->setHandle(sur);
Py_Return;

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

@ -142,6 +142,26 @@ void ViewProviderBoolean::updateData(const App::Property* prop)
this->DiffuseColor.setValues(colBool);
}
}
else if (prop->getTypeId() == App::PropertyLink::getClassTypeId()) {
App::DocumentObject *pBase = static_cast<const App::PropertyLink*>(prop)->getValue();
if (pBase)
Gui::Application::Instance->hideViewProvider(pBase);
}
}
bool ViewProviderBoolean::onDelete(const std::vector<std::string> &)
{
// get the input shapes
Part::Boolean* pBool = static_cast<Part::Boolean*>(getObject());
App::DocumentObject *pBase = pBool->Base.getValue();
App::DocumentObject *pTool = pBool->Tool.getValue();
if (pBase)
Gui::Application::Instance->showViewProvider(pBase);
if (pTool)
Gui::Application::Instance->showViewProvider(pTool);
return true;
}
PROPERTY_SOURCE(PartGui::ViewProviderMultiFuse,PartGui::ViewProviderPart)
@ -207,6 +227,26 @@ void ViewProviderMultiFuse::updateData(const App::Property* prop)
if (setColor)
this->DiffuseColor.setValues(colBool);
}
else if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) {
std::vector<App::DocumentObject*> pShapes = static_cast<const App::PropertyLinkList*>(prop)->getValues();
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
if (*it)
Gui::Application::Instance->hideViewProvider(*it);
}
}
}
bool ViewProviderMultiFuse::onDelete(const std::vector<std::string> &)
{
// get the input shapes
Part::MultiFuse* pBool = static_cast<Part::MultiFuse*>(getObject());
std::vector<App::DocumentObject*> pShapes = pBool->Shapes.getValues();
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
if (*it)
Gui::Application::Instance->showViewProvider(*it);
}
return true;
}
@ -273,4 +313,24 @@ void ViewProviderMultiCommon::updateData(const App::Property* prop)
if (setColor)
this->DiffuseColor.setValues(colBool);
}
else if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) {
std::vector<App::DocumentObject*> pShapes = static_cast<const App::PropertyLinkList*>(prop)->getValues();
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
if (*it)
Gui::Application::Instance->hideViewProvider(*it);
}
}
}
bool ViewProviderMultiCommon::onDelete(const std::vector<std::string> &)
{
// get the input shapes
Part::MultiCommon* pBool = static_cast<Part::MultiCommon*>(getObject());
std::vector<App::DocumentObject*> pShapes = pBool->Shapes.getValues();
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
if (*it)
Gui::Application::Instance->showViewProvider(*it);
}
return true;
}

View File

@ -43,6 +43,7 @@ public:
std::vector<App::DocumentObject*> claimChildren(void) const;
QIcon getIcon(void) const;
void updateData(const App::Property*);
bool onDelete(const std::vector<std::string> &);
};
/// ViewProvider for the MultiFuse feature
@ -60,6 +61,7 @@ public:
std::vector<App::DocumentObject*> claimChildren(void) const;
QIcon getIcon(void) const;
void updateData(const App::Property*);
bool onDelete(const std::vector<std::string> &);
};
/// ViewProvider for the MultiFuse feature
@ -77,6 +79,7 @@ public:
std::vector<App::DocumentObject*> claimChildren(void) const;
QIcon getIcon(void) const;
void updateData(const App::Property*);
bool onDelete(const std::vector<std::string> &);
};

View File

@ -243,6 +243,17 @@ std::vector<App::DocumentObject*> ViewProviderFillet::claimChildren() const
return temp;
}
bool ViewProviderFillet::onDelete(const std::vector<std::string> &)
{
// get the input shape
Part::Fillet* pFillet = static_cast<Part::Fillet*>(getObject());
App::DocumentObject *pBase = pFillet->Base.getValue();
if (pBase)
Gui::Application::Instance->showViewProvider(pBase);
return true;
}
// ---------------------------------------
PROPERTY_SOURCE(PartGui::ViewProviderChamfer, PartGui::ViewProviderPart)
@ -296,6 +307,17 @@ std::vector<App::DocumentObject*> ViewProviderChamfer::claimChildren() const
return temp;
}
bool ViewProviderChamfer::onDelete(const std::vector<std::string> &)
{
// get the input shape
Part::Chamfer* pChamfer = static_cast<Part::Chamfer*>(getObject());
App::DocumentObject *pBase = pChamfer->Base.getValue();
if (pBase)
Gui::Application::Instance->showViewProvider(pBase);
return true;
}
// ---------------------------------------
PROPERTY_SOURCE(PartGui::ViewProviderRevolution, PartGui::ViewProviderPart)
@ -315,3 +337,14 @@ std::vector<App::DocumentObject*> ViewProviderRevolution::claimChildren() const
temp.push_back(static_cast<Part::Revolution*>(getObject())->Source.getValue());
return temp;
}
bool ViewProviderRevolution::onDelete(const std::vector<std::string> &)
{
// get the input shape
Part::Revolution* pRevolve = static_cast<Part::Revolution*>(getObject());
App::DocumentObject *pBase = pRevolve->Source.getValue();
if (pBase)
Gui::Application::Instance->showViewProvider(pBase);
return true;
}

View File

@ -64,6 +64,7 @@ public:
//@{
void setupContextMenu(QMenu*, QObject*, const char*);
std::vector<App::DocumentObject*> claimChildren() const;
bool onDelete(const std::vector<std::string> &);
protected:
bool setEdit(int ModNum);
@ -84,6 +85,7 @@ public:
//@{
void setupContextMenu(QMenu*, QObject*, const char*);
std::vector<App::DocumentObject*> claimChildren() const;
bool onDelete(const std::vector<std::string> &);
protected:
bool setEdit(int ModNum);
@ -103,6 +105,7 @@ public:
/// grouping handling
std::vector<App::DocumentObject*> claimChildren(void)const;
bool onDelete(const std::vector<std::string> &);
};
} // namespace PartGui

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

@ -224,7 +224,11 @@ Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const
assert(GeoId == H_Axis || GeoId == V_Axis ||
(GeoId <= getHighestCurveIndex() && GeoId >= -getExternalGeometryCount()) );
const Part::Geometry *geo = getGeometry(GeoId);
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) {
const Part::GeomPoint *p = dynamic_cast<const Part::GeomPoint*>(geo);
if (PosId == start || PosId == mid || PosId == end)
return p->getPoint();
} else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment*>(geo);
if (PosId == start)
return lineSeg->getStartPoint();

View File

@ -14,8 +14,8 @@
height="64px"
id="svg2726"
sodipodi:version="0.32"
inkscape:version="0.48.1 r9760"
sodipodi:docname="Sketcher_Point.svg"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Sketcher_CreatePoint.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1"
inkscape:export-filename="/home/yorik/Sources/FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreatePoint.svg.png"
@ -87,6 +87,17 @@
id="radialGradient3888"
xlink:href="#linearGradient3144-3"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3144"
id="radialGradient3767"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
cx="225.26402"
cy="672.79736"
fx="225.26402"
fy="672.79736"
r="34.345188" />
</defs>
<sodipodi:namedview
id="base"
@ -96,17 +107,17 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.8890873"
inkscape:cx="18.496032"
inkscape:cx="33.923816"
inkscape:cy="23.749836"
inkscape:current-layer="g4289"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1280"
inkscape:window-height="756"
inkscape:window-x="0"
inkscape:window-y="22"
inkscape:window-maximized="1" />
inkscape:window-width="657"
inkscape:window-height="716"
inkscape:window-x="710"
inkscape:window-y="24"
inkscape:window-maximized="0" />
<metadata
id="metadata2731">
<rdf:RDF>
@ -115,7 +126,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -133,35 +144,29 @@
sodipodi:cy="655.2193"
sodipodi:cx="197.14285"
id="path3162-2"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5.80000019000000044;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;opacity:0.67000001"
style="opacity:0.67000002;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5.09976673;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"
sodipodi:type="arc"
transform="matrix(-2.047093,-0.04650869,0.04650869,-2.047093,549.55577,1983.2711)" />
<g
inkscape:export-ydpi="7.0721951"
inkscape:export-xdpi="7.0721951"
inkscape:export-filename="/home/yorik/Documents/Lab/Draft/icons/line.png"
transform="matrix(-2.047093,-0.04650867,0.04650867,-2.047093,528.32631,1950.9451)"
id="g3160">
<path
sodipodi:type="arc"
style="fill:#ff2100;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5.80000019;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"
id="path3162"
sodipodi:cx="197.14285"
sodipodi:cy="655.2193"
sodipodi:rx="48.57143"
sodipodi:ry="48.57143"
d="m 245.71428,655.2193 c 0,26.82526 -21.74617,48.57143 -48.57143,48.57143 -26.82526,0 -48.57143,-21.74617 -48.57143,-48.57143 0,-26.82526 21.74617,-48.57143 48.57143,-48.57143 26.82526,0 48.57143,21.74617 48.57143,48.57143 z" />
<path
sodipodi:type="arc"
style="fill:url(#radialGradient3850);fill-opacity:1;stroke:none"
id="path3164"
sodipodi:cx="225.26402"
sodipodi:cy="672.79736"
sodipodi:rx="34.345188"
sodipodi:ry="23.991123"
d="m 259.60921,672.79736 c 0,13.24993 -15.37686,23.99113 -34.34519,23.99113 -18.96832,0 -34.34519,-10.7412 -34.34519,-23.99113 0,-13.24993 15.37687,-23.99112 34.34519,-23.99112 18.96833,0 34.34519,10.74119 34.34519,23.99112 z"
transform="matrix(0.8513023,-0.5246754,0.5246754,0.8513023,-338.69692,214.19328)" />
</g>
transform="matrix(-1.135537,-0.02584694,0.0257987,-1.13766,378.69194,1376.1392)" />
<path
d="m 245.71428,655.2193 a 48.57143,48.57143 0 1 1 -97.14286,0 48.57143,48.57143 0 1 1 97.14286,0 z"
sodipodi:ry="48.57143"
sodipodi:rx="48.57143"
sodipodi:cy="655.2193"
sodipodi:cx="197.14285"
id="path3162"
style="fill:#ff2100;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5.09976673;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"
sodipodi:type="arc"
transform="matrix(-1.135537,-0.02584692,0.02579869,-1.13766,366.91582,1358.1743)" />
<path
transform="matrix(-0.9802212,0.57489869,-0.57382585,-0.98205382,757.04461,1123.2494)"
d="m 259.60921,672.79736 a 34.345188,23.991123 0 1 1 -68.69038,0 34.345188,23.991123 0 1 1 68.69038,0 z"
sodipodi:ry="23.991123"
sodipodi:rx="34.345188"
sodipodi:cy="672.79736"
sodipodi:cx="225.26402"
id="path3164"
style="fill:url(#radialGradient3767);fill-opacity:1;stroke:none"
sodipodi:type="arc" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -65,8 +65,6 @@ public:
protected:
ViewProviderSketch *sketchView;
std::string documentName;
TaskSketcherConstrains *Constraints;
TaskSketcherGeneral *General;
TaskSketcherMessages *Messages;

View File

@ -34,6 +34,7 @@ def main():
gitattr.write("zipios++ export-ignore\n")
gitattr.write("Pivy-0.5 export-ignore\n")
gitattr.write("Pivy export-ignore\n")
gitattr.write("3Dconnexion export-ignore\n")
gitattr.write("Kuka export-ignore\n")
gitattr.close()