From d9400ff0a21d2da531081049936c81cc3331e691 Mon Sep 17 00:00:00 2001 From: Maxime Tournier Date: Mon, 30 Jan 2017 16:37:52 +0100 Subject: [PATCH] added compliant_qtquickgui + interactor --- .gitignore | 3 +- CMakeLists.txt | 11 +- .../compliant_qtquickgui/CMakeLists.txt | 101 ++++++++++ .../CompliantQtQuickGUI.cpp | 95 ++++++++++ .../CompliantQtQuickGUI.h | 32 ++++ .../SofaCompliantInteractor.cpp | 178 ++++++++++++++++++ .../SofaCompliantInteractor.h | 132 +++++++++++++ .../compliant_qtquickguiConfig.cmake.in | 13 ++ .../UserInteractor_Compliant.qml | 72 +++++++ .../data/qml/compliant_qml.qrc | 5 + 10 files changed, 640 insertions(+), 2 deletions(-) create mode 100644 applications-dev/plugins/compliant_qtquickgui/CMakeLists.txt create mode 100644 applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.cpp create mode 100644 applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.h create mode 100644 applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.cpp create mode 100644 applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.h create mode 100644 applications-dev/plugins/compliant_qtquickgui/compliant_qtquickguiConfig.cmake.in create mode 100644 applications-dev/plugins/compliant_qtquickgui/data/qml/SofaInteractors/UserInteractor_Compliant.qml create mode 100644 applications-dev/plugins/compliant_qtquickgui/data/qml/compliant_qml.qrc diff --git a/.gitignore b/.gitignore index 496ee2ca..538c8c55 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.DS_Store \ No newline at end of file +.DS_Store +*~ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ee25778..c3be039a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,14 +11,23 @@ sofa_add_application(applications-dev/projects/qtQuickSofa qtQuickSofa) set(SOFAQTQUICKGUI_TARGETS "") find_package(image QUIET) +find_package(Compliant QUIET) find_package(SofaQtQuickGUI QUIET) # if(PLUGIN_IMAGE AND PLUGIN_SOFAQTQUICKGUI) + if(image_FOUND AND SofaQtQuickGUI_FOUND) list(APPEND SOFAQTQUICKGUI_TARGETS image_qtquickgui) - message("Adding automatically image_qtquickgui (image and SofaQtQuickGUI are activated)") + message("Adding (auto) image_qtquickgui (image and SofaQtQuickGUI are activated)") add_subdirectory(applications-dev/plugins/image_qtquickgui) endif() +if(Compliant_FOUND AND SofaQtQuickGUI_FOUND) + list(APPEND SOFAQTQUICKGUI_TARGETS compliant_qtquickgui) + message("Adding (auto) compliant_qtquickgui (since Compliant and SofaQtQuickGUI are activated)") + add_subdirectory(applications-dev/plugins/compliant_qtquickgui) +endif() + + ## Version set(SOFAQTQUICKGUI_VERSION "1.0") diff --git a/applications-dev/plugins/compliant_qtquickgui/CMakeLists.txt b/applications-dev/plugins/compliant_qtquickgui/CMakeLists.txt new file mode 100644 index 00000000..c66cd056 --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/CMakeLists.txt @@ -0,0 +1,101 @@ +cmake_minimum_required(VERSION 2.8.12) +project(compliant_qtquickgui) + +set(compliant_qtquickgui_MAJOR_VERSION 0) +set(compliant_qtquickgui_MINOR_VERSION 1) +set(compliant_qtquickgui_VERSION ${compliant_qtquickgui_MAJOR_VERSION}.${compliant_qtquickgui_MINOR_VERSION}) + +set(SOURCE_FILES + CompliantQtQuickGUI.cpp + SofaCompliantInteractor.cpp +) + +set(MOC_FILES + SofaCompliantInteractor.h +) + +set(HEADER_FILES + CompliantQtQuickGUI.h + SofaCompliantInteractor.h +) + +set(QML_FILES + # data/qml/SofaImage/qmldir + # data/qml/SofaImage/SofaImagePlaneItem.qml + # data/qml/SofaDataTypes/SofaDataType_imageplane.qml + data/qml/SofaInteractors/UserInteractor_Compliant.qml +) + +set(QRC_FILES + data/qml/compliant_qml.qrc +) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +find_package(SofaFramework REQUIRED) +find_package(Compliant REQUIRED) +find_package(SofaQtQuickGUI REQUIRED) + +# TODO do we need all the crap following? + + +# on Window, Qt packages need the glu32 lib full path, but they do not find it without help +if(WIN32) + if(CMAKE_CL_64) + set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um/x64") + else() + set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um/x86") + endif() + + # to fix a bug when one is compiling a debug version of the code + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DQT_NO_DEBUG) + endif() +endif() + +find_package(Qt5 COMPONENTS Core Gui Widgets Quick Qml REQUIRED PATHS "${SOFA-EXTERNAL_QT5_PATH}") +# make sure to use QT > 5.0 + +include_directories(${Qt5Core_INCLUDE_DIRS}) +include_directories(${Qt5Gui_INCLUDE_DIRS}) +include_directories(${Qt5Widgets_INCLUDE_DIRS}) +include_directories(${Qt5Qml_INCLUDE_DIRS}) +include_directories(${Qt5Quick_INCLUDE_DIRS}) + +add_definitions(${Qt5Core_DEFINITIONS}) +add_definitions(${Qt5Gui_DEFINITIONS}) +add_definitions(${Qt5Widgets_DEFINITIONS}) +add_definitions(${Qt5Qml_DEFINITIONS}) +add_definitions(${Qt5Quick_DEFINITIONS}) + + +qt5_wrap_cpp(MOC_FILES ${MOC_FILES}) # do not use "set(CMAKE_AUTOMOC ON)" since all the mocced files will be compiled by a single compilation unit leading to a "out of heap space" issue on MSVC +qt5_add_resources(RESOURCE_FILES ${QRC_FILES}) + +add_definitions(-DQT_PLUGIN) + +add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${MOC_FILES} ${SOURCE_FILES} ${QRC_FILES} ${RESOURCE_FILES} ${QML_FILES} ${CONFIG_FILES}) + + +# if(NOT MSVC) +# target_compile_options(${PROJECT_NAME} PUBLIC "$<$,CXX>:${CXX11_FLAG}>") +# endif() + +# find_package(CImg REQUIRED) +# target_include_directories(${PROJECT_NAME} PUBLIC "$") + +# if(APPLE) +# find_package(X11) +# if(NOT X11_FOUND) +# message(FATAL_ERROR "Failed to find X11 which is required to build plugin 'image'") +# endif() +# target_link_libraries(${PROJECT_NAME} ${X11_X11_LIB}) +# target_include_directories(${PROJECT_NAME} PUBLIC "$") +# endif() + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-DSOFA_BUILD_COMPLIANT_QTQUICKGUI") + +target_link_libraries(${PROJECT_NAME} Compliant SofaQtQuickGUI) + +## Install rules for the library; CMake package configurations files +sofa_create_package(${PROJECT_NAME} ${compliant_qtquickgui_VERSION} ${PROJECT_NAME} ${PROJECT_NAME}) diff --git a/applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.cpp b/applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.cpp new file mode 100644 index 00000000..d868b1ba --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.cpp @@ -0,0 +1,95 @@ +/* +Copyright 2015, Anatoscope + +This file is part of sofaqtquick. + +sofaqtquick is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sofaqtquick is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sofaqtquick. If not, see . +*/ + +#include "CompliantQtQuickGUI.h" + +#include +#include + +#include + +#include "SofaCompliantInteractor.h" + +using namespace sofa::qtquick; + +const int versionMajor = 1; +const int versionMinor = 0; + +static void initResources() +{ + Q_INIT_RESOURCE(compliant_qml); +} + +namespace sofa +{ + +namespace component +{ + +extern "C" { + SOFA_COMPLIANT_QTQUICKGUI_API void initExternalModule(); + SOFA_COMPLIANT_QTQUICKGUI_API const char* getModuleName(); + SOFA_COMPLIANT_QTQUICKGUI_API const char* getModuleVersion(); + SOFA_COMPLIANT_QTQUICKGUI_API const char* getModuleLicense(); + SOFA_COMPLIANT_QTQUICKGUI_API const char* getModuleDescription(); + SOFA_COMPLIANT_QTQUICKGUI_API const char* getModuleComponentList(); +} + +void initExternalModule() +{ + static bool first = true; + if (first) + { + first = false; + + initResources(); + + qmlRegisterType ("SofaCompliantInteractor", + versionMajor, versionMinor, "SofaCompliantInteractor"); + } +} + +const char* getModuleName() +{ + return "Compliant Plugin - QtQuick GUI"; +} + +const char* getModuleVersion() +{ + return "0.1"; +} + +const char* getModuleLicense() +{ + return "LGPL"; +} + +const char* getModuleDescription() +{ + return "Compliant QtQuick GUI"; +} + +const char* getModuleComponentList() +{ + return ""; +} + +} // namespace component + +} // namespace sofa diff --git a/applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.h b/applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.h new file mode 100644 index 00000000..9ce69945 --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/CompliantQtQuickGUI.h @@ -0,0 +1,32 @@ +/* +Copyright 2015, Anatoscope + +This file is part of sofaqtquick. + +sofaqtquick is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sofaqtquick is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sofaqtquick. If not, see . +*/ + +#ifndef COMPLIANT_QTQUICKGUI_INIT_H +#define COMPLIANT_QTQUICKGUI_INIT_H + +#include + +#ifdef SOFA_BUILD_COMPLIANT_QTQUICKGUI +#define SOFA_COMPLIANT_QTQUICKGUI_API SOFA_EXPORT_DYNAMIC_LIBRARY +#else +#define SOFA_COMPLIANT_QTQUICKGUI_API SOFA_IMPORT_DYNAMIC_LIBRARY +#endif + +#endif //COMPLIANT_QTQUICKGUI_INIT_H + diff --git a/applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.cpp b/applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.cpp new file mode 100644 index 00000000..9fa5efcb --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.cpp @@ -0,0 +1,178 @@ +/* +Copyright 2015, Anatoscope + +This file is part of sofaqtquick. + +sofaqtquick is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sofaqtquick is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sofaqtquick. If not, see . +*/ + +#include "SofaCompliantInteractor.h" +#include +// #include "SofaViewer.h" +// #include "Manipulator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include + +#include +#include + +namespace sofa +{ + +typedef sofa::simulation::Node Node; + +namespace qtquick +{ + +using namespace sofa::defaulttype; +using namespace sofa::core::behavior; +using namespace sofa::component::container; +using namespace sofa::component::projectiveconstraintset; +using namespace sofa::component::interactionforcefield; + +SofaCompliantInteractor::SofaCompliantInteractor(QObject *parent) + : QObject(parent), + compliance(1) +{ + +} + +SofaCompliantInteractor::~SofaCompliantInteractor() +{ + +} + +template +static std::function< bool(const QVector3D&) > update_thunk(Node* node, + core::objectmodel::Base* component, + unsigned index, + double compliance) { + + using state_type = MechanicalObject; + auto state = dynamic_cast(component); + (void)(state); + + assert(state && "bad state type in interactor thunk"); + + using namespace component; + using core::objectmodel::New; + + // dofs + auto dofs = New>(); + + // mapping + auto mapping = New>(); + mapping->setFrom(state); + mapping->setTo(dofs.get()); + helper::write(mapping->indices).wref().resize(1); + helper::write(mapping->indices).wref()[0] = index; + + helper::write(mapping->targets).wref().resize(1); + + // forcefield + auto ff = New>(); + ff->compliance.setValue(compliance); + ff->damping.setValue(1.0 / (1.0 + compliance) ); + + // display + auto style = New(); + helper::write(style->displayFlags).wref().setShowMechanicalMappings(true); + + + // node + node->addObject(dofs); + node->addObject(mapping); + node->addObject(ff); + node->addObject(style); + + node->init( core::ExecParams::defaultInstance() ); + + return [mapping](const QVector3D& pos) -> bool { + // std::clog << "update" << std::endl; + helper::write(mapping->targets).wref()[0] = {pos.x(), pos.y(), pos.z()}; + mapping->reinit(); + + return true; + }; +} + +bool SofaCompliantInteractor::start(SofaComponent* sofaComponent, int particleIndex) +{ + + using thunk_type = update_cb_type (*)(Node* node, + core::objectmodel::Base* component, + unsigned index, + double compliance); + + // TODO rigid interactors + static std::map< std::type_index, thunk_type> dispatch { + {std::type_index(typeid(MechanicalObject)), &update_thunk}, + {std::type_index(typeid(MechanicalObject)), &update_thunk} + }; + + std::type_index key = typeid(*sofaComponent->base()); + auto it = dispatch.find(key); + + if(it == dispatch.end()) { + return false; + } + + // std::clog << "start: " << particleIndex << std::endl; + node = sofaComponent->sofaScene()->sofaRootNode()->createChild("Interactor"); + update_cb = it->second(node.get(), sofaComponent->base(), particleIndex, compliance); + + return true; +} + +bool SofaCompliantInteractor::update(const QVector3D& position) +{ + if(update_cb) return update_cb(position); + else return false; +} + +bool SofaCompliantInteractor::interacting() const { + return bool(update_cb); +} + +void SofaCompliantInteractor::release() +{ + // std::clog << "release" << std::endl; + update_cb = 0; + + node->detachFromGraph(); + node = 0; +} + + + + +} + +} diff --git a/applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.h b/applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.h new file mode 100644 index 00000000..4c61448c --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/SofaCompliantInteractor.h @@ -0,0 +1,132 @@ +/* +Copyright 2015, Anatoscope + +This file is part of sofaqtquick. + +sofaqtquick is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sofaqtquick is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sofaqtquick. If not, see . +*/ + +#ifndef SOFA_COMPLIANT_INTERACTOR_H +#define SOFA_COMPLIANT_INTERACTOR_H + +#include + +#include +// #include "SofaViewer.h" +#include + +#include +#include + +#include +#include + +#include + +namespace sofa +{ + +namespace core +{ + +namespace behavior +{ + class BaseMechanicalState; + class BaseInteractionForceField; +} + +namespace objectmodel +{ + class BaseNode; +} + +namespace visual +{ + +class CompliantPainter : public VisualModel +{ +public: + SOFA_CLASS(CompliantPainter, VisualModel); + + CompliantPainter(); + virtual void drawVisual(const VisualParams* vparams); + +private: + +}; + +} // namespace visual + +} // namespace core + +namespace qtquick +{ + +class SofaComponent; +class SofaScene; +class Manipulator; + + +/// \class Allow us to interact with a sofa particle, typically a +/// degree of freedom (dof) in a sofa MechanicalObject +class SOFA_SOFAQTQUICKGUI_API SofaCompliantInteractor : public QObject +{ + Q_OBJECT + +public: + SofaCompliantInteractor(QObject *parent = 0); + ~SofaCompliantInteractor(); + +public: + Q_PROPERTY(double compliance MEMBER compliance NOTIFY complianceChanged) + // Q_PROPERTY(QVector3D interactorPosition READ interactorPosition NOTIFY interactorPositionChanged) + Q_PROPERTY(bool interacting READ interacting NOTIFY interactingChanged) + +public: + + // double compliance() const; + // void setCompliance(double compliance); + + QVector3D interactorPosition() const; + bool interacting() const; + + // Q_INVOKABLE sofa::qtquick::SofaComponent* sofaComponent() const; + +signals: + + void complianceChanged(double); + void interactingChanged(bool); + + // void interactorPositionChanged(const QVector3D&); + + +public slots: + bool start(sofa::qtquick::SofaComponent* sofaComponent, int particleIndex); + bool update(const QVector3D& interactorNewPosition); + void release(); + +private: + double compliance; + + sofa::simulation::Node::SPtr node; + + using update_cb_type = std::function< bool(const QVector3D&) >; + update_cb_type update_cb; +}; + +} + +} + +#endif // SOFAPARTICLEINTERACTOR_H diff --git a/applications-dev/plugins/compliant_qtquickgui/compliant_qtquickguiConfig.cmake.in b/applications-dev/plugins/compliant_qtquickgui/compliant_qtquickguiConfig.cmake.in new file mode 100644 index 00000000..f0d90273 --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/compliant_qtquickguiConfig.cmake.in @@ -0,0 +1,13 @@ +# CMake package configuration file for the image_qtquickgui "plugin" + +@PACKAGE_INIT@ + +find_package(Compliant REQUIRED) +find_package(SofaQtQuickGUI REQUIRED) + +# wtf am i writing lol +if(NOT TARGET Compliant_qtquickgui) + include("${CMAKE_CURRENT_LIST_DIR}/compliant_qtquickguiTargets.cmake") +endif() + +check_required_components(compliant_qtquickgui) diff --git a/applications-dev/plugins/compliant_qtquickgui/data/qml/SofaInteractors/UserInteractor_Compliant.qml b/applications-dev/plugins/compliant_qtquickgui/data/qml/SofaInteractors/UserInteractor_Compliant.qml new file mode 100644 index 00000000..8ad1b939 --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/data/qml/SofaInteractors/UserInteractor_Compliant.qml @@ -0,0 +1,72 @@ +/* +Copyright 2015, Anatoscope + +This file is part of sofaqtquick. + +sofaqtquick is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sofaqtquick is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sofaqtquick. If not, see . +*/ + +import QtQuick 2.0 +import SofaBasics 1.0 +import SofaComponent 1.0 +import SofaCompliantInteractor 1.0 + +UserInteractor_MoveCamera { + id: root + + property var selectedManipulator: null + property var selectedComponent: null + + property var interactor : SofaCompliantInteractor { + compliance: 1e-1 + onInteractingChanged: SofaApplication.overrideCursorShape = interacting ? Qt.BlankCursor : 0 + } + + function init() { + + console.log('compliant interactor init') + + moveCamera_init(); + + addMousePressedMapping(Qt.LeftButton, function(mouse, sofaViewer) { + selectedManipulator = sofaScene.selectedManipulator; + selectedComponent = sofaScene.selectedComponent; + + var sofaComponentParticle = sofaViewer.pickParticle(Qt.point(mouse.x, mouse.y)); + + if(sofaComponentParticle) { + interactor.start(sofaComponentParticle.sofaComponent, sofaComponentParticle.particleIndex); + + setMouseMovedMapping(function(mouse, sofaViewer) { + var z = sofaViewer.computeDepth(interactor.interactorPosition); + var position = sofaViewer.mapToWorld(Qt.point(mouse.x, mouse.y), z); + interactor.update(position); + }); + } + }); + + addMouseReleasedMapping(Qt.LeftButton, function(mouse, sofaViewer) { + if(interactor) + interactor.release(); + + if(selectedManipulator && selectedManipulator.mouseReleased) + selectedManipulator.mouseReleased(mouse, sofaViewer); + + sofaScene.selectedManipulator = null; + + setMouseMovedMapping(null); + }); + + } +} diff --git a/applications-dev/plugins/compliant_qtquickgui/data/qml/compliant_qml.qrc b/applications-dev/plugins/compliant_qtquickgui/data/qml/compliant_qml.qrc new file mode 100644 index 00000000..c72324e4 --- /dev/null +++ b/applications-dev/plugins/compliant_qtquickgui/data/qml/compliant_qml.qrc @@ -0,0 +1,5 @@ + + + SofaInteractors/UserInteractor_Compliant.qml + +