Merge branch 'master' into logari81/sketcher
This commit is contained in:
commit
b3284357d2
|
@ -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}")
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ IF(OCC_LIBRARY)
|
|||
TKSTEPBase
|
||||
TKSTEPAttr
|
||||
TKHLR
|
||||
TKFeat
|
||||
)
|
||||
ENDIF(OCC_LIBRARY)
|
||||
|
||||
|
|
|
@ -329,6 +329,7 @@ set(OCC_LIBRARIES
|
|||
TKSTEPBase
|
||||
TKSTEPAttr
|
||||
TKHLR
|
||||
TKFeat
|
||||
)
|
||||
set(OCC_LIBRARY_DIR
|
||||
${FREECAD_LIBPACK_DIR}/lib
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
2
src/3rdParty/salomesmesh/CMakeLists.txt
vendored
2
src/3rdParty/salomesmesh/CMakeLists.txt
vendored
|
@ -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")
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
|
718
src/Gui/3Dconnexion/GuiApplicationNativeEventAwareWin32.cpp
Normal file
718
src/Gui/3Dconnexion/GuiApplicationNativeEventAwareWin32.cpp
Normal 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
|
91
src/Gui/3Dconnexion/I3dMouseParams.h
Normal file
91
src/Gui/3Dconnexion/I3dMouseParams.h
Normal 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
|
||||
|
95
src/Gui/3Dconnexion/MouseParameters.cpp
Normal file
95
src/Gui/3Dconnexion/MouseParameters.cpp
Normal 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;
|
||||
}
|
56
src/Gui/3Dconnexion/MouseParameters.h
Normal file
56
src/Gui/3Dconnexion/MouseParameters.h
Normal 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
|
||||
|
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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, °Min, °Max, &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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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> &);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 |
|
@ -65,8 +65,6 @@ public:
|
|||
|
||||
protected:
|
||||
ViewProviderSketch *sketchView;
|
||||
std::string documentName;
|
||||
|
||||
TaskSketcherConstrains *Constraints;
|
||||
TaskSketcherGeneral *General;
|
||||
TaskSketcherMessages *Messages;
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user