diff --git a/CMakeLists.txt b/CMakeLists.txt index f1aa5f66..490ca6b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,23 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.10) -PROJECT( octomap-distribution ) +cmake_minimum_required(VERSION 3.10...4.1) +project( + octomap-distribution + VERSION 1.10.0 + LANGUAGES NONE +) -ENABLE_TESTING() # enable CTest environment of subprojects -set(CMAKE_POSITION_INDEPENDENT_CODE ON) # enables -fPIC in applicable compilers (required to avoid link errors in some cases) +include(CTest) +option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(BUILD_OCTOVIS_SUBPROJECT "Build targets from subproject octovis" ON) -option(BUILD_DYNAMICETD3D_SUBPROJECT "Build targets from subproject dynamicEDT3D" ON) -option(OCTOVIS_QT6 "Link Octovis against Qt6?" ON) - -set(CMAKE_CXX_STANDARD 11) - -ADD_SUBDIRECTORY( octomap ) +option(BUILD_DYNAMICETD3D_SUBPROJECT + "Build targets from subproject dynamicEDT3D" ON +) +add_subdirectory(octomap) if(BUILD_OCTOVIS_SUBPROJECT) - ADD_SUBDIRECTORY( octovis ) + set(OCTOVIS_BUILD_OPTIONAL TRUE) + add_subdirectory(octovis) endif() - if(BUILD_DYNAMICETD3D_SUBPROJECT) - ADD_SUBDIRECTORY( dynamicEDT3D ) + add_subdirectory(dynamicEDT3D) endif() diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 3dfd2399..a9a05efa 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -1,177 +1,139 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.10) -PROJECT(dynamicEDT3D) - -include(CTest) -include(GNUInstallDirs) +cmake_minimum_required(VERSION 3.10...4.1) +project( + dynamicEDT3D + VERSION 1.10.0 + LANGUAGES CXX +) -# version (e.g. for packaging) -set(DYNAMICEDT3D_MAJOR_VERSION 1) -set(DYNAMICEDT3D_MINOR_VERSION 10) -set(DYNAMICEDT3D_PATCH_VERSION 0) -set(DYNAMICEDT3D_VERSION ${DYNAMICEDT3D_MAJOR_VERSION}.${DYNAMICEDT3D_MINOR_VERSION}.${DYNAMICEDT3D_PATCH_VERSION}) -set(DYNAMICEDT3D_SOVERSION ${DYNAMICEDT3D_MAJOR_VERSION}.${DYNAMICEDT3D_MINOR_VERSION}) - -if(COMMAND cmake_policy) - cmake_policy(SET CMP0003 NEW) - if(POLICY CMP0042) - # Enable MACOSX_RPATH by default. - cmake_policy(SET CMP0042 NEW) - endif(POLICY CMP0042) -endif(COMMAND cmake_policy) - -SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") - -# COMPILER SETTINGS (default: Release) and flags -INCLUDE(CompilerSettings) - - -# Set output directories for libraries and executables -SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) -SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) -SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) -SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) -# output dirs for multi-config builds (MSVC) -foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) - STRING( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) - SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/lib ) - SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/lib ) - SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/bin ) -endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) - -set(INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include") -INCLUDE_DIRECTORIES(${INCLUDE_DIRS}) - -LINK_DIRECTORIES(${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) +option(DYNAMICEDT3D_BUILD_EXAMPLES "Build examples" ON) -# Installation +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) -set(INSTALL_TARGETS_DEFAULT_ARGS - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") +include(CompilerSettings) +include(InstallPkgConfigFile) -find_package(octomap REQUIRED - HINTS ${CMAKE_SOURCE_DIR}/lib/cmake/octomap - ${CMAKE_SOURCE_DIR}/../octomap/lib/cmake/octomap +# version (e.g. for packaging) +set(DYNAMICEDT3D_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) +set(DYNAMICEDT3D_MINOR_VERSION ${PROJECT_VERSION_MINOR}) +set(DYNAMICEDT3D_PATCH_VERSION ${PROJECT_VERSION_PATCH}) +set(DYNAMICEDT3D_VERSION ${PROJECT_VERSION}) +set(DYNAMICEDT3D_SOVERSION + "${DYNAMICEDT3D_MAJOR_VERSION}.${DYNAMICEDT3D_MINOR_VERSION}" ) -MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) -MESSAGE(STATUS "octomap libraries: ${OCTOMAP_LIBRARIES}") - -INCLUDE_DIRECTORIES(BEFORE SYSTEM ${OCTOMAP_INCLUDE_DIRS}) -ADD_SUBDIRECTORY(src) +if(NOT TARGET octomap::octomap) + find_package(octomap "${DYNAMICEDT3D_VERSION}" REQUIRED) +endif() +set(DYNAMICEDT3D_FIND_DEPENDENCIES + "include(CMakeFindDependencyMacro)\nfind_dependency(octomap ${DYNAMICEDT3D_VERSION})" +) -file(GLOB dynamicEDT3D_HDRS ${PROJECT_SOURCE_DIR}/include/dynamicEDT3D/*.h ${PROJECT_SOURCE_DIR}/include/dynamicEDT3D/*.hxx) -install(FILES ${dynamicEDT3D_HDRS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dynamicEDT3D") +set(dynamicEDT3D_SOURCES src/dynamicEDT3D.cpp) -# Install catkin package.xml, attention package.xml names the catkin package "dynamic_edt_3d", so this is also the location where it needs to be installed to (and not "dynamicEDT3D") -install(FILES package.xml DESTINATION "${CMAKE_INSTALL_DATADIR}/dynamic_edt_3d") +add_library(dynamicEDT3D ${dynamicEDT3D_SOURCES}) +target_compile_features(dynamicEDT3D PUBLIC cxx_std_11) +target_include_directories( + dynamicEDT3D PUBLIC $ + $ +) +set_target_properties( + dynamicEDT3D + PROPERTIES VERSION "${DYNAMICEDT3D_VERSION}" + SOVERSION "${DYNAMICEDT3D_SOVERSION}" + OUTPUT_NAME "dynamicedt3d" +) +target_link_libraries(dynamicEDT3D PUBLIC octomap::octomap) +add_library(octomap::dynamicEDT3D ALIAS dynamicEDT3D) -# Allows Colcon to find non-Ament packages when using workspace underlays -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/share/ament_index/resource_index/packages/${PROJECT_NAME} "") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/share/ament_index/resource_index/packages/${PROJECT_NAME} DESTINATION share/ament_index/resource_index/packages) +# Examples +if(DYNAMICEDT3D_BUILD_EXAMPLES) + add_executable(exampleEDT3D src/examples/exampleEDT3D.cpp) + target_link_libraries(exampleEDT3D PRIVATE dynamicEDT3D) -#TODO: this conflicts with the octomap uninstall -#it is not only a target name problem, also both will use the same manifest file -#in the same binary directory -if(NOT TARGET uninstall) - configure_file( - "${PROJECT_SOURCE_DIR}/CMakeModules/CMakeUninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) + add_executable(exampleEDTOctomap src/examples/exampleEDTOctomap.cpp) + target_link_libraries(exampleEDTOctomap PRIVATE dynamicEDT3D) - add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + add_executable( + exampleEDTOctomapStamped src/examples/exampleEDTOctomapStamped.cpp + ) + target_link_libraries(exampleEDTOctomapStamped PRIVATE dynamicEDT3D) endif() -# Export the package for use from the build-tree -# (this registers the build-tree with a global CMake-registry) +# Export build tree +configure_package_config_file( + dynamicedt3d-config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/dynamicedt3d-config.cmake" + INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/dynamicedt3d-config-version.cmake" + VERSION ${DYNAMICEDT3D_VERSION} + COMPATIBILITY SameMinorVersion +) +export( + TARGETS dynamicEDT3D + NAMESPACE octomap:: + FILE "${CMAKE_CURRENT_BINARY_DIR}/dynamicedt3d-targets.cmake" +) export(PACKAGE dynamicEDT3D) -# Create a dynamicEDT3DConfig.cmake file for the use from the build tree -set(DYNAMICEDT3D_INCLUDE_DIRS "${INCLUDE_DIRS}") -set(DYNAMICEDT3D_LIB_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") -# Set library names as absolute paths -# Windows, spec. MSVC requires the .lib suffix for imported libs -IF(WIN32) - set(DYNAMICEDT3D_LIBRARY - "${CMAKE_IMPORT_LIBRARY_PREFIX}dynamicedt3d${CMAKE_IMPORT_LIBRARY_SUFFIX}" - ) -ELSE() - set(DYNAMICEDT3D_LIBRARY - "${CMAKE_SHARED_LIBRARY_PREFIX}dynamicedt3d${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) -ENDIF() -# not used right now (export depends?) -#set(DYNEDT3D_CMAKE_DIR "${PROJECT_BINARY_DIR}") -include(CMakePackageConfigHelpers) +# Installation +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(TARGETS dynamicEDT3D EXPORT dynamicedt3d-targets) +install( + EXPORT dynamicedt3d-targets + NAMESPACE octomap:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynamicEDT3D" +) +set(DYNAMICEDT3D_INCLUDE_DIRS "${CMAKE_INSTALL_INCLUDEDIR}") +set(DYNAMICEDT3D_LIBRARY_DIRS "${CMAKE_INSTALL_LIBDIR}") +configure_package_config_file( + dynamicedt3d-config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/dynamicedt3d-config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynamicEDT3D" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/dynamicedt3d-config-version.cmake" + VERSION ${DYNAMICEDT3D_VERSION} + COMPATIBILITY SameMinorVersion +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/dynamicedt3d-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/dynamicedt3d-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynamicEDT3D" +) -CONFIGURE_PACKAGE_CONFIG_FILE( - dynamicEDT3DConfig.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DConfig.cmake" - PATH_VARS DYNAMICEDT3D_INCLUDE_DIRS DYNAMICEDT3D_LIB_DIR - INSTALL_DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/dynamicEDT3D") - -WRITE_BASIC_PACKAGE_VERSION_FILE( - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DConfig-version.cmake" - VERSION ${DYNAMICEDT3D_VERSION} - COMPATIBILITY AnyNewerVersion) - -# Install the export set for use with the install-tree -#install(EXPORT FooBarLibraryDepends DESTINATION -# "${INSTALL_DATA_DIR}/FooBar/CMake" -# COMPONENT dev) - -# Create a dynamicEDT3DConfig.cmake file for the use from the install tree -# and install it -set(DYNAMICEDT3D_INCLUDE_DIRS "${CMAKE_INSTALL_FULL_INCLUDEDIR}") -set(DYNAMICEDT3D_LIB_DIR "${CMAKE_INSTALL_FULL_LIBDIR}") -#set(DYNAMICEDT3D_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") - -set(DYNAMICEDT3D_INCLUDE_TARGETS - "include(\${CMAKE_CURRENT_LIST_DIR}/dynamicEDT3DTargets.cmake)") - -CONFIGURE_PACKAGE_CONFIG_FILE( - dynamicEDT3DConfig.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig.cmake" - PATH_VARS DYNAMICEDT3D_INCLUDE_DIRS DYNAMICEDT3D_LIB_DIR - INSTALL_DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/dynamicEDT3D") - -WRITE_BASIC_PACKAGE_VERSION_FILE( - "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig-version.cmake" - VERSION ${DYNAMICEDT3D_VERSION} - COMPATIBILITY AnyNewerVersion) - -install(FILES - "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig.cmake" - "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig-version.cmake" - DESTINATION "${CMAKE_INSTALL_DATADIR}/dynamicEDT3D") - -# Write pkgconfig-file: +# ROS support +install(FILES package.xml DESTINATION "${CMAKE_INSTALL_DATADIR}/dynamicEDT3D") + +# pkg-config support include(InstallPkgConfigFile) -install_pkg_config_file(dynamicEDT3D +install_pkg_config_file( + dynamicEDT3D CFLAGS - LIBS -ldynamicEDT3D + LIBS + -ldynamicedt3d REQUIRES - VERSION ${DYNAMICEDT3D_VERSION}) - + octomap + VERSION + ${DYNAMICEDT3D_VERSION} +) # Documentation -FIND_PACKAGE(Doxygen) -IF(DOXYGEN_FOUND) - ADD_CUSTOM_TARGET(docs_dynamicEDT3D ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/dynamicEDT3D.dox - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating documentation (Doxygen)...") -ENDIF(DOXYGEN_FOUND) +find_package(Doxygen QUIET) +if(DOXYGEN_FOUND) + add_custom_target( + docs_dynamicEDT3D + COMMAND ${DOXYGEN_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/dynamicEDT3D.dox + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Generating documentation (Doxygen)" + ) +endif(DOXYGEN_FOUND) # Needs to be last statement: -INCLUDE(CPackSettings) - -# Finished: -MESSAGE (STATUS "\n") -MESSAGE (STATUS "Compile dynamicEDT3D using: make") -MESSAGE (STATUS "Install dynamicEDT3D using: make install") -MESSAGE (STATUS " (be sure to set the correct CMAKE_INSTALL_PREFIX before)") -MESSAGE (STATUS "Compile API-documentation using: make docs_dynamicEDT3D\n") +include(CPackSettings) diff --git a/dynamicEDT3D/CMakeModules/CMakeUninstall.cmake.in b/dynamicEDT3D/CMakeModules/CMakeUninstall.cmake.in deleted file mode 100644 index c6d80941..00000000 --- a/dynamicEDT3D/CMakeModules/CMakeUninstall.cmake.in +++ /dev/null @@ -1,22 +0,0 @@ -if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") -endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - -file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") -list(REVERSE files) -foreach (file ${files}) - message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - if (EXISTS "$ENV{DESTDIR}${file}") - execute_process( - COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval - ) - if(NOT ${rm_retval} EQUAL 0) - message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") - endif (NOT ${rm_retval} EQUAL 0) - else (EXISTS "$ENV{DESTDIR}${file}") - message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") - endif (EXISTS "$ENV{DESTDIR}${file}") -endforeach(file) diff --git a/dynamicEDT3D/CMakeModules/CompilerSettings.cmake b/dynamicEDT3D/CMakeModules/CompilerSettings.cmake index e2e6b4f5..d7c3951f 100644 --- a/dynamicEDT3D/CMakeModules/CompilerSettings.cmake +++ b/dynamicEDT3D/CMakeModules/CompilerSettings.cmake @@ -1,40 +1,18 @@ # COMPILER SETTINGS (default: Release) # use "-DCMAKE_BUILD_TYPE=Debug" in cmake for a Debug-build -IF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE Release) -ENDIF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) -MESSAGE (STATUS "\n") -MESSAGE (STATUS "${PROJECT_NAME} building as ${CMAKE_BUILD_TYPE}") - -# OCTOMAP_OMP = enable OpenMP -# SET(OCTOMAP_OMP 1 CACHE BOOL "Enable/disable OpenMP") -# IF($ENV{OCTOMAP_OMP}) -# SET(OCTOMAP_OMP $ENV{OCTOMAP_OMP}) -# MESSAGE(STATUS "Found OCTOMAP_OMP=${OCTOMAP_OMP}") -# ENDIF($ENV{OCTOMAP_OMP}) +message(STATUS "${PROJECT_NAME} building as ${CMAKE_BUILD_TYPE}") # COMPILER FLAGS -IF (CMAKE_COMPILER_IS_GNUCC) - SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-error ") - SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-error ") - SET (CMAKE_CXX_FLAGS_RELEASE "-O3 -funroll-loops -DNDEBUG") - SET (CMAKE_CXX_FLAGS_DEBUG "-O0 -g") - # Shared object compilation under 64bit (vtable) - ADD_DEFINITIONS(-fPIC) - # IF(OCTOMAP_OMP) - # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp") - # SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -fopenmp") - # ENDIF(OCTOMAP_OMP) -ENDIF() - - -# Set full rpath http://www.paraview.org/Wiki/CMake_RPATH_handling -# (good to have and required with ROS) -set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -funroll-loops -DNDEBUG") + set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") +endif() -# no prefix needed for python modules -set(CMAKE_SHARED_MODULE_PREFIX "") +# enables -fPIC in applicable compilers +set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in deleted file mode 100644 index c8ffd885..00000000 --- a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in +++ /dev/null @@ -1,32 +0,0 @@ -# - Config file for the dynamicEDT3D package -# -# Usage from an external project: -# In your CMakeLists.txt, add these lines: -# -# FIND_PACKAGE(dynamicedt3d REQUIRED ) -# INCLUDE_DIRECTORIES(${DYNAMICEDT3D_INCLUDE_DIRS}) -# TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${DYNAMICEDT3D_LIBRARIES}) -# -# It defines the following variables -# DYNAMICEDT3D_INCLUDE_DIRS - include directories for dynamicEDT3D -# DYNAMICEDT3D_LIBRARY_DIRS - library directories for dynamicEDT3D (normally not used!) -# DYNAMICEDT3D_LIBRARIES - libraries to link against -# DYNAMICEDT3D_MAJOR_VERSION - major version -# DYNAMICEDT3D_MINOR_VERSION - minor version -# DYNAMICEDT3D_PATCH_VERSION - patch version -# DYNAMICEDT3D_VERSION - major.minor.patch version - -@PACKAGE_INIT@ - -set(DYNAMICEDT3D_MAJOR_VERSION "@DYNAMICEDT3D_MAJOR_VERSION@") -set(DYNAMICEDT3D_MINOR_VERSION "@DYNAMICEDT3D_MINOR_VERSION@") -set(DYNAMICEDT3D_PATCH_VERSION "@DYNAMICEDT3D_PATCH_VERSION@") -set(DYNAMICEDT3D_VERSION "@DYNAMICEDT3D_VERSION@") - -# Tell the user project where to find our headers and libraries -set_and_check(DYNAMICEDT3D_INCLUDE_DIRS "@PACKAGE_DYNAMICEDT3D_INCLUDE_DIRS@") -set_and_check(DYNAMICEDT3D_LIBRARY_DIRS "@PACKAGE_DYNAMICEDT3D_LIB_DIR@") - -set(DYNAMICEDT3D_LIBRARIES "@PACKAGE_DYNAMICEDT3D_LIB_DIR@/@DYNAMICEDT3D_LIBRARY@") - -@DYNAMICEDT3D_INCLUDE_TARGETS@ diff --git a/dynamicEDT3D/dynamicedt3d-config.cmake.in b/dynamicEDT3D/dynamicedt3d-config.cmake.in new file mode 100644 index 00000000..92eb9a29 --- /dev/null +++ b/dynamicEDT3D/dynamicedt3d-config.cmake.in @@ -0,0 +1,33 @@ +# =================================================================================== +# The dynamicEDT3D CMake configuration file +# +# ** File generated automatically, do not modify ** +# +# Usage from an external project: +# In your CMakeLists.txt, add these lines: +# +# find_package(dynamicEDT3D REQUIRED) +# target_link_libraries(MY_TARGET_NAME PRIVATE octomap::dynamicEDT3D) +# +# +# This file will also define the following variables: +# - DYNAMICEDT3D_LIBRARIES : For backwards compatibility with existing code +# - DYNAMICEDT3D_MAJOR_VERSION : Major version. +# - DYNAMICEDT3D_MINOR_VERSION : Minor version. +# - DYNAMICEDT3D_PATCH_VERSION : Patch version. +# - DYNAMICEDT3D_VERSION : Major.Minor.Patch version. +# +# =================================================================================== + +@PACKAGE_INIT@ + +@DYNAMICEDT3D_FIND_DEPENDENCIES@ + +set(DYNAMICEDT3D_MAJOR_VERSION "@DYNAMICEDT3D_MAJOR_VERSION@") +set(DYNAMICEDT3D_MINOR_VERSION "@DYNAMICEDT3D_MINOR_VERSION@") +set(DYNAMICEDT3D_PATCH_VERSION "@DYNAMICEDT3D_PATCH_VERSION@") +set(DYNAMICEDT3D_VERSION "@DYNAMICEDT3D_VERSION@") + +set(DYNAMICEDT3D_LIBRARIES octomap::dynamicEDT3D) + +include(${CMAKE_CURRENT_LIST_DIR}/dynamicedt3d-targets.cmake) diff --git a/dynamicEDT3D/src/examples/CMakeLists.txt b/dynamicEDT3D/src/examples/CMakeLists.txt deleted file mode 100644 index 01473157..00000000 --- a/dynamicEDT3D/src/examples/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_executable(exampleEDT3D exampleEDT3D.cpp) -target_link_libraries(exampleEDT3D dynamicedt3d) - -add_executable(exampleEDTOctomap exampleEDTOctomap.cpp) -target_link_libraries(exampleEDTOctomap dynamicedt3d) - -add_executable(exampleEDTOctomapStamped exampleEDTOctomapStamped.cpp) -target_link_libraries(exampleEDTOctomapStamped dynamicedt3d) \ No newline at end of file diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index 148a1332..7ed758ab 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -1,180 +1,216 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.10) -PROJECT( octomap ) +cmake_minimum_required(VERSION 3.10...4.1) +project( + octomap + VERSION 1.10.0 + LANGUAGES CXX +) + +option(OCTOMAP_USE_OPENMP "Enable experimental OpenMP support" OFF) + +# version (e.g. for packaging) +set(OCTOMAP_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) +set(OCTOMAP_MINOR_VERSION ${PROJECT_VERSION_MINOR}) +set(OCTOMAP_PATCH_VERSION ${PROJECT_VERSION_PATCH}) +set(OCTOMAP_VERSION ${PROJECT_VERSION}) +set(OCTOMAP_SOVERSION "${OCTOMAP_MAJOR_VERSION}.${OCTOMAP_MINOR_VERSION}") +include(CMakePackageConfigHelpers) include(CTest) include(GNUInstallDirs) -# version (e.g. for packaging) -set(OCTOMAP_MAJOR_VERSION 1) -set(OCTOMAP_MINOR_VERSION 10) -set(OCTOMAP_PATCH_VERSION 0) -set(OCTOMAP_VERSION ${OCTOMAP_MAJOR_VERSION}.${OCTOMAP_MINOR_VERSION}.${OCTOMAP_PATCH_VERSION}) -set(OCTOMAP_SOVERSION ${OCTOMAP_MAJOR_VERSION}.${OCTOMAP_MINOR_VERSION}) -if(COMMAND cmake_policy) - cmake_policy(SET CMP0003 NEW) - if(POLICY CMP0042) - # Enable MACOSX_RPATH by default. - cmake_policy(SET CMP0042 NEW) - endif(POLICY CMP0042) -endif(COMMAND cmake_policy) - -SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") - -# COMPILER SETTINGS (default: Release) and flags -INCLUDE(CompilerSettings) - -# OCTOMAP_OMP = enable OpenMP parallelization (experimental, defaults to OFF) -SET(OCTOMAP_OMP FALSE CACHE BOOL "Enable/disable OpenMP parallelization") -IF(DEFINED ENV{OCTOMAP_OMP}) - SET(OCTOMAP_OMP $ENV{OCTOMAP_OMP}) -ENDIF(DEFINED ENV{OCTOMAP_OMP}) -IF(OCTOMAP_OMP) - FIND_PACKAGE( OpenMP REQUIRED) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") -ENDIF(OCTOMAP_OMP) - -# Set output directories for libraries and executables -SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) -SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) -SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) -SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) -# output dirs for multi-config builds (MSVC) -foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) - STRING( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) - SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/lib ) - SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/lib ) - SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/bin ) -endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) - -set(INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include") -INCLUDE_DIRECTORIES(${INCLUDE_DIRS}) - -LINK_DIRECTORIES(${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") +include(CompilerSettings) +include(InstallPkgConfigFile) -# Installation +set(OCTOMAP_FIND_DEPENDENCIES "include(CMakeFindDependencyMacro)") +if(OCTOMAP_USE_OPENMP) + find_package(OpenMP REQUIRED) + set(OCTOMAP_FIND_DEPENDENCIES + "${OCTOMAP_FIND_DEPENDENCIES}\nfind_dependency(OpenMP)" + ) +endif() -set(INSTALL_TARGETS_DEFAULT_ARGS - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" +# octomath library +set(octomath_SOURCES src/math/Pose6D.cpp src/math/Quaternion.cpp + src/math/Vector3.cpp ) +add_library(octomath ${octomath_SOURCES}) +target_compile_features(octomath PUBLIC cxx_std_11) +target_include_directories( + octomath PUBLIC $ + $ +) +set_target_properties( + octomath PROPERTIES VERSION "${OCTOMAP_VERSION}" SOVERSION + "${OCTOMAP_SOVERSION}" +) +if(TARGET OpenMP::OpenMP_CXX) + target_link_libraries(octomath PRIVATE OpenMP::OpenMP_CXX) +endif() -ADD_SUBDIRECTORY( src/math ) -ADD_SUBDIRECTORY( src ) +# octomap library +set(octomap_SOURCES + src/AbstractOcTree.cpp + src/AbstractOccupancyOcTree.cpp + src/Pointcloud.cpp + src/ScanGraph.cpp + src/CountingOcTree.cpp + src/OcTree.cpp + src/OcTreeNode.cpp + src/OcTreeStamped.cpp + src/ColorOcTree.cpp +) +add_library(octomap ${octomap_SOURCES}) +target_compile_features(octomap PUBLIC cxx_std_11) +target_include_directories( + octomap PUBLIC $ + $ +) +set_target_properties( + octomap PROPERTIES VERSION "${OCTOMAP_VERSION}" SOVERSION + "${OCTOMAP_SOVERSION}" +) +target_link_libraries(octomap PUBLIC octomath) +if(TARGET OpenMP::OpenMP_CXX) + target_link_libraries(octomap PRIVATE OpenMP::OpenMP_CXX) +endif() +add_library(octomap::octomap ALIAS octomap) -file(GLOB octomap_HDRS ${PROJECT_SOURCE_DIR}/include/octomap/*.h ${PROJECT_SOURCE_DIR}/include/octomap/*.hxx) -install(FILES ${octomap_HDRS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/octomap") -file(GLOB octomap_math_HDRS ${PROJECT_SOURCE_DIR}/include/octomap/math/*.h) -install(FILES ${octomap_math_HDRS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/octomap/math") +# Utilities +add_executable(graph2tree src/graph2tree.cpp) +target_link_libraries(graph2tree PRIVATE octomap) -# Install package.xml (catkin/ament/rosdep) -install(FILES package.xml DESTINATION "${CMAKE_INSTALL_DATADIR}/octomap") +add_executable(log2graph src/log2graph.cpp) +target_link_libraries(log2graph PRIVATE octomap) -# Allows Colcon to find non-Ament packages when using workspace underlays -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/share/ament_index/resource_index/packages/${PROJECT_NAME} "") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/share/ament_index/resource_index/packages/${PROJECT_NAME} DESTINATION share/ament_index/resource_index/packages) +add_executable(binvox2bt src/binvox2bt.cpp) +target_link_libraries(binvox2bt PRIVATE octomap) -# uninstall target -if(NOT TARGET uninstall) - configure_file( - "${PROJECT_SOURCE_DIR}/CMakeModules/CMakeUninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) +add_executable(binvox2bt_unique_offsets src/binvox2bt_unique_offsets.cpp) +target_link_libraries(binvox2bt_unique_offsets PRIVATE octomap) + +add_executable(bt2vrml src/bt2vrml.cpp) +target_link_libraries(bt2vrml PRIVATE octomap) + +add_executable(edit_octree src/edit_octree.cpp) +target_link_libraries(edit_octree PRIVATE octomap) + +add_executable(convert_octree src/convert_octree.cpp) +target_link_libraries(convert_octree PRIVATE octomap) + +add_executable(eval_octree_accuracy src/eval_octree_accuracy.cpp) +target_link_libraries(eval_octree_accuracy PRIVATE octomap) + +add_executable(compare_octrees src/compare_octrees.cpp) +target_link_libraries(compare_octrees PRIVATE octomap) - add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +add_executable(simple_example src/simple_example.cpp) +target_link_libraries(simple_example PRIVATE octomap) + +add_executable(pcd_to_bt_example src/pcd_to_bt_example.cpp) +target_link_libraries(pcd_to_bt_example PRIVATE octomap) + +add_executable(normals_example src/normals_example.cpp) +target_link_libraries(normals_example PRIVATE octomap) + +add_executable(intersection_example src/intersection_example.cpp) +target_link_libraries(intersection_example PRIVATE octomap) + +add_executable(octree2pointcloud src/octree2pointcloud.cpp) +target_link_libraries(octree2pointcloud PRIVATE octomap) + +add_executable(merge_octomaps src/merge_octomaps.cpp) +target_link_libraries(merge_octomaps PRIVATE octomap) + +# Testing +if(BUILD_TESTING) + add_subdirectory(src/testing) endif() -# Export the package for use from the build-tree -# (this registers the build-tree with a global CMake-registry) +# Export build tree +configure_package_config_file( + octomap-config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/octomap-config.cmake" + INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/octomap-config-version.cmake" + VERSION ${OCTOMAP_VERSION} + COMPATIBILITY SameMinorVersion +) +export( + TARGETS octomath octomap + NAMESPACE octomap:: + FILE "${CMAKE_CURRENT_BINARY_DIR}/octomap-targets.cmake" +) export(PACKAGE octomap) -# Create a octomap-config.cmake file for the use from the build tree -set(OCTOMAP_INCLUDE_DIRS "${INCLUDE_DIRS}") -set(OCTOMAP_LIB_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") -# Set library names as absolute paths -# Windows, spec. MSVC requires the .lib suffix for imported libs -IF(WIN32) - set(OCTOMAP_LIBRARY - "${CMAKE_IMPORT_LIBRARY_PREFIX}octomap${CMAKE_IMPORT_LIBRARY_SUFFIX}" - ) - set(OCTOMATH_LIBRARY - "${CMAKE_IMPORT_LIBRARY_PREFIX}octomath${CMAKE_IMPORT_LIBRARY_SUFFIX}" - ) -ELSE() - set(OCTOMAP_LIBRARY - "${CMAKE_SHARED_LIBRARY_PREFIX}octomap${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - set(OCTOMATH_LIBRARY - "${CMAKE_SHARED_LIBRARY_PREFIX}octomath${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) -ENDIF() - -# not used right now (export depends?) -#set(OCTOMAP_CMAKE_DIR "${PROJECT_BINARY_DIR}") -include(CMakePackageConfigHelpers) +# Installation +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(TARGETS octomath octomap EXPORT octomap-targets) +install( + TARGETS graph2tree + log2graph + binvox2bt + binvox2bt_unique_offsets + bt2vrml + edit_octree + convert_octree + eval_octree_accuracy + compare_octrees +) +install( + EXPORT octomap-targets + NAMESPACE octomap:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/octomap" +) -CONFIGURE_PACKAGE_CONFIG_FILE( - octomap-config.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-config.cmake" - PATH_VARS OCTOMAP_INCLUDE_DIRS OCTOMAP_LIB_DIR - INSTALL_DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/octomap") - -WRITE_BASIC_PACKAGE_VERSION_FILE( - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-config-version.cmake" - VERSION ${OCTOMAP_VERSION} - COMPATIBILITY AnyNewerVersion) - -# Create a octomap-config.cmake file for the use from the install tree -# and install it -set(OCTOMAP_INCLUDE_DIRS "${CMAKE_INSTALL_FULL_INCLUDEDIR}") -set(OCTOMAP_LIB_DIR "${CMAKE_INSTALL_FULL_LIBDIR}") -#set(OCTOMAP_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") - -set(OCTOMAP_INCLUDE_TARGETS - "include(\${CMAKE_CURRENT_LIST_DIR}/octomap-targets.cmake)") - -CONFIGURE_PACKAGE_CONFIG_FILE( - octomap-config.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config.cmake" - PATH_VARS OCTOMAP_INCLUDE_DIRS OCTOMAP_LIB_DIR - INSTALL_DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/octomap") - -WRITE_BASIC_PACKAGE_VERSION_FILE( - ${PROJECT_BINARY_DIR}/InstallFiles/octomap-config-version.cmake - VERSION ${OCTOMAP_VERSION} - COMPATIBILITY AnyNewerVersion) - -install(FILES - "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config.cmake" - "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config-version.cmake" - DESTINATION "${CMAKE_INSTALL_DATADIR}/octomap") - -# Write pkgconfig-file: -include(InstallPkgConfigFile) -install_pkg_config_file(octomap +configure_package_config_file( + octomap-config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octomap-config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/octomap" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octomap-config-version.cmake" + VERSION ${OCTOMAP_VERSION} + COMPATIBILITY SameMinorVersion +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octomap-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octomap-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/octomap" +) + +# ROS support +install(FILES package.xml DESTINATION "${CMAKE_INSTALL_DATADIR}/octomap") + +# pkg-config support +install_pkg_config_file( + octomap CFLAGS - LIBS -loctomap -loctomath + LIBS + -loctomap + -loctomath REQUIRES - VERSION ${OCTOMAP_VERSION}) + VERSION + ${OCTOMAP_VERSION} +) # Documentation -FIND_PACKAGE(Doxygen) -IF(DOXYGEN_FOUND) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/octomap.dox.in ${CMAKE_CURRENT_BINARY_DIR}/octomap.dox @ONLY) - ADD_CUSTOM_TARGET(docs ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/octomap.dox - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMENT "Generating documentation (Doxygen) at location ${PROJECT_SOURCE_DIR}/doc/html/") -ENDIF(DOXYGEN_FOUND) +find_package(Doxygen QUIET) +if(DOXYGEN_FOUND) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/octomap.dox.in + ${CMAKE_CURRENT_BINARY_DIR}/octomap.dox @ONLY + ) + add_custom_target( + docs + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/octomap.dox + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT + "Generating documentation (Doxygen) at location ${PROJECT_SOURCE_DIR}/doc/html/" + ) +endif(DOXYGEN_FOUND) # Needs to be last statement: -INCLUDE(CPackSettings) - -# Finished: -MESSAGE (STATUS "\n") -MESSAGE (STATUS "Compile octomap using: make") -MESSAGE (STATUS "Install octomap using: make install") -MESSAGE (STATUS " (be sure to set the correct CMAKE_INSTALL_PREFIX before)") -MESSAGE (STATUS "Compile API-documentation using: make docs\n") +include(CPackSettings) diff --git a/octomap/CMakeModules/CMakeUninstall.cmake.in b/octomap/CMakeModules/CMakeUninstall.cmake.in deleted file mode 100644 index af4c1499..00000000 --- a/octomap/CMakeModules/CMakeUninstall.cmake.in +++ /dev/null @@ -1,25 +0,0 @@ -# Ignore empty list items. -cmake_policy(SET CMP0007 OLD) - -if (NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_BINARY_DIR@/install_manifest.txt\"") -endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") - -file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") -list(REVERSE files) -foreach (file ${files}) - message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - if (EXISTS "$ENV{DESTDIR}${file}") - execute_process( - COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval - ) - if(NOT ${rm_retval} EQUAL 0) - message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") - endif (NOT ${rm_retval} EQUAL 0) - else (EXISTS "$ENV{DESTDIR}${file}") - message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") - endif (EXISTS "$ENV{DESTDIR}${file}") -endforeach(file) diff --git a/octomap/CMakeModules/CompilerSettings.cmake b/octomap/CMakeModules/CompilerSettings.cmake index bae0cc48..ca110f6b 100644 --- a/octomap/CMakeModules/CompilerSettings.cmake +++ b/octomap/CMakeModules/CompilerSettings.cmake @@ -1,29 +1,18 @@ # COMPILER SETTINGS (default: Release) # use "-DCMAKE_BUILD_TYPE=Debug" in cmake for a Debug-build -IF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE Release) -ENDIF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) -MESSAGE (STATUS "\n") -MESSAGE (STATUS "${PROJECT_NAME} building as ${CMAKE_BUILD_TYPE}") +message(STATUS "${PROJECT_NAME} building as ${CMAKE_BUILD_TYPE}") # COMPILER FLAGS -IF (CMAKE_COMPILER_IS_GNUCC) - SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-error ") - SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wpedantic") - SET (CMAKE_CXX_FLAGS_RELEASE "-O3 -funroll-loops -DNDEBUG") - SET (CMAKE_CXX_FLAGS_DEBUG "-O0 -g") - # Shared object compilation under 64bit (vtable) - ADD_DEFINITIONS(-fPIC) -ENDIF() +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-error ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -pedantic") + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -funroll-loops -DNDEBUG") + set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") +endif() - -# Set full rpath http://www.paraview.org/Wiki/CMake_RPATH_handling -# (good to have and required with ROS) -set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - -# no prefix needed for python modules -set(CMAKE_SHARED_MODULE_PREFIX "") +# enables -fPIC in applicable compilers +set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/octomap/octomap-config.cmake.in b/octomap/octomap-config.cmake.in index 0bcacc7d..05490841 100644 --- a/octomap/octomap-config.cmake.in +++ b/octomap/octomap-config.cmake.in @@ -6,16 +6,12 @@ # Usage from an external project: # In your CMakeLists.txt, add these lines: # -# FIND_PACKAGE(OCTOMAP REQUIRED ) -# INCLUDE_DIRECTORIES(${OCTOMAP_INCLUDE_DIRS}) -# TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${OCTOMAP_LIBRARIES}) +# find_package(octomap REQUIRED) +# target_link_libraries(MY_TARGET_NAME PRIVATE octomap::octomap) # # -# This file will define the following variables: -# - OCTOMAP_LIBRARIES : The list of libraries to links against. -# - OCTOMAP_LIBRARY_DIRS : The directory where lib files are. Calling -# LINK_DIRECTORIES with this path is NOT needed. -# - OCTOMAP_INCLUDE_DIRS : The OctoMap include directories. +# This file will also define the following variables: +# - OCTOMAP_LIBRARIES : For backwards compatibility with existing code # - OCTOMAP_MAJOR_VERSION : Major version. # - OCTOMAP_MINOR_VERSION : Minor version. # - OCTOMAP_PATCH_VERSION : Patch version. @@ -25,19 +21,14 @@ @PACKAGE_INIT@ +@OCTOMAP_FIND_DEPENDENCIES@ + set(OCTOMAP_MAJOR_VERSION "@OCTOMAP_MAJOR_VERSION@") set(OCTOMAP_MINOR_VERSION "@OCTOMAP_MINOR_VERSION@") set(OCTOMAP_PATCH_VERSION "@OCTOMAP_PATCH_VERSION@") set(OCTOMAP_VERSION "@OCTOMAP_VERSION@") -set_and_check(OCTOMAP_INCLUDE_DIRS "@PACKAGE_OCTOMAP_INCLUDE_DIRS@") -set_and_check(OCTOMAP_LIBRARY_DIRS "@PACKAGE_OCTOMAP_LIB_DIR@") - -# Set library names -set(OCTOMAP_LIBRARIES - "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMAP_LIBRARY@" - "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMATH_LIBRARY@" -) +set(OCTOMAP_LIBRARIES octomap::octomap) # Additionally set the variables using a lower-case project name. # This fixes discovery for downstream packages that search for lower-case octomap, which has been common in downstream code: @@ -45,9 +36,6 @@ set(octomap_MAJOR_VERSION "${OCTOMAP_MAJOR_VERSION}") set(octomap_MINOR_VERSION "${OCTOMAP_MINOR_VERSION}") set(octomap_PATCH_VERSION "${OCTOMAP_PATCH_VERSION}") set(octomap_VERSION "${OCTOMAP_VERSION}") -set(octomap_INCLUDE_DIRS "${OCTOMAP_INCLUDE_DIRS}") -set(octomap_LIBRARY_DIRS "${OCTOMAP_LIBRARY_DIRS}") set(octomap_LIBRARIES "${OCTOMAP_LIBRARIES}") - -@OCTOMAP_INCLUDE_TARGETS@ +include(${CMAKE_CURRENT_LIST_DIR}/octomap-targets.cmake) diff --git a/octomap/src/CMakeLists.txt b/octomap/src/CMakeLists.txt deleted file mode 100644 index 4c168211..00000000 --- a/octomap/src/CMakeLists.txt +++ /dev/null @@ -1,99 +0,0 @@ -SET (octomap_SRCS - AbstractOcTree.cpp - AbstractOccupancyOcTree.cpp - Pointcloud.cpp - ScanGraph.cpp - CountingOcTree.cpp - OcTree.cpp - OcTreeNode.cpp - OcTreeStamped.cpp - ColorOcTree.cpp - ) - -# dynamic and static libs, see CMake FAQ: -ADD_LIBRARY( octomap SHARED ${octomap_SRCS}) -set_target_properties( octomap PROPERTIES - VERSION ${OCTOMAP_VERSION} - SOVERSION ${OCTOMAP_SOVERSION} -) -ADD_LIBRARY( octomap-static STATIC ${octomap_SRCS}) -SET_TARGET_PROPERTIES(octomap-static PROPERTIES OUTPUT_NAME "octomap") -add_dependencies(octomap-static octomath-static) - -TARGET_LINK_LIBRARIES(octomap octomath) - -if(NOT EXISTS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") - file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") -endif() - -export(TARGETS octomap octomap-static - APPEND FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-targets.cmake") - -ADD_SUBDIRECTORY( testing ) - -ADD_EXECUTABLE(graph2tree graph2tree.cpp) -TARGET_LINK_LIBRARIES(graph2tree octomap) - -ADD_EXECUTABLE(log2graph log2graph.cpp) -TARGET_LINK_LIBRARIES(log2graph octomap) - -ADD_EXECUTABLE(binvox2bt binvox2bt.cpp) -TARGET_LINK_LIBRARIES(binvox2bt octomap) - -ADD_EXECUTABLE(binvox2bt_unique_offsets binvox2bt_unique_offsets.cpp) -TARGET_LINK_LIBRARIES(binvox2bt_unique_offsets octomap) - -ADD_EXECUTABLE(bt2vrml bt2vrml.cpp) -TARGET_LINK_LIBRARIES(bt2vrml octomap) - -ADD_EXECUTABLE(edit_octree edit_octree.cpp) -TARGET_LINK_LIBRARIES(edit_octree octomap) - -ADD_EXECUTABLE(convert_octree convert_octree.cpp) -TARGET_LINK_LIBRARIES(convert_octree octomap) - -ADD_EXECUTABLE(eval_octree_accuracy eval_octree_accuracy.cpp) -TARGET_LINK_LIBRARIES(eval_octree_accuracy octomap) - -ADD_EXECUTABLE(compare_octrees compare_octrees.cpp) -TARGET_LINK_LIBRARIES(compare_octrees octomap) - -ADD_EXECUTABLE(simple_example simple_example.cpp) -TARGET_LINK_LIBRARIES(simple_example octomap) - -ADD_EXECUTABLE(pcd_to_bt_example pcd_to_bt_example.cpp) -TARGET_LINK_LIBRARIES(pcd_to_bt_example octomap) - -ADD_EXECUTABLE(normals_example normals_example.cpp) -TARGET_LINK_LIBRARIES(normals_example octomap) - -ADD_EXECUTABLE(intersection_example intersection_example.cpp) -TARGET_LINK_LIBRARIES(intersection_example octomap) - -ADD_EXECUTABLE(octree2pointcloud octree2pointcloud.cpp) -TARGET_LINK_LIBRARIES(octree2pointcloud octomap) - -ADD_EXECUTABLE(merge_octomaps merge_octomaps.cpp) -TARGET_LINK_LIBRARIES(merge_octomaps octomap) - - -install(TARGETS octomap octomap-static - EXPORT octomap-targets - INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" - ${INSTALL_TARGETS_DEFAULT_ARGS} -) -install(EXPORT octomap-targets DESTINATION "${CMAKE_INSTALL_DATADIR}/octomap") - -install(TARGETS - graph2tree - log2graph - binvox2bt - binvox2bt_unique_offsets - bt2vrml - edit_octree - convert_octree - eval_octree_accuracy - compare_octrees - ${INSTALL_TARGETS_DEFAULT_ARGS} -) - diff --git a/octomap/src/math/CMakeLists.txt b/octomap/src/math/CMakeLists.txt deleted file mode 100644 index 3b47ec44..00000000 --- a/octomap/src/math/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -SET (octomath_SRCS - Vector3.cpp - Quaternion.cpp - Pose6D.cpp - ) - - -ADD_LIBRARY( octomath SHARED ${octomath_SRCS}) - -SET_TARGET_PROPERTIES( octomath PROPERTIES - VERSION ${OCTOMAP_VERSION} - SOVERSION ${OCTOMAP_SOVERSION} -) - -ADD_LIBRARY( octomath-static STATIC ${octomath_SRCS}) -SET_TARGET_PROPERTIES(octomath-static PROPERTIES OUTPUT_NAME "octomath") - -if(NOT EXISTS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") - file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") -endif() - -export(TARGETS octomath octomath-static - APPEND FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-targets.cmake") - -install(TARGETS octomath octomath-static - EXPORT octomap-targets - INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" - ${INSTALL_TARGETS_DEFAULT_ARGS} -) diff --git a/octomap/src/testing/CMakeLists.txt b/octomap/src/testing/CMakeLists.txt index 5dc1d952..4ca72f8b 100644 --- a/octomap/src/testing/CMakeLists.txt +++ b/octomap/src/testing/CMakeLists.txt @@ -1,55 +1,62 @@ -if(BUILD_TESTING) - ADD_EXECUTABLE(test_raycasting test_raycasting.cpp) - TARGET_LINK_LIBRARIES(test_raycasting octomap) - - ADD_EXECUTABLE(test_iterators test_iterators.cpp) - TARGET_LINK_LIBRARIES(test_iterators octomap) - - ADD_EXECUTABLE(test_io test_io.cpp) - TARGET_LINK_LIBRARIES(test_io octomap) - - ADD_EXECUTABLE(test_changedkeys test_changedkeys.cpp) - TARGET_LINK_LIBRARIES(test_changedkeys octomap) - - ADD_EXECUTABLE(test_scans test_scans.cpp) - TARGET_LINK_LIBRARIES(test_scans octomap) - - ADD_EXECUTABLE(test_color_tree test_color_tree.cpp) - TARGET_LINK_LIBRARIES(test_color_tree octomap) - - ADD_EXECUTABLE(color_tree_histogram color_tree_histogram.cpp) - TARGET_LINK_LIBRARIES(color_tree_histogram octomap) - - ADD_EXECUTABLE(test_mapcollection test_mapcollection.cpp) - TARGET_LINK_LIBRARIES(test_mapcollection octomap octomath) - - ADD_EXECUTABLE(test_pruning test_pruning.cpp) - TARGET_LINK_LIBRARIES(test_pruning octomap octomath) - - ADD_EXECUTABLE(test_bbx test_bbx.cpp) - TARGET_LINK_LIBRARIES(test_bbx octomap) - - - # CTest tests below - - ADD_EXECUTABLE(unit_tests unit_tests.cpp) - TARGET_LINK_LIBRARIES(unit_tests octomap) - - ADD_TEST (NAME MathVector COMMAND unit_tests MathVector ) - ADD_TEST (NAME MathPose COMMAND unit_tests MathPose ) - ADD_TEST (NAME InsertRay COMMAND unit_tests InsertRay ) - ADD_TEST (NAME InsertScan COMMAND unit_tests InsertScan ) - ADD_TEST (NAME ReadGraph COMMAND unit_tests ReadGraph ) - ADD_TEST (NAME StampedTree COMMAND unit_tests StampedTree ) - ADD_TEST (NAME OcTreeKey COMMAND unit_tests OcTreeKey ) - ADD_TEST (NAME test_scans COMMAND test_scans ${PROJECT_SOURCE_DIR}/share/data/spherical_scan.graph) - ADD_TEST (NAME test_raycasting COMMAND test_raycasting) - ADD_TEST (NAME test_io COMMAND test_io ${PROJECT_SOURCE_DIR}/share/data/geb079.bt) - ADD_TEST (NAME test_pruning COMMAND test_pruning ) - ADD_TEST (NAME test_iterators COMMAND test_iterators ${PROJECT_SOURCE_DIR}/share/data/geb079.bt) - ADD_TEST (NAME test_mapcollection COMMAND test_mapcollection ${PROJECT_SOURCE_DIR}/share/data/mapcoll.txt) - ADD_TEST (NAME test_color_tree COMMAND test_color_tree) - ADD_TEST (NAME test_bbx COMMAND test_bbx) - - SET_TESTS_PROPERTIES (ReadGraph PROPERTIES DEPENDS InsertScan) -endif() +add_executable(test_raycasting test_raycasting.cpp) +target_link_libraries(test_raycasting octomap) + +add_executable(test_iterators test_iterators.cpp) +target_link_libraries(test_iterators octomap) + +add_executable(test_io test_io.cpp) +target_link_libraries(test_io octomap) + +add_executable(test_changedkeys test_changedkeys.cpp) +target_link_libraries(test_changedkeys octomap) + +add_executable(test_scans test_scans.cpp) +target_link_libraries(test_scans octomap) + +add_executable(test_color_tree test_color_tree.cpp) +target_link_libraries(test_color_tree octomap) + +add_executable(color_tree_histogram color_tree_histogram.cpp) +target_link_libraries(color_tree_histogram octomap) + +add_executable(test_mapcollection test_mapcollection.cpp) +target_link_libraries(test_mapcollection octomap octomath) + +add_executable(test_pruning test_pruning.cpp) +target_link_libraries(test_pruning octomap octomath) + +add_executable(test_bbx test_bbx.cpp) +target_link_libraries(test_bbx octomap) + +# CTest tests below + +add_executable(unit_tests unit_tests.cpp) +target_link_libraries(unit_tests octomap) + +add_test(NAME MathVector COMMAND unit_tests MathVector) +add_test(NAME MathPose COMMAND unit_tests MathPose) +add_test(NAME InsertRay COMMAND unit_tests InsertRay) +add_test(NAME InsertScan COMMAND unit_tests InsertScan) +add_test(NAME ReadGraph COMMAND unit_tests ReadGraph) +add_test(NAME StampedTree COMMAND unit_tests StampedTree) +add_test(NAME OcTreeKey COMMAND unit_tests OcTreeKey) +add_test(NAME test_scans + COMMAND test_scans + ${PROJECT_SOURCE_DIR}/share/data/spherical_scan.graph +) +add_test(NAME test_raycasting COMMAND test_raycasting) +add_test(NAME test_io COMMAND test_io + ${PROJECT_SOURCE_DIR}/share/data/geb079.bt +) +add_test(NAME test_pruning COMMAND test_pruning) +add_test(NAME test_iterators COMMAND test_iterators + ${PROJECT_SOURCE_DIR}/share/data/geb079.bt +) +add_test(NAME test_mapcollection + COMMAND test_mapcollection + ${PROJECT_SOURCE_DIR}/share/data/mapcoll.txt +) +add_test(NAME test_color_tree COMMAND test_color_tree) +add_test(NAME test_bbx COMMAND test_bbx) + +set_tests_properties(ReadGraph PROPERTIES DEPENDS InsertScan) diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index 2ef4711f..583e126b 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -1,168 +1,315 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.10) -PROJECT( octovis ) - -include(CTest) -include(GNUInstallDirs) - -# # version (e.g. for packaging) -set(OCTOVIS_MAJOR_VERSION 1) -set(OCTOVIS_MINOR_VERSION 10) -set(OCTOVIS_PATCH_VERSION 0) -set(OCTOVIS_VERSION ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION}.${OCTOVIS_PATCH_VERSION}) -set(OCTOVIS_SOVERSION ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION}) -# get rid of a useless warning: -if(COMMAND cmake_policy) - cmake_policy(SET CMP0003 NEW) - if(POLICY CMP0042) - # Enable MACOSX_RPATH by default. - cmake_policy(SET CMP0042 NEW) - endif(POLICY CMP0042) -endif(COMMAND cmake_policy) - -SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") - -# COMPILER SETTINGS (default: Release) and flags -INCLUDE(CompilerSettings) - -# Set output directories for libraries and executables -SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) -SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) -SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) -SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) -# output dirs for multi-config builds (MSVC) -foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) - STRING( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) - SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/lib ) - SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/lib ) - SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BASE_DIR}/bin ) -endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) - -# We need the main octomap library to link against (same version as octovis) -# Look at parent directory by default, in case the complete distribution -# (octomap & octovis together) is built. -# -# Otherwise you need to export octomap_DIR to the directory containing -# the file octomap-config.cmake -find_package(octomap ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION} REQUIRED -HINTS ${CMAKE_SOURCE_DIR}/lib/cmake/octomap -${CMAKE_SOURCE_DIR}/../octomap/lib/cmake/octomap +cmake_minimum_required(VERSION 3.10...4.1) +project( + octovis + VERSION 1.10.0 + LANGUAGES CXX ) -MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) +if(NOT DEFINED OCTOVIS_BUILD_OPTIONAL) + set(OCTOVIS_BUILD_OPTIONAL FALSE) +endif() -INCLUDE_DIRECTORIES(BEFORE SYSTEM ${OCTOMAP_INCLUDE_DIRS}) - -# Export the package for use from the build-tree -# (this registers the build-tree with a global CMake-registry) -export(PACKAGE octovis) +set(OCTOVIS_USE_QT_VERSION + "auto" + CACHE STRING "choose which Qt version to use" +) +set_property(CACHE OCTOVIS_USE_QT_VERSION PROPERTY STRINGS "auto" "5" "6") +message( + STATUS "OCTOVIS_USE_QT_VERSION set to \"${OCTOVIS_USE_QT_VERSION}\"" +) -set(INSTALL_TARGETS_DEFAULT_ARGS - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" +set(OCTOVIS_USE_QGLVIEWER + "auto" + CACHE STRING "choose which QGLViewer library to use" +) +set_property( + CACHE OCTOVIS_USE_QGLVIEWER PROPERTY STRINGS "auto" "installed" "vendored" ) +message(STATUS "OCTOVIS_USE_QGLVIEWER set to \"${OCTOVIS_USE_QGLVIEWER}\"") -# Builds the "octovis" viewer based on OpenGL and -# libQGLViewer, if dependencies available -SET( BUILD_VIEWER 0) +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) -option(OCTOVIS_QT6 "Link Octovis against Qt6?" ON) +# version (e.g. for packaging) +set(OCTOVIS_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) +set(OCTOVIS_MINOR_VERSION ${PROJECT_VERSION_MINOR}) +set(OCTOVIS_PATCH_VERSION ${PROJECT_VERSION_PATCH}) +set(OCTOVIS_VERSION ${PROJECT_VERSION}) +set(OCTOVIS_SOVERSION "${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION}") -# Look for required libraries: -set(OpenGL_GL_PREFERENCE LEGACY) -FIND_PACKAGE(OpenGL) +include(CTest) +include(GNUInstallDirs) -IF (OpenGL-NOTFOUND) - MESSAGE ( "OpenGL is required for octovis but could not be found.") -ELSE() - FIND_PACKAGE(QGLViewer) - IF(QGLViewer_FOUND) - SET( BUILD_VIEWER 1) - ELSE() - MESSAGE ( "\n") - MESSAGE ( "libQGLViewer could not be found or generated.") - ENDIF() -ENDIF() +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") +include(CompilerSettings) +if (OCTOVIS_BUILD_OPTIONAL) + set(_required) +else() + set(_required REQUIRED) +endif() -IF(BUILD_VIEWER) - MESSAGE(STATUS "\n") - MESSAGE(STATUS "viewer octovis will be built") +# We need the main octomap library to link against (same version as octovis) +if(NOT TARGET octomap::octomap) + find_package(octomap "${OCTOVIS_VERSION}" ${_required}) +endif() +find_package(OpenGL ${_required}) +set(OCTOVIS_FIND_DEPENDENCIES + "include(CMakeFindDependencyMacro)\nfind_dependency(octomap ${OCTOVIS_VERSION})\nfind_dependency(OpenGL)\n" +) - set(INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include") - INCLUDE_DIRECTORIES(${INCLUDE_DIRS}) +# Looking for installed QGLViewer library +if(NOT OCTOVIS_USE_QT_VERSION STREQUAL "auto") + set(QGLViewer_USE_QT_VERSION "${OCTOVIS_USE_QT_VERSION}") +else() + unset(QGLViewer_USE_QT_VERSION) +endif() +if(OCTOVIS_USE_QGLVIEWER STREQUAL "installed") + find_package(QGLViewer ${_required}) + if(NOT QGLViewer_FOUND) + message(WARNING "No QGLViewer library found; skipping octovis build") + return() + endif() +elseif(OCTOVIS_USE_QGLVIEWER STREQUAL "auto") + find_package(QGLViewer) +elseif(NOT OCTOVIS_USE_QGLVIEWER STREQUAL "vendored") + message( + FATAL_ERROR + "OCTOVIS_USE_QGLVIEWER must be one of \"auto\", \"installed\", \"vendored\"" + ) +endif() +if(QGLViewer_FOUND AND QGLViewer_QT_VERSION) + set(OCTOVIS_QT_VERSION "${QGLViewer_QT_VERSION}") +elseif(NOT OCTOVIS_USE_QT_VERSION STREQUAL "auto") + set(OCTOVIS_QT_VERSION "${OCTOVIS_USE_QT_VERSION}") +else() + unset(OCTOVIS_QT_VERSION) + set(_required) +endif() - INCLUDE( CMakeLists_src.txt ) +if(NOT DEFINED OCTOVIS_QT_VERSION OR OCTOVIS_QT_VERSION STREQUAL "5") + find_package(Qt5 ${_required} COMPONENTS Core Gui OpenGL Widgets Xml) + if(Qt5_FOUND) + set(OCTOVIS_FIND_DEPENDENCIES + "${OCTOVIS_FIND_DEPENDENCIES}\nfind_dependency(Qt5 ${Qt5_VERSION} COMPONENTS Core Gui OpenGL Widgets Xml)" + ) + set(OCTOVIS_QT_TARGETS Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets + Qt5::Xml + ) + message(STATUS "octovis building with Qt ${Qt5_VERSION}") + set(OCTOVIS_QT_VERSION "5") + endif() +endif() +if(NOT DEFINED OCTOVIS_QT_VERSION OR OCTOVIS_QT_VERSION STREQUAL "6") + find_package(Qt6 ${_required} COMPONENTS Core Gui OpenGLWidgets Widgets Xml) + if(Qt6_FOUND) + set(OCTOVIS_FIND_DEPENDENCIES + "${OCTOVIS_FIND_DEPENDENCIES}\nfind_dependency(Qt6 ${Qt6_VERSION} COMPONENTS Core Gui OpenGLWidgets Widgets Xml)" + ) + set(OCTOVIS_QT_TARGETS Qt6::Core Qt6::Gui Qt6::OpenGLWidgets + Qt6::Widgets Qt6::Xml + ) + message(STATUS "octovis building with Qt ${Qt6_VERSION}") + set(OCTOVIS_QT_VERSION "6") + endif() +endif() +if(NOT OCTOVIS_QT_TARGETS) + if(OCTOVIS_BUILD_OPTIONAL) + message(WARNING "No Qt library found; skipping octovis build") + return() + else() + message(FATAL_ERROR "No Qt library found") + endif() +endif() - # Create an octovis-config.cmake file for the use from the build tree - set(OCTOVIS_INCLUDE_DIRS "${INCLUDE_DIRS}") - set(OCTOVIS_LIB_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") - # Set library names as absolute paths - # Windows, spec. MSVC requires the .lib suffix for imported libs - IF(WIN32) - set(OCTOVIS_LIBRARY - "${CMAKE_IMPORT_LIBRARY_PREFIX}octovis${CMAKE_IMPORT_LIBRARY_SUFFIX}" +foreach(target IN ITEMS octomap::octomap OpenGL::GL OpenGL::GLU ${OCTOVIS_QT_TARGETS}) + if(NOT TARGET ${target}) + message(WARNING "Missing target ${target}; skipping octovis build") + return() + endif() +endforeach() + +if(TARGET QGLViewer::QGLViewer) + message(STATUS "octovis building with installed QGLViewer library") + set(QGLVIEWER_TARGET QGLViewer::QGLViewer) + set(OCTOVIS_FIND_DEPENDENCIES + "${OCTOVIS_FIND_DEPENDENCIES}\nlist(APPEND CMAKE_MODULE_PATH \"\${CMAKE_CURRENT_LIST_DIR}/Modules\")\nset(QGLViewer_USE_QT_VERSION ${OCTOVIS_QT_VERSION})\nfind_dependency(QGLViewer)" + ) + install(FILES CMakeModules/FindQGLViewer.cmake + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/octovis/Modules" + ) +else() + message(STATUS "octovis building with vendored QGLViewer library") + set(qglviewer_SOURCES + src/extern/QGLViewer/VRender/BackFaceCullingOptimizer.cpp + src/extern/QGLViewer/VRender/BSPSortMethod.cpp + src/extern/QGLViewer/VRender/EPSExporter.cpp + src/extern/QGLViewer/VRender/Exporter.cpp + src/extern/QGLViewer/VRender/FIGExporter.cpp + src/extern/QGLViewer/VRender/gpc.cpp + src/extern/QGLViewer/VRender/NVector3.cpp + src/extern/QGLViewer/VRender/ParserGL.cpp + src/extern/QGLViewer/VRender/Primitive.cpp + src/extern/QGLViewer/VRender/PrimitivePositioning.cpp + src/extern/QGLViewer/VRender/TopologicalSortMethod.cpp + src/extern/QGLViewer/VRender/Vector2.cpp + src/extern/QGLViewer/VRender/Vector3.cpp + src/extern/QGLViewer/VRender/VisibilityOptimizer.cpp + src/extern/QGLViewer/VRender/VRender.cpp + src/extern/QGLViewer/camera.cpp + src/extern/QGLViewer/constraint.cpp + src/extern/QGLViewer/frame.cpp + src/extern/QGLViewer/keyFrameInterpolator.cpp + src/extern/QGLViewer/manipulatedCameraFrame.cpp + src/extern/QGLViewer/manipulatedFrame.cpp + src/extern/QGLViewer/mouseGrabber.cpp + src/extern/QGLViewer/qglviewer.cpp + src/extern/QGLViewer/quaternion.cpp + src/extern/QGLViewer/saveSnapshot.cpp + src/extern/QGLViewer/vec.cpp + ) + add_library(QGLViewer ${qglviewer_SOURCES}) + target_include_directories( + QGLViewer + PUBLIC + $ + $ + $ + ) + target_link_libraries(QGLViewer PUBLIC ${OCTOVIS_QT_TARGETS}) + set_target_properties( + QGLViewer + PROPERTIES VERSION "${OCTOVIS_VERSION}" + SOVERSION "${OCTOVIS_SOVERSION}" + OUTPUT_NAME "octovis_qglviewer" + AUTOMOC ON + AUTOUIC ON ) - ELSE() - set(OCTOVIS_LIBRARY - "${CMAKE_SHARED_LIBRARY_PREFIX}octovis${CMAKE_SHARED_LIBRARY_SUFFIX}" + install( + DIRECTORY src/extern/QGLViewer/ + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/octovis/qglviewer" + FILES_MATCHING + PATTERN "*.h" ) - ENDIF() + install(TARGETS QGLViewer EXPORT octovis-targets) + set(QGLVIEWER_TARGET QGLViewer) + add_library(octomap::QGLViewer ALIAS QGLViewer) +endif() - include(CMakePackageConfigHelpers) +# octovis library +set(octovis_SOURCES + src/SceneObject.cpp src/PointcloudDrawer.cpp src/OcTreeDrawer.cpp + src/SelectionBox.cpp src/TrajectoryDrawer.cpp src/ColorOcTreeDrawer.cpp +) +set(octovis_HEADERS + include/octovis/CameraFollowMode.h + include/octovis/ColorOcTreeDrawer.h + include/octovis/OcTreeDrawer.h + include/octovis/OcTreeRecord.h + include/octovis/PointcloudDrawer.h + include/octovis/SceneObject.h + include/octovis/SelectionBox.h + include/octovis/TrajectoryDrawer.h + include/octovis/ViewerGui.h + include/octovis/ViewerGui.ui + include/octovis/ViewerSettings.h + include/octovis/ViewerSettings.ui + include/octovis/ViewerSettingsPanel.h + include/octovis/ViewerSettingsPanel.ui + include/octovis/ViewerSettingsPanelCamera.h + include/octovis/ViewerSettingsPanelCamera.ui + include/octovis/ViewerWidget.h +) +add_library(octovis ${octovis_HEADERS} ${octovis_SOURCES}) +target_compile_features(octovis PUBLIC cxx_std_11) +target_include_directories( + octovis + PUBLIC + $ + $ + $ +) +target_link_libraries( + octovis PUBLIC octomap::octomap ${QGLVIEWER_TARGET} ${OCTOVIS_QT_TARGETS} + OpenGL::GL OpenGL::GLU +) +set_target_properties( + octovis + PROPERTIES VERSION "${OCTOVIS_VERSION}" + SOVERSION "${OCTOVIS_SOVERSION}" + AUTOMOC ON + AUTOUIC ON + AUTOGEN_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/octovis_autogen" +) +add_library(octomap::octovis ALIAS octovis) - CONFIGURE_PACKAGE_CONFIG_FILE( - octovis-config.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-config.cmake" - PATH_VARS OCTOVIS_INCLUDE_DIRS OCTOVIS_LIB_DIR - INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/octovis) +# sources for viewer binary +set(octovis_viewer_SOURCES + src/main.cpp + src/ViewerGui.cpp + src/ViewerWidget.cpp + src/ViewerSettings.cpp + src/ViewerSettingsPanel.cpp + src/ViewerSettingsPanelCamera.cpp + src/CameraFollowMode.cpp +) +add_executable(octovis_viewer ${octovis_viewer_SOURCES}) +target_link_libraries(octovis_viewer PRIVATE octovis) +set_target_properties(octovis_viewer PROPERTIES OUTPUT_NAME "octovis") - WRITE_BASIC_PACKAGE_VERSION_FILE( - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-config-version.cmake" +# Export build tree +configure_package_config_file( + octovis-config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/octovis-config.cmake" + INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/octovis-config-version.cmake" VERSION ${OCTOVIS_VERSION} - COMPATIBILITY AnyNewerVersion) - - # not used right now (export depends?) - #set(OCTOMAP_CMAKE_DIR "${PROJECT_BINARY_DIR}") - - # Create a octovis-config.cmake file for the use from the install tree - # and install it - set(OCTOVIS_INCLUDE_DIRS "${CMAKE_INSTALL_FULL_INCLUDEDIR}") - set(OCTOVIS_LIB_DIR "${CMAKE_INSTALL_FULL_LIBDIR}") - #set(OCTOMAP_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") + COMPATIBILITY SameMinorVersion +) +export( + TARGETS octovis + NAMESPACE octomap:: + FILE "${CMAKE_CURRENT_BINARY_DIR}/octovis-targets.cmake" +) +if(TARGET QGLViewer) + export( + TARGETS QGLViewer + NAMESPACE octomap:: + APPEND + FILE "${CMAKE_CURRENT_BINARY_DIR}/octovis-targets.cmake" + ) +endif() +export(PACKAGE octovis) - set(OCTOVIS_INCLUDE_TARGETS - "include(\${CMAKE_CURRENT_LIST_DIR}/octovis-targets.cmake)") +# Installation +install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/octovis_autogen/include/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/octovis" +) +install(TARGETS octovis_viewer) +install(TARGETS octovis EXPORT octovis-targets) +install( + EXPORT octovis-targets + NAMESPACE octomap:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/octovis" +) - CONFIGURE_PACKAGE_CONFIG_FILE( +configure_package_config_file( octovis-config.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config.cmake" - PATH_VARS OCTOVIS_INCLUDE_DIRS OCTOVIS_LIB_DIR - INSTALL_DESTINATION "${CMAKE_INSTALL_FULL_DATADIR}/octovis") - - WRITE_BASIC_PACKAGE_VERSION_FILE( - "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octovis-config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/octovis" +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octovis-config-version.cmake" VERSION ${OCTOVIS_VERSION} - COMPATIBILITY AnyNewerVersion) - - install(FILES - "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config.cmake" - "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config-version.cmake" - DESTINATION "${CMAKE_INSTALL_DATADIR}/octovis") - - # #installation: - # # store all header files to install: - file(GLOB octovis_HDRS *.h *.hxx *.hpp) - install(FILES ${octovis_HDRS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/octovis") - - # Install catkin package.xml - install(FILES package.xml DESTINATION "${CMAKE_INSTALL_DATADIR}/octovis") - - # Allows Colcon to find non-Ament packages when using workspace underlays - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/share/ament_index/resource_index/packages/${PROJECT_NAME} "") - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/share/ament_index/resource_index/packages/${PROJECT_NAME} DESTINATION share/ament_index/resource_index/packages) - -ELSE() - MESSAGE ( "Unfortunately, the viewer (octovis) can not be built because some requirements are missing.") - MESSAGE ( "This will not affect the compilation of the stand-alone library and tools (octomap)") - MESSAGE ( "See README.txt or http://octomap.sf.net for further information.\n") -ENDIF() + COMPATIBILITY SameMinorVersion +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octovis-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/InstallFiles/octovis-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/octovis" +) + +# ROS support +install(FILES package.xml DESTINATION "${CMAKE_INSTALL_DATADIR}/octovis") diff --git a/octovis/CMakeLists_src.txt b/octovis/CMakeLists_src.txt deleted file mode 100644 index 6eaa31ad..00000000 --- a/octovis/CMakeLists_src.txt +++ /dev/null @@ -1,165 +0,0 @@ - -if(OCTOVIS_QT6) - find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGLWidgets Widgets Xml) - set(QT_LIBRARIES Qt6::Core Qt6::Gui Qt6::OpenGLWidgets Qt6::Widgets Qt6::Xml "${OPENGL_gl_LIBRARY}" "${OPENGL_glu_LIBRARY}") -else(OCTOVIS_QT6) - find_package(Qt5Core REQUIRED) - find_package(Qt5Gui REQUIRED) - find_package(Qt5OpenGL REQUIRED) - find_package(Qt5Widgets REQUIRED) - find_package(Qt5Xml REQUIRED) - set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets Qt5::Xml "${OPENGL_gl_LIBRARY}" "${OPENGL_glu_LIBRARY}") - include_directories( - "${Qt5Core_INCLUDE_DIRS}" - "${Qt5Gui_INCLUDE_DIRS}" - "${Qt5OpenGL_INCLUDE_DIRS}" - "${Qt5Widgets_INCLUDE_DIRS}" - "${Qt5Xml_INCLUDE_DIRS}" - ) -endif(OCTOVIS_QT6) - -# Mac OS X seems to require special linker flags: -IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework OpenGL") - SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -framework OpenGL") - SET (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -framework OpenGL") -ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - -# sources for octovis library -set(viewerlib_SRCS - src/SceneObject.cpp - src/PointcloudDrawer.cpp - src/OcTreeDrawer.cpp - src/SelectionBox.cpp - src/TrajectoryDrawer.cpp - src/ColorOcTreeDrawer.cpp -) - -# sources for viewer binary -set(viewer_SRCS - src/main.cpp - src/ViewerGui.cpp - src/ViewerWidget.cpp - src/ViewerSettings.cpp - src/ViewerSettingsPanel.cpp - src/ViewerSettingsPanelCamera.cpp - src/CameraFollowMode.cpp -) - -# Resource files (icons, ...) -if(OCTOVIS_QT6) - QT6_ADD_RESOURCES(viewer_RES src/icons.qrc) -else(OCTOVIS_QT6) - QT5_ADD_RESOURCES(viewer_RES src/icons.qrc) -endif(OCTOVIS_QT6) - -#found QGLViewer lib dir -link_directories(${QGLViewer_LIBRARY_DIR}) - -INCLUDE_DIRECTORIES( - ${QGLViewer_INCLUDE_DIR} -) - -SET(viewer_MOC_HDRS - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerGui.h - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerWidget.h - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettings.h - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettingsPanel.h - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettingsPanelCamera.h - ${PROJECT_SOURCE_DIR}/include/octovis/CameraFollowMode.h -) - -# generate list of MOC srcs: -if(OCTOVIS_QT6) - QT6_WRAP_CPP(viewer_MOC_SRCS ${viewer_MOC_HDRS}) -else(OCTOVIS_QT6) - QT5_WRAP_CPP(viewer_MOC_SRCS ${viewer_MOC_HDRS}) -endif(OCTOVIS_QT6) - -# let cmake generate ui*.h files from .ui files (Qt Designer): -SET(viewer_UIS - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerGui.ui - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettings.ui - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettingsPanel.ui - ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettingsPanelCamera.ui -) -if(OCTOVIS_QT6) - QT6_WRAP_UI(viewer_UIS_H ${viewer_UIS}) -else(OCTOVIS_QT6) - QT5_WRAP_UI(viewer_UIS_H ${viewer_UIS}) -endif(OCTOVIS_QT6) - -# Don't forget to include output directory, otherwise -# the UI file won't be wrapped! -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR}) - - -# Library target -add_library(octovis-static STATIC ${viewerlib_SRCS}) -target_link_libraries(octovis-static - ${QT_LIBRARIES} - ${OPENGL_gl_LIBRARY} - ${OPENGL_glu_LIBRARY} - ${OCTOMAP_LIBRARIES} - ${QGLViewer_LIBRARIES} -) -set_target_properties(octovis-static PROPERTIES OUTPUT_NAME octovis) - -add_library(octovis-shared SHARED ${viewerlib_SRCS}) -target_link_libraries(octovis-shared - ${QT_LIBRARIES} - ${OPENGL_gl_LIBRARY} - ${OPENGL_glu_LIBRARY} - ${OCTOMAP_LIBRARIES} - ${QGLViewer_LIBRARIES} -) -set_target_properties(octovis-shared PROPERTIES - OUTPUT_NAME octovis - VERSION ${OCTOVIS_VERSION} - SOVERSION ${OCTOVIS_SOVERSION} -) - -# directly depend on the octomap library target when building the -# complete distribution, so it is recompiled as needed -if (CMAKE_PROJECT_NAME STREQUAL "octomap-distribution") - ADD_DEPENDENCIES(octovis-static octomap-static) - ADD_DEPENDENCIES(octovis-shared octomap) -endif() - - -# Now add these generated files to the ADD_EXECUTABLE step -# If this is NOT done, then the ui_*.h files will not be generated -add_executable(octovis ${viewer_SRCS} ${viewer_UIS_H} ${viewer_MOC_SRCS} ${viewer_RES}) - -target_link_libraries(octovis -# ${QGLViewer_LIBRARIES} - ${OCTOMAP_LIBRARIES} - octovis-shared -) - -# special handling of MacOS X: -IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_custom_command(TARGET octovis POST_BUILD - COMMAND install_name_tool -change libQGLViewer.2.dylib /opt/local/lib/libQGLViewer.2.dylib ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/octovis - ) -ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - -if(NOT EXISTS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis") - file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis") -endif() - -export(TARGETS octovis octovis-static octovis-shared - FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-targets.cmake") - -install(TARGETS octovis octovis-static octovis-shared - EXPORT octovis-targets - INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" - ${INSTALL_TARGETS_DEFAULT_ARGS} -) -install(EXPORT octovis-targets DESTINATION "${CMAKE_INSTALL_DATADIR}/octovis") - -file(GLOB octovis_HDRS ${PROJECT_SOURCE_DIR}/include/octovis/*.h) -# filter generated headers for GUI: -list(REMOVE_ITEM octovis_HDRS ${viewer_MOC_HDRS} ${viewer_UIS_H}) -install(FILES ${octovis_HDRS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/octovis") - diff --git a/octovis/CMakeModules/CMakeUninstall.cmake.in b/octovis/CMakeModules/CMakeUninstall.cmake.in deleted file mode 100644 index c6d80941..00000000 --- a/octovis/CMakeModules/CMakeUninstall.cmake.in +++ /dev/null @@ -1,22 +0,0 @@ -if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") -endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - -file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") -list(REVERSE files) -foreach (file ${files}) - message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - if (EXISTS "$ENV{DESTDIR}${file}") - execute_process( - COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval - ) - if(NOT ${rm_retval} EQUAL 0) - message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") - endif (NOT ${rm_retval} EQUAL 0) - else (EXISTS "$ENV{DESTDIR}${file}") - message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") - endif (EXISTS "$ENV{DESTDIR}${file}") -endforeach(file) diff --git a/octovis/CMakeModules/CompilerSettings.cmake b/octovis/CMakeModules/CompilerSettings.cmake index 51f689b0..d7c3951f 100644 --- a/octovis/CMakeModules/CompilerSettings.cmake +++ b/octovis/CMakeModules/CompilerSettings.cmake @@ -1,41 +1,18 @@ # COMPILER SETTINGS (default: Release) # use "-DCMAKE_BUILD_TYPE=Debug" in cmake for a Debug-build -IF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE Release) -ENDIF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) -MESSAGE (STATUS "\n") -MESSAGE (STATUS "${PROJECT_NAME} building as ${CMAKE_BUILD_TYPE}") - -# OCTOMAP_OMP = enable OpenMP -# SET(OCTOMAP_OMP 1 CACHE BOOL "Enable/disable OpenMP") -# IF($ENV{OCTOMAP_OMP}) -# SET(OCTOMAP_OMP $ENV{OCTOMAP_OMP}) -# MESSAGE(STATUS "Found OCTOMAP_OMP=${OCTOMAP_OMP}") -# ENDIF($ENV{OCTOMAP_OMP}) +message(STATUS "${PROJECT_NAME} building as ${CMAKE_BUILD_TYPE}") # COMPILER FLAGS -IF (CMAKE_COMPILER_IS_GNUCC) - SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-error ") - SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-error ") - SET (CMAKE_CXX_FLAGS_RELEASE "-O3 -funroll-loops -DNDEBUG") #sse3 disabled for compatibility -# SET (CMAKE_CXX_FLAGS_RELEASE "-O3 -funroll-loops -DNDEBUG -msse3 -mssse3") - SET (CMAKE_CXX_FLAGS_DEBUG "-O0 -g") - # IF(OCTOMAP_OMP) - # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp") - # SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -fopenmp") - # ENDIF(OCTOMAP_OMP) -ENDIF() - -# Set full rpath http://www.paraview.org/Wiki/CMake_RPATH_handling -# (good to have and required with ROS) -set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -funroll-loops -DNDEBUG") + set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") +endif() # enables -fPIC in applicable compilers set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -# no prefix needed for python modules -set(CMAKE_SHARED_MODULE_PREFIX "") diff --git a/octovis/CMakeModules/FindQGLViewer.cmake b/octovis/CMakeModules/FindQGLViewer.cmake index 982d294c..b663a7b4 100644 --- a/octovis/CMakeModules/FindQGLViewer.cmake +++ b/octovis/CMakeModules/FindQGLViewer.cmake @@ -1,126 +1,38 @@ -# Find QGLViewer library -# Looks for a system-wide version of libQGLViewer (qglviewer-qt4 or 5 in Ubuntu). -# If none is found, it builds and uses the local copy in "extern" -# -# Many thanks to L. Ott for assistance! -# -# QGLViewer_INCLUDE_DIR where to find the include files -# QGLViewer_LIBRARY_DIR where to find the libraries -# QGLViewer_LIBRARIES list of libraries to link -# QGLViewer_FOUND true if QGLViewer was found - -SET( QGLViewer_FOUND 0 CACHE BOOL "Do we have QGLViewer?" ) - -FIND_PATH( QGLVIEWER_BASE_DIR qglviewer.h - ${CMAKE_SOURCE_DIR}/src/extern/QGLViewer - ${CMAKE_SOURCE_DIR}/octovis/src/extern/QGLViewer +set(QGLViewer_LIBRARY_CANDIDATES) +if(NOT DEFINED QGLViewer_USE_QT_VERSION OR QGLViewer_USE_QT_VERSION STREQUAL "6") + list(APPEND QGLViewer_LIBRARY_CANDIDATES QGLViewer-qt6 qglviewer-qt6) +endif() +if(NOT DEFINED QGLViewer_USE_QT_VERSION OR QGLViewer_USE_QT_VERSION STREQUAL "5") + list(APPEND QGLViewer_LIBRARY_CANDIDATES QGLViewer-qt5 qglviewer-qt5) +endif() +list(APPEND QGLViewer_LIBRARY_CANDIDATES QGLViewer2 QGLViewer) +find_library( + QGLViewer_LIBRARY NAMES ${QGLViewer_LIBRARY_CANDIDATES} ) - -FIND_PATH( QGLViewer_INCLUDE_DIR qglviewer.h - /usr/include/qglviewer-qt4 - /usr/include/QGLViewer - /opt/local/include/QGLViewer - ${QGLVIEWER_BASE_DIR} +find_path( + QGLViewer_INCLUDE_DIR + NAMES qglviewer.h + PATH_SUFFIXES QGLViewer +) +mark_as_advanced(QGLViewer_INCLUDE_DIR QGLViewer_LIBRARY) + +if(QGLViewer_LIBRARY MATCHES "-qt([56])") + set(QGLViewer_QT_VERSION "${CMAKE_MATCH_1}") +else() + set(QGLViewer_QT_VERSION "") +endif() +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + QGLViewer + REQUIRED_VARS QGLViewer_LIBRARY QGLViewer_INCLUDE_DIR + FAIL_MESSAGE "Could NOT find QGLViewer library" ) -IF( QT4_FOUND ) - FIND_LIBRARY( QGLViewer_LIBRARY_DIR_UBUNTU NAMES qglviewer-qt4 QGLViewer-qt4) -ELSE() - FIND_LIBRARY( QGLViewer_LIBRARY_DIR_UBUNTU NAMES qglviewer-qt5 QGLViewer-qt5) -ENDIF() -FIND_LIBRARY( QGLViewer_LIBRARY_DIR_WINDOWS QGLViewer2 ${QGLVIEWER_BASE_DIR}) -FIND_LIBRARY( QGLViewer_LIBRARY_DIR_OTHER QGLViewer ${QGLVIEWER_BASE_DIR}) - -SET( BUILD_LIB_FROM_SOURCE 0) - -IF( QGLViewer_INCLUDE_DIR ) - - MESSAGE(STATUS "QGLViewer includes found in ${QGLViewer_INCLUDE_DIR}") - IF (QGLViewer_LIBRARY_DIR_UBUNTU) - MESSAGE(STATUS "QGLViewer library found in ${QGLViewer_LIBRARY_DIR_UBUNTU}") - SET( QGLViewer_LIBRARIES ${QGLViewer_LIBRARY_DIR_UBUNTU}) - SET( QGLViewer_FOUND 1 CACHE BOOL "Do we have QGLViewer?" FORCE ) - ELSEIF(QGLViewer_LIBRARY_DIR_WINDOWS) - MESSAGE(STATUS "QGLViewer2 found in ${QGLViewer_LIBRARY_DIR_WINDOWS}") - SET( QGLViewer_LIBRARIES ${QGLViewer_LIBRARY_DIR_WINDOWS}) - SET( QGLViewer_FOUND 1 CACHE BOOL "Do we have QGLViewer?" FORCE ) - ELSEIF(QGLViewer_LIBRARY_DIR_OTHER) - MESSAGE(STATUS "QGLViewer found in ${QGLViewer_LIBRARY_DIR_OTHER}") - SET( QGLViewer_LIBRARIES ${QGLViewer_LIBRARY_DIR_OTHER}) - SET( QGLViewer_FOUND 1 CACHE BOOL "Do we have QGLViewer?" FORCE ) - ELSE() - MESSAGE(STATUS "QGLViewer library not found.") - SET( BUILD_LIB_FROM_SOURCE 1) - SET( QGLViewer_FOUND 0 CACHE BOOL "Do we have QGLViewer?" FORCE ) - ENDIF() - -ELSE() - SET( BUILD_LIB_FROM_SOURCE 1) -ENDIF() - -# build own libQGLViewer -IF(BUILD_LIB_FROM_SOURCE) - - IF (WIN32) - MESSAGE("Cannot generate QGLViewer2 from source automatically.") - MESSAGE("Please build libQGLViewer from source, instructions to do so") - MESSAGE("can be found in octovis/README.txt") - MESSAGE("Please rerun CMAKE when you are ready.") - - ELSE (WIN32) - IF(QGLVIEWER_BASE_DIR) - MESSAGE(STATUS "Trying to build libQGLViewer from source in ${QGLVIEWER_BASE_DIR}") - - FIND_PROGRAM(QMAKE-QT4 qmake-qt4) - IF (QMAKE-QT4) - MESSAGE(STATUS "\t generating Makefile using qmake-qt4") - EXECUTE_PROCESS( - WORKING_DIRECTORY ${QGLVIEWER_BASE_DIR} - COMMAND qmake-qt4 - OUTPUT_QUIET - ) - ELSE(QMAKE-QT4) - MESSAGE(STATUS "\t generating Makefile using qmake") - EXECUTE_PROCESS( - WORKING_DIRECTORY ${QGLVIEWER_BASE_DIR} - COMMAND qmake - OUTPUT_QUIET - ) - ENDIF(QMAKE-QT4) - - MESSAGE(STATUS "\t building library (this may take some time...)") - EXECUTE_PROCESS( - WORKING_DIRECTORY ${QGLVIEWER_BASE_DIR} - COMMAND make - OUTPUT_QUIET - ) - ENDIF(QGLVIEWER_BASE_DIR) - ENDIF(WIN32) - -ELSE(BUILD_LIB_FROM_SOURCE) - IF (NOT QGLViewer_FOUND) - MESSAGE(STATUS "QGLViewer sources NOT found. Exiting.") - ENDIF () -ENDIF(BUILD_LIB_FROM_SOURCE) - -# verify that QGLViewer lib was build if we didnt find it elsewhere -IF (NOT QGLViewer_FOUND) - #FIND_LIBRARY(QGLViewer_LIBRARY_DIR_OTHER QGLViewer ${QGLVIEWER_BASE_DIR}) - FIND_PATH(QGLLIB libQGLViewer.so ${QGLVIEWER_BASE_DIR}) - IF (NOT QGLLIB) - MESSAGE(WARNING "Could not find libQGLViewer.so, failed to build?") - SET( QGLViewer_FOUND 0 CACHE BOOL "Do we have QGLViewer?" FORCE ) - ELSE() - MESSAGE(STATUS "Successfully built library in:\n${QGLLIB}") - SET( QGLViewer_INCLUDE_DIR ${QGLVIEWER_BASE_DIR} CACHE PATH "QGLViewer Include directory" FORCE) - SET( QGLViewer_LIBRARY_DIR ${QGLVIEWER_BASE_DIR} CACHE PATH "QGLViewer Library directory" FORCE) - # TODO: also include "m pthread QGLViewerGen QGLViewerUtility"? - SET( QGLViewer_LIBRARIES QGLViewer) - SET( QGLViewer_FOUND 1 CACHE BOOL "Do we have QGLViewer?" FORCE ) - ENDIF() -ENDIF() - -# You need to use qmake of QT4. You are using QT3 if you get: - -#CMakeFiles/octovis.dir/ViewerWidget.cpp.o: In function `octomap::ViewerWidget::ViewerWidget(QWidget*)': -#ViewerWidget.cpp:(.text+0x1715): undefined reference to `QGLViewer::QGLViewer(QWidget*, QGLWidget const*, QFlags)' +if(QGLViewer_FOUND AND NOT TARGET QGLViewer::QGLViewer) + add_library(QGLViewer::QGLViewer UNKNOWN IMPORTED) + set_target_properties( + QGLViewer::QGLViewer + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${QGLViewer_INCLUDE_DIR}" + IMPORTED_LOCATION "${QGLViewer_LIBRARY}" + ) +endif() diff --git a/octovis/octovis-config.cmake.in b/octovis/octovis-config.cmake.in index 3add82ee..f560b210 100644 --- a/octovis/octovis-config.cmake.in +++ b/octovis/octovis-config.cmake.in @@ -1,27 +1,33 @@ -# It defines the following variables -# OCTOVIS_INCLUDE_DIRS - include directories for OctoMap viewer -# OCTOVIS_LIBRARY_DIRS - library directories for OctoMap viewer -# OCTOVIS_LIBRARIES - libraries to link against -# OCTOVIS_MAJOR_VERSION - major version -# OCTOVIS_MINOR_VERSION - minor version -# OCTOVIS_PATCH_VERSION - patch version -# OCTOVIS_VERSION - major.minor.patch version +# =================================================================================== +# The OctoVis CMake configuration file +# +# ** File generated automatically, do not modify ** +# +# Usage from an external project: +# In your CMakeLists.txt, add these lines: +# +# find_package(octovis REQUIRED) +# target_link_libraries(MY_TARGET_NAME PRIVATE octomap::octovis) +# +# +# This file will also define the following variables: +# - OCTOVIS_LIBRARIES : For backwards compatibility with existing code +# - OCTOVIS_MAJOR_VERSION : Major version. +# - OCTOVIS_MINOR_VERSION : Minor version. +# - OCTOVIS_PATCH_VERSION : Patch version. +# - OCTOVIS_VERSION : Major.Minor.Patch version. +# +# =================================================================================== @PACKAGE_INIT@ +@OCTOVIS_FIND_DEPENDENCIES@ + set(OCTOVIS_MAJOR_VERSION "@OCTOVIS_MAJOR_VERSION@") set(OCTOVIS_MINOR_VERSION "@OCTOVIS_MINOR_VERSION@") set(OCTOVIS_PATCH_VERSION "@OCTOVIS_PATCH_VERSION@") set(OCTOVIS_VERSION "@OCTOVIS_VERSION@") -set_and_check(OCTOVIS_INCLUDE_DIRS "@PACKAGE_OCTOVIS_INCLUDE_DIRS@" "@QGLViewer_INCLUDE_DIR@") -set_and_check(OCTOVIS_LIBRARY_DIRS "@PACKAGE_OCTOVIS_LIB_DIR@" "@QGLViewer_LIBRARY_DIR@") - -# Set library names as absolute paths: -set(OCTOVIS_LIBRARIES - "@QGLViewer_LIBRARIES@" - "@QT_LIBRARIES@" - "@PACKAGE_OCTOVIS_LIB_DIR@/@OCTOVIS_LIBRARY@" -) +set(OCTOVIS_LIBRARIES octomap::octovis) -@OCTOVIS_INCLUDE_TARGETS@ +include(${CMAKE_CURRENT_LIST_DIR}/octovis-targets.cmake) diff --git a/octovis/src/extern/QGLViewer/.gitignore b/octovis/src/extern/QGLViewer/.gitignore deleted file mode 100644 index c02b9cc6..00000000 --- a/octovis/src/extern/QGLViewer/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.moc -.obj -*.so -*.so.* -ui_*.h -libQGLViewer.prl - - diff --git a/octovis/src/extern/QGLViewer/CHANGELOG b/octovis/src/extern/QGLViewer/CHANGELOG index db13655f..62e1015e 100644 --- a/octovis/src/extern/QGLViewer/CHANGELOG +++ b/octovis/src/extern/QGLViewer/CHANGELOG @@ -1,4 +1,4 @@ -This is libQGLViewer version 2.6.3. Packaged on July 10, 2015. +This is libQGLViewer version 2.9.1. The complete change log is available in doc/changeLog.html diff --git a/octovis/src/extern/QGLViewer/INSTALL b/octovis/src/extern/QGLViewer/INSTALL deleted file mode 100644 index c58603af..00000000 --- a/octovis/src/extern/QGLViewer/INSTALL +++ /dev/null @@ -1,20 +0,0 @@ - - l i b Q G L V i e w e r I n s t a l l a t i o n - - - -libQGLViewer requires the Qt library, available from Digia. - -In order to compile the library from its sources: - -- On UNIX platforms, simply type (see doc/installUnix.html for details): - - > qmake - > make - > make install [optional] - -- For Windows installation, see doc/installWindows.html. - - - -See doc/compilation.html for details on compiling programs that use libQGLViewer. diff --git a/octovis/src/extern/QGLViewer/ImageInterface.ui b/octovis/src/extern/QGLViewer/ImageInterface.ui index db85b690..01691d38 100644 --- a/octovis/src/extern/QGLViewer/ImageInterface.ui +++ b/octovis/src/extern/QGLViewer/ImageInterface.ui @@ -242,16 +242,16 @@ - + - OK + Cancel - + - Cancel + OK diff --git a/octovis/src/extern/QGLViewer/LICENCE b/octovis/src/extern/QGLViewer/LICENCE index 441a6877..53747494 100644 --- a/octovis/src/extern/QGLViewer/LICENCE +++ b/octovis/src/extern/QGLViewer/LICENCE @@ -1037,4 +1037,4 @@ Public License instead of this License. But first, please read ------------------------------------------------------------------------- - The QGLViewer library is Copyright (C) 2002-2014 Gilles Debunne. + The QGLViewer library is Copyright (C) 2002-2023 Gilles Debunne. diff --git a/octovis/src/extern/QGLViewer/QGLViewer.pro b/octovis/src/extern/QGLViewer/QGLViewer.pro index 8210248a..190d0e18 100644 --- a/octovis/src/extern/QGLViewer/QGLViewer.pro +++ b/octovis/src/extern/QGLViewer/QGLViewer.pro @@ -6,10 +6,11 @@ TEMPLATE = lib TARGET = QGLViewer -VERSION = 2.6.3 +VERSION = 2.9.1 CONFIG *= qt opengl warn_on shared thread create_prl rtti no_keywords -QGL_HEADERS = qglviewer.h \ +QGL_HEADERS = \ + qglviewer.h \ camera.h \ manipulatedFrame.h \ manipulatedCameraFrame.h \ @@ -22,7 +23,8 @@ QGL_HEADERS = qglviewer.h \ domUtils.h \ config.h -SOURCES = qglviewer.cpp \ +SOURCES = \ + qglviewer.cpp \ camera.cpp \ manipulatedFrame.cpp \ manipulatedCameraFrame.cpp \ @@ -42,9 +44,12 @@ TRANSLATIONS = qglviewer_fr.ts QT *= xml opengl -contains ( $$[QT_VERSION], "^5.*" ) { +equals (QT_MAJOR_VERSION, 5) { QT *= gui widgets } +equals (QT_MAJOR_VERSION, 6) { + QT *= gui widgets openglwidgets +} !isEmpty( QGLVIEWER_STATIC ) { CONFIG *= staticlib @@ -117,12 +122,24 @@ unix { PREFIX_=$${PREFIX} } isEmpty( LIB_DIR ) { - LIB_DIR_ = $${PREFIX_}/lib + macx|darwin-g++ { + LIB_DIR_ = /Library/Frameworks + } else { + LIB_DIR_ = $${PREFIX_}/lib + } } else { LIB_DIR_ = $${LIB_DIR} } isEmpty( INCLUDE_DIR ) { - INCLUDE_DIR_ = $${PREFIX_}/include + macx|darwin-g++ { + isEmpty( PREFIX ) { + INCLUDE_DIR_ = $${PWD}/Library/Developer/Headers + } else { + INCLUDE_DIR_ = $${PREFIX}/Headers + } + } else { + INCLUDE_DIR_ = $${PREFIX_}/include + } } else { INCLUDE_DIR_ = $${INCLUDE_DIR} } @@ -147,6 +164,18 @@ unix { # GLU is part of the OpenGL framework } else { QMAKE_LIBS_OPENGL *= -lGLU + + isEmpty( NO_QT_VERSION_SUFFIX ) { + equals (QT_MAJOR_VERSION, 4) { + TARGET = $$join(TARGET,,,-qt4) + } + equals (QT_MAJOR_VERSION, 5) { + TARGET = $$join(TARGET,,,-qt5) + } + equals (QT_MAJOR_VERSION, 6) { + TARGET = $$join(TARGET,,,-qt6) + } + } } MOC_DIR = .moc @@ -193,6 +222,13 @@ unix { # "make install" configuration options INSTALLS *= target include documentation docImages docRefManual + + # "make uninstall" for all targets + target.uninstall = @echo "uninstall" + include.uninstall = @echo "uninstall" + documentation.uninstall = @echo "uninstall" + docImages.uninstall = @echo "uninstall" + docRefManual.uninstall = @echo "uninstall" } @@ -200,11 +236,14 @@ unix { # -- M a c O S X -- # ------------------- macx|darwin-g++ { - # This setting creates a Mac framework. Comment out this line to create a dylib instead. + # Default setting creates a Mac framework. Comment out this line to create a dylib instead. !staticlib: CONFIG *= lib_bundle include.files *= qglviewer.icns + # Or whatever exists in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ + #QMAKE_MAC_SDK = macosx10.15 + lib_bundle { FRAMEWORK_HEADERS.version = Versions # Should be $$replace(TRANSLATIONS, .ts, .qm), but 'replace' is only available in Qt 4.3 diff --git a/octovis/src/extern/QGLViewer/README b/octovis/src/extern/QGLViewer/README index 44f36292..cefab8b7 100644 --- a/octovis/src/extern/QGLViewer/README +++ b/octovis/src/extern/QGLViewer/README @@ -1,11 +1,11 @@ l i b Q G L V i e w e r - Version 2.6.3. Packaged on July 10, 2015 + Version #VERSION#. Packaged on #DATE# - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. - http://www.libqglviewer.com + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. + #WEBURL# Send e-mail to contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/AxisAlignedBox.h b/octovis/src/extern/QGLViewer/VRender/AxisAlignedBox.h index db401fd4..181aa5d5 100644 --- a/octovis/src/extern/QGLViewer/VRender/AxisAlignedBox.h +++ b/octovis/src/extern/QGLViewer/VRender/AxisAlignedBox.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/BSPSortMethod.cpp b/octovis/src/extern/QGLViewer/VRender/BSPSortMethod.cpp index 7d436815..eb076e52 100644 --- a/octovis/src/extern/QGLViewer/VRender/BSPSortMethod.cpp +++ b/octovis/src/extern/QGLViewer/VRender/BSPSortMethod.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -70,7 +70,7 @@ class BSPTree void recursFillPrimitiveArray(vector&) const; private: BSPNode *_root; - vector _segments; // these are for storing segments and points when _root is null + vector _segments; // these are for storing segments and points when _root is null vector _points; }; @@ -88,7 +88,7 @@ void BSPSortMethod::sortPrimitives(std::vector& primitive_tab,VRen // by the insertion and can not be dynamic_casted anymore. for(unsigned int i=0;i(primitive_tab[i])) != NULL) + if((P = dynamic_cast(primitive_tab[i])) != nullptr) tree.insert(P); else segments_and_points.push_back(primitive_tab[i]); @@ -104,9 +104,9 @@ void BSPSortMethod::sortPrimitives(std::vector& primitive_tab,VRen for(unsigned int j=0;j(segments_and_points[j])) != NULL) + if((S = dynamic_cast(segments_and_points[j])) != nullptr) tree.insert(S); - else if((p = dynamic_cast(segments_and_points[j])) != NULL) + else if((p = dynamic_cast(segments_and_points[j])) != nullptr) tree.insert(p); if(nbinserted%N==0) @@ -156,7 +156,7 @@ class BSPNode BSPTree::BSPTree() { - _root = NULL; + _root = nullptr; } BSPTree::~BSPTree() @@ -164,13 +164,13 @@ BSPTree::~BSPTree() delete _root; } -void BSPTree::insert(Point *P) { if(_root == NULL) _points.push_back(P) ; else _root->insert(P); } -void BSPTree::insert(Segment *S) { if(_root == NULL) _segments.push_back(S); else _root->insert(S); } -void BSPTree::insert(Polygone *P){ if(_root == NULL) _root = new BSPNode(P); else _root->insert(P); } +void BSPTree::insert(Point *P) { if(_root == nullptr) _points.push_back(P) ; else _root->insert(P); } +void BSPTree::insert(Segment *S) { if(_root == nullptr) _segments.push_back(S); else _root->insert(S); } +void BSPTree::insert(Polygone *P){ if(_root == nullptr) _root = new BSPNode(P); else _root->insert(P); } void BSPTree::recursFillPrimitiveArray(vector& tab) const { - if(_root != NULL) _root->recursFillPrimitiveArray(tab); + if(_root != nullptr) _root->recursFillPrimitiveArray(tab); for(unsigned int i=0;i<_points.size();++i) tab.push_back(_points[i]); for(unsigned int j=0;j<_segments.size();++j) tab.push_back(_segments[j]); @@ -220,7 +220,7 @@ void BSPNode::Classify(Segment *S, Segment * & moins_, Segment * & plus_) if(s1 == 0) { moins_ = S; - plus_ = NULL; + plus_ = nullptr; return; } else @@ -255,12 +255,12 @@ void BSPNode::Classify(Segment *S, Segment * & moins_, Segment * & plus_) if(s1 == -1) { moins_ = S; - plus_ = NULL; + plus_ = nullptr; return; } else { - moins_ = NULL; + moins_ = nullptr; plus_ = S; return; } @@ -269,14 +269,14 @@ void BSPNode::Classify(Segment *S, Segment * & moins_, Segment * & plus_) { if(s2 > 0) { - moins_ = NULL; + moins_ = nullptr; plus_ = S; return; } else { moins_ = S; - plus_ = NULL; + plus_ = nullptr; return; } } @@ -284,14 +284,14 @@ void BSPNode::Classify(Segment *S, Segment * & moins_, Segment * & plus_) { if(s1 > 0) { - moins_ = NULL; + moins_ = nullptr; plus_ = S; return; } else { moins_ = S; - plus_ = NULL; + plus_ = nullptr; return; } } @@ -304,12 +304,12 @@ void BSPNode::Classify(Polygone *P, Polygone * & moins_, Polygone * & plus_) static int Signs[100]; static double Zvals[100]; - moins_ = NULL; - plus_ = NULL; + moins_ = nullptr; + plus_ = nullptr; - if(P == NULL) + if(P == nullptr) { - //printf("BSPNode::Classify: Error. Null polygon.\n"); + //printf("BSPNode::Classify: Error. Null polygon.\n"); return; } @@ -342,7 +342,7 @@ void BSPNode::Classify(Polygone *P, Polygone * & moins_, Polygone * & plus_) if((Smin == 0)&&(Smax == 0)) { moins_ = P; - plus_ = NULL; + plus_ = nullptr; return; } @@ -351,7 +351,7 @@ void BSPNode::Classify(Polygone *P, Polygone * & moins_, Polygone * & plus_) if(Smin == 1) { plus_ = P; - moins_ = NULL; + moins_ = nullptr; return; } @@ -359,14 +359,14 @@ void BSPNode::Classify(Polygone *P, Polygone * & moins_, Polygone * & plus_) if(Smax == -1) { - plus_ = NULL; + plus_ = nullptr; moins_ = P; return; } if((Smin == -1)&&(Smax == 0)) { - plus_ = NULL; + plus_ = nullptr; moins_ = P; return; } @@ -374,7 +374,7 @@ void BSPNode::Classify(Polygone *P, Polygone * & moins_, Polygone * & plus_) if((Smin == 0)&&(Smax == 1)) { plus_ = P; - moins_ = NULL; + moins_ = nullptr; return; } @@ -404,7 +404,7 @@ void BSPNode::Classify(Polygone *P, Polygone * & moins_, Polygone * & plus_) // Ils y a des imprecisions numeriques dues au fait que le poly estpres du plan. moins_ = P; - plus_ = NULL; + plus_ = nullptr; return; } @@ -488,7 +488,7 @@ void BSPNode::Classify(Polygone *P, Polygone * & moins_, Polygone * & plus_) void BSPNode::insert(Polygone *P) { - Polygone *side_plus = NULL, *side_moins = NULL; + Polygone *side_plus = nullptr, *side_moins = nullptr; // 1 - Check on which size the polygon is, possibly split. @@ -496,15 +496,15 @@ void BSPNode::insert(Polygone *P) // 2 - insert polygons - if(side_plus != NULL) { - if(fils_plus == NULL) + if(side_plus != nullptr) { + if(fils_plus == nullptr) fils_plus = new BSPNode(side_plus); else fils_plus->insert(side_plus); } - if(side_moins != NULL) { - if(fils_moins == NULL) + if(side_moins != nullptr) { + if(fils_moins == nullptr) fils_moins = new BSPNode(side_moins); else fils_moins->insert(side_moins); @@ -513,7 +513,7 @@ void BSPNode::insert(Polygone *P) void BSPNode::recursFillPrimitiveArray(vector& primitive_tab) const { - if(fils_plus != NULL) + if(fils_plus != nullptr) fils_plus->recursFillPrimitiveArray(primitive_tab); for(unsigned int i=0;i& primitive_tab) cons for(unsigned int j=0;jrecursFillPrimitiveArray(primitive_tab); for(unsigned int i2=0;i2insert(P); } if(res == 1) { - if(fils_plus == NULL) + if(fils_plus == nullptr) pts_plus.push_back(P); else fils_plus->insert(P); @@ -554,19 +554,19 @@ void BSPNode::insert(Point *P) void BSPNode::insert(Segment *S) { - Segment *side_plus = NULL, *side_moins = NULL; + Segment *side_plus = nullptr, *side_moins = nullptr; Classify(S,side_moins,side_plus); - if(side_plus != NULL) { - if(fils_plus == NULL) + if(side_plus != nullptr) { + if(fils_plus == nullptr) seg_plus.push_back(side_plus); else fils_plus->insert(side_plus); } - if(side_moins != NULL) { - if(fils_moins == NULL) + if(side_moins != nullptr) { + if(fils_moins == nullptr) seg_moins.push_back(side_moins); else fils_moins->insert(side_moins); @@ -579,8 +579,8 @@ BSPNode::BSPNode(Polygone *P) initEquation(P,a,b,c,d); - fils_moins = NULL; - fils_plus = NULL; + fils_moins = nullptr; + fils_plus = nullptr; } void BSPNode::initEquation(const Polygone *P,double & a, double & b, double & c, double & d) diff --git a/octovis/src/extern/QGLViewer/VRender/BackFaceCullingOptimizer.cpp b/octovis/src/extern/QGLViewer/VRender/BackFaceCullingOptimizer.cpp index 3cc08689..beef49f3 100644 --- a/octovis/src/extern/QGLViewer/VRender/BackFaceCullingOptimizer.cpp +++ b/octovis/src/extern/QGLViewer/VRender/BackFaceCullingOptimizer.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -59,13 +59,13 @@ void BackFaceCullingOptimizer::optimize(std::vector& primitives_ta int nb_culled = 0 ; for(size_t i=0;i(primitives_tab[i])) != NULL) + if((P = dynamic_cast(primitives_tab[i])) != nullptr) { for(unsigned int j=0;jnbVertices();++j) if(( (P->vertex(j+2) - P->vertex(j+1))^(P->vertex(j+1) - P->vertex(j))).z() > 0.0 ) { delete primitives_tab[i] ; - primitives_tab[i] = NULL ; + primitives_tab[i] = nullptr ; ++nb_culled ; break ; } @@ -75,7 +75,7 @@ void BackFaceCullingOptimizer::optimize(std::vector& primitives_ta int j=0 ; for(size_t k=0;k(primitive_tab[i]) ; Polygone *P = dynamic_cast(primitive_tab[i]) ; - if(p != NULL) spewPoint(p,out) ; - if(s != NULL) spewSegment(s,out) ; - if(P != NULL) spewPolygone(P,out) ; + if(p != nullptr) spewPoint(p,out) ; + if(s != nullptr) spewSegment(s,out) ; + if(P != nullptr) spewPolygone(P,out) ; if(i%N == 0) vparams.progress(i/(float)primitive_tab.size(),QGLViewer::tr("Exporting to file %1").arg(filename)) ; diff --git a/octovis/src/extern/QGLViewer/VRender/Exporter.h b/octovis/src/extern/QGLViewer/VRender/Exporter.h index 4bf5669b..6fffd120 100644 --- a/octovis/src/extern/QGLViewer/VRender/Exporter.h +++ b/octovis/src/extern/QGLViewer/VRender/Exporter.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -60,7 +60,7 @@ namespace vrender { public: Exporter() ; - virtual ~Exporter() {} + virtual ~Exporter() {}; virtual void exportToFile(const QString& filename,const std::vector&,VRenderParams&) ; @@ -92,7 +92,7 @@ namespace vrender { public: EPSExporter() ; - virtual ~EPSExporter() {} + virtual ~EPSExporter() {}; protected: virtual void spewPoint(const Point *, QTextStream& out) ; @@ -120,7 +120,7 @@ namespace vrender class PSExporter: public EPSExporter { public: - virtual ~PSExporter() {} + virtual ~PSExporter() {}; protected: virtual void writeFooter(QTextStream& out) const ; }; @@ -129,7 +129,7 @@ namespace vrender { public: FIGExporter() ; - virtual ~FIGExporter() {} + virtual ~FIGExporter() {}; protected: virtual void spewPoint(const Point *, QTextStream& out) ; diff --git a/octovis/src/extern/QGLViewer/VRender/FIGExporter.cpp b/octovis/src/extern/QGLViewer/VRender/FIGExporter.cpp index b7411586..79edd7d5 100644 --- a/octovis/src/extern/QGLViewer/VRender/FIGExporter.cpp +++ b/octovis/src/extern/QGLViewer/VRender/FIGExporter.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -113,62 +113,6 @@ void FIGExporter::spewSegment(const Segment *S, QTextStream& out) const Feedback3DColor& P1 = Feedback3DColor(S->sommet3DColor(0)) ; const Feedback3DColor& P2 = Feedback3DColor(S->sommet3DColor(1)) ; - GLdouble dx, dy; - GLfloat dr, dg, db, absR, absG, absB, colormax; - int steps; - GLdouble xstep, ystep; - GLfloat rstep, gstep, bstep; - GLdouble xnext, ynext, distance; - GLfloat rnext, gnext, bnext; - - dr = P2.red() - P1.red(); - dg = P2.green() - P1.green(); - db = P2.blue() - P1.blue(); - - if (dr != 0 || dg != 0 || db != 0) - { - /* Smooth shaded line. */ - - dx = P2.x() - P1.x(); - dy = P2.y() - P1.y(); - - distance = sqrt(dx * dx + dy * dy); - - absR = fabs(dr); - absG = fabs(dg); - absB = fabs(db); - - colormax = max(absR, max(absG, absB)); - steps = int(0.5f + max(1.0, colormax * distance * EPS_SMOOTH_LINE_FACTOR)); - - xstep = dx / steps; - ystep = dy / steps; - - rstep = dr / steps; - gstep = dg / steps; - bstep = db / steps; - - xnext = P1.x(); - ynext = P1.y(); - rnext = P1.red(); - gnext = P1.green(); - bnext = P1.blue(); - - /* Back up half a step; we want the end points to be - exactly the their endpoint colors. */ - - xnext -= xstep / 2.0; - ynext -= ystep / 2.0; - rnext -= rstep / 2.0f; - gnext -= gstep / 2.0f; - bnext -= bstep / 2.0f; - } - else - { - /* Single color line. */ - steps = 0; - } - out << "2 1 0 1 0 7 " << (_depth--) << " 0 -1 0.000 0 0 -1 0 0 2\n"; out << "\t " << FigCoordX(P1.x()) << " " << FigCoordY(P1.y()); diff --git a/octovis/src/extern/QGLViewer/VRender/NVector3.cpp b/octovis/src/extern/QGLViewer/VRender/NVector3.cpp index 80864a90..cd7e7afe 100644 --- a/octovis/src/extern/QGLViewer/VRender/NVector3.cpp +++ b/octovis/src/extern/QGLViewer/VRender/NVector3.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/NVector3.h b/octovis/src/extern/QGLViewer/VRender/NVector3.h index cac62e47..1d788f90 100644 --- a/octovis/src/extern/QGLViewer/VRender/NVector3.h +++ b/octovis/src/extern/QGLViewer/VRender/NVector3.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/Optimizer.h b/octovis/src/extern/QGLViewer/VRender/Optimizer.h index be344b4d..160b118d 100644 --- a/octovis/src/extern/QGLViewer/VRender/Optimizer.h +++ b/octovis/src/extern/QGLViewer/VRender/Optimizer.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/ParserGL.cpp b/octovis/src/extern/QGLViewer/VRender/ParserGL.cpp index 4afe15db..c8f0b755 100644 --- a/octovis/src/extern/QGLViewer/VRender/ParserGL.cpp +++ b/octovis/src/extern/QGLViewer/VRender/ParserGL.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -137,7 +137,7 @@ void ParserGL::parseFeedbackBuffer( GLfloat *buffer,int size, primitive_tab.push_back(ParserUtils::checkSegment(S)) ; - if(S == NULL) + if(S == nullptr) nb_degenerated_lines++ ; nb_lines++ ; @@ -159,7 +159,7 @@ void ParserGL::parseFeedbackBuffer( GLfloat *buffer,int size, primitive_tab.push_back(ParserUtils::checkPolygon(P)) ; - if(P == NULL) + if(P == nullptr) nb_degenerated_polys++ ; nb_polys++ ; @@ -172,7 +172,7 @@ void ParserGL::parseFeedbackBuffer( GLfloat *buffer,int size, primitive_tab.push_back(Pt);//ParserUtils::checkPoint(Pt)) ; - if(Pt == NULL) + if(Pt == nullptr) nb_degenerated_points++ ; nb_points++ ; @@ -200,7 +200,7 @@ PtrPrimitive ParserUtils::checkSegment(Segment *& P) { Point *pp = new Point(P->sommet3DColor(0)) ; delete P ; - P = NULL ; + P = nullptr ; return checkPoint(pp) ; } @@ -214,7 +214,7 @@ PtrPrimitive ParserUtils::checkPolygon(Polygone *& P) { cout << "unexpected case: Polygon with " << P->nbVertices() << " vertices !" << endl ; delete P ; - return NULL ; + return nullptr ; } if(P->FlatFactor() < FLAT_POLYGON_EPS) @@ -228,14 +228,14 @@ PtrPrimitive ParserUtils::checkPolygon(Polygone *& P) { Segment *pp = new Segment(P->sommet3DColor((i+1)%n),P->sommet3DColor((i+2)%n)) ; delete P ; - P = NULL ; + P = nullptr ; return checkSegment(pp) ; } Point *pp = new Point(P->sommet3DColor(0)) ; delete P ; - P = NULL ; + P = nullptr ; return checkPoint(pp) ; } diff --git a/octovis/src/extern/QGLViewer/VRender/ParserGL.h b/octovis/src/extern/QGLViewer/VRender/ParserGL.h index 2374a787..19a3506b 100644 --- a/octovis/src/extern/QGLViewer/VRender/ParserGL.h +++ b/octovis/src/extern/QGLViewer/VRender/ParserGL.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/Primitive.cpp b/octovis/src/extern/QGLViewer/VRender/Primitive.cpp index b7c27238..8838dd21 100644 --- a/octovis/src/extern/QGLViewer/VRender/Primitive.cpp +++ b/octovis/src/extern/QGLViewer/VRender/Primitive.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/Primitive.h b/octovis/src/extern/QGLViewer/VRender/Primitive.h index 34d1f750..ea57cc80 100644 --- a/octovis/src/extern/QGLViewer/VRender/Primitive.h +++ b/octovis/src/extern/QGLViewer/VRender/Primitive.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.cpp b/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.cpp index 072d45c9..5a318c87 100644 --- a/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.cpp +++ b/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -399,8 +399,8 @@ gpc_polygon PrimitivePositioning::createGPCPolygon_XY(const Polygone *P) gpc_polygon p ; p.num_contours = 0 ; - p.hole = NULL ; - p.contour = NULL ; + p.hole = nullptr ; + p.contour = nullptr ; gpc_vertex_list *gpc_p_verts = new gpc_vertex_list ; @@ -421,7 +421,7 @@ gpc_polygon PrimitivePositioning::createGPCPolygon_XY(const Polygone *P) void PrimitivePositioning::getsigns(const Primitive *P,const NVector3& v,double C, vector& signs,vector& zvals,int& Smin,int& Smax,double I_EPS) { - if(P == NULL) + if(P == nullptr) throw runtime_error("Null primitive in getsigns !") ; size_t n = P->nbVertices() ; @@ -466,8 +466,8 @@ void PrimitivePositioning::split(Polygone *P,const NVector3& v,double C,Primitiv vector Signs ; vector Zvals ; - P_plus = NULL ; - P_moins = NULL ; + P_plus = nullptr ; + P_moins = nullptr ; int Smin = 1 ; int Smax = -1 ; @@ -476,12 +476,12 @@ void PrimitivePositioning::split(Polygone *P,const NVector3& v,double C,Primitiv size_t n = P->nbVertices() ; - if((Smin == 0)&&(Smax == 0)){ P_moins = P ; P_plus = NULL ; return ; } // Polygone inclus dans le plan - if(Smin == 1) { P_plus = P ; P_moins = NULL ; return ; } // Polygone tout positif - if(Smax == -1) { P_plus = NULL ; P_moins = P ; return ; } // Polygone tout negatif + if((Smin == 0)&&(Smax == 0)){ P_moins = P ; P_plus = nullptr ; return ; } // Polygone inclus dans le plan + if(Smin == 1) { P_plus = P ; P_moins = nullptr ; return ; } // Polygone tout positif + if(Smax == -1) { P_plus = nullptr ; P_moins = P ; return ; } // Polygone tout negatif - if((Smin == -1)&&(Smax == 0)) { P_plus = NULL ; P_moins = P ; return ; } // Polygone tout negatif ou null - if((Smin == 0)&&(Smax == 1)) { P_plus = P ; P_moins = NULL ; return ; } // Polygone tout positif ou null + if((Smin == -1)&&(Smax == 0)) { P_plus = nullptr ; P_moins = P ; return ; } // Polygone tout negatif ou null + if((Smin == 0)&&(Smax == 1)) { P_plus = P ; P_moins = nullptr ; return ; } // Polygone tout positif ou null // Reste le cas Smin = -1 et Smax = 1. Il faut couper @@ -505,7 +505,7 @@ void PrimitivePositioning::split(Polygone *P,const NVector3& v,double C,Primitiv } // Ils y a des imprecisions numeriques dues au fait que le poly estpres du plan. - if((nZero > 2)||(nconsZero > 0)) { P_moins = P ; P_plus = NULL ; return ; } + if((nZero > 2)||(nconsZero > 0)) { P_moins = P ; P_plus = nullptr ; return ; } int dep=0 ; while(Signs[dep] == 0) dep++ ; int prev_sign = Signs[dep] ; @@ -583,12 +583,12 @@ void PrimitivePositioning::split(Point *P,const NVector3& v,double C,Primitive * if(v*P->vertex(0)-C > -_EPS) { P_plus = P ; - P_moins = NULL ; + P_moins = nullptr ; } else { P_moins = P ; - P_plus = NULL ; + P_plus = nullptr ; } } @@ -597,8 +597,8 @@ void PrimitivePositioning::split(Segment *S,const NVector3& v,double C,Primitive vector Signs ; vector Zvals ; - P_plus = NULL ; - P_moins = NULL ; + P_plus = nullptr ; + P_moins = nullptr ; int Smin = 1 ; int Smax = -1 ; @@ -607,12 +607,12 @@ void PrimitivePositioning::split(Segment *S,const NVector3& v,double C,Primitive size_t n = S->nbVertices() ; - if((Smin == 0)&&(Smax == 0)) { P_moins = S ; P_plus = NULL ; return ; } // Polygone inclus dans le plan - if(Smin == 1) { P_plus = S ; P_moins = NULL ; return ; } // Polygone tout positif - if(Smax == -1) { P_plus = NULL ; P_moins = S ; return ; } // Polygone tout negatif + if((Smin == 0)&&(Smax == 0)) { P_moins = S ; P_plus = nullptr ; return ; } // Polygone inclus dans le plan + if(Smin == 1) { P_plus = S ; P_moins = nullptr ; return ; } // Polygone tout positif + if(Smax == -1) { P_plus = nullptr ; P_moins = S ; return ; } // Polygone tout negatif - if((Smin == -1)&&(Smax == 0)) { P_plus = NULL ; P_moins = S ; return ; } // Polygone tout negatif ou null - if((Smin == 0)&&(Smax == 1)) { P_plus = S ; P_moins = NULL ; return ; } // Polygone tout positif ou null + if((Smin == -1)&&(Smax == 0)) { P_plus = nullptr ; P_moins = S ; return ; } // Polygone tout negatif ou null + if((Smin == 0)&&(Smax == 1)) { P_plus = S ; P_moins = nullptr ; return ; } // Polygone tout positif ou null // Reste le cas Smin = -1 et Smax = 1. Il faut couper // On teste la coherence des signes. @@ -632,7 +632,7 @@ void PrimitivePositioning::split(Segment *S,const NVector3& v,double C,Primitive } // Ils y a des imprecisions numeriques dues au fait que le poly estpres du plan. - if((nZero > 2)||(nconsZero > 0)) { P_moins = S ; P_plus = NULL ; return ; } + if((nZero > 2)||(nconsZero > 0)) { P_moins = S ; P_plus = nullptr ; return ; } double Z1 = Zvals[0] ; double Z2 = Zvals[1] ; @@ -664,8 +664,8 @@ void PrimitivePositioning::split(Segment *S,const NVector3& v,double C,Primitive void PrimitivePositioning::splitPrimitive(Primitive *P,const NVector3& v,double c, Primitive *& prim_up,Primitive *& prim_lo) { - Polygone *p1 = dynamic_cast(P) ; if(p1 != NULL) PrimitivePositioning::split(p1,v,c,prim_up,prim_lo) ; - Segment *p2 = dynamic_cast(P) ; if(p2 != NULL) PrimitivePositioning::split(p2,v,c,prim_up,prim_lo) ; - Point *p3 = dynamic_cast(P) ; if(p3 != NULL) PrimitivePositioning::split(p3,v,c,prim_up,prim_lo) ; + Polygone *p1 = dynamic_cast(P) ; if(p1 != nullptr) PrimitivePositioning::split(p1,v,c,prim_up,prim_lo) ; + Segment *p2 = dynamic_cast(P) ; if(p2 != nullptr) PrimitivePositioning::split(p2,v,c,prim_up,prim_lo) ; + Point *p3 = dynamic_cast(P) ; if(p3 != nullptr) PrimitivePositioning::split(p3,v,c,prim_up,prim_lo) ; } diff --git a/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.h b/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.h index 1d323a34..adfa7d9b 100644 --- a/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.h +++ b/octovis/src/extern/QGLViewer/VRender/PrimitivePositioning.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/SortMethod.h b/octovis/src/extern/QGLViewer/VRender/SortMethod.h index e326842c..603b0ba9 100644 --- a/octovis/src/extern/QGLViewer/VRender/SortMethod.h +++ b/octovis/src/extern/QGLViewer/VRender/SortMethod.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/TopologicalSortMethod.cpp b/octovis/src/extern/QGLViewer/VRender/TopologicalSortMethod.cpp index 420e8e0c..f626a498 100644 --- a/octovis/src/extern/QGLViewer/VRender/TopologicalSortMethod.cpp +++ b/octovis/src/extern/QGLViewer/VRender/TopologicalSortMethod.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -499,12 +499,12 @@ void TopologicalSortUtils::recursTopologicalSort( vector< vector >& prec bool prim_lower_prec_contains_ip1 = false ; bool prim_upper_prec_contains_ip1 = false ; - Primitive *prim_upper = NULL ; - Primitive *prim_lower = NULL ; + Primitive *prim_upper = nullptr ; + Primitive *prim_lower = nullptr ; PrimitivePositioning::splitPrimitive(primitive_tab[ancestors[i3]],normal,c,prim_upper,prim_lower) ; - if(prim_upper == NULL || prim_lower == NULL) + if(prim_upper == nullptr || prim_lower == nullptr) continue ; #ifdef DEBUG_TS cout << "Splitted primitive " << ancestors[i3] << endl ; diff --git a/octovis/src/extern/QGLViewer/VRender/Types.h b/octovis/src/extern/QGLViewer/VRender/Types.h index e7c0944e..296df84f 100644 --- a/octovis/src/extern/QGLViewer/VRender/Types.h +++ b/octovis/src/extern/QGLViewer/VRender/Types.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/VRender/VRender.cpp b/octovis/src/extern/QGLViewer/VRender/VRender.cpp index 60562fe1..0caa01ce 100644 --- a/octovis/src/extern/QGLViewer/VRender/VRender.cpp +++ b/octovis/src/extern/QGLViewer/VRender/VRender.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -42,11 +42,14 @@ *****************************************************************************/ -#ifdef WIN32 +#include + +#ifdef Q_OS_WIN32 # include #endif -#ifdef __APPLE__ +#ifdef Q_OS_MAC +# define GL_SILENCE_DEPRECATION # include #else # include @@ -68,9 +71,9 @@ using namespace std ; void vrender::VectorialRender(RenderCB render_callback, void *callback_params, VRenderParams& vparams) { - GLfloat *feedbackBuffer = NULL ; - SortMethod *sort_method = NULL ; - Exporter *exporter = NULL ; + GLfloat *feedbackBuffer = nullptr ; + SortMethod *sort_method = nullptr ; + Exporter *exporter = nullptr ; try { @@ -84,12 +87,12 @@ void vrender::VectorialRender(RenderCB render_callback, void *callback_params, V while(returned < 0) { - if(feedbackBuffer != NULL) + if(feedbackBuffer != nullptr) delete[] feedbackBuffer ; feedbackBuffer = new GLfloat[vparams.size()] ; - if(feedbackBuffer == NULL) + if(feedbackBuffer == nullptr) throw std::runtime_error("Out of memory during feedback buffer allocation.") ; glFeedbackBuffer(vparams.size(), GL_3D_COLOR, feedbackBuffer); @@ -127,10 +130,10 @@ void vrender::VectorialRender(RenderCB render_callback, void *callback_params, V ParserGL parserGL ; parserGL.parseFeedbackBuffer(feedbackBuffer,returned,primitive_tab,vparams) ; - if(feedbackBuffer != NULL) + if(feedbackBuffer != nullptr) { delete[] feedbackBuffer ; - feedbackBuffer = NULL ; + feedbackBuffer = nullptr ; } if(vparams.isEnabled(VRenderParams::OptimizeBackFaceCulling)) @@ -224,16 +227,16 @@ void vrender::VectorialRender(RenderCB render_callback, void *callback_params, V for(unsigned int i=0;i& primitives,VRenderParam gpc_polygon cumulated_union ; cumulated_union.num_contours = 0 ; - cumulated_union.hole = NULL ; - cumulated_union.contour = NULL ; + cumulated_union.hole = nullptr ; + cumulated_union.contour = nullptr ; size_t nboptimised = 0 ; for(size_t pindex = primitives.size() - 1; long(pindex) >= 0;--pindex,++nboptimised) - if(primitives[pindex] != NULL) + if(primitives[pindex] != nullptr) { #ifdef A_FAIRE percentage_finished = pindex / (float)primitives.size() ; @@ -131,11 +131,11 @@ void VisibilityOptimizer::optimize(vector& primitives,VRenderParam gpc_polygon new_poly ; gpc_polygon new_poly_reduced ; new_poly.num_contours = 0 ; - new_poly.hole = NULL ; - new_poly.contour = NULL ; + new_poly.hole = nullptr ; + new_poly.contour = nullptr ; new_poly_reduced.num_contours = 0 ; - new_poly_reduced.hole = NULL ; - new_poly_reduced.contour = NULL ; + new_poly_reduced.hole = nullptr ; + new_poly_reduced.contour = nullptr ; // 1 - creates a gpc_polygon corresponding to the current primitive @@ -215,7 +215,7 @@ void VisibilityOptimizer::optimize(vector& primitives,VRenderParam { ++nb_culled ; delete p ; - primitives[pindex] = NULL ; + primitives[pindex] = nullptr ; continue ; } @@ -226,8 +226,8 @@ void VisibilityOptimizer::optimize(vector& primitives,VRenderParam { gpc_polygon cumulated_union_tmp ; cumulated_union_tmp.num_contours = 0 ; - cumulated_union_tmp.hole = NULL ; - cumulated_union_tmp.contour = NULL ; + cumulated_union_tmp.hole = nullptr ; + cumulated_union_tmp.contour = nullptr ; gpc_polygon_clip(GPC_UNION,&new_poly,&cumulated_union,&cumulated_union_tmp) ; diff --git a/octovis/src/extern/QGLViewer/VRender/gpc.cpp b/octovis/src/extern/QGLViewer/VRender/gpc.cpp index 96ffa3ef..26217218 100644 --- a/octovis/src/extern/QGLViewer/VRender/gpc.cpp +++ b/octovis/src/extern/QGLViewer/VRender/gpc.cpp @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -150,9 +150,9 @@ using namespace std ; #define MALLOC(p, b, s, t) {if ((b) > 0) { \ p= (t*)malloc(b); if (!(p)) { \ fprintf(stderr, "gpc malloc failure: %s\n", s); \ - exit(0);}} else p= NULL;} + exit(0);}} else p= nullptr;} -#define FREE(p) {if (p) {free(p); (p)= NULL;}} +#define FREE(p) {if (p) {free(p); (p)= nullptr;}} /* @@ -387,8 +387,8 @@ static edge_node **bound_list(lmt_node **lmt, double y) /* Add node onto the tail end of the LMT */ MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); (*lmt)->y= y; - (*lmt)->first_bound= NULL; - (*lmt)->next= NULL; + (*lmt)->first_bound= nullptr; + (*lmt)->next= nullptr; return &((*lmt)->first_bound); } else @@ -398,7 +398,7 @@ static edge_node **bound_list(lmt_node **lmt, double y) existing_node= *lmt; MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); (*lmt)->y= y; - (*lmt)->first_bound= NULL; + (*lmt)->first_bound= nullptr; (*lmt)->next= existing_node; return &((*lmt)->first_bound); } @@ -419,8 +419,8 @@ static void add_to_sbtree(int *entries, sb_tree **sbtree, double y) /* Add a new tree node here */ MALLOC(*sbtree, sizeof(sb_tree), "scanbeam tree insertion", sb_tree); (*sbtree)->y= y; - (*sbtree)->less= NULL; - (*sbtree)->more= NULL; + (*sbtree)->less= nullptr; + (*sbtree)->more= nullptr; (*entries)++; } else @@ -555,14 +555,14 @@ static edge_node *build_lmt(lmt_node **lmt, sb_tree **sbtree, e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / (e[i].top.y - e[i].bot.y); e[i].type= type; - e[i].outp[ABOVE]= NULL; - e[i].outp[BELOW]= NULL; - e[i].next= NULL; - e[i].prev= NULL; + e[i].outp[ABOVE]= nullptr; + e[i].outp[BELOW]= nullptr; + e[i].next= nullptr; + e[i].prev= nullptr; e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? - &(e[i + 1]) : NULL; - e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; - e[i].next_bound= NULL; + &(e[i + 1]) : nullptr; + e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : nullptr; + e[i].next_bound= nullptr; e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; e[i].bside[SUBJ]= LEFT; } @@ -605,14 +605,14 @@ static edge_node *build_lmt(lmt_node **lmt, sb_tree **sbtree, e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / (e[i].top.y - e[i].bot.y); e[i].type= type; - e[i].outp[ABOVE]= NULL; - e[i].outp[BELOW]= NULL; - e[i].next= NULL; - e[i].prev= NULL; + e[i].outp[ABOVE]= nullptr; + e[i].outp[BELOW]= nullptr; + e[i].next= nullptr; + e[i].prev= nullptr; e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? - &(e[i + 1]) : NULL; - e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; - e[i].next_bound= NULL; + &(e[i + 1]) : nullptr; + e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : nullptr; + e[i].next_bound= nullptr; e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; e[i].bside[SUBJ]= LEFT; } @@ -632,7 +632,7 @@ static void add_edge_to_aet(edge_node **aet, edge_node *edge, edge_node *prev) /* Append edge onto the tail end of the AET */ *aet= edge; edge->prev= prev; - edge->next= NULL; + edge->next= nullptr; } else { @@ -687,7 +687,7 @@ static void add_intersection(it_node **it, edge_node *edge0, edge_node *edge1, (*it)->ie[1]= edge1; (*it)->point.x= x; (*it)->point.y= y; - (*it)->next= NULL; + (*it)->next= nullptr; } else { @@ -723,7 +723,7 @@ static void add_st_edge(st_node **st, it_node **it, edge_node *edge, (*st)->xb= edge->xb; (*st)->xt= edge->xt; (*st)->dx= edge->dx; - (*st)->prev= NULL; + (*st)->prev= nullptr; } else { @@ -766,7 +766,7 @@ static void build_intersection_table(it_node **it, edge_node *aet, double dy) /* Build intersection table for the current scanbeam */ reset_it(it); - st= NULL; + st= nullptr; /* Process each AET edge */ for (edge= aet; edge; edge= edge->next) @@ -823,7 +823,7 @@ static void add_left(polygon_node *p, double x, double y) { vertex_node *nv; - if(p == NULL) throw runtime_error("GPC: Something's wrong.") ; + if(p == nullptr) throw runtime_error("GPC: Something's wrong.") ; /* Create a new vertex node and set its fields */ MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); @@ -842,8 +842,8 @@ static void merge_left(polygon_node *p, polygon_node *q, polygon_node *list) { polygon_node *target; - if(p == NULL) throw runtime_error("GPC: Something's wrong.") ; - if(q == NULL) throw runtime_error("GPC: Something's wrong.") ; + if(p == nullptr) throw runtime_error("GPC: Something's wrong.") ; + if(q == nullptr) throw runtime_error("GPC: Something's wrong.") ; /* Label contour as a hole */ q->proxy->hole= TRUE; @@ -872,13 +872,13 @@ static void add_right(polygon_node *p, double x, double y) { vertex_node *nv = 0; - if(p == NULL) throw runtime_error("GPC: Something's wrong.") ; + if(p == nullptr) throw runtime_error("GPC: Something's wrong.") ; /* Create a new vertex node and set its fields */ MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); nv->x= x; nv->y= y; - nv->next= NULL; + nv->next= nullptr; /* Add vertex nv to the right end of the polygon's vertex list */ p->proxy->v[RIGHT]->next= nv; @@ -892,8 +892,8 @@ static void merge_right(polygon_node *p, polygon_node *q, polygon_node *list) { polygon_node *target = 0; - if(p == NULL) throw runtime_error("GPC: Something's wrong.") ; - if(q == NULL) throw runtime_error("GPC: Something's wrong.") ; + if(p == nullptr) throw runtime_error("GPC: Something's wrong.") ; + if(q == nullptr) throw runtime_error("GPC: Something's wrong.") ; /* Label contour as external */ @@ -935,7 +935,7 @@ static void add_local_min(polygon_node **p, edge_node *edge, nv->x= x; nv->y= y; - nv->next= NULL; + nv->next= nullptr; /* Initialise proxy to point to p itself */ (*p)->proxy= (*p); @@ -969,7 +969,7 @@ static void add_vertex(vertex_node **t, double x, double y) MALLOC(*t, sizeof(vertex_node), "tristrip vertex creation", vertex_node); (*t)->x= x; (*t)->y= y; - (*t)->next= NULL; + (*t)->next= nullptr; } else /* Head further down the list */ @@ -985,9 +985,9 @@ static void new_tristrip(polygon_node **tn, edge_node *edge, MALLOC(*tn, sizeof(polygon_node), "tristrip node creation", polygon_node); **tn = polygon_node() ; - (*tn)->next= NULL; - (*tn)->v[LEFT]= NULL; - (*tn)->v[RIGHT]= NULL; + (*tn)->next= nullptr; + (*tn)->v[LEFT]= nullptr; + (*tn)->v[RIGHT]= nullptr; (*tn)->active= 1; add_vertex(&((*tn)->v[LEFT]), x, y); edge->outp[ABOVE]= *tn; @@ -1189,27 +1189,27 @@ void gpc_add_contour(gpc_polygon *p, gpc_vertex_list *new_contour, int hole) void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, gpc_polygon *result) { - sb_tree *sbtree= NULL; - it_node *it= NULL, *intersect=0; + sb_tree *sbtree= nullptr; + it_node *it= nullptr, *intersect=0; edge_node *edge=0, *prev_edge=0, *next_edge=0, *succ_edge=0, *e0=0, *e1=0; - edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL; - lmt_node *lmt= NULL, *local_min=0; - polygon_node *out_poly= NULL, *p=0, *q=0, *poly=0, *npoly=0, *cf= NULL; + edge_node *aet= nullptr, *c_heap= nullptr, *s_heap= nullptr; + lmt_node *lmt= nullptr, *local_min=0; + polygon_node *out_poly= nullptr, *p=0, *q=0, *poly=0, *npoly=0, *cf= nullptr; vertex_node *vtx=0, *nv=0; h_state horiz[2]; int in[2], exists[2], parity[2]= {LEFT, LEFT}; int c, v, contributing=0, search, scanbeam= 0, sbt_entries= 0; int vclass=0, bl=0, br=0, tl=0, tr=0; - double *sbt= NULL, xb, px, yb, yt=0.0, dy=0.0, ix, iy; + double *sbt= nullptr, xb, px, yb, yt=0.0, dy=0.0, ix, iy; - /* Test for trivial NULL result cases */ + /* Test for trivial nullptr result cases */ if (((subj->num_contours == 0) && (clip->num_contours == 0)) || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) || ((clip->num_contours == 0) && (op == GPC_INT))) { result->num_contours= 0; - result->hole= NULL; - result->contour= NULL; + result->hole= nullptr; + result->contour= nullptr; return; } @@ -1224,12 +1224,12 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, if (clip->num_contours > 0) c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); - /* Return a NULL result if no contours contribute */ - if (lmt == NULL) + /* Return a nullptr result if no contours contribute */ + if (lmt == nullptr) { result->num_contours= 0; - result->hole= NULL; - result->contour= NULL; + result->hole= nullptr; + result->contour= nullptr; reset_lmt(&lmt); FREE(s_heap); FREE(c_heap); @@ -1274,7 +1274,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { /* Add edges starting at this local minimum to the AET */ for (edge= local_min->first_bound; edge; edge= edge->next_bound) - add_edge_to_aet(&aet, edge, NULL); + add_edge_to_aet(&aet, edge, nullptr); local_min= local_min->next; } @@ -1415,7 +1415,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, px= xb; } edge->outp[ABOVE]= cf; - cf= NULL; + cf= nullptr; break; case ELI: add_left(edge->outp[BELOW], xb, yb); @@ -1429,7 +1429,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, px= xb; } merge_right(cf, edge->outp[BELOW], out_poly); - cf= NULL; + cf= nullptr; break; case ILI: if (xb != px) @@ -1438,13 +1438,13 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, px= xb; } edge->outp[ABOVE]= cf; - cf= NULL; + cf= nullptr; break; case IRI: add_right(edge->outp[BELOW], xb, yb); px= xb; cf= edge->outp[BELOW]; - edge->outp[BELOW]= NULL; + edge->outp[BELOW]= nullptr; break; case IMX: if (xb != px) @@ -1453,8 +1453,8 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, px= xb; } merge_left(cf, edge->outp[BELOW], out_poly); - cf= NULL; - edge->outp[BELOW]= NULL; + cf= nullptr; + edge->outp[BELOW]= nullptr; break; case IMM: if (xb != px) @@ -1463,7 +1463,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, px= xb; } merge_left(cf, edge->outp[BELOW], out_poly); - edge->outp[BELOW]= NULL; + edge->outp[BELOW]= nullptr; add_local_min(&out_poly, edge, xb, yb); cf= edge->outp[ABOVE]; break; @@ -1474,7 +1474,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, px= xb; } merge_right(cf, edge->outp[BELOW], out_poly); - edge->outp[BELOW]= NULL; + edge->outp[BELOW]= nullptr; add_local_min(&out_poly, edge, xb, yb); cf= edge->outp[ABOVE]; break; @@ -1612,7 +1612,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { add_right(p, ix, iy); e1->outp[ABOVE]= p; - e0->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; } break; case ELI: @@ -1620,7 +1620,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { add_left(q, ix, iy); e0->outp[ABOVE]= q; - e1->outp[ABOVE]= NULL; + e1->outp[ABOVE]= nullptr; } break; case EMX: @@ -1628,8 +1628,8 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { add_left(p, ix, iy); merge_right(p, q, out_poly); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; + e1->outp[ABOVE]= nullptr; } break; case IMN: @@ -1641,7 +1641,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { add_left(p, ix, iy); e1->outp[ABOVE]= p; - e0->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; } break; case IRI: @@ -1649,7 +1649,7 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { add_right(q, ix, iy); e0->outp[ABOVE]= q; - e1->outp[ABOVE]= NULL; + e1->outp[ABOVE]= nullptr; } break; case IMX: @@ -1657,8 +1657,8 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { add_right(p, ix, iy); merge_left(p, q, out_poly); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; + e1->outp[ABOVE]= nullptr; } break; case IMM: @@ -1727,8 +1727,8 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, e1->next= prev_edge->next; prev_edge->next= e0->next; } - if(e0->next == NULL) throw runtime_error("GPC internal error.") ; - if(e1->next == NULL) throw runtime_error("GPC internal error.") ; + if(e0->next == nullptr) throw runtime_error("GPC internal error.") ; + if(e1->next == nullptr) throw runtime_error("GPC internal error.") ; e0->next->prev= prev_edge; e1->next->prev= e1; e0->next= next_edge; @@ -1766,14 +1766,14 @@ void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; edge->xb= edge->xt; } - edge->outp[ABOVE]= NULL; + edge->outp[ABOVE]= nullptr; } } } /* === END OF SCANBEAM PROCESSING ================================== */ /* Generate result polygon from out_poly */ - result->contour= NULL; - result->hole= NULL; + result->contour= nullptr; + result->hole= nullptr; result->num_contours= count_contours(out_poly); if (result->num_contours > 0) { @@ -1840,8 +1840,8 @@ void gpc_polygon_to_tristrip(gpc_polygon *s, gpc_tristrip *t) gpc_polygon c; c.num_contours= 0; - c.hole= NULL; - c.contour= NULL; + c.hole= nullptr; + c.contour= nullptr; gpc_tristrip_clip(GPC_DIFF, s, &c, t); } @@ -1849,27 +1849,27 @@ void gpc_polygon_to_tristrip(gpc_polygon *s, gpc_tristrip *t) void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, gpc_tristrip *result) { - sb_tree *sbtree= NULL; - it_node *it= NULL, *intersect; + sb_tree *sbtree= nullptr; + it_node *it= nullptr, *intersect; edge_node *edge=0, *prev_edge=0, *next_edge=0, *succ_edge=0, *e0=0, *e1=0; - edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL, *cf=0; - lmt_node *lmt= NULL, *local_min; - polygon_node *tlist= NULL, *tn, *tnn, *p, *q; + edge_node *aet= nullptr, *c_heap= nullptr, *s_heap= nullptr, *cf=0; + lmt_node *lmt= nullptr, *local_min; + polygon_node *tlist= nullptr, *tn, *tnn, *p, *q; vertex_node *lt, *ltn, *rt, *rtn; h_state horiz[2]; vertex_type cft = NUL; int in[2], exists[2], parity[2]= {LEFT, LEFT}; int s, v, contributing=0, search, scanbeam= 0, sbt_entries= 0; int vclass=0, bl=0, br=0, tl=0, tr=0; - double *sbt= NULL, xb, px, nx, yb, yt=0.0, dy=0.0, ix, iy; + double *sbt= nullptr, xb, px, nx, yb, yt=0.0, dy=0.0, ix, iy; - /* Test for trivial NULL result cases */ + /* Test for trivial nullptr result cases */ if (((subj->num_contours == 0) && (clip->num_contours == 0)) || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) || ((clip->num_contours == 0) && (op == GPC_INT))) { result->num_strips= 0; - result->strip= NULL; + result->strip= nullptr; return; } @@ -1884,11 +1884,11 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, if (clip->num_contours > 0) c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); - /* Return a NULL result if no contours contribute */ - if (lmt == NULL) + /* Return a nullptr result if no contours contribute */ + if (lmt == nullptr) { result->num_strips= 0; - result->strip= NULL; + result->strip= nullptr; reset_lmt(&lmt); FREE(s_heap); FREE(c_heap); @@ -1927,7 +1927,7 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { /* Add edges starting at this local minimum to the AET */ for (edge= local_min->first_bound; edge; edge= edge->next_bound) - add_edge_to_aet(&aet, edge, NULL); + add_edge_to_aet(&aet, edge, nullptr); local_min= local_min->next; } @@ -2063,18 +2063,18 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, edge->outp[ABOVE]= cf->outp[ABOVE]; if (xb != cf->xb) VERTEX(edge, ABOVE, RIGHT, xb, yb); - cf= NULL; + cf= nullptr; break; case ELI: VERTEX(edge, BELOW, LEFT, xb, yb); - edge->outp[ABOVE]= NULL; + edge->outp[ABOVE]= nullptr; cf= edge; break; case EMX: if (xb != cf->xb) VERTEX(edge, BELOW, RIGHT, xb, yb); - edge->outp[ABOVE]= NULL; - cf= NULL; + edge->outp[ABOVE]= nullptr; + cf= nullptr; break; case IMN: if (cft == LED) @@ -2099,11 +2099,11 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, new_tristrip(&tlist, cf, cf->xb, yb); } VERTEX(edge, BELOW, RIGHT, xb, yb); - edge->outp[ABOVE]= NULL; + edge->outp[ABOVE]= nullptr; break; case IMX: VERTEX(edge, BELOW, LEFT, xb, yb); - edge->outp[ABOVE]= NULL; + edge->outp[ABOVE]= nullptr; cft= IMX; break; case IMM: @@ -2115,7 +2115,7 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, break; case EMM: VERTEX(edge, BELOW, RIGHT, xb, yb); - edge->outp[ABOVE]= NULL; + edge->outp[ABOVE]= nullptr; new_tristrip(&tlist, edge, xb, yb); cf= edge; break; @@ -2148,7 +2148,7 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, VERTEX(edge, BELOW, RIGHT, xb, yb); VERTEX(edge, ABOVE, RIGHT, xb, yb); } - cf= NULL; + cf= nullptr; break; default: break; @@ -2274,7 +2274,7 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, VERTEX(prev_edge, ABOVE, LEFT, px, iy); VERTEX(e0, ABOVE, RIGHT, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; - e0->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; } break; case ELI: @@ -2284,15 +2284,15 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, VERTEX(e1, ABOVE, LEFT, ix, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; - e1->outp[ABOVE]= NULL; + e1->outp[ABOVE]= nullptr; } break; case EMX: if (p && q) { VERTEX(e0, ABOVE, LEFT, ix, iy); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; + e1->outp[ABOVE]= nullptr; } break; case IMN: @@ -2314,7 +2314,7 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; - e0->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; } break; case IRI: @@ -2324,7 +2324,7 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; - e1->outp[ABOVE]= NULL; + e1->outp[ABOVE]= nullptr; } break; case IMX: @@ -2332,8 +2332,8 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, { VERTEX(e0, ABOVE, RIGHT, ix, iy); VERTEX(e1, ABOVE, LEFT, ix, iy); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; + e0->outp[ABOVE]= nullptr; + e1->outp[ABOVE]= nullptr; P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); new_tristrip(&tlist, prev_edge, px, iy); @@ -2453,13 +2453,13 @@ void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; edge->xb= edge->xt; } - edge->outp[ABOVE]= NULL; + edge->outp[ABOVE]= nullptr; } } } /* === END OF SCANBEAM PROCESSING ================================== */ /* Generate result tristrip from tlist */ - result->strip= NULL; + result->strip= nullptr; result->num_strips= count_tristrips(tlist); if (result->num_strips > 0) { diff --git a/octovis/src/extern/QGLViewer/VRender/gpc.h b/octovis/src/extern/QGLViewer/VRender/gpc.h index 07841c65..aee468cc 100644 --- a/octovis/src/extern/QGLViewer/VRender/gpc.h +++ b/octovis/src/extern/QGLViewer/VRender/gpc.h @@ -22,9 +22,9 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com diff --git a/octovis/src/extern/QGLViewer/camera.cpp b/octovis/src/extern/QGLViewer/camera.cpp index 45f028ce..d8fd9e8b 100644 --- a/octovis/src/extern/QGLViewer/camera.cpp +++ b/octovis/src/extern/QGLViewer/camera.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,493 +19,515 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - -#include "domUtils.h" #include "camera.h" -#include "qglviewer.h" +#include "domUtils.h" #include "manipulatedCameraFrame.h" +#include "qglviewer.h" using namespace std; using namespace qglviewer; /*! Default constructor. - sceneCenter() is set to (0,0,0) and sceneRadius() is set to 1.0. type() is Camera::PERSPECTIVE, - with a \c M_PI/4 fieldOfView(). + sceneCenter() is set to (0,0,0) and sceneRadius() is set to 1.0. type() is + Camera::PERSPECTIVE, with a \c M_PI/4 fieldOfView(). - See IODistance(), physicalDistanceToScreen(), physicalScreenWidth() and focusDistance() - documentations for default stereo parameter values. */ + See IODistance(), physicalDistanceToScreen(), physicalScreenWidth() and + focusDistance() documentations for default stereo parameter values. */ Camera::Camera() - : frame_(NULL), fieldOfView_(M_PI/4.0), modelViewMatrixIsUpToDate_(false), projectionMatrixIsUpToDate_(false) -{ - // #CONNECTION# Camera copy constructor - interpolationKfi_ = new KeyFrameInterpolator; - // Requires the interpolationKfi_ - setFrame(new ManipulatedCameraFrame()); - - // #CONNECTION# All these default values identical in initFromDOMElement. - - // Requires fieldOfView() to define focusDistance() - setSceneRadius(1.0); - - // Initial value (only scaled after this) - orthoCoef_ = tan(fieldOfView()/2.0); - - // Also defines the pivotPoint(), which changes orthoCoef_. Requires a frame(). - setSceneCenter(Vec(0.0, 0.0, 0.0)); - - // Requires fieldOfView() when called with ORTHOGRAPHIC. Attention to projectionMatrix_ below. - setType(PERSPECTIVE); - - // #CONNECTION# initFromDOMElement default values - setZNearCoefficient(0.005); - setZClippingCoefficient(sqrt(3.0)); - - // Dummy values - setScreenWidthAndHeight(600, 400); - - // Stereo parameters - setIODistance(0.062); - setPhysicalScreenWidth(0.5); - // focusDistance is set from setFieldOfView() - - // #CONNECTION# Camera copy constructor - for (unsigned short j=0; j<16; ++j) - { - modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0); - // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost everywhere. - projectionMatrix_[j] = 0.0; - } - computeProjectionMatrix(); + : frame_(nullptr), fieldOfView_(M_PI / 4.0), modelViewMatrixIsUpToDate_(false), + projectionMatrixIsUpToDate_(false) { + // #CONNECTION# Camera copy constructor + interpolationKfi_ = new KeyFrameInterpolator; + // Requires the interpolationKfi_ + setFrame(new ManipulatedCameraFrame()); + + // #CONNECTION# All these default values identical in initFromDOMElement. + + // Requires fieldOfView() to define focusDistance() + setSceneRadius(1.0); + + // Initial value (only scaled after this) + orthoCoef_ = tan(fieldOfView() / 2.0); + + // Also defines the pivotPoint(), which changes orthoCoef_. Requires a + // frame(). + setSceneCenter(Vec(0.0, 0.0, 0.0)); + + // Requires fieldOfView() when called with ORTHOGRAPHIC. Attention to + // projectionMatrix_ below. + setType(PERSPECTIVE); + + // #CONNECTION# initFromDOMElement default values + setZNearCoefficient(0.005); + setZClippingCoefficient(sqrt(3.0)); + + // Dummy values + setScreenWidthAndHeight(600, 400); + + // Stereo parameters + setIODistance(0.062); + setPhysicalScreenWidth(0.5); + // focusDistance is set from setFieldOfView() + + // Default value + setDevicePixelRatio(1.0); + + // #CONNECTION# Camera copy constructor + for (unsigned short j = 0; j < 16; ++j) { + modelViewMatrix_[j] = ((j % 5 == 0) ? 1.0 : 0.0); + // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost + // everywhere. + projectionMatrix_[j] = 0.0; + } + computeProjectionMatrix(); } /*! Virtual destructor. - The frame() is deleted, but the different keyFrameInterpolator() are \e not deleted (in case they - are shared). */ -Camera::~Camera() -{ - delete frame_; - delete interpolationKfi_; + The frame() is deleted, but the different keyFrameInterpolator() are \e not + deleted (in case they are shared). */ +Camera::~Camera() { + delete frame_; + delete interpolationKfi_; } - /*! Copy constructor. Performs a deep copy using operator=(). */ -Camera::Camera(const Camera& camera) - : QObject(), frame_(NULL) -{ - // #CONNECTION# Camera constructor - interpolationKfi_ = new KeyFrameInterpolator; - // Requires the interpolationKfi_ - setFrame(new ManipulatedCameraFrame(*camera.frame())); - - for (unsigned short j=0; j<16; ++j) - { - modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0); - // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost everywhere. - projectionMatrix_[j] = 0.0; - } +Camera::Camera(const Camera &camera) : QObject(), frame_(nullptr) { + // #CONNECTION# Camera constructor + interpolationKfi_ = new KeyFrameInterpolator; + // Requires the interpolationKfi_ + setFrame(new ManipulatedCameraFrame(*camera.frame())); + + for (unsigned short j = 0; j < 16; ++j) { + modelViewMatrix_[j] = ((j % 5 == 0) ? 1.0 : 0.0); + // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost + // everywhere. + projectionMatrix_[j] = 0.0; + } - (*this)=camera; + (*this) = camera; } /*! Equal operator. - All the parameters of \p camera are copied. The frame() pointer is not modified, but its - Frame::position() and Frame::orientation() are set to those of \p camera. + All the parameters of \p camera are copied. The frame() pointer is not + modified, but its Frame::position() and Frame::orientation() are set to those + of \p camera. - \attention The Camera screenWidth() and screenHeight() are set to those of \p camera. If your - Camera is associated with a QGLViewer, you should update these value after the call to this method: - \code + \attention The Camera screenWidth() and screenHeight() are set to those of \p + camera. If your Camera is associated with a QGLViewer, you should update these + value after the call to this method: \code *(camera()) = otherCamera; camera()->setScreenWidthAndHeight(width(), height()); \endcode The same applies to sceneCenter() and sceneRadius(), if needed. */ -Camera& Camera::operator=(const Camera& camera) -{ - setScreenWidthAndHeight(camera.screenWidth(), camera.screenHeight()); - setFieldOfView(camera.fieldOfView()); - setSceneRadius(camera.sceneRadius()); - setSceneCenter(camera.sceneCenter()); - setZNearCoefficient(camera.zNearCoefficient()); - setZClippingCoefficient(camera.zClippingCoefficient()); - setType(camera.type()); +Camera &Camera::operator=(const Camera &camera) { + setScreenWidthAndHeight(camera.screenWidth(), camera.screenHeight()); + setFieldOfView(camera.fieldOfView()); + setSceneRadius(camera.sceneRadius()); + setSceneCenter(camera.sceneCenter()); + setZNearCoefficient(camera.zNearCoefficient()); + setZClippingCoefficient(camera.zClippingCoefficient()); + setType(camera.type()); - // Stereo parameters - setIODistance(camera.IODistance()); - setFocusDistance(camera.focusDistance()); - setPhysicalScreenWidth(camera.physicalScreenWidth()); + // Stereo parameters + setIODistance(camera.IODistance()); + setFocusDistance(camera.focusDistance()); + setPhysicalScreenWidth(camera.physicalScreenWidth()); - orthoCoef_ = camera.orthoCoef_; - projectionMatrixIsUpToDate_ = false; + orthoCoef_ = camera.orthoCoef_; + projectionMatrixIsUpToDate_ = false; - // frame_ and interpolationKfi_ pointers are not shared. - frame_->setReferenceFrame(NULL); - frame_->setPosition(camera.position()); - frame_->setOrientation(camera.orientation()); + // frame_ and interpolationKfi_ pointers are not shared. + frame_->setReferenceFrame(nullptr); + frame_->setPosition(camera.position()); + frame_->setOrientation(camera.orientation()); - interpolationKfi_->resetInterpolation(); + interpolationKfi_->resetInterpolation(); - kfi_ = camera.kfi_; + kfi_ = camera.kfi_; - computeProjectionMatrix(); - computeModelViewMatrix(); + computeProjectionMatrix(); + computeModelViewMatrix(); - return *this; + return *this; } /*! Sets Camera screenWidth() and screenHeight() (expressed in pixels). -You should not call this method when the Camera is associated with a QGLViewer, since the -latter automatically updates these values when it is resized (hence overwritting your values). +You should not call this method when the Camera is associated with a QGLViewer, +since the latter automatically updates these values when it is resized (hence +overwritting your values). -Non-positive dimension are silently replaced by a 1 pixel value to ensure frustrum coherence. +Non-positive dimension are silently replaced by a 1 pixel value to ensure +frustrum coherence. -If your Camera is used without a QGLViewer (offscreen rendering, shadow maps), use setAspectRatio() -instead to define the projection matrix. */ -void Camera::setScreenWidthAndHeight(int width, int height) -{ - // Prevent negative and zero dimensions that would cause divisions by zero. - screenWidth_ = width > 0 ? width : 1; - screenHeight_ = height > 0 ? height : 1; - projectionMatrixIsUpToDate_ = false; +If your Camera is used without a QGLViewer (offscreen rendering, shadow maps), +use setAspectRatio() instead to define the projection matrix. */ +void Camera::setScreenWidthAndHeight(int width, int height) { + // Prevent negative and zero dimensions that would cause divisions by zero. + screenWidth_ = width > 0 ? width : 1; + screenHeight_ = height > 0 ? height : 1; + projectionMatrixIsUpToDate_ = false; } -/*! Returns the near clipping plane distance used by the Camera projection matrix. +/*! Sets the screen's pixel ratio. - The clipping planes' positions depend on the sceneRadius() and sceneCenter() rather than being fixed - small-enough and large-enough values. A good scene dimension approximation will hence result in an - optimal precision of the z-buffer. +See QScreen::devicePixelRatio() for a definition. +Automatically set by the associated QGLViewer. +*/ +void Camera::setDevicePixelRatio(qreal ratio) { + devicePixelRatio_ = ratio; +} - The near clipping plane is positioned at a distance equal to zClippingCoefficient() * sceneRadius() - in front of the sceneCenter(): - \code +/*! Returns the near clipping plane distance used by the Camera projection + matrix. + + The clipping planes' positions depend on the sceneRadius() and sceneCenter() + rather than being fixed small-enough and large-enough values. A good scene + dimension approximation will hence result in an optimal precision of the + z-buffer. + + The near clipping plane is positioned at a distance equal to + zClippingCoefficient() * sceneRadius() in front of the sceneCenter(): \code zNear = distanceToSceneCenter() - zClippingCoefficient()*sceneRadius(); \endcode - In order to prevent negative or too small zNear() values (which would degrade the z precision), - zNearCoefficient() is used when the Camera is inside the sceneRadius() sphere: - \code - const qreal zMin = zNearCoefficient() * zClippingCoefficient() * sceneRadius(); - if (zNear < zMin) - zNear = zMin; + In order to prevent negative or too small zNear() values (which would degrade + the z precision), zNearCoefficient() is used when the Camera is inside the + sceneRadius() sphere: \code const qreal zMin = zNearCoefficient() * + zClippingCoefficient() * sceneRadius(); if (zNear < zMin) zNear = zMin; // With an ORTHOGRAPHIC type, the value is simply clamped to 0.0 \endcode - See also the zFar(), zClippingCoefficient() and zNearCoefficient() documentations. + See also the zFar(), zClippingCoefficient() and zNearCoefficient() + documentations. - If you need a completely different zNear computation, overload the zNear() and zFar() methods in a - new class that publicly inherits from Camera and use QGLViewer::setCamera(): - \code - class myCamera :: public qglviewer::Camera + If you need a completely different zNear computation, overload the zNear() and + zFar() methods in a new class that publicly inherits from Camera and use + QGLViewer::setCamera(): \code class myCamera :: public qglviewer::Camera { - virtual qreal Camera::zNear() const { return 0.001; } - virtual qreal Camera::zFar() const { return 100.0; } + virtual qreal Camera::zNear() const { return 0.001; }; + virtual qreal Camera::zFar() const { return 100.0; }; } \endcode - See the standardCamera example for an application. - - \attention The value is always positive although the clipping plane is positioned at a negative z - value in the Camera coordinate system. This follows the \c gluPerspective standard. */ -qreal Camera::zNear() const -{ - const qreal zNearScene = zClippingCoefficient() * sceneRadius(); - qreal z = distanceToSceneCenter() - zNearScene; - - // Prevents negative or null zNear values. - const qreal zMin = zNearCoefficient() * zNearScene; - if (z < zMin) - switch (type()) - { - case Camera::PERSPECTIVE : z = zMin; break; - case Camera::ORTHOGRAPHIC : z = 0.0; break; - } - return z; -} - -/*! Returns the far clipping plane distance used by the Camera projection matrix. - -The far clipping plane is positioned at a distance equal to zClippingCoefficient() * sceneRadius() -behind the sceneCenter(): -\code -zFar = distanceToSceneCenter() + zClippingCoefficient()*sceneRadius(); -\endcode + See the standardCamera example + for an application. + + \attention The value is always positive although the clipping plane is + positioned at a negative z value in the Camera coordinate system. This follows + the \c gluPerspective standard. */ +qreal Camera::zNear() const { + const qreal zNearScene = zClippingCoefficient() * sceneRadius(); + qreal z = distanceToSceneCenter() - zNearScene; + + // Prevents negative or null zNear values. + const qreal zMin = zNearCoefficient() * zNearScene; + if (z < zMin) + switch (type()) { + case Camera::PERSPECTIVE: + z = zMin; + break; + case Camera::ORTHOGRAPHIC: + z = 0.0; + break; + } + return z; +} + +/*! Returns the far clipping plane distance used by the Camera projection +matrix. + +The far clipping plane is positioned at a distance equal to +zClippingCoefficient() * sceneRadius() behind the sceneCenter(): \code zFar = +distanceToSceneCenter() + zClippingCoefficient()*sceneRadius(); \endcode See the zNear() documentation for details. */ -qreal Camera::zFar() const -{ - return distanceToSceneCenter() + zClippingCoefficient() * sceneRadius(); +qreal Camera::zFar() const { + return distanceToSceneCenter() + zClippingCoefficient() * sceneRadius(); } - /*! Sets the vertical fieldOfView() of the Camera (in radians). -Note that focusDistance() is set to sceneRadius() / tan(fieldOfView()/2) by this method. */ +Note that focusDistance() is set to sceneRadius() / tan(fieldOfView()/2) by this +method. */ void Camera::setFieldOfView(qreal fov) { - fieldOfView_ = fov; - setFocusDistance(sceneRadius() / tan(fov/2.0)); - projectionMatrixIsUpToDate_ = false; + fieldOfView_ = fov; + setFocusDistance(sceneRadius() / tan(fov / 2.0)); + projectionMatrixIsUpToDate_ = false; } /*! Defines the Camera type(). -Changing the camera Type alters the viewport and the objects' sizes can be changed. -This method garantees that the two frustum match in a plane normal to viewDirection(), passing through the pivotPoint(). +Changing the camera Type alters the viewport and the objects' sizes can be +changed. This method garantees that the two frustum match in a plane normal to +viewDirection(), passing through the pivotPoint(). Prefix the type with \c Camera if needed, as in: \code camera()->setType(Camera::ORTHOGRAPHIC); // or even qglviewer::Camera::ORTHOGRAPHIC if you do not use namespace \endcode */ -void Camera::setType(Type type) -{ - // make ORTHOGRAPHIC frustum fit PERSPECTIVE (at least in plane normal to viewDirection(), passing - // through RAP). Done only when CHANGING type since orthoCoef_ may have been changed with a - // setPivotPoint() in the meantime. - if ( (type == Camera::ORTHOGRAPHIC) && (type_ == Camera::PERSPECTIVE) ) - orthoCoef_ = tan(fieldOfView()/2.0); - type_ = type; - projectionMatrixIsUpToDate_ = false; +void Camera::setType(Type type) { + // make ORTHOGRAPHIC frustum fit PERSPECTIVE (at least in plane normal to + // viewDirection(), passing through RAP). Done only when CHANGING type since + // orthoCoef_ may have been changed with a setPivotPoint() in the meantime. + if ((type == Camera::ORTHOGRAPHIC) && (type_ == Camera::PERSPECTIVE)) + orthoCoef_ = tan(fieldOfView() / 2.0); + type_ = type; + projectionMatrixIsUpToDate_ = false; } /*! Sets the Camera frame(). -If you want to move the Camera, use setPosition() and setOrientation() or one of the Camera -positioning methods (lookAt(), fitSphere(), showEntireScene()...) instead. +If you want to move the Camera, use setPosition() and setOrientation() or one of +the Camera positioning methods (lookAt(), fitSphere(), showEntireScene()...) +instead. -If you want to save the Camera position(), there's no need to call this method either. Use -addKeyFrameToPath() and playPath() instead. +If you want to save the Camera position(), there's no need to call this method +either. Use addKeyFrameToPath() and playPath() instead. -This method is actually mainly useful if you derive the ManipulatedCameraFrame class and want to -use an instance of your new class to move the Camera. +This method is actually mainly useful if you derive the ManipulatedCameraFrame +class and want to use an instance of your new class to move the Camera. -A \c NULL \p mcf pointer will silently be ignored. The calling method is responsible for -deleting the previous frame() pointer if needed in order to prevent memory leaks. */ -void Camera::setFrame(ManipulatedCameraFrame* const mcf) -{ - if (!mcf) - return; +A \c nullptr \p mcf pointer will silently be ignored. The calling method is +responsible for deleting the previous frame() pointer if needed in order to +prevent memory leaks. */ +void Camera::setFrame(ManipulatedCameraFrame *const mcf) { + if (!mcf) + return; - if (frame_) { - disconnect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified())); - } + if (frame_) { + disconnect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified())); + } - frame_ = mcf; - interpolationKfi_->setFrame(frame()); + frame_ = mcf; + interpolationKfi_->setFrame(frame()); - connect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified())); - onFrameModified(); + connect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified())); + onFrameModified(); } -/*! Returns the distance from the Camera center to sceneCenter(), projected along the Camera Z axis. - Used by zNear() and zFar() to optimize the Z range. */ -qreal Camera::distanceToSceneCenter() const -{ - return fabs((frame()->coordinatesOf(sceneCenter())).z); +/*! Returns the distance from the Camera center to sceneCenter(), projected + along the Camera Z axis. Used by zNear() and zFar() to optimize the Z range. +*/ +qreal Camera::distanceToSceneCenter() const { + return fabs((frame()->coordinatesOf(sceneCenter())).z); } +/*! Returns the \p halfWidth and \p halfHeight of the Camera orthographic + frustum. -/*! Returns the \p halfWidth and \p halfHeight of the Camera orthographic frustum. + These values are only valid and used when the Camera is of type() + Camera::ORTHOGRAPHIC. They are expressed in OpenGL units and are used by + loadProjectionMatrix() to define the projection matrix using: \code glOrtho( + -halfWidth, halfWidth, -halfHeight, halfHeight, zNear(), zFar() ) \endcode - These values are only valid and used when the Camera is of type() Camera::ORTHOGRAPHIC. They are - expressed in OpenGL units and are used by loadProjectionMatrix() to define the projection matrix - using: - \code - glOrtho( -halfWidth, halfWidth, -halfHeight, halfHeight, zNear(), zFar() ) - \endcode - - These values are proportional to the Camera (z projected) distance to the pivotPoint(). - When zooming on the object, the Camera is translated forward \e and its frustum is narrowed, making - the object appear bigger on screen, as intuitively expected. + These values are proportional to the Camera (z projected) distance to the + pivotPoint(). When zooming on the object, the Camera is translated forward \e + and its frustum is narrowed, making the object appear bigger on screen, as + intuitively expected. Overload this method to change this behavior if desired, as is done in the standardCamera example. */ -void Camera::getOrthoWidthHeight(GLdouble& halfWidth, GLdouble& halfHeight) const -{ - const qreal dist = orthoCoef_ * fabs(cameraCoordinatesOf(pivotPoint()).z); - //#CONNECTION# fitScreenRegion - halfWidth = dist * ((aspectRatio() < 1.0) ? 1.0 : aspectRatio()); - halfHeight = dist * ((aspectRatio() < 1.0) ? 1.0/aspectRatio() : 1.0); +void Camera::getOrthoWidthHeight(GLdouble &halfWidth, + GLdouble &halfHeight) const { + const qreal dist = orthoCoef_ * fabs(cameraCoordinatesOf(pivotPoint()).z); + //#CONNECTION# fitScreenRegion + halfWidth = dist * ((aspectRatio() < 1.0) ? 1.0 : aspectRatio()); + halfHeight = dist * ((aspectRatio() < 1.0) ? 1.0 / aspectRatio() : 1.0); } - /*! Computes the projection matrix associated with the Camera. - If type() is Camera::PERSPECTIVE, defines a \c GL_PROJECTION matrix similar to what would \c - gluPerspective() do using the fieldOfView(), window aspectRatio(), zNear() and zFar() parameters. - - If type() is Camera::ORTHOGRAPHIC, the projection matrix is as what \c glOrtho() would do. - Frustum's width and height are set using getOrthoWidthHeight(). + If type() is Camera::PERSPECTIVE, defines a \c GL_PROJECTION matrix similar to + what would \c gluPerspective() do using the fieldOfView(), window + aspectRatio(), zNear() and zFar() parameters. + + If type() is Camera::ORTHOGRAPHIC, the projection matrix is as what \c + glOrtho() would do. Frustum's width and height are set using + getOrthoWidthHeight(). + + Both types use zNear() and zFar() to place clipping planes. These values are + determined from sceneRadius() and sceneCenter() so that they best fit the scene + size. + + Use getProjectionMatrix() to retrieve this matrix. Overload + loadProjectionMatrix() if you want your Camera to use an exotic projection + matrix. + + \note You must call this method if your Camera is not associated with a + QGLViewer and is used for offscreen computations (using + (un)projectedCoordinatesOf() for instance). loadProjectionMatrix() does it + otherwise. */ +void Camera::computeProjectionMatrix() const { + if (projectionMatrixIsUpToDate_) + return; + + const qreal ZNear = zNear(); + const qreal ZFar = zFar(); + + switch (type()) { + case Camera::PERSPECTIVE: { + // #CONNECTION# all non null coefficients were set to 0.0 in constructor. + const qreal f = 1.0 / tan(fieldOfView() / 2.0); + projectionMatrix_[0] = f / aspectRatio(); + projectionMatrix_[5] = f; + projectionMatrix_[10] = (ZNear + ZFar) / (ZNear - ZFar); + projectionMatrix_[11] = -1.0; + projectionMatrix_[14] = 2.0 * ZNear * ZFar / (ZNear - ZFar); + projectionMatrix_[15] = 0.0; + // same as gluPerspective( 180.0*fieldOfView()/M_PI, aspectRatio(), zNear(), + // zFar() ); + break; + } + case Camera::ORTHOGRAPHIC: { + GLdouble w, h; + getOrthoWidthHeight(w, h); + projectionMatrix_[0] = 1.0 / w; + projectionMatrix_[5] = 1.0 / h; + projectionMatrix_[10] = -2.0 / (ZFar - ZNear); + projectionMatrix_[11] = 0.0; + projectionMatrix_[14] = -(ZFar + ZNear) / (ZFar - ZNear); + projectionMatrix_[15] = 1.0; + // same as glOrtho( -w, w, -h, h, zNear(), zFar() ); + break; + } + } - Both types use zNear() and zFar() to place clipping planes. These values are determined from - sceneRadius() and sceneCenter() so that they best fit the scene size. + projectionMatrixIsUpToDate_ = true; +} - Use getProjectionMatrix() to retrieve this matrix. Overload loadProjectionMatrix() if you want your - Camera to use an exotic projection matrix. +/*! Computes the modelView matrix associated with the Camera's position() and + orientation(). - \note You must call this method if your Camera is not associated with a QGLViewer and is used for - offscreen computations (using (un)projectedCoordinatesOf() for instance). loadProjectionMatrix() - does it otherwise. */ -void Camera::computeProjectionMatrix() const -{ - if (projectionMatrixIsUpToDate_) return; - - const qreal ZNear = zNear(); - const qreal ZFar = zFar(); - - switch (type()) - { - case Camera::PERSPECTIVE: - { - // #CONNECTION# all non null coefficients were set to 0.0 in constructor. - const qreal f = 1.0/tan(fieldOfView()/2.0); - projectionMatrix_[0] = f/aspectRatio(); - projectionMatrix_[5] = f; - projectionMatrix_[10] = (ZNear + ZFar) / (ZNear - ZFar); - projectionMatrix_[11] = -1.0; - projectionMatrix_[14] = 2.0 * ZNear * ZFar / (ZNear - ZFar); - projectionMatrix_[15] = 0.0; - // same as gluPerspective( 180.0*fieldOfView()/M_PI, aspectRatio(), zNear(), zFar() ); - break; - } - case Camera::ORTHOGRAPHIC: - { - GLdouble w, h; - getOrthoWidthHeight(w,h); - projectionMatrix_[0] = 1.0/w; - projectionMatrix_[5] = 1.0/h; - projectionMatrix_[10] = -2.0/(ZFar - ZNear); - projectionMatrix_[11] = 0.0; - projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear); - projectionMatrix_[15] = 1.0; - // same as glOrtho( -w, w, -h, h, zNear(), zFar() ); - break; - } - } - - projectionMatrixIsUpToDate_ = true; -} - -/*! Computes the modelView matrix associated with the Camera's position() and orientation(). - - This matrix converts from the world coordinates system to the Camera coordinates system, so that - coordinates can then be projected on screen using the projection matrix (see computeProjectionMatrix()). + This matrix converts from the world coordinates system to the Camera + coordinates system, so that coordinates can then be projected on screen using + the projection matrix (see computeProjectionMatrix()). Use getModelViewMatrix() to retrieve this matrix. - \note You must call this method if your Camera is not associated with a QGLViewer and is used for - offscreen computations (using (un)projectedCoordinatesOf() for instance). loadModelViewMatrix() - does it otherwise. */ -void Camera::computeModelViewMatrix() const -{ - if (modelViewMatrixIsUpToDate_) return; + \note You must call this method if your Camera is not associated with a + QGLViewer and is used for offscreen computations (using + (un)projectedCoordinatesOf() for instance). loadModelViewMatrix() does it + otherwise. */ +void Camera::computeModelViewMatrix() const { + if (modelViewMatrixIsUpToDate_) + return; - const Quaternion q = frame()->orientation(); + const Quaternion q = frame()->orientation(); - const qreal q00 = 2.0 * q[0] * q[0]; - const qreal q11 = 2.0 * q[1] * q[1]; - const qreal q22 = 2.0 * q[2] * q[2]; + const qreal q00 = 2.0 * q[0] * q[0]; + const qreal q11 = 2.0 * q[1] * q[1]; + const qreal q22 = 2.0 * q[2] * q[2]; - const qreal q01 = 2.0 * q[0] * q[1]; - const qreal q02 = 2.0 * q[0] * q[2]; - const qreal q03 = 2.0 * q[0] * q[3]; + const qreal q01 = 2.0 * q[0] * q[1]; + const qreal q02 = 2.0 * q[0] * q[2]; + const qreal q03 = 2.0 * q[0] * q[3]; - const qreal q12 = 2.0 * q[1] * q[2]; - const qreal q13 = 2.0 * q[1] * q[3]; + const qreal q12 = 2.0 * q[1] * q[2]; + const qreal q13 = 2.0 * q[1] * q[3]; - const qreal q23 = 2.0 * q[2] * q[3]; + const qreal q23 = 2.0 * q[2] * q[3]; - modelViewMatrix_[0] = 1.0 - q11 - q22; - modelViewMatrix_[1] = q01 - q23; - modelViewMatrix_[2] = q02 + q13; - modelViewMatrix_[3] = 0.0; + modelViewMatrix_[0] = 1.0 - q11 - q22; + modelViewMatrix_[1] = q01 - q23; + modelViewMatrix_[2] = q02 + q13; + modelViewMatrix_[3] = 0.0; - modelViewMatrix_[4] = q01 + q23; - modelViewMatrix_[5] = 1.0 - q22 - q00; - modelViewMatrix_[6] = q12 - q03; - modelViewMatrix_[7] = 0.0; + modelViewMatrix_[4] = q01 + q23; + modelViewMatrix_[5] = 1.0 - q22 - q00; + modelViewMatrix_[6] = q12 - q03; + modelViewMatrix_[7] = 0.0; - modelViewMatrix_[8] = q02 - q13; - modelViewMatrix_[9] = q12 + q03; - modelViewMatrix_[10] = 1.0 - q11 - q00; - modelViewMatrix_[11] = 0.0; + modelViewMatrix_[8] = q02 - q13; + modelViewMatrix_[9] = q12 + q03; + modelViewMatrix_[10] = 1.0 - q11 - q00; + modelViewMatrix_[11] = 0.0; - const Vec t = q.inverseRotate(frame()->position()); + const Vec t = q.inverseRotate(frame()->position()); - modelViewMatrix_[12] = -t.x; - modelViewMatrix_[13] = -t.y; - modelViewMatrix_[14] = -t.z; - modelViewMatrix_[15] = 1.0; + modelViewMatrix_[12] = -t.x; + modelViewMatrix_[13] = -t.y; + modelViewMatrix_[14] = -t.z; + modelViewMatrix_[15] = 1.0; - modelViewMatrixIsUpToDate_ = true; + modelViewMatrixIsUpToDate_ = true; } - /*! Loads the OpenGL \c GL_PROJECTION matrix with the Camera projection matrix. The Camera projection matrix is computed using computeProjectionMatrix(). - When \p reset is \c true (default), the method clears the previous projection matrix by calling \c - glLoadIdentity before setting the matrix. Setting \p reset to \c false is useful for \c GL_SELECT - mode, to combine the pushed matrix with a picking matrix. See QGLViewer::beginSelection() for details. + When \p reset is \c true (default), the method clears the previous projection + matrix by calling \c glLoadIdentity before setting the matrix. Setting \p reset + to \c false is useful for \c GL_SELECT mode, to combine the pushed matrix with + a picking matrix. See QGLViewer::beginSelection() for details. - This method is used by QGLViewer::preDraw() (called before user's QGLViewer::draw() method) to - set the \c GL_PROJECTION matrix according to the viewer's QGLViewer::camera() settings. + This method is used by QGLViewer::preDraw() (called before user's + QGLViewer::draw() method) to set the \c GL_PROJECTION matrix according to the + viewer's QGLViewer::camera() settings. - Use getProjectionMatrix() to retrieve this matrix. Overload this method if you want your Camera to - use an exotic projection matrix. See also loadModelViewMatrix(). + Use getProjectionMatrix() to retrieve this matrix. Overload this method if you + want your Camera to use an exotic projection matrix. See also + loadModelViewMatrix(). \attention \c glMatrixMode is set to \c GL_PROJECTION. - \attention If you use several OpenGL contexts and bypass the Qt main refresh loop, you should call - QGLWidget::makeCurrent() before this method in order to activate the right OpenGL context. */ -void Camera::loadProjectionMatrix(bool reset) const -{ - // WARNING: makeCurrent must be called by every calling method - glMatrixMode(GL_PROJECTION); + \attention If you use several OpenGL contexts and bypass the Qt main refresh + loop, you should call QOpenGLWidget::makeCurrent() before this method in order + to activate the right OpenGL context. */ +void Camera::loadProjectionMatrix(bool reset) const { + // WARNING: makeCurrent must be called by every calling method + glMatrixMode(GL_PROJECTION); - if (reset) - glLoadIdentity(); + if (reset) + glLoadIdentity(); - computeProjectionMatrix(); + computeProjectionMatrix(); - glMultMatrixd(projectionMatrix_); + glMultMatrixd(projectionMatrix_); } -/*! Loads the OpenGL \c GL_MODELVIEW matrix with the modelView matrix corresponding to the Camera. +/*! Loads the OpenGL \c GL_MODELVIEW matrix with the modelView matrix + corresponding to the Camera. Calls computeModelViewMatrix() to compute the Camera's modelView matrix. - This method is used by QGLViewer::preDraw() (called before user's QGLViewer::draw() method) to - set the \c GL_MODELVIEW matrix according to the viewer's QGLViewer::camera() position() and - orientation(). + This method is used by QGLViewer::preDraw() (called before user's + QGLViewer::draw() method) to set the \c GL_MODELVIEW matrix according to the + viewer's QGLViewer::camera() position() and orientation(). - As a result, the vertices used in QGLViewer::draw() can be defined in the so called world - coordinate system. They are multiplied by this matrix to get converted to the Camera coordinate - system, before getting projected using the \c GL_PROJECTION matrix (see loadProjectionMatrix()). + As a result, the vertices used in QGLViewer::draw() can be defined in the so + called world coordinate system. They are multiplied by this matrix to get + converted to the Camera coordinate system, before getting projected using the + \c GL_PROJECTION matrix (see loadProjectionMatrix()). - When \p reset is \c true (default), the method loads (overwrites) the \c GL_MODELVIEW matrix. Setting - \p reset to \c false simply calls \c glMultMatrixd (might be useful for some applications). + When \p reset is \c true (default), the method loads (overwrites) the \c + GL_MODELVIEW matrix. Setting \p reset to \c false simply calls \c glMultMatrixd + (might be useful for some applications). - Overload this method or simply call glLoadMatrixd() at the beginning of QGLViewer::draw() if you - want your Camera to use an exotic modelView matrix. See also loadProjectionMatrix(). + Overload this method or simply call glLoadMatrixd() at the beginning of + QGLViewer::draw() if you want your Camera to use an exotic modelView matrix. + See also loadProjectionMatrix(). getModelViewMatrix() returns the 4x4 modelView matrix. \attention glMatrixMode is set to \c GL_MODELVIEW - \attention If you use several OpenGL contexts and bypass the Qt main refresh loop, you should call - QGLWidget::makeCurrent() before this method in order to activate the right OpenGL context. */ -void Camera::loadModelViewMatrix(bool reset) const -{ - // WARNING: makeCurrent must be called by every calling method - glMatrixMode(GL_MODELVIEW); - computeModelViewMatrix(); - if (reset) - glLoadMatrixd(modelViewMatrix_); - else - glMultMatrixd(modelViewMatrix_); + \attention If you use several OpenGL contexts and bypass the Qt main refresh + loop, you should call QOpenGLWidget::makeCurrent() before this method in order + to activate the right OpenGL context. */ +void Camera::loadModelViewMatrix(bool reset) const { + // WARNING: makeCurrent must be called by every calling method + glMatrixMode(GL_MODELVIEW); + computeModelViewMatrix(); + if (reset) + glLoadMatrixd(modelViewMatrix_); + else + glMultMatrixd(modelViewMatrix_); } /*! Same as loadProjectionMatrix() but for a stereo setup. @@ -513,14 +535,15 @@ void Camera::loadModelViewMatrix(bool reset) const Only the Camera::PERSPECTIVE type() is supported for stereo mode. See QGLViewer::setStereoDisplay(). - Uses focusDistance(), IODistance(), and physicalScreenWidth() to compute cameras - offset and asymmetric frustums. + Uses focusDistance(), IODistance(), and physicalScreenWidth() to compute + cameras offset and asymmetric frustums. - When \p leftBuffer is \c true, computes the projection matrix associated to the left eye (right eye - otherwise). See also loadModelViewMatrixStereo(). + When \p leftBuffer is \c true, computes the projection matrix associated to the + left eye (right eye otherwise). See also loadModelViewMatrixStereo(). See the stereoViewer and the anaglyph examples for an illustration. + href="../examples/contribs.html#anaglyph">anaglyph examples for an + illustration. To retrieve this matrix, use a code like: \code @@ -533,41 +556,40 @@ void Camera::loadModelViewMatrix(bool reset) const Note that getProjectionMatrix() always returns the mono-vision matrix. \attention glMatrixMode is set to \c GL_PROJECTION. */ -void Camera::loadProjectionMatrixStereo(bool leftBuffer) const -{ - qreal left, right, bottom, top; - qreal screenHalfWidth, halfWidth, side, shift, delta; - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - switch (type()) - { - case Camera::PERSPECTIVE: - // compute half width of screen, - // corresponding to zero parallax plane to deduce decay of cameras - screenHalfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0); - shift = screenHalfWidth * IODistance() / physicalScreenWidth(); - // should be * current y / y total - // to take into account that the window doesn't cover the entire screen - - // compute half width of "view" at znear and the delta corresponding to - // the shifted camera to deduce what to set for asymmetric frustums - halfWidth = zNear() * tan(horizontalFieldOfView() / 2.0); - delta = shift * zNear() / focusDistance(); - side = leftBuffer ? -1.0 : 1.0; - - left = -halfWidth + side * delta; - right = halfWidth + side * delta; - top = halfWidth / aspectRatio(); - bottom = -top; - glFrustum(left, right, bottom, top, zNear(), zFar() ); - break; - - case Camera::ORTHOGRAPHIC: - qWarning("Camera::setProjectionMatrixStereo: Stereo not available with Ortho mode"); - break; - } +void Camera::loadProjectionMatrixStereo(bool leftBuffer) const { + qreal left, right, bottom, top; + qreal screenHalfWidth, halfWidth, side, shift, delta; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + switch (type()) { + case Camera::PERSPECTIVE: + // compute half width of screen, + // corresponding to zero parallax plane to deduce decay of cameras + screenHalfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0); + shift = screenHalfWidth * IODistance() / physicalScreenWidth(); + // should be * current y / y total + // to take into account that the window doesn't cover the entire screen + + // compute half width of "view" at znear and the delta corresponding to + // the shifted camera to deduce what to set for asymmetric frustums + halfWidth = zNear() * tan(horizontalFieldOfView() / 2.0); + delta = shift * zNear() / focusDistance(); + side = leftBuffer ? -1.0 : 1.0; + + left = -halfWidth + side * delta; + right = halfWidth + side * delta; + top = halfWidth / aspectRatio(); + bottom = -top; + glFrustum(left, right, bottom, top, zNear(), zFar()); + break; + + case Camera::ORTHOGRAPHIC: + qWarning("Camera::setProjectionMatrixStereo: Stereo not available with " + "Ortho mode"); + break; + } } /*! Same as loadModelViewMatrix() but for a stereo setup. @@ -575,63 +597,66 @@ void Camera::loadProjectionMatrixStereo(bool leftBuffer) const Only the Camera::PERSPECTIVE type() is supported for stereo mode. See QGLViewer::setStereoDisplay(). - The modelView matrix is almost identical to the mono-vision one. It is simply translated along its - horizontal axis by a value that depends on stereo parameters (see focusDistance(), - IODistance(), and physicalScreenWidth()). + The modelView matrix is almost identical to the mono-vision one. It is simply + translated along its horizontal axis by a value that depends on stereo + parameters (see focusDistance(), IODistance(), and physicalScreenWidth()). - When \p leftBuffer is \c true, computes the modelView matrix associated to the left eye (right eye - otherwise). + When \p leftBuffer is \c true, computes the modelView matrix associated to the + left eye (right eye otherwise). loadProjectionMatrixStereo() explains how to retrieve to resulting matrix. See the stereoViewer and the anaglyph examples for an illustration. + href="../examples/contribs.html#anaglyph">anaglyph examples for an + illustration. \attention glMatrixMode is set to \c GL_MODELVIEW. */ -void Camera::loadModelViewMatrixStereo(bool leftBuffer) const -{ - // WARNING: makeCurrent must be called by every calling method - glMatrixMode(GL_MODELVIEW); - - qreal halfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0); - qreal shift = halfWidth * IODistance() / physicalScreenWidth(); // * current window width / full screen width - - computeModelViewMatrix(); - if (leftBuffer) - modelViewMatrix_[12] -= shift; - else - modelViewMatrix_[12] += shift; - glLoadMatrixd(modelViewMatrix_); +void Camera::loadModelViewMatrixStereo(bool leftBuffer) const { + // WARNING: makeCurrent must be called by every calling method + glMatrixMode(GL_MODELVIEW); + + qreal halfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0); + qreal shift = + halfWidth * IODistance() / + physicalScreenWidth(); // * current window width / full screen width + + computeModelViewMatrix(); + if (leftBuffer) + modelViewMatrix_[12] -= shift; + else + modelViewMatrix_[12] += shift; + glLoadMatrixd(modelViewMatrix_); } /*! Fills \p m with the Camera projection matrix values. - Based on computeProjectionMatrix() to make sure the Camera projection matrix is up to date. + Based on computeProjectionMatrix() to make sure the Camera projection matrix is + up to date. - This matrix only reflects the Camera's internal parameters and it may differ from the \c - GL_PROJECTION matrix retrieved using \c glGetDoublev(GL_PROJECTION_MATRIX, m). It actually - represents the state of the \c GL_PROJECTION after QGLViewer::preDraw(), at the beginning of - QGLViewer::draw(). If you modified the \c GL_PROJECTION matrix (for instance using - QGLViewer::startScreenCoordinatesSystem()), the two results differ. + This matrix only reflects the Camera's internal parameters and it may differ + from the \c GL_PROJECTION matrix retrieved using \c + glGetDoublev(GL_PROJECTION_MATRIX, m). It actually represents the state of the + \c GL_PROJECTION after QGLViewer::preDraw(), at the beginning of + QGLViewer::draw(). If you modified the \c GL_PROJECTION matrix (for instance + using QGLViewer::startScreenCoordinatesSystem()), the two results differ. - The result is an OpenGL 4x4 matrix, which is given in \e column-major order (see \c glMultMatrix - man page for details). + The result is an OpenGL 4x4 matrix, which is given in \e column-major order + (see \c glMultMatrix man page for details). See also getModelViewMatrix() and setFromProjectionMatrix(). */ -void Camera::getProjectionMatrix(GLdouble m[16]) const -{ - computeProjectionMatrix(); - for (unsigned short i=0; i<16; ++i) - m[i] = projectionMatrix_[i]; +void Camera::getProjectionMatrix(GLdouble m[16]) const { + computeProjectionMatrix(); + for (unsigned short i = 0; i < 16; ++i) + m[i] = projectionMatrix_[i]; } -/*! Overloaded getProjectionMatrix(GLdouble m[16]) method using a \c GLfloat array instead. */ -void Camera::getProjectionMatrix(GLfloat m[16]) const -{ - static GLdouble mat[16]; - getProjectionMatrix(mat); - for (unsigned short i=0; i<16; ++i) - m[i] = float(mat[i]); +/*! Overloaded getProjectionMatrix(GLdouble m[16]) method using a \c GLfloat + * array instead. */ +void Camera::getProjectionMatrix(GLfloat m[16]) const { + static GLdouble mat[16]; + getProjectionMatrix(mat); + for (unsigned short i = 0; i < 16; ++i) + m[i] = float(mat[i]); } /*! Fills \p m with the Camera modelView matrix values. @@ -639,210 +664,202 @@ void Camera::getProjectionMatrix(GLfloat m[16]) const First calls computeModelViewMatrix() to define the Camera modelView matrix. Note that this matrix may \e not be the one you would get from a \c - glGetDoublev(GL_MODELVIEW_MATRIX, m). It actually represents the state of the \c - GL_MODELVIEW after QGLViewer::preDraw(), at the \e beginning of QGLViewer::draw(). It converts from - the world to the Camera coordinate system. As soon as you modify the \c GL_MODELVIEW in your - QGLViewer::draw() method (using glTranslate, glRotate... or similar methods), the two matrices differ. + glGetDoublev(GL_MODELVIEW_MATRIX, m). It actually represents the state of the + \c GL_MODELVIEW after QGLViewer::preDraw(), at the \e beginning of + QGLViewer::draw(). It converts from the world to the Camera coordinate system. + As soon as you modify the \c GL_MODELVIEW in your QGLViewer::draw() method + (using glTranslate, glRotate... or similar methods), the two matrices differ. - The result is an OpenGL 4x4 matrix, which is given in \e column-major order (see \c glMultMatrix - man page for details). + The result is an OpenGL 4x4 matrix, which is given in \e column-major order + (see \c glMultMatrix man page for details). See also getProjectionMatrix() and setFromModelViewMatrix(). */ -void Camera::getModelViewMatrix(GLdouble m[16]) const -{ - // May not be needed, but easier like this. - // Prevents from retrieving matrix in stereo mode -> overwrites shifted value. - computeModelViewMatrix(); - for (unsigned short i=0; i<16; ++i) - m[i] = modelViewMatrix_[i]; +void Camera::getModelViewMatrix(GLdouble m[16]) const { + // May not be needed, but easier like this. + // Prevents from retrieving matrix in stereo mode -> overwrites shifted value. + computeModelViewMatrix(); + for (unsigned short i = 0; i < 16; ++i) + m[i] = modelViewMatrix_[i]; } - -/*! Overloaded getModelViewMatrix(GLdouble m[16]) method using a \c GLfloat array instead. */ -void Camera::getModelViewMatrix(GLfloat m[16]) const -{ - static GLdouble mat[16]; - getModelViewMatrix(mat); - for (unsigned short i=0; i<16; ++i) - m[i] = float(mat[i]); +/*! Overloaded getModelViewMatrix(GLdouble m[16]) method using a \c GLfloat + * array instead. */ +void Camera::getModelViewMatrix(GLfloat m[16]) const { + static GLdouble mat[16]; + getModelViewMatrix(mat); + for (unsigned short i = 0; i < 16; ++i) + m[i] = float(mat[i]); } /*! Fills \p m with the product of the ModelView and Projection matrices. - Calls getModelViewMatrix() and getProjectionMatrix() and then fills \p m with the product of these two matrices. */ -void Camera::getModelViewProjectionMatrix(GLdouble m[16]) const -{ - GLdouble mv[16]; - GLdouble proj[16]; - getModelViewMatrix(mv); - getProjectionMatrix(proj); - - for (unsigned short i=0; i<4; ++i) - { - for (unsigned short j=0; j<4; ++j) - { - qreal sum = 0.0; - for (unsigned short k=0; k<4; ++k) - sum += proj[i+4*k]*mv[k+4*j]; - m[i+4*j] = sum; - } - } -} - -/*! Overloaded getModelViewProjectionMatrix(GLdouble m[16]) method using a \c GLfloat array instead. */ -void Camera::getModelViewProjectionMatrix(GLfloat m[16]) const -{ - static GLdouble mat[16]; - getModelViewProjectionMatrix(mat); - for (unsigned short i=0; i<16; ++i) - m[i] = float(mat[i]); + Calls getModelViewMatrix() and getProjectionMatrix() and then fills \p m with + the product of these two matrices. */ +void Camera::getModelViewProjectionMatrix(GLdouble m[16]) const { + GLdouble mv[16]; + GLdouble proj[16]; + getModelViewMatrix(mv); + getProjectionMatrix(proj); + + for (unsigned short i = 0; i < 4; ++i) { + for (unsigned short j = 0; j < 4; ++j) { + qreal sum = 0.0; + for (unsigned short k = 0; k < 4; ++k) + sum += proj[i + 4 * k] * mv[k + 4 * j]; + m[i + 4 * j] = sum; + } + } +} + +/*! Overloaded getModelViewProjectionMatrix(GLdouble m[16]) method using a \c + * GLfloat array instead. */ +void Camera::getModelViewProjectionMatrix(GLfloat m[16]) const { + static GLdouble mat[16]; + getModelViewProjectionMatrix(mat); + for (unsigned short i = 0; i < 16; ++i) + m[i] = float(mat[i]); } /*! Sets the sceneRadius() value. Negative values are ignored. -\attention This methods also sets focusDistance() to sceneRadius() / tan(fieldOfView()/2) and -flySpeed() to 1% of sceneRadius(). */ -void Camera::setSceneRadius(qreal radius) -{ - if (radius <= 0.0) - { - qWarning("Scene radius must be positive - Ignoring value"); - return; - } +\attention This methods also sets focusDistance() to sceneRadius() / +tan(fieldOfView()/2) and flySpeed() to 1% of sceneRadius(). */ +void Camera::setSceneRadius(qreal radius) { + if (radius <= 0.0) { + qWarning("Scene radius must be positive - Ignoring value"); + return; + } - sceneRadius_ = radius; - projectionMatrixIsUpToDate_ = false; + sceneRadius_ = radius; + projectionMatrixIsUpToDate_ = false; - setFocusDistance(sceneRadius() / tan(fieldOfView()/2.0)); + setFocusDistance(sceneRadius() / tan(fieldOfView() / 2.0)); - frame()->setFlySpeed(0.01*sceneRadius()); + frame()->setFlySpeed(0.01 * sceneRadius()); } -/*! Similar to setSceneRadius() and setSceneCenter(), but the scene limits are defined by a (world - axis aligned) bounding box. */ -void Camera::setSceneBoundingBox(const Vec& min, const Vec& max) -{ - setSceneCenter((min+max)/2.0); - setSceneRadius(0.5*(max-min).norm()); +/*! Similar to setSceneRadius() and setSceneCenter(), but the scene limits are + defined by a (world axis aligned) bounding box. */ +void Camera::setSceneBoundingBox(const Vec &min, const Vec &max) { + setSceneCenter((min + max) / 2.0); + setSceneRadius(0.5 * (max - min).norm()); } - /*! Sets the sceneCenter(). \attention This method also sets the pivotPoint() to sceneCenter(). */ -void Camera::setSceneCenter(const Vec& center) -{ - sceneCenter_ = center; - setPivotPoint(sceneCenter()); - projectionMatrixIsUpToDate_ = false; +void Camera::setSceneCenter(const Vec ¢er) { + sceneCenter_ = center; + setPivotPoint(sceneCenter()); + projectionMatrixIsUpToDate_ = false; } /*! setSceneCenter() to the result of pointUnderPixel(\p pixel). - Returns \c true if a pointUnderPixel() was found and sceneCenter() was actually changed. + Returns \c true if a pointUnderPixel() was found and sceneCenter() was + actually changed. See also setPivotPointFromPixel(). See the pointUnderPixel() documentation. */ -bool Camera::setSceneCenterFromPixel(const QPoint& pixel) -{ - bool found; - Vec point = pointUnderPixel(pixel, found); - if (found) - setSceneCenter(point); - return found; +bool Camera::setSceneCenterFromPixel(const QPoint &pixel) { + bool found; + Vec point = pointUnderPixel(pixel, found); + if (found) + setSceneCenter(point); + return found; } #ifndef DOXYGEN -void Camera::setRevolveAroundPoint(const Vec& point) { - qWarning("setRevolveAroundPoint() is deprecated, use setPivotPoint() instead"); - setPivotPoint(point); +void Camera::setRevolveAroundPoint(const Vec &point) { + qWarning( + "setRevolveAroundPoint() is deprecated, use setPivotPoint() instead"); + setPivotPoint(point); } -bool Camera::setRevolveAroundPointFromPixel(const QPoint& pixel) { - qWarning("setRevolveAroundPointFromPixel() is deprecated, use setPivotPointFromPixel() instead"); - return setPivotPointFromPixel(pixel); +bool Camera::setRevolveAroundPointFromPixel(const QPoint &pixel) { + qWarning("setRevolveAroundPointFromPixel() is deprecated, use " + "setPivotPointFromPixel() instead"); + return setPivotPointFromPixel(pixel); } Vec Camera::revolveAroundPoint() const { - qWarning("revolveAroundPoint() is deprecated, use pivotPoint() instead"); - return pivotPoint(); + qWarning("revolveAroundPoint() is deprecated, use pivotPoint() instead"); + return pivotPoint(); } #endif -/*! Changes the pivotPoint() to \p point (defined in the world coordinate system). */ -void Camera::setPivotPoint(const Vec& point) -{ - const qreal prevDist = fabs(cameraCoordinatesOf(pivotPoint()).z); +/*! Changes the pivotPoint() to \p point (defined in the world coordinate + * system). */ +void Camera::setPivotPoint(const Vec &point) { + const qreal prevDist = fabs(cameraCoordinatesOf(pivotPoint()).z); - // If frame's RAP is set directly, projectionMatrixIsUpToDate_ should also be - // set to false to ensure proper recomputation of the ORTHO projection matrix. - frame()->setPivotPoint(point); + // If frame's RAP is set directly, projectionMatrixIsUpToDate_ should also be + // set to false to ensure proper recomputation of the ORTHO projection matrix. + frame()->setPivotPoint(point); - // orthoCoef_ is used to compensate for changes of the pivotPoint, so that the image does - // not change when the pivotPoint is changed in ORTHOGRAPHIC mode. - const qreal newDist = fabs(cameraCoordinatesOf(pivotPoint()).z); - // Prevents division by zero when rap is set to camera position - if ((prevDist > 1E-9) && (newDist > 1E-9)) - orthoCoef_ *= prevDist / newDist; - projectionMatrixIsUpToDate_ = false; + // orthoCoef_ is used to compensate for changes of the pivotPoint, so that the + // image does not change when the pivotPoint is changed in ORTHOGRAPHIC mode. + const qreal newDist = fabs(cameraCoordinatesOf(pivotPoint()).z); + // Prevents division by zero when rap is set to camera position + if ((prevDist > 1E-9) && (newDist > 1E-9)) + orthoCoef_ *= prevDist / newDist; + projectionMatrixIsUpToDate_ = false; } /*! The pivotPoint() is set to the point located under \p pixel on screen. -Returns \c true if a pointUnderPixel() was found. If no point was found under \p pixel, the -pivotPoint() is left unchanged. +Returns \c true if a pointUnderPixel() was found. If no point was found under \p +pixel, the pivotPoint() is left unchanged. -\p pixel is expressed in Qt format (origin in the upper left corner of the window). See -pointUnderPixel(). +\p pixel is expressed in Qt format (origin in the upper left corner of the +window). See pointUnderPixel(). See also setSceneCenterFromPixel(). */ -bool Camera::setPivotPointFromPixel(const QPoint& pixel) -{ - bool found; - Vec point = pointUnderPixel(pixel, found); - if (found) - setPivotPoint(point); - return found; +bool Camera::setPivotPointFromPixel(const QPoint &pixel) { + bool found; + Vec point = pointUnderPixel(pixel, found); + if (found) + setPivotPoint(point); + return found; } /*! Returns the ratio between pixel and OpenGL units at \p position. - A line of \c n * pixelGLRatio() OpenGL units, located at \p position in the world coordinates - system, will be projected with a length of \c n pixels on screen. + A line of \c n * pixelGLRatio() OpenGL units, located at \p position in the + world coordinates system, will be projected with a length of \c n pixels on + screen. - Use this method to scale objects so that they have a constant pixel size on screen. The following - code will draw a 20 pixel line, starting at sceneCenter() and always directed along the screen - vertical direction: - \code + Use this method to scale objects so that they have a constant pixel size on + screen. The following code will draw a 20 pixel line, starting at sceneCenter() + and always directed along the screen vertical direction: \code glBegin(GL_LINES); glVertex3fv(sceneCenter()); - glVertex3fv(sceneCenter() + 20 * pixelGLRatio(sceneCenter()) * camera()->upVector()); - glEnd(); - \endcode */ -qreal Camera::pixelGLRatio(const Vec& position) const -{ - switch (type()) - { - case Camera::PERSPECTIVE : - return 2.0 * fabs((frame()->coordinatesOf(position)).z) * tan(fieldOfView()/2.0) / screenHeight(); - case Camera::ORTHOGRAPHIC : - { - GLdouble w, h; - getOrthoWidthHeight(w,h); - return 2.0 * h / screenHeight(); - } - } - // Bad compilers complain - return 1.0; -} - -/*! Changes the Camera fieldOfView() so that the entire scene (defined by QGLViewer::sceneCenter() - and QGLViewer::sceneRadius()) is visible from the Camera position(). - - The position() and orientation() of the Camera are not modified and you first have to orientate the - Camera in order to actually see the scene (see lookAt(), showEntireScene() or fitSphere()). - - This method is especially useful for \e shadow \e maps computation. Use the Camera positioning - tools (setPosition(), lookAt()) to position a Camera at the light position. Then use this method to - define the fieldOfView() so that the shadow map resolution is optimally used: - \code + glVertex3fv(sceneCenter() + 20 * pixelGLRatio(sceneCenter()) * + camera()->upVector()); glEnd(); \endcode */ +qreal Camera::pixelGLRatio(const Vec &position) const { + switch (type()) { + case Camera::PERSPECTIVE: + return 2.0 * fabs((frame()->coordinatesOf(position)).z) * + tan(fieldOfView() / 2.0) / screenHeight(); + case Camera::ORTHOGRAPHIC: { + GLdouble w, h; + getOrthoWidthHeight(w, h); + return 2.0 * h / screenHeight(); + } + } + // Bad compilers complain + return 1.0; +} + +/*! Changes the Camera fieldOfView() so that the entire scene (defined by + QGLViewer::sceneCenter() and QGLViewer::sceneRadius()) is visible from the + Camera position(). + + The position() and orientation() of the Camera are not modified and you first + have to orientate the Camera in order to actually see the scene (see lookAt(), + showEntireScene() or fitSphere()). + + This method is especially useful for \e shadow \e maps computation. Use the + Camera positioning tools (setPosition(), lookAt()) to position a Camera at the + light position. Then use this method to define the fieldOfView() so that the + shadow map resolution is optimally used: \code // The light camera needs size hints in order to optimize its fieldOfView lightCamera->setSceneRadius(sceneRadius()); lightCamera->setSceneCenter(sceneCenter()); @@ -853,411 +870,426 @@ qreal Camera::pixelGLRatio(const Vec& position) const lightCamera->setFOVToFitScene(); \endcode - See the (soon available) shadowMap contribution example for a practical implementation. + See the (soon available) shadowMap contribution example for a practical + implementation. - \attention The fieldOfView() is clamped to M_PI/2.0. This happens when the Camera is at a distance - lower than sqrt(2.0) * sceneRadius() from the sceneCenter(). It optimizes the shadow map - resolution, although it may miss some parts of the scene. */ -void Camera::setFOVToFitScene() -{ - if (distanceToSceneCenter() > sqrt(2.0)*sceneRadius()) - setFieldOfView(2.0 * asin(sceneRadius() / distanceToSceneCenter())); - else - setFieldOfView(M_PI / 2.0); + \attention The fieldOfView() is clamped to M_PI/2.0. This happens when the + Camera is at a distance lower than sqrt(2.0) * sceneRadius() from the + sceneCenter(). It optimizes the shadow map resolution, although it may miss + some parts of the scene. */ +void Camera::setFOVToFitScene() { + if (distanceToSceneCenter() > sqrt(2.0) * sceneRadius()) + setFieldOfView(2.0 * asin(sceneRadius() / distanceToSceneCenter())); + else + setFieldOfView(M_PI / 2.0); } /*! Makes the Camera smoothly zoom on the pointUnderPixel() \p pixel. - Nothing happens if no pointUnderPixel() is found. Otherwise a KeyFrameInterpolator is created that - animates the Camera on a one second path that brings the Camera closer to the point under \p pixel. + Nothing happens if no pointUnderPixel() is found. Otherwise a + KeyFrameInterpolator is created that animates the Camera on a one second path + that brings the Camera closer to the point under \p pixel. See also interpolateToFitScene(). */ -void Camera::interpolateToZoomOnPixel(const QPoint& pixel) -{ - const qreal coef = 0.1; +void Camera::interpolateToZoomOnPixel(const QPoint &pixel) { + const qreal coef = 0.1; - bool found; - Vec target = pointUnderPixel(pixel, found); + bool found; + Vec target = pointUnderPixel(pixel, found); - if (!found) - return; + if (!found) + return; - if (interpolationKfi_->interpolationIsStarted()) - interpolationKfi_->stopInterpolation(); + if (interpolationKfi_->interpolationIsStarted()) + interpolationKfi_->stopInterpolation(); - interpolationKfi_->deletePath(); - interpolationKfi_->addKeyFrame(*(frame())); + interpolationKfi_->deletePath(); + interpolationKfi_->addKeyFrame(*(frame())); - interpolationKfi_->addKeyFrame(Frame(0.3*frame()->position() + 0.7*target, frame()->orientation()), 0.4); + interpolationKfi_->addKeyFrame( + Frame(0.3 * frame()->position() + 0.7 * target, frame()->orientation()), + 0.4); - // Small hack: attach a temporary frame to take advantage of lookAt without modifying frame - static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame(); - ManipulatedCameraFrame* const originalFrame = frame(); - tempFrame->setPosition(coef*frame()->position() + (1.0-coef)*target); - tempFrame->setOrientation(frame()->orientation()); - setFrame(tempFrame); - lookAt(target); - setFrame(originalFrame); + // Small hack: attach a temporary frame to take advantage of lookAt without + // modifying frame + static ManipulatedCameraFrame *tempFrame = new ManipulatedCameraFrame(); + ManipulatedCameraFrame *const originalFrame = frame(); + tempFrame->setPosition(coef * frame()->position() + (1.0 - coef) * target); + tempFrame->setOrientation(frame()->orientation()); + setFrame(tempFrame); + lookAt(target); + setFrame(originalFrame); - interpolationKfi_->addKeyFrame(*(tempFrame), 1.0); + interpolationKfi_->addKeyFrame(*(tempFrame), 1.0); - interpolationKfi_->startInterpolation(); + interpolationKfi_->startInterpolation(); } -/*! Interpolates the Camera on a one second KeyFrameInterpolator path so that the entire scene fits - the screen at the end. +/*! Interpolates the Camera on a one second KeyFrameInterpolator path so that + the entire scene fits the screen at the end. - The scene is defined by its sceneCenter() and its sceneRadius(). See showEntireScene(). + The scene is defined by its sceneCenter() and its sceneRadius(). See + showEntireScene(). - The orientation() of the Camera is not modified. See also interpolateToZoomOnPixel(). */ -void Camera::interpolateToFitScene() -{ - if (interpolationKfi_->interpolationIsStarted()) - interpolationKfi_->stopInterpolation(); + The orientation() of the Camera is not modified. See also + interpolateToZoomOnPixel(). */ +void Camera::interpolateToFitScene() { + if (interpolationKfi_->interpolationIsStarted()) + interpolationKfi_->stopInterpolation(); - interpolationKfi_->deletePath(); - interpolationKfi_->addKeyFrame(*(frame())); + interpolationKfi_->deletePath(); + interpolationKfi_->addKeyFrame(*(frame())); - // Small hack: attach a temporary frame to take advantage of lookAt without modifying frame - static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame(); - ManipulatedCameraFrame* const originalFrame = frame(); - tempFrame->setPosition(frame()->position()); - tempFrame->setOrientation(frame()->orientation()); - setFrame(tempFrame); - showEntireScene(); - setFrame(originalFrame); + // Small hack: attach a temporary frame to take advantage of lookAt without + // modifying frame + static ManipulatedCameraFrame *tempFrame = new ManipulatedCameraFrame(); + ManipulatedCameraFrame *const originalFrame = frame(); + tempFrame->setPosition(frame()->position()); + tempFrame->setOrientation(frame()->orientation()); + setFrame(tempFrame); + showEntireScene(); + setFrame(originalFrame); - interpolationKfi_->addKeyFrame(*(tempFrame)); + interpolationKfi_->addKeyFrame(*(tempFrame)); - interpolationKfi_->startInterpolation(); + interpolationKfi_->startInterpolation(); } +/*! Smoothly interpolates the Camera on a KeyFrameInterpolator path so that it + goes to \p fr. -/*! Smoothly interpolates the Camera on a KeyFrameInterpolator path so that it goes to \p fr. - - \p fr is expressed in world coordinates. \p duration tunes the interpolation speed (default is - 1 second). + \p fr is expressed in world coordinates. \p duration tunes the interpolation + speed (default is 1 second). See also interpolateToFitScene() and interpolateToZoomOnPixel(). */ -void Camera::interpolateTo(const Frame& fr, qreal duration) -{ - if (interpolationKfi_->interpolationIsStarted()) - interpolationKfi_->stopInterpolation(); +void Camera::interpolateTo(const Frame &fr, qreal duration) { + if (interpolationKfi_->interpolationIsStarted()) + interpolationKfi_->stopInterpolation(); - interpolationKfi_->deletePath(); - interpolationKfi_->addKeyFrame(*(frame())); - interpolationKfi_->addKeyFrame(fr, duration); + interpolationKfi_->deletePath(); + interpolationKfi_->addKeyFrame(*(frame())); + interpolationKfi_->addKeyFrame(fr, duration); - interpolationKfi_->startInterpolation(); + interpolationKfi_->startInterpolation(); } - /*! Returns the coordinates of the 3D point located at pixel (x,y) on screen. - Calls a \c glReadPixel to get the pixel depth and applies an unprojectedCoordinatesOf() to the - result. \p found indicates whether a point was found or not (i.e. background pixel, result's depth - is zFar() in that case). - - \p x and \p y are expressed in pixel units with an origin in the upper left corner. Use - screenHeight() - y to convert to OpenGL standard. - - \attention This method assumes that a GL context is available, and that its content was drawn using - the Camera (i.e. using its projection and modelview matrices). This method hence cannot be used for - offscreen Camera computations. Use cameraCoordinatesOf() and worldCoordinatesOf() to perform - similar operations in that case. - - \note The precision of the z-Buffer highly depends on how the zNear() and zFar() values are fitted - to your scene. Loose boundaries will result in imprecision along the viewing direction. */ -Vec Camera::pointUnderPixel(const QPoint& pixel, bool& found) const -{ - float depth; - // Qt uses upper corner for its origin while GL uses the lower corner. - glReadPixels(pixel.x(), screenHeight()-1-pixel.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); - found = depth < 1.0; - Vec point(pixel.x(), pixel.y(), depth); - point = unprojectedCoordinatesOf(point); - return point; + Calls a \c glReadPixel to get the pixel depth and applies an + unprojectedCoordinatesOf() to the result. \p found indicates whether a point + was found or not (i.e. background pixel, result's depth is zFar() in that + case). + + \p x and \p y are expressed in pixel units with an origin in the upper left + corner. Use screenHeight() - y to convert to OpenGL standard. + + \attention This method assumes that a GL context is available, and that its + content was drawn using the Camera (i.e. using its projection and modelview + matrices). This method hence cannot be used for offscreen Camera computations. + Use cameraCoordinatesOf() and worldCoordinatesOf() to perform similar + operations in that case. + + \note The precision of the z-Buffer highly depends on how the zNear() and + zFar() values are fitted to your scene. Loose boundaries will result in + imprecision along the viewing direction. */ +Vec Camera::pointUnderPixel(const QPoint &pixel, bool &found) const { + float depth; + // Qt uses upper corner for its origin while GL uses the lower corner. + glReadPixels(pixel.x() * devicePixelRatio_, devicePixelRatio_ * (screenHeight() - pixel.y()) - 1, + 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + found = static_cast(depth) < 1.0; + Vec point(pixel.x(), pixel.y(), static_cast(depth)); + point = unprojectedCoordinatesOf(point); + return point; } /*! Moves the Camera so that the entire scene is visible. - Simply calls fitSphere() on a sphere defined by sceneCenter() and sceneRadius(). + Simply calls fitSphere() on a sphere defined by sceneCenter() and + sceneRadius(). - You will typically use this method in QGLViewer::init() after you defined a new sceneRadius(). */ -void Camera::showEntireScene() -{ - fitSphere(sceneCenter(), sceneRadius()); -} + You will typically use this method in QGLViewer::init() after you defined a new + sceneRadius(). */ +void Camera::showEntireScene() { fitSphere(sceneCenter(), sceneRadius()); } -/*! Moves the Camera so that its sceneCenter() is projected on the center of the window. The - orientation() and fieldOfView() are unchanged. +/*! Moves the Camera so that its sceneCenter() is projected on the center of the + window. The orientation() and fieldOfView() are unchanged. - Simply projects the current position on a line passing through sceneCenter(). See also - showEntireScene().*/ -void Camera::centerScene() -{ - frame()->projectOnLine(sceneCenter(), viewDirection()); + Simply projects the current position on a line passing through sceneCenter(). + See also showEntireScene().*/ +void Camera::centerScene() { + frame()->projectOnLine(sceneCenter(), viewDirection()); } -/*! Sets the Camera orientation(), so that it looks at point \p target (defined in the world - coordinate system). +/*! Sets the Camera orientation(), so that it looks at point \p target (defined + in the world coordinate system). The Camera position() is not modified. Simply setViewDirection(). - See also setUpVector(), setOrientation(), showEntireScene(), fitSphere() and fitBoundingBox(). */ -void Camera::lookAt(const Vec& target) -{ - setViewDirection(target - position()); + See also setUpVector(), setOrientation(), showEntireScene(), fitSphere() and + fitBoundingBox(). */ +void Camera::lookAt(const Vec &target) { + setViewDirection(target - position()); } -/*! Moves the Camera so that the sphere defined by (\p center, \p radius) is visible and fits in the frustum. +/*! Moves the Camera so that the sphere defined by (\p center, \p radius) is + visible and fits in the frustum. - The Camera is simply translated to center the sphere in the screen and make it fit the frustum. Its - orientation() and its fieldOfView() are unchanged. + The Camera is simply translated to center the sphere in the screen and make it + fit the frustum. Its orientation() and its fieldOfView() are unchanged. - You should therefore orientate the Camera before you call this method. See lookAt(), - setOrientation() and setUpVector(). */ -void Camera::fitSphere(const Vec& center, qreal radius) -{ - qreal distance = 0.0; - switch (type()) - { - case Camera::PERSPECTIVE : - { - const qreal yview = radius / sin(fieldOfView() / 2.0); - const qreal xview = radius / sin(horizontalFieldOfView() / 2.0); - distance = qMax(xview, yview); - break; - } - case Camera::ORTHOGRAPHIC : - { - distance = ((center-pivotPoint()) * viewDirection()) + (radius / orthoCoef_); - break; - } - } - Vec newPos(center - distance * viewDirection()); - frame()->setPositionWithConstraint(newPos); -} - -/*! Moves the Camera so that the (world axis aligned) bounding box (\p min, \p max) is entirely - visible, using fitSphere(). */ -void Camera::fitBoundingBox(const Vec& min, const Vec& max) -{ - qreal diameter = qMax(fabs(max[1]-min[1]), fabs(max[0]-min[0])); - diameter = qMax(fabs(max[2]-min[2]), diameter); - fitSphere(0.5*(min+max), 0.5*diameter); + You should therefore orientate the Camera before you call this method. See + lookAt(), setOrientation() and setUpVector(). */ +void Camera::fitSphere(const Vec ¢er, qreal radius) { + qreal distance = 0.0; + switch (type()) { + case Camera::PERSPECTIVE: { + const qreal yview = radius / sin(fieldOfView() / 2.0); + const qreal xview = radius / sin(horizontalFieldOfView() / 2.0); + distance = qMax(xview, yview); + break; + } + case Camera::ORTHOGRAPHIC: { + distance = + ((center - pivotPoint()) * viewDirection()) + (radius / orthoCoef_); + break; + } + } + Vec newPos(center - distance * viewDirection()); + frame()->setPositionWithConstraint(newPos); +} + +/*! Moves the Camera so that the (world axis aligned) bounding box (\p min, \p + max) is entirely visible, using fitSphere(). */ +void Camera::fitBoundingBox(const Vec &min, const Vec &max) { + qreal diameter = qMax(fabs(max[1] - min[1]), fabs(max[0] - min[0])); + diameter = qMax(fabs(max[2] - min[2]), diameter); + fitSphere(0.5 * (min + max), 0.5 * diameter); +} + +/*! Moves the Camera so that the rectangular screen region defined by \p + rectangle (pixel units, with origin in the upper left corner) fits the screen. + + The Camera is translated (its orientation() is unchanged) so that \p rectangle + is entirely visible. Since the pixel coordinates only define a \e frustum in + 3D, it's the intersection of this frustum with a plane (orthogonal to the + viewDirection() and passing through the sceneCenter()) that is used to define + the 3D rectangle that is eventually fitted. */ +void Camera::fitScreenRegion(const QRect &rectangle) { + const Vec vd = viewDirection(); + const qreal distToPlane = distanceToSceneCenter(); + const QPoint center = rectangle.center(); + + Vec orig, dir; + convertClickToLine(center, orig, dir); + Vec newCenter = orig + distToPlane / (dir * vd) * dir; + + convertClickToLine(QPoint(rectangle.x(), center.y()), orig, dir); + const Vec pointX = orig + distToPlane / (dir * vd) * dir; + + convertClickToLine(QPoint(center.x(), rectangle.y()), orig, dir); + const Vec pointY = orig + distToPlane / (dir * vd) * dir; + + qreal distance = 0.0; + switch (type()) { + case Camera::PERSPECTIVE: { + const qreal distX = + (pointX - newCenter).norm() / sin(horizontalFieldOfView() / 2.0); + const qreal distY = (pointY - newCenter).norm() / sin(fieldOfView() / 2.0); + distance = qMax(distX, distY); + break; + } + case Camera::ORTHOGRAPHIC: { + const qreal dist = ((newCenter - pivotPoint()) * vd); + //#CONNECTION# getOrthoWidthHeight + const qreal distX = (pointX - newCenter).norm() / orthoCoef_ / + ((aspectRatio() < 1.0) ? 1.0 : aspectRatio()); + const qreal distY = (pointY - newCenter).norm() / orthoCoef_ / + ((aspectRatio() < 1.0) ? 1.0 / aspectRatio() : 1.0); + distance = dist + qMax(distX, distY); + break; + } + } + + Vec newPos(newCenter - distance * vd); + frame()->setPositionWithConstraint(newPos); } -/*! Moves the Camera so that the rectangular screen region defined by \p rectangle (pixel units, - with origin in the upper left corner) fits the screen. +/*! Rotates the Camera so that its upVector() becomes \p up (defined in the + world coordinate system). - The Camera is translated (its orientation() is unchanged) so that \p rectangle is entirely - visible. Since the pixel coordinates only define a \e frustum in 3D, it's the intersection of this - frustum with a plane (orthogonal to the viewDirection() and passing through the sceneCenter()) - that is used to define the 3D rectangle that is eventually fitted. */ -void Camera::fitScreenRegion(const QRect& rectangle) -{ - const Vec vd = viewDirection(); - const qreal distToPlane = distanceToSceneCenter(); - const QPoint center = rectangle.center(); - - Vec orig, dir; - convertClickToLine( center, orig, dir ); - Vec newCenter = orig + distToPlane / (dir*vd) * dir; - - convertClickToLine( QPoint(rectangle.x(), center.y()), orig, dir ); - const Vec pointX = orig + distToPlane / (dir*vd) * dir; - - convertClickToLine( QPoint(center.x(), rectangle.y()), orig, dir ); - const Vec pointY = orig + distToPlane / (dir*vd) * dir; - - qreal distance = 0.0; - switch (type()) - { - case Camera::PERSPECTIVE : - { - const qreal distX = (pointX-newCenter).norm() / sin(horizontalFieldOfView()/2.0); - const qreal distY = (pointY-newCenter).norm() / sin(fieldOfView()/2.0); - distance = qMax(distX, distY); - break; - } - case Camera::ORTHOGRAPHIC : - { - const qreal dist = ((newCenter-pivotPoint()) * vd); - //#CONNECTION# getOrthoWidthHeight - const qreal distX = (pointX-newCenter).norm() / orthoCoef_ / ((aspectRatio() < 1.0) ? 1.0 : aspectRatio()); - const qreal distY = (pointY-newCenter).norm() / orthoCoef_ / ((aspectRatio() < 1.0) ? 1.0/aspectRatio() : 1.0); - distance = dist + qMax(distX, distY); - break; - } - } - - Vec newPos(newCenter - distance * vd); - frame()->setPositionWithConstraint(newPos); -} - -/*! Rotates the Camera so that its upVector() becomes \p up (defined in the world coordinate - system). - - The Camera is rotated around an axis orthogonal to \p up and to the current upVector() direction. - Use this method in order to define the Camera horizontal plane. - - When \p noMove is set to \c false, the orientation modification is compensated by a translation, so - that the pivotPoint() stays projected at the same position on screen. This is especially - useful when the Camera is used as an observer of the scene (default mouse binding). - - When \p noMove is \c true (default), the Camera position() is left unchanged, which is an intuitive - behavior when the Camera is in a walkthrough fly mode (see the QGLViewer::MOVE_FORWARD and - QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction). + The Camera is rotated around an axis orthogonal to \p up and to the current + upVector() direction. Use this method in order to define the Camera horizontal + plane. + + When \p noMove is set to \c false, the orientation modification is compensated + by a translation, so that the pivotPoint() stays projected at the same position + on screen. This is especially useful when the Camera is used as an observer of + the scene (default mouse binding). + + When \p noMove is \c true (default), the Camera position() is left unchanged, + which is an intuitive behavior when the Camera is in a walkthrough fly mode + (see the QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD + QGLViewer::MouseAction). The frame()'s ManipulatedCameraFrame::sceneUpVector() is set accordingly. See also setViewDirection(), lookAt() and setOrientation(). */ -void Camera::setUpVector(const Vec& up, bool noMove) -{ - Quaternion q(Vec(0.0, 1.0, 0.0), frame()->transformOf(up)); +void Camera::setUpVector(const Vec &up, bool noMove) { + Quaternion q(Vec(0.0, 1.0, 0.0), frame()->transformOf(up)); - if (!noMove) - frame()->setPosition(pivotPoint() - (frame()->orientation()*q).rotate(frame()->coordinatesOf(pivotPoint()))); + if (!noMove) + frame()->setPosition(pivotPoint() - + (frame()->orientation() * q) + .rotate(frame()->coordinatesOf(pivotPoint()))); - frame()->rotate(q); + frame()->rotate(q); - // Useful in fly mode to keep the horizontal direction. - frame()->updateSceneUpVector(); + // Useful in fly mode to keep the horizontal direction. + frame()->updateSceneUpVector(); } /*! Sets the orientation() of the Camera using polar coordinates. - \p theta rotates the Camera around its Y axis, and \e then \p phi rotates it around its X axis. - The polar coordinates are defined in the world coordinates system: \p theta = \p phi = 0 means - that the Camera is directed towards the world Z axis. Both angles are expressed in radians. + \p theta rotates the Camera around its Y axis, and \e then \p phi rotates it + around its X axis. The polar coordinates are defined in the world coordinates + system: \p theta = \p phi = 0 means that the Camera is directed towards the + world Z axis. Both angles are expressed in radians. - See also setUpVector(). The position() of the Camera is unchanged, you may want to call showEntireScene() - after this method to move the Camera. + See also setUpVector(). The position() of the Camera is unchanged, you may want + to call showEntireScene() after this method to move the Camera. This method can be useful to create Quicktime VR panoramic sequences, see the QGLViewer::saveSnapshot() documentation for details. */ -void Camera::setOrientation(qreal theta, qreal phi) -{ - Vec axis(0.0, 1.0, 0.0); - const Quaternion rot1(axis, theta); - axis = Vec(-cos(theta), 0.0, sin(theta)); - const Quaternion rot2(axis, phi); - setOrientation(rot1 * rot2); +void Camera::setOrientation(qreal theta, qreal phi) { + Vec axis(0.0, 1.0, 0.0); + const Quaternion rot1(axis, theta); + axis = Vec(-cos(theta), 0.0, sin(theta)); + const Quaternion rot2(axis, phi); + setOrientation(rot1 * rot2); } /*! Sets the Camera orientation(), defined in the world coordinate system. */ -void Camera::setOrientation(const Quaternion& q) -{ - frame()->setOrientation(q); - frame()->updateSceneUpVector(); -} - -/*! Rotates the Camera so that its viewDirection() is \p direction (defined in the world coordinate - system). - - The Camera position() is not modified. The Camera is rotated so that the horizon (defined by its - upVector()) is preserved. See also lookAt() and setUpVector(). */ -void Camera::setViewDirection(const Vec& direction) -{ - if (direction.squaredNorm() < 1E-10) - return; - - Vec xAxis = direction ^ upVector(); - if (xAxis.squaredNorm() < 1E-10) - { - // target is aligned with upVector, this means a rotation around X axis - // X axis is then unchanged, let's keep it ! - xAxis = frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0)); - } +void Camera::setOrientation(const Quaternion &q) { + frame()->setOrientation(q); + frame()->updateSceneUpVector(); +} + +/*! Rotates the Camera so that its viewDirection() is \p direction (defined in + the world coordinate system). + + The Camera position() is not modified. The Camera is rotated so that the + horizon (defined by its upVector()) is preserved. See also lookAt() and + setUpVector(). */ +void Camera::setViewDirection(const Vec &direction) { + if (direction.squaredNorm() < 1E-10) + return; + + Vec xAxis = direction ^ upVector(); + if (xAxis.squaredNorm() < 1E-10) { + // target is aligned with upVector, this means a rotation around X axis + // X axis is then unchanged, let's keep it ! + xAxis = frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0)); + } - Quaternion q; - q.setFromRotatedBasis(xAxis, xAxis^direction, -direction); - frame()->setOrientationWithConstraint(q); + Quaternion q; + q.setFromRotatedBasis(xAxis, xAxis ^ direction, -direction); + frame()->setOrientationWithConstraint(q); } // Compute a 3 by 3 determinant. -static qreal det(qreal m00,qreal m01,qreal m02, - qreal m10,qreal m11,qreal m12, - qreal m20,qreal m21,qreal m22) -{ - return m00*m11*m22 + m01*m12*m20 + m02*m10*m21 - m20*m11*m02 - m10*m01*m22 - m00*m21*m12; +static qreal det(qreal m00, qreal m01, qreal m02, qreal m10, qreal m11, + qreal m12, qreal m20, qreal m21, qreal m22) { + return m00 * m11 * m22 + m01 * m12 * m20 + m02 * m10 * m21 - m20 * m11 * m02 - + m10 * m01 * m22 - m00 * m21 * m12; } // Computes the index of element [i][j] in a \c qreal matrix[3][4]. -static inline unsigned int ind(unsigned int i, unsigned int j) -{ - return (i*4+j); +static inline unsigned int ind(unsigned int i, unsigned int j) { + return (i * 4 + j); } -/*! Returns the Camera position (the eye), defined in the world coordinate system. +/*! Returns the Camera position (the eye), defined in the world coordinate +system. -Use setPosition() to set the Camera position. Other convenient methods are showEntireScene() or -fitSphere(). Actually returns \c frame()->position(). +Use setPosition() to set the Camera position. Other convenient methods are +showEntireScene() or fitSphere(). Actually returns \c frame()->position(). -This position corresponds to the projection center of a Camera::PERSPECTIVE Camera. It is not -located in the image plane, which is at a zNear() distance ahead. */ +This position corresponds to the projection center of a Camera::PERSPECTIVE +Camera. It is not located in the image plane, which is at a zNear() distance +ahead. */ Vec Camera::position() const { return frame()->position(); } -/*! Returns the normalized up vector of the Camera, defined in the world coordinate system. +/*! Returns the normalized up vector of the Camera, defined in the world +coordinate system. -Set using setUpVector() or setOrientation(). It is orthogonal to viewDirection() and to -rightVector(). +Set using setUpVector() or setOrientation(). It is orthogonal to viewDirection() +and to rightVector(). It corresponds to the Y axis of the associated frame() (actually returns frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0)) ). */ -Vec Camera::upVector() const -{ - return frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0)); +Vec Camera::upVector() const { + return frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0)); } -/*! Returns the normalized view direction of the Camera, defined in the world coordinate system. +/*! Returns the normalized view direction of the Camera, defined in the world +coordinate system. -Change this value using setViewDirection(), lookAt() or setOrientation(). It is orthogonal to -upVector() and to rightVector(). +Change this value using setViewDirection(), lookAt() or setOrientation(). It is +orthogonal to upVector() and to rightVector(). -This corresponds to the negative Z axis of the frame() ( frame()->inverseTransformOf(Vec(0.0, -0.0, -1.0)) ). */ -Vec Camera::viewDirection() const { return frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)); } +This corresponds to the negative Z axis of the frame() ( +frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)) ). */ +Vec Camera::viewDirection() const { + return frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)); +} -/*! Returns the normalized right vector of the Camera, defined in the world coordinate system. +/*! Returns the normalized right vector of the Camera, defined in the world +coordinate system. -This vector lies in the Camera horizontal plane, directed along the X axis (orthogonal to -upVector() and to viewDirection()). Set using setUpVector(), lookAt() or setOrientation(). +This vector lies in the Camera horizontal plane, directed along the X axis +(orthogonal to upVector() and to viewDirection()). Set using setUpVector(), +lookAt() or setOrientation(). Simply returns frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0)). */ -Vec Camera::rightVector() const -{ - return frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0)); +Vec Camera::rightVector() const { + return frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0)); } /*! Returns the Camera orientation, defined in the world coordinate system. -Actually returns \c frame()->orientation(). Use setOrientation(), setUpVector() or lookAt() to -set the Camera orientation. */ +Actually returns \c frame()->orientation(). Use setOrientation(), setUpVector() +or lookAt() to set the Camera orientation. */ Quaternion Camera::orientation() const { return frame()->orientation(); } -/*! Sets the Camera position() (the eye), defined in the world coordinate system. */ -void Camera::setPosition(const Vec& pos) { frame()->setPosition(pos); } +/*! Sets the Camera position() (the eye), defined in the world coordinate + * system. */ +void Camera::setPosition(const Vec &pos) { frame()->setPosition(pos); } -/*! Returns the Camera frame coordinates of a point \p src defined in world coordinates. +/*! Returns the Camera frame coordinates of a point \p src defined in world +coordinates. worldCoordinatesOf() performs the inverse transformation. -Note that the point coordinates are simply converted in a different coordinate system. They are -not projected on screen. Use projectedCoordinatesOf() for that. */ -Vec Camera::cameraCoordinatesOf(const Vec& src) const { return frame()->coordinatesOf(src); } +Note that the point coordinates are simply converted in a different coordinate +system. They are not projected on screen. Use projectedCoordinatesOf() for that. +*/ +Vec Camera::cameraCoordinatesOf(const Vec &src) const { + return frame()->coordinatesOf(src); +} -/*! Returns the world coordinates of the point whose position \p src is defined in the Camera -coordinate system. +/*! Returns the world coordinates of the point whose position \p src is defined +in the Camera coordinate system. cameraCoordinatesOf() performs the inverse transformation. */ -Vec Camera::worldCoordinatesOf(const Vec& src) const { return frame()->inverseCoordinatesOf(src); } +Vec Camera::worldCoordinatesOf(const Vec &src) const { + return frame()->inverseCoordinatesOf(src); +} /*! Returns the fly speed of the Camera. -Simply returns frame()->flySpeed(). See the ManipulatedCameraFrame::flySpeed() documentation. -This value is only meaningful when the MouseAction bindings is QGLViewer::MOVE_FORWARD or -QGLViewer::MOVE_BACKWARD. +Simply returns frame()->flySpeed(). See the ManipulatedCameraFrame::flySpeed() +documentation. This value is only meaningful when the MouseAction bindings is +QGLViewer::MOVE_FORWARD or QGLViewer::MOVE_BACKWARD. Set to 1% of the sceneRadius() by setSceneRadius(). See also setFlySpeed(). */ qreal Camera::flySpeed() const { return frame()->flySpeed(); } @@ -1267,531 +1299,543 @@ qreal Camera::flySpeed() const { return frame()->flySpeed(); } \attention This value is modified by setSceneRadius(). */ void Camera::setFlySpeed(qreal speed) { frame()->setFlySpeed(speed); } -/*! The point the Camera pivots around with the QGLViewer::ROTATE mouse binding. Defined in world coordinate system. +/*! The point the Camera pivots around with the QGLViewer::ROTATE mouse binding. +Defined in world coordinate system. Default value is the sceneCenter(). \attention setSceneCenter() changes this value. */ Vec Camera::pivotPoint() const { return frame()->pivotPoint(); } -/*! Sets the Camera's position() and orientation() from an OpenGL ModelView matrix. +/*! Sets the Camera's position() and orientation() from an OpenGL ModelView +matrix. -This enables a Camera initialisation from an other OpenGL application. \p modelView is a 16 GLdouble -vector representing a valid OpenGL ModelView matrix, such as one can get using: -\code -GLdouble mvm[16]; +This enables a Camera initialisation from an other OpenGL application. \p +modelView is a 16 GLdouble vector representing a valid OpenGL ModelView matrix, +such as one can get using: \code GLdouble mvm[16]; glGetDoublev(GL_MODELVIEW_MATRIX, mvm); myCamera->setFromModelViewMatrix(mvm); \endcode -After this method has been called, getModelViewMatrix() returns a matrix equivalent to \p -modelView. +After this method has been called, getModelViewMatrix() returns a matrix +equivalent to \p modelView. Only the orientation() and position() of the Camera are modified. -\note If you defined your matrix as \c GLdouble \c mvm[4][4], pass \c &(mvm[0][0]) as a -parameter. */ -void Camera::setFromModelViewMatrix(const GLdouble* const modelViewMatrix) -{ - // Get upper left (rotation) matrix - qreal upperLeft[3][3]; - for (int i=0; i<3; ++i) - for (int j=0; j<3; ++j) - upperLeft[i][j] = modelViewMatrix[i*4+j]; +\note If you defined your matrix as \c GLdouble \c mvm[4][4], pass \c +&(mvm[0][0]) as a parameter. */ +void Camera::setFromModelViewMatrix(const GLdouble *const modelViewMatrix) { + // Get upper left (rotation) matrix + qreal upperLeft[3][3]; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + upperLeft[i][j] = modelViewMatrix[i * 4 + j]; - // Transform upperLeft into the associated Quaternion - Quaternion q; - q.setFromRotationMatrix(upperLeft); + // Transform upperLeft into the associated Quaternion + Quaternion q; + q.setFromRotationMatrix(upperLeft); - setOrientation(q); - setPosition(-q.rotate(Vec(modelViewMatrix[12], modelViewMatrix[13], modelViewMatrix[14]))); + setOrientation(q); + setPosition(-q.rotate( + Vec(modelViewMatrix[12], modelViewMatrix[13], modelViewMatrix[14]))); } -/*! Defines the Camera position(), orientation() and fieldOfView() from a projection matrix. +/*! Defines the Camera position(), orientation() and fieldOfView() from a + projection matrix. - \p matrix has to be given in the format used by vision algorithm. It has 3 lines and 4 columns. It - transforms a point from the world homogeneous coordinate system (4 coordinates: \c sx, \c sy, \c sz - and \c s) into a point in the screen homogeneous coordinate system (3 coordinates: \c sx, \c sy, - and \c s, where \c x and \c y are the pixel coordinates on the screen). + \p matrix has to be given in the format used by vision algorithm. It has 3 + lines and 4 columns. It transforms a point from the world homogeneous + coordinate system (4 coordinates: \c sx, \c sy, \c sz and \c s) into a point in + the screen homogeneous coordinate system (3 coordinates: \c sx, \c sy, and \c + s, where \c x and \c y are the pixel coordinates on the screen). - Its three lines correspond to the homogeneous coordinates of the normals to the planes x=0, y=0 and - z=0, defined in the Camera coordinate system. + Its three lines correspond to the homogeneous coordinates of the normals to the + planes x=0, y=0 and z=0, defined in the Camera coordinate system. The elements of the matrix are ordered in line major order: you can call \c - setFromProjectionMatrix(&(matrix[0][0])) if you defined your matrix as a \c qreal \c matrix[3][4]. + setFromProjectionMatrix(&(matrix[0][0])) if you defined your matrix as a \c + qreal \c matrix[3][4]. - \attention Passing the result of getProjectionMatrix() or getModelViewMatrix() to this method is - not possible (purposefully incompatible matrix dimensions). \p matrix is more likely to be the - product of these two matrices, without the last line. + \attention Passing the result of getProjectionMatrix() or getModelViewMatrix() + to this method is not possible (purposefully incompatible matrix dimensions). + \p matrix is more likely to be the product of these two matrices, without the + last line. - Use setFromModelViewMatrix() to set position() and orientation() from a \c GL_MODELVIEW matrix. - fieldOfView() can also be retrieved from a \e perspective \c GL_PROJECTION matrix using 2.0 * - atan(1.0/projectionMatrix[5]). + Use setFromModelViewMatrix() to set position() and orientation() from a \c + GL_MODELVIEW matrix. fieldOfView() can also be retrieved from a \e perspective + \c GL_PROJECTION matrix using 2.0 * atan(1.0/projectionMatrix[5]). This code was written by Sylvain Paris. */ -void Camera::setFromProjectionMatrix(const qreal matrix[12]) -{ - // The 3 lines of the matrix are the normals to the planes x=0, y=0, z=0 - // in the camera CS. As we normalize them, we do not need the 4th coordinate. - Vec line_0(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)]); - Vec line_1(matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)]); - Vec line_2(matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)]); - - line_0.normalize(); - line_1.normalize(); - line_2.normalize(); - - // The camera position is at (0,0,0) in the camera CS so it is the - // intersection of the 3 planes. It can be seen as the kernel - // of the 3x4 projection matrix. We calculate it through 4 dimensional - // vectorial product. We go directly into 3D that is to say we directly - // divide the first 3 coordinates by the 4th one. - - // We derive the 4 dimensional vectorial product formula from the - // computation of a 4x4 determinant that is developped according to - // its 4th column. This implies some 3x3 determinants. - const Vec cam_pos = Vec(det(matrix[ind(0,1)],matrix[ind(0,2)],matrix[ind(0,3)], - matrix[ind(1,1)],matrix[ind(1,2)],matrix[ind(1,3)], - matrix[ind(2,1)],matrix[ind(2,2)],matrix[ind(2,3)]), - - -det(matrix[ind(0,0)],matrix[ind(0,2)],matrix[ind(0,3)], - matrix[ind(1,0)],matrix[ind(1,2)],matrix[ind(1,3)], - matrix[ind(2,0)],matrix[ind(2,2)],matrix[ind(2,3)]), - - det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,3)], - matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,3)], - matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,3)])) / - - (-det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)], - matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)], - matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)])); - - // We compute the rotation matrix column by column. - - // GL Z axis is front facing. - Vec column_2 = -line_2; - - // X-axis is almost like line_0 but should be orthogonal to the Z axis. - Vec column_0 = ((column_2^line_0)^column_2); - column_0.normalize(); - - // Y-axis is almost like line_1 but should be orthogonal to the Z axis. - // Moreover line_1 is downward oriented as the screen CS. - Vec column_1 = -((column_2^line_1)^column_2); - column_1.normalize(); - - qreal rot[3][3]; - rot[0][0] = column_0[0]; - rot[1][0] = column_0[1]; - rot[2][0] = column_0[2]; - - rot[0][1] = column_1[0]; - rot[1][1] = column_1[1]; - rot[2][1] = column_1[2]; - - rot[0][2] = column_2[0]; - rot[1][2] = column_2[1]; - rot[2][2] = column_2[2]; - - // We compute the field of view - - // line_1^column_0 -> vector of intersection line between - // y_screen=0 and x_camera=0 plane. - // column_2*(...) -> cos of the angle between Z vector et y_screen=0 plane - // * 2 -> field of view = 2 * half angle - - // We need some intermediate values. - Vec dummy = line_1^column_0; - dummy.normalize(); - qreal fov = acos(column_2*dummy) * 2.0; - - // We set the camera. - Quaternion q; - q.setFromRotationMatrix(rot); - setOrientation(q); - setPosition(cam_pos); - setFieldOfView(fov); +void Camera::setFromProjectionMatrix(const qreal matrix[12]) { + // The 3 lines of the matrix are the normals to the planes x=0, y=0, z=0 + // in the camera CS. As we normalize them, we do not need the 4th coordinate. + Vec line_0(matrix[ind(0, 0)], matrix[ind(0, 1)], matrix[ind(0, 2)]); + Vec line_1(matrix[ind(1, 0)], matrix[ind(1, 1)], matrix[ind(1, 2)]); + Vec line_2(matrix[ind(2, 0)], matrix[ind(2, 1)], matrix[ind(2, 2)]); + + line_0.normalize(); + line_1.normalize(); + line_2.normalize(); + + // The camera position is at (0,0,0) in the camera CS so it is the + // intersection of the 3 planes. It can be seen as the kernel + // of the 3x4 projection matrix. We calculate it through 4 dimensional + // vectorial product. We go directly into 3D that is to say we directly + // divide the first 3 coordinates by the 4th one. + + // We derive the 4 dimensional vectorial product formula from the + // computation of a 4x4 determinant that is developped according to + // its 4th column. This implies some 3x3 determinants. + const Vec cam_pos = + Vec(det(matrix[ind(0, 1)], matrix[ind(0, 2)], matrix[ind(0, 3)], + matrix[ind(1, 1)], matrix[ind(1, 2)], matrix[ind(1, 3)], + matrix[ind(2, 1)], matrix[ind(2, 2)], matrix[ind(2, 3)]), + + -det(matrix[ind(0, 0)], matrix[ind(0, 2)], matrix[ind(0, 3)], + matrix[ind(1, 0)], matrix[ind(1, 2)], matrix[ind(1, 3)], + matrix[ind(2, 0)], matrix[ind(2, 2)], matrix[ind(2, 3)]), + + det(matrix[ind(0, 0)], matrix[ind(0, 1)], matrix[ind(0, 3)], + matrix[ind(1, 0)], matrix[ind(1, 1)], matrix[ind(1, 3)], + matrix[ind(2, 0)], matrix[ind(2, 1)], matrix[ind(2, 3)])) / + + (-det(matrix[ind(0, 0)], matrix[ind(0, 1)], matrix[ind(0, 2)], + matrix[ind(1, 0)], matrix[ind(1, 1)], matrix[ind(1, 2)], + matrix[ind(2, 0)], matrix[ind(2, 1)], matrix[ind(2, 2)])); + + // We compute the rotation matrix column by column. + + // GL Z axis is front facing. + Vec column_2 = -line_2; + + // X-axis is almost like line_0 but should be orthogonal to the Z axis. + Vec column_0 = ((column_2 ^ line_0) ^ column_2); + column_0.normalize(); + + // Y-axis is almost like line_1 but should be orthogonal to the Z axis. + // Moreover line_1 is downward oriented as the screen CS. + Vec column_1 = -((column_2 ^ line_1) ^ column_2); + column_1.normalize(); + + qreal rot[3][3]; + rot[0][0] = column_0[0]; + rot[1][0] = column_0[1]; + rot[2][0] = column_0[2]; + + rot[0][1] = column_1[0]; + rot[1][1] = column_1[1]; + rot[2][1] = column_1[2]; + + rot[0][2] = column_2[0]; + rot[1][2] = column_2[1]; + rot[2][2] = column_2[2]; + + // We compute the field of view + + // line_1^column_0 -> vector of intersection line between + // y_screen=0 and x_camera=0 plane. + // column_2*(...) -> cos of the angle between Z vector et y_screen=0 plane + // * 2 -> field of view = 2 * half angle + + // We need some intermediate values. + Vec dummy = line_1 ^ column_0; + dummy.normalize(); + qreal fov = acos(column_2 * dummy) * 2.0; + + // We set the camera. + Quaternion q; + q.setFromRotationMatrix(rot); + setOrientation(q); + setPosition(cam_pos); + setFieldOfView(fov); } - /* - // persp : projectionMatrix_[0] = f/aspectRatio(); + // persp : projectionMatrix_[0] = f/aspectRatio(); void Camera::setFromProjectionMatrix(const GLdouble* projectionMatrix) { QString message; if ((fabs(projectionMatrix[1]) > 1E-3) || - (fabs(projectionMatrix[2]) > 1E-3) || - (fabs(projectionMatrix[3]) > 1E-3) || - (fabs(projectionMatrix[4]) > 1E-3) || - (fabs(projectionMatrix[6]) > 1E-3) || - (fabs(projectionMatrix[7]) > 1E-3) || - (fabs(projectionMatrix[8]) > 1E-3) || - (fabs(projectionMatrix[9]) > 1E-3)) - message = "Non null coefficient in projection matrix - Aborting"; + (fabs(projectionMatrix[2]) > 1E-3) || + (fabs(projectionMatrix[3]) > 1E-3) || + (fabs(projectionMatrix[4]) > 1E-3) || + (fabs(projectionMatrix[6]) > 1E-3) || + (fabs(projectionMatrix[7]) > 1E-3) || + (fabs(projectionMatrix[8]) > 1E-3) || + (fabs(projectionMatrix[9]) > 1E-3)) + message = "Non null coefficient in projection matrix - Aborting"; else - if ((fabs(projectionMatrix[11]+1.0) < 1E-5) && (fabs(projectionMatrix[15]) < 1E-5)) - { - if (projectionMatrix[5] < 1E-4) - message="Negative field of view in Camera::setFromProjectionMatrix"; - else - setType(Camera::PERSPECTIVE); - } - else - if ((fabs(projectionMatrix[11]) < 1E-5) && (fabs(projectionMatrix[15]-1.0) < 1E-5)) - setType(Camera::ORTHOGRAPHIC); - else - message = "Unable to determine camera type in setFromProjectionMatrix - Aborting"; + if ((fabs(projectionMatrix[11]+1.0) < 1E-5) && (fabs(projectionMatrix[15]) < +1E-5)) + { + if (projectionMatrix[5] < 1E-4) + message="Negative field of view in Camera::setFromProjectionMatrix"; + else + setType(Camera::PERSPECTIVE); + } + else + if ((fabs(projectionMatrix[11]) < 1E-5) && (fabs(projectionMatrix[15]-1.0) < +1E-5)) setType(Camera::ORTHOGRAPHIC); else message = "Unable to determine camera +type in setFromProjectionMatrix - Aborting"; if (!message.isEmpty()) - { - qWarning(message); - return; - } + { + qWarning(message); + return; + } switch (type()) - { - case Camera::PERSPECTIVE: - { - setFieldOfView(2.0 * atan(1.0/projectionMatrix[5])); - const qreal far = projectionMatrix[14] / (2.0 * (1.0 + projectionMatrix[10])); - const qreal near = (projectionMatrix[10]+1.0) / (projectionMatrix[10]-1.0) * far; - setSceneRadius((far-near)/2.0); - setSceneCenter(position() + (near + sceneRadius())*viewDirection()); - break; - } - case Camera::ORTHOGRAPHIC: - { - GLdouble w, h; - getOrthoWidthHeight(w,h); - projectionMatrix_[0] = 1.0/w; - projectionMatrix_[5] = 1.0/h; - projectionMatrix_[10] = -2.0/(ZFar - ZNear); - projectionMatrix_[11] = 0.0; - projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear); - projectionMatrix_[15] = 1.0; - // same as glOrtho( -w, w, -h, h, zNear(), zFar() ); - break; - } - } + { + case Camera::PERSPECTIVE: + { + setFieldOfView(2.0 * atan(1.0/projectionMatrix[5])); + const qreal far = projectionMatrix[14] / (2.0 * (1.0 + projectionMatrix[10])); + const qreal near = (projectionMatrix[10]+1.0) / (projectionMatrix[10]-1.0) * +far; setSceneRadius((far-near)/2.0); setSceneCenter(position() + (near + +sceneRadius())*viewDirection()); break; + } + case Camera::ORTHOGRAPHIC: + { + GLdouble w, h; + getOrthoWidthHeight(w,h); + projectionMatrix_[0] = 1.0/w; + projectionMatrix_[5] = 1.0/h; + projectionMatrix_[10] = -2.0/(ZFar - ZNear); + projectionMatrix_[11] = 0.0; + projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear); + projectionMatrix_[15] = 1.0; + // same as glOrtho( -w, w, -h, h, zNear(), zFar() ); + break; + } + } } */ ///////////////////////// Camera to world transform /////////////////////// -/*! Same as cameraCoordinatesOf(), but with \c qreal[3] parameters (\p src and \p res may be identical pointers). */ -void Camera::getCameraCoordinatesOf(const qreal src[3], qreal res[3]) const -{ - Vec r = cameraCoordinatesOf(Vec(src)); - for (int i=0; i<3; ++i) - res[i] = r[i]; +/*! Same as cameraCoordinatesOf(), but with \c qreal[3] parameters (\p src and + * \p res may be identical pointers). */ +void Camera::getCameraCoordinatesOf(const qreal src[3], qreal res[3]) const { + Vec r = cameraCoordinatesOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } -/*! Same as worldCoordinatesOf(), but with \c qreal[3] parameters (\p src and \p res may be identical pointers). */ -void Camera::getWorldCoordinatesOf(const qreal src[3], qreal res[3]) const -{ - Vec r = worldCoordinatesOf(Vec(src)); - for (int i=0; i<3; ++i) - res[i] = r[i]; +/*! Same as worldCoordinatesOf(), but with \c qreal[3] parameters (\p src and \p + * res may be identical pointers). */ +void Camera::getWorldCoordinatesOf(const qreal src[3], qreal res[3]) const { + Vec r = worldCoordinatesOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Fills \p viewport with the Camera OpenGL viewport. -This method is mainly used in conjunction with \c gluProject, which requires such a viewport. -Returned values are (0, screenHeight(), screenWidth(), - screenHeight()), so that the origin is -located in the \e upper left corner of the window (Qt style coordinate system). */ -void Camera::getViewport(GLint viewport[4]) const -{ - viewport[0] = 0; - viewport[1] = screenHeight(); - viewport[2] = screenWidth(); - viewport[3] = -screenHeight(); +This method is mainly used in conjunction with \c gluProject, which requires +such a viewport. Returned values are (0, screenHeight(), screenWidth(), - +screenHeight()), so that the origin is located in the \e upper left corner of +the window (Qt style coordinate system). */ +void Camera::getViewport(GLint viewport[4]) const { + viewport[0] = 0; + viewport[1] = screenHeight(); + viewport[2] = screenWidth(); + viewport[3] = -screenHeight(); } -/*! Returns the screen projected coordinates of a point \p src defined in the \p frame coordinate - system. +/*! Returns the screen projected coordinates of a point \p src defined in the \p + frame coordinate system. - When \p frame in \c NULL (default), \p src is expressed in the world coordinate system. + When \p frame in \c nullptr (default), \p src is expressed in the world coordinate + system. - The x and y coordinates of the returned Vec are expressed in pixel, (0,0) being the \e upper left - corner of the window. The z coordinate ranges between 0.0 (near plane) and 1.0 (excluded, far - plane). See the \c gluProject man page for details. + The x and y coordinates of the returned Vec are expressed in pixel, (0,0) being + the \e upper left corner of the window. The z coordinate ranges between 0.0 + (near plane) and 1.0 (excluded, far plane). See the \c gluProject man page for + details. unprojectedCoordinatesOf() performs the inverse transformation. - See the screenCoordSystem example. + See the screenCoordSystem + example. - This method only uses the intrinsic Camera parameters (see getModelViewMatrix(), - getProjectionMatrix() and getViewport()) and is completely independent of the OpenGL \c - GL_MODELVIEW, \c GL_PROJECTION and viewport matrices. You can hence define a virtual Camera and use - this method to compute projections out of a classical rendering context. + This method only uses the intrinsic Camera parameters (see + getModelViewMatrix(), getProjectionMatrix() and getViewport()) and is + completely independent of the OpenGL \c GL_MODELVIEW, \c GL_PROJECTION and + viewport matrices. You can hence define a virtual Camera and use this method to + compute projections out of a classical rendering context. - \attention However, if your Camera is not attached to a QGLViewer (used for offscreen computations - for instance), make sure the Camera matrices are updated before calling this method. Call - computeModelViewMatrix() and computeProjectionMatrix() to do so. + \attention However, if your Camera is not attached to a QGLViewer (used for + offscreen computations for instance), make sure the Camera matrices are updated + before calling this method. Call computeModelViewMatrix() and + computeProjectionMatrix() to do so. - If you call this method several times with no change in the matrices, consider precomputing the - projection times modelview matrix to save computation time if required (\c P x \c M in the \c - gluProject man page). + If you call this method several times with no change in the matrices, consider + precomputing the projection times modelview matrix to save computation time if + required (\c P x \c M in the \c gluProject man page). - Here is the code corresponding to what this method does (kindly submitted by Robert W. Kuhn) : - \code - Vec project(Vec point) + Here is the code corresponding to what this method does (kindly submitted by + Robert W. Kuhn) : \code Vec project(Vec point) { - GLint Viewport[4]; - GLdouble Projection[16], Modelview[16]; - GLdouble matrix[16]; - - // Precomputation begin - glGetIntegerv(GL_VIEWPORT , Viewport); - glGetDoublev (GL_MODELVIEW_MATRIX , Modelview); - glGetDoublev (GL_PROJECTION_MATRIX, Projection); - - for (unsigned short m=0; m<4; ++m) - { - for (unsigned short l=0; l<4; ++l) - { - qreal sum = 0.0; - for (unsigned short k=0; k<4; ++k) - sum += Projection[l+4*k]*Modelview[k+4*m]; - matrix[l+4*m] = sum; - } - } - // Precomputation end - - GLdouble v[4], vs[4]; - v[0]=point[0]; v[1]=point[1]; v[2]=point[2]; v[3]=1.0; - - vs[0]=matrix[0 ]*v[0] + matrix[4 ]*v[1] + matrix[8 ]*v[2] + matrix[12 ]*v[3]; - vs[1]=matrix[1 ]*v[0] + matrix[5 ]*v[1] + matrix[9 ]*v[2] + matrix[13 ]*v[3]; - vs[2]=matrix[2 ]*v[0] + matrix[6 ]*v[1] + matrix[10]*v[2] + matrix[14 ]*v[3]; - vs[3]=matrix[3 ]*v[0] + matrix[7 ]*v[1] + matrix[11]*v[2] + matrix[15 ]*v[3]; - - vs[0] /= vs[3]; - vs[1] /= vs[3]; - vs[2] /= vs[3]; - - vs[0] = vs[0] * 0.5 + 0.5; - vs[1] = vs[1] * 0.5 + 0.5; - vs[2] = vs[2] * 0.5 + 0.5; - - vs[0] = vs[0] * Viewport[2] + Viewport[0]; - vs[1] = vs[1] * Viewport[3] + Viewport[1]; - - return Vec(vs[0], Viewport[3]-vs[1], vs[2]); + GLint Viewport[4]; + GLdouble Projection[16], Modelview[16]; + GLdouble matrix[16]; + + // Precomputation begin + glGetIntegerv(GL_VIEWPORT , Viewport); + glGetDoublev (GL_MODELVIEW_MATRIX , Modelview); + glGetDoublev (GL_PROJECTION_MATRIX, Projection); + + for (unsigned short m=0; m<4; ++m) + { + for (unsigned short l=0; l<4; ++l) + { + qreal sum = 0.0; + for (unsigned short k=0; k<4; ++k) + sum += Projection[l+4*k]*Modelview[k+4*m]; + matrix[l+4*m] = sum; + } + } + // Precomputation end + + GLdouble v[4], vs[4]; + v[0]=point[0]; v[1]=point[1]; v[2]=point[2]; v[3]=1.0; + + vs[0]=matrix[0 ]*v[0] + matrix[4 ]*v[1] + matrix[8 ]*v[2] + matrix[12 ]*v[3]; + vs[1]=matrix[1 ]*v[0] + matrix[5 ]*v[1] + matrix[9 ]*v[2] + matrix[13 ]*v[3]; + vs[2]=matrix[2 ]*v[0] + matrix[6 ]*v[1] + matrix[10]*v[2] + matrix[14 ]*v[3]; + vs[3]=matrix[3 ]*v[0] + matrix[7 ]*v[1] + matrix[11]*v[2] + matrix[15 ]*v[3]; + + vs[0] /= vs[3]; + vs[1] /= vs[3]; + vs[2] /= vs[3]; + + vs[0] = vs[0] * 0.5 + 0.5; + vs[1] = vs[1] * 0.5 + 0.5; + vs[2] = vs[2] * 0.5 + 0.5; + + vs[0] = vs[0] * Viewport[2] + Viewport[0]; + vs[1] = vs[1] * Viewport[3] + Viewport[1]; + + return Vec(vs[0], Viewport[3]-vs[1], vs[2]); } \endcode */ -Vec Camera::projectedCoordinatesOf(const Vec& src, const Frame* frame) const -{ - GLdouble x,y,z; - static GLint viewport[4]; - getViewport(viewport); +Vec Camera::projectedCoordinatesOf(const Vec &src, const Frame *frame) const { + GLdouble x, y, z; + static GLint viewport[4]; + getViewport(viewport); - if (frame) - { - const Vec tmp = frame->inverseCoordinatesOf(src); - gluProject(tmp.x,tmp.y,tmp.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z); - } - else - gluProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z); + if (frame) { + const Vec tmp = frame->inverseCoordinatesOf(src); + gluProject(tmp.x, tmp.y, tmp.z, modelViewMatrix_, projectionMatrix_, + viewport, &x, &y, &z); + } else + gluProject(src.x, src.y, src.z, modelViewMatrix_, projectionMatrix_, + viewport, &x, &y, &z); - return Vec(x,y,z); + return Vec(x, y, z); } -/*! Returns the world unprojected coordinates of a point \p src defined in the screen coordinate - system. +/*! Returns the world unprojected coordinates of a point \p src defined in the + screen coordinate system. - The \p src.x and \p src.y input values are expressed in pixels, (0,0) being the \e upper left corner - of the window. \p src.z is a depth value ranging in [0..1[ (respectively corresponding to the near - and far planes). Note that src.z is \e not a linear interpolation between zNear and zFar. - /code - src.z = zFar() / (zFar() - zNear()) * (1.0 - zNear() / z); - /endcode - Where z is the distance from the point you project to the camera, along the viewDirection(). - See the \c gluUnProject man page for details. + The \p src.x and \p src.y input values are expressed in pixels, (0,0) being the + \e upper left corner of the window. \p src.z is a depth value ranging in [0..1[ + (respectively corresponding to the near and far planes). Note that src.z is \e + not a linear interpolation between zNear and zFar. /code src.z = zFar() / + (zFar() - zNear()) * (1.0 - zNear() / z); /endcode Where z is the distance from + the point you project to the camera, along the viewDirection(). See the \c + gluUnProject man page for details. - The result is expressed in the \p frame coordinate system. When \p frame is \c NULL (default), the - result is expressed in the world coordinates system. The possible \p frame Frame::referenceFrame() - are taken into account. + The result is expressed in the \p frame coordinate system. When \p frame is \c + nullptr (default), the result is expressed in the world coordinates system. The + possible \p frame Frame::referenceFrame() are taken into account. projectedCoordinatesOf() performs the inverse transformation. - This method only uses the intrinsic Camera parameters (see getModelViewMatrix(), - getProjectionMatrix() and getViewport()) and is completely independent of the OpenGL \c - GL_MODELVIEW, \c GL_PROJECTION and viewport matrices. You can hence define a virtual Camera and use - this method to compute un-projections out of a classical rendering context. - - \attention However, if your Camera is not attached to a QGLViewer (used for offscreen computations - for instance), make sure the Camera matrices are updated before calling this method (use - computeModelViewMatrix(), computeProjectionMatrix()). See also setScreenWidthAndHeight(). + This method only uses the intrinsic Camera parameters (see + getModelViewMatrix(), getProjectionMatrix() and getViewport()) and is + completely independent of the OpenGL \c GL_MODELVIEW, \c GL_PROJECTION and + viewport matrices. You can hence define a virtual Camera and use this method to + compute un-projections out of a classical rendering context. + + \attention However, if your Camera is not attached to a QGLViewer (used for + offscreen computations for instance), make sure the Camera matrices are updated + before calling this method (use computeModelViewMatrix(), + computeProjectionMatrix()). See also setScreenWidthAndHeight(). + + This method is not computationally optimized. If you call it several times with + no change in the matrices, you should buffer the entire inverse projection + matrix (modelview, projection and then viewport) to speed-up the queries. See + the \c gluUnProject man page for details. */ +Vec Camera::unprojectedCoordinatesOf(const Vec &src, const Frame *frame) const { + GLdouble x, y, z; + static GLint viewport[4]; + getViewport(viewport); + gluUnProject(src.x, src.y, src.z, modelViewMatrix_, projectionMatrix_, + viewport, &x, &y, &z); + if (frame) + return frame->coordinatesOf(Vec(x, y, z)); + else + return Vec(x, y, z); +} - This method is not computationally optimized. If you call it several times with no change in the - matrices, you should buffer the entire inverse projection matrix (modelview, projection and then - viewport) to speed-up the queries. See the \c gluUnProject man page for details. */ -Vec Camera::unprojectedCoordinatesOf(const Vec& src, const Frame* frame) const -{ - GLdouble x,y,z; - static GLint viewport[4]; - getViewport(viewport); - gluUnProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z); - if (frame) - return frame->coordinatesOf(Vec(x,y,z)); - else - return Vec(x,y,z); -} - -/*! Same as projectedCoordinatesOf(), but with \c qreal parameters (\p src and \p res can be identical pointers). */ -void Camera::getProjectedCoordinatesOf(const qreal src[3], qreal res[3], const Frame* frame) const -{ - Vec r = projectedCoordinatesOf(Vec(src), frame); - for (int i=0; i<3; ++i) - res[i] = r[i]; +/*! Same as projectedCoordinatesOf(), but with \c qreal parameters (\p src and + * \p res can be identical pointers). */ +void Camera::getProjectedCoordinatesOf(const qreal src[3], qreal res[3], + const Frame *frame) const { + Vec r = projectedCoordinatesOf(Vec(src), frame); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } -/*! Same as unprojectedCoordinatesOf(), but with \c qreal parameters (\p src and \p res can be identical pointers). */ -void Camera::getUnprojectedCoordinatesOf(const qreal src[3], qreal res[3], const Frame* frame) const -{ - Vec r = unprojectedCoordinatesOf(Vec(src), frame); - for (int i=0; i<3; ++i) - res[i] = r[i]; +/*! Same as unprojectedCoordinatesOf(), but with \c qreal parameters (\p src and + * \p res can be identical pointers). */ +void Camera::getUnprojectedCoordinatesOf(const qreal src[3], qreal res[3], + const Frame *frame) const { + Vec r = unprojectedCoordinatesOf(Vec(src), frame); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } -///////////////////////////////////// KFI ///////////////////////////////////////// +///////////////////////////////////// KFI +//////////////////////////////////////////// /*! Returns the KeyFrameInterpolator that defines the Camera path number \p i. -If path \p i is not defined for this index, the method returns a \c NULL pointer. */ -KeyFrameInterpolator* Camera::keyFrameInterpolator(unsigned int i) const -{ - if (kfi_.contains(i)) - return kfi_[i]; - else - return NULL; +If path \p i is not defined for this index, the method returns a \c nullptr +pointer. */ +KeyFrameInterpolator *Camera::keyFrameInterpolator(unsigned int i) const { + if (kfi_.contains(i)) + return kfi_[i]; + else + return nullptr; } /*! Sets the KeyFrameInterpolator that defines the Camera path of index \p i. - The previous keyFrameInterpolator() is lost and should be deleted by the calling method if - needed. + The previous keyFrameInterpolator() is lost and should be deleted by the + calling method if needed. - The KeyFrameInterpolator::interpolated() signal of \p kfi probably needs to be connected to the - Camera's associated QGLViewer::update() slot, so that when the Camera position is interpolated - using \p kfi, every interpolation step updates the display: - \code - myViewer.camera()->deletePath(3); + The KeyFrameInterpolator::interpolated() signal of \p kfi probably needs to be + connected to the Camera's associated QGLViewer::update() slot, so that when the + Camera position is interpolated using \p kfi, every interpolation step updates + the display: \code myViewer.camera()->deletePath(3); myViewer.camera()->setKeyFrameInterpolator(3, myKeyFrameInterpolator); - connect(myKeyFrameInterpolator, SIGNAL(interpolated()), myViewer, SLOT(update()); - \endcode + connect(myKeyFrameInterpolator, SIGNAL(interpolated()), myViewer, + SLOT(update()); \endcode - \note These connections are done automatically when a Camera is attached to a QGLViewer, or when a - new KeyFrameInterpolator is defined using the QGLViewer::addKeyFrameKeyboardModifiers() and - QGLViewer::pathKey() (default is Alt+F[1-12]). See the keyboard page - for details. */ -void Camera::setKeyFrameInterpolator(unsigned int i, KeyFrameInterpolator* const kfi) -{ - if (kfi) - kfi_[i] = kfi; - else - kfi_.remove(i); + \note These connections are done automatically when a Camera is attached to a + QGLViewer, or when a new KeyFrameInterpolator is defined using the + QGLViewer::addKeyFrameKeyboardModifiers() and QGLViewer::pathKey() (default is + Alt+F[1-12]). See the keyboard page for details. + */ +void Camera::setKeyFrameInterpolator(unsigned int i, + KeyFrameInterpolator *const kfi) { + if (kfi) + kfi_[i] = kfi; + else + kfi_.remove(i); } -/*! Adds the current Camera position() and orientation() as a keyFrame to the path number \p i. +/*! Adds the current Camera position() and orientation() as a keyFrame to the +path number \p i. -This method can also be used if you simply want to save a Camera point of view (a path made of a -single keyFrame). Use playPath() to make the Camera play the keyFrame path (resp. restore -the point of view). Use deletePath() to clear the path. +This method can also be used if you simply want to save a Camera point of view +(a path made of a single keyFrame). Use playPath() to make the Camera play the +keyFrame path (resp. restore the point of view). Use deletePath() to clear the +path. -The default keyboard shortcut for this method is Alt+F[1-12]. Set QGLViewer::pathKey() and -QGLViewer::addKeyFrameKeyboardModifiers(). +The default keyboard shortcut for this method is Alt+F[1-12]. Set +QGLViewer::pathKey() and QGLViewer::addKeyFrameKeyboardModifiers(). -If you use directly this method and the keyFrameInterpolator(i) does not exist, a new one is -created. Its KeyFrameInterpolator::interpolated() signal should then be connected to the -QGLViewer::update() slot (see setKeyFrameInterpolator()). */ -void Camera::addKeyFrameToPath(unsigned int i) -{ - if (!kfi_.contains(i)) - setKeyFrameInterpolator(i, new KeyFrameInterpolator(frame())); +If you use directly this method and the keyFrameInterpolator(i) does not exist, +a new one is created. Its KeyFrameInterpolator::interpolated() signal should +then be connected to the QGLViewer::update() slot (see +setKeyFrameInterpolator()). */ +void Camera::addKeyFrameToPath(unsigned int i) { + if (!kfi_.contains(i)) + setKeyFrameInterpolator(i, new KeyFrameInterpolator(frame())); - kfi_[i]->addKeyFrame(*(frame())); + kfi_[i]->addKeyFrame(*(frame())); } /*! Makes the Camera follow the path of keyFrameInterpolator() number \p i. If the interpolation is started, it stops it instead. - This method silently ignores undefined (empty) paths (see keyFrameInterpolator()). - - The default keyboard shortcut for this method is F[1-12]. Set QGLViewer::pathKey() and - QGLViewer::playPathKeyboardModifiers(). */ -void Camera::playPath(unsigned int i) -{ - if (kfi_.contains(i)) { - if (kfi_[i]->interpolationIsStarted()) - kfi_[i]->stopInterpolation(); - else - kfi_[i]->startInterpolation(); - } + This method silently ignores undefined (empty) paths (see + keyFrameInterpolator()). + + The default keyboard shortcut for this method is F[1-12]. Set + QGLViewer::pathKey() and QGLViewer::playPathKeyboardModifiers(). */ +void Camera::playPath(unsigned int i) { + if (kfi_.contains(i)) { + if (kfi_[i]->interpolationIsStarted()) + kfi_[i]->stopInterpolation(); + else + kfi_[i]->startInterpolation(); + } } /*! Resets the path of the keyFrameInterpolator() number \p i. If this path is \e not being played (see playPath() and -KeyFrameInterpolator::interpolationIsStarted()), resets it to its starting position (see -KeyFrameInterpolator::resetInterpolation()). If the path is played, simply stops interpolation. */ -void Camera::resetPath(unsigned int i) -{ - if (kfi_.contains(i)) { - if ((kfi_[i]->interpolationIsStarted())) - kfi_[i]->stopInterpolation(); - else - { - kfi_[i]->resetInterpolation(); - kfi_[i]->interpolateAtTime(kfi_[i]->interpolationTime()); - } - } +KeyFrameInterpolator::interpolationIsStarted()), resets it to its starting +position (see KeyFrameInterpolator::resetInterpolation()). If the path is +played, simply stops interpolation. */ +void Camera::resetPath(unsigned int i) { + if (kfi_.contains(i)) { + if ((kfi_[i]->interpolationIsStarted())) + kfi_[i]->stopInterpolation(); + else { + kfi_[i]->resetInterpolation(); + kfi_[i]->interpolateAtTime(kfi_[i]->interpolationTime()); + } + } } /*! Deletes the keyFrameInterpolator() of index \p i. -Disconnect the keyFrameInterpolator() KeyFrameInterpolator::interpolated() signal before deleting the -keyFrameInterpolator() if needed: -\code -disconnect(camera()->keyFrameInterpolator(i), SIGNAL(interpolated()), this, SLOT(update())); -camera()->deletePath(i); -\endcode */ -void Camera::deletePath(unsigned int i) -{ - if (kfi_.contains(i)) - { - kfi_[i]->stopInterpolation(); - delete kfi_[i]; - kfi_.remove(i); - } +Disconnect the keyFrameInterpolator() KeyFrameInterpolator::interpolated() +signal before deleting the keyFrameInterpolator() if needed: \code +disconnect(camera()->keyFrameInterpolator(i), SIGNAL(interpolated()), this, +SLOT(update())); camera()->deletePath(i); \endcode */ +void Camera::deletePath(unsigned int i) { + if (kfi_.contains(i)) { + kfi_[i]->stopInterpolation(); + delete kfi_[i]; + kfi_.remove(i); + } } /*! Draws all the Camera paths defined by the keyFrameInterpolator(). - Simply calls KeyFrameInterpolator::drawPath() for all the defined paths. The path color is the - current \c glColor(). + Simply calls KeyFrameInterpolator::drawPath() for all the defined paths. The + path color is the current \c glColor(). - \attention The OpenGL state is modified by this method: see KeyFrameInterpolator::drawPath(). */ -void Camera::drawAllPaths() -{ - for (QMap::ConstIterator it = kfi_.begin(), end=kfi_.end(); it != end; ++it) - (it.value())->drawPath(3, 5, sceneRadius()); + \attention The OpenGL state is modified by this method: see + KeyFrameInterpolator::drawPath(). */ +void Camera::drawAllPaths() { + for (QMap::ConstIterator + it = kfi_.begin(), + end = kfi_.end(); + it != end; ++it) + (it.value())->drawPath(3, 5, sceneRadius()); } //////////////////////////////////////////////////////////////////////////////// /*! Returns an XML \c QDomElement that represents the Camera. - \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create - QDomElement. + \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument + factory used to create QDomElement. - Concatenates the Camera parameters, the ManipulatedCameraFrame::domElement() and the paths' - KeyFrameInterpolator::domElement(). + Concatenates the Camera parameters, the ManipulatedCameraFrame::domElement() + and the paths' KeyFrameInterpolator::domElement(). - Use initFromDOMElement() to restore the Camera state from the resulting \c QDomElement. + Use initFromDOMElement() to restore the Camera state from the resulting \c + QDomElement. If you want to save the Camera state in a file, use: \code @@ -1800,55 +1844,65 @@ void Camera::drawAllPaths() QFile f("myCamera.xml"); if (f.open(IO_WriteOnly)) - { - QTextStream out(&f); - document.save(out, 2); - } + { + QTextStream out(&f); + document.save(out, 2); + } \endcode - Note that the QGLViewer::camera() is automatically saved by QGLViewer::saveStateToFile() when a - QGLViewer is closed. Use QGLViewer::restoreStateFromFile() to restore it back. */ -QDomElement Camera::domElement(const QString& name, QDomDocument& document) const -{ - QDomElement de = document.createElement(name); - QDomElement paramNode = document.createElement("Parameters"); - paramNode.setAttribute("fieldOfView", QString::number(fieldOfView())); - paramNode.setAttribute("zNearCoefficient", QString::number(zNearCoefficient())); - paramNode.setAttribute("zClippingCoefficient", QString::number(zClippingCoefficient())); - paramNode.setAttribute("orthoCoef", QString::number(orthoCoef_)); - paramNode.setAttribute("sceneRadius", QString::number(sceneRadius())); - paramNode.appendChild(sceneCenter().domElement("SceneCenter", document)); - - switch (type()) - { - case Camera::PERSPECTIVE : paramNode.setAttribute("Type", "PERSPECTIVE"); break; - case Camera::ORTHOGRAPHIC : paramNode.setAttribute("Type", "ORTHOGRAPHIC"); break; - } - de.appendChild(paramNode); - - QDomElement stereoNode = document.createElement("Stereo"); - stereoNode.setAttribute("IODist", QString::number(IODistance())); - stereoNode.setAttribute("focusDistance", QString::number(focusDistance())); - stereoNode.setAttribute("physScreenWidth", QString::number(physicalScreenWidth())); - de.appendChild(stereoNode); - - de.appendChild(frame()->domElement("ManipulatedCameraFrame", document)); - - // KeyFrame paths - for (QMap::ConstIterator it = kfi_.begin(), end=kfi_.end(); it != end; ++it) - { - QDomElement kfNode = (it.value())->domElement("KeyFrameInterpolator", document); - kfNode.setAttribute("index", QString::number(it.key())); - de.appendChild(kfNode); - } - - return de; + Note that the QGLViewer::camera() is automatically saved by + QGLViewer::saveStateToFile() when a QGLViewer is closed. Use + QGLViewer::restoreStateFromFile() to restore it back. */ +QDomElement Camera::domElement(const QString &name, + QDomDocument &document) const { + QDomElement de = document.createElement(name); + QDomElement paramNode = document.createElement("Parameters"); + paramNode.setAttribute("fieldOfView", QString::number(fieldOfView())); + paramNode.setAttribute("zNearCoefficient", + QString::number(zNearCoefficient())); + paramNode.setAttribute("zClippingCoefficient", + QString::number(zClippingCoefficient())); + paramNode.setAttribute("orthoCoef", QString::number(orthoCoef_)); + paramNode.setAttribute("sceneRadius", QString::number(sceneRadius())); + paramNode.appendChild(sceneCenter().domElement("SceneCenter", document)); + + switch (type()) { + case Camera::PERSPECTIVE: + paramNode.setAttribute("Type", "PERSPECTIVE"); + break; + case Camera::ORTHOGRAPHIC: + paramNode.setAttribute("Type", "ORTHOGRAPHIC"); + break; + } + de.appendChild(paramNode); + + QDomElement stereoNode = document.createElement("Stereo"); + stereoNode.setAttribute("IODist", QString::number(IODistance())); + stereoNode.setAttribute("focusDistance", QString::number(focusDistance())); + stereoNode.setAttribute("physScreenWidth", + QString::number(physicalScreenWidth())); + de.appendChild(stereoNode); + + de.appendChild(frame()->domElement("ManipulatedCameraFrame", document)); + + // KeyFrame paths + for (QMap::ConstIterator + it = kfi_.begin(), + end = kfi_.end(); + it != end; ++it) { + QDomElement kfNode = + (it.value())->domElement("KeyFrameInterpolator", document); + kfNode.setAttribute("index", QString::number(it.key())); + de.appendChild(kfNode); + } + + return de; } /*! Restores the Camera state from a \c QDomElement created by domElement(). - Use the following code to retrieve a Camera state from a file created using domElement(): - \code + Use the following code to retrieve a Camera state from a file created using + domElement(): \code // Load DOM from file QDomDocument document; QFile f("myCamera.xml"); @@ -1863,251 +1917,252 @@ QDomElement Camera::domElement(const QString& name, QDomDocument& document) cons myCamera->initFromDOMElement(main); \endcode - The frame() pointer is not modified by this method. The frame() state is however modified. + The frame() pointer is not modified by this method. The frame() state is + however modified. - \attention The original keyFrameInterpolator() are deleted and should be copied first if they are shared. */ -void Camera::initFromDOMElement(const QDomElement& element) -{ - QDomElement child=element.firstChild().toElement(); - - QMutableMapIterator it(kfi_); - while (it.hasNext()) { - it.next(); - deletePath(it.key()); - } - - while (!child.isNull()) - { - if (child.tagName() == "Parameters") - { - // #CONNECTION# Default values set in constructor - setFieldOfView(DomUtils::qrealFromDom(child, "fieldOfView", M_PI/4.0)); - setZNearCoefficient(DomUtils::qrealFromDom(child, "zNearCoefficient", 0.005)); - setZClippingCoefficient(DomUtils::qrealFromDom(child, "zClippingCoefficient", sqrt(3.0))); - orthoCoef_ = DomUtils::qrealFromDom(child, "orthoCoef", tan(fieldOfView()/2.0)); - setSceneRadius(DomUtils::qrealFromDom(child, "sceneRadius", sceneRadius())); - - setType(PERSPECTIVE); - QString type = child.attribute("Type", "PERSPECTIVE"); - if (type == "PERSPECTIVE") setType(Camera::PERSPECTIVE); - if (type == "ORTHOGRAPHIC") setType(Camera::ORTHOGRAPHIC); - - QDomElement child2=child.firstChild().toElement(); - while (!child2.isNull()) - { - /* Although the scene does not change when a camera is loaded, restore the saved center and radius values. - Mainly useful when a the viewer is restored on startup, with possible additional cameras. */ - if (child2.tagName() == "SceneCenter") - setSceneCenter(Vec(child2)); - - child2 = child2.nextSibling().toElement(); - } - } - - if (child.tagName() == "ManipulatedCameraFrame") - frame()->initFromDOMElement(child); - - if (child.tagName() == "Stereo") - { - setIODistance(DomUtils::qrealFromDom(child, "IODist", 0.062)); - setFocusDistance(DomUtils::qrealFromDom(child, "focusDistance", focusDistance())); - setPhysicalScreenWidth(DomUtils::qrealFromDom(child, "physScreenWidth", 0.5)); - } - - if (child.tagName() == "KeyFrameInterpolator") - { - unsigned int index = DomUtils::uintFromDom(child, "index", 0); - setKeyFrameInterpolator(index, new KeyFrameInterpolator(frame())); - if (keyFrameInterpolator(index)) - keyFrameInterpolator(index)->initFromDOMElement(child); - } - - child = child.nextSibling().toElement(); - } -} - -/*! Gives the coefficients of a 3D half-line passing through the Camera eye and pixel (x,y). - - The origin of the half line (eye position) is stored in \p orig, while \p dir contains the properly - oriented and normalized direction of the half line. - - \p x and \p y are expressed in Qt format (origin in the upper left corner). Use screenHeight() - y - to convert to OpenGL units. + \attention The original keyFrameInterpolator() are deleted and should be copied + first if they are shared. */ +void Camera::initFromDOMElement(const QDomElement &element) { + QDomElement child = element.firstChild().toElement(); + + QMutableMapIterator it(kfi_); + while (it.hasNext()) { + it.next(); + deletePath(it.key()); + } + + while (!child.isNull()) { + if (child.tagName() == "Parameters") { + // #CONNECTION# Default values set in constructor + setFieldOfView(DomUtils::qrealFromDom(child, "fieldOfView", M_PI / 4.0)); + setZNearCoefficient( + DomUtils::qrealFromDom(child, "zNearCoefficient", 0.005)); + setZClippingCoefficient( + DomUtils::qrealFromDom(child, "zClippingCoefficient", sqrt(3.0))); + orthoCoef_ = + DomUtils::qrealFromDom(child, "orthoCoef", tan(fieldOfView() / 2.0)); + setSceneRadius( + DomUtils::qrealFromDom(child, "sceneRadius", sceneRadius())); + + setType(PERSPECTIVE); + QString type = child.attribute("Type", "PERSPECTIVE"); + if (type == "PERSPECTIVE") + setType(Camera::PERSPECTIVE); + if (type == "ORTHOGRAPHIC") + setType(Camera::ORTHOGRAPHIC); + + QDomElement child2 = child.firstChild().toElement(); + while (!child2.isNull()) { + /* Although the scene does not change when a camera is loaded, restore + the saved center and radius values. Mainly useful when a the viewer is + restored on startup, with possible additional cameras. */ + if (child2.tagName() == "SceneCenter") + setSceneCenter(Vec(child2)); + + child2 = child2.nextSibling().toElement(); + } + } + + if (child.tagName() == "ManipulatedCameraFrame") + frame()->initFromDOMElement(child); + + if (child.tagName() == "Stereo") { + setIODistance(DomUtils::qrealFromDom(child, "IODist", 0.062)); + setFocusDistance( + DomUtils::qrealFromDom(child, "focusDistance", focusDistance())); + setPhysicalScreenWidth( + DomUtils::qrealFromDom(child, "physScreenWidth", 0.5)); + } + + if (child.tagName() == "KeyFrameInterpolator") { + unsigned int index = DomUtils::uintFromDom(child, "index", 0); + setKeyFrameInterpolator(index, new KeyFrameInterpolator(frame())); + if (keyFrameInterpolator(index)) + keyFrameInterpolator(index)->initFromDOMElement(child); + } + + child = child.nextSibling().toElement(); + } +} + +/*! Gives the coefficients of a 3D half-line passing through the Camera eye and + pixel (x,y). + + The origin of the half line (eye position) is stored in \p orig, while \p dir + contains the properly oriented and normalized direction of the half line. + + \p x and \p y are expressed in Qt format (origin in the upper left corner). Use + screenHeight() - y to convert to OpenGL units. This method is useful for analytical intersection in a selection method. - See the select example for an illustration. */ -void Camera::convertClickToLine(const QPoint& pixel, Vec& orig, Vec& dir) const -{ - switch (type()) - { - case Camera::PERSPECTIVE: - orig = position(); - dir = Vec( ((2.0 * pixel.x() / screenWidth()) - 1.0) * tan(fieldOfView()/2.0) * aspectRatio(), - ((2.0 * (screenHeight()-pixel.y()) / screenHeight()) - 1.0) * tan(fieldOfView()/2.0), - -1.0 ); - dir = worldCoordinatesOf(dir) - orig; - dir.normalize(); - break; - - case Camera::ORTHOGRAPHIC: - { - GLdouble w,h; - getOrthoWidthHeight(w,h); - orig = Vec((2.0 * pixel.x() / screenWidth() - 1.0)*w, -(2.0 * pixel.y() / screenHeight() - 1.0)*h, 0.0); - orig = worldCoordinatesOf(orig); - dir = viewDirection(); - break; - } - } + See the select example for an + illustration. */ +void Camera::convertClickToLine(const QPoint &pixel, Vec &orig, + Vec &dir) const { + switch (type()) { + case Camera::PERSPECTIVE: + orig = position(); + dir = Vec(((2.0 * pixel.x() / screenWidth()) - 1.0) * + tan(fieldOfView() / 2.0) * aspectRatio(), + ((2.0 * (screenHeight() - pixel.y()) / screenHeight()) - 1.0) * + tan(fieldOfView() / 2.0), + -1.0); + dir = worldCoordinatesOf(dir) - orig; + dir.normalize(); + break; + + case Camera::ORTHOGRAPHIC: { + GLdouble w, h; + getOrthoWidthHeight(w, h); + orig = Vec((2.0 * pixel.x() / screenWidth() - 1.0) * w, + -(2.0 * pixel.y() / screenHeight() - 1.0) * h, 0.0); + orig = worldCoordinatesOf(orig); + dir = viewDirection(); + break; + } + } } #ifndef DOXYGEN /*! This method has been deprecated in libQGLViewer version 2.2.0 */ -void Camera::drawCamera(qreal, qreal, qreal) -{ - qWarning("drawCamera is deprecated. Use Camera::draw() instead."); +void Camera::drawCamera(qreal, qreal, qreal) { + qWarning("drawCamera is deprecated. Use Camera::draw() instead."); } #endif /*! Draws a representation of the Camera in the 3D world. -The near and far planes are drawn as quads, the frustum is drawn using lines and the camera up -vector is represented by an arrow to disambiguate the drawing. See the -standardCamera example for an illustration. +The near and far planes are drawn as quads, the frustum is drawn using lines and +the camera up vector is represented by an arrow to disambiguate the drawing. See +the standardCamera example for an +illustration. -Note that the current \c glColor and \c glPolygonMode are used to draw the near and far planes. See -the frustumCulling example for an example of -semi-transparent plane drawing. Similarly, the current \c glLineWidth and \c glColor is used to draw -the frustum outline. +Note that the current \c glColor and \c glPolygonMode are used to draw the near +and far planes. See the frustumCulling +example for an example of semi-transparent plane drawing. Similarly, the +current \c glLineWidth and \c glColor is used to draw the frustum outline. -When \p drawFarPlane is \c false, only the near plane is drawn. \p scale can be used to scale the -drawing: a value of 1.0 (default) will draw the Camera's frustum at its actual size. +When \p drawFarPlane is \c false, only the near plane is drawn. \p scale can be +used to scale the drawing: a value of 1.0 (default) will draw the Camera's +frustum at its actual size. -This method assumes that the \c glMatrixMode is \c GL_MODELVIEW and that the current ModelView -matrix corresponds to the world coordinate system (as it is at the beginning of QGLViewer::draw()). -The Camera is then correctly positioned and orientated. +This method assumes that the \c glMatrixMode is \c GL_MODELVIEW and that the +current ModelView matrix corresponds to the world coordinate system (as it is at +the beginning of QGLViewer::draw()). The Camera is then correctly positioned and +orientated. -\note The drawing of a QGLViewer's own QGLViewer::camera() should not be visible, but may create -artefacts due to numerical imprecisions. */ -void Camera::draw(bool drawFarPlane, qreal scale) const -{ - glPushMatrix(); - glMultMatrixd(frame()->worldMatrix()); - - // 0 is the upper left coordinates of the near corner, 1 for the far one - Vec points[2]; - - points[0].z = scale * zNear(); - points[1].z = scale * zFar(); - - switch (type()) - { - case Camera::PERSPECTIVE: - { - points[0].y = points[0].z * tan(fieldOfView()/2.0); - points[0].x = points[0].y * aspectRatio(); - - const qreal ratio = points[1].z / points[0].z; - - points[1].y = ratio * points[0].y; - points[1].x = ratio * points[0].x; - break; - } - case Camera::ORTHOGRAPHIC: - { - GLdouble hw, hh; - getOrthoWidthHeight(hw, hh); - points[0].x = points[1].x = scale * qreal(hw); - points[0].y = points[1].y = scale * qreal(hh); - break; - } - } - - const int farIndex = drawFarPlane?1:0; - - // Near and (optionally) far plane(s) - glBegin(GL_QUADS); - for (int i=farIndex; i>=0; --i) - { - glNormal3d(0.0f, 0.0f, (i==0)?1.0f:-1.0f); - glVertex3d( points[i].x, points[i].y, -points[i].z); - glVertex3d(-points[i].x, points[i].y, -points[i].z); - glVertex3d(-points[i].x, -points[i].y, -points[i].z); - glVertex3d( points[i].x, -points[i].y, -points[i].z); - } - glEnd(); - - // Up arrow - const qreal arrowHeight = 1.5 * points[0].y; - const qreal baseHeight = 1.2 * points[0].y; - const qreal arrowHalfWidth = 0.5 * points[0].x; - const qreal baseHalfWidth = 0.3 * points[0].x; - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - // Base - glBegin(GL_QUADS); - glVertex3d(-baseHalfWidth, points[0].y, -points[0].z); - glVertex3d( baseHalfWidth, points[0].y, -points[0].z); - glVertex3d( baseHalfWidth, baseHeight, -points[0].z); - glVertex3d(-baseHalfWidth, baseHeight, -points[0].z); - glEnd(); - - // Arrow - glBegin(GL_TRIANGLES); - glVertex3d( 0.0, arrowHeight, -points[0].z); - glVertex3d(-arrowHalfWidth, baseHeight, -points[0].z); - glVertex3d( arrowHalfWidth, baseHeight, -points[0].z); - glEnd(); - - // Frustum lines - switch (type()) - { - case Camera::PERSPECTIVE : - glBegin(GL_LINES); - glVertex3d(0.0, 0.0, 0.0); - glVertex3d( points[farIndex].x, points[farIndex].y, -points[farIndex].z); - glVertex3d(0.0, 0.0, 0.0); - glVertex3d(-points[farIndex].x, points[farIndex].y, -points[farIndex].z); - glVertex3d(0.0, 0.0, 0.0); - glVertex3d(-points[farIndex].x, -points[farIndex].y, -points[farIndex].z); - glVertex3d(0.0, 0.0, 0.0); - glVertex3d( points[farIndex].x, -points[farIndex].y, -points[farIndex].z); - glEnd(); - break; - case Camera::ORTHOGRAPHIC : - if (drawFarPlane) - { - glBegin(GL_LINES); - glVertex3d( points[0].x, points[0].y, -points[0].z); - glVertex3d( points[1].x, points[1].y, -points[1].z); - glVertex3d(-points[0].x, points[0].y, -points[0].z); - glVertex3d(-points[1].x, points[1].y, -points[1].z); - glVertex3d(-points[0].x, -points[0].y, -points[0].z); - glVertex3d(-points[1].x, -points[1].y, -points[1].z); - glVertex3d( points[0].x, -points[0].y, -points[0].z); - glVertex3d( points[1].x, -points[1].y, -points[1].z); - glEnd(); - } - } - - glPopMatrix(); -} +\note The drawing of a QGLViewer's own QGLViewer::camera() should not be +visible, but may create artefacts due to numerical imprecisions. */ +void Camera::draw(bool drawFarPlane, qreal scale) const { + glPushMatrix(); + glMultMatrixd(frame()->worldMatrix()); + + // 0 is the upper left coordinates of the near corner, 1 for the far one + Vec points[2]; + points[0].z = scale * zNear(); + points[1].z = scale * zFar(); + + switch (type()) { + case Camera::PERSPECTIVE: { + points[0].y = points[0].z * tan(fieldOfView() / 2.0); + points[0].x = points[0].y * aspectRatio(); + + const qreal ratio = points[1].z / points[0].z; + + points[1].y = ratio * points[0].y; + points[1].x = ratio * points[0].x; + break; + } + case Camera::ORTHOGRAPHIC: { + GLdouble hw, hh; + getOrthoWidthHeight(hw, hh); + points[0].x = points[1].x = scale * qreal(hw); + points[0].y = points[1].y = scale * qreal(hh); + break; + } + } + + const int farIndex = drawFarPlane ? 1 : 0; + + // Near and (optionally) far plane(s) + glBegin(GL_QUADS); + for (int i = farIndex; i >= 0; --i) { + glNormal3d(0.0f, 0.0f, (i == 0) ? 1.0f : -1.0f); + glVertex3d(points[i].x, points[i].y, -points[i].z); + glVertex3d(-points[i].x, points[i].y, -points[i].z); + glVertex3d(-points[i].x, -points[i].y, -points[i].z); + glVertex3d(points[i].x, -points[i].y, -points[i].z); + } + glEnd(); + + // Up arrow + const qreal arrowHeight = 1.5 * points[0].y; + const qreal baseHeight = 1.2 * points[0].y; + const qreal arrowHalfWidth = 0.5 * points[0].x; + const qreal baseHalfWidth = 0.3 * points[0].x; + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + // Base + glBegin(GL_QUADS); + glVertex3d(-baseHalfWidth, points[0].y, -points[0].z); + glVertex3d(baseHalfWidth, points[0].y, -points[0].z); + glVertex3d(baseHalfWidth, baseHeight, -points[0].z); + glVertex3d(-baseHalfWidth, baseHeight, -points[0].z); + glEnd(); + + // Arrow + glBegin(GL_TRIANGLES); + glVertex3d(0.0, arrowHeight, -points[0].z); + glVertex3d(-arrowHalfWidth, baseHeight, -points[0].z); + glVertex3d(arrowHalfWidth, baseHeight, -points[0].z); + glEnd(); + + // Frustum lines + switch (type()) { + case Camera::PERSPECTIVE: + glBegin(GL_LINES); + glVertex3d(0.0, 0.0, 0.0); + glVertex3d(points[farIndex].x, points[farIndex].y, -points[farIndex].z); + glVertex3d(0.0, 0.0, 0.0); + glVertex3d(-points[farIndex].x, points[farIndex].y, -points[farIndex].z); + glVertex3d(0.0, 0.0, 0.0); + glVertex3d(-points[farIndex].x, -points[farIndex].y, -points[farIndex].z); + glVertex3d(0.0, 0.0, 0.0); + glVertex3d(points[farIndex].x, -points[farIndex].y, -points[farIndex].z); + glEnd(); + break; + case Camera::ORTHOGRAPHIC: + if (drawFarPlane) { + glBegin(GL_LINES); + glVertex3d(points[0].x, points[0].y, -points[0].z); + glVertex3d(points[1].x, points[1].y, -points[1].z); + glVertex3d(-points[0].x, points[0].y, -points[0].z); + glVertex3d(-points[1].x, points[1].y, -points[1].z); + glVertex3d(-points[0].x, -points[0].y, -points[0].z); + glVertex3d(-points[1].x, -points[1].y, -points[1].z); + glVertex3d(points[0].x, -points[0].y, -points[0].z); + glVertex3d(points[1].x, -points[1].y, -points[1].z); + glEnd(); + } + } + + glPopMatrix(); +} /*! Returns the 6 plane equations of the Camera frustum. -The six 4-component vectors of \p coef respectively correspond to the left, right, near, far, top -and bottom Camera frustum planes. Each vector holds a plane equation of the form: -\code -a*x + b*y + c*z + d = 0 -\endcode -where \c a, \c b, \c c and \c d are the 4 components of each vector, in that order. +The six 4-component vectors of \p coef respectively correspond to the left, +right, near, far, top and bottom Camera frustum planes. Each vector holds a +plane equation of the form: \code a*x + b*y + c*z + d = 0 \endcode where \c a, +\c b, \c c and \c d are the 4 components of each vector, in that order. -See the frustumCulling example for an application. +See the frustumCulling example for +an application. -This format is compatible with the \c glClipPlane() function. One camera frustum plane can hence be -applied in an other viewer to visualize the culling results: +This format is compatible with the \c glClipPlane() function. One camera frustum +plane can hence be applied in an other viewer to visualize the culling results: \code // Retrieve plane equations GLdouble coef[6][4]; @@ -2118,92 +2173,89 @@ applied in an other viewer to visualize the culling results: glClipPlane(GL_CLIP_PLANE0, coef[2]); glClipPlane(GL_CLIP_PLANE1, coef[3]); \endcode */ -void Camera::getFrustumPlanesCoefficients(GLdouble coef[6][4]) const -{ - // Computed once and for all - const Vec pos = position(); - const Vec viewDir = viewDirection(); - const Vec up = upVector(); - const Vec right = rightVector(); - const qreal posViewDir = pos * viewDir; - - static Vec normal[6]; - static GLdouble dist[6]; - - switch (type()) - { - case Camera::PERSPECTIVE : - { - const qreal hhfov = horizontalFieldOfView() / 2.0; - const qreal chhfov = cos(hhfov); - const qreal shhfov = sin(hhfov); - normal[0] = - shhfov * viewDir; - normal[1] = normal[0] + chhfov * right; - normal[0] = normal[0] - chhfov * right; - - normal[2] = -viewDir; - normal[3] = viewDir; - - const qreal hfov = fieldOfView() / 2.0; - const qreal chfov = cos(hfov); - const qreal shfov = sin(hfov); - normal[4] = - shfov * viewDir; - normal[5] = normal[4] - chfov * up; - normal[4] = normal[4] + chfov * up; - - for (int i=0; i<2; ++i) - dist[i] = pos * normal[i]; - for (int j=4; j<6; ++j) - dist[j] = pos * normal[j]; - - // Natural equations are: - // dist[0,1,4,5] = pos * normal[0,1,4,5]; - // dist[2] = (pos + zNear() * viewDir) * normal[2]; - // dist[3] = (pos + zFar() * viewDir) * normal[3]; - - // 2 times less computations using expanded/merged equations. Dir vectors are normalized. - const qreal posRightCosHH = chhfov * pos * right; - dist[0] = -shhfov * posViewDir; - dist[1] = dist[0] + posRightCosHH; - dist[0] = dist[0] - posRightCosHH; - const qreal posUpCosH = chfov * pos * up; - dist[4] = - shfov * posViewDir; - dist[5] = dist[4] - posUpCosH; - dist[4] = dist[4] + posUpCosH; - - break; - } - case Camera::ORTHOGRAPHIC : - normal[0] = -right; - normal[1] = right; - normal[4] = up; - normal[5] = -up; - - GLdouble hw, hh; - getOrthoWidthHeight(hw, hh); - dist[0] = (pos - hw * right) * normal[0]; - dist[1] = (pos + hw * right) * normal[1]; - dist[4] = (pos + hh * up) * normal[4]; - dist[5] = (pos - hh * up) * normal[5]; - break; - } - - // Front and far planes are identical for both camera types. - normal[2] = -viewDir; - normal[3] = viewDir; - dist[2] = -posViewDir - zNear(); - dist[3] = posViewDir + zFar(); - - for (int i=0; i<6; ++i) - { - coef[i][0] = GLdouble(normal[i].x); - coef[i][1] = GLdouble(normal[i].y); - coef[i][2] = GLdouble(normal[i].z); - coef[i][3] = dist[i]; - } +void Camera::getFrustumPlanesCoefficients(GLdouble coef[6][4]) const { + // Computed once and for all + const Vec pos = position(); + const Vec viewDir = viewDirection(); + const Vec up = upVector(); + const Vec right = rightVector(); + const qreal posViewDir = pos * viewDir; + + static Vec normal[6]; + static GLdouble dist[6]; + + switch (type()) { + case Camera::PERSPECTIVE: { + const qreal hhfov = horizontalFieldOfView() / 2.0; + const qreal chhfov = cos(hhfov); + const qreal shhfov = sin(hhfov); + normal[0] = -shhfov * viewDir; + normal[1] = normal[0] + chhfov * right; + normal[0] = normal[0] - chhfov * right; + + normal[2] = -viewDir; + normal[3] = viewDir; + + const qreal hfov = fieldOfView() / 2.0; + const qreal chfov = cos(hfov); + const qreal shfov = sin(hfov); + normal[4] = -shfov * viewDir; + normal[5] = normal[4] - chfov * up; + normal[4] = normal[4] + chfov * up; + + for (int i = 0; i < 2; ++i) + dist[i] = pos * normal[i]; + for (int j = 4; j < 6; ++j) + dist[j] = pos * normal[j]; + + // Natural equations are: + // dist[0,1,4,5] = pos * normal[0,1,4,5]; + // dist[2] = (pos + zNear() * viewDir) * normal[2]; + // dist[3] = (pos + zFar() * viewDir) * normal[3]; + + // 2 times less computations using expanded/merged equations. Dir vectors + // are normalized. + const qreal posRightCosHH = chhfov * pos * right; + dist[0] = -shhfov * posViewDir; + dist[1] = dist[0] + posRightCosHH; + dist[0] = dist[0] - posRightCosHH; + const qreal posUpCosH = chfov * pos * up; + dist[4] = -shfov * posViewDir; + dist[5] = dist[4] - posUpCosH; + dist[4] = dist[4] + posUpCosH; + + break; + } + case Camera::ORTHOGRAPHIC: + normal[0] = -right; + normal[1] = right; + normal[4] = up; + normal[5] = -up; + + GLdouble hw, hh; + getOrthoWidthHeight(hw, hh); + dist[0] = (pos - hw * right) * normal[0]; + dist[1] = (pos + hw * right) * normal[1]; + dist[4] = (pos + hh * up) * normal[4]; + dist[5] = (pos - hh * up) * normal[5]; + break; + } + + // Front and far planes are identical for both camera types. + normal[2] = -viewDir; + normal[3] = viewDir; + dist[2] = -posViewDir - zNear(); + dist[3] = posViewDir + zFar(); + + for (int i = 0; i < 6; ++i) { + coef[i][0] = GLdouble(normal[i].x); + coef[i][1] = GLdouble(normal[i].y); + coef[i][2] = GLdouble(normal[i].z); + coef[i][3] = dist[i]; + } } void Camera::onFrameModified() { - projectionMatrixIsUpToDate_ = false; - modelViewMatrixIsUpToDate_ = false; + projectionMatrixIsUpToDate_ = false; + modelViewMatrixIsUpToDate_ = false; } diff --git a/octovis/src/extern/QGLViewer/camera.h b/octovis/src/extern/QGLViewer/camera.h index 4657f952..5555b1ab 100644 --- a/octovis/src/extern/QGLViewer/camera.h +++ b/octovis/src/extern/QGLViewer/camera.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,10 +19,10 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_CAMERA_H #define QGLVIEWER_CAMERA_H +#include #include "keyFrameInterpolator.h" class QGLViewer; @@ -33,478 +33,535 @@ class ManipulatedCameraFrame; /*! \brief A perspective or orthographic camera. \class Camera camera.h QGLViewer/camera.h - A Camera defines some intrinsic parameters (fieldOfView(), position(), viewDirection(), - upVector()...) and useful positioning tools that ease its placement (showEntireScene(), - fitSphere(), lookAt()...). It exports its associated OpenGL projection and modelview matrices and - can interactively be modified using the mouse. + A Camera defines some intrinsic parameters (fieldOfView(), position(), + viewDirection(), upVector()...) and useful positioning tools that ease its + placement (showEntireScene(), fitSphere(), lookAt()...). It exports its + associated OpenGL projection and modelview matrices and can interactively be + modified using the mouse.

Mouse manipulation

- The position() and orientation() of the Camera are defined by a ManipulatedCameraFrame (retrieved - using frame()). These methods are just convenient wrappers to the equivalent Frame methods. This - also means that the Camera frame() can be attached to a Frame::referenceFrame() which enables + The position() and orientation() of the Camera are defined by a + ManipulatedCameraFrame (retrieved using frame()). These methods are just + convenient wrappers to the equivalent Frame methods. This also means that the + Camera frame() can be attached to a Frame::referenceFrame() which enables complex Camera setups. - Different displacements can be performed using the mouse. The list of possible actions is defined - by the QGLViewer::MouseAction enum. Use QGLViewer::setMouseBinding() to attach a specific action - to an arbitrary mouse button-state key binding. These actions are detailed in the mouse page. - The default button binding are: QGLViewer::ROTATE (left), QGLViewer::ZOOM (middle) and - QGLViewer::TRANSLATE (right). With this configuration, the Camera \e observes a scene and rotates - around its pivotPoint(). You can switch between this mode and a fly mode using the - QGLViewer::CAMERA_MODE (see QGLViewer::toggleCameraMode()) keyboard shortcut (default is 'Space'). + The default button binding are: QGLViewer::ROTATE (left), QGLViewer::ZOOM + (middle) and QGLViewer::TRANSLATE (right). With this configuration, the Camera + \e observes a scene and rotates around its pivotPoint(). You can switch + between this mode and a fly mode using the QGLViewer::CAMERA_MODE (see + QGLViewer::toggleCameraMode()) keyboard shortcut (default is 'Space').

Other functionalities

- The type() of the Camera can be Camera::ORTHOGRAPHIC or Camera::PERSPECTIVE (see Type()). - fieldOfView() is meaningless with Camera::ORTHOGRAPHIC. + The type() of the Camera can be Camera::ORTHOGRAPHIC or Camera::PERSPECTIVE + (see Type()). fieldOfView() is meaningless with Camera::ORTHOGRAPHIC. - The near and far planes of the Camera are fitted to the scene and determined from - QGLViewer::sceneRadius(), QGLViewer::sceneCenter() and zClippingCoefficient() by the zNear() and - zFar() methods. Reasonable values on the scene extends hence have to be provided to the QGLViewer - in order for the Camera to correctly display the scene. High level positioning methods also use + The near and far planes of the Camera are fitted to the scene and determined + from QGLViewer::sceneRadius(), QGLViewer::sceneCenter() and + zClippingCoefficient() by the zNear() and zFar() methods. Reasonable values on + the scene extends hence have to be provided to the QGLViewer in order for the + Camera to correctly display the scene. High level positioning methods also use this information (showEntireScene(), centerScene()...). - A Camera holds KeyFrameInterpolator that can be used to save Camera positions and paths. You can - interactively addKeyFrameToPath() to a given path using the default \c Alt+F[1-12] shortcuts. Use - playPath() to make the Camera follow the path (default shortcut is F[1-12]). See the keyboard page for details on key customization. - Use cameraCoordinatesOf() and worldCoordinatesOf() to convert to and from the Camera frame() - coordinate system. projectedCoordinatesOf() and unprojectedCoordinatesOf() will convert from - screen to 3D coordinates. convertClickToLine() is very useful for analytical object selection. + Use cameraCoordinatesOf() and worldCoordinatesOf() to convert to and from the + Camera frame() coordinate system. projectedCoordinatesOf() and + unprojectedCoordinatesOf() will convert from screen to 3D coordinates. + convertClickToLine() is very useful for analytical object selection. - Stereo display is possible on machines with quad buffer capabilities (with Camera::PERSPECTIVE - type() only). Test the stereoViewer example to check. + Stereo display is possible on machines with quad buffer capabilities (with + Camera::PERSPECTIVE type() only). Test the stereoViewer example to check. - A Camera can also be used outside of a QGLViewer or even without OpenGL for its coordinate system - conversion capabilities. Note however that some of them explicitly rely on the presence of a - Z-buffer. \nosubgrouping */ -class QGLVIEWER_EXPORT Camera : public QObject -{ + A Camera can also be used outside of a QGLViewer or even without OpenGL for + its coordinate system conversion capabilities. Note however that some of them + explicitly rely on the presence of a Z-buffer. \nosubgrouping */ +class QGLVIEWER_EXPORT Camera : public QObject { #ifndef DOXYGEN - friend class ::QGLViewer; + friend class ::QGLViewer; #endif - Q_OBJECT + Q_OBJECT public: - Camera(); - virtual ~Camera(); - - Camera(const Camera& camera); - Camera& operator=(const Camera& camera); + Camera(); + virtual ~Camera(); + Camera(const Camera &camera); + Camera &operator=(const Camera &camera); - /*! Enumerates the two possible types of Camera. + /*! Enumerates the two possible types of Camera. - See type() and setType(). This type mainly defines different Camera projection matrix (see - loadProjectionMatrix()). Many other methods (pointUnderPixel(), convertClickToLine(), - projectedCoordinatesOf(), pixelGLRatio()...) are affected by this Type. */ - enum Type { PERSPECTIVE, ORTHOGRAPHIC }; + See type() and setType(). This type mainly defines different Camera projection + matrix (see loadProjectionMatrix()). Many other methods (pointUnderPixel(), + convertClickToLine(), projectedCoordinatesOf(), pixelGLRatio()...) are + affected by this Type. */ + enum Type { PERSPECTIVE, ORTHOGRAPHIC }; - /*! @name Position and orientation */ - //@{ + /*! @name Position and orientation */ + //@{ public: - Vec position() const; - Vec upVector() const; - Vec viewDirection() const; - Vec rightVector() const; - Quaternion orientation() const; + Vec position() const; + Vec upVector() const; + Vec viewDirection() const; + Vec rightVector() const; + Quaternion orientation() const; - void setFromModelViewMatrix(const GLdouble* const modelViewMatrix); - void setFromProjectionMatrix(const qreal matrix[12]); + void setFromModelViewMatrix(const GLdouble *const modelViewMatrix); + void setFromProjectionMatrix(const qreal matrix[12]); public Q_SLOTS: - void setPosition(const Vec& pos); - void setOrientation(const Quaternion& q); - void setOrientation(qreal theta, qreal phi); - void setUpVector(const Vec& up, bool noMove=true); - void setViewDirection(const Vec& direction); - //@} - - - /*! @name Positioning tools */ - //@{ + void setPosition(const Vec &pos); + void setOrientation(const Quaternion &q); + void setOrientation(qreal theta, qreal phi); + void setUpVector(const Vec &up, bool noMove = true); + void setViewDirection(const Vec &direction); + //@} + + /*! @name Positioning tools */ + //@{ public Q_SLOTS: - void lookAt(const Vec& target); - void showEntireScene(); - void fitSphere(const Vec& center, qreal radius); - void fitBoundingBox(const Vec& min, const Vec& max); - void fitScreenRegion(const QRect& rectangle); - void centerScene(); - void interpolateToZoomOnPixel(const QPoint& pixel); - void interpolateToFitScene(); - void interpolateTo(const Frame& fr, qreal duration); - //@} - - - /*! @name Frustum */ - //@{ + void lookAt(const Vec &target); + void showEntireScene(); + void fitSphere(const Vec ¢er, qreal radius); + void fitBoundingBox(const Vec &min, const Vec &max); + void fitScreenRegion(const QRect &rectangle); + void centerScene(); + void interpolateToZoomOnPixel(const QPoint &pixel); + void interpolateToFitScene(); + void interpolateTo(const Frame &fr, qreal duration); + //@} + + /*! @name Frustum */ + //@{ public: - /*! Returns the Camera::Type of the Camera. - - Set by setType(). Mainly used by loadProjectionMatrix(). - - A Camera::PERSPECTIVE Camera uses a classical projection mainly defined by its fieldOfView(). - - With a Camera::ORTHOGRAPHIC type(), the fieldOfView() is meaningless and the width and height of - the Camera frustum are inferred from the distance to the pivotPoint() using - getOrthoWidthHeight(). + /*! Returns the Camera::Type of the Camera. - Both types use zNear() and zFar() (to define their clipping planes) and aspectRatio() (for - frustum shape). */ - Type type() const { return type_; } + Set by setType(). Mainly used by loadProjectionMatrix(). - /*! Returns the vertical field of view of the Camera (in radians). + A Camera::PERSPECTIVE Camera uses a classical projection mainly defined by its + fieldOfView(). - Value is set using setFieldOfView(). Default value is pi/4 radians. This value is meaningless if - the Camera type() is Camera::ORTHOGRAPHIC. + With a Camera::ORTHOGRAPHIC type(), the fieldOfView() is meaningless and the + width and height of the Camera frustum are inferred from the distance to the + pivotPoint() using getOrthoWidthHeight(). - The field of view corresponds the one used in \c gluPerspective (see manual). It sets the Y - (vertical) aperture of the Camera. The X (horizontal) angle is inferred from the window aspect - ratio (see aspectRatio() and horizontalFieldOfView()). + Both types use zNear() and zFar() (to define their clipping planes) and + aspectRatio() (for frustum shape). */ + Type type() const { return type_; } - Use setFOVToFitScene() to adapt the fieldOfView() to a given scene. */ - qreal fieldOfView() const { return fieldOfView_; } + /*! Returns the vertical field of view of the Camera (in radians). - /*! Returns the horizontal field of view of the Camera (in radians). + Value is set using setFieldOfView(). Default value is pi/4 radians. This value + is meaningless if the Camera type() is Camera::ORTHOGRAPHIC. - Value is set using setHorizontalFieldOfView() or setFieldOfView(). These values - are always linked by: - \code - horizontalFieldOfView() = 2.0 * atan ( tan(fieldOfView()/2.0) * aspectRatio() ). - \endcode */ - qreal horizontalFieldOfView() const { return 2.0 * atan ( tan(fieldOfView()/2.0) * aspectRatio() ); } + The field of view corresponds the one used in \c gluPerspective (see manual). + It sets the Y (vertical) aperture of the Camera. The X (horizontal) angle is + inferred from the window aspect ratio (see aspectRatio() and + horizontalFieldOfView()). - /*! Returns the Camera aspect ratio defined by screenWidth() / screenHeight(). + Use setFOVToFitScene() to adapt the fieldOfView() to a given scene. */ + qreal fieldOfView() const { return fieldOfView_; } - When the Camera is attached to a QGLViewer, these values and hence the aspectRatio() are - automatically fitted to the viewer's window aspect ratio using setScreenWidthAndHeight(). */ - qreal aspectRatio() const { return screenWidth_ / static_cast(screenHeight_); } - /*! Returns the width (in pixels) of the Camera screen. + /*! Returns the horizontal field of view of the Camera (in radians). - Set using setScreenWidthAndHeight(). This value is automatically fitted to the QGLViewer's - window dimensions when the Camera is attached to a QGLViewer. See also QGLWidget::width() */ - int screenWidth() const { return screenWidth_; } - /*! Returns the height (in pixels) of the Camera screen. + Value is set using setHorizontalFieldOfView() or setFieldOfView(). These + values are always linked by: \code horizontalFieldOfView() = 2.0 * atan ( + tan(fieldOfView()/2.0) * aspectRatio() ). \endcode */ + qreal horizontalFieldOfView() const { + return 2.0 * atan(tan(fieldOfView() / 2.0) * aspectRatio()); + } - Set using setScreenWidthAndHeight(). This value is automatically fitted to the QGLViewer's - window dimensions when the Camera is attached to a QGLViewer. See also QGLWidget::height() */ - int screenHeight() const { return screenHeight_; } - void getViewport(GLint viewport[4]) const; - qreal pixelGLRatio(const Vec& position) const; + /*! Returns the Camera aspect ratio defined by screenWidth() / screenHeight(). - /*! Returns the coefficient which is used to set zNear() when the Camera is inside the sphere - defined by sceneCenter() and zClippingCoefficient() * sceneRadius(). + When the Camera is attached to a QGLViewer, these values and hence the + aspectRatio() are automatically fitted to the viewer's window aspect ratio + using setScreenWidthAndHeight(). */ + qreal aspectRatio() const { + return screenWidth_ / static_cast(screenHeight_); + } + /*! Returns the width (in pixels) of the Camera screen. - In that case, the zNear() value is set to zNearCoefficient() * zClippingCoefficient() * - sceneRadius(). See the zNear() documentation for details. + Set using setScreenWidthAndHeight(). This value is automatically fitted to the + QGLViewer's window dimensions when the Camera is attached to a QGLViewer. See + also QOpenGLWidget::width() */ + int screenWidth() const { return screenWidth_; } + /*! Returns the height (in pixels) of the Camera screen. - Default value is 0.005, which is appropriate for most applications. In case you need a high - dynamic ZBuffer precision, you can increase this value (~0.1). A lower value will prevent - clipping of very close objects at the expense of a worst Z precision. + Set using setScreenWidthAndHeight(). This value is automatically fitted to the + QGLViewer's window dimensions when the Camera is attached to a QGLViewer. See + also QOpenGLWidget::height() */ + int screenHeight() const { return screenHeight_; } - Only meaningful when Camera type is Camera::PERSPECTIVE. */ - qreal zNearCoefficient() const { return zNearCoef_; } - /*! Returns the coefficient used to position the near and far clipping planes. + /*! Returns the pixel ratio (physical to device independent pixel ratio) of the + Camera screen. - The near (resp. far) clipping plane is positioned at a distance equal to zClippingCoefficient() * - sceneRadius() in front of (resp. behind) the sceneCenter(). This garantees an optimal use of - the z-buffer range and minimizes aliasing. See the zNear() and zFar() documentations. + Set using setDevicePixelRatio(). Defaults to 1.0. - Default value is square root of 3.0 (so that a cube of size sceneRadius() is not clipped). + This value is automatically fitted to the QGLViewer's screen pixel ratio when the + Camera is attached to a QGLViewer. See also QWindow::devicePixelRatio() */ + qreal devicePixelRatio() const { return devicePixelRatio_; } - However, since the sceneRadius() is used for other purposes (see showEntireScene(), flySpeed(), - ...) and you may want to change this value to define more precisely the location of the clipping - planes. See also zNearCoefficient(). + void getViewport(GLint viewport[4]) const; + qreal pixelGLRatio(const Vec &position) const; - For a total control on clipping planes' positions, an other option is to overload the zNear() - and zFar() methods. See the standardCamera example. + /*! Returns the coefficient which is used to set zNear() when the Camera is + inside the sphere defined by sceneCenter() and zClippingCoefficient() * + sceneRadius(). - \attention When QGLViewer::cameraPathAreEdited(), this value is set to 5.0 so that the Camera - paths are not clipped. The previous zClippingCoefficient() value is restored back when you leave - this mode. */ - qreal zClippingCoefficient() const { return zClippingCoef_; } + In that case, the zNear() value is set to zNearCoefficient() * + zClippingCoefficient() * sceneRadius(). See the zNear() documentation for + details. - virtual qreal zNear() const; - virtual qreal zFar() const; - virtual void getOrthoWidthHeight(GLdouble& halfWidth, GLdouble& halfHeight) const; - void getFrustumPlanesCoefficients(GLdouble coef[6][4]) const; + Default value is 0.005, which is appropriate for most applications. In case + you need a high dynamic ZBuffer precision, you can increase this value (~0.1). + A lower value will prevent clipping of very close objects at the expense of a + worst Z precision. -public Q_SLOTS: - void setType(Type type); - - void setFieldOfView(qreal fov); - - /*! Sets the horizontalFieldOfView() of the Camera (in radians). - - horizontalFieldOfView() and fieldOfView() are linked by the aspectRatio(). This method actually - calls setFieldOfView(( 2.0 * atan (tan(hfov / 2.0) / aspectRatio()) )) so that a call to - horizontalFieldOfView() returns the expected value. */ - void setHorizontalFieldOfView(qreal hfov) { setFieldOfView( 2.0 * atan (tan(hfov / 2.0) / aspectRatio()) ); } + Only meaningful when Camera type is Camera::PERSPECTIVE. */ + qreal zNearCoefficient() const { return zNearCoef_; } + /*! Returns the coefficient used to position the near and far clipping planes. - void setFOVToFitScene(); + The near (resp. far) clipping plane is positioned at a distance equal to + zClippingCoefficient() * sceneRadius() in front of (resp. behind) the + sceneCenter(). This garantees an optimal use of the z-buffer range and + minimizes aliasing. See the zNear() and zFar() documentations. - /*! Defines the Camera aspectRatio(). + Default value is square root of 3.0 (so that a cube of size sceneRadius() is + not clipped). - This value is actually inferred from the screenWidth() / screenHeight() ratio. You should use - setScreenWidthAndHeight() instead. + However, since the sceneRadius() is used for other purposes (see + showEntireScene(), flySpeed(), + ...) and you may want to change this value to define more precisely the + location of the clipping planes. See also zNearCoefficient(). - This method might however be convenient when the Camera is not associated with a QGLViewer. It - actually sets the screenHeight() to 100 and the screenWidth() accordingly. See also - setFOVToFitScene(). + For a total control on clipping planes' positions, an other option is to + overload the zNear() and zFar() methods. See the standardCamera example. - \note If you absolutely need an aspectRatio() that does not correspond to your viewer's window - dimensions, overload loadProjectionMatrix() or multiply the created GL_PROJECTION matrix by a - scaled diagonal matrix in your QGLViewer::draw() method. */ - void setAspectRatio(qreal aspect) { setScreenWidthAndHeight(int(100.0*aspect), 100); } + \attention When QGLViewer::cameraPathAreEdited(), this value is set to 5.0 so + that the Camera paths are not clipped. The previous zClippingCoefficient() + value is restored back when you leave this mode. */ + qreal zClippingCoefficient() const { return zClippingCoef_; } - void setScreenWidthAndHeight(int width, int height); - /*! Sets the zNearCoefficient() value. */ - void setZNearCoefficient(qreal coef) { zNearCoef_ = coef; projectionMatrixIsUpToDate_ = false; } - /*! Sets the zClippingCoefficient() value. */ - void setZClippingCoefficient(qreal coef) { zClippingCoef_ = coef; projectionMatrixIsUpToDate_ = false; } - //@} + virtual qreal zNear() const; + virtual qreal zFar() const; + virtual void getOrthoWidthHeight(GLdouble &halfWidth, + GLdouble &halfHeight) const; + void getFrustumPlanesCoefficients(GLdouble coef[6][4]) const; - - /*! @name Scene radius and center */ - //@{ +public Q_SLOTS: + void setType(Type type); + + void setFieldOfView(qreal fov); + + /*! Sets the horizontalFieldOfView() of the Camera (in radians). + + horizontalFieldOfView() and fieldOfView() are linked by the aspectRatio(). + This method actually calls setFieldOfView(( 2.0 * atan (tan(hfov / 2.0) / + aspectRatio()) )) so that a call to horizontalFieldOfView() returns the + expected value. */ + void setHorizontalFieldOfView(qreal hfov) { + setFieldOfView(2.0 * atan(tan(hfov / 2.0) / aspectRatio())); + } + + void setFOVToFitScene(); + + /*! Defines the Camera aspectRatio(). + + This value is actually inferred from the screenWidth() / screenHeight() ratio. + You should use setScreenWidthAndHeight() instead. + + This method might however be convenient when the Camera is not associated with + a QGLViewer. It actually sets the screenHeight() to 100 and the screenWidth() + accordingly. See also setFOVToFitScene(). + + \note If you absolutely need an aspectRatio() that does not correspond to your + viewer's window dimensions, overload loadProjectionMatrix() or multiply the + created GL_PROJECTION matrix by a scaled diagonal matrix in your + QGLViewer::draw() method. */ + void setAspectRatio(qreal aspect) { + setScreenWidthAndHeight(int(100.0 * aspect), 100); + } + + void setScreenWidthAndHeight(int width, int height); + void setDevicePixelRatio(qreal ratio); + + /*! Sets the zNearCoefficient() value. */ + void setZNearCoefficient(qreal coef) { + zNearCoef_ = coef; + projectionMatrixIsUpToDate_ = false; + } + /*! Sets the zClippingCoefficient() value. */ + void setZClippingCoefficient(qreal coef) { + zClippingCoef_ = coef; + projectionMatrixIsUpToDate_ = false; + } + //@} + + /*! @name Scene radius and center */ + //@{ public: - /*! Returns the radius of the scene observed by the Camera. + /*! Returns the radius of the scene observed by the Camera. - You need to provide such an approximation of the scene dimensions so that the Camera can adapt - its zNear() and zFar() values. See the sceneCenter() documentation. + You need to provide such an approximation of the scene dimensions so that the + Camera can adapt its zNear() and zFar() values. See the sceneCenter() + documentation. - See also setSceneBoundingBox(). + See also setSceneBoundingBox(). - Note that QGLViewer::sceneRadius() (resp. QGLViewer::setSceneRadius()) simply call this method - (resp. setSceneRadius()) on its associated QGLViewer::camera(). */ - qreal sceneRadius() const { return sceneRadius_; } + Note that QGLViewer::sceneRadius() (resp. QGLViewer::setSceneRadius()) simply + call this method (resp. setSceneRadius()) on its associated + QGLViewer::camera(). */ + qreal sceneRadius() const { return sceneRadius_; } - /*! Returns the position of the scene center, defined in the world coordinate system. + /*! Returns the position of the scene center, defined in the world coordinate + system. - The scene observed by the Camera should be roughly centered on this position, and included in a - sceneRadius() sphere. This approximate description of the scene permits a zNear() and zFar() - clipping planes definition, and allows convenient positioning methods such as showEntireScene(). + The scene observed by the Camera should be roughly centered on this position, + and included in a sceneRadius() sphere. This approximate description of the + scene permits a zNear() and zFar() clipping planes definition, and allows + convenient positioning methods such as showEntireScene(). - Default value is (0,0,0) (world origin). Use setSceneCenter() to change it. See also - setSceneBoundingBox(). + Default value is (0,0,0) (world origin). Use setSceneCenter() to change it. + See also setSceneBoundingBox(). - Note that QGLViewer::sceneCenter() (resp. QGLViewer::setSceneCenter()) simply calls this method - (resp. setSceneCenter()) on its associated QGLViewer::camera(). */ - Vec sceneCenter() const { return sceneCenter_; } - qreal distanceToSceneCenter() const; + Note that QGLViewer::sceneCenter() (resp. QGLViewer::setSceneCenter()) simply + calls this method (resp. setSceneCenter()) on its associated + QGLViewer::camera(). */ + Vec sceneCenter() const { return sceneCenter_; } + qreal distanceToSceneCenter() const; public Q_SLOTS: - void setSceneRadius(qreal radius); - void setSceneCenter(const Vec& center); - bool setSceneCenterFromPixel(const QPoint& pixel); - void setSceneBoundingBox(const Vec& min, const Vec& max); - //@} - - - /*! @name Pivot Point */ - //@{ + void setSceneRadius(qreal radius); + void setSceneCenter(const Vec ¢er); + bool setSceneCenterFromPixel(const QPoint &pixel); + void setSceneBoundingBox(const Vec &min, const Vec &max); + //@} + + /*! @name Pivot Point */ + //@{ public Q_SLOTS: - void setPivotPoint(const Vec& point); - bool setPivotPointFromPixel(const QPoint& pixel); + void setPivotPoint(const Vec &point); + bool setPivotPointFromPixel(const QPoint &pixel); public: - Vec pivotPoint() const; + Vec pivotPoint() const; #ifndef DOXYGEN public Q_SLOTS: - void setRevolveAroundPoint(const Vec& point); - bool setRevolveAroundPointFromPixel(const QPoint& pixel); + void setRevolveAroundPoint(const Vec &point); + bool setRevolveAroundPointFromPixel(const QPoint &pixel); + public: - Vec revolveAroundPoint() const; + Vec revolveAroundPoint() const; #endif - //@} + //@} - - /*! @name Associated frame */ - //@{ + /*! @name Associated frame */ + //@{ public: - /*! Returns the ManipulatedCameraFrame attached to the Camera. + /*! Returns the ManipulatedCameraFrame attached to the Camera. - This ManipulatedCameraFrame defines its position() and orientation() and can translate mouse - events into Camera displacement. Set using setFrame(). */ - ManipulatedCameraFrame* frame() const { return frame_; } + This ManipulatedCameraFrame defines its position() and orientation() and can + translate mouse events into Camera displacement. Set using setFrame(). */ + ManipulatedCameraFrame *frame() const { return frame_; } public Q_SLOTS: - void setFrame(ManipulatedCameraFrame* const mcf); - //@} - + void setFrame(ManipulatedCameraFrame *const mcf); + //@} - /*! @name KeyFramed paths */ - //@{ + /*! @name KeyFramed paths */ + //@{ public: - KeyFrameInterpolator* keyFrameInterpolator(unsigned int i) const; + KeyFrameInterpolator *keyFrameInterpolator(unsigned int i) const; public Q_SLOTS: - void setKeyFrameInterpolator(unsigned int i, KeyFrameInterpolator* const kfi); + void setKeyFrameInterpolator(unsigned int i, KeyFrameInterpolator *const kfi); - virtual void addKeyFrameToPath(unsigned int i); - virtual void playPath(unsigned int i); - virtual void deletePath(unsigned int i); - virtual void resetPath(unsigned int i); - virtual void drawAllPaths(); - //@} + virtual void addKeyFrameToPath(unsigned int i); + virtual void playPath(unsigned int i); + virtual void deletePath(unsigned int i); + virtual void resetPath(unsigned int i); + virtual void drawAllPaths(); + //@} - - /*! @name OpenGL matrices */ - //@{ + /*! @name OpenGL matrices */ + //@{ public: - virtual void loadProjectionMatrix(bool reset=true) const; - virtual void loadModelViewMatrix(bool reset=true) const; - void computeProjectionMatrix() const; - void computeModelViewMatrix() const; - - virtual void loadProjectionMatrixStereo(bool leftBuffer=true) const; - virtual void loadModelViewMatrixStereo(bool leftBuffer=true) const; + virtual void loadProjectionMatrix(bool reset = true) const; + virtual void loadModelViewMatrix(bool reset = true) const; + void computeProjectionMatrix() const; + void computeModelViewMatrix() const; - void getProjectionMatrix(GLfloat m[16]) const; - void getProjectionMatrix(GLdouble m[16]) const; + virtual void loadProjectionMatrixStereo(bool leftBuffer = true) const; + virtual void loadModelViewMatrixStereo(bool leftBuffer = true) const; - void getModelViewMatrix(GLfloat m[16]) const; - void getModelViewMatrix(GLdouble m[16]) const; + void getProjectionMatrix(GLfloat m[16]) const; + void getProjectionMatrix(GLdouble m[16]) const; - void getModelViewProjectionMatrix(GLfloat m[16]) const; - void getModelViewProjectionMatrix(GLdouble m[16]) const; - //@} + void getModelViewMatrix(GLfloat m[16]) const; + void getModelViewMatrix(GLdouble m[16]) const; + void getModelViewProjectionMatrix(GLfloat m[16]) const; + void getModelViewProjectionMatrix(GLdouble m[16]) const; +//@} - /*! @name Drawing */ - //@{ +/*! @name Drawing */ +//@{ #ifndef DOXYGEN - static void drawCamera(qreal scale=1.0, qreal aspectRatio=1.33, qreal fieldOfView=qreal(M_PI)/4.0); + static void drawCamera(qreal scale = 1.0, qreal aspectRatio = 1.33, + qreal fieldOfView = qreal(M_PI) / 4.0); #endif - virtual void draw(bool drawFarPlane=true, qreal scale=1.0) const; - //@} - + virtual void draw(bool drawFarPlane = true, qreal scale = 1.0) const; + //@} - /*! @name World to Camera coordinate systems conversions */ - //@{ + /*! @name World to Camera coordinate systems conversions */ + //@{ public: - Vec cameraCoordinatesOf(const Vec& src) const; - Vec worldCoordinatesOf(const Vec& src) const; - void getCameraCoordinatesOf(const qreal src[3], qreal res[3]) const; - void getWorldCoordinatesOf(const qreal src[3], qreal res[3]) const; - //@} - - - /*! @name 2D screen to 3D world coordinate systems conversions */ - //@{ + Vec cameraCoordinatesOf(const Vec &src) const; + Vec worldCoordinatesOf(const Vec &src) const; + void getCameraCoordinatesOf(const qreal src[3], qreal res[3]) const; + void getWorldCoordinatesOf(const qreal src[3], qreal res[3]) const; + //@} + + /*! @name 2D screen to 3D world coordinate systems conversions */ + //@{ public: - Vec projectedCoordinatesOf(const Vec& src, const Frame* frame=NULL) const; - Vec unprojectedCoordinatesOf(const Vec& src, const Frame* frame=NULL) const; - void getProjectedCoordinatesOf(const qreal src[3], qreal res[3], const Frame* frame=NULL) const; - void getUnprojectedCoordinatesOf(const qreal src[3], qreal res[3], const Frame* frame=NULL) const; - void convertClickToLine(const QPoint& pixel, Vec& orig, Vec& dir) const; - Vec pointUnderPixel(const QPoint& pixel, bool& found) const; - //@} - - - /*! @name Fly speed */ - //@{ + Vec projectedCoordinatesOf(const Vec &src, const Frame *frame = nullptr) const; + Vec unprojectedCoordinatesOf(const Vec &src, const Frame *frame = nullptr) const; + void getProjectedCoordinatesOf(const qreal src[3], qreal res[3], + const Frame *frame = nullptr) const; + void getUnprojectedCoordinatesOf(const qreal src[3], qreal res[3], + const Frame *frame = nullptr) const; + void convertClickToLine(const QPoint &pixel, Vec &orig, Vec &dir) const; + Vec pointUnderPixel(const QPoint &pixel, bool &found) const; + //@} + + /*! @name Fly speed */ + //@{ public: - qreal flySpeed() const; + qreal flySpeed() const; public Q_SLOTS: - void setFlySpeed(qreal speed); - //@} + void setFlySpeed(qreal speed); + //@} - - /*! @name Stereo parameters */ - //@{ + /*! @name Stereo parameters */ + //@{ public: - /*! Returns the user's inter-ocular distance (in meters). Default value is 0.062m, which fits most people. + /*! Returns the user's inter-ocular distance (in meters). Default value is + 0.062m, which fits most people. - loadProjectionMatrixStereo() uses this value to define the Camera offset and frustum. See - setIODistance(). */ - qreal IODistance() const { return IODistance_; } + loadProjectionMatrixStereo() uses this value to define the Camera offset and + frustum. See setIODistance(). */ + qreal IODistance() const { return IODistance_; } - /*! Returns the physical distance between the user's eyes and the screen (in meters). + /*! Returns the physical distance between the user's eyes and the screen (in + meters). - physicalDistanceToScreen() and focusDistance() represent the same distance. The former is - expressed in physical real world units, while the latter is expressed in OpenGL virtual world - units. + physicalDistanceToScreen() and focusDistance() represent the same distance. + The former is expressed in physical real world units, while the latter is + expressed in OpenGL virtual world units. - This is a helper function. It simply returns physicalScreenWidth() / 2.0 / tan(horizontalFieldOfView() / 2.0); */ - qreal physicalDistanceToScreen() const { return physicalScreenWidth() / 2.0 / tan(horizontalFieldOfView() / 2.0); } + This is a helper function. It simply returns physicalScreenWidth() / 2.0 / + tan(horizontalFieldOfView() / 2.0); */ + qreal physicalDistanceToScreen() const { + return physicalScreenWidth() / 2.0 / tan(horizontalFieldOfView() / 2.0); + } - /*! Returns the physical screen width, in meters. Default value is 0.5m (average monitor width). + /*! Returns the physical screen width, in meters. Default value is 0.5m + (average monitor width). - Used for stereo display only (see loadModelViewMatrixStereo() and loadProjectionMatrixStereo()). - Set using setPhysicalScreenWidth(). */ - qreal physicalScreenWidth() const { return physicalScreenWidth_; } + Used for stereo display only (see loadModelViewMatrixStereo() and + loadProjectionMatrixStereo()). Set using setPhysicalScreenWidth(). */ + qreal physicalScreenWidth() const { return physicalScreenWidth_; } - /*! Returns the focus distance used by stereo display, expressed in OpenGL units. + /*! Returns the focus distance used by stereo display, expressed in OpenGL + units. - This is the distance in the virtual world between the Camera and the plane where the horizontal - stereo parallax is null (the stereo left and right cameras' lines of sigth cross at this distance). + This is the distance in the virtual world between the Camera and the plane + where the horizontal stereo parallax is null (the stereo left and right + cameras' lines of sigth cross at this distance). - This distance is the virtual world equivalent of the real-world physicalDistanceToScreen(). + This distance is the virtual world equivalent of the real-world + physicalDistanceToScreen(). - \attention This value is modified by QGLViewer::setSceneRadius(), setSceneRadius() and - setFieldOfView(). When one of these values is modified, focusDistance() is set to sceneRadius() - / tan(fieldOfView()/2), which provides good results. */ - qreal focusDistance() const { return focusDistance_; } + \attention This value is modified by QGLViewer::setSceneRadius(), + setSceneRadius() and setFieldOfView(). When one of these values is modified, + focusDistance() is set to sceneRadius() / tan(fieldOfView()/2), which provides + good results. */ + qreal focusDistance() const { return focusDistance_; } public Q_SLOTS: - /*! Sets the IODistance(). */ - void setIODistance(qreal distance) { IODistance_ = distance; } + /*! Sets the IODistance(). */ + void setIODistance(qreal distance) { IODistance_ = distance; } #ifndef DOXYGEN - /*! This method is deprecated. Use setPhysicalScreenWidth() instead. */ - void setPhysicalDistanceToScreen(qreal distance) { Q_UNUSED(distance); qWarning("setPhysicalDistanceToScreen is deprecated, use setPhysicalScreenWidth instead"); } + /*! This method is deprecated. Use setPhysicalScreenWidth() instead. */ + void setPhysicalDistanceToScreen(qreal distance) { + Q_UNUSED(distance); + qWarning("setPhysicalDistanceToScreen is deprecated, use " + "setPhysicalScreenWidth instead"); + } #endif - /*! Sets the physical screen (monitor or projected wall) width (in meters). */ - void setPhysicalScreenWidth(qreal width) { physicalScreenWidth_ = width; } - - /*! Sets the focusDistance(), in OpenGL scene units. */ - void setFocusDistance(qreal distance) { focusDistance_ = distance; } - //@} + /*! Sets the physical screen (monitor or projected wall) width (in meters). */ + void setPhysicalScreenWidth(qreal width) { physicalScreenWidth_ = width; } + /*! Sets the focusDistance(), in OpenGL scene units. */ + void setFocusDistance(qreal distance) { focusDistance_ = distance; } + //@} - /*! @name XML representation */ - //@{ + /*! @name XML representation */ + //@{ public: - virtual QDomElement domElement(const QString& name, QDomDocument& document) const; + virtual QDomElement domElement(const QString &name, + QDomDocument &document) const; public Q_SLOTS: - virtual void initFromDOMElement(const QDomElement& element); - //@} - + virtual void initFromDOMElement(const QDomElement &element); + //@} private Q_SLOTS: - void onFrameModified(); + void onFrameModified(); private: - // F r a m e - ManipulatedCameraFrame* frame_; - - // C a m e r a p a r a m e t e r s - int screenWidth_, screenHeight_; // size of the window, in pixels - qreal fieldOfView_; // in radians - Vec sceneCenter_; - qreal sceneRadius_; // OpenGL units - qreal zNearCoef_; - qreal zClippingCoef_; - qreal orthoCoef_; - Type type_; // PERSPECTIVE or ORTHOGRAPHIC - mutable GLdouble modelViewMatrix_[16]; // Buffered model view matrix. - mutable bool modelViewMatrixIsUpToDate_; - mutable GLdouble projectionMatrix_[16]; // Buffered projection matrix. - mutable bool projectionMatrixIsUpToDate_; - - // S t e r e o p a r a m e t e r s - qreal IODistance_; // inter-ocular distance, in meters - qreal focusDistance_; // in scene units - qreal physicalScreenWidth_; // in meters - - // P o i n t s o f V i e w s a n d K e y F r a m e s - QMap kfi_; - KeyFrameInterpolator* interpolationKfi_; + // F r a m e + ManipulatedCameraFrame *frame_; + + // C a m e r a p a r a m e t e r s + int screenWidth_, screenHeight_; // size of the window, in pixels + qreal fieldOfView_; // in radians + Vec sceneCenter_; + qreal sceneRadius_; // OpenGL units + qreal zNearCoef_; + qreal zClippingCoef_; + qreal orthoCoef_; + qreal devicePixelRatio_; + Type type_; // PERSPECTIVE or ORTHOGRAPHIC + mutable GLdouble modelViewMatrix_[16]; // Buffered model view matrix. + mutable bool modelViewMatrixIsUpToDate_; + mutable GLdouble projectionMatrix_[16]; // Buffered projection matrix. + mutable bool projectionMatrixIsUpToDate_; + + // S t e r e o p a r a m e t e r s + qreal IODistance_; // inter-ocular distance, in meters + qreal focusDistance_; // in scene units + qreal physicalScreenWidth_; // in meters + + // P o i n t s o f V i e w s a n d K e y F r a m e s + QMap kfi_; + KeyFrameInterpolator *interpolationKfi_; }; } // namespace qglviewer diff --git a/octovis/src/extern/QGLViewer/config.h b/octovis/src/extern/QGLViewer/config.h index dbe1cfa0..715a50a1 100644 --- a/octovis/src/extern/QGLViewer/config.h +++ b/octovis/src/extern/QGLViewer/config.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,7 +19,6 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - /////////////////////////////////////////////////////////////////// // libQGLViewer configuration file // // Modify these settings according to your local configuration // @@ -28,53 +27,48 @@ #ifndef QGLVIEWER_CONFIG_H #define QGLVIEWER_CONFIG_H -#define QGLVIEWER_VERSION 0x020603 - -// Needed for Qt < 4 (?) -#ifndef QT_CLEAN_NAMESPACE -# define QT_CLEAN_NAMESPACE -#endif +#define QGLVIEWER_VERSION 0x020901 // Get QT_VERSION and other Qt flags #include -#if QT_VERSION < 0x040000 -Error : libQGLViewer requires a minimum Qt version of 4.0 +#if QT_VERSION < 0x050400 +Error : libQGLViewer requires a minimum Qt version of 5.4 Error + : Use a version prior to 2.7.0 to remove this constraint #endif // Win 32 DLL export macros #ifdef Q_OS_WIN32 # ifndef M_PI # define M_PI 3.14159265358979323846 -# endif +# endif // M_PI # ifndef QGLVIEWER_STATIC -# ifdef CREATE_QGLVIEWER_DLL -# if QT_VERSION >= 0x040500 -# define QGLVIEWER_EXPORT Q_DECL_EXPORT -# else -# define QGLVIEWER_EXPORT __declspec(dllexport) -# endif -# else -# if QT_VERSION >= 0x040500 -# define QGLVIEWER_EXPORT Q_DECL_IMPORT -# else -# define QGLVIEWER_EXPORT __declspec(dllimport) -# endif +# ifdef CREATE_QGLVIEWER_DLL +# define QGLVIEWER_EXPORT Q_DECL_EXPORT +# else +# define QGLVIEWER_EXPORT Q_DECL_IMPORT # endif -# endif +# endif // QGLVIEWER_STATIC + # ifndef __MINGW32__ -# pragma warning( disable : 4251 ) // DLL interface, needed with Visual 6 -# pragma warning( disable : 4786 ) // identifier truncated to 255 in browser information (Visual 6). +# pragma warning(disable : 4251) // DLL interface, needed with Visual 6 +# pragma warning(disable : 4786) // identifier truncated to 255 in browser + // information (Visual 6). # endif #endif // Q_OS_WIN32 // For other architectures, this macro is empty #ifndef QGLVIEWER_EXPORT -# define QGLVIEWER_EXPORT +#define QGLVIEWER_EXPORT +#endif + +#ifdef Q_OS_MAC +# define GL_SILENCE_DEPRECATION #endif -// OpenGL includes - Included here and hence shared by all the files that need OpenGL headers. -# include +// OpenGL includes - Included here and hence shared by all the files that need +// OpenGL headers. +#include // GLU was removed from Qt in version 4.8 #ifdef Q_OS_MAC @@ -90,14 +84,14 @@ Error : libQGLViewer requires a minimum Qt version of 4.0 // For deprecated methods // #define __WHERE__ "In file "<<__FILE__<<", line "<<__LINE__<<": " -// #define orientationAxisAngle(x,y,z,a) { std::cout << __WHERE__ << "getOrientationAxisAngle()." << std::endl; exit(0); } - -// Patch for gcc version <= 2.95. Seems to no longer be needed with recent Qt versions. -// Uncomment these lines if you have error message dealing with operator << on QStrings -// #if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ < 3) && (__GNUC_MINOR__ < 96) -// # include -// # include -// std::ostream& operator<<(std::ostream& out, const QString& str) +// #define orientationAxisAngle(x,y,z,a) { std::cout << __WHERE__ << +// "getOrientationAxisAngle()." << std::endl; exit(0); } + +// Patch for gcc version <= 2.95. Seems to no longer be needed with recent Qt +// versions. Uncomment these lines if you have error message dealing with +// operator << on QStrings #if defined(__GNUC__) && defined(__GNUC_MINOR__) && +// (__GNUC__ < 3) && (__GNUC_MINOR__ < 96) # include # include +// std::ostream& operator<<(std::ostream& out, const QString& str) // { out << str.latin1(); return out; } // #endif diff --git a/octovis/src/extern/QGLViewer/constraint.cpp b/octovis/src/extern/QGLViewer/constraint.cpp index fbb9a6c2..5c6966b6 100644 --- a/octovis/src/extern/QGLViewer/constraint.cpp +++ b/octovis/src/extern/QGLViewer/constraint.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,10 +19,9 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #include "constraint.h" -#include "frame.h" #include "camera.h" +#include "frame.h" #include "manipulatedCameraFrame.h" using namespace qglviewer; @@ -34,258 +33,247 @@ using namespace std; /*! Default constructor. -translationConstraintType() and rotationConstraintType() are set to AxisPlaneConstraint::FREE. -translationConstraintDirection() and rotationConstraintDirection() are set to (0,0,0). */ +translationConstraintType() and rotationConstraintType() are set to +AxisPlaneConstraint::FREE. translationConstraintDirection() and +rotationConstraintDirection() are set to (0,0,0). */ AxisPlaneConstraint::AxisPlaneConstraint() - : translationConstraintType_(FREE), rotationConstraintType_(FREE) -{ - // Do not use set since setRotationConstraintType needs a read. + : translationConstraintType_(FREE), rotationConstraintType_(FREE) { + // Do not use set since setRotationConstraintType needs a read. } -/*! Simply calls setTranslationConstraintType() and setTranslationConstraintDirection(). */ -void AxisPlaneConstraint::setTranslationConstraint(Type type, const Vec& direction) -{ - setTranslationConstraintType(type); - setTranslationConstraintDirection(direction); +/*! Simply calls setTranslationConstraintType() and + * setTranslationConstraintDirection(). */ +void AxisPlaneConstraint::setTranslationConstraint(Type type, + const Vec &direction) { + setTranslationConstraintType(type); + setTranslationConstraintDirection(direction); } -/*! Defines the translationConstraintDirection(). The coordinate system where \p direction is expressed depends on your class implementation. */ -void AxisPlaneConstraint::setTranslationConstraintDirection(const Vec& direction) -{ - if ((translationConstraintType()!=AxisPlaneConstraint::FREE) && (translationConstraintType()!=AxisPlaneConstraint::FORBIDDEN)) - { - const qreal norm = direction.norm(); - if (norm < 1E-8) - { - qWarning("AxisPlaneConstraint::setTranslationConstraintDir: null vector for translation constraint"); - translationConstraintType_ = AxisPlaneConstraint::FREE; - } - else - translationConstraintDir_ = direction/norm; - } +/*! Defines the translationConstraintDirection(). The coordinate system where \p + * direction is expressed depends on your class implementation. */ +void AxisPlaneConstraint::setTranslationConstraintDirection( + const Vec &direction) { + if ((translationConstraintType() != AxisPlaneConstraint::FREE) && + (translationConstraintType() != AxisPlaneConstraint::FORBIDDEN)) { + const qreal norm = direction.norm(); + if (norm < 1E-8) { + qWarning("AxisPlaneConstraint::setTranslationConstraintDir: null vector " + "for translation constraint"); + translationConstraintType_ = AxisPlaneConstraint::FREE; + } else + translationConstraintDir_ = direction / norm; + } } -/*! Simply calls setRotationConstraintType() and setRotationConstraintDirection(). */ -void AxisPlaneConstraint::setRotationConstraint(Type type, const Vec& direction) -{ - setRotationConstraintType(type); - setRotationConstraintDirection(direction); +/*! Simply calls setRotationConstraintType() and + * setRotationConstraintDirection(). */ +void AxisPlaneConstraint::setRotationConstraint(Type type, + const Vec &direction) { + setRotationConstraintType(type); + setRotationConstraintDirection(direction); } -/*! Defines the rotationConstraintDirection(). The coordinate system where \p direction is expressed depends on your class implementation. */ -void AxisPlaneConstraint::setRotationConstraintDirection(const Vec& direction) -{ - if ((rotationConstraintType()!=AxisPlaneConstraint::FREE) && (rotationConstraintType()!=AxisPlaneConstraint::FORBIDDEN)) - { - const qreal norm = direction.norm(); - if (norm < 1E-8) - { - qWarning("AxisPlaneConstraint::setRotationConstraintDir: null vector for rotation constraint"); - rotationConstraintType_ = AxisPlaneConstraint::FREE; - } - else - rotationConstraintDir_ = direction/norm; - } +/*! Defines the rotationConstraintDirection(). The coordinate system where \p + * direction is expressed depends on your class implementation. */ +void AxisPlaneConstraint::setRotationConstraintDirection(const Vec &direction) { + if ((rotationConstraintType() != AxisPlaneConstraint::FREE) && + (rotationConstraintType() != AxisPlaneConstraint::FORBIDDEN)) { + const qreal norm = direction.norm(); + if (norm < 1E-8) { + qWarning("AxisPlaneConstraint::setRotationConstraintDir: null vector for " + "rotation constraint"); + rotationConstraintType_ = AxisPlaneConstraint::FREE; + } else + rotationConstraintDir_ = direction / norm; + } } -/*! Set the Type() of the rotationConstraintType(). Default is AxisPlaneConstraint::FREE. +/*! Set the Type() of the rotationConstraintType(). Default is + AxisPlaneConstraint::FREE. - Depending on this value, the Frame will freely rotate (AxisPlaneConstraint::FREE), will only be able - to rotate around an axis (AxisPlaneConstraint::AXIS), or will not able to rotate at all + Depending on this value, the Frame will freely rotate + (AxisPlaneConstraint::FREE), will only be able to rotate around an axis + (AxisPlaneConstraint::AXIS), or will not able to rotate at all (AxisPlaneConstraint::FORBIDDEN). - Use Frame::setOrientation() to define the orientation of the constrained Frame before it gets - constrained. + Use Frame::setOrientation() to define the orientation of the constrained Frame + before it gets constrained. - \attention An AxisPlaneConstraint::PLANE Type() is not meaningful for rotational constraints and - will be ignored. */ -void AxisPlaneConstraint::setRotationConstraintType(Type type) -{ - if (rotationConstraintType() == AxisPlaneConstraint::PLANE) - { - qWarning("AxisPlaneConstraint::setRotationConstraintType: the PLANE type cannot be used for a rotation constraints"); - return; - } + \attention An AxisPlaneConstraint::PLANE Type() is not meaningful for + rotational constraints and will be ignored. */ +void AxisPlaneConstraint::setRotationConstraintType(Type type) { + if (rotationConstraintType() == AxisPlaneConstraint::PLANE) { + qWarning("AxisPlaneConstraint::setRotationConstraintType: the PLANE type " + "cannot be used for a rotation constraints"); + return; + } - rotationConstraintType_ = type; + rotationConstraintType_ = type; } - //////////////////////////////////////////////////////////////////////////////// // LocalConstraint // //////////////////////////////////////////////////////////////////////////////// -/*! Depending on translationConstraintType(), constrain \p translation to be along an axis or - limited to a plane defined in the Frame local coordinate system by - translationConstraintDirection(). */ -void LocalConstraint::constrainTranslation(Vec& translation, Frame* const frame) -{ - Vec proj; - switch (translationConstraintType()) - { - case AxisPlaneConstraint::FREE: - break; - case AxisPlaneConstraint::PLANE: - proj = frame->rotation().rotate(translationConstraintDirection()); - translation.projectOnPlane(proj); - break; - case AxisPlaneConstraint::AXIS: - proj = frame->rotation().rotate(translationConstraintDirection()); - translation.projectOnAxis(proj); - break; - case AxisPlaneConstraint::FORBIDDEN: - translation = Vec(0.0, 0.0, 0.0); - break; - } +/*! Depending on translationConstraintType(), constrain \p translation to be + along an axis or limited to a plane defined in the Frame local coordinate + system by translationConstraintDirection(). */ +void LocalConstraint::constrainTranslation(Vec &translation, + Frame *const frame) { + Vec proj; + switch (translationConstraintType()) { + case AxisPlaneConstraint::FREE: + break; + case AxisPlaneConstraint::PLANE: + proj = frame->rotation().rotate(translationConstraintDirection()); + translation.projectOnPlane(proj); + break; + case AxisPlaneConstraint::AXIS: + proj = frame->rotation().rotate(translationConstraintDirection()); + translation.projectOnAxis(proj); + break; + case AxisPlaneConstraint::FORBIDDEN: + translation = Vec(0.0, 0.0, 0.0); + break; + } } -/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p rotation to be a rotation - around an axis whose direction is defined in the Frame local coordinate system by - rotationConstraintDirection(). */ -void LocalConstraint::constrainRotation(Quaternion& rotation, Frame* const) -{ - switch (rotationConstraintType()) - { - case AxisPlaneConstraint::FREE: - break; - case AxisPlaneConstraint::PLANE: - break; - case AxisPlaneConstraint::AXIS: - { - Vec axis = rotationConstraintDirection(); - Vec quat = Vec(rotation[0], rotation[1], rotation[2]); - quat.projectOnAxis(axis); - rotation = Quaternion(quat, 2.0*acos(rotation[3])); - } - break; - case AxisPlaneConstraint::FORBIDDEN: - rotation = Quaternion(); // identity - break; - } +/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p + rotation to be a rotation around an axis whose direction is defined in the + Frame local coordinate system by rotationConstraintDirection(). */ +void LocalConstraint::constrainRotation(Quaternion &rotation, Frame *const) { + switch (rotationConstraintType()) { + case AxisPlaneConstraint::FREE: + break; + case AxisPlaneConstraint::PLANE: + break; + case AxisPlaneConstraint::AXIS: { + Vec axis = rotationConstraintDirection(); + Vec quat = Vec(rotation[0], rotation[1], rotation[2]); + quat.projectOnAxis(axis); + rotation = Quaternion(quat, 2.0 * acos(rotation[3])); + } break; + case AxisPlaneConstraint::FORBIDDEN: + rotation = Quaternion(); // identity + break; + } } //////////////////////////////////////////////////////////////////////////////// // WorldConstraint // //////////////////////////////////////////////////////////////////////////////// -/*! Depending on translationConstraintType(), constrain \p translation to be along an axis or - limited to a plane defined in the world coordinate system by +/*! Depending on translationConstraintType(), constrain \p translation to be + along an axis or limited to a plane defined in the world coordinate system by translationConstraintDirection(). */ -void WorldConstraint::constrainTranslation(Vec& translation, Frame* const frame) -{ - Vec proj; - switch (translationConstraintType()) - { - case AxisPlaneConstraint::FREE: - break; - case AxisPlaneConstraint::PLANE: - if (frame->referenceFrame()) - { - proj = frame->referenceFrame()->transformOf(translationConstraintDirection()); - translation.projectOnPlane(proj); - } - else - translation.projectOnPlane(translationConstraintDirection()); - break; - case AxisPlaneConstraint::AXIS: - if (frame->referenceFrame()) - { - proj = frame->referenceFrame()->transformOf(translationConstraintDirection()); - translation.projectOnAxis(proj); - } - else - translation.projectOnAxis(translationConstraintDirection()); - break; - case AxisPlaneConstraint::FORBIDDEN: - translation = Vec(0.0, 0.0, 0.0); - break; - } +void WorldConstraint::constrainTranslation(Vec &translation, + Frame *const frame) { + Vec proj; + switch (translationConstraintType()) { + case AxisPlaneConstraint::FREE: + break; + case AxisPlaneConstraint::PLANE: + if (frame->referenceFrame()) { + proj = frame->referenceFrame()->transformOf( + translationConstraintDirection()); + translation.projectOnPlane(proj); + } else + translation.projectOnPlane(translationConstraintDirection()); + break; + case AxisPlaneConstraint::AXIS: + if (frame->referenceFrame()) { + proj = frame->referenceFrame()->transformOf( + translationConstraintDirection()); + translation.projectOnAxis(proj); + } else + translation.projectOnAxis(translationConstraintDirection()); + break; + case AxisPlaneConstraint::FORBIDDEN: + translation = Vec(0.0, 0.0, 0.0); + break; + } } -/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p rotation to be a rotation - around an axis whose direction is defined in the world coordinate system by - rotationConstraintDirection(). */ -void WorldConstraint::constrainRotation(Quaternion& rotation, Frame* const frame) -{ - switch (rotationConstraintType()) - { - case AxisPlaneConstraint::FREE: - break; - case AxisPlaneConstraint::PLANE: - break; - case AxisPlaneConstraint::AXIS: - { - Vec quat(rotation[0], rotation[1], rotation[2]); - Vec axis = frame->transformOf(rotationConstraintDirection()); - quat.projectOnAxis(axis); - rotation = Quaternion(quat, 2.0*acos(rotation[3])); - break; - } - case AxisPlaneConstraint::FORBIDDEN: - rotation = Quaternion(); // identity - break; - } +/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p + rotation to be a rotation around an axis whose direction is defined in the + world coordinate system by rotationConstraintDirection(). */ +void WorldConstraint::constrainRotation(Quaternion &rotation, + Frame *const frame) { + switch (rotationConstraintType()) { + case AxisPlaneConstraint::FREE: + break; + case AxisPlaneConstraint::PLANE: + break; + case AxisPlaneConstraint::AXIS: { + Vec quat(rotation[0], rotation[1], rotation[2]); + Vec axis = frame->transformOf(rotationConstraintDirection()); + quat.projectOnAxis(axis); + rotation = Quaternion(quat, 2.0 * acos(rotation[3])); + break; + } + case AxisPlaneConstraint::FORBIDDEN: + rotation = Quaternion(); // identity + break; + } } //////////////////////////////////////////////////////////////////////////////// -// CameraConstraint // +// CameraConstraint // //////////////////////////////////////////////////////////////////////////////// -/*! Creates a CameraConstraint, whose constrained directions are defined in the \p camera coordinate - system. */ -CameraConstraint::CameraConstraint(const Camera* const camera) - : AxisPlaneConstraint(), camera_(camera) -{} - -/*! Depending on translationConstraintType(), constrain \p translation to be along an axis or - limited to a plane defined in the camera() coordinate system by - translationConstraintDirection(). */ -void CameraConstraint::constrainTranslation(Vec& translation, Frame* const frame) -{ - Vec proj; - switch (translationConstraintType()) - { - case AxisPlaneConstraint::FREE: - break; - case AxisPlaneConstraint::PLANE: - proj = camera()->frame()->inverseTransformOf(translationConstraintDirection()); - if (frame->referenceFrame()) - proj = frame->referenceFrame()->transformOf(proj); - translation.projectOnPlane(proj); - break; - case AxisPlaneConstraint::AXIS: - proj = camera()->frame()->inverseTransformOf(translationConstraintDirection()); - if (frame->referenceFrame()) - proj = frame->referenceFrame()->transformOf(proj); - translation.projectOnAxis(proj); - break; - case AxisPlaneConstraint::FORBIDDEN: - translation = Vec(0.0, 0.0, 0.0); - break; - } +/*! Creates a CameraConstraint, whose constrained directions are defined in the + \p camera coordinate system. */ +CameraConstraint::CameraConstraint(const Camera *const camera) + : AxisPlaneConstraint(), camera_(camera) {} + +/*! Depending on translationConstraintType(), constrain \p translation to be + along an axis or limited to a plane defined in the camera() coordinate system + by translationConstraintDirection(). */ +void CameraConstraint::constrainTranslation(Vec &translation, + Frame *const frame) { + Vec proj; + switch (translationConstraintType()) { + case AxisPlaneConstraint::FREE: + break; + case AxisPlaneConstraint::PLANE: + proj = + camera()->frame()->inverseTransformOf(translationConstraintDirection()); + if (frame->referenceFrame()) + proj = frame->referenceFrame()->transformOf(proj); + translation.projectOnPlane(proj); + break; + case AxisPlaneConstraint::AXIS: + proj = + camera()->frame()->inverseTransformOf(translationConstraintDirection()); + if (frame->referenceFrame()) + proj = frame->referenceFrame()->transformOf(proj); + translation.projectOnAxis(proj); + break; + case AxisPlaneConstraint::FORBIDDEN: + translation = Vec(0.0, 0.0, 0.0); + break; + } } -/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p rotation to be a rotation - around an axis whose direction is defined in the camera() coordinate system by - rotationConstraintDirection(). */ -void CameraConstraint::constrainRotation(Quaternion& rotation, Frame* const frame) -{ - switch (rotationConstraintType()) - { - case AxisPlaneConstraint::FREE: - break; - case AxisPlaneConstraint::PLANE: - break; - case AxisPlaneConstraint::AXIS: - { - Vec axis = frame->transformOf(camera()->frame()->inverseTransformOf(rotationConstraintDirection())); - Vec quat = Vec(rotation[0], rotation[1], rotation[2]); - quat.projectOnAxis(axis); - rotation = Quaternion(quat, 2.0*acos(rotation[3])); - } - break; - case AxisPlaneConstraint::FORBIDDEN: - rotation = Quaternion(); // identity - break; - } +/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p + rotation to be a rotation around an axis whose direction is defined in the + camera() coordinate system by rotationConstraintDirection(). */ +void CameraConstraint::constrainRotation(Quaternion &rotation, + Frame *const frame) { + switch (rotationConstraintType()) { + case AxisPlaneConstraint::FREE: + break; + case AxisPlaneConstraint::PLANE: + break; + case AxisPlaneConstraint::AXIS: { + Vec axis = frame->transformOf( + camera()->frame()->inverseTransformOf(rotationConstraintDirection())); + Vec quat = Vec(rotation[0], rotation[1], rotation[2]); + quat.projectOnAxis(axis); + rotation = Quaternion(quat, 2.0 * acos(rotation[3])); + } break; + case AxisPlaneConstraint::FORBIDDEN: + rotation = Quaternion(); // identity + break; + } } diff --git a/octovis/src/extern/QGLViewer/constraint.h b/octovis/src/extern/QGLViewer/constraint.h index cc1d8ad1..8dcdae69 100644 --- a/octovis/src/extern/QGLViewer/constraint.h +++ b/octovis/src/extern/QGLViewer/constraint.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,12 +19,11 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_CONSTRAINT_H #define QGLVIEWER_CONSTRAINT_H -#include "vec.h" #include "quaternion.h" +#include "vec.h" namespace qglviewer { class Frame; @@ -33,304 +32,333 @@ class Camera; /*! \brief An interface class for Frame constraints. \class Constraint constraint.h QGLViewer/constraint.h - This class defines the interface for the Constraints that can be applied to a Frame to limit its - motion. Use Frame::setConstraint() to associate a Constraint to a Frame (default is a \c NULL - Frame::constraint()). + This class defines the interface for the Constraints that can be applied to a + Frame to limit its motion. Use Frame::setConstraint() to associate a + Constraint to a Frame (default is a \c nullptr Frame::constraint()).

How does it work ?

- The Constraint acts as a filter on the translation and rotation Frame increments. - constrainTranslation() and constrainRotation() should be overloaded to specify the constraint - behavior: the desired displacement is given as a parameter that can optionally be modified. + The Constraint acts as a filter on the translation and rotation Frame + increments. constrainTranslation() and constrainRotation() should be + overloaded to specify the constraint behavior: the desired displacement is + given as a parameter that can optionally be modified. - Here is how the Frame::translate() and Frame::rotate() methods use the Constraint: - \code - Frame::translate(Vec& T) + Here is how the Frame::translate() and Frame::rotate() methods use the + Constraint: \code Frame::translate(Vec& T) { - if (constraint()) - constraint()->constrainTranslation(T, this); - t += T; + if (constraint()) + constraint()->constrainTranslation(T, this); + t += T; } Frame::rotate(Quaternion& Q) { - if (constraint()) - constraint()->constrainRotation(Q, this); - q *= Q; + if (constraint()) + constraint()->constrainRotation(Q, this); + q *= Q; } \endcode - The default behavior of constrainTranslation() and constrainRotation() is empty (meaning no - filtering). + The default behavior of constrainTranslation() and constrainRotation() is + empty (meaning no filtering). - The Frame which uses the Constraint is passed as a parameter to the constrainTranslation() and - constrainRotation() methods, so that they can have access to its current state (mainly - Frame::position() and Frame::orientation()). It is not \c const for versatility reasons, but + The Frame which uses the Constraint is passed as a parameter to the + constrainTranslation() and constrainRotation() methods, so that they can have + access to its current state (mainly Frame::position() and + Frame::orientation()). It is not \c const for versatility reasons, but directly modifying it should be avoided. - \attention Frame::setTranslation(), Frame::setRotation() and similar methods will actually indeed - set the frame position and orientation, without taking the constraint into account. Use the \e - WithConstraint versions of these methods to enforce the Constraint. + \attention Frame::setTranslation(), Frame::setRotation() and similar methods + will actually indeed set the frame position and orientation, without taking + the constraint into account. Use the \e WithConstraint versions of these + methods to enforce the Constraint.

Implemented Constraints

- Classical axial and plane Constraints are provided for convenience: see the LocalConstraint, - WorldConstraint and CameraConstraint classes' documentations. + Classical axial and plane Constraints are provided for convenience: see the + LocalConstraint, WorldConstraint and CameraConstraint classes' documentations. - Try the constrainedFrame and constrainedCamera examples for an illustration. + Try the constrainedFrame and + constrainedCamera examples + for an illustration.

Creating new Constraints

- The implementation of a new Constraint class simply consists in overloading the filtering methods: - \code - // This Constraint enforces that the Frame cannot have a negative z world coordinate. - class myConstraint : public Constraint + The implementation of a new Constraint class simply consists in overloading + the filtering methods: \code + // This Constraint enforces that the Frame cannot have a negative z world + coordinate. class myConstraint : public Constraint { public: - virtual void constrainTranslation(Vec& t, Frame * const fr) - { - // Express t in the world coordinate system. - const Vec tWorld = fr->inverseTransformOf(t); - if (fr->position().z + tWorld.z < 0.0) // check the new fr z coordinate - t.z = fr->transformOf(-fr->position().z); // t.z is clamped so that next z position is 0.0 - } + virtual void constrainTranslation(Vec& t, Frame * const fr) + { + // Express t in the world coordinate system. + const Vec tWorld = fr->inverseTransformOf(t); + if (fr->position().z + tWorld.z < 0.0) // check the new fr z coordinate + t.z = fr->transformOf(-fr->position().z); // t.z is clamped so that + next z position is 0.0 + } }; \endcode - Note that the translation (resp. rotation) parameter passed to constrainTranslation() (resp. - constrainRotation()) is expressed in the \e local Frame coordinate system. Here, we use the - Frame::transformOf() and Frame::inverseTransformOf() method to convert it to and from the world + Note that the translation (resp. rotation) parameter passed to + constrainTranslation() (resp. constrainRotation()) is expressed in the \e + local Frame coordinate system. Here, we use the Frame::transformOf() and + Frame::inverseTransformOf() method to convert it to and from the world coordinate system. - Combined constraints can easily be achieved by creating a new class that applies the different - constraint filters: - \code + Combined constraints can easily be achieved by creating a new class that + applies the different constraint filters: \code myConstraint::constrainTranslation(Vec& v, Frame* const fr) { - constraint1->constrainTranslation(v, fr); - constraint2->constrainTranslation(v, fr); - // and so on, with possible branches, tests, loops... + constraint1->constrainTranslation(v, fr); + constraint2->constrainTranslation(v, fr); + // and so on, with possible branches, tests, loops... } \endcode */ -class QGLVIEWER_EXPORT Constraint -{ +class QGLVIEWER_EXPORT Constraint { public: - /*! Virtual destructor. Empty. */ - virtual ~Constraint() {} - - /*! Filters the translation applied to the \p frame. This default implementation is empty (no - filtering). - - Overload this method in your own Constraint class to define a new translation constraint. \p - frame is the Frame to which is applied the translation. It is not defined \c const, but you - should refrain from directly changing its value in the constraint. Use its Frame::position() and - update the \p translation accordingly instead. - - \p translation is expressed in local frame coordinate system. Use Frame::inverseTransformOf() to - express it in the world coordinate system if needed. */ - virtual void constrainTranslation(Vec& translation, Frame* const frame) { Q_UNUSED(translation); Q_UNUSED(frame); } - /*! Filters the rotation applied to the \p frame. This default implementation is empty (no - filtering). + /*! Virtual destructor. Empty. */ + virtual ~Constraint() {} + + /*! Filters the translation applied to the \p frame. This default + implementation is empty (no filtering). + + Overload this method in your own Constraint class to define a new translation + constraint. \p frame is the Frame to which is applied the translation. It is + not defined \c const, but you should refrain from directly changing its value + in the constraint. Use its Frame::position() and update the \p translation + accordingly instead. + + \p translation is expressed in local frame coordinate system. Use + Frame::inverseTransformOf() to express it in the world coordinate system if + needed. */ + virtual void constrainTranslation(Vec &translation, Frame *const frame) { + Q_UNUSED(translation); + Q_UNUSED(frame); + } + /*! Filters the rotation applied to the \p frame. This default implementation + is empty (no filtering). - Overload this method in your own Constraint class to define a new rotation constraint. See - constrainTranslation() for details. + Overload this method in your own Constraint class to define a new rotation + constraint. See constrainTranslation() for details. - Use Frame::inverseTransformOf() on the \p rotation Quaternion::axis() to express \p rotation in - the world coordinate system if needed. */ - virtual void constrainRotation(Quaternion& rotation, Frame* const frame) { Q_UNUSED(rotation); Q_UNUSED(frame); } + Use Frame::inverseTransformOf() on the \p rotation Quaternion::axis() to + express \p rotation in the world coordinate system if needed. */ + virtual void constrainRotation(Quaternion &rotation, Frame *const frame) { + Q_UNUSED(rotation); + Q_UNUSED(frame); + } }; /*! \brief An abstract class for Frame Constraints defined by an axis or a plane. \class AxisPlaneConstraint constraint.h QGLViewer/constraint.h - AxisPlaneConstraint is an interface for (translation and/or rotation) Constraint that are defined - by a direction. translationConstraintType() and rotationConstraintType() define how this - direction should be interpreted: as an axis (AxisPlaneConstraint::AXIS) or as a plane normal + AxisPlaneConstraint is an interface for (translation and/or rotation) + Constraint that are defined by a direction. translationConstraintType() and + rotationConstraintType() define how this direction should be interpreted: as + an axis (AxisPlaneConstraint::AXIS) or as a plane normal (AxisPlaneConstraint::PLANE). See the Type() documentation for details. - The three implementations of this class: LocalConstraint, WorldConstraint and CameraConstraint - differ by the coordinate system in which this direction is expressed. + The three implementations of this class: LocalConstraint, WorldConstraint and + CameraConstraint differ by the coordinate system in which this direction is + expressed. Different implementations of this class are illustrated in the contrainedCamera and constrainedFrame examples. - \attention When applied, the rotational Constraint may not intuitively follow the mouse - displacement. A solution would be to directly measure the rotation angle in screen coordinates, - but that would imply to know the QGLViewer::camera(), so that we can compute the projected - coordinates of the rotation center (as is done with the QGLViewer::SCREEN_ROTATE binding). - However, adding an extra pointer to the QGLViewer::camera() in all the AxisPlaneConstraint - derived classes (which the user would have to update in a multi-viewer application) was judged as - an overkill. */ -class QGLVIEWER_EXPORT AxisPlaneConstraint : public Constraint -{ + \attention When applied, the rotational Constraint may not intuitively follow + the mouse displacement. A solution would be to directly measure the rotation + angle in screen coordinates, but that would imply to know the + QGLViewer::camera(), so that we can compute the projected coordinates of the + rotation center (as is done with the QGLViewer::SCREEN_ROTATE binding). + However, adding an extra pointer to the QGLViewer::camera() in all the + AxisPlaneConstraint derived classes (which the user would have to update in a + multi-viewer application) was judged as an overkill. */ +class QGLVIEWER_EXPORT AxisPlaneConstraint : public Constraint { public: - AxisPlaneConstraint(); - /*! Virtual destructor. Empty. */ - virtual ~AxisPlaneConstraint() {} - - /*! Type lists the different types of translation and rotation constraints that are available. - - It specifies the meaning of the constraint direction (see translationConstraintDirection() and - rotationConstraintDirection()): as an axis direction (AxisPlaneConstraint::AXIS) or a plane - normal (AxisPlaneConstraint::PLANE). AxisPlaneConstraint::FREE means no constraint while - AxisPlaneConstraint::FORBIDDEN completely forbids the translation and/or the rotation. - - See translationConstraintType() and rotationConstraintType(). - - \attention The AxisPlaneConstraint::PLANE Type is not valid for rotational constraint. - - New derived classes can use their own extended enum for specific constraints: - \code - class MyAxisPlaneConstraint : public AxisPlaneConstraint - { - public: - enum MyType { FREE, AXIS, PLANE, FORBIDDEN, CUSTOM }; - virtual void constrainTranslation(Vec &translation, Frame *const frame) - { - // translationConstraintType() is simply an int. CUSTOM Type is handled seamlessly. - switch (translationConstraintType()) - { - case MyAxisPlaneConstraint::FREE: ... break; - case MyAxisPlaneConstraint::CUSTOM: ... break; - } - } - - MyAxisPlaneConstraint* c = new MyAxisPlaneConstraint(); - // Note the Type conversion - c->setTranslationConstraintType(AxisPlaneConstraint::Type(MyAxisPlaneConstraint::CUSTOM)); - }; - \endcode */ - enum Type { FREE, AXIS, PLANE, FORBIDDEN }; - - /*! @name Translation constraint */ - //@{ - /*! Overloading of Constraint::constrainTranslation(). Empty */ - virtual void constrainTranslation(Vec& translation, Frame* const frame) { Q_UNUSED(translation); Q_UNUSED(frame); } - - void setTranslationConstraint(Type type, const Vec& direction); - /*! Sets the Type() of the translationConstraintType(). Default is AxisPlaneConstraint::FREE. */ - void setTranslationConstraintType(Type type) { translationConstraintType_ = type; } - void setTranslationConstraintDirection(const Vec& direction); - - /*! Returns the translation constraint Type(). - - Depending on this value, the Frame will freely translate (AxisPlaneConstraint::FREE), will only - be able to translate along an axis direction (AxisPlaneConstraint::AXIS), will be forced to stay - into a plane (AxisPlaneConstraint::PLANE) or will not able to translate at all - (AxisPlaneConstraint::FORBIDDEN). - - Use Frame::setPosition() to define the position of the constrained Frame before it gets - constrained. */ - Type translationConstraintType() const { return translationConstraintType_; } - /*! Returns the direction used by the translation constraint. - - It represents the axis direction (AxisPlaneConstraint::AXIS) or the plane normal - (AxisPlaneConstraint::PLANE) depending on the translationConstraintType(). It is undefined for - AxisPlaneConstraint::FREE or AxisPlaneConstraint::FORBIDDEN. - - The AxisPlaneConstraint derived classes express this direction in different coordinate system - (camera for CameraConstraint, local for LocalConstraint, and world for WorldConstraint). This - value can be modified with setTranslationConstraintDirection(). */ - Vec translationConstraintDirection() const { return translationConstraintDir_; } - //@} - - /*! @name Rotation constraint */ - //@{ - /*! Overloading of Constraint::constrainRotation(). Empty. */ - virtual void constrainRotation(Quaternion& rotation, Frame* const frame) { Q_UNUSED(rotation); Q_UNUSED(frame); } - - void setRotationConstraint(Type type, const Vec& direction); - void setRotationConstraintType(Type type); - void setRotationConstraintDirection(const Vec& direction); - - /*! Returns the rotation constraint Type(). */ - Type rotationConstraintType() const { return rotationConstraintType_; } - /*! Returns the axis direction used by the rotation constraint. - - This direction is defined only when rotationConstraintType() is AxisPlaneConstraint::AXIS. - - The AxisPlaneConstraint derived classes express this direction in different coordinate system - (camera for CameraConstraint, local for LocalConstraint, and world for WorldConstraint). This - value can be modified with setRotationConstraintDirection(). */ - Vec rotationConstraintDirection() const { return rotationConstraintDir_; } - //@} + AxisPlaneConstraint(); + /*! Virtual destructor. Empty. */ + virtual ~AxisPlaneConstraint() {} + + /*! Type lists the different types of translation and rotation constraints + that are available. + + It specifies the meaning of the constraint direction (see + translationConstraintDirection() and rotationConstraintDirection()): as an + axis direction (AxisPlaneConstraint::AXIS) or a plane normal + (AxisPlaneConstraint::PLANE). AxisPlaneConstraint::FREE means no constraint + while AxisPlaneConstraint::FORBIDDEN completely forbids the translation and/or + the rotation. + + See translationConstraintType() and rotationConstraintType(). + + \attention The AxisPlaneConstraint::PLANE Type is not valid for rotational + constraint. + + New derived classes can use their own extended enum for specific constraints: + \code + class MyAxisPlaneConstraint : public AxisPlaneConstraint + { + public: + enum MyType { FREE, AXIS, PLANE, FORBIDDEN, CUSTOM }; + virtual void constrainTranslation(Vec &translation, Frame *const frame) + { + // translationConstraintType() is simply an int. CUSTOM Type is + handled seamlessly. switch (translationConstraintType()) + { + case MyAxisPlaneConstraint::FREE: ... break; + case MyAxisPlaneConstraint::CUSTOM: ... break; + } + }; + + MyAxisPlaneConstraint* c = new MyAxisPlaneConstraint(); + // Note the Type conversion + c->setTranslationConstraintType(AxisPlaneConstraint::Type(MyAxisPlaneConstraint::CUSTOM)); + }; + \endcode */ + enum Type { FREE, AXIS, PLANE, FORBIDDEN }; + + /*! @name Translation constraint */ + //@{ + /*! Overloading of Constraint::constrainTranslation(). Empty */ + virtual void constrainTranslation(Vec &translation, Frame *const frame) { + Q_UNUSED(translation); + Q_UNUSED(frame); + }; + + void setTranslationConstraint(Type type, const Vec &direction); + /*! Sets the Type() of the translationConstraintType(). Default is + * AxisPlaneConstraint::FREE. */ + void setTranslationConstraintType(Type type) { + translationConstraintType_ = type; + }; + void setTranslationConstraintDirection(const Vec &direction); + + /*! Returns the translation constraint Type(). + + Depending on this value, the Frame will freely translate + (AxisPlaneConstraint::FREE), will only be able to translate along an axis + direction (AxisPlaneConstraint::AXIS), will be forced to stay into a plane + (AxisPlaneConstraint::PLANE) or will not able to translate at all + (AxisPlaneConstraint::FORBIDDEN). + + Use Frame::setPosition() to define the position of the constrained Frame + before it gets constrained. */ + Type translationConstraintType() const { return translationConstraintType_; }; + /*! Returns the direction used by the translation constraint. + + It represents the axis direction (AxisPlaneConstraint::AXIS) or the plane + normal (AxisPlaneConstraint::PLANE) depending on the + translationConstraintType(). It is undefined for AxisPlaneConstraint::FREE or + AxisPlaneConstraint::FORBIDDEN. + + The AxisPlaneConstraint derived classes express this direction in different + coordinate system (camera for CameraConstraint, local for LocalConstraint, and + world for WorldConstraint). This value can be modified with + setTranslationConstraintDirection(). */ + Vec translationConstraintDirection() const { + return translationConstraintDir_; + }; + //@} + + /*! @name Rotation constraint */ + //@{ + /*! Overloading of Constraint::constrainRotation(). Empty. */ + virtual void constrainRotation(Quaternion &rotation, Frame *const frame) { + Q_UNUSED(rotation); + Q_UNUSED(frame); + }; + + void setRotationConstraint(Type type, const Vec &direction); + void setRotationConstraintType(Type type); + void setRotationConstraintDirection(const Vec &direction); + + /*! Returns the rotation constraint Type(). */ + Type rotationConstraintType() const { return rotationConstraintType_; }; + /*! Returns the axis direction used by the rotation constraint. + + This direction is defined only when rotationConstraintType() is + AxisPlaneConstraint::AXIS. + + The AxisPlaneConstraint derived classes express this direction in different + coordinate system (camera for CameraConstraint, local for LocalConstraint, and + world for WorldConstraint). This value can be modified with + setRotationConstraintDirection(). */ + Vec rotationConstraintDirection() const { return rotationConstraintDir_; }; + //@} private: - // int and not Type to allow for overloading and new types definition. - Type translationConstraintType_; - Type rotationConstraintType_; + // int and not Type to allow for overloading and new types definition. + Type translationConstraintType_; + Type rotationConstraintType_; - Vec translationConstraintDir_; - Vec rotationConstraintDir_; + Vec translationConstraintDir_; + Vec rotationConstraintDir_; }; - /*! \brief An AxisPlaneConstraint defined in the Frame local coordinate system. \class LocalConstraint constraint.h QGLViewer/constraint.h - The translationConstraintDirection() and rotationConstraintDirection() are expressed in the Frame - local coordinate system (see Frame::referenceFrame()). + The translationConstraintDirection() and rotationConstraintDirection() are + expressed in the Frame local coordinate system (see Frame::referenceFrame()). - See the constrainedFrame example for an illustration. */ -class QGLVIEWER_EXPORT LocalConstraint : public AxisPlaneConstraint -{ + See the constrainedFrame + example for an illustration. */ +class QGLVIEWER_EXPORT LocalConstraint : public AxisPlaneConstraint { public: - /*! Virtual destructor. Empty. */ - virtual ~LocalConstraint() {} + /*! Virtual destructor. Empty. */ + virtual ~LocalConstraint(){}; - virtual void constrainTranslation(Vec& translation, Frame* const frame); - virtual void constrainRotation (Quaternion& rotation, Frame* const frame); + virtual void constrainTranslation(Vec &translation, Frame *const frame); + virtual void constrainRotation(Quaternion &rotation, Frame *const frame); }; - - /*! \brief An AxisPlaneConstraint defined in the world coordinate system. - \class WorldConstraint constraint.h QGLViewer/constraint.h + \class WorldConstraint constraint.h QGLViewer/constraint.h - The translationConstraintDirection() and rotationConstraintDirection() are expressed in world - coordinate system. + The translationConstraintDirection() and rotationConstraintDirection() are + expressed in world coordinate system. - See the constrainedFrame and multiView examples for an illustration. */ -class QGLVIEWER_EXPORT WorldConstraint : public AxisPlaneConstraint -{ + See the constrainedFrame and + multiView examples for an + illustration. */ +class QGLVIEWER_EXPORT WorldConstraint : public AxisPlaneConstraint { public: - /*! Virtual destructor. Empty. */ - virtual ~WorldConstraint() {} + /*! Virtual destructor. Empty. */ + virtual ~WorldConstraint(){}; - virtual void constrainTranslation(Vec& translation, Frame* const frame); - virtual void constrainRotation (Quaternion& rotation, Frame* const frame); + virtual void constrainTranslation(Vec &translation, Frame *const frame); + virtual void constrainRotation(Quaternion &rotation, Frame *const frame); }; - - /*! \brief An AxisPlaneConstraint defined in the camera coordinate system. \class CameraConstraint constraint.h QGLViewer/constraint.h - The translationConstraintDirection() and rotationConstraintDirection() are expressed in the - associated camera() coordinate system. + The translationConstraintDirection() and rotationConstraintDirection() are + expressed in the associated camera() coordinate system. - See the constrainedFrame and constrainedCamera examples for an illustration. */ -class QGLVIEWER_EXPORT CameraConstraint : public AxisPlaneConstraint -{ + See the constrainedFrame and + constrainedCamera examples + for an illustration. */ +class QGLVIEWER_EXPORT CameraConstraint : public AxisPlaneConstraint { public: - explicit CameraConstraint(const Camera* const camera); - /*! Virtual destructor. Empty. */ - virtual ~CameraConstraint() {} + explicit CameraConstraint(const Camera *const camera); + /*! Virtual destructor. Empty. */ + virtual ~CameraConstraint(){}; - virtual void constrainTranslation(Vec& translation, Frame* const frame); - virtual void constrainRotation (Quaternion& rotation, Frame* const frame); + virtual void constrainTranslation(Vec &translation, Frame *const frame); + virtual void constrainRotation(Quaternion &rotation, Frame *const frame); - /*! Returns the associated Camera. Set using the CameraConstraint constructor. */ - const Camera* camera() const { return camera_; } + /*! Returns the associated Camera. Set using the CameraConstraint constructor. + */ + const Camera *camera() const { return camera_; }; private: - const Camera* const camera_; + const Camera *const camera_; }; } // namespace qglviewer diff --git a/octovis/src/extern/QGLViewer/domUtils.h b/octovis/src/extern/QGLViewer/domUtils.h index 39944683..48cc3f89 100644 --- a/octovis/src/extern/QGLViewer/domUtils.h +++ b/octovis/src/extern/QGLViewer/domUtils.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,143 +19,173 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #include "config.h" +#include #include #include #include -#include #include #ifndef DOXYGEN // QDomElement loading with syntax checking. -class DomUtils -{ +class DomUtils { private: - static void warning(const QString& message) - { - qWarning("%s", message.toLatin1().constData()); - } + static void warning(const QString &message) { + qWarning("%s", message.toLatin1().constData()); + } public: - static qreal qrealFromDom(const QDomElement& e, const QString& attribute, qreal defValue) - { - qreal value = defValue; - if (e.hasAttribute(attribute)) { - const QString s = e.attribute(attribute); - bool ok; - value = s.toDouble(&ok); - if (!ok) { - warning(QString("'%1' is not a valid qreal syntax for attribute \"%2\" in initialization of \"%3\". Setting value to %4.") - .arg(s).arg(attribute).arg(e.tagName()).arg(QString::number(defValue))); - value = defValue; - } - } else { - warning(QString("\"%1\" attribute missing in initialization of \"%2\". Setting value to %3.") - .arg(attribute).arg(e.tagName()).arg(QString::number(value))); - } + static qreal qrealFromDom(const QDomElement &e, const QString &attribute, + qreal defValue) { + qreal value = defValue; + if (e.hasAttribute(attribute)) { + const QString s = e.attribute(attribute); + bool ok; + value = s.toDouble(&ok); + if (!ok) { + warning(QString("'%1' is not a valid qreal syntax for attribute \"%2\" " + "in initialization of \"%3\". Setting value to %4.") + .arg(s) + .arg(attribute) + .arg(e.tagName()) + .arg(QString::number(defValue))); + value = defValue; + } + } else { + warning(QString("\"%1\" attribute missing in initialization of \"%2\". " + "Setting value to %3.") + .arg(attribute) + .arg(e.tagName()) + .arg(QString::number(value))); + } #if defined(isnan) - // The "isnan" method may not be available on all platforms. - // Find its equivalent or simply remove these two lines - if (isnan(value)) - warning(QString("Warning, attribute \"%1\" initialized to Not a Number in \"%2\"") - .arg(attribute).arg(e.tagName())); + // The "isnan" method may not be available on all platforms. + // Find its equivalent or simply remove these two lines + if (isnan(value)) + warning( + QString( + "Warning, attribute \"%1\" initialized to Not a Number in \"%2\"") + .arg(attribute) + .arg(e.tagName())); #endif - return value; - } - - static int intFromDom(const QDomElement& e, const QString& attribute, int defValue) - { - int value = defValue; - if (e.hasAttribute(attribute)) - { - const QString s = e.attribute(attribute); - bool ok; - value = s.toInt(&ok); - if (!ok) { - warning(QString("'%1' is not a valid integer syntax for attribute \"%2\" in initialization of \"%3\". Setting value to %4.") - .arg(s).arg(attribute).arg(e.tagName()).arg(QString::number(defValue))); - value = defValue; - } - } else { - warning(QString("\"%1\" attribute missing in initialization of \"%2\". Setting value to %3.") - .arg(attribute).arg(e.tagName()).arg(QString::number(value))); - } - - return value; - } - - static unsigned int uintFromDom(const QDomElement& e, const QString& attribute, unsigned int defValue) - { - unsigned int value = defValue; - if (e.hasAttribute(attribute)) - { - const QString s = e.attribute(attribute); - bool ok; - value = s.toUInt(&ok); - if (!ok) { - warning(QString("'%1' is not a valid unsigned integer syntax for attribute \"%2\" in initialization of \"%3\". Setting value to %4.") - .arg(s).arg(attribute).arg(e.tagName()).arg(QString::number(defValue))); - value = defValue; - } - } else { - warning(QString("\"%1\" attribute missing in initialization of \"%2\". Setting value to %3.") - .arg(attribute).arg(e.tagName()).arg(QString::number(value))); - } - - return value; - } - - static bool boolFromDom(const QDomElement& e, const QString& attribute, bool defValue) - { - bool value = defValue; - if (e.hasAttribute(attribute)) - { - const QString s = e.attribute(attribute); - if (s.toLower() == QString("true")) - value = true; - else if (s.toLower() == QString("false")) - value = false; - else - { - warning(QString("'%1' is not a valid boolean syntax for attribute \"%2\" in initialization of \"%3\". Setting value to %4.") - .arg(s).arg(attribute).arg(e.tagName()).arg(defValue?"true":"false")); - } - } else { - warning(QString("\"%1\" attribute missing in initialization of \"%2\". Setting value to %3.") - .arg(attribute).arg(e.tagName()).arg(value?"true":"false")); - } - - return value; - } - - static void setBoolAttribute(QDomElement& element, const QString& attribute, bool value) { - element.setAttribute(attribute, (value ? "true" : "false")); - } - - static QDomElement QColorDomElement(const QColor& color, const QString& name, QDomDocument& doc) - { - QDomElement de = doc.createElement(name); - de.setAttribute("red", QString::number(color.red())); - de.setAttribute("green", QString::number(color.green())); - de.setAttribute("blue", QString::number(color.blue())); - return de; - } - - static QColor QColorFromDom(const QDomElement& e) - { - int color[3]; - QStringList attribute; - attribute << "red" << "green" << "blue"; - for (int i=0; i using namespace qglviewer; using namespace std; - /*! Creates a default Frame. - Its position() is (0,0,0) and it has an identity orientation() Quaternion. The referenceFrame() - and the constraint() are \c NULL. */ -Frame::Frame() - : constraint_(NULL), referenceFrame_(NULL) -{} + Its position() is (0,0,0) and it has an identity orientation() Quaternion. The + referenceFrame() and the constraint() are \c nullptr. */ +Frame::Frame() : constraint_(nullptr), referenceFrame_(nullptr) {} /*! Creates a Frame with a position() and an orientation(). - See the Vec and Quaternion documentations for convenient constructors and methods. + See the Vec and Quaternion documentations for convenient constructors and + methods. - The Frame is defined in the world coordinate system (its referenceFrame() is \c NULL). It - has a \c NULL associated constraint(). */ -Frame::Frame(const Vec& position, const Quaternion& orientation) - : t_(position), q_(orientation), constraint_(NULL), referenceFrame_(NULL) -{} + The Frame is defined in the world coordinate system (its referenceFrame() is \c + nullptr). It has a \c nullptr associated constraint(). */ +Frame::Frame(const Vec &position, const Quaternion &orientation) + : t_(position), q_(orientation), constraint_(nullptr), referenceFrame_(nullptr) {} /*! Equal operator. The referenceFrame() and constraint() pointers are copied. \attention Signal and slot connections are not copied. */ -Frame& Frame::operator=(const Frame& frame) -{ - // Automatic compiler generated version would not emit the modified() signals as is done in - // setTranslationAndRotation. - setTranslationAndRotation(frame.translation(), frame.rotation()); - setConstraint(frame.constraint()); - setReferenceFrame(frame.referenceFrame()); - return *this; +Frame &Frame::operator=(const Frame &frame) { + // Automatic compiler generated version would not emit the modified() signals + // as is done in setTranslationAndRotation. + setTranslationAndRotation(frame.translation(), frame.rotation()); + setConstraint(frame.constraint()); + setReferenceFrame(frame.referenceFrame()); + return *this; } /*! Copy constructor. - The translation() and rotation() as well as constraint() and referenceFrame() pointers are - copied. */ -Frame::Frame(const Frame& frame) - : QObject() -{ - (*this) = frame; -} + The translation() and rotation() as well as constraint() and referenceFrame() + pointers are copied. */ +Frame::Frame(const Frame &frame) : QObject() { (*this) = frame; } /////////////////////////////// MATRICES ////////////////////////////////////// /*! Returns the 4x4 OpenGL transformation matrix represented by the Frame. - This method should be used in conjunction with \c glMultMatrixd() to modify the OpenGL modelview - matrix from a Frame hierarchy. With this Frame hierarchy: + This method should be used in conjunction with \c glMultMatrixd() to modify + the OpenGL modelview matrix from a Frame hierarchy. With this Frame hierarchy: \code Frame* body = new Frame(); Frame* leftArm = new Frame(); @@ -89,83 +80,87 @@ Frame::Frame(const Frame& frame) \code void Viewer::draw() { - glPushMatrix(); - glMultMatrixd(body->matrix()); - drawBody(); + glPushMatrix(); + glMultMatrixd(body->matrix()); + drawBody(); - glPushMatrix(); - glMultMatrixd(leftArm->matrix()); - drawArm(); - glPopMatrix(); + glPushMatrix(); + glMultMatrixd(leftArm->matrix()); + drawArm(); + glPopMatrix(); - glPushMatrix(); - glMultMatrixd(rightArm->matrix()); - drawArm(); - glPopMatrix(); + glPushMatrix(); + glMultMatrixd(rightArm->matrix()); + drawArm(); + glPopMatrix(); - glPopMatrix(); + glPopMatrix(); } \endcode - Note the use of nested \c glPushMatrix() and \c glPopMatrix() blocks to represent the frame hierarchy: \c - leftArm and \c rightArm are both correctly drawn with respect to the \c body coordinate system. + Note the use of nested \c glPushMatrix() and \c glPopMatrix() blocks to + represent the frame hierarchy: \c leftArm and \c rightArm are both correctly + drawn with respect to the \c body coordinate system. - This matrix only represents the local Frame transformation (i.e. with respect to the - referenceFrame()). Use worldMatrix() to get the full Frame transformation matrix (i.e. from the - world to the Frame coordinate system). These two match when the referenceFrame() is \c NULL. + This matrix only represents the local Frame transformation (i.e. with respect + to the referenceFrame()). Use worldMatrix() to get the full Frame + transformation matrix (i.e. from the world to the Frame coordinate system). + These two match when the referenceFrame() is \c nullptr. - The result is only valid until the next call to matrix(), getMatrix(), worldMatrix() or - getWorldMatrix(). Use it immediately (as above) or use getMatrix() instead. + The result is only valid until the next call to matrix(), getMatrix(), + worldMatrix() or getWorldMatrix(). Use it immediately (as above) or use + getMatrix() instead. - \attention The OpenGL format of the result is the transpose of the actual mathematical European - representation (translation is on the last \e line instead of the last \e column). + \attention The OpenGL format of the result is the transpose of the actual + mathematical European representation (translation is on the last \e line + instead of the last \e column). \note The scaling factor of the 4x4 matrix is 1.0. */ -const GLdouble* Frame::matrix() const -{ - static GLdouble m[4][4]; - getMatrix(m); - return (const GLdouble*)(m); +const GLdouble *Frame::matrix() const { + static GLdouble m[4][4]; + getMatrix(m); + return (const GLdouble *)(m); } -/*! \c GLdouble[4][4] version of matrix(). See also getWorldMatrix() and matrix(). */ -void Frame::getMatrix(GLdouble m[4][4]) const -{ - q_.getMatrix(m); +/*! \c GLdouble[4][4] version of matrix(). See also getWorldMatrix() and + * matrix(). */ +void Frame::getMatrix(GLdouble m[4][4]) const { + q_.getMatrix(m); - m[3][0] = t_[0]; - m[3][1] = t_[1]; - m[3][2] = t_[2]; + m[3][0] = t_[0]; + m[3][1] = t_[1]; + m[3][2] = t_[2]; } -/*! \c GLdouble[16] version of matrix(). See also getWorldMatrix() and matrix(). */ -void Frame::getMatrix(GLdouble m[16]) const -{ - q_.getMatrix(m); +/*! \c GLdouble[16] version of matrix(). See also getWorldMatrix() and matrix(). + */ +void Frame::getMatrix(GLdouble m[16]) const { + q_.getMatrix(m); - m[12] = t_[0]; - m[13] = t_[1]; - m[14] = t_[2]; + m[12] = t_[0]; + m[13] = t_[1]; + m[14] = t_[2]; } /*! Returns a Frame representing the inverse of the Frame space transformation. - The rotation() of the new Frame is the Quaternion::inverse() of the original rotation. - Its translation() is the negated inverse rotated image of the original translation. + The rotation() of the new Frame is the Quaternion::inverse() of the original + rotation. Its translation() is the negated inverse rotated image of the + original translation. - If a Frame is considered as a space rigid transformation (translation and rotation), the inverse() - Frame performs the inverse transformation. + If a Frame is considered as a space rigid transformation (translation and + rotation), the inverse() Frame performs the inverse transformation. - Only the local Frame transformation (i.e. defined with respect to the referenceFrame()) is inverted. - Use worldInverse() for a global inverse. + Only the local Frame transformation (i.e. defined with respect to the + referenceFrame()) is inverted. Use worldInverse() for a global inverse. - The resulting Frame has the same referenceFrame() as the Frame and a \c NULL constraint(). + The resulting Frame has the same referenceFrame() as the Frame and a \c nullptr + constraint(). \note The scaling factor of the 4x4 matrix is 1.0. */ -Frame Frame::inverse() const -{ - Frame fr(-(q_.inverseRotate(t_)), q_.inverse()); - fr.setReferenceFrame(referenceFrame()); - return fr; +Frame Frame::inverse() const { + Frame fr(-(q_.inverseRotate(t_)), q_.inverse()); + fr.setReferenceFrame(referenceFrame()); + return fr; } /*! Returns the 4x4 OpenGL transformation matrix represented by the Frame. @@ -181,72 +176,71 @@ Frame Frame::inverse() const glPopMatrix(); \endcode - This matrix represents the global Frame transformation: the entire referenceFrame() hierarchy is - taken into account to define the Frame transformation from the world coordinate system. Use - matrix() to get the local Frame transformation matrix (i.e. defined with respect to the - referenceFrame()). These two match when the referenceFrame() is \c NULL. + This matrix represents the global Frame transformation: the entire + referenceFrame() hierarchy is taken into account to define the Frame + transformation from the world coordinate system. Use matrix() to get the local + Frame transformation matrix (i.e. defined with respect to the + referenceFrame()). These two match when the referenceFrame() is \c nullptr. - The OpenGL format of the result is the transpose of the actual mathematical European - representation (translation is on the last \e line instead of the last \e column). + The OpenGL format of the result is the transpose of the actual mathematical + European representation (translation is on the last \e line instead of the + last \e column). - \attention The result is only valid until the next call to matrix(), getMatrix(), worldMatrix() or - getWorldMatrix(). Use it immediately (as above) or use getWorldMatrix() instead. + \attention The result is only valid until the next call to matrix(), + getMatrix(), worldMatrix() or getWorldMatrix(). Use it immediately (as above) + or use getWorldMatrix() instead. \note The scaling factor of the 4x4 matrix is 1.0. */ -const GLdouble* Frame::worldMatrix() const -{ - // This test is done for efficiency reasons (creates lots of temp objects otherwise). - if (referenceFrame()) - { - static Frame fr; - fr.setTranslation(position()); - fr.setRotation(orientation()); - return fr.matrix(); - } - else - return matrix(); -} - -/*! qreal[4][4] parameter version of worldMatrix(). See also getMatrix() and matrix(). */ -void Frame::getWorldMatrix(GLdouble m[4][4]) const -{ - const GLdouble* mat = worldMatrix(); - for (int i=0; i<4; ++i) - for (int j=0; j<4; ++j) - m[i][j] = mat[i*4+j]; -} - -/*! qreal[16] parameter version of worldMatrix(). See also getMatrix() and matrix(). */ -void Frame::getWorldMatrix(GLdouble m[16]) const -{ - const GLdouble* mat = worldMatrix(); - for (int i=0; i<16; ++i) - m[i] = mat[i]; -} - -/*! This is an overloaded method provided for convenience. Same as setFromMatrix(). */ -void Frame::setFromMatrix(const GLdouble m[4][4]) -{ - if (fabs(m[3][3]) < 1E-8) - { - qWarning("Frame::setFromMatrix: Null homogeneous coefficient"); - return; - } - - qreal rot[3][3]; - for (int i=0; i<3; ++i) - { - t_[i] = m[3][i] / m[3][3]; - for (int j=0; j<3; ++j) - // Beware of the transposition (OpenGL to European math) - rot[i][j] = m[j][i] / m[3][3]; - } - q_.setFromRotationMatrix(rot); - Q_EMIT modified(); -} - -/*! Sets the Frame from an OpenGL matrix representation (rotation in the upper left 3x3 matrix and - translation on the last line). +const GLdouble *Frame::worldMatrix() const { + // This test is done for efficiency reasons (creates lots of temp objects + // otherwise). + if (referenceFrame()) { + static Frame fr; + fr.setTranslation(position()); + fr.setRotation(orientation()); + return fr.matrix(); + } else + return matrix(); +} + +/*! qreal[4][4] parameter version of worldMatrix(). See also getMatrix() and + * matrix(). */ +void Frame::getWorldMatrix(GLdouble m[4][4]) const { + const GLdouble *mat = worldMatrix(); + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + m[i][j] = mat[i * 4 + j]; +} + +/*! qreal[16] parameter version of worldMatrix(). See also getMatrix() and + * matrix(). */ +void Frame::getWorldMatrix(GLdouble m[16]) const { + const GLdouble *mat = worldMatrix(); + for (int i = 0; i < 16; ++i) + m[i] = mat[i]; +} + +/*! This is an overloaded method provided for convenience. Same as + * setFromMatrix(). */ +void Frame::setFromMatrix(const GLdouble m[4][4]) { + if (fabs(m[3][3]) < 1E-8) { + qWarning("Frame::setFromMatrix: Null homogeneous coefficient"); + return; + } + + qreal rot[3][3]; + for (int i = 0; i < 3; ++i) { + t_[i] = m[3][i] / m[3][3]; + for (int j = 0; j < 3; ++j) + // Beware of the transposition (OpenGL to European math) + rot[i][j] = m[j][i] / m[3][3]; + } + q_.setFromRotationMatrix(rot); + Q_EMIT modified(); +} + +/*! Sets the Frame from an OpenGL matrix representation (rotation in the upper + left 3x3 matrix and translation on the last line). Hence, if a code fragment looks like: \code @@ -260,260 +254,248 @@ void Frame::setFromMatrix(const GLdouble m[4][4]) glMultMatrixd(fr.matrix()); \endcode - Using this conversion, you can benefit from the powerful Frame transformation methods to translate - points and vectors to and from the Frame coordinate system to any other Frame coordinate system - (including the world coordinate system). See coordinatesOf() and transformOf(). + Using this conversion, you can benefit from the powerful Frame transformation + methods to translate points and vectors to and from the Frame coordinate system + to any other Frame coordinate system (including the world coordinate system). + See coordinatesOf() and transformOf(). Emits the modified() signal. See also matrix(), getMatrix() and Quaternion::setFromRotationMatrix(). - \attention A Frame does not contain a scale factor. The possible scaling in \p m will not be - converted into the Frame by this method. */ -void Frame::setFromMatrix(const GLdouble m[16]) -{ - GLdouble mat[4][4]; - for (int i=0; i<4; ++i) - for (int j=0; j<4; ++j) - mat[i][j] = m[i*4+j]; - setFromMatrix(mat); + \attention A Frame does not contain a scale factor. The possible scaling in \p + m will not be converted into the Frame by this method. */ +void Frame::setFromMatrix(const GLdouble m[16]) { + GLdouble mat[4][4]; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + mat[i][j] = m[i * 4 + j]; + setFromMatrix(mat); } -//////////////////// SET AND GET LOCAL TRANSLATION AND ROTATION /////////////////////////////// - +//////////////////// SET AND GET LOCAL TRANSLATION AND ROTATION +////////////////////////////////// /*! Same as setTranslation(), but with \p qreal parameters. */ -void Frame::setTranslation(qreal x, qreal y, qreal z) -{ - setTranslation(Vec(x, y, z)); +void Frame::setTranslation(qreal x, qreal y, qreal z) { + setTranslation(Vec(x, y, z)); } /*! Fill \c x, \c y and \c z with the translation() of the Frame. */ -void Frame::getTranslation(qreal& x, qreal& y, qreal& z) const -{ - const Vec t = translation(); - x = t[0]; - y = t[1]; - z = t[2]; +void Frame::getTranslation(qreal &x, qreal &y, qreal &z) const { + const Vec t = translation(); + x = t[0]; + y = t[1]; + z = t[2]; } /*! Same as setRotation() but with \c qreal Quaternion parameters. */ -void Frame::setRotation(qreal q0, qreal q1, qreal q2, qreal q3) -{ - setRotation(Quaternion(q0, q1, q2, q3)); +void Frame::setRotation(qreal q0, qreal q1, qreal q2, qreal q3) { + setRotation(Quaternion(q0, q1, q2, q3)); } /*! The \p q are set to the rotation() of the Frame. See Quaternion::Quaternion(qreal, qreal, qreal, qreal) for details on \c q. */ -void Frame::getRotation(qreal& q0, qreal& q1, qreal& q2, qreal& q3) const -{ - const Quaternion q = rotation(); - q0 = q[0]; - q1 = q[1]; - q2 = q[2]; - q3 = q[3]; +void Frame::getRotation(qreal &q0, qreal &q1, qreal &q2, qreal &q3) const { + const Quaternion q = rotation(); + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; } //////////////////////////////////////////////////////////////////////////////// /*! Translates the Frame of \p t (defined in the Frame coordinate system). - The translation actually applied to the Frame may differ from \p t since it can be filtered by the - constraint(). Use translate(Vec&) or setTranslationWithConstraint() to retrieve the filtered - translation value. Use setTranslation() to directly translate the Frame without taking the + The translation actually applied to the Frame may differ from \p t since it + can be filtered by the constraint(). Use translate(Vec&) or + setTranslationWithConstraint() to retrieve the filtered translation value. Use + setTranslation() to directly translate the Frame without taking the constraint() into account. See also rotate(const Quaternion&). Emits the modified() signal. */ -void Frame::translate(const Vec& t) -{ - Vec tbis = t; - translate(tbis); +void Frame::translate(const Vec &t) { + Vec tbis = t; + translate(tbis); } -/*! Same as translate(const Vec&) but \p t may be modified to satisfy the translation constraint(). - Its new value corresponds to the translation that has actually been applied to the Frame. */ -void Frame::translate(Vec& t) -{ - if (constraint()) - constraint()->constrainTranslation(t, this); - t_ += t; - Q_EMIT modified(); +/*! Same as translate(const Vec&) but \p t may be modified to satisfy the + translation constraint(). Its new value corresponds to the translation that + has actually been applied to the Frame. */ +void Frame::translate(Vec &t) { + if (constraint()) + constraint()->constrainTranslation(t, this); + t_ += t; + Q_EMIT modified(); } /*! Same as translate(const Vec&) but with \c qreal parameters. */ -void Frame::translate(qreal x, qreal y, qreal z) -{ - Vec t(x,y,z); - translate(t); +void Frame::translate(qreal x, qreal y, qreal z) { + Vec t(x, y, z); + translate(t); } /*! Same as translate(Vec&) but with \c qreal parameters. */ -void Frame::translate(qreal& x, qreal& y, qreal& z) -{ - Vec t(x,y,z); - translate(t); - x = t[0]; - y = t[1]; - z = t[2]; +void Frame::translate(qreal &x, qreal &y, qreal &z) { + Vec t(x, y, z); + translate(t); + x = t[0]; + y = t[1]; + z = t[2]; } /*! Rotates the Frame by \p q (defined in the Frame coordinate system): R = R*q. - The rotation actually applied to the Frame may differ from \p q since it can be filtered by the - constraint(). Use rotate(Quaternion&) or setRotationWithConstraint() to retrieve the filtered - rotation value. Use setRotation() to directly rotate the Frame without taking the constraint() + The rotation actually applied to the Frame may differ from \p q since it can + be filtered by the constraint(). Use rotate(Quaternion&) or + setRotationWithConstraint() to retrieve the filtered rotation value. Use + setRotation() to directly rotate the Frame without taking the constraint() into account. See also translate(const Vec&). Emits the modified() signal. */ -void Frame::rotate(const Quaternion& q) -{ - Quaternion qbis = q; - rotate(qbis); +void Frame::rotate(const Quaternion &q) { + Quaternion qbis = q; + rotate(qbis); } -/*! Same as rotate(const Quaternion&) but \p q may be modified to satisfy the rotation constraint(). - Its new value corresponds to the rotation that has actually been applied to the Frame. */ -void Frame::rotate(Quaternion& q) -{ - if (constraint()) - constraint()->constrainRotation(q, this); - q_ *= q; - q_.normalize(); // Prevents numerical drift - Q_EMIT modified(); +/*! Same as rotate(const Quaternion&) but \p q may be modified to satisfy the + rotation constraint(). Its new value corresponds to the rotation that has + actually been applied to the Frame. */ +void Frame::rotate(Quaternion &q) { + if (constraint()) + constraint()->constrainRotation(q, this); + q_ *= q; + q_.normalize(); // Prevents numerical drift + Q_EMIT modified(); } /*! Same as rotate(Quaternion&) but with \c qreal Quaternion parameters. */ -void Frame::rotate(qreal& q0, qreal& q1, qreal& q2, qreal& q3) -{ - Quaternion q(q0,q1,q2,q3); - rotate(q); - q0 = q[0]; - q1 = q[1]; - q2 = q[2]; - q3 = q[3]; +void Frame::rotate(qreal &q0, qreal &q1, qreal &q2, qreal &q3) { + Quaternion q(q0, q1, q2, q3); + rotate(q); + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; } -/*! Same as rotate(const Quaternion&) but with \c qreal Quaternion parameters. */ -void Frame::rotate(qreal q0, qreal q1, qreal q2, qreal q3) -{ - Quaternion q(q0,q1,q2,q3); - rotate(q); +/*! Same as rotate(const Quaternion&) but with \c qreal Quaternion parameters. + */ +void Frame::rotate(qreal q0, qreal q1, qreal q2, qreal q3) { + Quaternion q(q0, q1, q2, q3); + rotate(q); } /*! Makes the Frame rotate() by \p rotation around \p point. - \p point is defined in the world coordinate system, while the \p rotation axis is defined in the - Frame coordinate system. + \p point is defined in the world coordinate system, while the \p rotation axis + is defined in the Frame coordinate system. If the Frame has a constraint(), \p rotation is first constrained using - Constraint::constrainRotation(). The translation which results from the filtered rotation around - \p point is then computed and filtered using Constraint::constrainTranslation(). The new \p - rotation value corresponds to the rotation that has actually been applied to the Frame. + Constraint::constrainRotation(). The translation which results from the + filtered rotation around \p point is then computed and filtered using + Constraint::constrainTranslation(). The new \p rotation value corresponds to + the rotation that has actually been applied to the Frame. Emits the modified() signal. */ -void Frame::rotateAroundPoint(Quaternion& rotation, const Vec& point) -{ - if (constraint()) - constraint()->constrainRotation(rotation, this); - q_ *= rotation; - q_.normalize(); // Prevents numerical drift - Vec trans = point + Quaternion(inverseTransformOf(rotation.axis()), rotation.angle()).rotate(position()-point) - t_; - if (constraint()) - constraint()->constrainTranslation(trans, this); - t_ += trans; - Q_EMIT modified(); -} - -/*! Same as rotateAroundPoint(), but with a \c const \p rotation Quaternion. Note that the actual - rotation may differ since it can be filtered by the constraint(). */ -void Frame::rotateAroundPoint(const Quaternion& rotation, const Vec& point) -{ - Quaternion rot = rotation; - rotateAroundPoint(rot, point); -} - -//////////////////// SET AND GET WORLD POSITION AND ORIENTATION /////////////////////////////// - -/*! Sets the position() of the Frame, defined in the world coordinate system. Emits the modified() - signal. - -Use setTranslation() to define the \e local frame translation (with respect to the -referenceFrame()). The potential constraint() of the Frame is not taken into account, use -setPositionWithConstraint() instead. */ -void Frame::setPosition(const Vec& position) -{ - if (referenceFrame()) - setTranslation(referenceFrame()->coordinatesOf(position)); - else - setTranslation(position); +void Frame::rotateAroundPoint(Quaternion &rotation, const Vec &point) { + if (constraint()) + constraint()->constrainRotation(rotation, this); + q_ *= rotation; + q_.normalize(); // Prevents numerical drift + Vec trans = point + + Quaternion(inverseTransformOf(rotation.axis()), rotation.angle()) + .rotate(position() - point) - + t_; + if (constraint()) + constraint()->constrainTranslation(trans, this); + t_ += trans; + Q_EMIT modified(); +} + +/*! Same as rotateAroundPoint(), but with a \c const \p rotation Quaternion. + Note that the actual rotation may differ since it can be filtered by the + constraint(). */ +void Frame::rotateAroundPoint(const Quaternion &rotation, const Vec &point) { + Quaternion rot = rotation; + rotateAroundPoint(rot, point); +} + +//////////////////// SET AND GET WORLD POSITION AND ORIENTATION +////////////////////////////////// + +/*! Sets the position() of the Frame, defined in the world coordinate system. +Emits the modified() signal. + +Use setTranslation() to define the \e local frame translation (with respect to +the referenceFrame()). The potential constraint() of the Frame is not taken into +account, use setPositionWithConstraint() instead. */ +void Frame::setPosition(const Vec &position) { + if (referenceFrame()) + setTranslation(referenceFrame()->coordinatesOf(position)); + else + setTranslation(position); } /*! Same as setPosition(), but with \c qreal parameters. */ -void Frame::setPosition(qreal x, qreal y, qreal z) -{ - setPosition(Vec(x, y, z)); +void Frame::setPosition(qreal x, qreal y, qreal z) { + setPosition(Vec(x, y, z)); } /*! Same as successive calls to setPosition() and then setOrientation(). -Only one modified() signal is emitted, which is convenient if this signal is connected to a -QGLViewer::update() slot. See also setTranslationAndRotation() and -setPositionAndOrientationWithConstraint(). */ -void Frame::setPositionAndOrientation(const Vec& position, const Quaternion& orientation) -{ - if (referenceFrame()) - { - t_ = referenceFrame()->coordinatesOf(position); - q_ = referenceFrame()->orientation().inverse() * orientation; - } - else - { - t_ = position; - q_ = orientation; - } - Q_EMIT modified(); +Only one modified() signal is emitted, which is convenient if this signal is +connected to a QGLViewer::update() slot. See also setTranslationAndRotation() +and setPositionAndOrientationWithConstraint(). */ +void Frame::setPositionAndOrientation(const Vec &position, + const Quaternion &orientation) { + if (referenceFrame()) { + t_ = referenceFrame()->coordinatesOf(position); + q_ = referenceFrame()->orientation().inverse() * orientation; + } else { + t_ = position; + q_ = orientation; + } + Q_EMIT modified(); } - /*! Same as successive calls to setTranslation() and then setRotation(). -Only one modified() signal is emitted, which is convenient if this signal is connected to a -QGLViewer::update() slot. See also setPositionAndOrientation() and -setTranslationAndRotationWithConstraint(). */ -void Frame::setTranslationAndRotation(const Vec& translation, const Quaternion& rotation) -{ - t_ = translation; - q_ = rotation; - Q_EMIT modified(); +Only one modified() signal is emitted, which is convenient if this signal is +connected to a QGLViewer::update() slot. See also setPositionAndOrientation() +and setTranslationAndRotationWithConstraint(). */ +void Frame::setTranslationAndRotation(const Vec &translation, + const Quaternion &rotation) { + t_ = translation; + q_ = rotation; + Q_EMIT modified(); } - /*! \p x, \p y and \p z are set to the position() of the Frame. */ -void Frame::getPosition(qreal& x, qreal& y, qreal& z) const -{ - Vec p = position(); - x = p.x; - y = p.y; - z = p.z; +void Frame::getPosition(qreal &x, qreal &y, qreal &z) const { + Vec p = position(); + x = p.x; + y = p.y; + z = p.z; } -/*! Sets the orientation() of the Frame, defined in the world coordinate system. Emits the modified() signal. +/*! Sets the orientation() of the Frame, defined in the world coordinate system. +Emits the modified() signal. -Use setRotation() to define the \e local frame rotation (with respect to the referenceFrame()). The -potential constraint() of the Frame is not taken into account, use setOrientationWithConstraint() -instead. */ -void Frame::setOrientation(const Quaternion& orientation) -{ - if (referenceFrame()) - setRotation(referenceFrame()->orientation().inverse() * orientation); - else - setRotation(orientation); +Use setRotation() to define the \e local frame rotation (with respect to the +referenceFrame()). The potential constraint() of the Frame is not taken into +account, use setOrientationWithConstraint() instead. */ +void Frame::setOrientation(const Quaternion &orientation) { + if (referenceFrame()) + setRotation(referenceFrame()->orientation().inverse() * orientation); + else + setRotation(orientation); } /*! Same as setOrientation(), but with \c qreal parameters. */ -void Frame::setOrientation(qreal q0, qreal q1, qreal q2, qreal q3) -{ - setOrientation(Quaternion(q0, q1, q2, q3)); +void Frame::setOrientation(qreal q0, qreal q1, qreal q2, qreal q3) { + setOrientation(Quaternion(q0, q1, q2, q3)); } /*! Get the current orientation of the frame (same as orientation()). @@ -523,459 +505,435 @@ void Frame::setOrientation(qreal q0, qreal q1, qreal q2, qreal q3) /*! The \p q are set to the orientation() of the Frame. See Quaternion::Quaternion(qreal, qreal, qreal, qreal) for details on \c q. */ -void Frame::getOrientation(qreal& q0, qreal& q1, qreal& q2, qreal& q3) const -{ - Quaternion o = orientation(); - q0 = o[0]; - q1 = o[1]; - q2 = o[2]; - q3 = o[3]; +void Frame::getOrientation(qreal &q0, qreal &q1, qreal &q2, qreal &q3) const { + Quaternion o = orientation(); + q0 = o[0]; + q1 = o[1]; + q2 = o[2]; + q3 = o[3]; } -/*! Returns the position of the Frame, defined in the world coordinate system. See also - orientation(), setPosition() and translation(). */ +/*! Returns the position of the Frame, defined in the world coordinate system. + See also orientation(), setPosition() and translation(). */ Vec Frame::position() const { - if (referenceFrame_) - return inverseCoordinatesOf(Vec(0.0,0.0,0.0)); - else - return t_; + if (referenceFrame_) + return inverseCoordinatesOf(Vec(0.0, 0.0, 0.0)); + else + return t_; +} + +/*! Returns the orientation of the Frame, defined in the world coordinate + system. See also position(), setOrientation() and rotation(). */ +Quaternion Frame::orientation() const { + Quaternion res = rotation(); + const Frame *fr = referenceFrame(); + while (fr != nullptr) { + res = fr->rotation() * res; + fr = fr->referenceFrame(); + } + return res; } -/*! Returns the orientation of the Frame, defined in the world coordinate system. See also - position(), setOrientation() and rotation(). */ -Quaternion Frame::orientation() const -{ - Quaternion res = rotation(); - const Frame* fr = referenceFrame(); - while (fr != NULL) - { - res = fr->rotation() * res; - fr = fr->referenceFrame(); - } - return res; -} +////////////////////// C o n s t r a i n t V e r s i o n s +///////////////////////////// + +/*! Same as setTranslation(), but \p translation is modified so that the + potential constraint() of the Frame is satisfied. + Emits the modified() signal. See also setRotationWithConstraint() and + setPositionWithConstraint(). */ +void Frame::setTranslationWithConstraint(Vec &translation) { + Vec deltaT = translation - this->translation(); + if (constraint()) + constraint()->constrainTranslation(deltaT, this); + + setTranslation(this->translation() + deltaT); + translation = this->translation(); +} -////////////////////// C o n s t r a i n t V e r s i o n s ////////////////////////// +/*! Same as setRotation(), but \p rotation is modified so that the potential + constraint() of the Frame is satisfied. -/*! Same as setTranslation(), but \p translation is modified so that the potential constraint() of the - Frame is satisfied. + Emits the modified() signal. See also setTranslationWithConstraint() and + setOrientationWithConstraint(). */ +void Frame::setRotationWithConstraint(Quaternion &rotation) { + Quaternion deltaQ = this->rotation().inverse() * rotation; + if (constraint()) + constraint()->constrainRotation(deltaQ, this); - Emits the modified() signal. See also setRotationWithConstraint() and setPositionWithConstraint(). */ -void Frame::setTranslationWithConstraint(Vec& translation) -{ - Vec deltaT = translation - this->translation(); - if (constraint()) - constraint()->constrainTranslation(deltaT, this); + // Prevent numerical drift + deltaQ.normalize(); - setTranslation(this->translation() + deltaT); - translation = this->translation(); + setRotation(this->rotation() * deltaQ); + q_.normalize(); + rotation = this->rotation(); } -/*! Same as setRotation(), but \p rotation is modified so that the potential constraint() of the - Frame is satisfied. +/*! Same as setTranslationAndRotation(), but \p translation and \p orientation + are modified to satisfy the constraint(). Emits the modified() signal. */ +void Frame::setTranslationAndRotationWithConstraint(Vec &translation, + Quaternion &rotation) { + Vec deltaT = translation - this->translation(); + Quaternion deltaQ = this->rotation().inverse() * rotation; - Emits the modified() signal. See also setTranslationWithConstraint() and setOrientationWithConstraint(). */ -void Frame::setRotationWithConstraint(Quaternion& rotation) -{ - Quaternion deltaQ = this->rotation().inverse() * rotation; - if (constraint()) - constraint()->constrainRotation(deltaQ, this); + if (constraint()) { + constraint()->constrainTranslation(deltaT, this); + constraint()->constrainRotation(deltaQ, this); + } - // Prevent numerical drift - deltaQ.normalize(); + // Prevent numerical drift + deltaQ.normalize(); - setRotation(this->rotation() * deltaQ); - q_.normalize(); - rotation = this->rotation(); -} + t_ += deltaT; + q_ *= deltaQ; + q_.normalize(); -/*! Same as setTranslationAndRotation(), but \p translation and \p orientation are modified to - satisfy the constraint(). Emits the modified() signal. */ -void Frame::setTranslationAndRotationWithConstraint(Vec& translation, Quaternion& rotation) -{ - Vec deltaT = translation - this->translation(); - Quaternion deltaQ = this->rotation().inverse() * rotation; + translation = this->translation(); + rotation = this->rotation(); + + Q_EMIT modified(); +} - if (constraint()) - { - constraint()->constrainTranslation(deltaT, this); - constraint()->constrainRotation(deltaQ, this); - } +/*! Same as setPosition(), but \p position is modified so that the potential + constraint() of the Frame is satisfied. See also + setOrientationWithConstraint() and setTranslationWithConstraint(). */ +void Frame::setPositionWithConstraint(Vec &position) { + if (referenceFrame()) + position = referenceFrame()->coordinatesOf(position); - // Prevent numerical drift - deltaQ.normalize(); + setTranslationWithConstraint(position); +} - t_ += deltaT; - q_ *= deltaQ; - q_.normalize(); +/*! Same as setOrientation(), but \p orientation is modified so that the + potential constraint() of the Frame is satisfied. See also + setPositionWithConstraint() and setRotationWithConstraint(). */ +void Frame::setOrientationWithConstraint(Quaternion &orientation) { + if (referenceFrame()) + orientation = referenceFrame()->orientation().inverse() * orientation; - translation = this->translation(); - rotation = this->rotation(); + setRotationWithConstraint(orientation); +} - Q_EMIT modified(); +/*! Same as setPositionAndOrientation() but \p position and \p orientation are +modified to satisfy the constraint. Emits the modified() signal. */ +void Frame::setPositionAndOrientationWithConstraint(Vec &position, + Quaternion &orientation) { + if (referenceFrame()) { + position = referenceFrame()->coordinatesOf(position); + orientation = referenceFrame()->orientation().inverse() * orientation; + } + setTranslationAndRotationWithConstraint(position, orientation); } -/*! Same as setPosition(), but \p position is modified so that the potential constraint() of the - Frame is satisfied. See also setOrientationWithConstraint() and setTranslationWithConstraint(). */ -void Frame::setPositionWithConstraint(Vec& position) -{ - if (referenceFrame()) - position = referenceFrame()->coordinatesOf(position); +///////////////////////////// REFERENCE FRAMES +////////////////////////////////////////// + +/*! Sets the referenceFrame() of the Frame. + +The Frame translation() and rotation() are then defined in the referenceFrame() +coordinate system. Use position() and orientation() to express these in the +world coordinate system. + +Emits the modified() signal if \p refFrame differs from the current +referenceFrame(). + +Using this method, you can create a hierarchy of Frames. This hierarchy needs to +be a tree, which root is the world coordinate system (i.e. a \c nullptr +referenceFrame()). A warning is printed and no action is performed if setting \p +refFrame as the referenceFrame() would create a loop in the Frame hierarchy (see +settingAsReferenceFrameWillCreateALoop()). */ +void Frame::setReferenceFrame(const Frame *const refFrame) { + if (settingAsReferenceFrameWillCreateALoop(refFrame)) + qWarning("Frame::setReferenceFrame would create a loop in Frame hierarchy"); + else { + bool identical = (referenceFrame_ == refFrame); + referenceFrame_ = refFrame; + if (!identical) + Q_EMIT modified(); + } +} - setTranslationWithConstraint(position); +/*! Returns \c true if setting \p frame as the Frame's referenceFrame() would + create a loop in the Frame hierarchy. */ +bool Frame::settingAsReferenceFrameWillCreateALoop(const Frame *const frame) { + const Frame *f = frame; + while (f != nullptr) { + if (f == this) + return true; + f = f->referenceFrame(); + } + return false; } -/*! Same as setOrientation(), but \p orientation is modified so that the potential constraint() of the Frame - is satisfied. See also setPositionWithConstraint() and setRotationWithConstraint(). */ -void Frame::setOrientationWithConstraint(Quaternion& orientation) -{ - if (referenceFrame()) - orientation = referenceFrame()->orientation().inverse() * orientation; +///////////////////////// FRAME TRANSFORMATIONS OF 3D POINTS +///////////////////////////////// + +/*! Returns the Frame coordinates of a point \p src defined in the world + coordinate system (converts from world to Frame). - setRotationWithConstraint(orientation); + inverseCoordinatesOf() performs the inverse convertion. transformOf() converts + 3D vectors instead of 3D coordinates. + + See the frameTransform example + for an illustration. */ +Vec Frame::coordinatesOf(const Vec &src) const { + if (referenceFrame()) + return localCoordinatesOf(referenceFrame()->coordinatesOf(src)); + else + return localCoordinatesOf(src); } -/*! Same as setPositionAndOrientation() but \p position and \p orientation are modified to satisfy -the constraint. Emits the modified() signal. */ -void Frame::setPositionAndOrientationWithConstraint(Vec& position, Quaternion& orientation) -{ - if (referenceFrame()) - { - position = referenceFrame()->coordinatesOf(position); - orientation = referenceFrame()->orientation().inverse() * orientation; - } - setTranslationAndRotationWithConstraint(position, orientation); +/*! Returns the world coordinates of the point whose position in the Frame + coordinate system is \p src (converts from Frame to world). + + coordinatesOf() performs the inverse convertion. Use inverseTransformOf() to + transform 3D vectors instead of 3D coordinates. */ +Vec Frame::inverseCoordinatesOf(const Vec &src) const { + const Frame *fr = this; + Vec res = src; + while (fr != nullptr) { + res = fr->localInverseCoordinatesOf(res); + fr = fr->referenceFrame(); + } + return res; } +/*! Returns the Frame coordinates of a point \p src defined in the + referenceFrame() coordinate system (converts from referenceFrame() to Frame). + + localInverseCoordinatesOf() performs the inverse convertion. See also + localTransformOf(). */ +Vec Frame::localCoordinatesOf(const Vec &src) const { + return rotation().inverseRotate(src - translation()); +} -///////////////////////////// REFERENCE FRAMES /////////////////////////////////////// +/*! Returns the referenceFrame() coordinates of a point \p src defined in the + Frame coordinate system (converts from Frame to referenceFrame()). -/*! Sets the referenceFrame() of the Frame. + localCoordinatesOf() performs the inverse convertion. See also + localInverseTransformOf(). */ +Vec Frame::localInverseCoordinatesOf(const Vec &src) const { + return rotation().rotate(src) + translation(); +} -The Frame translation() and rotation() are then defined in the referenceFrame() coordinate system. -Use position() and orientation() to express these in the world coordinate system. - -Emits the modified() signal if \p refFrame differs from the current referenceFrame(). - -Using this method, you can create a hierarchy of Frames. This hierarchy needs to be a tree, which -root is the world coordinate system (i.e. a \c NULL referenceFrame()). A warning is printed and no -action is performed if setting \p refFrame as the referenceFrame() would create a loop in the Frame -hierarchy (see settingAsReferenceFrameWillCreateALoop()). */ -void Frame::setReferenceFrame(const Frame* const refFrame) -{ - if (settingAsReferenceFrameWillCreateALoop(refFrame)) - qWarning("Frame::setReferenceFrame would create a loop in Frame hierarchy"); - else - { - bool identical = (referenceFrame_ == refFrame); - referenceFrame_ = refFrame; - if (!identical) - Q_EMIT modified(); - } -} - -/*! Returns \c true if setting \p frame as the Frame's referenceFrame() would create a loop in the - Frame hierarchy. */ -bool Frame::settingAsReferenceFrameWillCreateALoop(const Frame* const frame) -{ - const Frame* f = frame; - while (f != NULL) - { - if (f == this) - return true; - f = f->referenceFrame(); - } - return false; -} - -///////////////////////// FRAME TRANSFORMATIONS OF 3D POINTS ////////////////////////////// - -/*! Returns the Frame coordinates of a point \p src defined in the world coordinate system (converts - from world to Frame). - - inverseCoordinatesOf() performs the inverse convertion. transformOf() converts 3D vectors instead - of 3D coordinates. - - See the frameTransform example for an - illustration. */ -Vec Frame::coordinatesOf(const Vec& src) const -{ - if (referenceFrame()) - return localCoordinatesOf(referenceFrame()->coordinatesOf(src)); - else - return localCoordinatesOf(src); -} - -/*! Returns the world coordinates of the point whose position in the Frame coordinate system is \p - src (converts from Frame to world). - - coordinatesOf() performs the inverse convertion. Use inverseTransformOf() to transform 3D vectors - instead of 3D coordinates. */ -Vec Frame::inverseCoordinatesOf(const Vec& src) const -{ - const Frame* fr = this; - Vec res = src; - while (fr != NULL) - { - res = fr->localInverseCoordinatesOf(res); - fr = fr->referenceFrame(); - } - return res; -} - -/*! Returns the Frame coordinates of a point \p src defined in the referenceFrame() coordinate - system (converts from referenceFrame() to Frame). - - localInverseCoordinatesOf() performs the inverse convertion. See also localTransformOf(). */ -Vec Frame::localCoordinatesOf(const Vec& src) const -{ - return rotation().inverseRotate(src - translation()); -} - -/*! Returns the referenceFrame() coordinates of a point \p src defined in the Frame coordinate - system (converts from Frame to referenceFrame()). - - localCoordinatesOf() performs the inverse convertion. See also localInverseTransformOf(). */ -Vec Frame::localInverseCoordinatesOf(const Vec& src) const -{ - return rotation().rotate(src) + translation(); -} - -/*! Returns the Frame coordinates of the point whose position in the \p from coordinate system is \p - src (converts from \p from to Frame). +/*! Returns the Frame coordinates of the point whose position in the \p from + coordinate system is \p src (converts from \p from to Frame). coordinatesOfIn() performs the inverse transformation. */ -Vec Frame::coordinatesOfFrom(const Vec& src, const Frame* const from) const -{ - if (this == from) - return src; - else - if (referenceFrame()) - return localCoordinatesOf(referenceFrame()->coordinatesOfFrom(src, from)); - else - return localCoordinatesOf(from->inverseCoordinatesOf(src)); +Vec Frame::coordinatesOfFrom(const Vec &src, const Frame *const from) const { + if (this == from) + return src; + else if (referenceFrame()) + return localCoordinatesOf(referenceFrame()->coordinatesOfFrom(src, from)); + else + return localCoordinatesOf(from->inverseCoordinatesOf(src)); } -/*! Returns the \p in coordinates of the point whose position in the Frame coordinate system is \p - src (converts from Frame to \p in). +/*! Returns the \p in coordinates of the point whose position in the Frame + coordinate system is \p src (converts from Frame to \p in). coordinatesOfFrom() performs the inverse transformation. */ -Vec Frame::coordinatesOfIn(const Vec& src, const Frame* const in) const -{ - const Frame* fr = this; - Vec res = src; - while ((fr != NULL) && (fr != in)) - { - res = fr->localInverseCoordinatesOf(res); - fr = fr->referenceFrame(); - } +Vec Frame::coordinatesOfIn(const Vec &src, const Frame *const in) const { + const Frame *fr = this; + Vec res = src; + while ((fr != nullptr) && (fr != in)) { + res = fr->localInverseCoordinatesOf(res); + fr = fr->referenceFrame(); + } - if (fr != in) - // in was not found in the branch of this, res is now expressed in the world - // coordinate system. Simply convert to in coordinate system. - res = in->coordinatesOf(res); + if (fr != in) + // in was not found in the branch of this, res is now expressed in the world + // coordinate system. Simply convert to in coordinate system. + res = in->coordinatesOf(res); - return res; + return res; } ////// qreal[3] versions /*! Same as coordinatesOf(), but with \c qreal parameters. */ -void Frame::getCoordinatesOf(const qreal src[3], qreal res[3]) const -{ - const Vec r = coordinatesOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getCoordinatesOf(const qreal src[3], qreal res[3]) const { + const Vec r = coordinatesOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as inverseCoordinatesOf(), but with \c qreal parameters. */ -void Frame::getInverseCoordinatesOf(const qreal src[3], qreal res[3]) const -{ - const Vec r = inverseCoordinatesOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getInverseCoordinatesOf(const qreal src[3], qreal res[3]) const { + const Vec r = inverseCoordinatesOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as localCoordinatesOf(), but with \c qreal parameters. */ -void Frame::getLocalCoordinatesOf(const qreal src[3], qreal res[3]) const -{ - const Vec r = localCoordinatesOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getLocalCoordinatesOf(const qreal src[3], qreal res[3]) const { + const Vec r = localCoordinatesOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as localInverseCoordinatesOf(), but with \c qreal parameters. */ -void Frame::getLocalInverseCoordinatesOf(const qreal src[3], qreal res[3]) const -{ - const Vec r = localInverseCoordinatesOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getLocalInverseCoordinatesOf(const qreal src[3], + qreal res[3]) const { + const Vec r = localInverseCoordinatesOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as coordinatesOfIn(), but with \c qreal parameters. */ -void Frame::getCoordinatesOfIn(const qreal src[3], qreal res[3], const Frame* const in) const -{ - const Vec r = coordinatesOfIn(Vec(src), in); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getCoordinatesOfIn(const qreal src[3], qreal res[3], + const Frame *const in) const { + const Vec r = coordinatesOfIn(Vec(src), in); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as coordinatesOfFrom(), but with \c qreal parameters. */ -void Frame::getCoordinatesOfFrom(const qreal src[3], qreal res[3], const Frame* const from) const -{ - const Vec r = coordinatesOfFrom(Vec(src), from); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; -} - - -///////////////////////// FRAME TRANSFORMATIONS OF VECTORS ////////////////////////////// - -/*! Returns the Frame transform of a vector \p src defined in the world coordinate system (converts - vectors from world to Frame). - - inverseTransformOf() performs the inverse transformation. coordinatesOf() converts 3D coordinates - instead of 3D vectors (here only the rotational part of the transformation is taken into account). - - See the frameTransform example for an - illustration. */ -Vec Frame::transformOf(const Vec& src) const -{ - if (referenceFrame()) - return localTransformOf(referenceFrame()->transformOf(src)); - else - return localTransformOf(src); -} - -/*! Returns the world transform of the vector whose coordinates in the Frame coordinate - system is \p src (converts vectors from Frame to world). - - transformOf() performs the inverse transformation. Use inverseCoordinatesOf() to transform 3D - coordinates instead of 3D vectors. */ -Vec Frame::inverseTransformOf(const Vec& src) const -{ - const Frame* fr = this; - Vec res = src; - while (fr != NULL) - { - res = fr->localInverseTransformOf(res); - fr = fr->referenceFrame(); - } - return res; +void Frame::getCoordinatesOfFrom(const qreal src[3], qreal res[3], + const Frame *const from) const { + const Vec r = coordinatesOfFrom(Vec(src), from); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; +} + +///////////////////////// FRAME TRANSFORMATIONS OF VECTORS +///////////////////////////////// + +/*! Returns the Frame transform of a vector \p src defined in the world + coordinate system (converts vectors from world to Frame). + + inverseTransformOf() performs the inverse transformation. coordinatesOf() + converts 3D coordinates instead of 3D vectors (here only the rotational part of + the transformation is taken into account). + + See the frameTransform example + for an illustration. */ +Vec Frame::transformOf(const Vec &src) const { + if (referenceFrame()) + return localTransformOf(referenceFrame()->transformOf(src)); + else + return localTransformOf(src); +} + +/*! Returns the world transform of the vector whose coordinates in the Frame + coordinate system is \p src (converts vectors from Frame to world). + + transformOf() performs the inverse transformation. Use inverseCoordinatesOf() + to transform 3D coordinates instead of 3D vectors. */ +Vec Frame::inverseTransformOf(const Vec &src) const { + const Frame *fr = this; + Vec res = src; + while (fr != nullptr) { + res = fr->localInverseTransformOf(res); + fr = fr->referenceFrame(); + } + return res; } -/*! Returns the Frame transform of a vector \p src defined in the referenceFrame() coordinate system - (converts vectors from referenceFrame() to Frame). +/*! Returns the Frame transform of a vector \p src defined in the + referenceFrame() coordinate system (converts vectors from referenceFrame() to + Frame). - localInverseTransformOf() performs the inverse transformation. See also localCoordinatesOf(). */ -Vec Frame::localTransformOf(const Vec& src) const -{ - return rotation().inverseRotate(src); + localInverseTransformOf() performs the inverse transformation. See also + localCoordinatesOf(). */ +Vec Frame::localTransformOf(const Vec &src) const { + return rotation().inverseRotate(src); } -/*! Returns the referenceFrame() transform of a vector \p src defined in the Frame coordinate - system (converts vectors from Frame to referenceFrame()). +/*! Returns the referenceFrame() transform of a vector \p src defined in the + Frame coordinate system (converts vectors from Frame to referenceFrame()). - localTransformOf() performs the inverse transformation. See also localInverseCoordinatesOf(). */ -Vec Frame::localInverseTransformOf(const Vec& src) const -{ - return rotation().rotate(src); + localTransformOf() performs the inverse transformation. See also + localInverseCoordinatesOf(). */ +Vec Frame::localInverseTransformOf(const Vec &src) const { + return rotation().rotate(src); } -/*! Returns the Frame transform of the vector whose coordinates in the \p from coordinate system is \p - src (converts vectors from \p from to Frame). +/*! Returns the Frame transform of the vector whose coordinates in the \p from + coordinate system is \p src (converts vectors from \p from to Frame). transformOfIn() performs the inverse transformation. */ -Vec Frame::transformOfFrom(const Vec& src, const Frame* const from) const -{ - if (this == from) - return src; - else - if (referenceFrame()) - return localTransformOf(referenceFrame()->transformOfFrom(src, from)); - else - return localTransformOf(from->inverseTransformOf(src)); +Vec Frame::transformOfFrom(const Vec &src, const Frame *const from) const { + if (this == from) + return src; + else if (referenceFrame()) + return localTransformOf(referenceFrame()->transformOfFrom(src, from)); + else + return localTransformOf(from->inverseTransformOf(src)); } -/*! Returns the \p in transform of the vector whose coordinates in the Frame coordinate system is \p - src (converts vectors from Frame to \p in). +/*! Returns the \p in transform of the vector whose coordinates in the Frame + coordinate system is \p src (converts vectors from Frame to \p in). transformOfFrom() performs the inverse transformation. */ -Vec Frame::transformOfIn(const Vec& src, const Frame* const in) const -{ - const Frame* fr = this; - Vec res = src; - while ((fr != NULL) && (fr != in)) - { - res = fr->localInverseTransformOf(res); - fr = fr->referenceFrame(); - } +Vec Frame::transformOfIn(const Vec &src, const Frame *const in) const { + const Frame *fr = this; + Vec res = src; + while ((fr != nullptr) && (fr != in)) { + res = fr->localInverseTransformOf(res); + fr = fr->referenceFrame(); + } - if (fr != in) - // in was not found in the branch of this, res is now expressed in the world - // coordinate system. Simply convert to in coordinate system. - res = in->transformOf(res); + if (fr != in) + // in was not found in the branch of this, res is now expressed in the world + // coordinate system. Simply convert to in coordinate system. + res = in->transformOf(res); - return res; + return res; } ///////////////// qreal[3] versions ////////////////////// /*! Same as transformOf(), but with \c qreal parameters. */ -void Frame::getTransformOf(const qreal src[3], qreal res[3]) const -{ - Vec r = transformOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getTransformOf(const qreal src[3], qreal res[3]) const { + Vec r = transformOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as inverseTransformOf(), but with \c qreal parameters. */ -void Frame::getInverseTransformOf(const qreal src[3], qreal res[3]) const -{ - Vec r = inverseTransformOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getInverseTransformOf(const qreal src[3], qreal res[3]) const { + Vec r = inverseTransformOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as localTransformOf(), but with \c qreal parameters. */ -void Frame::getLocalTransformOf(const qreal src[3], qreal res[3]) const -{ - Vec r = localTransformOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getLocalTransformOf(const qreal src[3], qreal res[3]) const { + Vec r = localTransformOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as localInverseTransformOf(), but with \c qreal parameters. */ -void Frame::getLocalInverseTransformOf(const qreal src[3], qreal res[3]) const -{ - Vec r = localInverseTransformOf(Vec(src)); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getLocalInverseTransformOf(const qreal src[3], qreal res[3]) const { + Vec r = localInverseTransformOf(Vec(src)); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as transformOfIn(), but with \c qreal parameters. */ -void Frame::getTransformOfIn(const qreal src[3], qreal res[3], const Frame* const in) const -{ - Vec r = transformOfIn(Vec(src), in); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getTransformOfIn(const qreal src[3], qreal res[3], + const Frame *const in) const { + Vec r = transformOfIn(Vec(src), in); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } /*! Same as transformOfFrom(), but with \c qreal parameters. */ -void Frame::getTransformOfFrom(const qreal src[3], qreal res[3], const Frame* const from) const -{ - Vec r = transformOfFrom(Vec(src), from); - for (int i=0; i<3 ; ++i) - res[i] = r[i]; +void Frame::getTransformOfFrom(const qreal src[3], qreal res[3], + const Frame *const from) const { + Vec r = transformOfFrom(Vec(src), from); + for (int i = 0; i < 3; ++i) + res[i] = r[i]; } //////////////////////////// STATE ////////////////////////////// /*! Returns an XML \c QDomElement that represents the Frame. - \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create - QDomElement. + \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument + factory used to create QDomElement. The resulting QDomElement looks like: \code @@ -985,160 +943,158 @@ void Frame::getTransformOfFrom(const qreal src[3], qreal res[3], const Frame* co \endcode - Use initFromDOMElement() to restore the Frame state from the resulting \c QDomElement. + Use initFromDOMElement() to restore the Frame state from the resulting \c + QDomElement. - See Vec::domElement() for a complete example. See also Quaternion::domElement(), - Camera::domElement()... + See Vec::domElement() for a complete example. See also + Quaternion::domElement(), Camera::domElement()... - \attention The constraint() and referenceFrame() are not saved in the QDomElement. */ -QDomElement Frame::domElement(const QString& name, QDomDocument& document) const -{ - // TODO: use translation and rotation instead when referenceFrame is coded... - QDomElement e = document.createElement(name); - e.appendChild(position().domElement("position", document)); - e.appendChild(orientation().domElement("orientation", document)); - return e; + \attention The constraint() and referenceFrame() are not saved in the + QDomElement. */ +QDomElement Frame::domElement(const QString &name, + QDomDocument &document) const { + // TODO: use translation and rotation instead when referenceFrame is coded... + QDomElement e = document.createElement(name); + e.appendChild(position().domElement("position", document)); + e.appendChild(orientation().domElement("orientation", document)); + return e; } /*! Restores the Frame state from a \c QDomElement created by domElement(). - See domElement() for the \c QDomElement syntax. See the Vec::initFromDOMElement() and - Quaternion::initFromDOMElement() documentations for details on default values if an argument is - missing. + See domElement() for the \c QDomElement syntax. See the + Vec::initFromDOMElement() and Quaternion::initFromDOMElement() documentations + for details on default values if an argument is missing. - \attention The constraint() and referenceFrame() are not restored by this method and are left - unchanged. */ -void Frame::initFromDOMElement(const QDomElement& element) -{ - // TODO: use translation and rotation instead when referenceFrame is coded... + \attention The constraint() and referenceFrame() are not restored by this + method and are left unchanged. */ +void Frame::initFromDOMElement(const QDomElement &element) { + // TODO: use translation and rotation instead when referenceFrame is coded... - // Reset default values. Attention: destroys constraint. - // *this = Frame(); - // This instead ? Better : what is not set is not changed. - // setPositionAndOrientation(Vec(), Quaternion()); + // Reset default values. Attention: destroys constraint. + // *this = Frame(); + // This instead ? Better : what is not set is not changed. + // setPositionAndOrientation(Vec(), Quaternion()); - QDomElement child=element.firstChild().toElement(); - while (!child.isNull()) - { - if (child.tagName() == "position") - setPosition(Vec(child)); - if (child.tagName() == "orientation") - setOrientation(Quaternion(child).normalized()); + QDomElement child = element.firstChild().toElement(); + while (!child.isNull()) { + if (child.tagName() == "position") + setPosition(Vec(child)); + if (child.tagName() == "orientation") + setOrientation(Quaternion(child).normalized()); - child = child.nextSibling().toElement(); - } + child = child.nextSibling().toElement(); + } } ///////////////////////////////// ALIGN ///////////////////////////////// /*! Aligns the Frame with \p frame, so that two of their axis are parallel. -If one of the X, Y and Z axis of the Frame is almost parallel to any of the X, Y, or Z axis of \p -frame, the Frame is rotated so that these two axis actually become parallel. - -If, after this first rotation, two other axis are also almost parallel, a second alignment is -performed. The two frames then have identical orientations, up to 90 degrees rotations. - -\p threshold measures how close two axis must be to be considered parallel. It is compared with the -absolute values of the dot product of the normalized axis. As a result, useful range is sqrt(2)/2 -(systematic alignment) to 1 (no alignment). - -When \p move is set to \c true, the Frame position() is also affected by the alignment. The new -Frame's position() is such that the \p frame position (computed with coordinatesOf(), in the Frame -coordinates system) does not change. - -\p frame may be \c NULL and then represents the world coordinate system (same convention than for -the referenceFrame()). - -The rotation (and translation when \p move is \c true) applied to the Frame are filtered by the -possible constraint(). */ -void Frame::alignWithFrame(const Frame* const frame, bool move, qreal threshold) -{ - Vec directions[2][3]; - for (unsigned short d=0; d<3; ++d) - { - Vec dir((d==0)? 1.0 : 0.0, (d==1)? 1.0 : 0.0, (d==2)? 1.0 : 0.0); - if (frame) - directions[0][d] = frame->inverseTransformOf(dir); - else - directions[0][d] = dir; - directions[1][d] = inverseTransformOf(dir); - } - - qreal maxProj = 0.0; - qreal proj; - unsigned short index[2]; - index[0] = index[1] = 0; - for (unsigned short i=0; i<3; ++i) - for (unsigned short j=0; j<3; ++j) - if ( (proj=fabs(directions[0][i]*directions[1][j])) >= maxProj ) - { - index[0] = i; - index[1] = j; - maxProj = proj; - } - - Frame old; - old=*this; - - qreal coef = directions[0][index[0]] * directions[1][index[1]]; - if (fabs(coef) >= threshold) - { - const Vec axis = cross(directions[0][index[0]], directions[1][index[1]]); - qreal angle = asin(axis.norm()); - if (coef >= 0.0) - angle = -angle; - rotate(rotation().inverse() * Quaternion(axis, angle) * orientation()); - - // Try to align an other axis direction - unsigned short d = (index[1]+1) % 3; - Vec dir((d==0)? 1.0 : 0.0, (d==1)? 1.0 : 0.0, (d==2)? 1.0 : 0.0); - dir = inverseTransformOf(dir); - - qreal max = 0.0; - for (unsigned short i=0; i<3; ++i) - { - qreal proj = fabs(directions[0][i]*dir); - if (proj > max) - { - index[0] = i; - max = proj; - } - } - - if (max >= threshold) - { - const Vec axis = cross(directions[0][index[0]], dir); - qreal angle = asin(axis.norm()); - if (directions[0][index[0]] * dir >= 0.0) - angle = -angle; - rotate(rotation().inverse() * Quaternion(axis, angle) * orientation()); - } - } - - if (move) - { - Vec center; - if (frame) - center = frame->position(); - - translate(center - orientation().rotate(old.coordinatesOf(center)) - translation()); - } -} - -/*! Translates the Frame so that its position() lies on the line defined by \p origin and \p - direction (defined in the world coordinate system). - -Simply uses an orthogonal projection. \p direction does not need to be normalized. */ -void Frame::projectOnLine(const Vec& origin, const Vec& direction) -{ - // If you are trying to find a bug here, because of memory problems, you waste your time. - // This is a bug in the gcc 3.3 compiler. Compile the library in debug mode and test. - // Uncommenting this line also seems to solve the problem. Horrible. - // cout << "position = " << position() << endl; - // If you found a problem or are using a different compiler, please let me know. - const Vec shift = origin - position(); - Vec proj = shift; - proj.projectOnAxis(direction); - translate(shift-proj); +If one of the X, Y and Z axis of the Frame is almost parallel to any of the X, +Y, or Z axis of \p frame, the Frame is rotated so that these two axis actually +become parallel. + +If, after this first rotation, two other axis are also almost parallel, a second +alignment is performed. The two frames then have identical orientations, up to +90 degrees rotations. + +\p threshold measures how close two axis must be to be considered parallel. It +is compared with the absolute values of the dot product of the normalized axis. +As a result, useful range is sqrt(2)/2 (systematic alignment) to 1 (no +alignment). + +When \p move is set to \c true, the Frame position() is also affected by the +alignment. The new Frame's position() is such that the \p frame position +(computed with coordinatesOf(), in the Frame coordinates system) does not +change. + +\p frame may be \c nullptr and then represents the world coordinate system (same +convention than for the referenceFrame()). + +The rotation (and translation when \p move is \c true) applied to the Frame are +filtered by the possible constraint(). */ +void Frame::alignWithFrame(const Frame *const frame, bool move, + qreal threshold) { + Vec directions[2][3]; + for (unsigned short d = 0; d < 3; ++d) { + Vec dir((d == 0) ? 1.0 : 0.0, (d == 1) ? 1.0 : 0.0, (d == 2) ? 1.0 : 0.0); + if (frame) + directions[0][d] = frame->inverseTransformOf(dir); + else + directions[0][d] = dir; + directions[1][d] = inverseTransformOf(dir); + } + + qreal maxProj = 0.0; + qreal proj; + unsigned short index[2]; + index[0] = index[1] = 0; + for (unsigned short i = 0; i < 3; ++i) + for (unsigned short j = 0; j < 3; ++j) + if ((proj = fabs(directions[0][i] * directions[1][j])) >= maxProj) { + index[0] = i; + index[1] = j; + maxProj = proj; + } + + Frame old; + old = *this; + + qreal coef = directions[0][index[0]] * directions[1][index[1]]; + if (fabs(coef) >= threshold) { + const Vec axis = cross(directions[0][index[0]], directions[1][index[1]]); + qreal angle = asin(axis.norm()); + if (coef >= 0.0) + angle = -angle; + rotate(rotation().inverse() * Quaternion(axis, angle) * orientation()); + + // Try to align an other axis direction + unsigned short d = (index[1] + 1) % 3; + Vec dir((d == 0) ? 1.0 : 0.0, (d == 1) ? 1.0 : 0.0, (d == 2) ? 1.0 : 0.0); + dir = inverseTransformOf(dir); + + qreal max = 0.0; + for (unsigned short i = 0; i < 3; ++i) { + qreal proj = fabs(directions[0][i] * dir); + if (proj > max) { + index[0] = i; + max = proj; + } + } + + if (max >= threshold) { + const Vec axis = cross(directions[0][index[0]], dir); + qreal angle = asin(axis.norm()); + if (directions[0][index[0]] * dir >= 0.0) + angle = -angle; + rotate(rotation().inverse() * Quaternion(axis, angle) * orientation()); + } + } + + if (move) { + Vec center; + if (frame) + center = frame->position(); + + translate(center - orientation().rotate(old.coordinatesOf(center)) - + translation()); + } +} + +/*! Translates the Frame so that its position() lies on the line defined by \p +origin and \p direction (defined in the world coordinate system). + +Simply uses an orthogonal projection. \p direction does not need to be +normalized. */ +void Frame::projectOnLine(const Vec &origin, const Vec &direction) { + // If you are trying to find a bug here, because of memory problems, you waste + // your time. This is a bug in the gcc 3.3 compiler. Compile the library in + // debug mode and test. Uncommenting this line also seems to solve the + // problem. Horrible. cout << "position = " << position() << endl; If you + // found a problem or are using a different compiler, please let me know. + const Vec shift = origin - position(); + Vec proj = shift; + proj.projectOnAxis(direction); + translate(shift - proj); } diff --git a/octovis/src/extern/QGLViewer/frame.h b/octovis/src/extern/QGLViewer/frame.h index 2b88540a..a193d0f5 100644 --- a/octovis/src/extern/QGLViewer/frame.h +++ b/octovis/src/extern/QGLViewer/frame.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,7 +19,6 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_FRAME_H #define QGLVIEWER_FRAME_H @@ -30,17 +29,17 @@ // #include "GL/gl.h" is now included in config.h for ease of configuration namespace qglviewer { -/*! \brief The Frame class represents a coordinate system, defined by a position and an - orientation. \class Frame frame.h QGLViewer/frame.h +/*! \brief The Frame class represents a coordinate system, defined by a position + and an orientation. \class Frame frame.h QGLViewer/frame.h - A Frame is a 3D coordinate system, represented by a position() and an orientation(). The order of - these transformations is important: the Frame is first translated \e and \e then rotated around - the new translated origin. + A Frame is a 3D coordinate system, represented by a position() and an + orientation(). The order of these transformations is important: the Frame is + first translated \e and \e then rotated around the new translated origin. - A Frame is useful to define the position and orientation of a 3D rigid object, using its matrix() - method, as shown below: - \code - // Builds a Frame at position (0.5,0,0) and oriented such that its Y axis is along the (1,1,1) + A Frame is useful to define the position and orientation of a 3D rigid object, + using its matrix() method, as shown below: \code + // Builds a Frame at position (0.5,0,0) and oriented such that its Y axis is + along the (1,1,1) // direction. One could also have used setPosition() and setOrientation(). Frame fr(Vec(0.5,0,0), Quaternion(Vec(0,1,0), Vec(1,1,1))); glPushMatrix(); @@ -49,365 +48,409 @@ namespace qglviewer { glPopMatrix(); \endcode - Many functions are provided to transform a 3D point from one coordinate system (Frame) to an - other: see coordinatesOf(), inverseCoordinatesOf(), coordinatesOfIn(), coordinatesOfFrom()... + Many functions are provided to transform a 3D point from one coordinate system + (Frame) to an other: see coordinatesOf(), inverseCoordinatesOf(), + coordinatesOfIn(), coordinatesOfFrom()... - You may also want to transform a 3D vector (such as a normal), which corresponds to applying only - the rotational part of the frame transformation: see transformOf() and inverseTransformOf(). See - the frameTransform example for an illustration. + You may also want to transform a 3D vector (such as a normal), which + corresponds to applying only the rotational part of the frame transformation: + see transformOf() and inverseTransformOf(). See the frameTransform example for an + illustration. - The translation() and the rotation() that are encapsulated in a Frame can also be used to - represent a \e rigid \e transformation of space. Such a transformation can also be interpreted as - a change of coordinate system, and the coordinate system conversion functions actually allow you - to use a Frame as a rigid transformation. Use inverseCoordinatesOf() (resp. coordinatesOf()) to - apply the transformation (resp. its inverse). Note the inversion. + The translation() and the rotation() that are encapsulated in a Frame can also + be used to represent a \e rigid \e transformation of space. Such a + transformation can also be interpreted as a change of coordinate system, and + the coordinate system conversion functions actually allow you to use a Frame + as a rigid transformation. Use inverseCoordinatesOf() (resp. coordinatesOf()) + to apply the transformation (resp. its inverse). Note the inversion.

Hierarchy of Frames

- The position and the orientation of a Frame are actually defined with respect to a - referenceFrame(). The default referenceFrame() is the world coordinate system (represented by a \c - NULL referenceFrame()). If you setReferenceFrame() to a different Frame, you must then - differentiate: + The position and the orientation of a Frame are actually defined with respect + to a referenceFrame(). The default referenceFrame() is the world coordinate + system (represented by a \c nullptr referenceFrame()). If you setReferenceFrame() + to a different Frame, you must then differentiate: - \arg the \e local translation() and rotation(), defined with respect to the referenceFrame(), + \arg the \e local translation() and rotation(), defined with respect to the + referenceFrame(), - \arg the \e global position() and orientation(), always defined with respect to the world - coordinate system. + \arg the \e global position() and orientation(), always defined with respect + to the world coordinate system. - A Frame is actually defined by its translation() with respect to its referenceFrame(), and then by - a rotation() of the coordinate system around the new translated origin. + A Frame is actually defined by its translation() with respect to its + referenceFrame(), and then by a rotation() of the coordinate system around the + new translated origin. - This terminology for \e local (translation() and rotation()) and \e global (position() and - orientation()) definitions is used in all the methods' names and should be sufficient to prevent - ambiguities. These notions are obviously identical when the referenceFrame() is \c NULL, i.e. when - the Frame is defined in the world coordinate system (the one you are in at the beginning of the - QGLViewer::draw() method, see the introduction page). + This terminology for \e local (translation() and rotation()) and \e global + (position() and orientation()) definitions is used in all the methods' names + and should be sufficient to prevent ambiguities. These notions are obviously + identical when the referenceFrame() is \c nullptr, i.e. when the Frame is defined + in the world coordinate system (the one you are in at the beginning of the + QGLViewer::draw() method, see the introduction + page). - Frames can hence easily be organized in a tree hierarchy, which root is the world coordinate - system. A loop in the hierarchy would result in an inconsistent (multiple) Frame definition. - settingAsReferenceFrameWillCreateALoop() checks this and prevents setReferenceFrame() from - creating such a loop. + Frames can hence easily be organized in a tree hierarchy, which root is the + world coordinate system. A loop in the hierarchy would result in an + inconsistent (multiple) Frame definition. + settingAsReferenceFrameWillCreateALoop() checks this and prevents + setReferenceFrame() from creating such a loop. - This frame hierarchy is used in methods like coordinatesOfIn(), coordinatesOfFrom()... which allow - coordinates (or vector) conversions from a Frame to any other one (including the world coordinate - system). + This frame hierarchy is used in methods like coordinatesOfIn(), + coordinatesOfFrom()... which allow coordinates (or vector) conversions from a + Frame to any other one (including the world coordinate system). - However, one must note that this hierarchical representation is internal to the Frame classes. - When the Frames represent OpenGL coordinates system, one should map this hierarchical - representation to the OpenGL GL_MODELVIEW matrix stack. See the matrix() documentation for - details. + However, one must note that this hierarchical representation is internal to + the Frame classes. When the Frames represent OpenGL coordinates system, one + should map this hierarchical representation to the OpenGL GL_MODELVIEW matrix + stack. See the matrix() documentation for details.

Constraints

- An interesting feature of Frames is that their displacements can be constrained. When a Constraint - is attached to a Frame, it filters the input of translate() and rotate(), and only the resulting - filtered motion is applied to the Frame. The default constraint() is \c NULL resulting in no - filtering. Use setConstraint() to attach a Constraint to a frame. + An interesting feature of Frames is that their displacements can be + constrained. When a Constraint is attached to a Frame, it filters the input of + translate() and rotate(), and only the resulting filtered motion is applied to + the Frame. The default constraint() is \c nullptr resulting in no filtering. Use + setConstraint() to attach a Constraint to a frame. - Constraints are especially usefull for the ManipulatedFrame instances, in order to forbid some - mouse motions. See the constrainedFrame, constrainedFrame, constrainedCamera and luxo examples for an illustration. - Classical constraints are provided for convenience (see LocalConstraint, WorldConstraint and - CameraConstraint) and new constraints can very easily be implemented. + Classical constraints are provided for convenience (see LocalConstraint, + WorldConstraint and CameraConstraint) and new constraints can very easily be + implemented.

Derived classes

- The ManipulatedFrame class inherits Frame and implements a mouse motion convertion, so that a - Frame (and hence an object) can be manipulated in the scene with the mouse. + The ManipulatedFrame class inherits Frame and implements a mouse motion + convertion, so that a Frame (and hence an object) can be manipulated in the + scene with the mouse. \nosubgrouping */ -class QGLVIEWER_EXPORT Frame : public QObject -{ - Q_OBJECT +class QGLVIEWER_EXPORT Frame : public QObject { + Q_OBJECT public: - Frame(); + Frame(); - /*! Virtual destructor. Empty. */ - virtual ~Frame() {} + /*! Virtual destructor. Empty. */ + virtual ~Frame() {} - Frame(const Frame& frame); - Frame& operator=(const Frame& frame); + Frame(const Frame &frame); + Frame &operator=(const Frame &frame); Q_SIGNALS: - /*! This signal is emitted whenever the position() or the orientation() of the Frame is modified. + /*! This signal is emitted whenever the position() or the orientation() of the + Frame is modified. - Connect this signal to any object that must be notified: - \code - QObject::connect(myFrame, SIGNAL(modified()), myObject, SLOT(update())); - \endcode - Use the QGLViewer::QGLViewerPool() to connect the signal to all the viewers. + Connect this signal to any object that must be notified: + \code + QObject::connect(myFrame, SIGNAL(modified()), myObject, SLOT(update())); + \endcode + Use the QGLViewer::QGLViewerPool() to connect the signal to all the viewers. - \note If your Frame is part of a Frame hierarchy (see referenceFrame()), a modification of one - of the parents of this Frame will \e not emit this signal. Use code like this to change this - behavior (you can do this recursively for all the referenceFrame() until the \c NULL world root - frame is encountered): - \code - // Emits the Frame modified() signal when its referenceFrame() is modified(). - connect(myFrame->referenceFrame(), SIGNAL(modified()), myFrame, SIGNAL(modified())); - \endcode + \note If your Frame is part of a Frame hierarchy (see referenceFrame()), a + modification of one of the parents of this Frame will \e not emit this signal. + Use code like this to change this behavior (you can do this recursively for + all the referenceFrame() until the \c nullptr world root frame is encountered): + \code + // Emits the Frame modified() signal when its referenceFrame() is modified(). + connect(myFrame->referenceFrame(), SIGNAL(modified()), myFrame, + SIGNAL(modified())); \endcode - \attention Connecting this signal to a QGLWidget::update() slot (or a method that calls it) - will prevent you from modifying the Frame \e inside your QGLViewer::draw() method as it would - result in an infinite loop. However, QGLViewer::draw() should not modify the scene. + \attention Connecting this signal to a QOpenGLWidget::update() slot (or a + method that calls it) will prevent you from modifying the Frame \e inside your + QGLViewer::draw() method as it would result in an infinite loop. However, + QGLViewer::draw() should not modify the scene. - \note Note that this signal might be emitted even if the Frame is not actually modified, for - instance after a translate(Vec(0,0,0)) or a setPosition(position()). */ - void modified(); + \note Note that this signal might be emitted even if the Frame is not actually + modified, for instance after a translate(Vec(0,0,0)) or a + setPosition(position()). */ + void modified(); - /*! This signal is emitted when the Frame is interpolated by a KeyFrameInterpolator. + /*! This signal is emitted when the Frame is interpolated by a + KeyFrameInterpolator. - See the KeyFrameInterpolator documentation for details. + See the KeyFrameInterpolator documentation for details. - If a KeyFrameInterpolator is used to successively interpolate several Frames in your scene, - connect the KeyFrameInterpolator::interpolated() signal instead (identical, but independent of - the interpolated Frame). */ - void interpolated(); + If a KeyFrameInterpolator is used to successively interpolate several Frames + in your scene, connect the KeyFrameInterpolator::interpolated() signal instead + (identical, but independent of the interpolated Frame). */ + void interpolated(); public: - /*! @name World coordinates position and orientation */ - //@{ - Frame(const Vec& position, const Quaternion& orientation); - - void setPosition(const Vec& position); - void setPosition(qreal x, qreal y, qreal z); - void setPositionWithConstraint(Vec& position); + /*! @name World coordinates position and orientation */ + //@{ + Frame(const Vec &position, const Quaternion &orientation); - void setOrientation(const Quaternion& orientation); - void setOrientation(qreal q0, qreal q1, qreal q2, qreal q3); - void setOrientationWithConstraint(Quaternion& orientation); + void setPosition(const Vec &position); + void setPosition(qreal x, qreal y, qreal z); + void setPositionWithConstraint(Vec &position); - void setPositionAndOrientation(const Vec& position, const Quaternion& orientation); - void setPositionAndOrientationWithConstraint(Vec& position, Quaternion& orientation); + void setOrientation(const Quaternion &orientation); + void setOrientation(qreal q0, qreal q1, qreal q2, qreal q3); + void setOrientationWithConstraint(Quaternion &orientation); - Vec position() const; - Quaternion orientation() const; + void setPositionAndOrientation(const Vec &position, + const Quaternion &orientation); + void setPositionAndOrientationWithConstraint(Vec &position, + Quaternion &orientation); - void getPosition(qreal& x, qreal& y, qreal& z) const; - void getOrientation(qreal& q0, qreal& q1, qreal& q2, qreal& q3) const; - //@} + Vec position() const; + Quaternion orientation() const; + void getPosition(qreal &x, qreal &y, qreal &z) const; + void getOrientation(qreal &q0, qreal &q1, qreal &q2, qreal &q3) const; + //@} public: - /*! @name Local translation and rotation w/r reference Frame */ - //@{ - /*! Sets the translation() of the frame, locally defined with respect to the referenceFrame(). - Emits the modified() signal. - - Use setPosition() to define the world coordinates position(). Use - setTranslationWithConstraint() to take into account the potential constraint() of the Frame. */ - void setTranslation(const Vec& translation) { t_ = translation; Q_EMIT modified(); } - void setTranslation(qreal x, qreal y, qreal z); - void setTranslationWithConstraint(Vec& translation); - - /*! Set the current rotation Quaternion. See rotation() and the different Quaternion - constructors. Emits the modified() signal. See also setTranslation() and - setRotationWithConstraint(). */ - - /*! Sets the rotation() of the Frame, locally defined with respect to the referenceFrame(). - Emits the modified() signal. - - Use setOrientation() to define the world coordinates orientation(). The potential - constraint() of the Frame is not taken into account, use setRotationWithConstraint() - instead. */ - void setRotation(const Quaternion& rotation) { q_ = rotation; Q_EMIT modified(); } - void setRotation(qreal q0, qreal q1, qreal q2, qreal q3); - void setRotationWithConstraint(Quaternion& rotation); - - void setTranslationAndRotation(const Vec& translation, const Quaternion& rotation); - void setTranslationAndRotationWithConstraint(Vec& translation, Quaternion& rotation); - - /*! Returns the Frame translation, defined with respect to the referenceFrame(). - - Use position() to get the result in the world coordinates. These two values are identical - when the referenceFrame() is \c NULL (default). - - See also setTranslation() and setTranslationWithConstraint(). */ - Vec translation() const { return t_; } - /*! Returns the Frame rotation, defined with respect to the referenceFrame(). - - Use orientation() to get the result in the world coordinates. These two values are identical - when the referenceFrame() is \c NULL (default). - - See also setRotation() and setRotationWithConstraint(). */ - - /*! Returns the current Quaternion orientation. See setRotation(). */ - Quaternion rotation() const { return q_; } - - void getTranslation(qreal& x, qreal& y, qreal& z) const; - void getRotation(qreal& q0, qreal& q1, qreal& q2, qreal& q3) const; - //@} + /*! @name Local translation and rotation w/r reference Frame */ + //@{ + /*! Sets the translation() of the frame, locally defined with respect to the + referenceFrame(). Emits the modified() signal. + + Use setPosition() to define the world coordinates position(). Use + setTranslationWithConstraint() to take into account the potential constraint() + of the Frame. */ + void setTranslation(const Vec &translation) { + t_ = translation; + Q_EMIT modified(); + } + void setTranslation(qreal x, qreal y, qreal z); + void setTranslationWithConstraint(Vec &translation); + + /*! Set the current rotation Quaternion. See rotation() and the different + Quaternion constructors. Emits the modified() signal. See also + setTranslation() and setRotationWithConstraint(). */ + + /*! Sets the rotation() of the Frame, locally defined with respect to the + referenceFrame(). Emits the modified() signal. + + Use setOrientation() to define the world coordinates orientation(). The + potential constraint() of the Frame is not taken into account, use + setRotationWithConstraint() instead. */ + void setRotation(const Quaternion &rotation) { + q_ = rotation; + Q_EMIT modified(); + } + void setRotation(qreal q0, qreal q1, qreal q2, qreal q3); + void setRotationWithConstraint(Quaternion &rotation); + + void setTranslationAndRotation(const Vec &translation, + const Quaternion &rotation); + void setTranslationAndRotationWithConstraint(Vec &translation, + Quaternion &rotation); + + /*! Returns the Frame translation, defined with respect to the + referenceFrame(). + + Use position() to get the result in the world coordinates. These two values + are identical when the referenceFrame() is \c nullptr (default). + + See also setTranslation() and setTranslationWithConstraint(). */ + Vec translation() const { return t_; } + /*! Returns the Frame rotation, defined with respect to the referenceFrame(). + + Use orientation() to get the result in the world coordinates. These two values + are identical when the referenceFrame() is \c nullptr (default). + + See also setRotation() and setRotationWithConstraint(). */ + + /*! Returns the current Quaternion orientation. See setRotation(). */ + Quaternion rotation() const { return q_; } + + void getTranslation(qreal &x, qreal &y, qreal &z) const; + void getRotation(qreal &q0, qreal &q1, qreal &q2, qreal &q3) const; + //@} public: - /*! @name Frame hierarchy */ - //@{ - /*! Returns the reference Frame, in which coordinates system the Frame is defined. - - The translation() and rotation() of the Frame are defined with respect to the referenceFrame() - coordinate system. A \c NULL referenceFrame() (default value) means that the Frame is defined in - the world coordinate system. - - Use position() and orientation() to recursively convert values along the referenceFrame() chain - and to get values expressed in the world coordinate system. The values match when the - referenceFrame() is \c NULL. - - Use setReferenceFrame() to set this value and create a Frame hierarchy. Convenient functions - allow you to convert 3D coordinates from one Frame to an other: see coordinatesOf(), - localCoordinatesOf(), coordinatesOfIn() and their inverse functions. - - Vectors can also be converted using transformOf(), transformOfIn, localTransformOf() and their - inverse functions. */ - const Frame* referenceFrame() const { return referenceFrame_; } - void setReferenceFrame(const Frame* const refFrame); - bool settingAsReferenceFrameWillCreateALoop(const Frame* const frame); - //@} - - - /*! @name Frame modification */ - //@{ - void translate(Vec& t); - void translate(const Vec& t); - // Some compilers complain about "overloading cannot distinguish from previous declaration" - // Simply comment out the following method and its associated implementation - void translate(qreal x, qreal y, qreal z); - void translate(qreal& x, qreal& y, qreal& z); - - void rotate(Quaternion& q); - void rotate(const Quaternion& q); - // Some compilers complain about "overloading cannot distinguish from previous declaration" - // Simply comment out the following method and its associated implementation - void rotate(qreal q0, qreal q1, qreal q2, qreal q3); - void rotate(qreal& q0, qreal& q1, qreal& q2, qreal& q3); - - void rotateAroundPoint(Quaternion& rotation, const Vec& point); - void rotateAroundPoint(const Quaternion& rotation, const Vec& point); - - void alignWithFrame(const Frame* const frame, bool move=false, qreal threshold=0.0); - void projectOnLine(const Vec& origin, const Vec& direction); - //@} - - - /*! @name Coordinate system transformation of 3D coordinates */ - //@{ - Vec coordinatesOf(const Vec& src) const; - Vec inverseCoordinatesOf(const Vec& src) const; - Vec localCoordinatesOf(const Vec& src) const; - Vec localInverseCoordinatesOf(const Vec& src) const; - Vec coordinatesOfIn(const Vec& src, const Frame* const in) const; - Vec coordinatesOfFrom(const Vec& src, const Frame* const from) const; - - void getCoordinatesOf(const qreal src[3], qreal res[3]) const; - void getInverseCoordinatesOf(const qreal src[3], qreal res[3]) const; - void getLocalCoordinatesOf(const qreal src[3], qreal res[3]) const; - void getLocalInverseCoordinatesOf(const qreal src[3], qreal res[3]) const; - void getCoordinatesOfIn(const qreal src[3], qreal res[3], const Frame* const in) const; - void getCoordinatesOfFrom(const qreal src[3], qreal res[3], const Frame* const from) const; - //@} - - /*! @name Coordinate system transformation of vectors */ - // A frame is as a new coordinate system, defined with respect to a reference frame (the world - // coordinate system by default, see the "Composition of frame" section). - - // The transformOf() (resp. inverseTransformOf()) functions transform a 3D vector from (resp. - // to) the world coordinates system. This section defines the 3D vector transformation - // functions. See the Coordinate system transformation of 3D points above for the transformation - // of 3D points. The difference between the two sets of functions is simple: for vectors, only - // the rotational part of the transformations is taken into account, while translation is also - // considered for 3D points. - - // The length of the resulting transformed vector is identical to the one of the source vector - // for all the described functions. - - // When local is prepended to the names of the functions, the functions simply transform from - // (and to) the reference frame. - - // When In (resp. From) is appended to the names, the functions transform from (resp. To) the - // frame that is given as an argument. The frame does not need to be in the same branch or the - // hierarchical tree, and can be \c NULL (the world coordinates system). - - // Combining any of these functions with its inverse (in any order) leads to the identity. - //@{ - Vec transformOf(const Vec& src) const; - Vec inverseTransformOf(const Vec& src) const; - Vec localTransformOf(const Vec& src) const; - Vec localInverseTransformOf(const Vec& src) const; - Vec transformOfIn(const Vec& src, const Frame* const in) const; - Vec transformOfFrom(const Vec& src, const Frame* const from) const; - - void getTransformOf(const qreal src[3], qreal res[3]) const; - void getInverseTransformOf(const qreal src[3], qreal res[3]) const; - void getLocalTransformOf(const qreal src[3], qreal res[3]) const; - void getLocalInverseTransformOf(const qreal src[3], qreal res[3]) const; - void getTransformOfIn(const qreal src[3], qreal res[3], const Frame* const in) const; - void getTransformOfFrom(const qreal src[3], qreal res[3], const Frame* const from) const; - //@} - - - /*! @name Constraint on the displacement */ - //@{ - /*! Returns the current constraint applied to the Frame. - - A \c NULL value (default) means that no Constraint is used to filter Frame translation and - rotation. See the Constraint class documentation for details. - - You may have to use a \c dynamic_cast to convert the result to a Constraint derived class. */ - Constraint* constraint() const { return constraint_; } - /*! Sets the constraint() attached to the Frame. - - A \c NULL value means no constraint. The previous constraint() should be deleted by the calling - method if needed. */ - void setConstraint(Constraint* const constraint) { constraint_ = constraint; } - //@} - - /*! @name Associated matrices */ - //@{ + /*! @name Frame hierarchy */ + //@{ + /*! Returns the reference Frame, in which coordinates system the Frame is + defined. + + The translation() and rotation() of the Frame are defined with respect to the + referenceFrame() coordinate system. A \c nullptr referenceFrame() (default value) + means that the Frame is defined in the world coordinate system. + + Use position() and orientation() to recursively convert values along the + referenceFrame() chain and to get values expressed in the world coordinate + system. The values match when the referenceFrame() is \c nullptr. + + Use setReferenceFrame() to set this value and create a Frame hierarchy. + Convenient functions allow you to convert 3D coordinates from one Frame to an + other: see coordinatesOf(), localCoordinatesOf(), coordinatesOfIn() and their + inverse functions. + + Vectors can also be converted using transformOf(), transformOfIn, + localTransformOf() and their inverse functions. */ + const Frame *referenceFrame() const { return referenceFrame_; } + void setReferenceFrame(const Frame *const refFrame); + bool settingAsReferenceFrameWillCreateALoop(const Frame *const frame); + //@} + + /*! @name Frame modification */ + //@{ + void translate(Vec &t); + void translate(const Vec &t); + // Some compilers complain about "overloading cannot distinguish from previous + // declaration" Simply comment out the following method and its associated + // implementation + void translate(qreal x, qreal y, qreal z); + void translate(qreal &x, qreal &y, qreal &z); + + void rotate(Quaternion &q); + void rotate(const Quaternion &q); + // Some compilers complain about "overloading cannot distinguish from previous + // declaration" Simply comment out the following method and its associated + // implementation + void rotate(qreal q0, qreal q1, qreal q2, qreal q3); + void rotate(qreal &q0, qreal &q1, qreal &q2, qreal &q3); + + void rotateAroundPoint(Quaternion &rotation, const Vec &point); + void rotateAroundPoint(const Quaternion &rotation, const Vec &point); + + void alignWithFrame(const Frame *const frame, bool move = false, + qreal threshold = 0.0); + void projectOnLine(const Vec &origin, const Vec &direction); + //@} + + /*! @name Coordinate system transformation of 3D coordinates */ + //@{ + Vec coordinatesOf(const Vec &src) const; + Vec inverseCoordinatesOf(const Vec &src) const; + Vec localCoordinatesOf(const Vec &src) const; + Vec localInverseCoordinatesOf(const Vec &src) const; + Vec coordinatesOfIn(const Vec &src, const Frame *const in) const; + Vec coordinatesOfFrom(const Vec &src, const Frame *const from) const; + + void getCoordinatesOf(const qreal src[3], qreal res[3]) const; + void getInverseCoordinatesOf(const qreal src[3], qreal res[3]) const; + void getLocalCoordinatesOf(const qreal src[3], qreal res[3]) const; + void getLocalInverseCoordinatesOf(const qreal src[3], qreal res[3]) const; + void getCoordinatesOfIn(const qreal src[3], qreal res[3], + const Frame *const in) const; + void getCoordinatesOfFrom(const qreal src[3], qreal res[3], + const Frame *const from) const; + //@} + + /*! @name Coordinate system transformation of vectors */ + // A frame is as a new coordinate system, defined with respect to a reference + // frame (the world coordinate system by default, see the "Composition of + // frame" section). + + // The transformOf() (resp. inverseTransformOf()) functions transform a 3D + // vector from (resp. to) the world coordinates system. This section defines + // the 3D vector transformation functions. See the Coordinate system + // transformation of 3D points above for the transformation of 3D points. The + // difference between the two sets of functions is simple: for vectors, only + // the rotational part of the transformations is taken into account, while + // translation is also considered for 3D points. + + // The length of the resulting transformed vector is identical to the one of + // the source vector for all the described functions. + + // When local is prepended to the names of the functions, the functions simply + // transform from (and to) the reference frame. + + // When In (resp. From) is appended to the names, the functions transform from + // (resp. To) the frame that is given as an argument. The frame does not need + // to be in the same branch or the hierarchical tree, and can be \c nullptr (the + // world coordinates system). + + // Combining any of these functions with its inverse (in any order) leads to + // the identity. + //@{ + Vec transformOf(const Vec &src) const; + Vec inverseTransformOf(const Vec &src) const; + Vec localTransformOf(const Vec &src) const; + Vec localInverseTransformOf(const Vec &src) const; + Vec transformOfIn(const Vec &src, const Frame *const in) const; + Vec transformOfFrom(const Vec &src, const Frame *const from) const; + + void getTransformOf(const qreal src[3], qreal res[3]) const; + void getInverseTransformOf(const qreal src[3], qreal res[3]) const; + void getLocalTransformOf(const qreal src[3], qreal res[3]) const; + void getLocalInverseTransformOf(const qreal src[3], qreal res[3]) const; + void getTransformOfIn(const qreal src[3], qreal res[3], + const Frame *const in) const; + void getTransformOfFrom(const qreal src[3], qreal res[3], + const Frame *const from) const; + //@} + + /*! @name Constraint on the displacement */ + //@{ + /*! Returns the current constraint applied to the Frame. + + A \c nullptr value (default) means that no Constraint is used to filter Frame + translation and rotation. See the Constraint class documentation for details. + + You may have to use a \c dynamic_cast to convert the result to a Constraint + derived class. */ + Constraint *constraint() const { return constraint_; } + /*! Sets the constraint() attached to the Frame. + + A \c nullptr value means no constraint. The previous constraint() should be + deleted by the calling method if needed. */ + void setConstraint(Constraint *const constraint) { constraint_ = constraint; } + //@} + + /*! @name Associated matrices */ + //@{ public: - const GLdouble* matrix() const; - void getMatrix(GLdouble m[4][4]) const; - void getMatrix(GLdouble m[16]) const; - - const GLdouble* worldMatrix() const; - void getWorldMatrix(GLdouble m[4][4]) const; - void getWorldMatrix(GLdouble m[16]) const; - - void setFromMatrix(const GLdouble m[4][4]); - void setFromMatrix(const GLdouble m[16]); - //@} - - /*! @name Inversion of the transformation */ - //@{ - Frame inverse() const; - /*! Returns the inverse() of the Frame world transformation. - - The orientation() of the new Frame is the Quaternion::inverse() of the original orientation. - Its position() is the negated and inverse rotated image of the original position. - - The result Frame has a \c NULL referenceFrame() and a \c NULL constraint(). - - Use inverse() for a local (i.e. with respect to referenceFrame()) transformation inverse. */ - Frame worldInverse() const { return Frame(-(orientation().inverseRotate(position())), orientation().inverse()); } - //@} - - /*! @name XML representation */ - //@{ + const GLdouble *matrix() const; + void getMatrix(GLdouble m[4][4]) const; + void getMatrix(GLdouble m[16]) const; + + const GLdouble *worldMatrix() const; + void getWorldMatrix(GLdouble m[4][4]) const; + void getWorldMatrix(GLdouble m[16]) const; + + void setFromMatrix(const GLdouble m[4][4]); + void setFromMatrix(const GLdouble m[16]); + //@} + + /*! @name Inversion of the transformation */ + //@{ + Frame inverse() const; + /*! Returns the inverse() of the Frame world transformation. + + The orientation() of the new Frame is the Quaternion::inverse() of the + original orientation. Its position() is the negated and inverse rotated image + of the original position. + + The result Frame has a \c nullptr referenceFrame() and a \c nullptr constraint(). + + Use inverse() for a local (i.e. with respect to referenceFrame()) + transformation inverse. */ + Frame worldInverse() const { + return Frame(-(orientation().inverseRotate(position())), + orientation().inverse()); + } + //@} + + /*! @name XML representation */ + //@{ public: - virtual QDomElement domElement(const QString& name, QDomDocument& document) const; + virtual QDomElement domElement(const QString &name, + QDomDocument &document) const; public Q_SLOTS: - virtual void initFromDOMElement(const QDomElement& element); - //@} + virtual void initFromDOMElement(const QDomElement &element); + //@} private: - // P o s i t i o n a n d o r i e n t a t i o n - Vec t_; - Quaternion q_; + // P o s i t i o n a n d o r i e n t a t i o n + Vec t_; + Quaternion q_; - // C o n s t r a i n t s - Constraint* constraint_; + // C o n s t r a i n t s + Constraint *constraint_; - // F r a m e c o m p o s i t i o n - const Frame* referenceFrame_; + // F r a m e c o m p o s i t i o n + const Frame *referenceFrame_; }; } // namespace qglviewer diff --git a/octovis/src/extern/QGLViewer/keyFrameInterpolator.cpp b/octovis/src/extern/QGLViewer/keyFrameInterpolator.cpp index 480774bf..d3987b1a 100644 --- a/octovis/src/extern/QGLViewer/keyFrameInterpolator.cpp +++ b/octovis/src/extern/QGLViewer/keyFrameInterpolator.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,7 +19,6 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #include "domUtils.h" #include "qglviewer.h" // for QGLViewer::drawAxis and Camera::drawCamera @@ -30,284 +29,282 @@ using namespace std; The frame() can be set or changed using setFrame(). - interpolationTime(), interpolationSpeed() and interpolationPeriod() are set to their default - values. */ -KeyFrameInterpolator::KeyFrameInterpolator(Frame* frame) - : frame_(NULL), period_(40), interpolationTime_(0.0), interpolationSpeed_(1.0), interpolationStarted_(false), - closedPath_(false), loopInterpolation_(false), pathIsValid_(false), valuesAreValid_(true), currentFrameValid_(false) - // #CONNECTION# Values cut pasted initFromDOMElement() + interpolationTime(), interpolationSpeed() and interpolationPeriod() are set to + their default values. */ +KeyFrameInterpolator::KeyFrameInterpolator(Frame *frame) + : frame_(nullptr), period_(40), interpolationTime_(0.0), + interpolationSpeed_(1.0), interpolationStarted_(false), + closedPath_(false), loopInterpolation_(false), pathIsValid_(false), + valuesAreValid_(true), currentFrameValid_(false) +// #CONNECTION# Values cut pasted initFromDOMElement() { - setFrame(frame); - for (int i=0; i<4; ++i) - currentFrame_[i] = new QMutableListIterator(keyFrame_); - connect(&timer_, SIGNAL(timeout()), SLOT(update())); + setFrame(frame); + for (int i = 0; i < 4; ++i) + currentFrame_[i] = new QMutableListIterator(keyFrame_); + connect(&timer_, SIGNAL(timeout()), SLOT(update())); } /*! Virtual destructor. Clears the keyFrame path. */ -KeyFrameInterpolator::~KeyFrameInterpolator() -{ - deletePath(); - for (int i=0; i<4; ++i) - delete currentFrame_[i]; +KeyFrameInterpolator::~KeyFrameInterpolator() { + deletePath(); + for (int i = 0; i < 4; ++i) + delete currentFrame_[i]; } /*! Sets the frame() associated to the KeyFrameInterpolator. */ -void KeyFrameInterpolator::setFrame(Frame* const frame) -{ - if (this->frame()) - disconnect(this, SIGNAL( interpolated() ), this->frame(), SIGNAL( interpolated() )); +void KeyFrameInterpolator::setFrame(Frame *const frame) { + if (this->frame()) + disconnect(this, SIGNAL(interpolated()), this->frame(), + SIGNAL(interpolated())); - frame_ = frame; + frame_ = frame; - if (this->frame()) - connect(this, SIGNAL( interpolated() ), this->frame(), SIGNAL( interpolated() )); + if (this->frame()) + connect(this, SIGNAL(interpolated()), this->frame(), + SIGNAL(interpolated())); } /*! Updates frame() state according to current interpolationTime(). Then adds interpolationPeriod()*interpolationSpeed() to interpolationTime(). - This internal method is called by a timer when interpolationIsStarted(). It can be used for - debugging purpose. stopInterpolation() is called when interpolationTime() reaches firstTime() or - lastTime(), unless loopInterpolation() is \c true. */ -void KeyFrameInterpolator::update() -{ - interpolateAtTime(interpolationTime()); - - interpolationTime_ += interpolationSpeed() * interpolationPeriod() / 1000.0; - - if (interpolationTime() > keyFrame_.last()->time()) - { - if (loopInterpolation()) - setInterpolationTime(keyFrame_.first()->time() + interpolationTime_ - keyFrame_.last()->time()); - else - { - // Make sure last KeyFrame is reached and displayed - interpolateAtTime(keyFrame_.last()->time()); - stopInterpolation(); - } - Q_EMIT endReached(); - } - else - if (interpolationTime() < keyFrame_.first()->time()) - { - if (loopInterpolation()) - setInterpolationTime(keyFrame_.last()->time() - keyFrame_.first()->time() + interpolationTime_); - else - { - // Make sure first KeyFrame is reached and displayed - interpolateAtTime(keyFrame_.first()->time()); - stopInterpolation(); - } - Q_EMIT endReached(); - } + This internal method is called by a timer when interpolationIsStarted(). It + can be used for debugging purpose. stopInterpolation() is called when + interpolationTime() reaches firstTime() or lastTime(), unless + loopInterpolation() is \c true. */ +void KeyFrameInterpolator::update() { + interpolateAtTime(interpolationTime()); + + interpolationTime_ += interpolationSpeed() * interpolationPeriod() / 1000.0; + + if (interpolationTime() > keyFrame_.last()->time()) { + if (loopInterpolation()) + setInterpolationTime(keyFrame_.first()->time() + interpolationTime_ - + keyFrame_.last()->time()); + else { + // Make sure last KeyFrame is reached and displayed + interpolateAtTime(keyFrame_.last()->time()); + stopInterpolation(); + } + Q_EMIT endReached(); + } else if (interpolationTime() < keyFrame_.first()->time()) { + if (loopInterpolation()) + setInterpolationTime(keyFrame_.last()->time() - + keyFrame_.first()->time() + interpolationTime_); + else { + // Make sure first KeyFrame is reached and displayed + interpolateAtTime(keyFrame_.first()->time()); + stopInterpolation(); + } + Q_EMIT endReached(); + } } - /*! Starts the interpolation process. - A timer is started with an interpolationPeriod() period that updates the frame()'s position and - orientation. interpolationIsStarted() will return \c true until stopInterpolation() or - toggleInterpolation() is called. - - If \p period is positive, it is set as the new interpolationPeriod(). The previous - interpolationPeriod() is used otherwise (default). + A timer is started with an interpolationPeriod() period that updates the + frame()'s position and orientation. interpolationIsStarted() will return \c + true until stopInterpolation() or toggleInterpolation() is called. - If interpolationTime() is larger than lastTime(), interpolationTime() is reset to firstTime() - before interpolation starts (and inversely for negative interpolationSpeed()). + If \p period is positive, it is set as the new interpolationPeriod(). The + previous interpolationPeriod() is used otherwise (default). - Use setInterpolationTime() before calling this method to change the starting interpolationTime(). + If interpolationTime() is larger than lastTime(), interpolationTime() is reset + to firstTime() before interpolation starts (and inversely for negative + interpolationSpeed()). - See the keyFrames example for an illustration. + Use setInterpolationTime() before calling this method to change the starting + interpolationTime(). - You may also be interested in QGLViewer::animate() and QGLViewer::startAnimation(). + See the keyFrames example for an + illustration. - \attention The keyFrames must be defined (see addKeyFrame()) \e before you startInterpolation(), - or else the interpolation will naturally immediately stop. */ -void KeyFrameInterpolator::startInterpolation(int period) -{ - if (period >= 0) - setInterpolationPeriod(period); - - if (!keyFrame_.isEmpty()) - { - if ((interpolationSpeed() > 0.0) && (interpolationTime() >= keyFrame_.last()->time())) - setInterpolationTime(keyFrame_.first()->time()); - if ((interpolationSpeed() < 0.0) && (interpolationTime() <= keyFrame_.first()->time())) - setInterpolationTime(keyFrame_.last()->time()); - timer_.start(interpolationPeriod()); - interpolationStarted_ = true; - update(); - } + You may also be interested in QGLViewer::animate() and + QGLViewer::startAnimation(). + + \attention The keyFrames must be defined (see addKeyFrame()) \e before you + startInterpolation(), or else the interpolation will naturally immediately + stop. */ +void KeyFrameInterpolator::startInterpolation(int period) { + if (period >= 0) + setInterpolationPeriod(period); + + if (!keyFrame_.isEmpty()) { + if ((interpolationSpeed() > 0.0) && + (interpolationTime() >= keyFrame_.last()->time())) + setInterpolationTime(keyFrame_.first()->time()); + if ((interpolationSpeed() < 0.0) && + (interpolationTime() <= keyFrame_.first()->time())) + setInterpolationTime(keyFrame_.last()->time()); + timer_.start(interpolationPeriod()); + interpolationStarted_ = true; + update(); + } } - -/*! Stops an interpolation started with startInterpolation(). See interpolationIsStarted() and toggleInterpolation(). */ -void KeyFrameInterpolator::stopInterpolation() -{ - timer_.stop(); - interpolationStarted_ = false; +/*! Stops an interpolation started with startInterpolation(). See + * interpolationIsStarted() and toggleInterpolation(). */ +void KeyFrameInterpolator::stopInterpolation() { + timer_.stop(); + interpolationStarted_ = false; } - /*! Stops the interpolation and resets interpolationTime() to the firstTime(). -If desired, call interpolateAtTime() after this method to actually move the frame() to -firstTime(). */ -void KeyFrameInterpolator::resetInterpolation() -{ - stopInterpolation(); - setInterpolationTime(firstTime()); +If desired, call interpolateAtTime() after this method to actually move the +frame() to firstTime(). */ +void KeyFrameInterpolator::resetInterpolation() { + stopInterpolation(); + setInterpolationTime(firstTime()); } -/*! Appends a new keyFrame to the path, with its associated \p time (in seconds). +/*! Appends a new keyFrame to the path, with its associated \p time (in + seconds). The keyFrame is given as a pointer to a Frame, which will be connected to the - KeyFrameInterpolator: when \p frame is modified, the KeyFrameInterpolator path is updated - accordingly. This allows for dynamic paths, where keyFrame can be edited, even during the - interpolation. See the keyFrames example for an - illustration. + KeyFrameInterpolator: when \p frame is modified, the KeyFrameInterpolator path + is updated accordingly. This allows for dynamic paths, where keyFrame can be + edited, even during the interpolation. See the keyFrames example for an illustration. - \c NULL \p frame pointers are silently ignored. The keyFrameTime() has to be monotonously - increasing over keyFrames. + \c nullptr \p frame pointers are silently ignored. The keyFrameTime() has to be + monotonously increasing over keyFrames. Use addKeyFrame(const Frame&, qreal) to add keyFrame by values. */ -void KeyFrameInterpolator::addKeyFrame(const Frame* const frame, qreal time) -{ - if (!frame) - return; - - if (keyFrame_.isEmpty()) - interpolationTime_ = time; - - if ( (!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time) ) - qWarning("Error in KeyFrameInterpolator::addKeyFrame: time is not monotone"); - else - keyFrame_.append(new KeyFrame(frame, time)); - connect(frame, SIGNAL(modified()), SLOT(invalidateValues())); - valuesAreValid_ = false; - pathIsValid_ = false; - currentFrameValid_ = false; - resetInterpolation(); +void KeyFrameInterpolator::addKeyFrame(const Frame *const frame, qreal time) { + if (!frame) + return; + + if (keyFrame_.isEmpty()) + interpolationTime_ = time; + + if ((!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time)) + qWarning( + "Error in KeyFrameInterpolator::addKeyFrame: time is not monotone"); + else + keyFrame_.append(new KeyFrame(frame, time)); + connect(frame, SIGNAL(modified()), SLOT(invalidateValues())); + valuesAreValid_ = false; + pathIsValid_ = false; + currentFrameValid_ = false; + resetInterpolation(); } -/*! Appends a new keyFrame to the path, with its associated \p time (in seconds). +/*! Appends a new keyFrame to the path, with its associated \p time (in + seconds). - The path will use the current \p frame state. If you want the path to change when \p frame is - modified, you need to pass a \e pointer to the Frame instead (see addKeyFrame(const Frame*, - qreal)). + The path will use the current \p frame state. If you want the path to change + when \p frame is modified, you need to pass a \e pointer to the Frame instead + (see addKeyFrame(const Frame*, qreal)). The keyFrameTime() have to be monotonously increasing over keyFrames. */ -void KeyFrameInterpolator::addKeyFrame(const Frame& frame, qreal time) -{ - if (keyFrame_.isEmpty()) - interpolationTime_ = time; - - if ( (!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time) ) - qWarning("Error in KeyFrameInterpolator::addKeyFrame: time is not monotone"); - else - keyFrame_.append(new KeyFrame(frame, time)); - - valuesAreValid_ = false; - pathIsValid_ = false; - currentFrameValid_ = false; - resetInterpolation(); +void KeyFrameInterpolator::addKeyFrame(const Frame &frame, qreal time) { + if (keyFrame_.isEmpty()) + interpolationTime_ = time; + + if ((!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time)) + qWarning( + "Error in KeyFrameInterpolator::addKeyFrame: time is not monotone"); + else + keyFrame_.append(new KeyFrame(frame, time)); + + valuesAreValid_ = false; + pathIsValid_ = false; + currentFrameValid_ = false; + resetInterpolation(); } - /*! Appends a new keyFrame to the path. - Same as addKeyFrame(const Frame* frame, qreal), except that the keyFrameTime() is set to the - previous keyFrameTime() plus one second (or 0.0 if there is no previous keyFrame). */ -void KeyFrameInterpolator::addKeyFrame(const Frame* const frame) -{ - qreal time; - if (keyFrame_.isEmpty()) - time = 0.0; - else - time = lastTime() + 1.0; - - addKeyFrame(frame, time); + Same as addKeyFrame(const Frame* frame, qreal), except that the keyFrameTime() + is set to the previous keyFrameTime() plus one second (or 0.0 if there is no + previous keyFrame). */ +void KeyFrameInterpolator::addKeyFrame(const Frame *const frame) { + qreal time; + if (keyFrame_.isEmpty()) + time = 0.0; + else + time = lastTime() + 1.0; + + addKeyFrame(frame, time); } /*! Appends a new keyFrame to the path. - Same as addKeyFrame(const Frame& frame, qreal), except that the keyFrameTime() is automatically set - to previous keyFrameTime() plus one second (or 0.0 if there is no previous keyFrame). */ -void KeyFrameInterpolator::addKeyFrame(const Frame& frame) -{ - qreal time; - if (keyFrame_.isEmpty()) - time = 0.0; - else - time = keyFrame_.last()->time() + 1.0; - - addKeyFrame(frame, time); + Same as addKeyFrame(const Frame& frame, qreal), except that the keyFrameTime() + is automatically set to previous keyFrameTime() plus one second (or 0.0 if + there is no previous keyFrame). */ +void KeyFrameInterpolator::addKeyFrame(const Frame &frame) { + qreal time; + if (keyFrame_.isEmpty()) + time = 0.0; + else + time = keyFrame_.last()->time() + 1.0; + + addKeyFrame(frame, time); } /*! Removes all keyFrames from the path. The numberOfKeyFrames() is set to 0. */ -void KeyFrameInterpolator::deletePath() -{ - stopInterpolation(); - qDeleteAll(keyFrame_); - keyFrame_.clear(); - pathIsValid_ = false; - valuesAreValid_ = false; - currentFrameValid_ = false; +void KeyFrameInterpolator::deletePath() { + stopInterpolation(); + qDeleteAll(keyFrame_); + keyFrame_.clear(); + pathIsValid_ = false; + valuesAreValid_ = false; + currentFrameValid_ = false; } -static void drawCamera(qreal scale) -{ - glDisable(GL_LIGHTING); - - const qreal halfHeight = scale * 0.07; - const qreal halfWidth = halfHeight * 1.3; - const qreal dist = halfHeight / tan(qreal(M_PI)/8.0); - - const qreal arrowHeight = 1.5 * halfHeight; - const qreal baseHeight = 1.2 * halfHeight; - const qreal arrowHalfWidth = 0.5 * halfWidth; - const qreal baseHalfWidth = 0.3 * halfWidth; - - // Frustum outline - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glBegin(GL_LINE_STRIP); - glVertex3d(-halfWidth, halfHeight,-dist); - glVertex3d(-halfWidth,-halfHeight,-dist); - glVertex3d( 0.0, 0.0, 0.0); - glVertex3d( halfWidth,-halfHeight,-dist); - glVertex3d(-halfWidth,-halfHeight,-dist); - glEnd(); - glBegin(GL_LINE_STRIP); - glVertex3d( halfWidth,-halfHeight,-dist); - glVertex3d( halfWidth, halfHeight,-dist); - glVertex3d( 0.0, 0.0, 0.0); - glVertex3d(-halfWidth, halfHeight,-dist); - glVertex3d( halfWidth, halfHeight,-dist); - glEnd(); - - // Up arrow - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - // Base - glBegin(GL_QUADS); - glVertex3d(-baseHalfWidth, halfHeight,-dist); - glVertex3d( baseHalfWidth, halfHeight,-dist); - glVertex3d( baseHalfWidth, baseHeight,-dist); - glVertex3d(-baseHalfWidth, baseHeight,-dist); - glEnd(); - - // Arrow - glBegin(GL_TRIANGLES); - glVertex3d( 0.0, arrowHeight,-dist); - glVertex3d(-arrowHalfWidth, baseHeight, -dist); - glVertex3d( arrowHalfWidth, baseHeight, -dist); - glEnd(); +static void drawCamera(qreal scale) { + glDisable(GL_LIGHTING); + + const qreal halfHeight = scale * 0.07; + const qreal halfWidth = halfHeight * 1.3; + const qreal dist = halfHeight / tan(qreal(M_PI) / 8.0); + + const qreal arrowHeight = 1.5 * halfHeight; + const qreal baseHeight = 1.2 * halfHeight; + const qreal arrowHalfWidth = 0.5 * halfWidth; + const qreal baseHalfWidth = 0.3 * halfWidth; + + // Frustum outline + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glBegin(GL_LINE_STRIP); + glVertex3d(-halfWidth, halfHeight, -dist); + glVertex3d(-halfWidth, -halfHeight, -dist); + glVertex3d(0.0, 0.0, 0.0); + glVertex3d(halfWidth, -halfHeight, -dist); + glVertex3d(-halfWidth, -halfHeight, -dist); + glEnd(); + glBegin(GL_LINE_STRIP); + glVertex3d(halfWidth, -halfHeight, -dist); + glVertex3d(halfWidth, halfHeight, -dist); + glVertex3d(0.0, 0.0, 0.0); + glVertex3d(-halfWidth, halfHeight, -dist); + glVertex3d(halfWidth, halfHeight, -dist); + glEnd(); + + // Up arrow + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + // Base + glBegin(GL_QUADS); + glVertex3d(-baseHalfWidth, halfHeight, -dist); + glVertex3d(baseHalfWidth, halfHeight, -dist); + glVertex3d(baseHalfWidth, baseHeight, -dist); + glVertex3d(-baseHalfWidth, baseHeight, -dist); + glEnd(); + + // Arrow + glBegin(GL_TRIANGLES); + glVertex3d(0.0, arrowHeight, -dist); + glVertex3d(-arrowHalfWidth, baseHeight, -dist); + glVertex3d(arrowHalfWidth, baseHeight, -dist); + glEnd(); } /*! Draws the path used to interpolate the frame(). - \p mask controls what is drawn: if (mask & 1) (default), the position path is drawn. If (mask & - 2), a camera representation is regularly drawn and if (mask & 4), an oriented axis is regularly - drawn. Examples: + \p mask controls what is drawn: if (mask & 1) (default), the position path is + drawn. If (mask & 2), a camera representation is regularly drawn and if (mask + & 4), an oriented axis is regularly drawn. Examples: \code drawPath(); // Simply draws the interpolation path @@ -315,400 +312,399 @@ static void drawCamera(qreal scale) drawPath(5); // Draws path and axis \endcode - In the case where camera or axis is drawn, \p nbFrames controls the number of objects (axis or - camera) drawn between two successive keyFrames. When \p nbFrames=1, only the path KeyFrames are - drawn. \p nbFrames=2 also draws the intermediate orientation, etc. The maximum value is 30. \p - nbFrames should divide 30 so that an object is drawn for each KeyFrame. Default value is 6. + In the case where camera or axis is drawn, \p nbFrames controls the number of + objects (axis or camera) drawn between two successive keyFrames. When \p + nbFrames=1, only the path KeyFrames are drawn. \p nbFrames=2 also draws the + intermediate orientation, etc. The maximum value is 30. \p nbFrames should + divide 30 so that an object is drawn for each KeyFrame. Default value is 6. - \p scale (default=1.0) controls the scaling of the camera and axis drawing. A value of - QGLViewer::sceneRadius() should give good results. + \p scale (default=1.0) controls the scaling of the camera and axis drawing. A + value of QGLViewer::sceneRadius() should give good results. - See the keyFrames example for an illustration. + See the keyFrames example for an + illustration. The color of the path is the current \c glColor(). - \attention The OpenGL state is modified by this method: GL_LIGHTING is disabled and line width set - to 2. Use this code to preserve your current OpenGL state: - \code - glPushAttrib(GL_ALL_ATTRIB_BITS); + \attention The OpenGL state is modified by this method: GL_LIGHTING is + disabled and line width set to 2. Use this code to preserve your current + OpenGL state: \code glPushAttrib(GL_ALL_ATTRIB_BITS); drawPathModifyGLState(mask, nbFrames, scale); glPopAttrib(); \endcode */ -void KeyFrameInterpolator::drawPath(int mask, int nbFrames, qreal scale) -{ - const int nbSteps = 30; - if (!pathIsValid_) - { - path_.clear(); - - if (keyFrame_.isEmpty()) - return; - - if (!valuesAreValid_) - updateModifiedFrameValues(); - - if (keyFrame_.first() == keyFrame_.last()) - path_.push_back(Frame(keyFrame_.first()->position(), keyFrame_.first()->orientation())); - else - { - static Frame fr; - KeyFrame* kf_[4]; - kf_[0] = keyFrame_.first(); - kf_[1] = kf_[0]; - int index = 1; - kf_[2] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL; - index++; - kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL; - - while (kf_[2]) - { - Vec diff = kf_[2]->position() - kf_[1]->position(); - Vec v1 = 3.0 * diff - 2.0 * kf_[1]->tgP() - kf_[2]->tgP(); - Vec v2 = -2.0 * diff + kf_[1]->tgP() + kf_[2]->tgP(); - - // cout << kf_[0]->time() << " , " << kf_[1]->time() << " , " << kf_[2]->time() << " , " << kf_[3]->time() << endl; - for (int step=0; step(nbSteps); - fr.setPosition(kf_[1]->position() + alpha * (kf_[1]->tgP() + alpha * (v1+alpha*v2))); - fr.setOrientation(Quaternion::squad(kf_[1]->orientation(), kf_[1]->tgQ(), kf_[2]->tgQ(), kf_[2]->orientation(), alpha)); - path_.push_back(fr); - } - - // Shift - kf_[0] = kf_[1]; - kf_[1] = kf_[2]; - kf_[2] = kf_[3]; - index++; - kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL; - } - // Add last KeyFrame - path_.push_back(Frame(kf_[1]->position(), kf_[1]->orientation())); - } - pathIsValid_ = true; - } - - if (mask) - { - glDisable(GL_LIGHTING); - glLineWidth(2); - - if (mask & 1) - { - glBegin(GL_LINE_STRIP); - Q_FOREACH (Frame fr, path_) - glVertex3fv(fr.position()); - glEnd(); - } - if (mask & 6) - { - int count = 0; - if (nbFrames > nbSteps) - nbFrames = nbSteps; - qreal goal = 0.0; - Q_FOREACH (Frame fr, path_) - if ((count++) >= goal) - { - goal += nbSteps / static_cast(nbFrames); - glPushMatrix(); - glMultMatrixd(fr.matrix()); - if (mask & 2) drawCamera(scale); - if (mask & 4) QGLViewer::drawAxis(scale/10.0); - glPopMatrix(); - } - } - } +void KeyFrameInterpolator::drawPath(int mask, int nbFrames, qreal scale) { + const int nbSteps = 30; + if (!pathIsValid_) { + path_.clear(); + + if (keyFrame_.isEmpty()) + return; + + if (!valuesAreValid_) + updateModifiedFrameValues(); + + if (keyFrame_.first() == keyFrame_.last()) + path_.push_back(Frame(keyFrame_.first()->position(), + keyFrame_.first()->orientation())); + else { + static Frame fr; + KeyFrame *kf_[4]; + kf_[0] = keyFrame_.first(); + kf_[1] = kf_[0]; + int index = 1; + kf_[2] = (index < keyFrame_.size()) ? keyFrame_.at(index) : nullptr; + index++; + kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : nullptr; + + while (kf_[2]) { + Vec diff = kf_[2]->position() - kf_[1]->position(); + Vec v1 = 3.0 * diff - 2.0 * kf_[1]->tgP() - kf_[2]->tgP(); + Vec v2 = -2.0 * diff + kf_[1]->tgP() + kf_[2]->tgP(); + + // cout << kf_[0]->time() << " , " << kf_[1]->time() << " , " << + // kf_[2]->time() << " , " << kf_[3]->time() << endl; + for (int step = 0; step < nbSteps; ++step) { + qreal alpha = step / static_cast(nbSteps); + fr.setPosition(kf_[1]->position() + + alpha * (kf_[1]->tgP() + alpha * (v1 + alpha * v2))); + fr.setOrientation(Quaternion::squad(kf_[1]->orientation(), + kf_[1]->tgQ(), kf_[2]->tgQ(), + kf_[2]->orientation(), alpha)); + path_.push_back(fr); + } + + // Shift + kf_[0] = kf_[1]; + kf_[1] = kf_[2]; + kf_[2] = kf_[3]; + index++; + kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : nullptr; + } + // Add last KeyFrame + path_.push_back(Frame(kf_[1]->position(), kf_[1]->orientation())); + } + pathIsValid_ = true; + } + + if (mask) { + glDisable(GL_LIGHTING); + glLineWidth(2); + + if (mask & 1) { + glBegin(GL_LINE_STRIP); + Q_FOREACH (Frame fr, path_) + glVertex3fv(fr.position()); + glEnd(); + } + if (mask & 6) { + int count = 0; + if (nbFrames > nbSteps) + nbFrames = nbSteps; + qreal goal = 0.0; + Q_FOREACH (Frame fr, path_) + if ((count++) >= goal) { + goal += nbSteps / static_cast(nbFrames); + glPushMatrix(); + glMultMatrixd(fr.matrix()); + if (mask & 2) + drawCamera(scale); + if (mask & 4) + QGLViewer::drawAxis(scale / 10.0); + glPopMatrix(); + } + } + } } -void KeyFrameInterpolator::updateModifiedFrameValues() -{ - Quaternion prevQ = keyFrame_.first()->orientation(); - KeyFrame* kf; - for (int i=0; iframe()) - kf->updateValuesFromPointer(); - kf->flipOrientationIfNeeded(prevQ); - prevQ = kf->orientation(); - } - - KeyFrame* prev = keyFrame_.first(); - kf = keyFrame_.first(); - int index = 1; - while (kf) - { - KeyFrame* next = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL; - index++; - if (next) - kf->computeTangent(prev, next); - else - kf->computeTangent(prev, kf); - prev = kf; - kf = next; - } - valuesAreValid_ = true; +void KeyFrameInterpolator::updateModifiedFrameValues() { + Quaternion prevQ = keyFrame_.first()->orientation(); + KeyFrame *kf; + for (int i = 0; i < keyFrame_.size(); ++i) { + kf = keyFrame_.at(i); + if (kf->frame()) + kf->updateValuesFromPointer(); + kf->flipOrientationIfNeeded(prevQ); + prevQ = kf->orientation(); + } + + KeyFrame *prev = keyFrame_.first(); + kf = keyFrame_.first(); + int index = 1; + while (kf) { + KeyFrame *next = (index < keyFrame_.size()) ? keyFrame_.at(index) : nullptr; + index++; + if (next) + kf->computeTangent(prev, next); + else + kf->computeTangent(prev, kf); + prev = kf; + kf = next; + } + valuesAreValid_ = true; } /*! Returns the Frame associated with the keyFrame at index \p index. - See also keyFrameTime(). \p index has to be in the range 0..numberOfKeyFrames()-1. + See also keyFrameTime(). \p index has to be in the range + 0..numberOfKeyFrames()-1. - \note If this keyFrame was defined using a pointer to a Frame (see addKeyFrame(const Frame* - const)), the \e current pointed Frame state is returned. */ -Frame KeyFrameInterpolator::keyFrame(int index) const -{ - const KeyFrame* const kf = keyFrame_.at(index); - return Frame(kf->position(), kf->orientation()); + \note If this keyFrame was defined using a pointer to a Frame (see + addKeyFrame(const Frame* const)), the \e current pointed Frame state is + returned. */ +Frame KeyFrameInterpolator::keyFrame(int index) const { + const KeyFrame *const kf = keyFrame_.at(index); + return Frame(kf->position(), kf->orientation()); } /*! Returns the time corresponding to the \p index keyFrame. - See also keyFrame(). \p index has to be in the range 0..numberOfKeyFrames()-1. */ -qreal KeyFrameInterpolator::keyFrameTime(int index) const -{ - return keyFrame_.at(index)->time(); + See also keyFrame(). \p index has to be in the range 0..numberOfKeyFrames()-1. + */ +qreal KeyFrameInterpolator::keyFrameTime(int index) const { + return keyFrame_.at(index)->time(); } /*! Returns the duration of the KeyFrameInterpolator path, expressed in seconds. - Simply corresponds to lastTime() - firstTime(). Returns 0.0 if the path has less than 2 keyFrames. - See also keyFrameTime(). */ -qreal KeyFrameInterpolator::duration() const -{ - return lastTime() - firstTime(); + Simply corresponds to lastTime() - firstTime(). Returns 0.0 if the path has + less than 2 keyFrames. See also keyFrameTime(). */ +qreal KeyFrameInterpolator::duration() const { + return lastTime() - firstTime(); } /*! Returns the time corresponding to the first keyFrame, expressed in seconds. -Returns 0.0 if the path is empty. See also lastTime(), duration() and keyFrameTime(). */ -qreal KeyFrameInterpolator::firstTime() const -{ - if (keyFrame_.isEmpty()) - return 0.0; - else - return keyFrame_.first()->time(); +Returns 0.0 if the path is empty. See also lastTime(), duration() and +keyFrameTime(). */ +qreal KeyFrameInterpolator::firstTime() const { + if (keyFrame_.isEmpty()) + return 0.0; + else + return keyFrame_.first()->time(); } /*! Returns the time corresponding to the last keyFrame, expressed in seconds. -Returns 0.0 if the path is empty. See also firstTime(), duration() and keyFrameTime(). */ -qreal KeyFrameInterpolator::lastTime() const -{ - if (keyFrame_.isEmpty()) - return 0.0; - else - return keyFrame_.last()->time(); +Returns 0.0 if the path is empty. See also firstTime(), duration() and +keyFrameTime(). */ +qreal KeyFrameInterpolator::lastTime() const { + if (keyFrame_.isEmpty()) + return 0.0; + else + return keyFrame_.last()->time(); } -void KeyFrameInterpolator::updateCurrentKeyFrameForTime(qreal time) -{ - // Assertion: times are sorted in monotone order. - // Assertion: keyFrame_ is not empty - - // TODO: Special case for loops when closed path is implemented !! - if (!currentFrameValid_) - // Recompute everything from scrach - currentFrame_[1]->toFront(); - - while (currentFrame_[1]->peekNext()->time() > time) - { - currentFrameValid_ = false; - if (!currentFrame_[1]->hasPrevious()) - break; - currentFrame_[1]->previous(); - } - - if (!currentFrameValid_) - *currentFrame_[2] = *currentFrame_[1]; - - while (currentFrame_[2]->peekNext()->time() < time) - { - currentFrameValid_ = false; - if (!currentFrame_[2]->hasNext()) - break; - currentFrame_[2]->next(); - } - - if (!currentFrameValid_) - { - *currentFrame_[1] = *currentFrame_[2]; - if ((currentFrame_[1]->hasPrevious()) && (time < currentFrame_[2]->peekNext()->time())) - currentFrame_[1]->previous(); - - *currentFrame_[0] = *currentFrame_[1]; - if (currentFrame_[0]->hasPrevious()) - currentFrame_[0]->previous(); - - *currentFrame_[3] = *currentFrame_[2]; - if (currentFrame_[3]->hasNext()) - currentFrame_[3]->next(); - - currentFrameValid_ = true; - splineCacheIsValid_ = false; - } - - // cout << "Time = " << time << " : " << currentFrame_[0]->peekNext()->time() << " , " << - // currentFrame_[1]->peekNext()->time() << " , " << currentFrame_[2]->peekNext()->time() << " , " << currentFrame_[3]->peekNext()->time() << endl; +void KeyFrameInterpolator::updateCurrentKeyFrameForTime(qreal time) { + // Assertion: times are sorted in monotone order. + // Assertion: keyFrame_ is not empty + + // TODO: Special case for loops when closed path is implemented !! + if (!currentFrameValid_) + // Recompute everything from scrach + currentFrame_[1]->toFront(); + + while (currentFrame_[1]->peekNext()->time() > time) { + currentFrameValid_ = false; + if (!currentFrame_[1]->hasPrevious()) + break; + currentFrame_[1]->previous(); + } + + if (!currentFrameValid_) + *currentFrame_[2] = *currentFrame_[1]; + + while (currentFrame_[2]->peekNext()->time() < time) { + currentFrameValid_ = false; + if (!currentFrame_[2]->hasNext()) + break; + currentFrame_[2]->next(); + } + + if (!currentFrameValid_) { + *currentFrame_[1] = *currentFrame_[2]; + if ((currentFrame_[1]->hasPrevious()) && + (time < currentFrame_[2]->peekNext()->time())) + currentFrame_[1]->previous(); + + *currentFrame_[0] = *currentFrame_[1]; + if (currentFrame_[0]->hasPrevious()) + currentFrame_[0]->previous(); + + *currentFrame_[3] = *currentFrame_[2]; + if (currentFrame_[3]->hasNext()) + currentFrame_[3]->next(); + + currentFrameValid_ = true; + splineCacheIsValid_ = false; + } + + // cout << "Time = " << time << " : " << currentFrame_[0]->peekNext()->time() + // << " , " << currentFrame_[1]->peekNext()->time() << " , " << + // currentFrame_[2]->peekNext()->time() << " , " << + // currentFrame_[3]->peekNext()->time() << endl; } -void KeyFrameInterpolator::updateSplineCache() -{ - Vec delta = currentFrame_[2]->peekNext()->position() - currentFrame_[1]->peekNext()->position(); - v1 = 3.0 * delta - 2.0 * currentFrame_[1]->peekNext()->tgP() - currentFrame_[2]->peekNext()->tgP(); - v2 = -2.0 * delta + currentFrame_[1]->peekNext()->tgP() + currentFrame_[2]->peekNext()->tgP(); - splineCacheIsValid_ = true; +void KeyFrameInterpolator::updateSplineCache() { + Vec delta = currentFrame_[2]->peekNext()->position() - + currentFrame_[1]->peekNext()->position(); + v1 = 3.0 * delta - 2.0 * currentFrame_[1]->peekNext()->tgP() - + currentFrame_[2]->peekNext()->tgP(); + v2 = -2.0 * delta + currentFrame_[1]->peekNext()->tgP() + + currentFrame_[2]->peekNext()->tgP(); + splineCacheIsValid_ = true; } -/*! Interpolate frame() at time \p time (expressed in seconds). interpolationTime() is set to \p - time and frame() is set accordingly. - - If you simply want to change interpolationTime() but not the frame() state, use - setInterpolationTime() instead. - - Emits the interpolated() signal and makes the frame() emit the Frame::interpolated() signal. */ -void KeyFrameInterpolator::interpolateAtTime(qreal time) -{ - setInterpolationTime(time); - - if ((keyFrame_.isEmpty()) || (!frame())) - return; - - if (!valuesAreValid_) - updateModifiedFrameValues(); - - updateCurrentKeyFrameForTime(time); - - if (!splineCacheIsValid_) - updateSplineCache(); - - qreal alpha; - qreal dt = currentFrame_[2]->peekNext()->time() - currentFrame_[1]->peekNext()->time(); - if (dt == 0.0) - alpha = 0.0; - else - alpha = (time - currentFrame_[1]->peekNext()->time()) / dt; - - // Linear interpolation - debug - // Vec pos = alpha*(currentFrame_[2]->peekNext()->position()) + (1.0-alpha)*(currentFrame_[1]->peekNext()->position()); - Vec pos = currentFrame_[1]->peekNext()->position() + alpha * (currentFrame_[1]->peekNext()->tgP() + alpha * (v1+alpha*v2)); - Quaternion q = Quaternion::squad(currentFrame_[1]->peekNext()->orientation(), currentFrame_[1]->peekNext()->tgQ(), - currentFrame_[2]->peekNext()->tgQ(), currentFrame_[2]->peekNext()->orientation(), alpha); - frame()->setPositionAndOrientationWithConstraint(pos, q); - - Q_EMIT interpolated(); +/*! Interpolate frame() at time \p time (expressed in seconds). + interpolationTime() is set to \p time and frame() is set accordingly. + + If you simply want to change interpolationTime() but not the frame() state, + use setInterpolationTime() instead. + + Emits the interpolated() signal and makes the frame() emit the + Frame::interpolated() signal. */ +void KeyFrameInterpolator::interpolateAtTime(qreal time) { + setInterpolationTime(time); + + if ((keyFrame_.isEmpty()) || (!frame())) + return; + + if (!valuesAreValid_) + updateModifiedFrameValues(); + + updateCurrentKeyFrameForTime(time); + + if (!splineCacheIsValid_) + updateSplineCache(); + + qreal alpha; + qreal dt = currentFrame_[2]->peekNext()->time() - + currentFrame_[1]->peekNext()->time(); + if (dt == 0.0) + alpha = 0.0; + else + alpha = (time - currentFrame_[1]->peekNext()->time()) / dt; + + // Linear interpolation - debug + // Vec pos = alpha*(currentFrame_[2]->peekNext()->position()) + + // (1.0-alpha)*(currentFrame_[1]->peekNext()->position()); + Vec pos = + currentFrame_[1]->peekNext()->position() + + alpha * (currentFrame_[1]->peekNext()->tgP() + alpha * (v1 + alpha * v2)); + Quaternion q = Quaternion::squad( + currentFrame_[1]->peekNext()->orientation(), + currentFrame_[1]->peekNext()->tgQ(), currentFrame_[2]->peekNext()->tgQ(), + currentFrame_[2]->peekNext()->orientation(), alpha); + frame()->setPositionAndOrientationWithConstraint(pos, q); + + Q_EMIT interpolated(); } /*! Returns an XML \c QDomElement that represents the KeyFrameInterpolator. - The resulting QDomElement holds the KeyFrameInterpolator parameters as well as the path keyFrames - (if the keyFrame is defined by a pointer to a Frame, use its current value). - - \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create - QDomElement. - - Use initFromDOMElement() to restore the ManipulatedFrame state from the resulting QDomElement. - - See Vec::domElement() for a complete example. See also Quaternion::domElement(), - Camera::domElement()... - - Note that the Camera::keyFrameInterpolator() are automatically saved by QGLViewer::saveStateToFile() - when a QGLViewer is closed. */ -QDomElement KeyFrameInterpolator::domElement(const QString& name, QDomDocument& document) const -{ - QDomElement de = document.createElement(name); - int count = 0; - Q_FOREACH (KeyFrame* kf, keyFrame_) - { - Frame fr(kf->position(), kf->orientation()); - QDomElement kfNode = fr.domElement("KeyFrame", document); - kfNode.setAttribute("index", QString::number(count)); - kfNode.setAttribute("time", QString::number(kf->time())); - de.appendChild(kfNode); - ++count; - } - de.setAttribute("nbKF", QString::number(keyFrame_.count())); - de.setAttribute("time", QString::number(interpolationTime())); - de.setAttribute("speed", QString::number(interpolationSpeed())); - de.setAttribute("period", QString::number(interpolationPeriod())); - DomUtils::setBoolAttribute(de, "closedPath", closedPath()); - DomUtils::setBoolAttribute(de, "loop", loopInterpolation()); - return de; + The resulting QDomElement holds the KeyFrameInterpolator parameters as well as + the path keyFrames (if the keyFrame is defined by a pointer to a Frame, use its + current value). + + \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument + factory used to create QDomElement. + + Use initFromDOMElement() to restore the ManipulatedFrame state from the + resulting QDomElement. + + See Vec::domElement() for a complete example. See also + Quaternion::domElement(), Camera::domElement()... + + Note that the Camera::keyFrameInterpolator() are automatically saved by + QGLViewer::saveStateToFile() when a QGLViewer is closed. */ +QDomElement KeyFrameInterpolator::domElement(const QString &name, + QDomDocument &document) const { + QDomElement de = document.createElement(name); + int count = 0; + Q_FOREACH (KeyFrame *kf, keyFrame_) { + Frame fr(kf->position(), kf->orientation()); + QDomElement kfNode = fr.domElement("KeyFrame", document); + kfNode.setAttribute("index", QString::number(count)); + kfNode.setAttribute("time", QString::number(kf->time())); + de.appendChild(kfNode); + ++count; + } + de.setAttribute("nbKF", QString::number(keyFrame_.count())); + de.setAttribute("time", QString::number(interpolationTime())); + de.setAttribute("speed", QString::number(interpolationSpeed())); + de.setAttribute("period", QString::number(interpolationPeriod())); + DomUtils::setBoolAttribute(de, "closedPath", closedPath()); + DomUtils::setBoolAttribute(de, "loop", loopInterpolation()); + return de; } -/*! Restores the KeyFrameInterpolator state from a \c QDomElement created by domElement(). +/*! Restores the KeyFrameInterpolator state from a \c QDomElement created by + domElement(). - Note that the frame() pointer is not included in the domElement(): you need to setFrame() after - this method to attach a Frame to the KeyFrameInterpolator. + Note that the frame() pointer is not included in the domElement(): you need to + setFrame() after this method to attach a Frame to the KeyFrameInterpolator. See Vec::initFromDOMElement() for a complete code example. See also Camera::initFromDOMElement() and Frame::initFromDOMElement(). */ -void KeyFrameInterpolator::initFromDOMElement(const QDomElement& element) -{ - qDeleteAll(keyFrame_); - keyFrame_.clear(); - QDomElement child=element.firstChild().toElement(); - while (!child.isNull()) - { - if (child.tagName() == "KeyFrame") - { - Frame fr; - fr.initFromDOMElement(child); - qreal time = DomUtils::qrealFromDom(child, "time", 0.0); - addKeyFrame(fr, time); - } - - child = child.nextSibling().toElement(); - } - - // #CONNECTION# Values cut pasted from constructor - setInterpolationTime(DomUtils::qrealFromDom(element, "time", 0.0)); - setInterpolationSpeed(DomUtils::qrealFromDom(element, "speed", 1.0)); - setInterpolationPeriod(DomUtils::intFromDom(element, "period", 40)); - setClosedPath(DomUtils::boolFromDom(element, "closedPath", false)); - setLoopInterpolation(DomUtils::boolFromDom(element, "loop", false)); - - // setFrame(NULL); - pathIsValid_ = false; - valuesAreValid_ = false; - currentFrameValid_ = false; - - stopInterpolation(); +void KeyFrameInterpolator::initFromDOMElement(const QDomElement &element) { + qDeleteAll(keyFrame_); + keyFrame_.clear(); + QDomElement child = element.firstChild().toElement(); + while (!child.isNull()) { + if (child.tagName() == "KeyFrame") { + Frame fr; + fr.initFromDOMElement(child); + qreal time = DomUtils::qrealFromDom(child, "time", 0.0); + addKeyFrame(fr, time); + } + + child = child.nextSibling().toElement(); + } + + // #CONNECTION# Values cut pasted from constructor + setInterpolationTime(DomUtils::qrealFromDom(element, "time", 0.0)); + setInterpolationSpeed(DomUtils::qrealFromDom(element, "speed", 1.0)); + setInterpolationPeriod(DomUtils::intFromDom(element, "period", 40)); + setClosedPath(DomUtils::boolFromDom(element, "closedPath", false)); + setLoopInterpolation(DomUtils::boolFromDom(element, "loop", false)); + + // setFrame(nullptr); + pathIsValid_ = false; + valuesAreValid_ = false; + currentFrameValid_ = false; + + stopInterpolation(); } #ifndef DOXYGEN //////////// KeyFrame private class implementation ///////// -KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame& fr, qreal t) - : time_(t), frame_(NULL) -{ - p_ = fr.position(); - q_ = fr.orientation(); +KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame &fr, qreal t) + : time_(t), frame_(nullptr) { + p_ = fr.position(); + q_ = fr.orientation(); } -KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame* fr, qreal t) - : time_(t), frame_(fr) -{ - updateValuesFromPointer(); +KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame *fr, qreal t) + : time_(t), frame_(fr) { + updateValuesFromPointer(); } -void KeyFrameInterpolator::KeyFrame::updateValuesFromPointer() -{ - p_ = frame()->position(); - q_ = frame()->orientation(); +void KeyFrameInterpolator::KeyFrame::updateValuesFromPointer() { + p_ = frame()->position(); + q_ = frame()->orientation(); } -void KeyFrameInterpolator::KeyFrame::computeTangent(const KeyFrame* const prev, const KeyFrame* const next) -{ - tgP_ = 0.5 * (next->position() - prev->position()); - tgQ_ = Quaternion::squadTangent(prev->orientation(), q_, next->orientation()); +void KeyFrameInterpolator::KeyFrame::computeTangent( + const KeyFrame *const prev, const KeyFrame *const next) { + tgP_ = 0.5 * (next->position() - prev->position()); + tgQ_ = Quaternion::squadTangent(prev->orientation(), q_, next->orientation()); } -void KeyFrameInterpolator::KeyFrame::flipOrientationIfNeeded(const Quaternion& prev) -{ - if (Quaternion::dot(prev, q_) < 0.0) - q_.negate(); +void KeyFrameInterpolator::KeyFrame::flipOrientationIfNeeded( + const Quaternion &prev) { + if (Quaternion::dot(prev, q_) < 0.0) + q_.negate(); } -#endif //DOXYGEN +#endif // DOXYGEN diff --git a/octovis/src/extern/QGLViewer/keyFrameInterpolator.h b/octovis/src/extern/QGLViewer/keyFrameInterpolator.h index 100cd2f1..6fe41f8c 100644 --- a/octovis/src/extern/QGLViewer/keyFrameInterpolator.h +++ b/octovis/src/extern/QGLViewer/keyFrameInterpolator.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,7 +19,6 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_KEY_FRAME_INTERPOLATOR_H #define QGLVIEWER_KEY_FRAME_INTERPOLATOR_H @@ -38,318 +37,342 @@ namespace qglviewer { class Camera; class Frame; /*! \brief A keyFrame Catmull-Rom Frame interpolator. - \class KeyFrameInterpolator keyFrameInterpolator.h QGLViewer/keyFrameInterpolator.h + \class KeyFrameInterpolator keyFrameInterpolator.h + QGLViewer/keyFrameInterpolator.h - A KeyFrameInterpolator holds keyFrames (that define a path) and a pointer to a Frame of your - application (which will be interpolated). When the user startInterpolation(), the - KeyFrameInterpolator regularly updates the frame() position and orientation along the path. + A KeyFrameInterpolator holds keyFrames (that define a path) and a pointer to a + Frame of your application (which will be interpolated). When the user + startInterpolation(), the KeyFrameInterpolator regularly updates the frame() + position and orientation along the path. - Here is a typical utilization example (see also the keyFrames - example): - \code + Here is a typical utilization example (see also the keyFrames example): \code init() { - // The KeyFrameInterpolator kfi is given the Frame that it will drive over time. - kfi = new KeyFrameInterpolator( new Frame() ); - kfi->addKeyFrame( Frame( Vec(1,0,0), Quaternion() ) ); - kfi->addKeyFrame( new Frame( Vec(2,1,0), Quaternion() ) ); - // ...and so on for all the keyFrames. + // The KeyFrameInterpolator kfi is given the Frame that it will drive + over time. kfi = new KeyFrameInterpolator( new Frame() ); kfi->addKeyFrame( + Frame( Vec(1,0,0), Quaternion() ) ); kfi->addKeyFrame( new Frame( Vec(2,1,0), + Quaternion() ) ); + // ...and so on for all the keyFrames. - // Ask for a display update after each update of the KeyFrameInterpolator - connect(kfi, SIGNAL(interpolated()), SLOT(update())); + // Ask for a display update after each update of the + KeyFrameInterpolator connect(kfi, SIGNAL(interpolated()), SLOT(update())); - kfi->startInterpolation(); + kfi->startInterpolation(); } draw() { - glPushMatrix(); - glMultMatrixd( kfi->frame()->matrix() ); - // Draw your object here. Its position and orientation are interpolated. - glPopMatrix(); + glPushMatrix(); + glMultMatrixd( kfi->frame()->matrix() ); + // Draw your object here. Its position and orientation are interpolated. + glPopMatrix(); } \endcode - The keyFrames are defined by a Frame and a time, expressed in seconds. The Frame can be provided - as a const reference or as a pointer to a Frame (see the addKeyFrame() methods). In the latter - case, the path will automatically be updated when the Frame is modified (using the - Frame::modified() signal). + The keyFrames are defined by a Frame and a time, expressed in seconds. The + Frame can be provided as a const reference or as a pointer to a Frame (see the + addKeyFrame() methods). In the latter case, the path will automatically be + updated when the Frame is modified (using the Frame::modified() signal). - The time has to be monotonously increasing over keyFrames. When interpolationSpeed() equals 1.0 - (default value), these times correspond to actual user's seconds during interpolation (provided - that your main loop is fast enough). The interpolation is then real-time: the keyFrames will be + The time has to be monotonously increasing over keyFrames. When + interpolationSpeed() equals 1.0 (default value), these times correspond to + actual user's seconds during interpolation (provided that your main loop is + fast enough). The interpolation is then real-time: the keyFrames will be reached at their keyFrameTime().

Interpolation details

- When the user startInterpolation(), a timer is started which will update the frame()'s position - and orientation every interpolationPeriod() milliseconds. This update increases the - interpolationTime() by interpolationPeriod() * interpolationSpeed() milliseconds. - - Note that this mechanism ensures that the number of interpolation steps is constant and equal to - the total path duration() divided by the interpolationPeriod() * interpolationSpeed(). This is - especially useful for benchmarking or movie creation (constant number of snapshots). - - During the interpolation, the KeyFrameInterpolator emits an interpolated() signal, which will - usually be connected to the QGLViewer::update() slot. The interpolation is stopped when - interpolationTime() is greater than the lastTime() (unless loopInterpolation() is \c true) and the - endReached() signal is then emitted. - - Note that a Camera has Camera::keyFrameInterpolator(), that can be used to drive the Camera along a - path, or to restore a saved position (a path made of a single keyFrame). Press Alt+Fx to define a - new keyFrame for path x. Pressing Fx plays/pauses path interpolation. See QGLViewer::pathKey() and - the keyboard page for details. - - \attention If a Constraint is attached to the frame() (see Frame::constraint()), it should be - deactivated before interpolationIsStarted(), otherwise the interpolated motion (computed as if + When the user startInterpolation(), a timer is started which will update the + frame()'s position and orientation every interpolationPeriod() milliseconds. + This update increases the interpolationTime() by interpolationPeriod() * + interpolationSpeed() milliseconds. + + Note that this mechanism ensures that the number of interpolation steps is + constant and equal to the total path duration() divided by the + interpolationPeriod() * interpolationSpeed(). This is especially useful for + benchmarking or movie creation (constant number of snapshots). + + During the interpolation, the KeyFrameInterpolator emits an interpolated() + signal, which will usually be connected to the QGLViewer::update() slot. The + interpolation is stopped when interpolationTime() is greater than the + lastTime() (unless loopInterpolation() is \c true) and the endReached() signal + is then emitted. + + Note that a Camera has Camera::keyFrameInterpolator(), that can be used to + drive the Camera along a path, or to restore a saved position (a path made of + a single keyFrame). Press Alt+Fx to define a new keyFrame for path x. Pressing + Fx plays/pauses path interpolation. See QGLViewer::pathKey() and the keyboard page for details. + + \attention If a Constraint is attached to the frame() (see + Frame::constraint()), it should be deactivated before + interpolationIsStarted(), otherwise the interpolated motion (computed as if there was no constraint) will probably be erroneous.

Retrieving interpolated values

- This code defines a KeyFrameInterpolator, and displays the positions that will be followed by the - frame() along the path: - \code - KeyFrameInterpolator kfi( new Frame() ); + This code defines a KeyFrameInterpolator, and displays the positions that will + be followed by the frame() along the path: \code KeyFrameInterpolator kfi( new + Frame() ); // calls to kfi.addKeyFrame() to define the path. const qreal deltaTime = 0.04; // output a position every deltaTime seconds for (qreal time=kfi.firstTime(); time<=kfi.lastTime(); time += deltaTime) { - kfi.interpolateAtTime(time); - cout << "t=" << time << "\tpos=" << kfi.frame()->position() << endl; + kfi.interpolateAtTime(time); + cout << "t=" << time << "\tpos=" << kfi.frame()->position() << endl; } \endcode - You may want to temporally disconnect the \c kfi interpolated() signal from the - QGLViewer::update() slot before calling this code. \nosubgrouping */ -class QGLVIEWER_EXPORT KeyFrameInterpolator : public QObject -{ - // todo closedPath, insertKeyFrames, deleteKeyFrame, replaceKeyFrame - Q_OBJECT + You may want to temporally disconnect the \c kfi interpolated() signal from + the QGLViewer::update() slot before calling this code. \nosubgrouping */ +class QGLVIEWER_EXPORT KeyFrameInterpolator : public QObject { + // todo closedPath, insertKeyFrames, deleteKeyFrame, replaceKeyFrame + Q_OBJECT public: - KeyFrameInterpolator(Frame* fr=NULL); - virtual ~KeyFrameInterpolator(); + KeyFrameInterpolator(Frame *fr = nullptr); + virtual ~KeyFrameInterpolator(); Q_SIGNALS: - /*! This signal is emitted whenever the frame() state is interpolated. + /*! This signal is emitted whenever the frame() state is interpolated. - The emission of this signal triggers the synchronous emission of the frame() - Frame::interpolated() signal, which may also be useful. + The emission of this signal triggers the synchronous emission of the frame() + Frame::interpolated() signal, which may also be useful. - This signal should especially be connected to your QGLViewer::update() slot, so that the display - is updated after every update of the KeyFrameInterpolator frame(): - \code - connect(myKeyFrameInterpolator, SIGNAL(interpolated()), SLOT(update())); - \endcode - Use the QGLViewer::QGLViewerPool() to connect the signal to all the viewers. + This signal should especially be connected to your QGLViewer::update() slot, + so that the display is updated after every update of the KeyFrameInterpolator + frame(): \code connect(myKeyFrameInterpolator, SIGNAL(interpolated()), + SLOT(update())); \endcode Use the QGLViewer::QGLViewerPool() to connect the + signal to all the viewers. - Note that the QGLViewer::camera() Camera::keyFrameInterpolator() created using QGLViewer::pathKey() - have their interpolated() signals automatically connected to the QGLViewer::update() slot. */ - void interpolated(); + Note that the QGLViewer::camera() Camera::keyFrameInterpolator() created using + QGLViewer::pathKey() have their interpolated() signals automatically connected + to the QGLViewer::update() slot. */ + void interpolated(); - /*! This signal is emitted when the interpolation reaches the first (when interpolationSpeed() - is negative) or the last keyFrame. + /*! This signal is emitted when the interpolation reaches the first (when + interpolationSpeed() is negative) or the last keyFrame. - When loopInterpolation() is \c true, interpolationTime() is reset and the interpolation - continues. It otherwise stops. */ - void endReached(); + When loopInterpolation() is \c true, interpolationTime() is reset and the + interpolation continues. It otherwise stops. */ + void endReached(); - /*! @name Path creation */ - //@{ + /*! @name Path creation */ + //@{ public Q_SLOTS: - void addKeyFrame(const Frame& frame); - void addKeyFrame(const Frame& frame, qreal time); + void addKeyFrame(const Frame &frame); + void addKeyFrame(const Frame &frame, qreal time); - void addKeyFrame(const Frame* const frame); - void addKeyFrame(const Frame* const frame, qreal time); + void addKeyFrame(const Frame *const frame); + void addKeyFrame(const Frame *const frame, qreal time); - void deletePath(); - //@} + void deletePath(); + //@} - /*! @name Associated Frame */ - //@{ + /*! @name Associated Frame */ + //@{ public: - /*! Returns the associated Frame and that is interpolated by the KeyFrameInterpolator. + /*! Returns the associated Frame and that is interpolated by the + KeyFrameInterpolator. - When interpolationIsStarted(), this Frame's position and orientation will regularly be updated - by a timer, so that they follow the KeyFrameInterpolator path. + When interpolationIsStarted(), this Frame's position and orientation will + regularly be updated by a timer, so that they follow the KeyFrameInterpolator + path. - Set using setFrame() or with the KeyFrameInterpolator constructor. */ - Frame* frame() const { return frame_; } + Set using setFrame() or with the KeyFrameInterpolator constructor. */ + Frame *frame() const { return frame_; } public Q_SLOTS: - void setFrame(Frame* const frame); - //@} + void setFrame(Frame *const frame); + //@} - /*! @name Path parameters */ - //@{ + /*! @name Path parameters */ + //@{ public: - Frame keyFrame(int index) const; - qreal keyFrameTime(int index) const; - /*! Returns the number of keyFrames used by the interpolation. Use addKeyFrame() to add new keyFrames. */ - int numberOfKeyFrames() const { return keyFrame_.count(); } - qreal duration() const; - qreal firstTime() const; - qreal lastTime() const; - //@} - - /*! @name Interpolation parameters */ - //@{ + Frame keyFrame(int index) const; + qreal keyFrameTime(int index) const; + /*! Returns the number of keyFrames used by the interpolation. Use + * addKeyFrame() to add new keyFrames. */ + int numberOfKeyFrames() const { return keyFrame_.count(); } + qreal duration() const; + qreal firstTime() const; + qreal lastTime() const; + //@} + + /*! @name Interpolation parameters */ + //@{ public: - /*! Returns the current interpolation time (in seconds) along the KeyFrameInterpolator path. + /*! Returns the current interpolation time (in seconds) along the + KeyFrameInterpolator path. - This time is regularly updated when interpolationIsStarted(). Can be set directly with - setInterpolationTime() or interpolateAtTime(). */ - qreal interpolationTime() const { return interpolationTime_; } - /*! Returns the current interpolation speed. + This time is regularly updated when interpolationIsStarted(). Can be set + directly with setInterpolationTime() or interpolateAtTime(). */ + qreal interpolationTime() const { return interpolationTime_; } + /*! Returns the current interpolation speed. - Default value is 1.0, which means keyFrameTime() will be matched during the interpolation - (provided that your main loop is fast enough). + Default value is 1.0, which means keyFrameTime() will be matched during the + interpolation (provided that your main loop is fast enough). - A negative value will result in a reverse interpolation of the keyFrames. See also - interpolationPeriod(). */ - qreal interpolationSpeed() const { return interpolationSpeed_; } - /*! Returns the current interpolation period, expressed in milliseconds. + A negative value will result in a reverse interpolation of the keyFrames. See + also interpolationPeriod(). */ + qreal interpolationSpeed() const { return interpolationSpeed_; } + /*! Returns the current interpolation period, expressed in milliseconds. - The update of the frame() state will be done by a timer at this period when - interpolationIsStarted(). + The update of the frame() state will be done by a timer at this period when + interpolationIsStarted(). - This period (multiplied by interpolationSpeed()) is added to the interpolationTime() at each - update, and the frame() state is modified accordingly (see interpolateAtTime()). Default value - is 40 milliseconds. */ - int interpolationPeriod() const { return period_; } - /*! Returns \c true when the interpolation is played in an infinite loop. + This period (multiplied by interpolationSpeed()) is added to the + interpolationTime() at each update, and the frame() state is modified + accordingly (see interpolateAtTime()). Default value is 40 milliseconds. */ + int interpolationPeriod() const { return period_; } + /*! Returns \c true when the interpolation is played in an infinite loop. - When \c false (default), the interpolation stops when interpolationTime() reaches firstTime() - (with negative interpolationSpeed()) or lastTime(). + When \c false (default), the interpolation stops when interpolationTime() + reaches firstTime() (with negative interpolationSpeed()) or lastTime(). - interpolationTime() is otherwise reset to firstTime() (+ interpolationTime() - lastTime()) (and - inversely for negative interpolationSpeed()) and interpolation continues. + interpolationTime() is otherwise reset to firstTime() (+ interpolationTime() - + lastTime()) (and inversely for negative interpolationSpeed()) and + interpolation continues. - In both cases, the endReached() signal is emitted. */ - bool loopInterpolation() const { return loopInterpolation_; } + In both cases, the endReached() signal is emitted. */ + bool loopInterpolation() const { return loopInterpolation_; } #ifndef DOXYGEN - /*! Whether or not (default) the path defined by the keyFrames is a closed loop. When \c true, - the last and the first KeyFrame are linked by a new spline segment. + /*! Whether or not (default) the path defined by the keyFrames is a closed + loop. When \c true, the last and the first KeyFrame are linked by a new spline + segment. - Use setLoopInterpolation() to create a continuous animation over the entire path. - \attention The closed path feature is not yet implemented. */ - bool closedPath() const { return closedPath_; } + Use setLoopInterpolation() to create a continuous animation over the entire + path. \attention The closed path feature is not yet implemented. */ + bool closedPath() const { return closedPath_; } #endif public Q_SLOTS: - /*! Sets the interpolationTime(). - - \attention The frame() state is not affected by this method. Use this function to define the - starting time of a future interpolation (see startInterpolation()). Use interpolateAtTime() to - actually interpolate at a given time. */ - void setInterpolationTime(qreal time) { interpolationTime_ = time; } - /*! Sets the interpolationSpeed(). Negative or null values are allowed. */ - void setInterpolationSpeed(qreal speed) { interpolationSpeed_ = speed; } - /*! Sets the interpolationPeriod(). */ - void setInterpolationPeriod(int period) { period_ = period; } - /*! Sets the loopInterpolation() value. */ - void setLoopInterpolation(bool loop=true) { loopInterpolation_ = loop; } + /*! Sets the interpolationTime(). + + \attention The frame() state is not affected by this method. Use this function + to define the starting time of a future interpolation (see + startInterpolation()). Use interpolateAtTime() to actually interpolate at a + given time. */ + void setInterpolationTime(qreal time) { interpolationTime_ = time; } + /*! Sets the interpolationSpeed(). Negative or null values are allowed. */ + void setInterpolationSpeed(qreal speed) { interpolationSpeed_ = speed; } + /*! Sets the interpolationPeriod(). */ + void setInterpolationPeriod(int period) { period_ = period; } + /*! Sets the loopInterpolation() value. */ + void setLoopInterpolation(bool loop = true) { loopInterpolation_ = loop; } #ifndef DOXYGEN - /*! Sets the closedPath() value. \attention The closed path feature is not yet implemented. */ - void setClosedPath(bool closed=true) { closedPath_ = closed; } + /*! Sets the closedPath() value. \attention The closed path feature is not yet + * implemented. */ + void setClosedPath(bool closed = true) { closedPath_ = closed; } #endif - //@} + //@} - - /*! @name Interpolation */ - //@{ + /*! @name Interpolation */ + //@{ public: - /*! Returns \c true when the interpolation is being performed. Use startInterpolation(), - stopInterpolation() or toggleInterpolation() to modify this state. */ - bool interpolationIsStarted() const { return interpolationStarted_; } + /*! Returns \c true when the interpolation is being performed. Use + startInterpolation(), stopInterpolation() or toggleInterpolation() to modify + this state. */ + bool interpolationIsStarted() const { return interpolationStarted_; } public Q_SLOTS: - void startInterpolation(int period = -1); - void stopInterpolation(); - void resetInterpolation(); - /*! Calls startInterpolation() or stopInterpolation(), depending on interpolationIsStarted(). */ - void toggleInterpolation() { if (interpolationIsStarted()) stopInterpolation(); else startInterpolation(); } - virtual void interpolateAtTime(qreal time); - //@} - - /*! @name Path drawing */ - //@{ + void startInterpolation(int period = -1); + void stopInterpolation(); + void resetInterpolation(); + /*! Calls startInterpolation() or stopInterpolation(), depending on + * interpolationIsStarted(). */ + void toggleInterpolation() { + if (interpolationIsStarted()) + stopInterpolation(); + else + startInterpolation(); + } + virtual void interpolateAtTime(qreal time); + //@} + + /*! @name Path drawing */ + //@{ public: - virtual void drawPath(int mask=1, int nbFrames=6, qreal scale=1.0); - //@} + virtual void drawPath(int mask = 1, int nbFrames = 6, qreal scale = 1.0); + //@} - /*! @name XML representation */ - //@{ + /*! @name XML representation */ + //@{ public: - virtual QDomElement domElement(const QString& name, QDomDocument& document) const; - virtual void initFromDOMElement(const QDomElement& element); - //@} + virtual QDomElement domElement(const QString &name, + QDomDocument &document) const; + virtual void initFromDOMElement(const QDomElement &element); + //@} private Q_SLOTS: - virtual void update(); - virtual void invalidateValues() { valuesAreValid_ = false; pathIsValid_ = false; splineCacheIsValid_ = false; } + virtual void update(); + virtual void invalidateValues() { + valuesAreValid_ = false; + pathIsValid_ = false; + splineCacheIsValid_ = false; + } private: - // Copy constructor and opertor= are declared private and undefined - // Prevents everyone from trying to use them - // KeyFrameInterpolator(const KeyFrameInterpolator& kfi); - // KeyFrameInterpolator& operator=(const KeyFrameInterpolator& kfi); + // Copy constructor and opertor= are declared private and undefined + // Prevents everyone from trying to use them + // KeyFrameInterpolator(const KeyFrameInterpolator& kfi); + // KeyFrameInterpolator& operator=(const KeyFrameInterpolator& kfi); - void updateCurrentKeyFrameForTime(qreal time); - void updateModifiedFrameValues(); - void updateSplineCache(); + void updateCurrentKeyFrameForTime(qreal time); + void updateModifiedFrameValues(); + void updateSplineCache(); #ifndef DOXYGEN - // Internal private KeyFrame representation - class KeyFrame - { - public: - KeyFrame(const Frame& fr, qreal t); - KeyFrame(const Frame* fr, qreal t); - - Vec position() const { return p_; } - Quaternion orientation() const { return q_; } - Vec tgP() const { return tgP_; } - Quaternion tgQ() const { return tgQ_; } - qreal time() const { return time_; } - const Frame* frame() const { return frame_; } - void updateValuesFromPointer(); - void flipOrientationIfNeeded(const Quaternion& prev); - void computeTangent(const KeyFrame* const prev, const KeyFrame* const next); - private: - Vec p_, tgP_; - Quaternion q_, tgQ_; - qreal time_; - const Frame* const frame_; - }; + // Internal private KeyFrame representation + class KeyFrame { + public: + KeyFrame(const Frame &fr, qreal t); + KeyFrame(const Frame *fr, qreal t); + + Vec position() const { return p_; } + Quaternion orientation() const { return q_; } + Vec tgP() const { return tgP_; } + Quaternion tgQ() const { return tgQ_; } + qreal time() const { return time_; } + const Frame *frame() const { return frame_; } + void updateValuesFromPointer(); + void flipOrientationIfNeeded(const Quaternion &prev); + void computeTangent(const KeyFrame *const prev, const KeyFrame *const next); + + private: + Vec p_, tgP_; + Quaternion q_, tgQ_; + qreal time_; + const Frame *const frame_; + }; #endif - // K e y F r a m e s - mutable QList keyFrame_; - QMutableListIterator* currentFrame_[4]; - QList path_; - - // A s s o c i a t e d f r a m e - Frame* frame_; - - // R h y t h m - QTimer timer_; - int period_; - qreal interpolationTime_; - qreal interpolationSpeed_; - bool interpolationStarted_; - - // M i s c - bool closedPath_; - bool loopInterpolation_; - - // C a c h e d v a l u e s a n d f l a g s - bool pathIsValid_; - bool valuesAreValid_; - bool currentFrameValid_; - bool splineCacheIsValid_; - Vec v1, v2; + // K e y F r a m e s + mutable QList keyFrame_; + QMutableListIterator *currentFrame_[4]; + QList path_; + + // A s s o c i a t e d f r a m e + Frame *frame_; + + // R h y t h m + QTimer timer_; + int period_; + qreal interpolationTime_; + qreal interpolationSpeed_; + bool interpolationStarted_; + + // M i s c + bool closedPath_; + bool loopInterpolation_; + + // C a c h e d v a l u e s a n d f l a g s + bool pathIsValid_; + bool valuesAreValid_; + bool currentFrameValid_; + bool splineCacheIsValid_; + Vec v1, v2; }; } // namespace qglviewer diff --git a/octovis/src/extern/QGLViewer/manipulatedCameraFrame.cpp b/octovis/src/extern/QGLViewer/manipulatedCameraFrame.cpp index 723b0f77..4eafa2e0 100644 --- a/octovis/src/extern/QGLViewer/manipulatedCameraFrame.cpp +++ b/octovis/src/extern/QGLViewer/manipulatedCameraFrame.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,9 +19,8 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - -#include "domUtils.h" #include "manipulatedCameraFrame.h" +#include "domUtils.h" #include "qglviewer.h" #include @@ -31,95 +30,95 @@ using namespace std; /*! Default constructor. - flySpeed() is set to 0.0 and sceneUpVector() is (0,1,0). The pivotPoint() is set to (0,0,0). + flySpeed() is set to 0.0 and sceneUpVector() is (0,1,0). The pivotPoint() is + set to (0,0,0). \attention Created object is removeFromMouseGrabberPool(). */ ManipulatedCameraFrame::ManipulatedCameraFrame() - : driveSpeed_(0.0), sceneUpVector_(0.0, 1.0, 0.0), rotatesAroundUpVector_(false), zoomsOnPivotPoint_(false) -{ - setFlySpeed(0.0); - removeFromMouseGrabberPool(); - connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate())); + : driveSpeed_(0.0), sceneUpVector_(0.0, 1.0, 0.0), + rotatesAroundUpVector_(false), zoomsOnPivotPoint_(false) { + setFlySpeed(0.0); + removeFromMouseGrabberPool(); + connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate())); } -/*! Equal operator. Calls ManipulatedFrame::operator=() and then copy attributes. */ -ManipulatedCameraFrame& ManipulatedCameraFrame::operator=(const ManipulatedCameraFrame& mcf) -{ - ManipulatedFrame::operator=(mcf); +/*! Equal operator. Calls ManipulatedFrame::operator=() and then copy + * attributes. */ +ManipulatedCameraFrame &ManipulatedCameraFrame:: +operator=(const ManipulatedCameraFrame &mcf) { + ManipulatedFrame::operator=(mcf); - setFlySpeed(mcf.flySpeed()); - setSceneUpVector(mcf.sceneUpVector()); - setRotatesAroundUpVector(mcf.rotatesAroundUpVector_); - setZoomsOnPivotPoint(mcf.zoomsOnPivotPoint_); + setFlySpeed(mcf.flySpeed()); + setSceneUpVector(mcf.sceneUpVector()); + setRotatesAroundUpVector(mcf.rotatesAroundUpVector_); + setZoomsOnPivotPoint(mcf.zoomsOnPivotPoint_); - return *this; + return *this; } /*! Copy constructor. Performs a deep copy of all members using operator=(). */ -ManipulatedCameraFrame::ManipulatedCameraFrame(const ManipulatedCameraFrame& mcf) - : ManipulatedFrame(mcf) -{ - removeFromMouseGrabberPool(); - connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate())); - (*this)=(mcf); +ManipulatedCameraFrame::ManipulatedCameraFrame( + const ManipulatedCameraFrame &mcf) + : ManipulatedFrame(mcf) { + removeFromMouseGrabberPool(); + connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate())); + (*this) = (mcf); } //////////////////////////////////////////////////////////////////////////////// /*! Overloading of ManipulatedFrame::spin(). -Rotates the ManipulatedCameraFrame around its pivotPoint() instead of its origin. */ -void ManipulatedCameraFrame::spin() -{ - rotateAroundPoint(spinningQuaternion(), pivotPoint()); +Rotates the ManipulatedCameraFrame around its pivotPoint() instead of its +origin. */ +void ManipulatedCameraFrame::spin() { + rotateAroundPoint(spinningQuaternion(), pivotPoint()); } #ifndef DOXYGEN -/*! Called for continuous frame motion in fly mode (see QGLViewer::MOVE_FORWARD). Emits - manipulated(). */ -void ManipulatedCameraFrame::flyUpdate() -{ - static Vec flyDisp(0.0, 0.0, 0.0); - switch (action_) - { - case QGLViewer::MOVE_FORWARD: - flyDisp.z = -flySpeed(); - translate(localInverseTransformOf(flyDisp)); - break; - case QGLViewer::MOVE_BACKWARD: - flyDisp.z = flySpeed(); - translate(localInverseTransformOf(flyDisp)); - break; - case QGLViewer::DRIVE: - flyDisp.z = flySpeed() * driveSpeed_; - translate(localInverseTransformOf(flyDisp)); - break; - default: - break; - } - - // Needs to be out of the switch since ZOOM/fastDraw()/wheelEvent use this callback to trigger a final draw(). - // #CONNECTION# wheelEvent. - Q_EMIT manipulated(); +/*! Called for continuous frame motion in fly mode (see + QGLViewer::MOVE_FORWARD). Emits manipulated(). */ +void ManipulatedCameraFrame::flyUpdate() { + static Vec flyDisp(0.0, 0.0, 0.0); + switch (action_) { + case QGLViewer::MOVE_FORWARD: + flyDisp.z = -flySpeed(); + translate(localInverseTransformOf(flyDisp)); + break; + case QGLViewer::MOVE_BACKWARD: + flyDisp.z = flySpeed(); + translate(localInverseTransformOf(flyDisp)); + break; + case QGLViewer::DRIVE: + flyDisp.z = flySpeed() * driveSpeed_; + translate(localInverseTransformOf(flyDisp)); + break; + default: + break; + } + + // Needs to be out of the switch since ZOOM/fastDraw()/wheelEvent use this + // callback to trigger a final draw(). #CONNECTION# wheelEvent. + Q_EMIT manipulated(); } Vec ManipulatedCameraFrame::flyUpVector() const { - qWarning("flyUpVector() is deprecated. Use sceneUpVector() instead."); - return sceneUpVector(); + qWarning("flyUpVector() is deprecated. Use sceneUpVector() instead."); + return sceneUpVector(); } -void ManipulatedCameraFrame::setFlyUpVector(const Vec& up) { - qWarning("setFlyUpVector() is deprecated. Use setSceneUpVector() instead."); - setSceneUpVector(up); +void ManipulatedCameraFrame::setFlyUpVector(const Vec &up) { + qWarning("setFlyUpVector() is deprecated. Use setSceneUpVector() instead."); + setSceneUpVector(up); } #endif -/*! This method will be called by the Camera when its orientation is changed, so that the -sceneUpVector (private) is changed accordingly. You should not need to call this method. */ -void ManipulatedCameraFrame::updateSceneUpVector() -{ - sceneUpVector_ = inverseTransformOf(Vec(0.0, 1.0, 0.0)); +/*! This method will be called by the Camera when its orientation is changed, so +that the sceneUpVector (private) is changed accordingly. You should not need to +call this method. */ +void ManipulatedCameraFrame::updateSceneUpVector() { + sceneUpVector_ = inverseTransformOf(Vec(0.0, 1.0, 0.0)); } //////////////////////////////////////////////////////////////////////////////// @@ -128,342 +127,397 @@ void ManipulatedCameraFrame::updateSceneUpVector() /*! Returns an XML \c QDomElement that represents the ManipulatedCameraFrame. - Adds to the ManipulatedFrame::domElement() the ManipulatedCameraFrame specific informations in a \c - ManipulatedCameraParameters child QDomElement. - - \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create - QDomElement. - - Use initFromDOMElement() to restore the ManipulatedCameraFrame state from the resulting - \c QDomElement. - - See Vec::domElement() for a complete example. See also Quaternion::domElement(), - Frame::domElement(), Camera::domElement()... */ -QDomElement ManipulatedCameraFrame::domElement(const QString& name, QDomDocument& document) const -{ - QDomElement e = ManipulatedFrame::domElement(name, document); - QDomElement mcp = document.createElement("ManipulatedCameraParameters"); - mcp.setAttribute("flySpeed", QString::number(flySpeed())); - DomUtils::setBoolAttribute(mcp, "rotatesAroundUpVector", rotatesAroundUpVector()); - DomUtils::setBoolAttribute(mcp, "zoomsOnPivotPoint", zoomsOnPivotPoint()); - mcp.appendChild(sceneUpVector().domElement("sceneUpVector", document)); - e.appendChild(mcp); - return e; + Adds to the ManipulatedFrame::domElement() the ManipulatedCameraFrame specific + informations in a \c ManipulatedCameraParameters child QDomElement. + + \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument + factory used to create QDomElement. + + Use initFromDOMElement() to restore the ManipulatedCameraFrame state from the + resulting \c QDomElement. + + See Vec::domElement() for a complete example. See also + Quaternion::domElement(), Frame::domElement(), Camera::domElement()... */ +QDomElement ManipulatedCameraFrame::domElement(const QString &name, + QDomDocument &document) const { + QDomElement e = ManipulatedFrame::domElement(name, document); + QDomElement mcp = document.createElement("ManipulatedCameraParameters"); + mcp.setAttribute("flySpeed", QString::number(flySpeed())); + DomUtils::setBoolAttribute(mcp, "rotatesAroundUpVector", + rotatesAroundUpVector()); + DomUtils::setBoolAttribute(mcp, "zoomsOnPivotPoint", zoomsOnPivotPoint()); + mcp.appendChild(sceneUpVector().domElement("sceneUpVector", document)); + e.appendChild(mcp); + return e; } -/*! Restores the ManipulatedCameraFrame state from a \c QDomElement created by domElement(). - -First calls ManipulatedFrame::initFromDOMElement() and then initializes ManipulatedCameraFrame -specific parameters. */ -void ManipulatedCameraFrame::initFromDOMElement(const QDomElement& element) -{ - // No need to initialize, since default sceneUpVector and flySpeed are not meaningful. - // It's better to keep current ones. And it would destroy constraint() and referenceFrame(). - // *this = ManipulatedCameraFrame(); - ManipulatedFrame::initFromDOMElement(element); - - QDomElement child=element.firstChild().toElement(); - while (!child.isNull()) - { - if (child.tagName() == "ManipulatedCameraParameters") - { - setFlySpeed(DomUtils::qrealFromDom(child, "flySpeed", flySpeed())); - setRotatesAroundUpVector(DomUtils::boolFromDom(child, "rotatesAroundUpVector", false)); - setZoomsOnPivotPoint(DomUtils::boolFromDom(child, "zoomsOnPivotPoint", false)); - - QDomElement schild=child.firstChild().toElement(); - while (!schild.isNull()) - { - if (schild.tagName() == "sceneUpVector") - setSceneUpVector(Vec(schild)); - - schild = schild.nextSibling().toElement(); - } - } - child = child.nextSibling().toElement(); - } +/*! Restores the ManipulatedCameraFrame state from a \c QDomElement created by +domElement(). + +First calls ManipulatedFrame::initFromDOMElement() and then initializes +ManipulatedCameraFrame specific parameters. */ +void ManipulatedCameraFrame::initFromDOMElement(const QDomElement &element) { + // No need to initialize, since default sceneUpVector and flySpeed are not + // meaningful. It's better to keep current ones. And it would destroy + // constraint() and referenceFrame(). *this = ManipulatedCameraFrame(); + ManipulatedFrame::initFromDOMElement(element); + + QDomElement child = element.firstChild().toElement(); + while (!child.isNull()) { + if (child.tagName() == "ManipulatedCameraParameters") { + setFlySpeed(DomUtils::qrealFromDom(child, "flySpeed", flySpeed())); + setRotatesAroundUpVector( + DomUtils::boolFromDom(child, "rotatesAroundUpVector", false)); + setZoomsOnPivotPoint( + DomUtils::boolFromDom(child, "zoomsOnPivotPoint", false)); + + QDomElement schild = child.firstChild().toElement(); + while (!schild.isNull()) { + if (schild.tagName() == "sceneUpVector") + setSceneUpVector(Vec(schild)); + + schild = schild.nextSibling().toElement(); + } + } + child = child.nextSibling().toElement(); + } } - //////////////////////////////////////////////////////////////////////////////// // M o u s e h a n d l i n g // //////////////////////////////////////////////////////////////////////////////// #ifndef DOXYGEN /*! Protected internal method used to handle mouse events. */ -void ManipulatedCameraFrame::startAction(int ma, bool withConstraint) -{ - ManipulatedFrame::startAction(ma, withConstraint); - - switch (action_) - { - case QGLViewer::MOVE_FORWARD: - case QGLViewer::MOVE_BACKWARD: - case QGLViewer::DRIVE: - flyTimer_.setSingleShot(false); - flyTimer_.start(10); - break; - case QGLViewer::ROTATE: - constrainedRotationIsReversed_ = transformOf(sceneUpVector_).y < 0.0; - break; - default: - break; - } +void ManipulatedCameraFrame::startAction(int ma, bool withConstraint) { + ManipulatedFrame::startAction(ma, withConstraint); + + switch (action_) { + case QGLViewer::MOVE_FORWARD: + case QGLViewer::MOVE_BACKWARD: + case QGLViewer::DRIVE: + flyTimer_.setSingleShot(false); + flyTimer_.start(10); + break; + case QGLViewer::ROTATE: + constrainedRotationIsReversed_ = transformOf(sceneUpVector_).y < 0.0; + break; + default: + break; + } } -void ManipulatedCameraFrame::zoom(qreal delta, const Camera * const camera) { - const qreal sceneRadius = camera->sceneRadius(); - if (zoomsOnPivotPoint_) { - Vec direction = position() - camera->pivotPoint(); - if (direction.norm() > 0.02 * sceneRadius || delta > 0.0) - translate(delta * direction); - } else { - const qreal coef = qMax(fabs((camera->frame()->coordinatesOf(camera->pivotPoint())).z), 0.2 * sceneRadius); - Vec trans(0.0, 0.0, -coef * delta); - translate(inverseTransformOf(trans)); - } +void ManipulatedCameraFrame::zoom(qreal delta, const Camera *const camera) { + const qreal sceneRadius = camera->sceneRadius(); + if (zoomsOnPivotPoint_) { + Vec direction = position() - camera->pivotPoint(); + if (direction.norm() > 0.02 * sceneRadius || delta > 0.0) + translate(delta * direction); + } else { + const qreal coef = + qMax(fabs((camera->frame()->coordinatesOf(camera->pivotPoint())).z), + qreal(0.2) * sceneRadius); + Vec trans(0.0, 0.0, -coef * delta); + translate(inverseTransformOf(trans)); + } } #endif /*! Overloading of ManipulatedFrame::mouseMoveEvent(). -Motion depends on mouse binding (see mouse page for details). The -resulting displacements are basically inverted from those of a ManipulatedFrame. */ -void ManipulatedCameraFrame::mouseMoveEvent(QMouseEvent* const event, Camera* const camera) -{ - // #CONNECTION# QGLViewer::mouseMoveEvent does the update(). - switch (action_) - { - case QGLViewer::TRANSLATE: - { - const QPoint delta = prevPos_ - event->pos(); - Vec trans(delta.x(), -delta.y(), 0.0); - // Scale to fit the screen mouse displacement - switch (camera->type()) - { - case Camera::PERSPECTIVE : - trans *= 2.0 * tan(camera->fieldOfView()/2.0) * - fabs((camera->frame()->coordinatesOf(pivotPoint())).z) / camera->screenHeight(); - break; - case Camera::ORTHOGRAPHIC : - { - GLdouble w,h; - camera->getOrthoWidthHeight(w, h); - trans[0] *= 2.0 * w / camera->screenWidth(); - trans[1] *= 2.0 * h / camera->screenHeight(); - break; - } - } - translate(inverseTransformOf(translationSensitivity()*trans)); - break; - } - - case QGLViewer::MOVE_FORWARD: - { - Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera); - rotate(rot); - //#CONNECTION# wheelEvent MOVE_FORWARD case - // actual translation is made in flyUpdate(). - //translate(inverseTransformOf(Vec(0.0, 0.0, -flySpeed()))); - break; - } - - case QGLViewer::MOVE_BACKWARD: - { - Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera); - rotate(rot); - // actual translation is made in flyUpdate(). - //translate(inverseTransformOf(Vec(0.0, 0.0, flySpeed()))); - break; - } - - case QGLViewer::DRIVE: - { - Quaternion rot = turnQuaternion(event->x(), camera); - rotate(rot); - // actual translation is made in flyUpdate(). - driveSpeed_ = 0.01 * (event->y() - pressPos_.y()); - break; - } - - case QGLViewer::ZOOM: - { - zoom(deltaWithPrevPos(event, camera), camera); - break; - } - - case QGLViewer::LOOK_AROUND: - { - Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera); - rotate(rot); - break; - } - - case QGLViewer::ROTATE: - { - Quaternion rot; - if (rotatesAroundUpVector_) { - // Multiply by 2.0 to get on average about the same speed as with the deformed ball - qreal dx = 2.0 * rotationSensitivity() * (prevPos_.x() - event->x()) / camera->screenWidth(); - qreal dy = 2.0 * rotationSensitivity() * (prevPos_.y() - event->y()) / camera->screenHeight(); - if (constrainedRotationIsReversed_) dx = -dx; - Vec verticalAxis = transformOf(sceneUpVector_); - rot = Quaternion(verticalAxis, dx) * Quaternion(Vec(1.0, 0.0, 0.0), dy); - } else { - Vec trans = camera->projectedCoordinatesOf(pivotPoint()); - rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1], camera); - } - //#CONNECTION# These two methods should go together (spinning detection and activation) - computeMouseSpeed(event); - setSpinningQuaternion(rot); - spin(); - break; - } - - case QGLViewer::SCREEN_ROTATE: - { - Vec trans = camera->projectedCoordinatesOf(pivotPoint()); - - const qreal angle = atan2(event->y() - trans[1], event->x() - trans[0]) - atan2(prevPos_.y()-trans[1], prevPos_.x()-trans[0]); - - Quaternion rot(Vec(0.0, 0.0, 1.0), angle); - //#CONNECTION# These two methods should go together (spinning detection and activation) - computeMouseSpeed(event); - setSpinningQuaternion(rot); - spin(); - updateSceneUpVector(); - break; - } - - case QGLViewer::ROLL: - { - const qreal angle = M_PI * (event->x() - prevPos_.x()) / camera->screenWidth(); - Quaternion rot(Vec(0.0, 0.0, 1.0), angle); - rotate(rot); - setSpinningQuaternion(rot); - updateSceneUpVector(); - break; - } - - case QGLViewer::SCREEN_TRANSLATE: - { - Vec trans; - int dir = mouseOriginalDirection(event); - if (dir == 1) - trans.setValue(prevPos_.x() - event->x(), 0.0, 0.0); - else if (dir == -1) - trans.setValue(0.0, event->y() - prevPos_.y(), 0.0); - - switch (camera->type()) - { - case Camera::PERSPECTIVE : - trans *= 2.0 * tan(camera->fieldOfView()/2.0) * - fabs((camera->frame()->coordinatesOf(pivotPoint())).z) / camera->screenHeight(); - break; - case Camera::ORTHOGRAPHIC : - { - GLdouble w,h; - camera->getOrthoWidthHeight(w, h); - trans[0] *= 2.0 * w / camera->screenWidth(); - trans[1] *= 2.0 * h / camera->screenHeight(); - break; - } - } - - translate(inverseTransformOf(translationSensitivity()*trans)); - break; - } - - case QGLViewer::ZOOM_ON_REGION: - case QGLViewer::NO_MOUSE_ACTION: - break; - } - - if (action_ != QGLViewer::NO_MOUSE_ACTION) - { - prevPos_ = event->pos(); - if (action_ != QGLViewer::ZOOM_ON_REGION) - // ZOOM_ON_REGION should not emit manipulated(). - // prevPos_ is used to draw rectangle feedback. - Q_EMIT manipulated(); - } -} +Motion depends on mouse binding (see mouse page for +details). The resulting displacements are basically inverted from those of a +ManipulatedFrame. */ +void ManipulatedCameraFrame::mouseMoveEvent(QMouseEvent *const event, + Camera *const camera) { + // #CONNECTION# QGLViewer::mouseMoveEvent does the update(). + switch (action_) { + case QGLViewer::TRANSLATE: { + const QPoint delta = prevPos_ - event->pos(); + Vec trans(delta.x(), -delta.y(), 0.0); + // Scale to fit the screen mouse displacement + switch (camera->type()) { + case Camera::PERSPECTIVE: + trans *= 2.0 * tan(camera->fieldOfView() / 2.0) * + fabs((camera->frame()->coordinatesOf(pivotPoint())).z) / + camera->screenHeight(); + break; + case Camera::ORTHOGRAPHIC: { + GLdouble w, h; + camera->getOrthoWidthHeight(w, h); + trans[0] *= 2.0 * w / camera->screenWidth(); + trans[1] *= 2.0 * h / camera->screenHeight(); + break; + } + } + translate(inverseTransformOf(translationSensitivity() * trans)); + break; + } + + case QGLViewer::MOVE_FORWARD: { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera); +#else + Quaternion rot = pitchYawQuaternion(event->position().x(), event->position().y(), camera); +#endif + rotate(rot); + //#CONNECTION# wheelEvent MOVE_FORWARD case + // actual translation is made in flyUpdate(). + // translate(inverseTransformOf(Vec(0.0, 0.0, -flySpeed()))); + break; + } + + case QGLViewer::MOVE_BACKWARD: { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera); +#else + Quaternion rot = pitchYawQuaternion(event->position().x(), event->position().y(), camera); +#endif + rotate(rot); + // actual translation is made in flyUpdate(). + // translate(inverseTransformOf(Vec(0.0, 0.0, flySpeed()))); + break; + } + + case QGLViewer::DRIVE: { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + Quaternion rot = turnQuaternion(event->x(), camera); +#else + Quaternion rot = turnQuaternion(event->position().x(), camera); +#endif + rotate(rot); + // actual translation is made in flyUpdate(). +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + driveSpeed_ = 0.01 * (event->y() - pressPos_.y()); +#else + driveSpeed_ = 0.01 * (event->position().y() - pressPos_.y()); +#endif + break; + } + + case QGLViewer::ZOOM: { + zoom(deltaWithPrevPos(event, camera), camera); + break; + } + + case QGLViewer::LOOK_AROUND: { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera); +#else + Quaternion rot = pitchYawQuaternion(event->position().x(), event->position().y(), camera); +#endif + rotate(rot); + break; + } + + case QGLViewer::ROTATE: { + Quaternion rot; + if (rotatesAroundUpVector_) { + // Multiply by 2.0 to get on average about the same speed as with the + // deformed ball +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + qreal dx = 2.0 * rotationSensitivity() * (prevPos_.x() - event->x()) / + camera->screenWidth(); + qreal dy = 2.0 * rotationSensitivity() * (prevPos_.y() - event->y()) / + camera->screenHeight(); +#else + qreal dx = 2.0 * rotationSensitivity() * (prevPos_.x() - event->position().x()) / + camera->screenWidth(); + qreal dy = 2.0 * rotationSensitivity() * (prevPos_.y() - event->position().y()) / + camera->screenHeight(); +#endif + if (constrainedRotationIsReversed_) + dx = -dx; + Vec verticalAxis = transformOf(sceneUpVector_); + rot = Quaternion(verticalAxis, dx) * Quaternion(Vec(1.0, 0.0, 0.0), dy); + } else { + Vec trans = camera->projectedCoordinatesOf(pivotPoint()); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1], camera); +#else + rot = deformedBallQuaternion(event->position().x(), event->position().y(), trans[0], trans[1], camera); +#endif + } + //#CONNECTION# These two methods should go together (spinning detection and + // activation) + computeMouseSpeed(event); + setSpinningQuaternion(rot); + spin(); + break; + } + + case QGLViewer::SCREEN_ROTATE: { + Vec trans = camera->projectedCoordinatesOf(pivotPoint()); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + const qreal angle = atan2(event->y() - trans[1], event->x() - trans[0]) - + atan2(prevPos_.y() - trans[1], prevPos_.x() - trans[0]); +#else + const qreal angle = atan2(event->position().y() - trans[1], event->position().x() - trans[0]) - + atan2(prevPos_.y() - trans[1], prevPos_.x() - trans[0]); +#endif + Quaternion rot(Vec(0.0, 0.0, 1.0), angle); + //#CONNECTION# These two methods should go together (spinning detection and + // activation) + computeMouseSpeed(event); + setSpinningQuaternion(rot); + spin(); + updateSceneUpVector(); + break; + } + + case QGLViewer::ROLL: { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + const qreal angle = M_PI * (event->x() - prevPos_.x()) / camera->screenWidth(); +#else + const qreal angle = M_PI * (event->position().x() - prevPos_.x()) / camera->screenWidth(); +#endif + Quaternion rot(Vec(0.0, 0.0, 1.0), angle); + rotate(rot); + setSpinningQuaternion(rot); + updateSceneUpVector(); + break; + } + + case QGLViewer::SCREEN_TRANSLATE: { + Vec trans; + int dir = mouseOriginalDirection(event); + if (dir == 1) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + trans.setValue(prevPos_.x() - event->x(), 0.0, 0.0); +#else + trans.setValue(prevPos_.x() - event->position().x(), 0.0, 0.0); +#endif + else if (dir == -1) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + trans.setValue(0.0, event->y() - prevPos_.y(), 0.0); +#else + trans.setValue(0.0, event->position().y() - prevPos_.y(), 0.0); +#endif + + switch (camera->type()) { + case Camera::PERSPECTIVE: + trans *= 2.0 * tan(camera->fieldOfView() / 2.0) * + fabs((camera->frame()->coordinatesOf(pivotPoint())).z) / + camera->screenHeight(); + break; + case Camera::ORTHOGRAPHIC: { + GLdouble w, h; + camera->getOrthoWidthHeight(w, h); + trans[0] *= 2.0 * w / camera->screenWidth(); + trans[1] *= 2.0 * h / camera->screenHeight(); + break; + } + } + + translate(inverseTransformOf(translationSensitivity() * trans)); + break; + } + + case QGLViewer::ZOOM_ON_REGION: + case QGLViewer::NO_MOUSE_ACTION: + break; + } + + if (action_ != QGLViewer::NO_MOUSE_ACTION) { + prevPos_ = event->pos(); + if (action_ != QGLViewer::ZOOM_ON_REGION) + // ZOOM_ON_REGION should not emit manipulated(). + // prevPos_ is used to draw rectangle feedback. + Q_EMIT manipulated(); + } +} -/*! This is an overload of ManipulatedFrame::mouseReleaseEvent(). The QGLViewer::MouseAction is - terminated. */ -void ManipulatedCameraFrame::mouseReleaseEvent(QMouseEvent* const event, Camera* const camera) -{ - if ((action_ == QGLViewer::MOVE_FORWARD) || (action_ == QGLViewer::MOVE_BACKWARD) || (action_ == QGLViewer::DRIVE)) - flyTimer_.stop(); +/*! This is an overload of ManipulatedFrame::mouseReleaseEvent(). The + QGLViewer::MouseAction is terminated. */ +void ManipulatedCameraFrame::mouseReleaseEvent(QMouseEvent *const event, + Camera *const camera) { + if ((action_ == QGLViewer::MOVE_FORWARD) || + (action_ == QGLViewer::MOVE_BACKWARD) || (action_ == QGLViewer::DRIVE)) + flyTimer_.stop(); - if (action_ == QGLViewer::ZOOM_ON_REGION) - camera->fitScreenRegion(QRect(pressPos_, event->pos())); + if (action_ == QGLViewer::ZOOM_ON_REGION) + camera->fitScreenRegion(QRect(pressPos_, event->pos())); - ManipulatedFrame::mouseReleaseEvent(event, camera); + ManipulatedFrame::mouseReleaseEvent(event, camera); } /*! This is an overload of ManipulatedFrame::wheelEvent(). -The wheel behavior depends on the wheel binded action. Current possible actions are QGLViewer::ZOOM, -QGLViewer::MOVE_FORWARD, QGLViewer::MOVE_BACKWARD. QGLViewer::ZOOM speed depends on -wheelSensitivity() while QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD depend on flySpeed(). -See QGLViewer::setWheelBinding() to customize the binding. */ -void ManipulatedCameraFrame::wheelEvent(QWheelEvent* const event, Camera* const camera) -{ - //#CONNECTION# QGLViewer::setWheelBinding, ManipulatedFrame::wheelEvent. - switch (action_) - { - case QGLViewer::ZOOM: - { - zoom(wheelDelta(event), camera); - Q_EMIT manipulated(); - break; - } - case QGLViewer::MOVE_FORWARD: - case QGLViewer::MOVE_BACKWARD: - //#CONNECTION# mouseMoveEvent() MOVE_FORWARD case - translate(inverseTransformOf(Vec(0.0, 0.0, 0.2*flySpeed()*event->delta()))); - Q_EMIT manipulated(); - break; - default: - break; - } - - // #CONNECTION# startAction should always be called before - if (previousConstraint_) - setConstraint(previousConstraint_); - - // The wheel triggers a fastDraw. A final update() is needed after the last wheel event to - // polish the rendering using draw(). Since the last wheel event does not say its name, we use - // the flyTimer_ to trigger flyUpdate(), which emits manipulated. Two wheel events - // separated by more than this delay milliseconds will trigger a draw(). - const int finalDrawAfterWheelEventDelay = 400; - - // Starts (or prolungates) the timer. - flyTimer_.setSingleShot(true); - flyTimer_.start(finalDrawAfterWheelEventDelay); - - // This could also be done *before* manipulated is emitted, so that isManipulated() returns false. - // But then fastDraw would not be used with wheel. - // Detecting the last wheel event and forcing a final draw() is done using the timer_. - action_ = QGLViewer::NO_MOUSE_ACTION; +The wheel behavior depends on the wheel binded action. Current possible actions +are QGLViewer::ZOOM, QGLViewer::MOVE_FORWARD, QGLViewer::MOVE_BACKWARD. +QGLViewer::ZOOM speed depends on wheelSensitivity() while +QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD depend on flySpeed(). See +QGLViewer::setWheelBinding() to customize the binding. */ +void ManipulatedCameraFrame::wheelEvent(QWheelEvent *const event, + Camera *const camera) { + //#CONNECTION# QGLViewer::setWheelBinding, ManipulatedFrame::wheelEvent. + switch (action_) { + case QGLViewer::ZOOM: { + zoom(wheelDelta(event), camera); + Q_EMIT manipulated(); + break; + } + case QGLViewer::MOVE_FORWARD: + case QGLViewer::MOVE_BACKWARD: + //#CONNECTION# mouseMoveEvent() MOVE_FORWARD case + translate( +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + inverseTransformOf(Vec(0.0, 0.0, 0.2 * flySpeed() * event->delta()))); +#else + inverseTransformOf(Vec(0.0, 0.0, 0.2 * flySpeed() * event->angleDelta().y()))); +#endif + Q_EMIT manipulated(); + break; + default: + break; + } + + // #CONNECTION# startAction should always be called before + if (previousConstraint_) + setConstraint(previousConstraint_); + + // The wheel triggers a fastDraw. A final update() is needed after the last + // wheel event to polish the rendering using draw(). Since the last wheel + // event does not say its name, we use the flyTimer_ to trigger flyUpdate(), + // which emits manipulated. Two wheel events separated by more than this delay + // milliseconds will trigger a draw(). + const int finalDrawAfterWheelEventDelay = 400; + + // Starts (or prolungates) the timer. + flyTimer_.setSingleShot(true); + flyTimer_.start(finalDrawAfterWheelEventDelay); + + // This could also be done *before* manipulated is emitted, so that + // isManipulated() returns false. But then fastDraw would not be used with + // wheel. Detecting the last wheel event and forcing a final draw() is done + // using the timer_. + action_ = QGLViewer::NO_MOUSE_ACTION; } //////////////////////////////////////////////////////////////////////////////// -/*! Returns a Quaternion that is a rotation around current camera Y, proportionnal to the horizontal mouse position. */ -Quaternion ManipulatedCameraFrame::turnQuaternion(int x, const Camera* const camera) -{ - return Quaternion(Vec(0.0, 1.0, 0.0), rotationSensitivity()*(prevPos_.x()-x)/camera->screenWidth()); +/*! Returns a Quaternion that is a rotation around current camera Y, + * proportionnal to the horizontal mouse position. */ +Quaternion ManipulatedCameraFrame::turnQuaternion(int x, + const Camera *const camera) { + return Quaternion(Vec(0.0, 1.0, 0.0), rotationSensitivity() * + (prevPos_.x() - x) / + camera->screenWidth()); } -/*! Returns a Quaternion that is the composition of two rotations, inferred from the - mouse pitch (X axis) and yaw (sceneUpVector() axis). */ -Quaternion ManipulatedCameraFrame::pitchYawQuaternion(int x, int y, const Camera* const camera) -{ - const Quaternion rotX(Vec(1.0, 0.0, 0.0), rotationSensitivity()*(prevPos_.y()-y)/camera->screenHeight()); - const Quaternion rotY(transformOf(sceneUpVector()), rotationSensitivity()*(prevPos_.x()-x)/camera->screenWidth()); - return rotY * rotX; +/*! Returns a Quaternion that is the composition of two rotations, inferred from + the mouse pitch (X axis) and yaw (sceneUpVector() axis). */ +Quaternion +ManipulatedCameraFrame::pitchYawQuaternion(int x, int y, + const Camera *const camera) { + const Quaternion rotX(Vec(1.0, 0.0, 0.0), rotationSensitivity() * + (prevPos_.y() - y) / + camera->screenHeight()); + const Quaternion rotY(transformOf(sceneUpVector()), + rotationSensitivity() * (prevPos_.x() - x) / + camera->screenWidth()); + return rotY * rotX; } diff --git a/octovis/src/extern/QGLViewer/manipulatedCameraFrame.h b/octovis/src/extern/QGLViewer/manipulatedCameraFrame.h index 1f500ad1..88fdb502 100644 --- a/octovis/src/extern/QGLViewer/manipulatedCameraFrame.h +++ b/octovis/src/extern/QGLViewer/manipulatedCameraFrame.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,213 +19,242 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_MANIPULATED_CAMERA_FRAME_H #define QGLVIEWER_MANIPULATED_CAMERA_FRAME_H #include "manipulatedFrame.h" namespace qglviewer { -/*! \brief The ManipulatedCameraFrame class represents a ManipulatedFrame with Camera specific mouse bindings. - \class ManipulatedCameraFrame manipulatedCameraFrame.h QGLViewer/manipulatedCameraFrame.h - - A ManipulatedCameraFrame is a specialization of a ManipulatedFrame, designed to be set as the - Camera::frame(). Mouse motions are basically interpreted in a negated way: when the mouse goes to - the right, the ManipulatedFrame translation goes to the right, while the ManipulatedCameraFrame - has to go to the \e left, so that the \e scene seems to move to the right. - - A ManipulatedCameraFrame rotates around its pivotPoint(), which corresponds to the - associated Camera::pivotPoint(). - - A ManipulatedCameraFrame can also "fly" in the scene. It basically moves forward, and turns - according to the mouse motion. See flySpeed(), sceneUpVector() and the QGLViewer::MOVE_FORWARD and - QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction. - - See the mouse page for a description of the possible actions that can - be performed using the mouse and their bindings. +/*! \brief The ManipulatedCameraFrame class represents a ManipulatedFrame with + Camera specific mouse bindings. \class ManipulatedCameraFrame + manipulatedCameraFrame.h QGLViewer/manipulatedCameraFrame.h + + A ManipulatedCameraFrame is a specialization of a ManipulatedFrame, designed + to be set as the Camera::frame(). Mouse motions are basically interpreted in a + negated way: when the mouse goes to the right, the ManipulatedFrame + translation goes to the right, while the ManipulatedCameraFrame has to go to + the \e left, so that the \e scene seems to move to the right. + + A ManipulatedCameraFrame rotates around its pivotPoint(), which corresponds to + the associated Camera::pivotPoint(). + + A ManipulatedCameraFrame can also "fly" in the scene. It basically moves + forward, and turns according to the mouse motion. See flySpeed(), + sceneUpVector() and the QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD + QGLViewer::MouseAction. + + See the mouse page for a description of the + possible actions that can be performed using the mouse and their bindings. \nosubgrouping */ -class QGLVIEWER_EXPORT ManipulatedCameraFrame : public ManipulatedFrame -{ +class QGLVIEWER_EXPORT ManipulatedCameraFrame : public ManipulatedFrame { #ifndef DOXYGEN - friend class Camera; - friend class ::QGLViewer; + friend class Camera; + friend class ::QGLViewer; #endif - Q_OBJECT + Q_OBJECT public: - ManipulatedCameraFrame(); - /*! Virtual destructor. Empty. */ - virtual ~ManipulatedCameraFrame() {} + ManipulatedCameraFrame(); + /*! Virtual destructor. Empty. */ + virtual ~ManipulatedCameraFrame() {} - ManipulatedCameraFrame(const ManipulatedCameraFrame& mcf); - ManipulatedCameraFrame& operator=(const ManipulatedCameraFrame& mcf); + ManipulatedCameraFrame(const ManipulatedCameraFrame &mcf); + ManipulatedCameraFrame &operator=(const ManipulatedCameraFrame &mcf); - /*! @name Pivot point */ - //@{ + /*! @name Pivot point */ + //@{ public: - /*! Returns the point the ManipulatedCameraFrame pivot point, around which the camera rotates. + /*! Returns the point the ManipulatedCameraFrame pivot point, around which the + camera rotates. - It is defined in the world coordinate system. Default value is (0,0,0). + It is defined in the world coordinate system. Default value is (0,0,0). - When the ManipulatedCameraFrame is associated to a Camera, Camera::pivotPoint() also - returns this value. This point can interactively be changed using the mouse (see - Camera::setPivotPointFromPixel() and QGLViewer::RAP_FROM_PIXEL and QGLViewer::RAP_IS_CENTER - in the mouse page). */ - Vec pivotPoint() const { return pivotPoint_; } - /*! Sets the pivotPoint(), defined in the world coordinate system. */ - void setPivotPoint(const Vec& point) { pivotPoint_ = point; } + When the ManipulatedCameraFrame is associated to a Camera, + Camera::pivotPoint() also returns this value. This point can interactively be + changed using the mouse (see Camera::setPivotPointFromPixel() and + QGLViewer::RAP_FROM_PIXEL and QGLViewer::RAP_IS_CENTER in the mouse page). */ + Vec pivotPoint() const { return pivotPoint_; } + /*! Sets the pivotPoint(), defined in the world coordinate system. */ + void setPivotPoint(const Vec &point) { pivotPoint_ = point; } #ifndef DOXYGEN - Vec revolveAroundPoint() const { qWarning("revolveAroundPoint() is deprecated, use pivotPoint() instead"); return pivotPoint(); } - void setRevolveArountPoint(const Vec& point) { qWarning("setRevolveAroundPoint() is deprecated, use setPivotPoint() instead"); setPivotPoint(point); } + Vec revolveAroundPoint() const { + qWarning("revolveAroundPoint() is deprecated, use pivotPoint() instead"); + return pivotPoint(); + } + void setRevolveAroundPoint(const Vec &point) { + qWarning( + "setRevolveAroundPoint() is deprecated, use setPivotPoint() instead"); + setPivotPoint(point); + } #endif - //@} + //@} - /*! @name Camera manipulation */ - //@{ + /*! @name Camera manipulation */ + //@{ public: - /*! Returns \c true when the frame's rotation is constrained around the sceneUpVector(), - and \c false otherwise, when the rotation is completely free (default). - - In free mode, the associated camera can be arbitrarily rotated in the scene, along its - three axis, thus possibly leading to any arbitrary orientation. - - When you setRotatesAroundUpVector() to \c true, the sceneUpVector() defines a - 'vertical' direction around which the camera rotates. The camera can rotate left - or right, around this axis. It can also be moved up or down to show the 'top' and - 'bottom' views of the scene. As a result, the sceneUpVector() will always appear vertical - in the scene, and the horizon is preserved and stays projected along the camera's - horizontal axis. - - Note that setting this value to \c true when the sceneUpVector() is not already - vertically projected will break these invariants. It will also limit the possible movement - of the camera, possibly up to a lock when the sceneUpVector() is projected horizontally. - Use Camera::setUpVector() to define the sceneUpVector() and align the camera before calling - this method to ensure this does not happen. */ - bool rotatesAroundUpVector() const { return rotatesAroundUpVector_; } - /*! Sets the value of rotatesAroundUpVector(). - - Default value is false (free rotation). */ - void setRotatesAroundUpVector(bool constrained) { rotatesAroundUpVector_ = constrained; } - - /*! Returns whether or not the QGLViewer::ZOOM action zooms on the pivot point. - - When set to \c false (default), a zoom action will move the camera along its Camera::viewDirection(), - i.e. back and forth along a direction perpendicular to the projection screen. - - setZoomsOnPivotPoint() to \c true will move the camera along an axis defined by the - Camera::pivotPoint() and its current position instead. As a result, the projected position of the - pivot point on screen will stay the same during a zoom. */ - bool zoomsOnPivotPoint() const { return zoomsOnPivotPoint_; } - /*! Sets the value of zoomsOnPivotPoint(). - - Default value is false. */ - void setZoomsOnPivotPoint(bool enabled) { zoomsOnPivotPoint_ = enabled; } + /*! Returns \c true when the frame's rotation is constrained around the + sceneUpVector(), and \c false otherwise, when the rotation is completely + free (default). + + In free mode, the associated camera can be arbitrarily rotated in the + scene, along its three axis, thus possibly leading to any arbitrary + orientation. + + When you setRotatesAroundUpVector() to \c true, the sceneUpVector() + defines a 'vertical' direction around which the camera rotates. The camera + can rotate left or right, around this axis. It can also be moved up or down + to show the 'top' and 'bottom' views of the scene. As a result, the + sceneUpVector() will always appear vertical in the scene, and the horizon + is preserved and stays projected along the camera's horizontal axis. + + Note that setting this value to \c true when the sceneUpVector() is + not already vertically projected will break these invariants. It will also + limit the possible movement of the camera, possibly up to a lock when the + sceneUpVector() is projected horizontally. Use Camera::setUpVector() to + define the sceneUpVector() and align the camera before calling this method + to ensure this does not happen. */ + bool rotatesAroundUpVector() const { return rotatesAroundUpVector_; } + /*! Sets the value of rotatesAroundUpVector(). + + Default value is false (free rotation). */ + void setRotatesAroundUpVector(bool constrained) { + rotatesAroundUpVector_ = constrained; + } + + /*! Returns whether or not the QGLViewer::ZOOM action zooms on the pivot + point. + + When set to \c false (default), a zoom action will move the camera along its + Camera::viewDirection(), i.e. back and forth along a direction perpendicular + to the projection screen. + + setZoomsOnPivotPoint() to \c true will move the camera along an axis defined + by the Camera::pivotPoint() and its current position instead. As a result, + the projected position of the pivot point on screen will stay the same + during a zoom. */ + bool zoomsOnPivotPoint() const { return zoomsOnPivotPoint_; } + /*! Sets the value of zoomsOnPivotPoint(). + + Default value is false. */ + void setZoomsOnPivotPoint(bool enabled) { zoomsOnPivotPoint_ = enabled; } private: #ifndef DOXYGEN - void zoom(qreal delta, const Camera * const camera); + void zoom(qreal delta, const Camera *const camera); #endif - //@} + //@} - /*! @name Fly parameters */ - //@{ + /*! @name Fly parameters */ + //@{ public Q_SLOTS: - /*! Sets the flySpeed(), defined in OpenGL units. + /*! Sets the flySpeed(), defined in OpenGL units. - Default value is 0.0, but it is modified according to the QGLViewer::sceneRadius() when the - ManipulatedCameraFrame is set as the Camera::frame(). */ - void setFlySpeed(qreal speed) { flySpeed_ = speed; } + Default value is 0.0, but it is modified according to the + QGLViewer::sceneRadius() when the ManipulatedCameraFrame is set as the + Camera::frame(). */ + void setFlySpeed(qreal speed) { flySpeed_ = speed; } - /*! Sets the sceneUpVector(), defined in the world coordinate system. + /*! Sets the sceneUpVector(), defined in the world coordinate system. - Default value is (0,1,0), but it is updated by the Camera when this object is set as its Camera::frame(). - Using Camera::setUpVector() instead is probably a better solution. */ - void setSceneUpVector(const Vec& up) { sceneUpVector_ = up; } + Default value is (0,1,0), but it is updated by the Camera when this object is + set as its Camera::frame(). Using Camera::setUpVector() instead is probably a + better solution. */ + void setSceneUpVector(const Vec &up) { sceneUpVector_ = up; } public: - /*! Returns the fly speed, expressed in OpenGL units. + /*! Returns the fly speed, expressed in OpenGL units. - It corresponds to the incremental displacement that is periodically applied to the - ManipulatedCameraFrame position when a QGLViewer::MOVE_FORWARD or QGLViewer::MOVE_BACKWARD - QGLViewer::MouseAction is proceeded. + It corresponds to the incremental displacement that is periodically applied to + the ManipulatedCameraFrame position when a QGLViewer::MOVE_FORWARD or + QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction is proceeded. - \attention When the ManipulatedCameraFrame is set as the Camera::frame(), this value is set - according to the QGLViewer::sceneRadius() by QGLViewer::setSceneRadius(). */ - qreal flySpeed() const { return flySpeed_; } + \attention When the ManipulatedCameraFrame is set as the Camera::frame(), this + value is set according to the QGLViewer::sceneRadius() by + QGLViewer::setSceneRadius(). */ + qreal flySpeed() const { return flySpeed_; } - /*! Returns the up vector of the scene, expressed in the world coordinate system. + /*! Returns the up vector of the scene, expressed in the world coordinate + system. - In 'fly mode' (corresponding to the QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD - QGLViewer::MouseAction bindings), horizontal displacements of the mouse rotate - the ManipulatedCameraFrame around this vector. Vertical displacements rotate always around the - Camera \c X axis. + In 'fly mode' (corresponding to the QGLViewer::MOVE_FORWARD and + QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction bindings), horizontal + displacements of the mouse rotate the ManipulatedCameraFrame around this + vector. Vertical displacements rotate always around the Camera \c X axis. - This value is also used when setRotationIsConstrained() is set to \c true to define the up vector - (and incidentally the 'horizon' plane) around which the camera will rotate. + This value is also used when setRotationIsConstrained() is set to \c true to + define the up vector (and incidentally the 'horizon' plane) around which the + camera will rotate. - Default value is (0,1,0), but it is updated by the Camera when this object is set as its Camera::frame(). - Camera::setOrientation() and Camera::setUpVector()) direclty modify this value and should be used - instead. */ - Vec sceneUpVector() const { return sceneUpVector_; } + Default value is (0,1,0), but it is updated by the Camera when this object is + set as its Camera::frame(). Camera::setOrientation() and + Camera::setUpVector()) direclty modify this value and should be used instead. +*/ + Vec sceneUpVector() const { return sceneUpVector_; } #ifndef DOXYGEN - Vec flyUpVector() const; - void setFlyUpVector(const Vec& up); + Vec flyUpVector() const; + void setFlyUpVector(const Vec &up); #endif - //@} + //@} - /*! @name Mouse event handlers */ - //@{ + /*! @name Mouse event handlers */ + //@{ protected: - virtual void mouseReleaseEvent(QMouseEvent* const event, Camera* const camera); - virtual void mouseMoveEvent (QMouseEvent* const event, Camera* const camera); - virtual void wheelEvent (QWheelEvent* const event, Camera* const camera); - //@} - - /*! @name Spinning */ - //@{ + virtual void mouseReleaseEvent(QMouseEvent *const event, + Camera *const camera); + virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera); + virtual void wheelEvent(QWheelEvent *const event, Camera *const camera); + //@} + + /*! @name Spinning */ + //@{ protected Q_SLOTS: - virtual void spin(); - //@} + virtual void spin(); + //@} - /*! @name XML representation */ - //@{ + /*! @name XML representation */ + //@{ public: - virtual QDomElement domElement(const QString& name, QDomDocument& document) const; + virtual QDomElement domElement(const QString &name, + QDomDocument &document) const; public Q_SLOTS: - virtual void initFromDOMElement(const QDomElement& element); - //@} + virtual void initFromDOMElement(const QDomElement &element); +//@} #ifndef DOXYGEN protected: - virtual void startAction(int ma, bool withConstraint=true); // int is really a QGLViewer::MouseAction + virtual void startAction( + int ma, + bool withConstraint = true); // int is really a QGLViewer::MouseAction #endif private Q_SLOTS: - virtual void flyUpdate(); + virtual void flyUpdate(); private: - void updateSceneUpVector(); - Quaternion turnQuaternion(int x, const Camera* const camera); - Quaternion pitchYawQuaternion(int x, int y, const Camera* const camera); + void updateSceneUpVector(); + Quaternion turnQuaternion(int x, const Camera *const camera); + Quaternion pitchYawQuaternion(int x, int y, const Camera *const camera); private: - // Fly mode data - qreal flySpeed_; - qreal driveSpeed_; - Vec sceneUpVector_; - QTimer flyTimer_; + // Fly mode data + qreal flySpeed_; + qreal driveSpeed_; + Vec sceneUpVector_; + QTimer flyTimer_; - bool rotatesAroundUpVector_; - // Inverse the direction of an horizontal mouse motion. Depends on the projected - // screen orientation of the vertical axis when the mouse button is pressed. - bool constrainedRotationIsReversed_; + bool rotatesAroundUpVector_; + // Inverse the direction of an horizontal mouse motion. Depends on the + // projected screen orientation of the vertical axis when the mouse button is + // pressed. + bool constrainedRotationIsReversed_; - bool zoomsOnPivotPoint_; + bool zoomsOnPivotPoint_; - Vec pivotPoint_; + Vec pivotPoint_; }; } // namespace qglviewer diff --git a/octovis/src/extern/QGLViewer/manipulatedFrame.cpp b/octovis/src/extern/QGLViewer/manipulatedFrame.cpp index b6b2d72b..306565c9 100644 --- a/octovis/src/extern/QGLViewer/manipulatedFrame.cpp +++ b/octovis/src/extern/QGLViewer/manipulatedFrame.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,12 +19,11 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - -#include "domUtils.h" #include "manipulatedFrame.h" +#include "camera.h" +#include "domUtils.h" #include "manipulatedCameraFrame.h" #include "qglviewer.h" -#include "camera.h" #include @@ -35,66 +34,67 @@ using namespace std; /*! Default constructor. - The translation is set to (0,0,0), with an identity rotation (0,0,0,1) (see Frame constructor - for details). + The translation is set to (0,0,0), with an identity rotation (0,0,0,1) (see + Frame constructor for details). - The different sensitivities are set to their default values (see rotationSensitivity(), - translationSensitivity(), spinningSensitivity() and wheelSensitivity()). */ + The different sensitivities are set to their default values (see + rotationSensitivity(), translationSensitivity(), spinningSensitivity() and + wheelSensitivity()). */ ManipulatedFrame::ManipulatedFrame() - : action_(QGLViewer::NO_MOUSE_ACTION), keepsGrabbingMouse_(false) -{ - // #CONNECTION# initFromDOMElement and accessor docs - setRotationSensitivity(1.0); - setTranslationSensitivity(1.0); - setSpinningSensitivity(0.3); - setWheelSensitivity(1.0); - setZoomSensitivity(1.0); - - isSpinning_ = false; - previousConstraint_ = NULL; - - connect(&spinningTimer_, SIGNAL(timeout()), SLOT(spinUpdate())); + : action_(QGLViewer::NO_MOUSE_ACTION), keepsGrabbingMouse_(false) { + // #CONNECTION# initFromDOMElement and accessor docs + setRotationSensitivity(1.0); + setTranslationSensitivity(1.0); + setSpinningSensitivity(0.3); + setWheelSensitivity(1.0); + setZoomSensitivity(1.0); + + isSpinning_ = false; + previousConstraint_ = nullptr; + + connect(&spinningTimer_, SIGNAL(timeout()), SLOT(spinUpdate())); } /*! Equal operator. Calls Frame::operator=() and then copy attributes. */ -ManipulatedFrame& ManipulatedFrame::operator=(const ManipulatedFrame& mf) -{ - Frame::operator=(mf); - - setRotationSensitivity(mf.rotationSensitivity()); - setTranslationSensitivity(mf.translationSensitivity()); - setSpinningSensitivity(mf.spinningSensitivity()); - setWheelSensitivity(mf.wheelSensitivity()); - setZoomSensitivity(mf.zoomSensitivity()); - - mouseSpeed_ = 0.0; - dirIsFixed_ = false; - keepsGrabbingMouse_ = false; - action_ = QGLViewer::NO_MOUSE_ACTION; - - return *this; +ManipulatedFrame &ManipulatedFrame::operator=(const ManipulatedFrame &mf) { + Frame::operator=(mf); + + setRotationSensitivity(mf.rotationSensitivity()); + setTranslationSensitivity(mf.translationSensitivity()); + setSpinningSensitivity(mf.spinningSensitivity()); + setWheelSensitivity(mf.wheelSensitivity()); + setZoomSensitivity(mf.zoomSensitivity()); + + mouseSpeed_ = 0.0; + dirIsFixed_ = false; + keepsGrabbingMouse_ = false; + action_ = QGLViewer::NO_MOUSE_ACTION; + + return *this; } -/*! Copy constructor. Performs a deep copy of all attributes using operator=(). */ -ManipulatedFrame::ManipulatedFrame(const ManipulatedFrame& mf) - : Frame(mf), MouseGrabber() -{ - (*this)=mf; +/*! Copy constructor. Performs a deep copy of all attributes using operator=(). + */ +ManipulatedFrame::ManipulatedFrame(const ManipulatedFrame &mf) + : Frame(mf), MouseGrabber() { + (*this) = mf; } //////////////////////////////////////////////////////////////////////////////// /*! Implementation of the MouseGrabber main method. -The ManipulatedFrame grabsMouse() when the mouse is within a 10 pixels region around its -Camera::projectedCoordinatesOf() position(). - -See the mouseGrabber example for an illustration. */ -void ManipulatedFrame::checkIfGrabsMouse(int x, int y, const Camera* const camera) -{ - const int thresold = 10; - const Vec proj = camera->projectedCoordinatesOf(position()); - setGrabsMouse(keepsGrabbingMouse_ || ((fabs(x-proj.x) < thresold) && (fabs(y-proj.y) < thresold))); +The ManipulatedFrame grabsMouse() when the mouse is within a 10 pixels region +around its Camera::projectedCoordinatesOf() position(). + +See the mouseGrabber example for an +illustration. */ +void ManipulatedFrame::checkIfGrabsMouse(int x, int y, + const Camera *const camera) { + const int thresold = 10; + const Vec proj = camera->projectedCoordinatesOf(position()); + setGrabsMouse(keepsGrabbingMouse_ || ((fabs(x - proj.x) < thresold) && + (fabs(y - proj.y) < thresold))); } //////////////////////////////////////////////////////////////////////////////// @@ -103,448 +103,484 @@ void ManipulatedFrame::checkIfGrabsMouse(int x, int y, const Camera* const camer /*! Returns an XML \c QDomElement that represents the ManipulatedFrame. - Adds to the Frame::domElement() the ManipulatedFrame specific informations in a \c - ManipulatedParameters child QDomElement. - - \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create - QDomElement. - - Use initFromDOMElement() to restore the ManipulatedFrame state from the resulting \c QDomElement. - - See Vec::domElement() for a complete example. See also Quaternion::domElement(), - Camera::domElement()... */ -QDomElement ManipulatedFrame::domElement(const QString& name, QDomDocument& document) const -{ - QDomElement e = Frame::domElement(name, document); - QDomElement mp = document.createElement("ManipulatedParameters"); - mp.setAttribute("rotSens", QString::number(rotationSensitivity())); - mp.setAttribute("transSens", QString::number(translationSensitivity())); - mp.setAttribute("spinSens", QString::number(spinningSensitivity())); - mp.setAttribute("wheelSens", QString::number(wheelSensitivity())); - mp.setAttribute("zoomSens", QString::number(zoomSensitivity())); - e.appendChild(mp); - return e; + Adds to the Frame::domElement() the ManipulatedFrame specific informations in a + \c ManipulatedParameters child QDomElement. + + \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument + factory used to create QDomElement. + + Use initFromDOMElement() to restore the ManipulatedFrame state from the + resulting \c QDomElement. + + See Vec::domElement() for a complete example. See also + Quaternion::domElement(), Camera::domElement()... */ +QDomElement ManipulatedFrame::domElement(const QString &name, + QDomDocument &document) const { + QDomElement e = Frame::domElement(name, document); + QDomElement mp = document.createElement("ManipulatedParameters"); + mp.setAttribute("rotSens", QString::number(rotationSensitivity())); + mp.setAttribute("transSens", QString::number(translationSensitivity())); + mp.setAttribute("spinSens", QString::number(spinningSensitivity())); + mp.setAttribute("wheelSens", QString::number(wheelSensitivity())); + mp.setAttribute("zoomSens", QString::number(zoomSensitivity())); + e.appendChild(mp); + return e; } -/*! Restores the ManipulatedFrame state from a \c QDomElement created by domElement(). +/*! Restores the ManipulatedFrame state from a \c QDomElement created by +domElement(). Fields that are not described in \p element are set to their default values (see ManipulatedFrame()). -First calls Frame::initFromDOMElement() and then initializes ManipulatedFrame specific parameters. -Note that constraint() and referenceFrame() are not restored and are left unchanged. +First calls Frame::initFromDOMElement() and then initializes ManipulatedFrame +specific parameters. Note that constraint() and referenceFrame() are not +restored and are left unchanged. See Vec::initFromDOMElement() for a complete code example. */ -void ManipulatedFrame::initFromDOMElement(const QDomElement& element) -{ - // Not called since it would set constraint() and referenceFrame() to NULL. - // *this = ManipulatedFrame(); - Frame::initFromDOMElement(element); - - stopSpinning(); - - QDomElement child=element.firstChild().toElement(); - while (!child.isNull()) - { - if (child.tagName() == "ManipulatedParameters") - { - // #CONNECTION# constructor default values and accessor docs - setRotationSensitivity (DomUtils::qrealFromDom(child, "rotSens", 1.0)); - setTranslationSensitivity(DomUtils::qrealFromDom(child, "transSens", 1.0)); - setSpinningSensitivity (DomUtils::qrealFromDom(child, "spinSens", 0.3)); - setWheelSensitivity (DomUtils::qrealFromDom(child, "wheelSens", 1.0)); - setZoomSensitivity (DomUtils::qrealFromDom(child, "zoomSens", 1.0)); - } - child = child.nextSibling().toElement(); - } +void ManipulatedFrame::initFromDOMElement(const QDomElement &element) { + // Not called since it would set constraint() and referenceFrame() to nullptr. + // *this = ManipulatedFrame(); + Frame::initFromDOMElement(element); + + stopSpinning(); + + QDomElement child = element.firstChild().toElement(); + while (!child.isNull()) { + if (child.tagName() == "ManipulatedParameters") { + // #CONNECTION# constructor default values and accessor docs + setRotationSensitivity(DomUtils::qrealFromDom(child, "rotSens", 1.0)); + setTranslationSensitivity( + DomUtils::qrealFromDom(child, "transSens", 1.0)); + setSpinningSensitivity(DomUtils::qrealFromDom(child, "spinSens", 0.3)); + setWheelSensitivity(DomUtils::qrealFromDom(child, "wheelSens", 1.0)); + setZoomSensitivity(DomUtils::qrealFromDom(child, "zoomSens", 1.0)); + } + child = child.nextSibling().toElement(); + } } - //////////////////////////////////////////////////////////////////////////////// // M o u s e h a n d l i n g // //////////////////////////////////////////////////////////////////////////////// -/*! Returns \c true when the ManipulatedFrame is being manipulated with the mouse. +/*! Returns \c true when the ManipulatedFrame is being manipulated with the + mouse. - Can be used to change the display of the manipulated object during manipulation. + Can be used to change the display of the manipulated object during + manipulation. - When Camera::frame() of the QGLViewer::camera() isManipulated(), QGLViewer::fastDraw() is used in - place of QGLViewer::draw() for scene rendering. A simplified drawing will then allow for - interactive camera displacements. */ -bool ManipulatedFrame::isManipulated() const -{ - return action_ != QGLViewer::NO_MOUSE_ACTION; + When Camera::frame() of the QGLViewer::camera() isManipulated(), + QGLViewer::fastDraw() is used in place of QGLViewer::draw() for scene + rendering. A simplified drawing will then allow for interactive camera + displacements. */ +bool ManipulatedFrame::isManipulated() const { + return action_ != QGLViewer::NO_MOUSE_ACTION; } /*! Starts the spinning of the ManipulatedFrame. -This method starts a timer that will call spin() every \p updateInterval milliseconds. The -ManipulatedFrame isSpinning() until you call stopSpinning(). */ -void ManipulatedFrame::startSpinning(int updateInterval) -{ - isSpinning_ = true; - spinningTimer_.start(updateInterval); +This method starts a timer that will call spin() every \p updateInterval +milliseconds. The ManipulatedFrame isSpinning() until you call stopSpinning(). +*/ +void ManipulatedFrame::startSpinning(int updateInterval) { + isSpinning_ = true; + spinningTimer_.start(updateInterval); } -/*! Rotates the ManipulatedFrame by its spinningQuaternion(). Called by a timer when the - ManipulatedFrame isSpinning(). */ -void ManipulatedFrame::spin() -{ - rotate(spinningQuaternion()); -} - -/* spin() and spinUpdate() differ since spin can be used by itself (for instance by - QGLViewer::SCREEN_ROTATE) without a spun emission. Much nicer to use the spinningQuaternion() and - hence spin() for these incremental updates. Nothing special to be done for continuous spinning - with this design. */ -void ManipulatedFrame::spinUpdate() -{ - spin(); - Q_EMIT spun(); +/*! Rotates the ManipulatedFrame by its spinningQuaternion(). Called by a timer + when the ManipulatedFrame isSpinning(). */ +void ManipulatedFrame::spin() { rotate(spinningQuaternion()); } + +/* spin() and spinUpdate() differ since spin can be used by itself (for instance + by QGLViewer::SCREEN_ROTATE) without a spun emission. Much nicer to use the + spinningQuaternion() and hence spin() for these incremental updates. Nothing + special to be done for continuous spinning with this design. */ +void ManipulatedFrame::spinUpdate() { + spin(); + Q_EMIT spun(); } #ifndef DOXYGEN /*! Protected internal method used to handle mouse events. */ -void ManipulatedFrame::startAction(int ma, bool withConstraint) -{ - action_ = (QGLViewer::MouseAction)(ma); - - // #CONNECTION# manipulatedFrame::wheelEvent, manipulatedCameraFrame::wheelEvent and mouseReleaseEvent() - // restore previous constraint - if (withConstraint) - previousConstraint_ = NULL; - else - { - previousConstraint_ = constraint(); - setConstraint(NULL); - } - - switch (action_) - { - case QGLViewer::ROTATE: - case QGLViewer::SCREEN_ROTATE: - mouseSpeed_ = 0.0; - stopSpinning(); - break; - - case QGLViewer::SCREEN_TRANSLATE: - dirIsFixed_ = false; - break; - - default: - break; - } +void ManipulatedFrame::startAction(int ma, bool withConstraint) { + action_ = static_cast(ma); + + // #CONNECTION# manipulatedFrame::wheelEvent, + // manipulatedCameraFrame::wheelEvent and mouseReleaseEvent() restore previous + // constraint + if (withConstraint) + previousConstraint_ = nullptr; + else { + previousConstraint_ = constraint(); + setConstraint(nullptr); + } + + switch (action_) { + case QGLViewer::ROTATE: + case QGLViewer::SCREEN_ROTATE: + mouseSpeed_ = 0.0; + stopSpinning(); + break; + + case QGLViewer::SCREEN_TRANSLATE: + dirIsFixed_ = false; + break; + + default: + break; + } } -/*! Updates mouse speed, measured in pixels/milliseconds. Should be called by any method which wants to -use mouse speed. Currently used to trigger spinning in mouseReleaseEvent(). */ -void ManipulatedFrame::computeMouseSpeed(const QMouseEvent* const e) -{ - const QPoint delta = (e->pos() - prevPos_); - const qreal dist = sqrt(qreal(delta.x()*delta.x() + delta.y()*delta.y())); - delay_ = last_move_time.restart(); - if (delay_ == 0) - // Less than a millisecond: assume delay = 1ms - mouseSpeed_ = dist; - else - mouseSpeed_ = dist/delay_; +/*! Updates mouse speed, measured in pixels/milliseconds. Should be called by +any method which wants to use mouse speed. Currently used to trigger spinning in +mouseReleaseEvent(). */ +void ManipulatedFrame::computeMouseSpeed(const QMouseEvent *const e) { + const QPoint delta = (e->pos() - prevPos_); + const qreal dist = sqrt(qreal(delta.x() * delta.x() + delta.y() * delta.y())); + delay_ = last_move_time.restart(); + if (delay_ == 0) + // Less than a millisecond: assume delay = 1ms + mouseSpeed_ = dist; + else + mouseSpeed_ = dist / delay_; } -/*! Return 1 if mouse motion was started horizontally and -1 if it was more vertical. Returns 0 if -this could not be determined yet (perfect diagonal motion, rare). */ -int ManipulatedFrame::mouseOriginalDirection(const QMouseEvent* const e) -{ - static bool horiz = true; // Two simultaneous manipulatedFrame require two mice ! - - if (!dirIsFixed_) - { - const QPoint delta = e->pos() - pressPos_; - dirIsFixed_ = abs(delta.x()) != abs(delta.y()); - horiz = abs(delta.x()) > abs(delta.y()); - } - - if (dirIsFixed_) - if (horiz) - return 1; - else - return -1; - else - return 0; +/*! Return 1 if mouse motion was started horizontally and -1 if it was more +vertical. Returns 0 if this could not be determined yet (perfect diagonal +motion, rare). */ +int ManipulatedFrame::mouseOriginalDirection(const QMouseEvent *const e) { + static bool horiz = + true; // Two simultaneous manipulatedFrame require two mice ! + + if (!dirIsFixed_) { + const QPoint delta = e->pos() - pressPos_; + dirIsFixed_ = abs(delta.x()) != abs(delta.y()); + horiz = abs(delta.x()) > abs(delta.y()); + } + + if (dirIsFixed_) + if (horiz) + return 1; + else + return -1; + else + return 0; } -qreal ManipulatedFrame::deltaWithPrevPos(QMouseEvent* const event, Camera* const camera) const { - qreal dx = qreal(event->x() - prevPos_.x()) / camera->screenWidth(); - qreal dy = qreal(event->y() - prevPos_.y()) / camera->screenHeight(); - - qreal value = fabs(dx) > fabs(dy) ? dx : dy; - return value * zoomSensitivity(); +qreal ManipulatedFrame::deltaWithPrevPos(QMouseEvent *const event, + Camera *const camera) const { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + qreal dx = qreal(event->x() - prevPos_.x()) / camera->screenWidth(); + qreal dy = qreal(event->y() - prevPos_.y()) / camera->screenHeight(); +#else + qreal dx = qreal(event->position().x() - prevPos_.x()) / camera->screenWidth(); + qreal dy = qreal(event->position().y() - prevPos_.y()) / camera->screenHeight(); +#endif + + qreal value = fabs(dx) > fabs(dy) ? dx : dy; + return value * zoomSensitivity(); } -qreal ManipulatedFrame::wheelDelta(const QWheelEvent* event) const { - static const qreal WHEEL_SENSITIVITY_COEF = 8E-4; - return event->delta() * wheelSensitivity() * WHEEL_SENSITIVITY_COEF; +qreal ManipulatedFrame::wheelDelta(const QWheelEvent *event) const { + static const qreal WHEEL_SENSITIVITY_COEF = 8E-4; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + return event->delta() * wheelSensitivity() * WHEEL_SENSITIVITY_COEF; +#else + return event->angleDelta().y() * wheelSensitivity() * WHEEL_SENSITIVITY_COEF; +#endif } -void ManipulatedFrame::zoom(qreal delta, const Camera * const camera) { - Vec trans(0.0, 0.0, (camera->position() - position()).norm() * delta); +void ManipulatedFrame::zoom(qreal delta, const Camera *const camera) { + Vec trans(0.0, 0.0, (camera->position() - position()).norm() * delta); - trans = camera->frame()->orientation().rotate(trans); - if (referenceFrame()) - trans = referenceFrame()->transformOf(trans); - translate(trans); + trans = camera->frame()->orientation().rotate(trans); + if (referenceFrame()) + trans = referenceFrame()->transformOf(trans); + translate(trans); } #endif // DOXYGEN /*! Initiates the ManipulatedFrame mouse manipulation. -Overloading of MouseGrabber::mousePressEvent(). See also mouseMoveEvent() and mouseReleaseEvent(). +Overloading of MouseGrabber::mousePressEvent(). See also mouseMoveEvent() and +mouseReleaseEvent(). -The mouse behavior depends on which button is pressed. See the QGLViewer -mouse page for details. */ -void ManipulatedFrame::mousePressEvent(QMouseEvent* const event, Camera* const camera) -{ - Q_UNUSED(camera); +The mouse behavior depends on which button is pressed. See the QGLViewer mouse page for details. */ +void ManipulatedFrame::mousePressEvent(QMouseEvent *const event, + Camera *const camera) { + Q_UNUSED(camera) - if (grabsMouse()) - keepsGrabbingMouse_ = true; + if (grabsMouse()) + keepsGrabbingMouse_ = true; - // #CONNECTION setMouseBinding - // action_ should no longer possibly be NO_MOUSE_ACTION since this value is not inserted in mouseBinding_ - //if (action_ == QGLViewer::NO_MOUSE_ACTION) - //event->ignore(); + // #CONNECTION setMouseBinding + // action_ should no longer possibly be NO_MOUSE_ACTION since this value is + // not inserted in mouseBinding_ + // if (action_ == QGLViewer::NO_MOUSE_ACTION) + // event->ignore(); - prevPos_ = pressPos_ = event->pos(); + prevPos_ = pressPos_ = event->pos(); } /*! Modifies the ManipulatedFrame according to the mouse motion. -Actual behavior depends on mouse bindings. See the QGLViewer::MouseAction enum and the QGLViewer mouse page for details. +Actual behavior depends on mouse bindings. See the QGLViewer::MouseAction enum +and the QGLViewer mouse page for details. The \p camera is used to fit the mouse motion with the display parameters (see Camera::screenWidth(), Camera::screenHeight(), Camera::fieldOfView()). Emits the manipulated() signal. */ -void ManipulatedFrame::mouseMoveEvent(QMouseEvent* const event, Camera* const camera) -{ - switch (action_) - { - case QGLViewer::TRANSLATE: - { - const QPoint delta = event->pos() - prevPos_; - Vec trans(delta.x(), -delta.y(), 0.0); - // Scale to fit the screen mouse displacement - switch (camera->type()) - { - case Camera::PERSPECTIVE : - trans *= 2.0 * tan(camera->fieldOfView()/2.0) * fabs((camera->frame()->coordinatesOf(position())).z) / camera->screenHeight(); - break; - case Camera::ORTHOGRAPHIC : - { - GLdouble w,h; - camera->getOrthoWidthHeight(w, h); - trans[0] *= 2.0 * w / camera->screenWidth(); - trans[1] *= 2.0 * h / camera->screenHeight(); - break; - } - } - // Transform to world coordinate system. - trans = camera->frame()->orientation().rotate(translationSensitivity()*trans); - // And then down to frame - if (referenceFrame()) trans = referenceFrame()->transformOf(trans); - translate(trans); - break; - } - - case QGLViewer::ZOOM: - { - zoom(deltaWithPrevPos(event, camera), camera); - break; - } - - case QGLViewer::SCREEN_ROTATE: - { - Vec trans = camera->projectedCoordinatesOf(position()); - - const qreal prev_angle = atan2(prevPos_.y()-trans[1], prevPos_.x()-trans[0]); - const qreal angle = atan2(event->y()-trans[1], event->x()-trans[0]); - - const Vec axis = transformOf(camera->frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0))); - Quaternion rot(axis, angle-prev_angle); - //#CONNECTION# These two methods should go together (spinning detection and activation) - computeMouseSpeed(event); - setSpinningQuaternion(rot); - spin(); - break; - } - - case QGLViewer::SCREEN_TRANSLATE: - { - Vec trans; - int dir = mouseOriginalDirection(event); - if (dir == 1) - trans.setValue(event->x() - prevPos_.x(), 0.0, 0.0); - else if (dir == -1) - trans.setValue(0.0, prevPos_.y() - event->y(), 0.0); - - switch (camera->type()) - { - case Camera::PERSPECTIVE : - trans *= 2.0 * tan(camera->fieldOfView()/2.0) * fabs((camera->frame()->coordinatesOf(position())).z) / camera->screenHeight(); - break; - case Camera::ORTHOGRAPHIC : - { - GLdouble w,h; - camera->getOrthoWidthHeight(w, h); - trans[0] *= 2.0 * w / camera->screenWidth(); - trans[1] *= 2.0 * h / camera->screenHeight(); - break; - } - } - // Transform to world coordinate system. - trans = camera->frame()->orientation().rotate(translationSensitivity()*trans); - // And then down to frame - if (referenceFrame()) - trans = referenceFrame()->transformOf(trans); - - translate(trans); - break; - } - - case QGLViewer::ROTATE: - { - Vec trans = camera->projectedCoordinatesOf(position()); - Quaternion rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1], camera); - trans = Vec(-rot[0], -rot[1], -rot[2]); - trans = camera->frame()->orientation().rotate(trans); - trans = transformOf(trans); - rot[0] = trans[0]; - rot[1] = trans[1]; - rot[2] = trans[2]; - //#CONNECTION# These two methods should go together (spinning detection and activation) - computeMouseSpeed(event); - setSpinningQuaternion(rot); - spin(); - break; - } - - case QGLViewer::MOVE_FORWARD: - case QGLViewer::MOVE_BACKWARD: - case QGLViewer::LOOK_AROUND: - case QGLViewer::ROLL: - case QGLViewer::DRIVE: - case QGLViewer::ZOOM_ON_REGION: - // These MouseAction values make no sense for a manipulatedFrame - break; - - case QGLViewer::NO_MOUSE_ACTION: - // Possible when the ManipulatedFrame is a MouseGrabber. This method is then called without startAction - // because of mouseTracking. - break; - } - - if (action_ != QGLViewer::NO_MOUSE_ACTION) - { - prevPos_ = event->pos(); - Q_EMIT manipulated(); - } +void ManipulatedFrame::mouseMoveEvent(QMouseEvent *const event, + Camera *const camera) { + switch (action_) { + case QGLViewer::TRANSLATE: { + const QPoint delta = event->pos() - prevPos_; + Vec trans(delta.x(), -delta.y(), 0.0); + // Scale to fit the screen mouse displacement + switch (camera->type()) { + case Camera::PERSPECTIVE: + trans *= 2.0 * tan(camera->fieldOfView() / 2.0) * + fabs((camera->frame()->coordinatesOf(position())).z) / + camera->screenHeight(); + break; + case Camera::ORTHOGRAPHIC: { + GLdouble w, h; + camera->getOrthoWidthHeight(w, h); + trans[0] *= 2.0 * w / camera->screenWidth(); + trans[1] *= 2.0 * h / camera->screenHeight(); + break; + } + } + // Transform to world coordinate system. + trans = + camera->frame()->orientation().rotate(translationSensitivity() * trans); + // And then down to frame + if (referenceFrame()) + trans = referenceFrame()->transformOf(trans); + translate(trans); + break; + } + + case QGLViewer::ZOOM: { + zoom(deltaWithPrevPos(event, camera), camera); + break; + } + + case QGLViewer::SCREEN_ROTATE: { + Vec trans = camera->projectedCoordinatesOf(position()); + + const qreal prev_angle = + atan2(prevPos_.y() - trans[1], prevPos_.x() - trans[0]); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + const qreal angle = atan2(event->y() - trans[1], event->x() - trans[0]); +#else + const qreal angle = atan2(event->position().y() - trans[1], event->position().x() - trans[0]); +#endif + + const Vec axis = + transformOf(camera->frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0))); + Quaternion rot(axis, angle - prev_angle); + //#CONNECTION# These two methods should go together (spinning detection and + // activation) + computeMouseSpeed(event); + setSpinningQuaternion(rot); + spin(); + break; + } + + case QGLViewer::SCREEN_TRANSLATE: { + Vec trans; + int dir = mouseOriginalDirection(event); + if (dir == 1) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + trans.setValue(event->x() - prevPos_.x(), 0.0, 0.0); +#else + trans.setValue(event->position().x() - prevPos_.x(), 0.0, 0.0); +#endif + else if (dir == -1) +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + trans.setValue(0.0, prevPos_.y() - event->y(), 0.0); +#else + trans.setValue(0.0, prevPos_.y() - event->position().y(), 0.0); +#endif + + switch (camera->type()) { + case Camera::PERSPECTIVE: + trans *= 2.0 * tan(camera->fieldOfView() / 2.0) * + fabs((camera->frame()->coordinatesOf(position())).z) / + camera->screenHeight(); + break; + case Camera::ORTHOGRAPHIC: { + GLdouble w, h; + camera->getOrthoWidthHeight(w, h); + trans[0] *= 2.0 * w / camera->screenWidth(); + trans[1] *= 2.0 * h / camera->screenHeight(); + break; + } + } + // Transform to world coordinate system. + trans = + camera->frame()->orientation().rotate(translationSensitivity() * trans); + // And then down to frame + if (referenceFrame()) + trans = referenceFrame()->transformOf(trans); + + translate(trans); + break; + } + + case QGLViewer::ROTATE: { + Vec trans = camera->projectedCoordinatesOf(position()); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + Quaternion rot = deformedBallQuaternion(event->x(), event->y(), trans[0], + trans[1], camera); +#else + Quaternion rot = deformedBallQuaternion(event->position().x(), event->position().y(), + trans[0], trans[1], camera); +#endif + trans = Vec(-rot[0], -rot[1], -rot[2]); + trans = camera->frame()->orientation().rotate(trans); + trans = transformOf(trans); + rot[0] = trans[0]; + rot[1] = trans[1]; + rot[2] = trans[2]; + //#CONNECTION# These two methods should go together (spinning detection and + // activation) + computeMouseSpeed(event); + setSpinningQuaternion(rot); + spin(); + break; + } + + case QGLViewer::MOVE_FORWARD: + case QGLViewer::MOVE_BACKWARD: + case QGLViewer::LOOK_AROUND: + case QGLViewer::ROLL: + case QGLViewer::DRIVE: + case QGLViewer::ZOOM_ON_REGION: + // These MouseAction values make no sense for a manipulatedFrame + break; + + case QGLViewer::NO_MOUSE_ACTION: + // Possible when the ManipulatedFrame is a MouseGrabber. This method is then + // called without startAction because of mouseTracking. + break; + } + + if (action_ != QGLViewer::NO_MOUSE_ACTION) { + prevPos_ = event->pos(); + Q_EMIT manipulated(); + } } /*! Stops the ManipulatedFrame mouse manipulation. Overloading of MouseGrabber::mouseReleaseEvent(). -If the action was a QGLViewer::ROTATE QGLViewer::MouseAction, a continuous spinning is possible if -the speed of the mouse cursor is larger than spinningSensitivity() when the button is released. -Press the rotate button again to stop spinning. See startSpinning() and isSpinning(). */ -void ManipulatedFrame::mouseReleaseEvent(QMouseEvent* const event, Camera* const camera) -{ - Q_UNUSED(event); - Q_UNUSED(camera); +If the action was a QGLViewer::ROTATE QGLViewer::MouseAction, a continuous +spinning is possible if the speed of the mouse cursor is larger than +spinningSensitivity() when the button is released. Press the rotate button again +to stop spinning. See startSpinning() and isSpinning(). */ +void ManipulatedFrame::mouseReleaseEvent(QMouseEvent *const event, + Camera *const camera) { + Q_UNUSED(event) + Q_UNUSED(camera) - keepsGrabbingMouse_ = false; + keepsGrabbingMouse_ = false; - if (previousConstraint_) - setConstraint(previousConstraint_); + if (previousConstraint_) + setConstraint(previousConstraint_); - if (((action_ == QGLViewer::ROTATE) || (action_ == QGLViewer::SCREEN_ROTATE)) && (mouseSpeed_ >= spinningSensitivity())) - startSpinning(delay_); + if (((action_ == QGLViewer::ROTATE) || + (action_ == QGLViewer::SCREEN_ROTATE)) && + (mouseSpeed_ >= spinningSensitivity())) + startSpinning(delay_); - action_ = QGLViewer::NO_MOUSE_ACTION; + action_ = QGLViewer::NO_MOUSE_ACTION; } /*! Overloading of MouseGrabber::mouseDoubleClickEvent(). -Left button double click aligns the ManipulatedFrame with the \p camera axis (see alignWithFrame() - and QGLViewer::ALIGN_FRAME). Right button projects the ManipulatedFrame on the \p camera view - direction. */ -void ManipulatedFrame::mouseDoubleClickEvent(QMouseEvent* const event, Camera* const camera) -{ - if (event->modifiers() == Qt::NoModifier) - switch (event->button()) - { - case Qt::LeftButton: alignWithFrame(camera->frame()); break; - case Qt::RightButton: projectOnLine(camera->position(), camera->viewDirection()); break; - default: break; - } +Left button double click aligns the ManipulatedFrame with the \p camera axis +(see alignWithFrame() and QGLViewer::ALIGN_FRAME). Right button projects the +ManipulatedFrame on the \p camera view direction. */ +void ManipulatedFrame::mouseDoubleClickEvent(QMouseEvent *const event, + Camera *const camera) { + if (event->modifiers() == Qt::NoModifier) + switch (event->button()) { + case Qt::LeftButton: + alignWithFrame(camera->frame()); + break; + case Qt::RightButton: + projectOnLine(camera->position(), camera->viewDirection()); + break; + default: + break; + } } /*! Overloading of MouseGrabber::wheelEvent(). Using the wheel is equivalent to a QGLViewer::ZOOM QGLViewer::MouseAction. See QGLViewer::setWheelBinding(), setWheelSensitivity(). */ -void ManipulatedFrame::wheelEvent(QWheelEvent* const event, Camera* const camera) -{ - //#CONNECTION# QGLViewer::setWheelBinding - if (action_ == QGLViewer::ZOOM) - { - zoom(wheelDelta(event), camera); - Q_EMIT manipulated(); - } - - // #CONNECTION# startAction should always be called before - if (previousConstraint_) - setConstraint(previousConstraint_); - - action_ = QGLViewer::NO_MOUSE_ACTION; +void ManipulatedFrame::wheelEvent(QWheelEvent *const event, + Camera *const camera) { + //#CONNECTION# QGLViewer::setWheelBinding + if (action_ == QGLViewer::ZOOM) { + zoom(wheelDelta(event), camera); + Q_EMIT manipulated(); + } + + // #CONNECTION# startAction should always be called before + if (previousConstraint_) + setConstraint(previousConstraint_); + + action_ = QGLViewer::NO_MOUSE_ACTION; } - //////////////////////////////////////////////////////////////////////////////// /*! Returns "pseudo-distance" from (x,y) to ball of radius size. -\arg for a point inside the ball, it is proportional to the euclidean distance to the ball -\arg for a point outside the ball, it is proportional to the inverse of this distance (tends to -zero) on the ball, the function is continuous. */ -static qreal projectOnBall(qreal x, qreal y) -{ - // If you change the size value, change angle computation in deformedBallQuaternion(). - const qreal size = 1.0; - const qreal size2 = size*size; - const qreal size_limit = size2*0.5; - - const qreal d = x*x + y*y; - return d < size_limit ? sqrt(size2 - d) : size_limit/sqrt(d); +\arg for a point inside the ball, it is proportional to the euclidean distance +to the ball \arg for a point outside the ball, it is proportional to the inverse +of this distance (tends to zero) on the ball, the function is continuous. */ +static qreal projectOnBall(qreal x, qreal y) { + // If you change the size value, change angle computation in + // deformedBallQuaternion(). + const qreal size = 1.0; + const qreal size2 = size * size; + const qreal size_limit = size2 * 0.5; + + const qreal d = x * x + y * y; + return d < size_limit ? sqrt(size2 - d) : size_limit / sqrt(d); } #ifndef DOXYGEN -/*! Returns a quaternion computed according to the mouse motion. Mouse positions are projected on a -deformed ball, centered on (\p cx,\p cy). */ -Quaternion ManipulatedFrame::deformedBallQuaternion(int x, int y, qreal cx, qreal cy, const Camera* const camera) -{ - // Points on the deformed ball - qreal px = rotationSensitivity() * (prevPos_.x() - cx) / camera->screenWidth(); - qreal py = rotationSensitivity() * (cy - prevPos_.y()) / camera->screenHeight(); - qreal dx = rotationSensitivity() * (x - cx) / camera->screenWidth(); - qreal dy = rotationSensitivity() * (cy - y) / camera->screenHeight(); - - const Vec p1(px, py, projectOnBall(px, py)); - const Vec p2(dx, dy, projectOnBall(dx, dy)); - // Approximation of rotation angle - // Should be divided by the projectOnBall size, but it is 1.0 - const Vec axis = cross(p2,p1); - const qreal angle = 5.0 * asin(sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm())); - return Quaternion(axis, angle); +/*! Returns a quaternion computed according to the mouse motion. Mouse positions +are projected on a deformed ball, centered on (\p cx,\p cy). */ +Quaternion +ManipulatedFrame::deformedBallQuaternion(int x, int y, qreal cx, qreal cy, + const Camera *const camera) { + // Points on the deformed ball + qreal px = + rotationSensitivity() * (prevPos_.x() - cx) / camera->screenWidth(); + qreal py = + rotationSensitivity() * (cy - prevPos_.y()) / camera->screenHeight(); + qreal dx = rotationSensitivity() * (x - cx) / camera->screenWidth(); + qreal dy = rotationSensitivity() * (cy - y) / camera->screenHeight(); + + const Vec p1(px, py, projectOnBall(px, py)); + const Vec p2(dx, dy, projectOnBall(dx, dy)); + // Approximation of rotation angle + // Should be divided by the projectOnBall size, but it is 1.0 + const Vec axis = cross(p2, p1); + const qreal angle = + 5.0 * + asin(sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm())); + return Quaternion(axis, angle); } #endif // DOXYGEN diff --git a/octovis/src/extern/QGLViewer/manipulatedFrame.h b/octovis/src/extern/QGLViewer/manipulatedFrame.h index b27fb25a..0d81f4ef 100644 --- a/octovis/src/extern/QGLViewer/manipulatedFrame.h +++ b/octovis/src/extern/QGLViewer/manipulatedFrame.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,7 +19,6 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_MANIPULATED_FRAME_H #define QGLVIEWER_MANIPULATED_FRAME_H @@ -27,307 +26,347 @@ #include "mouseGrabber.h" #include "qglviewer.h" -#include -#include #include +#include +#include namespace qglviewer { -/*! \brief A ManipulatedFrame is a Frame that can be rotated and translated using the mouse. - \class ManipulatedFrame manipulatedFrame.h QGLViewer/manipulatedFrame.h +/*! \brief A ManipulatedFrame is a Frame that can be rotated and translated + using the mouse. \class ManipulatedFrame manipulatedFrame.h + QGLViewer/manipulatedFrame.h - It converts the mouse motion into a translation and an orientation updates. A ManipulatedFrame is - used to move an object in the scene. Combined with object selection, its MouseGrabber properties - and a dynamic update of the scene, the ManipulatedFrame introduces a great reactivity in your - applications. + It converts the mouse motion into a translation and an orientation updates. A + ManipulatedFrame is used to move an object in the scene. Combined with object + selection, its MouseGrabber properties and a dynamic update of the scene, the + ManipulatedFrame introduces a great reactivity in your applications. - A ManipulatedFrame is attached to a QGLViewer using QGLViewer::setManipulatedFrame(): - \code - init() { setManipulatedFrame( new ManipulatedFrame() ); } + A ManipulatedFrame is attached to a QGLViewer using + QGLViewer::setManipulatedFrame(): \code init() { setManipulatedFrame( new + ManipulatedFrame() ); } draw() { - glPushMatrix(); - glMultMatrixd(manipulatedFrame()->matrix()); - // draw the manipulated object here - glPopMatrix(); + glPushMatrix(); + glMultMatrixd(manipulatedFrame()->matrix()); + // draw the manipulated object here + glPopMatrix(); } \endcode - See the manipulatedFrame example for a complete - application. + See the manipulatedFrame + example for a complete application. - Mouse events are normally sent to the QGLViewer::camera(). You have to press the QGLViewer::FRAME - state key (default is \c Control) to move the QGLViewer::manipulatedFrame() instead. See the mouse page for a description of mouse button bindings. + Mouse events are normally sent to the QGLViewer::camera(). You have to press + the QGLViewer::FRAME state key (default is \c Control) to move the + QGLViewer::manipulatedFrame() instead. See the mouse + page for a description of mouse button bindings.

Inherited functionalities

- A ManipulatedFrame is an overloaded instance of a Frame. The powerful coordinate system - transformation functions (Frame::coordinatesOf(), Frame::transformOf(), ...) can hence be applied - to a ManipulatedFrame. + A ManipulatedFrame is an overloaded instance of a Frame. The powerful + coordinate system transformation functions (Frame::coordinatesOf(), + Frame::transformOf(), ...) can hence be applied to a ManipulatedFrame. - A ManipulatedFrame is also a MouseGrabber. If the mouse cursor gets within a distance of 10 pixels - from the projected position of the ManipulatedFrame, the ManipulatedFrame becomes the new - QGLViewer::mouseGrabber(). It can then be manipulated directly, without any specific state key, - object selection or GUI intervention. This is very convenient to directly move some objects in the - scene (typically a light). See the mouseGrabber - example as an illustration. Note that QWidget::setMouseTracking() needs to be enabled in order - to use this feature (see the MouseGrabber documentation). + A ManipulatedFrame is also a MouseGrabber. If the mouse cursor gets within a + distance of 10 pixels from the projected position of the ManipulatedFrame, the + ManipulatedFrame becomes the new QGLViewer::mouseGrabber(). It can then be + manipulated directly, without any specific state key, object selection or GUI + intervention. This is very convenient to directly move some objects in the + scene (typically a light). See the mouseGrabber example as an + illustration. Note that QWidget::setMouseTracking() needs to be enabled in + order to use this feature (see the MouseGrabber documentation).

Advanced functionalities

- A QGLViewer can handle at most one ManipulatedFrame at a time. If you want to move several objects - in the scene, you simply have to keep a list of the different ManipulatedFrames, and to activate - the right one (using QGLViewer::setManipulatedFrame()) when needed. This can for instance be done - according to an object selection: see the luxo example for an - illustration. - - When the ManipulatedFrame is being manipulated using the mouse (mouse pressed and not yet - released), isManipulated() returns \c true. This might be used to trigger a specific action or - display (as is done with QGLViewer::fastDraw()). - - The ManipulatedFrame also emits a manipulated() signal each time its state is modified by the - mouse. This signal is automatically connected to the QGLViewer::update() slot when the - ManipulatedFrame is attached to a viewer using QGLViewer::setManipulatedFrame(). - - You can make the ManipulatedFrame spin() if you release the rotation mouse button while moving the - mouse fast enough (see spinningSensitivity()). See also translationSensitivity() and - rotationSensitivity() for sensitivity tuning. \nosubgrouping */ -class QGLVIEWER_EXPORT ManipulatedFrame : public Frame, public MouseGrabber -{ + A QGLViewer can handle at most one ManipulatedFrame at a time. If you want to + move several objects in the scene, you simply have to keep a list of the + different ManipulatedFrames, and to activate the right one (using + QGLViewer::setManipulatedFrame()) when needed. This can for instance be done + according to an object selection: see the luxo + example for an illustration. + + When the ManipulatedFrame is being manipulated using the mouse (mouse pressed + and not yet released), isManipulated() returns \c true. This might be used to + trigger a specific action or display (as is done with QGLViewer::fastDraw()). + + The ManipulatedFrame also emits a manipulated() signal each time its state is + modified by the mouse. This signal is automatically connected to the + QGLViewer::update() slot when the ManipulatedFrame is attached to a viewer + using QGLViewer::setManipulatedFrame(). + + You can make the ManipulatedFrame spin() if you release the rotation mouse + button while moving the mouse fast enough (see spinningSensitivity()). See + also translationSensitivity() and rotationSensitivity() for sensitivity + tuning. \nosubgrouping */ +class QGLVIEWER_EXPORT ManipulatedFrame : public Frame, public MouseGrabber { #ifndef DOXYGEN - friend class Camera; - friend class ::QGLViewer; + friend class Camera; + friend class ::QGLViewer; #endif - Q_OBJECT + Q_OBJECT public: - ManipulatedFrame(); - /*! Virtual destructor. Empty. */ - virtual ~ManipulatedFrame() {} + ManipulatedFrame(); + /*! Virtual destructor. Empty. */ + virtual ~ManipulatedFrame() {} - ManipulatedFrame(const ManipulatedFrame& mf); - ManipulatedFrame& operator=(const ManipulatedFrame& mf); + ManipulatedFrame(const ManipulatedFrame &mf); + ManipulatedFrame &operator=(const ManipulatedFrame &mf); Q_SIGNALS: - /*! This signal is emitted when ever the ManipulatedFrame is manipulated (i.e. rotated or - translated) using the mouse. Connect this signal to any object that should be notified. + /*! This signal is emitted when ever the ManipulatedFrame is manipulated (i.e. + rotated or translated) using the mouse. Connect this signal to any object that + should be notified. - Note that this signal is automatically connected to the QGLViewer::update() slot, when the - ManipulatedFrame is attached to a viewer using QGLViewer::setManipulatedFrame(), which is - probably all you need. + Note that this signal is automatically connected to the QGLViewer::update() + slot, when the ManipulatedFrame is attached to a viewer using + QGLViewer::setManipulatedFrame(), which is probably all you need. - Use the QGLViewer::QGLViewerPool() if you need to connect this signal to all the viewers. + Use the QGLViewer::QGLViewerPool() if you need to connect this signal to all + the viewers. - See also the spun(), modified(), interpolated() and KeyFrameInterpolator::interpolated() - signals' documentations. */ - void manipulated(); + See also the spun(), modified(), interpolated() and + KeyFrameInterpolator::interpolated() signals' documentations. */ + void manipulated(); - /*! This signal is emitted when the ManipulatedFrame isSpinning(). + /*! This signal is emitted when the ManipulatedFrame isSpinning(). - Note that for the QGLViewer::manipulatedFrame(), this signal is automatically connected to the - QGLViewer::update() slot. + Note that for the QGLViewer::manipulatedFrame(), this signal is automatically + connected to the QGLViewer::update() slot. - Connect this signal to any object that should be notified. Use the QGLViewer::QGLViewerPool() if - you need to connect this signal to all the viewers. + Connect this signal to any object that should be notified. Use the + QGLViewer::QGLViewerPool() if you need to connect this signal to all the + viewers. - See also the manipulated(), modified(), interpolated() and KeyFrameInterpolator::interpolated() - signals' documentations. */ - void spun(); + See also the manipulated(), modified(), interpolated() and + KeyFrameInterpolator::interpolated() signals' documentations. */ + void spun(); - /*! @name Manipulation sensitivity */ - //@{ + /*! @name Manipulation sensitivity */ + //@{ public Q_SLOTS: - /*! Defines the rotationSensitivity(). */ - void setRotationSensitivity(qreal sensitivity) { rotationSensitivity_ = sensitivity; } - /*! Defines the translationSensitivity(). */ - void setTranslationSensitivity(qreal sensitivity) { translationSensitivity_ = sensitivity; } - /*! Defines the spinningSensitivity(), in pixels per milliseconds. */ - void setSpinningSensitivity(qreal sensitivity) { spinningSensitivity_ = sensitivity; } - /*! Defines the wheelSensitivity(). */ - void setWheelSensitivity(qreal sensitivity) { wheelSensitivity_ = sensitivity; } - /*! Defines the zoomSensitivity(). */ - void setZoomSensitivity(qreal sensitivity) { zoomSensitivity_ = sensitivity; } + /*! Defines the rotationSensitivity(). */ + void setRotationSensitivity(qreal sensitivity) { + rotationSensitivity_ = sensitivity; + } + /*! Defines the translationSensitivity(). */ + void setTranslationSensitivity(qreal sensitivity) { + translationSensitivity_ = sensitivity; + } + /*! Defines the spinningSensitivity(), in pixels per milliseconds. */ + void setSpinningSensitivity(qreal sensitivity) { + spinningSensitivity_ = sensitivity; + } + /*! Defines the wheelSensitivity(). */ + void setWheelSensitivity(qreal sensitivity) { + wheelSensitivity_ = sensitivity; + } + /*! Defines the zoomSensitivity(). */ + void setZoomSensitivity(qreal sensitivity) { zoomSensitivity_ = sensitivity; } public: - /*! Returns the influence of a mouse displacement on the ManipulatedFrame rotation. - - Default value is 1.0. With an identical mouse displacement, a higher value will generate a - larger rotation (and inversely for lower values). A 0.0 value will forbid ManipulatedFrame mouse - rotation (see also constraint()). - - See also setRotationSensitivity(), translationSensitivity(), spinningSensitivity() and - wheelSensitivity(). */ - qreal rotationSensitivity() const { return rotationSensitivity_; } - /*! Returns the influence of a mouse displacement on the ManipulatedFrame translation. - - Default value is 1.0. You should not have to modify this value, since with 1.0 the - ManipulatedFrame precisely stays under the mouse cursor. - - With an identical mouse displacement, a higher value will generate a larger translation (and - inversely for lower values). A 0.0 value will forbid ManipulatedFrame mouse translation (see - also constraint()). - - \note When the ManipulatedFrame is used to move a \e Camera (see the ManipulatedCameraFrame - class documentation), after zooming on a small region of your scene, the camera may translate - too fast. For a camera, it is the Camera::pivotPoint() that exactly matches the mouse - displacement. Hence, instead of changing the translationSensitivity(), solve the problem by - (temporarily) setting the Camera::pivotPoint() to a point on the zoomed region (see the - QGLViewer::RAP_FROM_PIXEL mouse binding in the mouse page). - - See also setTranslationSensitivity(), rotationSensitivity(), spinningSensitivity() and - wheelSensitivity(). */ - qreal translationSensitivity() const { return translationSensitivity_; } - /*! Returns the minimum mouse speed required (at button release) to make the ManipulatedFrame - spin(). - - See spin(), spinningQuaternion() and startSpinning() for details. - - Mouse speed is expressed in pixels per milliseconds. Default value is 0.3 (300 pixels per - second). Use setSpinningSensitivity() to tune this value. A higher value will make spinning more - difficult (a value of 100.0 forbids spinning in practice). - - See also setSpinningSensitivity(), translationSensitivity(), rotationSensitivity() and - wheelSensitivity(). */ - qreal spinningSensitivity() const { return spinningSensitivity_; } - - /*! Returns the zoom sensitivity. - - Default value is 1.0. A higher value will make the zoom faster. - Use a negative value to invert the zoom in and out directions. - - See also setZoomSensitivity(), translationSensitivity(), rotationSensitivity() wheelSensitivity() - and spinningSensitivity(). */ - qreal zoomSensitivity() const { return zoomSensitivity_; } - /*! Returns the mouse wheel sensitivity. - - Default value is 1.0. A higher value will make the wheel action more efficient (usually meaning - a faster zoom). Use a negative value to invert the zoom in and out directions. - - See also setWheelSensitivity(), translationSensitivity(), rotationSensitivity() zoomSensitivity() - and spinningSensitivity(). */ - qreal wheelSensitivity() const { return wheelSensitivity_; } - //@} - - - /*! @name Spinning */ - //@{ + /*! Returns the influence of a mouse displacement on the ManipulatedFrame + rotation. + + Default value is 1.0. With an identical mouse displacement, a higher value + will generate a larger rotation (and inversely for lower values). A 0.0 value + will forbid ManipulatedFrame mouse rotation (see also constraint()). + + See also setRotationSensitivity(), translationSensitivity(), + spinningSensitivity() and wheelSensitivity(). */ + qreal rotationSensitivity() const { return rotationSensitivity_; } + /*! Returns the influence of a mouse displacement on the ManipulatedFrame + translation. + + Default value is 1.0. You should not have to modify this value, since with 1.0 + the ManipulatedFrame precisely stays under the mouse cursor. + + With an identical mouse displacement, a higher value will generate a larger + translation (and inversely for lower values). A 0.0 value will forbid + ManipulatedFrame mouse translation (see also constraint()). + + \note When the ManipulatedFrame is used to move a \e Camera (see the + ManipulatedCameraFrame class documentation), after zooming on a small region + of your scene, the camera may translate too fast. For a camera, it is the + Camera::pivotPoint() that exactly matches the mouse displacement. Hence, + instead of changing the translationSensitivity(), solve the problem by + (temporarily) setting the Camera::pivotPoint() to a point on the zoomed region + (see the QGLViewer::RAP_FROM_PIXEL mouse binding in the mouse page). + + See also setTranslationSensitivity(), rotationSensitivity(), + spinningSensitivity() and wheelSensitivity(). */ + qreal translationSensitivity() const { return translationSensitivity_; } + /*! Returns the minimum mouse speed required (at button release) to make the + ManipulatedFrame spin(). + + See spin(), spinningQuaternion() and startSpinning() for details. + + Mouse speed is expressed in pixels per milliseconds. Default value is 0.3 (300 + pixels per second). Use setSpinningSensitivity() to tune this value. A higher + value will make spinning more difficult (a value of 100.0 forbids spinning in + practice). + + See also setSpinningSensitivity(), translationSensitivity(), + rotationSensitivity() and wheelSensitivity(). */ + qreal spinningSensitivity() const { return spinningSensitivity_; } + + /*! Returns the zoom sensitivity. + + Default value is 1.0. A higher value will make the zoom faster. + Use a negative value to invert the zoom in and out directions. + + See also setZoomSensitivity(), translationSensitivity(), rotationSensitivity() + wheelSensitivity() and spinningSensitivity(). */ + qreal zoomSensitivity() const { return zoomSensitivity_; } + /*! Returns the mouse wheel sensitivity. + + Default value is 1.0. A higher value will make the wheel action more efficient + (usually meaning a faster zoom). Use a negative value to invert the zoom in + and out directions. + + See also setWheelSensitivity(), translationSensitivity(), + rotationSensitivity() zoomSensitivity() and spinningSensitivity(). */ + qreal wheelSensitivity() const { return wheelSensitivity_; } + //@} + + /*! @name Spinning */ + //@{ public: - /*! Returns \c true when the ManipulatedFrame is spinning. + /*! Returns \c true when the ManipulatedFrame is spinning. - During spinning, spin() rotates the ManipulatedFrame by its spinningQuaternion() at a frequency - defined when the ManipulatedFrame startSpinning(). + During spinning, spin() rotates the ManipulatedFrame by its + spinningQuaternion() at a frequency defined when the ManipulatedFrame + startSpinning(). - Use startSpinning() and stopSpinning() to change this state. Default value is \c false. */ - bool isSpinning() const { return isSpinning_; } - /*! Returns the incremental rotation that is applied by spin() to the ManipulatedFrame - orientation when it isSpinning(). + Use startSpinning() and stopSpinning() to change this state. Default value is + \c false. */ + bool isSpinning() const { return isSpinning_; } + /*! Returns the incremental rotation that is applied by spin() to the + ManipulatedFrame orientation when it isSpinning(). - Default value is a null rotation (identity Quaternion). Use setSpinningQuaternion() to change - this value. + Default value is a null rotation (identity Quaternion). Use + setSpinningQuaternion() to change this value. - The spinningQuaternion() axis is defined in the ManipulatedFrame coordinate system. You can use - Frame::transformOfFrom() to convert this axis from an other Frame coordinate system. */ - Quaternion spinningQuaternion() const { return spinningQuaternion_; } + The spinningQuaternion() axis is defined in the ManipulatedFrame coordinate + system. You can use Frame::transformOfFrom() to convert this axis from an + other Frame coordinate system. */ + Quaternion spinningQuaternion() const { return spinningQuaternion_; } public Q_SLOTS: - /*! Defines the spinningQuaternion(). Its axis is defined in the ManipulatedFrame coordinate - system. */ - void setSpinningQuaternion(const Quaternion& spinningQuaternion) { spinningQuaternion_ = spinningQuaternion; } - virtual void startSpinning(int updateInterval); - /*! Stops the spinning motion started using startSpinning(). isSpinning() will return \c false - after this call. */ - virtual void stopSpinning() { spinningTimer_.stop(); isSpinning_ = false; } + /*! Defines the spinningQuaternion(). Its axis is defined in the + ManipulatedFrame coordinate system. */ + void setSpinningQuaternion(const Quaternion &spinningQuaternion) { + spinningQuaternion_ = spinningQuaternion; + } + virtual void startSpinning(int updateInterval); + /*! Stops the spinning motion started using startSpinning(). isSpinning() will + return \c false after this call. */ + virtual void stopSpinning() { + spinningTimer_.stop(); + isSpinning_ = false; + } protected Q_SLOTS: - virtual void spin(); + virtual void spin(); private Q_SLOTS: - void spinUpdate(); - //@} + void spinUpdate(); + //@} - /*! @name Mouse event handlers */ - //@{ + /*! @name Mouse event handlers */ + //@{ protected: - virtual void mousePressEvent (QMouseEvent* const event, Camera* const camera); - virtual void mouseMoveEvent (QMouseEvent* const event, Camera* const camera); - virtual void mouseReleaseEvent (QMouseEvent* const event, Camera* const camera); - virtual void mouseDoubleClickEvent(QMouseEvent* const event, Camera* const camera); - virtual void wheelEvent (QWheelEvent* const event, Camera* const camera); - //@} + virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera); + virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera); + virtual void mouseReleaseEvent(QMouseEvent *const event, + Camera *const camera); + virtual void mouseDoubleClickEvent(QMouseEvent *const event, + Camera *const camera); + virtual void wheelEvent(QWheelEvent *const event, Camera *const camera); + //@} public: - /*! @name Current state */ - //@{ - bool isManipulated() const; - /*! Returns the \c MouseAction currently applied to this ManipulatedFrame. - - Will return QGLViewer::NO_MOUSE_ACTION unless a mouse button is being pressed - and has been bound to this QGLViewer::MouseHandler. - - The binding between mouse buttons and key modifiers and MouseAction is set using - QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton buttons, MouseHandler handler, MouseAction action, bool withConstraint). - */ - QGLViewer::MouseAction currentMouseAction() const { return action_; } - //@} - - /*! @name MouseGrabber implementation */ - //@{ + /*! @name Current state */ + //@{ + bool isManipulated() const; + /*! Returns the \c MouseAction currently applied to this ManipulatedFrame. + + Will return QGLViewer::NO_MOUSE_ACTION unless a mouse button is being + pressed and has been bound to this QGLViewer::MouseHandler. + + The binding between mouse buttons and key modifiers and MouseAction is set + using QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers + modifiers, Qt::MouseButton buttons, MouseHandler handler, MouseAction action, + bool withConstraint). + */ + QGLViewer::MouseAction currentMouseAction() const { return action_; } + //@} + + /*! @name MouseGrabber implementation */ + //@{ public: - virtual void checkIfGrabsMouse(int x, int y, const Camera* const camera); - //@} + virtual void checkIfGrabsMouse(int x, int y, const Camera *const camera); + //@} - /*! @name XML representation */ - //@{ + /*! @name XML representation */ + //@{ public: - virtual QDomElement domElement(const QString& name, QDomDocument& document) const; + virtual QDomElement domElement(const QString &name, + QDomDocument &document) const; public Q_SLOTS: - virtual void initFromDOMElement(const QDomElement& element); - //@} + virtual void initFromDOMElement(const QDomElement &element); +//@} #ifndef DOXYGEN protected: - Quaternion deformedBallQuaternion(int x, int y, qreal cx, qreal cy, const Camera* const camera); + Quaternion deformedBallQuaternion(int x, int y, qreal cx, qreal cy, + const Camera *const camera); - QGLViewer::MouseAction action_; - Constraint* previousConstraint_; // When manipulation is without Contraint. + QGLViewer::MouseAction action_; + Constraint *previousConstraint_; // When manipulation is without Contraint. - virtual void startAction(int ma, bool withConstraint=true); // int is really a QGLViewer::MouseAction - void computeMouseSpeed(const QMouseEvent* const e); - int mouseOriginalDirection(const QMouseEvent* const e); + virtual void startAction( + int ma, + bool withConstraint = true); // int is really a QGLViewer::MouseAction + void computeMouseSpeed(const QMouseEvent *const e); + int mouseOriginalDirection(const QMouseEvent *const e); - /*! Returns a screen scaled delta from event's position to prevPos_, along the - X or Y direction, whichever has the largest magnitude. */ - qreal deltaWithPrevPos(QMouseEvent* const event, Camera* const camera) const; - /*! Returns a normalized wheel delta, proportionnal to wheelSensitivity(). */ - qreal wheelDelta(const QWheelEvent* event) const; + /*! Returns a screen scaled delta from event's position to prevPos_, along the + X or Y direction, whichever has the largest magnitude. */ + qreal deltaWithPrevPos(QMouseEvent *const event, Camera *const camera) const; + /*! Returns a normalized wheel delta, proportionnal to wheelSensitivity(). */ + qreal wheelDelta(const QWheelEvent *event) const; - // Previous mouse position (used for incremental updates) and mouse press position. - QPoint prevPos_, pressPos_; + // Previous mouse position (used for incremental updates) and mouse press + // position. + QPoint prevPos_, pressPos_; private: - void zoom(qreal delta, const Camera * const camera); + void zoom(qreal delta, const Camera *const camera); #endif // DOXYGEN private: - // Sensitivity - qreal rotationSensitivity_; - qreal translationSensitivity_; - qreal spinningSensitivity_; - qreal wheelSensitivity_; - qreal zoomSensitivity_; - - // Mouse speed and spinning - QTime last_move_time; - qreal mouseSpeed_; - int delay_; - bool isSpinning_; - QTimer spinningTimer_; - Quaternion spinningQuaternion_; - - // Whether the SCREEN_TRANS direction (horizontal or vertical) is fixed or not. - bool dirIsFixed_; - - // MouseGrabber - bool keepsGrabbingMouse_; + // Sensitivity + qreal rotationSensitivity_; + qreal translationSensitivity_; + qreal spinningSensitivity_; + qreal wheelSensitivity_; + qreal zoomSensitivity_; + + // Mouse speed and spinning + QElapsedTimer last_move_time; + qreal mouseSpeed_; + int delay_; + bool isSpinning_; + QTimer spinningTimer_; + Quaternion spinningQuaternion_; + + // Whether the SCREEN_TRANS direction (horizontal or vertical) is fixed or + // not. + bool dirIsFixed_; + + // MouseGrabber + bool keepsGrabbingMouse_; }; } // namespace qglviewer diff --git a/octovis/src/extern/QGLViewer/mouseGrabber.cpp b/octovis/src/extern/QGLViewer/mouseGrabber.cpp index 38cfdd01..b9434950 100644 --- a/octovis/src/extern/QGLViewer/mouseGrabber.cpp +++ b/octovis/src/extern/QGLViewer/mouseGrabber.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,58 +19,54 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #include "mouseGrabber.h" using namespace qglviewer; // Static private variable -QList MouseGrabber::MouseGrabberPool_; +QList MouseGrabber::MouseGrabberPool_; /*! Default constructor. -Adds the created MouseGrabber in the MouseGrabberPool(). grabsMouse() is set to \c false. */ -MouseGrabber::MouseGrabber() - : grabsMouse_(false) -{ - addInMouseGrabberPool(); -} +Adds the created MouseGrabber in the MouseGrabberPool(). grabsMouse() is set to +\c false. */ +MouseGrabber::MouseGrabber() : grabsMouse_(false) { addInMouseGrabberPool(); } /*! Adds the MouseGrabber in the MouseGrabberPool(). -All created MouseGrabber are automatically added in the MouseGrabberPool() by the constructor. -Trying to add a MouseGrabber that already isInMouseGrabberPool() has no effect. - -Use removeFromMouseGrabberPool() to remove the MouseGrabber from the list, so that it is no longer -tested with checkIfGrabsMouse() by the QGLViewer, and hence can no longer grab mouse focus. Use -isInMouseGrabberPool() to know the current state of the MouseGrabber. */ -void MouseGrabber::addInMouseGrabberPool() -{ - if (!isInMouseGrabberPool()) - MouseGrabber::MouseGrabberPool_.append(this); +All created MouseGrabber are automatically added in the MouseGrabberPool() by +the constructor. Trying to add a MouseGrabber that already +isInMouseGrabberPool() has no effect. + +Use removeFromMouseGrabberPool() to remove the MouseGrabber from the list, so +that it is no longer tested with checkIfGrabsMouse() by the QGLViewer, and hence +can no longer grab mouse focus. Use isInMouseGrabberPool() to know the current +state of the MouseGrabber. */ +void MouseGrabber::addInMouseGrabberPool() { + if (!isInMouseGrabberPool()) + MouseGrabber::MouseGrabberPool_.append(this); } /*! Removes the MouseGrabber from the MouseGrabberPool(). -See addInMouseGrabberPool() for details. Removing a MouseGrabber that is not in MouseGrabberPool() -has no effect. */ -void MouseGrabber::removeFromMouseGrabberPool() -{ - if (isInMouseGrabberPool()) - MouseGrabber::MouseGrabberPool_.removeAll(const_cast(this)); +See addInMouseGrabberPool() for details. Removing a MouseGrabber that is not in +MouseGrabberPool() has no effect. */ +void MouseGrabber::removeFromMouseGrabberPool() { + if (isInMouseGrabberPool()) + MouseGrabber::MouseGrabberPool_.removeAll(const_cast(this)); } /*! Clears the MouseGrabberPool(). - Use this method only if it is faster to clear the MouseGrabberPool() and then to add back a few - MouseGrabbers than to remove each one independently. Use QGLViewer::setMouseTracking(false) instead - if you want to disable mouse grabbing. - - When \p autoDelete is \c true, the MouseGrabbers of the MouseGrabberPool() are actually deleted - (use this only if you're sure of what you do). */ -void MouseGrabber::clearMouseGrabberPool(bool autoDelete) -{ - if (autoDelete) - qDeleteAll(MouseGrabber::MouseGrabberPool_); - MouseGrabber::MouseGrabberPool_.clear(); + Use this method only if it is faster to clear the MouseGrabberPool() and then + to add back a few MouseGrabbers than to remove each one independently. Use + QGLViewer::setMouseTracking(false) instead if you want to disable mouse + grabbing. + + When \p autoDelete is \c true, the MouseGrabbers of the MouseGrabberPool() are + actually deleted (use this only if you're sure of what you do). */ +void MouseGrabber::clearMouseGrabberPool(bool autoDelete) { + if (autoDelete) + qDeleteAll(MouseGrabber::MouseGrabberPool_); + MouseGrabber::MouseGrabberPool_.clear(); } diff --git a/octovis/src/extern/QGLViewer/mouseGrabber.h b/octovis/src/extern/QGLViewer/mouseGrabber.h index e66a8b4e..d7380570 100644 --- a/octovis/src/extern/QGLViewer/mouseGrabber.h +++ b/octovis/src/extern/QGLViewer/mouseGrabber.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,7 +19,6 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_MOUSE_GRABBER_H #define QGLVIEWER_MOUSE_GRABBER_H @@ -35,228 +34,262 @@ class Camera; /*! \brief Abstract class for objects that grab mouse focus in a QGLViewer. \class MouseGrabber mouseGrabber.h QGLViewer/mouseGrabber.h - MouseGrabber are objects which react to the mouse cursor, usually when it hovers over them. This - abstract class only provides an interface for all these objects: their actual behavior has to be - defined in a derived class. + MouseGrabber are objects which react to the mouse cursor, usually when it + hovers over them. This abstract class only provides an interface for all these + objects: their actual behavior has to be defined in a derived class.

How does it work ?

- All the created MouseGrabber are grouped in a MouseGrabberPool(). The QGLViewers parse this pool, - calling all the MouseGrabbers' checkIfGrabsMouse() methods that setGrabsMouse() if desired. + All the created MouseGrabber are grouped in a MouseGrabberPool(). The + QGLViewers parse this pool, calling all the MouseGrabbers' checkIfGrabsMouse() + methods that setGrabsMouse() if desired. - When a MouseGrabber grabsMouse(), it becomes the QGLViewer::mouseGrabber(). All the mouse events - (mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent(), mouseDoubleClickEvent() and - wheelEvent()) are then transmitted to the QGLViewer::mouseGrabber() instead of being normally - processed. This continues while grabsMouse() (updated using checkIfGrabsMouse()) returns \c true. + When a MouseGrabber grabsMouse(), it becomes the QGLViewer::mouseGrabber(). + All the mouse events (mousePressEvent(), mouseReleaseEvent(), + mouseMoveEvent(), mouseDoubleClickEvent() and wheelEvent()) are then + transmitted to the QGLViewer::mouseGrabber() instead of being normally + processed. This continues while grabsMouse() (updated using + checkIfGrabsMouse()) returns \c true. - If you want to (temporarily) disable a specific MouseGrabbers, you can remove it from this pool - using removeFromMouseGrabberPool(). You can also disable a MouseGrabber in a specific QGLViewer - using QGLViewer::setMouseGrabberIsEnabled(). + If you want to (temporarily) disable a specific MouseGrabbers, you can remove + it from this pool using removeFromMouseGrabberPool(). You can also disable a + MouseGrabber in a specific QGLViewer using + QGLViewer::setMouseGrabberIsEnabled().

Implementation details

- In order to make MouseGrabber react to mouse events, mouse tracking has to be activated in the - QGLViewer which wants to use MouseGrabbers: - \code - init() { setMouseTracking(true); } - \endcode - Call \c QGLWidget::hasMouseTracking() to get the current state of this flag. + In order to make MouseGrabber react to mouse events, mouse tracking has to be + activated in the QGLViewer which wants to use MouseGrabbers: \code init() { + setMouseTracking(true); } \endcode Call \c QOpenGLWidget::hasMouseTracking() + to get the current state of this flag. - The \p camera parameter of the different mouse event methods is a pointer to the - QGLViewer::camera() of the QGLViewer that uses the MouseGrabber. It can be used to compute 2D to - 3D coordinates conversion using Camera::projectedCoordinatesOf() and - Camera::unprojectedCoordinatesOf(). + The \p camera parameter of the different mouse event methods is a pointer to + the QGLViewer::camera() of the QGLViewer that uses the MouseGrabber. It can be + used to compute 2D to 3D coordinates conversion using + Camera::projectedCoordinatesOf() and Camera::unprojectedCoordinatesOf(). - Very complex behaviors can be implemented using this framework: auto-selected objects (no need to - press a key to use them), automatic drop-down menus, 3D GUI, spinners using the wheelEvent(), and - whatever your imagination creates. See the mouseGrabber - example for an illustration. + Very complex behaviors can be implemented using this framework: auto-selected + objects (no need to press a key to use them), automatic drop-down menus, 3D + GUI, spinners using the wheelEvent(), and whatever your imagination creates. + See the mouseGrabber example for + an illustration. - Note that ManipulatedFrame are MouseGrabber: see the keyFrame - example for an illustration. Every created ManipulatedFrame is hence present in the - MouseGrabberPool() (note however that ManipulatedCameraFrame are not inserted). + Note that ManipulatedFrame are MouseGrabber: see the keyFrame example for an illustration. + Every created ManipulatedFrame is hence present in the MouseGrabberPool() + (note however that ManipulatedCameraFrame are not inserted).

Example

- Here is for instance a draft version of a MovableObject class. Instances of these class can freely - be moved on screen using the mouse, as movable post-it-like notes: - \code - class MovableObject : public MouseGrabber + Here is for instance a draft version of a MovableObject class. Instances of + these class can freely be moved on screen using the mouse, as movable + post-it-like notes: \code class MovableObject : public MouseGrabber { public: - MovableObject() : pos(0,0), moved(false) {} - - void checkIfGrabsMouse(int x, int y, const qglviewer::Camera* const) - { - // MovableObject is active in a region of 5 pixels around its pos. - // May depend on the actual shape of the object. Customize as desired. - // Once clicked (moved = true), it keeps grabbing mouse until button is released. - setGrabsMouse( moved || ((pos-QPoint(x,y)).manhattanLength() < 5) ); - } - - void mousePressEvent( QMouseEvent* const e, Camera* const) { prevPos = e->pos(); moved = true; } - - void mouseMoveEvent(QMouseEvent* const e, const Camera* const) - { - if (moved) - { - // Add position delta to current pos - pos += e->pos() - prevPos; - prevPos = e->pos(); - } - } - - void mouseReleaseEvent(QMouseEvent* const, Camera* const) { moved = false; } - - void draw() - { - // The object is drawn centered on its pos, with different possible aspects: - if (grabsMouse()) - if (moved) - // Object being moved, maybe a transparent display - else - // Object ready to be moved, maybe a highlighted visual feedback - else - // Normal display - } + MovableObject() : pos(0,0), moved(false) {} + + void checkIfGrabsMouse(int x, int y, const qglviewer::Camera* const) + { + // MovableObject is active in a region of 5 pixels around its pos. + // May depend on the actual shape of the object. Customize as desired. + // Once clicked (moved = true), it keeps grabbing mouse until button is + released. setGrabsMouse( moved || ((pos-QPoint(x,y)).manhattanLength() < 5) ); + } + + void mousePressEvent( QMouseEvent* const e, Camera* const) { prevPos = + e->pos(); moved = true; } + + void mouseMoveEvent(QMouseEvent* const e, const Camera* const) + { + if (moved) + { + // Add position delta to current pos + pos += e->pos() - prevPos; + prevPos = e->pos(); + } + } + + void mouseReleaseEvent(QMouseEvent* const, Camera* const) { moved = false; } + + void draw() + { + // The object is drawn centered on its pos, with different possible aspects: + if (grabsMouse()) + if (moved) + // Object being moved, maybe a transparent display + else + // Object ready to be moved, maybe a highlighted visual feedback + else + // Normal display + } private: - QPoint pos, prevPos; - bool moved; + QPoint pos, prevPos; + bool moved; }; \endcode - Note that the different event callback methods are called only once the MouseGrabber grabsMouse(). - \nosubgrouping */ -class QGLVIEWER_EXPORT MouseGrabber -{ + Note that the different event callback methods are called only once the + MouseGrabber grabsMouse(). \nosubgrouping */ +class QGLVIEWER_EXPORT MouseGrabber { #ifndef DOXYGEN - friend class ::QGLViewer; + friend class ::QGLViewer; #endif public: - MouseGrabber(); - /*! Virtual destructor. Removes the MouseGrabber from the MouseGrabberPool(). */ - virtual ~MouseGrabber() { MouseGrabber::MouseGrabberPool_.removeAll(this); } + MouseGrabber(); + /*! Virtual destructor. Removes the MouseGrabber from the MouseGrabberPool(). + */ + virtual ~MouseGrabber() { MouseGrabber::MouseGrabberPool_.removeAll(this); } - /*! @name Mouse grabbing detection */ - //@{ + /*! @name Mouse grabbing detection */ + //@{ public: - /*! Pure virtual method, called by the QGLViewers before they test if the MouseGrabber - grabsMouse(). Should setGrabsMouse() according to the mouse position. + /*! Pure virtual method, called by the QGLViewers before they test if the + MouseGrabber grabsMouse(). Should setGrabsMouse() according to the mouse + position. - This is the core method of the MouseGrabber. It has to be overloaded in your derived class. - Its goal is to update the grabsMouse() flag according to the mouse and MouseGrabber current - positions, using setGrabsMouse(). + This is the core method of the MouseGrabber. It has to be overloaded in your + derived class. Its goal is to update the grabsMouse() flag according to the + mouse and MouseGrabber current positions, using setGrabsMouse(). - grabsMouse() is usually set to \c true when the mouse cursor is close enough to the MouseGrabber - position. It should also be set to \c false when the mouse cursor leaves this region in order to - release the mouse focus. + grabsMouse() is usually set to \c true when the mouse cursor is close enough + to the MouseGrabber position. It should also be set to \c false when the mouse + cursor leaves this region in order to release the mouse focus. - \p x and \p y are the mouse cursor coordinates (Qt coordinate system: (0,0) corresponds to the upper - left corner). + \p x and \p y are the mouse cursor coordinates (Qt coordinate system: (0,0) + corresponds to the upper left corner). - A typical implementation will look like: - \code - // (posX,posY) is the position of the MouseGrabber on screen. - // Here, distance to mouse must be less than 10 pixels to activate the MouseGrabber. - setGrabsMouse( sqrt((x-posX)*(x-posX) + (y-posY)*(y-posY)) < 10); - \endcode + A typical implementation will look like: + \code + // (posX,posY) is the position of the MouseGrabber on screen. + // Here, distance to mouse must be less than 10 pixels to activate the + MouseGrabber. setGrabsMouse( sqrt((x-posX)*(x-posX) + (y-posY)*(y-posY)) < + 10); \endcode - If the MouseGrabber position is defined in 3D, use the \p camera parameter, corresponding to - the calling QGLViewer Camera. Project on screen and then compare the projected coordinates: - \code - Vec proj = camera->projectedCoordinatesOf(myMouseGrabber->frame()->position()); - setGrabsMouse((fabs(x-proj.x) < 5) && (fabs(y-proj.y) < 2)); // Rectangular region - \endcode + If the MouseGrabber position is defined in 3D, use the \p camera parameter, + corresponding to the calling QGLViewer Camera. Project on screen and then + compare the projected coordinates: \code Vec proj = + camera->projectedCoordinatesOf(myMouseGrabber->frame()->position()); + setGrabsMouse((fabs(x-proj.x) < 5) && (fabs(y-proj.y) < 2)); // Rectangular + region \endcode - See examples in the detailed description section and in the mouseGrabber example. */ - virtual void checkIfGrabsMouse(int x, int y, const Camera* const camera) = 0; + See examples in the detailed description section and + in the mouseGrabber example. */ + virtual void checkIfGrabsMouse(int x, int y, const Camera *const camera) = 0; - /*! Returns \c true when the MouseGrabber grabs the QGLViewer's mouse events. + /*! Returns \c true when the MouseGrabber grabs the QGLViewer's mouse events. - This flag is set with setGrabsMouse() by the checkIfGrabsMouse() method. */ - bool grabsMouse() const { return grabsMouse_; } + This flag is set with setGrabsMouse() by the checkIfGrabsMouse() method. */ + bool grabsMouse() const { return grabsMouse_; } protected: - /*! Sets the grabsMouse() flag. Normally used by checkIfGrabsMouse(). */ - void setGrabsMouse(bool grabs) { grabsMouse_ = grabs; } - //@} - + /*! Sets the grabsMouse() flag. Normally used by checkIfGrabsMouse(). */ + void setGrabsMouse(bool grabs) { grabsMouse_ = grabs; } + //@} - /*! @name MouseGrabber pool */ - //@{ + /*! @name MouseGrabber pool */ + //@{ public: - /*! Returns a list containing pointers to all the active MouseGrabbers. - - Used by the QGLViewer to parse all the MouseGrabbers and to check if any of them grabsMouse() - using checkIfGrabsMouse(). - - You should not have to directly use this list. Use removeFromMouseGrabberPool() and - addInMouseGrabberPool() to modify this list. - - \attention This method returns a \c QPtrList with Qt 3 and a \c QList with Qt 2. */ - static const QList& MouseGrabberPool() { return MouseGrabber::MouseGrabberPool_; } - - /*! Returns \c true if the MouseGrabber is currently in the MouseGrabberPool() list. - - Default value is \c true. When set to \c false using removeFromMouseGrabberPool(), the - QGLViewers no longer checkIfGrabsMouse() on this MouseGrabber. Use addInMouseGrabberPool() to - insert it back. */ - bool isInMouseGrabberPool() const { return MouseGrabber::MouseGrabberPool_.contains(const_cast(this)); } - void addInMouseGrabberPool(); - void removeFromMouseGrabberPool(); - void clearMouseGrabberPool(bool autoDelete=false); - //@} - - - /*! @name Mouse event handlers */ - //@{ + /*! Returns a list containing pointers to all the active MouseGrabbers. + + Used by the QGLViewer to parse all the MouseGrabbers and to check if any of + them grabsMouse() using checkIfGrabsMouse(). + + You should not have to directly use this list. Use + removeFromMouseGrabberPool() and addInMouseGrabberPool() to modify this list. + + \attention This method returns a \c QPtrList with Qt 3 and a \c + QList with Qt 2. */ + static const QList &MouseGrabberPool() { + return MouseGrabber::MouseGrabberPool_; + } + + /*! Returns \c true if the MouseGrabber is currently in the MouseGrabberPool() + list. + + Default value is \c true. When set to \c false using + removeFromMouseGrabberPool(), the QGLViewers no longer checkIfGrabsMouse() on + this MouseGrabber. Use addInMouseGrabberPool() to insert it back. */ + bool isInMouseGrabberPool() const { + return MouseGrabber::MouseGrabberPool_.contains( + const_cast(this)); + } + void addInMouseGrabberPool(); + void removeFromMouseGrabberPool(); + void clearMouseGrabberPool(bool autoDelete = false); + //@} + + /*! @name Mouse event handlers */ + //@{ protected: - /*! Callback method called when the MouseGrabber grabsMouse() and a mouse button is pressed. - - - The MouseGrabber will typically start an action or change its state when a mouse button is - pressed. mouseMoveEvent() (called at each mouse displacement) will then update the MouseGrabber - accordingly and mouseReleaseEvent() (called when the mouse button is released) will terminate - this action. - - Use the \p event QMouseEvent::state() and QMouseEvent::button() to test the keyboard - and button state and possibly change the MouseGrabber behavior accordingly. - - See the detailed description section and the mouseGrabber example for examples. - - See the \c QGLWidget::mousePressEvent() and the \c QMouseEvent documentations for details. */ - virtual void mousePressEvent(QMouseEvent* const event, Camera* const camera) { Q_UNUSED(event); Q_UNUSED(camera); } - /*! Callback method called when the MouseGrabber grabsMouse() and a mouse button is double clicked. - - See the \c QGLWidget::mouseDoubleClickEvent() and the \c QMouseEvent documentations for details. */ - virtual void mouseDoubleClickEvent(QMouseEvent* const event, Camera* const camera) { Q_UNUSED(event); Q_UNUSED(camera); } - /*! Mouse release event callback method. See mousePressEvent(). */ - virtual void mouseReleaseEvent(QMouseEvent* const event, Camera* const camera) { Q_UNUSED(event); Q_UNUSED(camera); } - /*! Callback method called when the MouseGrabber grabsMouse() and the mouse is moved while a - button is pressed. - - This method will typically update the state of the MouseGrabber from the mouse displacement. See - the mousePressEvent() documentation for details. */ - virtual void mouseMoveEvent(QMouseEvent* const event, Camera* const camera) { Q_UNUSED(event); Q_UNUSED(camera); } - /*! Callback method called when the MouseGrabber grabsMouse() and the mouse wheel is used. - - See the \c QGLWidget::wheelEvent() and the \c QWheelEvent documentations for details. */ - virtual void wheelEvent(QWheelEvent* const event, Camera* const camera) { Q_UNUSED(event); Q_UNUSED(camera); } - //@} + /*! Callback method called when the MouseGrabber grabsMouse() and a mouse + button is pressed. + + + The MouseGrabber will typically start an action or change its state when a + mouse button is pressed. mouseMoveEvent() (called at each mouse displacement) + will then update the MouseGrabber accordingly and mouseReleaseEvent() (called + when the mouse button is released) will terminate this action. + + Use the \p event QMouseEvent::state() and QMouseEvent::button() to test the + keyboard and button state and possibly change the MouseGrabber behavior + accordingly. + + See the detailed description section and the mouseGrabber example for examples. + + See the \c QOpenGLWidget::mousePressEvent() and the \c QMouseEvent + documentations for details. */ + virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera) { + Q_UNUSED(event); + Q_UNUSED(camera); + } + /*! Callback method called when the MouseGrabber grabsMouse() and a mouse + button is double clicked. + + See the \c QOpenGLWidget::mouseDoubleClickEvent() and the \c QMouseEvent + documentations for details. */ + virtual void mouseDoubleClickEvent(QMouseEvent *const event, + Camera *const camera) { + Q_UNUSED(event); + Q_UNUSED(camera); + } + /*! Mouse release event callback method. See mousePressEvent(). */ + virtual void mouseReleaseEvent(QMouseEvent *const event, + Camera *const camera) { + Q_UNUSED(event); + Q_UNUSED(camera); + } + /*! Callback method called when the MouseGrabber grabsMouse() and the mouse is + moved while a button is pressed. + + This method will typically update the state of the MouseGrabber from the mouse + displacement. See the mousePressEvent() documentation for details. */ + virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera) { + Q_UNUSED(event); + Q_UNUSED(camera); + } + /*! Callback method called when the MouseGrabber grabsMouse() and the mouse + wheel is used. + + See the \c QOpenGLWidget::wheelEvent() and the \c QWheelEvent documentations + for details. */ + virtual void wheelEvent(QWheelEvent *const event, Camera *const camera) { + Q_UNUSED(event); + Q_UNUSED(camera); + } + //@} private: - // Copy constructor and opertor= are declared private and undefined - // Prevents everyone from trying to use them - MouseGrabber(const MouseGrabber&); - MouseGrabber& operator=(const MouseGrabber&); + // Copy constructor and opertor= are declared private and undefined + // Prevents everyone from trying to use them + MouseGrabber(const MouseGrabber &); + MouseGrabber &operator=(const MouseGrabber &); - bool grabsMouse_; + bool grabsMouse_; - // Q G L V i e w e r p o o l - static QList MouseGrabberPool_; + // Q G L V i e w e r p o o l + static QList MouseGrabberPool_; }; } // namespace qglviewer diff --git a/octovis/src/extern/QGLViewer/qglviewer.cpp b/octovis/src/extern/QGLViewer/qglviewer.cpp index adf6e014..f258ead9 100644 --- a/octovis/src/extern/QGLViewer/qglviewer.cpp +++ b/octovis/src/extern/QGLViewer/qglviewer.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,288 +19,326 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - -#include "domUtils.h" #include "qglviewer.h" #include "camera.h" +#include "domUtils.h" #include "keyFrameInterpolator.h" #include "manipulatedCameraFrame.h" -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +# define MidButton MiddleButton +#endif using namespace std; using namespace qglviewer; // Static private variable -QList QGLViewer::QGLViewerPool_; - +QList QGLViewer::QGLViewerPool_; /*! \mainpage -libQGLViewer is a free C++ library based on Qt that enables the quick creation of OpenGL 3D viewers. -It features a powerful camera trackball and simple applications simply require an implementation of -the draw() method. This makes it a tool of choice for OpenGL beginners and -assignments. It provides screenshot saving, mouse manipulated frames, stereo display, interpolated +libQGLViewer is a free C++ library based on Qt that enables the quick creation +of OpenGL 3D viewers. It features a powerful camera trackball and simple +applications simply require an implementation of the draw() method. +This makes it a tool of choice for OpenGL beginners and assignments. It provides +screenshot saving, mouse manipulated frames, stereo display, interpolated keyFrames, object selection, and much more. It is fully -customizable and easy to extend to create complex applications, with a possible Qt GUI. +customizable and easy to extend to create complex applications, with a possible +Qt GUI. -libQGLViewer is not a 3D viewer that can be used directly to view 3D scenes in various -formats. It is more likely to be the starting point for the coding of such a viewer. +libQGLViewer is not a 3D viewer that can be used directly to view 3D +scenes in various formats. It is more likely to be the starting point for the +coding of such a viewer. -libQGLViewer is based on the Qt toolkit and hence compiles on any architecture (Unix-Linux, Mac, -Windows, ...). Full reference documentation and many examples are provided. +libQGLViewer is based on the Qt toolkit and hence compiles on any architecture +(Unix-Linux, Mac, Windows, ...). Full reference documentation and many examples +are provided. See the project main page for details on the project and installation steps. */ -void QGLViewer::defaultConstructor() -{ - // Test OpenGL context - // if (glGetString(GL_VERSION) == 0) - // qWarning("Unable to get OpenGL version, context may not be available - Check your configuration"); - - int poolIndex = QGLViewer::QGLViewerPool_.indexOf(NULL); - setFocusPolicy(Qt::StrongFocus); - - if (poolIndex >= 0) - QGLViewer::QGLViewerPool_.replace(poolIndex, this); - else - QGLViewer::QGLViewerPool_.append(this); - - camera_ = new Camera(); - setCamera(camera()); - - setDefaultShortcuts(); - setDefaultMouseBindings(); - - setSnapshotFileName(tr("snapshot", "Default snapshot file name")); - initializeSnapshotFormats(); - setSnapshotCounter(0); - setSnapshotQuality(95); - - fpsTime_.start(); - fpsCounter_ = 0; - f_p_s_ = 0.0; - fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg("?"); - visualHint_ = 0; - previousPathId_ = 0; - // prevPos_ is not initialized since pos() is not meaningful here. - // It will be set when setFullScreen(false) is called after setFullScreen(true) - - // #CONNECTION# default values in initFromDOMElement() - manipulatedFrame_ = NULL; - manipulatedFrameIsACamera_ = false; - mouseGrabberIsAManipulatedFrame_ = false; - mouseGrabberIsAManipulatedCameraFrame_ = false; - displayMessage_ = false; - connect(&messageTimer_, SIGNAL(timeout()), SLOT(hideMessage())); - messageTimer_.setSingleShot(true); - helpWidget_ = NULL; - setMouseGrabber(NULL); - - setSceneRadius(1.0); - showEntireScene(); - setStateFileName(".qglviewer.xml"); - - // #CONNECTION# default values in initFromDOMElement() - setAxisIsDrawn(false); - setGridIsDrawn(false); - setFPSIsDisplayed(false); - setCameraIsEdited(false); - setTextIsEnabled(true); - setStereoDisplay(false); - // Make sure move() is not called, which would call initializeGL() - fullScreen_ = false; - setFullScreen(false); - - animationTimerId_ = 0; - stopAnimation(); - setAnimationPeriod(40); // 25Hz - - selectBuffer_ = NULL; - setSelectBufferSize(4*1000); - setSelectRegionWidth(3); - setSelectRegionHeight(3); - setSelectedName(-1); - - bufferTextureId_ = 0; - bufferTextureMaxU_ = 0.0; - bufferTextureMaxV_ = 0.0; - bufferTextureWidth_ = 0; - bufferTextureHeight_ = 0; - previousBufferTextureFormat_ = 0; - previousBufferTextureInternalFormat_ = 0; - currentlyPressedKey_ = Qt::Key(0); - - setAttribute(Qt::WA_NoSystemBackground); - - tileRegion_ = NULL; -} - -#if !defined QT3_SUPPORT -/*! Constructor. See \c QGLWidget documentation for details. +void QGLViewer::defaultConstructor() { + // Test OpenGL context + // if (glGetString(GL_VERSION) == 0) + // qWarning("Unable to get OpenGL version, context may not be available - + // Check your configuration"); -All viewer parameters (display flags, scene parameters, associated objects...) are set to their default values. See -the associated documentation. + int poolIndex = QGLViewer::QGLViewerPool_.indexOf(nullptr); + setFocusPolicy(Qt::StrongFocus); -If the \p shareWidget parameter points to a valid \c QGLWidget, the QGLViewer will share the OpenGL -context with \p shareWidget (see isSharing()). */ -QGLViewer::QGLViewer(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags) - : QGLWidget(parent, shareWidget, flags) -{ defaultConstructor(); } + if (poolIndex >= 0) + QGLViewer::QGLViewerPool_.replace(poolIndex, this); + else + QGLViewer::QGLViewerPool_.append(this); + + camera_ = new Camera(); + setCamera(camera()); + + setDefaultShortcuts(); + setDefaultMouseBindings(); + + setSnapshotFileName(tr("snapshot", "Default snapshot file name")); + initializeSnapshotFormats(); + setSnapshotCounter(0); + setSnapshotQuality(95); + + fpsTime_.start(); + fpsCounter_ = 0; + f_p_s_ = 0.0; + fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg("?"); + visualHint_ = 0; + previousPathId_ = 0; + // prevPos_ is not initialized since pos() is not meaningful here. + // It will be set when setFullScreen(false) is called after + // setFullScreen(true) + + // #CONNECTION# default values in initFromDOMElement() + manipulatedFrame_ = nullptr; + manipulatedFrameIsACamera_ = false; + mouseGrabberIsAManipulatedFrame_ = false; + mouseGrabberIsAManipulatedCameraFrame_ = false; + displayMessage_ = false; + connect(&messageTimer_, SIGNAL(timeout()), SLOT(hideMessage())); + messageTimer_.setSingleShot(true); + helpWidget_ = nullptr; + setMouseGrabber(nullptr); + + setSceneRadius(1.0); + showEntireScene(); + setStateFileName(".qglviewer.xml"); + + // #CONNECTION# default values in initFromDOMElement() + setAxisIsDrawn(false); + setGridIsDrawn(false); + setFPSIsDisplayed(false); + setCameraIsEdited(false); + setTextIsEnabled(true); + setStereoDisplay(false); + // Make sure move() is not called, which would call initializeGL() + fullScreen_ = false; + setFullScreen(false); + + animationTimerId_ = 0; + stopAnimation(); + setAnimationPeriod(40); // 25Hz + + selectBuffer_ = nullptr; + setSelectBufferSize(4 * 1000); + setSelectRegionWidth(3); + setSelectRegionHeight(3); + setSelectedName(-1); + + bufferTextureId_ = 0; + bufferTextureMaxU_ = 0.0; + bufferTextureMaxV_ = 0.0; + bufferTextureWidth_ = 0; + bufferTextureHeight_ = 0; + previousBufferTextureFormat_ = 0; + previousBufferTextureInternalFormat_ = 0; + currentlyPressedKey_ = Qt::Key(0); + + setAttribute(Qt::WA_NoSystemBackground); + + tileRegion_ = nullptr; +} -/*! Same as QGLViewer(), but a \c QGLContext can be provided so that viewers share GL contexts, even -with \c QGLContext sub-classes (use \p shareWidget otherwise). */ -QGLViewer::QGLViewer(QGLContext *context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags) - : QGLWidget(context, parent, shareWidget, flags) -{ defaultConstructor(); } +/*! Constructor. See \c QGLWidget documentation for details. -/*! Same as QGLViewer(), but a specific \c QGLFormat can be provided. +All viewer parameters (display flags, scene parameters, associated objects...) +are set to their default values. See the associated documentation. */ +QGLViewer::QGLViewer(QWidget *parent, Qt::WindowFlags flags) + : QOpenGLWidget(parent, flags) { + defaultConstructor(); +} -This is for instance needed to ask for a stencil buffer or for stereo display (as is illustrated in -the stereoViewer example). */ -QGLViewer::QGLViewer(const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags) - : QGLWidget(format, parent, shareWidget, flags) -{ defaultConstructor(); } -#endif // QT3_SUPPORT +#ifndef DOXYGEN -/*! Virtual destructor. +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -The viewer is replaced by \c NULL in the QGLViewerPool() (in order to preserve other viewer's indexes) and allocated -memory is released. The camera() is deleted and should be copied before if it is shared by an other viewer. */ -QGLViewer::~QGLViewer() -{ - // See closeEvent comment. Destructor is called (and not closeEvent) only when the widget is embedded. - // Hence we saveToFile here. It is however a bad idea if virtual domElement() has been overloaded ! - // if (parent()) - // saveStateToFileForAllViewers(); +/*! These contructors are deprecated since version 2.7.0, since they are not + * supported by QOpenGlWidget */ - QGLViewer::QGLViewerPool_.replace(QGLViewer::QGLViewerPool_.indexOf(this), NULL); +/*! Constructor. See \c QGLWidget documentation for details. - delete camera(); - delete[] selectBuffer_; - if (helpWidget()) - { - // Needed for Qt 4 which has no main widget. - helpWidget()->close(); - delete helpWidget_; - } +All viewer parameters (display flags, scene parameters, associated objects...) +are set to their default values. See the associated documentation. + +If the \p shareWidget parameter points to a valid \c QGLWidget, the QGLViewer +will share the OpenGL context with \p shareWidget (see isSharing()). */ +QGLViewer::QGLViewer(QWidget *parent, const QGLWidget *shareWidget, + Qt::WindowFlags flags) + : QOpenGLWidget(parent, flags) { + Q_UNUSED(shareWidget) + qWarning("The constructor with a shareWidget is deprecated, use the regular " + "contructor instead."); + defaultConstructor(); +} + +/*! Same as QGLViewer(), but a \c QGLContext can be provided so that viewers +share GL contexts, even with \c QGLContext sub-classes (use \p shareWidget +otherwise). */ +QGLViewer::QGLViewer(QGLContext *context, QWidget *parent, + const QGLWidget *shareWidget, Qt::WindowFlags flags) + : QOpenGLWidget(parent, flags) { + Q_UNUSED(context) + Q_UNUSED(shareWidget) + qWarning("The constructor with a QGLContext is deprecated, use the regular " + "contructor instead."); + defaultConstructor(); } +/*! Same as QGLViewer(), but a specific \c QGLFormat can be provided. -static QString QGLViewerVersionString() -{ - return QString::number((QGLVIEWER_VERSION & 0xff0000) >> 16) + "." + - QString::number((QGLVIEWER_VERSION & 0x00ff00) >> 8) + "." + - QString::number(QGLVIEWER_VERSION & 0x0000ff); +This is for instance needed to ask for a stencil buffer or for stereo display +(as is illustrated in the stereoViewer +example). */ +QGLViewer::QGLViewer(const QGLFormat &format, QWidget *parent, + const QGLWidget *shareWidget, Qt::WindowFlags flags) + : QOpenGLWidget(parent, flags) { + Q_UNUSED(format) + Q_UNUSED(shareWidget) + qWarning("The constructor with a QGLFormat is deprecated, use the regular " + "contructor instead."); + defaultConstructor(); +} +#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#endif // DOXYGEN + +/*! Virtual destructor. + +The viewer is replaced by \c nullptr in the QGLViewerPool() (in order to preserve +other viewer's indexes) and allocated memory is released. The camera() is +deleted and should be copied before if it is shared by an other viewer. */ +QGLViewer::~QGLViewer() { + // See closeEvent comment. Destructor is called (and not closeEvent) only when + // the widget is embedded. Hence we saveToFile here. It is however a bad idea + // if virtual domElement() has been overloaded ! if (parent()) + // saveStateToFileForAllViewers(); + + QGLViewer::QGLViewerPool_.replace(QGLViewer::QGLViewerPool_.indexOf(this), + nullptr); + + delete camera(); + delete[] selectBuffer_; + if (helpWidget()) { + // Needed for Qt 4 which has no main widget. + helpWidget()->close(); + delete helpWidget_; + } } -static Qt::KeyboardModifiers keyboardModifiersFromState(unsigned int state) { - // Convertion of keyboard modifiers and mouse buttons as an int is no longer supported : emulate - return Qt::KeyboardModifiers(int(state & 0xFF000000)); +static QString QGLViewerVersionString() { + return QString::number((QGLVIEWER_VERSION & 0xff0000) >> 16) + "." + + QString::number((QGLVIEWER_VERSION & 0x00ff00) >> 8) + "." + + QString::number(QGLVIEWER_VERSION & 0x0000ff); } +static Qt::KeyboardModifiers keyboardModifiersFromState(unsigned int state) { + // Convertion of keyboard modifiers and mouse buttons as an int is no longer + // supported : emulate + return Qt::KeyboardModifiers(int(state & 0xFF000000)); +} static Qt::MouseButton mouseButtonFromState(unsigned int state) { - // Convertion of keyboard modifiers and mouse buttons as an int is no longer supported : emulate - return Qt::MouseButton(state & 0xFFFF); + // Convertion of keyboard modifiers and mouse buttons as an int is no longer + // supported : emulate + return Qt::MouseButton(state & 0xFFFF); } /*! Initializes the QGLViewer OpenGL context and then calls user-defined init(). This method is automatically called once, before the first call to paintGL(). -Overload init() instead of this method to modify viewer specific OpenGL state or to create display -lists. +Overload init() instead of this method to modify viewer specific OpenGL state or +to create display lists. -To make beginners' life easier and to simplify the examples, this method slightly modifies the -standard OpenGL state: -\code -glEnable(GL_LIGHT0); +To make beginners' life easier and to simplify the examples, this method +slightly modifies the standard OpenGL state: \code glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); \endcode -If you port an existing application to QGLViewer and your display changes, you probably want to -disable these flags in init() to get back to a standard OpenGL state. */ -void QGLViewer::initializeGL() -{ - glEnable(GL_LIGHT0); - glEnable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); - glEnable(GL_COLOR_MATERIAL); +If you port an existing application to QGLViewer and your display changes, you +probably want to disable these flags in init() to get back to a standard OpenGL +state. */ +void QGLViewer::initializeGL() { + glEnable(GL_LIGHT0); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + glEnable(GL_COLOR_MATERIAL); - // Default colors - setForegroundColor(QColor(180, 180, 180)); - setBackgroundColor(QColor(51, 51, 51)); + // Default colors + setForegroundColor(QColor(180, 180, 180)); + setBackgroundColor(QColor(51, 51, 51)); - // Clear the buffer where we're going to draw - if (format().stereo()) - { - glDrawBuffer(GL_BACK_RIGHT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDrawBuffer(GL_BACK_LEFT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - else - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Clear the buffer where we're going to draw + if (format().stereo()) { + glDrawBuffer(GL_BACK_RIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDrawBuffer(GL_BACK_LEFT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } else + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Calls user defined method. Default emits a signal. - init(); + // Calls user defined method. Default emits a signal. + init(); - // Give time to glInit to finish and then call setFullScreen(). - if (isFullScreen()) - QTimer::singleShot( 100, this, SLOT(delayedFullScreen()) ); + // Give time to glInit to finish and then call setFullScreen(). + if (isFullScreen()) + QTimer::singleShot(100, this, SLOT(delayedFullScreen())); } -/*! Main paint method, inherited from \c QGLWidget. +/*! Main paint method, inherited from \c QOpenGLWidget. Calls the following methods, in that order: -\arg preDraw() (or preDrawStereo() if viewer displaysInStereo()) : places the camera in the world coordinate system. -\arg draw() (or fastDraw() when the camera is manipulated) : main drawing method. Should be overloaded. -\arg postDraw() : display of visual hints (world axis, FPS...) */ -void QGLViewer::paintGL() -{ - if (displaysInStereo()) - { - for (int view=1; view>=0; --view) - { - // Clears screen, set model view matrix with shifted matrix for ith buffer - preDrawStereo(view); - // Used defined method. Default is empty - if (camera()->frame()->isManipulated()) - fastDraw(); - else - draw(); - postDraw(); - } - } - else - { - // Clears screen, set model view matrix... - preDraw(); - // Used defined method. Default calls draw() - if (camera()->frame()->isManipulated()) - fastDraw(); - else - draw(); - // Add visual hints: axis, camera, grid... - postDraw(); - } - Q_EMIT drawFinished(true); +\arg preDraw() (or preDrawStereo() if viewer displaysInStereo()) : places the +camera in the world coordinate system. \arg draw() (or fastDraw() when the +camera is manipulated) : main drawing method. Should be overloaded. \arg +postDraw() : display of visual hints (world axis, FPS...) */ +void QGLViewer::paintGL() { + if (displaysInStereo()) { + for (int view = 1; view >= 0; --view) { + // Clears screen, set model view matrix with shifted matrix for ith buffer + preDrawStereo(view); + // Used defined method. Default is empty + if (camera()->frame()->isManipulated()) + fastDraw(); + else + draw(); + postDraw(); + } + } else { + // Clears screen, set model view matrix... + preDraw(); + // Used defined method. Default calls draw() + if (camera()->frame()->isManipulated()) + fastDraw(); + else + draw(); + // Add visual hints: axis, camera, grid... + postDraw(); + } + Q_EMIT drawFinished(true); } /*! Sets OpenGL state before draw(). @@ -313,637 +351,711 @@ camera()->loadProjectionMatrix(); camera()->loadModelViewMatrix(); \endcode -Emits the drawNeeded() signal once this is done (see the callback example). */ -void QGLViewer::preDraw() -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +Emits the drawNeeded() signal once this is done (see the callback example). */ +void QGLViewer::preDraw() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // GL_PROJECTION matrix - camera()->loadProjectionMatrix(); - // GL_MODELVIEW matrix - camera()->loadModelViewMatrix(); + // GL_PROJECTION matrix + camera()->loadProjectionMatrix(); + // GL_MODELVIEW matrix + camera()->loadModelViewMatrix(); - Q_EMIT drawNeeded(); + Q_EMIT drawNeeded(); } /*! Called after draw() to draw viewer visual hints. -Default implementation displays axis, grid, FPS... when the respective flags are sets. +Default implementation displays axis, grid, FPS... when the respective flags are +sets. See the multiSelect and thumbnail examples for an overloading illustration. - -The GLContext (color, LIGHTING, BLEND...) is \e not modified by this method, so that in -draw(), the user can rely on the OpenGL context he defined. Respect this convention (by pushing/popping the -different attributes) if you overload this method. */ -void QGLViewer::postDraw() -{ - // Reset model view matrix to world coordinates origin - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - camera()->loadModelViewMatrix(); - // TODO restore model loadProjectionMatrixStereo - - // Save OpenGL state - glPushAttrib(GL_ALL_ATTRIB_BITS); - - // Set neutral GL state - glDisable(GL_TEXTURE_1D); - glDisable(GL_TEXTURE_2D); -#ifdef GL_TEXTURE_3D // OpenGL 1.2 Only... - glDisable(GL_TEXTURE_3D); +href="../examples/contribs.html#thumbnail">thumbnail examples for an +overloading illustration. + +The GLContext (color, LIGHTING, BLEND...) is \e not modified by this method, so +that in draw(), the user can rely on the OpenGL context he defined. Respect this +convention (by pushing/popping the different attributes) if you overload this +method. */ +void QGLViewer::postDraw() { + // Reset model view matrix to world coordinates origin + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + camera()->loadModelViewMatrix(); + // TODO restore model loadProjectionMatrixStereo + + // Save OpenGL state + glPushAttrib(GL_ALL_ATTRIB_BITS); + + // Set neutral GL state + glDisable(GL_TEXTURE_1D); + glDisable(GL_TEXTURE_2D); +#ifdef GL_TEXTURE_3D // OpenGL 1.2 Only... + glDisable(GL_TEXTURE_3D); #endif - glDisable(GL_TEXTURE_GEN_Q); - glDisable(GL_TEXTURE_GEN_R); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_Q); + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); -#ifdef GL_RESCALE_NORMAL // OpenGL 1.2 Only... - glEnable(GL_RESCALE_NORMAL); +#ifdef GL_RESCALE_NORMAL // OpenGL 1.2 Only... + glEnable(GL_RESCALE_NORMAL); #endif - glDisable(GL_COLOR_MATERIAL); - qglColor(foregroundColor()); + glDisable(GL_COLOR_MATERIAL); + glColor4f(foregroundColor().redF(), foregroundColor().greenF(), + foregroundColor().blueF(), foregroundColor().alphaF()); - if (cameraIsEdited()) - camera()->drawAllPaths(); + if (cameraIsEdited()) + camera()->drawAllPaths(); - // Pivot point, line when camera rolls, zoom region - drawVisualHints(); + // Pivot point, line when camera rolls, zoom region + drawVisualHints(); - if (gridIsDrawn()) { glLineWidth(1.0); drawGrid(camera()->sceneRadius()); } - if (axisIsDrawn()) { glLineWidth(2.0); drawAxis(camera()->sceneRadius()); } + if (gridIsDrawn()) { + glLineWidth(1.0); + drawGrid(camera()->sceneRadius()); + } + if (axisIsDrawn()) { + glLineWidth(2.0); + drawAxis(camera()->sceneRadius()); + } - // FPS computation - const unsigned int maxCounter = 20; - if (++fpsCounter_ == maxCounter) - { - f_p_s_ = 1000.0 * maxCounter / fpsTime_.restart(); - fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg(f_p_s_, 0, 'f', ((f_p_s_ < 10.0)?1:0)); - fpsCounter_ = 0; - } + // FPS computation + const unsigned int maxCounter = 20; + if (++fpsCounter_ == maxCounter) { + f_p_s_ = 1000.0 * maxCounter / fpsTime_.restart(); + fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz") + .arg(f_p_s_, 0, 'f', ((f_p_s_ < 10.0) ? 1 : 0)); + fpsCounter_ = 0; + } - // Restore foregroundColor - float color[4]; - color[0] = foregroundColor().red() / 255.0f; - color[1] = foregroundColor().green() / 255.0f; - color[2] = foregroundColor().blue() / 255.0f; - color[3] = 1.0f; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); + // Restore foregroundColor + float color[4]; + color[0] = foregroundColor().red() / 255.0f; + color[1] = foregroundColor().green() / 255.0f; + color[2] = foregroundColor().blue() / 255.0f; + color[3] = 1.0f; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); - if (FPSIsDisplayed()) displayFPS(); - if (displayMessage_) drawText(10, height()-10, message_); + if (FPSIsDisplayed()) + displayFPS(); + if (displayMessage_) + drawText(10, height() - 10, message_); - // Restore GL state - glPopAttrib(); - glPopMatrix(); + // Restore GL state + glPopAttrib(); + glPopMatrix(); } /*! Called before draw() (instead of preDraw()) when viewer displaysInStereo(). -Same as preDraw() except that the glDrawBuffer() is set to \c GL_BACK_LEFT or \c GL_BACK_RIGHT -depending on \p leftBuffer, and it uses qglviewer::Camera::loadProjectionMatrixStereo() and +Same as preDraw() except that the glDrawBuffer() is set to \c GL_BACK_LEFT or \c +GL_BACK_RIGHT depending on \p leftBuffer, and it uses +qglviewer::Camera::loadProjectionMatrixStereo() and qglviewer::Camera::loadModelViewMatrixStereo() instead. */ -void QGLViewer::preDrawStereo(bool leftBuffer) -{ - // Set buffer to draw in - // Seems that SGI and Crystal Eyes are not synchronized correctly ! - // That's why we don't draw in the appropriate buffer... - if (!leftBuffer) - glDrawBuffer(GL_BACK_LEFT); - else - glDrawBuffer(GL_BACK_RIGHT); +void QGLViewer::preDrawStereo(bool leftBuffer) { + // Set buffer to draw in + // Seems that SGI and Crystal Eyes are not synchronized correctly ! + // That's why we don't draw in the appropriate buffer... + if (!leftBuffer) + glDrawBuffer(GL_BACK_LEFT); + else + glDrawBuffer(GL_BACK_RIGHT); - // Clear the buffer where we're going to draw - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // GL_PROJECTION matrix - camera()->loadProjectionMatrixStereo(leftBuffer); - // GL_MODELVIEW matrix - camera()->loadModelViewMatrixStereo(leftBuffer); + // Clear the buffer where we're going to draw + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // GL_PROJECTION matrix + camera()->loadProjectionMatrixStereo(leftBuffer); + // GL_MODELVIEW matrix + camera()->loadModelViewMatrixStereo(leftBuffer); - Q_EMIT drawNeeded(); + Q_EMIT drawNeeded(); } -/*! Draws a simplified version of the scene to guarantee interactive camera displacements. +/*! Draws a simplified version of the scene to guarantee interactive camera +displacements. This method is called instead of draw() when the qglviewer::Camera::frame() is -qglviewer::ManipulatedCameraFrame::isManipulated(). Default implementation simply calls draw(). +qglviewer::ManipulatedCameraFrame::isManipulated(). Default implementation +simply calls draw(). -Overload this method if your scene is too complex to allow for interactive camera manipulation. See -the fastDraw example for an illustration. */ -void QGLViewer::fastDraw() -{ - draw(); -} +Overload this method if your scene is too complex to allow for interactive +camera manipulation. See the fastDraw +example for an illustration. */ +void QGLViewer::fastDraw() { draw(); } -/*! Starts (\p edit = \c true, default) or stops (\p edit=\c false) the edition of the camera(). +/*! Starts (\p edit = \c true, default) or stops (\p edit=\c false) the edition +of the camera(). -Current implementation is limited to paths display. Get current state using cameraIsEdited(). +Current implementation is limited to paths display. Get current state using +cameraIsEdited(). -\attention This method sets the qglviewer::Camera::zClippingCoefficient() to 5.0 when \p edit is \c -true, so that the Camera paths (see qglviewer::Camera::keyFrameInterpolator()) are not clipped. It -restores the previous value when \p edit is \c false. */ -void QGLViewer::setCameraIsEdited(bool edit) -{ - cameraIsEdited_ = edit; - if (edit) - { - previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient(); - // #CONNECTION# 5.0 also used in domElement() and in initFromDOMElement(). - camera()->setZClippingCoefficient(5.0); - } - else - camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_); +\attention This method sets the qglviewer::Camera::zClippingCoefficient() to 5.0 +when \p edit is \c true, so that the Camera paths (see +qglviewer::Camera::keyFrameInterpolator()) are not clipped. It restores the +previous value when \p edit is \c false. */ +void QGLViewer::setCameraIsEdited(bool edit) { + cameraIsEdited_ = edit; + if (edit) { + previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient(); + // #CONNECTION# 5.0 also used in domElement() and in initFromDOMElement(). + camera()->setZClippingCoefficient(5.0); + } else + camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_); - Q_EMIT cameraIsEditedChanged(edit); + Q_EMIT cameraIsEditedChanged(edit); - update(); + update(); } // Key bindings. 0 means not defined -void QGLViewer::setDefaultShortcuts() -{ - // D e f a u l t a c c e l e r a t o r s - setShortcut(DRAW_AXIS, Qt::Key_A); - setShortcut(DRAW_GRID, Qt::Key_G); - setShortcut(DISPLAY_FPS, Qt::Key_F); - setShortcut(ENABLE_TEXT, Qt::SHIFT+Qt::Key_Question); - setShortcut(EXIT_VIEWER, Qt::Key_Escape); - setShortcut(SAVE_SCREENSHOT, Qt::CTRL+Qt::Key_S); - setShortcut(CAMERA_MODE, Qt::Key_Space); - setShortcut(FULL_SCREEN, Qt::ALT+Qt::Key_Return); - setShortcut(STEREO, Qt::Key_S); - setShortcut(ANIMATION, Qt::Key_Return); - setShortcut(HELP, Qt::Key_H); - setShortcut(EDIT_CAMERA, Qt::Key_C); - setShortcut(MOVE_CAMERA_LEFT, Qt::Key_Left); - setShortcut(MOVE_CAMERA_RIGHT,Qt::Key_Right); - setShortcut(MOVE_CAMERA_UP, Qt::Key_Up); - setShortcut(MOVE_CAMERA_DOWN, Qt::Key_Down); - setShortcut(INCREASE_FLYSPEED, Qt::Key_Plus); - setShortcut(DECREASE_FLYSPEED, Qt::Key_Minus); - setShortcut(SNAPSHOT_TO_CLIPBOARD, Qt::CTRL+Qt::Key_C); - - keyboardActionDescription_[DISPLAY_FPS] = tr("Toggles the display of the FPS", "DISPLAY_FPS action description"); - keyboardActionDescription_[SAVE_SCREENSHOT] = tr("Saves a screenshot", "SAVE_SCREENSHOT action description"); - keyboardActionDescription_[FULL_SCREEN] = tr("Toggles full screen display", "FULL_SCREEN action description"); - keyboardActionDescription_[DRAW_AXIS] = tr("Toggles the display of the world axis", "DRAW_AXIS action description"); - keyboardActionDescription_[DRAW_GRID] = tr("Toggles the display of the XY grid", "DRAW_GRID action description"); - keyboardActionDescription_[CAMERA_MODE] = tr("Changes camera mode (observe or fly)", "CAMERA_MODE action description"); - keyboardActionDescription_[STEREO] = tr("Toggles stereo display", "STEREO action description"); - keyboardActionDescription_[HELP] = tr("Opens this help window", "HELP action description"); - keyboardActionDescription_[ANIMATION] = tr("Starts/stops the animation", "ANIMATION action description"); - keyboardActionDescription_[EDIT_CAMERA] = tr("Toggles camera paths display", "EDIT_CAMERA action description"); // TODO change - keyboardActionDescription_[ENABLE_TEXT] = tr("Toggles the display of the text", "ENABLE_TEXT action description"); - keyboardActionDescription_[EXIT_VIEWER] = tr("Exits program", "EXIT_VIEWER action description"); - keyboardActionDescription_[MOVE_CAMERA_LEFT] = tr("Moves camera left", "MOVE_CAMERA_LEFT action description"); - keyboardActionDescription_[MOVE_CAMERA_RIGHT] = tr("Moves camera right", "MOVE_CAMERA_RIGHT action description"); - keyboardActionDescription_[MOVE_CAMERA_UP] = tr("Moves camera up", "MOVE_CAMERA_UP action description"); - keyboardActionDescription_[MOVE_CAMERA_DOWN] = tr("Moves camera down", "MOVE_CAMERA_DOWN action description"); - keyboardActionDescription_[INCREASE_FLYSPEED] = tr("Increases fly speed", "INCREASE_FLYSPEED action description"); - keyboardActionDescription_[DECREASE_FLYSPEED] = tr("Decreases fly speed", "DECREASE_FLYSPEED action description"); - keyboardActionDescription_[SNAPSHOT_TO_CLIPBOARD] = tr("Copies a snapshot to clipboard", "SNAPSHOT_TO_CLIPBOARD action description"); - - // K e y f r a m e s s h o r t c u t k e y s - setPathKey(Qt::Key_F1, 1); - setPathKey(Qt::Key_F2, 2); - setPathKey(Qt::Key_F3, 3); - setPathKey(Qt::Key_F4, 4); - setPathKey(Qt::Key_F5, 5); - setPathKey(Qt::Key_F6, 6); - setPathKey(Qt::Key_F7, 7); - setPathKey(Qt::Key_F8, 8); - setPathKey(Qt::Key_F9, 9); - setPathKey(Qt::Key_F10, 10); - setPathKey(Qt::Key_F11, 11); - setPathKey(Qt::Key_F12, 12); - - setAddKeyFrameKeyboardModifiers(Qt::AltModifier); - setPlayPathKeyboardModifiers(Qt::NoModifier); +void QGLViewer::setDefaultShortcuts() { + // D e f a u l t a c c e l e r a t o r s + setShortcut(DRAW_AXIS, Qt::Key_A); + setShortcut(DRAW_GRID, Qt::Key_G); + setShortcut(DISPLAY_FPS, Qt::Key_F); + setShortcut(ENABLE_TEXT, Qt::SHIFT | Qt::Key_Question); + setShortcut(EXIT_VIEWER, Qt::Key_Escape); + setShortcut(SAVE_SCREENSHOT, Qt::CTRL | Qt::Key_S); + setShortcut(CAMERA_MODE, Qt::Key_Space); + setShortcut(FULL_SCREEN, Qt::ALT | Qt::Key_Return); + setShortcut(STEREO, Qt::Key_S); + setShortcut(ANIMATION, Qt::Key_Return); + setShortcut(HELP, Qt::Key_H); + setShortcut(EDIT_CAMERA, Qt::Key_C); + setShortcut(MOVE_CAMERA_LEFT, Qt::Key_Left); + setShortcut(MOVE_CAMERA_RIGHT, Qt::Key_Right); + setShortcut(MOVE_CAMERA_UP, Qt::Key_Up); + setShortcut(MOVE_CAMERA_DOWN, Qt::Key_Down); + setShortcut(INCREASE_FLYSPEED, Qt::Key_Plus); + setShortcut(DECREASE_FLYSPEED, Qt::Key_Minus); + setShortcut(SNAPSHOT_TO_CLIPBOARD, Qt::CTRL | Qt::Key_C); + + keyboardActionDescription_[DISPLAY_FPS] = + tr("Toggles the display of the FPS", "DISPLAY_FPS action description"); + keyboardActionDescription_[SAVE_SCREENSHOT] = + tr("Saves a screenshot", "SAVE_SCREENSHOT action description"); + keyboardActionDescription_[FULL_SCREEN] = + tr("Toggles full screen display", "FULL_SCREEN action description"); + keyboardActionDescription_[DRAW_AXIS] = tr( + "Toggles the display of the world axis", "DRAW_AXIS action description"); + keyboardActionDescription_[DRAW_GRID] = + tr("Toggles the display of the XY grid", "DRAW_GRID action description"); + keyboardActionDescription_[CAMERA_MODE] = tr( + "Changes camera mode (observe or fly)", "CAMERA_MODE action description"); + keyboardActionDescription_[STEREO] = + tr("Toggles stereo display", "STEREO action description"); + keyboardActionDescription_[HELP] = + tr("Opens this help window", "HELP action description"); + keyboardActionDescription_[ANIMATION] = + tr("Starts/stops the animation", "ANIMATION action description"); + keyboardActionDescription_[EDIT_CAMERA] = + tr("Toggles camera paths display", + "EDIT_CAMERA action description"); // TODO change + keyboardActionDescription_[ENABLE_TEXT] = + tr("Toggles the display of the text", "ENABLE_TEXT action description"); + keyboardActionDescription_[EXIT_VIEWER] = + tr("Exits program", "EXIT_VIEWER action description"); + keyboardActionDescription_[MOVE_CAMERA_LEFT] = + tr("Moves camera left", "MOVE_CAMERA_LEFT action description"); + keyboardActionDescription_[MOVE_CAMERA_RIGHT] = + tr("Moves camera right", "MOVE_CAMERA_RIGHT action description"); + keyboardActionDescription_[MOVE_CAMERA_UP] = + tr("Moves camera up", "MOVE_CAMERA_UP action description"); + keyboardActionDescription_[MOVE_CAMERA_DOWN] = + tr("Moves camera down", "MOVE_CAMERA_DOWN action description"); + keyboardActionDescription_[INCREASE_FLYSPEED] = + tr("Increases fly speed", "INCREASE_FLYSPEED action description"); + keyboardActionDescription_[DECREASE_FLYSPEED] = + tr("Decreases fly speed", "DECREASE_FLYSPEED action description"); + keyboardActionDescription_[SNAPSHOT_TO_CLIPBOARD] = + tr("Copies a snapshot to clipboard", + "SNAPSHOT_TO_CLIPBOARD action description"); + + // K e y f r a m e s s h o r t c u t k e y s + setPathKey(Qt::Key_F1, 1); + setPathKey(Qt::Key_F2, 2); + setPathKey(Qt::Key_F3, 3); + setPathKey(Qt::Key_F4, 4); + setPathKey(Qt::Key_F5, 5); + setPathKey(Qt::Key_F6, 6); + setPathKey(Qt::Key_F7, 7); + setPathKey(Qt::Key_F8, 8); + setPathKey(Qt::Key_F9, 9); + setPathKey(Qt::Key_F10, 10); + setPathKey(Qt::Key_F11, 11); + setPathKey(Qt::Key_F12, 12); + + setAddKeyFrameKeyboardModifiers(Qt::AltModifier); + setPlayPathKeyboardModifiers(Qt::NoModifier); } // M o u s e b e h a v i o r -void QGLViewer::setDefaultMouseBindings() -{ - const Qt::KeyboardModifiers cameraKeyboardModifiers = Qt::NoModifier; - const Qt::KeyboardModifiers frameKeyboardModifiers = Qt::ControlModifier; +void QGLViewer::setDefaultMouseBindings() { + const Qt::KeyboardModifiers cameraKeyboardModifiers = Qt::NoModifier; + const Qt::KeyboardModifiers frameKeyboardModifiers = Qt::ControlModifier; - //#CONNECTION# toggleCameraMode() - for (int handler=0; handler<2; ++handler) - { - MouseHandler mh = (MouseHandler)(handler); - Qt::KeyboardModifiers modifiers = (mh == FRAME) ? frameKeyboardModifiers : cameraKeyboardModifiers; + //#CONNECTION# toggleCameraMode() + for (int handler = 0; handler < 2; ++handler) { + MouseHandler mh = static_cast(handler); + Qt::KeyboardModifiers modifiers = + (mh == FRAME) ? frameKeyboardModifiers : cameraKeyboardModifiers; - setMouseBinding(modifiers, Qt::LeftButton, mh, ROTATE); - setMouseBinding(modifiers, Qt::MidButton, mh, ZOOM); - setMouseBinding(modifiers, Qt::RightButton, mh, TRANSLATE); + setMouseBinding(modifiers, Qt::LeftButton, mh, ROTATE); + setMouseBinding(modifiers, Qt::MidButton, mh, ZOOM); + setMouseBinding(modifiers, Qt::RightButton, mh, TRANSLATE); - setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, mh, SCREEN_ROTATE); + setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, mh, SCREEN_ROTATE); - setWheelBinding(modifiers, mh, ZOOM); - } + setWheelBinding(modifiers, mh, ZOOM); + } - // Z o o m o n r e g i o n - setMouseBinding(Qt::ShiftModifier, Qt::MidButton, CAMERA, ZOOM_ON_REGION); + // Z o o m o n r e g i o n + setMouseBinding(Qt::ShiftModifier, Qt::MidButton, CAMERA, ZOOM_ON_REGION); - // S e l e c t - setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, SELECT); + // S e l e c t + setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, SELECT); - setMouseBinding(Qt::ShiftModifier, Qt::RightButton, RAP_FROM_PIXEL); - // D o u b l e c l i c k - setMouseBinding(Qt::NoModifier, Qt::LeftButton, ALIGN_CAMERA, true); - setMouseBinding(Qt::NoModifier, Qt::MidButton, SHOW_ENTIRE_SCENE, true); - setMouseBinding(Qt::NoModifier, Qt::RightButton, CENTER_SCENE, true); + setMouseBinding(Qt::ShiftModifier, Qt::RightButton, RAP_FROM_PIXEL); + // D o u b l e c l i c k + setMouseBinding(Qt::NoModifier, Qt::LeftButton, ALIGN_CAMERA, true); + setMouseBinding(Qt::NoModifier, Qt::MidButton, SHOW_ENTIRE_SCENE, true); + setMouseBinding(Qt::NoModifier, Qt::RightButton, CENTER_SCENE, true); - setMouseBinding(frameKeyboardModifiers, Qt::LeftButton, ALIGN_FRAME, true); - // middle double click makes no sense for manipulated frame - setMouseBinding(frameKeyboardModifiers, Qt::RightButton, CENTER_FRAME, true); + setMouseBinding(frameKeyboardModifiers, Qt::LeftButton, ALIGN_FRAME, true); + // middle double click makes no sense for manipulated frame + setMouseBinding(frameKeyboardModifiers, Qt::RightButton, CENTER_FRAME, true); - // A c t i o n s w i t h k e y m o d i f i e r s - setMouseBinding(Qt::Key_Z, Qt::NoModifier, Qt::LeftButton, ZOOM_ON_PIXEL); - setMouseBinding(Qt::Key_Z, Qt::NoModifier, Qt::RightButton, ZOOM_TO_FIT); + // A c t i o n s w i t h k e y m o d i f i e r s + setMouseBinding(Qt::Key_Z, Qt::NoModifier, Qt::LeftButton, ZOOM_ON_PIXEL); + setMouseBinding(Qt::Key_Z, Qt::NoModifier, Qt::RightButton, ZOOM_TO_FIT); #ifdef Q_OS_MAC - // Specific Mac bindings for touchpads. Two fingers emulate a wheelEvent which zooms. - // There is no right button available : make Option key + left emulate the right button. - // A Control+Left indeed emulates a right click (OS X system configuration), but it does - // no seem to support dragging. - // Done at the end to override previous settings. - const Qt::KeyboardModifiers macKeyboardModifiers = Qt::AltModifier; - - setMouseBinding(macKeyboardModifiers, Qt::LeftButton, CAMERA, TRANSLATE); - setMouseBinding(macKeyboardModifiers, Qt::LeftButton, CENTER_SCENE, true); - setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers, Qt::LeftButton, CENTER_FRAME, true); - setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers, Qt::LeftButton, FRAME, TRANSLATE); + // Specific Mac bindings for touchpads. Two fingers emulate a wheelEvent which + // zooms. There is no right button available : make Option key + left emulate + // the right button. A Control+Left indeed emulates a right click (OS X system + // configuration), but it does no seem to support dragging. Done at the end to + // override previous settings. + const Qt::KeyboardModifiers macKeyboardModifiers = Qt::AltModifier; + + setMouseBinding(macKeyboardModifiers, Qt::LeftButton, CAMERA, TRANSLATE); + setMouseBinding(macKeyboardModifiers, Qt::LeftButton, CENTER_SCENE, true); + setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers, Qt::LeftButton, + CENTER_FRAME, true); + setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers, Qt::LeftButton, + FRAME, TRANSLATE); #endif } /*! Associates a new qglviewer::Camera to the viewer. -You should only use this method when you derive a new class from qglviewer::Camera and want to use -one of its instances instead of the original class. +You should only use this method when you derive a new class from +qglviewer::Camera and want to use one of its instances instead of the original +class. -It you simply want to save and restore Camera positions, use qglviewer::Camera::addKeyFrameToPath() -and qglviewer::Camera::playPath() instead. +It you simply want to save and restore Camera positions, use +qglviewer::Camera::addKeyFrameToPath() and qglviewer::Camera::playPath() +instead. -This method silently ignores \c NULL \p camera pointers. The calling method is responsible for deleting -the previous camera pointer in order to prevent memory leaks if needed. +This method silently ignores \c nullptr \p camera pointers. The calling method is +responsible for deleting the previous camera pointer in order to prevent memory +leaks if needed. -The sceneRadius() and sceneCenter() of \p camera are set to the \e current QGLViewer values. +The sceneRadius() and sceneCenter() of \p camera are set to the \e current +QGLViewer values. All the \p camera qglviewer::Camera::keyFrameInterpolator() -qglviewer::KeyFrameInterpolator::interpolated() signals are connected to the viewer update() slot. -The connections with the previous viewer's camera are removed. */ -void QGLViewer::setCamera(Camera* const camera) -{ - if (!camera) - return; - - camera->setSceneRadius(sceneRadius()); - camera->setSceneCenter(sceneCenter()); - camera->setScreenWidthAndHeight(width(), height()); - - // Disconnect current camera from this viewer. - disconnect(this->camera()->frame(), SIGNAL(manipulated()), this, SLOT(update())); - disconnect(this->camera()->frame(), SIGNAL(spun()), this, SLOT(update())); - - // Connect camera frame to this viewer. - connect(camera->frame(), SIGNAL(manipulated()), SLOT(update())); - connect(camera->frame(), SIGNAL(spun()), SLOT(update())); - - connectAllCameraKFIInterpolatedSignals(false); - camera_ = camera; - connectAllCameraKFIInterpolatedSignals(); - - previousCameraZClippingCoefficient_ = this->camera()->zClippingCoefficient(); -} - -void QGLViewer::connectAllCameraKFIInterpolatedSignals(bool connection) -{ - for (QMap::ConstIterator it = camera()->kfi_.begin(), end=camera()->kfi_.end(); it != end; ++it) - { - if (connection) - connect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), SLOT(update())); - else - disconnect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), this, SLOT(update())); - } +qglviewer::KeyFrameInterpolator::interpolated() signals are connected to the +viewer update() slot. The connections with the previous viewer's camera are +removed. */ +void QGLViewer::setCamera(Camera *const camera) { + if (!camera) + return; + + // Disconnect current camera from this viewer. + disconnect(this->camera()->frame(), SIGNAL(manipulated()), this, + SLOT(update())); + disconnect(this->camera()->frame(), SIGNAL(spun()), this, SLOT(update())); + disconnect(screen(), SIGNAL(physicalDotsPerInchChanged(qreal)), this->camera(), SLOT(setDevicePixelRatio(qreal))); + connectAllCameraKFIInterpolatedSignals(false); + + camera_ = camera; + + camera->setSceneRadius(sceneRadius()); + camera->setSceneCenter(sceneCenter()); + camera->setScreenWidthAndHeight(width(), height()); + camera->setDevicePixelRatio(screen()->devicePixelRatio()); + + // Connect camera frame to this viewer. + connect(camera->frame(), SIGNAL(manipulated()), SLOT(update())); + connect(camera->frame(), SIGNAL(spun()), SLOT(update())); + connect(screen(), SIGNAL(physicalDotsPerInchChanged(qreal)), camera, SLOT(setDevicePixelRatio(qreal))); + connectAllCameraKFIInterpolatedSignals(); + + previousCameraZClippingCoefficient_ = this->camera()->zClippingCoefficient(); +} + +void QGLViewer::connectAllCameraKFIInterpolatedSignals(bool connection) { + for (QMap::ConstIterator + it = camera()->kfi_.begin(), + end = camera()->kfi_.end(); + it != end; ++it) { + if (connection) + connect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), + SLOT(update())); + else + disconnect(camera()->keyFrameInterpolator(it.key()), + SIGNAL(interpolated()), this, SLOT(update())); + } - if (connection) - connect(camera()->interpolationKfi_, SIGNAL(interpolated()), SLOT(update())); - else - disconnect(camera()->interpolationKfi_, SIGNAL(interpolated()), this, SLOT(update())); + if (connection) + connect(camera()->interpolationKfi_, SIGNAL(interpolated()), + SLOT(update())); + else + disconnect(camera()->interpolationKfi_, SIGNAL(interpolated()), this, + SLOT(update())); } /*! Draws a representation of \p light. -Called in draw(), this method is useful to debug or display your light setup. Light drawing depends -on the type of light (point, spot, directional). +Called in draw(), this method is useful to debug or display your light setup. +Light drawing depends on the type of light (point, spot, directional). -The method retrieves the light setup using \c glGetLightfv. Position and define your lights before -calling this method. +The method retrieves the light setup using \c glGetLightfv. Position and define +your lights before calling this method. Light is drawn using its diffuse color. Disabled lights are not displayed. Drawing size is proportional to sceneRadius(). Use \p scale to rescale it. -See the drawLight example for an illustration. - -\attention You need to enable \c GL_COLOR_MATERIAL before calling this method. \c glColor is set to -the light diffuse color. */ -void QGLViewer::drawLight(GLenum light, qreal scale) const -{ - static GLUquadric* quadric = gluNewQuadric(); - - const qreal length = sceneRadius() / 5.0 * scale; - - GLboolean lightIsOn; - glGetBooleanv(light, &lightIsOn); - - if (lightIsOn) - { - // All light values are given in eye coordinates - glPushMatrix(); - glLoadIdentity(); - - float color[4]; - glGetLightfv(light, GL_DIFFUSE, color); - glColor4fv(color); - - float pos[4]; - glGetLightfv(light, GL_POSITION, pos); - - if (pos[3] != 0.0) - { - glTranslatef(pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3]); - - GLfloat cutOff; - glGetLightfv(light, GL_SPOT_CUTOFF, &cutOff); - if (cutOff != 180.0) - { - GLfloat dir[4]; - glGetLightfv(light, GL_SPOT_DIRECTION, dir); - glMultMatrixd(Quaternion(Vec(0,0,1), Vec(dir)).matrix()); - QGLViewer::drawArrow(length); - gluCylinder(quadric, 0.0, 0.7 * length * sin(cutOff * M_PI / 180.0), 0.7 * length * cos(cutOff * M_PI / 180.0), 12, 1); - } - else - gluSphere(quadric, 0.2*length, 10, 10); - } - else - { - // Directional light. - Vec dir(pos[0], pos[1], pos[2]); - dir.normalize(); - Frame fr=Frame(camera()->cameraCoordinatesOf(4.0 * length * camera()->frame()->inverseTransformOf(dir)), - Quaternion(Vec(0,0,-1), dir)); - glMultMatrixd(fr.matrix()); - drawArrow(length); - } - - glPopMatrix(); - } -} - - -/*! Draws \p text at position \p x, \p y (expressed in screen coordinates pixels, origin in the -upper left corner of the widget). - -The default QApplication::font() is used to render the text when no \p fnt is specified. Use -QApplication::setFont() to define this default font. - -You should disable \c GL_LIGHTING and \c GL_DEPTH_TEST before this method so that colors are properly rendered. - -This method can be used in conjunction with the qglviewer::Camera::projectedCoordinatesOf() -method to display a text attached to an object. In your draw() method use: -\code -qglviewer::Vec screenPos = camera()->projectedCoordinatesOf(myFrame.position()); -drawText((int)screenPos[0], (int)screenPos[1], "My Object"); -\endcode -See the screenCoordSystem example for an illustration. - -Text is displayed only when textIsEnabled() (default). This mechanism allows the user to -conveniently remove all the displayed text with a single keyboard shortcut. - -See also displayMessage() to drawText() for only a short amount of time. - -Use QGLWidget::renderText(x,y,z, text) instead if you want to draw a text located - at a specific 3D position instead of 2D screen coordinates (fixed size text, facing the camera). - -The \c GL_MODELVIEW and \c GL_PROJECTION matrices are not modified by this method. - -\attention This method uses display lists to render the characters, with an index that starts at -2000 by default (see the QGLWidget::renderText() documentation). If you use more than 2000 Display -Lists, they may overlap with these. Directly use QGLWidget::renderText() in that case, with a -higher \c listBase parameter (or overload fontDisplayListBase).*/ -void QGLViewer::drawText(int x, int y, const QString& text, const QFont& fnt) -{ - if (!textIsEnabled()) - return; +See the drawLight example for an +illustration. - if (tileRegion_ != NULL) { - renderText(int((x-tileRegion_->xMin) * width() / (tileRegion_->xMax - tileRegion_->xMin)), - int((y-tileRegion_->yMin) * height() / (tileRegion_->yMax - tileRegion_->yMin)), text, scaledFont(fnt)); - } else - renderText(x, y, text, fnt); +\attention You need to enable \c GL_COLOR_MATERIAL before calling this method. +\c glColor is set to the light diffuse color. */ +void QGLViewer::drawLight(GLenum light, qreal scale) const { + static GLUquadric *quadric = gluNewQuadric(); + + const qreal length = sceneRadius() / 5.0 * scale; + + GLboolean lightIsOn; + glGetBooleanv(light, &lightIsOn); + + if (lightIsOn) { + // All light values are given in eye coordinates + glPushMatrix(); + glLoadIdentity(); + + float color[4]; + glGetLightfv(light, GL_DIFFUSE, color); + glColor4fv(color); + + float pos[4]; + glGetLightfv(light, GL_POSITION, pos); + + if (static_cast(pos[3]) != 0.0) { + glTranslatef(pos[0] / pos[3], pos[1] / pos[3], pos[2] / pos[3]); + + GLfloat cutOff; + glGetLightfv(light, GL_SPOT_CUTOFF, &cutOff); + if (static_cast(cutOff) != 180.0) { + GLfloat dir[4]; + glGetLightfv(light, GL_SPOT_DIRECTION, dir); + glMultMatrixd(Quaternion(Vec(0, 0, 1), Vec(dir)).matrix()); + QGLViewer::drawArrow(length); + gluCylinder(quadric, 0.0, 0.7 * length * sin(static_cast(cutOff) * M_PI / 180.0), + 0.7 * length * cos(static_cast(cutOff) * M_PI / 180.0), 12, 1); + } else + gluSphere(quadric, 0.2 * length, 10, 10); + } else { + // Directional light. + Vec dir(static_cast(pos[0]), static_cast(pos[1]), static_cast(pos[2])); + dir.normalize(); + Frame fr = + Frame(camera()->cameraCoordinatesOf( + 4.0 * length * camera()->frame()->inverseTransformOf(dir)), + Quaternion(Vec(0, 0, -1), dir)); + glMultMatrixd(fr.matrix()); + drawArrow(length); + } + + glPopMatrix(); + } } -/*! Briefly displays a message in the lower left corner of the widget. Convenient to provide -feedback to the user. +#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) +void QGLViewer::renderText(int x, int y, const QString &str, + const QFont &font) { + // Retrieve last OpenGL color to use as a font color + GLdouble glColor[4]; + glGetDoublev(GL_CURRENT_COLOR, glColor); + QColor fontColor = QColor(255 * glColor[0], 255 * glColor[1], + 255 * glColor[2], 255 * glColor[3]); -\p message is displayed during \p delay milliseconds (default is 2 seconds) using drawText(). - -This method should not be called in draw(). If you want to display a text in each draw(), use -drawText() instead. - -If this method is called when a message is already displayed, the new message replaces the old one. -Use setTextIsEnabled() (default shortcut is '?') to enable or disable text (and hence messages) -display. */ -void QGLViewer::displayMessage(const QString& message, int delay) -{ - message_ = message; - displayMessage_ = true; - // Was set to single shot in defaultConstructor. - messageTimer_.start(delay); - if (textIsEnabled()) - update(); + // Render text + QPainter painter(this); + painter.setPen(fontColor); + painter.setFont(font); + painter.drawText(x, y, str); + painter.end(); } -void QGLViewer::hideMessage() -{ - displayMessage_ = false; - if (textIsEnabled()) - update(); +void QGLViewer::renderText(double x, double y, double z, const QString &str, + const QFont &font) { + const Vec proj = camera_->projectedCoordinatesOf(Vec(x, y, z)); + renderText(proj.x, proj.y, str, font); } +#endif +/*! Draws \p text at position \p x, \p y (expressed in screen coordinates +pixels, origin in the upper left corner of the widget). -/*! Displays the averaged currentFPS() frame rate in the upper left corner of the widget. +The default QApplication::font() is used to render the text when no \p fnt is +specified. Use QApplication::setFont() to define this default font. -update() should be called in a loop in order to have a meaningful value (this is the case when -you continuously move the camera using the mouse or when animationIsStarted()). -setAnimationPeriod(0) to make this loop as fast as possible in order to reach and measure the -maximum available frame rate. +You should disable \c GL_LIGHTING and \c GL_DEPTH_TEST before this method so +that colors are properly rendered. -When FPSIsDisplayed() is \c true (default is \c false), this method is called by postDraw() to -display the currentFPS(). Use QApplication::setFont() to define the font (see drawText()). */ -void QGLViewer::displayFPS() -{ - drawText(10, int(1.5*((QApplication::font().pixelSize()>0)?QApplication::font().pixelSize():QApplication::font().pointSize())), fpsString_); -} +This method can be used in conjunction with the +qglviewer::Camera::projectedCoordinatesOf() method to display a text attached to +an object. In your draw() method use: \code qglviewer::Vec screenPos = +camera()->projectedCoordinatesOf(myFrame.position()); +drawText((int)screenPos[0], (int)screenPos[1], "My Object"); +\endcode +See the screenCoordSystem +example for an illustration. + +Text is displayed only when textIsEnabled() (default). This mechanism allows the +user to conveniently remove all the displayed text with a single keyboard +shortcut. + +See also displayMessage() to drawText() for only a short amount of time. -/*! Modify the projection matrix so that drawing can be done directly with 2D screen coordinates. +Use renderText(x,y,z, text) instead if you want to draw a text located + at a specific 3D position instead of 2D screen coordinates (fixed size text, +facing the camera). -Once called, the \p x and \p y coordinates passed to \c glVertex are expressed in pixels screen -coordinates. The origin (0,0) is in the upper left corner of the widget by default. This follows -the Qt standards, so that you can directly use the \c pos() provided by for instance \c -QMouseEvent. Set \p upward to \c true to place the origin in the \e lower left corner, thus -following the OpenGL and mathematical standards. It is always possible to switch between the two +The \c GL_MODELVIEW and \c GL_PROJECTION matrices are not modified by this +method. +*/ +void QGLViewer::drawText(int x, int y, const QString &text, const QFont &fnt) { + if (!textIsEnabled()) + return; + + if (tileRegion_ != nullptr) { + renderText(int((x - tileRegion_->xMin) * width() / + (tileRegion_->xMax - tileRegion_->xMin)), + int((y - tileRegion_->yMin) * height() / + (tileRegion_->yMax - tileRegion_->yMin)), + text, scaledFont(fnt)); + } else + renderText(x, y, text, fnt); +} + +/*! Briefly displays a message in the lower left corner of the widget. +Convenient to provide feedback to the user. + +\p message is displayed during \p delay milliseconds (default is 2 seconds) +using drawText(). + +This method should not be called in draw(). If you want to display a text in +each draw(), use drawText() instead. + +If this method is called when a message is already displayed, the new message +replaces the old one. Use setTextIsEnabled() (default shortcut is '?') to enable +or disable text (and hence messages) display. */ +void QGLViewer::displayMessage(const QString &message, int delay) { + message_ = message; + displayMessage_ = true; + // Was set to single shot in defaultConstructor. + messageTimer_.start(delay); + if (textIsEnabled()) + update(); +} + +void QGLViewer::hideMessage() { + displayMessage_ = false; + if (textIsEnabled()) + update(); +} + +/*! Displays the averaged currentFPS() frame rate in the upper left corner of +the widget. + +update() should be called in a loop in order to have a meaningful value (this is +the case when you continuously move the camera using the mouse or when +animationIsStarted()). setAnimationPeriod(0) to make this loop as fast as +possible in order to reach and measure the maximum available frame rate. + +When FPSIsDisplayed() is \c true (default is \c false), this method is called by +postDraw() to display the currentFPS(). Use QApplication::setFont() to define +the font (see drawText()). */ +void QGLViewer::displayFPS() { + drawText(10, int(1.5 * ((QApplication::font().pixelSize() > 0) + ? QApplication::font().pixelSize() + : QApplication::font().pointSize())), + fpsString_); +} + +/*! Modify the projection matrix so that drawing can be done directly with 2D +screen coordinates. + +Once called, the \p x and \p y coordinates passed to \c glVertex are expressed +in pixels screen coordinates. The origin (0,0) is in the upper left corner of +the widget by default. This follows the Qt standards, so that you can directly +use the \c pos() provided by for instance \c QMouseEvent. Set \p upward to \c +true to place the origin in the \e lower left corner, thus following the OpenGL +and mathematical standards. It is always possible to switch between the two representations using \c newY = height() - \c y. -You need to call stopScreenCoordinatesSystem() at the end of the drawing block to restore the -previous camera matrix. +You need to call stopScreenCoordinatesSystem() at the end of the drawing block +to restore the previous camera matrix. -In practice, this method should be used in draw(). It sets an appropriate orthographic projection -matrix and then sets \c glMatrixMode to \c GL_MODELVIEW. +In practice, this method should be used in draw(). It sets an appropriate +orthographic projection matrix and then sets \c glMatrixMode to \c GL_MODELVIEW. See the screenCoordSystem, multiSelect and backgroundImage examples for an illustration. - -You may want to disable \c GL_LIGHTING, to enable \c GL_LINE_SMOOTH or \c GL_BLEND to draw when -this method is used. +href="../examples/contribs.html#backgroundImage">backgroundImage examples +for an illustration. + +You may want to disable \c GL_LIGHTING, to enable \c GL_LINE_SMOOTH or \c +GL_BLEND to draw when this method is used. + +If you want to link 2D drawings to 3D objects, use +qglviewer::Camera::projectedCoordinatesOf() to compute the 2D projection on +screen of a 3D point (see the screenCoordSystem example). See +also drawText(). + +In this mode, you should use z values that are in the [0.0, 1.0[ range (0.0 +corresponding to the near clipping plane and 1.0 being just beyond the far +clipping plane). This interval matches the values that can be read from the +z-buffer. Note that if you use the convenient \c glVertex2i() to provide +coordinates, the implicit 0.0 z coordinate will make your drawings appear \e on +\e top of the rest of the scene. */ +void QGLViewer::startScreenCoordinatesSystem(bool upward) const { + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + if (tileRegion_ != nullptr) + if (upward) + glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMin, + tileRegion_->yMax, 0.0, -1.0); + else + glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMax, + tileRegion_->yMin, 0.0, -1.0); + else if (upward) + glOrtho(0, width(), 0, height(), 0.0, -1.0); + else + glOrtho(0, width(), height(), 0, 0.0, -1.0); -If you want to link 2D drawings to 3D objects, use qglviewer::Camera::projectedCoordinatesOf() to -compute the 2D projection on screen of a 3D point (see the screenCoordSystem example). See also drawText(). + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); +} -In this mode, you should use z values that are in the [0.0, 1.0[ range (0.0 corresponding to the -near clipping plane and 1.0 being just beyond the far clipping plane). This interval matches the -values that can be read from the z-buffer. Note that if you use the convenient \c glVertex2i() to -provide coordinates, the implicit 0.0 z coordinate will make your drawings appear \e on \e top of -the rest of the scene. */ -void QGLViewer::startScreenCoordinatesSystem(bool upward) const -{ - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - if (tileRegion_ != NULL) - if (upward) - glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMin, tileRegion_->yMax, 0.0, -1.0); - else - glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMax, tileRegion_->yMin, 0.0, -1.0); - else - if (upward) - glOrtho(0, width(), 0, height(), 0.0, -1.0); - else - glOrtho(0, width(), height(), 0, 0.0, -1.0); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); -} - -/*! Stops the pixel coordinate drawing block started by startScreenCoordinatesSystem(). +/*! Stops the pixel coordinate drawing block started by +startScreenCoordinatesSystem(). The \c GL_MODELVIEW and \c GL_PROJECTION matrices modified in -startScreenCoordinatesSystem() are restored. \c glMatrixMode is set to \c GL_MODELVIEW. */ -void QGLViewer::stopScreenCoordinatesSystem() const -{ - glMatrixMode(GL_PROJECTION); - glPopMatrix(); +startScreenCoordinatesSystem() are restored. \c glMatrixMode is set to \c +GL_MODELVIEW. */ +void QGLViewer::stopScreenCoordinatesSystem() const { + glMatrixMode(GL_PROJECTION); + glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } /*! Overloading of the \c QObject method. If animationIsStarted(), calls animate() and draw(). */ -void QGLViewer::timerEvent(QTimerEvent *) -{ - if (animationIsStarted()) - { - animate(); - update(); - } +void QGLViewer::timerEvent(QTimerEvent *) { + if (animationIsStarted()) { + animate(); + update(); + } } /*! Starts the animation loop. See animationIsStarted(). */ -void QGLViewer::startAnimation() -{ - animationTimerId_ = startTimer(animationPeriod()); - animationStarted_ = true; +void QGLViewer::startAnimation() { + animationTimerId_ = startTimer(animationPeriod()); + animationStarted_ = true; } /*! Stops animation. See animationIsStarted(). */ -void QGLViewer::stopAnimation() -{ - animationStarted_ = false; - if (animationTimerId_ != 0) - killTimer(animationTimerId_); +void QGLViewer::stopAnimation() { + animationStarted_ = false; + if (animationTimerId_ != 0) + killTimer(animationTimerId_); } /*! Overloading of the \c QWidget method. -Saves the viewer state using saveStateToFile() and then calls QGLWidget::closeEvent(). */ -void QGLViewer::closeEvent(QCloseEvent *e) -{ - // When the user clicks on the window close (x) button: - // - If the viewer is a top level window, closeEvent is called and then saves to file. - // - Otherwise, nothing happen s:( - // When the user press the EXIT_VIEWER keyboard shortcut: - // - If the viewer is a top level window, saveStateToFile() is also called - // - Otherwise, closeEvent is NOT called and keyPressEvent does the job. +Saves the viewer state using saveStateToFile() and then calls +QOpenGLWidget::closeEvent(). */ +void QGLViewer::closeEvent(QCloseEvent *e) { + // When the user clicks on the window close (x) button: + // - If the viewer is a top level window, closeEvent is called and then saves + // to file. - Otherwise, nothing happen s:( When the user press the + // EXIT_VIEWER keyboard shortcut: - If the viewer is a top level window, + // saveStateToFile() is also called - Otherwise, closeEvent is NOT called and + // keyPressEvent does the job. - /* After tests: - E : Embedded widget - N : Widget created with new - C : closeEvent called - D : destructor called + /* After tests: + E : Embedded widget + N : Widget created with new + C : closeEvent called + D : destructor called - E N C D - y y - y n y - n y y - n n y y + E N C D + y y + y n y + n y y + n n y y - closeEvent is called iif the widget is NOT embedded. + closeEvent is called iif the widget is NOT embedded. - Destructor is called iif the widget is created on the stack - or if widget (resp. parent if embedded) is created with WDestructiveClose flag. + Destructor is called iif the widget is created on the stack + or if widget (resp. parent if embedded) is created with WDestructiveClose + flag. - closeEvent always before destructor. + closeEvent always before destructor. - Close using qApp->closeAllWindows or (x) is identical. - */ + Close using qApp->closeAllWindows or (x) is identical. + */ - // #CONNECTION# Also done for EXIT_VIEWER in keyPressEvent(). - saveStateToFile(); - QGLWidget::closeEvent(e); + // #CONNECTION# Also done for EXIT_VIEWER in keyPressEvent(). + saveStateToFile(); + QOpenGLWidget::closeEvent(e); } /*! Simple wrapper method: calls \c select(event->pos()). -Emits \c pointSelected(e) which is useful only if you rely on the Qt signal-slot mechanism and you -did not overload QGLViewer. If you choose to derive your own viewer class, simply overload -select() (or probably simply drawWithNames(), see the select -example) to implement your selection mechanism. +Emits \c pointSelected(e) which is useful only if you rely on the Qt signal-slot +mechanism and you did not overload QGLViewer. If you choose to derive your own +viewer class, simply overload select() (or probably simply drawWithNames(), see +the select example) to implement your +selection mechanism. -This method is called when you use the QGLViewer::SELECT mouse binding(s) (default is Shift + left -button). Use setMouseBinding() to change this. */ -void QGLViewer::select(const QMouseEvent* event) -{ - // For those who don't derive but rather rely on the signal-slot mechanism. - Q_EMIT pointSelected(event); - select(event->pos()); +This method is called when you use the QGLViewer::SELECT mouse binding(s) +(default is Shift + left button). Use setMouseBinding() to change this. */ +void QGLViewer::select(const QMouseEvent *event) { + // For those who don't derive but rather rely on the signal-slot mechanism. + Q_EMIT pointSelected(event); + select(event->pos()); } /*! This method performs a selection in the scene from pixel coordinates. -It is called when the user clicks on the QGLViewer::SELECT QGLViewer::ClickAction binded button(s) -(default is Shift + LeftButton). +It is called when the user clicks on the QGLViewer::SELECT +QGLViewer::ClickAction binded button(s) (default is Shift + LeftButton). This template method successively calls four other methods: \code @@ -953,99 +1065,113 @@ endSelection(point); postSelection(point); \endcode -The default implementation of these methods is as follows (see the methods' documentation for -more details): +The default implementation of these methods is as follows (see the methods' +documentation for more details): -\arg beginSelection() sets the \c GL_SELECT mode with the appropriate picking matrices. A -rectangular frustum (of size defined by selectRegionWidth() and selectRegionHeight()) centered on -\p point is created. +\arg beginSelection() sets the \c GL_SELECT mode with the appropriate picking +matrices. A rectangular frustum (of size defined by selectRegionWidth() and +selectRegionHeight()) centered on \p point is created. -\arg drawWithNames() is empty and should be overloaded. It draws each selectable object of the -scene, enclosed by calls to \c glPushName() / \c glPopName() to tag the object with an integer id. +\arg drawWithNames() is empty and should be overloaded. It draws each selectable +object of the scene, enclosed by calls to \c glPushName() / \c glPopName() to +tag the object with an integer id. -\arg endSelection() then restores \c GL_RENDER mode and analyzes the selectBuffer() to set in -selectedName() the id of the object that was drawn in the region. If several object are in the -region, the closest one in the depth buffer is chosen. If no object has been drawn under cursor, -selectedName() is set to -1. +\arg endSelection() then restores \c GL_RENDER mode and analyzes the +selectBuffer() to set in selectedName() the id of the object that was drawn in +the region. If several object are in the region, the closest one in the depth +buffer is chosen. If no object has been drawn under cursor, selectedName() is +set to -1. -\arg postSelection() is empty and can be overloaded for possible signal/display/interface update. +\arg postSelection() is empty and can be overloaded for possible +signal/display/interface update. See the \c glSelectBuffer() man page for details on this \c GL_SELECT mechanism. -This default implementation is quite limited: only the closer object is selected, and only one -level of names can be pushed. However, this reveals sufficient in many cases and you usually only -have to overload drawWithNames() to implement a simple object selection process. See the select example for an illustration. -If you need a more complex selection process (such as a point, edge or triangle selection, which -is easier with a 2 or 3 levels selectBuffer() heap, and which requires a finer depth sorting to -privilege point over edge and edges over triangles), overload the endSelection() method. Use -setSelectRegionWidth(), setSelectRegionHeight() and setSelectBufferSize() to tune the select -buffer configuration. See the multiSelect example for -an illustration. - -\p point is the center pixel (origin in the upper left corner) of the selection region. Use -qglviewer::Camera::convertClickToLine() to transform these coordinates in a 3D ray if you want to -perform an analytical intersection. - -\attention \c GL_SELECT mode seems to report wrong results when used in conjunction with backface -culling. If you encounter problems try to \c glDisable(GL_CULL_FACE). */ -void QGLViewer::select(const QPoint& point) -{ - beginSelection(point); - drawWithNames(); - endSelection(point); - postSelection(point); -} - -/*! This method should prepare the selection. It is called by select() before drawWithNames(). - -The default implementation uses the \c GL_SELECT mode to perform a selection. It uses -selectBuffer() and selectBufferSize() to define a \c glSelectBuffer(). The \c GL_PROJECTION is then -set using \c gluPickMatrix(), with a window selection size defined by selectRegionWidth() and -selectRegionHeight(). Finally, the \c GL_MODELVIEW matrix is set to the world coordinate system -using qglviewer::Camera::loadModelViewMatrix(). See the gluPickMatrix() documentation for details. - -You should not need to redefine this method (if you use the \c GL_SELECT mode to perform your -selection), since this code is fairly classical and can be tuned. You are more likely to overload -endSelection() if you want to use a more complex select buffer structure. */ -void QGLViewer::beginSelection(const QPoint& point) -{ - // Make OpenGL context current (may be needed with several viewers ?) - makeCurrent(); - - // Prepare the selection mode - glSelectBuffer(selectBufferSize(), selectBuffer()); - glRenderMode(GL_SELECT); - glInitNames(); - - // Loads the matrices - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - static GLint viewport[4]; - camera()->getViewport(viewport); - gluPickMatrix(point.x(), point.y(), selectRegionWidth(), selectRegionHeight(), viewport); - - // loadProjectionMatrix() first resets the GL_PROJECTION matrix with a glLoadIdentity(). - // The false parameter prevents this and hence multiplies the matrices. - camera()->loadProjectionMatrix(false); - // Reset the original (world coordinates) modelview matrix - camera()->loadModelViewMatrix(); -} - -/*! This method is called by select() after scene elements were drawn by drawWithNames(). It should -analyze the selection result to determine which object is actually selected. - -The default implementation relies on \c GL_SELECT mode (see beginSelection()). It assumes that -names were pushed and popped in drawWithNames(), and analyzes the selectBuffer() to find the name -that corresponds to the closer (z min) object. It then setSelectedName() to this value, or to -1 if -the selectBuffer() is empty (no object drawn in selection region). Use selectedName() (probably in -the postSelection() method) to retrieve this value and update your data structure accordingly. - -This default implementation, although sufficient for many cases is however limited and you may have -to overload this method. This will be the case if drawWithNames() uses several push levels in the -name heap. A more precise depth selection, for instance privileging points over edges and -triangles to avoid z precision problems, will also require an overloading. A typical implementation +If you need a more complex selection process (such as a point, edge or triangle +selection, which is easier with a 2 or 3 levels selectBuffer() heap, and which +requires a finer depth sorting to privilege point over edge and edges over +triangles), overload the endSelection() method. Use setSelectRegionWidth(), +setSelectRegionHeight() and setSelectBufferSize() to tune the select buffer +configuration. See the multiSelect +example for an illustration. + +\p point is the center pixel (origin in the upper left corner) of the selection +region. Use qglviewer::Camera::convertClickToLine() to transform these +coordinates in a 3D ray if you want to perform an analytical intersection. + +\attention \c GL_SELECT mode seems to report wrong results when used in +conjunction with backface culling. If you encounter problems try to \c +glDisable(GL_CULL_FACE). */ +void QGLViewer::select(const QPoint &point) { + beginSelection(point); + drawWithNames(); + endSelection(point); + postSelection(point); +} + +/*! This method should prepare the selection. It is called by select() before +drawWithNames(). + +The default implementation uses the \c GL_SELECT mode to perform a selection. It +uses selectBuffer() and selectBufferSize() to define a \c glSelectBuffer(). The +\c GL_PROJECTION is then set using \c gluPickMatrix(), with a window selection +size defined by selectRegionWidth() and selectRegionHeight(). Finally, the \c +GL_MODELVIEW matrix is set to the world coordinate system using +qglviewer::Camera::loadModelViewMatrix(). See the gluPickMatrix() documentation +for details. + +You should not need to redefine this method (if you use the \c GL_SELECT mode to +perform your selection), since this code is fairly classical and can be tuned. +You are more likely to overload endSelection() if you want to use a more complex +select buffer structure. */ +void QGLViewer::beginSelection(const QPoint &point) { + // Make OpenGL context current (may be needed with several viewers ?) + makeCurrent(); + + // Prepare the selection mode + glSelectBuffer(selectBufferSize(), selectBuffer()); + glRenderMode(GL_SELECT); + glInitNames(); + + // Loads the matrices + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + static GLint viewport[4]; + camera()->getViewport(viewport); + gluPickMatrix(point.x(), point.y(), selectRegionWidth(), selectRegionHeight(), + viewport); + + // loadProjectionMatrix() first resets the GL_PROJECTION matrix with a + // glLoadIdentity(). The false parameter prevents this and hence multiplies + // the matrices. + camera()->loadProjectionMatrix(false); + // Reset the original (world coordinates) modelview matrix + camera()->loadModelViewMatrix(); +} + +/*! This method is called by select() after scene elements were drawn by +drawWithNames(). It should analyze the selection result to determine which +object is actually selected. + +The default implementation relies on \c GL_SELECT mode (see beginSelection()). +It assumes that names were pushed and popped in drawWithNames(), and analyzes +the selectBuffer() to find the name that corresponds to the closer (z min) +object. It then setSelectedName() to this value, or to -1 if the selectBuffer() +is empty (no object drawn in selection region). Use selectedName() (probably in +the postSelection() method) to retrieve this value and update your data +structure accordingly. + +This default implementation, although sufficient for many cases is however +limited and you may have to overload this method. This will be the case if +drawWithNames() uses several push levels in the name heap. A more precise depth +selection, for instance privileging points over edges and triangles to avoid z +precision problems, will also require an overloading. A typical implementation will look like: \code glFlush(); @@ -1069,202 +1195,206 @@ setSelectedName((selectBuffer())[i*4+3]) See the multiSelect example for a multi-object selection implementation of this method. */ -void QGLViewer::endSelection(const QPoint& point) -{ - Q_UNUSED(point); - - // Flush GL buffers - glFlush(); - - // Get the number of objects that were seen through the pick matrix frustum. Reset GL_RENDER mode. - GLint nbHits = glRenderMode(GL_RENDER); - - if (nbHits <= 0) - setSelectedName(-1); - else - { - // Interpret results: each object created 4 values in the selectBuffer(). - // selectBuffer[4*i+1] is the object minimum depth value, while selectBuffer[4*i+3] is the id pushed on the stack. - // Of all the objects that were projected in the pick region, we select the closest one (zMin comparison). - // This code needs to be modified if you use several stack levels. See glSelectBuffer() man page. - GLuint zMin = (selectBuffer())[1]; - setSelectedName(int((selectBuffer())[3])); - for (int i=1; iinterpolateToZoomOnPixel(e->pos()); - break; - case ZOOM_TO_FIT : - camera()->interpolateToFitScene(); - break; - case SELECT : - select(e); - update(); - break; - case RAP_FROM_PIXEL : - if (! camera()->setPivotPointFromPixel(e->pos())) - camera()->setPivotPoint(sceneCenter()); - setVisualHintsMask(1); - update(); - break; - case RAP_IS_CENTER : - camera()->setPivotPoint(sceneCenter()); - setVisualHintsMask(1); - update(); - break; - case CENTER_FRAME : - if (manipulatedFrame()) - manipulatedFrame()->projectOnLine(camera()->position(), camera()->viewDirection()); - break; - case CENTER_SCENE : - camera()->centerScene(); - break; - case SHOW_ENTIRE_SCENE : - camera()->showEntireScene(); - break; - case ALIGN_FRAME : - if (manipulatedFrame()) - manipulatedFrame()->alignWithFrame(camera()->frame()); - break; - case ALIGN_CAMERA : - Frame * frame = new Frame(); - frame->setTranslation(camera()->pivotPoint()); - camera()->frame()->alignWithFrame(frame, true); - delete frame; - break; - } +void QGLViewer::setSelectBufferSize(int size) { + if (selectBuffer_) + delete[] selectBuffer_; + selectBufferSize_ = size; + selectBuffer_ = new GLuint[selectBufferSize()]; +} + +static QString mouseButtonsString(Qt::MouseButtons b) { + QString result(""); + bool addAmpersand = false; + if (b & Qt::LeftButton) { + result += QGLViewer::tr("Left", "left mouse button"); + addAmpersand = true; + } + if (b & Qt::MidButton) { + if (addAmpersand) + result += " & "; + result += QGLViewer::tr("Middle", "middle mouse button"); + addAmpersand = true; + } + if (b & Qt::RightButton) { + if (addAmpersand) + result += " & "; + result += QGLViewer::tr("Right", "right mouse button"); + } + return result; +} + +void QGLViewer::performClickAction(ClickAction ca, const QMouseEvent *const e) { + // Note: action that need it should call update(). + switch (ca) { + // # CONNECTION setMouseBinding prevents adding NO_CLICK_ACTION in + // clickBinding_ This case should hence not be possible. Prevents unused case + // warning. + case NO_CLICK_ACTION: + break; + case ZOOM_ON_PIXEL: + camera()->interpolateToZoomOnPixel(e->pos()); + break; + case ZOOM_TO_FIT: + camera()->interpolateToFitScene(); + break; + case SELECT: + select(e); + update(); + break; + case RAP_FROM_PIXEL: + makeCurrent(); + if (!camera()->setPivotPointFromPixel(e->pos())) + camera()->setPivotPoint(sceneCenter()); + setVisualHintsMask(1); + update(); + break; + case RAP_IS_CENTER: + camera()->setPivotPoint(sceneCenter()); + setVisualHintsMask(1); + update(); + break; + case CENTER_FRAME: + if (manipulatedFrame()) + manipulatedFrame()->projectOnLine(camera()->position(), + camera()->viewDirection()); + break; + case CENTER_SCENE: + camera()->centerScene(); + break; + case SHOW_ENTIRE_SCENE: + camera()->showEntireScene(); + break; + case ALIGN_FRAME: + if (manipulatedFrame()) + manipulatedFrame()->alignWithFrame(camera()->frame()); + break; + case ALIGN_CAMERA: + Frame *frame = new Frame(); + frame->setTranslation(camera()->pivotPoint()); + camera()->frame()->alignWithFrame(frame, true); + delete frame; + break; + } } /*! Overloading of the \c QWidget method. When the user clicks on the mouse: -\arg if a mouseGrabber() is defined, qglviewer::MouseGrabber::mousePressEvent() is called, -\arg otherwise, the camera() or the manipulatedFrame() interprets the mouse displacements, -depending on mouse bindings. - -Mouse bindings customization can be achieved using setMouseBinding() and setWheelBinding(). See the -mouse page for a complete description of mouse bindings. - -See the mouseMoveEvent() documentation for an example of more complex mouse behavior customization -using overloading. - -\note When the mouseGrabber() is a manipulatedFrame(), the modifier keys are not taken into -account. This allows for a direct manipulation of the manipulatedFrame() when the mouse hovers, -which is probably what is expected. */ -void QGLViewer::mousePressEvent(QMouseEvent* e) -{ - //#CONNECTION# mouseDoubleClickEvent has the same structure - //#CONNECTION# mouseString() concatenates bindings description in inverse order. - ClickBindingPrivate cbp(e->modifiers(), e->button(), false, (Qt::MouseButtons)(e->buttons() & ~(e->button())), currentlyPressedKey_); - - if (clickBinding_.contains(cbp)) { - performClickAction(clickBinding_[cbp], e); - } else - if (mouseGrabber()) - { - if (mouseGrabberIsAManipulatedFrame_) - { - for (QMap::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it!=end; ++it) - if ((it.value().handler == FRAME) && (it.key().button == e->button())) - { - ManipulatedFrame* mf = dynamic_cast(mouseGrabber()); - if (mouseGrabberIsAManipulatedCameraFrame_) - { - mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint); - mf->ManipulatedFrame::mousePressEvent(e, camera()); - } - else - { - mf->startAction(it.value().action, it.value().withConstraint); - mf->mousePressEvent(e, camera()); - } - break; - } - } - else - mouseGrabber()->mousePressEvent(e, camera()); - update(); - } - else - { - //#CONNECTION# wheelEvent has the same structure - const MouseBindingPrivate mbp(e->modifiers(), e->button(), currentlyPressedKey_); - - if (mouseBinding_.contains(mbp)) - { - MouseActionPrivate map = mouseBinding_[mbp]; - switch (map.handler) - { - case CAMERA : - camera()->frame()->startAction(map.action, map.withConstraint); - camera()->frame()->mousePressEvent(e, camera()); - break; - case FRAME : - if (manipulatedFrame()) - { - if (manipulatedFrameIsACamera_) - { - manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint); - manipulatedFrame()->ManipulatedFrame::mousePressEvent(e, camera()); - } - else - { - manipulatedFrame()->startAction(map.action, map.withConstraint); - manipulatedFrame()->mousePressEvent(e, camera()); - } - } - break; - } - if (map.action == SCREEN_ROTATE) - // Display visual hint line - update(); - } - else - e->ignore(); - } +\arg if a mouseGrabber() is defined, qglviewer::MouseGrabber::mousePressEvent() +is called, \arg otherwise, the camera() or the manipulatedFrame() interprets the +mouse displacements, depending on mouse bindings. + +Mouse bindings customization can be achieved using setMouseBinding() and +setWheelBinding(). See the mouse page for a complete +description of mouse bindings. + +See the mouseMoveEvent() documentation for an example of more complex mouse +behavior customization using overloading. + +\note When the mouseGrabber() is a manipulatedFrame(), the modifier keys are not +taken into account. This allows for a direct manipulation of the +manipulatedFrame() when the mouse hovers, which is probably what is expected. */ +void QGLViewer::mousePressEvent(QMouseEvent *e) { + //#CONNECTION# mouseDoubleClickEvent has the same structure + //#CONNECTION# mouseString() concatenates bindings description in inverse + // order. + ClickBindingPrivate cbp(e->modifiers(), e->button(), false, + static_cast((e->buttons() & ~(e->button()))), + currentlyPressedKey_); + + if (clickBinding_.contains(cbp)) { + performClickAction(clickBinding_[cbp], e); + } else if (mouseGrabber()) { + if (mouseGrabberIsAManipulatedFrame_) { + for (QMap::ConstIterator + it = mouseBinding_.begin(), + end = mouseBinding_.end(); + it != end; ++it) + if ((it.value().handler == FRAME) && (it.key().button == e->button())) { + ManipulatedFrame *mf = + dynamic_cast(mouseGrabber()); + if (mouseGrabberIsAManipulatedCameraFrame_) { + mf->ManipulatedFrame::startAction(it.value().action, + it.value().withConstraint); + mf->ManipulatedFrame::mousePressEvent(e, camera()); + } else { + mf->startAction(it.value().action, it.value().withConstraint); + mf->mousePressEvent(e, camera()); + } + break; + } + } else + mouseGrabber()->mousePressEvent(e, camera()); + update(); + } else { + //#CONNECTION# wheelEvent has the same structure + const MouseBindingPrivate mbp(e->modifiers(), e->button(), + currentlyPressedKey_); + + if (mouseBinding_.contains(mbp)) { + MouseActionPrivate map = mouseBinding_[mbp]; + switch (map.handler) { + case CAMERA: + camera()->frame()->startAction(map.action, map.withConstraint); + camera()->frame()->mousePressEvent(e, camera()); + break; + case FRAME: + if (manipulatedFrame()) { + if (manipulatedFrameIsACamera_) { + manipulatedFrame()->ManipulatedFrame::startAction( + map.action, map.withConstraint); + manipulatedFrame()->ManipulatedFrame::mousePressEvent(e, camera()); + } else { + manipulatedFrame()->startAction(map.action, map.withConstraint); + manipulatedFrame()->mousePressEvent(e, camera()); + } + } + break; + } + if (map.action == SCREEN_ROTATE) + // Display visual hint line + update(); + } else + e->ignore(); + } } /*! Overloading of the \c QWidget method. -Mouse move event is sent to the mouseGrabber() (if any) or to the camera() or the -manipulatedFrame(), depending on mouse bindings (see setMouseBinding()). +Mouse move event is sent to the mouseGrabber() (if any) or to the camera() or +the manipulatedFrame(), depending on mouse bindings (see setMouseBinding()). If you want to define your own mouse behavior, do something like this: \code @@ -1293,232 +1423,204 @@ else QGLViewer::mouseReleaseEvent(e); } \endcode */ -void QGLViewer::mouseMoveEvent(QMouseEvent* e) -{ - if (mouseGrabber()) - { - mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera()); - if (mouseGrabber()->grabsMouse()) - if (mouseGrabberIsAManipulatedCameraFrame_) - (dynamic_cast(mouseGrabber()))->ManipulatedFrame::mouseMoveEvent(e, camera()); - else - mouseGrabber()->mouseMoveEvent(e, camera()); - else - setMouseGrabber(NULL); - update(); - } - - if (!mouseGrabber()) - { - //#CONNECTION# mouseReleaseEvent has the same structure - if (camera()->frame()->isManipulated()) - { - camera()->frame()->mouseMoveEvent(e, camera()); - // #CONNECTION# manipulatedCameraFrame::mouseMoveEvent specific if at the beginning - if (camera()->frame()->action_ == ZOOM_ON_REGION) - update(); - } - else // ! - if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated())) - if (manipulatedFrameIsACamera_) - manipulatedFrame()->ManipulatedFrame::mouseMoveEvent(e, camera()); - else - manipulatedFrame()->mouseMoveEvent(e, camera()); - else - if (hasMouseTracking()) - { - Q_FOREACH (MouseGrabber* mg, MouseGrabber::MouseGrabberPool()) - { - mg->checkIfGrabsMouse(e->x(), e->y(), camera()); - if (mg->grabsMouse()) - { - setMouseGrabber(mg); - // Check that MouseGrabber is not disabled - if (mouseGrabber() == mg) - { - update(); - break; - } - } - } - } - } +void QGLViewer::mouseMoveEvent(QMouseEvent *e) { + if (mouseGrabber()) { + mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera()); + if (mouseGrabber()->grabsMouse()) + if (mouseGrabberIsAManipulatedCameraFrame_) + (dynamic_cast(mouseGrabber())) + ->ManipulatedFrame::mouseMoveEvent(e, camera()); + else + mouseGrabber()->mouseMoveEvent(e, camera()); + else + setMouseGrabber(nullptr); + update(); + } + + if (!mouseGrabber()) { + //#CONNECTION# mouseReleaseEvent has the same structure + if (camera()->frame()->isManipulated()) { + camera()->frame()->mouseMoveEvent(e, camera()); + // #CONNECTION# manipulatedCameraFrame::mouseMoveEvent specific if at the + // beginning + if (camera()->frame()->action_ == ZOOM_ON_REGION) + update(); + } else // ! + if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated())) + if (manipulatedFrameIsACamera_) + manipulatedFrame()->ManipulatedFrame::mouseMoveEvent(e, camera()); + else + manipulatedFrame()->mouseMoveEvent(e, camera()); + else if (hasMouseTracking()) { + Q_FOREACH (MouseGrabber *mg, MouseGrabber::MouseGrabberPool()) { + mg->checkIfGrabsMouse(e->x(), e->y(), camera()); + if (mg->grabsMouse()) { + setMouseGrabber(mg); + // Check that MouseGrabber is not disabled + if (mouseGrabber() == mg) { + update(); + break; + } + } + } + } + } } /*! Overloading of the \c QWidget method. -Calls the mouseGrabber(), camera() or manipulatedFrame \c mouseReleaseEvent method. - -See the mouseMoveEvent() documentation for an example of mouse behavior customization. */ -void QGLViewer::mouseReleaseEvent(QMouseEvent* e) -{ - if (mouseGrabber()) - { - if (mouseGrabberIsAManipulatedCameraFrame_) - (dynamic_cast(mouseGrabber()))->ManipulatedFrame::mouseReleaseEvent(e, camera()); - else - mouseGrabber()->mouseReleaseEvent(e, camera()); - mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera()); - if (!(mouseGrabber()->grabsMouse())) - setMouseGrabber(NULL); - // update(); - } - else - //#CONNECTION# mouseMoveEvent has the same structure - if (camera()->frame()->isManipulated()) - { - camera()->frame()->mouseReleaseEvent(e, camera()); - } - else - if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated())) - { - if (manipulatedFrameIsACamera_) - manipulatedFrame()->ManipulatedFrame::mouseReleaseEvent(e, camera()); - else - manipulatedFrame()->mouseReleaseEvent(e, camera()); - } - else - e->ignore(); - - // Not absolutely needed (see above commented code for the optimal version), but may reveal - // useful for specific applications. - update(); +Calls the mouseGrabber(), camera() or manipulatedFrame \c mouseReleaseEvent +method. + +See the mouseMoveEvent() documentation for an example of mouse behavior +customization. */ +void QGLViewer::mouseReleaseEvent(QMouseEvent *e) { + if (mouseGrabber()) { + if (mouseGrabberIsAManipulatedCameraFrame_) + (dynamic_cast(mouseGrabber())) + ->ManipulatedFrame::mouseReleaseEvent(e, camera()); + else + mouseGrabber()->mouseReleaseEvent(e, camera()); + mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera()); + if (!(mouseGrabber()->grabsMouse())) + setMouseGrabber(nullptr); + // update(); + } else + //#CONNECTION# mouseMoveEvent has the same structure + if (camera()->frame()->isManipulated()) { + camera()->frame()->mouseReleaseEvent(e, camera()); + } else if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated())) { + if (manipulatedFrameIsACamera_) + manipulatedFrame()->ManipulatedFrame::mouseReleaseEvent(e, camera()); + else + manipulatedFrame()->mouseReleaseEvent(e, camera()); + } else + e->ignore(); + + // Not absolutely needed (see above commented code for the optimal version), + // but may reveal useful for specific applications. + update(); } /*! Overloading of the \c QWidget method. -If defined, the wheel event is sent to the mouseGrabber(). It is otherwise sent according to wheel -bindings (see setWheelBinding()). */ -void QGLViewer::wheelEvent(QWheelEvent* e) -{ - if (mouseGrabber()) - { - if (mouseGrabberIsAManipulatedFrame_) - { - for (QMap::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it) - if (it.value().handler == FRAME) - { - ManipulatedFrame* mf = dynamic_cast(mouseGrabber()); - if (mouseGrabberIsAManipulatedCameraFrame_) - { - mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint); - mf->ManipulatedFrame::wheelEvent(e, camera()); - } - else - { - mf->startAction(it.value().action, it.value().withConstraint); - mf->wheelEvent(e, camera()); - } - break; - } - } - else - mouseGrabber()->wheelEvent(e, camera()); - update(); - } - else - { - //#CONNECTION# mousePressEvent has the same structure - WheelBindingPrivate wbp(e->modifiers(), currentlyPressedKey_); - - if (wheelBinding_.contains(wbp)) - { - MouseActionPrivate map = wheelBinding_[wbp]; - switch (map.handler) - { - case CAMERA : - camera()->frame()->startAction(map.action, map.withConstraint); - camera()->frame()->wheelEvent(e, camera()); - break; - case FRAME : - if (manipulatedFrame()) { - if (manipulatedFrameIsACamera_) - { - manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint); - manipulatedFrame()->ManipulatedFrame::wheelEvent(e, camera()); - } - else - { - manipulatedFrame()->startAction(map.action, map.withConstraint); - manipulatedFrame()->wheelEvent(e, camera()); - } - } - break; - } - } - else - e->ignore(); - } +If defined, the wheel event is sent to the mouseGrabber(). It is otherwise sent +according to wheel bindings (see setWheelBinding()). */ +void QGLViewer::wheelEvent(QWheelEvent *e) { + if (mouseGrabber()) { + if (mouseGrabberIsAManipulatedFrame_) { + for (QMap::ConstIterator + it = wheelBinding_.begin(), + end = wheelBinding_.end(); + it != end; ++it) + if (it.value().handler == FRAME) { + ManipulatedFrame *mf = + dynamic_cast(mouseGrabber()); + if (mouseGrabberIsAManipulatedCameraFrame_) { + mf->ManipulatedFrame::startAction(it.value().action, + it.value().withConstraint); + mf->ManipulatedFrame::wheelEvent(e, camera()); + } else { + mf->startAction(it.value().action, it.value().withConstraint); + mf->wheelEvent(e, camera()); + } + break; + } + } else + mouseGrabber()->wheelEvent(e, camera()); + update(); + } else { + //#CONNECTION# mousePressEvent has the same structure + WheelBindingPrivate wbp(e->modifiers(), currentlyPressedKey_); + + if (wheelBinding_.contains(wbp)) { + MouseActionPrivate map = wheelBinding_[wbp]; + switch (map.handler) { + case CAMERA: + camera()->frame()->startAction(map.action, map.withConstraint); + camera()->frame()->wheelEvent(e, camera()); + break; + case FRAME: + if (manipulatedFrame()) { + if (manipulatedFrameIsACamera_) { + manipulatedFrame()->ManipulatedFrame::startAction( + map.action, map.withConstraint); + manipulatedFrame()->ManipulatedFrame::wheelEvent(e, camera()); + } else { + manipulatedFrame()->startAction(map.action, map.withConstraint); + manipulatedFrame()->wheelEvent(e, camera()); + } + } + break; + } + } else + e->ignore(); + } } /*! Overloading of the \c QWidget method. -The behavior of the mouse double click depends on the mouse binding. See setMouseBinding() and the -mouse page. */ -void QGLViewer::mouseDoubleClickEvent(QMouseEvent* e) -{ - //#CONNECTION# mousePressEvent has the same structure - ClickBindingPrivate cbp(e->modifiers(), e->button(), true, (Qt::MouseButtons)(e->buttons() & ~(e->button())), currentlyPressedKey_); - if (clickBinding_.contains(cbp)) - performClickAction(clickBinding_[cbp], e); - else - if (mouseGrabber()) - mouseGrabber()->mouseDoubleClickEvent(e, camera()); - else - e->ignore(); +The behavior of the mouse double click depends on the mouse binding. See +setMouseBinding() and the mouse page. */ +void QGLViewer::mouseDoubleClickEvent(QMouseEvent *e) { + //#CONNECTION# mousePressEvent has the same structure + ClickBindingPrivate cbp(e->modifiers(), e->button(), true, + static_cast(e->buttons() & ~(e->button())), + currentlyPressedKey_); + if (clickBinding_.contains(cbp)) + performClickAction(clickBinding_[cbp], e); + else if (mouseGrabber()) + mouseGrabber()->mouseDoubleClickEvent(e, camera()); + else + e->ignore(); } /*! Sets the state of displaysInStereo(). See also toggleStereoDisplay(). -First checks that the display is able to handle stereovision using QGLWidget::format(). Opens a -warning message box in case of failure. Emits the stereoChanged() signal otherwise. */ -void QGLViewer::setStereoDisplay(bool stereo) -{ - if (format().stereo()) - { - stereo_ = stereo; - if (!displaysInStereo()) - { - glDrawBuffer(GL_BACK_LEFT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDrawBuffer(GL_BACK_RIGHT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - Q_EMIT stereoChanged(stereo_); - - update(); - } - else - if (stereo) - QMessageBox::warning(this, tr("Stereo not supported", "Message box window title"), tr("Stereo is not supported on this display.")); - else - stereo_ = false; +First checks that the display is able to handle stereovision using +QOpenGLWidget::format(). Opens a warning message box in case of failure. Emits +the stereoChanged() signal otherwise. */ +void QGLViewer::setStereoDisplay(bool stereo) { + if (format().stereo()) { + stereo_ = stereo; + if (!displaysInStereo()) { + glDrawBuffer(GL_BACK_LEFT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDrawBuffer(GL_BACK_RIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + Q_EMIT stereoChanged(stereo_); + + update(); + } else if (stereo) + QMessageBox::warning(this, + tr("Stereo not supported", "Message box window title"), + tr("Stereo is not supported on this display.")); + else + stereo_ = false; } /*! Sets the isFullScreen() state. -If the QGLViewer is embedded in an other QWidget (see QWidget::topLevelWidget()), this widget is -displayed in full screen instead. */ -void QGLViewer::setFullScreen(bool fullScreen) -{ - if (fullScreen_ == fullScreen) return; +If the QGLViewer is embedded in an other QWidget (see +QWidget::topLevelWidget()), this widget is displayed in full screen instead. */ +void QGLViewer::setFullScreen(bool fullScreen) { + if (fullScreen_ == fullScreen) + return; - fullScreen_ = fullScreen; + fullScreen_ = fullScreen; - QWidget* tlw = topLevelWidget(); + QWidget *tlw = topLevelWidget(); - if (isFullScreen()) - { - prevPos_ = topLevelWidget()->pos(); - tlw->showFullScreen(); - tlw->move(0,0); - } - else - { - tlw->showNormal(); - tlw->move(prevPos_); - } + if (isFullScreen()) { + prevPos_ = topLevelWidget()->pos(); + tlw->showFullScreen(); + tlw->move(0, 0); + } else { + tlw->showNormal(); + tlw->move(prevPos_); + } } /*! Directly defines the mouseGrabber(). @@ -1526,681 +1628,811 @@ void QGLViewer::setFullScreen(bool fullScreen) You should not call this method directly as it bypasses the qglviewer::MouseGrabber::checkIfGrabsMouse() test performed by mouseMoveEvent(). -If the MouseGrabber is disabled (see mouseGrabberIsEnabled()), this method silently does nothing. */ -void QGLViewer::setMouseGrabber(MouseGrabber* mouseGrabber) -{ - if (!mouseGrabberIsEnabled(mouseGrabber)) - return; +If the MouseGrabber is disabled (see mouseGrabberIsEnabled()), this method +silently does nothing. */ +void QGLViewer::setMouseGrabber(MouseGrabber *mouseGrabber) { + if (!mouseGrabberIsEnabled(mouseGrabber)) + return; - mouseGrabber_ = mouseGrabber; + mouseGrabber_ = mouseGrabber; - mouseGrabberIsAManipulatedFrame_ = (dynamic_cast(mouseGrabber) != NULL); - mouseGrabberIsAManipulatedCameraFrame_ = ((dynamic_cast(mouseGrabber) != NULL) && - (mouseGrabber != camera()->frame())); - Q_EMIT mouseGrabberChanged(mouseGrabber); + mouseGrabberIsAManipulatedFrame_ = + (dynamic_cast(mouseGrabber) != nullptr); + mouseGrabberIsAManipulatedCameraFrame_ = + ((dynamic_cast(mouseGrabber) != nullptr) && + (mouseGrabber != camera()->frame())); + Q_EMIT mouseGrabberChanged(mouseGrabber); } /*! Sets the mouseGrabberIsEnabled() state. */ -void QGLViewer::setMouseGrabberIsEnabled(const qglviewer::MouseGrabber* const mouseGrabber, bool enabled) -{ - if (enabled) - disabledMouseGrabbers_.remove(reinterpret_cast(mouseGrabber)); - else - disabledMouseGrabbers_[reinterpret_cast(mouseGrabber)]; +void QGLViewer::setMouseGrabberIsEnabled( + const qglviewer::MouseGrabber *const mouseGrabber, bool enabled) { + if (enabled) + disabledMouseGrabbers_.remove(reinterpret_cast(mouseGrabber)); + else + disabledMouseGrabbers_[reinterpret_cast(mouseGrabber)]; +} + +QString QGLViewer::mouseActionString(QGLViewer::MouseAction ma) { + switch (ma) { + case QGLViewer::NO_MOUSE_ACTION: + return QString(); + case QGLViewer::ROTATE: + return QGLViewer::tr("Rotates", "ROTATE mouse action"); + case QGLViewer::ZOOM: + return QGLViewer::tr("Zooms", "ZOOM mouse action"); + case QGLViewer::TRANSLATE: + return QGLViewer::tr("Translates", "TRANSLATE mouse action"); + case QGLViewer::MOVE_FORWARD: + return QGLViewer::tr("Moves forward", "MOVE_FORWARD mouse action"); + case QGLViewer::LOOK_AROUND: + return QGLViewer::tr("Looks around", "LOOK_AROUND mouse action"); + case QGLViewer::MOVE_BACKWARD: + return QGLViewer::tr("Moves backward", "MOVE_BACKWARD mouse action"); + case QGLViewer::SCREEN_ROTATE: + return QGLViewer::tr("Rotates in screen plane", + "SCREEN_ROTATE mouse action"); + case QGLViewer::ROLL: + return QGLViewer::tr("Rolls", "ROLL mouse action"); + case QGLViewer::DRIVE: + return QGLViewer::tr("Drives", "DRIVE mouse action"); + case QGLViewer::SCREEN_TRANSLATE: + return QGLViewer::tr("Horizontally/Vertically translates", + "SCREEN_TRANSLATE mouse action"); + case QGLViewer::ZOOM_ON_REGION: + return QGLViewer::tr("Zooms on region for", "ZOOM_ON_REGION mouse action"); + } + return QString(); +} + +QString QGLViewer::clickActionString(QGLViewer::ClickAction ca) { + switch (ca) { + case QGLViewer::NO_CLICK_ACTION: + return QString(); + case QGLViewer::ZOOM_ON_PIXEL: + return QGLViewer::tr("Zooms on pixel", "ZOOM_ON_PIXEL click action"); + case QGLViewer::ZOOM_TO_FIT: + return QGLViewer::tr("Zooms to fit scene", "ZOOM_TO_FIT click action"); + case QGLViewer::SELECT: + return QGLViewer::tr("Selects", "SELECT click action"); + case QGLViewer::RAP_FROM_PIXEL: + return QGLViewer::tr("Sets pivot point", "RAP_FROM_PIXEL click action"); + case QGLViewer::RAP_IS_CENTER: + return QGLViewer::tr("Resets pivot point", "RAP_IS_CENTER click action"); + case QGLViewer::CENTER_FRAME: + return QGLViewer::tr("Centers manipulated frame", + "CENTER_FRAME click action"); + case QGLViewer::CENTER_SCENE: + return QGLViewer::tr("Centers scene", "CENTER_SCENE click action"); + case QGLViewer::SHOW_ENTIRE_SCENE: + return QGLViewer::tr("Shows entire scene", + "SHOW_ENTIRE_SCENE click action"); + case QGLViewer::ALIGN_FRAME: + return QGLViewer::tr("Aligns manipulated frame", + "ALIGN_FRAME click action"); + case QGLViewer::ALIGN_CAMERA: + return QGLViewer::tr("Aligns camera", "ALIGN_CAMERA click action"); + } + return QString(); } -QString QGLViewer::mouseActionString(QGLViewer::MouseAction ma) -{ - switch (ma) - { - case QGLViewer::NO_MOUSE_ACTION : return QString(); - case QGLViewer::ROTATE : return QGLViewer::tr("Rotates", "ROTATE mouse action"); - case QGLViewer::ZOOM : return QGLViewer::tr("Zooms", "ZOOM mouse action"); - case QGLViewer::TRANSLATE : return QGLViewer::tr("Translates", "TRANSLATE mouse action"); - case QGLViewer::MOVE_FORWARD : return QGLViewer::tr("Moves forward", "MOVE_FORWARD mouse action"); - case QGLViewer::LOOK_AROUND : return QGLViewer::tr("Looks around", "LOOK_AROUND mouse action"); - case QGLViewer::MOVE_BACKWARD : return QGLViewer::tr("Moves backward", "MOVE_BACKWARD mouse action"); - case QGLViewer::SCREEN_ROTATE : return QGLViewer::tr("Rotates in screen plane", "SCREEN_ROTATE mouse action"); - case QGLViewer::ROLL : return QGLViewer::tr("Rolls", "ROLL mouse action"); - case QGLViewer::DRIVE : return QGLViewer::tr("Drives", "DRIVE mouse action"); - case QGLViewer::SCREEN_TRANSLATE : return QGLViewer::tr("Horizontally/Vertically translates", "SCREEN_TRANSLATE mouse action"); - case QGLViewer::ZOOM_ON_REGION : return QGLViewer::tr("Zooms on region for", "ZOOM_ON_REGION mouse action"); - } - return QString(); -} - -QString QGLViewer::clickActionString(QGLViewer::ClickAction ca) -{ - switch (ca) - { - case QGLViewer::NO_CLICK_ACTION : return QString(); - case QGLViewer::ZOOM_ON_PIXEL : return QGLViewer::tr("Zooms on pixel", "ZOOM_ON_PIXEL click action"); - case QGLViewer::ZOOM_TO_FIT : return QGLViewer::tr("Zooms to fit scene", "ZOOM_TO_FIT click action"); - case QGLViewer::SELECT : return QGLViewer::tr("Selects", "SELECT click action"); - case QGLViewer::RAP_FROM_PIXEL : return QGLViewer::tr("Sets pivot point", "RAP_FROM_PIXEL click action"); - case QGLViewer::RAP_IS_CENTER : return QGLViewer::tr("Resets pivot point", "RAP_IS_CENTER click action"); - case QGLViewer::CENTER_FRAME : return QGLViewer::tr("Centers manipulated frame", "CENTER_FRAME click action"); - case QGLViewer::CENTER_SCENE : return QGLViewer::tr("Centers scene", "CENTER_SCENE click action"); - case QGLViewer::SHOW_ENTIRE_SCENE : return QGLViewer::tr("Shows entire scene", "SHOW_ENTIRE_SCENE click action"); - case QGLViewer::ALIGN_FRAME : return QGLViewer::tr("Aligns manipulated frame", "ALIGN_FRAME click action"); - case QGLViewer::ALIGN_CAMERA : return QGLViewer::tr("Aligns camera", "ALIGN_CAMERA click action"); - } - return QString(); -} - -static QString keyString(unsigned int key) -{ -# if QT_VERSION >= 0x040100 - return QKeySequence(int(key)).toString(QKeySequence::NativeText); -# else - return QString(QKeySequence(key)); -# endif +static QString keyString(unsigned int key) { + return QKeySequence(int(key)).toString(QKeySequence::NativeText); } -QString QGLViewer::formatClickActionPrivate(ClickBindingPrivate cbp) -{ - bool buttonsBefore = cbp.buttonsBefore != Qt::NoButton; - QString keyModifierString = keyString(cbp.modifiers + cbp.key); - if (!keyModifierString.isEmpty()) { +QString QGLViewer::formatClickActionPrivate(ClickBindingPrivate cbp) { + bool buttonsBefore = cbp.buttonsBefore != Qt::NoButton; + QString keyModifierString = keyString(cbp.modifiers | cbp.key); + if (!keyModifierString.isEmpty()) { #ifdef Q_OS_MAC - // modifiers never has a '+' sign. Add one space to clearly separate modifiers (and possible key) from button - keyModifierString += " "; + // modifiers never has a '+' sign. Add one space to clearly separate + // modifiers (and possible key) from button + keyModifierString += " "; #else - // modifiers might be of the form : 'S' or 'Ctrl+S' or 'Ctrl+'. For consistency, add an other '+' if needed, no spaces - if (!keyModifierString.endsWith('+')) - keyModifierString += "+"; + // modifiers might be of the form : 'S' or 'Ctrl+S' or 'Ctrl+'. For + // consistency, add an other '+' if needed, no spaces + if (!keyModifierString.endsWith('+')) + keyModifierString += "+"; #endif - } + } - return tr("%1%2%3%4%5%6", "Modifier / button or wheel / double click / with / button / pressed") - .arg(keyModifierString) - .arg(mouseButtonsString(cbp.button)+(cbp.button == Qt::NoButton ? tr("Wheel", "Mouse wheel") : "")) - .arg(cbp.doubleClick ? tr(" double click", "Suffix after mouse button") : "") - .arg(buttonsBefore ? tr(" with ", "As in : Left button with Ctrl pressed") : "") - .arg(buttonsBefore ? mouseButtonsString(cbp.buttonsBefore) : "") - .arg(buttonsBefore ? tr(" pressed", "As in : Left button with Ctrl pressed") : ""); + return tr("%1%2%3%4%5%6", "Modifier / button or wheel / double click / with " + "/ button / pressed") + .arg(keyModifierString) + .arg(mouseButtonsString(cbp.button) + + (cbp.button == Qt::NoButton ? tr("Wheel", "Mouse wheel") : "")) + .arg(cbp.doubleClick ? tr(" double click", "Suffix after mouse button") + : "") + .arg(buttonsBefore ? tr(" with ", "As in : Left button with Ctrl pressed") + : "") + .arg(buttonsBefore ? mouseButtonsString(cbp.buttonsBefore) : "") + .arg(buttonsBefore + ? tr(" pressed", "As in : Left button with Ctrl pressed") + : ""); } bool QGLViewer::isValidShortcutKey(int key) { - return (key >= Qt::Key_Any && key < Qt::Key_Escape) || (key >= Qt::Key_F1 && key <= Qt::Key_F35); + return (key >= Qt::Key_Any && key < Qt::Key_Escape) || + (key >= Qt::Key_F1 && key <= Qt::Key_F35); } #ifndef DOXYGEN /*! This method is deprecated since version 2.5.0 - Use setMouseBindingDescription(Qt::KeyboardModifiers, Qt::MouseButtons, QString, bool, Qt::MouseButtons) instead. + Use setMouseBindingDescription(Qt::KeyboardModifiers, Qt::MouseButtons, + QString, bool, Qt::MouseButtons) instead. */ -void QGLViewer::setMouseBindingDescription(unsigned int state, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore) { - qWarning("setMouseBindingDescription(int state,...) is deprecated. Use the modifier/button equivalent"); - setMouseBindingDescription(keyboardModifiersFromState(state), - mouseButtonFromState(state), - description, - doubleClick, - buttonsBefore); +void QGLViewer::setMouseBindingDescription(unsigned int state, + QString description, + bool doubleClick, + Qt::MouseButtons buttonsBefore) { + qWarning("setMouseBindingDescription(int state,...) is deprecated. Use the " + "modifier/button equivalent"); + setMouseBindingDescription(keyboardModifiersFromState(state), + mouseButtonFromState(state), description, + doubleClick, buttonsBefore); } #endif -/*! Defines a custom mouse binding description, displayed in the help() window's Mouse tab. +/*! Defines a custom mouse binding description, displayed in the help() window's + Mouse tab. - Same as calling setMouseBindingDescription(Qt::Key, Qt::KeyboardModifiers, Qt::MouseButton, QString, bool, Qt::MouseButtons), - with a key value of Qt::Key(0) (i.e. binding description when no regular key needs to be pressed). */ -void QGLViewer::setMouseBindingDescription(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore) -{ - setMouseBindingDescription(Qt::Key(0), modifiers, button, description, doubleClick, buttonsBefore); + Same as calling setMouseBindingDescription(Qt::Key, Qt::KeyboardModifiers, + Qt::MouseButton, QString, bool, Qt::MouseButtons), with a key value of + Qt::Key(0) (i.e. binding description when no regular key needs to be pressed). + */ +void QGLViewer::setMouseBindingDescription(Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, + QString description, + bool doubleClick, + Qt::MouseButtons buttonsBefore) { + setMouseBindingDescription(Qt::Key(0), modifiers, button, description, + doubleClick, buttonsBefore); } -/*! Defines a custom mouse binding description, displayed in the help() window's Mouse tab. +/*! Defines a custom mouse binding description, displayed in the help() window's +Mouse tab. -\p modifiers is a combination of Qt::KeyboardModifiers (\c Qt::ControlModifier, \c Qt::AltModifier, \c -Qt::ShiftModifier, \c Qt::MetaModifier). Possibly combined using the \c "|" operator. +\p modifiers is a combination of Qt::KeyboardModifiers (\c Qt::ControlModifier, +\c Qt::AltModifier, \c Qt::ShiftModifier, \c Qt::MetaModifier). Possibly +combined using the \c "|" operator. \p button is one of the Qt::MouseButtons (\c Qt::LeftButton, \c Qt::MidButton, \c Qt::RightButton...). -\p doubleClick indicates whether or not the user has to double click this button to perform the -described action. \p buttonsBefore lists the buttons that need to be pressed before the double click. +\p doubleClick indicates whether or not the user has to double click this button +to perform the described action. \p buttonsBefore lists the buttons that need to +be pressed before the double click. Set an empty \p description to \e remove a mouse binding description. \code -// The R key combined with the Left mouse button rotates the camera in the screen plane. -setMouseBindingDescription(Qt::Key_R, Qt::NoModifier, Qt::LeftButton, "Rotates camera in screen plane"); +// The R key combined with the Left mouse button rotates the camera in the +screen plane. setMouseBindingDescription(Qt::Key_R, Qt::NoModifier, +Qt::LeftButton, "Rotates camera in screen plane"); // A left button double click toggles full screen -setMouseBindingDescription(Qt::NoModifier, Qt::LeftButton, "Toggles full screen mode", true); +setMouseBindingDescription(Qt::NoModifier, Qt::LeftButton, "Toggles full screen +mode", true); // Removes the description of Ctrl+Right button setMouseBindingDescription(Qt::ControlModifier, Qt::RightButton, ""); \endcode -Overload mouseMoveEvent() and friends to implement your custom mouse behavior (see the -mouseMoveEvent() documentation for an example). See the keyboardAndMouse example for an illustration. +Overload mouseMoveEvent() and friends to implement your custom mouse behavior +(see the mouseMoveEvent() documentation for an example). See the keyboardAndMouse example for an +illustration. -Use setMouseBinding() and setWheelBinding() to change the standard mouse action bindings. */ -void QGLViewer::setMouseBindingDescription(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore) -{ - ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key); +Use setMouseBinding() and setWheelBinding() to change the standard mouse action +bindings. */ +void QGLViewer::setMouseBindingDescription( + Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, + QString description, bool doubleClick, Qt::MouseButtons buttonsBefore) { + ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key); - if (description.isEmpty()) - mouseDescription_.remove(cbp); - else - mouseDescription_[cbp] = description; + if (description.isEmpty()) + mouseDescription_.remove(cbp); + else + mouseDescription_[cbp] = description; } -static QString tableLine(const QString& left, const QString& right) -{ - static bool even = false; - const QString tdtd(""); - const QString tdtr("\n"); +static QString tableLine(const QString &left, const QString &right) { + static bool even = false; + const QString tdtd(""); + const QString tdtr("\n"); - QString res(""; - else - res += "#ffffff\">"; - res += "" + left + tdtd + right + tdtr; - even = !even; + if (even) + res += "#eeeeff\">"; + else + res += "#ffffff\">"; + res += "" + left + tdtd + right + tdtr; + even = !even; - return res; + return res; } -/*! Returns a QString that describes the application mouse bindings, displayed in the help() window -\c Mouse tab. +/*! Returns a QString that describes the application mouse bindings, displayed +in the help() window \c Mouse tab. -Result is a table that describes custom application mouse binding descriptions defined using -setMouseBindingDescription() as well as standard mouse bindings (defined using setMouseBinding() -and setWheelBinding()). See the mouse page for details on mouse -bindings. +Result is a table that describes custom application mouse binding descriptions +defined using setMouseBindingDescription() as well as standard mouse bindings +(defined using setMouseBinding() and setWheelBinding()). See the mouse page for details on mouse bindings. See also helpString() and keyboardString(). */ -QString QGLViewer::mouseString() const -{ - QString text("
\n"); - const QString trtd("\n"); - const QString tdtd("\n"). - arg(tr("Button(s)", "Buttons column header in help window mouse tab")).arg(tr("Description", "Description column header in help window mouse tab")); - - QMap mouseBinding; - - // User-defined mouse bindings come first. - for (QMap::ConstIterator itm=mouseDescription_.begin(), endm=mouseDescription_.end(); itm!=endm; ++itm) - mouseBinding[itm.key()] = itm.value(); - - for (QMap::ConstIterator it=mouseBinding.begin(), end=mouseBinding.end(); it != end; ++it) - { - // Should not be needed (see setMouseBindingDescription()) - if (it.value().isNull()) - continue; - - text += tableLine(formatClickActionPrivate(it.key()), it.value()); - } - - // Optional separator line - if (!mouseBinding.isEmpty()) - { - mouseBinding.clear(); - text += QString("\n").arg(tr("Standard mouse bindings", "In help window mouse tab")); - } - - // Then concatenates the descriptions of wheelBinding_, mouseBinding_ and clickBinding_. - // The order is significant and corresponds to the priorities set in mousePressEvent() (reverse priority order, last one overwrites previous) - // #CONNECTION# mousePressEvent() order - for (QMap::ConstIterator itmb=mouseBinding_.begin(), endmb=mouseBinding_.end(); - itmb != endmb; ++itmb) - { - ClickBindingPrivate cbp(itmb.key().modifiers, itmb.key().button, false, Qt::NoButton, itmb.key().key); - - QString text = mouseActionString(itmb.value().action); - - if (!text.isNull()) - { - switch (itmb.value().handler) - { - case CAMERA: text += " " + tr("camera", "Suffix after action"); break; - case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break; - } - if (!(itmb.value().withConstraint)) - text += "*"; - } - mouseBinding[cbp] = text; - } - - for (QMap::ConstIterator itw=wheelBinding_.begin(), endw=wheelBinding_.end(); itw != endw; ++itw) - { - ClickBindingPrivate cbp(itw.key().modifiers, Qt::NoButton, false, Qt::NoButton, itw.key().key); - - QString text = mouseActionString(itw.value().action); - - if (!text.isNull()) - { - switch (itw.value().handler) - { - case CAMERA: text += " " + tr("camera", "Suffix after action"); break; - case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break; - } - if (!(itw.value().withConstraint)) - text += "*"; - } - - mouseBinding[cbp] = text; - } - - for (QMap::ConstIterator itcb=clickBinding_.begin(), endcb=clickBinding_.end(); itcb!=endcb; ++itcb) - mouseBinding[itcb.key()] = clickActionString(itcb.value()); - - for (QMap::ConstIterator it2=mouseBinding.begin(), end2=mouseBinding.end(); it2 != end2; ++it2) - { - if (it2.value().isNull()) - continue; - - text += tableLine(formatClickActionPrivate(it2.key()), it2.value()); - } - - text += "
"); - const QString tdtr("
"); - - text += QString("
%1%2
%1
"; - - return text; -} - -/*! Defines a custom keyboard shortcut description, that will be displayed in the help() window \c -Keyboard tab. - -The \p key definition is given as an \c int using Qt enumerated values. Set an empty \p description -to remove a shortcut description: -\code -setKeyDescription(Qt::Key_W, "Toggles wireframe display"); -setKeyDescription(Qt::CTRL+Qt::Key_L, "Loads a new scene"); -// Removes a description -setKeyDescription(Qt::CTRL+Qt::Key_C, ""); -\endcode +QString QGLViewer::mouseString() const { + QString text( + "
\n"); + const QString trtd("\n"); + const QString tdtd("\n") + .arg(tr("Button(s)", + "Buttons column header in help window mouse tab")) + .arg(tr("Description", + "Description column header in help window mouse tab")); + + QMap mouseBinding; + + // User-defined mouse bindings come first. + for (QMap::ConstIterator + itm = mouseDescription_.begin(), + endm = mouseDescription_.end(); + itm != endm; ++itm) + mouseBinding[itm.key()] = itm.value(); + + for (QMap::ConstIterator + it = mouseBinding.begin(), + end = mouseBinding.end(); + it != end; ++it) { + // Should not be needed (see setMouseBindingDescription()) + if (it.value().isNull()) + continue; + + text += tableLine(formatClickActionPrivate(it.key()), it.value()); + } -See the keyboardAndMouse example for illustration -and the keyboard page for details. */ -void QGLViewer::setKeyDescription(unsigned int key, QString description) -{ - if (description.isEmpty()) - keyDescription_.remove(key); - else - keyDescription_[key] = description; -} + // Optional separator line + if (!mouseBinding.isEmpty()) { + mouseBinding.clear(); + text += QString("\n") + .arg(tr("Standard mouse bindings", "In help window mouse tab")); + } -QString QGLViewer::cameraPathKeysString() const -{ - if (pathIndex_.isEmpty()) - return QString(); - - QVector keys; - keys.reserve(pathIndex_.count()); - for (QMap::ConstIterator i = pathIndex_.begin(), endi=pathIndex_.end(); i != endi; ++i) - keys.push_back(i.key()); - qSort(keys); - - QVector::const_iterator it = keys.begin(), end = keys.end(); - QString res = keyString(*it); - - const int maxDisplayedKeys = 6; - int nbDisplayedKeys = 0; - Qt::Key previousKey = (*it); - int state = 0; - ++it; - while ((it != end) && (nbDisplayedKeys < maxDisplayedKeys-1)) - { - switch (state) - { - case 0 : - if ((*it) == previousKey + 1) - state++; - else - { - res += ", " + keyString(*it); - nbDisplayedKeys++; - } - break; - case 1 : - if ((*it) == previousKey + 1) - state++; - else - { - res += ", " + keyString(previousKey); - res += ", " + keyString(*it); - nbDisplayedKeys += 2; - state = 0; - } - break; - default : - if ((*it) != previousKey + 1) - { - res += ".." + keyString(previousKey); - res += ", " + keyString(*it); - nbDisplayedKeys += 2; - state = 0; - } - break; - } - previousKey = *it; - ++it; - } - - if (state == 1) - res += ", " + keyString(previousKey); - if (state == 2) - res += ".." + keyString(previousKey); - if (it != end) - res += "..."; - - return res; -} - -/*! Returns a QString that describes the application keyboard shortcut bindings, and that will be -displayed in the help() window \c Keyboard tab. - -Default value is a table that describes the custom shortcuts defined using setKeyDescription() as -well as the \e standard QGLViewer::KeyboardAction shortcuts (defined using setShortcut()). See the -keyboard page for details on key customization. + // Then concatenates the descriptions of wheelBinding_, mouseBinding_ and + // clickBinding_. The order is significant and corresponds to the priorities + // set in mousePressEvent() (reverse priority order, last one overwrites + // previous) #CONNECTION# mousePressEvent() order + for (QMap::ConstIterator + itmb = mouseBinding_.begin(), + endmb = mouseBinding_.end(); + itmb != endmb; ++itmb) { + ClickBindingPrivate cbp(itmb.key().modifiers, itmb.key().button, false, + Qt::NoButton, itmb.key().key); + + QString text = mouseActionString(itmb.value().action); + + if (!text.isNull()) { + switch (itmb.value().handler) { + case CAMERA: + text += " " + tr("camera", "Suffix after action"); + break; + case FRAME: + text += " " + tr("manipulated frame", "Suffix after action"); + break; + } + if (!(itmb.value().withConstraint)) + text += "*"; + } + mouseBinding[cbp] = text; + } -See also helpString() and mouseString(). */ -QString QGLViewer::keyboardString() const -{ - QString text("
"); + const QString tdtr("
"); + + text += QString("
%1%2
%1
\n"); - text += QString("\n"). - arg(QGLViewer::tr("Key(s)", "Keys column header in help window mouse tab")).arg(QGLViewer::tr("Description", "Description column header in help window mouse tab")); + for (QMap::ConstIterator + itw = wheelBinding_.begin(), + endw = wheelBinding_.end(); + itw != endw; ++itw) { + ClickBindingPrivate cbp(itw.key().modifiers, Qt::NoButton, false, + Qt::NoButton, itw.key().key); + + QString text = mouseActionString(itw.value().action); + + if (!text.isNull()) { + switch (itw.value().handler) { + case CAMERA: + text += " " + tr("camera", "Suffix after action"); + break; + case FRAME: + text += " " + tr("manipulated frame", "Suffix after action"); + break; + } + if (!(itw.value().withConstraint)) + text += "*"; + } + + mouseBinding[cbp] = text; + } - QMap keyDescription; + for (QMap::ConstIterator + itcb = clickBinding_.begin(), + endcb = clickBinding_.end(); + itcb != endcb; ++itcb) + mouseBinding[itcb.key()] = clickActionString(itcb.value()); - // 1 - User defined key descriptions - for (QMap::ConstIterator kd=keyDescription_.begin(), kdend=keyDescription_.end(); kd!=kdend; ++kd) - keyDescription[kd.key()] = kd.value(); + for (QMap::ConstIterator + it2 = mouseBinding.begin(), + end2 = mouseBinding.end(); + it2 != end2; ++it2) { + if (it2.value().isNull()) + continue; - // Add to text in sorted order - for (QMap::ConstIterator kb=keyDescription.begin(), endb=keyDescription.end(); kb!=endb; ++kb) - text += tableLine(keyString(kb.key()), kb.value()); + text += tableLine(formatClickActionPrivate(it2.key()), it2.value()); + } + text += "
%1%2
"; - // 2 - Optional separator line - if (!keyDescription.isEmpty()) - { - keyDescription.clear(); - text += QString("%1\n").arg(QGLViewer::tr("Standard viewer keys", "In help window keys tab")); - } + return text; +} +/*! Defines a custom keyboard shortcut description, that will be displayed in +the help() window \c Keyboard tab. - // 3 - KeyboardAction bindings description - for (QMap::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end(); it != end; ++it) - if ((it.value() != 0) && ((!cameraIsInRotateMode()) || ((it.key() != INCREASE_FLYSPEED) && (it.key() != DECREASE_FLYSPEED)))) - keyDescription[it.value()] = keyboardActionDescription_[it.key()]; +The \p key definition is given as an \c int using Qt enumerated values. Set an +empty \p description to remove a shortcut description: \code +setKeyDescription(Qt::Key_W, "Toggles wireframe display"); +setKeyDescription(Qt::CTRL | Qt::Key_L, "Loads a new scene"); +// Removes a description +setKeyDescription(Qt::CTRL | Qt::Key_C, ""); +\endcode + +See the keyboardAndMouse example +for illustration and the keyboard page for +details. */ +void QGLViewer::setKeyDescription(unsigned int key, QString description) { + if (description.isEmpty()) + keyDescription_.remove(key); + else + keyDescription_[key] = description; +} + +QString QGLViewer::cameraPathKeysString() const { + if (pathIndex_.isEmpty()) + return QString(); + + QVector keys; + keys.reserve(pathIndex_.count()); + for (QMap::ConstIterator i = pathIndex_.begin(), + endi = pathIndex_.end(); + i != endi; ++i) + keys.push_back(i.key()); + std::sort(keys.begin(), keys.end()); + + QVector::const_iterator it = keys.begin(), end = keys.end(); + QString res = keyString(*it); + + const int maxDisplayedKeys = 6; + int nbDisplayedKeys = 0; + Qt::Key previousKey = (*it); + int state = 0; + ++it; + while ((it != end) && (nbDisplayedKeys < maxDisplayedKeys - 1)) { + switch (state) { + case 0: + if ((*it) == previousKey + 1) + state++; + else { + res += ", " + keyString(*it); + nbDisplayedKeys++; + } + break; + case 1: + if ((*it) == previousKey + 1) + state++; + else { + res += ", " + keyString(previousKey); + res += ", " + keyString(*it); + nbDisplayedKeys += 2; + state = 0; + } + break; + default: + if ((*it) != previousKey + 1) { + res += ".." + keyString(previousKey); + res += ", " + keyString(*it); + nbDisplayedKeys += 2; + state = 0; + } + break; + } + previousKey = *it; + ++it; + } + + if (state == 1) + res += ", " + keyString(previousKey); + if (state == 2) + res += ".." + keyString(previousKey); + if (it != end) + res += "..."; - // Add to text in sorted order - for (QMap::ConstIterator kb2=keyDescription.begin(), endb2=keyDescription.end(); kb2!=endb2; ++kb2) - text += tableLine(keyString(kb2.key()), kb2.value()); + return res; +} +/*! Returns a QString that describes the application keyboard shortcut bindings, +and that will be displayed in the help() window \c Keyboard tab. - // 4 - Camera paths keys description - const QString cpks = cameraPathKeysString(); - if (!cpks.isNull()) - { - text += "\n"; - text += QGLViewer::tr("Camera paths are controlled using the %1 keys (noted Fx below):", "Help window key tab camera keys").arg(cpks) + "\n"; - text += tableLine(keyString(playPathKeyboardModifiers()) + "" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "", - QGLViewer::tr("Plays path (or resets saved position)")); - text += tableLine(keyString(addKeyFrameKeyboardModifiers()) + "" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "", - QGLViewer::tr("Adds a key frame to path (or defines a position)")); - text += tableLine(keyString(addKeyFrameKeyboardModifiers()) + "" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "+" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "", - QGLViewer::tr("Deletes path (or saved position)")); - } - text += ""; +Default value is a table that describes the custom shortcuts defined using +setKeyDescription() as well as the \e standard QGLViewer::KeyboardAction +shortcuts (defined using setShortcut()). See the keyboard page for details on key customization. - return text; +See also helpString() and mouseString(). */ +QString QGLViewer::keyboardString() const { + QString text( + "
\n"); + text += QString("\n") + .arg(QGLViewer::tr("Key(s)", + "Keys column header in help window mouse tab")) + .arg(QGLViewer::tr( + "Description", + "Description column header in help window mouse tab")); + + QMap keyDescription; + + // 1 - User defined key descriptions + for (QMap::ConstIterator kd = keyDescription_.begin(), + kdend = keyDescription_.end(); + kd != kdend; ++kd) + keyDescription[kd.key()] = kd.value(); + + // Add to text in sorted order + for (QMap::ConstIterator kb = keyDescription.begin(), + endb = keyDescription.end(); + kb != endb; ++kb) + text += tableLine(keyString(kb.key()), kb.value()); + + // 2 - Optional separator line + if (!keyDescription.isEmpty()) { + keyDescription.clear(); + text += QString("\n") + .arg(QGLViewer::tr("Standard viewer keys", + "In help window keys tab")); + } + + // 3 - KeyboardAction bindings description + for (QMap::ConstIterator + it = keyboardBinding_.begin(), + end = keyboardBinding_.end(); + it != end; ++it) + if ((it.value() != 0) && + ((!cameraIsInRotateMode()) || + ((it.key() != INCREASE_FLYSPEED) && (it.key() != DECREASE_FLYSPEED)))) + keyDescription[it.value()] = keyboardActionDescription_[it.key()]; + + // Add to text in sorted order + for (QMap::ConstIterator kb2 = keyDescription.begin(), + endb2 = keyDescription.end(); + kb2 != endb2; ++kb2) + text += tableLine(keyString(kb2.key()), kb2.value()); + + // 4 - Camera paths keys description + const QString cpks = cameraPathKeysString(); + if (!cpks.isNull()) { + text += "\n"; + text += tableLine( + keyString(playPathKeyboardModifiers()) + "" + + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "", + QGLViewer::tr("Plays path (or resets saved position)")); + text += tableLine( + keyString(addKeyFrameKeyboardModifiers()) + "" + + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "", + QGLViewer::tr("Adds a key frame to path (or defines a position)")); + text += tableLine( + keyString(addKeyFrameKeyboardModifiers()) + "" + + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "+" + + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "", + QGLViewer::tr("Deletes path (or saved position)")); + } + text += "
%1%2
%1
\n"; + text += QGLViewer::tr("Camera paths are controlled using the %1 keys " + "(noted Fx below):", + "Help window key tab camera keys") + .arg(cpks) + + "
"; + + return text; } /*! Displays the help window "About" tab. See help() for details. */ void QGLViewer::aboutQGLViewer() { - help(); - helpWidget()->setCurrentIndex(3); + help(); + helpWidget()->setCurrentIndex(3); } +/*! Opens a modal help window that includes four tabs, respectively filled with +helpString(), keyboardString(), mouseString() and about libQGLViewer. -/*! Opens a modal help window that includes four tabs, respectively filled with helpString(), -keyboardString(), mouseString() and about libQGLViewer. +Rich html-like text can be used (see the QStyleSheet documentation). This method +is called when the user presses the QGLViewer::HELP key (default is 'H'). -Rich html-like text can be used (see the QStyleSheet documentation). This method is called when the -user presses the QGLViewer::HELP key (default is 'H'). - -You can use helpWidget() to access to the help widget (to add/remove tabs, change layout...). +You can use helpWidget() to access to the help widget (to add/remove tabs, +change layout...). The helpRequired() signal is emitted. */ -void QGLViewer::help() -{ - Q_EMIT helpRequired(); - - bool resize = false; - int width=600; - int height=400; - - static QString label[] = {tr("&Help", "Help window tab title"), tr("&Keyboard", "Help window tab title"), tr("&Mouse", "Help window tab title"), tr("&About", "Help window about title")}; - - if (!helpWidget()) - { - // Qt4 requires a NULL parent... - helpWidget_ = new QTabWidget(NULL); - helpWidget()->setWindowTitle(tr("Help", "Help window title")); - - resize = true; - for (int i=0; i<4; ++i) - { - QTextEdit* tab = new QTextEdit(NULL); - tab->setReadOnly(true); - - helpWidget()->insertTab(i, tab, label[i]); - if (i==3) { -# include "qglviewer-icon.xpm" - QPixmap pixmap(qglviewer_icon); - tab->document()->addResource(QTextDocument::ImageResource, - QUrl("mydata://qglviewer-icon.xpm"), QVariant(pixmap)); - } - } - } - - for (int i=0; i<4; ++i) - { - QString text; - switch (i) - { - case 0 : text = helpString(); break; - case 1 : text = keyboardString(); break; - case 2 : text = mouseString(); break; - case 3 : text = QString("

") + tr( - "

libQGLViewer

" - "

Version %1


" - "A versatile 3D viewer based on OpenGL and Qt
" - "Copyright 2002-%2 Gilles Debunne
" - "%3").arg(QGLViewerVersionString()).arg("2014").arg("http://www.libqglviewer.com") + - QString("
"); - break; - default : break; - } - - QTextEdit* textEdit = (QTextEdit*)(helpWidget()->widget(i)); - textEdit->setHtml(text); - textEdit->setText(text); - - if (resize && (textEdit->height() > height)) - height = textEdit->height(); - } - - if (resize) - helpWidget()->resize(width, height+40); // 40 pixels is ~ tabs' height - helpWidget()->show(); - helpWidget()->raise(); +void QGLViewer::help() { + Q_EMIT helpRequired(); + + bool resize = false; + int width = 600; + int height = 400; + + static QString label[] = {tr("&Help", "Help window tab title"), + tr("&Keyboard", "Help window tab title"), + tr("&Mouse", "Help window tab title"), + tr("&About", "Help window about title")}; + + if (!helpWidget()) { + // Qt4 requires a nullptr parent... + helpWidget_ = new QTabWidget(nullptr); + helpWidget()->setWindowTitle(tr("Help", "Help window title")); + + resize = true; + for (int i = 0; i < 4; ++i) { + QTextEdit *tab = new QTextEdit(nullptr); + tab->setReadOnly(true); + + helpWidget()->insertTab(i, tab, label[i]); + if (i == 3) { +#include "qglviewer-icon.xpm" + QPixmap pixmap(qglviewer_icon); + tab->document()->addResource(QTextDocument::ImageResource, + QUrl("mydata://qglviewer-icon.xpm"), + QVariant(pixmap)); + } + } + } + + for (int i = 0; i < 4; ++i) { + QString text; + switch (i) { + case 0: + text = helpString(); + break; + case 1: + text = keyboardString(); + break; + case 2: + text = mouseString(); + break; + case 3: + text = QString("

") + + tr("

libQGLViewer

" + "

Version %1


" + "A versatile 3D viewer based on OpenGL and Qt
" + "Copyright 2002-%2 Gilles Debunne
" + "%3") + .arg(QGLViewerVersionString()) + .arg("2023") + .arg("http://www.libqglviewer.com") + + QString("
"); + break; + default: + break; + } + + QTextEdit *textEdit = static_cast(helpWidget()->widget(i)); + textEdit->setHtml(text); + textEdit->setText(text); + + if (resize && (textEdit->height() > height)) + height = textEdit->height(); + } + + if (resize) + helpWidget()->resize(width, height + 40); // 40 pixels is ~ tabs' height + helpWidget()->show(); + helpWidget()->raise(); } /*! Overloading of the \c QWidget method. -Default keyboard shortcuts are defined using setShortcut(). Overload this method to implement a -specific keyboard binding. Call the original method if you do not catch the event to preserve the -viewer default key bindings: -\code -void Viewer::keyPressEvent(QKeyEvent *e) +Default keyboard shortcuts are defined using setShortcut(). Overload this method +to implement a specific keyboard binding. Call the original method if you do not +catch the event to preserve the viewer default key bindings: \code void +Viewer::keyPressEvent(QKeyEvent *e) { // Defines the Alt+R shortcut. if ((e->key() == Qt::Key_R) && (e->modifiers() == Qt::AltModifier)) { - myResetFunction(); - update(); // Refresh display + myResetFunction(); + update(); // Refresh display } else - QGLViewer::keyPressEvent(e); + QGLViewer::keyPressEvent(e); } // With Qt 2 or 3, you would retrieve modifiers keys using : -// const Qt::ButtonState modifiers = (Qt::ButtonState)(e->state() & Qt::KeyButtonMask); -\endcode -When you define a new keyboard shortcut, use setKeyDescription() to provide a short description -which is displayed in the help() window Keyboard tab. See the keyboardAndMouse example for an illustration. +// const Qt::ButtonState modifiers = (Qt::ButtonState)(e->state() & +Qt::KeyButtonMask); \endcode When you define a new keyboard shortcut, use +setKeyDescription() to provide a short description which is displayed in the +help() window Keyboard tab. See the keyboardAndMouse example for an +illustration. -See also QGLWidget::keyReleaseEvent(). */ -void QGLViewer::keyPressEvent(QKeyEvent *e) -{ - if (e->key() == 0) - { - e->ignore(); - return; - } - - const Qt::Key key = Qt::Key(e->key()); - - const Qt::KeyboardModifiers modifiers = e->modifiers(); - - QMap::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end(); - const unsigned int target = key | modifiers; - while ((it != end) && (it.value() != target)) - ++it; - - if (it != end) - handleKeyboardAction(it.key()); - else - if (pathIndex_.contains(Qt::Key(key))) - { - // Camera paths - unsigned int index = pathIndex_[Qt::Key(key)]; - - // not safe, but try to double press on two viewers at the same time ! - static QTime doublePress; - - if (modifiers == playPathKeyboardModifiers()) - { - int elapsed = doublePress.restart(); - if ((elapsed < 250) && (index==previousPathId_)) - camera()->resetPath(index); - else - { - // Stop previous interpolation before starting a new one. - if (index != previousPathId_) - { - KeyFrameInterpolator* previous = camera()->keyFrameInterpolator(previousPathId_); - if ((previous) && (previous->interpolationIsStarted())) - previous->resetInterpolation(); - } - camera()->playPath(index); - } - previousPathId_ = index; - } - else if (modifiers == addKeyFrameKeyboardModifiers()) - { - int elapsed = doublePress.restart(); - if ((elapsed < 250) && (index==previousPathId_)) - { - if (camera()->keyFrameInterpolator(index)) - { - disconnect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), this, SLOT(update())); - if (camera()->keyFrameInterpolator(index)->numberOfKeyFrames() > 1) - displayMessage(tr("Path %1 deleted", "Feedback message").arg(index)); - else - displayMessage(tr("Position %1 deleted", "Feedback message").arg(index)); - camera()->deletePath(index); - } - } - else - { - bool nullBefore = (camera()->keyFrameInterpolator(index) == NULL); - camera()->addKeyFrameToPath(index); - if (nullBefore) - connect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), SLOT(update())); - int nbKF = camera()->keyFrameInterpolator(index)->numberOfKeyFrames(); - if (nbKF > 1) - displayMessage(tr("Path %1, position %2 added", "Feedback message").arg(index).arg(nbKF)); - else - displayMessage(tr("Position %1 saved", "Feedback message").arg(index)); - } - previousPathId_ = index; - } - update(); - } else { - if (isValidShortcutKey(key)) currentlyPressedKey_ = key; - e->ignore(); - } -} - -void QGLViewer::keyReleaseEvent(QKeyEvent * e) { - if (isValidShortcutKey(e->key())) currentlyPressedKey_ = Qt::Key(0); -} - -void QGLViewer::handleKeyboardAction(KeyboardAction id) -{ - switch (id) - { - case DRAW_AXIS : toggleAxisIsDrawn(); break; - case DRAW_GRID : toggleGridIsDrawn(); break; - case DISPLAY_FPS : toggleFPSIsDisplayed(); break; - case ENABLE_TEXT : toggleTextIsEnabled(); break; - case EXIT_VIEWER : saveStateToFileForAllViewers(); qApp->closeAllWindows(); break; - case SAVE_SCREENSHOT : saveSnapshot(false, false); break; - case FULL_SCREEN : toggleFullScreen(); break; - case STEREO : toggleStereoDisplay(); break; - case ANIMATION : toggleAnimation(); break; - case HELP : help(); break; - case EDIT_CAMERA : toggleCameraIsEdited(); break; - case SNAPSHOT_TO_CLIPBOARD : snapshotToClipboard(); break; - case CAMERA_MODE : - toggleCameraMode(); - displayMessage(cameraIsInRotateMode()?tr("Camera in observer mode", "Feedback message"):tr("Camera in fly mode", "Feedback message")); - break; - - case MOVE_CAMERA_LEFT : - camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(-10.0*camera()->flySpeed(), 0.0, 0.0))); - update(); - break; - case MOVE_CAMERA_RIGHT : - camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec( 10.0*camera()->flySpeed(), 0.0, 0.0))); - update(); - break; - case MOVE_CAMERA_UP : - camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, 10.0*camera()->flySpeed(), 0.0))); - update(); - break; - case MOVE_CAMERA_DOWN : - camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, -10.0*camera()->flySpeed(), 0.0))); - update(); - break; - - case INCREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() * 1.5); break; - case DECREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() / 1.5); break; - } +See also QOpenGLWidget::keyReleaseEvent(). */ +void QGLViewer::keyPressEvent(QKeyEvent *e) { + if (e->key() == 0) { + e->ignore(); + return; + } + + const Qt::Key key = Qt::Key(e->key()); + + const Qt::KeyboardModifiers modifiers = e->modifiers(); + + QMap::ConstIterator it = keyboardBinding_.begin(), + end = keyboardBinding_.end(); + const unsigned int target = key | modifiers; + while ((it != end) && (it.value() != target)) + ++it; + + if (it != end) + handleKeyboardAction(it.key()); + else if (pathIndex_.contains(Qt::Key(key))) { + // Camera paths + unsigned int index = pathIndex_[Qt::Key(key)]; + + // not safe, but try to double press on two viewers at the same time ! + static QElapsedTimer doublePress; + + if (modifiers == playPathKeyboardModifiers()) { + int elapsed = doublePress.restart(); + if ((elapsed < 250) && (index == previousPathId_)) + camera()->resetPath(index); + else { + // Stop previous interpolation before starting a new one. + if (index != previousPathId_) { + KeyFrameInterpolator *previous = + camera()->keyFrameInterpolator(previousPathId_); + if ((previous) && (previous->interpolationIsStarted())) + previous->resetInterpolation(); + } + camera()->playPath(index); + } + previousPathId_ = index; + } else if (modifiers == addKeyFrameKeyboardModifiers()) { + int elapsed = doublePress.restart(); + if ((elapsed < 250) && (index == previousPathId_)) { + if (camera()->keyFrameInterpolator(index)) { + disconnect(camera()->keyFrameInterpolator(index), + SIGNAL(interpolated()), this, SLOT(update())); + if (camera()->keyFrameInterpolator(index)->numberOfKeyFrames() > 1) + displayMessage( + tr("Path %1 deleted", "Feedback message").arg(index)); + else + displayMessage( + tr("Position %1 deleted", "Feedback message").arg(index)); + camera()->deletePath(index); + } + } else { + bool nullBefore = (camera()->keyFrameInterpolator(index) == nullptr); + camera()->addKeyFrameToPath(index); + if (nullBefore) + connect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), + SLOT(update())); + int nbKF = camera()->keyFrameInterpolator(index)->numberOfKeyFrames(); + if (nbKF > 1) + displayMessage(tr("Path %1, position %2 added", "Feedback message") + .arg(index) + .arg(nbKF)); + else + displayMessage( + tr("Position %1 saved", "Feedback message").arg(index)); + } + previousPathId_ = index; + } + update(); + } else { + if (isValidShortcutKey(key)) + currentlyPressedKey_ = key; + e->ignore(); + } +} + +void QGLViewer::keyReleaseEvent(QKeyEvent *e) { + if (isValidShortcutKey(e->key())) + currentlyPressedKey_ = Qt::Key(0); +} + +void QGLViewer::handleKeyboardAction(KeyboardAction id) { + switch (id) { + case DRAW_AXIS: + toggleAxisIsDrawn(); + break; + case DRAW_GRID: + toggleGridIsDrawn(); + break; + case DISPLAY_FPS: + toggleFPSIsDisplayed(); + break; + case ENABLE_TEXT: + toggleTextIsEnabled(); + break; + case EXIT_VIEWER: + saveStateToFileForAllViewers(); + qApp->closeAllWindows(); + break; + case SAVE_SCREENSHOT: + saveSnapshot(false, false); + break; + case FULL_SCREEN: + toggleFullScreen(); + break; + case STEREO: + toggleStereoDisplay(); + break; + case ANIMATION: + toggleAnimation(); + break; + case HELP: + help(); + break; + case EDIT_CAMERA: + toggleCameraIsEdited(); + break; + case SNAPSHOT_TO_CLIPBOARD: + snapshotToClipboard(); + break; + case CAMERA_MODE: + toggleCameraMode(); + displayMessage(cameraIsInRotateMode() + ? tr("Camera in observer mode", "Feedback message") + : tr("Camera in fly mode", "Feedback message")); + break; + + case MOVE_CAMERA_LEFT: + camera()->frame()->translate(camera()->frame()->inverseTransformOf( + Vec(-10.0 * camera()->flySpeed(), 0.0, 0.0))); + update(); + break; + case MOVE_CAMERA_RIGHT: + camera()->frame()->translate(camera()->frame()->inverseTransformOf( + Vec(10.0 * camera()->flySpeed(), 0.0, 0.0))); + update(); + break; + case MOVE_CAMERA_UP: + camera()->frame()->translate(camera()->frame()->inverseTransformOf( + Vec(0.0, 10.0 * camera()->flySpeed(), 0.0))); + update(); + break; + case MOVE_CAMERA_DOWN: + camera()->frame()->translate(camera()->frame()->inverseTransformOf( + Vec(0.0, -10.0 * camera()->flySpeed(), 0.0))); + update(); + break; + + case INCREASE_FLYSPEED: + camera()->setFlySpeed(camera()->flySpeed() * 1.5); + break; + case DECREASE_FLYSPEED: + camera()->setFlySpeed(camera()->flySpeed() / 1.5); + break; + } } /*! Callback method used when the widget size is modified. -If you overload this method, first call the inherited method. Also called when the widget is -created, before its first display. */ -void QGLViewer::resizeGL(int width, int height) -{ - QGLWidget::resizeGL(width, height); - glViewport( 0, 0, GLint(width), GLint(height) ); - camera()->setScreenWidthAndHeight(this->width(), this->height()); +If you overload this method, first call the inherited method. Also called when +the widget is created, before its first display. */ +void QGLViewer::resizeGL(int width, int height) { + QOpenGLWidget::resizeGL(width, height); + glViewport(0, 0, GLint(width), GLint(height)); + camera()->setScreenWidthAndHeight(this->width(), this->height()); } ////////////////////////////////////////////////////////////////////////// @@ -2215,54 +2447,53 @@ Here are some examples: setShortcut(EXIT_VIEWER, Qt::Key_Q); // Alt+M toggles camera mode -setShortcut(CAMERA_MODE, Qt::ALT + Qt::Key_M); +setShortcut(CAMERA_MODE, Qt::ALT | Qt::Key_M); // The DISPLAY_FPS action is disabled setShortcut(DISPLAY_FPS, 0); \endcode -Only one shortcut can be assigned to a given QGLViewer::KeyboardAction (new bindings replace -previous ones). If several KeyboardAction are binded to the same shortcut, only one of them is -active. */ -void QGLViewer::setShortcut(KeyboardAction action, unsigned int key) -{ - keyboardBinding_[action] = key; +Only one shortcut can be assigned to a given QGLViewer::KeyboardAction (new +bindings replace previous ones). If several KeyboardAction are binded to the +same shortcut, only one of them is active. */ +void QGLViewer::setShortcut(KeyboardAction action, unsigned int key) { + keyboardBinding_[action] = key; } -/*! Returns the keyboard shortcut associated to a given QGLViewer::KeyboardAction. +/*! Returns the keyboard shortcut associated to a given +QGLViewer::KeyboardAction. -Result is an \c unsigned \c int defined using Qt enumerated values, as in \c Qt::Key_Q or -\c Qt::CTRL + Qt::Key_X. Use Qt::MODIFIER_MASK to separate the key from the state keys. Returns \c 0 if -the KeyboardAction is disabled (not binded). Set using setShortcut(). +Result is an \c unsigned \c int defined using Qt enumerated values, as in \c +Qt::Key_Q or \c Qt::CTRL | Qt::Key_X. Use Qt::MODIFIER_MASK to separate the key +from the state keys. Returns \c 0 if the KeyboardAction is disabled (not +binded). Set using setShortcut(). -If you want to define keyboard shortcuts for custom actions (say, open a scene file), overload -keyPressEvent() and then setKeyDescription(). +If you want to define keyboard shortcuts for custom actions (say, open a scene +file), overload keyPressEvent() and then setKeyDescription(). -These shortcuts and their descriptions are automatically included in the help() window \c Keyboard -tab. +These shortcuts and their descriptions are automatically included in the help() +window \c Keyboard tab. -See the keyboard page for details and default values and the keyboardAndMouse example for a practical -illustration. */ -unsigned int QGLViewer::shortcut(KeyboardAction action) const -{ - if (keyboardBinding_.contains(action)) - return keyboardBinding_[action]; - else - return 0; +See the keyboard page for details and default +values and the keyboardAndMouse +example for a practical illustration. */ +unsigned int QGLViewer::shortcut(KeyboardAction action) const { + if (keyboardBinding_.contains(action)) + return keyboardBinding_[action]; + else + return 0; } #ifndef DOXYGEN -void QGLViewer::setKeyboardAccelerator(KeyboardAction action, unsigned int key) -{ - qWarning("setKeyboardAccelerator is deprecated. Use setShortcut instead."); - setShortcut(action, key); +void QGLViewer::setKeyboardAccelerator(KeyboardAction action, + unsigned int key) { + qWarning("setKeyboardAccelerator is deprecated. Use setShortcut instead."); + setShortcut(action, key); } -unsigned int QGLViewer::keyboardAccelerator(KeyboardAction action) const -{ - qWarning("keyboardAccelerator is deprecated. Use shortcut instead."); - return shortcut(action); +unsigned int QGLViewer::keyboardAccelerator(KeyboardAction action) const { + qWarning("keyboardAccelerator is deprecated. Use shortcut instead."); + return shortcut(action); } #endif @@ -2272,131 +2503,129 @@ unsigned int QGLViewer::keyboardAccelerator(KeyboardAction action) const Default values are F1..F12 for indexes 1..12. -addKeyFrameKeyboardModifiers() (resp. playPathKeyboardModifiers()) define the state key(s) that -must be pressed with this key to add a KeyFrame to (resp. to play) the associated Key Frame path. -If you quickly press twice the pathKey(), the path is reset (resp. deleted). +addKeyFrameKeyboardModifiers() (resp. playPathKeyboardModifiers()) define the +state key(s) that must be pressed with this key to add a KeyFrame to (resp. to +play) the associated Key Frame path. If you quickly press twice the pathKey(), +the path is reset (resp. deleted). -Use camera()->keyFrameInterpolator( \p index ) to retrieve the KeyFrameInterpolator that defines -the path. +Use camera()->keyFrameInterpolator( \p index ) to retrieve the +KeyFrameInterpolator that defines the path. -If several keys are binded to a given \p index (see setPathKey()), one of them is returned. -Returns \c 0 if no key is associated with this index. +If several keys are binded to a given \p index (see setPathKey()), one of them +is returned. Returns \c 0 if no key is associated with this index. See also the keyboard page. */ -Qt::Key QGLViewer::pathKey(unsigned int index) const -{ - for (QMap::ConstIterator it = pathIndex_.begin(), end=pathIndex_.end(); it != end; ++it) - if (it.value() == index) - return it.key(); - return Qt::Key(0); +Qt::Key QGLViewer::pathKey(unsigned int index) const { + for (QMap::ConstIterator it = pathIndex_.begin(), + end = pathIndex_.end(); + it != end; ++it) + if (it.value() == index) + return it.key(); + return Qt::Key(0); } /*! Sets the pathKey() associated with the camera Key Frame path \p index. -Several keys can be binded to the same \p index. Use a negated \p key value to delete the binding -(the \p index value is then ignored): -\code +Several keys can be binded to the same \p index. Use a negated \p key value to +delete the binding (the \p index value is then ignored): \code // Press 'space' to play/pause/add/delete camera path of index 0. setPathKey(Qt::Key_Space, 0); // Remove this binding setPathKey(-Qt::Key_Space); \endcode */ -void QGLViewer::setPathKey(int key, unsigned int index) -{ - Qt::Key k = Qt::Key(abs(key)); - if (key < 0) - pathIndex_.remove(k); - else - pathIndex_[k] = index; +void QGLViewer::setPathKey(int key, unsigned int index) { + Qt::Key k = Qt::Key(abs(key)); + if (key < 0) + pathIndex_.remove(k); + else + pathIndex_[k] = index; } /*! Sets the playPathKeyboardModifiers() value. */ -void QGLViewer::setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers) -{ - playPathKeyboardModifiers_ = modifiers; +void QGLViewer::setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers) { + playPathKeyboardModifiers_ = modifiers; } /*! Sets the addKeyFrameKeyboardModifiers() value. */ -void QGLViewer::setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers) -{ - addKeyFrameKeyboardModifiers_ = modifiers; +void QGLViewer::setAddKeyFrameKeyboardModifiers( + Qt::KeyboardModifiers modifiers) { + addKeyFrameKeyboardModifiers_ = modifiers; } -/*! Returns the keyboard modifiers that must be pressed with a pathKey() to add the current camera -position to a KeyFrame path. +/*! Returns the keyboard modifiers that must be pressed with a pathKey() to add +the current camera position to a KeyFrame path. -It can be \c Qt::NoModifier, \c Qt::ControlModifier, \c Qt::ShiftModifier, \c Qt::AltModifier, \c -Qt::MetaModifier or a combination of these (using the bitwise '|' operator). +It can be \c Qt::NoModifier, \c Qt::ControlModifier, \c Qt::ShiftModifier, \c +Qt::AltModifier, \c Qt::MetaModifier or a combination of these (using the +bitwise '|' operator). -Default value is Qt::AltModifier. Defined using setAddKeyFrameKeyboardModifiers(). +Default value is Qt::AltModifier. Defined using +setAddKeyFrameKeyboardModifiers(). See also playPathKeyboardModifiers(). */ -Qt::KeyboardModifiers QGLViewer::addKeyFrameKeyboardModifiers() const -{ - return addKeyFrameKeyboardModifiers_; +Qt::KeyboardModifiers QGLViewer::addKeyFrameKeyboardModifiers() const { + return addKeyFrameKeyboardModifiers_; } -/*! Returns the keyboard modifiers that must be pressed with a pathKey() to play a camera KeyFrame path. +/*! Returns the keyboard modifiers that must be pressed with a pathKey() to play +a camera KeyFrame path. -It can be \c Qt::NoModifier, \c Qt::ControlModifier, \c Qt::ShiftModifier, \c Qt::AltModifier, \c -Qt::MetaModifier or a combination of these (using the bitwise '|' operator). +It can be \c Qt::NoModifier, \c Qt::ControlModifier, \c Qt::ShiftModifier, \c +Qt::AltModifier, \c Qt::MetaModifier or a combination of these (using the +bitwise '|' operator). Default value is Qt::NoModifier. Defined using setPlayPathKeyboardModifiers(). See also addKeyFrameKeyboardModifiers(). */ -Qt::KeyboardModifiers QGLViewer::playPathKeyboardModifiers() const -{ - return playPathKeyboardModifiers_; +Qt::KeyboardModifiers QGLViewer::playPathKeyboardModifiers() const { + return playPathKeyboardModifiers_; } #ifndef DOXYGEN // Deprecated methods -Qt::KeyboardModifiers QGLViewer::addKeyFrameStateKey() const -{ - qWarning("addKeyFrameStateKey has been renamed addKeyFrameKeyboardModifiers"); - return addKeyFrameKeyboardModifiers(); } +Qt::KeyboardModifiers QGLViewer::addKeyFrameStateKey() const { + qWarning("addKeyFrameStateKey has been renamed addKeyFrameKeyboardModifiers"); + return addKeyFrameKeyboardModifiers(); +} -Qt::KeyboardModifiers QGLViewer::playPathStateKey() const -{ - qWarning("playPathStateKey has been renamed playPathKeyboardModifiers"); - return playPathKeyboardModifiers(); +Qt::KeyboardModifiers QGLViewer::playPathStateKey() const { + qWarning("playPathStateKey has been renamed playPathKeyboardModifiers"); + return playPathKeyboardModifiers(); } -void QGLViewer::setAddKeyFrameStateKey(unsigned int buttonState) -{ - qWarning("setAddKeyFrameStateKey has been renamed setAddKeyFrameKeyboardModifiers"); - setAddKeyFrameKeyboardModifiers(keyboardModifiersFromState(buttonState)); +void QGLViewer::setAddKeyFrameStateKey(unsigned int buttonState) { + qWarning("setAddKeyFrameStateKey has been renamed " + "setAddKeyFrameKeyboardModifiers"); + setAddKeyFrameKeyboardModifiers(keyboardModifiersFromState(buttonState)); } -void QGLViewer::setPlayPathStateKey(unsigned int buttonState) -{ - qWarning("setPlayPathStateKey has been renamed setPlayPathKeyboardModifiers"); - setPlayPathKeyboardModifiers(keyboardModifiersFromState(buttonState)); +void QGLViewer::setPlayPathStateKey(unsigned int buttonState) { + qWarning("setPlayPathStateKey has been renamed setPlayPathKeyboardModifiers"); + setPlayPathKeyboardModifiers(keyboardModifiersFromState(buttonState)); } -Qt::Key QGLViewer::keyFrameKey(unsigned int index) const -{ - qWarning("keyFrameKey has been renamed pathKey."); - return pathKey(index); +Qt::Key QGLViewer::keyFrameKey(unsigned int index) const { + qWarning("keyFrameKey has been renamed pathKey."); + return pathKey(index); } -Qt::KeyboardModifiers QGLViewer::playKeyFramePathStateKey() const -{ - qWarning("playKeyFramePathStateKey has been renamed playPathKeyboardModifiers."); - return playPathKeyboardModifiers(); +Qt::KeyboardModifiers QGLViewer::playKeyFramePathStateKey() const { + qWarning( + "playKeyFramePathStateKey has been renamed playPathKeyboardModifiers."); + return playPathKeyboardModifiers(); } -void QGLViewer::setKeyFrameKey(unsigned int index, int key) -{ - qWarning("setKeyFrameKey is deprecated, use setPathKey instead, with swapped parameters."); - setPathKey(key, index); +void QGLViewer::setKeyFrameKey(unsigned int index, int key) { + qWarning("setKeyFrameKey is deprecated, use setPathKey instead, with swapped " + "parameters."); + setPathKey(key, index); } -void QGLViewer::setPlayKeyFramePathStateKey(unsigned int buttonState) -{ - qWarning("setPlayKeyFramePathStateKey has been renamed setPlayPathKeyboardModifiers."); - setPlayPathKeyboardModifiers(keyboardModifiersFromState(buttonState)); +void QGLViewer::setPlayKeyFramePathStateKey(unsigned int buttonState) { + qWarning("setPlayKeyFramePathStateKey has been renamed " + "setPlayPathKeyboardModifiers."); + setPlayPathKeyboardModifiers(keyboardModifiersFromState(buttonState)); } #endif @@ -2408,33 +2637,35 @@ void QGLViewer::setPlayKeyFramePathStateKey(unsigned int buttonState) Associates keyboard modifiers to MouseHandler \p handler. -The \p modifiers parameter is \c Qt::AltModifier, \c Qt::ShiftModifier, \c Qt::ControlModifier, \c -Qt::MetaModifier or a combination of these using the '|' bitwise operator. +The \p modifiers parameter is \c Qt::AltModifier, \c Qt::ShiftModifier, \c +Qt::ControlModifier, \c Qt::MetaModifier or a combination of these using the '|' +bitwise operator. -\e All the \p handler's associated bindings will then need the specified \p modifiers key(s) to be -activated. +\e All the \p handler's associated bindings will then need the specified \p +modifiers key(s) to be activated. With this code, \code setHandlerKeyboardModifiers(QGLViewer::CAMERA, Qt::AltModifier); setHandlerKeyboardModifiers(QGLViewer::FRAME, Qt::NoModifier); \endcode -you will have to press the \c Alt key while pressing mouse buttons in order to move the camera(), -while no key will be needed to move the manipulatedFrame(). - -This method has a very basic implementation: every action binded to \p handler has its keyboard -modifier replaced by \p modifiers. If \p handler had some actions binded to different modifiers, -these settings will be lost. You should hence consider using setMouseBinding() for finer tuning. - -The default binding associates \c Qt::ControlModifier to all the QGLViewer::FRAME actions and \c -Qt::NoModifier to all QGLViewer::CAMERA actions. See mouse page for -details. - -\attention This method calls setMouseBinding(), which ensures that only one action is binded to a -given modifiers. If you want to \e swap the QGLViewer::CAMERA and QGLViewer::FRAME keyboard -modifiers, you have to use a temporary dummy modifier (as if you were swapping two variables) or -else the first call will overwrite the previous settings: -\code +you will have to press the \c Alt key while pressing mouse buttons in order to +move the camera(), while no key will be needed to move the manipulatedFrame(). + +This method has a very basic implementation: every action binded to \p handler +has its keyboard modifier replaced by \p modifiers. If \p handler had some +actions binded to different modifiers, these settings will be lost. You should +hence consider using setMouseBinding() for finer tuning. + +The default binding associates \c Qt::ControlModifier to all the +QGLViewer::FRAME actions and \c Qt::NoModifier to all QGLViewer::CAMERA actions. +See mouse page for details. + +\attention This method calls setMouseBinding(), which ensures that only one +action is binded to a given modifiers. If you want to \e swap the +QGLViewer::CAMERA and QGLViewer::FRAME keyboard modifiers, you have to use a +temporary dummy modifier (as if you were swapping two variables) or else the +first call will overwrite the previous settings: \code // Associate FRAME with Alt (temporary value) setHandlerKeyboardModifiers(QGLViewer::FRAME, Qt::AltModifier); // Control is associated with CAMERA @@ -2442,283 +2673,330 @@ setHandlerKeyboardModifiers(QGLViewer::CAMERA, Qt::ControlModifier); // And finally, FRAME can be associated with NoModifier setHandlerKeyboardModifiers(QGLViewer::FRAME, Qt::NoModifier); \endcode */ -void QGLViewer::setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers) -{ - qWarning("setHandlerKeyboardModifiers is deprecated, call setMouseBinding() instead"); - - QMap newMouseBinding; - QMap newWheelBinding; - QMap newClickBinding_; - - QMap::Iterator mit; - QMap::Iterator wit; - - // First copy unchanged bindings. - for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit) - if ((mit.value().handler != handler) || (mit.value().action == ZOOM_ON_REGION)) - newMouseBinding[mit.key()] = mit.value(); - - for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit) - if (wit.value().handler != handler) - newWheelBinding[wit.key()] = wit.value(); - - // Then, add modified bindings, that can overwrite the previous ones. - for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit) - if ((mit.value().handler == handler) && (mit.value().action != ZOOM_ON_REGION)) - { - MouseBindingPrivate mbp(modifiers, mit.key().button, mit.key().key); - newMouseBinding[mbp] = mit.value(); - } - - for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit) - if (wit.value().handler == handler) - { - WheelBindingPrivate wbp(modifiers, wit.key().key); - newWheelBinding[wbp] = wit.value(); - } - - // Same for button bindings - for (QMap::ConstIterator cb=clickBinding_.begin(), end=clickBinding_.end(); cb != end; ++cb) - if (((handler==CAMERA) && ((cb.value() == CENTER_SCENE) || (cb.value() == ALIGN_CAMERA))) || - ((handler==FRAME) && ((cb.value() == CENTER_FRAME) || (cb.value() == ALIGN_FRAME)))) - { - ClickBindingPrivate cbp(modifiers, cb.key().button, cb.key().doubleClick, cb.key().buttonsBefore, cb.key().key); - newClickBinding_[cbp] = cb.value(); - } - else - newClickBinding_[cb.key()] = cb.value(); - - mouseBinding_ = newMouseBinding; - wheelBinding_ = newWheelBinding; - clickBinding_ = newClickBinding_; -} - -void QGLViewer::setHandlerStateKey(MouseHandler handler, unsigned int buttonState) -{ - qWarning("setHandlerStateKey has been renamed setHandlerKeyboardModifiers"); - setHandlerKeyboardModifiers(handler, keyboardModifiersFromState(buttonState)); -} - -void QGLViewer::setMouseStateKey(MouseHandler handler, unsigned int buttonState) -{ - qWarning("setMouseStateKey has been renamed setHandlerKeyboardModifiers."); - setHandlerKeyboardModifiers(handler, keyboardModifiersFromState(buttonState)); +void QGLViewer::setHandlerKeyboardModifiers(MouseHandler handler, + Qt::KeyboardModifiers modifiers) { + qWarning("setHandlerKeyboardModifiers is deprecated, call setMouseBinding() " + "instead"); + + QMap newMouseBinding; + QMap newWheelBinding; + QMap newClickBinding_; + + QMap::Iterator mit; + QMap::Iterator wit; + + // First copy unchanged bindings. + for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit) + if ((mit.value().handler != handler) || + (mit.value().action == ZOOM_ON_REGION)) + newMouseBinding[mit.key()] = mit.value(); + + for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit) + if (wit.value().handler != handler) + newWheelBinding[wit.key()] = wit.value(); + + // Then, add modified bindings, that can overwrite the previous ones. + for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit) + if ((mit.value().handler == handler) && + (mit.value().action != ZOOM_ON_REGION)) { + MouseBindingPrivate mbp(modifiers, mit.key().button, mit.key().key); + newMouseBinding[mbp] = mit.value(); + } + + for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit) + if (wit.value().handler == handler) { + WheelBindingPrivate wbp(modifiers, wit.key().key); + newWheelBinding[wbp] = wit.value(); + } + + // Same for button bindings + for (QMap::ConstIterator + cb = clickBinding_.begin(), + end = clickBinding_.end(); + cb != end; ++cb) + if (((handler == CAMERA) && + ((cb.value() == CENTER_SCENE) || (cb.value() == ALIGN_CAMERA))) || + ((handler == FRAME) && + ((cb.value() == CENTER_FRAME) || (cb.value() == ALIGN_FRAME)))) { + ClickBindingPrivate cbp(modifiers, cb.key().button, cb.key().doubleClick, + cb.key().buttonsBefore, cb.key().key); + newClickBinding_[cbp] = cb.value(); + } else + newClickBinding_[cb.key()] = cb.value(); + + mouseBinding_ = newMouseBinding; + wheelBinding_ = newWheelBinding; + clickBinding_ = newClickBinding_; +} + +void QGLViewer::setHandlerStateKey(MouseHandler handler, + unsigned int buttonState) { + qWarning("setHandlerStateKey has been renamed setHandlerKeyboardModifiers"); + setHandlerKeyboardModifiers(handler, keyboardModifiersFromState(buttonState)); +} + +void QGLViewer::setMouseStateKey(MouseHandler handler, + unsigned int buttonState) { + qWarning("setMouseStateKey has been renamed setHandlerKeyboardModifiers."); + setHandlerKeyboardModifiers(handler, keyboardModifiersFromState(buttonState)); } /*! This method is deprecated since version 2.5.0 - Use setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, MouseHandler, MouseAction, bool) instead. + Use setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, MouseHandler, + MouseAction, bool) instead. */ -void QGLViewer::setMouseBinding(unsigned int state, MouseHandler handler, MouseAction action, bool withConstraint) -{ - qWarning("setMouseBinding(int state, MouseHandler...) is deprecated. Use the modifier/button equivalent"); - setMouseBinding(keyboardModifiersFromState(state), - mouseButtonFromState(state), - handler, - action, - withConstraint); +void QGLViewer::setMouseBinding(unsigned int state, MouseHandler handler, + MouseAction action, bool withConstraint) { + qWarning("setMouseBinding(int state, MouseHandler...) is deprecated. Use the " + "modifier/button equivalent"); + setMouseBinding(keyboardModifiersFromState(state), + mouseButtonFromState(state), handler, action, withConstraint); } #endif /*! Defines a MouseAction binding. - Same as calling setMouseBinding(Qt::Key, Qt::KeyboardModifiers, Qt::MouseButton, MouseHandler, MouseAction, bool), - with a key value of Qt::Key(0) (i.e. no regular extra key needs to be pressed to perform this action). */ -void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, MouseHandler handler, MouseAction action, bool withConstraint) { - setMouseBinding(Qt::Key(0), modifiers, button, handler, action, withConstraint); + Same as calling setMouseBinding(Qt::Key, Qt::KeyboardModifiers, + Qt::MouseButton, MouseHandler, MouseAction, bool), with a key value of + Qt::Key(0) (i.e. no regular extra key needs to be pressed to perform this + action). */ +void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, MouseHandler handler, + MouseAction action, bool withConstraint) { + setMouseBinding(Qt::Key(0), modifiers, button, handler, action, + withConstraint); } -/*! Associates a MouseAction to any mouse \p button, while keyboard \p modifiers and \p key are pressed. -The receiver of the mouse events is a MouseHandler (QGLViewer::CAMERA or QGLViewer::FRAME). +/*! Associates a MouseAction to any mouse \p button, while keyboard \p modifiers +and \p key are pressed. The receiver of the mouse events is a MouseHandler +(QGLViewer::CAMERA or QGLViewer::FRAME). -The parameters should read: when the mouse \p button is pressed, while the keyboard \p modifiers and \p key are down, -activate \p action on \p handler. Use Qt::NoModifier to indicate that no modifier -key is needed, and a \p key value of 0 if no regular key has to be pressed -(or simply use setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButton, MouseHandler, MouseAction, bool)). +The parameters should read: when the mouse \p button is pressed, while the +keyboard \p modifiers and \p key are down, activate \p action on \p handler. Use +Qt::NoModifier to indicate that no modifier key is needed, and a \p key value of +0 if no regular key has to be pressed (or simply use +setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButton, MouseHandler, +MouseAction, bool)). Use the '|' operator to combine modifiers: \code -// The R key combined with the Left mouse button rotates the camera in the screen plane. -setMouseBinding(Qt::Key_R, Qt::NoModifier, Qt::LeftButton, CAMERA, SCREEN_ROTATE); +// The R key combined with the Left mouse button rotates the camera in the +screen plane. setMouseBinding(Qt::Key_R, Qt::NoModifier, Qt::LeftButton, CAMERA, +SCREEN_ROTATE); // Alt + Shift and Left button rotates the manipulatedFrame(). -setMouseBinding(Qt::AltModifier | Qt::ShiftModifier, Qt::LeftButton, FRAME, ROTATE); -\endcode +setMouseBinding(Qt::AltModifier | Qt::ShiftModifier, Qt::LeftButton, FRAME, +ROTATE); \endcode If \p withConstraint is \c true (default), the possible -qglviewer::Frame::constraint() of the associated Frame will be enforced during motion. +qglviewer::Frame::constraint() of the associated Frame will be enforced during +motion. -The list of all possible MouseAction, some binding examples and default bindings are provided in -the mouse page. +The list of all possible MouseAction, some binding examples and default bindings +are provided in the mouse page. -See the keyboardAndMouse example for an illustration. +See the keyboardAndMouse example +for an illustration. -If no mouse button is specified, the binding is ignored. If an action was previously -associated with this keyboard and button combination, it is silently overwritten (call mouseAction() -before to check). +If no mouse button is specified, the binding is ignored. If an action was +previously associated with this keyboard and button combination, it is silently +overwritten (call mouseAction() before to check). To remove a specific mouse binding, use \p NO_MOUSE_ACTION as the \p action. -See also setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, ClickAction, bool, int), setWheelBinding() and clearMouseBindings(). */ -void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, MouseHandler handler, MouseAction action, bool withConstraint) -{ - if ((handler == FRAME) && ((action == MOVE_FORWARD) || (action == MOVE_BACKWARD) || - (action == ROLL) || (action == LOOK_AROUND) || - (action == ZOOM_ON_REGION))) { - qWarning("Cannot bind %s to FRAME", mouseActionString(action).toLatin1().constData()); - return; - } +See also setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, ClickAction, +bool, int), setWheelBinding() and clearMouseBindings(). */ +void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, MouseHandler handler, + MouseAction action, bool withConstraint) { + if ((handler == FRAME) && + ((action == MOVE_FORWARD) || (action == MOVE_BACKWARD) || + (action == ROLL) || (action == LOOK_AROUND) || + (action == ZOOM_ON_REGION))) { + qWarning("Cannot bind %s to FRAME", + mouseActionString(action).toLatin1().constData()); + return; + } - if (button == Qt::NoButton) { - qWarning("No mouse button specified in setMouseBinding"); - return; - } + if (button == Qt::NoButton) { + qWarning("No mouse button specified in setMouseBinding"); + return; + } - MouseActionPrivate map; - map.handler = handler; - map.action = action; - map.withConstraint = withConstraint; + MouseActionPrivate map; + map.handler = handler; + map.action = action; + map.withConstraint = withConstraint; - MouseBindingPrivate mbp(modifiers, button, key); - if (action == NO_MOUSE_ACTION) - mouseBinding_.remove(mbp); - else - mouseBinding_.insert(mbp, map); + MouseBindingPrivate mbp(modifiers, button, key); + if (action == NO_MOUSE_ACTION) + mouseBinding_.remove(mbp); + else + mouseBinding_.insert(mbp, map); - ClickBindingPrivate cbp(modifiers, button, false, Qt::NoButton, key); - clickBinding_.remove(cbp); + ClickBindingPrivate cbp(modifiers, button, false, Qt::NoButton, key); + clickBinding_.remove(cbp); } #ifndef DOXYGEN /*! This method is deprecated since version 2.5.0 - Use setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, MouseHandler, MouseAction, bool) instead. + Use setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, MouseHandler, + MouseAction, bool) instead. */ -void QGLViewer::setMouseBinding(unsigned int state, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore) { - qWarning("setMouseBinding(int state, ClickAction...) is deprecated. Use the modifier/button equivalent"); - setMouseBinding(keyboardModifiersFromState(state), - mouseButtonFromState(state), - action, - doubleClick, - buttonsBefore); +void QGLViewer::setMouseBinding(unsigned int state, ClickAction action, + bool doubleClick, + Qt::MouseButtons buttonsBefore) { + qWarning("setMouseBinding(int state, ClickAction...) is deprecated. Use the " + "modifier/button equivalent"); + setMouseBinding(keyboardModifiersFromState(state), + mouseButtonFromState(state), action, doubleClick, + buttonsBefore); } #endif /*! Defines a ClickAction binding. - Same as calling setMouseBinding(Qt::Key, Qt::KeyboardModifiers, Qt::MouseButton, ClickAction, bool, Qt::MouseButtons), - with a key value of Qt::Key(0) (i.e. no regular key needs to be pressed to activate this action). */ -void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore) -{ - setMouseBinding(Qt::Key(0), modifiers, button, action, doubleClick, buttonsBefore); + Same as calling setMouseBinding(Qt::Key, Qt::KeyboardModifiers, + Qt::MouseButton, ClickAction, bool, Qt::MouseButtons), with a key value of + Qt::Key(0) (i.e. no regular key needs to be pressed to activate this action). + */ +void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, ClickAction action, + bool doubleClick, + Qt::MouseButtons buttonsBefore) { + setMouseBinding(Qt::Key(0), modifiers, button, action, doubleClick, + buttonsBefore); } -/*! Associates a ClickAction to a button and keyboard key and modifier(s) combination. +/*! Associates a ClickAction to a button and keyboard key and modifier(s) +combination. -The parameters should read: when \p button is pressed, while the \p modifiers and \p key keys are down, -and possibly as a \p doubleClick, then perform \p action. Use Qt::NoModifier to indicate that no modifier -key is needed, and a \p key value of 0 if no regular key has to be pressed (or simply use -setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButton, ClickAction, bool, Qt::MouseButtons)). +The parameters should read: when \p button is pressed, while the \p modifiers +and \p key keys are down, and possibly as a \p doubleClick, then perform \p +action. Use Qt::NoModifier to indicate that no modifier key is needed, and a \p +key value of 0 if no regular key has to be pressed (or simply use +setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButton, ClickAction, bool, +Qt::MouseButtons)). -If \p buttonsBefore is specified (valid only when \p doubleClick is \c true), then this (or these) other mouse -button(s) has (have) to be pressed \e before the double click occurs in order to execute \p action. +If \p buttonsBefore is specified (valid only when \p doubleClick is \c true), +then this (or these) other mouse button(s) has (have) to be pressed \e before +the double click occurs in order to execute \p action. -The list of all possible ClickAction, some binding examples and default bindings are listed in the -mouse page. See also the setMouseBinding() documentation. +The list of all possible ClickAction, some binding examples and default bindings +are listed in the mouse page. See also the +setMouseBinding() documentation. -See the keyboardAndMouse example for an -illustration. +See the keyboardAndMouse example +for an illustration. The binding is ignored if Qt::NoButton is specified as \p buttons. -See also setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, MouseHandler, MouseAction, bool), setWheelBinding() and clearMouseBindings(). +See also setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, MouseHandler, +MouseAction, bool), setWheelBinding() and clearMouseBindings(). */ -void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore) -{ - if ((buttonsBefore != Qt::NoButton) && !doubleClick) { - qWarning("Buttons before is only meaningful when doubleClick is true in setMouseBinding()."); - return; - } +void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, ClickAction action, + bool doubleClick, + Qt::MouseButtons buttonsBefore) { + if ((buttonsBefore != Qt::NoButton) && !doubleClick) { + qWarning("Buttons before is only meaningful when doubleClick is true in " + "setMouseBinding()."); + return; + } - if (button == Qt::NoButton) { - qWarning("No mouse button specified in setMouseBinding"); - return; - } + if (button == Qt::NoButton) { + qWarning("No mouse button specified in setMouseBinding"); + return; + } - ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key); + ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key); - // #CONNECTION performClickAction comment on NO_CLICK_ACTION - if (action == NO_CLICK_ACTION) - clickBinding_.remove(cbp); - else - clickBinding_.insert(cbp, action); + // #CONNECTION performClickAction comment on NO_CLICK_ACTION + if (action == NO_CLICK_ACTION) + clickBinding_.remove(cbp); + else + clickBinding_.insert(cbp, action); - if ((!doubleClick) && (buttonsBefore == Qt::NoButton)) { - MouseBindingPrivate mbp(modifiers, button, key); - mouseBinding_.remove(mbp); - } + if ((!doubleClick) && (buttonsBefore == Qt::NoButton)) { + MouseBindingPrivate mbp(modifiers, button, key); + mouseBinding_.remove(mbp); + } } /*! Defines a mouse wheel binding. - Same as calling setWheelBinding(Qt::Key, Qt::KeyboardModifiers, MouseHandler, MouseAction, bool), - with a key value of Qt::Key(0) (i.e. no regular key needs to be pressed to activate this action). */ -void QGLViewer::setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint) { - setWheelBinding(Qt::Key(0), modifiers, handler, action, withConstraint); + Same as calling setWheelBinding(Qt::Key, Qt::KeyboardModifiers, MouseHandler, + MouseAction, bool), with a key value of Qt::Key(0) (i.e. no regular key needs + to be pressed to activate this action). */ +void QGLViewer::setWheelBinding(Qt::KeyboardModifiers modifiers, + MouseHandler handler, MouseAction action, + bool withConstraint) { + setWheelBinding(Qt::Key(0), modifiers, handler, action, withConstraint); } /*! Associates a MouseAction and a MouseHandler to a mouse wheel event. This method is very similar to setMouseBinding(), but specific to the wheel. -In the current implementation only QGLViewer::ZOOM can be associated with QGLViewer::FRAME, while -QGLViewer::CAMERA can receive QGLViewer::ZOOM and QGLViewer::MOVE_FORWARD. - -The difference between QGLViewer::ZOOM and QGLViewer::MOVE_FORWARD is that QGLViewer::ZOOM speed -depends on the distance to the object, while QGLViewer::MOVE_FORWARD moves at a constant speed -defined by qglviewer::Camera::flySpeed(). */ -void QGLViewer::setWheelBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint) -{ - //#CONNECTION# ManipulatedFrame::wheelEvent and ManipulatedCameraFrame::wheelEvent switches - if ((action != ZOOM) && (action != MOVE_FORWARD) && (action != MOVE_BACKWARD) && (action != NO_MOUSE_ACTION)) { - qWarning("Cannot bind %s to wheel", mouseActionString(action).toLatin1().constData()); - return; - } +In the current implementation only QGLViewer::ZOOM can be associated with +QGLViewer::FRAME, while QGLViewer::CAMERA can receive QGLViewer::ZOOM and +QGLViewer::MOVE_FORWARD. + +The difference between QGLViewer::ZOOM and QGLViewer::MOVE_FORWARD is that +QGLViewer::ZOOM speed depends on the distance to the object, while +QGLViewer::MOVE_FORWARD moves at a constant speed defined by +qglviewer::Camera::flySpeed(). */ +void QGLViewer::setWheelBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, + MouseHandler handler, MouseAction action, + bool withConstraint) { + //#CONNECTION# ManipulatedFrame::wheelEvent and + // ManipulatedCameraFrame::wheelEvent switches + if ((action != ZOOM) && (action != MOVE_FORWARD) && + (action != MOVE_BACKWARD) && (action != NO_MOUSE_ACTION)) { + qWarning("Cannot bind %s to wheel", + mouseActionString(action).toLatin1().constData()); + return; + } - if ((handler == FRAME) && (action != ZOOM) && (action != NO_MOUSE_ACTION)) { - qWarning("Cannot bind %s to FRAME wheel", mouseActionString(action).toLatin1().constData()); - return; - } + if ((handler == FRAME) && (action != ZOOM) && (action != NO_MOUSE_ACTION)) { + qWarning("Cannot bind %s to FRAME wheel", + mouseActionString(action).toLatin1().constData()); + return; + } - MouseActionPrivate map; - map.handler = handler; - map.action = action; - map.withConstraint = withConstraint; + MouseActionPrivate map; + map.handler = handler; + map.action = action; + map.withConstraint = withConstraint; - WheelBindingPrivate wbp(modifiers, key); - if (action == NO_MOUSE_ACTION) - wheelBinding_.remove(wbp); - else - wheelBinding_[wbp] = map; + WheelBindingPrivate wbp(modifiers, key); + if (action == NO_MOUSE_ACTION) + wheelBinding_.remove(wbp); + else + wheelBinding_[wbp] = map; } /*! Clears all the default mouse bindings. -After this call, you will have to use setMouseBinding() and setWheelBinding() to restore the mouse bindings you are interested in. +After this call, you will have to use setMouseBinding() and setWheelBinding() to +restore the mouse bindings you are interested in. */ void QGLViewer::clearMouseBindings() { - mouseBinding_.clear(); - clickBinding_.clear(); - wheelBinding_.clear(); + mouseBinding_.clear(); + clickBinding_.clear(); + wheelBinding_.clear(); } /*! Clears all the default keyboard shortcuts. -After this call, you will have to use setShortcut() to define your own keyboard shortcuts. +After this call, you will have to use setShortcut() to define your own keyboard +shortcuts. */ void QGLViewer::clearShortcuts() { - keyboardBinding_.clear(); - pathIndex_.clear(); + keyboardBinding_.clear(); + pathIndex_.clear(); } /*! This method is deprecated since version 2.5.0 @@ -2726,15 +3004,18 @@ void QGLViewer::clearShortcuts() { Use mouseAction(Qt::Key, Qt::KeyboardModifiers, Qt::MouseButtons) instead. */ QGLViewer::MouseAction QGLViewer::mouseAction(unsigned int state) const { - qWarning("mouseAction(int state,...) is deprecated. Use the modifier/button equivalent"); - return mouseAction(Qt::Key(0), keyboardModifiersFromState(state), mouseButtonFromState(state)); + qWarning("mouseAction(int state,...) is deprecated. Use the modifier/button " + "equivalent"); + return mouseAction(Qt::Key(0), keyboardModifiersFromState(state), + mouseButtonFromState(state)); } -/*! Returns the MouseAction the will be triggered when the mouse \p button is pressed, -while the keyboard \p modifiers and \p key are pressed. +/*! Returns the MouseAction the will be triggered when the mouse \p button is +pressed, while the keyboard \p modifiers and \p key are pressed. -Returns QGLViewer::NO_MOUSE_ACTION if no action is associated with this combination. Use 0 for \p key -to indicate that no regular key needs to be pressed. +Returns QGLViewer::NO_MOUSE_ACTION if no action is associated with this +combination. Use 0 for \p key to indicate that no regular key needs to be +pressed. For instance, to know which motion corresponds to Alt+LeftButton, do: \code @@ -2742,15 +3023,16 @@ QGLViewer::MouseAction ma = mouseAction(0, Qt::AltModifier, Qt::LeftButton); if (ma != QGLViewer::NO_MOUSE_ACTION) ... \endcode -Use mouseHandler() to know which object (QGLViewer::CAMERA or QGLViewer::FRAME) will execute this -action. */ -QGLViewer::MouseAction QGLViewer::mouseAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const -{ - MouseBindingPrivate mbp(modifiers, button, key); - if (mouseBinding_.contains(mbp)) - return mouseBinding_[mbp].action; - else - return NO_MOUSE_ACTION; +Use mouseHandler() to know which object (QGLViewer::CAMERA or QGLViewer::FRAME) +will execute this action. */ +QGLViewer::MouseAction QGLViewer::mouseAction(Qt::Key key, + Qt::KeyboardModifiers modifiers, + Qt::MouseButton button) const { + MouseBindingPrivate mbp(modifiers, button, key); + if (mouseBinding_.contains(mbp)) + return mouseBinding_[mbp].action; + else + return NO_MOUSE_ACTION; } /*! This method is deprecated since version 2.5.0 @@ -2758,14 +3040,17 @@ QGLViewer::MouseAction QGLViewer::mouseAction(Qt::Key key, Qt::KeyboardModifiers Use mouseHanler(Qt::Key, Qt::KeyboardModifiers, Qt::MouseButtons) instead. */ int QGLViewer::mouseHandler(unsigned int state) const { - qWarning("mouseHandler(int state,...) is deprecated. Use the modifier/button equivalent"); - return mouseHandler(Qt::Key(0), keyboardModifiersFromState(state), mouseButtonFromState(state)); + qWarning("mouseHandler(int state,...) is deprecated. Use the modifier/button " + "equivalent"); + return mouseHandler(Qt::Key(0), keyboardModifiersFromState(state), + mouseButtonFromState(state)); } -/*! Returns the MouseHandler which will be activated when the mouse \p button is pressed, while the \p modifiers and \p key are pressed. +/*! Returns the MouseHandler which will be activated when the mouse \p button is +pressed, while the \p modifiers and \p key are pressed. -If no action is associated with this combination, returns \c -1. Use 0 for \p key and Qt::NoModifier for \p modifiers -to represent the lack of a key press. +If no action is associated with this combination, returns \c -1. Use 0 for \p +key and Qt::NoModifier for \p modifiers to represent the lack of a key press. For instance, to know which handler receives the Alt+LeftButton, do: \code @@ -2773,270 +3058,322 @@ int mh = mouseHandler(0, Qt::AltModifier, Qt::LeftButton); if (mh == QGLViewer::CAMERA) ... \endcode -Use mouseAction() to know which action (see the MouseAction enum) will be performed on this handler. */ -int QGLViewer::mouseHandler(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const -{ - MouseBindingPrivate mbp(modifiers, button, key); - if (mouseBinding_.contains(mbp)) - return mouseBinding_[mbp].handler; - else - return -1; +Use mouseAction() to know which action (see the MouseAction enum) will be +performed on this handler. */ +int QGLViewer::mouseHandler(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button) const { + MouseBindingPrivate mbp(modifiers, button, key); + if (mouseBinding_.contains(mbp)) + return mouseBinding_[mbp].handler; + else + return -1; } - #ifndef DOXYGEN /*! This method is deprecated since version 2.5.0 Use mouseButtons() and keyboardModifiers() instead. */ -int QGLViewer::mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const { - qWarning("mouseButtonState() is deprecated. Use mouseButtons() and keyboardModifiers() instead"); - for (QMap::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it) - if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) - return (int) it.key().modifiers | (int) it.key().button; - - return Qt::NoButton; +int QGLViewer::mouseButtonState(MouseHandler handler, MouseAction action, + bool withConstraint) const { + qWarning("mouseButtonState() is deprecated. Use mouseButtons() and " + "keyboardModifiers() instead"); + for (QMap::ConstIterator + it = mouseBinding_.begin(), + end = mouseBinding_.end(); + it != end; ++it) + if ((it.value().handler == handler) && (it.value().action == action) && + (it.value().withConstraint == withConstraint)) + return static_cast(it.key().modifiers) | static_cast(it.key().button); + + return Qt::NoButton; } #endif -/*! Returns the keyboard state that triggers \p action on \p handler \p withConstraint using the mouse wheel. +/*! Returns the keyboard state that triggers \p action on \p handler \p +withConstraint using the mouse wheel. If such a binding exists, results are stored in the \p key and \p modifiers -parameters. If the MouseAction \p action is not bound, \p key is set to the illegal -1 value. -If several keyboard states trigger the MouseAction, one of them is returned. +parameters. If the MouseAction \p action is not bound, \p key is set to the +illegal -1 value. If several keyboard states trigger the MouseAction, one of +them is returned. -See also setMouseBinding(), getClickActionBinding() and getMouseActionBinding(). */ -void QGLViewer::getWheelActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, - Qt::Key& key, Qt::KeyboardModifiers& modifiers) const -{ - for (QMap::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it != end; ++it) - if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) { - key = it.key().key; - modifiers = it.key().modifiers; - return; - } - - key = Qt::Key(-1); - modifiers = Qt::NoModifier; -} - -/*! Returns the mouse and keyboard state that triggers \p action on \p handler \p withConstraint. - -If such a binding exists, results are stored in the \p key, \p modifiers and \p button -parameters. If the MouseAction \p action is not bound, \p button is set to \c Qt::NoButton. -If several mouse and keyboard states trigger the MouseAction, one of them is returned. - -See also setMouseBinding(), getClickActionBinding() and getWheelActionBinding(). */ -void QGLViewer::getMouseActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, - Qt::Key& key, Qt::KeyboardModifiers& modifiers, Qt::MouseButton& button) const -{ - for (QMap::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it) { - if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) { - key = it.key().key; - modifiers = it.key().modifiers; - button = it.key().button; - return; - } - } +See also setMouseBinding(), getClickActionBinding() and getMouseActionBinding(). +*/ +void QGLViewer::getWheelActionBinding(MouseHandler handler, MouseAction action, + bool withConstraint, Qt::Key &key, + Qt::KeyboardModifiers &modifiers) const { + for (QMap::ConstIterator + it = wheelBinding_.begin(), + end = wheelBinding_.end(); + it != end; ++it) + if ((it.value().handler == handler) && (it.value().action == action) && + (it.value().withConstraint == withConstraint)) { + key = it.key().key; + modifiers = it.key().modifiers; + return; + } + + key = Qt::Key(-1); + modifiers = Qt::NoModifier; +} + +/*! Returns the mouse and keyboard state that triggers \p action on \p handler +\p withConstraint. + +If such a binding exists, results are stored in the \p key, \p modifiers and \p +button parameters. If the MouseAction \p action is not bound, \p button is set +to \c Qt::NoButton. If several mouse and keyboard states trigger the +MouseAction, one of them is returned. + +See also setMouseBinding(), getClickActionBinding() and getWheelActionBinding(). +*/ +void QGLViewer::getMouseActionBinding(MouseHandler handler, MouseAction action, + bool withConstraint, Qt::Key &key, + Qt::KeyboardModifiers &modifiers, + Qt::MouseButton &button) const { + for (QMap::ConstIterator + it = mouseBinding_.begin(), + end = mouseBinding_.end(); + it != end; ++it) { + if ((it.value().handler == handler) && (it.value().action == action) && + (it.value().withConstraint == withConstraint)) { + key = it.key().key; + modifiers = it.key().modifiers; + button = it.key().button; + return; + } + } - key = Qt::Key(0); - modifiers = Qt::NoModifier; - button = Qt::NoButton; + key = Qt::Key(0); + modifiers = Qt::NoModifier; + button = Qt::NoButton; } -/*! Returns the MouseAction (if any) that is performed when using the wheel, when the \p modifiers and \p key keyboard keys are pressed. +/*! Returns the MouseAction (if any) that is performed when using the wheel, +when the \p modifiers and \p key keyboard keys are pressed. -Returns NO_MOUSE_ACTION if no such binding has been defined using setWheelBinding(). +Returns NO_MOUSE_ACTION if no such binding has been defined using +setWheelBinding(). Same as mouseAction(), but for the wheel action. See also wheelHandler(). */ -QGLViewer::MouseAction QGLViewer::wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const -{ - WheelBindingPrivate wbp(modifiers, key); - if (wheelBinding_.contains(wbp)) - return wheelBinding_[wbp].action; - else - return NO_MOUSE_ACTION; +QGLViewer::MouseAction +QGLViewer::wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const { + WheelBindingPrivate wbp(modifiers, key); + if (wheelBinding_.contains(wbp)) + return wheelBinding_[wbp].action; + else + return NO_MOUSE_ACTION; } -/*! Returns the MouseHandler (if any) that receives wheel events when the \p modifiers and \p key keyboard keys are pressed. +/*! Returns the MouseHandler (if any) that receives wheel events when the \p + modifiers and \p key keyboard keys are pressed. - Returns -1 if no no such binding has been defined using setWheelBinding(). See also wheelAction(). + Returns -1 if no no such binding has been defined using setWheelBinding(). See + also wheelAction(). */ -int QGLViewer::wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const -{ - WheelBindingPrivate wbp(modifiers, key); - if (wheelBinding_.contains(wbp)) - return wheelBinding_[wbp].handler; - else - return -1; +int QGLViewer::wheelHandler(Qt::Key key, + Qt::KeyboardModifiers modifiers) const { + WheelBindingPrivate wbp(modifiers, key); + if (wheelBinding_.contains(wbp)) + return wheelBinding_[wbp].handler; + else + return -1; } /*! Same as mouseAction(), but for the ClickAction set using setMouseBinding(). -Returns NO_CLICK_ACTION if no click action is associated with this keyboard and mouse buttons combination. */ -QGLViewer::ClickAction QGLViewer::clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, - bool doubleClick, Qt::MouseButtons buttonsBefore) const { - ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key); - if (clickBinding_.contains(cbp)) - return clickBinding_[cbp]; - else - return NO_CLICK_ACTION; +Returns NO_CLICK_ACTION if no click action is associated with this keyboard and +mouse buttons combination. */ +QGLViewer::ClickAction +QGLViewer::clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, bool doubleClick, + Qt::MouseButtons buttonsBefore) const { + ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key); + if (clickBinding_.contains(cbp)) + return clickBinding_[cbp]; + else + return NO_CLICK_ACTION; } #ifndef DOXYGEN /*! This method is deprecated since version 2.5.0 - Use wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) instead. */ -QGLViewer::MouseAction QGLViewer::wheelAction(Qt::KeyboardModifiers modifiers) const { - qWarning("wheelAction() is deprecated. Use the new wheelAction() method with a key parameter instead"); - return wheelAction(Qt::Key(0), modifiers); + Use wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) instead. */ +QGLViewer::MouseAction +QGLViewer::wheelAction(Qt::KeyboardModifiers modifiers) const { + qWarning("wheelAction() is deprecated. Use the new wheelAction() method with " + "a key parameter instead"); + return wheelAction(Qt::Key(0), modifiers); } /*! This method is deprecated since version 2.5.0 - Use wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) instead. */ + Use wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) instead. */ int QGLViewer::wheelHandler(Qt::KeyboardModifiers modifiers) const { - qWarning("wheelHandler() is deprecated. Use the new wheelHandler() method with a key parameter instead"); - return wheelHandler(Qt::Key(0), modifiers); + qWarning("wheelHandler() is deprecated. Use the new wheelHandler() method " + "with a key parameter instead"); + return wheelHandler(Qt::Key(0), modifiers); } /*! This method is deprecated since version 2.5.0 Use wheelAction() and wheelHandler() instead. */ -unsigned int QGLViewer::wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const -{ - qWarning("wheelButtonState() is deprecated. Use the wheelAction() and wheelHandler() instead"); - for (QMap::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it) - if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) - return it.key().key + it.key().modifiers; - - return -1; +unsigned int QGLViewer::wheelButtonState(MouseHandler handler, + MouseAction action, + bool withConstraint) const { + qWarning("wheelButtonState() is deprecated. Use the wheelAction() and " + "wheelHandler() instead"); + for (QMap::ConstIterator + it = wheelBinding_.begin(), + end = wheelBinding_.end(); + it != end; ++it) + if ((it.value().handler == handler) && (it.value().action == action) && + (it.value().withConstraint == withConstraint)) + return it.key().key + it.key().modifiers; + + return -1; } /*! This method is deprecated since version 2.5.0 - Use clickAction(Qt::KeyboardModifiers, Qt::MouseButtons, bool, Qt::MouseButtons) instead. + Use clickAction(Qt::KeyboardModifiers, Qt::MouseButtons, bool, + Qt::MouseButtons) instead. */ -QGLViewer::ClickAction QGLViewer::clickAction(unsigned int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const { - qWarning("clickAction(int state,...) is deprecated. Use the modifier/button equivalent"); - return clickAction(Qt::Key(0), - keyboardModifiersFromState(state), - mouseButtonFromState(state), - doubleClick, - buttonsBefore); +QGLViewer::ClickAction +QGLViewer::clickAction(unsigned int state, bool doubleClick, + Qt::MouseButtons buttonsBefore) const { + qWarning("clickAction(int state,...) is deprecated. Use the modifier/button " + "equivalent"); + return clickAction(Qt::Key(0), keyboardModifiersFromState(state), + mouseButtonFromState(state), doubleClick, buttonsBefore); } /*! This method is deprecated since version 2.5.0 - Use getClickActionState(ClickAction, Qt::Key, Qt::KeyboardModifiers, Qt::MouseButton, bool, Qt::MouseButtons) instead. + Use getClickActionState(ClickAction, Qt::Key, Qt::KeyboardModifiers, + Qt::MouseButton, bool, Qt::MouseButtons) instead. */ -void QGLViewer::getClickButtonState(ClickAction action, unsigned int& state, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const { - qWarning("getClickButtonState(int state,...) is deprecated. Use the modifier/button equivalent"); - Qt::KeyboardModifiers modifiers; - Qt::MouseButton button; - Qt::Key key; - getClickActionBinding(action, key, modifiers, button, doubleClick, buttonsBefore); - state = (unsigned int) modifiers | (unsigned int) button | (unsigned int) key; +void QGLViewer::getClickButtonState(ClickAction action, unsigned int &state, + bool &doubleClick, + Qt::MouseButtons &buttonsBefore) const { + qWarning("getClickButtonState(int state,...) is deprecated. Use the " + "modifier/button equivalent"); + Qt::KeyboardModifiers modifiers; + Qt::MouseButton button; + Qt::Key key; + getClickActionBinding(action, key, modifiers, button, doubleClick, + buttonsBefore); + state = (unsigned int)modifiers | (unsigned int)button | (unsigned int)key; } #endif /*! Returns the mouse and keyboard state that triggers \p action. -If such a binding exists, results are stored in the \p key, \p modifiers, \p button, \p doubleClick and \p buttonsBefore -parameters. If the ClickAction \p action is not bound, \p button is set to \c Qt::NoButton. -If several mouse buttons trigger in the ClickAction, one of them is returned. +If such a binding exists, results are stored in the \p key, \p modifiers, \p +button, \p doubleClick and \p buttonsBefore parameters. If the ClickAction \p +action is not bound, \p button is set to \c Qt::NoButton. If several mouse +buttons trigger in the ClickAction, one of them is returned. -See also setMouseBinding(), getMouseActionBinding() and getWheelActionBinding(). */ -void QGLViewer::getClickActionBinding(ClickAction action, Qt::Key& key, Qt::KeyboardModifiers& modifiers, Qt::MouseButton &button, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const -{ - for (QMap::ConstIterator it=clickBinding_.begin(), end=clickBinding_.end(); it != end; ++it) - if (it.value() == action) { - modifiers = it.key().modifiers; - button = it.key().button; - doubleClick = it.key().doubleClick; - buttonsBefore = it.key().buttonsBefore; - key = it.key().key; - return; - } - - modifiers = Qt::NoModifier; - button = Qt::NoButton; - doubleClick = false; - buttonsBefore = Qt::NoButton; - key = Qt::Key(0); -} - -/*! This function should be used in conjunction with toggleCameraMode(). It returns \c true when at -least one mouse button is binded to the \c ROTATE mouseAction. This is crude way of determining -which "mode" the camera is in. */ -bool QGLViewer::cameraIsInRotateMode() const -{ - //#CONNECTION# used in toggleCameraMode() and keyboardString() - Qt::Key key; - Qt::KeyboardModifiers modifiers; - Qt::MouseButton button; - getMouseActionBinding(CAMERA, ROTATE, true /*constraint*/, key, modifiers, button); - return button != Qt::NoButton; +See also setMouseBinding(), getMouseActionBinding() and getWheelActionBinding(). +*/ +void QGLViewer::getClickActionBinding(ClickAction action, Qt::Key &key, + Qt::KeyboardModifiers &modifiers, + Qt::MouseButton &button, + bool &doubleClick, + Qt::MouseButtons &buttonsBefore) const { + for (QMap::ConstIterator + it = clickBinding_.begin(), + end = clickBinding_.end(); + it != end; ++it) + if (it.value() == action) { + modifiers = it.key().modifiers; + button = it.key().button; + doubleClick = it.key().doubleClick; + buttonsBefore = it.key().buttonsBefore; + key = it.key().key; + return; + } + + modifiers = Qt::NoModifier; + button = Qt::NoButton; + doubleClick = false; + buttonsBefore = Qt::NoButton; + key = Qt::Key(0); +} + +/*! This function should be used in conjunction with toggleCameraMode(). It +returns \c true when at least one mouse button is binded to the \c ROTATE +mouseAction. This is crude way of determining which "mode" the camera is in. */ +bool QGLViewer::cameraIsInRotateMode() const { + //#CONNECTION# used in toggleCameraMode() and keyboardString() + Qt::Key key; + Qt::KeyboardModifiers modifiers; + Qt::MouseButton button; + getMouseActionBinding(CAMERA, ROTATE, true /*constraint*/, key, modifiers, + button); + return button != Qt::NoButton; } /*! Swaps between two predefined camera mouse bindings. The first mode makes the camera observe the scene while revolving around the -qglviewer::Camera::pivotPoint(). The second mode is designed for walkthrough applications -and simulates a flying camera. +qglviewer::Camera::pivotPoint(). The second mode is designed for walkthrough +applications and simulates a flying camera. Practically, the three mouse buttons are respectively binded to: \arg In rotate mode: QGLViewer::ROTATE, QGLViewer::ZOOM, QGLViewer::TRANSLATE. -\arg In fly mode: QGLViewer::MOVE_FORWARD, QGLViewer::LOOK_AROUND, QGLViewer::MOVE_BACKWARD. - -The current mode is determined by checking if a mouse button is binded to QGLViewer::ROTATE for -the QGLViewer::CAMERA. The state key that was previously used to move the camera is preserved. */ -void QGLViewer::toggleCameraMode() -{ - Qt::Key key; - Qt::KeyboardModifiers modifiers; - Qt::MouseButton button; - getMouseActionBinding(CAMERA, ROTATE, true /*constraint*/, key, modifiers, button); - bool rotateMode = button != Qt::NoButton; - - if (!rotateMode) { - getMouseActionBinding(CAMERA, MOVE_FORWARD, true /*constraint*/, key, modifiers, button); - } +\arg In fly mode: QGLViewer::MOVE_FORWARD, QGLViewer::LOOK_AROUND, +QGLViewer::MOVE_BACKWARD. + +The current mode is determined by checking if a mouse button is binded to +QGLViewer::ROTATE for the QGLViewer::CAMERA. The state key that was previously +used to move the camera is preserved. */ +void QGLViewer::toggleCameraMode() { + Qt::Key key; + Qt::KeyboardModifiers modifiers; + Qt::MouseButton button; + getMouseActionBinding(CAMERA, ROTATE, true /*constraint*/, key, modifiers, + button); + bool rotateMode = button != Qt::NoButton; + + if (!rotateMode) { + getMouseActionBinding(CAMERA, MOVE_FORWARD, true /*constraint*/, key, + modifiers, button); + } - //#CONNECTION# setDefaultMouseBindings() - if (rotateMode) - { - camera()->frame()->updateSceneUpVector(); - camera()->frame()->stopSpinning(); + //#CONNECTION# setDefaultMouseBindings() + if (rotateMode) { + camera()->frame()->updateSceneUpVector(); + camera()->frame()->stopSpinning(); - setMouseBinding(modifiers, Qt::LeftButton, CAMERA, MOVE_FORWARD); - setMouseBinding(modifiers, Qt::MidButton, CAMERA, LOOK_AROUND); - setMouseBinding(modifiers, Qt::RightButton, CAMERA, MOVE_BACKWARD); + setMouseBinding(modifiers, Qt::LeftButton, CAMERA, MOVE_FORWARD); + setMouseBinding(modifiers, Qt::MidButton, CAMERA, LOOK_AROUND); + setMouseBinding(modifiers, Qt::RightButton, CAMERA, MOVE_BACKWARD); - setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, ROLL); + setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, ROLL); - setMouseBinding(Qt::NoModifier, Qt::LeftButton, NO_CLICK_ACTION, true); - setMouseBinding(Qt::NoModifier, Qt::MidButton, NO_CLICK_ACTION, true); - setMouseBinding(Qt::NoModifier, Qt::RightButton, NO_CLICK_ACTION, true); + setMouseBinding(Qt::NoModifier, Qt::LeftButton, NO_CLICK_ACTION, true); + setMouseBinding(Qt::NoModifier, Qt::MidButton, NO_CLICK_ACTION, true); + setMouseBinding(Qt::NoModifier, Qt::RightButton, NO_CLICK_ACTION, true); - setWheelBinding(modifiers, CAMERA, MOVE_FORWARD); - } - else - { - // Should stop flyTimer. But unlikely and not easy. - setMouseBinding(modifiers, Qt::LeftButton, CAMERA, ROTATE); - setMouseBinding(modifiers, Qt::MidButton, CAMERA, ZOOM); - setMouseBinding(modifiers, Qt::RightButton, CAMERA, TRANSLATE); + setWheelBinding(modifiers, CAMERA, MOVE_FORWARD); + } else { + // Should stop flyTimer. But unlikely and not easy. + setMouseBinding(modifiers, Qt::LeftButton, CAMERA, ROTATE); + setMouseBinding(modifiers, Qt::MidButton, CAMERA, ZOOM); + setMouseBinding(modifiers, Qt::RightButton, CAMERA, TRANSLATE); - setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, SCREEN_ROTATE); + setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, + SCREEN_ROTATE); - setMouseBinding(Qt::NoModifier, Qt::LeftButton, ALIGN_CAMERA, true); - setMouseBinding(Qt::NoModifier, Qt::MidButton, SHOW_ENTIRE_SCENE, true); - setMouseBinding(Qt::NoModifier, Qt::RightButton, CENTER_SCENE, true); + setMouseBinding(Qt::NoModifier, Qt::LeftButton, ALIGN_CAMERA, true); + setMouseBinding(Qt::NoModifier, Qt::MidButton, SHOW_ENTIRE_SCENE, true); + setMouseBinding(Qt::NoModifier, Qt::RightButton, CENTER_SCENE, true); - setWheelBinding(modifiers, CAMERA, ZOOM); - } + setWheelBinding(modifiers, CAMERA, ZOOM); + } } //////////////////////////////////////////////////////////////////////////////// @@ -3048,39 +3385,38 @@ void QGLViewer::toggleCameraMode() Several objects can be manipulated simultaneously, as is done the multiSelect example. -Defining the \e own viewer's camera()->frame() as the manipulatedFrame() is possible and will result -in a classical camera manipulation. See the luxo example for an -illustration. - -Note that a qglviewer::ManipulatedCameraFrame can be set as the manipulatedFrame(): it is possible -to manipulate the camera of a first viewer in a second viewer. */ -void QGLViewer::setManipulatedFrame(ManipulatedFrame* frame) -{ - if (manipulatedFrame()) - { - manipulatedFrame()->stopSpinning(); - - if (manipulatedFrame() != camera()->frame()) - { - disconnect(manipulatedFrame(), SIGNAL(manipulated()), this, SLOT(update())); - disconnect(manipulatedFrame(), SIGNAL(spun()), this, SLOT(update())); - } - } +Defining the \e own viewer's camera()->frame() as the manipulatedFrame() is +possible and will result in a classical camera manipulation. See the luxo example for an illustration. + +Note that a qglviewer::ManipulatedCameraFrame can be set as the +manipulatedFrame(): it is possible to manipulate the camera of a first viewer in +a second viewer. */ +void QGLViewer::setManipulatedFrame(ManipulatedFrame *frame) { + if (manipulatedFrame()) { + manipulatedFrame()->stopSpinning(); + + if (manipulatedFrame() != camera()->frame()) { + disconnect(manipulatedFrame(), SIGNAL(manipulated()), this, + SLOT(update())); + disconnect(manipulatedFrame(), SIGNAL(spun()), this, SLOT(update())); + } + } - manipulatedFrame_ = frame; + manipulatedFrame_ = frame; - manipulatedFrameIsACamera_ = ((manipulatedFrame() != camera()->frame()) && - (dynamic_cast(manipulatedFrame()) != NULL)); + manipulatedFrameIsACamera_ = + ((manipulatedFrame() != camera()->frame()) && + (dynamic_cast(manipulatedFrame()) != nullptr)); - if (manipulatedFrame()) - { - // Prevent multiple connections, that would result in useless display updates - if (manipulatedFrame() != camera()->frame()) - { - connect(manipulatedFrame(), SIGNAL(manipulated()), SLOT(update())); - connect(manipulatedFrame(), SIGNAL(spun()), SLOT(update())); - } - } + if (manipulatedFrame()) { + // Prevent multiple connections, that would result in useless display + // updates + if (manipulatedFrame() != camera()->frame()) { + connect(manipulatedFrame(), SIGNAL(manipulated()), SLOT(update())); + connect(manipulatedFrame(), SIGNAL(spun()), SLOT(update())); + } + } } #ifndef DOXYGEN @@ -3091,104 +3427,101 @@ void QGLViewer::setManipulatedFrame(ManipulatedFrame* frame) Displays the new qglviewer::Camera::pivotPoint() when it is changed. See the mouse page for details. Also draws a line between -qglviewer::Camera::pivotPoint() and mouse cursor when the camera is rotated around the -camera Z axis. +qglviewer::Camera::pivotPoint() and mouse cursor when the camera is rotated +around the camera Z axis. -See also setVisualHintsMask() and resetVisualHints(). The hint color is foregroundColor(). +See also setVisualHintsMask() and resetVisualHints(). The hint color is +foregroundColor(). -\note These methods may become more interesting one day. The current design is too limited and -should be improved when other visual hints must be drawn. +\note These methods may become more interesting one day. The current design is +too limited and should be improved when other visual hints must be drawn. Limitation : One needs to have access to visualHint_ to overload this method. Removed from the documentation for this reason. */ -void QGLViewer::drawVisualHints() -{ - // Pivot point cross - if (visualHint_ & 1) - { - const qreal size = 15.0; - Vec proj = camera()->projectedCoordinatesOf(camera()->pivotPoint()); - startScreenCoordinatesSystem(); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - glLineWidth(3.0); - glBegin(GL_LINES); - glVertex2d(proj.x - size, proj.y); - glVertex2d(proj.x + size, proj.y); - glVertex2d(proj.x, proj.y - size); - glVertex2d(proj.x, proj.y + size); - glEnd(); - glEnable(GL_DEPTH_TEST); - stopScreenCoordinatesSystem(); - } - - // if (visualHint_ & 2) - // drawText(80, 10, "Play"); - - // Screen rotate line - ManipulatedFrame* mf = NULL; - Vec pnt; - if (camera()->frame()->action_ == SCREEN_ROTATE) - { - mf = camera()->frame(); - pnt = camera()->pivotPoint(); - } - if (manipulatedFrame() && (manipulatedFrame()->action_ == SCREEN_ROTATE)) - { - mf = manipulatedFrame(); - // Maybe useful if the mf is a manipCameraFrame... - // pnt = manipulatedFrame()->pivotPoint(); - pnt = manipulatedFrame()->position(); - } - - if (mf) - { - pnt = camera()->projectedCoordinatesOf(pnt); - startScreenCoordinatesSystem(); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - glLineWidth(3.0); - glBegin(GL_LINES); - glVertex2d(pnt.x, pnt.y); - glVertex2i(mf->prevPos_.x(), mf->prevPos_.y()); - glEnd(); - glEnable(GL_DEPTH_TEST); - stopScreenCoordinatesSystem(); - } - - // Zoom on region: draw a rectangle - if (camera()->frame()->action_ == ZOOM_ON_REGION) - { - startScreenCoordinatesSystem(); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - glLineWidth(2.0); - glBegin(GL_LINE_LOOP); - glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->pressPos_.y()); - glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->pressPos_.y()); - glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->prevPos_.y()); - glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->prevPos_.y()); - glEnd(); - glEnable(GL_DEPTH_TEST); - stopScreenCoordinatesSystem(); - } -} - -/*! Defines the mask that will be used to drawVisualHints(). The only available mask is currently 1, -corresponding to the display of the qglviewer::Camera::pivotPoint(). resetVisualHints() is -automatically called after \p delay milliseconds (default is 2 seconds). */ -void QGLViewer::setVisualHintsMask(int mask, int delay) -{ - visualHint_ = visualHint_ | mask; - QTimer::singleShot(delay, this, SLOT(resetVisualHints())); +void QGLViewer::drawVisualHints() { + // Pivot point cross + if (visualHint_ & 1) { + const qreal size = 15.0; + Vec proj = camera()->projectedCoordinatesOf(camera()->pivotPoint()); + startScreenCoordinatesSystem(); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glLineWidth(3.0); + glBegin(GL_LINES); + glVertex2d(proj.x - size, proj.y); + glVertex2d(proj.x + size, proj.y); + glVertex2d(proj.x, proj.y - size); + glVertex2d(proj.x, proj.y + size); + glEnd(); + glEnable(GL_DEPTH_TEST); + stopScreenCoordinatesSystem(); + } + + // if (visualHint_ & 2) + // drawText(80, 10, "Play"); + + // Screen rotate line + ManipulatedFrame *mf = nullptr; + Vec pnt; + if (camera()->frame()->action_ == SCREEN_ROTATE) { + mf = camera()->frame(); + pnt = camera()->pivotPoint(); + } + if (manipulatedFrame() && (manipulatedFrame()->action_ == SCREEN_ROTATE)) { + mf = manipulatedFrame(); + // Maybe useful if the mf is a manipCameraFrame... + // pnt = manipulatedFrame()->pivotPoint(); + pnt = manipulatedFrame()->position(); + } + + if (mf) { + pnt = camera()->projectedCoordinatesOf(pnt); + startScreenCoordinatesSystem(); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glLineWidth(3.0); + glBegin(GL_LINES); + glVertex2d(pnt.x, pnt.y); + glVertex2i(mf->prevPos_.x(), mf->prevPos_.y()); + glEnd(); + glEnable(GL_DEPTH_TEST); + stopScreenCoordinatesSystem(); + } + + // Zoom on region: draw a rectangle + if (camera()->frame()->action_ == ZOOM_ON_REGION) { + startScreenCoordinatesSystem(); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glLineWidth(2.0); + glBegin(GL_LINE_LOOP); + glVertex2i(camera()->frame()->pressPos_.x(), + camera()->frame()->pressPos_.y()); + glVertex2i(camera()->frame()->prevPos_.x(), + camera()->frame()->pressPos_.y()); + glVertex2i(camera()->frame()->prevPos_.x(), + camera()->frame()->prevPos_.y()); + glVertex2i(camera()->frame()->pressPos_.x(), + camera()->frame()->prevPos_.y()); + glEnd(); + glEnable(GL_DEPTH_TEST); + stopScreenCoordinatesSystem(); + } } -/*! Reset the mask used by drawVisualHints(). Called by setVisualHintsMask() after 2 seconds to reset the display. */ -void QGLViewer::resetVisualHints() -{ - visualHint_ = 0; +/*! Defines the mask that will be used to drawVisualHints(). The only available +mask is currently 1, corresponding to the display of the +qglviewer::Camera::pivotPoint(). resetVisualHints() is automatically called +after \p delay milliseconds (default is 2 seconds). */ +void QGLViewer::setVisualHintsMask(int mask, int delay) { + visualHint_ = visualHint_ | mask; + QTimer::singleShot(delay, this, SLOT(resetVisualHints())); } + +/*! Reset the mask used by drawVisualHints(). Called by setVisualHintsMask() + * after 2 seconds to reset the display. */ +void QGLViewer::resetVisualHints() { visualHint_ = 0; } #endif //////////////////////////////////////////////////////////////////////////////// @@ -3197,163 +3530,171 @@ void QGLViewer::resetVisualHints() /*! Draws a 3D arrow along the positive Z axis. -\p length, \p radius and \p nbSubdivisions define its geometry. If \p radius is negative -(default), it is set to 0.05 * \p length. +\p length, \p radius and \p nbSubdivisions define its geometry. If \p radius is +negative (default), it is set to 0.05 * \p length. -Use drawArrow(const Vec& from, const Vec& to, qreal radius, int nbSubdivisions) or change the \c -ModelView matrix to place the arrow in 3D. +Use drawArrow(const Vec& from, const Vec& to, qreal radius, int nbSubdivisions) +or change the \c ModelView matrix to place the arrow in 3D. Uses current color and does not modify the OpenGL state. */ -void QGLViewer::drawArrow(qreal length, qreal radius, int nbSubdivisions) -{ - static GLUquadric* quadric = gluNewQuadric(); +void QGLViewer::drawArrow(qreal length, qreal radius, int nbSubdivisions) { + static GLUquadric *quadric = gluNewQuadric(); - if (radius < 0.0) - radius = 0.05 * length; + if (radius < 0.0) + radius = 0.05 * length; - const qreal head = 2.5*(radius / length) + 0.1; - const qreal coneRadiusCoef = 4.0 - 5.0 * head; + const qreal head = 2.5 * (radius / length) + 0.1; + const qreal coneRadiusCoef = 4.0 - 5.0 * head; - gluCylinder(quadric, radius, radius, length * (1.0 - head/coneRadiusCoef), nbSubdivisions, 1); - glTranslated(0.0, 0.0, length * (1.0 - head)); - gluCylinder(quadric, coneRadiusCoef * radius, 0.0, head * length, nbSubdivisions, 1); - glTranslated(0.0, 0.0, -length * (1.0 - head)); + gluCylinder(quadric, radius, radius, length * (1.0 - head / coneRadiusCoef), + nbSubdivisions, 1); + glTranslated(0.0, 0.0, length * (1.0 - head)); + gluCylinder(quadric, coneRadiusCoef * radius, 0.0, head * length, + nbSubdivisions, 1); + glTranslated(0.0, 0.0, -length * (1.0 - head)); } -/*! Draws a 3D arrow between the 3D point \p from and the 3D point \p to, both defined in the -current ModelView coordinates system. +/*! Draws a 3D arrow between the 3D point \p from and the 3D point \p to, both +defined in the current ModelView coordinates system. See drawArrow(qreal length, qreal radius, int nbSubdivisions) for details. */ -void QGLViewer::drawArrow(const Vec& from, const Vec& to, qreal radius, int nbSubdivisions) -{ - glPushMatrix(); - glTranslated(from[0], from[1], from[2]); - const Vec dir = to-from; - glMultMatrixd(Quaternion(Vec(0,0,1), dir).matrix()); - QGLViewer::drawArrow(dir.norm(), radius, nbSubdivisions); - glPopMatrix(); +void QGLViewer::drawArrow(const Vec &from, const Vec &to, qreal radius, + int nbSubdivisions) { + glPushMatrix(); + glTranslated(from[0], from[1], from[2]); + const Vec dir = to - from; + glMultMatrixd(Quaternion(Vec(0, 0, 1), dir).matrix()); + QGLViewer::drawArrow(dir.norm(), radius, nbSubdivisions); + glPopMatrix(); } /*! Draws an XYZ axis, with a given size (default is 1.0). -The axis position and orientation matches the current modelView matrix state: three arrows (red, -green and blue) of length \p length are drawn along the positive X, Y and Z directions. +The axis position and orientation matches the current modelView matrix state: +three arrows (red, green and blue) of length \p length are drawn along the +positive X, Y and Z directions. -Use the following code to display the current position and orientation of a qglviewer::Frame: -\code -glPushMatrix(); -glMultMatrixd(frame.matrix()); +Use the following code to display the current position and orientation of a +qglviewer::Frame: \code glPushMatrix(); glMultMatrixd(frame.matrix()); QGLViewer::drawAxis(sceneRadius() / 5.0); // Or any scale glPopMatrix(); \endcode -The current color and line width are used to draw the X, Y and Z characters at the extremities of -the three arrows. The OpenGL state is not modified by this method. - -axisIsDrawn() uses this method to draw a representation of the world coordinate system. See also -QGLViewer::drawArrow() and QGLViewer::drawGrid(). */ -void QGLViewer::drawAxis(qreal length) -{ - const qreal charWidth = length / 40.0; - const qreal charHeight = length / 30.0; - const qreal charShift = 1.04 * length; - - GLboolean lighting, colorMaterial; - glGetBooleanv(GL_LIGHTING, &lighting); - glGetBooleanv(GL_COLOR_MATERIAL, &colorMaterial); - - glDisable(GL_LIGHTING); - - glBegin(GL_LINES); - // The X - glVertex3d(charShift, charWidth, -charHeight); - glVertex3d(charShift, -charWidth, charHeight); - glVertex3d(charShift, -charWidth, -charHeight); - glVertex3d(charShift, charWidth, charHeight); - // The Y - glVertex3d( charWidth, charShift, charHeight); - glVertex3d(0.0, charShift, 0.0); - glVertex3d(-charWidth, charShift, charHeight); - glVertex3d(0.0, charShift, 0.0); - glVertex3d(0.0, charShift, 0.0); - glVertex3d(0.0, charShift, -charHeight); - // The Z - glVertex3d(-charWidth, charHeight, charShift); - glVertex3d( charWidth, charHeight, charShift); - glVertex3d( charWidth, charHeight, charShift); - glVertex3d(-charWidth, -charHeight, charShift); - glVertex3d(-charWidth, -charHeight, charShift); - glVertex3d( charWidth, -charHeight, charShift); - glEnd(); - - glEnable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - - float color[4]; - color[0] = 0.7f; color[1] = 0.7f; color[2] = 1.0f; color[3] = 1.0f; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); - QGLViewer::drawArrow(length, 0.01*length); - - color[0] = 1.0f; color[1] = 0.7f; color[2] = 0.7f; color[3] = 1.0f; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); - glPushMatrix(); - glRotatef(90.0f, 0.0f, 1.0f, 0.0f); - QGLViewer::drawArrow(length, 0.01*length); - glPopMatrix(); - - color[0] = 0.7f; color[1] = 1.0f; color[2] = 0.7f; color[3] = 1.0f; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); - glPushMatrix(); - glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); - QGLViewer::drawArrow(length, 0.01*length); - glPopMatrix(); - - if (colorMaterial) - glEnable(GL_COLOR_MATERIAL); - if (!lighting) - glDisable(GL_LIGHTING); -} - -/*! Draws a grid in the XY plane, centered on (0,0,0) (defined in the current coordinate system). - -\p size (OpenGL units) and \p nbSubdivisions define its geometry. Set the \c GL_MODELVIEW matrix to -place and orientate the grid in 3D space (see the drawAxis() documentation). +The current color and line width are used to draw the X, Y and Z characters at +the extremities of the three arrows. The OpenGL state is not modified by this +method. + +axisIsDrawn() uses this method to draw a representation of the world coordinate +system. See also QGLViewer::drawArrow() and QGLViewer::drawGrid(). */ +void QGLViewer::drawAxis(qreal length) { + const qreal charWidth = length / 40.0; + const qreal charHeight = length / 30.0; + const qreal charShift = 1.04 * length; + + GLboolean lighting, colorMaterial; + glGetBooleanv(GL_LIGHTING, &lighting); + glGetBooleanv(GL_COLOR_MATERIAL, &colorMaterial); + + glDisable(GL_LIGHTING); + + glBegin(GL_LINES); + // The X + glVertex3d(charShift, charWidth, -charHeight); + glVertex3d(charShift, -charWidth, charHeight); + glVertex3d(charShift, -charWidth, -charHeight); + glVertex3d(charShift, charWidth, charHeight); + // The Y + glVertex3d(charWidth, charShift, charHeight); + glVertex3d(0.0, charShift, 0.0); + glVertex3d(-charWidth, charShift, charHeight); + glVertex3d(0.0, charShift, 0.0); + glVertex3d(0.0, charShift, 0.0); + glVertex3d(0.0, charShift, -charHeight); + // The Z + glVertex3d(-charWidth, charHeight, charShift); + glVertex3d(charWidth, charHeight, charShift); + glVertex3d(charWidth, charHeight, charShift); + glVertex3d(-charWidth, -charHeight, charShift); + glVertex3d(-charWidth, -charHeight, charShift); + glVertex3d(charWidth, -charHeight, charShift); + glEnd(); + + glEnable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + + float color[4]; + color[0] = 0.7f; + color[1] = 0.7f; + color[2] = 1.0f; + color[3] = 1.0f; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); + QGLViewer::drawArrow(length, 0.01 * length); + + color[0] = 1.0f; + color[1] = 0.7f; + color[2] = 0.7f; + color[3] = 1.0f; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); + glPushMatrix(); + glRotatef(90.0f, 0.0f, 1.0f, 0.0f); + QGLViewer::drawArrow(length, 0.01 * length); + glPopMatrix(); + + color[0] = 0.7f; + color[1] = 1.0f; + color[2] = 0.7f; + color[3] = 1.0f; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); + glPushMatrix(); + glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); + QGLViewer::drawArrow(length, 0.01 * length); + glPopMatrix(); + + if (colorMaterial) + glEnable(GL_COLOR_MATERIAL); + if (!lighting) + glDisable(GL_LIGHTING); +} + +/*! Draws a grid in the XY plane, centered on (0,0,0) (defined in the current +coordinate system). + +\p size (OpenGL units) and \p nbSubdivisions define its geometry. Set the \c +GL_MODELVIEW matrix to place and orientate the grid in 3D space (see the +drawAxis() documentation). The OpenGL state is not modified by this method. */ -void QGLViewer::drawGrid(qreal size, int nbSubdivisions) -{ - GLboolean lighting; - glGetBooleanv(GL_LIGHTING, &lighting); - - glDisable(GL_LIGHTING); - - glBegin(GL_LINES); - for (int i=0; i<=nbSubdivisions; ++i) - { - const qreal pos = size*(2.0*i/nbSubdivisions-1.0); - glVertex2d(pos, -size); - glVertex2d(pos, +size); - glVertex2d(-size, pos); - glVertex2d( size, pos); - } - glEnd(); +void QGLViewer::drawGrid(qreal size, int nbSubdivisions) { + GLboolean lighting; + glGetBooleanv(GL_LIGHTING, &lighting); + + glDisable(GL_LIGHTING); + + glBegin(GL_LINES); + for (int i = 0; i <= nbSubdivisions; ++i) { + const qreal pos = size * (2.0 * i / nbSubdivisions - 1.0); + glVertex2d(pos, -size); + glVertex2d(pos, +size); + glVertex2d(-size, pos); + glVertex2d(size, pos); + } + glEnd(); - if (lighting) - glEnable(GL_LIGHTING); + if (lighting) + glEnable(GL_LIGHTING); } //////////////////////////////////////////////////////////////////////////////// // S t a t i c m e t h o d s : Q G L V i e w e r P o o l // //////////////////////////////////////////////////////////////////////////////// -/*! saveStateToFile() is called on all the QGLViewers using the QGLViewerPool(). */ -void QGLViewer::saveStateToFileForAllViewers() -{ - Q_FOREACH (QGLViewer* viewer, QGLViewer::QGLViewerPool()) - { - if (viewer) - viewer->saveStateToFile(); - } +/*! saveStateToFile() is called on all the QGLViewers using the QGLViewerPool(). + */ +void QGLViewer::saveStateToFileForAllViewers() { + Q_FOREACH (QGLViewer *viewer, QGLViewer::QGLViewerPool()) { + if (viewer) + viewer->saveStateToFile(); + } } ////////////////////////////////////////////////////////////////////////// @@ -3362,94 +3703,101 @@ void QGLViewer::saveStateToFileForAllViewers() /*! Returns the state file name. Default value is \c .qglviewer.xml. -This is the name of the XML file where saveStateToFile() saves the viewer state (camera state, -widget geometry, display flags... see domElement()) on exit. Use restoreStateFromFile() to restore -this state later (usually in your init() method). +This is the name of the XML file where saveStateToFile() saves the viewer state +(camera state, widget geometry, display flags... see domElement()) on exit. Use +restoreStateFromFile() to restore this state later (usually in your init() +method). + +Setting this value to \c QString::null will disable the automatic state file +saving that normally occurs on exit. + +If more than one viewer are created by the application, this function will +return a numbered file name (as in ".qglviewer1.xml", ".qglviewer2.xml"... using +QGLViewer::QGLViewerIndex()) for extra viewers. Each viewer will then read back +its own information in restoreStateFromFile(), provided that the viewers are +created in the same order, which is usually the case. */ +QString QGLViewer::stateFileName() const { + QString name = stateFileName_; + + if (!name.isEmpty() && QGLViewer::QGLViewerIndex(this) > 0) { + QFileInfo fi(name); + if (fi.suffix().isEmpty()) + name += QString::number(QGLViewer::QGLViewerIndex(this)); + else + name = fi.absolutePath() + '/' + fi.completeBaseName() + + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + + fi.suffix(); + } -Setting this value to \c QString() will disable the automatic state file saving that normally -occurs on exit. + return name; +} -If more than one viewer are created by the application, this function will return a numbered file -name (as in ".qglviewer1.xml", ".qglviewer2.xml"... using QGLViewer::QGLViewerIndex()) for extra -viewers. Each viewer will then read back its own information in restoreStateFromFile(), provided -that the viewers are created in the same order, which is usually the case. */ -QString QGLViewer::stateFileName() const -{ - QString name = stateFileName_; +/*! Saves in stateFileName() an XML representation of the QGLViewer state, +obtained from domElement(). - if (!name.isEmpty() && QGLViewer::QGLViewerIndex(this) > 0) - { - QFileInfo fi(name); - if (fi.suffix().isEmpty()) - name += QString::number(QGLViewer::QGLViewerIndex(this)); - else - name = fi.absolutePath() + '/' + fi.completeBaseName() + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.suffix(); - } +Use restoreStateFromFile() to restore this viewer state. - return name; -} +This method is automatically called when a viewer is closed (using Escape or +using the window's upper right \c x close button). setStateFileName() to \c +QString::null to prevent this. */ +void QGLViewer::saveStateToFile() { + QString name = stateFileName(); -/*! Saves in stateFileName() an XML representation of the QGLViewer state, obtained from -domElement(). + if (name.isEmpty()) + return; -Use restoreStateFromFile() to restore this viewer state. + QFileInfo fileInfo(name); -This method is automatically called when a viewer is closed (using Escape or using the window's -upper right \c x close button). setStateFileName() to \c QString() to prevent this. */ -void QGLViewer::saveStateToFile() -{ - QString name = stateFileName(); - - if (name.isEmpty()) - return; - - QFileInfo fileInfo(name); - - if (fileInfo.isDir()) - { - QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("State file name (%1) references a directory instead of a file.").arg(name)); - return; - } - - const QString dirName = fileInfo.absolutePath(); - if (!QFileInfo(dirName).exists()) - { - QDir dir; - if (!(dir.mkdir(dirName))) - { - QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to create directory %1").arg(dirName)); - return; - } - } - - // Write the DOM tree to file - QFile f(name); - if (f.open(QIODevice::WriteOnly)) - { - QTextStream out(&f); - QDomDocument doc("QGLVIEWER"); - doc.appendChild(domElement("QGLViewer", doc)); - doc.save(out, 2); - f.flush(); - f.close(); - } - else - QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to save to file %1").arg(name) + ":\n" + f.errorString()); -} - -/*! Restores the QGLViewer state from the stateFileName() file using initFromDOMElement(). - -States are saved using saveStateToFile(), which is automatically called on viewer exit. - -Returns \c true when the restoration is successful. Possible problems are an non existing or -unreadable stateFileName() file, an empty stateFileName() or an XML syntax error. - -A manipulatedFrame() should be defined \e before calling this method, so that its state can be -restored. Initialization code put \e after this function will override saved values: -\code -void Viewer::init() + if (fileInfo.isDir()) { + QMessageBox::warning( + this, tr("Save to file error", "Message box window title"), + tr("State file name (%1) references a directory instead of a file.") + .arg(name)); + return; + } + + const QString dirName = fileInfo.absolutePath(); + if (!QFileInfo(dirName).exists()) { + QDir dir; + if (!(dir.mkdir(dirName))) { + QMessageBox::warning(this, + tr("Save to file error", "Message box window title"), + tr("Unable to create directory %1").arg(dirName)); + return; + } + } + + // Write the DOM tree to file + QFile f(name); + if (f.open(QIODevice::WriteOnly)) { + QTextStream out(&f); + QDomDocument doc("QGLVIEWER"); + doc.appendChild(domElement("QGLViewer", doc)); + doc.save(out, 2); + f.flush(); + f.close(); + } else + QMessageBox::warning( + this, tr("Save to file error", "Message box window title"), + tr("Unable to save to file %1").arg(name) + ":\n" + f.errorString()); +} + +/*! Restores the QGLViewer state from the stateFileName() file using +initFromDOMElement(). + +States are saved using saveStateToFile(), which is automatically called on +viewer exit. + +Returns \c true when the restoration is successful. Possible problems are an non +existing or unreadable stateFileName() file, an empty stateFileName() or an XML +syntax error. + +A manipulatedFrame() should be defined \e before calling this method, so that +its state can be restored. Initialization code put \e after this function will +override saved values: \code void Viewer::init() { -// Default initialization goes here (including the declaration of a possible manipulatedFrame). +// Default initialization goes here (including the declaration of a possible +manipulatedFrame). if (!restoreStateFromFile()) showEntireScene(); // Previous state cannot be restored: fit camera to scene. @@ -3457,59 +3805,60 @@ showEntireScene(); // Previous state cannot be restored: fit camera to scene. // Specific initialization that overrides file savings goes here. } \endcode */ -bool QGLViewer::restoreStateFromFile() -{ - QString name = stateFileName(); - - if (name.isEmpty()) - return false; - - QFileInfo fileInfo(name); - - if (!fileInfo.isFile()) - // No warning since it would be displayed at first start. - return false; - - if (!fileInfo.isReadable()) - { - QMessageBox::warning(this, tr("Problem in state restoration", "Message box window title"), tr("File %1 is not readable.").arg(name)); - return false; - } - - // Read the DOM tree form file - QFile f(name); - if (f.open(QIODevice::ReadOnly)) - { - QDomDocument doc; - doc.setContent(&f); - f.close(); - QDomElement main = doc.documentElement(); - initFromDOMElement(main); - } - else - { - QMessageBox::warning(this, tr("Open file error", "Message box window title"), tr("Unable to open file %1").arg(name) + ":\n" + f.errorString()); - return false; - } - - return true; +bool QGLViewer::restoreStateFromFile() { + QString name = stateFileName(); + + if (name.isEmpty()) + return false; + + QFileInfo fileInfo(name); + + if (!fileInfo.isFile()) + // No warning since it would be displayed at first start. + return false; + + if (!fileInfo.isReadable()) { + QMessageBox::warning( + this, tr("Problem in state restoration", "Message box window title"), + tr("File %1 is not readable.").arg(name)); + return false; + } + + // Read the DOM tree form file + QFile f(name); + if (f.open(QIODevice::ReadOnly)) { + QDomDocument doc; + doc.setContent(&f); + f.close(); + QDomElement main = doc.documentElement(); + initFromDOMElement(main); + } else { + QMessageBox::warning( + this, tr("Open file error", "Message box window title"), + tr("Unable to open file %1").arg(name) + ":\n" + f.errorString()); + return false; + } + + return true; } /*! Returns an XML \c QDomElement that represents the QGLViewer. -Used by saveStateToFile(). restoreStateFromFile() uses initFromDOMElement() to restore the -QGLViewer state from the resulting \c QDomElement. +Used by saveStateToFile(). restoreStateFromFile() uses initFromDOMElement() to +restore the QGLViewer state from the resulting \c QDomElement. -\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create -QDomElement. +\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument +factory used to create QDomElement. -The created QDomElement contains state values (axisIsDrawn(), FPSIsDisplayed(), isFullScreen()...), -viewer geometry, as well as camera() (see qglviewer::Camera::domElement()) and manipulatedFrame() -(if defined, see qglviewer::ManipulatedFrame::domElement()) states. +The created QDomElement contains state values (axisIsDrawn(), FPSIsDisplayed(), +isFullScreen()...), viewer geometry, as well as camera() (see +qglviewer::Camera::domElement()) and manipulatedFrame() (if defined, see +qglviewer::ManipulatedFrame::domElement()) states. Overload this method to add your own attributes to the state file: \code -QDomElement Viewer::domElement(const QString& name, QDomDocument& document) const +QDomElement Viewer::domElement(const QString& name, QDomDocument& document) +const { // Creates a custom node for a light QDomElement de = document.createElement("Light"); @@ -3526,65 +3875,66 @@ return res; See initFromDOMElement() for the associated restoration code. \attention For the manipulatedFrame(), qglviewer::Frame::constraint() and -qglviewer::Frame::referenceFrame() are not saved. See qglviewer::Frame::domElement(). */ -QDomElement QGLViewer::domElement(const QString& name, QDomDocument& document) const -{ - QDomElement de = document.createElement(name); - de.setAttribute("version", QGLViewerVersionString()); - - QDomElement stateNode = document.createElement("State"); - // hasMouseTracking() is not saved - stateNode.appendChild(DomUtils::QColorDomElement(foregroundColor(), "foregroundColor", document)); - stateNode.appendChild(DomUtils::QColorDomElement(backgroundColor(), "backgroundColor", document)); - DomUtils::setBoolAttribute(stateNode, "stereo", displaysInStereo()); - // Revolve or fly camera mode is not saved - de.appendChild(stateNode); - - QDomElement displayNode = document.createElement("Display"); - DomUtils::setBoolAttribute(displayNode, "axisIsDrawn", axisIsDrawn()); - DomUtils::setBoolAttribute(displayNode, "gridIsDrawn", gridIsDrawn()); - DomUtils::setBoolAttribute(displayNode, "FPSIsDisplayed", FPSIsDisplayed()); - DomUtils::setBoolAttribute(displayNode, "cameraIsEdited", cameraIsEdited()); - // textIsEnabled() is not saved - de.appendChild(displayNode); - - QDomElement geometryNode = document.createElement("Geometry"); - DomUtils::setBoolAttribute(geometryNode, "fullScreen", isFullScreen()); - if (isFullScreen()) - { - geometryNode.setAttribute("prevPosX", QString::number(prevPos_.x())); - geometryNode.setAttribute("prevPosY", QString::number(prevPos_.y())); - } - else - { - QWidget* tlw = topLevelWidget(); - geometryNode.setAttribute("width", QString::number(tlw->width())); - geometryNode.setAttribute("height", QString::number(tlw->height())); - geometryNode.setAttribute("posX", QString::number(tlw->pos().x())); - geometryNode.setAttribute("posY", QString::number(tlw->pos().y())); - } - de.appendChild(geometryNode); - - // Restore original Camera zClippingCoefficient before saving. - if (cameraIsEdited()) - camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_); - de.appendChild(camera()->domElement("Camera", document)); - if (cameraIsEdited()) - // #CONNECTION# 5.0 from setCameraIsEdited() - camera()->setZClippingCoefficient(5.0); - - if (manipulatedFrame()) - de.appendChild(manipulatedFrame()->domElement("ManipulatedFrame", document)); - - return de; +qglviewer::Frame::referenceFrame() are not saved. See +qglviewer::Frame::domElement(). */ +QDomElement QGLViewer::domElement(const QString &name, + QDomDocument &document) const { + QDomElement de = document.createElement(name); + de.setAttribute("version", QGLViewerVersionString()); + + QDomElement stateNode = document.createElement("State"); + // hasMouseTracking() is not saved + stateNode.appendChild(DomUtils::QColorDomElement( + foregroundColor(), "foregroundColor", document)); + stateNode.appendChild(DomUtils::QColorDomElement( + backgroundColor(), "backgroundColor", document)); + DomUtils::setBoolAttribute(stateNode, "stereo", displaysInStereo()); + // Revolve or fly camera mode is not saved + de.appendChild(stateNode); + + QDomElement displayNode = document.createElement("Display"); + DomUtils::setBoolAttribute(displayNode, "axisIsDrawn", axisIsDrawn()); + DomUtils::setBoolAttribute(displayNode, "gridIsDrawn", gridIsDrawn()); + DomUtils::setBoolAttribute(displayNode, "FPSIsDisplayed", FPSIsDisplayed()); + DomUtils::setBoolAttribute(displayNode, "cameraIsEdited", cameraIsEdited()); + // textIsEnabled() is not saved + de.appendChild(displayNode); + + QDomElement geometryNode = document.createElement("Geometry"); + DomUtils::setBoolAttribute(geometryNode, "fullScreen", isFullScreen()); + if (isFullScreen()) { + geometryNode.setAttribute("prevPosX", QString::number(prevPos_.x())); + geometryNode.setAttribute("prevPosY", QString::number(prevPos_.y())); + } else { + QWidget *tlw = topLevelWidget(); + geometryNode.setAttribute("width", QString::number(tlw->width())); + geometryNode.setAttribute("height", QString::number(tlw->height())); + geometryNode.setAttribute("posX", QString::number(tlw->pos().x())); + geometryNode.setAttribute("posY", QString::number(tlw->pos().y())); + } + de.appendChild(geometryNode); + + // Restore original Camera zClippingCoefficient before saving. + if (cameraIsEdited()) + camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_); + de.appendChild(camera()->domElement("Camera", document)); + if (cameraIsEdited()) + // #CONNECTION# 5.0 from setCameraIsEdited() + camera()->setZClippingCoefficient(5.0); + + if (manipulatedFrame()) + de.appendChild( + manipulatedFrame()->domElement("ManipulatedFrame", document)); + + return de; } /*! Restores the QGLViewer state from a \c QDomElement created by domElement(). Used by restoreStateFromFile() to restore the QGLViewer state from a file. -Overload this method to retrieve custom attributes from the QGLViewer state file. This code -corresponds to the one given in the domElement() documentation: +Overload this method to retrieve custom attributes from the QGLViewer state +file. This code corresponds to the one given in the domElement() documentation: \code void Viewer::initFromDOMElement(const QDomElement& element) { @@ -3597,11 +3947,11 @@ while (!child.isNull()) if (child.tagName() == "Light") { if (child.hasAttribute("state")) -setLightOn(child.attribute("state").lower() == "on"); +setLightOn(child.attribute("state").toLower() == "on"); -// Assumes there is only one child. Otherwise you need to parse child's children recursively. -QDomElement lf = child.firstChild().toElement(); -if (!lf.isNull() && lf.tagName() == "LightFrame") +// Assumes there is only one child. Otherwise you need to parse child's children +recursively. QDomElement lf = child.firstChild().toElement(); if (!lf.isNull() +&& lf.tagName() == "LightFrame") lightManipulatedFrame()->initFromDomElement(lf); } child = child.nextSibling().toElement(); @@ -3609,143 +3959,140 @@ child = child.nextSibling().toElement(); } \endcode -See also qglviewer::Camera::initFromDOMElement(), qglviewer::ManipulatedFrame::initFromDOMElement(). +See also qglviewer::Camera::initFromDOMElement(), +qglviewer::ManipulatedFrame::initFromDOMElement(). + +\note The manipulatedFrame() \e pointer is not modified by this method. If +defined, its state is simply set from the \p element values. */ +void QGLViewer::initFromDOMElement(const QDomElement &element) { + const QString version = element.attribute("version"); + // if (version != QGLViewerVersionString()) + if (version[0] != '2') + // Patches for previous versions should go here when the state file syntax + // is modified. + qWarning("State file created using QGLViewer version %s may not be " + "correctly read.", + version.toLatin1().constData()); + + QDomElement child = element.firstChild().toElement(); + bool tmpCameraIsEdited = cameraIsEdited(); + while (!child.isNull()) { + if (child.tagName() == "State") { + // #CONNECTION# default values from defaultConstructor() + // setMouseTracking(DomUtils::boolFromDom(child, "mouseTracking", false)); + setStereoDisplay(DomUtils::boolFromDom(child, "stereo", false)); + // if ((child.attribute("cameraMode", "revolve") == "fly") && + // (cameraIsInRevolveMode())) toggleCameraMode(); + + QDomElement ch = child.firstChild().toElement(); + while (!ch.isNull()) { + if (ch.tagName() == "foregroundColor") + setForegroundColor(DomUtils::QColorFromDom(ch)); + if (ch.tagName() == "backgroundColor") + setBackgroundColor(DomUtils::QColorFromDom(ch)); + ch = ch.nextSibling().toElement(); + } + } + + if (child.tagName() == "Display") { + // #CONNECTION# default values from defaultConstructor() + setAxisIsDrawn(DomUtils::boolFromDom(child, "axisIsDrawn", false)); + setGridIsDrawn(DomUtils::boolFromDom(child, "gridIsDrawn", false)); + setFPSIsDisplayed(DomUtils::boolFromDom(child, "FPSIsDisplayed", false)); + // See comment below. + tmpCameraIsEdited = DomUtils::boolFromDom(child, "cameraIsEdited", false); + // setTextIsEnabled(DomUtils::boolFromDom(child, "textIsEnabled", true)); + } + + if (child.tagName() == "Geometry") { + setFullScreen(DomUtils::boolFromDom(child, "fullScreen", false)); + + if (isFullScreen()) { + prevPos_.setX(DomUtils::intFromDom(child, "prevPosX", 0)); + prevPos_.setY(DomUtils::intFromDom(child, "prevPosY", 0)); + } else { + int width = DomUtils::intFromDom(child, "width", 600); + int height = DomUtils::intFromDom(child, "height", 400); + topLevelWidget()->resize(width, height); + camera()->setScreenWidthAndHeight(this->width(), this->height()); + + QPoint pos; + pos.setX(DomUtils::intFromDom(child, "posX", 0)); + pos.setY(DomUtils::intFromDom(child, "posY", 0)); + topLevelWidget()->move(pos); + } + } + + if (child.tagName() == "Camera") { + connectAllCameraKFIInterpolatedSignals(false); + camera()->initFromDOMElement(child); + connectAllCameraKFIInterpolatedSignals(); + } + + if ((child.tagName() == "ManipulatedFrame") && (manipulatedFrame())) + manipulatedFrame()->initFromDOMElement(child); + + child = child.nextSibling().toElement(); + } -\note The manipulatedFrame() \e pointer is not modified by this method. If defined, its state is -simply set from the \p element values. */ -void QGLViewer::initFromDOMElement(const QDomElement& element) -{ - const QString version = element.attribute("version"); - // if (version != QGLViewerVersionString()) - if (version[0] != '2') - // Patches for previous versions should go here when the state file syntax is modified. - qWarning("State file created using QGLViewer version %s may not be correctly read.", version.toLatin1().constData()); - - QDomElement child=element.firstChild().toElement(); - bool tmpCameraIsEdited = cameraIsEdited(); - while (!child.isNull()) - { - if (child.tagName() == "State") - { - // #CONNECTION# default values from defaultConstructor() - // setMouseTracking(DomUtils::boolFromDom(child, "mouseTracking", false)); - setStereoDisplay(DomUtils::boolFromDom(child, "stereo", false)); - //if ((child.attribute("cameraMode", "revolve") == "fly") && (cameraIsInRevolveMode())) - // toggleCameraMode(); - - QDomElement ch=child.firstChild().toElement(); - while (!ch.isNull()) - { - if (ch.tagName() == "foregroundColor") - setForegroundColor(DomUtils::QColorFromDom(ch)); - if (ch.tagName() == "backgroundColor") - setBackgroundColor(DomUtils::QColorFromDom(ch)); - ch = ch.nextSibling().toElement(); - } - } - - if (child.tagName() == "Display") - { - // #CONNECTION# default values from defaultConstructor() - setAxisIsDrawn(DomUtils::boolFromDom(child, "axisIsDrawn", false)); - setGridIsDrawn(DomUtils::boolFromDom(child, "gridIsDrawn", false)); - setFPSIsDisplayed(DomUtils::boolFromDom(child, "FPSIsDisplayed", false)); - // See comment below. - tmpCameraIsEdited = DomUtils::boolFromDom(child, "cameraIsEdited", false); - // setTextIsEnabled(DomUtils::boolFromDom(child, "textIsEnabled", true)); - } - - if (child.tagName() == "Geometry") - { - setFullScreen(DomUtils::boolFromDom(child, "fullScreen", false)); - - if (isFullScreen()) - { - prevPos_.setX(DomUtils::intFromDom(child, "prevPosX", 0)); - prevPos_.setY(DomUtils::intFromDom(child, "prevPosY", 0)); - } - else - { - int width = DomUtils::intFromDom(child, "width", 600); - int height = DomUtils::intFromDom(child, "height", 400); - topLevelWidget()->resize(width, height); - camera()->setScreenWidthAndHeight(this->width(), this->height()); - - QPoint pos; - pos.setX(DomUtils::intFromDom(child, "posX", 0)); - pos.setY(DomUtils::intFromDom(child, "posY", 0)); - topLevelWidget()->move(pos); - } - } - - if (child.tagName() == "Camera") - { - connectAllCameraKFIInterpolatedSignals(false); - camera()->initFromDOMElement(child); - connectAllCameraKFIInterpolatedSignals(); - } - - if ((child.tagName() == "ManipulatedFrame") && (manipulatedFrame())) - manipulatedFrame()->initFromDOMElement(child); - - child = child.nextSibling().toElement(); - } - - // The Camera always stores its "real" zClippingCoef in domElement(). If it is edited, - // its "real" coef must be saved and the coef set to 5.0, as is done in setCameraIsEdited(). - // BUT : Camera and Display are read in an arbitrary order. We must initialize Camera's - // "real" coef BEFORE calling setCameraIsEdited. Hence this temp cameraIsEdited and delayed call - cameraIsEdited_ = tmpCameraIsEdited; - if (cameraIsEdited_) - { - previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient(); - // #CONNECTION# 5.0 from setCameraIsEdited. - camera()->setZClippingCoefficient(5.0); - } + // The Camera always stores its "real" zClippingCoef in domElement(). If it is + // edited, its "real" coef must be saved and the coef set to 5.0, as is done + // in setCameraIsEdited(). BUT : Camera and Display are read in an arbitrary + // order. We must initialize Camera's "real" coef BEFORE calling + // setCameraIsEdited. Hence this temp cameraIsEdited and delayed call + cameraIsEdited_ = tmpCameraIsEdited; + if (cameraIsEdited_) { + previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient(); + // #CONNECTION# 5.0 from setCameraIsEdited. + camera()->setZClippingCoefficient(5.0); + } } #ifndef DOXYGEN -/*! This method is deprecated since version 1.3.9-5. Use saveStateToFile() and setStateFileName() -instead. */ -void QGLViewer::saveToFile(const QString& fileName) -{ - if (!fileName.isEmpty()) - setStateFileName(fileName); +/*! This method is deprecated since version 1.3.9-5. Use saveStateToFile() and +setStateFileName() instead. */ +void QGLViewer::saveToFile(const QString &fileName) { + if (!fileName.isEmpty()) + setStateFileName(fileName); - qWarning("saveToFile() is deprecated, use saveStateToFile() instead."); - saveStateToFile(); + qWarning("saveToFile() is deprecated, use saveStateToFile() instead."); + saveStateToFile(); } -/*! This function is deprecated since version 1.3.9-5. Use restoreStateFromFile() and -setStateFileName() instead. */ -bool QGLViewer::restoreFromFile(const QString& fileName) -{ - if (!fileName.isEmpty()) - setStateFileName(fileName); +/*! This function is deprecated since version 1.3.9-5. Use +restoreStateFromFile() and setStateFileName() instead. */ +bool QGLViewer::restoreFromFile(const QString &fileName) { + if (!fileName.isEmpty()) + setStateFileName(fileName); - qWarning("restoreFromFile() is deprecated, use restoreStateFromFile() instead."); - return restoreStateFromFile(); + qWarning( + "restoreFromFile() is deprecated, use restoreStateFromFile() instead."); + return restoreStateFromFile(); } #endif /*! Makes a copy of the current buffer into a texture. -Creates a texture (when needed) and uses glCopyTexSubImage2D() to directly copy the buffer in it. +Creates a texture (when needed) and uses glCopyTexSubImage2D() to directly copy +the buffer in it. -Use \p internalFormat and \p format to define the texture format and hence which and how components -of the buffer are copied into the texture. See the glTexImage2D() documentation for details. +Use \p internalFormat and \p format to define the texture format and hence which +and how components of the buffer are copied into the texture. See the +glTexImage2D() documentation for details. -When \p format is c GL_NONE (default), its value is set to \p internalFormat, which fits most -cases. Typical \p internalFormat (and \p format) values are \c GL_DEPTH_COMPONENT and \c GL_RGBA. -Use \c GL_LUMINANCE as the \p internalFormat and \c GL_RED, \c GL_GREEN or \c GL_BLUE as \p format -to capture a single color component as a luminance (grey scaled) value. Note that \c GL_STENCIL is -not supported as a format. +When \p format is c GL_NONE (default), its value is set to \p internalFormat, +which fits most cases. Typical \p internalFormat (and \p format) values are \c +GL_DEPTH_COMPONENT and \c GL_RGBA. Use \c GL_LUMINANCE as the \p internalFormat +and \c GL_RED, \c GL_GREEN or \c GL_BLUE as \p format to capture a single color +component as a luminance (grey scaled) value. Note that \c GL_STENCIL is not +supported as a format. -The texture has dimensions which are powers of two. It is as small as possible while always being -larger or equal to the current size of the widget. The buffer image hence does not entirely fill -the texture: it is stuck to the lower left corner (corresponding to the (0,0) texture coordinates). -Use bufferTextureMaxU() and bufferTextureMaxV() to get the upper right corner maximum u and v -texture coordinates. Use bufferTextureId() to retrieve the id of the created texture. +The texture has dimensions which are powers of two. It is as small as possible +while always being larger or equal to the current size of the widget. The buffer +image hence does not entirely fill the texture: it is stuck to the lower left +corner (corresponding to the (0,0) texture coordinates). Use bufferTextureMaxU() +and bufferTextureMaxV() to get the upper right corner maximum u and v texture +coordinates. Use bufferTextureId() to retrieve the id of the created texture. Here is how to display a grey-level image of the z-buffer: \code @@ -3762,86 +4109,82 @@ startScreenCoordinatesSystem(true); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2i(0, 0); glTexCoord2f(bufferTextureMaxU(), 0.0); glVertex2i(width(), 0); -glTexCoord2f(bufferTextureMaxU(), bufferTextureMaxV()); glVertex2i(width(), height()); -glTexCoord2f(0.0, bufferTextureMaxV()); glVertex2i(0, height()); -glEnd(); +glTexCoord2f(bufferTextureMaxU(), bufferTextureMaxV()); glVertex2i(width(), +height()); glTexCoord2f(0.0, bufferTextureMaxV()); glVertex2i(0, +height()); glEnd(); stopScreenCoordinatesSystem(); glDisable(GL_TEXTURE_2D); \endcode -Use glReadBuffer() to select which buffer is copied into the texture. See also \c -glPixelTransfer(), \c glPixelZoom() and \c glCopyPixel() for pixel color transformations during -copy. +Use glReadBuffer() to select which buffer is copied into the texture. See also +\c glPixelTransfer(), \c glPixelZoom() and \c glCopyPixel() for pixel color +transformations during copy. -Call makeCurrent() before this method to make the OpenGL context active if needed. +Call makeCurrent() before this method to make the OpenGL context active if +needed. -\note The \c GL_DEPTH_COMPONENT format may not be supported by all hardware. It may sometimes be -emulated in software, resulting in poor performances. +\note The \c GL_DEPTH_COMPONENT format may not be supported by all hardware. It +may sometimes be emulated in software, resulting in poor performances. \note The bufferTextureId() texture is binded at the end of this method. */ -void QGLViewer::copyBufferToTexture(GLint internalFormat, GLenum format) -{ - int h = 16; - int w = 16; - // Todo compare performance with qt code. - while (w < width()) - w <<= 1; - while (h < height()) - h <<= 1; - - bool init = false; - - if ((w != bufferTextureWidth_) || (h != bufferTextureHeight_)) - { - bufferTextureWidth_ = w; - bufferTextureHeight_ = h; - bufferTextureMaxU_ = width() / qreal(bufferTextureWidth_); - bufferTextureMaxV_ = height() / qreal(bufferTextureHeight_); - init = true; - } - - if (bufferTextureId() == 0) - { - glGenTextures(1, &bufferTextureId_); - glBindTexture(GL_TEXTURE_2D, bufferTextureId_); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - init = true; - } - else - glBindTexture(GL_TEXTURE_2D, bufferTextureId_); - - if ((format != previousBufferTextureFormat_) || - (internalFormat != previousBufferTextureInternalFormat_)) - { - previousBufferTextureFormat_ = format; - previousBufferTextureInternalFormat_ = internalFormat; - init = true; - } - - if (init) - { - if (format == GL_NONE) - format = GLenum(internalFormat); - - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, bufferTextureWidth_, bufferTextureHeight_, 0, format, GL_UNSIGNED_BYTE, NULL); - } - - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width(), height()); +void QGLViewer::copyBufferToTexture(GLint internalFormat, GLenum format) { + int h = 16; + int w = 16; + // Todo compare performance with qt code. + while (w < width()) + w <<= 1; + while (h < height()) + h <<= 1; + + bool init = false; + + if ((w != bufferTextureWidth_) || (h != bufferTextureHeight_)) { + bufferTextureWidth_ = w; + bufferTextureHeight_ = h; + bufferTextureMaxU_ = width() / qreal(bufferTextureWidth_); + bufferTextureMaxV_ = height() / qreal(bufferTextureHeight_); + init = true; + } + + if (bufferTextureId() == 0) { + glGenTextures(1, &bufferTextureId_); + glBindTexture(GL_TEXTURE_2D, bufferTextureId_); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + init = true; + } else + glBindTexture(GL_TEXTURE_2D, bufferTextureId_); + + if ((format != previousBufferTextureFormat_) || + (internalFormat != previousBufferTextureInternalFormat_)) { + previousBufferTextureFormat_ = format; + previousBufferTextureInternalFormat_ = internalFormat; + init = true; + } + + if (init) { + if (format == GL_NONE) + format = GLenum(internalFormat); + + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, bufferTextureWidth_, + bufferTextureHeight_, 0, format, GL_UNSIGNED_BYTE, nullptr); + } + + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width(), height()); } /*! Returns the texture id of the texture created by copyBufferToTexture(). -Use glBindTexture() to use this texture. Note that this is already done by copyBufferToTexture(). +Use glBindTexture() to use this texture. Note that this is already done by +copyBufferToTexture(). -Returns \c 0 is copyBufferToTexture() was never called or if the texure was deleted using -glDeleteTextures() since then. */ -GLuint QGLViewer::bufferTextureId() const -{ - if (glIsTexture(bufferTextureId_)) - return bufferTextureId_; - else - return 0; +Returns \c 0 is copyBufferToTexture() was never called or if the texure was +deleted using glDeleteTextures() since then. */ +GLuint QGLViewer::bufferTextureId() const { + if (glIsTexture(bufferTextureId_)) + return bufferTextureId_; + else + return 0; } diff --git a/octovis/src/extern/QGLViewer/qglviewer.h b/octovis/src/extern/QGLViewer/qglviewer.h index 586ac457..04e5d2fa 100644 --- a/octovis/src/extern/QGLViewer/qglviewer.h +++ b/octovis/src/extern/QGLViewer/qglviewer.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,15 +19,17 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_QGLVIEWER_H #define QGLVIEWER_QGLVIEWER_H #include "camera.h" -#include #include -#include +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +# include +#endif +#include +#include class QTabWidget; @@ -35,1264 +37,1432 @@ namespace qglviewer { class MouseGrabber; class ManipulatedFrame; class ManipulatedCameraFrame; -} +} // namespace qglviewer -/*! \brief A versatile 3D OpenGL viewer based on QGLWidget. +/*! \brief A versatile 3D OpenGL viewer based on QOpenGLWidget. \class QGLViewer qglviewer.h QGLViewer/qglviewer.h -It features many classical viewer functionalities, such as a camera trackball, manipulated objects, -snapshot saving and much more. Its main goal is to ease the development -of new 3D applications. +It features many classical viewer functionalities, such as a camera trackball, +manipulated objects, snapshot saving and much more. Its main goal is to ease the development of +new 3D applications. -New users should read the introduction page to get familiar with -important notions such as sceneRadius(), sceneCenter() and the world coordinate system. Try the -numerous simple examples to discover the possibilities and +New users should read the introduction page +to get familiar with important notions such as sceneRadius(), sceneCenter() and +the world coordinate system. Try the numerous simple examples to discover the possibilities and understand how it works.

Usage

-To use a QGLViewer, derive you viewer class from the QGLViewer and overload its draw() virtual -method. See the simpleViewer example for an illustration. +To use a QGLViewer, derive you viewer class from the QGLViewer and overload its +draw() virtual method. See the simpleViewer example for an +illustration. -An other option is to connect your drawing methods to the signals emitted by the QGLViewer (Qt's -callback mechanism). See the callback example for a -complete implementation. +An other option is to connect your drawing methods to the signals emitted by the +QGLViewer (Qt's callback mechanism). See the callback example for a complete +implementation. \nosubgrouping */ -class QGLVIEWER_EXPORT QGLViewer : public QGLWidget -{ - Q_OBJECT +class QGLVIEWER_EXPORT QGLViewer : public QOpenGLWidget { + Q_OBJECT public: - // Complete implementation is provided so that the constructor is defined with QT3_SUPPORT when .h is included. - // (Would not be available otherwise since lib is compiled without QT3_SUPPORT). -#ifdef QT3_SUPPORT - explicit QGLViewer(QWidget* parent=NULL, const char* name=0, const QGLWidget* shareWidget=0, Qt::WindowFlags flags=0) - : QGLWidget(parent, name, shareWidget, flags) - { defaultConstructor(); } - - explicit QGLViewer(const QGLFormat& format, QWidget* parent=0, const char* name=0, const QGLWidget* shareWidget=0,Qt::WindowFlags flags=0) - : QGLWidget(format, parent, name, shareWidget, flags) - { defaultConstructor(); } - - QGLViewer(QGLContext* context, QWidget* parent, const char* name=0, const QGLWidget* shareWidget=0, Qt::WindowFlags flags=0) - : QGLWidget(context, parent, name, shareWidget, flags) { - defaultConstructor(); } - -#else - - explicit QGLViewer(QWidget* parent=0, const QGLWidget* shareWidget=0, Qt::WindowFlags flags=Qt::WindowFlags()); - explicit QGLViewer(QGLContext *context, QWidget* parent=0, const QGLWidget* shareWidget=0, Qt::WindowFlags flags=Qt::WindowFlags()); - explicit QGLViewer(const QGLFormat& format, QWidget* parent=0, const QGLWidget* shareWidget=0, Qt::WindowFlags flags=Qt::WindowFlags()); + explicit QGLViewer(QWidget *parent = 0, + Qt::WindowFlags flags = Qt::WindowFlags()); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + explicit QGLViewer(QWidget *parent, const QGLWidget *shareWidget, + Qt::WindowFlags flags = 0); + explicit QGLViewer(QGLContext *context, QWidget *parent = 0, + const QGLWidget *shareWidget = 0, + Qt::WindowFlags flags = 0); + explicit QGLViewer(const QGLFormat &format, QWidget *parent = 0, + const QGLWidget *shareWidget = 0, + Qt::WindowFlags flags = 0); #endif + virtual ~QGLViewer(); - virtual ~QGLViewer(); - - /*! @name Display of visual hints */ - //@{ + /*! @name Display of visual hints */ + //@{ public: - /*! Returns \c true if the world axis is drawn by the viewer. - - Set by setAxisIsDrawn() or toggleAxisIsDrawn(). Default value is \c false. */ - bool axisIsDrawn() const { return axisIsDrawn_; } - /*! Returns \c true if a XY grid is drawn by the viewer. + /*! Returns \c true if the world axis is drawn by the viewer. - Set by setGridIsDrawn() or toggleGridIsDrawn(). Default value is \c false. */ - bool gridIsDrawn() const { return gridIsDrawn_; } - /*! Returns \c true if the viewer displays the current frame rate (Frames Per Second). + Set by setAxisIsDrawn() or toggleAxisIsDrawn(). Default value is \c false. */ + bool axisIsDrawn() const { return axisIsDrawn_; } + /*! Returns \c true if a XY grid is drawn by the viewer. - Use QApplication::setFont() to define the display font (see drawText()). + Set by setGridIsDrawn() or toggleGridIsDrawn(). Default value is \c false. */ + bool gridIsDrawn() const { return gridIsDrawn_; } + /*! Returns \c true if the viewer displays the current frame rate (Frames Per + Second). - Set by setFPSIsDisplayed() or toggleFPSIsDisplayed(). Use currentFPS() to get the current FPS. - Default value is \c false. */ - bool FPSIsDisplayed() const { return FPSIsDisplayed_; } - /*! Returns \c true if text display (see drawText()) is enabled. + Use QApplication::setFont() to define the display font (see drawText()). - Set by setTextIsEnabled() or toggleTextIsEnabled(). This feature conveniently removes all the - possibly displayed text, cleaning display. Default value is \c true. */ - bool textIsEnabled() const { return textIsEnabled_; } + Set by setFPSIsDisplayed() or toggleFPSIsDisplayed(). Use currentFPS() to get + the current FPS. Default value is \c false. */ + bool FPSIsDisplayed() const { return FPSIsDisplayed_; } + /*! Returns \c true if text display (see drawText()) is enabled. - /*! Returns \c true if the camera() is being edited in the viewer. + Set by setTextIsEnabled() or toggleTextIsEnabled(). This feature conveniently + removes all the possibly displayed text, cleaning display. Default value is \c + true. */ + bool textIsEnabled() const { return textIsEnabled_; } - Set by setCameraIsEdited() or toggleCameraIsEdited(). Default value is \p false. + /*! Returns \c true if the camera() is being edited in the viewer. - The current implementation is limited: the defined camera() paths (see - qglviewer::Camera::keyFrameInterpolator()) are simply displayed using - qglviewer::Camera::drawAllPaths(). Actual camera and path edition will be implemented in the - future. */ - bool cameraIsEdited() const { return cameraIsEdited_; } + Set by setCameraIsEdited() or toggleCameraIsEdited(). Default value is \p + false. + The current implementation is limited: the defined camera() paths (see + qglviewer::Camera::keyFrameInterpolator()) are simply displayed using + qglviewer::Camera::drawAllPaths(). Actual camera and path edition will be + implemented in the future. */ + bool cameraIsEdited() const { return cameraIsEdited_; } public Q_SLOTS: - /*! Sets the state of axisIsDrawn(). Emits the axisIsDrawnChanged() signal. See also toggleAxisIsDrawn(). */ - void setAxisIsDrawn(bool draw=true) { axisIsDrawn_ = draw; Q_EMIT axisIsDrawnChanged(draw); update(); } - /*! Sets the state of gridIsDrawn(). Emits the gridIsDrawnChanged() signal. See also toggleGridIsDrawn(). */ - void setGridIsDrawn(bool draw=true) { gridIsDrawn_ = draw; Q_EMIT gridIsDrawnChanged(draw); update(); } - /*! Sets the state of FPSIsDisplayed(). Emits the FPSIsDisplayedChanged() signal. See also toggleFPSIsDisplayed(). */ - void setFPSIsDisplayed(bool display=true) { FPSIsDisplayed_ = display; Q_EMIT FPSIsDisplayedChanged(display); update(); } - /*! Sets the state of textIsEnabled(). Emits the textIsEnabledChanged() signal. See also toggleTextIsEnabled(). */ - void setTextIsEnabled(bool enable=true) { textIsEnabled_ = enable; Q_EMIT textIsEnabledChanged(enable); update(); } - void setCameraIsEdited(bool edit=true); - - /*! Toggles the state of axisIsDrawn(). See also setAxisIsDrawn(). */ - void toggleAxisIsDrawn() { setAxisIsDrawn(!axisIsDrawn()); } - /*! Toggles the state of gridIsDrawn(). See also setGridIsDrawn(). */ - void toggleGridIsDrawn() { setGridIsDrawn(!gridIsDrawn()); } - /*! Toggles the state of FPSIsDisplayed(). See also setFPSIsDisplayed(). */ - void toggleFPSIsDisplayed() { setFPSIsDisplayed(!FPSIsDisplayed()); } - /*! Toggles the state of textIsEnabled(). See also setTextIsEnabled(). */ - void toggleTextIsEnabled() { setTextIsEnabled(!textIsEnabled()); } - /*! Toggles the state of cameraIsEdited(). See also setCameraIsEdited(). */ - void toggleCameraIsEdited() { setCameraIsEdited(!cameraIsEdited()); } - //@} - - - /*! @name Viewer's colors */ - //@{ + /*! Sets the state of axisIsDrawn(). Emits the axisIsDrawnChanged() signal. + * See also toggleAxisIsDrawn(). */ + void setAxisIsDrawn(bool draw = true) { + axisIsDrawn_ = draw; + Q_EMIT axisIsDrawnChanged(draw); + update(); + } + /*! Sets the state of gridIsDrawn(). Emits the gridIsDrawnChanged() signal. + * See also toggleGridIsDrawn(). */ + void setGridIsDrawn(bool draw = true) { + gridIsDrawn_ = draw; + Q_EMIT gridIsDrawnChanged(draw); + update(); + } + /*! Sets the state of FPSIsDisplayed(). Emits the FPSIsDisplayedChanged() + * signal. See also toggleFPSIsDisplayed(). */ + void setFPSIsDisplayed(bool display = true) { + FPSIsDisplayed_ = display; + Q_EMIT FPSIsDisplayedChanged(display); + update(); + } + /*! Sets the state of textIsEnabled(). Emits the textIsEnabledChanged() + * signal. See also toggleTextIsEnabled(). */ + void setTextIsEnabled(bool enable = true) { + textIsEnabled_ = enable; + Q_EMIT textIsEnabledChanged(enable); + update(); + } + void setCameraIsEdited(bool edit = true); + + /*! Toggles the state of axisIsDrawn(). See also setAxisIsDrawn(). */ + void toggleAxisIsDrawn() { setAxisIsDrawn(!axisIsDrawn()); } + /*! Toggles the state of gridIsDrawn(). See also setGridIsDrawn(). */ + void toggleGridIsDrawn() { setGridIsDrawn(!gridIsDrawn()); } + /*! Toggles the state of FPSIsDisplayed(). See also setFPSIsDisplayed(). */ + void toggleFPSIsDisplayed() { setFPSIsDisplayed(!FPSIsDisplayed()); } + /*! Toggles the state of textIsEnabled(). See also setTextIsEnabled(). */ + void toggleTextIsEnabled() { setTextIsEnabled(!textIsEnabled()); } + /*! Toggles the state of cameraIsEdited(). See also setCameraIsEdited(). */ + void toggleCameraIsEdited() { setCameraIsEdited(!cameraIsEdited()); } + //@} + + /*! @name Viewer's colors */ + //@{ public: - /*! Returns the background color of the viewer. + /*! Returns the background color of the viewer. - This method is provided for convenience since the background color is an OpenGL state variable - set with \c glClearColor(). However, this internal representation has the advantage that it is - saved (resp. restored) with saveStateToFile() (resp. restoreStateFromFile()). + This method is provided for convenience since the background color is an + OpenGL state variable set with \c glClearColor(). However, this internal + representation has the advantage that it is saved (resp. restored) with + saveStateToFile() (resp. restoreStateFromFile()). - Use setBackgroundColor() to define and activate a background color. + Use setBackgroundColor() to define and activate a background color. - \attention Each QColor component is an integer ranging from 0 to 255. This differs from the qreal - values used by \c glClearColor() which are in the 0.0-1.0 range. Default value is (51, 51, 51) - (dark gray). You may have to change foregroundColor() accordingly. + \attention Each QColor component is an integer ranging from 0 to 255. This + differs from the qreal values used by \c glClearColor() which are in the + 0.0-1.0 range. Default value is (51, 51, 51) (dark gray). You may have to + change foregroundColor() accordingly. - \attention This method does not return the current OpenGL clear color as \c glGet() does. Instead, - it returns the QGLViewer internal variable. If you directly use \c glClearColor() or \c - qglClearColor() instead of setBackgroundColor(), the two results will differ. */ - QColor backgroundColor() const { return backgroundColor_; } + \attention This method does not return the current OpenGL clear color as \c + glGet() does. Instead, it returns the QGLViewer internal variable. If you + directly use \c glClearColor() or \c qglClearColor() instead of + setBackgroundColor(), the two results will differ. */ + QColor backgroundColor() const { return backgroundColor_; } - /*! Returns the foreground color used by the viewer. + /*! Returns the foreground color used by the viewer. - This color is used when FPSIsDisplayed(), gridIsDrawn(), to display the camera paths when the - cameraIsEdited(). + This color is used when FPSIsDisplayed(), gridIsDrawn(), to display the camera + paths when the cameraIsEdited(). - \attention Each QColor component is an integer in the range 0-255. This differs from the qreal - values used by \c glColor3f() which are in the range 0-1. Default value is (180, 180, 180) (light - gray). + \attention Each QColor component is an integer in the range 0-255. This + differs from the qreal values used by \c glColor3f() which are in the range + 0-1. Default value is (180, 180, 180) (light gray). - Use \c qglColor(foregroundColor()) to set the current OpenGL color to the foregroundColor(). + Use \c qglColor(foregroundColor()) to set the current OpenGL color to the + foregroundColor(). - See also backgroundColor(). */ - QColor foregroundColor() const { return foregroundColor_; } + See also backgroundColor(). */ + QColor foregroundColor() const { return foregroundColor_; } public Q_SLOTS: - /*! Sets the backgroundColor() of the viewer and calls \c qglClearColor(). See also - setForegroundColor(). */ - void setBackgroundColor(const QColor& color) { backgroundColor_=color; qglClearColor(color); } - /*! Sets the foregroundColor() of the viewer, used to draw visual hints. See also setBackgroundColor(). */ - void setForegroundColor(const QColor& color) { foregroundColor_ = color; } - //@} - - - /*! @name Scene dimensions */ - //@{ + /*! Sets the backgroundColor() of the viewer and calls \c qglClearColor(). See + also setForegroundColor(). */ + void setBackgroundColor(const QColor &color) { + backgroundColor_ = color; + glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF()); + } + /*! Sets the foregroundColor() of the viewer, used to draw visual hints. See + * also setBackgroundColor(). */ + void setForegroundColor(const QColor &color) { foregroundColor_ = color; } + //@} + + /*! @name Scene dimensions */ + //@{ public: - /*! Returns the scene radius. + /*! Returns the scene radius. - The entire displayed scene should be included in a sphere of radius sceneRadius(), centered on - sceneCenter(). + The entire displayed scene should be included in a sphere of radius + sceneRadius(), centered on sceneCenter(). - This approximate value is used by the camera() to set qglviewer::Camera::zNear() and - qglviewer::Camera::zFar(). It is also used to showEntireScene() or to scale the world axis - display.. + This approximate value is used by the camera() to set + qglviewer::Camera::zNear() and qglviewer::Camera::zFar(). It is also used to + showEntireScene() or to scale the world axis display.. - Default value is 1.0. This method is equivalent to camera()->sceneRadius(). See - setSceneRadius(). */ - qreal sceneRadius() const { return camera()->sceneRadius(); } - /*! Returns the scene center, defined in world coordinates. + Default value is 1.0. This method is equivalent to camera()->sceneRadius(). + See setSceneRadius(). */ + qreal sceneRadius() const { return camera()->sceneRadius(); } + /*! Returns the scene center, defined in world coordinates. - See sceneRadius() for details. + See sceneRadius() for details. - Default value is (0,0,0). Simply a wrapper for camera()->sceneCenter(). Set using - setSceneCenter(). + Default value is (0,0,0). Simply a wrapper for camera()->sceneCenter(). Set + using setSceneCenter(). - Do not mismatch this value (that only depends on the scene) with the qglviewer::Camera::pivotPoint(). */ - qglviewer::Vec sceneCenter() const { return camera()->sceneCenter(); } + Do not mismatch this value (that only depends on the scene) with the + qglviewer::Camera::pivotPoint(). */ + qglviewer::Vec sceneCenter() const { return camera()->sceneCenter(); } public Q_SLOTS: - /*! Sets the sceneRadius(). - - The camera() qglviewer::Camera::flySpeed() is set to 1% of this value by this method. Simple - wrapper around camera()->setSceneRadius(). */ - virtual void setSceneRadius(qreal radius) { camera()->setSceneRadius(radius); } - - /*! Sets the sceneCenter(), defined in world coordinates. - - \attention The qglviewer::Camera::pivotPoint() is set to the sceneCenter() value by this - method. */ - virtual void setSceneCenter(const qglviewer::Vec& center) { camera()->setSceneCenter(center); } - - /*! Convenient way to call setSceneCenter() and setSceneRadius() from a (world axis aligned) bounding box of the scene. - - This is equivalent to: - \code - setSceneCenter((min+max) / 2.0); - setSceneRadius((max-min).norm() / 2.0); - \endcode */ - void setSceneBoundingBox(const qglviewer::Vec& min, const qglviewer::Vec& max) { camera()->setSceneBoundingBox(min,max); } - - /*! Moves the camera so that the entire scene is visible. - - Simple wrapper around qglviewer::Camera::showEntireScene(). */ - void showEntireScene() { camera()->showEntireScene(); update(); } - //@} - - - /*! @name Associated objects */ - //@{ + /*! Sets the sceneRadius(). + + The camera() qglviewer::Camera::flySpeed() is set to 1% of this value by + this method. Simple wrapper around camera()->setSceneRadius(). */ + virtual void setSceneRadius(qreal radius) { + camera()->setSceneRadius(radius); + } + + /*! Sets the sceneCenter(), defined in world coordinates. + + \attention The qglviewer::Camera::pivotPoint() is set to the sceneCenter() + value by this method. */ + virtual void setSceneCenter(const qglviewer::Vec ¢er) { + camera()->setSceneCenter(center); + } + + /*! Convenient way to call setSceneCenter() and setSceneRadius() from a (world + axis aligned) bounding box of the scene. + + This is equivalent to: + \code + setSceneCenter((min+max) / 2.0); + setSceneRadius((max-min).norm() / 2.0); + \endcode */ + void setSceneBoundingBox(const qglviewer::Vec &min, + const qglviewer::Vec &max) { + camera()->setSceneBoundingBox(min, max); + } + + /*! Moves the camera so that the entire scene is visible. + + Simple wrapper around qglviewer::Camera::showEntireScene(). */ + void showEntireScene() { + camera()->showEntireScene(); + update(); + } + //@} + + /*! @name Associated objects */ + //@{ public: - /*! Returns the associated qglviewer::Camera, never \c NULL. */ - qglviewer::Camera* camera() const { return camera_; } + /*! Returns the associated qglviewer::Camera, never \c nullptr. */ + qglviewer::Camera *camera() const { return camera_; } - /*! Returns the viewer's qglviewer::ManipulatedFrame. + /*! Returns the viewer's qglviewer::ManipulatedFrame. - This qglviewer::ManipulatedFrame can be moved with the mouse when the associated mouse bindings - are used (default is when pressing the \c Control key with any mouse button). Use - setMouseBinding() to define new bindings. + This qglviewer::ManipulatedFrame can be moved with the mouse when the + associated mouse bindings are used (default is when pressing the \c Control + key with any mouse button). Use setMouseBinding() to define new bindings. - See the manipulatedFrame example for a complete - implementation. + See the manipulatedFrame + example for a complete implementation. - Default value is \c NULL, meaning that no qglviewer::ManipulatedFrame is set. */ - qglviewer::ManipulatedFrame* manipulatedFrame() const { return manipulatedFrame_; } + Default value is \c nullptr, meaning that no qglviewer::ManipulatedFrame is set. +*/ + qglviewer::ManipulatedFrame *manipulatedFrame() const { + return manipulatedFrame_; + } public Q_SLOTS: - void setCamera(qglviewer::Camera* const camera); - void setManipulatedFrame(qglviewer::ManipulatedFrame* frame); - //@} - + void setCamera(qglviewer::Camera *const camera); + void setManipulatedFrame(qglviewer::ManipulatedFrame *frame); + //@} - /*! @name Mouse grabbers */ - //@{ + /*! @name Mouse grabbers */ + //@{ public: - /*! Returns the current qglviewer::MouseGrabber, or \c NULL if no qglviewer::MouseGrabber - currently grabs mouse events. - - When qglviewer::MouseGrabber::grabsMouse(), the different mouse events are sent to the - mouseGrabber() instead of their usual targets (camera() or manipulatedFrame()). - - See the qglviewer::MouseGrabber documentation for details on MouseGrabber's mode of operation. - - In order to use MouseGrabbers, you need to enable mouse tracking (so that mouseMoveEvent() is - called even when no mouse button is pressed). Add this line in init() or in your viewer - constructor: - \code - setMouseTracking(true); - \endcode - Note that mouse tracking is disabled by default. Use QWidget::hasMouseTracking() to - retrieve current state. */ - qglviewer::MouseGrabber* mouseGrabber() const { return mouseGrabber_; } - - void setMouseGrabberIsEnabled(const qglviewer::MouseGrabber* const mouseGrabber, bool enabled=true); - /*! Returns \c true if \p mouseGrabber is enabled. - - Default value is \c true for all MouseGrabbers. When set to \c false using - setMouseGrabberIsEnabled(), the specified \p mouseGrabber will never become the mouseGrabber() of - this QGLViewer. This is useful when you use several viewers: some MouseGrabbers may only have a - meaning for some specific viewers and should not be selectable in others. - - You can also use qglviewer::MouseGrabber::removeFromMouseGrabberPool() to completely disable a - MouseGrabber in all the QGLViewers. */ - bool mouseGrabberIsEnabled(const qglviewer::MouseGrabber* const mouseGrabber) { return !disabledMouseGrabbers_.contains(reinterpret_cast(mouseGrabber)); } + /*! Returns the current qglviewer::MouseGrabber, or \c nullptr if no + qglviewer::MouseGrabber currently grabs mouse events. + + When qglviewer::MouseGrabber::grabsMouse(), the different mouse events are + sent to the mouseGrabber() instead of their usual targets (camera() or + manipulatedFrame()). + + See the qglviewer::MouseGrabber documentation for details on MouseGrabber's + mode of operation. + + In order to use MouseGrabbers, you need to enable mouse tracking (so that + mouseMoveEvent() is called even when no mouse button is pressed). Add this + line in init() or in your viewer constructor: \code setMouseTracking(true); + \endcode + Note that mouse tracking is disabled by default. Use + QWidget::hasMouseTracking() to retrieve current state. */ + qglviewer::MouseGrabber *mouseGrabber() const { return mouseGrabber_; } + + void + setMouseGrabberIsEnabled(const qglviewer::MouseGrabber *const mouseGrabber, + bool enabled = true); + /*! Returns \c true if \p mouseGrabber is enabled. + + Default value is \c true for all MouseGrabbers. When set to \c false using + setMouseGrabberIsEnabled(), the specified \p mouseGrabber will never become + the mouseGrabber() of this QGLViewer. This is useful when you use several + viewers: some MouseGrabbers may only have a meaning for some specific viewers + and should not be selectable in others. + + You can also use qglviewer::MouseGrabber::removeFromMouseGrabberPool() to + completely disable a MouseGrabber in all the QGLViewers. */ + bool + mouseGrabberIsEnabled(const qglviewer::MouseGrabber *const mouseGrabber) { + return !disabledMouseGrabbers_.contains( + reinterpret_cast(mouseGrabber)); + } public Q_SLOTS: - void setMouseGrabber(qglviewer::MouseGrabber* mouseGrabber); - //@} + void setMouseGrabber(qglviewer::MouseGrabber *mouseGrabber); + //@} - - /*! @name State of the viewer */ - //@{ + /*! @name State of the viewer */ + //@{ public: - /*! Returns the aspect ratio of the viewer's widget (width() / height()). */ - qreal aspectRatio() const { return width() / static_cast(height()); } - /*! Returns the current averaged viewer frame rate. - - This value is computed and averaged over 20 successive frames. It only changes every 20 draw() - (previously computed value is otherwise returned). - - This method is useful for true real-time applications that may adapt their computational load - accordingly in order to maintain a given frequency. - - This value is meaningful only when draw() is regularly called, either using a \c QTimer, when - animationIsStarted() or when the camera is manipulated with the mouse. */ - qreal currentFPS() { return f_p_s_; } - /*! Returns \c true if the viewer is in fullScreen mode. - - Default value is \c false. Set by setFullScreen() or toggleFullScreen(). - - Note that if the QGLViewer is embedded in an other QWidget, it returns \c true when the top level - widget is in full screen mode. */ - bool isFullScreen() const { return fullScreen_; } - /*! Returns \c true if the viewer displays in stereo. - - The QGLViewer object must be created with a stereo format to handle stereovision: - \code - QGLFormat format; - format.setStereoDisplay( TRUE ); - QGLViewer viewer(format); - \endcode - The hardware needs to support stereo display. Try the stereoViewer example to check. - - Set by setStereoDisplay() or toggleStereoDisplay(). Default value is \c false. - - Stereo is performed using the Parallel axis asymmetric frustum perspective projection method. - See Camera::loadProjectionMatrixStereo() and Camera::loadModelViewMatrixStereo(). - - The stereo parameters are defined by the camera(). See qglviewer::Camera::setIODistance(), - qglviewer::Camera::setPhysicalScreenWidth() and - qglviewer::Camera::setFocusDistance(). */ - bool displaysInStereo() const { return stereo_; } - /*! Returns the recommended size for the QGLViewer. Default value is 600x400 pixels. */ - virtual QSize sizeHint() const { return QSize(600, 400); } + /*! Returns the aspect ratio of the viewer's widget (width() / height()). */ + qreal aspectRatio() const { return width() / static_cast(height()); } + /*! Returns the current averaged viewer frame rate. + + This value is computed and averaged over 20 successive frames. It only changes + every 20 draw() (previously computed value is otherwise returned). + + This method is useful for true real-time applications that may adapt their + computational load accordingly in order to maintain a given frequency. + + This value is meaningful only when draw() is regularly called, either using a + \c QTimer, when animationIsStarted() or when the camera is manipulated with + the mouse. */ + qreal currentFPS() { return f_p_s_; } + /*! Returns \c true if the viewer is in fullScreen mode. + + Default value is \c false. Set by setFullScreen() or toggleFullScreen(). + + Note that if the QGLViewer is embedded in an other QWidget, it returns \c true + when the top level widget is in full screen mode. */ + bool isFullScreen() const { return fullScreen_; } + /*! Returns \c true if the viewer displays in stereo. + + The QGLViewer object must be created with a stereo format to handle + stereovision: \code QGLFormat format; format.setStereoDisplay( TRUE ); + QGLViewer viewer(format); + \endcode + The hardware needs to support stereo display. Try the stereoViewer example to check. + + Set by setStereoDisplay() or toggleStereoDisplay(). Default value is \c false. + + Stereo is performed using the Parallel axis asymmetric frustum perspective + projection method. See Camera::loadProjectionMatrixStereo() and + Camera::loadModelViewMatrixStereo(). + + The stereo parameters are defined by the camera(). See + qglviewer::Camera::setIODistance(), + qglviewer::Camera::setPhysicalScreenWidth() and + qglviewer::Camera::setFocusDistance(). */ + bool displaysInStereo() const { return stereo_; } + /*! Returns the recommended size for the QGLViewer. Default value is 600x400 + * pixels. */ + virtual QSize sizeHint() const { return QSize(600, 400); } public Q_SLOTS: - void setFullScreen(bool fullScreen=true); - void setStereoDisplay(bool stereo=true); - /*! Toggles the state of isFullScreen(). See also setFullScreen(). */ - void toggleFullScreen() { setFullScreen(!isFullScreen()); } - /*! Toggles the state of displaysInStereo(). See setStereoDisplay(). */ - void toggleStereoDisplay() { setStereoDisplay(!stereo_); } - void toggleCameraMode(); + void setFullScreen(bool fullScreen = true); + void setStereoDisplay(bool stereo = true); + /*! Toggles the state of isFullScreen(). See also setFullScreen(). */ + void toggleFullScreen() { setFullScreen(!isFullScreen()); } + /*! Toggles the state of displaysInStereo(). See setStereoDisplay(). */ + void toggleStereoDisplay() { setStereoDisplay(!stereo_); } + void toggleCameraMode(); private: - bool cameraIsInRotateMode() const; - //@} - + bool cameraIsInRotateMode() const; + //@} - /*! @name Display methods */ - //@{ + /*! @name Display methods */ + //@{ public: - static void drawArrow(qreal length=1.0, qreal radius=-1.0, int nbSubdivisions=12); - static void drawArrow(const qglviewer::Vec& from, const qglviewer::Vec& to, qreal radius=-1.0, int nbSubdivisions=12); - static void drawAxis(qreal length=1.0); - static void drawGrid(qreal size=1.0, int nbSubdivisions=10); + static void drawArrow(qreal length = 1.0, qreal radius = -1.0, + int nbSubdivisions = 12); + static void drawArrow(const qglviewer::Vec &from, const qglviewer::Vec &to, + qreal radius = -1.0, int nbSubdivisions = 12); + static void drawAxis(qreal length = 1.0); + static void drawGrid(qreal size = 1.0, int nbSubdivisions = 10); - virtual void startScreenCoordinatesSystem(bool upward=false) const; - virtual void stopScreenCoordinatesSystem() const; + virtual void startScreenCoordinatesSystem(bool upward = false) const; + virtual void stopScreenCoordinatesSystem() const; - void drawText(int x, int y, const QString& text, const QFont& fnt=QFont()); - void displayMessage(const QString& message, int delay=2000); - // void draw3DText(const qglviewer::Vec& pos, const qglviewer::Vec& normal, const QString& string, GLfloat height=0.1); + void drawText(int x, int y, const QString &text, const QFont &fnt = QFont()); + void displayMessage(const QString &message, int delay = 2000); + // void draw3DText(const qglviewer::Vec& pos, const qglviewer::Vec& normal, + // const QString& string, GLfloat height=0.1); protected: - virtual void drawLight(GLenum light, qreal scale = 1.0) const; + virtual void drawLight(GLenum light, qreal scale = 1.0) const; private: - void displayFPS(); - /*! Vectorial rendering callback method. */ - void drawVectorial() { paintGL(); } + void displayFPS(); + /*! Vectorial rendering callback method. */ + void drawVectorial() { paintGL(); } #ifndef DOXYGEN - friend void drawVectorial(void* param); + friend void drawVectorial(void *param); #endif - //@} - +//@} #ifdef DOXYGEN - /*! @name Useful inherited methods */ - //@{ + /*! @name Useful inherited methods */ + //@{ public: - /*! Returns viewer's widget width (in pixels). See QGLWidget documentation. */ - int width() const; - /*! Returns viewer's widget height (in pixels). See QGLWidget documentation. */ - int height() const; - /*! Updates the display. Do not call draw() directly, use this method instead. See QGLWidget documentation. */ - virtual void updateGL(); - /*! Converts \p image into the unnamed format expected by OpenGL methods such as glTexImage2D(). - See QGLWidget documentation. */ - static QImage convertToGLFormat(const QImage & image); - /*! Calls \c glColor3. See QGLWidget::qglColor(). */ - void qglColor(const QColor& color) const; - /*! Calls \c glClearColor. See QGLWidget documentation. */ - void qglClearColor(const QColor& color) const; - /*! Returns \c true if the widget has a valid GL rendering context. See QGLWidget - documentation. */ - bool isValid() const; - /*! Returns \c true if display list sharing with another QGLWidget was requested in the - constructor. See QGLWidget documentation. */ - bool isSharing() const; - /*! Makes this widget's rendering context the current OpenGL rendering context. Useful with - several viewers. See QGLWidget documentation. */ - virtual void makeCurrent(); - /*! Returns \c true if mouseMoveEvent() is called even when no mouse button is pressed. - - You need to setMouseTracking() to \c true in order to use MouseGrabber (see mouseGrabber()). See - details in the QWidget documentation. */ - bool hasMouseTracking () const; + /*! Returns viewer's widget width (in pixels). See QOpenGLWidget + * documentation. */ + int width() const; + /*! Returns viewer's widget height (in pixels). See QOpenGLWidget + * documentation. */ + int height() const; + /*! Updates the display. Do not call draw() directly, use this method instead. + * See QOpenGLWidget documentation. */ + virtual void update(); + /*! Returns \c true if the widget has a valid GL rendering context. See + QOpenGLWidget documentation. */ + bool isValid() const; + /*! Makes this widget's rendering context the current OpenGL rendering + context. Useful with several viewers. See QOpenGLWidget documentation. */ + virtual void makeCurrent(); + /*! Returns \c true if mouseMoveEvent() is called even when no mouse button is + pressed. + + You need to setMouseTracking() to \c true in order to use MouseGrabber (see + mouseGrabber()). See details in the QWidget documentation. */ + bool hasMouseTracking() const; public Q_SLOTS: - /*! Resizes the widget to size \p width by \p height pixels. See also width() and height(). */ - virtual void resize(int width, int height); - /*! Sets the hasMouseTracking() value. */ - virtual void setMouseTracking(bool enable); -protected: - /*! Returns \c true when buffers are automatically swapped (default). See details in the QGLWidget - documentation. */ - bool autoBufferSwap() const; -protected Q_SLOTS: - /*! Sets the autoBufferSwap() value. */ - void setAutoBufferSwap(bool on); - //@} + /*! Resizes the widget to size \p width by \p height pixels. See also width() + * and height(). */ + virtual void resize(int width, int height); + /*! Sets the hasMouseTracking() value. */ + virtual void setMouseTracking(bool enable); #endif - - /*! @name Snapshots */ - //@{ + /*! @name Snapshots */ + //@{ public: - /*! Returns the snapshot file name used by saveSnapshot(). + /*! Returns the snapshot file name used by saveSnapshot(). - This value is used in \p automatic mode (see saveSnapshot()). A dialog is otherwise popped-up to - set it. + This value is used in \p automatic mode (see saveSnapshot()). A dialog is + otherwise popped-up to set it. - You can also directly provide a file name using saveSnapshot(const QString&, bool). + You can also directly provide a file name using saveSnapshot(const QString&, + bool). - If the file name is relative, the current working directory at the moment of the method call is - used. Set using setSnapshotFileName(). */ - const QString& snapshotFileName() const { return snapshotFileName_; } + If the file name is relative, the current working directory at the moment of + the method call is used. Set using setSnapshotFileName(). */ + const QString &snapshotFileName() const { return snapshotFileName_; } #ifndef DOXYGEN - const QString& snapshotFilename() const; + const QString &snapshotFilename() const; #endif - /*! Returns the snapshot file format used by saveSnapshot(). + /*! Returns the snapshot file format used by saveSnapshot(). - This value is used when saveSnapshot() is passed the \p automatic flag. It is defined using a - saveAs pop-up dialog otherwise. + This value is used when saveSnapshot() is passed the \p automatic flag. It is + defined using a saveAs pop-up dialog otherwise. - The available formats are those handled by Qt. Classical values are \c "JPEG", \c "PNG", - \c "PPM", \c "BMP". Use the following code to get the actual list: - \code - QList formatList = QImageReader::supportedImageFormats(); - // or with Qt version 2 or 3: - QStringList formatList = QImage::outputFormatList(); - \endcode + The available formats are those handled by Qt. Classical values are \c "JPEG", + \c "PNG", \c "PPM", \c "BMP". Use the following code to get the actual list: + \code + QList formatList = QImageReader::supportedImageFormats(); + // or with Qt version 2 or 3: + QStringList formatList = QImage::outputFormatList(); + \endcode - If the library was compiled with the vectorial rendering option (default), three additional - vectorial formats are available: \c "EPS", \c "PS" and \c "XFIG". \c "SVG" and \c "PDF" formats - should soon be available. The VRender library - was created by Cyril Soler. + If the library was compiled with the vectorial rendering option (default), + three additional vectorial formats are available: \c "EPS", \c "PS" and \c + "XFIG". \c "SVG" and \c "PDF" formats should soon be available. The VRender library was created + by Cyril Soler. - Note that the VRender library has some limitations: vertex shader effects are not reproduced and - \c PASS_THROUGH tokens are not handled so one can not change point and line size in the middle of - a drawing. + Note that the VRender library has some limitations: vertex shader effects are + not reproduced and \c PASS_THROUGH tokens are not handled so one can not + change point and line size in the middle of a drawing. - Default value is the first supported among "JPEG, PNG, EPS, PS, PPM, BMP", in that order. + Default value is the first supported among "JPEG, PNG, EPS, PS, PPM, BMP", in + that order. - This value is set using setSnapshotFormat() or with openSnapshotFormatDialog(). + This value is set using setSnapshotFormat() or with + openSnapshotFormatDialog(). - \attention No verification is performed on the provided format validity. The next call to - saveSnapshot() may fail if the format string is not supported. */ - const QString& snapshotFormat() const { return snapshotFormat_; } - /*! Returns the value of the counter used to name snapshots in saveSnapshot() when \p automatic is - \c true. + \attention No verification is performed on the provided format validity. The + next call to saveSnapshot() may fail if the format string is not supported. */ + const QString &snapshotFormat() const { return snapshotFormat_; } + /*! Returns the value of the counter used to name snapshots in saveSnapshot() + when \p automatic is \c true. - Set using setSnapshotCounter(). Default value is 0, and it is incremented after each \p automatic - snapshot. See saveSnapshot() for details. */ - int snapshotCounter() const { return snapshotCounter_; } - /*! Defines the image quality of the snapshots produced with saveSnapshot(). + Set using setSnapshotCounter(). Default value is 0, and it is incremented + after each \p automatic snapshot. See saveSnapshot() for details. */ + int snapshotCounter() const { return snapshotCounter_; } + /*! Defines the image quality of the snapshots produced with saveSnapshot(). - Values must be in the range -1..100. Use 0 for lowest quality and 100 for highest quality (and - larger files). -1 means use Qt default quality. Default value is 95. + Values must be in the range -1..100. Use 0 for lowest quality and 100 for + highest quality (and larger files). -1 means use Qt default quality. Default + value is 95. - Set using setSnapshotQuality(). See also the QImage::save() documentation. + Set using setSnapshotQuality(). See also the QImage::save() documentation. - \note This value has no impact on the images produced in vectorial format. */ - int snapshotQuality() { return snapshotQuality_; } + \note This value has no impact on the images produced in vectorial format. */ + int snapshotQuality() { return snapshotQuality_; } - // Qt 2.3 does not support qreal default value parameters in slots. - // Remove "Q_SLOTS" from the following line to compile with Qt 2.3 + // Qt 2.3 does not support qreal default value parameters in slots. + // Remove "Q_SLOTS" from the following line to compile with Qt 2.3 public Q_SLOTS: - void saveSnapshot(bool automatic=true, bool overwrite=false); + void saveSnapshot(bool automatic = true, bool overwrite = false); public Q_SLOTS: - void saveSnapshot(const QString& fileName, bool overwrite=false); - void setSnapshotFileName(const QString& name); - - /*! Sets the snapshotFormat(). */ - void setSnapshotFormat(const QString& format) { snapshotFormat_ = format; } - /*! Sets the snapshotCounter(). */ - void setSnapshotCounter(int counter) { snapshotCounter_ = counter; } - /*! Sets the snapshotQuality(). */ - void setSnapshotQuality(int quality) { snapshotQuality_ = quality; } - bool openSnapshotFormatDialog(); - void snapshotToClipboard(); + void saveSnapshot(const QString &fileName, bool overwrite = false); + void setSnapshotFileName(const QString &name); + + /*! Sets the snapshotFormat(). */ + void setSnapshotFormat(const QString &format) { snapshotFormat_ = format; } + /*! Sets the snapshotCounter(). */ + void setSnapshotCounter(int counter) { snapshotCounter_ = counter; } + /*! Sets the snapshotQuality(). */ + void setSnapshotQuality(int quality) { snapshotQuality_ = quality; } + bool openSnapshotFormatDialog(); + void snapshotToClipboard(); private: - bool saveImageSnapshot(const QString& fileName); + bool saveImageSnapshot(const QString &fileName); #ifndef DOXYGEN - /* This class is used internally for screenshot that require tiling (image size size different - from window size). Only in that case, is the private tileRegion_ pointer non null. - It then contains the current tiled region, which is used by startScreenCoordinatesSystem - to adapt the coordinate system. Not using it would result in a tiled drawing of the parts - that use startScreenCoordinatesSystem. Also used by scaledFont for same purposes. */ - class TileRegion { public : qreal xMin, yMin, xMax, yMax, textScale; }; + /* This class is used internally for screenshot that require tiling (image + size size different from window size). Only in that case, is the private + tileRegion_ pointer non null. It then contains the current tiled region, which + is used by startScreenCoordinatesSystem to adapt the coordinate system. Not + using it would result in a tiled drawing of the parts that use + startScreenCoordinatesSystem. Also used by scaledFont for same purposes. */ + class TileRegion { + public: + qreal xMin, yMin, xMax, yMax, textScale; + }; #endif public: - /*! Return a possibly scaled version of \p font, used for snapshot rendering. - - From a user's point of view, this method simply returns \p font and can be used transparently. - - However when internally rendering a screen snapshot using saveSnapshot(), it returns a scaled version - of the font, so that the size of the rendered text on the snapshot is identical to what is displayed on screen, - even if the snapshot uses image tiling to create an image of dimensions different from those of the - current window. This scaled version will only be used when saveSnapshot() calls your draw() method - to generate the snapshot. - - All your calls to QGLWidget::renderText() function hence should use this method. - \code - renderText(x, y, z, "My Text", scaledFont(QFont())); - \endcode - will guarantee that this text will be properly displayed on arbitrary sized snapshots. - - Note that this method is not needed if you use drawText() which already calls it internally. */ - QFont scaledFont(const QFont& font) const { - if (tileRegion_ == NULL) - return font; - else { - QFont f(font); - if (f.pixelSize() == -1) - f.setPointSizeF(f.pointSizeF() * tileRegion_->textScale); - else - f.setPixelSize(int(f.pixelSize() * tileRegion_->textScale)); - return f; - } - } - //@} - - - /*! @name Buffer to texture */ - //@{ + /*! Return a possibly scaled version of \p font, used for snapshot rendering. + + From a user's point of view, this method simply returns \p font and can be + used transparently. + + However when internally rendering a screen snapshot using saveSnapshot(), it + returns a scaled version of the font, so that the size of the rendered text on + the snapshot is identical to what is displayed on screen, even if the snapshot + uses image tiling to create an image of dimensions different from those of the + current window. This scaled version will only be used when saveSnapshot() + calls your draw() method to generate the snapshot. + + All your calls to renderText() function hence should use this method. + \code + renderText(x, y, z, "My Text", scaledFont(QFont())); + \endcode + will guarantee that this text will be properly displayed on arbitrary sized + snapshots. + + Note that this method is not needed if you use drawText() which already calls + it internally. */ + QFont scaledFont(const QFont &font) const { + if (tileRegion_ == nullptr) + return font; + else { + QFont f(font); + if (f.pixelSize() == -1) + f.setPointSizeF(f.pointSizeF() * tileRegion_->textScale); + else + f.setPixelSize(int(f.pixelSize() * tileRegion_->textScale)); + return f; + } + } + //@} + + /*! @name Buffer to texture */ + //@{ public: - GLuint bufferTextureId() const; - /*! Returns the texture coordinate corresponding to the u extremum of the bufferTexture. - - The bufferTexture is created by copyBufferToTexture(). The texture size has powers of two - dimensions and the buffer image hence only fills a part of it. This value corresponds to the u - coordinate of the extremum right side of the buffer image. - - Use (0,0) to (bufferTextureMaxU(), bufferTextureMaxV()) texture coordinates to map the entire - texture on a quad. */ - qreal bufferTextureMaxU() const { return bufferTextureMaxU_; } - /*! Same as bufferTextureMaxU(), but for the v texture coordinate. */ - qreal bufferTextureMaxV() const { return bufferTextureMaxV_; } + GLuint bufferTextureId() const; + /*! Returns the texture coordinate corresponding to the u extremum of the + bufferTexture. + + The bufferTexture is created by copyBufferToTexture(). The texture size has + powers of two dimensions and the buffer image hence only fills a part of it. + This value corresponds to the u coordinate of the extremum right side of the + buffer image. + + Use (0,0) to (bufferTextureMaxU(), bufferTextureMaxV()) texture coordinates to + map the entire texture on a quad. */ + qreal bufferTextureMaxU() const { return bufferTextureMaxU_; } + /*! Same as bufferTextureMaxU(), but for the v texture coordinate. */ + qreal bufferTextureMaxV() const { return bufferTextureMaxV_; } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) + // These methods are part of the QGLWidget public API. + // As of version 2.7.0, the use of QOpenGLWidget instead means that they have + // to be provided for backward compatibility. + void renderText(int x, int y, const QString &str, + const QFont &font = QFont()); + void renderText(double x, double y, double z, const QString &str, + const QFont &font = QFont()); +#endif + public Q_SLOTS: - void copyBufferToTexture(GLint internalFormat, GLenum format=GL_NONE); - //@} + void copyBufferToTexture(GLint internalFormat, GLenum format = GL_NONE); + //@} - /*! @name Animation */ - //@{ + /*! @name Animation */ + //@{ public: - /*! Return \c true when the animation loop is started. + /*! Return \c true when the animation loop is started. - During animation, an infinite loop calls animate() and draw() and then waits for animationPeriod() - milliseconds before calling animate() and draw() again. And again. + During animation, an infinite loop calls animate() and draw() and then waits + for animationPeriod() milliseconds before calling animate() and draw() again. + And again. - Use startAnimation(), stopAnimation() or toggleAnimation() to change this value. + Use startAnimation(), stopAnimation() or toggleAnimation() to change this + value. - See the animation example for illustration. */ - bool animationIsStarted() const { return animationStarted_; } - /*! The animation loop period, in milliseconds. + See the animation example for + illustration. */ + bool animationIsStarted() const { return animationStarted_; } + /*! The animation loop period, in milliseconds. - When animationIsStarted(), this is delay waited after draw() to call animate() and draw() again. - Default value is 40 milliseconds (25 Hz). + When animationIsStarted(), this is delay waited after draw() to call animate() + and draw() again. Default value is 40 milliseconds (25 Hz). - This value will define the currentFPS() when animationIsStarted() (provided that your animate() - and draw() methods are fast enough). + This value will define the currentFPS() when animationIsStarted() (provided + that your animate() and draw() methods are fast enough). - If you want to know the maximum possible frame rate of your machine on a given scene, - setAnimationPeriod() to \c 0, and startAnimation() (keyboard shortcut is \c Enter). The display - will then be updated as often as possible, and the frame rate will be meaningful. + If you want to know the maximum possible frame rate of your machine on a given + scene, setAnimationPeriod() to \c 0, and startAnimation() (keyboard shortcut + is \c Enter). The display will then be updated as often as possible, and the + frame rate will be meaningful. - \note This value is taken into account only the next time you call startAnimation(). If - animationIsStarted(), you should stopAnimation() first. */ - int animationPeriod() const { return animationPeriod_; } + \note This value is taken into account only the next time you call + startAnimation(). If animationIsStarted(), you should stopAnimation() first. +*/ + int animationPeriod() const { return animationPeriod_; } public Q_SLOTS: - /*! Sets the animationPeriod(), in milliseconds. */ - void setAnimationPeriod(int period) { animationPeriod_ = period; } - virtual void startAnimation(); - virtual void stopAnimation(); - /*! Scene animation method. - - When animationIsStarted(), this method is in charge of the scene update before each draw(). - Overload it to define how your scene evolves over time. The time should either be regularly - incremented in this method (frame-rate independent animation) or computed from actual time (for - instance using QTime::elapsed()) for real-time animations. - - Note that KeyFrameInterpolator (which regularly updates a Frame) does not use this method - to animate a Frame, but rather rely on a QTimer signal-slot mechanism. - - See the animation example for an illustration. */ - virtual void animate() { Q_EMIT animateNeeded(); } - /*! Calls startAnimation() or stopAnimation(), depending on animationIsStarted(). */ - void toggleAnimation() { if (animationIsStarted()) stopAnimation(); else startAnimation(); } - //@} + /*! Sets the animationPeriod(), in milliseconds. */ + void setAnimationPeriod(int period) { animationPeriod_ = period; } + virtual void startAnimation(); + virtual void stopAnimation(); + /*! Scene animation method. + + When animationIsStarted(), this method is in charge of the scene update + before each draw(). Overload it to define how your scene evolves over time. + The time should either be regularly incremented in this method (frame-rate + independent animation) or computed from actual time (for instance using + QTime::elapsed()) for real-time animations. + + Note that KeyFrameInterpolator (which regularly updates a Frame) does + not use this method to animate a Frame, but rather rely on a QTimer + signal-slot mechanism. + + See the animation example for an + illustration. */ + virtual void animate() { Q_EMIT animateNeeded(); } + /*! Calls startAnimation() or stopAnimation(), depending on + * animationIsStarted(). */ + void toggleAnimation() { + if (animationIsStarted()) + stopAnimation(); + else + startAnimation(); + } + //@} public: Q_SIGNALS: - /*! Signal emitted by the default init() method. + /*! Signal emitted by the default init() method. - Connect this signal to the methods that need to be called to initialize your viewer or overload init(). */ - void viewerInitialized(); + Connect this signal to the methods that need to be called to initialize your + viewer or overload init(). */ + void viewerInitialized(); - /*! Signal emitted by the default draw() method. + /*! Signal emitted by the default draw() method. - Connect this signal to your main drawing method or overload draw(). See the callback example for an illustration. */ - void drawNeeded(); + Connect this signal to your main drawing method or overload draw(). See the callback example for an illustration. */ + void drawNeeded(); - /*! Signal emitted at the end of the QGLViewer::paintGL() method, when frame is drawn. + /*! Signal emitted at the end of the QGLViewer::paintGL() method, when frame + is drawn. - Can be used to notify an image grabbing process that the image is ready. A typical example is to - connect this signal to the saveSnapshot() method, so that a (numbered) snapshot is generated after - each new display, in order to create a movie: - \code - connect(viewer, SIGNAL(drawFinished(bool)), SLOT(saveSnapshot(bool))); - \endcode + Can be used to notify an image grabbing process that the image is ready. A + typical example is to connect this signal to the saveSnapshot() method, so + that a (numbered) snapshot is generated after each new display, in order to + create a movie: \code connect(viewer, SIGNAL(drawFinished(bool)), + SLOT(saveSnapshot(bool))); \endcode - The \p automatic bool variable is always \c true and has been added so that the signal can be - connected to saveSnapshot() with an \c automatic value set to \c true. */ - void drawFinished(bool automatic); + The \p automatic bool variable is always \c true and has been added so that + the signal can be connected to saveSnapshot() with an \c automatic value set + to \c true. */ + void drawFinished(bool automatic); - /*! Signal emitted by the default animate() method. + /*! Signal emitted by the default animate() method. - Connect this signal to your scene animation method or overload animate(). */ - void animateNeeded(); + Connect this signal to your scene animation method or overload animate(). */ + void animateNeeded(); - /*! Signal emitted by the default QGLViewer::help() method. + /*! Signal emitted by the default QGLViewer::help() method. - Connect this signal to your own help method or overload help(). */ - void helpRequired(); + Connect this signal to your own help method or overload help(). */ + void helpRequired(); - /*! This signal is emitted whenever axisIsDrawn() changes value. */ - void axisIsDrawnChanged(bool drawn); - /*! This signal is emitted whenever gridIsDrawn() changes value. */ - void gridIsDrawnChanged(bool drawn); - /*! This signal is emitted whenever FPSIsDisplayed() changes value. */ - void FPSIsDisplayedChanged(bool displayed); - /*! This signal is emitted whenever textIsEnabled() changes value. */ - void textIsEnabledChanged(bool enabled); - /*! This signal is emitted whenever cameraIsEdited() changes value.. */ - void cameraIsEditedChanged(bool edited); - /*! This signal is emitted whenever displaysInStereo() changes value. */ - void stereoChanged(bool on); - /*! Signal emitted by select(). + /*! This signal is emitted whenever axisIsDrawn() changes value. */ + void axisIsDrawnChanged(bool drawn); + /*! This signal is emitted whenever gridIsDrawn() changes value. */ + void gridIsDrawnChanged(bool drawn); + /*! This signal is emitted whenever FPSIsDisplayed() changes value. */ + void FPSIsDisplayedChanged(bool displayed); + /*! This signal is emitted whenever textIsEnabled() changes value. */ + void textIsEnabledChanged(bool enabled); + /*! This signal is emitted whenever cameraIsEdited() changes value.. */ + void cameraIsEditedChanged(bool edited); + /*! This signal is emitted whenever displaysInStereo() changes value. */ + void stereoChanged(bool on); + /*! Signal emitted by select(). - Connect this signal to your selection method or overload select(), or more probably simply - drawWithNames(). */ - void pointSelected(const QMouseEvent* e); + Connect this signal to your selection method or overload select(), or more + probably simply drawWithNames(). */ + void pointSelected(const QMouseEvent *e); - /*! Signal emitted by setMouseGrabber() when the mouseGrabber() is changed. + /*! Signal emitted by setMouseGrabber() when the mouseGrabber() is changed. - \p mouseGrabber is a pointer to the new MouseGrabber. Note that this signal is emitted with a \c - NULL parameter each time a MouseGrabber stops grabbing mouse. */ - void mouseGrabberChanged(qglviewer::MouseGrabber* mouseGrabber); + \p mouseGrabber is a pointer to the new MouseGrabber. Note that this signal is + emitted with a \c nullptr parameter each time a MouseGrabber stops grabbing + mouse. */ + void mouseGrabberChanged(qglviewer::MouseGrabber *mouseGrabber); - /*! @name Help window */ - //@{ + /*! @name Help window */ + //@{ public: - /*! Returns the QString displayed in the help() window main tab. - - Overload this method to define your own help string, which should shortly describe your - application and explain how it works. Rich-text (HTML) tags can be used (see QStyleSheet() - documentation for available tags): - \code - QString myViewer::helpString() const - { - QString text("

M y V i e w e r

"); - text += "Displays a Scene using OpenGL. Move the camera using the mouse."; - return text; - } - \endcode - - See also mouseString() and keyboardString(). */ - virtual QString helpString() const { return tr("No help available."); } - - virtual QString mouseString() const; - virtual QString keyboardString() const; + /*! Returns the QString displayed in the help() window main tab. + + Overload this method to define your own help string, which should shortly + describe your application and explain how it works. Rich-text (HTML) tags can + be used (see QStyleSheet() documentation for available tags): \code QString + myViewer::helpString() const + { + QString text("

M y V i e w e r

"); + text += "Displays a Scene using OpenGL. Move the camera using the + mouse."; return text; + } + \endcode + + See also mouseString() and keyboardString(). */ + virtual QString helpString() const { return tr("No help available."); } + + virtual QString mouseString() const; + virtual QString keyboardString() const; #ifndef DOXYGEN - /*! This method is deprecated, use mouseString() instead. */ - virtual QString mouseBindingsString () const { return mouseString(); } - /*! This method is deprecated, use keyboardString() instead. */ - virtual QString shortcutBindingsString () const { return keyboardString(); } + /*! This method is deprecated, use mouseString() instead. */ + virtual QString mouseBindingsString() const { return mouseString(); } + /*! This method is deprecated, use keyboardString() instead. */ + virtual QString shortcutBindingsString() const { return keyboardString(); } #endif public Q_SLOTS: - virtual void help(); - virtual void aboutQGLViewer(); + virtual void help(); + virtual void aboutQGLViewer(); protected: - /*! Returns a pointer to the help widget. - - Use this only if you want to directly modify the help widget. Otherwise use helpString(), - setKeyDescription() and setMouseBindingDescription() to customize the text displayed in the help - window tabs. */ - QTabWidget* helpWidget() { return helpWidget_; } - //@} + /*! Returns a pointer to the help widget. + Use this only if you want to directly modify the help widget. Otherwise use + helpString(), setKeyDescription() and setMouseBindingDescription() to + customize the text displayed in the help window tabs. */ + QTabWidget *helpWidget() { return helpWidget_; } + //@} - /*! @name Drawing methods */ - //@{ + /*! @name Drawing methods */ + //@{ protected: - virtual void resizeGL(int width, int height); - virtual void initializeGL(); - - /*! Initializes the viewer OpenGL context. - - This method is called before the first drawing and should be overloaded to initialize some of the - OpenGL flags. The default implementation is empty. See initializeGL(). - - Typical usage include camera() initialization (showEntireScene()), previous viewer state - restoration (restoreStateFromFile()), OpenGL state modification and display list creation. - - Note that initializeGL() modifies the standard OpenGL context. These values can be restored back - in this method. - - \attention You should not call updateGL() (or any method that calls it) in this method, as it will - result in an infinite loop. The different QGLViewer set methods (setAxisIsDrawn(), - setFPSIsDisplayed()...) are protected against this problem and can safely be called. - - \note All the OpenGL specific initializations must be done in this method: the OpenGL context is - not yet available in your viewer constructor. */ - virtual void init() { Q_EMIT viewerInitialized(); } - - virtual void paintGL(); - virtual void preDraw(); - virtual void preDrawStereo(bool leftBuffer=true); - - /*! The core method of the viewer, that draws the scene. - - If you build a class that inherits from QGLViewer, this is the method you want to overload. See - the simpleViewer example for an illustration. - - The camera modelView matrix set in preDraw() converts from the world to the camera coordinate - systems. Vertices given in draw() can then be considered as being given in the world coordinate - system. The camera is moved in this world using the mouse. This representation is much more - intuitive than the default camera-centric OpenGL standard. - - \attention The \c GL_PROJECTION matrix should not be modified by this method, to correctly display - visual hints (axis, grid, FPS...) in postDraw(). Use push/pop or call - camera()->loadProjectionMatrix() at the end of draw() if you need to change the projection matrix - (unlikely). On the other hand, the \c GL_MODELVIEW matrix can be modified and left in a arbitrary - state. */ - virtual void draw() {} - virtual void fastDraw(); - virtual void postDraw(); - //@} - - /*! @name Mouse, keyboard and event handlers */ - //@{ + virtual void resizeGL(int width, int height); + virtual void initializeGL(); + + /*! Initializes the viewer OpenGL context. + + This method is called before the first drawing and should be overloaded to + initialize some of the OpenGL flags. The default implementation is empty. See + initializeGL(). + + Typical usage include camera() initialization (showEntireScene()), previous + viewer state restoration (restoreStateFromFile()), OpenGL state modification + and display list creation. + + Note that initializeGL() modifies the standard OpenGL context. These values + can be restored back in this method. + + \attention You should not call updateGL() (or any method that calls it) in + this method, as it will result in an infinite loop. The different QGLViewer + set methods (setAxisIsDrawn(), setFPSIsDisplayed()...) are protected against + this problem and can safely be called. + + \note All the OpenGL specific initializations must be done in this method: the + OpenGL context is not yet available in your viewer constructor. */ + virtual void init() { Q_EMIT viewerInitialized(); } + + virtual void paintGL(); + virtual void preDraw(); + virtual void preDrawStereo(bool leftBuffer = true); + + /*! The core method of the viewer, that draws the scene. + + If you build a class that inherits from QGLViewer, this is the method you want + to overload. See the simpleViewer + example for an illustration. + + The camera modelView matrix set in preDraw() converts from the world to the + camera coordinate systems. Vertices given in draw() can then be considered as + being given in the world coordinate system. The camera is moved in this world + using the mouse. This representation is much more intuitive than the default + camera-centric OpenGL standard. + + \attention The \c GL_PROJECTION matrix should not be modified by this method, + to correctly display visual hints (axis, grid, FPS...) in postDraw(). Use + push/pop or call camera()->loadProjectionMatrix() at the end of draw() if you + need to change the projection matrix (unlikely). On the other hand, the \c + GL_MODELVIEW matrix can be modified and left in a arbitrary state. */ + virtual void draw() {} + virtual void fastDraw(); + virtual void postDraw(); + //@} + + /*! @name Mouse, keyboard and event handlers */ + //@{ protected: - virtual void mousePressEvent(QMouseEvent *); - virtual void mouseMoveEvent(QMouseEvent *); - virtual void mouseReleaseEvent(QMouseEvent *); - virtual void mouseDoubleClickEvent(QMouseEvent *); - virtual void wheelEvent(QWheelEvent *); - virtual void keyPressEvent(QKeyEvent *); - virtual void keyReleaseEvent(QKeyEvent *); - virtual void timerEvent(QTimerEvent *); - virtual void closeEvent(QCloseEvent *); - //@} - - /*! @name Object selection */ - //@{ + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void mouseDoubleClickEvent(QMouseEvent *); + virtual void wheelEvent(QWheelEvent *); + virtual void keyPressEvent(QKeyEvent *); + virtual void keyReleaseEvent(QKeyEvent *); + virtual void timerEvent(QTimerEvent *); + virtual void closeEvent(QCloseEvent *); + //@} + + /*! @name Object selection */ + //@{ public: - /*! Returns the name (an integer value) of the entity that was last selected by select(). This - value is set by endSelection(). See the select() documentation for details. + /*! Returns the name (an integer value) of the entity that was last selected + by select(). This value is set by endSelection(). See the select() + documentation for details. - As a convention, this method returns -1 if the selectBuffer() was empty, meaning that no object - was selected. + As a convention, this method returns -1 if the selectBuffer() was empty, + meaning that no object was selected. - Return value is -1 before the first call to select(). This value is modified using setSelectedName(). */ - int selectedName() const { return selectedObjectId_; } - /*! Returns the selectBuffer() size. + Return value is -1 before the first call to select(). This value is modified + using setSelectedName(). */ + int selectedName() const { return selectedObjectId_; } + /*! Returns the selectBuffer() size. - See the select() documentation for details. Use setSelectBufferSize() to change this value. + See the select() documentation for details. Use setSelectBufferSize() to + change this value. - Default value is 4000 (i.e. 1000 objects in selection region, since each object pushes 4 values). - This size should be over estimated to prevent a buffer overflow when many objects are drawn under - the mouse cursor. */ - int selectBufferSize() const { return selectBufferSize_; } + Default value is 4000 (i.e. 1000 objects in selection region, since each + object pushes 4 values). This size should be over estimated to prevent a + buffer overflow when many objects are drawn under the mouse cursor. */ + int selectBufferSize() const { return selectBufferSize_; } - /*! Returns the width (in pixels) of a selection frustum, centered on the mouse cursor, that is - used to select objects. + /*! Returns the width (in pixels) of a selection frustum, centered on the + mouse cursor, that is used to select objects. - The height of the selection frustum is defined by selectRegionHeight(). + The height of the selection frustum is defined by selectRegionHeight(). - The objects that will be drawn in this region by drawWithNames() will be recorded in the - selectBuffer(). endSelection() then analyzes this buffer and setSelectedName() to the name of the - closest object. See the gluPickMatrix() documentation for details. + The objects that will be drawn in this region by drawWithNames() will be + recorded in the selectBuffer(). endSelection() then analyzes this buffer and + setSelectedName() to the name of the closest object. See the gluPickMatrix() + documentation for details. - The default value is 3, which is adapted to standard applications. A smaller value results in a - more precise selection but the user has to be careful for small feature selection. + The default value is 3, which is adapted to standard applications. A smaller + value results in a more precise selection but the user has to be careful for + small feature selection. - See the multiSelect example for an illustration. */ - int selectRegionWidth() const { return selectRegionWidth_; } - /*! See the selectRegionWidth() documentation. Default value is 3 pixels. */ - int selectRegionHeight() const { return selectRegionHeight_; } + See the multiSelect example for an + illustration. */ + int selectRegionWidth() const { return selectRegionWidth_; } + /*! See the selectRegionWidth() documentation. Default value is 3 pixels. */ + int selectRegionHeight() const { return selectRegionHeight_; } - /*! Returns a pointer to an array of \c GLuint. + /*! Returns a pointer to an array of \c GLuint. - This buffer is used by the \c GL_SELECT mode in select() to perform object selection. The buffer - size can be modified using setSelectBufferSize(). If you overload endSelection(), you will analyze - the content of this buffer. See the \c glSelectBuffer() man page for details. */ - GLuint* selectBuffer() { return selectBuffer_; } + This buffer is used by the \c GL_SELECT mode in select() to perform object + selection. The buffer size can be modified using setSelectBufferSize(). If you + overload endSelection(), you will analyze the content of this buffer. See the + \c glSelectBuffer() man page for details. */ + GLuint *selectBuffer() { return selectBuffer_; } public Q_SLOTS: - virtual void select(const QMouseEvent* event); - virtual void select(const QPoint& point); + virtual void select(const QMouseEvent *event); + virtual void select(const QPoint &point); - void setSelectBufferSize(int size); - /*! Sets the selectRegionWidth(). */ - void setSelectRegionWidth(int width) { selectRegionWidth_ = width; } - /*! Sets the selectRegionHeight(). */ - void setSelectRegionHeight(int height) { selectRegionHeight_ = height; } - /*! Set the selectedName() value. + void setSelectBufferSize(int size); + /*! Sets the selectRegionWidth(). */ + void setSelectRegionWidth(int width) { selectRegionWidth_ = width; } + /*! Sets the selectRegionHeight(). */ + void setSelectRegionHeight(int height) { selectRegionHeight_ = height; } + /*! Set the selectedName() value. - Used in endSelection() during a selection. You should only call this method if you overload the - endSelection() method. */ - void setSelectedName(int id) { selectedObjectId_=id; } + Used in endSelection() during a selection. You should only call this method + if you overload the endSelection() method. */ + void setSelectedName(int id) { selectedObjectId_ = id; } protected: - virtual void beginSelection(const QPoint& point); - /*! This method is called by select() and should draw selectable entities. - - Default implementation is empty. Overload and draw the different elements of your scene you want - to be able to select. The default select() implementation relies on the \c GL_SELECT, and requires - that each selectable element is drawn within a \c glPushName() - \c glPopName() block. A typical - usage would be (see the select example): -\code -void Viewer::drawWithNames() { - for (int i=0; idraw(); - glPopName(); + virtual void beginSelection(const QPoint &point); + /*! This method is called by select() and should draw selectable entities. + + Default implementation is empty. Overload and draw the different elements of +your scene you want to be able to select. The default select() implementation +relies on the \c GL_SELECT, and requires that each selectable element is drawn +within a \c glPushName() - \c glPopName() block. A typical usage would be (see +the select example): \code void +Viewer::drawWithNames() { for (int i=0; idraw(); + glPopName(); } } \endcode - The resulting selected name is computed by endSelection(), which setSelectedName() to the integer - id pushed by this method (a value of -1 means no selection). Use selectedName() to update your - selection, probably in the postSelection() method. - - \attention If your selected objects are points, do not use \c glBegin(GL_POINTS); and \c glVertex3fv() - in the above \c draw() method (not compatible with raster mode): use \c glRasterPos3fv() instead. */ - virtual void drawWithNames() {} - virtual void endSelection(const QPoint& point); - /*! This method is called at the end of the select() procedure. It should finalize the selection - process and update the data structure/interface/computation/display... according to the newly - selected entity. - - The default implementation is empty. Overload this method if needed, and use selectedName() to - retrieve the selected entity name (returns -1 if no object was selected). See the select example for an illustration. */ - virtual void postSelection(const QPoint& point) { Q_UNUSED(point); } - //@} - - - /*! @name Keyboard customization */ - //@{ + The resulting selected name is computed by endSelection(), which +setSelectedName() to the integer id pushed by this method (a value of -1 means +no selection). Use selectedName() to update your selection, probably in the +postSelection() method. + + \attention If your selected objects are points, do not use \c +glBegin(GL_POINTS); and \c glVertex3fv() in the above \c draw() method (not +compatible with raster mode): use \c glRasterPos3fv() instead. */ + virtual void drawWithNames() {} + virtual void endSelection(const QPoint &point); + /*! This method is called at the end of the select() procedure. It should + finalize the selection process and update the data + structure/interface/computation/display... according to the newly selected + entity. + + The default implementation is empty. Overload this method if needed, and use + selectedName() to retrieve the selected entity name (returns -1 if no object + was selected). See the select example + for an illustration. */ + virtual void postSelection(const QPoint &point) { Q_UNUSED(point); } + //@} + + /*! @name Keyboard customization */ + //@{ public: - /*! Defines the different actions that can be associated with a keyboard shortcut using - setShortcut(). - - See the keyboard page for details. */ - enum KeyboardAction { DRAW_AXIS, DRAW_GRID, DISPLAY_FPS, ENABLE_TEXT, EXIT_VIEWER, - SAVE_SCREENSHOT, CAMERA_MODE, FULL_SCREEN, STEREO, ANIMATION, HELP, EDIT_CAMERA, - MOVE_CAMERA_LEFT, MOVE_CAMERA_RIGHT, MOVE_CAMERA_UP, MOVE_CAMERA_DOWN, - INCREASE_FLYSPEED, DECREASE_FLYSPEED, SNAPSHOT_TO_CLIPBOARD }; - - unsigned int shortcut(KeyboardAction action) const; + /*! Defines the different actions that can be associated with a keyboard + shortcut using setShortcut(). + + See the keyboard page for details. */ + enum KeyboardAction { + DRAW_AXIS, + DRAW_GRID, + DISPLAY_FPS, + ENABLE_TEXT, + EXIT_VIEWER, + SAVE_SCREENSHOT, + CAMERA_MODE, + FULL_SCREEN, + STEREO, + ANIMATION, + HELP, + EDIT_CAMERA, + MOVE_CAMERA_LEFT, + MOVE_CAMERA_RIGHT, + MOVE_CAMERA_UP, + MOVE_CAMERA_DOWN, + INCREASE_FLYSPEED, + DECREASE_FLYSPEED, + SNAPSHOT_TO_CLIPBOARD + }; + + unsigned int shortcut(KeyboardAction action) const; #ifndef DOXYGEN - // QGLViewer 1.x - unsigned int keyboardAccelerator(KeyboardAction action) const; - Qt::Key keyFrameKey(unsigned int index) const; - Qt::KeyboardModifiers playKeyFramePathStateKey() const; - // QGLViewer 2.0 without Qt4 support - Qt::KeyboardModifiers addKeyFrameStateKey() const; - Qt::KeyboardModifiers playPathStateKey() const; + // QGLViewer 1.x + unsigned int keyboardAccelerator(KeyboardAction action) const; + Qt::Key keyFrameKey(unsigned int index) const; + Qt::KeyboardModifiers playKeyFramePathStateKey() const; + // QGLViewer 2.0 without Qt4 support + Qt::KeyboardModifiers addKeyFrameStateKey() const; + Qt::KeyboardModifiers playPathStateKey() const; #endif - Qt::Key pathKey(unsigned int index) const; - Qt::KeyboardModifiers addKeyFrameKeyboardModifiers() const; - Qt::KeyboardModifiers playPathKeyboardModifiers() const; + Qt::Key pathKey(unsigned int index) const; + Qt::KeyboardModifiers addKeyFrameKeyboardModifiers() const; + Qt::KeyboardModifiers playPathKeyboardModifiers() const; public Q_SLOTS: - void setShortcut(KeyboardAction action, unsigned int key); + void setShortcut(KeyboardAction action, unsigned int key); #ifndef DOXYGEN - void setKeyboardAccelerator(KeyboardAction action, unsigned int key); + void setKeyboardAccelerator(KeyboardAction action, unsigned int key); #endif - void setKeyDescription(unsigned int key, QString description); - void clearShortcuts(); + void setKeyDescription(unsigned int key, QString description); + void clearShortcuts(); - // Key Frames shortcut keys +// Key Frames shortcut keys #ifndef DOXYGEN - // QGLViewer 1.x compatibility methods - virtual void setKeyFrameKey(unsigned int index, int key); - virtual void setPlayKeyFramePathStateKey(unsigned int buttonState); - // QGLViewer 2.0 without Qt4 support - virtual void setPlayPathStateKey(unsigned int buttonState); - virtual void setAddKeyFrameStateKey(unsigned int buttonState); + // QGLViewer 1.x compatibility methods + virtual void setKeyFrameKey(unsigned int index, int key); + virtual void setPlayKeyFramePathStateKey(unsigned int buttonState); + // QGLViewer 2.0 without Qt4 support + virtual void setPlayPathStateKey(unsigned int buttonState); + virtual void setAddKeyFrameStateKey(unsigned int buttonState); #endif - virtual void setPathKey(int key, unsigned int index = 0); - virtual void setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers); - virtual void setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers); - //@} - + virtual void setPathKey(int key, unsigned int index = 0); + virtual void setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers); + virtual void setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers); + //@} public: - /*! @name Mouse customization */ - //@{ - /*! Defines the different mouse handlers: camera() or manipulatedFrame(). - - Used by setMouseBinding(), setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButtons, ClickAction, bool, int) - and setWheelBinding() to define which handler receives the mouse events. */ - enum MouseHandler { CAMERA, FRAME }; - - /*! Defines the possible actions that can be binded to a mouse click using - setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, ClickAction, bool, int). - - See the mouse page for details. */ - enum ClickAction { NO_CLICK_ACTION, ZOOM_ON_PIXEL, ZOOM_TO_FIT, SELECT, RAP_FROM_PIXEL, RAP_IS_CENTER, - CENTER_FRAME, CENTER_SCENE, SHOW_ENTIRE_SCENE, ALIGN_FRAME, ALIGN_CAMERA }; - - - /*! Defines the possible actions that can be binded to a mouse action (a click, followed by a - mouse displacement). - - These actions may be binded to the camera() or to the manipulatedFrame() (see QGLViewer::MouseHandler) using - setMouseBinding(). */ - enum MouseAction { NO_MOUSE_ACTION, - ROTATE, ZOOM, TRANSLATE, - MOVE_FORWARD, LOOK_AROUND, MOVE_BACKWARD, - SCREEN_ROTATE, ROLL, DRIVE, - SCREEN_TRANSLATE, ZOOM_ON_REGION }; + /*! @name Mouse customization */ + //@{ + /*! Defines the different mouse handlers: camera() or manipulatedFrame(). + + Used by setMouseBinding(), setMouseBinding(Qt::KeyboardModifiers modifiers, + Qt::MouseButtons, ClickAction, bool, int) and setWheelBinding() to define + which handler receives the mouse events. */ + enum MouseHandler { CAMERA, FRAME }; + + /*! Defines the possible actions that can be binded to a mouse click using + setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, ClickAction, bool, + int). + + See the mouse page for details. */ + enum ClickAction { + NO_CLICK_ACTION, + ZOOM_ON_PIXEL, + ZOOM_TO_FIT, + SELECT, + RAP_FROM_PIXEL, + RAP_IS_CENTER, + CENTER_FRAME, + CENTER_SCENE, + SHOW_ENTIRE_SCENE, + ALIGN_FRAME, + ALIGN_CAMERA + }; + + /*! Defines the possible actions that can be binded to a mouse action (a + click, followed by a mouse displacement). + + These actions may be binded to the camera() or to the manipulatedFrame() (see + QGLViewer::MouseHandler) using setMouseBinding(). */ + enum MouseAction { + NO_MOUSE_ACTION, + ROTATE, + ZOOM, + TRANSLATE, + MOVE_FORWARD, + LOOK_AROUND, + MOVE_BACKWARD, + SCREEN_ROTATE, + ROLL, + DRIVE, + SCREEN_TRANSLATE, + ZOOM_ON_REGION + }; #ifndef DOXYGEN - MouseAction mouseAction(unsigned int state) const; - int mouseHandler(unsigned int state) const; - int mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const; - ClickAction clickAction(unsigned int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const; - void getClickButtonState(ClickAction action, unsigned int & state, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const; - unsigned int wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const; + MouseAction mouseAction(unsigned int state) const; + int mouseHandler(unsigned int state) const; + int mouseButtonState(MouseHandler handler, MouseAction action, + bool withConstraint = true) const; + ClickAction clickAction(unsigned int state, bool doubleClick, + Qt::MouseButtons buttonsBefore) const; + void getClickButtonState(ClickAction action, unsigned int &state, + bool &doubleClick, + Qt::MouseButtons &buttonsBefore) const; + unsigned int wheelButtonState(MouseHandler handler, MouseAction action, + bool withConstraint = true) const; #endif - MouseAction mouseAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const; - int mouseHandler(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const; + MouseAction mouseAction(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button) const; + int mouseHandler(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button) const; - void getMouseActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, - Qt::Key& key, Qt::KeyboardModifiers& modifiers, Qt::MouseButton& button) const; + void getMouseActionBinding(MouseHandler handler, MouseAction action, + bool withConstraint, Qt::Key &key, + Qt::KeyboardModifiers &modifiers, + Qt::MouseButton &button) const; - ClickAction clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, - bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton) const; + ClickAction clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, bool doubleClick = false, + Qt::MouseButtons buttonsBefore = Qt::NoButton) const; - void getClickActionBinding(ClickAction action, Qt::Key& key, Qt::KeyboardModifiers& modifiers, - Qt::MouseButton& button, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const; + void getClickActionBinding(ClickAction action, Qt::Key &key, + Qt::KeyboardModifiers &modifiers, + Qt::MouseButton &button, bool &doubleClick, + Qt::MouseButtons &buttonsBefore) const; - MouseAction wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const; - int wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const; + MouseAction wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const; + int wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const; - void getWheelActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, - Qt::Key& key, Qt::KeyboardModifiers& modifiers) const; + void getWheelActionBinding(MouseHandler handler, MouseAction action, + bool withConstraint, Qt::Key &key, + Qt::KeyboardModifiers &modifiers) const; public Q_SLOTS: #ifndef DOXYGEN - void setMouseBinding(unsigned int state, MouseHandler handler, MouseAction action, bool withConstraint=true); - void setMouseBinding(unsigned int state, ClickAction action, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton); - void setMouseBindingDescription(unsigned int state, QString description, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton); + void setMouseBinding(unsigned int state, MouseHandler handler, + MouseAction action, bool withConstraint = true); + void setMouseBinding(unsigned int state, ClickAction action, + bool doubleClick = false, + Qt::MouseButtons buttonsBefore = Qt::NoButton); + void + setMouseBindingDescription(unsigned int state, QString description, + bool doubleClick = false, + Qt::MouseButtons buttonsBefore = Qt::NoButton); #endif - void setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton buttons, MouseHandler handler, MouseAction action, bool withConstraint=true); - void setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton); - void setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint=true); - void setMouseBindingDescription(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, QString description, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton); - - void setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton buttons, MouseHandler handler, MouseAction action, bool withConstraint=true); - void setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton); - void setWheelBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint=true); - void setMouseBindingDescription(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, QString description, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton); - - void clearMouseBindings(); + void setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton buttons, + MouseHandler handler, MouseAction action, + bool withConstraint = true); + void setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, + ClickAction action, bool doubleClick = false, + Qt::MouseButtons buttonsBefore = Qt::NoButton); + void setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, + MouseAction action, bool withConstraint = true); + void + setMouseBindingDescription(Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, QString description, + bool doubleClick = false, + Qt::MouseButtons buttonsBefore = Qt::NoButton); + + void setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton buttons, MouseHandler handler, + MouseAction action, bool withConstraint = true); + void setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, ClickAction action, + bool doubleClick = false, + Qt::MouseButtons buttonsBefore = Qt::NoButton); + void setWheelBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, + MouseHandler handler, MouseAction action, + bool withConstraint = true); + void + setMouseBindingDescription(Qt::Key key, Qt::KeyboardModifiers modifiers, + Qt::MouseButton button, QString description, + bool doubleClick = false, + Qt::MouseButtons buttonsBefore = Qt::NoButton); + + void clearMouseBindings(); #ifndef DOXYGEN - MouseAction wheelAction(Qt::KeyboardModifiers modifiers) const; - int wheelHandler(Qt::KeyboardModifiers modifiers) const; + MouseAction wheelAction(Qt::KeyboardModifiers modifiers) const; + int wheelHandler(Qt::KeyboardModifiers modifiers) const; - void setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers); - void setHandlerStateKey(MouseHandler handler, unsigned int buttonState); - void setMouseStateKey(MouseHandler handler, unsigned int buttonState); + void setHandlerKeyboardModifiers(MouseHandler handler, + Qt::KeyboardModifiers modifiers); + void setHandlerStateKey(MouseHandler handler, unsigned int buttonState); + void setMouseStateKey(MouseHandler handler, unsigned int buttonState); #endif private: - static QString mouseActionString(QGLViewer::MouseAction ma); - static QString clickActionString(QGLViewer::ClickAction ca); - //@} - + static QString mouseActionString(QGLViewer::MouseAction ma); + static QString clickActionString(QGLViewer::ClickAction ca); + //@} - /*! @name State persistence */ - //@{ + /*! @name State persistence */ + //@{ public: - QString stateFileName() const; - virtual QDomElement domElement(const QString& name, QDomDocument& document) const; + QString stateFileName() const; + virtual QDomElement domElement(const QString &name, + QDomDocument &document) const; public Q_SLOTS: - virtual void initFromDOMElement(const QDomElement& element); - virtual void saveStateToFile(); // cannot be const because of QMessageBox - virtual bool restoreStateFromFile(); + virtual void initFromDOMElement(const QDomElement &element); + virtual void saveStateToFile(); // cannot be const because of QMessageBox + virtual bool restoreStateFromFile(); - /*! Defines the stateFileName() used by saveStateToFile() and restoreStateFromFile(). + /*! Defines the stateFileName() used by saveStateToFile() and + restoreStateFromFile(). - The file name can have an optional prefix directory (no prefix meaning current directory). If the - directory does not exist, it will be created by saveStateToFile(). + The file name can have an optional prefix directory (no prefix meaning + current directory). If the directory does not exist, it will be created by + saveStateToFile(). - \code - // Name depends on the displayed 3D model. Saved in current directory. - setStateFileName(3DModelName() + ".xml"); + \code + // Name depends on the displayed 3D model. Saved in current directory. + setStateFileName(3DModelName() + ".xml"); - // Files are stored in a dedicated directory under user's home directory. - setStateFileName(QDir::homeDirPath + "/.config/myApp.xml"); - \endcode */ - void setStateFileName(const QString& name) { stateFileName_ = name; } + // Files are stored in a dedicated directory under user's home directory. + setStateFileName(QDir::homeDirPath + "/.config/myApp.xml"); + \endcode */ + void setStateFileName(const QString &name) { stateFileName_ = name; } #ifndef DOXYGEN - void saveToFile(const QString& fileName=QString()); - bool restoreFromFile(const QString& fileName=QString()); + void saveToFile(const QString &fileName = QString()); + bool restoreFromFile(const QString &fileName = QString()); #endif private: - static void saveStateToFileForAllViewers(); - //@} + static void saveStateToFileForAllViewers(); + //@} - - /*! @name QGLViewer pool */ - //@{ + /*! @name QGLViewer pool */ + //@{ public: - /*! Returns a \c QList that contains pointers to all the created QGLViewers. - Note that this list may contain \c NULL pointers if the associated viewer has been deleted. - - Can be useful to apply a method or to connect a signal to all the viewers: - \code - foreach (QGLViewer* viewer, QGLViewer::QGLViewerPool()) - connect(myObject, SIGNAL(IHaveChangedSignal()), viewer, SLOT(update())); - \endcode - - \attention With Qt version 3, this method returns a \c QPtrList instead. Use a \c QPtrListIterator - to iterate on the list instead.*/ - static const QList& QGLViewerPool() { return QGLViewer::QGLViewerPool_; } - - - /*! Returns the index of the QGLViewer \p viewer in the QGLViewerPool(). This index in unique and - can be used to identify the different created QGLViewers (see stateFileName() for an application - example). - - When a QGLViewer is deleted, the QGLViewers' indexes are preserved and NULL is set for that index. - When a QGLViewer is created, it is placed in the first available position in that list. - Returns -1 if the QGLViewer could not be found (which should not be possible). */ - static int QGLViewerIndex(const QGLViewer* const viewer) { return QGLViewer::QGLViewerPool_.indexOf(const_cast(viewer)); } - //@} + /*! Returns a \c QList that contains pointers to all the created QGLViewers. + Note that this list may contain \c nullptr pointers if the associated viewer + has been deleted. + + Can be useful to apply a method or to connect a signal to all the viewers: + \code + foreach (QGLViewer* viewer, QGLViewer::QGLViewerPool()) + connect(myObject, SIGNAL(IHaveChangedSignal()), viewer, SLOT(update())); + \endcode + + \attention With Qt version 3, this method returns a \c QPtrList instead. Use a + \c QPtrListIterator to iterate on the list instead.*/ + static const QList &QGLViewerPool() { + return QGLViewer::QGLViewerPool_; + } + + /*! Returns the index of the QGLViewer \p viewer in the QGLViewerPool(). This + index in unique and can be used to identify the different created QGLViewers + (see stateFileName() for an application example). + + When a QGLViewer is deleted, the QGLViewers' indexes are preserved and nullptr is + set for that index. When a QGLViewer is created, it is placed in the first + available position in that list. Returns -1 if the QGLViewer could not be + found (which should not be possible). */ + static int QGLViewerIndex(const QGLViewer *const viewer) { + return QGLViewer::QGLViewerPool_.indexOf(const_cast(viewer)); + } +//@} #ifndef DOXYGEN - /*! @name Visual hints */ - //@{ + /*! @name Visual hints */ + //@{ public: - virtual void setVisualHintsMask(int mask, int delay = 2000); - virtual void drawVisualHints(); + virtual void setVisualHintsMask(int mask, int delay = 2000); + virtual void drawVisualHints(); public Q_SLOTS: - virtual void resetVisualHints(); - //@} + virtual void resetVisualHints(); +//@} #endif private Q_SLOTS: - // Patch for a Qt bug with fullScreen on startup - void delayedFullScreen() { move(prevPos_); setFullScreen(); } - void hideMessage(); + // Patch for a Qt bug with fullScreen on startup + void delayedFullScreen() { + move(prevPos_); + setFullScreen(); + } + void hideMessage(); private: - // Copy constructor and operator= are declared private and undefined - // Prevents everyone from trying to use them - QGLViewer(const QGLViewer& v); - QGLViewer& operator=(const QGLViewer& v); - - // Set parameters to their default values. Called by the constructors. - void defaultConstructor(); - - void handleKeyboardAction(KeyboardAction id); - - // C a m e r a - qglviewer::Camera* camera_; - bool cameraIsEdited_; - qreal previousCameraZClippingCoefficient_; - unsigned int previousPathId_; // double key press recognition - void connectAllCameraKFIInterpolatedSignals(bool connection=true); - - // C o l o r s - QColor backgroundColor_, foregroundColor_; - - // D i s p l a y f l a g s - bool axisIsDrawn_; // world axis - bool gridIsDrawn_; // world XY grid - bool FPSIsDisplayed_; // Frame Per Seconds - bool textIsEnabled_; // drawText() actually draws text or not - bool stereo_; // stereo display - bool fullScreen_; // full screen mode - QPoint prevPos_; // Previous window position, used for full screen mode - - // A n i m a t i o n - bool animationStarted_; // animation mode started - int animationPeriod_; // period in msecs - int animationTimerId_; - - // F P S d i s p l a y - QTime fpsTime_; - unsigned int fpsCounter_; - QString fpsString_; - qreal f_p_s_; - - // M e s s a g e s - QString message_; - bool displayMessage_; - QTimer messageTimer_; - - // M a n i p u l a t e d f r a m e - qglviewer::ManipulatedFrame* manipulatedFrame_; - bool manipulatedFrameIsACamera_; - - // M o u s e G r a b b e r - qglviewer::MouseGrabber* mouseGrabber_; - bool mouseGrabberIsAManipulatedFrame_; - bool mouseGrabberIsAManipulatedCameraFrame_; - QMap disabledMouseGrabbers_; - - // S e l e c t i o n - int selectRegionWidth_, selectRegionHeight_; - int selectBufferSize_; - GLuint* selectBuffer_; - int selectedObjectId_; - - // V i s u a l h i n t s - int visualHint_; - - // S h o r t c u t k e y s - void setDefaultShortcuts(); - QString cameraPathKeysString() const; - QMap keyboardActionDescription_; - QMap keyboardBinding_; - QMap keyDescription_; - - // K e y F r a m e s s h o r t c u t s - QMap pathIndex_; - Qt::KeyboardModifiers addKeyFrameKeyboardModifiers_, playPathKeyboardModifiers_; - - // B u f f e r T e x t u r e - GLuint bufferTextureId_; - qreal bufferTextureMaxU_, bufferTextureMaxV_; - int bufferTextureWidth_, bufferTextureHeight_; - unsigned int previousBufferTextureFormat_; - int previousBufferTextureInternalFormat_; + // Copy constructor and operator= are declared private and undefined + // Prevents everyone from trying to use them + QGLViewer(const QGLViewer &v); + QGLViewer &operator=(const QGLViewer &v); + + // Set parameters to their default values. Called by the constructors. + void defaultConstructor(); + + void handleKeyboardAction(KeyboardAction id); + + // C a m e r a + qglviewer::Camera *camera_; + bool cameraIsEdited_; + qreal previousCameraZClippingCoefficient_; + unsigned int previousPathId_; // double key press recognition + void connectAllCameraKFIInterpolatedSignals(bool connection = true); + + // C o l o r s + QColor backgroundColor_, foregroundColor_; + + // D i s p l a y f l a g s + bool axisIsDrawn_; // world axis + bool gridIsDrawn_; // world XY grid + bool FPSIsDisplayed_; // Frame Per Seconds + bool textIsEnabled_; // drawText() actually draws text or not + bool stereo_; // stereo display + bool fullScreen_; // full screen mode + QPoint prevPos_; // Previous window position, used for full screen mode + + // A n i m a t i o n + bool animationStarted_; // animation mode started + int animationPeriod_; // period in msecs + int animationTimerId_; + + // F P S d i s p l a y + QElapsedTimer fpsTime_; + unsigned int fpsCounter_; + QString fpsString_; + qreal f_p_s_; + + // M e s s a g e s + QString message_; + bool displayMessage_; + QTimer messageTimer_; + + // M a n i p u l a t e d f r a m e + qglviewer::ManipulatedFrame *manipulatedFrame_; + bool manipulatedFrameIsACamera_; + + // M o u s e G r a b b e r + qglviewer::MouseGrabber *mouseGrabber_; + bool mouseGrabberIsAManipulatedFrame_; + bool mouseGrabberIsAManipulatedCameraFrame_; + QMap disabledMouseGrabbers_; + + // S e l e c t i o n + int selectRegionWidth_, selectRegionHeight_; + int selectBufferSize_; + GLuint *selectBuffer_; + int selectedObjectId_; + + // V i s u a l h i n t s + int visualHint_; + + // S h o r t c u t k e y s + void setDefaultShortcuts(); + QString cameraPathKeysString() const; + QMap keyboardActionDescription_; + QMap keyboardBinding_; + QMap keyDescription_; + + // K e y F r a m e s s h o r t c u t s + QMap pathIndex_; + Qt::KeyboardModifiers addKeyFrameKeyboardModifiers_, + playPathKeyboardModifiers_; + + // B u f f e r T e x t u r e + GLuint bufferTextureId_; + qreal bufferTextureMaxU_, bufferTextureMaxV_; + int bufferTextureWidth_, bufferTextureHeight_; + unsigned int previousBufferTextureFormat_; + int previousBufferTextureInternalFormat_; #ifndef DOXYGEN - // M o u s e a c t i o n s - struct MouseActionPrivate { - MouseHandler handler; - MouseAction action; - bool withConstraint; - }; - - // M o u s e b i n d i n g s - struct MouseBindingPrivate { - const Qt::KeyboardModifiers modifiers; - const Qt::MouseButton button; - const Qt::Key key; - - MouseBindingPrivate(Qt::KeyboardModifiers m, Qt::MouseButton b, Qt::Key k) - : modifiers(m), button(b), key(k) {} - - // This sort order is used in mouseString() to display sorted mouse bindings - bool operator<(const MouseBindingPrivate& mbp) const - { - if (key != mbp.key) - return key < mbp.key; - if (modifiers != mbp.modifiers) - return modifiers < mbp.modifiers; - return button < mbp.button; - } - }; - - // W h e e l b i n d i n g s - struct WheelBindingPrivate { - const Qt::KeyboardModifiers modifiers; - const Qt::Key key; - - WheelBindingPrivate(Qt::KeyboardModifiers m, Qt::Key k) - : modifiers(m), key(k) {} - - // This sort order is used in mouseString() to display sorted wheel bindings - bool operator<(const WheelBindingPrivate& wbp) const - { - if (key != wbp.key) - return key < wbp.key; - return modifiers < wbp.modifiers; - } - }; - - // C l i c k b i n d i n g s - struct ClickBindingPrivate { - const Qt::KeyboardModifiers modifiers; - const Qt::MouseButton button; - const bool doubleClick; - const Qt::MouseButtons buttonsBefore; // only defined when doubleClick is true - const Qt::Key key; - - ClickBindingPrivate(Qt::KeyboardModifiers m, Qt::MouseButton b, bool dc, Qt::MouseButtons bb, Qt::Key k) - : modifiers(m), button(b), doubleClick(dc), buttonsBefore(bb), key(k) {} - - // This sort order is used in mouseString() to display sorted mouse bindings - bool operator<(const ClickBindingPrivate& cbp) const - { - if (key != cbp.key) - return key < cbp.key; - if (buttonsBefore != cbp.buttonsBefore) - return buttonsBefore < cbp.buttonsBefore; - if (modifiers != cbp.modifiers) - return modifiers < cbp.modifiers; - if (button != cbp.button) - return button < cbp.button; - return doubleClick != cbp.doubleClick; - } - }; + // M o u s e a c t i o n s + struct MouseActionPrivate { + MouseHandler handler; + MouseAction action; + bool withConstraint; + }; + + // M o u s e b i n d i n g s + struct MouseBindingPrivate { + const Qt::KeyboardModifiers modifiers; + const Qt::MouseButton button; + const Qt::Key key; + + MouseBindingPrivate(Qt::KeyboardModifiers m, Qt::MouseButton b, Qt::Key k) + : modifiers(m), button(b), key(k) {} + + // This sort order is used in mouseString() to display sorted mouse bindings + bool operator<(const MouseBindingPrivate &mbp) const { + if (key != mbp.key) + return key < mbp.key; + if (modifiers != mbp.modifiers) + return modifiers < mbp.modifiers; + return button < mbp.button; + } + }; + + // W h e e l b i n d i n g s + struct WheelBindingPrivate { + const Qt::KeyboardModifiers modifiers; + const Qt::Key key; + + WheelBindingPrivate(Qt::KeyboardModifiers m, Qt::Key k) + : modifiers(m), key(k) {} + + // This sort order is used in mouseString() to display sorted wheel bindings + bool operator<(const WheelBindingPrivate &wbp) const { + if (key != wbp.key) + return key < wbp.key; + return modifiers < wbp.modifiers; + } + }; + + // C l i c k b i n d i n g s + struct ClickBindingPrivate { + const Qt::KeyboardModifiers modifiers; + const Qt::MouseButton button; + const bool doubleClick; + const Qt::MouseButtons + buttonsBefore; // only defined when doubleClick is true + const Qt::Key key; + + ClickBindingPrivate(Qt::KeyboardModifiers m, Qt::MouseButton b, bool dc, + Qt::MouseButtons bb, Qt::Key k) + : modifiers(m), button(b), doubleClick(dc), buttonsBefore(bb), key(k) {} + + // This sort order is used in mouseString() to display sorted mouse bindings + bool operator<(const ClickBindingPrivate &cbp) const { + if (key != cbp.key) + return key < cbp.key; + if (buttonsBefore != cbp.buttonsBefore) + return buttonsBefore < cbp.buttonsBefore; + if (modifiers != cbp.modifiers) + return modifiers < cbp.modifiers; + if (button != cbp.button) + return button < cbp.button; + return doubleClick < cbp.doubleClick; + } + }; #endif - static QString formatClickActionPrivate(ClickBindingPrivate cbp); - static bool isValidShortcutKey(int key); + static QString formatClickActionPrivate(ClickBindingPrivate cbp); + static bool isValidShortcutKey(int key); - QMap mouseDescription_; + QMap mouseDescription_; - void setDefaultMouseBindings(); - void performClickAction(ClickAction ca, const QMouseEvent* const e); - QMap mouseBinding_; - QMap wheelBinding_; - QMap clickBinding_; - Qt::Key currentlyPressedKey_; + void setDefaultMouseBindings(); + void performClickAction(ClickAction ca, const QMouseEvent *const e); + QMap mouseBinding_; + QMap wheelBinding_; + QMap clickBinding_; + Qt::Key currentlyPressedKey_; - // S n a p s h o t s - void initializeSnapshotFormats(); - QImage frameBufferSnapshot(); - QString snapshotFileName_, snapshotFormat_; - int snapshotCounter_, snapshotQuality_; - TileRegion* tileRegion_; + // S n a p s h o t s + void initializeSnapshotFormats(); + QImage frameBufferSnapshot(); + QString snapshotFileName_, snapshotFormat_; + int snapshotCounter_, snapshotQuality_; + TileRegion *tileRegion_; - // Q G L V i e w e r p o o l - static QList QGLViewerPool_; + // Q G L V i e w e r p o o l + static QList QGLViewerPool_; - // S t a t e F i l e - QString stateFileName_; + // S t a t e F i l e + QString stateFileName_; - // H e l p w i n d o w - QTabWidget* helpWidget_; + // H e l p w i n d o w + QTabWidget *helpWidget_; }; #endif // QGLVIEWER_QGLVIEWER_H diff --git a/octovis/src/extern/QGLViewer/quaternion.cpp b/octovis/src/extern/QGLViewer/quaternion.cpp index 0c308094..d43802bb 100644 --- a/octovis/src/extern/QGLViewer/quaternion.cpp +++ b/octovis/src/extern/QGLViewer/quaternion.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,157 +19,132 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - -#include "domUtils.h" #include "quaternion.h" +#include "domUtils.h" #include // RAND_MAX // All the methods are declared inline in Quaternion.h using namespace qglviewer; using namespace std; -/*! Constructs a Quaternion that will rotate from the \p from direction to the \p to direction. - -Note that this rotation is not uniquely defined. The selected axis is usually orthogonal to \p from -and \p to, minimizing the rotation angle. This method is robust and can handle small or almost identical vectors. */ -Quaternion::Quaternion(const Vec& from, const Vec& to) -{ - const qreal epsilon = 1E-10; - - const qreal fromSqNorm = from.squaredNorm(); - const qreal toSqNorm = to.squaredNorm(); - // Identity Quaternion when one vector is null - if ((fromSqNorm < epsilon) || (toSqNorm < epsilon)) - { - q[0]=q[1]=q[2]=0.0; - q[3]=1.0; - } - else - { - Vec axis = cross(from, to); - const qreal axisSqNorm = axis.squaredNorm(); - - // Aligned vectors, pick any axis, not aligned with from or to - if (axisSqNorm < epsilon) - axis = from.orthogonalVec(); - - qreal angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm))); - - if (from*to < 0.0) - angle = M_PI-angle; - - setAxisAngle(axis, angle); - } +/*! Constructs a Quaternion that will rotate from the \p from direction to the +\p to direction. + +Note that this rotation is not uniquely defined. The selected axis is usually +orthogonal to \p from and \p to, minimizing the rotation angle. This method is +robust and can handle small or almost identical vectors. */ +Quaternion::Quaternion(const Vec &from, const Vec &to) { + const qreal epsilon = 1E-10; + + const qreal fromSqNorm = from.squaredNorm(); + const qreal toSqNorm = to.squaredNorm(); + // Identity Quaternion when one vector is null + if ((fromSqNorm < epsilon) || (toSqNorm < epsilon)) { + q[0] = q[1] = q[2] = 0.0; + q[3] = 1.0; + } else { + Vec axis = cross(from, to); + const qreal axisSqNorm = axis.squaredNorm(); + + // Aligned vectors, pick any axis, not aligned with from or to + if (axisSqNorm < epsilon) + axis = from.orthogonalVec(); + + qreal angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm))); + + if (from * to < 0.0) + angle = M_PI - angle; + + setAxisAngle(axis, angle); + } } /*! Returns the image of \p v by the Quaternion inverse() rotation. rotate() performs an inverse transformation. Same as inverse().rotate(v). */ -Vec Quaternion::inverseRotate(const Vec& v) const -{ - return inverse().rotate(v); +Vec Quaternion::inverseRotate(const Vec &v) const { + return inverse().rotate(v); } /*! Returns the image of \p v by the Quaternion rotation. See also inverseRotate() and operator*(const Quaternion&, const Vec&). */ -Vec Quaternion::rotate(const Vec& v) const -{ - const qreal q00 = 2.0 * q[0] * q[0]; - const qreal q11 = 2.0 * q[1] * q[1]; - const qreal q22 = 2.0 * q[2] * q[2]; +Vec Quaternion::rotate(const Vec &v) const { + const qreal q00 = 2.0 * q[0] * q[0]; + const qreal q11 = 2.0 * q[1] * q[1]; + const qreal q22 = 2.0 * q[2] * q[2]; - const qreal q01 = 2.0 * q[0] * q[1]; - const qreal q02 = 2.0 * q[0] * q[2]; - const qreal q03 = 2.0 * q[0] * q[3]; + const qreal q01 = 2.0 * q[0] * q[1]; + const qreal q02 = 2.0 * q[0] * q[2]; + const qreal q03 = 2.0 * q[0] * q[3]; - const qreal q12 = 2.0 * q[1] * q[2]; - const qreal q13 = 2.0 * q[1] * q[3]; + const qreal q12 = 2.0 * q[1] * q[2]; + const qreal q13 = 2.0 * q[1] * q[3]; - const qreal q23 = 2.0 * q[2] * q[3]; + const qreal q23 = 2.0 * q[2] * q[3]; - return Vec((1.0 - q11 - q22)*v[0] + ( q01 - q23)*v[1] + ( q02 + q13)*v[2], - ( q01 + q23)*v[0] + (1.0 - q22 - q00)*v[1] + ( q12 - q03)*v[2], - ( q02 - q13)*v[0] + ( q12 + q03)*v[1] + (1.0 - q11 - q00)*v[2] ); + return Vec((1.0 - q11 - q22) * v[0] + (q01 - q23) * v[1] + (q02 + q13) * v[2], + (q01 + q23) * v[0] + (1.0 - q22 - q00) * v[1] + (q12 - q03) * v[2], + (q02 - q13) * v[0] + (q12 + q03) * v[1] + + (1.0 - q11 - q00) * v[2]); } /*! Set the Quaternion from a (supposedly correct) 3x3 rotation matrix. - The matrix is expressed in European format: its three \e columns are the images by the rotation of - the three vectors of an orthogonal basis. Note that OpenGL uses a symmetric representation for its - matrices. - - setFromRotatedBasis() sets a Quaternion from the three axis of a rotated frame. It actually fills - the three columns of a matrix with these rotated basis vectors and calls this method. */ -void Quaternion::setFromRotationMatrix(const qreal m[3][3]) -{ - // Compute one plus the trace of the matrix - const qreal onePlusTrace = 1.0 + m[0][0] + m[1][1] + m[2][2]; - - if (onePlusTrace > 1E-5) - { - // Direct computation - const qreal s = sqrt(onePlusTrace) * 2.0; - q[0] = (m[2][1] - m[1][2]) / s; - q[1] = (m[0][2] - m[2][0]) / s; - q[2] = (m[1][0] - m[0][1]) / s; - q[3] = 0.25 * s; - } - else - { - // Computation depends on major diagonal term - if ((m[0][0] > m[1][1])&(m[0][0] > m[2][2])) - { - const qreal s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2.0; - q[0] = 0.25 * s; - q[1] = (m[0][1] + m[1][0]) / s; - q[2] = (m[0][2] + m[2][0]) / s; - q[3] = (m[1][2] - m[2][1]) / s; - } - else - if (m[1][1] > m[2][2]) - { - const qreal s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2.0; - q[0] = (m[0][1] + m[1][0]) / s; - q[1] = 0.25 * s; - q[2] = (m[1][2] + m[2][1]) / s; - q[3] = (m[0][2] - m[2][0]) / s; - } - else - { - const qreal s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2.0; - q[0] = (m[0][2] + m[2][0]) / s; - q[1] = (m[1][2] + m[2][1]) / s; - q[2] = 0.25 * s; - q[3] = (m[0][1] - m[1][0]) / s; - } - } - normalize(); + The matrix is expressed in European format: its three \e columns are the + images by the rotation of the three vectors of an orthogonal basis. Note that + OpenGL uses a symmetric representation for its matrices. + + setFromRotatedBasis() sets a Quaternion from the three axis of a rotated + frame. It actually fills the three columns of a matrix with these rotated + basis vectors and calls this method. */ +void Quaternion::setFromRotationMatrix(const qreal m[3][3]) { + // Compute one plus the trace of the matrix + const qreal onePlusTrace = 1.0 + m[0][0] + m[1][1] + m[2][2]; + + if (onePlusTrace > 1E-5) { + // Direct computation + const qreal s = sqrt(onePlusTrace) * 2.0; + q[0] = (m[2][1] - m[1][2]) / s; + q[1] = (m[0][2] - m[2][0]) / s; + q[2] = (m[1][0] - m[0][1]) / s; + q[3] = 0.25 * s; + } else { + // Computation depends on major diagonal term + if ((m[0][0] > m[1][1]) & (m[0][0] > m[2][2])) { + const qreal s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2.0; + q[0] = 0.25 * s; + q[1] = (m[0][1] + m[1][0]) / s; + q[2] = (m[0][2] + m[2][0]) / s; + q[3] = (m[1][2] - m[2][1]) / s; + } else if (m[1][1] > m[2][2]) { + const qreal s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2.0; + q[0] = (m[0][1] + m[1][0]) / s; + q[1] = 0.25 * s; + q[2] = (m[1][2] + m[2][1]) / s; + q[3] = (m[0][2] - m[2][0]) / s; + } else { + const qreal s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2.0; + q[0] = (m[0][2] + m[2][0]) / s; + q[1] = (m[1][2] + m[2][1]) / s; + q[2] = 0.25 * s; + q[3] = (m[0][1] - m[1][0]) / s; + } + } + normalize(); } #ifndef DOXYGEN -void Quaternion::setFromRotationMatrix(const float m[3][3]) -{ - qWarning("setFromRotationMatrix now expects a double[3][3] parameter"); - - qreal mat[3][3]; - for (int i=0; i<3; ++i) - for (int j=0; j<3; ++j) - mat[i][j] = qreal(m[i][j]); - - setFromRotationMatrix(mat); -} - -void Quaternion::setFromRotatedBase(const Vec& X, const Vec& Y, const Vec& Z) -{ - qWarning("setFromRotatedBase is deprecated, use setFromRotatedBasis instead"); - setFromRotatedBasis(X,Y,Z); +void Quaternion::setFromRotatedBase(const Vec &X, const Vec &Y, const Vec &Z) { + qWarning("setFromRotatedBase is deprecated, use setFromRotatedBasis instead"); + setFromRotatedBasis(X, Y, Z); } #endif /*! Sets the Quaternion from the three rotated vectors of an orthogonal basis. - The three vectors do not have to be normalized but must be orthogonal and direct (X^Y=k*Z, with k>0). + The three vectors do not have to be normalized but must be orthogonal and + direct (X^Y=k*Z, with k>0). \code Quaternion q; @@ -179,374 +154,371 @@ void Quaternion::setFromRotatedBase(const Vec& X, const Vec& Y, const Vec& Z) \endcode See also setFromRotationMatrix() and Quaternion(const Vec&, const Vec&). */ -void Quaternion::setFromRotatedBasis(const Vec& X, const Vec& Y, const Vec& Z) -{ - qreal m[3][3]; - qreal normX = X.norm(); - qreal normY = Y.norm(); - qreal normZ = Z.norm(); - - for (int i=0; i<3; ++i) - { - m[i][0] = X[i] / normX; - m[i][1] = Y[i] / normY; - m[i][2] = Z[i] / normZ; - } - - setFromRotationMatrix(m); +void Quaternion::setFromRotatedBasis(const Vec &X, const Vec &Y, const Vec &Z) { + qreal m[3][3]; + qreal normX = X.norm(); + qreal normY = Y.norm(); + qreal normZ = Z.norm(); + + for (int i = 0; i < 3; ++i) { + m[i][0] = X[i] / normX; + m[i][1] = Y[i] / normY; + m[i][2] = Z[i] / normZ; + } + + setFromRotationMatrix(m); } -/*! Returns the axis vector and the angle (in radians) of the rotation represented by the Quaternion. - See the axis() and angle() documentations. */ -void Quaternion::getAxisAngle(Vec& axis, qreal& angle) const -{ - angle = 2.0 * acos(q[3]); - axis = Vec(q[0], q[1], q[2]); - const qreal sinus = axis.norm(); - if (sinus > 1E-8) - axis /= sinus; - - if (angle > M_PI) - { - angle = 2.0 * qreal(M_PI) - angle; - axis = -axis; - } +/*! Returns the axis vector and the angle (in radians) of the rotation + represented by the Quaternion. See the axis() and angle() documentations. */ +void Quaternion::getAxisAngle(Vec &axis, qreal &angle) const { + angle = 2.0 * acos(q[3]); + axis = Vec(q[0], q[1], q[2]); + const qreal sinus = axis.norm(); + if (sinus > 1E-8) + axis /= sinus; + + if (angle > M_PI) { + angle = 2.0 * qreal(M_PI) - angle; + axis = -axis; + } } -/*! Returns the normalized axis direction of the rotation represented by the Quaternion. +/*! Returns the normalized axis direction of the rotation represented by the +Quaternion. It is null for an identity Quaternion. See also angle() and getAxisAngle(). */ -Vec Quaternion::axis() const -{ - Vec res = Vec(q[0], q[1], q[2]); - const qreal sinus = res.norm(); - if (sinus > 1E-8) - res /= sinus; - return (acos(q[3]) <= M_PI/2.0) ? res : -res; +Vec Quaternion::axis() const { + Vec res = Vec(q[0], q[1], q[2]); + const qreal sinus = res.norm(); + if (sinus > 1E-8) + res /= sinus; + return (acos(q[3]) <= M_PI / 2.0) ? res : -res; } -/*! Returns the angle (in radians) of the rotation represented by the Quaternion. +/*! Returns the angle (in radians) of the rotation represented by the + Quaternion. - This value is always in the range [0-pi]. Larger rotational angles are obtained by inverting the - axis() direction. + This value is always in the range [0-pi]. Larger rotational angles are obtained + by inverting the axis() direction. See also axis() and getAxisAngle(). */ -qreal Quaternion::angle() const -{ - const qreal angle = 2.0 * acos(q[3]); - return (angle <= M_PI) ? angle : 2.0*M_PI - angle; +qreal Quaternion::angle() const { + const qreal angle = 2.0 * acos(q[3]); + return (angle <= M_PI) ? angle : 2.0 * M_PI - angle; } /*! Returns an XML \c QDomElement that represents the Quaternion. - \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create - QDomElement. + \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument + factory used to create QDomElement. When output to a file, the resulting QDomElement will look like: \code \endcode - Use initFromDOMElement() to restore the Quaternion state from the resulting \c QDomElement. See - also the Quaternion(const QDomElement&) constructor. - - See the Vec::domElement() documentation for a complete QDomDocument creation and saving example. - - See also Frame::domElement(), Camera::domElement(), KeyFrameInterpolator::domElement()... */ -QDomElement Quaternion::domElement(const QString& name, QDomDocument& document) const -{ - QDomElement de = document.createElement(name); - de.setAttribute("q0", QString::number(q[0])); - de.setAttribute("q1", QString::number(q[1])); - de.setAttribute("q2", QString::number(q[2])); - de.setAttribute("q3", QString::number(q[3])); - return de; + Use initFromDOMElement() to restore the Quaternion state from the resulting \c + QDomElement. See also the Quaternion(const QDomElement&) constructor. + + See the Vec::domElement() documentation for a complete QDomDocument creation + and saving example. + + See also Frame::domElement(), Camera::domElement(), + KeyFrameInterpolator::domElement()... */ +QDomElement Quaternion::domElement(const QString &name, + QDomDocument &document) const { + QDomElement de = document.createElement(name); + de.setAttribute("q0", QString::number(q[0])); + de.setAttribute("q1", QString::number(q[1])); + de.setAttribute("q2", QString::number(q[2])); + de.setAttribute("q3", QString::number(q[3])); + return de; } /*! Restores the Quaternion state from a \c QDomElement created by domElement(). - The \c QDomElement should contain the \c q0, \c q1 , \c q2 and \c q3 attributes. If one of these - attributes is missing or is not a number, a warning is displayed and these fields are respectively - set to 0.0, 0.0, 0.0 and 1.0 (identity Quaternion). + The \c QDomElement should contain the \c q0, \c q1 , \c q2 and \c q3 + attributes. If one of these attributes is missing or is not a number, a warning + is displayed and these fields are respectively set to 0.0, 0.0, 0.0 and 1.0 + (identity Quaternion). See also the Quaternion(const QDomElement&) constructor. */ -void Quaternion::initFromDOMElement(const QDomElement& element) -{ - Quaternion q(element); - *this = q; +void Quaternion::initFromDOMElement(const QDomElement &element) { + Quaternion q(element); + *this = q; } -/*! Constructs a Quaternion from a \c QDomElement representing an XML code of the form - \code< anyTagName q0=".." q1=".." q2=".." q3=".." />\endcode +/*! Constructs a Quaternion from a \c QDomElement representing an XML code of + the form \code< anyTagName q0=".." q1=".." q2=".." q3=".." />\endcode - If one of these attributes is missing or is not a number, a warning is displayed and the associated - value is respectively set to 0, 0, 0 and 1 (identity Quaternion). + If one of these attributes is missing or is not a number, a warning is + displayed and the associated value is respectively set to 0, 0, 0 and 1 + (identity Quaternion). See also domElement() and initFromDOMElement(). */ -Quaternion::Quaternion(const QDomElement& element) -{ - QStringList attribute; - attribute << "q0" << "q1" << "q2" << "q3"; - for (int i=0; i #include +#include namespace qglviewer { /*! \brief The Quaternion class represents 3D rotations and orientations. - \class Quaternion quaternion.h QGLViewer/quaternion.h + \class Quaternion quaternion.h QGLViewer/quaternion.h - The Quaternion is an appropriate (although not very intuitive) representation for 3D rotations and - orientations. Many tools are provided to ease the definition of a Quaternion: see constructors, - setAxisAngle(), setFromRotationMatrix(), setFromRotatedBasis(). + The Quaternion is an appropriate (although not very intuitive) + representation for 3D rotations and orientations. Many tools are provided to + ease the definition of a Quaternion: see constructors, setAxisAngle(), + setFromRotationMatrix(), setFromRotatedBasis(). - You can apply the rotation represented by the Quaternion to 3D points using rotate() and - inverseRotate(). See also the Frame class that represents a coordinate system and provides other - conversion functions like Frame::coordinatesOf() and Frame::transformOf(). + You can apply the rotation represented by the Quaternion to 3D points + using rotate() and inverseRotate(). See also the Frame class that represents + a coordinate system and provides other conversion functions like + Frame::coordinatesOf() and Frame::transformOf(). - You can apply the Quaternion \c q rotation to the OpenGL matrices using: - \code - glMultMatrixd(q.matrix()); - // equvalent to glRotate(q.angle()*180.0/M_PI, q.axis().x, q.axis().y, q.axis().z); - \endcode + You can apply the Quaternion \c q rotation to the OpenGL matrices using: + \code glMultMatrixd(q.matrix()); + // equivalent to glRotate(q.angle()*180.0/M_PI, q.axis().x, q.axis().y, q.axis().z); \endcode - Quaternion is part of the \c qglviewer namespace, specify \c qglviewer::Quaternion or use the qglviewer - namespace: \code using namespace qglviewer; \endcode + Quaternion is part of the \c qglviewer namespace, specify \c + qglviewer::Quaternion or use the qglviewer namespace: + \code using namespace qglviewer; \endcode -

Internal representation

+

Internal representation

- The internal representation of a Quaternion corresponding to a rotation around axis \c axis, with an angle - \c alpha is made of four qreals (i.e. doubles) q[i]: - \code - {q[0],q[1],q[2]} = sin(alpha/2) * {axis[0],axis[1],axis[2]} - q[3] = cos(alpha/2) - \endcode + The internal representation of a Quaternion corresponding to a rotation + around axis \c axis, with an angle \c alpha is made of four qreals (i.e. + doubles) q[i]: \code {q[0],q[1],q[2]} = sin(alpha/2) * + {axis[0],axis[1],axis[2]} q[3] = cos(alpha/2) \endcode - Note that certain implementations place the cosine term in first position (instead of last here). + Note that certain implementations place the cosine term in first + position (instead of last here). - The Quaternion is always normalized, so that its inverse() is actually its conjugate. + The Quaternion is always normalized, so that its inverse() is actually + its conjugate. - See also the Vec and Frame classes' documentations. - \nosubgrouping */ -class QGLVIEWER_EXPORT Quaternion -{ + See also the Vec and Frame classes' documentations. + \nosubgrouping */ +class QGLVIEWER_EXPORT Quaternion { public: - /*! @name Defining a Quaternion */ - //@{ - /*! Default constructor, builds an identity rotation. */ - Quaternion() - { q[0]=q[1]=q[2]=0.0; q[3]=1.0; } - - /*! Constructor from rotation axis (non null) and angle (in radians). See also setAxisAngle(). */ - Quaternion(const Vec& axis, qreal angle) - { - setAxisAngle(axis, angle); - } - - Quaternion(const Vec& from, const Vec& to); - - /*! Constructor from the four values of a Quaternion. First three values are axis*sin(angle/2) and - last one is cos(angle/2). - - \attention The identity Quaternion is Quaternion(0,0,0,1) and \e not Quaternion(0,0,0,0) (which is - not unitary). The default Quaternion() creates such identity Quaternion. */ - Quaternion(qreal q0, qreal q1, qreal q2, qreal q3) - { q[0]=q0; q[1]=q1; q[2]=q2; q[3]=q3; } - - /*! Copy constructor. */ - Quaternion(const Quaternion& Q) - { for (int i=0; i<4; ++i) q[i] = Q.q[i]; } - - /*! Equal operator. */ - Quaternion& operator=(const Quaternion& Q) - { - for (int i=0; i<4; ++i) - q[i] = Q.q[i]; - return (*this); - } - - /*! Sets the Quaternion as a rotation of axis \p axis and angle \p angle (in radians). - - \p axis does not need to be normalized. A null \p axis will result in an identity Quaternion. */ - void setAxisAngle(const Vec& axis, qreal angle) - { - const qreal norm = axis.norm(); - if (norm < 1E-8) - { - // Null rotation - q[0] = 0.0; q[1] = 0.0; q[2] = 0.0; q[3] = 1.0; - } - else - { - const qreal sin_half_angle = sin(angle / 2.0); - q[0] = sin_half_angle*axis[0]/norm; - q[1] = sin_half_angle*axis[1]/norm; - q[2] = sin_half_angle*axis[2]/norm; - q[3] = cos(angle / 2.0); - } - } - - /*! Sets the Quaternion value. See the Quaternion(qreal, qreal, qreal, qreal) constructor documentation. */ - void setValue(qreal q0, qreal q1, qreal q2, qreal q3) - { q[0]=q0; q[1]=q1; q[2]=q2; q[3]=q3; } + /*! @name Defining a Quaternion */ + //@{ + /*! Default constructor, builds an identity rotation. */ + Quaternion() { + q[0] = q[1] = q[2] = 0.0; + q[3] = 1.0; + } + + /*! Constructor from rotation axis (non null) and angle (in radians). See also + * setAxisAngle(). */ + Quaternion(const Vec &axis, qreal angle) { setAxisAngle(axis, angle); } + + Quaternion(const Vec &from, const Vec &to); + + /*! Constructor from the four values of a Quaternion. First three values are + axis*sin(angle/2) and last one is cos(angle/2). + + \attention The identity Quaternion is Quaternion(0,0,0,1) and \e not + Quaternion(0,0,0,0) (which is not unitary). The default Quaternion() + creates such identity Quaternion. */ + Quaternion(qreal q0, qreal q1, qreal q2, qreal q3) { + q[0] = q0; + q[1] = q1; + q[2] = q2; + q[3] = q3; + } + + /*! Copy constructor. */ + Quaternion(const Quaternion &Q) { + for (int i = 0; i < 4; ++i) + q[i] = Q.q[i]; + } + + /*! Equal operator. */ + Quaternion &operator=(const Quaternion &Q) { + for (int i = 0; i < 4; ++i) + q[i] = Q.q[i]; + return (*this); + } + + /*! Sets the Quaternion as a rotation of axis \p axis and angle \p angle (in + radians). + + \p axis does not need to be normalized. A null \p axis will result in + an identity Quaternion. */ + void setAxisAngle(const Vec &axis, qreal angle) { + const qreal norm = axis.norm(); + if (norm < 1E-8) { + // Null rotation + q[0] = 0.0; + q[1] = 0.0; + q[2] = 0.0; + q[3] = 1.0; + } else { + const qreal sin_half_angle = sin(angle / 2.0); + q[0] = sin_half_angle * axis[0] / norm; + q[1] = sin_half_angle * axis[1] / norm; + q[2] = sin_half_angle * axis[2] / norm; + q[3] = cos(angle / 2.0); + } + } + + /*! Sets the Quaternion value. See the Quaternion(qreal, qreal, qreal, qreal) + * constructor documentation. */ + void setValue(qreal q0, qreal q1, qreal q2, qreal q3) { + q[0] = q0; + q[1] = q1; + q[2] = q2; + q[3] = q3; + } #ifndef DOXYGEN - void setFromRotationMatrix(const float m[3][3]); - void setFromRotatedBase(const Vec& X, const Vec& Y, const Vec& Z); + void setFromRotatedBase(const Vec &X, const Vec &Y, const Vec &Z); #endif - void setFromRotationMatrix(const qreal m[3][3]); - void setFromRotatedBasis(const Vec& X, const Vec& Y, const Vec& Z); - //@} - - - /*! @name Accessing values */ - //@{ - Vec axis() const; - qreal angle() const; - void getAxisAngle(Vec& axis, qreal& angle) const; - - /*! Bracket operator, with a constant return value. \p i must range in [0..3]. See the Quaternion(qreal, qreal, qreal, qreal) documentation. */ - qreal operator[](int i) const { return q[i]; } - - /*! Bracket operator returning an l-value. \p i must range in [0..3]. See the Quaternion(qreal, qreal, qreal, qreal) documentation. */ - qreal& operator[](int i) { return q[i]; } - //@} - - - /*! @name Rotation computations */ - //@{ - /*! Returns the composition of the \p a and \p b rotations. - - The order is important. When applied to a Vec \c v (see operator*(const Quaternion&, const Vec&) - and rotate()) the resulting Quaternion acts as if \p b was applied first and then \p a was - applied. This is obvious since the image \c v' of \p v by the composited rotation satisfies: \code - v'= (a*b) * v = a * (b*v) \endcode - - Note that a*b usually differs from b*a. - - \attention For efficiency reasons, the resulting Quaternion is not normalized. Use normalize() in - case of numerical drift with small rotation composition. */ - friend Quaternion operator*(const Quaternion& a, const Quaternion& b) - { - return Quaternion(a.q[3]*b.q[0] + b.q[3]*a.q[0] + a.q[1]*b.q[2] - a.q[2]*b.q[1], - a.q[3]*b.q[1] + b.q[3]*a.q[1] + a.q[2]*b.q[0] - a.q[0]*b.q[2], - a.q[3]*b.q[2] + b.q[3]*a.q[2] + a.q[0]*b.q[1] - a.q[1]*b.q[0], - a.q[3]*b.q[3] - b.q[0]*a.q[0] - a.q[1]*b.q[1] - a.q[2]*b.q[2]); - } - - /*! Quaternion rotation is composed with \p q. - - See operator*(), since this is equivalent to \c this = \c this * \p q. - - \note For efficiency reasons, the resulting Quaternion is not normalized. - You may normalize() it after each application in case of numerical drift. */ - Quaternion& operator*=(const Quaternion &quat) - { - *this = (*this)*quat; - return *this; - } - - /*! Returns the image of \p v by the rotation \p q. - - Same as q.rotate(v). See rotate() and inverseRotate(). */ - friend Vec operator*(const Quaternion& quat, const Vec& v) - { - return quat.rotate(v); - } - - Vec rotate(const Vec& v) const; - Vec inverseRotate(const Vec& v) const; - //@} - - - /*! @name Inversion */ - //@{ - /*! Returns the inverse Quaternion (inverse rotation). - - Result has a negated axis() direction and the same angle(). A composition (see operator*()) of a - Quaternion and its inverse() results in an identity function. - - Use invert() to actually modify the Quaternion. */ - Quaternion inverse() const { return Quaternion(-q[0], -q[1], -q[2], q[3]); } - - /*! Inverses the Quaternion (same rotation angle(), but negated axis()). - - See also inverse(). */ - void invert() { q[0] = -q[0]; q[1] = -q[1]; q[2] = -q[2]; } - - /*! Negates all the coefficients of the Quaternion. - - This results in an other representation of the \e same rotation (opposite rotation angle, but with - a negated axis direction: the two cancel out). However, note that the results of axis() and - angle() are unchanged after a call to this method since angle() always returns a value in [0,pi]. - - This method is mainly useful for Quaternion interpolation, so that the spherical - interpolation takes the shortest path on the unit sphere. See slerp() for details. */ - void negate() { invert(); q[3] = -q[3]; } - - /*! Normalizes the Quaternion coefficients. - - This method should not need to be called since we only deal with unit Quaternions. This is however - useful to prevent numerical drifts, especially with small rotational increments. See also - normalized(). */ - qreal normalize() - { - const qreal norm = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); - for (int i=0; i<4; ++i) - q[i] /= norm; - return norm; - } - - /*! Returns a normalized version of the Quaternion. - - See also normalize(). */ - Quaternion normalized() const - { - qreal Q[4]; - const qreal norm = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); - for (int i=0; i<4; ++i) - Q[i] = q[i] / norm; - return Quaternion(Q[0], Q[1], Q[2], Q[3]); - } - //@} - - - /*! @name Associated matrix */ - //@{ - const GLdouble* matrix() const; - void getMatrix(GLdouble m[4][4]) const; - void getMatrix(GLdouble m[16]) const; - - void getRotationMatrix(qreal m[3][3]) const; - - const GLdouble* inverseMatrix() const; - void getInverseMatrix(GLdouble m[4][4]) const; - void getInverseMatrix(GLdouble m[16]) const; - - void getInverseRotationMatrix(qreal m[3][3]) const; - //@} - - - /*! @name Slerp interpolation */ - //@{ - static Quaternion slerp(const Quaternion& a, const Quaternion& b, qreal t, bool allowFlip=true); - static Quaternion squad(const Quaternion& a, const Quaternion& tgA, const Quaternion& tgB, const Quaternion& b, qreal t); - /*! Returns the "dot" product of \p a and \p b: a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]. */ - static qreal dot(const Quaternion& a, const Quaternion& b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]; } - - Quaternion log(); - Quaternion exp(); - static Quaternion lnDif(const Quaternion& a, const Quaternion& b); - static Quaternion squadTangent(const Quaternion& before, const Quaternion& center, const Quaternion& after); - //@} - - /*! @name Random Quaternion */ - //@{ - static Quaternion randomQuaternion(); - //@} - - /*! @name XML representation */ - //@{ - explicit Quaternion(const QDomElement& element); - QDomElement domElement(const QString& name, QDomDocument& document) const; - void initFromDOMElement(const QDomElement& element); - //@} + void setFromRotationMatrix(const qreal m[3][3]); + void setFromRotatedBasis(const Vec &X, const Vec &Y, const Vec &Z); + //@} + + /*! @name Accessing values */ + //@{ + Vec axis() const; + qreal angle() const; + void getAxisAngle(Vec &axis, qreal &angle) const; + + /*! Bracket operator, with a constant return value. \p i must range in [0..3]. + * See the Quaternion(qreal, qreal, qreal, qreal) documentation. */ + qreal operator[](int i) const { return q[i]; } + + /*! Bracket operator returning an l-value. \p i must range in [0..3]. See the + * Quaternion(qreal, qreal, qreal, qreal) documentation. */ + qreal &operator[](int i) { return q[i]; } + //@} + + /*! @name Rotation computations */ + //@{ + /*! Returns the composition of the \p a and \p b rotations. + + The order is important. When applied to a Vec \c v (see + operator*(const Quaternion&, const Vec&) and rotate()) the resulting + Quaternion acts as if \p b was applied first and then \p a was applied. + This is obvious since the image \c v' of \p v by the composited rotation + satisfies: \code v'= (a*b) * v = a * (b*v) \endcode + + Note that a*b usually differs from b*a. + + \attention For efficiency reasons, the resulting Quaternion is not + normalized. Use normalize() in case of numerical drift with small rotation + composition. */ + friend Quaternion operator*(const Quaternion &a, const Quaternion &b) { + return Quaternion( + a.q[3] * b.q[0] + b.q[3] * a.q[0] + a.q[1] * b.q[2] - a.q[2] * b.q[1], + a.q[3] * b.q[1] + b.q[3] * a.q[1] + a.q[2] * b.q[0] - a.q[0] * b.q[2], + a.q[3] * b.q[2] + b.q[3] * a.q[2] + a.q[0] * b.q[1] - a.q[1] * b.q[0], + a.q[3] * b.q[3] - b.q[0] * a.q[0] - a.q[1] * b.q[1] - a.q[2] * b.q[2]); + } + + /*! Quaternion rotation is composed with \p q. + + See operator*(), since this is equivalent to \c this = \c this * \p q. + + \note For efficiency reasons, the resulting Quaternion is not + normalized. You may normalize() it after each application in case of + numerical drift. */ + Quaternion &operator*=(const Quaternion &q) { + *this = (*this) * q; + return *this; + } + + /*! Returns the image of \p v by the rotation \p q. + + Same as q.rotate(v). See rotate() and inverseRotate(). */ + friend Vec operator*(const Quaternion &q, const Vec &v) { + return q.rotate(v); + } + + Vec rotate(const Vec &v) const; + Vec inverseRotate(const Vec &v) const; + //@} + + /*! @name Inversion */ + //@{ + /*! Returns the inverse Quaternion (inverse rotation). + + Result has a negated axis() direction and the same angle(). A + composition (see operator*()) of a Quaternion and its inverse() results in + an identity function. + + Use invert() to actually modify the Quaternion. */ + Quaternion inverse() const { return Quaternion(-q[0], -q[1], -q[2], q[3]); } + + /*! Inverses the Quaternion (same rotation angle(), but negated axis()). + + See also inverse(). */ + void invert() { + q[0] = -q[0]; + q[1] = -q[1]; + q[2] = -q[2]; + } + + /*! Negates all the coefficients of the Quaternion. + + This results in an other representation of the \e same rotation + (opposite rotation angle, but with a negated axis direction: the two cancel + out). However, note that the results of axis() and angle() are unchanged + after a call to this method since angle() always returns a value in [0,pi]. + + This method is mainly useful for Quaternion interpolation, so that the + spherical interpolation takes the shortest path on the unit sphere. See + slerp() for details. */ + void negate() { + invert(); + q[3] = -q[3]; + } + + /*! Normalizes the Quaternion coefficients. + + This method should not need to be called since we only deal with unit + Quaternions. This is however useful to prevent numerical drifts, especially + with small rotational increments. See also normalized(). */ + qreal normalize() { + const qreal norm = + sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); + for (int i = 0; i < 4; ++i) + q[i] /= norm; + return norm; + } + + /*! Returns a normalized version of the Quaternion. + + See also normalize(). */ + Quaternion normalized() const { + qreal Q[4]; + const qreal norm = + sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); + for (int i = 0; i < 4; ++i) + Q[i] = q[i] / norm; + return Quaternion(Q[0], Q[1], Q[2], Q[3]); + } + //@} + + /*! @name Associated matrix */ + //@{ + const GLdouble *matrix() const; + void getMatrix(GLdouble m[4][4]) const; + void getMatrix(GLdouble m[16]) const; + + void getRotationMatrix(qreal m[3][3]) const; + + const GLdouble *inverseMatrix() const; + void getInverseMatrix(GLdouble m[4][4]) const; + void getInverseMatrix(GLdouble m[16]) const; + + void getInverseRotationMatrix(qreal m[3][3]) const; + //@} + + /*! @name Slerp interpolation */ + //@{ + static Quaternion slerp(const Quaternion &a, const Quaternion &b, qreal t, + bool allowFlip = true); + static Quaternion squad(const Quaternion &a, const Quaternion &tgA, + const Quaternion &tgB, const Quaternion &b, qreal t); + /*! Returns the "dot" product of \p a and \p b: a[0]*b[0] + a[1]*b[1] + + * a[2]*b[2] + a[3]*b[3]. */ + static qreal dot(const Quaternion &a, const Quaternion &b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + + Quaternion log(); + Quaternion exp(); + static Quaternion lnDif(const Quaternion &a, const Quaternion &b); + static Quaternion squadTangent(const Quaternion &before, + const Quaternion ¢er, + const Quaternion &after); + //@} + + /*! @name Random Quaternion */ + //@{ + static Quaternion randomQuaternion(); + //@} + + /*! @name XML representation */ + //@{ + explicit Quaternion(const QDomElement &element); + QDomElement domElement(const QString &name, QDomDocument &document) const; + void initFromDOMElement(const QDomElement &element); +//@} #ifdef DOXYGEN - /*! @name Output stream */ - //@{ - /*! Output stream operator. Enables debugging code like: - \code - Quaternion rot(...); - cout << "Rotation=" << rot << endl; - \endcode */ - std::ostream& operator<<(std::ostream& o, const qglviewer::Vec&); - //@} + /*! @name Output stream */ + //@{ + /*! Output stream operator. Enables debugging code like: + \code + Quaternion rot(...); + cout << "Rotation=" << rot << endl; + \endcode */ + std::ostream &operator<<(std::ostream &o, const qglviewer::Vec &); +//@} #endif private: - /*! The internal data representation is private, use operator[] to access values. */ - qreal q[4]; + /*! The internal data representation is private, use operator[] to access + * values. */ + qreal q[4]; }; -} // namespace +} // namespace qglviewer -std::ostream& operator<<(std::ostream& o, const qglviewer::Quaternion&); +std::ostream &operator<<(std::ostream &o, const qglviewer::Quaternion &); #endif // QGLVIEWER_QUATERNION_H diff --git a/octovis/src/extern/QGLViewer/saveSnapshot.cpp b/octovis/src/extern/QGLViewer/saveSnapshot.cpp index 4a53b8bb..122f8332 100644 --- a/octovis/src/extern/QGLViewer/saveSnapshot.cpp +++ b/octovis/src/extern/QGLViewer/saveSnapshot.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,27 +19,27 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #include "qglviewer.h" #ifndef NO_VECTORIAL_RENDER -# include "ui_VRenderInterface.h" -# include "VRender/VRender.h" +#include "VRender/VRender.h" +#include "ui_VRenderInterface.h" #endif #include "ui_ImageInterface.h" // Output format list -# include +#include -#include -#include -#include #include -#include +#include +#include +#include #include +#include +#include #include -#include +#include using namespace std; @@ -53,586 +53,606 @@ static QMap FDFormatString; // Converts snapshotFormat to file extension static QMap extension; - /*! Sets snapshotFileName(). */ -void QGLViewer::setSnapshotFileName(const QString& name) -{ - snapshotFileName_ = QFileInfo(name).absoluteFilePath(); +void QGLViewer::setSnapshotFileName(const QString &name) { + snapshotFileName_ = QFileInfo(name).absoluteFilePath(); } #ifndef DOXYGEN -const QString& QGLViewer::snapshotFilename() const -{ - qWarning("snapshotFilename is deprecated. Use snapshotFileName() (uppercase N) instead."); - return snapshotFileName(); +const QString &QGLViewer::snapshotFilename() const { + qWarning("snapshotFilename is deprecated. Use snapshotFileName() (uppercase " + "N) instead."); + return snapshotFileName(); } #endif - /*! Opens a dialog that displays the different available snapshot formats. Then calls setSnapshotFormat() with the selected one (unless the user cancels). Returns \c false if the user presses the Cancel button and \c true otherwise. */ -bool QGLViewer::openSnapshotFormatDialog() -{ - bool ok = false; - QStringList list = formats.split(";;", QString::SkipEmptyParts); - int current = list.indexOf(FDFormatString[snapshotFormat()]); - QString format = QInputDialog::getItem(this, "Snapshot format", "Select a snapshot format", list, current, false, &ok); - if (ok) - setSnapshotFormat(Qtformat[format]); - return ok; +bool QGLViewer::openSnapshotFormatDialog() { + bool ok = false; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QStringList list = formats.split(";;", QString::SkipEmptyParts); +#else + QStringList list = formats.split(";;", Qt::SkipEmptyParts); +#endif + int current = list.indexOf(FDFormatString[snapshotFormat()]); + QString format = + QInputDialog::getItem(this, "Snapshot format", "Select a snapshot format", + list, current, false, &ok); + if (ok) + setSnapshotFormat(Qtformat[format]); + return ok; } - // Finds all available Qt output formats, so that they can be available in // saveSnapshot dialog. Initialize snapshotFormat() to the first one. -void QGLViewer::initializeSnapshotFormats() -{ - QList list = QImageWriter::supportedImageFormats(); - QStringList formatList; - for (int i=0; i < list.size(); ++i) - formatList << QString(list.at(i).toUpper()); - // qWarning("Available image formats: "); - // QStringList::Iterator it = formatList.begin(); - // while( it != formatList.end() ) - // qWarning((*it++).); QT4 change this. qWarning no longer accepts QString +void QGLViewer::initializeSnapshotFormats() { + QList list = QImageWriter::supportedImageFormats(); + QStringList formatList; + for (int i = 0; i < list.size(); ++i) + formatList << QString(list.at(i).toUpper()); +// qWarning("Available image formats: "); +// QStringList::Iterator it = formatList.begin(); +// while( it != formatList.end() ) +// qWarning((*it++).); QT4 change this. qWarning no longer accepts +// QString #ifndef NO_VECTORIAL_RENDER - // We add the 3 vectorial formats to the list - formatList += "EPS"; - formatList += "PS"; - formatList += "XFIG"; + // We add the 3 vectorial formats to the list + formatList += "EPS"; + formatList += "PS"; + formatList += "XFIG"; #endif - // Check that the interesting formats are available and add them in "formats" - // Unused formats: XPM XBM PBM PGM - QStringList QtText, MenuText, Ext; - QtText += "JPEG"; MenuText += "JPEG (*.jpg)"; Ext += "jpg"; - QtText += "PNG"; MenuText += "PNG (*.png)"; Ext += "png"; - QtText += "EPS"; MenuText += "Encapsulated Postscript (*.eps)"; Ext += "eps"; - QtText += "PS"; MenuText += "Postscript (*.ps)"; Ext += "ps"; - QtText += "PPM"; MenuText += "24bit RGB Bitmap (*.ppm)"; Ext += "ppm"; - QtText += "BMP"; MenuText += "Windows Bitmap (*.bmp)"; Ext += "bmp"; - QtText += "XFIG"; MenuText += "XFig (*.fig)"; Ext += "fig"; - - QStringList::iterator itText = QtText.begin(); - QStringList::iterator itMenu = MenuText.begin(); - QStringList::iterator itExt = Ext.begin(); - - while (itText != QtText.end()) - { - //QMessageBox::information(this, "Snapshot ", "Trying format\n"+(*itText)); - if (formatList.contains((*itText))) - { - //QMessageBox::information(this, "Snapshot ", "Recognized format\n"+(*itText)); - if (formats.isEmpty()) - setSnapshotFormat(*itText); - else - formats += ";;"; - formats += (*itMenu); - Qtformat[(*itMenu)] = (*itText); - FDFormatString[(*itText)] = (*itMenu); - extension[(*itText)] = (*itExt); - } - // Synchronize parsing - itText++; - itMenu++; - itExt++; - } + // Check that the interesting formats are available and add them in "formats" + // Unused formats: XPM XBM PBM PGM + QStringList QtText, MenuText, Ext; + QtText += "JPEG"; + MenuText += "JPEG (*.jpg)"; + Ext += "jpg"; + QtText += "PNG"; + MenuText += "PNG (*.png)"; + Ext += "png"; + QtText += "EPS"; + MenuText += "Encapsulated Postscript (*.eps)"; + Ext += "eps"; + QtText += "PS"; + MenuText += "Postscript (*.ps)"; + Ext += "ps"; + QtText += "PPM"; + MenuText += "24bit RGB Bitmap (*.ppm)"; + Ext += "ppm"; + QtText += "BMP"; + MenuText += "Windows Bitmap (*.bmp)"; + Ext += "bmp"; + QtText += "XFIG"; + MenuText += "XFig (*.fig)"; + Ext += "fig"; + + QStringList::iterator itText = QtText.begin(); + QStringList::iterator itMenu = MenuText.begin(); + QStringList::iterator itExt = Ext.begin(); + + while (itText != QtText.end()) { + // QMessageBox::information(this, "Snapshot ", "Trying format\n"+(*itText)); + if (formatList.contains((*itText))) { + // QMessageBox::information(this, "Snapshot ", "Recognized + // format\n"+(*itText)); + if (formats.isEmpty()) + setSnapshotFormat(*itText); + else + formats += ";;"; + formats += (*itMenu); + Qtformat[(*itMenu)] = (*itText); + FDFormatString[(*itText)] = (*itMenu); + extension[(*itText)] = (*itExt); + } + // Synchronize parsing + itText++; + itMenu++; + itExt++; + } } // Returns false if the user refused to use the fileName -static bool checkFileName(QString& fileName, QWidget* widget, const QString& snapshotFormat) -{ - if (fileName.isEmpty()) - return false; - - // Check that extension has been provided - QFileInfo info(fileName); - - if (info.suffix().isEmpty()) - { - // No extension given. Silently add one - if (fileName.right(1) != ".") - fileName += "."; - fileName += extension[snapshotFormat]; - info.setFile(fileName); - } - else if (info.suffix() != extension[snapshotFormat]) - { - // Extension is not appropriate. Propose a modification - QString modifiedName = info.absolutePath() + '/' + info.baseName() + "." + extension[snapshotFormat]; - QFileInfo modifInfo(modifiedName); - int i=(QMessageBox::warning(widget,"Wrong extension", - info.fileName()+" has a wrong extension.\nSave as "+modifInfo.fileName()+" instead ?", - QMessageBox::Yes, - QMessageBox::No, - QMessageBox::Cancel)); - if (i==QMessageBox::Cancel) - return false; - - if (i==QMessageBox::Yes) - { - fileName = modifiedName; - info.setFile(fileName); - } - } - - return true; +static bool checkFileName(QString &fileName, QWidget *widget, + const QString &snapshotFormat) { + if (fileName.isEmpty()) + return false; + + // Check that extension has been provided + QFileInfo info(fileName); + + if (info.suffix().isEmpty()) { + // No extension given. Silently add one + if (fileName.right(1) != ".") + fileName += "."; + fileName += extension[snapshotFormat]; + info.setFile(fileName); + } else if (info.suffix() != extension[snapshotFormat]) { + // Extension is not appropriate. Propose a modification + QString modifiedName = info.absolutePath() + '/' + info.baseName() + "." + + extension[snapshotFormat]; + QFileInfo modifInfo(modifiedName); + int i = (QMessageBox::warning( + widget, "Wrong extension", + info.fileName() + " has a wrong extension.\nSave as " + + modifInfo.fileName() + " instead ?", + QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel)); + if (i == QMessageBox::Cancel) + return false; + + if (i == QMessageBox::Yes) { + fileName = modifiedName; + info.setFile(fileName); + } + } + + return true; } #ifndef NO_VECTORIAL_RENDER // static void drawVectorial(void* param) -void drawVectorial(void* param) -{ - ( (QGLViewer*) param )->drawVectorial(); -} +void drawVectorial(void *param) { ((QGLViewer *)param)->drawVectorial(); } #ifndef DOXYGEN -class ProgressDialog -{ +class ProgressDialog { public: - static void showProgressDialog(QGLWidget* parent); - static void updateProgress(float progress, const QString& stepString); - static void hideProgressDialog(); + static void showProgressDialog(QOpenGLWidget *parent); + static void updateProgress(float progress, const QString &stepString); + static void hideProgressDialog(); private: - static QProgressDialog* progressDialog; + static QProgressDialog *progressDialog; }; -QProgressDialog* ProgressDialog::progressDialog = NULL; +QProgressDialog *ProgressDialog::progressDialog = nullptr; -void ProgressDialog::showProgressDialog(QGLWidget* parent) -{ - progressDialog = new QProgressDialog(parent); - progressDialog->setWindowTitle("Image rendering progress"); - progressDialog->setMinimumSize(300, 40); - progressDialog->setCancelButton(NULL); - progressDialog->show(); +void ProgressDialog::showProgressDialog(QOpenGLWidget *parent) { + progressDialog = new QProgressDialog(parent); + progressDialog->setWindowTitle("Image rendering progress"); + progressDialog->setMinimumSize(300, 40); + progressDialog->setCancelButton(nullptr); + progressDialog->show(); } -void ProgressDialog::updateProgress(float progress, const QString& stepString) -{ - progressDialog->setValue(int(progress*100)); - QString message(stepString); - if (message.length() > 33) - message = message.left(17) + "..." + message.right(12); - progressDialog->setLabelText(message); - progressDialog->update(); - qApp->processEvents(); +void ProgressDialog::updateProgress(float progress, const QString &stepString) { + progressDialog->setValue(int(progress * 100)); + QString message(stepString); + if (message.length() > 33) + message = message.left(17) + "..." + message.right(12); + progressDialog->setLabelText(message); + progressDialog->update(); + qApp->processEvents(); } -void ProgressDialog::hideProgressDialog() -{ - progressDialog->close(); - delete progressDialog; - progressDialog = NULL; +void ProgressDialog::hideProgressDialog() { + progressDialog->close(); + delete progressDialog; + progressDialog = nullptr; } -class VRenderInterface: public QDialog, public Ui::VRenderInterface -{ -public: VRenderInterface(QWidget *parent) : QDialog(parent) { setupUi(this); } +class VRenderInterface : public QDialog, public Ui::VRenderInterface { +public: + VRenderInterface(QWidget *parent) : QDialog(parent) { setupUi(this); } }; -#endif //DOXYGEN +#endif // DOXYGEN // Pops-up a vectorial output option dialog box and save to fileName -// Returns -1 in case of Cancel, 0 for success and (todo) error code in case of problem. -static int saveVectorialSnapshot(const QString& fileName, QGLWidget* widget, const QString& snapshotFormat) -{ - static VRenderInterface* VRinterface = NULL; - - if (!VRinterface) - VRinterface = new VRenderInterface(widget); - - - // Configure interface according to selected snapshotFormat - if (snapshotFormat == "XFIG") - { - VRinterface->tightenBBox->setEnabled(false); - VRinterface->colorBackground->setEnabled(false); - } - else - { - VRinterface->tightenBBox->setEnabled(true); - VRinterface->colorBackground->setEnabled(true); - } - - if (VRinterface->exec() == QDialog::Rejected) - return -1; - - vrender::VRenderParams vparams; - vparams.setFilename(fileName); - - if (snapshotFormat == "EPS") vparams.setFormat(vrender::VRenderParams::EPS); - if (snapshotFormat == "PS") vparams.setFormat(vrender::VRenderParams::PS); - if (snapshotFormat == "XFIG") vparams.setFormat(vrender::VRenderParams::XFIG); - - vparams.setOption(vrender::VRenderParams::CullHiddenFaces, !(VRinterface->includeHidden->isChecked())); - vparams.setOption(vrender::VRenderParams::OptimizeBackFaceCulling, VRinterface->cullBackFaces->isChecked()); - vparams.setOption(vrender::VRenderParams::RenderBlackAndWhite, VRinterface->blackAndWhite->isChecked()); - vparams.setOption(vrender::VRenderParams::AddBackground, VRinterface->colorBackground->isChecked()); - vparams.setOption(vrender::VRenderParams::TightenBoundingBox, VRinterface->tightenBBox->isChecked()); - - switch (VRinterface->sortMethod->currentIndex()) - { - case 0: vparams.setSortMethod(vrender::VRenderParams::NoSorting); break; - case 1: vparams.setSortMethod(vrender::VRenderParams::BSPSort); break; - case 2: vparams.setSortMethod(vrender::VRenderParams::TopologicalSort); break; - case 3: vparams.setSortMethod(vrender::VRenderParams::AdvancedTopologicalSort); break; - default: - qWarning("VRenderInterface::saveVectorialSnapshot: Unknown SortMethod"); - } - - vparams.setProgressFunction(&ProgressDialog::updateProgress); - ProgressDialog::showProgressDialog(widget); - widget->makeCurrent(); - widget->raise(); - vrender::VectorialRender(drawVectorial, (void*) widget, vparams); - ProgressDialog::hideProgressDialog(); - widget->setCursor(QCursor(Qt::ArrowCursor)); - - // Should return vparams.error(), but this is currently not set. - return 0; +// Returns -1 in case of Cancel, 0 for success and (todo) error code in case of +// problem. +static int saveVectorialSnapshot(const QString &fileName, QOpenGLWidget *widget, + const QString &snapshotFormat) { + static VRenderInterface *VRinterface = nullptr; + + if (!VRinterface) + VRinterface = new VRenderInterface(widget); + + // Configure interface according to selected snapshotFormat + if (snapshotFormat == "XFIG") { + VRinterface->tightenBBox->setEnabled(false); + VRinterface->colorBackground->setEnabled(false); + } else { + VRinterface->tightenBBox->setEnabled(true); + VRinterface->colorBackground->setEnabled(true); + } + + if (VRinterface->exec() == QDialog::Rejected) + return -1; + + vrender::VRenderParams vparams; + vparams.setFilename(fileName); + + if (snapshotFormat == "EPS") + vparams.setFormat(vrender::VRenderParams::EPS); + if (snapshotFormat == "PS") + vparams.setFormat(vrender::VRenderParams::PS); + if (snapshotFormat == "XFIG") + vparams.setFormat(vrender::VRenderParams::XFIG); + + vparams.setOption(vrender::VRenderParams::CullHiddenFaces, + !(VRinterface->includeHidden->isChecked())); + vparams.setOption(vrender::VRenderParams::OptimizeBackFaceCulling, + VRinterface->cullBackFaces->isChecked()); + vparams.setOption(vrender::VRenderParams::RenderBlackAndWhite, + VRinterface->blackAndWhite->isChecked()); + vparams.setOption(vrender::VRenderParams::AddBackground, + VRinterface->colorBackground->isChecked()); + vparams.setOption(vrender::VRenderParams::TightenBoundingBox, + VRinterface->tightenBBox->isChecked()); + + switch (VRinterface->sortMethod->currentIndex()) { + case 0: + vparams.setSortMethod(vrender::VRenderParams::NoSorting); + break; + case 1: + vparams.setSortMethod(vrender::VRenderParams::BSPSort); + break; + case 2: + vparams.setSortMethod(vrender::VRenderParams::TopologicalSort); + break; + case 3: + vparams.setSortMethod(vrender::VRenderParams::AdvancedTopologicalSort); + break; + default: + qWarning("VRenderInterface::saveVectorialSnapshot: Unknown SortMethod"); + } + + vparams.setProgressFunction(&ProgressDialog::updateProgress); + ProgressDialog::showProgressDialog(widget); + widget->makeCurrent(); + widget->raise(); + vrender::VectorialRender(drawVectorial, (void *)widget, vparams); + ProgressDialog::hideProgressDialog(); + widget->setCursor(QCursor(Qt::ArrowCursor)); + + // Should return vparams.error(), but this is currently not set. + return 0; } #endif // NO_VECTORIAL_RENDER - -class ImageInterface: public QDialog, public Ui::ImageInterface -{ -public: ImageInterface(QWidget *parent) : QDialog(parent) { setupUi(this); } +class ImageInterface : public QDialog, public Ui::ImageInterface { +public: + ImageInterface(QWidget *parent) : QDialog(parent) { setupUi(this); } }; - // Pops-up an image settings dialog box and save to fileName. // Returns false in case of problem. -bool QGLViewer::saveImageSnapshot(const QString& fileName) -{ - static ImageInterface* imageInterface = NULL; - - if (!imageInterface) - imageInterface = new ImageInterface(this); - - imageInterface->imgWidth->setValue(width()); - imageInterface->imgHeight->setValue(height()); - - imageInterface->imgQuality->setValue(snapshotQuality()); - - if (imageInterface->exec() == QDialog::Rejected) - return true; - - // Hide closed dialog - qApp->processEvents(); - - setSnapshotQuality(imageInterface->imgQuality->value()); - - QColor previousBGColor = backgroundColor(); - if (imageInterface->whiteBackground->isChecked()) - setBackgroundColor(Qt::white); - - QSize finalSize(imageInterface->imgWidth->value(), imageInterface->imgHeight->value()); - - qreal oversampling = imageInterface->oversampling->value(); - QSize subSize(int(this->width()/oversampling), int(this->height()/oversampling)); - - qreal aspectRatio = width() / static_cast(height()); - qreal newAspectRatio = finalSize.width() / static_cast(finalSize.height()); - - qreal zNear = camera()->zNear(); - qreal zFar = camera()->zFar(); - - qreal xMin, yMin; - bool expand = imageInterface->expandFrustum->isChecked(); - if (camera()->type() == qglviewer::Camera::PERSPECTIVE) - if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatiofieldOfView() / 2.0); - xMin = newAspectRatio * yMin; - } - else - { - xMin = zNear * tan(camera()->fieldOfView() / 2.0) * aspectRatio; - yMin = xMin / newAspectRatio; - } - else - { - camera()->getOrthoWidthHeight(xMin, yMin); - if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatio(finalSize.width()); - qreal scaleY = subSize.height() / static_cast(finalSize.height()); - - qreal deltaX = 2.0 * xMin * scaleX; - qreal deltaY = 2.0 * yMin * scaleY; - - int nbX = finalSize.width() / subSize.width(); - int nbY = finalSize.height() / subSize.height(); - - // Extra subimage on the right/bottom border(s) if needed - if (nbX * subSize.width() < finalSize.width()) - nbX++; - if (nbY * subSize.height() < finalSize.height()) - nbY++; - - makeCurrent(); - - // tileRegion_ is used by startScreenCoordinatesSystem to appropriately set the local - // coordinate system when tiling - tileRegion_ = new TileRegion(); - qreal tileXMin, tileWidth, tileYMin, tileHeight; - if ((expand && (newAspectRatio>aspectRatio)) || (!expand && (newAspectRatiotextScale = 1.0 / scaleY; - } - else - { - qreal tileTotalHeight = width() / newAspectRatio; - tileYMin = (height() - tileTotalHeight) / 2.0; - tileHeight = tileTotalHeight * scaleY; - tileXMin = 0.0; - tileWidth = width() * scaleX; - tileRegion_->textScale = 1.0 / scaleX; - } - - int count=0; - for (int i=0; itype() == qglviewer::Camera::PERSPECTIVE) - glFrustum(-xMin + i*deltaX, -xMin + (i+1)*deltaX, yMin - (j+1)*deltaY, yMin - j*deltaY, zNear, zFar); - else - glOrtho(-xMin + i*deltaX, -xMin + (i+1)*deltaX, yMin - (j+1)*deltaY, yMin - j*deltaY, zNear, zFar); - glMatrixMode(GL_MODELVIEW); - - tileRegion_->xMin = tileXMin + i * tileWidth; - tileRegion_->xMax = tileXMin + (i+1) * tileWidth; - tileRegion_->yMin = tileYMin + j * tileHeight; - tileRegion_->yMax = tileYMin + (j+1) * tileHeight; - - draw(); - postDraw(); - - // ProgressDialog::hideProgressDialog(); - // qApp->processEvents(); - - QImage snapshot = grabFrameBuffer(true); - - // ProgressDialog::showProgressDialog(this); - // ProgressDialog::updateProgress(count / (qreal)(nbX*nbY), - // "Generating image ["+QString::number(count)+"/"+QString::number(nbX*nbY)+"]"); - // qApp->processEvents(); - - QImage subImage = snapshot.scaled(subSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - - // Copy subImage in image - for (int ii=0; iiwhiteBackground->isChecked()) - setBackgroundColor(previousBGColor); - - return saveOK; +bool QGLViewer::saveImageSnapshot(const QString &fileName) { + static ImageInterface *imageInterface = nullptr; + qreal devicePixelRatio = screen()->devicePixelRatio(); + qreal dipWidth = devicePixelRatio * width(); + qreal dipHeight = devicePixelRatio * height(); + + if (!imageInterface) + imageInterface = new ImageInterface(this); + + imageInterface->imgWidth->setValue(dipWidth); + imageInterface->imgHeight->setValue(dipHeight); + + imageInterface->imgQuality->setValue(snapshotQuality()); + + if (imageInterface->exec() == QDialog::Rejected) + return true; + + // Hide closed dialog + qApp->processEvents(); + + setSnapshotQuality(imageInterface->imgQuality->value()); + + QColor previousBGColor = backgroundColor(); + if (imageInterface->whiteBackground->isChecked()) + setBackgroundColor(Qt::white); + + QSize finalSize(imageInterface->imgWidth->value(), + imageInterface->imgHeight->value()); + + qreal oversampling = imageInterface->oversampling->value(); + QSize subSize(int(dipWidth / oversampling), int(dipHeight / oversampling)); + + qreal aspectRatio = dipWidth / static_cast(dipHeight); + qreal newAspectRatio = finalSize.width() / static_cast(finalSize.height()); + + qreal zNear = camera()->zNear(); + qreal zFar = camera()->zFar(); + + qreal xMin, yMin; + bool expand = imageInterface->expandFrustum->isChecked(); + if (camera()->type() == qglviewer::Camera::PERSPECTIVE) + if ((expand && (newAspectRatio > aspectRatio)) || + (!expand && (newAspectRatio < aspectRatio))) { + yMin = zNear * tan(camera()->fieldOfView() / 2.0); + xMin = newAspectRatio * yMin; + } else { + xMin = zNear * tan(camera()->fieldOfView() / 2.0) * aspectRatio; + yMin = xMin / newAspectRatio; + } + else { + GLdouble width, height; + camera()->getOrthoWidthHeight(width, height); + xMin = qreal(width); + yMin = qreal(height); + if ((expand && (newAspectRatio > aspectRatio)) || + (!expand && (newAspectRatio < aspectRatio))) + xMin = newAspectRatio * yMin; + else + yMin = xMin / newAspectRatio; + } + + QImage image(finalSize.width(), finalSize.height(), QImage::Format_ARGB32); + + if (image.isNull()) { + QMessageBox::warning(this, "Image saving error", + "Unable to create resulting image", QMessageBox::Ok, + QMessageBox::NoButton); + return false; + } + + // ProgressDialog disabled since it interfers with the screen grabing mecanism + // on some platforms. Too bad. ProgressDialog::showProgressDialog(this); + + qreal scaleX = subSize.width() / static_cast(finalSize.width()); + qreal scaleY = subSize.height() / static_cast(finalSize.height()); + + qreal deltaX = 2.0 * xMin * scaleX; + qreal deltaY = 2.0 * yMin * scaleY; + + int nbX = finalSize.width() / subSize.width(); + int nbY = finalSize.height() / subSize.height(); + + // Extra subimage on the right/bottom border(s) if needed + if (nbX * subSize.width() < finalSize.width()) + nbX++; + if (nbY * subSize.height() < finalSize.height()) + nbY++; + + makeCurrent(); + + // tileRegion_ is used by startScreenCoordinatesSystem to appropriately set + // the local coordinate system when tiling + tileRegion_ = new TileRegion(); + qreal tileXMin, tileWidth, tileYMin, tileHeight; + if ((expand && (newAspectRatio > aspectRatio)) || + (!expand && (newAspectRatio < aspectRatio))) { + qreal tileTotalWidth = newAspectRatio * dipHeight; + tileXMin = (dipWidth - tileTotalWidth) / 2.0; + tileWidth = tileTotalWidth * scaleX; + tileYMin = 0.0; + tileHeight = dipHeight * scaleY; + tileRegion_->textScale = 1.0 / scaleY; + } else { + qreal tileTotalHeight = dipWidth / newAspectRatio; + tileYMin = (dipHeight - tileTotalHeight) / 2.0; + tileHeight = tileTotalHeight * scaleY; + tileXMin = 0.0; + tileWidth = dipWidth * scaleX; + tileRegion_->textScale = 1.0 / scaleX; + } + + int count = 0; + for (int i = 0; i < nbX; i++) + for (int j = 0; j < nbY; j++) { + preDraw(); + + // Change projection matrix + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (camera()->type() == qglviewer::Camera::PERSPECTIVE) + glFrustum(-xMin + i * deltaX, -xMin + (i + 1) * deltaX, + yMin - (j + 1) * deltaY, yMin - j * deltaY, zNear, zFar); + else + glOrtho(-xMin + i * deltaX, -xMin + (i + 1) * deltaX, + yMin - (j + 1) * deltaY, yMin - j * deltaY, zNear, zFar); + glMatrixMode(GL_MODELVIEW); + + tileRegion_->xMin = tileXMin + i * tileWidth; + tileRegion_->xMax = tileXMin + (i + 1) * tileWidth; + tileRegion_->yMin = tileYMin + j * tileHeight; + tileRegion_->yMax = tileYMin + (j + 1) * tileHeight; + + draw(); + postDraw(); + + // ProgressDialog::hideProgressDialog(); + // qApp->processEvents(); + + QImage snapshot = QOpenGLWidget::grabFramebuffer(); + + // ProgressDialog::showProgressDialog(this); + // ProgressDialog::updateProgress(count / (qreal)(nbX*nbY), + // "Generating image + // ["+QString::number(count)+"/"+QString::number(nbX*nbY)+"]"); + // qApp->processEvents(); + + QImage subImage = snapshot.scaled(subSize, Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + + // Copy subImage in image + for (int ii = 0; ii < subSize.width(); ii++) { + int fi = i * subSize.width() + ii; + if (fi == image.width()) + break; + for (int jj = 0; jj < subSize.height(); jj++) { + int fj = j * subSize.height() + jj; + if (fj == image.height()) + break; + image.setPixel(fi, fj, subImage.pixel(ii, jj)); + } + } + count++; + } + + bool saveOK = image.save(fileName, snapshotFormat().toLatin1().constData(), + snapshotQuality()); + + // ProgressDialog::hideProgressDialog(); + // setCursor(QCursor(Qt::ArrowCursor)); + + delete tileRegion_; + tileRegion_ = nullptr; + + if (imageInterface->whiteBackground->isChecked()) + setBackgroundColor(previousBGColor); + + return saveOK; } - /*! Saves a snapshot of the current image displayed by the widget. - Options are set using snapshotFormat(), snapshotFileName() and snapshotQuality(). For non vectorial - image formats, the image size is equal to the current viewer's dimensions (see width() and - height()). See snapshotFormat() for details on supported formats. + Options are set using snapshotFormat(), snapshotFileName() and + snapshotQuality(). For non vectorial image formats, the image size is equal to + the current viewer's dimensions (see width() and height()). See + snapshotFormat() for details on supported formats. - If \p automatic is \c false (or if snapshotFileName() is empty), a file dialog is opened to ask for - the file name. + If \p automatic is \c false (or if snapshotFileName() is empty), a file dialog + is opened to ask for the file name. - When \p automatic is \c true, the file name is set to \c NAME-NUMBER, where \c NAME is - snapshotFileName() and \c NUMBER is snapshotCounter(). The snapshotCounter() is automatically - incremented after each snapshot saving. This is useful to create videos from your application: - \code - void Viewer::init() + When \p automatic is \c true, the file name is set to \c NAME-NUMBER, where \c + NAME is snapshotFileName() and \c NUMBER is snapshotCounter(). The + snapshotCounter() is automatically incremented after each snapshot saving. This + is useful to create videos from your application: \code void Viewer::init() { resize(720, 576); // PAL DV format (use 720x480 for NTSC DV) connect(this, SIGNAL(drawFinished(bool)), SLOT(saveSnapshot(bool))); } \endcode - Then call draw() in a loop (for instance using animate() and/or a camera() KeyFrameInterpolator - replay) to create your image sequence. + Then call draw() in a loop (for instance using animate() and/or a camera() + KeyFrameInterpolator replay) to create your image sequence. - If you want to create a Quicktime VR panoramic sequence, simply use code like this: - \code - void Viewer::createQuicktime() + If you want to create a Quicktime VR panoramic sequence, simply use code like + this: \code void Viewer::createQuicktime() { const int nbImages = 36; for (int i=0; isetOrientation(2.0*M_PI/nbImages, 0.0); // Theta-Phi orientation - showEntireScene(); - update(); // calls draw(), which emits drawFinished(), which calls saveSnapshot() - } + { + camera()->setOrientation(2.0*M_PI/nbImages, 0.0); // Theta-Phi + orientation showEntireScene(); update(); // calls draw(), which emits + drawFinished(), which calls saveSnapshot() + } } \endcode - If snapshotCounter() is negative, no number is appended to snapshotFileName() and the - snapshotCounter() is not incremented. This is useful to force the creation of a file, overwriting - the previous one. - - When \p overwrite is set to \c false (default), a window asks for confirmation if the file already - exists. In \p automatic mode, the snapshotCounter() is incremented (if positive) until a - non-existing file name is found instead. Otherwise the file is overwritten without confirmation. - - The VRender library was written by Cyril Soler (Cyril dot Soler at imag dot fr). If the generated - PS or EPS file is not properly displayed, remove the anti-aliasing option in your postscript viewer. - - \note In order to correctly grab the frame buffer, the QGLViewer window is raised in front of - other windows by this method. */ -void QGLViewer::saveSnapshot(bool automatic, bool overwrite) -{ - // Ask for file name - if (snapshotFileName().isEmpty() || !automatic) - { - QString fileName; - QString selectedFormat = FDFormatString[snapshotFormat()]; - fileName = QFileDialog::getSaveFileName(this, "Choose a file name to save under", snapshotFileName(), formats, &selectedFormat, - overwrite?QFileDialog::DontConfirmOverwrite:QFlags(0)); - setSnapshotFormat(Qtformat[selectedFormat]); - - if (checkFileName(fileName, this, snapshotFormat())) - setSnapshotFileName(fileName); - else - return; - } - - QFileInfo fileInfo(snapshotFileName()); - - if ((automatic) && (snapshotCounter() >= 0)) - { - // In automatic mode, names have a number appended - const QString baseName = fileInfo.baseName(); - QString count; - count.sprintf("%.04d", snapshotCounter_++); - QString suffix; - suffix = fileInfo.suffix(); - if (suffix.isEmpty()) - suffix = extension[snapshotFormat()]; - fileInfo.setFile(fileInfo.absolutePath()+ '/' + baseName + '-' + count + '.' + suffix); - - if (!overwrite) - while (fileInfo.exists()) - { - count.sprintf("%.04d", snapshotCounter_++); - fileInfo.setFile(fileInfo.absolutePath() + '/' +baseName + '-' + count + '.' + fileInfo.suffix()); - } - } - - bool saveOK; + If snapshotCounter() is negative, no number is appended to snapshotFileName() + and the snapshotCounter() is not incremented. This is useful to force the + creation of a file, overwriting the previous one. + + When \p overwrite is set to \c false (default), a window asks for confirmation + if the file already exists. In \p automatic mode, the snapshotCounter() is + incremented (if positive) until a non-existing file name is found instead. + Otherwise the file is overwritten without confirmation. + + The VRender library was written by Cyril Soler (Cyril dot Soler at imag dot + fr). If the generated PS or EPS file is not properly displayed, remove the + anti-aliasing option in your postscript viewer. + + \note In order to correctly grab the frame buffer, the QGLViewer window is + raised in front of other windows by this method. */ +void QGLViewer::saveSnapshot(bool automatic, bool overwrite) { + // Ask for file name + if (snapshotFileName().isEmpty() || !automatic) { + QString fileName; + QString selectedFormat = FDFormatString[snapshotFormat()]; + fileName = QFileDialog::getSaveFileName( + this, "Choose a file name to save under", snapshotFileName(), formats, + &selectedFormat, + overwrite ? QFileDialog::DontConfirmOverwrite + : QFlags(0)); + setSnapshotFormat(Qtformat[selectedFormat]); + + if (checkFileName(fileName, this, snapshotFormat())) + setSnapshotFileName(fileName); + else + return; + } + + QFileInfo fileInfo(snapshotFileName()); + + if ((automatic) && (snapshotCounter() >= 0)) { + // In automatic mode, names have a number appended + const QString baseName = fileInfo.baseName(); + QString count = QString("%1").arg(snapshotCounter_++, 4, 10, QChar('0')); + QString suffix; + suffix = fileInfo.suffix(); + if (suffix.isEmpty()) + suffix = extension[snapshotFormat()]; + fileInfo.setFile(fileInfo.absolutePath() + '/' + baseName + '-' + count + + '.' + suffix); + + if (!overwrite) + while (fileInfo.exists()) { + count = QString("%1").arg(snapshotCounter_++, 4, 10, QChar('0')); + fileInfo.setFile(fileInfo.absolutePath() + '/' + baseName + '-' + + count + '.' + fileInfo.suffix()); + } + } + + bool saveOK; #ifndef NO_VECTORIAL_RENDER - if ( (snapshotFormat() == "EPS") || (snapshotFormat() == "PS") || (snapshotFormat() == "XFIG") ) - // Vectorial snapshot. -1 means cancel, 0 is ok, >0 (should be) an error - saveOK = (saveVectorialSnapshot(fileInfo.filePath(), this, snapshotFormat()) <= 0); - else + if ((snapshotFormat() == "EPS") || (snapshotFormat() == "PS") || + (snapshotFormat() == "XFIG")) + // Vectorial snapshot. -1 means cancel, 0 is ok, >0 (should be) an error + saveOK = (saveVectorialSnapshot(fileInfo.filePath(), this, + snapshotFormat()) <= 0); + else #endif - if (automatic) - { - QImage snapshot = frameBufferSnapshot(); - saveOK = snapshot.save(fileInfo.filePath(), snapshotFormat().toLatin1().constData(), snapshotQuality()); - } - else - saveOK = saveImageSnapshot(fileInfo.filePath()); - - if (!saveOK) - QMessageBox::warning(this, "Snapshot problem", "Unable to save snapshot in\n"+fileInfo.filePath()); + if (automatic) { + QImage snapshot = frameBufferSnapshot(); + saveOK = snapshot.save(fileInfo.filePath(), + snapshotFormat().toLatin1().constData(), + snapshotQuality()); + } else + saveOK = saveImageSnapshot(fileInfo.filePath()); + + if (!saveOK) + QMessageBox::warning(this, "Snapshot problem", + "Unable to save snapshot in\n" + fileInfo.filePath()); } -QImage QGLViewer::frameBufferSnapshot() -{ - // Viewer must be on top of other windows. - makeCurrent(); - raise(); - // Hack: Qt has problems if the frame buffer is grabbed after QFileDialog is displayed. - // We grab the frame buffer before, even if it might be not necessary (vectorial rendering). - // The problem could not be reproduced on a simple example to submit a Qt bug. - // However, only grabs the backgroundImage in the eponym example. May come from the driver. - return grabFrameBuffer(true); +QImage QGLViewer::frameBufferSnapshot() { + // Viewer must be on top of other windows. + makeCurrent(); + raise(); + // Hack: Qt has problems if the frame buffer is grabbed after QFileDialog is + // displayed. We grab the frame buffer before, even if it might be not + // necessary (vectorial rendering). The problem could not be reproduced on a + // simple example to submit a Qt bug. However, only grabs the backgroundImage + // in the eponym example. May come from the driver. + return QOpenGLWidget::grabFramebuffer(); } -/*! Same as saveSnapshot(), except that it uses \p fileName instead of snapshotFileName(). +/*! Same as saveSnapshot(), except that it uses \p fileName instead of + snapshotFileName(). If \p fileName is empty, opens a file dialog to select the name. Snapshot settings are set from snapshotFormat() and snapshotQuality(). - Asks for confirmation when \p fileName already exists and \p overwrite is \c false (default). - - \attention If \p fileName is a char* (as is "myFile.jpg"), it may be casted into a \c bool, and the - other saveSnapshot() method may be used instead. Pass QString("myFile.jpg") as a parameter to - prevent this. */ -void QGLViewer::saveSnapshot(const QString& fileName, bool overwrite) -{ - const QString previousName = snapshotFileName(); - const int previousCounter = snapshotCounter(); - setSnapshotFileName(fileName); - setSnapshotCounter(-1); - saveSnapshot(true, overwrite); - setSnapshotFileName(previousName); - setSnapshotCounter(previousCounter); + Asks for confirmation when \p fileName already exists and \p overwrite is \c + false (default). + + \attention If \p fileName is a char* (as is "myFile.jpg"), it may be casted + into a \c bool, and the other saveSnapshot() method may be used instead. Pass + QString("myFile.jpg") as a parameter to prevent this. */ +void QGLViewer::saveSnapshot(const QString &fileName, bool overwrite) { + const QString previousName = snapshotFileName(); + const int previousCounter = snapshotCounter(); + setSnapshotFileName(fileName); + setSnapshotCounter(-1); + saveSnapshot(true, overwrite); + setSnapshotFileName(previousName); + setSnapshotCounter(previousCounter); } /*! Takes a snapshot of the current display and pastes it to the clipboard. -This action is activated by the KeyboardAction::SNAPSHOT_TO_CLIPBOARD enum, binded to \c Ctrl+C by default. +This action is activated by the KeyboardAction::SNAPSHOT_TO_CLIPBOARD enum, +binded to \c Ctrl+C by default. */ -void QGLViewer::snapshotToClipboard() -{ - QClipboard *cb = QApplication::clipboard(); - cb->setImage(frameBufferSnapshot()); +void QGLViewer::snapshotToClipboard() { + QClipboard *cb = QApplication::clipboard(); + cb->setImage(frameBufferSnapshot()); } - diff --git a/octovis/src/extern/QGLViewer/vec.cpp b/octovis/src/extern/QGLViewer/vec.cpp index 669d6f71..f1fbfcac 100644 --- a/octovis/src/extern/QGLViewer/vec.cpp +++ b/octovis/src/extern/QGLViewer/vec.cpp @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,86 +19,87 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - -#include "domUtils.h" #include "vec.h" +#include "domUtils.h" // Most of the methods are declared inline in vec.h using namespace qglviewer; using namespace std; -/*! Projects the Vec on the axis of direction \p direction that passes through the origin. +/*! Projects the Vec on the axis of direction \p direction that passes through +the origin. \p direction does not need to be normalized (but must be non null). */ -void Vec::projectOnAxis(const Vec& direction) -{ +void Vec::projectOnAxis(const Vec &direction) { #ifndef QT_NO_DEBUG - if (direction.squaredNorm() < 1.0E-10) - qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).", direction.norm()); + if (direction.squaredNorm() < 1.0E-10) + qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).", + direction.norm()); #endif - *this = (((*this)*direction) / direction.squaredNorm()) * direction; + *this = (((*this) * direction) / direction.squaredNorm()) * direction; } -/*! Projects the Vec on the plane whose normal is \p normal that passes through the origin. +/*! Projects the Vec on the plane whose normal is \p normal that passes through +the origin. \p normal does not need to be normalized (but must be non null). */ -void Vec::projectOnPlane(const Vec& normal) -{ +void Vec::projectOnPlane(const Vec &normal) { #ifndef QT_NO_DEBUG - if (normal.squaredNorm() < 1.0E-10) - qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).", normal.norm()); + if (normal.squaredNorm() < 1.0E-10) + qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).", + normal.norm()); #endif - *this -= (((*this)*normal) / normal.squaredNorm()) * normal; + *this -= (((*this) * normal) / normal.squaredNorm()) * normal; } -/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is zero only for a - null Vec. Note that the function that associates an orthogonalVec() to a Vec is not continous. */ -Vec Vec::orthogonalVec() const -{ - // Find smallest component. Keep equal case for null values. - if ((fabs(y) >= 0.9*fabs(x)) && (fabs(z) >= 0.9*fabs(x))) - return Vec(0.0, -z, y); - else - if ((fabs(x) >= 0.9*fabs(y)) && (fabs(z) >= 0.9*fabs(y))) - return Vec(-z, 0.0, x); - else - return Vec(-y, x, 0.0); +/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is + zero only for a null Vec. Note that the function that associates an + orthogonalVec() to a Vec is not continous. */ +Vec Vec::orthogonalVec() const { + // Find smallest component. Keep equal case for null values. + if ((fabs(y) >= 0.9 * fabs(x)) && (fabs(z) >= 0.9 * fabs(x))) + return Vec(0.0, -z, y); + else if ((fabs(x) >= 0.9 * fabs(y)) && (fabs(z) >= 0.9 * fabs(y))) + return Vec(-z, 0.0, x); + else + return Vec(-y, x, 0.0); } /*! Constructs a Vec from a \c QDomElement representing an XML code of the form \code< anyTagName x=".." y=".." z=".." />\endcode -If one of these attributes is missing or is not a number, a warning is displayed and the associated -value is set to 0.0. +If one of these attributes is missing or is not a number, a warning is displayed +and the associated value is set to 0.0. See also domElement() and initFromDOMElement(). */ -Vec::Vec(const QDomElement& element) -{ - QStringList attribute; - attribute << "x" << "y" << "z"; - for (int i=0; ioperator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0); + this->operator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0); #else - v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0); + v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0); #endif } /*! Returns an XML \c QDomElement that represents the Vec. - \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument factory used to create - QDomElement. + \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument + factory used to create QDomElement. When output to a file, the resulting QDomElement will look like: \code \endcode - Use initFromDOMElement() to restore the Vec state from the resulting \c QDomElement. See also the - Vec(const QDomElement&) constructor. + Use initFromDOMElement() to restore the Vec state from the resulting \c + QDomElement. See also the Vec(const QDomElement&) constructor. Here is complete example that creates a QDomDocument and saves it into a file: \code @@ -120,20 +121,21 @@ Vec::Vec(const QDomElement& element) } \endcode - See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()... */ -QDomElement Vec::domElement(const QString& name, QDomDocument& document) const -{ - QDomElement de = document.createElement(name); - de.setAttribute("x", QString::number(x)); - de.setAttribute("y", QString::number(y)); - de.setAttribute("z", QString::number(z)); - return de; + See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()... + */ +QDomElement Vec::domElement(const QString &name, QDomDocument &document) const { + QDomElement de = document.createElement(name); + de.setAttribute("x", QString::number(x)); + de.setAttribute("y", QString::number(y)); + de.setAttribute("z", QString::number(z)); + return de; } /*! Restores the Vec state from a \c QDomElement created by domElement(). - The \c QDomElement should contain \c x, \c y and \c z attributes. If one of these attributes is - missing or is not a number, a warning is displayed and the associated value is set to 0.0. + The \c QDomElement should contain \c x, \c y and \c z attributes. If one of + these attributes is missing or is not a number, a warning is displayed and the + associated value is set to 0.0. To restore the Vec state from an xml file, use: \code @@ -151,14 +153,11 @@ QDomElement Vec::domElement(const QString& name, QDomDocument& document) const \endcode See also the Vec(const QDomElement&) constructor. */ -void Vec::initFromDOMElement(const QDomElement& element) -{ - const Vec v(element); - *this = v; +void Vec::initFromDOMElement(const QDomElement &element) { + const Vec v(element); + *this = v; } -ostream& operator<<(ostream& o, const Vec& v) -{ - return o << v.x << '\t' << v.y << '\t' << v.z; +ostream &operator<<(ostream &o, const Vec &v) { + return o << v.x << '\t' << v.y << '\t' << v.z; } - diff --git a/octovis/src/extern/QGLViewer/vec.h b/octovis/src/extern/QGLViewer/vec.h index 429ab62a..221c7d8c 100644 --- a/octovis/src/extern/QGLViewer/vec.h +++ b/octovis/src/extern/QGLViewer/vec.h @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (C) 2002-2014 Gilles Debunne. All rights reserved. + Copyright (C) 2002-2023 Gilles Debunne. All rights reserved. - This file is part of the QGLViewer library version 2.6.3. + This file is part of the QGLViewer library version 2.9.1. http://www.libqglviewer.com - contact@libqglviewer.com @@ -19,14 +19,13 @@ WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ - #ifndef QGLVIEWER_VEC_H #define QGLVIEWER_VEC_H -#include #include +#include -# include +#include // Included by all files as vec.h is at the end of the include hierarchy #include "config.h" // Specific configuration options. @@ -36,8 +35,9 @@ namespace qglviewer { /*! \brief The Vec class represents 3D positions and 3D vectors. \class Vec vec.h QGLViewer/vec.h - Vec is used as a parameter and return type by many methods of the library. It provides classical - algebraic computational methods and is compatible with OpenGL: + Vec is used as a parameter and return type by many methods of the library. It + provides classical algebraic computational methods and is compatible with + OpenGL: \code // Draws a point located at 3.0 OpenGL units in front of the camera @@ -47,344 +47,337 @@ namespace qglviewer { glEnd(); \endcode - This makes of Vec a good candidate for representing positions and vectors in your programs. Since - it is part of the \c qglviewer namespace, specify \c qglviewer::Vec or use the qglviewer - namespace: - \code - using namespace qglviewer; - \endcode + This makes of Vec a good candidate for representing positions and vectors in + your programs. Since it is part of the \c qglviewer namespace, specify \c + qglviewer::Vec or use the qglviewer namespace: \code using namespace + qglviewer; \endcode

Interface with other vector classes

Vec implements a universal explicit converter, based on the \c [] \c operator. - Everywhere a \c const \c Vec& argument is expected, you can use your own vector type - instead, as long as it implements this operator (see the Vec(const C& c) documentation). + Everywhere a \c const \c Vec& argument is expected, you can use your own + vector type instead, as long as it implements this operator (see the Vec(const + C& c) documentation). See also the Quaternion and the Frame documentations. \nosubgrouping */ -class QGLVIEWER_EXPORT Vec -{ +class QGLVIEWER_EXPORT Vec { - // If your compiler complains the "The class "qglviewer::Vec" has no member "x"." - // Add your architecture Q_OS_XXXX flag (see qglobal.h) in this list. -#if defined (Q_OS_IRIX) || defined (Q_OS_AIX) || defined (Q_OS_HPUX) -# define QGLVIEWER_UNION_NOT_SUPPORTED +// If your compiler complains the "The class "qglviewer::Vec" has no member +// "x"." Add your architecture Q_OS_XXXX flag (see qglobal.h) in this list. +#if defined(Q_OS_IRIX) || defined(Q_OS_AIX) || defined(Q_OS_HPUX) +#define QGLVIEWER_UNION_NOT_SUPPORTED #endif public: - /*! The internal data representation is public. One can use v.x, v.y, v.z. See also operator[](). */ -#if defined (DOXYGEN) || defined (QGLVIEWER_UNION_NOT_SUPPORTED) - qreal x, y, z; +/*! The internal data representation is public. One can use v.x, v.y, v.z. See + * also operator[](). */ +#if defined(DOXYGEN) || defined(QGLVIEWER_UNION_NOT_SUPPORTED) + qreal x, y, z; #else - union - { - struct { qreal x, y, z; }; - qreal v_[3]; - }; + union { + struct { + qreal x, y, z; + }; + qreal v_[3]; + }; #endif - /*! @name Setting the value */ - //@{ - /*! Default constructor. Value is set to (0,0,0). */ - Vec() : x(0.0), y(0.0), z(0.0) {} + /*! @name Setting the value */ + //@{ + /*! Default constructor. Value is set to (0,0,0). */ + Vec() : x(0.0), y(0.0), z(0.0) {} - /*! Standard constructor with the x, y and z values. */ - Vec(qreal X, qreal Y, qreal Z) : x(X), y(Y), z(Z) {} + /*! Standard constructor with the x, y and z values. */ + Vec(qreal X, qreal Y, qreal Z) : x(X), y(Y), z(Z) {} - /*! Universal explicit converter from any class to Vec. You can use your own vector class everywhere - a \c const \c Vec& parameter is required, as long as it implements the \c operator[ ]: + /*! Universal explicit converter from any class to Vec. You can use your own +vector class everywhere a \c const \c Vec& parameter is required, as long as it +implements the \c operator[ ]: - \code - class MyVec - { - // ... - qreal operator[](int i) const { returns x, y or z when i=0, 1 or 2; } +\code +class MyVec +{ + // ... + qreal operator[](int i) const { returns x, y or z when i=0, 1 or 2; } +} + +MyVec v(...); +camera()->setPosition(v); +\endcode + +Note that standard vector types (STL, \c qreal[3], ...) implement this operator +and can hence be used in place of Vec. See also operator const qreal*() .*/ + template explicit Vec(const C &c) : x(c[0]), y(c[1]), z(c[2]) {} + // Should NOT be explicit to prevent conflicts with operator<<. + + // ! Copy constructor + // Vec(const Vec& v) : x(v.x), y(v.y), z(v.z) {} + + /*! Equal operator. + Vec &operator=(const Vec &v) { + x = v.x; + y = v.y; + z = v.z; + return *this; + } + */ + + /*! Set the current value. May be faster than using operator=() with a + * temporary Vec(x,y,z). */ + void setValue(qreal X, qreal Y, qreal Z) { + x = X; + y = Y; + z = Z; } - MyVec v(...); - camera()->setPosition(v); - \endcode - - Note that standard vector types (STL, \c qreal[3], ...) implement this operator and can hence - be used in place of Vec. See also operator const qreal*() .*/ - template - explicit Vec(const C& c) : x(c[0]), y(c[1]), z(c[2]) {} - // Should NOT be explicit to prevent conflicts with operator<<. - - // ! Copy constructor - // Vec(const Vec& v) : x(v.x), y(v.y), z(v.z) {} - - /*! Equal operator. */ - Vec& operator=(const Vec& v) - { - x = v.x; y = v.y; z = v.z; - return *this; - } - - /*! Set the current value. May be faster than using operator=() with a temporary Vec(x,y,z). */ - void setValue(qreal X, qreal Y, qreal Z) - { x=X; y=Y; z=Z; } - - // Universal equal operator which allows the use of any type in place of Vec, - // as long as the [] operator is implemented (v[0]=v.x, v[1]=v.y, v[2]=v.z). - // template - // Vec& operator=(const C& c) - // { - // x=c[0]; y=c[1]; z=c[2]; - // return *this; - // } - //@} - - /*! @name Accessing the value */ - //@{ - /*! Bracket operator, with a constant return value. \p i must range in [0..2]. */ - qreal operator[](int i) const { + // Universal equal operator which allows the use of any type in place of Vec, + // as long as the [] operator is implemented (v[0]=v.x, v[1]=v.y, v[2]=v.z). + // template + // Vec& operator=(const C& c) + // { + // x=c[0]; y=c[1]; z=c[2]; + // return *this; + // } + //@} + + /*! @name Accessing the value */ + //@{ + /*! Bracket operator, with a constant return value. \p i must range in [0..2]. + */ + qreal operator[](int i) const { #ifdef QGLVIEWER_UNION_NOT_SUPPORTED - return (&x)[i]; + return (&x)[i]; #else - return v_[i]; + return v_[i]; #endif - } + } - /*! Bracket operator returning an l-value. \p i must range in [0..2]. */ - qreal& operator[](int i) { + /*! Bracket operator returning an l-value. \p i must range in [0..2]. */ + qreal &operator[](int i) { #ifdef QGLVIEWER_UNION_NOT_SUPPORTED - return (&x)[i]; + return (&x)[i]; #else - return v_[i]; + return v_[i]; #endif - } + } #ifndef DOXYGEN - /*! This method is deprecated since version 2.0. Use operator const double* instead. */ - const double* address() const { qWarning("Vec::address() is deprecated, use operator const double* instead."); return operator const double*(); } + /*! This method is deprecated since version 2.0. Use operator const qreal* + * instead. */ + const qreal *address() const { + qWarning( + "Vec::address() is deprecated, use operator const qreal* instead."); + return operator const qreal *(); + } #endif - /*! Conversion operator returning the memory address of the vector. + /*! Conversion operator returning the memory address of the vector. - Very convenient to pass a Vec pointer as a parameter to \c GLdouble OpenGL functions: - \code - Vec pos, normal; - glNormal3dv(normal); - glVertex3dv(pos); - \endcode */ - operator const double*() const { +Very convenient to pass a Vec pointer as a parameter to \c GLdouble OpenGL +functions: \code Vec pos, normal; glNormal3dv(normal); glVertex3dv(pos); +\endcode */ + operator const qreal *() const { #ifdef QGLVIEWER_UNION_NOT_SUPPORTED - return &x; + return &x; #else - return v_; + return v_; #endif - } + } - /*! Non const conversion operator returning the memory address of the vector. + /*! Non const conversion operator returning the memory address of the vector. - Useful to pass a Vec to a method that requires and fills a \c double*, as provided by certain libraries. */ - operator double*() { +Useful to pass a Vec to a method that requires and fills a \c qreal*, as +provided by certain libraries. */ + operator qreal *() { #ifdef QGLVIEWER_UNION_NOT_SUPPORTED - return &x; + return &x; #else - return v_; + return v_; #endif - } + } - /*! Conversion operator returning the memory address of the vector. + /*! Conversion operator returning the memory address of the vector. + +Very convenient to pass a Vec pointer as a \c float parameter to OpenGL +functions: \code Vec pos, normal; glNormal3fv(normal); glVertex3fv(pos); +\endcode +\note The returned float array is a static shared by all \c Vec instances. */ + operator const float *() const { + static float *const result = new float[3]; + result[0] = (float)x; + result[1] = (float)y; + result[2] = (float)z; + return result; + } + //@} - Very convenient to pass a Vec pointer as a \c float parameter to OpenGL functions: - \code - Vec pos, normal; - glNormal3fv(normal); - glVertex3fv(pos); - \endcode - \note The returned float array is a static shared by all \c Vec instances. */ - operator const float*() const { - static float* const result = new float[3]; - result[0] = (float)x; - result[1] = (float)y; - result[2] = (float)z; - return result; - } - //@} - - /*! @name Algebraic computations */ - //@{ - /*! Returns the sum of the two vectors. */ - friend Vec operator+(const Vec &a, const Vec &b) - { - return Vec(a.x+b.x, a.y+b.y, a.z+b.z); - } - - /*! Returns the difference of the two vectors. */ - friend Vec operator-(const Vec &a, const Vec &b) - { - return Vec(a.x-b.x, a.y-b.y, a.z-b.z); - } - - /*! Unary minus operator. */ - friend Vec operator-(const Vec &a) - { - return Vec(-a.x, -a.y, -a.z); - } - - /*! Returns the product of the vector with a scalar. */ - friend Vec operator*(const Vec &a, qreal k) - { - return Vec(a.x*k, a.y*k, a.z*k); - } - - /*! Returns the product of a scalar with the vector. */ - friend Vec operator*(qreal k, const Vec &a) - { - return a*k; - } - - /*! Returns the division of the vector with a scalar. - - Too small \p k values are \e not tested (unless the library was compiled with the "debug" Qt \c - CONFIG flag) and may result in \c NaN values. */ - friend Vec operator/(const Vec &a, qreal k) - { + /*! @name Algebraic computations */ + //@{ + /*! Returns the sum of the two vectors. */ + friend Vec operator+(const Vec &a, const Vec &b) { + return Vec(a.x + b.x, a.y + b.y, a.z + b.z); + } + + /*! Returns the difference of the two vectors. */ + friend Vec operator-(const Vec &a, const Vec &b) { + return Vec(a.x - b.x, a.y - b.y, a.z - b.z); + } + + /*! Unary minus operator. */ + friend Vec operator-(const Vec &a) { return Vec(-a.x, -a.y, -a.z); } + + /*! Returns the product of the vector with a scalar. */ + friend Vec operator*(const Vec &a, qreal k) { + return Vec(a.x * k, a.y * k, a.z * k); + } + + /*! Returns the product of a scalar with the vector. */ + friend Vec operator*(qreal k, const Vec &a) { return a * k; } + + /*! Returns the division of the vector with a scalar. + +Too small \p k values are \e not tested (unless the library was compiled with +the "debug" Qt \c CONFIG flag) and may result in \c NaN values. */ + friend Vec operator/(const Vec &a, qreal k) { #ifndef QT_NO_DEBUG - if (fabs(k) < 1.0E-10) - qWarning("Vec::operator / : dividing by a null value (%f)", k); + if (fabs(k) < 1.0E-10) + qWarning("Vec::operator / : dividing by a null value (%f)", k); #endif - return Vec(a.x/k, a.y/k, a.z/k); - } - - /*! Returns \c true only when the two vector are not equal (see operator==()). */ - friend bool operator!=(const Vec &a, const Vec &b) - { - return !(a==b); - } - - /*! Returns \c true when the squaredNorm() of the difference vector is lower than 1E-10. */ - friend bool operator==(const Vec &a, const Vec &b) - { - const qreal epsilon = 1.0E-10; - return (a-b).squaredNorm() < epsilon; - } - - /*! Adds \p a to the vector. */ - Vec& operator+=(const Vec &a) - { - x += a.x; y += a.y; z += a.z; - return *this; - } - - /*! Subtracts \p a to the vector. */ - Vec& operator-=(const Vec &a) - { - x -= a.x; y -= a.y; z -= a.z; - return *this; - } - - /*! Multiply the vector by a scalar \p k. */ - Vec& operator*=(qreal k) - { - x *= k; y *= k; z *= k; - return *this; - } - - /*! Divides the vector by a scalar \p k. - - An absolute \p k value lower than 1E-10 will print a warning if the library was compiled with the - "debug" Qt \c CONFIG flag. Otherwise, no test is performed for efficiency reasons. */ - Vec& operator/=(qreal k) - { + return Vec(a.x / k, a.y / k, a.z / k); + } + + /*! Returns \c true only when the two vector are not equal (see operator==()). + */ + friend bool operator!=(const Vec &a, const Vec &b) { return !(a == b); } + + /*! Returns \c true when the squaredNorm() of the difference vector is lower + * than 1E-10. */ + friend bool operator==(const Vec &a, const Vec &b) { + const qreal epsilon = 1.0E-10; + return (a - b).squaredNorm() < epsilon; + } + + /*! Adds \p a to the vector. */ + Vec &operator+=(const Vec &a) { + x += a.x; + y += a.y; + z += a.z; + return *this; + } + + /*! Subtracts \p a to the vector. */ + Vec &operator-=(const Vec &a) { + x -= a.x; + y -= a.y; + z -= a.z; + return *this; + } + + /*! Multiply the vector by a scalar \p k. */ + Vec &operator*=(qreal k) { + x *= k; + y *= k; + z *= k; + return *this; + } + + /*! Divides the vector by a scalar \p k. + +An absolute \p k value lower than 1E-10 will print a warning if the library was +compiled with the "debug" Qt \c CONFIG flag. Otherwise, no test is performed for +efficiency reasons. */ + Vec &operator/=(qreal k) { #ifndef QT_NO_DEBUG - if (fabs(k)<1.0E-10) - qWarning("Vec::operator /= : dividing by a null value (%f)", k); + if (fabs(k) < 1.0E-10) + qWarning("Vec::operator /= : dividing by a null value (%f)", k); #endif - x /= k; y /= k; z /= k; - return *this; - } - - /*! Dot product of the two Vec. */ - friend qreal operator*(const Vec &a, const Vec &b) - { - return a.x*b.x + a.y*b.y + a.z*b.z; - } - - /*! Cross product of the two vectors. Same as cross(). */ - friend Vec operator^(const Vec &a, const Vec &b) - { - return cross(a,b); - } - - /*! Cross product of the two Vec. Mind the order ! */ - friend Vec cross(const Vec &a, const Vec &b) - { - return Vec(a.y*b.z - a.z*b.y, - a.z*b.x - a.x*b.z, - a.x*b.y - a.y*b.x); - } - - Vec orthogonalVec() const; - //@} - - /*! @name Norm of the vector */ - //@{ + x /= k; + y /= k; + z /= k; + return *this; + } + + /*! Dot product of the two Vec. */ + friend qreal operator*(const Vec &a, const Vec &b) { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + + /*! Cross product of the two vectors. Same as cross(). */ + friend Vec operator^(const Vec &a, const Vec &b) { return cross(a, b); } + + /*! Cross product of the two Vec. Mind the order ! */ + friend Vec cross(const Vec &a, const Vec &b) { + return Vec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, + a.x * b.y - a.y * b.x); + } + + Vec orthogonalVec() const; +//@} + +/*! @name Norm of the vector */ +//@{ #ifndef DOXYGEN - /*! This method is deprecated since version 2.0. Use squaredNorm() instead. */ - qreal sqNorm() const { return x*x + y*y + z*z; } + /*! This method is deprecated since version 2.0. Use squaredNorm() instead. */ + qreal sqNorm() const { return x * x + y * y + z * z; } #endif - /*! Returns the \e squared norm of the Vec. */ - qreal squaredNorm() const { return x*x + y*y + z*z; } + /*! Returns the \e squared norm of the Vec. */ + qreal squaredNorm() const { return x * x + y * y + z * z; } - /*! Returns the norm of the vector. */ - qreal norm() const { return sqrt(x*x + y*y + z*z); } + /*! Returns the norm of the vector. */ + qreal norm() const { return sqrt(x * x + y * y + z * z); } - /*! Normalizes the Vec and returns its original norm. + /*! Normalizes the Vec and returns its original norm. - Normalizing a null vector will result in \c NaN values. */ - qreal normalize() - { - const qreal n = norm(); +Normalizing a null vector will result in \c NaN values. */ + qreal normalize() { + const qreal n = norm(); #ifndef QT_NO_DEBUG - if (n < 1.0E-10) - qWarning("Vec::normalize: normalizing a null vector (norm=%f)", n); + if (n < 1.0E-10) + qWarning("Vec::normalize: normalizing a null vector (norm=%f)", n); #endif - *this /= n; - return n; - } - - /*! Returns a unitary (normalized) \e representation of the vector. The original Vec is not modified. */ - Vec unit() const - { - Vec v = *this; - v.normalize(); - return v; - } - //@} - - /*! @name Projection */ - //@{ - void projectOnAxis(const Vec& direction); - void projectOnPlane(const Vec& normal); - //@} - - /*! @name XML representation */ - //@{ - explicit Vec(const QDomElement& element); - QDomElement domElement(const QString& name, QDomDocument& document) const; - void initFromDOMElement(const QDomElement& element); - //@} + *this /= n; + return n; + } + + /*! Returns a unitary (normalized) \e representation of the vector. The + * original Vec is not modified. */ + Vec unit() const { + Vec v = *this; + v.normalize(); + return v; + } + //@} + + /*! @name Projection */ + //@{ + void projectOnAxis(const Vec &direction); + void projectOnPlane(const Vec &normal); + //@} + + /*! @name XML representation */ + //@{ + explicit Vec(const QDomElement &element); + QDomElement domElement(const QString &name, QDomDocument &document) const; + void initFromDOMElement(const QDomElement &element); +//@} #ifdef DOXYGEN - /*! @name Output stream */ - //@{ - /*! Output stream operator. Enables debugging code like: - \code - Vec pos(...); - cout << "Position=" << pos << endl; - \endcode */ - std::ostream& operator<<(std::ostream& o, const qglviewer::Vec&); - //@} + /*! @name Output stream */ + //@{ + /*! Output stream operator. Enables debugging code like: +\code +Vec pos(...); +cout << "Position=" << pos << endl; +\endcode */ + std::ostream &operator<<(std::ostream &o, const qglviewer::Vec &); +//@} #endif }; -} // namespace +} // namespace qglviewer -std::ostream& operator<<(std::ostream& o, const qglviewer::Vec&); +std::ostream &operator<<(std::ostream &o, const qglviewer::Vec &); #endif // QGLVIEWER_VEC_H diff --git a/scripts/increase_version.py b/scripts/increase_version.py index 472bf214..53757636 100755 --- a/scripts/increase_version.py +++ b/scripts/increase_version.py @@ -6,108 +6,124 @@ # # Borrows heaviliy from ROS / catkin release tools - +import argparse import re import sys -import copy - -manifest_match = "(\d+)\.(\d+)\.(\d+)" - - -if __name__ == '__main__': - bump = "patch" - if len(sys.argv) > 1: - bump = sys.argv[1] - if bump not in {"major","minor","patch"}: - print sys.argv[0]+" [major|minor|patch] (default: patch)" - exit(-1) - - - - manifests=["octomap/package.xml","octovis/package.xml","dynamicEDT3D/package.xml"] - cmakelists=["octomap/CMakeLists.txt","octovis/CMakeLists.txt","dynamicEDT3D/CMakeLists.txt"] - versions = [] - - # find versions in package.xml - for manifest in manifests: - with open(manifest, 'r') as f: - package_str = f.read() - match = re.search(manifest_match, package_str) - if match is None: - print "Error: no version tag found in %s" % manifest - exit(-1) - else: - v= match.groups() - v = [int(x) for x in v] - versions.append(v) - - # find version in CMakeLists: - for cmake in cmakelists: - with open(cmake, 'r') as f: - cmake_str = f.read() - v = [] - for m in ["MAJOR","MINOR","PATCH"]: - searchstr = "_%s_VERSION (\d+)\)" % m - match = re.search(searchstr, cmake_str) - if match is None: - print "Error: no version tag %s found in %s" % (searchstr,cmake) - exit(-1) - - v.append(int(match.group(1))) - - versions.append(v) - - new_version = copy.deepcopy(versions[0]) - for v in versions: - if v != versions[0]: - print "Error: check current versions, mismatch: %d.%d.%d vs. %d.%d.%d" %(tuple(v)+tuple(versions[0])) - exit(-1) - - print "OctoMap component versions found: %d.%d.%d" % tuple(versions[0]) - # "bump version" from catkin: - # find the desired index - idx = dict(major=0, minor=1, patch=2)[bump] - # increment the desired part - new_version[idx] += 1 - # reset all parts behind the bumped part - new_version = new_version[:idx + 1] + [0 for x in new_version[idx + 1:]] - new_version_str = "%d.%d.%d" % tuple(new_version) - print 'Updating to new version: %s\n' % new_version_str - - # adjust CMakeLists - for cmake in cmakelists: - with open(cmake, 'r') as f: - cmake_str = f.read() - idx = dict(MAJOR=0, MINOR=1, PATCH=2) - for m in ["MAJOR","MINOR","PATCH"]: - old_str = "_%s_VERSION %d)" % (m,versions[0][idx[m]]) - new_str = "_%s_VERSION %d)" % (m,new_version[idx[m]]) - cmake_str = cmake_str.replace(old_str, new_str) - - with open(cmake, 'w') as f: - f.write(cmake_str) - - - - # adjust package.xml - for manifest in manifests: - with open(manifest, 'r') as f: - package_str = f.read() - old_str = "%d.%d.%d" % tuple(versions[0]) - new_str = "%s" % new_version_str - new_package_str = package_str.replace(old_str, new_str) - - with open(manifest, 'w') as f: - f.write(new_package_str) - - print "Finished writing package.xml and CMakeLists.txt files.\n" - print "Now check the output, adjust CHANGELOG, and \"git commit\".\nFinally, run:" - print " git checkout master && git merge --no-ff devel && git tag v%s" % new_version_str - print " git push origin master devel && git push --tags" - print "\n(adjust when not on the \"devel\" branch)\n" - - - - - - \ No newline at end of file +from pathlib import Path + +SUBPROJECTS = ["octomap", "octovis", "dynamicEDT3D"] +DEFAULT_ROOTDIR = Path(__file__).parent.parent + +parser = argparse.ArgumentParser() +parser.add_argument( + "--rootdir", + metavar="DIR", + type=Path, + default=DEFAULT_ROOTDIR, + help=f"Octomap source tree (default: {DEFAULT_ROOTDIR})", +) +m = parser.add_mutually_exclusive_group() +m.add_argument( + "--bump", + choices=["major", "minor", "patch"], + default="patch", + help="Which part of the version number to bump? (default: patch)", +) +m.add_argument( + "--version", metavar="MAJOR.MINOR.PATCH", help="Set a specific version to use" +) + +args = parser.parse_args() + +MANIFESTS = [args.rootdir / p / "package.xml" for p in SUBPROJECTS] +CMAKELISTS = [args.rootdir / p / "CMakeLists.txt" for p in SUBPROJECTS] + [ + args.rootdir / "CMakeLists.txt" +] + +missing_files = [str(f) for f in MANIFESTS + CMAKELISTS if not f.is_file()] +if missing_files: + sys.stderr.write(f"Missing files:\n* {'\n* '.join(missing_files)}\n") + sys.exit(1) + +if args.version is None: + # Verify that all versions are consistent before bumping + versions = set() + for manifest in MANIFESTS: + with open(manifest, "r") as f: + content = f.read() + mo = re.search(r"(\d)+\.(\d+)\.(\d+)", content) + if not mo: + sys.stderr.write(f"Cannot find tag in {manifest}\n") + sys.exit(1) + versions.add((int(mo.group(1)), int(mo.group(2)), int(mo.group(3)))) + for cmakelist in CMAKELISTS: + with open(cmakelist, "r") as f: + content = f.read() + mo = re.search(r"project\s*\([^)]+VERSION\s+(\d)+\.(\d+)\.(\d+)", content) + if not mo: + sys.stderr.write(f"Cannot find project VERSION option in {cmakelist}\n") + sys.exit(1) + versions.add((int(mo.group(1)), int(mo.group(2)), int(mo.group(3)))) + if len(versions) != 1: + sys.stderr.write( + f"Cannot bump multiple inconsistent versions: {', '.join('.'.join(str(v) for v in version) for version in sorted(versions))}\n" + ) + version_numbers = [v for v in list(versions)[0]] + if args.bump == "patch": + version_numbers[2] += 1 + if args.bump == "minor": + version_numbers[1] += 1 + version_numbers[2] = 0 + if args.bump == "major": + version_numbers[0] += 1 + version_numbers[1] = 0 + version_numbers[2] = 0 + args.version = ".".join(str(v) for v in version_numbers) +elif not re.match(r"^(\d+)\.(\d+)\.(\d+)$", args.version): + sys.stderr.write(f"Version {args.version!r} is not in MAJOR.MINOR.PATCH format\n") + sys.exit(1) + +anything_changed = False + +for manifest in MANIFESTS: + with open(manifest, "r") as f: + old_content = f.read() + new_content = re.sub( + r"[0-9.]+", f"{args.version}", old_content + ) + if old_content != new_content: + anything_changed = True + sys.stdout.write(f"Updating {manifest} ...\n") + with open(manifest, "w") as f: + f.write(new_content) + +for cmakelist in CMAKELISTS: + with open(cmakelist, "r") as f: + old_content = f.read() + new_content = re.sub( + r"(project\s*\([^)]+)VERSION\s+[0-9.]+", + f"\\1VERSION {args.version}", + old_content, + ) + if old_content != new_content: + anything_changed = True + sys.stdout.write(f"Updating {cmakelist} ...\n") + with open(cmakelist, "w") as f: + f.write(new_content) + +if not anything_changed: + sys.stdout.write("Nothing to update.\n") + sys.exit(0) + +sys.stdout.write( + f"""\n +Finished writing package.xml and CMakeLists.txt files. +Now check the output, adjust CHANGELOG, and "git commit". +Finally, run: + git checkout master && git merge --no-ff devel && git tag v{args.version} + git push origin master devel && git push origin --tags + (adjust if not on the "devel" branch) + +""" +) +sys.exit(0)