rviz-1.12.4/000077500000000000000000000000001300447110700125665ustar00rootroot00000000000000rviz-1.12.4/.gitignore000066400000000000000000000000531300447110700145540ustar00rootroot00000000000000*~ *.pyc bin build lib *.sublime-workspace rviz-1.12.4/CHANGELOG.rst000066400000000000000000000543401300447110700146150ustar00rootroot00000000000000^^^^^^^^^^^^^^^^^^^^^^^^^^ Changelog for package rviz ^^^^^^^^^^^^^^^^^^^^^^^^^^ 1.12.4 (2016-10-27) ------------------- * Restored "Use ``urdf::*ShredPtr`` instead of ``boost::shared_ptr``" (`#1064 `_) Now supports ``urdfdom`` 0.3 and 0.4 through a compatibility header in ``urdf``. * You can now visualize joint axis and display type and limits (`#1029 `_) * Contributors: Lucas Walter, Robert Haschke, William Woodall 1.12.3 (2016-10-19) ------------------- * Revert "Use ``urdf::*ShredPtr`` instead of ``boost::shared_ptr``" (`#1060 `_) * Contributors: William Woodall 1.12.2 (2016-10-18) ------------------- * Paths can now be rendered as 3D arrows or pose markers (`#1059 `_) * Allow float edits to work with different Locales (`#1043 `_) * Now check for a valid root link before walking the robot model (`#1041 `_) * Added close() signal to Tool class (`#1051 `_) * Fix double free in display dialog (`#1053 `_) * Tweak focal shape size marker depending on focal distance (`#1021 `_) * Support 3D arrows and axes for visualizing PoseArrays (`#1022 `_) * Use ``urdf::*ShredPtr`` instead of ``boost::shared_ptr`` (`#1044 `_) * Fixed two valgrind-reported issues (`#1027 `_) * in ~RenderPanel() * in VisualizationManager(): initialization order * Added option to disable the RViz splash-screen (`#1024 `_) * Fix compile error due to the user-defined string literals feature (`#1010 `_) * Fixed some Qt5 related build issues (`#1008 `_) * Removed dependency on OpenCV (`#1009 `_) * Contributors: 1r0b1n0, Atsushi Watanabe, Blake Anderson, Jochen Sprickerhof, Kartik Mohta, Maarten de Vries, Michael Görner, Robert Haschke, Victor Lamoine, Víctor Mayoral Vilches, William Woodall 1.12.1 (2016-04-20) ------------------- * Updated the ``plugin_description.xml`` to reflect the new default plugin library name, see: `#1004 `_ * Contributors: William Woodall 1.12.0 (2016-04-11) ------------------- * Qt5 is now the default build option, but Qt4 support is still available (for C++ only). * Fixed support for PyQt5, but disabled PySide2 until we get it working. * The default plugin's library was changed to ``rviz_default_plugin``. * Changed to use CMake's ``file(GENERATE ...)`` macro when exporting the default plugin's library name. * Changed costmap lethal color to be different from illegal values. * Cleaned-up and generalized the WrenchVisual display: * renamed ``WrenchStampedVisual`` to ``WrenchVisual`` * cleanup: removed deprecated API * Updated the marker display and tf plugins to update the map of enabled namespaces and frames whenever those frames are enabled/disabled using the check boxes. Also updated the plugins so that the map of enabled namespaces and frames does not get erased whenever the plugin is reset. (`#988 `_) This allows the currently selected namespaces/frames to remain selected after the Reset button is pressed. * Contributors: Brett, Robert Haschke, William Woodall 1.11.14 (2016-04-03) -------------------- * Added the ``rviz_QT_VERSION`` cmake variable that exports the Qt version used by rviz. * Changed the way ``rviz_DEFAULT_PLUGIN_LIBRARIES`` is set so it works with ``catkin_make`` too. * Contributors: William Woodall 1.11.13 (2016-03-23) -------------------- * Changed the way the rviz_DEFAULT_PLUGIN_LIBRARIES are generated to support cmake < 2.8.12. See pull request: `#981 `_ * Contributors: William Woodall 1.11.12 (2016-03-22) -------------------- * Relaxed the required CMake version to 2.8.11.2 in order to support Ubuntu Saucy. * Contributors: William Woodall 1.11.11 (2016-03-22) -------------------- * Added Qt version to rosout and help->about. * Added optional support for Qt5 with continued support for Qt4. * Fixed a C++11 warning about literals needing a space after them. * Added a "duplicate" button for duplicating displays. * Fixed remove display so that it selects another display after removing one (if one is available). * Fix for `#959 `_: jumping marker in MOVE_3D mode See pull request: `#961 `_ * Added a raw mode for map vizualization. See pull request: `#972 `_ * Added an option in many of the topic based Displays to prefer UDP/unreliable transport. See pull request: `#976 `_ * Fixed the marker display to allow namespaces to be enabled/disabled based on the loaded config. Also enabled state is stored for each namespace in a map, which is used to lookup the state whenever a namespace is added to the display. See pull request: `#962 `_ * Fixed crash in ``Display::deleteStatus()`` when no statuses where created beforehand. See pull request: `#960 `_ * Read-only properties are now no longer editable. See pull request: `#958 `_ * The binary STL loading logic has been relaxed to support files that contain more data than expected. A warning is printed instead of failing with an error now. See pull request: `#951 `_ * Fixed an issue where tf configurations were not saved and reloaded from the rviz config file. See pull request: `#946 `_ * Anti-Aliasing (AA) is now enabled by default, but it can be disabled with ``--disable-anti-aliasing``. See pull request: `#931 `_ See pull request: `#950 `_ * The default plugin shared library is no longer exported via rviz_LIBRARIES, but in stead is now in a cmake variable called rviz_DEFAULT_PLUGIN_LIBRARIES. See pull request: `#948 `_ See pull request: `#979 `_ * Fixed a bug in billboard line generation where a zero point line caused a crash. See pull request: `#942 `_ * Downsampled maps will now result in a Warning status, previously it was OK. See pull request: `#934 `_ * The map display will no longer try to transform a map until one has been received. See pull request: `#932 `_ * Enable antialiasing * Contributors: Aaron Hoy, Benjamin Chrétien, Chris Mansley, Dave Coleman, David V. Lu!!, Joao Avelino, Jochen Sprickerhof, Kentaro Wada, Martin Pecka, Mike O'Driscoll, Nikolaus Demmel, Robert Haschke, Simon Schmeisser (isys vision), Stephan, Tobias Berling, William Woodall, bponsler, caguero, frosthand 1.11.10 (2015-10-13) -------------------- * Fixed Qt assertions triggered in debug build of Qt. * build: Use PKG_CONFIG_EXECUTABLE Instead of using a hard-coded pkg-config to make cross-compiling possible where the pkg-config binary is host-prefixed (e.g. armv7-unknown-linux-pkg-config when cross-compiling for armv7) * Fix `#911 `_ `#616 `_ : TF Segfaults on reset/update Do not needlessly delete tree_property\_ elements, update them instead. Most likely fixes `#808 `_ too. * python_bindings: sip: Use CATKIN_PACKAGE_LIB_DESTINATION instead of hardcoded lib. Fixes build with libdir != lib. https://bugs.gentoo.org/show_bug.cgi?id=561480 * Contributors: Alexis Ballier, Arnaud TANGUY, Dave Hershberger, Marvin Schmidt, William Woodall 1.11.9 (2015-09-21) ------------------- * Updated warning message to indicate triangle count is a 32bit integer, and not 16bit. * Fixed the error checking of large STL files. * Smoothed updates for map display plugin. Map displays previously only updated when receiving a message. This means that if your fixed frame was base_link, the costmaps would not move appropriately around the robot unless a message was received in order to update the transform that should be applied to the scene. For global costmaps, this is a slow update and for static maps, this never happened. This fixes that by hooking into rviz' periodic call to continuously update the transform to be applied to the scene. * Displays are not disabled if associated Panel becomes invisible. Otherwise the state between Panel & Display becomes inconsistent. Fixed symptom: When loading a configuration that contains a disabled CameraDisplay, during the configuration of the panel(the camera render widget), the panel is set visible for a very short period of time. Because of the missing logic, the CameraDisplay is enabled together with the panel, but the Display remains enabled after the Panel is set invisible. One ends up with an enabled (and subscribed) CameraDisplay without the corresponding RenderWidget, even so the configuration specified that the Display is not enabled. * Removed shortkeys from ``shortkey_to_tool_map_`` this should fix `#880 `_ * Contributors: Daniel Stonier, Henning Deeken, Jonathan Meyer, Michael Görner, William Woodall 1.11.8 (2015-08-05) ------------------- * Force and Torque can now be scaled separately in the Wrench display: `#862 `_ * Fixed a bug in the Wrench display: `#883 `_ * Improved error checking when loading ascii stl files. * Suppressing some new CMake warnings by setting cmake policies. * Re-enable most all of the tests. * Added option to start rviz with the ROS logger level set to Debug * Fixed setting of status bar from python by checking if the original status bar is being used or not. * Added a third person follower view controller. * Fix decaying of tf2 static transforms in the TF display. * Correctly display color and alpha in pointclouds. * Restored functionality to force opacity and color for meshes that have null rgba values. * Use the ``find_package``'ed python version detected by catkin. Otherwise it might happen that catkin (and the rest of the workspace) uses 2.x and rviz detects & tries to use 3.x. This can produce some nasty collisions. See rospack, roslz4, qt_gui_cpp and others for similar invokation. * Fix processing empty of pointclouds. Otherwise, given a stream of clouds with some of them empty, the last non-empty message will still be displayed until a the next non-empty cloud comes in. * Check if position and orientation of links of robots contain NaNs when updating pose of robot links. * Fixed DELETEALL marker action, by not iterating on the marker list. * Contributors: Carlos Agüero, Gustavo N Goretkin, Jonathan Bohren, Kei Okada, Michael Ferguson, Ryohei Ueda, Thomas Moinel, William Woodall, loganE, louise, otim, v4hn, 寺田 耕志 1.11.7 (2015-03-02) ------------------- * Fixed a bug where the timestamp was not set for the /initialpose message published by the 2D Pose Estimate tool. * Added a method/Qt Signal for refreshing tools called ``refreshTool()``. Calling this method updates the name and icon of a tool in the toolbar. * Fixed a bug with ``setCurrentTool``. This fixes a rare gui bug: if an incoming tool directly calls another tool during it's activate() function the tool gets changed accordingly but the toolbar gui becomes inconsistent because Tool* tool pointer is outdated in this case. using Tool* current_tool fixes this. * Fixed initialization of Tool's ``shortcut_key_`` and fixed a bug in ``toKeys()``. * Initialized the ``shortcut_key_`` param with '/0' to be able to check whether a tool has a shortkey assigned or not. * Made the tool manager check if a tool has a shortkey before converting the char to a key code. * Fixed the ``toKeys()`` method by removing the assertions, making at a boolean returning function and allowing a single key only, as this is what is to be expected from the ``shortcut_key_`` param this should fix `#851 `_ * Contributors: Henning Deeken, William Woodall, lsouchet 1.11.6 (2015-02-13) ------------------- * Fixed a mesh memory leak in ogre_helpers/mesh_shape.h/.cpp This fixes a memory leak which is caused due to no meshes ever being destroyed without removing the mesh from the mesh manager. This gets really bad when drawing meshes with 50K triangles at 10Hz, resulting in a leak rate @ ~60MB/sec. * Add a simple 'About' dialog to the help menu. * Contributors: Jonathan Bohren, William Woodall, gavanderhoorn 1.11.5 (2015-02-11) ------------------- * Tools (on the toolbar) can now indicate if they need access to keypresses by setting the ``access_all_keys_`` attribute. The handling of keypresses in tools has also been refactored. See: pull request `#838 `_ * Path display now has an additional display style called "Billboards" which allows to set the line width of the paths. It also now has an offset property to shift the path with regard to the fixed frame origin. See: pull request `#842 `_ * Meshes now have their ambient values scaled by 0.5 which gives a softer look, which is more in line with Gazebo's look and feel. See: pull request `#841 `_ * The default ambient color for meshes is now 0,0,0, down from 0.5,0.5,0.5. See: pull request `#837 `_ * Triangle-list markers are now shaded like other objects. See: pull request `#833 `_ * Color is now applied to all visuals of the line class, closes `#820 `_. See: pull request `#827 `_ * The find_package logic for assimp/yamlcpp has been moved to before add_library for librviz to fix building on OS X. See: pull request `#825 `_ * Fixed moc generation errors with boost >= 1.57. See: pull request `#826 `_ * Contributors: Daniel Stonier, Dave Hershberger, Henning Deeken, Michael Ferguson, Timm Linder, William Woodall, v4hn 1.11.4 (2014-10-30) ------------------- * Fixed stereo support for custom projection matrices * Fixed read off end of array in triangle_list_marker * Add dependency on opengl rviz calls find_package(OpenGL), so it should have a direct dependency on OpenGL. This matters on ARM, where the other packages that rviz depends on use OpenGL.ES, and don't provide a transitive dependency on OpenGL. * Update map via QT signal instead of in ros thread Resolved issues when running RViz in rqt where the incomingMap callback is not issued from RViz's main QThread causing a crash in Ogre. Map updates are now handled by emitting a signal to update the map from the callback thread. * fix rainbow color, see `#813 `_ * Added TF listener as parameter to constructors of VisualizationManager and FrameManager * Fix add by topic for Marker and MarkerArray * Fixed map plugin to only show when active * stereo: restore camera after rendering (Avoids a segfault) * fix stereo eye separation * fix ogre includes * Contributors: Acorn Pooley, Alex Bencz, Austin, Austin Hendrix, Ben Charrow, Dave Hershberger, Jonathan Bohren, Kei Okada, William Woodall, ZdenekM, v4hn 1.11.3 (2014-06-26) ------------------- * remove explicit dependency on urdfdom urdfdom is provided via urdf and catkin_* CMake variables. The current setup was unbalanced anyways because along with urdfdom, urdfdom_headers should have been being depended on and used. This precipitated from urdfdom's rosdep key changing as it became a system dependency in Indigo. * Add ability to delete all markers in Marker plugin * fix hidden cursor bug On some systems loading a pixmap from an svg file can fail. On these machines an empty cursor results, meaning the cursor is invisible inside Rviz. This works around the problem by using an arrow cursor when the desired cursor pixmap canot be loaded. * Install rviz to the global bin * Added display for sensor_msgs/RelativeHumidity * Contributors: Acorn Pooley, Adam Leeper, Chad Rockey, Dave Coleman, William Woodall, hersh, trainman419 1.11.2 (2014-05-13) ------------------- * Fix an issue with rendering laser scans: `#762 `_ * Fix an issue with using boost::signal instead of boost::signal2 with tf tf recently moved to boost::signal2, so the effort display needed to be updated too I made it so that it would conditionally use boost::signal2 if the tf version is greater than or equal to 1.11.3 I also fixed some compiler warnings in this code closes `#700 `_ * Contributors: Vincent Rabaud, William Woodall 1.11.1 (2014-05-01) ------------------- * fix fragment reference in point_cloud_box.material Closes `#759 `_ * upgrade ogre model meshs with the OgreMeshUpgrader from ogre 1.9 * Changed TF listener to use a dedicated thread. * Speed up point cloud rendering by caching some computations and using proper loop iterations * Fixed rendering of mesh resource type markers with respect to texture rendering and color tinting * Fix segfault on exit for OSX * Fix memory leak in BillboardLine destructor (material not being destroyed correctly) * Fix disabling of groups (`#709 `_) This was broken with commit 5897285, which reverted the changes in commit c6dacb1, but rather than only removing the change concerning the read-only attribute, commented out the entire check, including the ``parent_->getDisableChildren()`` call (which existed prior to commit 5897285). * Add missing libraries to rviz link step, fixes OS X build. * fix failing sip bindings when path contains spaces * EffortDisplay: Added a check to avoid segfaults when receiving a joint state without efforts * Contributors: Dirk Thomas, Hans Gaiser, Jordan Brindza, Mike Purvis, Mirko, Siegfried-A. Gevatter Pujals, Timm Linder, Vincent Rabaud, William Woodall 1.11.0 (2014-03-04) ------------------- * fixing problems with urdfdom_headers 0.3.0 * Contributors: William Woodall 1.10.14 (2014-03-04) -------------------- * Fixed a bug in tutorials caused by uninitialized ros::Time here. * Contributors: Dave Hershberger, William Woodall 1.10.13 (2014-02-26) -------------------- * Use assimp-dev as a `build_depend` and leave assimp as the `run_depend` * Contributors: Scott K Logan, William Woodall 1.10.12 (2014-02-25) -------------------- * Shiboken is now disabled when a version which would segfault is detected (fix `#728 `_) * Eigen is now found using the FindEigen.cmake from the `cmake_modules` package. * Added support for rendering rviz in stereo. For more information see this commit: https://github.com/ros-visualization/rviz/commit/9cfaf78e2ae8d34e4481de19568b353964846842 * Added a "Queue Size" option for the Range display type. * Added Ogre-1.10 compatibility This allows rviz to compile (and work) against Ogre 1.10 (currently the latest version of ogre). It also still works with earlier versions of Ogre (tested with Ogre 1.7.4 as installed via debs on Ubuntu 12.04). * Now includes ogre without OGRE prefix This is necessary to find Ogre files in the right place with compatibility between Ogre < 1.9 and Ogre >= 1.9. This is also necessary when 2 versions of Ogre are installed on the build machine. * RVIZ doesn't use __connection_header from incoming messages, but only uses ros::MessageEvent's * Better feature detection for assimp version The unified headers were introduced in Assimp 2.0.1150, so checking for Assimp 3.0.0 is not quite the best solution. See https://github.com/assimp/assimp/commit/6fa251c2f2e7a142bb861227dce0c26362927fbc * Contributors: Acorn Pooley, Benjamin Chrétien, Dave Hershberger, Kevin Watts, Scott K Logan, Siegfried-A. Gevatter Pujals, Tully Foote, William Woodall, hersh 1.10.11 (2014-01-26) -------------------- * Fixed in selection_manager which allows interactive markers to work with orthographic cameras views * Add support for yamlcpp 0.5 with backwards compatibility with yamlcpp 0.3 * Fixed message type for Polygon display. The polygon display type actually subscribes to PolygonStamped. * Contributors: Austin, Ken Tossell, Max Schwarz, William Woodall 1.10.10 (2013-12-22) -------------------- * Fixed a severe memory leak with markers and marker arrays: `#704 `_ and `#695 `_ * Contributors: David Gossow, Vincent Rabaud 1.10.6 (2013-09-03) ------------------- * Added a new method for adding displays, by topic as opposed to by type. * Added new exception handling for loading mesh files which have no content. 1.10.5 (2013-08-28 03:50) ------------------------- * Removed run_dep on the media_export package * All previous history is not curated, see the commit `history `. rviz-1.12.4/CMakeLists.txt000066400000000000000000000140271300447110700153320ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.11.2) project(rviz) if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() if (POLICY CMP0054) cmake_policy(SET CMP0054 NEW) endif() find_package(Boost REQUIRED COMPONENTS filesystem program_options signals system thread ) find_package(urdfdom_headers REQUIRED) find_package(PkgConfig REQUIRED) find_package(ASSIMP QUIET) if (NOT ASSIMP_FOUND) pkg_check_modules(ASSIMP assimp) endif() if (ASSIMP_FOUND) if( NOT ${ASSIMP_VERSION} VERSION_LESS "2.0.1150" ) add_definitions(-DASSIMP_UNIFIED_HEADER_NAMES) message(STATUS "Assimp version has unified headers") else() message(STATUS "Assimp version does not have unified headers") endif() include_directories(${ASSIMP_INCLUDE_DIRS}) link_directories(${ASSIMP_LIBRARY_DIRS}) else() message(STATUS "could not find assimp (perhaps available thorugh ROS package?), so assimping assimp v2") set(ASSIMP_LIBRARIES assimp) set(ASSIMP_LIBRARY_DIRS) set(ASSIMP_CXX_FLAGS) set(ASSIMP_CFLAGS_OTHER) set(ASSIMP_LINK_FLAGS) set(ASSIMP_INCLUDE_DIRS) endif() pkg_check_modules(OGRE_OV OGRE OGRE-Overlay) # Old versions of OGRE (pre 1.9) included OGRE-Overlay in the main package # (i.e. there was no OGRE-Overlay component). So if the above # pkg_check_modules() failed, try looking for just OGRE. if(NOT OGRE_OV_FOUND) pkg_check_modules(OGRE_OV REQUIRED OGRE) endif(NOT OGRE_OV_FOUND) ## Find OGRE Plugin path (not necessarily platform-independent, I guess) execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=plugindir OGRE OUTPUT_VARIABLE OGRE_PLUGIN_PATH OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS OGRE_PLUGIN_PATH=${OGRE_PLUGIN_PATH}) # find absolute path of ogre libraries. # This is stored in the cache to save time on cmake re-run. # Using absolute paths is necessary if pkg-config finds Ogre in a different # location than the default. This can happen when Ogre is built from source, # or when 2 versions of Ogre are installed. Using absolute paths ensures that # components that link against Ogre (rviz and any packages depending on rviz) # all find the same Ogre shared library. if(NOT DEFINED OGRE_OV_LIBRARIES_ABS) unset(OGRE_OV_LIBRARIES_ABS_TMP) foreach(_lib ${OGRE_OV_LIBRARIES}) set(OGRE_OV_LIB_TAG "OGRE_OV_RVIZ_LIB_${_lib}") find_library(${OGRE_OV_LIB_TAG} NAMES ${_lib} HINTS ${OGRE_OV_LIBRARY_DIRS} PATHS ${OGRE_OV_LIBRARY_DIRS} ) set(OGRE_OV_LIBRARIES_ABS_TMP ${OGRE_OV_LIBRARIES_ABS_TMP} ${${OGRE_OV_LIB_TAG}}) endforeach(_lib) set(OGRE_OV_LIBRARIES_ABS ${OGRE_OV_LIBRARIES_ABS_TMP} CACHE FILEPATH "Pathname of library ${_lib}") endif(NOT DEFINED OGRE_OV_LIBRARIES_ABS) if(APPLE) FIND_LIBRARY(Cocoa_LIBRARIES Cocoa) set(rviz_ADDITIONAL_LIBRARIES ${Cocoa_LIBRARIES}) endif() find_package(OpenGL REQUIRED) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) option(UseQt5 "UseQt5" ON) if (UseQt5) find_package(Qt5 REQUIRED COMPONENTS Core Widgets OpenGL) # set variable names already used with Qt4 set(QT_LIBRARIES Qt5::Widgets) set(QTVERSION ${Qt5Widgets_VERSION}) else() find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtOpenGL) include(${QT_USE_FILE}) endif() add_definitions(-DQT_NO_KEYWORDS) find_package(catkin REQUIRED COMPONENTS angles cmake_modules geometry_msgs image_transport interactive_markers laser_geometry map_msgs message_filters nav_msgs pluginlib python_qt_binding resource_retriever rosbag rosconsole roscpp roslib rospy sensor_msgs std_msgs std_srvs tf urdf visualization_msgs urdfdom_headers ) if(${tf_VERSION} VERSION_LESS "1.11.3") add_definitions("-DRVIZ_USE_BOOST_SIGNAL_1") endif() find_package(PythonLibs "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" REQUIRED) find_package(Eigen3 QUIET) if(NOT EIGEN3_FOUND) # Fallback to cmake_modules find_package(cmake_modules REQUIRED) find_package(Eigen REQUIRED) set(EIGEN3_INCLUDE_DIRS ${EIGEN_INCLUDE_DIRS}) set(EIGEN3_LIBRARIES ${EIGEN_LIBRARIES}) # Not strictly necessary as Eigen is head only # Possibly map additional variables to the EIGEN3_ prefix. else() set(EIGEN3_INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR}) endif() catkin_python_setup() if(NOT OGRE_OV_LIBRARIES_ABS) set(OGRE_OV_LIBRARIES_ABS ${OGRE_OV_LIBRARIES}) endif() # Set the Qt version for use in the extras file. set(rviz_QT_VERSION ${QTVERSION}) # This variable controls the target name of the default plugin library. # It is used in the extras file (processed in caktin_package(...)) and the # cmake code for the default plugin. # There is a matching instance of this in the plugin_description.xml. set(rviz_DEFAULT_PLUGIN_LIBRARY_TARGET_NAME rviz_default_plugin) catkin_package( CFG_EXTRAS rviz-extras.cmake INCLUDE_DIRS src ${EIGEN3_INCLUDE_DIRS} ${OGRE_OV_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} LIBRARIES rviz ${OGRE_OV_LIBRARIES_ABS} ${rviz_ADDITIONAL_LIBRARIES} ${OPENGL_LIBRARIES} CATKIN_DEPENDS geometry_msgs image_transport interactive_markers laser_geometry map_msgs message_filters nav_msgs pluginlib resource_retriever roscpp roslib sensor_msgs std_msgs tf urdf visualization_msgs ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIRS} ${OGRE_OV_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} ${PYTHON_INCLUDE_PATH} ${urdfdom_headers_INCLUDE_DIRS} ) include_directories(src ${catkin_INCLUDE_DIRS}) #### If gtk ends up being the best way to get the correct window #### position under X11, this is how to compile it in. # # find_package(GTK2) # include_directories(${GTK2_INCLUDE_DIRS}) # include_directories(/usr/include/gdk-pixbuf-2.0) add_subdirectory(src) install(DIRECTORY ogre_media DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(DIRECTORY icons DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(DIRECTORY images DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(FILES default.rviz DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(FILES plugin_description.xml DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) rviz-1.12.4/README.md000066400000000000000000000006121300447110700140440ustar00rootroot00000000000000![rviz logo](https://raw.githubusercontent.com/ros-visualization/rviz/kinetic-devel/images/splash.png) [![Build Status](http://build.ros.org/buildStatus/icon?job=Kpr__rviz__ubuntu_xenial_amd64)](http://build.ros.org/job/Kpr__rviz__ubuntu_xenial_amd64) rviz is a 3D visualizer for the Robot Operating System (ROS) framework. For more information, please see the wiki: http://wiki.ros.org/rviz rviz-1.12.4/cmake/000077500000000000000000000000001300447110700136465ustar00rootroot00000000000000rviz-1.12.4/cmake/rviz-extras.cmake.in000066400000000000000000000020701300447110700175520ustar00rootroot00000000000000# Export the Qt version used by rviz. set(rviz_QT_VERSION @rviz_QT_VERSION@) # Set the rviz_DEFAULT_PLUGIN_LIBRARIES variable. # If the target exists, then this file was included during a cmake invocation # that is shared with rviz's cmake, e.g. when building with catkin_make. if(TARGET @rviz_DEFAULT_PLUGIN_LIBRARY_TARGET_NAME@) # So just set it to the target name. set(rviz_DEFAULT_PLUGIN_LIBRARIES @rviz_DEFAULT_PLUGIN_LIBRARY_TARGET_NAME@) else() # Otherwise rviz was built separately and this was sourced from a devel space or install space. # If the location file doesn't exist at this point it is an error. if(EXISTS "${rviz_DIR}/default_plugin_location.cmake") # The file being included is generated by src/rviz/default_plugin/CMakeLists.txt include("${rviz_DIR}/default_plugin_location.cmake") set(rviz_DEFAULT_PLUGIN_LIBRARIES "${rviz_DIR}/../../../@CATKIN_PACKAGE_LIB_DESTINATION@/${rviz_DEFAULT_PLUGIN_FILE_NAME}") else() message(FATAL_ERROR "the default_plugin_location.cmake file was not found and is required") endif() endif() rviz-1.12.4/default.rviz000066400000000000000000000067341300447110700151400ustar00rootroot00000000000000Panels: - Class: rviz/Displays Help Height: 78 Name: Displays Property Tree Widget: Expanded: - /Global Options1 - /Status1 Splitter Ratio: 0.5 Tree Height: 464 - Class: rviz/Selection Name: Selection - Class: rviz/Tool Properties Expanded: - /2D Pose Estimate1 - /2D Nav Goal1 - /Publish Point1 Name: Tool Properties Splitter Ratio: 0.588679 - Class: rviz/Views Expanded: - /Current View1 Name: Views Splitter Ratio: 0.5 - Class: rviz/Time Name: Time SyncMode: 0 SyncSource: "" Visualization Manager: Class: "" Displays: - Alpha: 0.5 Cell Size: 1 Class: rviz/Grid Color: 160; 160; 164 Enabled: true Line Style: Line Width: 0.03 Value: Lines Name: Grid Normal Cell Count: 0 Offset: X: 0 Y: 0 Z: 0 Plane: XY Plane Cell Count: 10 Reference Frame: Value: true Enabled: true Global Options: Background Color: 48; 48; 48 Fixed Frame: /map Name: root Tools: - Class: rviz/Interact Hide Inactive Objects: true - Class: rviz/MoveCamera - Class: rviz/Select - Class: rviz/FocusCamera - Class: rviz/Measure - Class: rviz/SetInitialPose Topic: /initialpose - Class: rviz/SetGoal Topic: /move_base_simple/goal - Class: rviz/PublishPoint Single click: true Topic: /clicked_point Value: true Views: Current: Class: rviz/Orbit Distance: 10 Focal Point: X: 0 Y: 0 Z: 0 Name: Current View Near Clip Distance: 0.01 Pitch: 0.785398 Target Frame: Value: Orbit (rviz) Yaw: 0.785398 Saved: ~ Window Geometry: Displays: collapsed: false Height: 846 Hide Left Dock: false Hide Right Dock: false QMainWindow State: 000000ff00000000fd00000004000000000000013c0000025ffc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006400fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c00610079007301000000410000025f000000dd00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f0000025ffc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a0056006900650077007301000000410000025f000000b000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000028900fffffffb0000000800540069006d00650100000000000004500000000000000000000001eb0000025f00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: collapsed: false Tool Properties: collapsed: false Views: collapsed: false Width: 1200 X: 60 Y: 60 rviz-1.12.4/doc/000077500000000000000000000000001300447110700133335ustar00rootroot00000000000000rviz-1.12.4/doc/add-button.png000066400000000000000000000146601300447110700161110ustar00rootroot00000000000000PNG  IHDRAN1M3sRGBbKGD pHYs+tIME U0IDATx]yt[W}e-$[&ٝmh@ᴥCa(ak0C@0 PBhMdiӤMN}e˖E;i"a'L +ZihSkdJfXB˾l:-zfJfXAF,H`Jf@TZNv8S{! +q.MÞQÔΚԟT0`~Υ*ɘaiRcX)fl%3 2%3( 3N'c$(Pe8䱾!`1 Em¡χyfHM`Lçad%rR ,f ˑ[o1XR&ٌ176t:~fuK"0a{wlPJBve^lSJǻ+˲2d쟜DngEr855_ZZb0xOSCv5k D2#0iCk2n$dz۶n%Ot 撲ǚ#GKP MV\`vv68aP(a_@aQV%"JB$j '8L s- ]1"`әetH/^hBNvdmZ9Q '{!lҘ(!cM%`7@2h B"KDJK&qeRoD+LB!$JW|/1(Y4G/ kIh<!BI%DT,&_@Y\PWuE7a LB0BC&$)vE(۳ ,BĐ)â!BcBQk"dne^Ş`Dحfi!p&ߝ(k֢ӇtwQ|F=|j Zv k݊by^ԭxՔR4mi\CCy1lR1%RAxRs( X!ILee P&iQwkGo>tz~>=etO+bR,&g&JI]q憂bG% \(h1BQ 뒤ka2Uw='4sۻJ !$}ዱ "g̏; M NEX5*WvA\탈-ԇBC"%x$R_ٷ['#`/] GM`|^ZaiX.oA4Ѿ[(W$[7 98HiHڣs[JK1B(YC@]yS߄ܘMV ),LI= vKF ᕔCJC嬫=|z"kj`ciiPlǑe?z_ڬvoP疙@<<ҋGiAiPP c6{k- 2>Bf}Qxz=!52Sa\fcmA@}=# 4| G}=oTmy-y ~xD{oԡrk6l}jb:-sMdN!4u,ȡ"6"ZvF,9J~ZZ/اSnSc SOdZKɺ\ Ԧu*$n 6负`UNMVCl)EUeqWybi14j4q_<>XsG]n7a|w毫7EZ2OGk~H_Rݯ$y^g.Ȗ,SʀÄF%wL[Wi"#tҩai8 !O&%T1q@ OW#U抺 Z줗@W[$nӹ ( <nL; OMRX4%j]aj`t[ ZGfa}=oLb(E(6 -C*f^}5ܲ,Nؖ ܳPd1 x r2jy,<`>LSP">S}.= GG$΄R q&qi-i8unz|#'-d32 ߤ#%!ѴDdA PlTށaEv^BtD2zUrJ2ada D7 UC5%C>e^GS:R<vt4 Ӕp"¨iJ U;`*#:w-'7",W(b 2 w/U677P(ݞ!b Tl-`q2@Y+S;j:.˵lVfoGɊjӲS'=뭥F8޼Q bB ]ÒV[J+Ho p'mRT",0)u2>u3gGQT =D/͋ШSD(%F JNF&!s6r΂D)HSXi`Q J}G'Êb,>6/(.PȠ@Aw$:].!E@Aڈ Zded}bm[ Ո04H MDHe k+ J#ݜQ(B_>?V506=is QB8OWX+)/MgOo\UŪʺ:kt|jï>E9[>Ek;cۻ;{'b" ق2AW$E&{e+ -=Sa U}cQ{m:DdSb/YvE>8=rZ/O  N[Pl芋}y6do686N! t;!JAh ‚SP^Z!@ aRq )j K ,.oq\#Y4NcTg9vO{fH{/\dps 0qcT*աCzĹ3hqqI($@ʒf]z΍GbCT'C8 atYeҜ@C:Gz!.(H).J  nySE~E7SL0ʤ~IL爥8Ǜy~NBL$ALYe[VpH#%/"G(@1F0s1@ E # PĀ3t_vfd,=I:xiaeq`d>!@džM"u)x4b$:_d$JaDy۞X^$C(Hd3P9X!!!*${~Z+1d` m`b=8L 1 ;\qתŌ'[<[uȗvx{$TqqIR;/ z?*KOpg\17.6AxvǸ6n]N-O!$7sox0Ox8nkK:k]yFQGhoH+ c?C|d<Ÿ_}l^Mi77-1m?44sud3_{/䄓E?zoRHU/CiyAi}}!뼋-y)g&c+TG?}yV" wKy{x'>˷Yz]@K?IT[svtSEO>x3}u0[O5=sMATnP"=A4{.Ax{gO~On?%i>eW;/BBQqc(uw9?7x 07C )аd}yBԹR%յ7t=ч-4 mHWa|$YOG[r[.#귝|qFfgCɽaT{~Z;{񝦹TZ+asb{4N ;n~sa`?g l/~t-<.h͇T]O_> yA|#.-{F#C :|& t! {.@aF s 9KU\x8LeƲ{|nǟo 6/<eD5FTq1.mg"NH)ػpHi:A/'y__BgJ ׷0gYaXB.,mmcbboܸRA֨fBzA}/k]a`5$5тG[I},;gJ$ SMgSH_L* 5r5J``,R"%.%FzRIITj(BI t">AdidBİJ) ZlV  3MQ@ ={K>_@hk!Q*EiXN w93oHII^536ESQ8SJyέ& Ēm <WތeMMJQ(^}׿أ F6ūQ W5>TQjB²0R)(+Wi4,5lX_VHm?G}|FRjN 9M#WHۿOuETfW7s(5BӸfuZ *6tE.BҦZ/f 3nhGB$DR) Ѯz|ң;IK?EY5!$lݴEƮy<^B-J{~bu}x{V$ȺL(!*kġU 7V$hHR_,*( (BIQhoGZ,˲, J(dRİm^} ?*[uc_v5(g> Ot\AQT^0`w7c5R'TP!OJ@K@$~u^IȕK7h>O $w(2 V7&B@ EϏJu{A45>g@@%nĦh@#ޠl9gut>& ' $y8Bի+gD)r @ t^*RJ'R9BIr6k@W?!R]ʸ@x4MSaY²l\NSZyꍎD !iɋlըh)D엹xZ5B utt5junPT5¼P#mIuD_9qs,7e"LP!RR3 ,M( utGjfZ()II& 4_XG2O !0j@V %9EGG6SRE1j&,˲bAQPďɘHz~!sEQ@B>c ]qBeXPcbb4 P@4KXRDB!E( 9WS)P("d~OJ3%|>_=DgYv,UDBBJ%HR\ʲ,!l|D"cx^N$/?Ո ˰,iy@W$`FR?Bq\j <˕2QS9. E¯zjWX!F ")B\Br[A!{! مw8cB܆)B\)B\)B\)B\)B\)B\)B\)B\)B\)B\)B\)B\Bhj_)${7cE65-3!!#gA(CߣϤ ^\P|o硓>!!A>k"wO`UkaZٷI<~UR,q&sz~ƭSI8:B|2Q%ŤG}~m!`~v|e󹻛6~A+rPY&Icst--E຿gJTj o $/UvY )&;{1Mlݳ{zBtiy惇;<\Գ(TӠ x6"ABE4uΉ0uT\T %סGG8$5Axy~ZY*fe|*RYx!*IIx"!$X=iٵh1cSx"U+[f D?6Sˎ)QoI41zN_tm3ԯ7mm4 ;2-[oLܶo揔h=t/~T"{r5kw;*6;/X&.I,[Vܪü[|vtb,My~-BLqV!Tp?8NXM,&.ƾ:je-ڴa!h]FN~hMWɸKb2(_ύyғۡ@WR|tT`[ɘ/{=1T0`(kQA }R?[5nn6r}c*&,MY\/:5]3iQi'J C?_M{V*7u:U?Nr)w ZMUƯW#<SBC ïBr5 |B,eMRLdTj7raF=VϨLA{K(UjЦaM-ĚؐoySJe-mʕʹi-4QZ2Я]>f囏A@T4kl{o#ZMxNKBc.=վsw3֤T0zJu߈&Œq{#B/!TR(gTiߡM Lr,CT t_ UP KflBZΞx7X_!P(B0B0B0BˊgOBߎG%̿Bbc>) i֑H-,-M(NJL(޼v%O?Ks2>.kΟ z{o<9|xnmϞy <*VSaY6kKٗ} ܜLjGV.Y0EZGֈ] ERBb)"P2􌌊,(M&fq1r:jǏCCC>09c-X^byz>N-,CϤxSS<761UP~ eT*?|puHMw O>}j}QϞ=VVVY6(J $%%2eGGG4P( bccSRRj59pK_|.B%%UјG^{hІz,oeeս{RJ5ҲO>#^< !JB "($$"880H$aױ<{kd2ȝꎺ): _'YJ&@/7fB(y =cbb>z$<|S8sE.]N8njjhty-uuuuK2m+0utrr*'zZB[V^ɓ'nnnիWm3PRS4111fff::: i611ӎ3v6u4Q/ʚdJvEMy+˻-Ǝ+ nj^TTQ||ד'OLMM˕+lccST)mkqBENXD_=>5-ʈn=:g3>3K BX.ڴiSfdwwwⅩB(Uϣ Zwa`eB^/n"* ˇ|499aWƵKB )k#>?g^{S{tkhߜ{CcqeEB?,X"mN4Dz a4BLW2e]xE+KB94IBB5)Ϟ:T+u̧y B4 0 xS'Ç5)BrIJTѓB(җ3 Fvrv)oHq3qMJo%SVP!@!,hG',+0ncA?'ğ e (6+/"r\pps^!~7ӧ FMXB!,aYF0F!طSn?|8gㅳ'BBB(rwaǏ0i̙s;Bߢ(( ,(2uS͗74i\y !{ Ex畔.eنB/2_d !6qƦbG/}vD=lp|@?Hp^;§(±|A}YW]Ƿzt<B5S;籅FS~$Q_kPܳV"4&Enԑ׏X&nwƁ,}b&2LVI7 B%\Ƨ^{-`JyB :gnu4ظ/}H@}J/'T'[~=P$ɪa*YavwWYr/ک]nzw-Y'!31sCEQ\1kR<.>{5ZWQUpAeOye~:m}ϲ:qB xX+06Ny䘩ii?} -N^*8 ҷKgߕ<;|9~[ЭTCYUY"d3k91k$@h^N}*R0T~{Ԧ?*S*8=߱z PFb3Ffo`mgTͽd|fpسX_K{O^XkbnmlsqF7ߪ0-"8iKw=MzyP9J=p6jU0Ú5ܼ/ jd{yHM̗j5u\v+3pWSg0sjckxlĝ ]YYfǶGV85ԕ+O;woߏO4ZyQ] Ыm͚4oyͨ'G9A@MyzUzp!T;;lb"ĈGxMyB!mܝϓF5ؘ{VZ[ܝB?u3k!0MaW+V1 #4 MhfY6&&feY**\ڸq[ _ϲIIM)"PQX޾};u۷رϟvϟi%E4ݸqaӂ.ܼܽJe{kEBrk}o߾.]b&>>n䩟>}ʲU˛7k}_6B,PF z8NC !T8f͚:u*ܺuӧ<?00pJ3I}a^sjnxp?G+ĖmGLk6i+/~}&Z>s֫hRQ(Ϯ](Ľɀ#9)PWa۶_'r8 B3guԹvD"ӻbccX U,YD7qzf+1Eg,r?4!(4k*w'WZ̬v0Hy{񮙋=ͯe@:i"/]0bu4(vBQY Bq9;uP(r\.hݪ- Ѱ,Us}RU$9Lк5j;u'UmC!ȪruoO TrHri.UUT4|}n;ŜrxJjTtZk VU4rȜ".p9$ɴiS'M̲\.#$XFP( B%*hnBKt (:c>l @ gAIizD͏!߾ckʕs+[(JBHXX9R"ν.JOC-$>~sܴtQ3ǹGθC_°Bͼm3jRK!w-S.>>u "22>>O,) mjH]x}| e'oY͘FZZ Y{6y: BS>&&&--M___P( DJԦoY[Շd~a?~V '7KؿoIF.FOi߶qo+̖nfB' h8 BS%P(LKK'G웽}z萡93o4cMێ]~)WOKc@d`]N7ߗЦm`6غgΥTBr-&7k ڀ𧎂BTRbB7ɣ ~Ǐry[nնaÆ[ݺ~٣}{Ѩ KX% h4ZطSn?| gO8<ֵ[eYB  JΦ|4S! S! S! S! SX p!\];g_8Pz@AR@ L_M zx~Ҙ} sDPDR<|3.G+)wiBw9VߺkZ:?Z+*ɚǫZ Մ&Ǯ= MfA`XbCʼO Bٔ2eʥK M,X"#Lj\25oDSzo2szEaM.SQM@7" )cǎ۷7qkTTT7nܘkC*U6}iurRsyVXԌέͶO=Laҳngxzv/0UY d9;D5(>f\ 4qrһTif4Ҡ%IlSkn=Whg;K(7z|m## @je7o=Yl+^ Ji6qr! gSٳk֬///e=<<{yy ŋkoh/Uʕ+ߨλ{m;p-Q\ i>?j=~Ŀ}ӌ`ARÀ>СW6!᷶\7n>z XǡWufЅ]G/fww׊C51})cGV:~^k{6*:MyD:uiaaѳgϐRi>Xz8gͳojTey!:h{fd٫]k-'dvAJLH0hn :>%;g̀\N7->.wG_4gPEyԒ~BE)ߵk״4FvZ#FD"KK˥Kj;w.[؏6K:|g4)Ĥ0rwٔO#Zn>B >B%gS~ĉ'Nrg*U=zTJ7oX'o`Q\Y(h> ! 4+c_I`*X|MMSt-EQ%$!X6䠧%zy\>wܪUW|||.]T@k :ղ=l eĶt;3qJ_v:PBI_/(U=ݹ~Bu=,Íڍؤ7?e%G)<=K}zzv+O r>B4f׎9;ϰo߾{կ__{9Mc6jԨEyC}Mjǀ'1n-6-' {σضZ~H Խ;7;e-(Siu%T;݆uYԲ٬۫o2~06҈E z l:z]~!-.7o&O4q˗/O2C ɓ 63gۧM$نBJnc<>w), [Ә "EO>RM]A^#Par߿_.:uשSgɒ%ƍ5 |||ڵkwĉS>qKIj],14|16g62b#SC>l޼ ==z[=zXr?w (,u1MUDK{;;;Y3k)>T4~u>)_\o߾} VX<== raÆl20Uv㠑7,?wSEckW4E!AH.]::nܸ7;vlvvv3o`)OO_#ԄT&~a[!SV\9k֬C[nĈ6l000{/JB꒤~' V8PhU4?DW&ϝ;G k ]U޾V9 }3>'zY S}L+'*JPk7gh;ByF|n[XXp⛇~VUd^\dBߊ"HmuV@dų^ݔND}5Ӎoi8_ΑC6z6֫> wS* bE "rEQPgFlm>o&i&+_ J]N#c6ѥ ^|ȂwY-r"~B"t}dQ1rN^QKǕV?߷`̈́53ϥwӖ_$64_KPvMl36Y&j>/lZ8n嬟}>َA–6f63O\يĺ\N%Yˏ\;3#)5rSmQ{'5k֭WNE}gT77PeZ3Q?ؼEj(7/ = MmZbWU{W3~s+ P>-cmeeنEQPǽVwC*AJgouZRgGk;LԱZ)u(:mMy<]3]^H)_ N.:ȇATQ!n"HWn떃ګٔF!2}W\w`Քj5Vmm[7#+q{SWW_ߌ>_P>{fzĴkOFAE8DEEYXXhoT}, CZ*"_䥽}`ߞ>j4je h4Fh4zԥS;w.sX!~GMy>C!56!0B0B0B0B0B8{%eawE@a Bw)VK}{jҭgB M_sg =ۺheՑtoMyPd w>ճ{B`简ӆ. p:za5㸻V,5yG|~|-z<_3}q?MP!U+nv͝3Xf@T.qʖc8&5RPY|繛 (g4!NJ}Z\>i$8r@:@)^6ai!񊀙ESI**NwD{^8EQjik} Tu7^&k봲I/n~JRg1o"߉yGtGD/q`NzW=`#W3kMA!TjEOyBHͮ@yfeW/ݶx^|51йׂII6lyU׳,SQƙKO)Cjk!U`|߸rq;E-7|{-ui5~]ٶMǮo:6#8t!N TreDGEz!Tp! gl8KB BqYQw gSKUTW~qw! gS{L ÔGqgS!Slt~ԯ=埞S**\Nyn=tiJӴ0q< jaX0ҵ+!rB<@jklY[X{Oڠ F?}|`E'W3/-!L\NyiZO*tCQZ^? aY` $B/%p >1Y*2զ<ߔgﯙRX9wiҭ3goV *5m7Z7mn_;3~-¬zlٷ@u,'(0݈jo!+mDV˓>gJxpZ)FiE2`,^wΛDV,hYUj5DYaS_DC |0Y}'lyV=o̒ƬUa5,:e:+kLg4o)*@WB(oOy E0jh_ >deXI[¸~.Ds!|E9K8i!nrp" ΰ1K3" SNuosɸyoV^ʎʠX5&5{ԖN^?yh@TحS"+bEk; aajmZ㇯B_yoPhkOU;ĩ6rd O,]lhmIAmkkV4@ǢRDz0B)OQԔz~w(pڬզ'8[x6w2ߡ[i3i]I={<[5mB Φ[sUe_T!ӶW3o5Q\g!T"p6[6oղy)a/&:Z߾jwB%gS7BWsLqw!T"|!e%.?|( /TRu9;BPJ׎;YII$H Wd"P a6%Vqox;I3u^K4YII5t촍3-mII Æ}g6xZ>[R{eޘf:_\J6u QtNj,k4a!.*v%%Oiۅ+/״:ӗ>'w~%-?pYm`5MBXkoe+^^}# *'fw~u֏GYu#xFhӨL&ww'pVd2 9#ӵL&ݢ/Y3Fh]_&dmI"Gk dG>!CA @&uz&R{2L&JtN3_{4)w'7u{>0g#{#) l]GkjJKw?ϗ62@rT2|7e=L&51a" Z;w2L&k6TT@owWϦ(,֡L&fS@t`Ɛ-d2Yݮl=d2Y&gߌǹ U VTD6ǧg5*MH7+BI)0G#ڊ=lzɳJ_L.8pŔ4mD$ɪaYRfxwUc?>?s6eti"W)ţ+1Eg,r?4!|n[ӖYlćxW :@ l3inR6wܧҋv1һG.hZ[VP1VO 'x>)uK_)!NLi޼]]]W^ѣL*X`}7iLdYzU c./Nmj g'# Dl 44\E_wUZuo[͚U2uQ l?jKBl 2Y;:9Id\B{4r_k܌Jyq[ i\ Z$Gcƍwz*fRɷHݥ5D%kD3*/7'p;i?!dxeٚ 'N@joho)Y*YF7M_FY֎2/> B%*hMy$wLKWmQ?icq*!ylBnc +߽S{b}fk *RH{wj}_ƩRZ M]Pܜ3t-BK)UwXDJx" *K#U;> \\ini7S헣$BPs|cu.z~5M/# XDD9KHUji}MލHWD9Ŀ~/ڧWr.H< BFmgFD62Bb,ؙswTsjӏ . )ˇA|j$>QʊNBҽ]>j4je h4Fh4zԥS;w*UJT!p! S! S! S! S! S! S! S>wXHT6٢L&nyȬAX/!TJ̷2d,H~w7'ٳUE 7ŒBf:![7O$SN~Ha6pgve ;,{3$(])'=ڽtkAI i^v&ĻL=ot#$)f<:Z}k"J*N|S4?|3fVz3IO^.َA–6f63O ^̻|\hM<ϠgnY~cT_6f vˏ\;SqD5rlovݯ3mRL)g՗WBPI݁! D=0ߧKN.n¯elGL]t@ע|o)+ ME[4hk!J9|woݗ~K쿲gg/+2(6hwNzvcAQ|24k̳їzjYOԦ`جM޵wN_2znrF.ȫB%[L 5}̮ܧr¿]9m&NLT]Br݁US[wY"47' t:e)PҺSk6.ߺi@:6s>IBŪ*rw^!!nlHeɸ&c&=$' 7 mبd8?MMޤΛOjJz=E)0uDP]Fx w"{H?*>AA/tU6?NG2L˻/ӼYd^ig {$L]O !Tpv,}&cF{O9 *1^ӷƝ:M.~tV]AF&kX"[:P*wCm-ykT僷OU{Eqwj1O B$l1QǍoiq Y6[w]v0SƥkŦSGTG #vڠ|/ <@_)_ش9E[6v^kp`q=s/&9 Lĉ6G{҈V˳̱1 ( )0B?)1cD 1c( =+u.ξR HW4TOX} ,B s<;F1gO8B<ֱaI JЦnq0n+;P|MNR w|bQV̄IF-|'YMCx^ ]U ̼ QNٜ R{.ET !TrLgS>ܾ0w45\c|&6ee[r#~kW݇ njMK win~lggϜIZ0H/kE!o)_ʰX>P e:2W2R0#ӻ4d2Y U?Y4G2L&k3NR6n?6%𜁭dG )϶M߱ImL&k8p#~e&1 !`@ _FC3 ̥48x|$Rp8u$"`[S:1Usg9WZ֒9lv246J;bN;{!hO{eTaޟXx]]Zu"3:MciW !Tt@ =AT4"[͚UW+Sh"/]:,Ah;wױØ9w#-ئSR'!rۦO `5 |Y "1'-d-nY˄ax~*$\NyC7|;G`cZPKs7i@ߺ_>"=BpVoc׈( t ֊7}CJ"`>m}˻8%s6LԣnrghW {[c!M\NeZ 4—L@Q!>ꥪMz \0KE'v4uJ`lO('"+Y݇n_܅wS-gl27蟠ʖ|a#JJl MfF!tm5(A)B%QR?\ƔGCQ@Q@P|sw!p;~دEq!|p9A2"@z+xU=B/2/Φg姦N9eDԿfx,{ST6sٔR%*_w,;Lb`9XuD}" B(GpYq6mD6p`(Y~EX !Q9/[VTj/Z2BH,$}TZ8:@X(3n/y|>K{FNm{O~/n tQ |U1ٔo( eڇ̌o=^sZRrZNm5ifҧ;}}z䬻Gz6-d[Tl̙!dF?9ӹe7g=B!Py8ORIg֝ISDQEm~Ḅ  "ﻒJ\f~w~poUoM{Ӈt)z8I,Sz71;riVv(Q]LjciH:$Uq4~   3B9Jq?"4}onS4B) VATTSTd9\0GITڊؙIIRd@dSzn5; J rm[͚U*{UY8}JM䅹#V՛3u^ݻ1 uߟ>ᯭmCNWК/kڹ|w2d=ܷͼj,V޻UIfykοH!lbp[-a/A2a 陟>S88;r[w+(*`3ׯ)BffWVa߭" o-&4ɺT[9:-^8}V;rMD"+j4Tl4sv& Fu ^1nX_@;I勯v\`3eSz$pLZk)ytNUdo|H%[t  pcިU*$1kp*~O*]}vTɐ!2S"UX5cV\6#SofpzǏU[x3fsa^;gcֹ8zH) Y*v^`jgt:̙9gqS,io'-]N4&]]> tw._7YN]w"4Q*R] O4G#<˺=?x4ަ9SD"!EhP4(Tg?!cï>L@Dp9Cߪ"tkv^{IoF߬ ʎW_z*(1hHW.܅:s\L^MI30Ŧ~ |#_ə;z(훔TO'uuu#:('q|F˫aLLq7xkˆ3q˪]`_Bסi%9)988F `jjV(X (IݘTܽ@7704Ԯq@T glB$ÔG!.ÔG!.+y).|hV_޺jmUNSh 9PeQ:ͽObJBT2II`bX_ɆϮljХ[Wv{,oXLW3WYgx%Ӓ!~#]qJ1}._G'YUs=ސy&[>dp['3%}l!WO89B?#".NM.`5pD([\$)>^f5): 5*?KxͭkL/1"+wg쮉}C7S@oafP2eϩ ľv.O]{!52udRB>vSOT|&Əh(on,eɥ w Sԛzތw${WZ}hREqq'Q7U߽yیwjgq)\^Jk0}zЮ9p/vS 3^Ⱦ߳}mذ^|9vZa@v׮|Ön:LA61gB[u飪=7~fV^ƒ];tSV{E^Z`q#JWSA( `(7ލOb9YMx0BPvBlʳOR넧t/e:mKճGQzAw(TǾSB*u_lW4}8uaڹ]w5'ĔVA|lGԵu]u[\G`R!YwnlhfMdiu[m,E\a/ң.ǽ<=kG''; Z|֢=£-w?b'J,^cöc{-P{6+LM 9&߹XFTu^]I$HcY2}iweCuГշ s 71)JOO Ҙd2LV(H Oϕ5w t,(BnTW٘/3B{8;jbJD*|26֥l 0v‹G!&[Q`YLI| _°h%-(@ͼ.!FK-u&m֋wc}`Ӹg_ewqvg|sVm.*#<$]Xkά?-i_͘zA͇L]֕qFdR ph%_E62Bb[:J :%M; mӥ塳_nPךD$+ѣdE嵸D*( RXxZamxJ:LynQoΠ]!qq"Tas̠]7w/B! S!D؜M={5H#SBD7&n\`BWWEs;VmSET%7Sؔޅfr}k\)*&%wfq$6 \E9}4nj; +lѣo*f}!~;%4%n7W{{Ѩ\bR׼Uui!Nn_3;&V7(!,%%c i$\eZ:kO  (*k 9~}g'9ԽÛJ/DM{n!&mwVN_!~S^NSKX'',y</MĺB`JeԀN 8dYΕֵ, ӦÅ -{x9N*Bxʧ) ޕr 48l&XJTSfMO[(k{!bTW-yVrP$Brʳ:#=ŞͥͥYPPW+5ɷs6|۵bөG#S@:M Mat2)5_N 4K̗0AAg-S@(76֡Sm1gۙ(DBM8&ߘNlHέ|yoTOX} ,B \?`E8~~l"l8ǒioL2ħ imZϘ:oj蚕bC_5DsWqB &! B1XWWǷ;B B\)B\)B\)B\VR/+!J&yW=N-ƈ"ߚA~V_$i([: sDpNAJౝ}סB\ }~Fog5G^m"3#$4a銵_+>?S>?HUCߤ2euلN Hh !S893?9V&>ݿlŞ+oXMG g+ԛ#NTM=&YE$pPؓsޥjO5ykҠ%I7lSkn=Whg;K(7z|m## @je7o=Yl+^ Ji6q ~N|~dkE@uQ72NMM91>kEs[ޝ߸. K@u؅Cu|A3ӆ. p:za5㸻V,5y5 ZyULPܧ!+ϜkTP|7Fm]ٙd>nP֧-= ^uVrY Fy#Ss ht:NrCι|wd+IEsQU\WN-)W! q=ɡ" tuSRְ?T=3͝LQtr߽My4ib})Y.`_.#TBq=2>#9TO}ȣЬ9~&`+`(Q3YTQ@Xի*~|~;vn˻:ڦG<\W7˵3Og)Qp`z7;Om0anLn&,+9J)YCԫHշiw $"TB|Ge.Ma2}O7|adaómcqbkCwѮKO{CVD^|%v~Fog5gȦ߼f)DlQa1Û;qM38)y=+7֮-l:h5;暿B .| W+fl@ xpc["u,Ax\N(L=*R<4I u/p?3xƸ>_ZܯHR_7j! SiWdSga̖׀PT"q_rE@65`ộKV? kXVdc#qы/8׆ X0:dg[-f]\ۀ ƴ8_ H~yt@I7gƠzee%~+xFeuO4L[y)04VHl>_uӂQ*y8;&urr2444h@ԃ46-?mfY)Kwx%wYW`U:zʏw_m|.卌|||~"-L4(rjo&\~'U$Fėm),K~P< 6,58$~'5T)# CСEˇn;ܢ|cRB{!ٮzAgqcw7_\˙r!T8ݻwz OsHO Ԭģg2ǦvGNX I<bpb@t`-Ct+ukf{<||ïҿAŷjԿ-3O(_qdO8͝Et / h)gB& =lӀ[>d)gGh h0\ac Хްt~ 𬸻BZկjXRS>>,NK1PܽA7K8/ ~aJ!ZX!'[ u u!5T{Z9" BWR萾c 5$^kZw+`E@~V}Zߥ5=tԑ7/^w^XmR! \$C7 D?>C Bb|M\^'UӇ&P]?{?5NjdF@R6e1+ew_5fIӫ!?%"ٸGGQ*!7<؆SWtAڣr" 㢯w;*7OPɥhAցӇУ/!POzlT;0]Yڛ|j=omC>]Ρ"nPe*u80qAW[ءRE< hf=kh9 RAJII622Q"@OBX]K+6Q|xεc;uZPb3#xJؘh}}C>!e @\͈ɃUB֢]Ki޶gG•?Kѩo?PV3[Jy?WYDJ˲џ# @3}[/@yL(%=7uɰt>]޴A ,x$5sW{C^(ok$lqS*[ "ċl*ʹ&0$8D" BVäIFƶv @Myް !wwnФ[ϭ"&9BR@ڳӴi \;xc'dgXxz}Bň\˕OJL),<#/98J@E@ dظYx?>?!McV\{XS! i`#Pq8i0<oܹJS"glOw'BW^\,<[V)a) j?ʧvqw!ʺ_ +ĖGttQ*")IblZ, #)BѴR_˺N6-e*v"R"{vvMRcC~@!]]Qɲ>eRRX,.c?C'W|&7Fy{s؍4z`huY=ec/ű?BW\fYsdq[SDGAZ[Ұy[B <3*]C^WARpUNCZ3;i//n;Z!ߎ'X6je uXGGϠp93A!EQffEz#P )B\)B\klB$[:H)B4jNS;kA!nuLpBL !MV\{]&7R6磘<6"w'}]5B>CK$B1j%E3cC,q*P"Re<|hTZ\4B}K05V.R'}݌lq !AGMywR'M}/]6}Lx(4&]W_Ǥ9vwjϋ,Q]7&ugG%kfj޵niI(?z.Ո2e kGVyێxӽ&D&(]*-kQFuȡt=5MxXvkz|3bj66My7c+NCKHd'jPXóŻxwEO$5yÇ$hL+5f|q$6w=Gֶ楆>:u`P)-@g6vE/)ա>FREpsDX~j$*WtB7Sn SUrwZ/B ~T^ˢ Ѕ~}99xsfQcoܤI "J9ƠJs-}"WB_ŀmg]e arb͆#;cHOb}W Q "qc1њ:w.:wo*eEh+y4A)~{~7b51bK V"(o,8bN>㙹Xщ/т'}i*ESDS[W{>E$ݣ00+[J!hE9Oy k o^90@&< ߶^9tmXVpk}:Xg/xk<•l:eyiqr+oo~ /hݦN%iն(1V.+u].lZ|_O q;^cMFo! ǭ: ݻp*-+ӿ]i!>Qk[^ˁIlq | 5g'0IeYZػVmҢn9c>Ao!_%tt-sFl7RD8jo:B)cyJIxPD{tvۜJ%O߁-3eO^흷QaBPyy _^ڽzϣV^ۅ $~[1t41nsY(}cV~:~˥W P+w]:)-Bqa岣>%x*5ҷME#哥?T^5GbO-,_6Hzl}cn\JbUNޝ},$͑;o $3rY"/h%[ʻe~\{=B&ejٽ^O!~+^G\V~({sSϢ< KSajRGL&.ۈC E<p~9'PqQ)T__bBYN<`|TԠa`ǵ|!h^~O xB~bd"/ᑴW8"JRLG_ Vi ).J$ ?b\2kx!O_uJ{ %weZޘ֟my)м{IE閑_E aj9M;vށ+v?Oo^c[`ּZZGԌ-:۸eY_g Gmܶi^[ H~&֞6mX緼 '2"P~p&DYf,VU=M]}u ZiQCкٝQ*F]VAgׯ Jq2MeP'C 9;xW,تVQW}gj bթJeDǧ1  ľ3K`!')o|`@ۙiJl=uyk?8kvWoxB>a\x;z(ЯԪ}5G?L@7>Oxxy`P^K(Y]u]`ƝL̍u~?lC7] y@²&UW3^Ycxﭠ36D|wwvYԚ$ڡ~K7jo}2j4,:V,@Q<1 J-[5%q5,W@cLj--̣aI2+!4x.M6-0-ZHh۵[];lШQeLycCzĽ6B̟*N~)UDG<3k=>@iCY 0f٪q+GwƇ8S1a.vnRQ Xթ]Jwgiy>]>A#4u-%~|D' a&ENO/sJVakFyҗ ! (cyJhha@h`SFOh^ZeZ\IJR^F1Hb*?hr/w j4W<4>Xmp~PW$Ku=񷰰*/O_YMIN666է!|i)PH v56,<!  b2Ly2Ly2Ly2Ly2Ly2Ly2Ly2Ly2Ly2Ly2Ly"B-1XS!iP!M 8/BVTcyYVG!TP+yyu$XCc~!􇉌726^Gͼ<Ƿ/ Қ~iB?0?Gs7{{w|"EzZd[rcRM`'V$h(F?FƨZh˶dHv-dQLR2EI<_w3cn#ţD}@s3C;of]sOhQ'vW.Μ>чw Ƙ?7o=M%eߖ2˗GĒҲrr !Loü2M4o ( ɐA8Ry 'C*OdH ˅H i Xaaa$lhƘsnuXӒʫՖ9<躞h-e.t# Ș Y89OE587Gzjw/}ܛ]B1]{YC$$^|)uwmR\&!*[g9PemCC0GV?ǽU[Z?jxpsCkZ*s˶R=%C96`RJF<،xesOxKkH/|њ"WKC&yuj7KJcyX"R@{6"{M^_tHO_֦%>z_[˱.Vy"wRĥo96` XnayW1r՗ZG(wpӘhܿ}3Um7^E>pb:;@źGw:L]m9_o)YwS_k=] n7TO=|G+=ބa[Izӓ[6ZӲ%><ly Ort1c[[/67MLM4E!ȱ!bOTnJʡsegKv})?vno_,J1To=gy_?ʏ|Ž/WlהK9|zs뚿W^y_e?}֭jWBxuS2USHB$d:5%~ݭtMAv,1|HgGoʛh]+JrniWLi#*rl-Wi6v~x_W*BZ/jyr?nX0rZ?[Q)S_]k}i}$o=!,-/v7 F!)Y`nct٥sdžL e1QvE%r⸩orLJ֬hVRyRrl4M%+3V}Zc~yr*ɹ[I',P1zw{? {mDF{/D{bQ'Nӫݴ")&Ͳޮ=fw, ^vu@ۈM)gL.%'G(nS&`ɈkY"E+*S|?3 u.o2/A\6 !r[\2e^޾HjkR \7,_~0Wt FF{c}A.{7/?qqcɪdVnM=(RMA)JT qS->=Wzx޺G,w%D9ipι OI8=g;Gd!Zam1 ]s(.K܅i&OVIuy Fpi_˷Bp Ǖ_S{.v ۮDPM lێ~9bdEX҅2H*'dž ]S(UbbJ\l 6>|Wo?ش"2"W:U]U̻o/F] K?>ʋڱk^yWcnpz|ѕȁ_tMll< 7sd,/s] Єȸ[%_2 qm'?>:4\HaWU垔@mӽzK`־ee%!ʆ c 896\>zM:OILl}{G;XQ*.@gm?ŠW$ D 5gmY_[mNs(jBh4Mۨ/Zjc2{i1MӼ^gSʙv=q.-ɦ< ̷r=CҚBdv/_j\Bg.= _ eOE+zS6H1j'OI 3lP2 + e(Ȗ!`E֣pɱ!Gn7+dxMi}bv" d@~ż%%I'0G11ri"gce*`%O?te>w )J/9Ryׯ;zeեN۷ΐv$^#ȩSoߖ64W^np x=֜fGIY!>!e>p>G{8a)Β-c‚yۅO>XOq ?0]]ܵ7<^y~w -t .ݻ'X4Ť'>{T^>%K==[EbcŁ@`xd|3ut <gK7L8%tEXtdate:create2012-10-05T10:25:44-07:00S%tEXtdate:modify2012-10-05T10:25:44-07:00"tEXtSoftwaregnome-screenshot>IENDB`rviz-1.12.4/doc/conf.py000066400000000000000000000172711300447110700146420ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # RViz documentation build configuration file, created by # sphinx-quickstart on Thu Oct 4 14:41:13 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'RViz' copyright = u'2012, Willow Garage, Inc' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.9' # The full version, including alpha/beta/rc tags. release = '1.9.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {"rightsidebar": "true"} html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'RVizdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'RViz.tex', u'RViz Documentation', u'Josh Faust, Dave Hershberger, David Gossow, and others', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'rviz', u'RViz Documentation', [u'Josh Faust, Dave Hershberger, David Gossow, and others'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'RViz', u'RViz Documentation', u'Josh Faust, Dave Hershberger, David Gossow, and others', 'RViz', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' rviz-1.12.4/doc/display-properties.png000066400000000000000000000517441300447110700177130ustar00rootroot00000000000000PNG  IHDRBYbKGD oFFsA# pHYs+ vpAgz_aRIDATxeX_3KJ7H"(b+6*vm[QED.TRIݙ*s_|XfϜsfv9$&v@ ddd~uT Ig!BPXJ*r FS_wZqISE"!`qBH$bpE֩aCG| #`yppw%E:'8K>( A0AE#J d 0L,0$Dj|'5"PB E) $2FuJYU+/5USۿR[7\&d ɉ'AMWu1$5 4 ,HrSK교k6副t{e'!.:܆9'(LHEba=(%MAyiȕ3B2Xut//MQ78 bpj[p9S>V=[mjY&]'㼼qq8/N O8)uϞ{NV~_$,j0 8A2i}xٵbqZ:x9.>TaѫKFyukk#}?yo+?CX滏n<(⨿@̋~"*L$`hh_ (f ZԎ|΅}3x@b0{Y-@_N\:t զ7IBDj1@UnE^)8 qIdӝG;8B(6w>j\B SlY?Bann@ DCIOj90g2) $*.?|1|jFEBEq>(әd ё8{iٻ2P: 8EY}_rtG E!С7g!#b@$P%y2 9ˎ|O28ʡ p)amI qhW>~u̼NTnܕq ,k̨*LH?hSy]`,_Jluoeerp؂r%9 u 0\ ]/̀և⼬bsVQ{>mV"NBEKJ?$!XIw P>3#gd$8v|7UUΈxQyZU:c{^bsXJ$a"pW+5==5~%E^OLQý(YJ4n<66Eb`_J{0T.è ϖ8ѽG뎳CՏK..A֗WNF(c_0]UjRފfH}2 (d9o_}QUyU !rU"~faG겶I9i'/^i I5L"qT/XJnjW[\^0Y@jh`(݆FJ> +kwӮȔ%TXcp{+엶$KB|[QU9$V˚77QR(&8&++楫 i5äKDBpqsduN XKZ +9@R5AR]X jr|A'*ueix .?_oCn5 .ߏ-+p@Hd & qqT@yre Z1_pbV}V2X[;Z ^0X#F?;n #LR'Jn~oZKr~|X[U,W ]EX 4&9փu6o?H]T?y7 rW򠢹ZK OUTm z`"ܤGP}yEV QhL' @qBE(@E>p׋wV.. 51Qn݅G-A^5`nd6: 'ihUI4h 0WFRD⌷)g!/"@ScK2|ktv-Ȁp4Qal2!c1#32W_}w3B@ uȆ=o佤h9jY\ݯeT*Bd|1҈L[lAKܬ'W.=+(<4߽4aN{񥢿*Ae18~٩i{wbeOw0GAl{/'~rN;۠+tU;I BmakGEl ,(#G;vL gz1]ö~?8HYJ\<}!T,u]n䦷8s]#Od5FJ#X(޸qc??N?sx~ MUV007#ڸ!K&x?tkC^3Aߙ.oOQ&#[ |U~}͛wgGUǢ>yx=x ?|Mڮ͛7olv8 /8{sjQO?o 0P$tEΓE7l]o$|†;דnӞtkGOu 2QSS~رc%)񘔇uW*yU7W1\οm<ȕ>-|3qy|9<0N'ilb*"܈ Ӿb}Uik`E.%P[ ݣb+5w?EG8bo"2F:/i\W&8]>X@R0RՇ Uv 17Ghm6}T)1BUpPn ]ѢfϾ5\Iȹs(Uػ2VBz)F;fvEe)!{,4nay ^N;MG0C'k?tq ;^Wt _n}ibWeʸ3;wI,ƽZЎzӫ1@Yf]Ԓ05^U H*'g"e$R c`6V@'m3Abv7 _HWtAk僇o?P*lY5}\ZSEv?6b'oȘf`bBXQX JmQ qJvbW߿L:XN&*hK';VyX7*R##=bRG92)^hs{m.;hޙL!7(Xy=m 9oXKxDF#ƸR,c>d=~[ZKsRb j_?Xi܋<еVc YޔCo{ak X֨0 %BaҀW MMG/ _玾S2ʼKGd߶hx٠GTQ Ec{芭Wj Bus3L}FuEm U0Q>x\'T$.En=sӶ5$G^9a= /,Usaj/ȸv>NXxy53p‘E vԥsU, (;0VBLklXƀ*ۻRi˾݋"ynj9C (5wjYŲolկ c%DTPmz/\O ٸ]vܱ$\T,:_=< 0t 3UM:%rc"]&>? V9kֶ 2~?60e߈"7c9ćGu3_coװ2+=UC!t4ͷ2#2n&ү*Pqes)'lL0#QVdRƨƀC4u. sfPu<~D@ diL}0 DwV (H$?5ǭBȸa(8x>7%VRD٨N j&Xj\2)ckX o;_2qW}:ۻL]8@_:g|݁7kgL,*IM, 2 3RԹ&-dS)180GG#_Nˮ2WDEW=@q@mX|š:?~7@U1v9J{?p~V=[mjY&]BXɝճw<6ѿ1 +ψO•Da">2H&/q>V82YXKs/'*3l=z5u~ R!cG^ \=F-ť/ö:V LCg/baD%ώo}:&#+[ Yc JNzdV!Vt' @Q5uɬzJӋFl,#fDca[AYf̟eдx8 qIdӝG;8B(6w>j\B S R!c|vQygmZJ ?y ߝܸU,!L 2c~}Rk\A %l* 45uB+n \ƴ՞k'w)5X~8;6pƒ|wxrxCVS+\r3Bջϟ{ 1+Y,֘Q#_pmR!cU~)vP> @oJ3>S `;U^R\IaO6xlŘ6z(Եi:VIԝO2ykͨZ:^%oN+{tRIk}~E\J85ʢ0HTӫ~w^"E'&Ѩ^^x^u%Q7Bƀ .?mʻW.?w6zlʓRِ)1;'7-#kt:-!)WsR82nHkhsУM>>>8uBU&CA$I82g.ZR|g_hҝvmc―  :vLvnnZFFͷ=z` Bpqs@d\ 0vi"\HM .p0ys2=4L,󄕼# kkoZzhtD_a.\,ŠA(3ة3ٹ`malk%xz0X#5>TȘxx9uK]:Vs\!j1€T3 RC T: pRC7f][7aB_/&U'W;yhZ1׊^RHsmw.;oVZQ 9_%?Uie7{Iu]ϐX= [NZ(7շɻqBE(@E>p׋wV.. H6n&o`Ԥy%ܼ|kQWj^˜U[un%rDąQw^同;[+izHw5j0 jd)wυx 0nejW6*wߕw٥v+'\x)*NҩWd. ߌNn^m Fۛw.;"\W̴f"e\^^T.I|+-TeI(HyDK+pH(@ u;d0LԮC qFǽ*4!O-<'?%1><0?fji7nIKaӔ&> @g04L-3 Ia!S(,%BB9CAC2!c1CȘ@i2ʟ,[v=" EZ804ɨ&&$HɀS&> /y!HR!c@$@}ϝw<[Y^;piŬ3_3?͒x!aUNz(隷Sf%e+#]'?q8l)+jH~I" <<džԠV*tL6 LK6fTX;O;0$ uة|xH!Qqr޴='`]ܼibSWr\ĉ<6vեxJvΆl(oxj&;0o7H%;NTOFI9ЅV(v֦@$yPiϑykEEo#n.J`71(%ml`aw#2`it^߽:Ʋ:qaJ@⓫)V-識$9m6'd> jLƍt0 MIg^0MN ~9@\?$O ^HhC" ~1BI>/tp"4tأmfe 4 %Yc)EoңݬG{ 6ui܆:/ٖ iސ;,BA=ʹ3ߌX\Pson,kK!%RMQ3Հg%,{;zȑ#Gm֊tJ(VzEtcト/?>Ktͳ4R[v x1˶nY52rګi1k>c>OƁb鹤wO#ZUqi.{]U?+J^͘Rݾnڲ4@5%~7t,Kd~kTn|>aE[ ,XY%S‚Vzw>A40!*4r.xuG !& A*Ս py8-\L<k9j 29炢,ۡ3m:BT4{< dCƿ`o\6cC;yXLFJ@ Hʼ=fu5*.nYu&S4RSUş W;?=ghGL|&P'Lz"f54w7)E*:FBU~jfL<5'}ֺ)5KS\2bϡos9@װ6wfcb@*dL|D2BIO^3uɱ ]qi#kwiXtQcivҥW&\wpByfĺfT]ޜNj95E^.wf3zG՘C!Li8]nrωK_mu*:^8I˩^;o}:k皾dE>K,ۻq7BY|k>; =nh5AL9zoN_lHs;#Ǒ?yGr}ݳqQaU7-q_~CVNiBi꬇=:쏏Fʵa%Oh@*JcU~)vP> 1 @\x=XBMhSDQb],,_jĨiVuK2P 9 ѡ;tԧ}nEkņdn>,ة4@R̦ͷ5s#9,+fP6S 8V(CeA*D$@\]$dhiݻ b#t`Ezk8TV\uL:O&>$:hA5HC%? NjHm Aƿd!;/CdB2!cGdM ]05D1=MYDe r~=Ey'#s{H=ܦm>b~OI;Ad,̸x&?A,=1#D;HqvlY,zqYCE  Czursss{;RfͭS/rq1='>|oaΕM^LpKHa}贮y ׃KnwfHP|聕SrO+`Oe,K:B2ruז˵ZN6i(C.@γńwϿXu"V{y]izĥ~StuTs଄s6eqQ7<1fÇ>zwu2}mыUM{QS~ .ѥCJϥ[iJ~'ICg#*3˵TucUxQT% U;y))~'] !DܤW󱲃=~>Xv:E{>|EHd0 +0/D߭.g}3ـf,TaH1^2ћb%w,<}Y 8WF*G/Q<.=܊TԗK@SVxy!tJ'K>-ľJ:{(խ[qlG˗<#׈ %[PN=vaX-&?P 2UJ}7Y_ձs<'LqMٷgNA(~iۥl.2c@\zx@`!@ftT#cdT˘;vnJD,a#|bJM|4& hT4T7 pKq=x+o dU랓mDG] vڛ|>v}E/唐Y N& -<^g꽏m\ʄqo zv= 7_TG9)QYOEjVF컷#蠂R)7w,[oBʢ'm Țm^8UyڎGze~Nl6|{ݮ VF)pNʕ=A''d Lj< w/G |Ϗ eP"T@VaI-@a ShB4;+ca^hXG֕,(SS8|Yr=|A@gSEAa)5'8 lC^}Iqg'uz8k#dpq4BpۿYQi/ߊcbDi \J5H46=h(Yg`]{Gd9tciMn;v^tegOHh&G۞ttFSwrw?}`uʶÍ 7G/fʘo_ۭ#|m.Cma#|  _HqyIiP.bUWpfaT72M= \e9C@{|U7dLm9M ??Y& h^jWj@!dL@ 4/3&׭\׳njs9?6& -mP l;x0Q u;gWrRf$BU12lФkpN\Ɣ{GS[̽3?eM]\ܶvu&~iV }8qvTWY.[y1! 9%//=Qc\X(Q w_*9OKa=qS ow zwݥ6~Khg<9cZ{@su im +]\hV=l R"c`ٳGooftT*ޜھ]m)&{@T<fvϲ#6AJNzdVީ>ƈl "GRn1r!6(dE#}m=Ғ~%,+6^U37PԬ{M]2 g׮9"-R@R>n??c-Ǭp طbE5d^}8~u*PhD-((YD Ȍskseiq=Hty*|1.81o־vN˾s pJPʇVtL_@֡|m\l* 45umYyGNڜgŎn@S_M^Bs4h6~3<ޓ݉+lDbB+n \ƴ՞<=ɕ)Qlo6,\19f|Ȓ9vר5a4ӝh3rp{4s/!I3OoCŲ4 |(ݧPaV wAa^9N)6l[ %R V$)z&&K?o;0 hQ2|"mlIZ&]ogS27vvu[ۮ.XhD$7f+vE;']28ٱ{0D{/}W.ꟷ~GU\gqn2 A)aOw-?Uq[!Moݸ5vk֜-m=f:xQ|r5դ<ڪ6dZtfQ;<ῐ/e&}raS*ĦCuqQ#&ֱ Cma 좪+IWvG_OԢLOngWcZ di*'nudQZ*r(PrhTua;gC}φv^Ew?#DF+Ktxvk-J5~%΍?GKؿKD5 R n&ҥM}#2$z[Jm3NHӯ&oeccen[a[1I1ܚ%OrAAJQ1y /_!T&x܆$BuЇoKk$ -KM?LoAxxMx%C,Ǭg~duOnY^:v>MbrbRF*i)+==F'Gy+sM'-d@\*.C]Tnmwk;Zv QU;og@NaUP(|"E *YwR{+۽(*y3u\!d(!P-~? ~nq3CQG:[=` ̉yT P|jS?O0u?"J5!dL@ 2& y< dB2 +lّߏ@eW{Q-p^ՍStvsss9;2霄 ~?/] 8obeiH,.v'O M˶=H+nwx$MW0pjD _UG`E L[u9ȃ%q}4KD.զMS Zr?EG8b̔RBcvO4xCXumyzVtbE=wQG!+űGMc{:0m:X,Hq}"2 hŬn瞃k=>-LLF5(1saεb2KtQDӱv` I ҷup% -bI" <<,#dւ BAy8Pv?XЍc2ـ0/ ZrтnD,i܍gﺝU΃gOtQT[ӯ`vy~0-{?,cV@% 7]+Eո[ǘ`o 4*̽#:_8pm3KZ9y.utd{!C췧JK-_8'n :}LH;t/LI^?,q񫻯fR^ȡ3sމymK@h?jak CO/dC~V37۱|Sښ%aYrY:怗GQf ]FO $\ڞYQcg,9w['7n;EQ%ʚ"%+rYo- 5zjah}<$[ʌ Ny3hDH%)Y7yOGl$_/]h^?:t)kn.Jrl V&WW{S(7~* Aɢm#*XX\I^Ą+MˡK[1[^ 025QFқ.7* `WtXȥ$$!=vQ9&gR K ipmn7̀|,`B4 Rr3qz= rcD*m5kWRZ+ bx %zqR.o3wwN}nVmݏ|f9!cgn &d%M!ALnnnnnJ^q7A? Q Hx{.)׎u~_w&7$RQ(&7K6p( :* oNi gTg1N.{"֠p`v\sy]U+_9(hY&㡛fe\5yn {?[BCb%E*JcDv@{fҿ.>ڭȥ_>Sg)Z+q1w%'Qێ۳ϼgH&sG_hʠjY鈖a !4fn=~dA   ^iK#o*viFlgPˬyk&NI1BCN\.[o̞.i2S po>xoֵݘ-,[:c\ΝY=7u Jdb zu5P x?8Aq|: joޕ]f^Ӛx& W9o7o:_k-*'/ܨW_koxq *u͵23SoQm ɑWDX6 Kzذh&E^)tڒPF:d @j}1DqR @Q2u*O&GdX!RVn?5߇zֺm' l-$GbP@UpA?m2|;Ұ+o|d3ޮ>cQub878@e-B@bwi 1qeSqgbԯ*>_o#;MjB=&\t_{? a#Ȑ0ȸўGדC#&> %hdDIE L8{篌$=%h\Dwv'T49{lGbGc@Șq!zԹhHŀ@77_=Mk?!f/=4#ÕjćY,4"RT&>s8\LQ14r\/y´˭ j4=p]23}"v]$XG?X,@YFX0IFN}]Ⱥ$XE\޽ssꂩjOOw~a#;2"nCWuqIxڍ}0b< VP);r5OW)9:݊2u$RNȵ;RCk~f:wm[4XJ+}k.n?{7N-h_uq7l{4R!7Y?ZOq?o,﮽*'WnmzǗ߉_v MoYQiis?`ewMeJ-. P}%n"]D*d,&>n|%7;$p@pӖ+<$z$4͏&r.,[vYqR cN2tħ#λ|jZ/ҔR5 -Cr˖ZL{_GpvɰwJ&-„ǎd3;Xs"&yfs0VhoXfdCM9qЛls]%*Fu)|IVܝoyOAzwGQ>P<> ;iaB^>xL}@OcPRtXM|7HgCCl)*p‰2S۾ǜ@$1(bhXv(quݔQ닝SPpJاCrwDnC?}`uʶÍ)t1W!_x +i٭d8~$@Q1un8{&IHW։,8Yg`?[ڽEƹP^΁G4NMGLʊ"q8jvuueEyiIqa~^nvVNVfMuDyEGL8y97n8._mRM4Cs"S^b}2nHB6jQRXD@!dL@ 2& y^X눠}7s`(%k#?T=")vM%tEXtdate:create2012-10-05T10:40:10-07:009%tEXtdate:modify2012-10-05T10:40:10-07:00mIENDB`rviz-1.12.4/doc/display-statuses.png000066400000000000000000001603041300447110700173630ustar00rootroot00000000000000PNG  IHDR0JBbKGD oFFs5Z pHYs+ vpAg4IDATxwXGwz(G#"{Q?X%{M,w.*"Rz}wX9p~#K\ ;ܬT!44C'N477|Q@-oUX8r]!صmx &nGrb5/^hyaQln5]+07wُ/ӜF5eCV̤=r?,Ejڽ&w҂eFijs'~^ZbQ|exx,kw9H ^~%?'ƨVmZ4g\ޓvv|>/:&~A@#\021*]|ǷQ:l<|PVO>=((C? ^PiL ]3ߜX`5 eoӶ_ikd}|G^Xgm>qϹY޳cEU4w0`S/Qs3c2L@laL/KU,Qvf-G2NEE^Y> BS g22mߦT{4"@bػ lv֭:h[b fm"X!{?D&_ qk.'}Md7E>V_,*)m*"4f̠B SR 85(=}< (D bPԵXYX8050[ZHw﮲]>E4A(=~'sagQEcDzROcǒi@bDߴ8\\IOx,P`s23fzE=W }.Zyk `(ؾ(K2{.q1 !`iiDgs'!4<( APZ-$yK #Dոh &lL ,LMF,3sPMS tJpEsS @MW$pW8I:{JD-C]2'H#6aC!H$t_I.&s*E{τ`R'9E$HTdw$ *2h&0 |ɝb TG# P( kI 0 p8 aa:waX]BQZFT;$Ifc>W%%A im;1E] ^2$ejj֬ekC#Ymg H7,=6}M=pqD_d{aVyM>Z;W/_ֳOm织TƔ+9QɎ8u8,CⅤUQ#ar;|X,@^NNm H]”+ՋUL.3S6-:^<<{+E@$! xAoS>_^yAa˽R_-LXApY Oy#8 a[5ѣ2W)N[SFPa |J ww}Cnh;4_}iy3 p􊑍TQLEad;VOco H\.ws ӧOr,_ƔMk{Syׅpt\mk1J)WG_7qIs}.s'clGoIrf_}řѣ y]QcoS}>ݟG#?_gQg)r8#jT_[ .caэ#985o?L)X VlzV?c5z_~&NXbK ^P\E&##׬kFfbO}o]ŽP5ⰀM$ j7nXX?.OY"}AF2UbXql+^'yz|PhGð:$L oYx}1S n\S?j!yAN^#Z LHV̲Y7 $it*İψ0 Coy$.hS.=\oF;#=bMcVmdlmá}y5HG1$ I $Ǚۓ >Z s Q7U7N6t͛))R* ObZ$IOCt'La&!AHm#[l6['mq0]0 tHaN 0 8 aa:$FWVVV0 >ٿ/9)vY>&*?k 0 bԁk幩yNg4OKϻk<+5Hc}ę>PTS'Oz{{wةe51sK``(Ϛ[8\u>2~3hn4o)3 ma҃脴<9$_ل_.0 >/Hm") C[R]g}JuLLWPPD8ټk3Qm0Ln@{9̸eo]*IͥN>lic˾~“" oh ѳR9n _7[`JoP3#q5<&gުc v8,׺mj\)5Ǩw ;vg(gJVЮkK>ð/īWX:I$. 1IjN7] ,гo^gi ïߺ(1gPAͬy\ +LzRTC 290 zN&;:QuhnR%.=NW:= Q:}=,[F}t" !R>=r?LJ/֭ۘd { 7.Hglyvfg )ğ44( #74/JIYV__PYXB\Z<9S&'xQ\>, ð:D'M>P*W.Q4ckkרQwDߥyOF9IObc"kӶٛ9cTa0i)uytCɮ.zUV!IE^jH;a;҉;l6SΎp툻Cǎ-6unجk. r\yX(nzz&פ'@%؞q/&+hP‚b""$v(捸<0LD@$p8oP[GUX@^ Js (CCO{3##Y@bA xb(K>;ޫ*9*5u ɝXU`v^aX}]v嬬LLLLLL\]] SbhcsTO >r5)}J9R&e=Jmi.҅gLnGEĊ$tZQ^rN2>*WW,ɋ}R,I:/ z6(/U2ʎksѣ^BBU0!cd'|iY!Ň^fڳPW0 >' Hڵo/S1yx޿}cW `^v3W!-?x*HNR5qvؽgAջ’+6I`EqIH= mC𭃺u3(>< $OjرCC<zyk{iaؗ磥0(AXxUO I[a0 8 aa:$ 0L'a0 0aY@bONy2g0 ct9$4ȿo!kگ&- X|=>-`0 H6EQs-4w#H] l]{a;HE; bb $ͻ7ia#3^ O-ThH_`+ v 4ͻ1%Z`,kg%0 MTN\JhOezvTIFF!ߧYS3>#ϊy]Ϧ\ӮsoĐk$xm 0ݥ)KHPw r&"偓亅6VK+Sуw%^^=)"^eܥ" 0çj$MbX<#H2KWW(=+S"a\=9[o$$B0 H,=s)f++"05h UNFHLŬWW7@Ij?aV=$R܍7mvtxJc "Ze!%Rmۉ_Tgj8J;J(; 0ݤ upwo}@@}ֳ9j&ƎA_7D܊9A 5pinc#b& HlC^yg>҅:*צÐ/:stu 0L=$ 0Katˮ[n] 0c-$ 0L'}9u͛v1}a|aJUŰT*#tm0 r@){ _#Qf'$fh[lbl)ѡ93o8]$tol*L%C~0=QE)Y͎I An)D>,>C )RJNb05!-/J@C1q@TC-=My,^511ls'O#$I}iŇHG6nXtA.Wd^&HN" pm<|,+z#UU-pmN߼inطšW{a5 >$QI1,DOlLY{i,F ^o+@)/lDkh$WՓI^ )3܍X4lRkI[8[ 0CɭؔlVF@dG'(9Ɯ79q84n`O9s%風3'*6kd.It\ݦgQd&er3ZS2aXWQj ""ny$`R*5%_:#!b UQ36Jj-yybDi(j-y!^8((C\՗ !C QS +TiK {{,̤Tҽq_ZLaSK3C|-|ckk =|3 B1$OV~ fq!?N.):Xs W-HOL/Al*ޭ$iyC,{3G! |}Z H\BM/Ng %*ҥYY=ŒUFXQiXFֆYIaf ]0Eӣ#26R|s&V^;4 x ]dﰤMѪ<eRe%&޿wa#0@ZS=-+R UEW0 g(A-O6_ػ"p<ªϛmuqX]V0 0ap@0 tBHڼa³/ȟ|San.MMJS%S9S\ 0nҭmzq)ðiٹh_zaN bg{(ϹN jO~xtQm>]:k>?q?ͷݛs>)*0\KÀ;Quj]CÐ@Wh2H7insQbuSw-]p\^l`7lf/䳴o]3y):zwM6Bm>Ĕ&<9zq ?ћɑ*Lll,-m4obN=+~vIhjgomaidϑ@MM,]YExӕ]S$qia^l<`z,a Ή_BlÀGL` HڼOʐޡm^|Ԋ[@E^' @R=rviæ9go}aH7&qJ6"JKWPelJ9PUfFS@ z* Jj{o1 ðJD@ReDj X^b0GݍNSlHL1u) }!62?M7M eR֣b.]# 0ݤ )gІY+b[g;9߽};ö nƕhg`>ȭ6OE ; 0SRk}n6;tư:0 Q8 aa:A! M!Cka'[HaN-$'+zjS"\F&ʦP_hB@͵p.)uu0h5 Sڪw^o M'<1R?a۱.5G H4=֦'F`v@EG] )=5vIZ;k hJ[8ªCo*- ϛbi~LW0V"c;hWR=T,>T$/o|eD,"cބ4jM1PZDQM!F%}OKhVEưwP] )33sȐ! ݻw0t[TD#DQa*y *Ŗ&E5c11 C!J}'wZyOK#ǢE;[ubػ. 8ԩSDFFvhTqO9ϛG$*I'x0ԥxB2;v Fk&^!!)iϑ3y:yQc;ON#UY n!auGFFFU!&?S ڊ^;v?~לF]Bl&XHΏGkDM[ `J* @?:VҴZK7M9Sr䵢篖Fihi+00LYacG139cbOT!EV/p܉'VaZҨ֏IQH}b H@4<,P5bieݗIm?۶;>de@na:aDSL^z5Cq0M!a=$郱GrNjjk',bz6֚9rdO'CE5̣U>zM78,3RGt*{E O5vGj e2=>qUcC"XZ"YD܉| }5."JCpV|̩>?9XM ã4 )>Anǝ^U" $<}C!\a~¹O_R<$ @zML{T 6۠>,,R$'E"HTC< ݢI *2hpjn>I -PVn -C\ȅpmdϹcH&|6@IFƃ_O9x3JȊhϊGUE,ϐ_]AmU$A_9sjuOՊ\N$x,4PhqVj TG#ΩcckAO$WQZ@6hfС-B@(R`'Q_@r?Ka0 tnps ð/$0K+]vϭBs`m"fWy?t㭁efUV9,|` ð:SCQپHg߭Hhro"cVmF[ڃd˟O"w~]dݧU#@zx 0 Ϝ;VB̺~U1 @fFa:Ӹ}r8fl46jڠBPW"nq˲X`}wş!nbT_?'&1bTOJ\NwkBY8^]`rvdD ʛ5P<-dsyܣ41kͩ Wp=5]p|@rlR &l~la:߿ѣG322d2YAA[ӟWm=Kl^ys BdBMIBPUsRҀ WY_иI[S>Bոv ujd??'C2A.# *|yG=bn#`hDS IDy9 T/Pv<5`(ؒC䕄N8VOW|5nB99M4y'$6 (0 >a@*O>gP?}ӟ!E> EV*FeZҟFc<ޏ:֣ GZ|kh$y&k-2}> {LH\^b[OEZUwLEIoI_$ДqMMYͶDNioٔ,QIIOy$9),Y@#692ngԘvI( auܧ<[ӟ3O<6"v/-T}soW$N}i4wᒶHy-pH_°Y 1#d-_1)ub'7(8]b茍Md }J uF F&b& oR+ȫ'֬H*8ðz9vR?܇'t*2$5[(7pXiS~#oz6kZeoA =뺱³×)*$px~~vFɝ) %y@sk  pniq5ڳĴճ'IT|h*N:?fTOԪiU_PRtouj,c؞K!jiO\[Tsn#@LBF#w3XQw}>A!9>+Jj  "*J5om,$b^qޅ9[e];4zLNֳ$ع™EIw *1꨸ L-dqһ[z"6 q"!(;N'4ava䮅`fNVNhcm/ k+RMaHW "Lإ@·aT_x<6_VI@qM{qGs@(\k-nvUm2߼D&O>>1\&\MA TPғ4hzIxm;D?u51-K:#.[__+ ð擤0t)1>L)??0 jNeaa8 aa:$ 0L'a/" N<<]0 >n%X7RL+aaH=HG"o 'Dž}%jQO7k*'0 {g6 !ct7߮K/r9*qQ597upw2Zj#O<~ڈ^mCCCC[v+{0cw{}t^oQu˱,lUDsxƸr2;~&iyεX=Z:j ~#޳h{7#)2vS~k $_WL3޲(o٦M6mZ6.̹'{Ƿu1m4p?K[o+= c{Ԋt~GZDYTNG!n𑺶Pٽ5se ߸eZh԰W ^n!ǬJk6sa@siɿ8,Βͥoh LV]ٓ[GЬâ5?9;:ypp9zwrdӾK҂g?}9߶sxcOE6{;kydW[#S{蕩3LimV/,BZ﷏r3s=0?+Q1A{wV a tn>QBun+9D}a){mk>|p:_X'|;@rl@yqaq4:BК= o$ܜwb-\ ;ΝB*n$Itk-s+t\]Px嫫Nf}5KLZ46F]'e:xl޲Kzua^n(2\wg,"La{n^1tB嫯S#R0s1ch?]QcVl=(W4jJ}Qs+WxrJVŠGj X~'ξq. B_K8:AYT ?ê%RZrvxՋKmɵGryMz8 Q50L'ԓ@/KI=-=4L|xۄc?p?} 5}5^8%H PK~_څrx{ھ~hܧ=y]QX]EHuÿл1YSqfS'0"^~lcq#VOcmNw}jE= Hm}tAyfR=Ҹˆ{G6Z˸WVs=;y닇-{ Z{yW,;nh8ρ;K{wG^}hb4eOC,oV~ۣa%;=׿/ukyoscΥ0oZ@'\M?]vݙm?\D 0:qXg_0 þ@ 0 UX6"Ш.aX}[HaN?-$'+zjS"\F&ӞB&ԐM4\ kSWiMj<:֞[kvN죨494u([Zn=?&*8.IkvI1 T;kułO{ϙ89VT,ꡒצ5d"WyK@i뉰-a=]h_[~sRСjx9z0Kh0U$YZsuZHTm1*FR$!T|TF-Mb؇Ịi l36:j xbGy<"QI:0ɠ.H6 ߾9噄r2b5`(n0\nVRܢNW+T6-B\*>.Ɓ2 >ߤy6fJ_bnNFں7Ox+c?E7:%zȟ_x˩\-Ļ?tvVy~Vn6xTJ69JӨhu.l2OJS}h]gr@4*7ayvN/T`#d_j=eK}\@}s3S.<.HC B 3ه|L dEͥ(3Am;9ww-^/,D6M7,@3kp~-svcN\[|@b$+G4*MsũLn4!2!Ħ$!`o$%rC9ٛOO~"ezȧFI:"u5nDlBjgsD\/3j <9TfT֟T=;9%n⎯wB)r6tF0аe Fw`Ru{?<㷿[Щ,ڲnA?66\ÌlӦ~m(5jS6,4}u4hSM56g\9{tj(A玞{g$YW/?ok'"y+jbL*(336o?.n>fXV%O,ݹk[6e13}˂Fƨ TJ~l&f\NP6hҮ+1 njQ'lyV'i]j,K:@q5'''8 ՚:Q!E> EV*FeZȰf;KΓ~7eޠ+@*awAR&ien6+S!"Oz@)\ʲ?=S>b(xGOׅ]I<5P) ]wIG8Usv5 '[I!Ԛ ~goa&Whx8r"Nu?GΝXLȵPg6_dZ=mPN†98+|ơMٸ^'Q;v-+U#"{/Gh"R2TnGK[VG׮7Y:koɀRtD3勓 j(ŀ_tDoW< D1@Y:o7)2T!oy[gƃ,jxژ8w:;qÖ! ~^^s ,XW'dys+dHOJJ:7:7F V5q>~Z%zͰlB +k̇)iCZZ@ w}1na۲o?_zjbSJti) <f}Dr..6MF" c)x`:[sձRTWVYXLZH Fg!ssh^MP>ﲫzWwjgS:p^D>VzzҰc}؇oHU{9ε>I{S* Lqfk\ ]"X}R"i}$niNV@HٸKz?_QѬ+āJӱO:Yx,BMmWV:L}+ױאSמq5S MiwthqvTLlL| :>;ns A(U!l?}Νs"-O= fNkwn_?wh -|?5mCa_=<4*}z'"杧~| >?9XM ã4 )>\vq}eO$ lY μ1zdj|3GH1^8$H--|ұ:2:^ͬ\I{cS5pso`h! w֢-;f/%ްl?p ݻLW݅/۪U+wmyL 0֭C/._w=pۮ_VO _[sD_1-"6 cBQ/_);OK{~(Vԟe9ʍ!e+m [+arfY`X÷}H s&o^чo 0t|"Y 5$r//P w3wYW06ri77.b_zj*V>4ZMa(t=-?ڼG*,|LZ>>܏jHaj%ܨKm>5ȕR`0 tHaN 0 8 aa:eS0 (;&Ȉ^f[JZ;94q ~ٔe82aػЍT=XdTVOXɭI N۬ k{0  HLq?~Dz8k1oGPݿGO;T)un=t^.";I,o)3v0UIR`g *Fh% Kt%i c~> /)X'V/z~V-~^2:aXӽS*^Sïg/U[bF1\Zvo;gfR۴6WbKV>Z{C|cĤ[57a'܉+@oMu04|l :3-خqp;܈A|+os 3`UK73Xr 6HSߕkވ,f"'4Mm^OUM+ж.whPo,m˫GfV0 êA+Ưx`EA²%W1$$5|*wLW.#<0;ʰ::{ϩ5u7{)sAfT3VFIWK˟) ffhm潇l[OS!ˏJ#Iao-Jmnwq?~ԉIIAESN]ƎHv<"MN+`sG=(-Do:ЂS׎hPps粫䷞\`.of%^)ը)rgPe!v"mA>aYaT<5'1`ފǭȱ @LY>Ad׺)G<3gK<qiߦ -e֎gְόI#īyl˞WV-߱va5ݿZ$ ðJԫ&n&x?|kol=a!'{ߊ°jԑy sMYpiۮ4nS>A40 >v˕@65spw0 + O,qʈc ðzn0 0 0ap@0 tH)Ks9=e_ODf6vfF7c7:ey ðOD}S91=3VD< %ׁxqq/ܿKat \c7?c<=xM?׸]WR 4FnǏ /+82ώOP'H`(NxϔƆq=[_K{XId"eجYEF E@C-7"35ݘ9IEb7N^Yl}[3_da5?w嚃72IX45~z֝7[F6˿@0Q-'uIg}ҦG}[y˚}l+_`H`h|-;k`óG~cś=gISyR&p~퉗 qˁWLѕyW\vhuszvųo {lڷlLrANE֭kBQwM)$$$&mO!"bV;jBiSw{ bI'лUHHH?ҧ"qpbY-\/~4o2~c( T|eBː>khj/).*qjt/BqQ}/.6Gv5R]Vaul 5k,be9խ\;znMnM?q]y),*DeUىčnۺu֭W\H,o27aUU ֍ηmlGmlߗh7]{z57qs轢#qfEo5oI}Ls.ITT'Viyo:`gXB Fey7SϙO})Mt:qbG# p$!e_hYB5i OKQL1k9~cWN=|pڐv=f/)TZKq:-ΔU-c؇@ă<k9VD@b8XpUGCK=e٘I@ki-y~g\ 6$XEpeho_]4oMF>{až~l,[Q aL"k&4#}0sЉ6?!BR|vsp7$%1Ӄ,krd&RfkCz-",|,!7:Sh|;c~ll )i{OqNe {ު+gX'.$1cӍ/6ïM[ȸpE m; k+cԾđKmka'%U*j0mi% hf cqܺ;Gur2iq{l~H莙'QiaD')}zuM90k(M}hs"X}.%b $ܰ䲦̈́Y ,[a< c H}cn$Ҩ+]֬g3*Yq^ w_c 8J-B$$]]L|!jmn2pY[ɼug]3w6)k5}aٖ#wک=yK!QOdȼ1𼉤Np}[ mTY/qϏz?t0&~CF.7S˱/Naou"9q?dٹ1o(3a}teytLtP&ab@֯_m0 Lp0 wV֭ٗ.%%޴E !CdV1 CSbJ$bXY)|Ԩ]ܽY!XyNXw*aԹy'(#Z`^F#汍3bm=}kVS9 ],=ݾwoͽ{p-M#8 ڷ/pbǎ-Oư:Ido"V='z3CS w̻$OvKa51RQfFΪs瀦! @ͥy0OIhJ[8ªCo*- @@|Mg+Q+wv1|A yn%S#bà` 0 E"#]\roϻuMP)߷fofovSN& aBHK@SHA4PCiE!B4- =-Qw~[mAu-!C(WV`wmnn‰[{yi"#MB B|߁aTv[V2Q'j~U)nNu30a V"pSNyzzٵk7d_d dYczLa2ҥj>W0lPݴA>>AAAU-&J 2B1 B%= \!#Uye}H)&\zi׎8G hMVҪJ@ԧH@@Ř09N_͎hӻb:a-"~bg$&'=rE@ݍB:=^$m_~N8eL[PfgR}T1YB^@!EE-ZT)3!gHPT|)@QǔY`n.Yo4< @hXxs8 7íW֊ e1ZLa66_+ HLN.F۴r4R1Ci+tMƍ+Ð!11WWDĠÿ mg0dHHv]~S#W=)~zvz{ˎc&v|<%z϶"ڶ96~ oZtvY A"M1yi(ELO7@oMyP4. ;j:h@ Gs=<A'Pm}= ny>] tzJwo$.()TӮUvZv^ Q-$e5ss5yNNEii<B*E@ @ B*y}|j:M$J@/hh`=[vmEMhiLNgevH_x<aX>UgNr= ڋ M|D)cbvX?*f'Y6V8;aX>U@ϙ %*smm; =1K͸J8]ḻWl%?D\e/'Pʆ-Vp ̳IN9kt=ǖ??Zr^};eG-`ߣ?ht4\,8N1+#--~c[>Vy`Fڳ%y +Zq0^ь LVPP~CWmaBU?'My_ᾋ*N|kgh}%[mx@ ,GYƏ?3ATubŭ9$6,xPy9PAޔSvwٱ\,,S<9( ոyz!'2ĎK+ Sv?{,h̡K1ytpv& sώ]}vVsDQ~Ab{p40<9sBa||?]snǼQuѰ@!_ڋ^UAG3z*kղE UfJF(yj ȗw\w\wS񳰓O*rkoHhb¨O==(?+l=XfӒ3l 5j,Сa=}@i@'gXz?lͻHN4KL!2΀e&/m'- @Xm#Lp j6ݥV}!6r0 0דaV}Qv5Jg+~mKVML}F? o΋Lgo;ysl I4o&Ibqo~еpސcr2S.{yK%bW+Nj0 Eӟ"Q`dekVO^vg9@ilIREG-Qj7ㆦ+-7|[0 8 aa:$ 0L'|L]v쒜.aVn%X7RL[0 ðZQґȣ0qaz|'4vzW%5A-azB{1o%WԇL;|7upw2Zj#O<~ڈ^mCCCC[vy?Zyi=Ӷ5]aMci`oPQy 96WQ 0w8auOo!ih͞[{ 7n;`]͇~AUĝNf7$ 5ܹ:}.(BESP3|R>T`)9ysF + G)!vmOK. :6=n?tCm_zuyN Ҽߗv3޾T%~hܧ=ߞ+*EHuÿл1YSqfS'0"^~lcq#VOcmNw}jE= Hm}tAyfR=Ҹˆ{G6Z˸WVs=;y닇-{ Z{yW,;nh8ρ;K{wG^}hb4eOC,oV~ۣa%;=׿/ukyoscn0Z@'\M?]vݙm?\D 07]Oa!8/a_ ܅aܪxg,QhTm0-$ 0L'ԫRޭ[[f_Tb{{- v0 ð?)|Ԩ]ܽY!XyNX aUt]QrZ޽r6<\u9ۜ͝2y.\ر\[$jYz9&'h!1 P4rYɓQ0A>9~{}{ǟ2Ghtͩ;m\?jſ+N&1Aϟz2M]˻=rF ?WWZa;Fh%+hV&444ͷ?{hD68g]Kv>Yw6ec 6,5TyiӎX}8]3V.[vKu<)BB  *2R?0yoOun憽]n27'Eu>s{8 ז۬X S>*}!>p]cLM+/>vI=z \$xzd仞4##z}򡵝eqar̞oQ ̪Vru%fV/_*⎇XnC H"W&nC }TR{ڴ S \7 nuDF"T vKܺD[T~L'2LܹRO MU̧D-xKk$:nȼgMRl#}*jm·]t{=~櫖:˒߹=;FztaiNu9}钵66bmVfJ"eKGxA<yO$A>h~lI|ROӆf9'K$!x~S\*0e;[z]mF@dLc pZzGl6g=a9E ZMmܔ;)u㑪ԫ_|I`qꑬSwT ǧYk~_P Xcm9$kg@"l Y@gL|.Z .lkdő)b?4uNLZ1l+\4 D|.p:+ss *I[H^ J̳Svb7O{<*%GNmyx؃L%ii?wh.o{͡[i Rr }<%o }cWmꓴ"5ȧZp;{;P˷l2i:EP \Z ^z$@ŧ=f'Nz٨C(f{ن>—դ){'1D 5_q{ءհv[{ڔg2ZttCMk?9jSQZwT^PRYR14: ()^3ZEAk%jbK$}~uڔ*,:-aV,&vA,b&9ݝl#sF#QgV$ӈFyɼ~7oܠyCӇ; QYLޙዽ[B˷0oIJ-jlF+Ȍ[6(dÒyڇ3K ~U:ŝыy- 3TJw6 y:wiNes6˸eG>FGg>za  n\`t.{&,k@ӨQUF~[Zk&X-:7%V99g$(-*/6- n@lMpGvI:zPK]D@mOϸw& RYo3lZAMH[67$}ȂCC!}Tq$r ~Uӽj 55s![Lu8܎ 2⍱ zJX͌oZ@nҰaVKLE^zqYYv=, ){rnYyz 7jFZZŊVvYg[R_&nWj~J7nZP~ZIi;761! QJn:Z,En'VHOu>s%\4u-gUlwÞ6v3j@@C'2ߢM6/7 < Җ!0$y{I +p3?saUO?wP>F:Kl>{}õ$UGN^7 :)rGcAj?:zfl-ο;M3nۦ{!''ȻZ{*:L㻚ަT_6ؾq@w44ϸݩ & ^b[^ywT^Щų_G<jV{,k``#+6xHyգC<tRVtP=Mҩs-;-+U#M*ӣrs ):vS84SGR "5! =xXd@[վw@wSzϳBWΑ<41Ps޽ L*M5U[CiN)]⊔ WN]5iRPEBD)!%RuQi۶9j%i;5"r|Ye7m͚Ww|wj@?kq!*'|i3֤-cg&jBwΏ6~ dD&26= rvtt֤Ian"*}pҹsȻcaJ)k9eCI3cE{pX{w=XH kj{0Ss5#!j,@@"n~*y${Ohi+ɤY;sŹ\SHc2긎S4]Vd\ڸhi 7vтחȰ/sX,?[o1! CLl=ڙ˔=>l h_1Son*yT{ު>-4sbeJ'KӦ\pը Qۧ;\]GOڲ|Oe_zRKlm̯y@@RtY;wMTsئ-F-6q?~v*suF -t֕cO#%;aO V2c`%]ҝI/'ݜl%@`gޜ.l fUMEAE\(3X๊XS'/5FQGVo9i@[R>Z{C|cĤ[dפv1L7PW ,cY?;~N_M~eÌn^/6Ǔ::Z`olS| wgDž{lKnm7|ЦYߺmpvOM*3cb́tIz'1'EMxVڞaɏr!w6_QLZ|et[}X? EMRBs;}_F4^֠iI*-$S|Ea3 &mIqU!l]Ggp@x$/up`ώh$5W,9, C1@rW^ڮeVge d+_fe+H~a.Ӧ_<" ^ 2e)sAfT͋V<c~)rMpD$m =r ]M4#kMtg:. ݭ w(&(vݝ(v"(݁ ؂"tsr?nowvvy~χ$-$Ar~C_&F䌲_n(aY-}5?v)ܽ"C*I|r?MmFHP@BqO K[&:OM 9i=S*nAkVMiےyHj]v_R#Ja )e bf7#]j( !kP bwᅯ\y 48 aO^pPfA@G~}`w5vJb } jDR`}y9IGG;cQNТp6 ykn![ sWG/I]\8ֶbr}<;x~,J ע༒rLNJ-#QeeH !(}xmq}'8{|Wqz殺H뱆\0NrEQv xghv9kePC0iۥIT2v—~x)5e\i^ X$mbffjZ]AF?]3̽N^*Vg>} ȊrO8>u{jˎ3a* N7ZR'ɛ53qUvB<R %7wDE(e|}g>1M)g$^==H.^OIChO:g%HjNOpXXy"6w}M"uϕo&޾]kF@zPʕ7d&laʬ8Q." I~nO6S}=rVoɃ4-LcH$=5bEgY  V~'cgLYFq`Ko({*PefZ|qкJt~RguIAP!ȎT[$\s^~?IkTxzjojɑJR^ OEնݢdzVx;>ʝ޲EIZcM|$IMC-)%ULOZy偽 ڶ*=לQrT=ET9]KP!1-oc}"oԗgNECB$Rm=t!̋暹@kt!R(A3wY5Փ CWZ bM,adZ6_HT:B@L}#  H X@ ARyߚ>J^JvDğ&BAA@"Du/&98 $AIsg)GvhPg6sSojټn\V.kR#HհoAʵoqiR qY0<">~KK{L_7WKˤ ֬vךAZ DF_ɲܣ#outj喛29"umM=I}YrpYωKJ`@p옾F2q K 2Aic,$ŁGXJa!8tϮs̫h_knoiB|~x3}cv*f:xh0؀śYP53lIq;L|Lg30Ӥ=ie سJCҢ"?0ڲ $06ݍ'EUZs{#H 6YaHCId;)x=VvvcW[j=v\흜u6oAg@Qڢi(^*A#FTY j2W]IM 2lͥwp.84$~ɚnnFt`ieܼRgJ )Z;C۔nҔ 4D}8}s7 HT[noi Ryܕ[x1NXp1^ aïF}޷^yIGZ dW>@2KAF]2w3'wfDAL!A tl[xޣ/^zY`D D#ՖY3WDŽNmE*4ܻ FUVgI\[ ϸr u̐]KnoGTZV&(zȳKt8$Dsx䜨T>ai{( \f.KCuHĴ1D;gTb`c:]Y0'cӌKk bJ$%A@_yuUzGQwcprHf׉ w]O+d wk+Iےu#6s(Jei0\v2qbw- ՖAĞǼ4lN}]qr)̛T0tU@AĀ H H#Hbp!$Y{ABgAѡ "P@BA H X@\m.YA[[=:lv9B?=cP6v"2eiQaϓJLvDpb&eE?My |ao6fm抸\Dss`잫ޔ2ыfws&cEn>ЃfWG'gLe=5ͅfƭP/(Ogΰ\3$2{|94ґf3CJ|g65HDBSnny&1pb;4#JI \Pzp hFչ4zٖQd5i/€"I/;s]*EOnީ}a(㷅37 4M<%QSӪ$8os[n&QvzE WwDwWOZ{ %Om<:wS5\)1$0ɳ:%ͅ}~k_GYFqHVrj#8}?oӔd)MCÊ=DS]PϿz^%(L<vz\-@M׮WxAxͫ ߩ9l;O(׹99DvΊ$.1dҕt +6srvD ? ts#XHG 8$ud򂯑N]6\ԙg"omi98H5ު*)'#,]k/fYNW*/A5T7040l]38(fVg+ @/ tXw$eCY ^몊.)$ DAEd_\b$ p>AZq HU²> j2<.OѰj?'clp@uU$c$?s\~(Q%- $N81ꝴ(SU;En@7Eֵ-{t&wc?p>B/ZIAVRߧ? rb^VFhްUպ '֯ә=|믊 4 K=JcmJlyA1 &,B}rblLBIyƮm0sl;&@մ` &qfGw,Y֠nmj)':TBr U7.%fm+NIXpFsA)m]0?>bOGF#rT%Ip_J~*m(ITtr_}'*?}TCm9׮uEO<a1\nGFmx㜜?ƬyT]9`h<3$D8.$04&ٰ= + KAM._1Hiԧˋ SW@RWW5jԝ;wڶm[JdddkF5U?z.9I@I|#BsRlH׏igd FkI/3:!l*I)vwbƦ,+`}c:=~\Hr}vGYʙ-HhQ,G& )or<$S)j(?لF<*yxy![bлDE p~-a\տ &  ];Bs[ SFdjwmmm I~#D 9Ç t>) O$z't+ Rnyړl!|2~TqFax&X4 ao32R,FtT} Lݣu0T5vʦdpMI0 |ᳰ#O ? @% G8A ̷_zpnڙ 0rYYٱGsJp4iih4SRR-ZDiH@Րa  Ax^f2) E일bN2*yFt~1QEs82S=mBv;VE B k*C K/cq6d~܌:4 t[Zkna#}gBbCbrk,-{cb4jG.σMMM###tc<{r?#;9h _ @S]%mG0 _WrzrjH;D_K>@a$b3 *eˣKl))BBC㸀pNA'kqiғRR_`ccea[p^S-\Fy{{ga*z@1U[2bQ_\C%~DV$(=#k"ɑH@~WTWU"Hd1hPEV$W@RWW?vXF'Nϥ]V7gL$$EQo9bCs?2?p\D@nk sRpeϣ# JQz$ R3fᄈya9Q19y գI^d4'Fxn3&@[3S;6 \({HH Sn=&cW9 ٯbY*_#kkM!dOc:ka_W$]%`Es>cY^WtKyx{7nTgJ쒭{o{*i0ɭ8YHkJu *,w|O$JUPA1@$$eb1x:XY?&| à쐖9fnxp.Jd*CGs5 [D8d>Pť$1@h~zw Zl>R/e%F 3A%YUѤf{Z,l/D@VUaXTUE(Jd R!P%rt4mL/ `PȄTXNi@F&.$H(̆!JT[%* D"Dg*P} )SUœ[VOǷ} #̭/V34aHi(4AZ0jdΘA׶ a*UVNE#i")d6w)I X@ A ( ! b$s. $ZF@zrQOB$hjPٛunw AE^yt![d ,Q9ATʽox1_kBi: qi~=|W}&tՕ0 $-.!^ST.D7v[/V[0bg֡A~T!5J _v{κe\4u-؈׸ts?+ʹ3Kd7IɍqhW׋_uAZHϵ{6a„Ga'.4S3];p.^4ؑ= devRofcba& ‡S-)a|ViEV%aɎx<%IR.r10 (Z (UΤnOMݕms>EO@YL|O O\=qϽo^4АP o(lfu9*t)7ɬxD9L{pb݋ dWA%A[^HަM:ҟEs/D$>|k#11MMbO0f)!ȿXT'y5u~2Rf1Θ{25x$)&}fﻓPZg *揿uPb AÚ>]8#QT6dKwFRa:ɯ=4~kozͿ.=QϯRD!'-Ɉ86`Qca5Z1XN??Ɛp S Wz?($h|!'M6ESN/7I[ ix$ J?,Tuj6V쬵!Mҟ E^W%u!(*0++D$9֬!K|~Ԓ#$]w?qsܻhD YYgg`ki*U[ͶaX:J_tkX)ʍc*Bs&MٶlQM+33S%{v2ﺸq2љ%FM{Cz ʒێm8KD^j@I3_^sҳzEU^co 'n.[q)I\Bqq2Y{½|=^@Q41u_HE :a?'B<\K6׀.4E/Ӕ)N T2zfAjHa 0ū< z A ( ! b$AD, D@BA_H59 bG?Fjҿ?o8=dH4~#.?׹!}*EsVz?&jط^Fm̍$Zm"͆}{zllӀX!xvz;&AgÆJzrT4~j79Y#B7zy/4P*뻱J$~{ϑֈDwajD|^J[)(}`kRnʈߵo.W!`cEtU>iR b6]c9zBc'lhyUӹy@QY B{BS(W^'MG2rmjAZsB\E Y> /x4ߑ5T2 B}sF7֘*7{6bNp6N,}OhE%16Lqb=f<ABbX}'*#BTԒQX,k|AbX,ǁSO9htw j* >|l_5ryB 'Һ X,cɵoUbX>nd k)6AMqbz^(mEW&,|93}ޓʪ.ؗ5X"^rg׌N, <ج'Sge [H M^ <Ɣ#5aPoޢЅf|T^w"?5굮?rzMޞemK 4 }?MvQiV@ॾ(:VLRh 'זM˜:rn9[$uSd9w]YL~m٬}Yfn݆x}Kd-mo.vKffQ4i}W~ֶ%V4 dL[$K*iQjXӖaL[3DV"7-*/̼~w-|8jwO_uyZ NRx'ϿiMZJ^TJ*5{.ULt1 ($}&I\?:C(j45XkM*/dMU;gm+k5;πAç2S3 ~G3ÿ́)y}`vq-{fH;sݏ%|Ɋ+=u|˹syytNcDo9d~ spUvrw=G|9Xb AgxY4Ĝ`2nhP|>YŢu52Y(rfl,i`&:w3{ʫObh[W0"Nn啳}s\wpo@b(K@RN(@הrpn t\z1}kҭ#G?qLia0MTBUKiiBv*@o-+ҟs1#c@DԲ8N@CR "ȟ䠥}\MGHMd*fQqz!NSuDFSFS  ݉{9*~,*F'Y> :*R^v5o6snwXxes:Ss_@"HR AbbkEkPj8r֋ϮkQgK0`!5HM}LMcf%س6ܱ8H$ecoǿz5h/~cknp$T1ssT)Iywm/ a=tb;tm@Sx>`-G-'YG92Ym.}A{]Ij˓Tс0Wr@IjuVI}qk^l *0w@S4R#8]jF)Ғ1ׁ=r^ܵ*e/g _ҟw/KSE[01hl4")J (q㳤$sBIl 8 MGT|.T.R3jR H@QT.B X@ A R#P s#J?]oԈi f.s:D9.spl6i򅴚' \fZpfgjoR+[9?ti2'kou*=Ý<+҉\da+ȈԎl'40]} /K {T˭l6p QlW˼4{Nm%'5z8jţH;vẎ,CżkIKr֬l: 'Y7zgx+>= {O]E)6ETUjPԮJZLBZ8>Ƌ?x1 $|r=w4)q=*.ʃ{UtUxnsuy$Y̫O5OEc,'W7pSn%œӻ|/p@Z5d1vJ^ψ7ZoĔО'J#\yow9r~9UƦA䞣WS8TYM+iz=ݳ7DVy8kc4sBդ$-ݾ"Jfi62$s1*訔>4~O%/RqӇtѢ@ٱ&=|o/C Bor}zxCk|$@3b{cB xiUꬊZ& ҿ00e ,//w]$W5O-'aoJ^dF͏_x\=4j7'JP5\=q{:H|2tUHnkPwE>/E(e|}g>1vvq2TQ~|_+x;(WmxU?rqYa֫ >OkM^>{ڛbqBP$^\W/ꇆ evZV 玗喃(*$4!4Am5h[C@k06Ncv3׌u ; n?hZ0|ךGfoQ#W[ jculZ/7R0&]٣h뢭ZT.WNVrRZ@Hs奼o{N&ͳV<:I&_?H2u`&ɵi*z/&/jGg>OsİiʬMwZzZ w/xy-Rv`Wjc86L|u+#^s];6ið;("0 BN#dY-% ^[ր2FƀYoc{XSŖ5ɕjmKHX)XHPIӴ }}=ŒѸ~Oؒ2 }4c6Ef^~E$0 d'M>%]efsAwTv4RgW3׮nlbThj'W57 EDIйC5gś^xvn'Kɒ0IC[7#DDQ0֓#*ҹ b҄Z2G-+u:]ZR#WxYBX@Լ1$EjVY5~ sf-_l}a]3J%\i5E-|U'TNӶ1S& *0['\淵1R`Ia/gFk[$g?yױ%^} 'ӴF,I˝Oݓre$I3ݼt.K9&o0Ds}%0/!$HvYy/? ]*T xA!$!SK0mGۻYc,QPke -S eoE Oї챋6ڴ5jd ̒]Kw&vS/{Z1yaG y,`c";_y)CQ<u4+ 8~ٛNdɑ@`<Ǧ3g\S}b@z7[I@Oa>ΚuLոAk8WN0a~ ky~@'G朏-)GUQ@BaRyWn?5)U'0m̝N_ Rz m+Q9FM;FT4[IPskG2g*jM+ψ^JYVmr^P56@.=$'x ݬ=˨O4dI&tڳzhϜ[|ՀջZʍb`{'EuYth܎sIrN3R$ _xE8Pm=-Z4,ek<D/5ga!V/.4.BGmqe:R,{xs.x/^kߖU{Uyey.Ӂcϧ $7vK`XŠi=-$Aꝛ\P'Iĭ? Kt? 9yy I9YF_[^XAkCcwk=k~U>Hj7wa)Нpjv W`XXîN] *%%EOOK MGVm*~tN[ +qkC# Q( ! b?P sA60ŷ30 #-x]+ ?)pm;5(7tm׾OR0kAaLQ $A@e\K-"7A7 2.=l#@7iQ'Cl6yAe@30ihɚSvv}V/4:tL9x}y% [A/~pW/mE$ˇ]Ϲ~> g p%V ͕~מF~)E׾#&`kU$/ wqLJiR@pӔ5aooh)'Yۇ{) "VD}}[yo n{%r%f4/ҽtnOLyPrC& LtW?J_{yMp`$/G?pDsf_(/l5O5=oBѨuj5SUu<mm= !N$%Мr^)OGsՊ.7iC +2#4:{Xޖڲ0\B9A!*z3CwL=#|((UDȷWеmt+f![mCVX?/dNNŗ?=Vdy+)~~,&c:&8KD!|a sT!,o UTTjNYDz{ˋ{KY]YdI1A7qB{wT9Qڨ*4U`9yk)R3Kk@v M[> o`B=5ϦRC[ړyXjSAcVvkQnN,*H}0b9׊/;W7b9 A ]Z7b9{,M@lw #8!?dto3zɉ9{D\:ɣWǧNWPQˏ_>aʖ[_y~ᩁSج~kFTr k< 89ƞOsC e;M=#S!A0 =}l\wAר| +JvƵg7?k`De:~kWXm7rHv_})ՋkgbJ/lqdTTT/%g Flxm>/!Bŷ[ݹz'/ꄁS>~hj @e+wn_orS_Td(go$(ZcI~^ij;W!Ap郤ӆwo]7 Bz$mtVYl /|2]?~2 7F^S5E&3v/yΕ# R@s:&$BTy=vHǁk{ɃDK٢ZkLwʑ߻~m.~8BV}!Hl 褿4[cqkwtAaߋsazz }XyB8݇QaVS.gƳ/n_ԟw6OχgvIJǝy9!!!!9LXaPk蚀/^<X=~cQ9k܁;o޼} fgGY]3؞WOO99h3Xn;?r$6{zL;Q 㡟ڬt Œ;z:xTS@jSM'aa."*cLl Bߍ  Γr5iQ!:Lu+O/b6^qze+2x>A@sZ!d0]Uto XlC<#r&CT4f@aSO?{CHLTj3%A+`S[5b֙Jqd-$'jJCPQJm<'7:*$ =)k-(O e͚j"]Pg HSk쫓Xs3^Aů4L+Y"ݺ,ݑ&QY#O&W~Y5@Zά_+ݩcXᜪe<_r=?Pk|" z:XޕhԚZFKaG;tS``$I 7/6$oEBpiG]fnRH@Erlݰgweއ|GWWԊDT%Ce_X}Ӫ[wʇB_/&4 02I5e ]fENg`Nk8X 2aF5ʾ}6>սyц H|lIvU\...rm%K򬝉5~ mL(;xId^^P* wfUKj s_Z9eH_' #14#Wڳ0Tyui(Td͖Ք/ nUMmgczeZ-z~n8ԣfռXLE\ѶW,iU 2&F'.#!1Ią^6 /A?ܙa됪*a5&b&dϼ؋U~yatU6Y[HxG95ţ*o$B߽}thV#T'I(3ѝGo}t㷰L6=/PS6+Ql߉W{ּF&*&͟]-k6Tjqh*f1z0Nj2AH2(M0fhz4V ?&DL֥MIڴ!BfmTxI,MP/{ ]'bp  )<%Güw.I;§~fٛ#?b?VLW1دDŽp Oh+SnpC>Ak߮m]M3#ၣ؃-4GϽrzIuZ2 (+m?=2 8ealhX>S캲+c|xD4^w, 灀QT?3RV5D쵒aM¼ kEK0&@:R @V3Iߺ]WM:ފGjz[U׉eRa}T4M3JeMw %U\=]ZGAA~x BPR$IQE88I̬N4J4MS YVt)YJ$Ii0d211iTB5XӲlEE8`s9|.JJ#mx`Kg_jqAA~TMkkk33S==}QffVzzZ||Btt4b0#ИzZI*2HGGK ʎ+R)ɺ؛Zشj`tr R~H]| Zm//(u)͸ӿ;;NSOeQFAOiRR q@%=ÕJjƍ )dM5rR20iZϯoϐ$)?-2 *j}QG dj$<36"eYAE`Ҩ)$Fma{ك23:*^8,L X4  :$JRiffp@&4MQjF  T 噚$B|X,[(KѲesBQUr `(ʶ|CZN{y|TEPt;;nV6GSMܹI3N!hUs]Mc1y  -4ED"$iROY0 p($1!QT*!IRn˖4uB0i41!0%I66*s(S뚸²$+^%4(@Ā{)Yª@Zk1Z#^S$\<[r+ghiL˗鶘:=3>i146   E>_.A*eUQG0Ty<"|\.Woz$$y[aIZp0*_LSwl֢Sy`9Tn&PiR|>bw}fLho?dbz .m ӡܗkp!̗j5?{; 凣h-^v"   B >|Rr UlZ_ j+VmE4ͣTVxQʜCbR4](vob9om軸!_wg0<2ˋ/sX\©7b>@ֽKwJ$~EAA~ 0 $b)Max&TժTU!) @"baT*0`]l(e2aJdliU!&~Z; ]ICQ*E,,ڡ-'ab;<M8KÜ KE'e3t񖒘 "OY@t{lAAkpQb/j*axnn.N@8gghiiq( fP4+$EQħ\AQsoΖ; XqDG6p' FJA 0yώHF <;b`W4oow)fuƘ–iq o[  G`0T> E8EfVݪ($8"I1Ǐ۹R(Zc1 V*Mh"OQiNbu+Mb*߸"bX 8Ga4)WR@ T+Tc8#!I014GB?p5   MAbq0cN`a@Ӡ/#M88$%;8:YL.A8`4EE%Je؇0.G Ź+̥昌Rq.lRAp&때4+(/߼}xX0L2-4sYeJut"  M,;*2mh&1RsĚi Ǖre\l,1p!//W}_(1Ƣ",6k2I?#6yٚ-!Rg0Iؒp9D5mAA)4 $`0r9y<O5jUV&&&b11q,\&)Ԙ4l1 HOQp0XlF%#sIH0 p♄-GK2jMs"  TMB`X/Z|a8MSR4/7???0YL 0A5cQ(䱱qB6_g@crrRtл1ʍyqv+F༸Oy4@țW̕4jx Iqz7o9A˺ Mty"Ýێڹh[pw KA @|}߮o)0KѽLu81QGAA~ r!FAE51s۽ENO4}[p~SR&Vdo[w1K麷uЈ2t<;ֽĄv9)3v$em;Ǿ.)cĊw g0̂I|)aw1uwϊLvCzN>mŃ,ͭFnn9vuhܵy DAA7kֵ.!lEOiyvk"|c4@.ϊnMl9oVR3L&1wiֻu9RL-}<>Y4\̀<‚߾ͥ!$r^1Ix))CPV4B*!BntHHx#li6]Dס}[c3N&vX7*YP [OogP:<  }C{}kZ$!r/ "6* w0C2ݙH!Ftw2qHORҔd;K}*{+C )   5"+.*"Z1 @|_VdUR;rOhB-Se]Eic[Qw-Ǝ+eK")rۦq%-ptѸGumiΡ\}#*%ʜ؈/X tĞE{WdWhkǼ  r# 1EZDʌN} NĉyE9&B >6u\b_Q+Ƿldv |4eVtsd(z%;K4QhnҾGAAʪ`M3Ši"YO@!]3Nw;{\k'KLm;<ɡt_Y.m$Cu;6?:>S1s68K򽊙/\Izm:,xm<evXs=&xOЅ  v7t3gꊩkCŊ  țqk  _5  TX۽Gڀ܆myOc~  HP5  T FAAj5  TtKAAӮ]k4b   ՠr( TRߏ8L  Z&DFE~&##k!B$zx;;98Q"  ծZP%<~0 h`d$322^ ZYZ$Y-EAAh&Ie7.. qU %!Rn:rsss&#kAAjk233=== TM9h΅Hũ:iK~^ Ì_xAAjJXSE`.a,YXWFJi( 8.EA*534EQ*@@=F+HW%+Qu,EQWAAjJkUS I%KGU_HT6tY  HR`㬚k5֪'t!ճ4+QFA@Y=tRU% (UWf͌(R_-ZMFAAPgo ֠Q \l%oRWb_K4;ݫ-@NvVM&AA_:KP`.HP<$UW1DGGGEEQH:YݙTaRU"SP hϟ? jToZׯ{_ѳWyc_ywd5+! |Rӭ@/|Z׶4M WdĚQT111gΜΝ;[ZZk N=מzE?X,CCCՃjm&% 4a̎$rѩ[Ek uH7-*N#B>cvunŜm/G?5ĻLb^eų[U Wo ֢'/-~RQkep󤠚~.o.QJ\lJ7n1cƠl]Y0Mi̸R1_-QP[3R7Ou}KCv/G9z!;V.;l0kSUV80 t Μ=۷t~}.< K0EnGUwxR&^w}ViWסe`ًYwjs)O-O~qv9$Cha6| L}a2yVNu[oaP-Ag?Z5cݫ|OLmS'&zrשu%~Uo|n`p=Y݅"VP?39VdgQktZ DeBsz-oaͭeuaq G7ynt[uX3*.(J=_*UoڴIߍ7=SNdk4OOeom nS8͛D$瓀q}Z "RkuFP?(1yo021KJpmDQOF ܀9ƹrN:tMײ{{{)>[ ?m8+>&C2pk9`tzػw!M#As5X:l^ūZWd֬Yg=UF*Lxİ.NlzM "CilL6gq2!ޜ}<жk;evOd]?*5 Ti3 X19VHl{\g8^Rŕu|Z4>x{W[ '''^F1y|zׁ/7צ.ut2őK.n9u@'@..E9hIԵN>ΥePoIM .J1fʄ7\ MS0 <[w<84)Y>jD+T ?N0t5(ȸ`l!hDZ;ȾQ߳8wbl}ti*b-|ԥQYRXfGksn)R p{MxiӪ]YA4 *8q>>>7of03fڻw/4-5g-K Mv=UL{wq՛L UE?F`@شE34l^/eX/$4u|8AJkR- [7wƓdfF r]{.oۉsdvY2svmaxwmbָ.vVnFp}Wǀʉ dY7d;{|dH<8s1A^B'\~+o}FٶqcP'kLq+֓XHIrdLQ>ALq7/mٶ1+Ís7^ɒEf>;RKm͉>{&M~>ݰmLN8znMkW_<"ܘYJVS_!Zj?NUKx<)l匪4MDrLCW7 ɛɇFIt3T}Or Dg܊zyvƅ)%VY7ߥINC)|) %绽B-[V0n5ax]&=1۸yVp03cM{Ԙ3}Gt׻o;ku(60)32 +28#6K];;>>;~5ŤDzۛ1&mtKjgf^팍VZ4 61c0ͧfD}J wGt7c뷏CF.M0um ihвqRFyhIS#՛V5+H$2440ɴa2PB" dV~a $i\M_234JG?gJ K G%`;UQRXfMǬl;7Z~}i3z:DJ ~Y85Ը2u1Jw\ES:Օ3v$K eޜoFbp_ʍeξiܐ7aeڈF؝41 Pu<}ce[=icmbй_qje9YZ!ދfw)KO4k|g,gRF']ZptJ.$XuW<9UL@Q4EXN$h[cnA*Q_4M 2t2'KU؛1@}I5 ؠESv߿X`mig_W/GvcZw"C,eұ{KoS@^v[!H׫٥Z0j:j[ [;s]q8fj-rV?æS @I ݉qMU|>/Ⱥ'Gd߭Q}W3&\ŀb=yaJb4\_GG]B!1o`g??vAWvv:-ȳ/d?½AˤmBY *|(z,ލb0TGyQPvmEۙ<+ZЃiyhi꭬>,wH20#nMг1>S6V=&N.wgZ0Cn +="mL>pu/Ҫ\2 S͛;2yB{صޙnv dN-Wº6VB?p3(\ǻǞ~!v]ƴ iQ[s霰a2;S'g.u3 \]z0ԷAO9sL~Rrez5(*orfJ_uY+ʰ0www#EQ ӳSr,4 fM>iiXA Co?oc s5Ui~WN\mL4M,xp.K;{jNJikn3[wGx \˦`N*%[Q qUb%|_\={Bn!gdv\DTxzH#Ka0WG5btĀYX pϩ}GoZuB"`_{~@ȴ2yP{_'%0t4Qi= 9vm{Zu%v˅˯Ϣxݐfҥ n T|@h-)MbڼgwR~-;t x^=z^}{fIuX s֞W:IKv۰,mqZ@uΌKtrA)#*JЭ͘>B on^q?U#7S@h[ٚ XwW%5almG@ f=ש?/؞6?6(ȼjwu0hX QM6ָ))[n:lIMA̞waDZ>~EK@"ο| G {]]]#Fm222LՈ!jͿ 5aAaثWzY,X6LGGcz{{7#  H-1;qRTIZs Âݻm6 ?%u9jpZP(qbY¿-}mjBAAz7^Y4Vշ,Ql {AMLUl*QVN5J  5hfT(X&Qˠ݁P8|UAhՊ.U!5dAAu.ehޅD=zRͫUJ K  HmPt͇Zrb9"`|[hROkNR-EAAPgJXg+T?VV&Z @6zu#  RK|ŋܬ _UCF&P<`  R qd2w;ŨVF99-u-  Hm¨5A0#" )Vj~?bF4ViՏ$55n:EtAA/*=433y?%''t-8xu(n  E*~񢁾!IBAA!a= I$Q)  Pgi*|AAAŋr7& qnLYAA[`   ՠHfT`=AAAJRgi4b   ߮X)HECAADS?Ev<ͤju#  Qj:ƙkcoQO+fBf>yh9闋 ?֜3zjeյ H-@Y1k٭P)R~jƺWu,=ǔ|S3A*` rus+ThHȜ3KN~& ?pɄ\3̉e,l=fBB)~̇r`MJ!n83~3hk5/Q6ٳN.6MBCB߫u-A=Zz<ɕSTyY6ϻ7^5H)P.D`"<6oz럹6ossHWa";^D]۽\X͞Ԑ>v띏qib0g㮃z7)Uytъ9Jw#;vMGpJ>o^IgxSnuE0IQ #?kN{U-^L4 H -r_ T$j6wc6o-hDZ;ȾQ3R.ΙrX{†9ZN>mǺѮyI ~;2t9eO䫾߇jFڞyҳŊsk<6O/]:+)HD2ƚROr:a^ S IB߫pW-!Gk9iʻMŊ ylx[s?}"=YfC٨ϙ=j_]o;J߹ӧ71|ۨ-@eE*?83ߍж+fYѣIk׉ V~HW1̏.u ,|lDnJ. NCWB"ӕ%XSyhNcuWm u͞EvHh;{ f}P:4p<|2C:JaI+#3Ġm`> *XMk (U#Rp[ݽq}^-x#Xlܮ%ZdO3tal5,7v6EhAƽL1!98,N,LOQ2=}n]/CݺJ::{NJl}ϯƚU7A{cY4ma&sM6 t+2V&ņ@xo!7%e+',R2׫nܳ1-zwhg5|z@Ӊ!U(=X+R^eǹWMdv}üEH2vNҏl#;e3-x-|$˳C'k3c`<mZ2J:A%˾:]k1 N4EƋ!ߠz4 |Vop׶+3ahFRk}P@+qdfJ '- 'YGwMu.S_ ֊/08&ur~K#eŞVO;GS4%Ɛ[>סu#[7޾z*ɇXv?}KQF~2N.sfT 0 UU-Apz걣.]{~'? !#"clf0SSwF͛7e[XwCߺZf]wm֊%Lo5R}ri5ֹC9JIV緮>OPPWQ>,8Է1KG/P^ _(53g\]z0Է_{MYX_> kǚ {B)MO1DR!!lZMA~$Lֱ޼ πQ N+@vwft8SF,̓UX-kM3@f4ڈOg5-@P.1+A5K[|̊||Lm|gk&Hwk׭d)&3wH #XVmzszC;S⦥ckzrTi0 }|sAlZSסɈa ͜>[- p,V.vܼԹpc9yac1 LmQYwiusm 0cz 1b/x*fuN̩dT?C;|`/AlӾ-.27QƟ9i% ; Өqn wܮ& CFqvLIfGEf2ST  djE&^R`4pon|TM  l3X8-FuMw  |;4  TAA`   ՠMn R2uDšn]x֭WM@0 ǀ04&XhrVuQYņt#jmmm]ӭ@߃7k  ?iib+qᘛP4U:9*Cjt{  e0,###"*I___h0ij5ҟ?Kv/MiiiAthm  R QџT*uQ'5 PM7t RGB---pzz4E}[^E0O>dG#"5R#F?yvKe=:o0Y)Xw(nA0 (ii$U )"IB*$ɒ=ZaBDb9b|`=sY<@3j-6x~nFQ&>xyE Upi8Ǒ_( YӧY P*8:b:Viv{UΔE8T*1;KAT 3Q Txb\<;tP~(q};_y1Uҵ :zLGM#oyR`l56xpGwQf;gxp- 72vA,U5+ 5̠Ruf AUݎ㸺 *{V9b|=%&&< &&&V>~q8>q$;Dʩ.~br^n3gcf{iqo"0w=Ty`s] }mZV."3,GAa)M5p%YyQa7h7_A.*{t`;Cf_-Kxtᅰe{7N3#J$Qݱ4Msj*vZ&&&|jIpppǎKjѭ׿׌=$h _ӣ[ jl7m/lk)Ke>ڃ>eQ3#hfԎ>6ߊwq\hߴɽqE̱Yh瑉9 B׹Y;q1e1W/r]zuZ5Ȏe R*[%>o]zնNdGe<G]Mij?~ww5(=6Sv"߆$ t(e4ř#i zk>n:SݷZ(aگXW2!֧Os%$$gdd(>}J{ѭ׆Mk<5ɣ Vh7Gf" [c;7u T}&gյCK^:wIHt-SzMڵ+cR E~Ac6(ɇClV]ᤧUZ _8|N!NQ28z&JV鉔iޢOGov`Z,J9*uү^,kYخ٫zв ?;)C*tY,֔)S-Zϟb9\jgg?sW._K~𾉱jP,X)Xa:]6,#{q}_wPca&slT,}n˿}/o,bޒ8XXs.XX'?*ڪg`C d^FCVvv;WT:B~ ~|4.Y׹_.~AA9BL(bϯ>xlKS7u,UU`y{t;醞;q8!3킦BzOs+XR3!t^ȕ'y6=Lj`t4+(cۼ;7Z?EkmĜ>}cǎgU!"#Αz D]&1ڎ@Y"k~6\x: r:ߎ===_9%#zT]Wi[i6BEj;е7IR\ʿm|m[oQofT~w,:Μʜٸ؁CuFziQiO&:)W=j19Sסa0$oܪdh3N ;|8A¢M$YtCz(o2돎f 2ֈCy'篍i9V ]s׽Ԙٗ__Xz>=fm]ER@ 8}tΝIW ôf2TEMЊ[o674P#I'==}Lm߱_w[Oah⬞6LEsG?&ǵ,[ԆWU@JaÇ6mZR-Շ}޵jjt΍m;u9 c&|x'`+XF+3o"bߌGS7U99o7bڙ gI[=JY;0K|c@A|4mh+[>.+7Oԅ zB_EjHXÐ yk>bJ=ȉzty)bb&~`? : 룗Ķv3֋ iU_LV0F(ty S&a){Bq^}u:,М1ِBzP{*مss{;rU1K`20~;PԏqrQ] >F4(2ˆx)t~tpn׊ fZu6 @+g̠iױ^!jgϞU(pԩ]Z[[X\+C*Zynˮ3;;ri*v4щFs[^F}Fz0 !A;z+an#z"ǂuq Z%wA٣ѵͧ߾ZwiTv1%tG1`ՒaL>Ҿ֕r`lcNZ;_ kjATg~|ȋxro^0*rAnٓM+,ב@ |6ȭHQ;[qLc4`Fᬸ83)Ԩ|e;wc2>lвtuu0PՅ(shaVZ2\LqK^ mgШcdl,@KN@U\K?-gz_ESfmyE hYr;Oooˡ)\`NY;4Ssh+R~WQ-@'w86@UC=s.6ƽ_|4MB;w{ɣ\x.={`-^+<ָy\|ڏߵjrk$dEuQC:tὲ56~pݰ?ňGe+xIB sh9ͭa- ˪>zkg'k&Wj G:AO/,/[a0-s;e}7q53>p9h&_Uzl`+zqx}6,M=/l?݁Nj%l~%ӟcdEjA19uث.Ea7ԎJvK;%d֦q7}y)[Z' + Hdg_OiDdU v^@&a:jʪVd$0X8ַ?Ê~ jә7r\2,,Ԧ 69YG KS8sE~͡rޣvd) M2՗<*8%doe#(ؔijNN`ZV_ RC6^,xQa۹4pŃ=חJj" M3 cS82a2S2:fxHj~ P xRBNje",rb^swoz!YªV1 Wag?yȉ\&YEQ=P %ʋ5oRά ym_W>y}p0dG'ޗ?P 2,P_pd_#^4[NFgz:u|J/|wuO7law9ë猒<=9u.wANCVR~1Sy;+/"ڌYfL9dcKQ3IJl?wwKF7R[Ω3/`o߽~c]qoUN |;[/?ykVbճ׉҄:`70@J=GCU1M`]~ilLબH}zq6ӹ%RF|yp1Z>ASE,$+:0rsh{sʡDu(D\8f64/bW0M)ʌ6_9 <'P$98ǸNnrb.`lC]NfEIv5rqf8< *qUg+6[6ZuTبćRkaZz[jadM!t[{}zi,'bͬJW`>ȹ}Ь'  sޚW3!֮[RL`gUP|*wƮUgH ,5W&լg-HlCz~黫PٯO1j+ HM_<~ CӴvZZUs҉nOd0 b9hNII644,3)6I9+E#ٳnJ/=mԯϯ{.&F_fFP4UnǏB]oPEQiii:h;G!)XSgGv[2Yӷ}{x+"w mw"FWu\(ggu\ HmW2FxtHgϞ?y򤦛+"B[[;((BT\W;GeuHm *փLW8 ,,ݶnj1]<ܙS)";nMwwC<G_ńAe=X4`·wtb;Vn:$N :TkV>dK`RAu4,v=8"U ;k׊_~3^wk m,ؠ|b#r,}|w|K l ;Ke#S!w»)$Ϫq/y(u\ڍ7 dN~84KjgAB~yQb}`ב2>AA2O$dLr|/վ`MS$I`afǡ~+6,o g.F7if?޵tݴUG ЦR- .QqOl )먅s8Fe~o>l,O2%pʹuNZx}M]ɬ>|'-dC>ٳ?.c^Y?-e=jL&;?C O#.sV61$comZk cfxr%6v1&a`L/.O{g7z]-{5eAo(^#Ts<6G'9tk+n_b5PwKeDK=iF[}x_X5w68٥Tr{j&?،9?υ]y&l~ǟ] =sj\uߵM&.lݹדЬ!zYer+].(\-¼'Wkdok=v1v̗Ǿ{c6 xF ؼoޝPFQX5 Hվ`m;b U5ַf{4`n+#=~3yJeƢ.}Y*d oY=i.kklD2/H>WJUFLrSrI~ y%n!h U&޽ɯ?έdghAhJ L)re4A~awCc3,>.}֦ L7x/d-OGZz0 ߬kk_L2\ G 菵#ԃ@ àBd]]5kf2ܼ;3˄vs}%w1Pd14ER߾%h8ѵqrUcIJtAF ,jw]Vo ^+ ?*;A俧#,ܞNpC}3Y&nOQIkkJsoKxxyj+S[XxHʲVLXQe6.?"֥Z T[z|9eƃ҂5y"0W 6>F+X+bN.ٙ7wy[z[d[}Suno0yN^&,qbtMێnZ V#Zf҂d%pL#73yn)N o9dy%V8ݙW}W@+m*2YDzYYqU R >y kH~`M]3q&8q޽>u`[vz}$Bwp\`Ɩņn?Gת^)[`u^07vͳ*)0pU8FbZeQ^'l8R5ՇM98Gߔ[؁L#K%.L] Km(^6j^;y!͗nO\{ ظ*0Hmmm -Ytf긺⾕ Hxpgz6jܤۅ|3V!Ŗ ~u-/LO$9)iȈ8L#ȷG_ӨMDGmhA$ דuu sA~=zǏ R!"'sBb6án">}HsҭDIƽKrt9k0-XNO_;čץ_ƀ?R~l`@χfeyzJ_'D_9u=Ԫk;A)ӂ ',<k*͕]7bnc@Jsr(WWKe^PkؾoҘ.t2woj%՟ I%gچF*{Ǹ9 GddTM'&[vw,6c2sm7}SE0Qxt. pӪ giYۧ/|MS0^> t+?[2-"6LҚe(%eF:/ʣTeES59_7 erw*ɽ{j(?:x]N{׿E`0411)>y74+)$̢͏o L=mup29rpQ&h18;kf݆7S͇蝬"ɦЁ6bB?d632O5^1Tӧn V}WՏL{rhidM7ATTUP(ryRRRӧOkyя`ܨ]Z\._ۚ_^"!C~NȖQ@0 <.Hz>"5O`` 98zq Ԉ?MPPy)b%` &d^ʛ[.4ZZB-/nt⋨|hq p(1\I.S(Z@Ŧ)@ l3oύt^HUmn,x:fZ @2^ t~qyJPrB.j2;d@K>{c~hr"Y B{3.V9@nLd.@fDʼn |-p~.mf 9IyeQ6T47&jyP$9x({ M T?3X,֔)S-Zϟb^IvT~lݧpBz zI&WE+jl{[]]F,#[AjJ-L/͕~dž!K vv cyNutYÜ4"Q 숄,YQ0Aka@Qg8H׊RJm踻=N|c)1_[z(%p3P}l&\)SʑҲԦ` dSy򼴘{/uh<%Q9/7x_|iYi!'<6v1JI~STڱLLs̢P=I`]9u"e<u܍9:Cj=FZDN<ͪiEh?2Sp_9hwJ`@)evlIjRwd;)eMynixI&v Um=<=WSǹoS~ZLهR2{P?ݿzñ9Cǵ5 O}\-eͮ /]+F#lYzpD@w֮ .lXTУ͐)c0U; oZ:=q/O t3{Ls5M+,g;83Y%og߶lZkڦ{M>'ߙ V1Lg?.\M0zcM/~n|,?xnaɀ&.l zo{YN_z B=ӷW4Ƽ_ΏU6#KfeiZ*$޹t "lm7'W $UeO K6^~ZlZKyY`,.,"i(^zOgpBRG0t ~1@Z/ax\gŖW؈k[>:C&޹|$VĔm ɗYΩ]6&IòO-i$yֲ :ٍ5ߊIe?]5~~ Z2ST"X9r5lnJΊ=ǿS[U/eOS2$q/$z<4Tdy{u; 1~ٕGgrnRdi{lc\U?>梩{OЧ_dg_(\β[74E~O,R²_ӳw8@@/27!DfY/l|ˢIk=GWÔd==u9âIxRDL[`7h>sڣ~?/N|?ַ5"t-جAƇ`-^l׿ot=~:*9CJ`l-}K[3Єn>dȒ˕@pF~:2޼]lTIol.e߻T\JD2Ƴ Эc3ݴ>30$3-v1H m#s:\ ʺڛƇf+J`h7cAεбyMxB`p t x"<''iE?OӒ'LSe)ZDŽI ֎6Q IfL]挀fז_ش 9KA_% W65)/AUsڛs#_%ouzm: lev h\gb-gy$h'QGN_wWk|P$|Ne;xwRp{$tϚ'6 -~ %Ihn"۽zڕA55AZ +f#?;:uiw/#DJ^hw¨" 0^ݾ_ ڮ^ln~z yV}fo\bq6qt°A9'\M.moqnRꓸzٹso | -㰄ɋ/53(q :ϰQ7JnE={qosZy&vvg:oF>:ޓ~ʲ}/ij-5kE8yK ܾe+WhM+I8A@\:&Lx:VW]_ ̫W[W/ܯM3Km_'pջg/ R'g/dz7w󟇤} zz` +6^AsOlAj\ُEuu]'4ԣLVq/Xk\9l14;6rʌ,w g 7hXLi~Ĝӌ7o"S^KFp^hn@!@܏| (-cmx!I^beRךq٣XCY<]\vߚ65xWd~wiwy侩i|Y\EXHR\5?.rSd42vykG l՚ifc <,Աͼ=u3`^AjS9'm6 ӢAvD]jXv}׾`W!N{tlN]]"^K~w߾+x6\pWE\ЎwLOhaKɷlD5#FMY56f؆=vM:fsn¿,' 9*,n}O-[8w:ta/]rxk<,kw uFt7wjdz71%Ņ4^~9qo,okFG;r5`l@:݋[@^3xIt5;ԭ  zBKTغ斆\ ý|x.M-)o~;wct>zNkn[ <=֜ ё_|6]آ 7~ }xޘo"Z -?R (U6ѣ7͎EAj#O~u㚸5uS քĐy{ Wk(IDATƽC`5ՇM98Gߔ`l9t. 8Mz7Rm)/{s3XTbSw)V 3KøջW8`ijJ_w {ͻ@f^GoX#wӱճ+BsϦ6b [-kpjӧ!"+^JJUKR֘RͲMp9k&[{q m Y69(DNa=~rôm[Gȳ͌5Hb *6NAl*Rf#?^nk 5 woce2#cㆍUa?:̮srV{w/(((/kC{進i׽ZUb:n+KNP;@ZܽY67vtʨ7{v%o_Z9CypfrRҐqgn$ZpINmzDם}'LNܵy.G?m6j(?klA ʬN|-6τvF?ŦH !!acb;Ld)Gn\R_śhvmh9K߷lwV55˶j5[: ά '1ʃR4Ձ޷6o4tg&G7MH /L_ȝkB )z |Q-?>U5ޖ#?zvd78 Sݸdi/OsNpl.LuFnjdekfcch]2%(Z47u֠z%Ge:|Ձ{YF&0v| ٣mb*d{k>RJ)d811l7۠ȪAUo,QǷIQ/0۹sEܙ9#V>&[8^ύ{2,.20uS7Z#M} &|>fǴ9Zu/2N&ch!f\۰~4֎#dv؍[6| X;;ӎN61dkYaA+HY$M:͵ REP|ˑgmjv-Kܲ{j?{ 9ޝ1JoKnm;@ytS?e+a}ݮIw#1x- RtOl;[>Ɩ"e̩%y)>[5j{XбH.gΏ5O&|՚<́׌FK bmzW_XqϿfY,FFSli SҠ6ehN~c_ke-g-*`̳ݦӴ+x\v ̏_#ꡖ#n}agp3I)s g7%\scpVL\۹uNZx}M] Eƒf,kaΔJE_2"wQM +ǡb bF;mŨH޵="98$d\8`C2H*Ë$᪍pldQ;>?j*Nn (cs1vZTs/3csYd Aj+ꡖ# pʒ#G{_i: f;Kke`ob&WoyYX5WPXZ'&~%c)9ZIsCRȜ2.h'7%5\G]NkdL0)G *Ny7`Hj)DKZB \vB]z#{^_͕pXz|l@q"L!pfiܧ7{![W]IY5Њ `+Xޱo3JI3M4@9#~A~3ܴv?)szeMW.tg ~m@i7ΝKHHP*})uMJ!p $GcP0o pK˸Tz?M2K.ITN;KY᩷&LS pkqWg><3X{aq)YҰ}?{{\f 5a5zʈLWR_3&tL"^; W`q -(|x0rPL`j4UoAJSS9 5<63&\={Yxڊ8¿kSSaɤy\Jt):2d4M%y m?[`xv_ 86t!+K@k1vt?ulۼ CVȏ~rdUb[cèH\ J}bz\;~w?uF +sYz|# kC(1%dBFTuF*(sҀ#oTlج7"~T,Tk9Hmj܊amFƆ/8/ܩ)Ǭ󂹱Kn}ULk) ߸v×w.>)F>md4c-6=kQXؑ h\io>Re\B3*X @Lٻ(.gfK6H!NW)*MTTGGAWA; ece7[gfٽ̄;ϩ`Dz`nf>Eƞ۝FNڐ2  __eHXU.RIY'>Y fHlu0h4rl>=r5i(*GL>c4:z@bbB,i!zm:߫6|ep?Q1g)O|m֜;_ޝG/\|/_egp6k˧g+ϐ QE)(ū}uo ^ی}mw đgڴi#G:uj 2! 7G{*%H\ m#WE/4].-*uWMևl!$>0֟x44smoĻ#d7IpۛdjiIuY硓:g]p~K]wԴZL# + ]gVn!FCvuuݴiS,*}0?;Vtn#oλG9 Tv ʺ?+NUώ7d{Z.-[&%1d)8[̓:$*?mu,:^[B[P(*_aw^bͳ[22G6Fsalm__^<jEC*!*] ?,l>b]ZsV|[L!ϗ n=_?O89t_zHƨ{ҿ4sC~.-=gy{xkalIa^es9؀4i']x(L8IX@.**V\^/4Ӆ2.XB4pHKSw Hpӫand#keFyu7^zlu,"z XVad_ 輳w#wwedheб;$PqI;xq$Yi6xLL!ց1|2#F57.@ GWGw4 )3{ €yI']V$|:tz|^a&&O[|LJ|PqKҺӓC'}ЎCz$=;2 }ml 6@D=~GHd`%rwr7;@G_]xbGy~}=A#^'MBu3[1Horq7:8%~6 صtgGLr4̱b)؉wkσW`<M; bu1gOlLx]Ϩ#ػksvqiݮnږ'4ZIEX3#5{{{{H.;Ѩiok2m" Ξ{wn<' i.;٨$I呟-X`bB}1)Ǐۈ`b"Df#D.&0QEXW/fˇN+VU_ϒ}w'[9߲aL7i!öQ?jّE.^.zo11X4|]_[锴\?өh!p):5u(GU ;\OH]sy xV>ƺ׬usJ /f \42,mV,o>1.X'-c4kgszfV^GK%yEY]7`ͷCN~;~ K0QSP'bf5I 3'Q«'gmbC-Z{ D64ԇ_/T jnIxҔso8p5 8tʔPҴ`~v:3砆9zٮ ^eI:->Yv7~^ riwmW~JaA<}@DFbn4X{'z<\9tɰ;絷')GYY8j{ /|n}ԌoZfٸ<`[04oKf/:UZ@~@\D?{x͑ҚC[[fԋ;Ӷl,/Af|[Gn^Z5sxZRp.^[3q,,E)S:8gCM0bH^(έhlc/&u9>YAܹO-_Y(sqӎb _.hewo-7bNdugws 4^DžWy`f~l-Iv6Ok ʇr$mVAb3K:U YLY_<4d:=3ί qnŅw&yzj vNҬglnǑyᏇnY_[>_@= nl7ɟZW^b"h2i:s zªozz JI=N{?)GF?)uΗ[֯}Ӝ;J;HX 5LdeY$ ]rϴy[[\N OAS>*l mom)X2[x́XTE ٔ% (nn-o-ya4-d fnY0!r#:_L\#{N~zif~;޹oo㏣o2?˷ )ƺ|ůo<N@4MSKK 9M4B@)ś@@BG($޿wB,qFtfyOio|hQ0TkVmq\Ҥ_w) 1XTD(pC0c;o>z+l>kX ֤-<Vz$\y?BRs)M߃.|}'ٳ= r o+OG ˗ݵsuN {0wk{/,~[ͣ"åGm o38}'[g{mҴjK#&uզˉBmc ֔TBd"UZN% rG@E=ҙ$̩·5=-)Y$Al~AcϾ7N~vGX{/{ַ>]oO;ddk=}JleH:^(M*AN}tmTBrFKbuV&M7O䛬sc>kL|ةY0m"7?髙/xۜ&[)Zg]ٹftUׄhʺI@Pkg&gr^XUU^h~B x@Z}_G2+-hC_uwns- hu!:N_Pi *'$tA] 4E?Sҿi:?OZG,kzO/kM&TKv14m諛ɶU7kMIsINpP!y_[C{Kcm~~͕?ZxӚi/_lٽd Bgnj9q֭b'pGhյEOUP4.1Ϸqdf&t5NIN̖YX LN}DD8Y#nK[q/2ᅋoPo/RR=i\nGz?x"*oB%edAN6YR W!, 5$Gu 8d17?_9/&|Wc呂w֡m|&˓kA M@quMGoƦ䃅dMj)gݳ첮% ?dOooֆΏ>+OZrϒs(L% *GwI2FQw+ *UpbwbQ#ixcS>ʥ $i]lGMxb֪oT<ߌ~p&Voo"o݋xҜ, @0BϙpyQ˺&GT{qSc#iamE9{C^Z@tKZ']QоG򰁟=iҜ9?El %Ez@;nKyV?ՎPS=ܐ%pCumcCP/h_+XBi>aUW9Tw !BqN4Ft'Y6^[J+yqH/SvQs MG=몲)<+k8,.f,bΟ})TPSOUT8i=ȲDVnܭTF&RĠe$ hxKyvYWvQQ sbl>j./Y~ܫRU]h"p (8iǿ2̚uq ~W0/>doL.φMcT1[t?jՔc_7 ~ڪ1x[H2kRvoݹ|αPrw ;&Ze-YԳKNn?tD ?fejgMe'&Z&*l`wmlI%^?m,(~~䗇&~AAafx BU0n~lק?B5`q##;BOЅINaa_ HGN)dNjӫH @_R8+0o'(s@ȷnf+VvՌPv\zLťzzǕ[O#8ua|[h·]`Vͅ&M/u mC?]֥yyly ),):9ν*wF`׬WC#wzOkw<` l?^12)Ö~߾?#[6 i.^cčpk(3_tjۺ;le?kӼ#΍W*nh-FЦD:9Uv;6 Aػksvqiݮε-''xOi>-: ދHg6)ҽNE4jZw0t{7by!ܨBVחF:|ir ߹w&r)Ã;\wf=Яe#>!u΅QsX6UuToϻ7ft',Fl!)9N}.-{NZZ`ʵw/Z0XJғ2O)zq<'abkrSF52(FMi9˜Z|҅$O;Yʥ[{Cȥ̈́5{:ҭ-v\>n6?fGNݱBEZ)ێ{@y`,1X g Ѹ6va[Mm4nל?V̄lwҸo4eݤps v HN#fwv{s\7daVyQ…m?nw(+Bv|%}_ڝ&SYg[t7bZ\tT"sßDoU|IµR.ҾQ;/ʋO-:rw IrO( Hh D6]dޛBj쏻=dd??Z~2[k-Q%OI]U˦ƒ,V|g'.{ߩi{E>sFYX4o" "&]ϩdܟ/CEK')%4y-, h?='Ƅ7~ :yNrظXYّ۴|9pzNnrrk]Z",_ٳ٣FڵW_}%Tq_vy#K[P]+K?+pQqq3p4MKrhYZǾ}sK>r]g|YTK]Ry͝D(rd ֈI փ >|'|N&V8x `͛7ן8qbȑg幙?=;n>\ţ_=#[[cEQ2"Z(5ߤK J5M6T`?y𑿝8ScKUFRRylDZZUL&y^ A}@G9}6X''p-VM]_\ ZNMDaܕ -\̍YX<"s)Ҷ%ޕ@ R:uj˖-k~gf͚;sSN͞=;::ȑ#^dd… m6gΜ*~?P)gTZrqS-r%~;)%4b#Oڙ,:t2R/gIU04EIiy| n@ ZyxxYHjsb/hTGcHB@X CpVQ-I?O436bϖO!c?XBi%Eϋ;IP@QN=!HKG8za^wKA"åGm3j#2Ppƍik.3uGDDL8!+**:z(СÊ+bbb[n'O>诿2Xs<@Axɜ'hBvOnKMyxy ߙk3 MQ2hLqb˗{W yxP80:Z8?g9rf]Ƹ䠺siӰ(i|ͳ;fO"G߰-\֫g2޶omoyC@ =,no;m1gF[8sq+~%y?% xiȐNs~f' h8>fFaճ`3[vzjG!XgddŅL:Cݻwɒ%lٲ @&M⋵k׎?gϞ5P4Dv$lPr$y$N%(hd-B܅ʣ(JJTMZ<|8MR\|D"GO@tN7/4AafҀ?ڐ Y ptӰ.Ra,>[ ;/;ֹڿ5yŗa_?Ei2rUHo͸?m8),XgFʮ_9E/B}ʆS<0n~IIɜ9sj]c'|f͚>}zttӆ -[fccS -\r\KgfR\P54PoSG޾7&1)).>^ݺtg#~'Iii ,V!]yTrXjn;2Ii4= !VP+XΝ;5NOmeevk׮}w0q֟?bavJ5tA/Pdnܣ.;ѨiokAg6z>{rt>&o+GW8wLܻssCT>#xTjJgƒ$744-"?XDRc 6MQ)kc"#Nr`IBt= bXlQ F3pzklAeHr+!> *&2l`&ҦüNT#(B_1^8YtcD5}a'3/>APbӰvLc?nYM\O.1ho6Sx<*  7wQO]ģL>Я' $@aۓ緁7o}Z[i/kƬXԋ«uSE9} 2!G7-`E:/GcdE&Hۨ1έ޸iq"2mܗXL8U$vԙ :aӫ7Oj: :jK&8j~haEV>h2n/MRxd۾- W~i @;;Gt;<Ү\.<ļI7tZ#+O۶i(Bj@Ux"ij}8yZ{Ϻ~n_X10_-;@Y/obڿ9ڕTֿ.pU?4aGg@Y~<}W'>2gL  `R6Ӣ 7*M3 * Phq"~+?Wj7E3+}_G2+-hCv>Zla_dk %lDTk~\4{$<& +j=y'4k\ܦlJ͗>ZrnN$B{ "{~:=>Ĝi2b͡!9K`[m?|[FΞ>-bu(5ݫO{7KP7.Gt9#Ծu 7O GX(Tq~f {s`ʈuY}6l _^~ - \#8=sZsm`'>~jAe=?ǂSٓ K9, O[AI[t@Tq7I/=SHվgq4Aq2p(.p ,J{ϛd3OH@`V1c+ ϭ۹;:݉+B!/Z{ϗGI3'J<}lU Z`ՖU(pof@e>oen MZ7 @RyϮ-i{7<ʆ)t xn"Ɨ.b>ťuN ұxooocs"5v;x޶f uq({ 'cΞ{wnbN`<3sRSR>5$I! ʃ^?^XuCR(-׊u!d:0X#6НW _}+#m|Z}a-xTØ˷zC[x?~(E} 2!T5 A \!Kj]{QfX<xZsKia櫛Gegt1{&1u殂~Sڹ_w|gWm"x@hM-Uʙ_,u75bwo#-Hsgg>c珳'^Ӗo· O8yPoEA U_Mk׊/#??54i{A߯Iϝ6= !>>2gL  `)bT>APKS]'<%%r_MY7)iYr۷Ei;>UHI}l$/-wMy' mk@Xt y%vU~tm?^w[#;Ճ3/K(M?"hInV ^njz]r];Ȋ@j#R,0hT=}U@ZW\!¨Cng53ai)k+C(DRR,Oy}dȀɏgW:*yv mm{uʝa/|}b`_ynJ.XX9n&ʠr2n:ßbm۔M);6CGKz͉Bh޳ADcOGѧ󚘓6MF94$'=g WX qu ,* ~Y: EN ʖ xmV}.#b!H 4@Zz8s,KP7.Gt9#Ծu 7O GX(;'|Wdۆ@XE%&|: KdƹeEF}ɕKpWBԱNeoiFbouꌜ-BivacwiDl|Ԭ]^,уZUcfe aq8l`_1+OM`7Xgæ1 15c~#<56qCITs{~},h8= ;=\.Fkփ:g̓gu&X] KGs`FkpPs,M-O5cF0X#A g ]'u*X@nr,O.{}1cA!nbEvΊllg?%~xhIcnѾڛQo%Z5q k3: L>ym?YX$''P*9z˦'|~1N~Y0^9zx{9 o3f>{Z~a1דK=Z}:囡Mj}Jiʉ矶{ ,(}A_t hIv~# Me?/'=#:NSYW~}EK~ya_uTq<,H 7wU4Gs8ek N| <0Aw{35s>hРÇ'BPxrSJZzsƗf#-bVw-+^Mq ߥ_{Sg*ٔ r[fٔ~ޣ'䮘^r뱻)%`Us{ؽ8aGR ֟L9I\Ѱ"[GyfE8r EtI⩍+6T̳ 4IìIRu塅OWira=׹~ī?3@):*|8>g 7:"b81 l4A9b?̿컹µ3nTz>BZm4Ǿޞ_1ovνZ9{c1@sE`/[':6iQ}PDʹ7XHt:eJtUm O=La،Ǽ_^wl|BK7{YG?2@O&5B&/mdfF4zčh,!!!IIIϏ8qb-+ChJ. x$ ݓ'5b0Sk㛖6<1Kn;?7Mos3؋ g]yƿlhHI(/-;S ;ދYS? R;߽Gfi[':[ruPlKXh:iꝇyжUH̝Y2dŮN6+~}sw4gs!~=WIZ{y4_K Zx~o]{ ?k˹eɺ+ܱ] 0lO X"92]tB[9im Op/M6ap4%H8/ť+ZvSn>>}$@ṕw|gVD"Z%Y0vN~;Ы9zyh)`b]%LΕ~.ۻp"xR3tNr]*хxpkl0A_P`v'wS>~ئsC8GcKIdQ+ͻg^2=s60 YP$ fYRq.Ϳ|6P-\dָt]~咫`F! \Q 4Kcz- ;T qqq!!!SNewԊY0sJS>+94r]JI˯2 _s$B e5Kyubj{{W1<b6 <ʐETVz|93F'V?3+=k׭$enkl7#׮uIVBBM^=¨; xybvX|LO)L/:]ҫ-9ʒNŋZ,F2̖}'ֈ5FkoZݿdΜ9jtoZZCi /.nn-o-yZ::¶K< \;)񬜭!/%W^ZpIfJXZW館n5F?~g١$i>l\wAxP/0#({㏻ÀLtiLm8-Óg}9ۓWEkF[ MK&]+Bhh'Ԕ\9@&,l[S|HyMkJ2Ed!kԾLFz9|>sΣF N!bZD<Ε$0#-C蹇y]KAo>z+l>kXT5MQU^_hx7ܛxy9PSU`G>1jB`a9Ŕv4zb\qdGgSN=BZ@w3@I܎)su]t@˥.gX7#zosG2s/k^I$ک|džM]`[\Լь; ޑriǂATA|p]B?ȅ-a{oz8 K~5UT!5:G70X#dtd9qr:c>jFi\ݵݻw{j# )%qfk:yT m6H ^2!=2T^c"43!&c'n^"5BHY&bj6rMܚZ!aFH]\1bVN%:rip:MYf&F 5BpgMVG %YmbΔkA81+\CE[dMlj{5BJBV]p.xaɜQE j!dq9>*N`c%#TaF"[{$&&H=,!G1!Qo14,(JƏGȤ5B8T"LJ3\=}$8Ә`ɠoB!dhU+ngJNʥi*Pe.!!d85 揚3W(j(g5콦pF !Q'Hq,r8vFaU 5BHꚟ1[8juBHki XZ5:Ӭ4:1!qk^hX<`$V Z !UBbWaBbׄ77RiaF>+RGȊ%eF 5BH7 ;70L 773 G5BH 2 2 0fLB`Ҋsr [Xa gIBHB2ցd #e\&L9{P0X#4a܄gĤeʅuo#4!T7 B3|0 r5n`#4!0@``#*L<`F7ū 4!kdZ2XLQɲB.̬񚙅#=ELhLvƞN@&^; G0X#)ONcΊAXB0X#5:,Xk+ڍ]B!2c4׮\?R!n,[:^u \f?@Zr)!`g@ˍXY|5+X0M_S .m ئG 0X#ej .e S;p1[Wgr|k*3׾5<|XYj|Ԃל/qϯvA)aFB#+.*,烅jP)ITMvj[Y~A)`FzSfk UU&TkW7`FHb+ ިrRt􀘘}q(OLL0\U|0@)=L|ӯ?.AHbQgj3v7(Bɖe;;6P_>.AHb+usVPT)KTU|kJ7j +t.d% T.S  Uo֜L!Z\)D+u:4 i5BlUáNhf8W.ܬ&ށV`FH⚺Dek@v;Q`F;4xLh~i4۔.u!c`Gh 9,u`sо?;ZlAt@ Ai4B}P&Kխ\&$E`u@p!fm1ZM @95Z 5BA([i, l$B5B Oc-6lcdž`cF Kl6M@/^DUiױ"ElfM`Z bFՄ9Fs jHۂ9M`0Bp!T Oer)4;ѧ3 *`S M0VR*RZ !/!GeR TaF`q`q >dxj5Bn=eˊ`s u}@kPiu)V}P탞~5XLk&tuqL>Wؕ!ԂKAB՚&U:)J!pPm{ `ҜٚAL( -k]c@ȤRV4~㛥k 6.ZX+28cҖ\ ؊ Ssu\mB5BHO VY#W. !y9RV'uN3LPo!5!]nq-ǖk SO5,56V;b"3!0YkRUB| Oq1 !Sfk Tsj7 BKAB=*6+W.EG0(B:3!SUv[ݨ ه@30X#tB6U|ݨ MqkTMsi%v)5!r5a7*7nNCqX#&2of&ֿ5d:5 X#4W׏}Lma  {T =B!q7!8 5Bδ|rEIlH Ѹ7!5:պOά0Ɔ`C!!% !u2\ `CBp)Bv/ KƆT׆'LkP-\@\+EIlHezFe"clB 5BZE) aEOp' wLFUI1c V,5Xq!{%5B"}/u$'%3|!3w>)I{=aiO2ABQK 2 u=A4R?SƞT==1z[2M2uZ=\+#f&i(7G2'FU&r dp)B+2rfF%%,eb% *`bx&P2dfK 1pd׮ڂh Fp)B&c7$:lkU@-!` QFje}%v$%lK-)O90^#W!S4JOoeۢ)@0X#}lOJ:Hؖ*a[5"?!cڏ~-4?p-:a8B3q'UB3\a!& qWfٚ1Bi"; }s3!¥ q 9TesoULu4댱Gw0 C qdGs$$%Lu3UU.A#8ȡ: 1P;vƔ; k8Cj$ӌGJ5@2 !.L<FNu kVWsWE)6+Tx?+4 9qG˕+$&&VUN1*W4M4X4o erwg FbF#*դO6ir:55U.kZ!&f`1 ,g!d`ʷu ܦ\*RQueLƮl1ɢSBWxPAvUɈŋ322زw-X B(Nu d]K.;w.??w-؂dץ!èxDWuzvd26lxɜL&gk !>\ HaXTvՉ:\\.yo23[3]!$X#3pK&)5iСCLw0$H !M?dâfTn>DOaQ.d2Lc.]~\dke;BLKAB} ˵Ilh#,*flݺ5===//i!" kLf3ԱUWLrZ9i ߰aCZZѳeRB \)8sCuU|k&WAdDDDllJJJb:vBj{!Gvy8}t^Fd2̼xG9w\+++GielBj"=hDf\]+=0dɵ\.MΝ'NѣGAVVVVVV"ZC 5B&GS;cKLL |ڵk&MTPP@4I<$ i BHM$!S8v߱hT`oojժ(,cb&EL3TI`! vɸI({{{sssKKKPn:++ncaF X}7y;ƸI GGGsssŒ;;KvFHH iF J,MFSK;,iANNNfffXXX<~ʐ1i1? !c­u>&ܛuHchoILϊXXX(R~7b5BĄĖ7sɢ[\3g4rnV[+Ҷ0i!!A]Q%̜M6pYB:!N1u`l4 !`w0p&&(0i̘1sgCE0X# ?f+1SF5 X1-&i !v`G☭*l : i`4º{ջ\! : FKo;B`JuD Bȴ+4*6|NF<'auBuKA)3sE_ -kfne5 !c2dRi+ !#3@a=4`վ`XB`2>fDn,5WӡpoZa&_‚*@t8qu|B5(+Ƚ;7=PpN>:OD}_[B:cݺ]'c!u^WAӀo'j_@!>[f-u?i!TF16_M<`4Ci5B4K9o[lBHKB\;Uk[d\# 5BOS=cAtkBHkso0T BHxWpS1jvV5߉S5B2 !2[cQS;aBU¥ !<ƚRm vpC 5Bcfiw?:0X#$:zdW\`Q  X#A9SSj)*UL>"3!P2|j RkU dS'@-aBj¥ !.5)@[Yצ  5BjcgVIDATkNy)9@P!Dj|G:=aup'Dk^k**2 vB!B5BAioc.T* zo8 !f*f!E{ !+0`=Di42B&k`ʙ{=dۈ)<2Y:U ރOwS6;4v;!d]۷{ !aRs]Y+SwENG9a1 L^'L${Bۨ=!BHBE5|12lp5Bo2(=-]C!bgjKk2YBck8f:mDk!fG8f:a6r!U!wF7g[q6|N|qX#!\^!?BzĐ(è6vRGFPu0X#ˆk(6vRGp5B!{ YP%v%BfA%Np`u BH 5BH`ؒcDk.1?(0?`'u;2 !`09`'udl3BX#t]Ef鍢ykm\u]b5Fi!QLVLwKaFiu?ĐÁN6SwpYBl!!VOV`8ȁ  k&8]`:DkPq/(%`3u2. :Ƣ8`3u!`G˥E50XvTf\c|GHc}qM!(OLN3b6=әVD&UuwNs6BíIͭV~f3Szzd/^6B:bs裟Ʈɘ:LFktuţSDQ0X#AZkMyG.OUO~Y!]`7i]pGɂZ*~6Bk8K-bkY?lYG0X#J!Vu .8_γ.Z+Bƅ!.S(SO5aKuKk8ԂufK=L6:o`K q_ X!e3:*&f`WuJUſUg2 ?Ma]Q}U]ꃲ,!`U#]*B!tz0V‘c\1|ςP9_Q.ou e1ʓsfejT{;lk#hu@coƊ3yx5cmaiydž`C*7 I>\qh7@;+kfo}>`Uߙ4`PTMI)(tUsWL>7 (̫B4*2XzgRha[ݿ9oNw(es +]`//{; F4cV'abm50cU vkwHp:׭!S+UNtb ECX+Pm,QDuEmYҹRb2_[LJoDޠ,M5(zW5Y(*;+yO.)M{zb]k+&要HYD; ƘamNrnl^}YRy/_BC]ۦ~]"Jx~}H <}S!jHKA-P~]/:A=lOqx{4*3\|sr.z}>f?7^Q%rp(\lD2Ւk^ BWZ:P$>qM-ll`'W!UW2Bhm+ uN\F^ N>)-r hm%Y/=MΕ>D܄79)m,"O?O*3[d 4 G{Lk2L00ɺ %⤖-~ Qr*5{nelz Txuw;%OkgO_ \ ?!T:=Zi-uih[1ﶝ}wE~ƫ\Jhئ@<99@٥mk^gKaZ~}G.>͐VMGL=4{Cbof*F!\;or%E^GKdgj,+\KfMCdɏṇʏ~qȻaMKo]z& s'gs:'%O? 2fIyދkמGj,*;oj@"QA輇O A.taͫ,lP֍ 33ͼ6l4,+74B{&Q[hkw~~Ƒ-";I<}vn$yCqNܝKR]"lԲUn{מd.Z6XuN0a`fuxnv I!Ozʤѽ|/~9kw (iyf~\???{Gws}}mW:׭!ʟQI AZ$hZq5:uq}ߞ˩MS%ϟY6n#? *vT؇3S=ȧh{{s zr6VOd6h|<[N4MI"=xSwwyGz)_}D~u׆%jȐ1Ǝu__ϖ4MX7r)_}9=(u(mCD ?S#!MvY;_3027%EQ% gO5Y Ѯ>(|HӮH?`Gm"5l~g_TuͩfTkj« eVMH )(7-al>ظ *N}!QX4ug֎nA@`[WP;(H.hi֋gFD٢~ xWPrc_Z8 ..'=RX(@\~BKs.) S?z_,'Hyx_,P_. /,YލU[(UMh\F3qDd0ɺ z-}ӸGk/ظW#{[PON8vYb e Qa⋂H]O Wo!)=SfRcٝ64hJ1fQ%gCμ{eFL1ll m!"9U,X5ĝwu|10ʇ{infk/d=ًt(New̗Re !Nv|ynn3s[q9%H 446,]v>hيg?p-g}3M$ 4UUi([ų*z6%̊,mH0w43 lBUx;]I롇4Mؒ'Xs)-#;; dY/w&J?F{v<(FM)mi6&ȣIS/ 7'.htF %L#e&c MSN4Ӥ}~Zs|i^mOvDOzs|Rq kvĕ|+a>" wEʾ tuܯ[CpЋ2ꅄE) ]c(Jqs'  L(T(nґ#\~dyԫWPiو6H4M!GNQ7 ^t;):vuؐ*f'?]Mm~=颸 wu|@e0rPgo[t'6qC+Jc#MQ%psdOnWSo*Kx*ȖOlDBn%rU=˒'ٲ D4@e76Sorv<3Ӌ˜)wx2@Њi0Y928U P]Y)va"I^iOj+V=Ҋ s/޽{߾M ߖ|U;՗69dY`hFͳ)xJX]Rd+Bر݃hu@&0|(au(M6a+7Y9A7م)S.-l\-,5Fй_Gh"ŖQYjzu]ŅbG7W3p<0y={>ofG9[õ\qg_E1_a2\, 9333#"ĶW(VbQ߷?ɍ{/ҳ23Rm Rd}0j`>}PWLXr w;v'Ϟ=}`l=ү0.!1!1Puh@c4o oO?{x¥g5/Iq_㆐a}>i*|v f6gܝ'ϟ?s, ϾIyУS'/!!kPx^h1<&CEoo{ϟܻzF :xA=OHL|Yn@ )7c+WPʍ{z`[u]h3^i&nf6$M PۿNq@`db@?ZbPZenS& CBҥb7c>yc n@\ݰ=3]JAy iݴ7_4aMƝYI9(?N+QF ?N9~lmmKodueG~[/Fv\!r z/yU J_P3 |oG< 4ؾq:sb5 ַ{dr걦rqPqZ+R-/zv>BѺõTf"">O?}wi[7I' m )yԁ.S {9rm qC{{_7{gߝv}ŊDS;N?#}_g)(Hx"ȑ# J% 9%K*P U~q0.!HwM+x ׯ_5 J:n`]I9 ">` 3#tudž`CT_>5$w۫0E_).T>R~T:V|Q8P_$>ŝP4:&@P6NDiV|K-cr=]Eo30MV8tudž`ClȻ(zz#]v 'L>Ϩ+ꪗ|Vn]f EAPzMèDDV6(]A@$QJ1ꮁLD̙>6RUCY&+ ^Tx%էբ*B7Je  (Z$2rP~$JAA5C54{2#a+Ý8txdž`C*74X4mmmaoo\Mz!c*TW TZZ^*A$ϗH$<$"V,W ByCbܠ~Ui PtCR\l.2ryPW <t (c]!ؐ*R)jԨ+WCCCի\{/S婕EQwi׮mj<277LdVٰ| s@CIqq^^EUq졖 d,d>zUVLܥ" }u+y/ D ۼ߷[@M\|%7%XCٚ:ߨwN>[]1n-)vbx&{sx l:)ݯ> Ȫw$yo'Jq+{td8ݤ*|׺Ӽ#t;V<>{ן,]t0{E?ɝD)z^߸hb ~N5qz}᭥_x5uƖ*TW1f \e]~+K7 )suwa!S߸o J@ɊsrgZAI~ڋKX{ع#,^A4I)Pr\yKՋ&)햝(IS_Juu}YPiʩ56W~C/CWY}tt%9rÝe^>vve=jrr ޛԊ*r$'b(%̻G<(tou>bg'v;y/s󡓆DX@=w'$sXO[RxKx}"?%qUs{=2q^m@'߿Ʌ@Zzwb*$]<{3k޷m_`=aǵv(o`"7&Nͬ6ݜx@={ێ#Ws)3N>\$7 //reb&>WU:7{ 49m|6>ldjRR_lJ]y y}c ;^ K2=}{8vM!۔{{*{Gľm}?hHjhI9{/]1c͗|b~tdO~|AuLYx@ ~C^Z'M?SHV^};뒴{._v4?r:ؖtIҕ?wq8 4{CUmkY$->Z6%̚T<Α5ð4_گe>`v"wI4 @e/|qR[=n8Q/}x/'Z>*=k{;W)G?J Чՙr/ot$R- t@S]͘ѧxf}ƾˤ[/Oo)r =|hqtɩycO˨w束n?N՛!]uݾĴ2 @:7)Ѕmya!"//La§#3^~]h3-;@P$SQH92wڕk6VZxb(SjX@ut=Ł'& ʉz;wen:&f"mͽnvbc}Gge$xbe+"|>Qtl5?Zy[:U-VS^@tE䨱>N"T( 4P#+Ǥ@.2v{éh^X@@HbeIjĪy=kV?*89T&8FY C9fPy,:-qzC[v,:F]W0t ~z/GF:^<64eI~|+Gy 0yL⬍?|W |=rEWG/ 1!YȨagnP% vF?}2Xкڶf9Nd'zR4ƠXZRHe/w7SMO&2۾?"Mo ]p mlJQ@H(VYxC㎧Z%E xg (ҎE)勗^i~^J D<=fZ@$5єeގ]]|ܻt|M cwniγ|>Mm(TEPGqk^ˁ_o?iIn4 G0C4]OOM_ h?Îzs5J^2}<w\^d.v/I=|`^v f[Lόt$n9ga{^^ٱc~+8e 牤bP?xѤ;X^3 VS+ΫGz kF7[yK4]90BЅSts#ǛTBDۙŏ?.k2ⓎnrCdגo/{bU~/f[ eXr/HEFⱽ,.E/WӰɳP --I2;7P2U|JYw4#D aԌcm4yQ _iYah$cgr&`ŗy #XJNK/>j(QԹg,[r|m9lˠ5>,aYPR x0DEawf<d+hKELcV=t՟=ؒ>_cKa[q4~c RK Q5J~K !h2j΄V$fÆ>6{`Ty)7c$A#P·/̣}ؿ+/wRbbKL=0Y^Z8pfd;yuED,T[~|nQ屷TwoRe֛Vvt: r|oYo=U =XD]9Oz~BV确5z?(8ur;uY GxJ5!"z7JVlqtiŗwh:yՐοjϸ%wM}Jf.:r896~w9 A$%:6{J Ʈ2nνr%sgM:|܈ Sf?pfT M.H&n6[O)o;vϣ#Uo׷¤3m\AI?2gH_ӟ.B9'tu`3g}[F]ލ ۇVSV`q軷yZ^,(p`ۜ9r jB@|ҏN.|GRֱ}XUaf)Yi55ex$TOb?B4W=:3OUl|$GEOwK '=J_Q ݃_u #6Xv,=~qwYV=dS'4!Fw/p6{BǨvvbA+v)Y'u߅`?g?p=) :1{*:u>CB$gw1gBّ2I?Wf H;g=xwK]\gb @C&;s/'dj4%Z;5 oppOQڠ[WY3bG %w͛(b٩c+> o^̣KҲT;tWi:bB@x<>r;=H{~e-G2:e=;&jaAU搢͹\goS JPtva}ufUt|Uf>]>T%ѼZw&emqQVX,U;J)RbB ?ϨDw:h!kAWT.Z]u^̞=),vU=J `ج"+uH 8U`iY2hIfq_fn|^/Zu?"8]ᓧe;uPbcc*KL|zt}hR/i; Ʉ+в@lkT\R_D+vJSj>̎&I+'Wz\]Y//O24bp/IuRʡ|,r@}WV귬#}5YYE"[  -},XYd_^ˍ} kR/J;ݓϏD&e>!ۣJU D]Z):LϰnbC!*K+̥3?)K~:'#AXZSf4 ARRJ7|UyS5R.P+h-fY7:vڵP񏥦DUfc,#ƌ ѹWvN4uoaJ0 2, j:tRWeyݧzܙN{6˰ M}իofEѿ+YaXڠܿEftn?o،멫^L}| "31,7R5;RmU#2Ѭ=xW7~{\Ѣͻ~VS=۱lgjSٜVwBeAx`+gʼI댪T@h&lou=.M ao UASi ]~S5 ?skIxJpL ~~3 $"S!.S݈e!n1AYB D]7JTw<Uǟ>v8zC.~m 9YvGjU5Re5m⶝xbRjMs`ac@.bBl9F_Hl^ƶ K,OHA]b4ic]=ai.e#>|ذEul\ ĄP],MٵswoegV6}jRnRYQ|ЕՎgJ} '.dW]4lʬv"qw58|\굧dn!g+9;e,rh'W钧wsĎP*+tijr߿oM%_Ϸpw/STlLtڌ\ S5!m;؜OI*S|x[(?qfTu)WXPFeYp!Ç >On6n^&Dp| '!s瞕uE$ Poj}N7n @bMss ^&X5Q( ߯^s639^C?q+FNdUuCIߩ\ qjd[)UL;.}zfRn7FQ' ӄP*@kէr56Q$^ɴҳ!PP7uȽU`m.hx2W7s)h*T!e^M[jlGowxw/ZGfoXx*7nX}Q-7߲iIr+BB]tn4MWCd&Pnn፬RPo3p!oriӖB rQw8{? [%l3g::/ng:KY8 zW /O[~IiAḬ(+w[%mWV4%#dGZ.;[=wjuW-T}ڤO{Խ.ܹBpOjV=Q>{{ֆ ;[,-᷵e#:H6 ښacɞ8"njye^)QX=׋iH>]oƮ]c2k3{8мe YBI(M.c^ЉS \ ?A E|!^r$fi0{њ,_z2%S)N{"kLp~ݜnfE~3z801 (+n#{=ǧ$&TejMĮٶf=٩=Эc3RSZꍩmxXOnԩQu.ney,0ܵYN6 }Q03v1:&Ƕffeҹ3WNԛ' ɶϗ]wlzkCp:uљ5SR~"L%og~ 47 Dew_?[zTF]%,Z "4Ҟ E"QThXkNDoovS2vaA(7a}LC=)gw-uKDyk|h@').e[;Hy2Tk눚Rul[%`!6)Ͳ۴yoO\i1gIL~s x&vz8 /<`KȀ-dCw8Ap$ʑWt D־|Zx`߿ΣǷ?i5M"$I=5ð m"g,}r՜MZGL0sO UJ OȚ0m2bcO?Hɯd7S>aϥ$Ù"Ev;ZA({9q`˅ IPÜ0}j5f[j2ǩs_wq~VhӴGhF\{O+OCQSm=#!Fc~מw m/;v=! !׾U)D| LF~`QJD d *TZ+ϦB{oyM^PR'puޓ7/PiBl$cj='?WiYJ&O1jNh1tRs<4h©f[~۽欆'u >оgܰCEؔE̾_ېdAvUtO#ʼnJF9lHwyN_8mjDxGD>gxfBH*NƸ'u0pGI(3 at;ݺ ̹Ո!E$D. }O\ WO[55 ̌"ɹJ"S&ʇ_KNvOR+n<{F wիJۭ7{?wh}zj xA$I$)92j߽0ߊ6_\e"\BL;w\8 soAlE(U>^7z#?@R!֧O3a2eƺU'$_5^ :^`}蔇W9׺A6~ejEQYWKC6^q%UQr9r >j-thECHi"z,0R] Q%tEXtdate:create2012-10-04T17:25:48-07:00Gm%tEXtdate:modify2012-10-04T17:25:48-07:0060WtEXtSoftwaregnome-screenshot>IENDB`rviz-1.12.4/doc/focal-point.png000066400000000000000000001452331300447110700162640ustar00rootroot00000000000000PNG  IHDRbKGD oFFs4Po pHYsde vpAg @EVIDATxu|Gw$'D ;+b-h(+ZZxb5,z;GyٹpRJV{u`[ @!PvڭoSGiT[ ;p\rO(fʳ|k3` Wg*Y.ڂ4O s>eBNG賧%g,G-忿N?<&9n+P& ̽IAWd`yegm/ʑdEc\C~%y_b!O ;:<("RJ8VVBJ#11I?,`>oJ_C!P?kdUH^,;c!*m cL`QB!#EvڰBA!PNU*! >s)Ei@S!Yk!Q9()e-BiT#Fbse ɩZ5+:!>"huZVkxy'(iZ[*lB!W܏yB8B(be@@14MцGN+FtdwtΤ̍QGD4L_VxYbBdn- {RLJNVfXԄ'5?(ST gBe6 8d2ebbR||\xx۷oB!˲m@iTJT배,GNi4 sCkOK3ItmRC!b4mhX V *97zr&OžU X} xҼfg{Nx,M0 Μz:yT"*Xl@T*WC?S䈐g$MfmKew9S1 DBjN0& nӔ 3B&# 9J ]t8TH%Z-Z2tvy8^ "''GWW縸+WҝTV E9KEאdv3m`ig1JH( i ʕ4ƔV+dr;bXl*f̖BN0"s1U"0a5r5J`a-R"-!%Vffs?>EJba" IJ.KBB6#ï C}JT X8I9ɷ=rrM]k#kbx¼Q,pOO݈Kg++V@2y E`*5IKK#@ TMQ@JM:wti fYMSccB ==m8\ڱcǓ'Oqeڨ@ָLZ=KBm{i C w@)Lùpфh6v,ecBo`DRf.'kǮFP|fuq`g@mզC7g/FS, k߾ W (@x{yDŔ KÎYaH*d-sᑥX(^)W!gX&դ,e;c8s JA!TN]GTBx:((JۯVkLL$.1Q1BhxGGGL& .i4,wNVgCZhjOd$S/eR,qTGe'8M 󽊢%/j3@fiKɋf uZ3Gnb'!󦸿  m,ա]}==~'AQ8ʟ/qDpW(S捨r-6B/EG˗[f&39LYbMĒOn32Aln* q<+ ?{)S/'nk޳u{KB=qB!s$8Bx4N(yggȈHΎ 8:?…j92"( ǵ3Ѥ5D+}Se|ɃujФ39-P}! oi.5\ȫDf M*$)wH}co'2J)1O Sm]![!B R*]i|X p$%QiϭpI-\O-_ߵFb!a26h-5cWY"P= S3b0N 5j㽪S#+S"i( ʳ$ByNjjR)Nym/@(ӘJ$<LMMU*mTAr8dE&tyao9G%]iym-jR)|j"Aփ)F4 ݀m_ޕXެ~ryQψa4BOfB]Xf*ś+&,pA᠍ tcB!T8"exR<'P$((ZdaHBBF hy P* Ph{(as9MA"RDDC*O?W Y0b ˲j&XB! (J0HU*uLtsNfXH)m@ƃ"P@ Xkt )iaDBQ4||3@*eiDwՄx4Eь@ 鯆/B!7ݺjaXeqd,o?Y@)gD"F$paڥ [;\$2 8Tʂc;B!T4u)e BG"B B!!!BZ BcBiaLB! B!U1cx7c:Yv#gU6"%,`c{{B"~إ!`|שf/VX z HFB+-oĊI7^þب&QAj(1y%N|?K-R&{صd`I ȍ=BELu:>(,ɜR"-LƚX:Uksj.iT\!*7/?ITm⟼NLy2*k6|>] G1ޑ;NN {Ux[ҟ[vҩn-P??{ ={NP']ڿaϝy|=S]' oxRbc}] |xvOy(qx;[)R?~ Br)aN<[5IT|$7|%V8 -oz+#6ԷϞD뢗~<n]\#M}1xigc[T3~3k>S<}R>wa tzB( nndx"yǙa,F/6Fynl}Z+K.[p>٨~fH1iPRBCjyS|Yt3gΝ.+bݫy򃡪hmE w)\>}ۯbBbPИ@[u;Re?+#vdijEZb\lR[Mn~#5[Bp$9(:ϼ $ߨݶKמz{"}I:y^|lCQ'p`Gr't٘4BB((qH+{=BUDudC^}Y'`|/oOp]:CK˻ &m't#8e»D+ !5&d209^䣃mDx<В ]zH>v0g[8yji\W†m OT]9A$/{YSu{(%khr$^FD>x@߽w'Qz=?Q>N_:@1>$>{8h|}<\zwKy[I8!P7kd<6.pL!Bbv-""BH cB` 71cJ9śB B'@!G B@>㧌 BG׮7vBhCZqǵJM4¢'BИ@y㄄DcraҢfժVi "B92(&Шaa7o ްEQER3(R2q ?47pw8|BaPLq۳,KӴ:L"dPQt۵[\]]7<0&@!TB xOLL dYV 4 zqUipB#4=/^ݻX!J xgFkva8@Wa;!t]0-̸(qt'BehL_<tf` mYeߒE[ zrww71|~Y7Ì]qeX2Z5!PY@+8m@vZo0,((]?#ˊF/Òk 3;P&6Kb,< * H k;AhK*>~-}L6 /^laa1jԨ#FbxN§ǧ tjs1 X$*Oyv`GvM:6wdToާq@H~nTm48 B\T{-^gߺuٳgs7pm۶ܹsGV=ׯ?tЍ7ٳG{OkA`)qE5*PZIMq8vt^h]}v5/=ݘF4hϮWiWsu,tQI}y=Xe޸c][6* _Hܑ{NyN!ѡ j&y;t(L :g&trwvn>ypW&ޱv#?~"BԬ攊ަo 3SV{,=m(!& #&xtb{5O(5¼qm B(< *\"w )ZdW^\fM|rttuӇ V>:=]MXz5k|ѷ/3ͳ$爩嫑_o.pW=Uz5KO~&$5I(B/]m7S]{&V-ifUN O$uV .vsWʒwq/UT[;0B!\w7+W&;6$$dAAAK.S5lp`kk|OjaN!нYCuWN6 7":]x"!||F<`W{meØ*D<<ʵZ~9qY5ޟ]th/=ɵ'3rAq Dth*BO:^`te?+!v~?eM*_ڽ~ =Vk׮ORfotرԲBm.bbgg|||߿={S~WTY 'ix`̜Ew/cTnBޅ$Mkov'"!&9 ɻ8狦|^|^o@M n>=2<"K!VB6,)<O~,{rզ[6pdf,$d)ate* {vQ15vBu.b@W[I>h4/_Q<ϲl```'Ur5B! ڶM 4!h& 'RfM_дC}7AK%5S6rqgg!@֬mе{mVri)V1ӫ)]=t-o񶗲mۋ5W>ڊdu5fTWb3 ;}d&MxYB"]ߒ?:0_RNcOFXupzZbabn&B%)ļ<ɓQFi!P E1z]}V-7on+gr,Xm$!J3 ]$jL S[ݠB `<'@! M d] 7KW]8GN7PX*=(Kc@nBdt b* ; -gZ'#;!* ]$P1p[*:+]>9BD!Qqn<[I,lBE] * > G4MJJ%˲ښI{|`6dQ!A&-BaXOϐׯYYܣ%)G"ڵjWcgj[оZ/FqgvئB;{,w uZ_Jkޮͅ?mkCui-AMi3[66Юso\)8,NeتY[T{/987̾QUcǝ9y/l|^ (fcgg(?A/wޱcv iwB( O ph>ˑO܉kBY῕[85IJud /ڍqp3c`ɤ&Vbdl:Bw @r&qC ?zIWYmJw (OgLϻ@G  B!c(!gi`ZF *&xnYnZԪ]:yG4Ioz&x~闗 ^M܏*#Q;jAkBd`^f _WxPW]X *"lDzNnBSrz|2mYD= WdILӾj,PmkD]M)ֵس`ZoW32ʈ @7# x 1/ީ' B?Y6G?fN﵂24Po_,7mhmv3%m__~V*hZ ].ݡ3v*BmBʂBaB3&PG]y2FPK} Sb]tV7O*M<[_̩'\A;[TQ$sN-m#/{Ӻ-JI)ʫϞ8gyP~[u PPYY2EfGЛOnKT0 N)9.l4B[Ǎ7߮guB$˧\xmnG"ślA2* {tfhV jb;B!TdHZ_?w4˻~wG:,wZ{63~R/>=?"VWv}GQ2G2(7Mr-UL3b.QS?BYWRC1bĠABa{?w:4d҄b|}rD.Oމ)fw 5PuŖs[+p0µ?1!Z6ƒYfv/X.xӠҾBjS>?4i$=l՚ߎq\&2I֬3 ?UC8i>ݗO~gʝ^%bF7)C< >mN2 ~ݎUvI{~61WLеcFX{z Xʗ[fvIhTGn#'~]w i@4Y?tĉwOss742E XW6(ߟZpݱqjlp|3B 7o^``IrJ?\ҵS76k<9 i>Qvw55Lo\=kbmWST1Mc;Vsa:&:֌csT[+r\Y9|s"t6ǎ1JhV+ 1֍sFÎlݝX$K ?iAww6%?N3_ul#?j&GYaBghbkk+H=z_lݺ5`u?:y<,}׮_urtByjTLJ|P[C|,{V3"a:tಿώlO1 `I4e9G+4mP"GZY9u{|]^ߓmp lެ%ֳK`w-tzx{e$6$V7iB@]1-=67Va-KK7!Peg較Oh$yuM݇޾VVV7`7Oի #'Sձςӄ՚{gTٌMl )!{9e؅FܦE.BwN T6uxAyO48B{oHM@cDKϣb PBA1'O"""f͚lٲ|F,aٔwmp9;;{mXu:돵r@0mD&$< ԯO'"_ʩ:H`"{nW~G?;Ac(ΦmQ ߻oշ﷒o$B!V,ۮ]=F7Y=<87kٿgGOmٴ{߸[ f&돾m!@`k :ތn+.:Я{4 i=Y=m,Ru0D u؉ĊkdHjX݄"P$+r %#rs²[Fy  By<Ν; \ۄ˦t8sㅦ1 +hص{͛zJf-sNl:VjL~-$|ғioJl)3W^ >sli~~gw\9 ɍ[|f˺{{z L4gV}6OL2O=O[7Zщ!sO߷х/5"M{Uu=@;d۸z?_`ۢSՏ(5\ʕsbkUg3>D05LBXƍE"Q1ehB,X;֬:Ѿ~\p)!7l<;T~EBUAAA4MSѱX6J`;~ԬW]~2ϯjJI]ffemJ]/ƖZ;_!TlfΘoP0|.!i_gy#@!* ֭}E!* \L|ؙ@!I<+!B!( Mvɉc_8B!>Q1ۃ tDhR3? 0<ݔ!;g}Vj1'[.fD\!P#/[R8.\Qm Z6dí]1y琢Fj`VC.KG/*iB!#hܸino}оyzI= 22KfAsgw{~?tςY˶.;ToEK-LB7O;h3|߿v ^3^7;;_vu*c.y>8Z b纝?2!,pdB<ˣ.4WW7UEg`e_BŕL0t#F 4H(ڀ{`77oGlj%Nyxq2]+s{x}ܿԴc^ܸۙ} ݛZk˧jXtX7N\_ʛfaXE(J<-rQhrpZ>uÇ|ݦg]ͱ/g7I2cȊ?^1yf01#']Y>a}b9Sc~cѶL[w-lUʞg H<~b^˃^ێظ>kI7=zאVN:7p~ꤽU_ՎkC)ɾ {ba-K:m 5e`xM]m՟|zjM3~.Loz?:[N6f1.Eεa穿P$K^?~@1W#~-w}7ߍVo<@jUͤ@|E6+Ѽ [. * uQk4'c+<.ʔYɿ[mתt{bR7[nLՅ,Fe**C1?~e׻pmX؇ }o'вH$=/nݚcX@m9V}QQ[HZnE0X~ ڂE]5S̓*fqԝ`; K ^}6jQme}k4md[g_+R {> 7ȱ'|,r ݿt=#;DO k]30L[R.¥:l`GCFep-2}$ZO6m. [<~4nܴC߷l)y$F d:*_ݥ+[0EcOm "zK. H!`Һ}FWAvOw}(͈syHJ-1b+Q<5H NlvFeHX͸!*9|qFY6Ԯ6N?;% ~ ХQ #:7&Pm @'sQ?^B-sGuvAc`=ܲeVk;Y++ios1u(B/=NmjBhI)*]Z{XÉ_:Kģ[׺5g-8SS gᯪdL!iV؟b;|B3 ˏvmvLwd ]ټy-/J}P8˧ M(.l25,|:c vY UiXåƝ7wT^Ebm+þ}x1'id̜;ݯ=nco&}w䛶Ï ȼkN:A̽~<'sT~_6w:!Yیo&:H@ן/5c|h悝3[K>n覮&IhM]$eFdD{n^Մs+?O֞JyfݿuKcP:yu6ZͮLӭv{{>ǂf[/898pQ-b9MY@e\ M(fR#-XXf#,M,_hXcYw?q];kޟٙ`-\ܑڮm.ˀTv`¤E:M_.-;Ue׵jI;UO TiZՒ,j2roc~Rg]:[fɦ Y4Bڮ񴣃:ٵ5%-]뷷e@\ǭ??nkx^q|rԼ)6w5$<:o(+n b;iF4b+kb6Ta!<Gx>)ha񴇘(cgBlCJc#-hx]L@H D7yMBj\gE1,ZU0xgi_uc_*>JӡTҥ$*7n,2@L@1IZBI}DQ> `&,SWR(!e}Uj9`bSIAh.v"U"O<|@ ٳ]jF%2-z M圪fwqdyPuui+% NQ_?O(_t)ÙA1Sף{w m˴hܼy0l0___pqq9v؃:vؼysBщf<3. N6Y9L MRx/$[FE}<qBRNƻ6QgDЦ_G>}JӸ~J- G:z\\|n:y%VE}رmL&0`ǏoެY3JuΝ:uݻva*eMO|XƳ { qodygxkVVurK*j ԬY׮]uU`;o֨|}7f3gݾٓw_%Q4bkdv!DZ,LMͼ4I-l}!jBHr[w ]|χݾ?c}WeY6ƐDEi[haa!YCB~߼y3,,M6&&&ǏU֭?kk랽zXU+Zڷ mQ,hT>_96e?|ȑ#?wްaC-LfIu`,?Yڌ&z[q/+u!*e>M V Ԅm,EXxD۷Eσ^vD.. o۳?,"Wڨf15P#@v: -Ydgg[D4Y ;w.!Unv'6{7GL>;;UwO@>"1xmo1J.F&'y Ũ9 M(H_>݇ON`M D( xUvPQB?&):TM:wѝ}@dY@J/-nyKOdr[Z6 VHEÀP2q*&֒hC=-.=i'ϣU ~ v2 &]\݌TvEEG;:8oQ) COLz"(1srH,2ERx؇ll٪e|r ͜1EDȾ@$tbwVs;(FYEBC)# r!lD=*$>@L%t`8]Lq.7!TT1oc][OOOc8bPR; *OBA D EY"p;X'cB8ie-̾[X؇/<D`LBeWRN7p BUT_S1JЮ 1BpH*ie^/^FI!JZ׋W)χĘ!P^/;JcP`AyQ 搱W1Bx T  Pz!C0&@U%>zU miĘ!TIa 5*!T, }* ( BE]] QcPY)z#|efPEBU$\0(c4*}1B%uPS1Bo_iu>@"XYYaLPa`lllUF;!22;w`L*Nc!T0ϟ?WT BB( cB( 0&@3>@!B!GGGa0&@!*;gggH1BE/\!J̓r:kQYG4`LBXuAy0&@}P"Jc*0Dl0&@U82!TR{ArAe1B}C| cPP08`0&@}Pʡ@םsT  *)N՘[NJ08(0&@U.%Q/{dǒ0&@UXUȪ.EKqadP`L*YeaHATobӿ" FVcZ`dPaL `]12(0&@R>(t4U%8Ƞl*N ԮSp BD!*Q LvPiv\ al!TFht1,( !T40v~+m1a?a;B{ W  B咁5GYƌ*9 6Ø!T,Bڵ1,(0&@bYȐŸIID>{  l0aL*Ol@`8 ߌq-7( J 2 d0/8:#F G@cP*JAGE%ȑ686hF#`SAi˜!T>\GcoBYh6ȻÂR =  AכQa_`L*mXȸcDU@+{Xze ;( ʷр```SaL*GĀXh# TP 0&@(!/u \,*I@.8(DaLP1v^*c5T΀@@:F(l*0" ʟ\c켠Ҁܾ `LP$ 0 Ȣlh,fB2Th Pe*2 RAOˠSqˣQ kkHH$U ?;0ƙcs ,a$a߁V㜴b5 вFJc1ŋ֭stؙ(yE:ڰUwB9 r SS3^DGgXc#A1Bj:jբZ2v>@dkXTF ʥHà Gd=,(#1 BFVg$jU"Z6vnrgx462 #˜!Tթ];Rk* rV-ŏ[r|` w,F|46˜! Uf <+8:e'@F1B>(;MZJ4{pFr>d cPf@+{pJ3V-Ȟ2r @Տ+4{`AsXa#A!T&e 3$>Q9f\(1_1B|ȻL:yW w" ~r#߰UQ1"ʷy}> !TV !Tr׈5M`DŽ cP9c`XAeৃAØ!T}``maAdQ`L*  02(# ,0 0 B5FUǀp."Bl)EMV GctN* T`A(h9c@P`L Z`dPr Qw*s #hv: caɗ)NP W`AQ0 (k!T@ (Qpل1B,*ʣ y*bJy,RBEQKʈ ]>o유+1)9}sPa%2r`ẙKttppib,֮gl P *bdUb`QދCqpp`wPVXG.KYC8}EDZY)u^U,*F+vX1Br)@'{je.,ye ƍ 4aHWcP՘[_Sˊ TRڵk7c 0&@]}]IYTU*p(q˗7oNQm 0&(+id*T !h4 ԪUܹsmڴ(Ʀ,<~x@dhC S*E4m"1uptHԑ08W t88eن :uSN4M[YYU z@sPixǽxT.yYXZ "Jΰؖfd}h4,˲, ͛7?|pϞ=)0a~ߡʋ4jҌa2-bGg{GАn:*`8m6,h߾}>3+FX1"2YuMU|={laei윢%KMYB m'vhtm˖-#F(+*:ʳon4M'&aL`tF>0DzD @T ƍ( yX1Rk֬61Q&*rk+`_,8=4M~ZR H$f`L*/M>hz k"TtX7kFk׮1믿={vMC-BHn'K6y sƾRw8. vM4)11q2077733: +wb4YD}bLʶ;w)0v.P֭[7LƲUD"ɓ !4M3 S4o޼SN7ʣWqJJbWfC"v{byoEco*lmm;wd\ ʮsgcc'OB鮞Ov8ƽ˸Q}xo?s. [}6^N 7f?M~‚:?~lƾPPPg$ (GGGsssP0 XYY-ZܹsO<4vM1=%6 r)}ys%Qt5c#EЎZ$Hǐ!PFQF :::xJ*r T!QjX3M,D -uf2x\.|<:s1kuw#/ ƾJ͛Or0_U_BBU(T9̼]9s*ƴ- + >i%$|PGˆBe}))uwpv61yѣ޽mѺs>(W*tG`e }IW$)+-PpbW,N#vKV]<DғCL6ZK7^MRSU=MRxc_ByQ42yzX!<qÄ4Vm%'';!TJr;`M eo.~tyTΐ?qJlB)ƾDrRj׮˲,x(P+Bx^Cxo߰M >@"p8s;Y26,][4v䛢нţ:pk@`P^-[\9JBNUd&B\jֺFq5z}7PVn>[c_By#⣮g ] :~NE>z/JZڃ}zvgh+S^mƺ ~m`ƿųheI!B֕M {_ M+u37W3jZ]{6ߏy,ҡ郪x=pYp뚍fJVtd&vb "샧Z?&P;76jF~hM{woro;#|ݹ3md-S ]s9GH<<<3l\ߜZԣ{K=K"yq;kGvtb|瞤ncapw^L2rĮN 9nP4н\c޿> 1/tkϒz$R%OoGj_m!s;(@U"y4QGOlۗ-;ѩEhM<`Ó09Io/l|D@B)F!i%^ݿCg6u; 1m]4t7Ay}φ}W}H3 U[4h",Hb^F˦6yP>Y,j1ܯ}^F<ş$G p!fo.f(1(^AomSt*Wx\1%8w.cڌA%\}e ~;OZwEk|ܡM=ph}I?(/6Cog42SY[ʴjFf?]٣[Qu ߶s}8r]]3~{%FMk  p@tkX {ꂜfh < eԗM, f(PKG-JCwq̘!%\zBdh4h*bdXM|\@@<| i_M5[H|<@SnLûԄ PԌ蔗w>]uwI5>c,T4+:]ɷb$ML?Uȇ!/0R{)$( H )RǏ9}3BƑ{;A'&yBx'n[V ǺU}CcKS+ӌ!#\}w'7Tژۗ6%U_UʿX =;rlꭼi/Ds'^JݬO#`j-ʈ}=,[yZqVo"Y}_A-];Tϯ\(ú9N?W~H@{azP<>Yɥ;T:?-1Om7ޅvs]rf:xv&pe{U[rl׮ њjm璜i@7.^$k]gMBxe.u>vS^{ZV̀vWEV@\/qjak|ǜDI).ewr (\8 qFƺ{LWې`,4~U RPfM??BC>޸gզz=}|JlZ^6W1_qjs* Nk4W_'ٷqIfΟ7,=/>%Wq]26||-[0@`TD?N-6`X7[vvmf,^G4cleg=%/u-F[yE:/Nwʀ+ 0h?ibU2G6/;J`PN10~añQI,l>19m]+q}y_g%\P9=88:V(o2xZK\aou\[_|o'h8?QS+y|ܙGnyz=IPj=VRvFgϟ֮}wΑ_hԄ'<9|@mb %Z:'0&@(fΘoP(ؼ%$ݙ wt*@vcVJpm)e8 )o$呍Qm79I}W^E$(S.V:syU]泷~_C{#䴹WƎgJ&k KVX7f ucՌuo6]&袟?Sy̵ Nzc_z:|Çl1m <7o5)D?UV~m-|ʋ6{M2/ra͝ztSBR9`:/\fݘ!}-I{ul˖/Seb^Ԕ.[JOsey\ V| `:㓅Tg `s^=勥 r0lfN.ɿ>$._¯fAS]AE)T~D(O{y㫈Qsh߆yaJ|Vs֯_b_s`O(D8m]ٴKдQ"M_xO_ײy+eo|)cq -YPX3(=X`㹼 zwtqsƸmv紱-l?2"^,r;6#_כݏ{X=ZMl}حs Ni vfyȽyDu|{nWP~x'KN7x{_w]p]zK NBzk?j2yxzXP$Ӊ5/Ҋ&؝_)ԡ,|6Ԯ۞=x1|ޤN,X}4k)SzM=zGQ&*Q`)]<=2>5ԻQ>B궑~x彪^ o?}ׯ)սƼ9#|uʃ` 1ߎuuFu3j菏bR<ݜi#kȒԜ7B1w wvgk01R'\ `We[rYRoɋ޹_;/~?$uBqBzc B20`<ؽq '/b46AmؽШ^,4̾ %sD!8~7wͣS4SL~&nw#{ NX Dٞyq+G\q AA@bJb4&ςSE^߳agDS`atQO# ݯ}ѩ̘@.n葱X#cP?Te9CR|M ϧ:3W|v8{~(ʁed@3䴍@̡| Q|:}\= cbpӜdh |pC+]/+ud3;LLBl)gd+o?èi|!׊AlE`inN> ZbW!^Ų\6ע.f@PU66Pw͔ұ0 (ND"!h4(t2. 41O^vߍ h^QZ6Ч@j-ȼL|$buwzS}?-4@\c{~.X"kL۞>9nj.3yHzp&n@"e"RW#98W& ryJke~vw@kP^OQUӬDtY)<{)W& Xmڳ@D;fߛJv*7r n۵NckSR O.] EpÁkKT[FX{oSW[ЧE܁DRI(O78S gߎSQin[z҃:װc?$yKe.{ZqC ӃY9C{Y"3}d}%;\()^تMf.pcNsįOn;kb~pͳW(ӣ+q׋PLrmV#;ljv e1,ݶu=`m|2hf>ʧ䶭 _o/W92m=ZT}K tO.;ezڴQn1 ?[#Q%qj0VBJ/;ݾCgi@EQ P ̰!TYPѱz@mw'p _ d)o߆޽{[+k5j=}d}P=&T*pwT ;26M qb̂k --,-St)*m9mI~IDATaVzy¯KI/~]sBX*sB>:B!B9ygfu%%ݧJT/|Yȑ?s]*SТteuv]xI%t/ЌbIvPa;!Tzr,XoU-wIIWQ_nxyiʗ;o|1A%t@qxKf7pbTb]*DJuc]׃5mV3{M K?+y,T++U(dI -8*Ie')$Z?o[s%Rf*= J/K=t/z@$;XssK6a<ϧ&;!Tzr >lg;@i[6R^}k گGq]ԃTX UMzxh#7CSx`L=;:~K!I.I7hM<:mQQ-̫jH:SS.Wg [4jߏ NH\7o9 \u+vz`m*|tʃwC>_ݜ<"sǙJƢJ_QՌVμ=,:ǷU3L~xuik;t쨶nb*r*sSz9M&h}VI{yd$r{i`z#l1b7˝y*SAO%3(E\iKאf٤;/iCfq•8&Extb9DF|pusOzxLJL( ߶ObmN۸q*3{W@4sa;fnM.톏Sp{~ZsQnY+|iˮts7Ϛl_FUŚ;} Y2ۉ謉IVN[<`Mcn_W~,n㞚] I :iϊ6Csgm1`jْCBiOWz8:"¡URKU/֩%؂&dDW۵җTNJh9nmyU|%N59f6SYȖKb6d,woܥt'xŻml$SPk8\bie1AH1)mSNktڦ᪮o뚍S@Rn<wAUk 7<1]}ܾy~w{,=syʠC " ll5n~i\@XG]ߥUuL.8F[>I\̥]WRY> Pm <>1uṯ_?W;s>SDo?}ׯ)սƼ9#|s{4[ǜZK=K" >y=gT-}*2գg(׏0ĎٷDLJKI<$=O+vlMf lҿs' /4?J^Կ*-/XM4T X +/o_3sR Ba {n쓷2ՠ T{U[4hz'G?n4N@%l>redZ `dkdʤd RxsQ( ?hT6j͞~ ]~eOeH렫zN͡=)_v&"PeSL pcNsįO_s­S5QzX*eNi7,ؾ/ѠTĝtjy44S"躝;DvsKU% [յ1tc%U_UʿUs͒ [iw!M/NlRI(O71g'̾5q-u-1P͕1Uk,ĐOq@fŘfMTň(v_W%Y}&c˾Iޛ(p{6|B\Mnj~t_.}j`MmkTsSg 8R@@eoMYvN ۾ #'tYwh܃_}!t\<,_OK7_cSJܫ_vwzOE[7ߵnWeV>&m.g&נysLvpÒm?icƘy90Ϝq=8/{ 178ɷ~n`Sk80\y3L;`ٟ3-Reun`Ə?rqA p#e?>@@Կ{qptPIv:֌+sk灵i_?sSמA۷oJIIݵ۟>_5FDZjm@1By9cjC1T];" Q1mp†c}MX9ΉcJ$R(7wOݖ,HLII1EU84Ru+繘HG'BI*>zxN%9.$W8FUE 8bUmH/b ԙ?{'Z!UAQW##etU*Utt'iuqs(\Q)0v.*2L=^Ö?giGO?L2* @Xf`|\LTDxhKi1::XY[;w!TXMF(A!#!!BZ *>@( B@C) UWчw P4!<\&;K%iXlgk>}@@(T~ E%$$~jժ-@(ݵ|-|k!Ņ0 ceiEd9  $A Io޾J tߕ{-ݷ3:I]noHHHz6粥W PNneeh4MBx~cٯ{>]L&*@@(TaB9Ohhy^2Cx+(}^kiZP|c`] !Td,n썠67/wuW=@@.xh2Lo,8U ō(î{>L-M#{N 86-qBkUZ@SbL /B(O tPzHZc̼rb zte^|=zuw7v?,-xX̡anyKS29qWٿy|c6P9+Hp1[mӽ[wI)Ac;7>u:_ x M~{̛&sڇ.(;}9F8o^uom©RTwjYRsG-|X(@J@P"M;F'/%x5G?4Y/}E68 W=y]*/tQr`M-~_MXs///zzxޮ w;}] /kgh,>&EI$ 7pIjҧ/zZ2@ԱsZp6s~6^J|=\X,}lԼuC{ IT3枍z IH7[u nIj_~zZ2 !*3AdqX# Ky;. owoG9z.EDQT{רK5E[4vM1Qرw, ҥ@P쉿~۝yovʛ7o$_-zzcgJj<46|40)3hPm ]vsVC'Θ>=A^\>hFˋ D7R(P3in& 2g!ne|!FUQgMQ{d cfg*! /W2kƘ Q~=O!QrQ9BLuF|n `d ~4yc6P2vGu޺f9 ]MlO&XX4W 0Q S;{{1s¶ڭƋrې@e_:6apVߎa0%t#ݑ- v֝#05 rn4CjRQ\<ȠܑIS~M(b ͅ۷wcڴa$̊w/_Py-y:F>s:cc<<.S{#Lfc3PS| ,G&ށÍbLZ~VxV-}쭄y?,T 9,彁>`aѧu9ξ5y7>1 kE0 ñhv#Od`az @Ӏ(L k 'Сo5 c](/"AT}yM3]$/nr*1au x_&0`BPU)hFYRf= kHZ%geS-=emr3bS5v<ĠJI-?S4b?&L(52Rℨ3 *T8pjF n݁_ռ2ƖV]JgQ΀i[x]{E| x79f<;Ap\NJ:=ؼeKs1 `sV"ÄЄ`Զh H6 !1 <2p to${<zQ3ÄIAf6sbc aԹgso?tp1*cWV" HC;ԏǴG}ʞ R_M2>qam[W+ݼ,%p=>Mֺ@ui,)e]&8Zħ+wЋ^=B~(/"Aڊc>zagxĶ8Oj+ G ^QMs_Т^_7&LVL*^6-pa <Wco&3#< acGSxUBxuA-~iE`7g;7 \PdY|ayo`XXtW?]tBkVlks <@[u%o9ajjrrfeه^][XHsԿ@pQm)ĕ3@ZwuD)QR+d0Z=ƃG #݁ Z sNI&]=G9w;ѣĘ˷ @ƐsllrFvNNn N7p~!#ʇQV}=%! pc'_[֦Xѳgn)0Gcجq .Ɯfw;9Ӥ3G/JZٶ1TThTrT# EM־ $%jujo{ vi|GfN>{ioGd0_ja}@YC`81/7(,boXCv_TjÿC}[~[RaVff6 q >ر1pa t]g5N? ZF|#;Bx:Yqk>@X<[ ,,,,%5tuVz? =1F)ݼ80Mٳa,şh45hyz\/D?OoEg ']}>BH,fX]u"ӭQ, +g 彄 bZEGxyy8"T?뿟F:)..9с +V  { h7oļ$qAvv @X<[ ,% K?FC9:8`j7B4M?g aaaay@~^N }a: ,ofm&k?p]POWc8 czs XoC>Eٹr& q>okc-52q{xxd1 SRRJc; >8#]$) vOG}4QbS*\]]SSS۶1E SNPUUellLQq[z{MxuH$AOhtat Og>ߊc*;ȴK3->fv3yATYƃ'k {֤T1ɹj>$oʬi ]pfSOڮ4HiFJ;0 Cko'fW 2y=6?g5h= ORC9\V׬bݬPY7{GİڲO654}Zr2TڽUֻHwWhY"M#koՖ;\(mөAye[V~=y7d \c+|.?*tWj[;R>1iT)H>X\MaBb u5HExG*{_\l~bcW}r-*עƸ 0 ćX6ܱ&cLY4׸ec~T_"f܍ԲCk7D=*0KCzbݟS-8o6_Kyc%3f츊3Wߦ@xjvlyo\S-VdƎϿ;]Fbg^~{X7KEeCx,u ôcth2001 S8nM!3 iݢ}Fa)tP7?ZSJ*'~mwthYރq>[ix9<צk*H- &~WW8r`kwyF&TU@ޱ|FSL)@E^\aFr}a.ct i\/:e]Z~zoL83Ykj ʻJDvXs<+Q={3NՇ|k2 G7tl_ϧ_ZqH]pPw+X;fWы)K`h;f.K+jRGk{*B8`>Ts_|@U7jܦ0U?_J.Kug4X1֗j'-FgWաK.f|ksm&2EWvDXUxpݚyĊ*Far*  {S'XBv~Ť"Ď@~م%.iB7&xm.U%.UpG+šbΤD u]x@LMTJ{ 4qon8(O_sZA͋;@vj#яiXټ$ E𝇯$0C!}<~Eͷmeq 9O9PqA%ȏlQ'ܴ>Wh/%Ŵzyb]T௿H[`XIJ%J[{P_@Gu;W6mz~<֬öRJnC&vqcT=q?J@J}{Rܼ  Mө^6s=hFK y7h4v 6yL;>#OkLv]U4.| _[(M ~o~e׿jw]֖(ԾUڱ9BiU暂+;{[AHX3PSt33J\~ď4mx);h[dhgFZH=֛&!#?T= ?[٢^Dm\L*/R[~4qQ{".nf I:p0\`!x)<~ ʂ{Q.6X7WW%< f|j6z ECƕ4l'O!gc;iKK+3RA_pw* I0U%.ScmXf/bT ׳՝L@&W#*ت{+>kӒ*~p0ȒY끓[T}l 8Ckr45wNW3pTȕ'|5Fr|miRW)0$説'SC&i>SR %t*UY\5T}W|07v(.gUeG_; JC^8F^Z?}wzNޟtR;<@;.%ڸy̕O ~5jQ^3 # ʊM 4ƙ[>b"/[٬O?amƄ[~w/u6~.f[p3$mǍן-S+ـ=1 $R4ŗ7~%Q@[J‚[It},FZ0ϰf p1Dmj[ `9Ђ.LH"yɅÉ妟<%jP:WUzy粴tԏlq@`f%Je\>@[x /6PrnGͥ_s]7r":'Hݖ@A)_<^ ݼI(!ITOn ^kN!+fYO%q1j%&jjMY=FL ~I8ӱu)|GoF#;--嬝dJ0{UnC%Fut{'ğ\ݹs^6fb<얝ZI]/a4$e.l[ó[7֙W|M6s1G %< 72iK1QLv$01{Wlgsq k2<yGFI: @+ҁmkZunE@ߧtf=鷎02Qs1ۑli_]C;wWK!E yh1wH 1)ZY8e5 bFV*Ԟj <&uۯ#Wc+`9& "vF/HanSjY~|-};1РpƧFYQv3rO HI9HQȢYCg}C}zBs{{{ݽĮmҔm3wȶ~l7Krl_.<K#/p7߷ѕ#CUFR0kRyJByLX\b />T}A0Yf|K,fo#z5K*NZKpJ(_LqLAVD\z? UzrkzKtת&-fZ>o#!;y)hQeGߓ[tomFEW#bP}x8Lʾ՜Q.g<Ic.jz<]w)S#WJi#.|ow𼹓~_SYVZR_ꬨ*^߮'oZ0\vjɼ ײT~-ktcoG) v]ۛsZVτ:|8RwWWϕL_iQU_L=?|R%9 I@S N2) >]I;#僿pBTڐYuE4u-&W* t$F't md<[箼,˺XZD=+6H/\>}K.؄tXkD㹤rO]K՘U8]h5|~6$G"/h]zP"fQmE@Kgag?Em?DN, p1H8%K{g.ګcZ9֤0 ;3 .nYt/Wk^=Do܊}2ٱX qMu )+ej{`=ۏ}&2IcY{ÐQ\M&\ vѨzS(&ݜC3ih'u j 'ύF2yT'SUi4]hV2%AWߏ^>sp/+Ng*ȊyGꮕWi9ôڵ /Ty(]'sM "kY\>ƙf0t5jWT }i N_з[X8Dg[Y3>t&/lѦ'$~p~>2]'nSSJHv4e =oE4H-ъrb!펭IسGw_OC Ue@/ۨ:q9m pfj {]>hyNY?mI. YCQ$)Y6Ncrn/8z,kGsS 8* !*߉sqjڭ͍;mLrTXt $A]5DV>)}-Kzb/e [k/%{MzIwkDd$I`gm@CzZȄ**x&ƥ\p`FhU *h^5zG8(+ y9 %13%ʼ_@5' \:y/~ex҇@iXݥB%6s&/qFb02dp늓W3e`Lc eP]Z zRi+V>1suֱ_;Z5.ڨOZx#Ⓥy`;ܥU I9 d_oYD;xƦȬT1OcBK79w•IEυݿx}҅K$ת=p5%` HQdymtoG 4MV,JɣͳC7D>ECC]ofL'm+ gԪ!0 b}l6HŭݸxkϸlR ХL1`9b.n_>F]ǐpFui8H,Yf'k @QM%nۧu1-^rmˏ'_GGpmWMސJ;~[f"sxd Ҩ)XFY/4d՛`+hR@#S]njƩ5 lW[O`| N7%L\C.F k}hS|!sPL3(t/\yfaw1!H B&=e{iqYC[Xi-˞6k&,#^,Իl`q2r7g-< wmd_iՇsa7 iʻv%Ѻ0J0E>vg^)p۳()5_LxJӰ"ݿXet2zpu8hknҡ1@J:Z\F'>>y*-%8@UzF=+Lס8w %@WdVL < [meݢxNMԐT2 yAoFԹCr~^z8 J,mlZEQJ@H0e^>JxXt}Gb%fD51D#GJu%/c9]8uQh ݣy h!l5:7*a놰k)ryUiØKqE0Myau ԨK NZT,v?n?|*ѹȹʣ6#C!U3˓ % 8)$+jMtT3tpW N >h%_cdGOҔ6: 9M9FYR@b\~iSqǁFRPʔ${Wc(_Z_`8U+eEq)u@^)?*tthA=CtvY[_?v1~q[ 40*E%TRU)p0D>e\I 2'0Re?,2c1 tQ{܍2ǞPM\ss(M+[֩ʤT*{Ҥf ls$iWk b.wu~q~PDଁD[RV˨fP%ADTkwJB-8a4@dN<> J%-(YD!u3ioiNRC?(h*g/ W2h{>(e<^!}:60F@r>-\Nm r֭lÛ'yMb$h UejM~/ob`MPGB,%knKT=gH;ځllBJ ,۶q3b H|xAw['݌V|ۻќu>**ZjAx >;_eѿϋ JKȏyvxBY$%xxz3\ASp2Ozr󒓺㒞6>L,0(G殛& dҴSDilF]AixzoYHήS4~7cm}Wu3n8Fdn;SEA :غ.ڈ i{#WpC&%4w!^8J*$m=qޭv=|ا]jU-'1 ̃F! Lt}\z7x|JٜS3)R?/_I=+NeZ>53~[lԠx9 =9$>XaBm7ycUj MIgl]]k@RB@wSۙ+y|cngU@lACeߔCm+]xitދcݦ`VW '9?'0y`S>_;^\{:HXt};|!,†O/@3Z.ũ|^|yN%izŴP+׋p~3:J$3j=|@k=w%P*YݎP m-{o%¸Se|)u%U84W#̂3>=CM`3rVRY@' "$ϔĿsF\ǦIIUT^Y5Σ1e67oXfKgQ|XjC{7GQ/ٿa wTg;y)<"ߢV"49̶_3~"Ȏj6uU$mjes:EWSJ++!^F * "rPS~/O;`TU* \p#EUn J@de0`fzhW SJ*rd}{|VGczA A[uy{X^ZF<u-9-vHA3$-wm ` ac>Tѝnݶ%g6F'vlvNf%U0 ¼( bk#qka*Ā }aahwŵ)-N=?Y2O0p`/mkVm~n>1v·>U7Zp[qkGs>81ឍWzzj8l76^zÎ3y.SH> }~O>A PU64./٧!TJ {)Uϙ;9 I\9f鷡f| `3[nc./8.h(DJ<(Q5 >>1z[OZ:Q+l>[˾U9iݵ3j{;qe3{g}ݪT?& P4ik͠c2Eqg7tujVUlf;|P̬_oq|Zx$́&V|\5m^~|) չNJ95}˰yKڂOU0CߏcQ,xΣݔRIWdGJb  HΗw$wǮ] P*Zk~cL+nvP@t*a@{ G7foeayP{|}kя=@E}誂RL*$)R-\tl?anlE.+,,m@! 3QLJ >ZX=t+nU%)˯+! )TkE⶝g%x'\ed!G`ȣ@zno=^=j; ˿)!HT\\lbbI@GEgT6 sH_Bʣ3go±Э2TP'`*::ܜ$ Ôܹss`T<=eA]hqyVLL̻M:Ab888Ni"gj~hdstp*&@! K蔁CsZhZCƀ,,,,,,,gL< '8u]'\qf7BC>HkHoi`KJ F!qF 8$*IrR q pp8QS`ЈC[kS(UM9L p h4ׯ]ѳ/ѼT ;c2 o߼a6 EP$I䧥tKG0 O x6ޱ6$~& jR1]' )@h-Ψ;W.I$.ɖqE*d.,yh[' i 0H@дӏx p8dqa>C1ϟ@,EZn7+}j#/%tEXtdate:create2012-10-05T14:34:38-07:00pF%tEXtdate:modify2012-10-05T14:34:38-07:00tEXtSoftwaregnome-screenshot>IENDB`rviz-1.12.4/doc/grouped-displays.png000066400000000000000000000437051300447110700173450ustar00rootroot00000000000000PNG  IHDRؒbKGD oFFsC3 pHYs+ vpAg4FIDATxwxTU;'$J" U*pۺXUWvT֎(H&-!RfR&e2~9?&IHB&p>c2sܓ!s=_8o?tǧ+ mޓ( k#>S ‰,svnbHx1NWmZ@;/N{*6Q~ g=׷> m?1?EB#G֢uO 4V c>zE[MB:A q/:/[ TVVQgZ23===}.|Y9tmm|WC݁}Mm6t`߮fwp¡nu%VPWN nYw(;f@Q5lЊIQ)Z1)ݻ?/]no޼yΜ9iiiʺu^xᅴ6Jq=$K(ͬz#S>|wlS_ߌR!lk832:o-}.8cv84wx( v _ Fɝ}ϧSW c&&&5k$''ZfmٲE ̘1㭷`޼y?8L4o{|{x0%,>(_p@"Dvdtz/ z`Xa:&Ees2FA`XHq˶BZ}+~.&G0hZLsw[tңG.\gٸqcqq߮T*׮]uAAA=X;:j$D:/|eȃ:P+,bNO3, 6ٛ;[ tOp4_y3~w)/C0sOWV吝˯ Eb֥K5vǤQ4WiӦo3f 7{w~ŋqο]w?+>O:kKe{w5b97B1"zMu :a:}EUW?mHEwKVE:υ+fnnx.8| >sO=ҥK׮]]VH%0rCK墧RT.c_}WWTU7{ftڕH\:zb`֬Y7n\)w}w͚5}ڵkWZG].. Kkٖf<.xL G-fR=ØpZweKCO%M<`˜"Q@sÆ p=[ZZ !!v`7,˗_|E?+$):p21XB8ĺx!L˗Γ{D\8&u 1/\v\Hg4ъ  "gk/<*) QDI@AhDE!QG%61NK ӴBaI&SB@˻R+(jZaZ ^}B IH^.:V"^(KS+(jPId#/޶A BƗK|bRWL&ɆpEZ(EQgՅVP1noݺ}zFO>bƵgN4}᳒zc׀n6 w0UtTa-rotQWc9j|ip;^sZ1MiS+^\ڌ+g=Ol(gBaTfл9O=V#iW9ϺRQG]7]] ̬&Kk0FS+~ ӻJwX`tJEcM k,` >MZW 9t0FS+~ԊJDohJ%%%m{`}oWIa,V~,\!`"u^*3A{F ݥRV$ |xQ<-յhzQDά r| %brym.Yǡ"V+_d7c͏NVc?oib˩47HraH!MCx:n͚5<`m3ñe˖/B",Y$!!W^yW/e8H`Wr\Ҭo~?'_.RcɊ̍-~Vh/V \yq?(ޭ{)Db9R`jԅ;/IL&e{cA͹a?) H\sY>4o'̍X'&:㛟o]VVlش M"1H”l+(pV:4:GZ6))ɝZ[t86mk׆d'曋jS޼e󱧊x4fZ?k`Or,FCW ڵfnUϏZSs/Sx N^2]s59@zk>:#]|[ӛvr^yRPz4m|^zұ5i%A@[Bځ&(]1$[w oULјG϶mrss7l+'''***::Gӏ-[pr];]*\]nq@XВ@Y4Rod!FX8Rw`1`媛Gb۝UuomYBV b$"D  %ן0]̘)8%>oǎ0LuuG}/655=]qĈ9c=9.n0Ο`^'rAbTrr6 _9pY휍i%޽L<=k:w 5j Z^N{EaZAgR+ju@@BHP>|s;v̽AMM͌3|1$U xLx\5M m6PG=hnvGFJYQjJOځHa}jtbVPXJH@BVN4@3m_۝Wr ",T뿩ϮLh'1O-qdݝc$"@`jv T? XjqfDd2aۭVE-re˖{&Ep667`pD\ʀͯ3 \m0=jXaw`kRr*O4֮x"G& 'Z[ɹ,s!`>L?V!+p:9V uwg9w{|wSæ@/o}2%fyǙr|h8k-˰x(fP7G%^iqkR~ pȄ=>an,<|+5IG_~5<K=Łet~eqɥLCY1QƼO yx?>eSňQî?yמ?qnt`viɏ6'YSO68{4;_婃yfNNNN o_=~V WZ1~9oӡC,Xz뮻СCd`KǷ ~gKq;O!Ĵzިkhzϝ0d7h',{kBHXHx%w@o]Uk'1^M3L kAYK) Z:q/:S# Lk?WQ*m5겨<s7_d_7j7.<3y丸 +/Hxϗm޿'s¸mN}v{2VB X#M-Ԅ bWsC/<1#g6u$Ov hh(]92n+2@qVs7| ~ Ng]m/Nzcrؼw.1~ !@zZۼwDzggm}cW*?Y/ѫx _wTxT1>SO&|B/>_H9j0ͮ#HGpBi Q~_G|ӟ>?RÍ̮LLQۏts3ץfTz8~[wq2%s&;a|sJfK,b_w_~JJrꤱVL?A6!κ5zr |wJ pGOBcKZ1]pr۲>o(]g̍2bwBq5~Ab;!g7 S߰qZ$tݟv`B~{cyy?~U9?!?:;F24yVB״%oIq|@Idv`kѺvο4Vjq̏ґyhyI1|iqC|ʋt XjEyS+8Y-Fco{1 hShReS+( J=65/E]r(F+&EQhŤ(WcWTTxqTTTbRP7hj^;QQQp7޲Z1KqR0 BH.WG02ҡPՔϛ ..~놺0r: X @tA!D07kbINIVS^ċ*fEeETT  E6c1q@ahŤcln7&Em6  @  (*cɔwĊi0.J1RLTƎd%%%uuzLb>XJ~`ƭ "eT0*Rx^8}jbhpQj_[ \n65BFa]p(!4tϕƊիW8a?=㢢bu)GBLmV)H"@Gj;D 8 =&NS,yPbv`z0CTl6bmN(Rhp+fnnx<t8:_J QCSzİ b޿=!0ePY3B0axB@2oFuXEWgQq.lδ'_?L^oVLGfͺ{.bV`'s?%/uIR".v`Z74Xꬾ#k2(iII= ޠR N\_wm +T*ƄAcǤz6sÆ uc2z{fȴj62 ()H![mQ+$ O}tw;.JkJ:s&Xřw#&v&$!BIɇ0+DtvTjw$0Tb^l{kH1=ێ#DX$ Kn0#خSAg$0 GrO-r]6VaRllj;^5j@;<^;ԍWVl pw--,Z4o=EK' ZVZ^ èԚcijŻR+BBBlÍT^h@*\8Zrrx VP+jAʸq) u+8*s+Z,. H>=5@8ԭ(;xE"H6eqؔnEQ^N\PEy1 MK'>x𡇆!86 (UظDUPҊ9L'e㦧bk-=YEKk Q]Y0LTLloBZJ:u>/w-;7eqK~!:5\>:CXt@8V16GD BH>U9ԍVt? ?ܣ3tbþY& |b%*}'Uvf)zNVCavNQU}#F$OA+ %Id++V\|rH4 /g.4cfNad(Q:w顒>H6ya%4o/޽P-N8Gfc}: ˋڌxKjEOyD @pXbbo̫j28.urjg i.jR'tF;|7MXK鿛%xFG^[ZJg7ZxV3v҄X_!8~O[0Zw?W,!՗b7=*@i ?ՉVL?+o5"0vl=f M/h:~d{je2;bݺu}5yW<;/r5m/>&PE>Q968AymHh`XƜ@"$Q (|ӊڿ۝]95q|0rά !"+K5]nF]m(bld!ɳ`4:Y0΂tJ5W.W @4)5oso/Eh3ZA;0Th/Jp몛]"jO)bV()R!+}A/k22?47q!cp֧%p@ApԞ~>r O7״tak}A*ϮqDt):2F '^ &PmMFT@!#VbVޥNkDbR]Sg€1*'MK+g6cfGz?D"9)9^"::&)}̩_rvnHH Rgkkl#R|2+*c|ܿX67Bװ.)->NЈb$ؿuL\sytI&ENjR+@_@7=b[䉼GD0v\x,1. YهwbV=uAZDH6{"(;so)e@0333P(3aReZd2yo5bZhj#H8]S+v^!B+;/+wVP! ȸġn5\yiŤK$(EQҳr$4;A]E8tX5޶AF&Z:J]A8Bj%8vaQÕ0k$bIDt,!gnH%"5Uj$u)/-l6Ʀ>Θ]z?ui0vShRf!rzч (*cɔwԊS6M 8q9s9RM`xqq:EckqO_[M)ˇwĂbŊ; ni:[0qQs G7S+/n1|eG]R !  c9Ldj#uc).י.11ee s;Zp-"DenGI1% 5h(' {2+6BSB; ;Neg/is0_iST 22Z R%N:&=B0 FOKm~\3:24884kV͸k'<1Jr Xb-at`;ue ]PPcc9jKJJeYzt^*b)2W8]`rHpZbE@|^[\`:gTu8HATl6bmN(B+z,˪՚֖&ƘeBnnYλ&Djuؠ/F|kί{PS`*ڳ}uf\L1=I g.Uq=tzn;'}e2)ؽPFޒZ>bYbDBQrhF!EJ_??. }m<goq!~Z9\ɷWtM=SCTBjH#Bdf'a#Wt&P*I`Z1yQjE0s]w_ycd=+V};2k:)5*toDG)D!{0Rj66jwB Pk$ƍM4ץVm61b n!~KcҍKմ/9ZaZJZ[{ۋaZ8zX,ꟀޛZ!Jc NcIiP Xv~  jljP7bzl5nq7l̜4śSuE|b%#EyzIQ)Ǥ.4;A]EhjObRWZAUVPXJ~`ƭ "c|*;Dq])LI{ZA ~WXr˗D\g~z5Olߓ%MY,K !  +hך4WV=U(ph6'$>%O@솓UBuׄKP/Ά-NEӄufNfB:o:q<8e0۶3ɎD갤ctg`5hj{.׬Yjժ>Nһ@K"SE$ȡ=J |p=uiżPg"I7iT ߐ0k>ōF\ +K˛F辢eOx|.S)c"l T۫je2;bݺulv2P&T.}3ŇqX ֆhX@W"McU jb7{K1QeHxHP2ªI3moP/eYev_Io(`:@g`F U +&G/p~j6@hj H:<ܬ;h,8UTa'!aIQۏm.6>11.GzOH2nĖsENv},j)9v$dY!p !AGS+ Ot?mh{Y )SjκY<_,8? hN|_'M OHÇG^+8곶,W21o<_+0t4AԊ{[zػhIR".1bi#bG~w~i[\GH M.YY}n.\6;TBmMmۛlAB "zR+hjoIM w--:>"j62 ()H![mCS|[YQGrvDR{N8S+0,˲4@:Uch?|V6H"G/P^<"iP"åbb}q{|o.lY)nXSט >MXUĺCjʋ Ie9wԥ9W[njcԹ: D@P^ZgP7.T1yۺOO*[Batf԰ P72B\<jى+\z;`C"/I"oʿ H?= %{_;Rj ?\NO2c 1i;u<fLM/yaaaξөn˗/w\zts|2R8Y `6B1@ |]UssUO#eޱ炗8`*.hgK>01o m`B\Xv<7/3+kæm8nHFe[^AZ3Q@D?xUUj-++{ꩧ.9bqs}G ߹AvMs:`(0w~ o?K nq h6ߏxnґ|BW1Gp{?m%I$)}b֥K5vǤwᙟɓ'egg''')uOT;v#XKmgf=V!:Ĺ RcM/?# Eq~ʻ`] &+iD".(*[ϵue.0y<:5}'E"ի/gDRqbvʹ`U!Zo{9; 55;Dh@`A.Ӿ;N'~~?*-4t1"nDg1Ǥ=?~Bx _')T`kWNc/P /aWp" S?W!B8ĺx!L˗Γ{DIʩ p8'o/IK*d:*rm:NlBad:VTh9LS&ܹ<6?:sA,J(ml# bH[#ܗi’Ld11 շ%  u~jj/+{{ 16&!yӺXT:?hju5d1 G^v9{A BƗK|bRWL&ɆpEg?(Spx+Ꭶ;^)=G`qh8T? \+֯_t^W[^u=otv/>~0ҖZ ݨ=I]0aED2;6d Gt\۷oߴiի/jafyugB,-yǧIA!"5T_3ZMsKONxwGhgۿ$X|ތLUzJ{{HPw6Pn"AtlËis\v7 LΆTNI@ Ң9xTn(4r<,0# x+%q1AknE xoj.D\tmSir%W5fX\hڒQL aKES+~1u:ݚ5kypmDaao}Z*oCe=K=;IYWU˅Jƶ c%UԒa! ˖¿p=EErQJ \F}QnʋA#pİYD$YCmkfkn+#a/n_K+b75ܜ{VvVg;y ͕M?WX\ .@S+~ψVd999wyusjd2y\UR}`=BpZmvWٲ?mgnt'C_+܁[$5Ssc- 칲țo`&.f̊s"b؟fJJwdߴ^\y"Ai|ۛ*d:NF+N7#,k @7eOTlU錏p}4 T7Go ct @?vS+_?ǭ; hjշAF"11q}K xIݒr9N2n|c)WOTmv"V4vjvQyFN#T7}{YSn1YתrƖ" g\dQr0a9ۭ'L 7ND}uy[Sk w3zl5* #+Mip+fnnx.8N;歀VBp"8&!A[35:5 8kmsZ`K-[sPgG#<їC,#BtsYҹT??JHoMu@ZyP)~aF02%9Vr?Npemg%ZAh+@ 5k=s-[/~Ac>]AO[*W -GTLp-:'%.7bFѷG15]0!1j]^41)$O^Q6;?}5A8J6,%Dck)yd/$ܾOld#OaP@BӔbn*u3UcoÏvf]ޏG-{@S+ď痯hş$@\kS5 TOclĈH8Š|8ޣ#ݲGV;Vȑ P7G%u˒ߙ+G1H ~HEsooH UM)`09KKR1IO1JO8ijO^Z.ÞӲg<[8D9;rC`Gï.ij5P+BtiP7d )]Lr bRXkPKX=^L hjb^f u+(JwUNRE]Ǥ.4aS1ij4aS1ԊK[-Nl,9lMix|ԮԊK2ֿII+hjO4V\EhjO4ԊaVPDS+.ojط̖|3JǦFqB [s=}W̋;V$p5EF@ M4⅙>KBS+~pS+\{~8yf|ssǮ:>8czf}9r)!jhT+bݵ'ԥT?Ԋ˗Z57s {Il7<^KQg ~ސt{u!Wkygd͞" ^ZAM V؛M R#dW[$E5I#-hշUt&:Ln1x٦FS+~3@yqU|B-n/~dR qӝZq S+.\FI9ڔR_uH-qS5g6Y[u!.> o1 vVf5o-B/rm7u ưޱ;Yd!̏-B +ZAޱlihpԊMzGS+.cj6]ߝY/2FxgGm,0DD ՊpM'o;MV\Ԋŷ%spyR@wH轣вԁߑba%o#Z"Evȯ XuT -T?Ԋˉ[ZqY}z NM޶H!]hj5PhjP-_Q2[9|- M+*Ղ&@b1X9Vb^]ˊVPA+eJnY|PKF;8EQ(SbREyVL(OъIQC%[%tEXtdate:create2012-10-05T11:43:17-07:00e%tEXtdate:modify2012-10-05T11:43:17-07:00ceIENDB`rviz-1.12.4/doc/index.rst000066400000000000000000000305311300447110700151760ustar00rootroot00000000000000RViz User's Guide ================= Troubleshooting --------------- If you're running into problems and have not seen the answer below, try the `Troubleshooting Page `_. Build/Startup --------------- First satisfy any system dependencies.:: rosdep install rviz Now build the visualizer:: rosmake rviz Then start the visualizer:: rosrun rviz rviz When rviz starts for the first time, you will see an empty view: .. image:: empty-rviz.png The central area with the grid is the 3D view. On the left is the Displays list, which will show any displays you have loaded. Right now it just contains the global options and the time view, which I'll get to later. On the right are some of the other panels, described below. Displays -------- A display is something that draws something in the 3D world, and likely has some options available in the displays list. An example is a point cloud, the robot state, etc. For the current list of RViz display types, see `RViz Display Types `_. Adding a new display .................... To add a display, type "control-N" (for "new") or click the Add button at the bottom: .. image:: add-button.png This will pop up the new display dialog: .. image:: add-display-dialog.png The list at the top shows the available display types, grouped by the plugin that provides them. The text box in the middle gives a description of the selected display type. At the bottom you can give a name to the new instance of the display, which defaults to the name of the type name. Display Properties .................. Each display gets its own list of properties. For example: .. image:: display-properties.png Display Status .............. Each display gets its own status to help let you know if everything is OK or not. The status can be one of 4: OK, Warning, Error and Disabled. The status is indicated in the display's title by the text color and icon, as well as in the Status category that you can see if the display is expanded: .. image:: display-statuses.png The Status category also expands to show specific status information. This information is different for different displays, and the messages should be self explanitory. The top-level status level for the display is set based on the worst of the sub-statuses. Organizing Displays ................... You can move displays up or down in the list by dragging them with the left mouse button. You can select multiple displays and drag them together. You can also create a "Group" display, which serves as a container for other displays. Displays in a group can be enabled and disabled together with the group's checkbox. In this example, the "Sensor data" group has been disabled and the "Plans" group is enabled: .. image:: grouped-displays.png Naming Displays ............... In the above example, the "Group" and "Path" displays have been given meaningful names. You can do this either at creation time in the new display dialog (described above) or any time later by selecting one display and typing "control-R" (for "rename") or by clicking the "Rename" button. Configurations -------------- Different configurations of displays are often useful for different uses of the visualizer. A configuration useful for a full PR2 is not necessarily useful for a test cart, for example. To this end, the visualizer lets you load and save different configurations. A configuration contains: * Displays and their properties * Tools and their properties * View controller type and settings for the initial viewpoint, plus saved views * Window layout and the list of panels RViz treats configurations similarly to files in an editor. When a configuration file is opened, changes are made, and the "save" menu (or control-"s") is triggered, the original config file is overwritten. When no config file is specified, rviz loads the file ``~/.rviz/default.rviz``, creating it if it does not exist. When a config file other than the default is in use, RViz includes the file name in the window title bar. An asterisk ("*") next to the file name indicates changes have been made since the last time the configuration was loaded or saved. The config file format is YAML. This has changed since the Fuerte version of RViz, so config files saved with Fuerte RViz will not load in Groovy RViz. Views Panel ----------- The "Views" panel shows properties of the current view controller in use, and optionally a list of saved views: .. image:: views-panel.png Clicking on a saved view ("Top view" and "Side view" above) copies it to the "Current View" entry and activates it. The properties of the current view change as you move the viewpoint with the mouse in the 3D display, but they can also be edited directly via the keyboard for precise control. There is a combobox control labelled "Type" at the top of the Views panel. This lets you change the type of the current view controller. To the right of it is the "Zero" button. This resets the current view controller to look at the point "0, 0, 0" from a short distance away. This is useful to get back to a known location if the viewpoint gets "lost". The keyboard shortcut for "Zero" is "z". Built-in view types ................... "Views" in RViz are view controllers. They control both the viewpoint and the camera projection. There are 4 built-in types, but more can be added via plugins. Orbit (default) ,,,,,,,,,,,,,,, The orbital camera simply rotates around a focal point, while always looking at that point. The focal point is visualized as a small disc while you're moving the camera: .. image:: focal-point.png Controls: * Left mouse button: Click and drag to rotate around the focal point. * Middle mouse button: Click and drag to move the focal point in the plane formed by the camera's up and right vectors. The distance moved depends on the focal point -- if there is an object on the focal point, and you click on top of it, it will stay under your mouse. * Right mouse button: Click and drag to zoom in/out of the focal point. Dragging up zooms in, down zooms out. * Scrollwheel: Zoom in/out of the focal point * 'f' key: move the focal point to whatever 3D object is currently under the mouse. XYOrbit ,,,,,,, The "XYOrbit" view controller is similar to Orbit, but the focal point is constrained to move only in the XY plane. Also, the focal point is kept lower in the window and is cyan colored. Controls: * Left mouse button: Click and drag to rotate around the focal point. * Middle mouse button: Click and drag to move the focal point in the XY plane. The distance moved depends on the focal point -- if there is an object on the focal point, and you click on top of it, it will stay under your mouse. * Right mouse button: Click and drag to zoom in/out of the focal point. Dragging up zooms in, down zooms out. * Scrollwheel: Zoom in/out of the focal point * 'f' key: move the focal point to whatever 3D object is currently under the mouse. FPS (first-person shooter) ,,,,,,,,,,,,,,,,,,,,,,,,,, The FPS camera is a first-person camera, so it rotates as if you're looking with your head. Controls: * Left mouse button: Click and drag to rotate. Control-click to pick the object under the mouse and look directly at it. * Middle mouse button: Click and drag to move along the plane formed by the camera's up and right vectors * Right mouse button: Click and drag to move along the camera's forward vector. Dragging up moves forward, down moves backward. * Scrollwheel: Move forward/backward Top-down Orthographic ,,,,,,,,,,,,,,,,,,,,, The top-down orthographic camera always looks down along the Z axis (in the robot frame), and is an orthographic view which means things do not get smaller as they get farther away. Controls: * Left mouse button: Click and drag to rotate around the Z axis * Middle mouse button: Click and drag to move the camera along the XY plane * Right mouse button: Click and drag to zoom the image * Scrollwheel: Zoom the image Coordinate Frames ----------------- RViz uses the tf transform system for transforming data from the coordinate frame it arrives in into a global reference frame. There are two coordinate frames that are important to know about in the visualizer. Here is a `video that explains them both `_. .. Should really implement a youtube directive for embedding videos. The Fixed Frame ............... The more-important of the two frames is the fixed frame. The fixed frame is the reference frame used to denote the "world" frame. This is usually the "map", or "world", or something similar, but can also be, for example, your odometry frame. If the fixed frame is erroneously set to, say, the base of the robot, then all the objects the robot has ever seen will appear in front of the robot, at the position relative to the robot at which they were detected. For correct results, the fixed frame should not be moving relative to the world. If you change the fixed frame, all data currently being shown is cleared rather than re-transformed. The Target Frame ................ Most view controllers provide a "target frame" which provides a reference frame for the camera view. For example, if your target frame is the map, you'll see the robot driving around the map. If your target frame is the base of the robot, the robot will stay in the same place while everything else moves relative to it. The built-in view controllers use the target frame only for position, and ignore its orientation, so when the robot rotates, you will see it spin, but when in drives it will stay in the same place in the view. Tools ----- The visualizer has a number of tools you can use on the toolbar: Move Camera ........... * Keyboard shortcut: m The Move Camera tool is the default tool. When this is selected, the current View gets to do its thing when you click inside the 3d view. Interact ........ * Keyboard shortcut: i The Interact tool allows the use of Interactive Marker displays. When the mouse is not over an interactive element, it behaves like the Move Camera tool. Select ...... * Keyboard shortcut: s The Select tool allows you to select items being displayed in the 3D view. It supports single-point selection as well as click/drag box selection. .. image:: selection-box.png Once objects are selected, they are surrounded by cyan-colored bounding boxes, and information about the selected objects can be viewed in the "Selection" panel. Here you can see the position of the robot link "head_tilt_link" has been expanded to show the XYZ coordinates: .. image:: selection-properties.png You can add to a selection with the Shift key, and remove from the selection with the Ctrl key. If you want to move the camera around while selecting without switching back to the Move Camera tool you can hold down the Alt key. The f key will focus the camera on the current selection. 2D Nav Goal ........... * Keyboard shortcut: g This tool lets you set a goal sent on the "/move_base_simple/goal" ROS topic. Click on a location on the ground plane and drag to select the orientation. The output topic can be changed in the "Tool Properties" panel. This tool works with the navigation stack. 2D Pose Estimate ................ * Keyboard shortcut: p This tool lets you set an initial pose to seed the localization system (sent on the "/initialpose" ROS topic). Click on a location on the ground plane and drag to select the orientation. The output topic can be changed in the "Tool Properties" panel. This tool works with the navigation stack. Time ---- The Time panel is mostly useful when running in a simulator: it allows you to see how much ROS Time time has passed, vs. how much "Wall Clock" (aka real) time has passed. The time panel also lets you reset the visualizer's internal time state -- this causes a reset of all the displays, as well as a reset of tf's internal cache of data. .. image:: time-panel.png If you are not running in simulation, the time panel is mostly useless. In most cases it can be closed and you will probably not even notice (other than having a bit more screen real estate for the rest of rviz). Plugins ------- RViz is setup so that new displays, tools, view controllers, and panels can be added through plugins. Installed plugins are indexed and made available within RViz automatically. For information on writing your own RViz plugin, see the plugin tutorials within `the RViz tutorials wiki page `_. rviz-1.12.4/doc/selection-box.png000066400000000000000000003211131300447110700166150ustar00rootroot00000000000000PNG  IHDRbKGD oFFsdG pHYsde vpAg @EVIDATxu\XdSԩ>]w}kTwg4+zg$77 affƲ,,|!B fppKY$;p  cBajj C{B!PElKSSSe"wuq sO_?_D\(P yGrBPg p=-Iiң"Q"Dd_?YȥE<*=(F " p ˲@k⹢.; ⿮Jl(-T7$9ʊK}{V v>~Bh(>CcB~󢜚_' nklkq[ȶ[ ?sD tB!BŖP(Tr==]uw !B?@ 011$ŝ!B% \tuuB!8[XG3B!P28C3, ufAlAD2_l+  u|pL"g2SS B?<2L&340 ò$A$IRKȭ ,,22Vl.QeerieY "8r $ %P/g%))!Sd1?J -= Ըg2R|! !B菧4@fH__/))9!!>""244q8oBY#rDjaa䨧m+Ni\,tt46҈I&x&(Rs,P4|JN4E5$Tk ^&l9##LSdLa!BOZ*@V hi&==[[[ٺݹ{W*q\P.8٤ISSahE<">>ʭ;derU-< H~QB怼mk`$")Ia ȃ.=HB4r$&hVM-R^!? O !c+#\"Bzoߦ$1t/mX?-#Bf@N---H$beQ\J@bL&ZXZF(J.g̴4533Ep]\f͚dbbIG&24a3e) 5JRZ|Zf\z$yb{ /O(vnT`аA_#ػ7CX.G=d<^;. l;Ϛ9ZAMX05ٽ\CFW=N (B! M3"hfYF9= (/$ a (Śfbiź͚5V{2 e+K( 4XCe#WT@)YUj6f3R5.Ljxˋy"TZ~oe@rC:ڵ&mQK (c?Gr AIz:q8h(BO0m^yªNr#B ԔJ%d)ߗAд\S(dX`ZSSS**7Q${VeJDM¬2 xMip;]Nk]ߋHeҒah+M { Y }z:QBdMz|FQm֒$_fkg뎙1Гwm#_Xm @AO,!ʣ^L!B(VqW Pxiԩ(b}Ed@%+(f&>_˲)-:L<51k!`d,2osP˳o̦=RŭMU'$W9?H_^zʣoJECf |ҝ@BɥC%x\;"B eY (+VP iD L1A@A`NaaXV"YH§U\S Eһv.nY LU ydB_an62pjPV!yҏ6>%wb>c&0N]&@}g{)|. )B!T!$ dffd֠rE ȴ4%ILIIdY$Ia̚;EQiaHOO% $ibahWJǓ/uiY{G*ip$~ZK|K.?ٱ[vN}7áxtMژ@½7GUe .{ṱx!e)!B,'>>NSS!IH\NYr)Iʭh&Ieɓge *p<.~B1r95cIceq z[cLw;^  w7g +eh aiizQ|`iYzLQ'y-=ct Z\B&N1wBr8 B!ʆe JPIP$EA˂n,Ò$KPER$M3"Qs%g>˰@H)0,0"I2ӇOB!EqXLK[a%"$\Jjh|SNj-c2I.4VCK[K.yTӬ\r}2B!*:hfUo VA$lppp|$I,:8$ aY HX"$$*FȤ2}Yߦ:L1[bpwZI@L^=djZSƆB!Be.f r8\a,zƌo߾QHX$iZ8؎aX_~cF$A@@qtBQ2 .,ò, I=&yEW*a˕cB!*XxOH@$E Cgff&$$&$$|O$A$@Iq$\$0X"NNJ8#H @1ʅPAKIO'!!ei'2u)dǖ3 -,By_!!Bo,J$jIؘxZHp8B -BQ'g eY.D aX!$IC B Tp82%I ).4zǢq B!Berq\JQCfM2B(Uhmr$)>ъS\9FE9T*)T!Beow\B!!BB!R?#B!~B!R?Y@!BU!B]'1#B!fRs9B!BjƔu֣pPǢɀ 뗍o+{Q;rB!Tl[5.˷vȵE8}՜;кzMKay=!B(N!V']OBvNY>9:":)MV%t|/UYIӷǪ?K]:~k8kedik-y%RwB! W.O}GPufB{29z~Mbݯf!BۼjWsyz䧏U0inq+& *!thԯ_4!ֱ'^t ͫPt yӻz 7l=HϮu ,ۏ>U95:L}{qn?{Rۭ-k+zkvR[=ZְQ/Ma~:Zn=Gh/ NKeo!B@ "IJei&ϬJ7?ዣk~߈s^*,IK2e@r$t[_J$ <[i_V>O;{YvD:5q儆kƟDgR)3TZ8ñ;?qMya rå~qg~̽+EpZ6qxUzxX^ܹCav-? VB!T>;ٰsH㤛sz\fmo}3D ǥ:U/GEWN$9B}+=_dfy_ӭoa}ɟ߾Mc! bD-~w.>$ݭWcEg?[Kih@Zh@@P B&"64۴:>ȝˮC^w~${bwD,ܭw!B]lQryYiJD^W{BKG}0hf?kQNmxHǿ;zXkZC\,HgN86*<$;YP LOϙ\ e_yUDf1էCY?z5j}+ 0lKkǚhR(yܻWq]$!B{1_B4< 8mhk=22a/m{u4k`yҘ R)&*9 o|)<9i 1׋5!B%YYz\krx'8OzOo餎 q%?$6$P?TWweS^<ر̙[dCKwB2XZ(*U}]_^i$X 3YTZ3?^Y'np S_z̈YoUoOvl>ZnX}w'g B!ʎ?;Һ{.ϗߏr!ݫW.# /\.vqܘizL&ޜ63`)=67 tz#dвoO=pձw9S%ݵv\e`KWzwikD XӁ&io0mNFy51)!Ov/>4D! w7guw$x'B!PES B! s9B!BWq,lϹ߀!ܼr@!BrB! Ǘ#B!T&`.G!BH8]z\tU=A!BOԺu TPwOB!q$B%I.Ѵa*PI$I㩻#!*1i$bQȗo$&&/(==]//OWB - LSwwc `YV*" @ái:11K][SB- ynbbpHTD[n1=g-#T;Ir+++.c{;{!PJDB%a$ooorI,*alRteY$s~gP= ^xehB!T8Z.\* a(R`p8?eqe-krȑ{v'$Ɋ}m+B!uc"Q djt+zsIQ7C`!B!H'8eYe9Y@qi9h,PVp#BQš:FEZlV}D9\ENTGc.G!*h*e9YYfVD؜>Z(/KUvO9D^0KZeBE&(JDZ GGGuڟKGWRSQje<*;.A!P)r9Ylٺmm!!!>?T:u?z/j 4M+.U.QD2Nq8n+A9Eq9Wȯǩ~P _VYm+w!ʡz6ع<$$d7nQF>Ax&&&%0dR˄[|Tu/QOe;t`kk;cƌKz0qıcǞ_?QE(.Wr+w_K}["gtRQ6Jg5?@%+-`B"s䴼򐐐MlڴIƍG9r|yeV~ȪZ*BĬ>)o0AwO]xMJuMBLKj$xk13,]-ӄ[&'ۖ1ry1xT#-ȼ0+0wM}  XYJXp$ab%馞QU&]ż{34Oe-+yq[a4Gާ-5 :ʢ?IٺT׼MS/o 6ʩ_e(~XTkߵ>86w [Nk;^Et,-ezbK}[L*>(dm9W$^qq?>{7_\]+M{ijQFi} OY01|K}AU@Yr`Wf@,/uXATwo^V7.شdY|9ȻEa⤘BH`lONro޼y4Mp~ρKмj ୧w6Ş/"۠5HC-\q)(U ݵIpטT)ҨݝoR|*m(9(${4={Mc.Oo=p'04>Ct0w3 m};ؼBE깺I:uymŦ=vd1 0CTQ?ow3hԞq@DImZIy}Ͽ"|gUI=ѣ8ޡ=}ԧu/ `f^v:C%?gMweҥ;cZyᳮwN-M5،VȅA&5t*KPEρqr/\=;W7wTYigݰߑUrEER^6aKVtM- XY^v8 Zv&"=_cE_~Qh lbY;7eT`wm],ٱ'v];Ud|{9ٺNOWvɢA~lI/)qot޻mY7bڮ]n@@@ժY/\5lpNo>P<`YVGW/ZXIL``nCݵ.8j 'кULl W7n?hV ô'X|ZtRT bA7&w8$<\7{}'T3'Hmt)H* &mӧ|fHT}JLXC<Wj`C_(0F#ڭ;4t"*siA/\}!FRV{heҞn)i #P9㊀^XF^z0"t&9,-Y3OV^~4E)rn/mޫ/\K'|!haY _:owZHގ;7\3xzc;(.2!ίܨyU 4~w~l"0%̮{;6=`-~Uv8.S==8j%KR>C:喪Y\0N_*9)ǔgxŃ0<>(xw*dq%X;U222  ll~.ҴT)eپgZ~Nj?9 4?;t.p%}qg&޵-~Y&(QD^ 農_#3 Ѭ S/Ke)ܮtkT'knݿ?}LZʳ*<[E\ SW*11G|FX]ϟ4cPhaa|>_q%˲zzz65qVKa-z3ȣ/ 0QfS>uI&"M8Vi=%ZVۃJ}4'cl @ MlllPdjK.=sP:ɤմiTs9m o^~L4Wo+w=FMo^=t\wlZY۲,济.! kCڽIfVtZ@b@ósA򴵳O옭 xe4[= 4#avɷ2;_tE"V.I%İ.5!ىk] kcv5|q䛶SdΊ1l;8?67#!4xzVr 1w,[Cޕ=(p ?Sym#FVϴ)8'?|?R̘e:ɧԑ {6N%{9^V u ~-[<4i~NgJoQR0ɵͦCAZ>;a /q, , ܭ><>B7^/XΟ?)]]ݥKyzy >P񔯯oBBɓ']<>!S3gL1#N߄5ĊcHԻD)"A_2տ\hYs y,% EȣBDyhؓY\ z*u! (Ê=tdWD=qtLA&eA@GD >JV c]4LsIti _VJ311!B(˵rL&+p1NN39iܧHN< Ib9ڑ<=̣IbJȓoSj`—-۵h"Rߧk# \ON|@&cZT3,ڶ/=r6uO$5ٹ})Oc8BCcA%M$ZĈ 3}*XIu ;M~a2ϳiYoػ!MM)iЇpZqVzwyՎSkҢeK?/S>{,{3n9aLTHئۋL ۬e˦:Zm  7Ԁi^n@X|&2{йih [>ɏeTlZ ^󡶗Sqgp$NegX$UDz-~9uAo<02-i"]BdY`a!S4+gX3_^*m*}~'LMM`yo߳g ,9sԬ׭k8}O3T15!totڙ9jPDJKlh{iw>s'j@, =~|LquUǝrm 'b$Ɏ&mOe% >r\vL(tV(,YXv5֏rsQM}uف.]ZBv߲Cy- CC~@хhH`s!X#fvWv':d$vnKdc9A*(淑(*Q^:9}t TUYDV4ҳѷ@U^YgDH ~i!g)ͺS:RZ^Tx1?Qs|$I* d*M+=MlkQg_[=lqwI(llsjŪAZ\@Ky zs_=[kԂ5|e'0y|9Ϧݬ 5^߾x9g/u;]BKK3lO< eVLwX7#nӍ+uY&10*~ΗUkjd_7^;;w+דg1B>DKV.JKK5>Hsd;m叝[ןPJΫG*P?vBE#s ?\dJ߆Zyǯ]m|4."(OY&p8BEBp\HH0Y͉q=˟n٣$}8 ڨ3wUBr\euqVg7JO5^&M%Wk/Z{ Um~ 4&Eeak(~%QaYRsՑ*֒O|yr*a]4ai9lCWr^V̳i!<+F8%doߧr\`9zNwk]U+X*WnXo] i7Ң.Ẏ0Ƽ]f,8:Ysoy&&*8^`Vħ{UehSwrrVy4VztVsya|L VUm7|/ip߶%BPZn}5GX y濭<Ǣɓ'2훷o}F.Rfdjl(&#]ʂ^]QoJ'iכZLjRZ+k[ά]ٽees<)2Aק/!ʨޠ>gk7c8.<ժa\&:勧oԵ%bDX7nXgVByr2ǽU%ʩwuci5M1 v4 lΫ3vӹ_LhدR?@:!"4$13A9 ˔fJ ʘP΃U5;MV"n{~-*%tC7z40J%YX+",K;]{hjZF"vmf2m ٯw6m;6d߼ihoCPf:HI !z(fkOܩYׯ_ET^MݝB)kD 0EUBB˗ [j4SU/]!Õϑ\!R ת7-?M<Ȅw:: Z4geL/\{EЬjF?--3x ;XLP߄nݗ6/=_D@xq*MOOc:q*d.Le{jQreߑ0I& \= [Feeuw>i''jf ]jp Yy1{UQu}ݿQXBͭuJroH?wE`q@,3)[WOU̜QE%|&*1޽{>~xx g)aO!B$?ٸhk:ְ݆bS#>:2e\%li'ܾFhYi5it{[{T@aBڭZ֌}gGi,1 zz3i 4-vל. 9pťT9ТZ뿆w=acY놻 1g>Vcޟ۾ҋL 47Vѯ|^ݟSx2ʪxB!T4ҨW ^蔀{\/,U[opU<סߜsʋtql5qF7$_5k4'o{x ^V=Jq +4OC[t* j4m%$RJ*sMnunU._Qiz$Wɐ!'6Ήj<2~@؎kjW]xÛ-@eX7J>n[{k)C]e 1!r/י3UID C9B!T|\=CxjV̒egMF7S8u qбK/}-OJ4B hц $- ɾ޺w"gzLƷwkD8} U4󋛥4~=kbˇ9LFB:hVAz.ժV!r[Oފ)ɚxO.ubkɑD"3kKC3Aي NAI*)rBPfjO-4lҼy@0+52p;0~mZĕhKGuRB"KMr'eaN!Oг6(䍈Z=V^U+;8O¥UՠJUp=:]tlƄ [lѤ ^B ghu}|z˯s0yj7Ԑ0DC?V5ˠUb<)u5L :5 !:eO!["6AK6i:bOlPosRǹs:ؔ`Nx`fZ6ZS+w| Mkh-4Uc+X@u_޼x=-¢pS4?ZAW埙0#B%6Zm3>ϒ, =4kquM)H:_ؒv;g+$E[9K6i,wJ,ףU qB`^9mڕI: ͿO2,%(չc}[[{pn(ͷiVoOM#Y=&pND^ TQ͜1Mܤoߕ⿊%!*1!$~MblTXRD8y3v6'Sƪ&Bi$PM\ !yp"iA/Zh-jȭ^5@.J瑺 kHȕxֶYoC/T\)"ğ=b[-u(j],:|կ(25vf>?~a'7~Jϣ^pmwc#k筓ܾPyX3K.>4~+skw A}I2JǮf1 BݷcĄM65g۲Gw{x䳨] Ļ/m^z@)X\u>+ zx4k7dP2%*T!B҄0ƹe 0vkf簾]35|pB]yS:U{vv_wvߩZ&UcBdGm_yi>6n}6}~sSɵ=~2j8~s`+.ʹ ߷!!ipf-g\4{xfQ[op.JӃ/45i腽EHْm0 IHƏkz6UF!BU%yO:qش)3erP+۳mf7mrk#W~ u1c%o?ALF̓_y>N =M:S3]f|whfWJL8B!~ Ӡs!ssl+8ul'N  7fb\LH!TD;::G&Ƒ}5:h9/3>B!T>:[ʕ+%ڵk65b,MEL@[Kk݆5];w/`(6ֿ}yOQ?ˤ>z۟eC'il,{ŻpԨ =*oǧ_@`VӸCuW4d~Y枓YʯFӞ9K/ Nжi3p6^һ /mπuϳ粯'.8<$*U@6koW7,z] U\ߑ B!*a󑑑FFFrg+N];w߸yrImN:VN_rxsZ^BM5wv72Ucں#R֮Ϗl4>w`]KeP˸E9lj Mwq Ϧv:4a+#y'Ӗ37?4,lbf],lkBhY} '5Nժtp7%]gkjI50!BJǛ8q… BaPPܹsya7댸dFõOe7=J̀B!ԦԮ]ݽvnf>wvtׯUĩc_jW, st~>mP1Z1+6SU|-˰.6MĂ$:lTaG"@&ߓBLj!eh4<GCȈKkn@=|ul'A!BD!I2e Ǜ߮,rв6o&$OXwՔ34u-\D:6fb'+MlggSg@=>Iж=1U@!Bљ4kN=hjfVAhf>ERvՁE=VS]{>}T%zy`\975+P;;;uL{xw6h~!Be½w-yDoPޭ'p|􎣗Q<^##B!TR)\ަk}\!B3xbѬ}uw!B'!B!TJ0#B!fA'`.G!BH\.{x_cR^uA;,~qms$))7M9@ӄB!TRA.ܬݬۉLq[~؝0 _boY a!}Izpt ҋß?yYwB!ZXsC;27T75+BvߞN +jk {t>[c{\ #B!e)+ X2VV#ltymoU;VxIsPiP+:хKǬ_zBr{*UtU L̙]7:+bA&Xќ$?\wv[vu dvLR׹QIzhd|8fiH湞g*U*K脇[n'Ю9}V,!y6klKk>Ⱦ\TܧKzh944kZJB At >ye}= =>w"RשQzT%@a)Geu{Nѿ.J]ݰdw2VreG+yucrȴqxk w^| gR#XTWgşS{ӆAXcG!PRr94M+BAPJv8;7,⻢nU`3׏uլuMR^~Jj0qY¶㘅,''WiZ )`<4>:P$jߝtɔw'W_Nftg%5/moO=nGNiM]]nrܽyЧ bGݿ$}Iz7#|+Duyܗv#ygz}yiԻױ2wY\2Zŧ n¯4wvZZTv|wеk!=w>zp^u֫^F$=^rKϩ[40 .B!ڕ\0dȎiKY==ԠÆ~H|vlz8#|~9^[m\B4d'z`펋/ASCjYAZlhDEL=27EuRh\2.6p?u抂.np^`XIH,m .-c`Îݺuim#$2 q"SߑBs;=xN|6V\u@*|}'De/kY4Q/_M`!.ʤGI X$];Www37u~ԝ1W՜k9!8| :ka|zX"\Uw{|a|~k,i# =}Eעc?C;e'˲`qɲ.?23iV+k "S:W-]`FX/GQpUD\ߩIC.U]-`>:jHƦNlaz89ۗjםk,g^V}L$^YkY]@X !(k%oV-^ F ճ,ۍB͘γh>sb CfΝle_nB_B9sR.ǀTr۩%"}f-s0>YiK7?Am':ܾ9/3*4پU;my!-L[3~~֞FT wnwڡ1/-4@ye֛ᷮHx $}g ^yI[zod=[&$FqM:;V.L$prZ  Ei_Dޝ[?97u*x ʰĕ 8k>e"3Cu΀^vBQr9poîJC#FWxՉN8ԘigJס؆m=ԫ3ubu;/Vm/J1ca۶̸&k  p B%ssߵ7״ BH}J̲rA0#B׷uxxrIO8\ׯ_M߿^#Pzl\* (KzzzWRwB(zl\GL- -W0 ر)g;V=Rپ(BU,ſ4)(rSs9ß?ycޝQw?r#{6}ӃϡSD9Y~I|j?fMښtҊi-@Z"qȱ铏ƪ7-f3`)/2yёխMK%P ]q*0 Lrquj}n7G+m#2Mۺ='_M'w`BR{k+bşS{ӆA+ru_F. n]p@+?_ܸjwq2WˁGqƴ%snSs}@a]![>8̉kfz۟eC'iliȱ+N?"U{B};5wsM{,ͷ2#;f3q/=LBwvT8l? &[LIq%}c#諸μ3fom ?ELcz'NtTQXҢޜ?4niӪeaw/9wS3*km'72{,!Yۂ61MtбW [ܺè l5Yyp:<4>:@#s5iy-'.9IcJ/o&;iYNrVYxUw~Α3xVO7r&ow"͉FMfmeӚCn4{FL?.)|x라eMb ^,Iy;һl[\7q4+knB_~V2\N HZxe.*rͨg /y.]lbέv!T! г|27rA^K&ZJ۬!U4 =wGK޽UxD}+.$=^rKϩ[40@̮ǴϼbmrUǍ yDŋ%iw̗&Cﺑw>zp^u֫^FI]KrqF/kT6pϛ`]^s }}T;&3%jx&}@@Y*ke~ǍxkTu"CzycOsEǪ֯]MHC,:Է>, =]m==/ s稡2k_Iry)c9|OOS#]۴e6.u r=k[πK([ȴ^&NO?Ȣ^ӽv7\/, ʮT/2!K[d3*^.;8:jzUNz31 ]5eI#'i+ 0,S:W-]`Fi[K)Y HZFy,EʴO9޿5쫌W#P.һK/Z#нGEf,T\⠋7b2Ru[\6E߁{wJ2ﰸgυ=;1`k 77%K32#^^hi+[jzDV 証Rr V&a>&j_RRAʴkq XaΚWE5N 6]}Hv?k?6cUO 8,( <j^`֖q}j'>9d`Zѽtn~vB_ݺԯ=Ո}f2C;Uॿs%c'6_a;w5ՠS"> =yM_5c5WC7'7KvSH! ~sJTm|]4"nXryS09efXK lL4HƦ^e+GVȆȖwMM=ܴwTΆB l ~`SifcWkNR]*닂m9۴57|u5EL Pp|e^*N售 ήc #{ϦVեU."Zudă@ mkYhVqzr &UkPU ߾ۼ,[\*[I庶N<"Q-Y ;krъX*V-߻~EkYA;Aʄs5z6_5 k^3[bLg|zǞ3Lz^ L2_߭gz΍Go͖ zu 6oݍ-jgڃ 'd5:_8ZOg~Eˀu3p٤V`")Chj[.ڶct-]M,SBcggBC^J0rx(Tu%уffu4.v`ZiOoleg_jggW~_UhiiݿH;|Xkg[hs&^ySjkyxw6hWEPVw7a|[> sc@rAw!-ܭs"l]3r`ƾ94YMthѦ6O]͖ /99|䩭-9rrSƯ U* Q.4\~WnҢ@>{:ā;ΘTK@ٴ*I>ƿP46 -J:EܽpGSR#e&zxWx*Sy+M Q.\βg&ç+>+_y!z0rي$=8qҿ}y6d碶7l`#Qj 7x y1&pC,|,ٻ~δPg,=  z>޹~T>׌]"7o8ʕYnZT3験ÇKkN|n]?mor }1#TR _*YEPv6 (T(*󑑑FFFrgϞw_^{2-@Oy@v]}u~Qh7# :6wB ZZ)"u~n6 =Ƒ1L }&az zq-*;/T树/_-Rhiʠ急GFZQ֏8_G;j!0uChG"wv={pC"xer9ͪHG_Z{)vʲYЮ1~im{Q+q5gk0#TLQTaUǷHƹ\PA(x'.\P(͝;,> ~4lW3#GD/$Uߕ /iLW.^tsiBu1ȼڄS{ꛆwZ-`Ȳ*m;Wbv׶.ƹV̹Σl{idZ >z_-+i|J^:SNP.౱?dpIPxFF jPSqV~F:M䧷1VL-{\ G> ԩ`:/\ ^X&(^X8 KAK׮]ۻvy&IHzdɥeR$02ϥG,}izٿUTvEF{o#1o,J~V.pt ||H D+e !tr}EںiA |g^O3皲+KudՒqޭ6dN݃:9V6UVeX ɛml:9ac^'~)i`? 7e5X?ٓmu]g?X6h )9xKm|ˏ74e ߪ-lyw7DܪJɜM ~&Y=5;lgC^P))"tp++kWW@-d2˲oVw˄l׷f7  w=9$gd"|eBFY;ݘD,Ͱzx67 ҟ:JjfMvtf^fF >6g{~?ZCC fw84ԍ)U+aҧ -(ri(Q\w ad)nBOUݔ3s'h˱۱p:VɁg+fsw ;$~ٻo;[qe`bW[O&8Wsg Uyc,zlz+׽?uXt'-?n~hoR?xoKP9(yE4:\I(0 GJ+UwKt 'GZm`]+Fq4nd^ݭVS_yCGN.RL³lþZob\Z;tzAOK ".z4 QYT4ыڴth1hƿ#Vu>-ƾS/l>ޏfMxP<=M8 2sW n toͥ5! &tkҧ@dnm]P>k;m/ظnxMupesmwŭ'i"GQ8/R6mϳ-tȿ\<ܥ0YJ 7?QE/ pKYSr9˲Gxtr{oU:|[-a/~ZVsgƖ]-%zx-V]mu1Rkua2BnuqbWoyvz,dg?Յf;a67O_/=()iUYnTJУ3Wj9L~~Ggݙtq84yN^v;/ise,V&rEJB4 )))[:/kAr< E*e?oɑǣS]\*N[ޅhao3^ǖ}^SUIaf9簓>US&Q~;,mNTqqgimGXzY*amIDAT@˺Om'ZNJϯ&[yjߢ'ZuuvQ!s`TE&\ZuрE'4~y\=lQe arM ;d8".wW^e BQ:/f(UUD"(hhhܸqCQJp8W&%%V  y)ਕ\GRR~z$)#q%I@?U^T1԰pHa{'ٰ3kj L߂c=~D:# y }kS)ѺK|I-;N,ʒqsv|5t$ m,e3v2d9ia{:%:e iS=-;-㩍#'.N* P8W{+<Efi@i~X,(<:EQ>|(=vСx#\Z.NxcmEtת޺>zMIeAӾ[ ++Ť A0N\#j/d[Ce{׶ºڳώuo9!\`Y;TDl>=,I\GK*jezݪ$W*s^*N 97{¦QcWVMy:Vp^foStꥧ''' ·o*,LU^d 伯"+LR>[ bKi,K՟jβ rF<z(`bz%U}|xe M:%`{ ]J¾OC8d΍]{!w.jd\aH-{},sq|ߑ HwBӭ-0q OM] ;E+C8l|B{!376NJJrwwTӥ"ϊ"此$4 +'Xɫ&,_c//V.Z>Ͼ ̚gHUkS&4yޅ-M9ѼDp}l3 λum\L|FF胆I<99911Ȍdk4ֈ@ Սgʀ^~ׯ+;k7u*bLY<*s;@OCwY%ff%2ujjAZQFtófoq8F^=tOm=9m=~ΚM]q(ʗ{?5A j45*'a |Rݻ:viRtmᯎ r݄ǂYu]۩b(K31\8~PJhuLf͚mX&5:qW:WnxuCCC.Kddd$=:ʺ,/'453۠;EFX.UwG P^޻]z )KJi ~>"rell,2uѩglӲOIBBbFFz>;gXC```Goܸ?OjZJ(r8|ZSNE΋|2-[J̀^w-y˂SW(zxVLtt}bK^!T]3j^RJpk9Oϰ-Z۷O\.' 2 4P?#$innnnnnkkrfff߿u?r2L-˲_P8zMӊV555UGd&pHi L(*;QiSg h^ 5,+.t~СlOWs$Xbp XeF@5_zX@_@_ Ut?~ÑJ`hh6Z:f?rJK[KP>s,j:Ѿ}v(!C˸\xrJz7B{sMM.ñMOO TҫWp8\uk$e2AEx4Nbp\TJ$9b'b*퀎YOQRx0'Ou~N?xzFqK.$J@#Js535ښkY o{955M$EDFyyy,K$EQ4MxR&1T,U&)OHE;8`@,'\r0 -`/.b\a4/l'^Y[rXk%\)ӱ|)65X{ICR1gyYOQTZZZѺ[J\&A,0Eo$ k= .G^nsy8Zl |Uz{ij(Wh7yi6%H-M|f䙴L$XFE~lnigea٢ CCCy-IB P,!R X4rV&EWEV9yTIQ3,\eTZhyԬY2F$+X^NMh Ikgq~訥k02Q)̚W( |^2XPN}0`@Ϟ= Μ9yfXpôRJ6mvu϶tj¬MϦX~녠wS\jf+P^"HD,OH9Va>`%YeIM]RS. tz5nU᣹f-')Iq eܽRVˑr|es $RH.GÈgIj;,-31P<-oEiYk:Xhijp S,3a1AY;4JKKh֬9|('R<'Z ufٹK*; e2իWϞ=;yڵkOf͚:cƌ[n͞=k׮b… ͚5Yh޽{Ν頳)g'n&\&6*i?< Y$R=zp%ӛ_-C\`}w%qM ڙ>02X#uQ5VPvuw֞RD'+@eSEJej"Rp;w&y_r9{rP.4!0R Fhi #X.IũfIV4CWv2Hː~O ϐIs - -[JLL,.#\ S`@GJ_`ooq3ѣ"ŋoʕ'N-ZL8|}};w|\s9 m\gPt૘Q.!P[ׯFEI2%) aYK_ϞlI[߷똒 *o4/71-hkkkdd\¡.],+4 wmU?wiO{o'NE PvhٿRZ-e~BiePZF!!̐8vby޺!,[WNs=)1Wۺ}>ò8&"q-_ pR$`@Chra& l*ӑ0c @8xmhOB<8'NlذSZaE h0Q.6U{|m]@(bIa0nZF|SV˙jx^t$`p ӧ?~_~Ξ=0o޼ogw饗&74ې y~M%--d%)]>lQ.(}^_ts Lg 9/E~SƶH$ C;#pcLᢧ;hx'--br0*| 3ō\Rt:M&((y pT)|WWd,g趇^:bYN +;tXfNC)i4$Z$I@@ڵ$?:_bA[nƮXeN  o.[~D b(--/BƆdk88ZNdVN[@nEJt/i͎_͙pLqCUH$;Mg|VUV,K),,} fwx#@_or\]2W/WYdTRqn ^oKKK0L#a܅eY0۷o TrO>-nzKԒEÎ_lW^} *&r_1a$EM^#5GQaW 3f0  0 S(A=z\AB1?^zYR:QlT<F-))Lt:fwK RT*`8R_ɘxI#V穦 =AFk@E.͑>vL9L;țA ̱\Rz C__J+;XwYna&=uF]vY yJ (VQ-/Ш(AbE9aVvf♩Fq[V<dcTo*k"b?׮ˊǔgber\.l D"Njvsп[n|Q3ˍ+M(HiRVLЫ!* I$IXRR(RI)ǣՈx2"i"YᱩXyOrE߯T*M&VB!SѨjJ5Թ֡ئM}k0KrpX]qgY6<4R1 #oj/VVVhZ[@(ߒ ] <%8NC CM`7Jzr-X'0v{qq1|fXVi&I߯V50ޠ\MW{+'|/7@Eg0EflqI0ajk}c"sG$S/>'[B[̄,Ygr@{n9< Ue3-=IZz[Jf̙F#O#i>q>lS| "Hvv6I333% P*,: fsvv6 taT.#q\n˳44MjY QKcEH$z4*X>HK>9@=ȜS=o޿oK/.cYaS5O^q @4?x^h1dƨX I"׬Y3S҄Ǐ_|űc(y((aXjZX/\R xk$I Ñ:3LdB ȍ HB7vE (|~҉< !s`Wr]'74D0Jg<pߜCF$ŸKA|p߸uUuGz}ܧnl0 sE%A999]vJMB >דּΊ[|qA<)aaEQ^>w̺4 tr82n o%{{{G;|Pg~ţ8!EU.YV~J5p?Ő5w7kKQY<' R\D^^ :}%&qH3w3VXX4v`8N;Anŋ~ggg~~-((o-??_cʧia~ZaD" F28'0ӝQEq BLJ_wuׯ-uBx_y||It{xmm͹9]pEA7)1@E#< oԹ(ZP~txY3 'xߐjÑ4H S<rQD<7iniiDa*$IiX0z(xommRv=oix|R#(j5TaX0 JRfffb6&-Y>;*=k>$Yݼy|pC"IgtcP nn>F˗떮yjjó®m;?r5y}ʕ?SIo{\SŸ oYo4m; ?Lo@HL/\lh-FLckǎ/**elAiJI,ģڷ5L@ 77wHT* (]]] t:(%Qﯭa,@UUa@`ɒ%<755V}:u8B aLEJnwT n) J2pĩ kݻQ,tLJd嵵===?x]]=3h%,nb8:e? IlJNlw#n"؎R Wn̯{ǨlJ9LE`pǍbּאH'FEVĀRs؞}Ƿ/4l8ǟ4o47^ןDM8jvx i>!$iOdɒn4].T1IpWTP8zO:5o޼aFכL&gTQ `4M755JJJ(9@E)q\__`N%BIf|3-guIYʷ)O|¼LFsȑnW_M B`eQ56mOd=ƒi&w?:~BA㕆d~#ɚMR1B捿UP0\cD# 'T?5xӧ ' 5kRֆH#Mx,)[or3q>niHTeB‡z=,rTRREqٲe*$IX} ^" B!@AAAEE07nOiZ zzzzˁIq(a+PPqd2 C:N+47tQap D˺/D<ռkqm%URҀ]gg&Dwnv !hM#z sJ mR#+bBp]=mpJ<~ ˲87Št(a" ]]'-胊@RZZZ*++iz$t:Ng6=޽{-KEE ^Wtuu,+ i: bzJO/W_}ggg[,a@0d8 AEQ.1 S(1Yjx(h1!<$i~͗?~З={00B,6YVpMxl?y +_D  o-r܈x@pwxnWOO[G|vUd} ("]>L&<(2>DSoM -".M""#zf\p8\TTxn7б7 MMM*颢"f(999999@  s9$I~t!!U1tS~I}<մx,(܂Hk$IX[otw ̇` z~yy9r]n<YGDDND]eozk̘VxV-c NrLn;c.dC9`y1awb~%r a@X|@LA;òkW* #gUT/cVo\=:i덵7?=v7h '2+]{VDIG2vciGrEYe˖֎a);klll<8u]wCI].WaaQ8xx,>G8I* -$(܂H.G ̤Nc;vl޼y^4 u1 >}ȷJe*'NJ0+W677c-`49#C5u,p8e&q/O)rt$ ,L) 8p1wYfY, EOOlSXXp8 ,aXl%r±08} X .:GZ|tA[4} Ԃ8۳/{{DNNsWdX@IkiB<ɴV\P(4 Lc駟Zjx=tPeee 0,$eX4gΜy!$KKK9:GZ|@sC~;@ $X޽s[AQkh ݾu˚+[!ⱤN>\z arAh~ԩn蒑x$!If9UHOS<2eO|@!D4 l^rY1A[_EL6RYO)(Es`Xtݻ].Wee%I06{%HߩTNDQRRv=0MdHdvkZB1 un2{fynp^aÁ3rrrO/~)Mq&}>Y+HJ_wuׯ=I;D9W}%*C;۲h,a0bL4B<.cC9QC>h@___vv fl6vgZ ˲P\~Ǯ"bL&|J}$cYv\sͮ]*}#x=_>LbYsA_^>݄aA\Z[g0 3MOm@l JManѯv|놻J_Pm0 m @xϖd+1 05{ϛ'0 0CՅnUu.GL8PÎ,9C{NBWURu]7[tPhgV~UQQQUUe0j5avĉsνK#cB^DL {}P嵵===?x]]=ܓ("YkWeG^_Wvv/?ZЎgeF-&_\q[_s]Ooտm0ӌW^{K3dSpl㌫\w\wyJ (Ks3st~~~|v-_5ϵ0>ýO\qCuۧ7^E kLjƹDyOU^^>ѧ 4Mss3LBVw9lٲE>y)E[ 2Ch9rM7&Υe:UBkW.u gd-Xb XoP?WOREyqk@S MV>O{} ˟^w]wߵnq?q_b^gB.g,uy^Ry+~Mi^|rD0* "P,KQTa D"4P%A1"l^`AcccOOq 8`08o޼_>"-H CP÷ACI;w|*kz ނrD0 i2yb/a/_\ٙd Bmp#J8G2c J&( XV.?QB(~}H~xҥ#ݧ<蒤4ܼg=O.|z? nZ}>=ķ~>CE;W>0UNlq7Meξ{? qcs߿UQ~ :ؚۏ;3"t9"HFOd܌2.|> rss/O>dɒ%*$Xu=rVT? ۋe`&byy9a45k>صR\ À 8Oi&>HHJ$bŊ[ouI:Cq8s#[ (Tf2W򭫪:a@]KL @{E-`'?lxӤ `Ojݸ@Ѓ#`t9"Ոp8c>S~caEQE<ϲU/Ǐ: Ǒ$9PeH$RPP0гPCi-Ac5:yys0+˖3쎏} )][oBrQBDǡ/6KY?RWpݻ>f3><f2p|0c_]c~ t k;VG]m%/+6S_~xȺb] ɫ\}kgNfu+f#~׉˦g{&xqfګ%>{_r'b,`ɒo˱jU*|\XXR* T*vG}睮 .YSS`mkv`P(ZV ;>}z4Jrܤ9e&R7AQzV>}vmR/y}}}SP1ϑdBdWN -5ۖ6;>![*L~'*\z[9yn?}?3V][WG߂*|i PY3ο W}Gu~f~.[Կqo6{2xg KGkKiE@R 4gW)T%6"-rc*B Ysvɓ',X{o1 :NQU*N$D Zz^(=z믿>8 ZJ'@ @dGGEQ_j 7ܐu)6q׮] .Ξ2&1a㍜eϛAL%DžC֓MNcp7L3s a/̏Zs&&'ɤS4OYF~zj_ ]deOevבb 5D$I 9M ÈOT7PĠqzjZ M'#(=us=wwp g~d21/R}}W\Q__o6>ayԌdS:fkii۷6-M}֭gy&aS\'nIe9]-C@ #gTk"i;z(EQW_}0;;;򗿼}ŋ;V[[~bXfΜP8:w\0sQ$IDQl0eqd,s0A8 ٳg{.aeKsHP$ǧ eĘ3iH$SQE͙3pX,Z=-8wyeɒ%%%%{?{߿>M3fXŋ[,10 O4kyy$-ZyիW8n64qGoS 7'/@:SITfƹR,((P]]]fb K׷:uj޼ygqF?`K/j~g֭K7T ]]]$I;vLPL$=q ,(K 98uKUgy|f L&TY>+1\k1)8Qp'T*jH8#1ίfɔ ,P+zn{ӦMmmm ,| A FZ^^x`+TWWH$aX8SKayu^(˲o@" $9=_<,?֭g44"}C 3D"6}ϯVm҂/9'L"mq|`0Xf544477zpZ'qE) f3} B GDžB!Qa@ ÔJ%˲4M `6(?Cc_ 0/Q/~W֯_a`o&1C71lL󭗚mԁgp$ԳxLOw:úyZm*QBo*rTiqlnEoQL2L~+nHSz,𜳵'-ф2bH٢H>ٹJ$I jkk?JU[[_PŲ8`0 u2(a%%%[lپ}g̘ CWWj5kԎV .]b@VÚ ( pGpNN@l( áP*Q|'BRAiFMc$\W]uU8;1 %'4I}gLtN6릗u:.qEEcz.bׁ> K kN;Nf~ _0O6.ݟ JWR&Vi#w]TIy៫'sZEω,QkÆN}i~崉>dĨFB<$ӂyYYYss3 mp1cA}ٳ낂8 B1P>677[VqLhuuuZ* >X~=|xpjQuP([[[EQljj*///,,Tz2!0 ܳgŋ5c#Yt:wر~[nGRMw||,!8H.ru׭_vvHrKo@<%$W{ZXvǎK漺L$b* #G ^[$" t;9Lَ p"谨sD::E\kÏ54kfwD/bl:e i d\UV-\ y9 , #F1cFm³eYOEa<-ؗ ;ݗ]vnGyW9Bi>*&$a-t9˲7oAۡ\.bOoZnnnE3yj{͆:CK*ooxaVR^-θyMmA[u5Ȋ]R:ƿZvb΢S=z, gvlN4/(H Qyii.,,1cF8-Zx3fؽ{w$|PK35{zzvr`jEy$)qҒdVU`0eggC (8NE6ɃN0h}NN˲v=FOwuu[a$yGy?.ƒ [&'W{4<~.j.ZqJ@y6_ 3۾3瑪V`zB x뙗ͽnXG϶"S"UAe0Tjqx7 z}/,x?8 `"yO-{hx(G)ֺ14kcd{s60Ңݎ-pcރbȊPj۳o'3F3(|fr X4O}V#X,$I‘K#sA222 ӟMզ~%].ӗ!rV[[{'oÇ1 +//OߟXMʜ\y_W+dEyFXbRwmv6"p FwqJ<~VN-a@V(]ݿLlaAYlP~It f}?wS0l5-AMZjcXB\VĄ{ '{::&JyD`eqn1!eITs+lܹS׷vww?ǧ咔ae/ZjA5z=Ե`p~@gggggҥK9knnzz:O}UN8c [ .6pVw76?=Ю_fC0@18yoq(b5oӨO?S~ +'qk_ǻ]==mWmdm&T*VtLAA|\XX(U طo_UU… l#_Z[TTwA$`%}>ʩP(]C(q@믿ð$E:`kq:n,em6[GGǮ]lN׋8<` '8 3:0,++ 5Z677l6t̗O94"$WXq뭷:Ro41 tv_xz%9rdaTfl xy2Baeܔ~dK)@֤οUj5_D;wr_ųy߻@AFJ (tc@AI(1hn6o瀪 p  @mFCd\Ho=. >y;}a͵wQ$n7%1:&IDND]eozk̘VxV-c ʗH$'7|.4Mo۶ijqBX{af4p^^l-M:zzzfsUUp8pOst8JR2EQBPsss{{{NNdO&F_(\r%,=|I _0ow]5=揻WeamYX[@*`s-{Puua/W^Q5 ;7,'0N{f_paI(0wm`go` DA]΅@~}̗<8oLeE5@][|k3~UU[|<oFGSulB95zR","6vzܺYѯD0 +)/77?$$Ǔ^xAޅwr*qd0N:URR~k2FcWWW?EQ 8c!z>;;СCwuܚVloo".# ,͑#G`~i8eYQ)Ei (0L)83u$IFŞ#K30id@T&7 wꊊp8LtF78;.]z1~+| -;|[t߿m񣎿<0d\ !ϴ$?fgjڴܻ/.8O̼t@Wd5ŗ15{Z>p#&[",ǙXQ4>ev׍3T*jmۗ/?pbRJwݝ}TC<5Qi49Uwe`FRє1EXD\3P?/=߇ %!-a؀хdھ}gI$z}{{g `H)iZ`a >1dyoo/ [,OsΊ  )Χ[9p̙wy$arٳO8A$yqqA rhzk81H|ܐ5>TRjJ1)K*h';7x>׿#4 JseYp&x?QVVWXNNp-Q;;;{{{= sE}**###j?~2#bnnj:xQIRJh4QH D"FRMTfBn!hnDt91|9ʴ2ou|I(s?dsQjxC 7ŋv;, 2ͭ8p ??vC;H4 P(///I?|Vb{Usn7Z:K/x.G hjjIyFSOg.Alc6OpaE4]YY Ht:رCJNIKpd`riX^5g w9t9dT ;.G S*G}/޵k8[\,qt_{e˖]QT9rdܹXlVfzx Z;qµAtHq7ݡ(x^3S H`qR)1$ay$/OAέBQ` äy'kK޽{ _ o 9-aUABcǎdV?tІ ~_ϝ;(755T*(a3M!FhN$AݡPHszl0K8T)ߗBP$1 n<:G4 !'}˗?;w|'FPqY% uuu\y֭[`iӪ\.W__R[{B,Ew8XXXjB:q޽ j4-0"OˋHg 9RiVK0 $kڤ>:/,,$S~@ FH:Dh%8qΛT( E"p8zzzV9SRRR]]zj8ٳg/X`۶mHu?8m;Vg;-Zpj5Zs_tTl6x$%Aoy^RqV ׍).}}}0p86KJJes_w݀) Am4,SkV9ա6477:رc ,I\ȑ#sYd`x4M.-.1 [l+..njn6F);;d4HS0atvZ-*OG.$)B4xm6[__T($I䤻.G SnO1 TtI1Ex===>82,MNDccc⑰0 Çuuu\r Nc;N-\0?++3tuu~t:kjC0iF)JB gF+˽(J&^AX[/ecQií$Z\\%Сw8N:u DR0iLOsw1XiZ\{+<ϲ3_GGD8STQ: R)ǂ@&)e"F8)%JKK{zz1V,ٺuk~~@cNlN@>|o^o0FV}NQ eMui23-pH"EARP8fX.]l627t!P͚C+w8U ˵w^s=qc(SQ)q9bt91 i>i2]g}>Ztɓ'8N*>hl3x˗<w?8 _DJU;}")Fg_Na`*˹cǮ@ ڒ_.y" |ð`0h2z;`}}n j (Q|qG89b҃t9@ ȨKtQ u'MMM p\è(m?Ax8E^{-f,̪ ):"F>slKtutt:JW2eYk]҇x Nw,Ry)*ʸRG.)c@H#&1H#'#5'ëW~ꩧe'|2322?Q @(x|~/0QsssV-KAA|deERQ;p'=dKW^8߯R04WYs$.RE l`N Z-˲Q:ۗ4:l4vuLo8RI 1ÐI!"b۰tO?]QQT(0L-[e{zl^/z}yx>Ӭbłaؙ˖*+ʏ;oa9n޼9y:N.͛@3jnY8֙ദl$I©08w\8t`]G<6k|P:GL2.G dO2yA'8E%a/Xb$:#hZ|z&n²r%#3M}Qo5{,BVq\8\8duP~HE$i2(q\e;::}ߩShV|z2sX B ޽{…R*=jBj𩸺&dH%/.ǣ@ ]@-HI~q?_ցPJD=\R4gu0rܲeKOOO2\ "*r뭷fggMMM555[r֓-'O8 Zi7>(֛\sMCCܹs='~FF 4Ms,=9s&ܚ3L$EB.gk _9sAuy:GRtrb̙.]25_^R0}9f MQwܹs@C%"߿]}Y( 0 H;V:|pEEJ:|ٳ +vtt MӰ;"$>ԨjZݴiSEEE^^MGN$"? %$|< ]>AA ]@ cNMi.blOJ)ꢖ'߳gO|屢w/KeJe&R/ϟR̙3^JKK2>vجY:UUUH:,O'j(HzjROM-!:;;sD*t91LM Sŭwy7AD$I޽{MMMUUUH$ ⸫D(e˖eff/DQEaxl0&n(%{ 9 b1)(9(< ر#bb*VkwY.첨P*,ʛq&ދZv86lXr#Gz=Aǎ9sfnW^E(JUVVg2䫈"|wvc/{u{Hn& RTrbmK/tWڵk%%%J򫯾ZtRt8QS t:]vvv0Q9j 7Rr1L-TR 9 `ٓqOEQ%0'C,r-ȣՏ>޽{Gx"T 8HX+_lͷ={z%%%[l >ҙrg2`[=xu&pRrb -1UG1^hhC?JƁrz*ȁ2p8,J"ĉ}u 8sX h4>`O_~r Ö,Yfuj4 H4 `ǹoׄyN 1 uk.G QLi  b|wwh4 ƋJ~3Y(c=2ggFM8Nw}ݺG(be˖lpAD"7(T*Zt8\6yuvQaߟ+F0J5֯)".H#aȵţ"Be#Œ10kjjO~ĉd*8R`=@ z㎱8`:6lX`A#F+E"^?f8NI( ceUAqIayyNG}viT\8NA|A1 ]@ FcҼ%*T*9xT%n:\Ӆa՚)ʼnF)))D"[ݸNPeX,8ð/+Vtfꪪ={Yg^9 I0p9fTZb ->B&4ȋ>*4GӴkQT/|9s9st?|DǗ_~9+'/ʇ ðٱs;s/(j*wsA$R!t91AZ|4pdffj4{F")z~~t⾕0^?zɓ'}>_Ԁ+WJwMIt$I(D" q߾{DɌW(aq\&/F!Fɭ#t9DCZ$Qv{.}v=J,$_.|@LiӋ-oGOa o8CZ<}IGiD* 'kt:ND=ܯSŒd6^RRR]] ixb 'OL0AE9˲}p:~3# B rĤ!]92LJnF$&0Ĉ@Z|Ґv`0$@lD"fݺuo=zim#/b9۽{ȏcz}2jl? R$04hF}ғ<5j"@DJ2CZ|^\%3LRh]wWX  ]y9rx4o߾AHІq\^^ޡCm}qp0LM9c#;;[ɜҥKw[ĄR G ŧ"u:V*88o߾}edd\qP}$aEn#EQ$I2=*AE(7o6Lyyy} 7A yyP<wwPGo2v!& W)rc0eAH9 iIZHUB @~-Z4|٬j333cNjH42(4Mę90BTKgxbݾo>ؓ( H[0Q8EQ!.*"r5> bj/"Eu r"X"dZLqR_0iZ ܻw޽{+W8C9S:^~eZ>ɠ,;w*ۛ(۶mkkk~v2`ېH ^P(p뭷nذ[ P*7xc92S #qF%5b|d(F","vΥJiRya8A͛#J z#qC5rKQQoqI`&a+**̙Cyc>:b2oSA ]@9)O & o&aN{{{;::bpl2U*lBJrHAEa^l6fph8۳gۓ eqb/<(6}z~?O͛T<62<( [؁)CɄ }3@LA,9۽{o%E Pbvtt78y,GQԭ*msJ$NFGqonKXX㨈re%]( it3@#=w7L F @ F & w͇18㲲@&L(E 5yo4<_x'|84ˡP/͍ZWOpvQp'<ÌnziBr+ŋó~$Z&6A>B 4 ,RDJ1Øɲ"4MQ$s \ݪT*F#u̙3> Cآ5???j۶mM7%`p>rBPՐ$TF&*ƃ%Q_F= 1}r;IDAT"=pjL௄6N|JRqaaDXb0zzzt:|ҳ---ӧOOfz%vX(p+Jy6Z1 v8m48~|ĺ!'>)ntdy$RثHRbQTxFw [^#u^ 64 "Y[[[EQ4>OPĊΨ<EQj!E֯_/_ĉ%y־/rgZ*X."˲HD2J,p6*tc =/Oȁ'5S#z4DvP%]@~9@7V MMM͓Q`VUU%HVmoowݰ1'r zlB*HzVapFRE8Lѧ䨀t93Já 1vP?_0 M~l6XH$dTT 88 8N1 D"4 '4a"EQhq8 ˥] Y.,=>=JU*Ujjj oq7{ $.qڌAQT) ]@$zA+cCQQQܑ (^aJJJ`sJ%ITWW;NF Ir鍍ʸ.;0.R߉iiAXnx 0*=b?/|ǎr.qj1*}J H#IR!z5$1 t&)*NӴZ(9`0E^5kV}}(0w-8KFqAas)9* ]@$E ~C,sDb O( 4]ZZ (;Tpz:P(, 8sGTJָ|-Je0t:p~'؝l...niiZW:vP%) d5~ySS2AH "KF;`\P ۧϟj322vʹ$ ;q.^XٹwGĂ zzzB| Z6j(<)i6j"|,HG<IOQr")R]YdX.j)iFAyt&pٓ$I *6m^߾};l2QO+@ {%KfΜp XXXX[[{СQ dqr`,u {8-&e$5?%b!EAy{<Ʋ,aPΒdffJ7`Ĩb02 [B\RAfqFQ78qnaڴieee펢:6k/uRy>_.53#52G$35 .G d# F{<&BE"6aI_0aEA 1 8R,Y2`0p8x74MT*Z'B!ߏa(tDJ7 ov_Jȿy^pS>ORe$7.8tYVL/#]@L4:ШޯJ2AQ˛,pXʂ$KlqƓ$IQTiiBv= }ٻwhjcмJ7|vڴi.kڴiբ(Aps.oq*J)AR?,a3AG2 <蚌^@@ ҀQÐjzPS~KTH$h RHO@d2e`Yȑ#$ISǮ#2Χ#I'cTq Ek3j^/Ey<F`!a6 iHYVh===gqƾ}1c y/_]|1 p- Œa èTܼ&A i:" ˏ?ja\ZP(XE6W|@Q>էq rĄt9@#$咍 =]L]ަgxP]Esh.䒏>VJDn~ 88P৯R)< ٳgwww8n۝NQ:i z= rq>ENPH# d5% PRUwEV3 Rp(p<*AjJR6lؠRJKKkjjt9AցQ(999FiǺ\@ ݊h4Q2`Ϩ0sd#&ݽrH&V $# H2=qŝҺ À}7G 0  zN0Ls= ?tNoHBA)j0 0AT*KKKx< T 0??R-.\?u$`tczrbR,``XdpG$($-$u\J2q1ER7L8?oeٍ7+ʁhQA|oO?lժO>d^^… -`~[P(CPM X֪*B)DT*1 J,q158G9"A@ ƉZN& (ԎBy@ 0PCy~H;H$"7o(@+liiYlYqqqyy~vCP0JBTvmUVLX"!{{{yp8$,$ ʳ,+b\˹ze^x{{6<3gHNE9@TϚ5+v$$ԨیH$R/AT*SSCR8O@ 1L&B~_b&9t0b.%K===Q`z(%{ިRα%===pr8Ar>}y .xp8,bԜW$]RD;31kO?Irb҂,1b|K?8'S fa`p8VO:)-0L:NCɲ^wxeAQuI{]+iaKql)K392bp=8><$i^TT4`b (**r:\"H8/Q(E&aEuvvG qQSWaͨ74At(EرcI?|!0u9gX|$#H#dI(B3f`0k  n7a~z JeYYYkk+0ek'lz$P(z3/1 9fv2 T²lnnSN4MG'8IE⣈[&E;I  r_y:8 ~FP(BP$i:33eٯh4:!rRlhhע(B{{88NtT*&nð,~C˲,-a̙3:;;ChÌP gWi]m"&7H#d'O@=8= {k4 ӦM38p`Җ+++a0eq|YYY{a.K~Oh,[\\,^z!(}(9qfHd# H#SdC6lzzzbCA@0t pѹsJF{UuM^TG*TPK^5v +,D"z&Ir)"O CD`0nOĺKT*y=+iDb"2H#zzz-3%mەJ]`䚋x @#$CG 0 nN@~yP(4j`Dرcqr L&Svvkp8@$αQ J% :th޼y"_E\Ta ZH.XJr A<͋(ﵩP)Yh4رcӧO!V muAhf\t: f943331Tap8x u9AQ d9߯`R_~: r,Q7¢.+@bcJWWd7aY(Dv(n;//rA[\\ WWUwwu9x`p$j$IRV(Œ/h4F*"W  ҷc6s,Eu@].",_=<輺k} S2@ rb 1-sdDz,~V0f"Hcc DaR.jf$++K.yP&St:B/8K0 pxA͖`<6E#Ad_5`t:]nnY)^]!"@ZL2i OE.bB2uI G ]@ $'?F1''m6)!===ff$Yt,PpUpEaf$ɨBuÇJ%0j'jsg2<z/P&ʄBYf ,˲.+ ,+} 0LlT*(6m1cXcK8GLq.G ijfggS%ML*ʆ!VVVYOXjBaX$D"(ð;v@ F1:CuJ?U*A4 f˓ ,x<φBp8 -pa<6 t,Ub爩 "AIJqƸ ia} . :u8Ͳ,q.+3 0 ˲9aZvx  FZ uFFFGGGaacx^̐${R|8L.K,-2SH[HO,c)-?@y>+{: ?lՑH$ܕ%nBVI0z.MOrƧRTq+t:(*++zW_EKc)((PT 85߷o݇w1"csĔrb:9 O>dQQQQE hfǛsss"a0S~AX6f9U(~?P?z|B<`yQώ}b]N$doCQD笳΂ޜH'o]+29 q: ]@ &d>3.=rPP%{{ӦM{nYYYGG,P( EQQA^ A8qRIQ˲:.ho6c X1K/4wE%qvf|!!E9b*t91uwށyI|Kc:+|˖-+,,z,-Zhiih\.NHCd I {YSXFnO.@qsĤrbJ3nTwq%!.WFW830 kll7 DCgggeeBqEooonnn80,/8Z!rbIzEtSΟ022@O ~_IQO%)\(`wq\8V*Q{oo+x<CZ^7AV.[buhp`G$w(8p`mPRP#1Y!NDHF2O_ 1((Ν;W)RXk$M6͟??//aiӦ577jr*3~h\V4~b ~].נragp",|twwuK!#1 G HOqD,r' q𿝃F( z/2$83 {{{ӌ S lذau:pHuu5| EYEvwĤE9bbD9ҥK^)TȇaoݺuʕplapdffPPP0B|QOﺯO9Ҽ{smDyl8GL.G C'QJF.rquhr㉭~naF/ύ78P(IJ,Mӱ}=$I,{Ѳ2XGQ_e@"19@@ev".FQqaÑP(vi$-c$ t[S* Px3X;;;Y!AK/5z,W;B&_42b&߇7T[[ ]dj?dٳG:NBQh NjTvǝFc$&)A~1|>%]J @]8,Rdָ(0GyX" ]@ !2Gr|SXXXQQqĉiӦ%CYdaO>dǎ V _bJ2'OsD"- IA^"[Ba6{{{r[p$W^r- 0|Y> i>uqHS.G ڵWwuY<TVVXSSsرYf%md34?rȧ~o>p838c8։|3>yf|v7]RmAYf_|<Aj$ݑ0E*2\416ZEEE3gά5k\[-1JK\r}g;wlhh|P [Vy={\~:n"-]TT 9p?>p84׃Oa1!"2B|>$ @-L| qH/.G .q?4R3g΄9)%EQy^j?)֭[o~vDVUo޻ki8T88.7@B<D;w R z6$)9:u NR^RjzJr>,6@9"@r p(kkk%RGIK_@  ]@LFTCz3f̀<6k.)`0gϞ:tp@'U_lQoi:jB'hH---? ֜,Qd탎~yN ?>a$IŽnݰaW_}]w7|AA9"A̠@3fE!lǃa؏~;o۶mOq\jN+ Z%}HAIdG-7 ,*XͲ瞻[(P*r[:yNc`ρeq Kt %9NH9s8.µ^k6?%  ]@LBF]6̧ A bIIgΜ sP<"D:!%Ut:]nnnCCYdlq\M6s-++{'/J4bY(834'زeKOOcΜ9y>A^OO<8.j$4ڣd^؏?xTA2r"#9>(3E766FBTRկ~|rxz6lHr^|>h$Gt:F#Ƚg/ b ~߿)۠ch$AAC-=aR{ [[[1@ |Cotr"-HOz0Q MӢ(8$=xffc=6sf^ZZZSSyfԧ(.R[,ˆB!N:5Py 7 =oVKEEQdeYy0}TFz|ͱ8 |Dotr"(pZ EQD"͒xnn/˳>;;;ɓ6m$cԴED^7 pǎʊ̈́)qf%ꑖ?wH wtt0Э噙9[ LGUw3:eA9"E@H&08IOz̞=@i_>;M6VVVnܸJeE]]H<~? @9bbAH-'8>$4)YfMB`9yiβeaC*gT*5 7p[oU]]]YYMZ-l twwwuun >77pҥ[l!I@555p:(?OXn֞H$bZ=\H4Mj ZcAP*\')ͯ?h4MJ T /=wȂW(H$a9眣1 j+Y0˥VG8Aʱ @%US/M(r__ǣG>s}}}P[tvvŋo߾fӕU֬Y#?я}]0 cs aDY"d uVp8BP(Kx^o㣨??3d{@T4O<ˉz;OST,y"*(*( Bz/g &My/_d7g/m~$-5zUW۷Nj"x[n$8N'|eYJraNG?u)2Қ^tգ`9LX/Gh %f8EQlll\~d:pN:eRRR>}tll9眓q\`` !h4^ve~}rZPWWG;dAؿ .K~E|-[O?YVѸfrjşe\\ntp q{ :qv^r?tиOR[?ӧs4h^I\СC'OV}饗;zɓsss]Ǝ[PP5nܸSNz .YUT&44+زewlii),,3f >}z߾}HHZƍ+((E1###99d2۷oEq׮]]<"mVTZ6))>_z7mƭELTfy۷(cǎݱcW_Mc7ˈ~;/33`0ГitNȑ#Jr{رcO>p8 q^z) 8hz}PPPrr/LIqƍW]uHr mmiiyeYs1EQJ677ޘӧoڴ颋.ڹsgghz{ 2""TT:I&u}/A***[x^p: 777}駞ظcǎnMR|EPm*v]EJp8RRRvܹh"0̒%KI=+\nܹs///4=ư?~  ,?)4pprziė;%sΥklCiS*ǎ>} 4,YTTDxbA kkki^jOr)@cc={>|šf2f3]fBBv;!dV̙3_|'4MEEEHHHiiOMM m1PH:ow~m~1))ntM]fY֊JfE< /t}qY^V*!!!EEEd2+ bt!s4yf/F ,~`FZ7v˃4}<--mƌT*###O>6ydzK|cǎ⋥Iћeff:t(---;;K;a:~144sϽ;JӧFZ >sLrrrlllmmm)w[nz cXhhTt$6f-ӧ+* x]lST !bfVkZS{4SprzcƒHD]JtPٜ6sLJJJ2 j:222??G6m\ iӦOmRYY뛞~ԩ'NZVSR_tE]tQPPP@@V=|^[UUt:###Μ9STTD1MNN衇^}UO|Ig1G /F5uZfX,UWWk]?/:_0juBBF&uUQ\B,h7]tꆆs9hZmDD0SLóiXdYVs6Y=|'*++=,ҍM>ꫯ  jCBBN>h8 ;2Э_hiix .t ˈot{_TssZ.//ONN 9nwI p۷u _`.GG*eA}NSEB:|9sAC&hۥ6mܸСCMMM =tܸq\p^h2?NckMM͢EnZRR²''O|I<G ?pY>wc `4y.VЀ9#^h>"Iӵtm6J*,,T*s9vBHNN@u:<;҈{ve5`Zn3:ӦMDwaʕK.>az j4z꩕+Wݻ7##RSSp8~AAAsҥKcccFS{jӦM0uTax `Q.~v./K~R<0.f3˲СeO:$BccOiii/X8G!F)Bt:~FsAx8l6+reǍV7PNNqqqq_*88X͡-݆oknn>x ]v'$$\uUW\qJƾѣoZju]]]nnn7(]˧'R__n0˩/Ff]vm۶"4`rP`|ڵkܹs EE7y/--UT111K.q:999 "&&aJ8e؇~_OOOWIII˖-KMMU(ݾ}my6[TPO;cX h6q\CCqs9!4zDEE}---:NyLs++l"## 448***???..NMeSSS|b:\K9[ΪEsC/Ԡ/|ɘ.}JV@/t#GЁ9P(0AX8G` ('ANqqq#9,t:mZjkkU*FټyZ!;;ܱcǞ:uJ~ #McYV)s]}a󼴚f7e|||~)4BXQQ! T0hZsssrz0б^i!UPPPWWK eYҢR ==bTUU544T*tVKή!rǎZ\5qǩT*z#q:-_,yeYDX](vhM:,80hllT5*_]XXHTUTTx NџuSOGj233LBO)Qմ vt:m60---4 bƌN3+++11Ϗe٤={̝;WJ,* ޱ^6{.uHKP!oA=-,FDD@'m :3g  DQz$-c6m6BoYWWG5MFFFZZNS*YYY4>L& *.m\^E)z%Ns15@CpyC~3M2oڵkQ;S[[+MAΑDAC!jjjT*UllTh4Zf p8Nbl6NgXXV=v5?~8qiRK F\fh+++SaaaJQ*X,ќކR[[0 ~!R9cƌ4B$mvQ}M[ڔ]t6s!.6~T__h<~"H!riZǩjf2t:iZ BKNٳgR9sѣGJe||kZ~w%j\2;l%wv"| ׮]Ǎ7k,-]O3[p,K${G5K ,r8'!ϰd>deeҁ>>> XVbytzRI;Nguu`0_~EP8xhaS?5.%J_pGޱey'h݊I)))9s;.)6=_ IO?TEz,oR ZxvB #@VVư0nXZV3UT*f:Nnu[:JN:rٸۄ-uLP(8kjj]:uI姟z2#oƦMi(gj://oP_(h`ɠBa333SRRh$NifT*^jN'!fl6!'OLMME,<<ڷHcN<]l:q.q++{4E[o%)QN'jg}$2 a!4 d>477gff2 Rt:b -jf::8NWYYB)is#v֣9.jl:\\i.p&'ۃӋˎ[zSSK(nPRz:hrB;v`innX,:`08!jiv]P(J^O&''˳D%ݎkKRkOC)7^ p@F #6g! r@SF J[__ofVh4tLAN'qt!ܬhX].> L< @nAXަut qzw*]̙3~~~C9Eg A#NQ 0#FqqJ2L t< ˲jpIO5 ØfѨT*@V{ȑ^BX5 @]LElRD^NCBby8Wsȑr>ګh]#F^^ 1yJi<+JzJt_V{̙'N%{z@&h4QRRR'}Ūs)^ZZR]61jdnt8TdBffl6VKWM&S0/"q;Alȷ'ÿ]Zewtc6-''gÆ &=DA'Dz Ϭ\B#no#;;;%%st:ts(MYnRHT˯?P׹m7ynjN/755^:88eɤ% &rX8Fs9BhPa|q)wҒ9aQ =`0Oʤ8_̙{W^JrYF߱\^D-++۰aCppcN9X8F0#F2[}}}AAAtt40Jpмqn ˲tc}'iC6tW twAl0`oq , Bmܭ*irVu8IZv;^ӱ-JNlnhhx뭷BBBt:]0!N!X2XN;s ]ćV.CݻsuUO~yNp\2**Jl6N/&r4hp>d=v5Bh]ܭJP(d lN'rHy>ޒcInWTTKAAAtA~8D·s9B;d> D,+++55`0"nƪr9n7ؗ\^\\jժȐ98]+Ǒa|\BN?NNNVTsBhllKw .]###CCC[Ёs9Bkd>D`.Gy`qqq ÈرՄeٴ4__YfL&ze}E8NR)m{(fl6˷@?bzLaG νs9B0/UQQR"##:dYVT!}e;;^BY<ًp8fƍA/uDEQB?D),{rQZXRRTTNIIjtQ>Rۑ,(t:׬Y#ByyhtYY2t>Bso\>,)R|}};~I ħO:zy󢣣Y..X/W*---hڮOASF,q\4H5r|1¹ !4 V^^^bbbg𖖖`On<744TWW9re.Vbc ~D#Fag\0P.wp8Į;U*U}}}uuuzzzDDDDDDhhhHHԂBy^Z 666ӭuؾE9шѱp|`.GafRX,ىRPP\\0Lpp˲ZVTfN뛛(|.։$R\:0tmRlhhɉtb]]]]]zAu~h Ba1#А7L nUWW+1ce#(Z֖riNb׹s1GH!4`rT*|ZyO}QA0$r|UmQ(1# 10 nv1|Щǹ-@FN?p8{r*FjܭJe2,˲,1j0kU~2(c8rА3 ̈/':.;.| (|aa?܏~z5rQU n&%%bq@'r Fs4dP!4I&yk-KFk ;h\BgrM>8?a4GC!jeHuszx{BHhhh_F GCi\B ۳gѼwSl9LCr5 y+ݬ{#4a.G i.` E@w8zM e/| }B`!uA<8pۻ@ßNrP7S }qaZw}}2_hD>`.G^_x/555=K0?WV܉!4 Ȃr4@ kBYs9By Oha4G}?z^\W@Fs;G0=9I5b(!Z@9&ėc~ @%ka>ۻB^r44a4GnaaDۊ c? K @&8Hd`,0II֖Ӽ3!4x@0/>~;;UA^Vw{!$GcJ;kq~*y/y4H?#h}ZŚuΜ9{B hêeQB KgF 0#3 ш|4D>j).H>Vc[-fB_ihdh>7w4S\' 4t!KP@F#RĄo BCѩ o2CF!J!!zC>6QH H@qMsѨ%5qazByoByr>-0`udaz{7B; a4.3ܦxw!| ]0a"G][r^{|!3|E3>!0  9򄝀aCƿVg޷ XP a̽s\APa4jہ<=,^,VJ6=V-8z\=2캗^!C ~'a"A0d`~Pz4jnRᓮJ ꮪJ+m.=3[)Łsk*78]sx_ܬoD_yC%fv5 F1uņG?_sm *&ҧW1Y{tOYxo"O\;N@`/OVCݻh|vփD8knS [GQ_(/wd}g}ߜXkKZ i`7=OIg}ݿ+7YAzO j[mC:H.Ji Nh(mu>&07ˎoƼ$^zpn9pj`iph[%kчk'4o{OB=r FAGh4tK7ua׽ FYsxp~G_gܿ x/.y?%k fc@PyOJw0o977^wVa@<)Fc=>T՘'vyc?rJ%t'kv=B#V0 A `.ܹ XtKwٔmct Z'kxh⣔_>tHKV'(S"L~̈CCqvV^ NN Uy9wa8%I8ch\I BY;~W@h7E_ th$a>pZ MLH 4H< ~ CnA:EO u޵].ל8vd _=VXX;gϕ*z[.G^C{:EB`.G0{d@ uè@·F0#)Gu 9!4a4!oYf5{{7(b)ؾaöbgO,{[-={W.;W،ې;8CnCÑ3z{7:Gn**U:yox}`lY}ws%|p=&4e?^a].wy/WnY8ji[I 7>B#yI0| |wGw^޳X3Kbv~/_~4K CHD|s:pOp5i5>,А[7.bw߷t|'߸Ѽ{Pm8͇x7buO<)ꈶlω^rPK|Ԥ%Xb1s-3u[n~V +g閧X[tL $ ulVɋ8?Rmמ }uIXsAӯ/W,;; _Bͯ=d%=zNXucIߤKzR}lۛ^{;Oü%@w2Ge{̤۞P>"_H'v ;=2 Yr뭗.agLKֶ( u6Mo9| z]Tq*\ۑ/"\2o ^kU(G-Esa?핝MiE̜2N!UbǴƴr_7FyGjn]Bi|ߵ2QsSk>vڜX cEvW^~h=W6hX2BǍ//wGI7Z+6* ؅ɩ  L{RX(}C;w,sUQ󦚶5\וVξl*,)+Z[uލ~{+W7f~ޏo[2J͘s|{Áٺ> >+=',:<˦M~Eww/'fͿ3" bQu[ŚG΄ ]lwϟ]+.`OF:>ntX[S޶\βͿ^nU%[<C\Vr z6 iX  Nv\ܷ\YВ6|S='hco\Y7N`ta3nHǹ [x2_߸f.Pϻkڼ;};3fOse_ra_.p vk=8(17ovTƐIztYϽoTeEU@,hpo va*H/2e $441!Pt*##eJKy  7 &ro.kN;2wޯ+,,ݳʊ_Z!W!4~|Bс kG !~:1`pG:Ń#a r0,3[9XQ4gop/|+?~=8#[~~A#G|tly_|v} o~2kˏAV4{q>36//Z~bK }o\r޼`@?^'o6hl3IKζ/H{%b?kk-_?T+l귢|W9wNs}ͮ z37䶊FtHpAӀ}ưٶ~ `z@hֻFЀPpg/ܪoFP{G/sL*0{j_zWU?9#s@ϫeuA Vy>u,ECO #hBmzz_5GҒD5Lz{_@0i~iZ߷3a9Bhh5>K~ϥ|溟OWYhݲky">cܰ+jf^xYzK&Їovq쥏?{{:]@IJ޺.mzͺ/na o{ټ0_om>u?ѷ.orp.\2Gu|oiE&d{vM Ĝ}Ϳ5ꠔKn}YJ~5cM5=x6/Xv/eAu޾/)۳tΙ[r݋&GZ;~0ɮSՇd]+nА[7.bw߷t/΢ϯs/-FaS.ku[|l˺u/hLdC׍QKwmXᎌj'?6N tZ ,!_oZF,3|ZN{yZ+ǧKnӒ{bNZ?g`;g^ګ7(:_{͠ W7͐%sza8Deξ|#^F%} tW߿b?cC2| 3)E;׮^Rpb\t".z#ֲoX}iZ+.VUsJ8KU9/zrCԛqMW=ڢy/}}'q:ު#E'c=$^Ӝ>yomąXMMoozeC;OR?=Yן)v-'^l~oNStE?|_͆>Ϗl,"垧eg_ {oy-'6t^䎏 #-k݋d&|X=Vqxi%̟>?] hܼfr[. aYl4%DW@A֧,MjS]9Bh$h 4 )D3a4fPM1-YHo9| z]t)TRu~+vL`otrSs0~(C35}?&i y [x_;ri)8@2=u &Wv䋈̛WZyD?)+^*Q8CWGfn"/ux5wc| H꒻Wu0N*[Ļ_  uB`~U˓8}sS8r׺f~"/i%޼(wn83.OG2mz 9z~ϳ/x[yȒU0V FV ]F~1g:L i']n7X:!Jq*$eT- ohҔݗsZ |n~1ϞnJUmjG'?\<9 Mvq Hy;.m7ox/f?҃zb BNQ$l?)#* !*p*# 0 0ozM zp H`\ϐ8!U]YI'}W=i>~yx :}-qs.3Z 3cnMaU z} 3`^'?-Ns9ԩl45sTlJ~0o wm>p~= ~y`m$ + ^&^F5~i0].wď;[&<UB0Uu=\갔8|$~ID yCjxiS ֐S9Vۗ=XI8.vʨ: N~BeSL 9IĒ/gFj 7YJ;iұ{>x5/}ӺlOAmTI?{->'(6US/NZz͸{NsZGf[pT=5Y?~逋f]w㹟=⍳߿cۖLtL*OTpȉv['x (_Wn|j+}N[`dX=U0?);s1@b0\_|V`9aC3;1E+m%'˭т=OiLP|}f?q(HċB:}-13֬Xfwהiyy;5̍+[=k.y?74<%-DHzJ^<)7ϛZֆ_zCth.9ӚK IYhp2jO)֬g7uheDz>/*.{ڵ[6 JjEB\Jo>xܔq>r, MIמ5μ?-l`lh~K+>c=WF({gSǝ<"&8{0޸I}ofܐzgӬOޫ}_ Bch'J߮YPM7KUYP/KB8Ps]?gov⵷g=cʪ폵냐kKBKPMr22R&.4yj0#wnGcs.kN;2wޯ+,,ݳʊ_N<gvm?ؖ=]xC^_Kb]o$o`|Ò9B}}o+:3k1z,k翝"S/Mx{Ҡ NY[6^{! E`[툴`Aaw h`" EQe,=:f^}A`:w?$,tY R!M2lۇh͠XxvPnҮ"jBh=k< LȻ wr m;œm1aS쥿opuO2G.}ҐѥN[ڧVCD!H-wطHk 5ut 1CCZ[.otNJ?ra돯ώ~~tk4j׷7-Њ((&!9>X#m I 0uY2I󧇪*}rMtP__ 9wX)̏gCEcJS{ʼn''Lg8q3,H}% 9 53ן?3R0*ĩq%VK=z <;w@Bh gB#O4"˥,ާ^SKe|5SZ[V8KgX sIAJ?cRSŞҦ &_N6u5{Y{(Κ]e Έ%(A!FQT{IYQ; yKsXDHX@)ozE!l偳n DQTD̙go^7Fe./njZ~kQE{uA Lҵ>,cM.l!Z;ݝdz6Zm XߎPq[/s>I$*[l`+c[,tLpb `U:`i8A4 FuQ~p5֊>4PSkOm[nG]W*]cʠe.P܌*XXw8p! &[!U--BIyy%,u%e N֨Tʾ<Z.*:&,"R^n7qyOA^:Ҳ}m?{e˯yWDOl=yPhMD:PyOhJOq˗jKف4хfn^ H1uTg1냃0nfj!RKH XFV& /QK gNTۂT%5 5&jt~%3m+Yt9y|pu")PZ!09Ѥsѱē8!a&@]D>8m8An 9;1o3Or\xB}Iq0a4L ͙wPtq~V\sR$޿u;`{Y9ZvRbI ;~>''gҤI.g8Nqji陌7˲V3ؑSZov6黄ry\Z&X%oO-Qmgsd4as/dmZyyYYEͭ^:U_;fd K_>h٦# +aXQl me!ꐄp&d3ƏԦ,,)/.Jޫe aʆ̣gjkҏqƌ1Ƽj&86@>bl)eu5g [x Q$H't> Km}bwX|T_Vl8h<'@5kfASUUaSRtss-V.T D$Dih@$  O}K[NXP_WgYvVݶ]\KCUG:.+y%Nnis޼),>և%nn>]PMSx.6 y6rie.~ti=P۲ҡR'TʮJFMdg8#pM1!DdԟѶ=P&>Z"0*cumwLё3$"ƗkJQjSdrx DF :]cZ/Bm 2Z_=w8pZqŻ88jcqk( y ?9e2qf,-4.߹<0@;h R0,;aĒbη))owG{n8a'˲Qeж}Ӎ/ZƍW^yf:B]ga70i!ʥs<)WI>zq NL3B_ݬ+^ÿf4b"8\B=նRHZ^E#IP(U+:;ES."IFȇ~?Ϟ)RR'~dDaF$zb aKi`Z3ېnu ) @Ximn]!< !SX&e@) áRk ŴS>,--,JǦ"ҶBZsod;// R  cju׻$Rv$MMMNuآܚv}?<Ϸe\"_|v%O XҶ NÉN'AiBðia]PaU0q~8z6$4L~e``ט|LyEA+: d3hx({ ++^B׶5^j=r\Iq@׹j\qܝStttMCcSS]] %>>>555RO| ~+c"t),WUU}v,ҏz2t5i݁E)u#&j0 Hfjn_x@Bsȇ $84$((eOHLN9ߘD$DA6)!DiEöVڶ~'0(]$X0j6&eC8p`PqϹ΋j`ߞB4(4:m}]}ccw1 P(Z-OBunh)/-<3\N_pv}ICCMsOώh5@F~Mgnwfg%&$u']:b545}|bb>( 46WkڈhZGU1s^zpXzNF?I!;C'*v;gBDGF,쵎s)BjR[[ٙ0 qz>?h4}k*?d}[^毭-.!Bhr9NK\N/3 k6atF!Bk9R\E)4K'_JE?60qeYeyg0#B}\V EvH~I3}[Qq٠YR=rB!4iY\J紪-u1"J]|Ri崔.}B!@V& m?z2&yeW]Cuqny˞r9=8.!B!4"ܚZV"oklyv[~>CV3 0(BVB!Jĵ-E] 68v̘q'E:~q% S Ƿ}巌jkrן?FǀؒǟAaa˂LSEXB!b˥hZ oyo[Zo;;o&R7>Ƴ[Pۄq ϋxw۪gΙ7ىaZVh(*A7>մR_d~M,, rB!4=؟ݜ)P0 ~t_?>b:HDIZveJi*v>9]?XO~OH]qD2(˧4y!Bh(+ Yu| !DQ$@3?^R62 if#%3}"Cդn ia@X-6Q OB!4/k.EȗĮ _p~CUäf~YNfؽ"8SE%EyYvՠs`ˑ}xfvV{B5ܾDv ZH%!Bvz#c7}^0)`XvIU6gԓzϟ0 nVgZgMp%tEXtdate:create2012-10-05T17:19:50-07:00%tEXtdate:modify2012-10-05T17:19:50-07:00GtEXtSoftwaregnome-screenshot>IENDB`rviz-1.12.4/doc/selection-properties.png000066400000000000000000005033371300447110700202330ustar00rootroot00000000000000PNG  IHDR' XbKGD oFFsev pHYsde vpAg @EVIDATxu\+F@RT@[vwVF 0n||ml>#tuu/!B!}X` òϖP`&K(RP|w(C xVno ~|"jCe:YOqn|5Db}[ie.Ds?=^Q௟_~GJ׏[s?^BKc`#'&Z+t%.l*鉲(}qOPlye_G6Je9~s[/OeX6vV`!B)jNj]%B!!@WWsD]B!iSՊB!B9"%!BU4EeYeae1 -p>(- B,U$  P(}9NNːPJZN9-B! @&draX$$Ir)R2*7˲LF,[DfY\.ifY%Eq\"I,e.6rV&fIqJ&'5=CU-e^8--] dѮ~N"VPߩ9.j L {2RF 8${!KPh\ugi3 K7bH[UV&$'Nn6•be>rmAQ^Z{Ś$9#B VR |\A BaE"T*[D|Ҵh.E04m" laQW}rzd~cؖND: C/q8dG+c)cZi{qhF!xܔ_7ʞ!)͕DJ ʳ*uFOHl ;r1O=ؔwCQqB>'Aܻlk{(J1"yd2R/=P4|b)eY!+S`RlUdݝv$ӓs_ erMy`ZV>uͻ-$tqDZ__>=4G)\> Κ%;249G$R!) =B!B r,KAUtW̠ð -& XB,A( 0 J$ /# *7IYd`Znq$3sUWvrxDĕϛum;rH{鞍j ( /隕d%d\ee.B! `Y(*;;˦ p9AIA'˰$Ifdf}Q(T&),*6|aY%E$/aXasrH޼S )òlvFrc1!aRRI\>8$gx%eeLV\R{*z3"B!Hia7!IfB)$0L*eY҂ ea$%Y x3 #sI  8d&K^O)!aYXż%IbCх:0\L+z3"B!XxJLLH@$E Cggg'%%'%%|O$A$@Iq\$0X"NMI8#H @ѧPAFHO"哐!2ޡ l5J p82> |B!x,J$ RY|\"Њ+$Iq82hg eY.qrr$Y ð,C$I AA[*UV<d,C3 KAR\.Wϥi:J)L!BUfyRp82wBb#+$0OyܼXL1Tyqx|^yH2zc9B!岟/wDB!PE"+!BӰ!Bm!BU$L!BU$«GE!B #B!Ta<!B %e1#B!TarS`rnJN?cب~5* Ra͸]B!kQ?9-m]9WLr$X n\+ФzM#៺5B!P)9SRHj4l7wL:56*6%CkIz?EK.(̉) fe18oqOKm Nt_-cr*z!B_BU{ddGgm=m&sgs 2x]3!Biβ$woeVy]O\,vVBh٠O,(iRێ>Mwg/}䮘UECϟH A M vpѠdxmcm)donvq)UCnL'm'U[ @ ؜;l JeɟRoݷ[Fʐtoٗi7Rپn 5n?\@!BRDNIR,K3ŦTJiݵZ6 s服)IKe@r$t~Χf-t2 lo`GɘcݓBͺnCƥD9+'zL['O]kbۂ.1͛þ;gp5x? r/K}Agvʸ=Fq[2aXҤwS/sp0L?c,Mm&V_2/8 @!% ^cpksT|\&3u-\ mZmW 11t_0r}nMtóY`#^FL:> t. ?0vˇ۪]MVvX_EGwXޱ etK)k*Ah| mwn㷓Pi8ԃ7h;;mrA"d !σ[ܱKͳo&3zyB!TyeK' Q#giQ]I4@6:1CGDn=pցtS\z5nak.sd<Ίc2A]HB!E Ywe|_~sbĴN>+\vYTO&_;U'¥5l Kc%tss늨6<ճNMuy7ŀB!xeIq?|ӏ >x㓼,#D^'$S&LILH( 昴4)sToFFvzNUߞnԨW_J8ZOLerR3Yg5?[o:VUmWkIІI?!BUF.~S];9.wwݣGNýwD.|n>m{MjH43}l6\6;oɪ߆:3Ƿóh+h#pEuN+[;n$+|boNN{ o6'>Dȍlçތjݣ5QrUtZ]>Lū:B!W*IAJNBM݇ϗB!aB!H{[} .Ͳ?W()G!BT݇؏!B B!`B!HDzZjE!BQ˖Ͱ B!BىPd4-g$I$*"!*7_B" )]_(uu5''G;[[*:!*@.EFF?xjUww `YWMO4]5E!P9D4-z޾.!IRjK n%+7]1ؘ޻w9B!wD ä8;;s8.K$K/VN,Kd᳅+B'O B!9K0 CQ Q\Y EFF p Iz!`"GaU +jUxJ>6U`!B?9KWe(-MӅ;gWy-sEɻ!a"G=R7o`~S9&rBo%p O>)a.Z*#BPʪWߥi] ?u..^Ƀl^gN%_B"?_Pxx-[7o^+UN`````w݊Kё[iV\7Ev+9U;o:(Vg;REco,VRp"|7m޲a9raC---+z9<OWWW\ f#CSt]tsLkč_ɲlv̦Od6mZq&L0f̘cǎKYﯜ|iеnS14G ۞!~|[Q ]tʻ.T'vro?~N y$ƴϯ6lwiPXm8^Y߆<<<|7nT 61ba%K~bD5|B'^+cdI[Ǐ_|*2]H[ν[ګOpG&1yP.6݉w/Y%Q {I).=3mS9$ܕcuխT⩃0>177`ı!y9hX͍9ĘDL-m?J~ Xiܓ^H9jkn#"؋ )6ujڪN]M;eݳ,_\UC[m;7ud?[<7 }V)|FZx"yFF2uO_*(dn'\eÖ\Ϭ:+;/>Hjƶw\z6xCzE!6ׯ_bvm3bHظqFm#͛O̷4FC}Z;v1Ҟ$w6@#)57:9k k6R+I6*Wܗ /V=G__ߺF=`SO=w؜*YVkڱ]q'o ð1e<ށ=O4RB~乕(Ay&w`O~s|Iv:k3/5##LP='tH#_?o鵛-a,0j?qP|E>OY:U|̴ RK3i BZU5~۪ynzoޢ Q: }z9;B( $wy-XΝKtݯ_w' @T^F5{*" i^:$O5@vh0GO(KI(?3|=wܞ?jkCIo8Y=ĖOٽLTkߠv_M{{K@}S6ym M ZҶ t]?.mq羺yeDzu6;ʞݧ<=t6-n|LfouvvolH3ώC7-AE=zV:pݼ-f_w/<&U\7k^MzoZ36*%<>bṚ݀~-Ev4e3.\xEФn5)`>qMz}g }d`oV|{G1 uz|+#,١e{qxj΍:4Sb"X!ی@̉aX`TE]Vԉv5/HYhFK%"iJKPVSi3Wξ\jz7wfC:Ze[[[eB6]k(trŧQ 2޼W.}W^%HT6o2qv[@XAJ|{{3XT;}\{E}e#6ͩ*yL9WǹY+7fBN7۰`81Gúna}sF ITGnIQu[ט_ޟ x[5޵ɼ68zYWSomeǧ"}- _!;F(';%r94hE̟W 4(\^hQ&;)0#W"w6L>D7%IXKLqM)O8ê|:~5{OcEEؽsʲm ɜVæh6xvVK]+t{߮=kuv1ٵj V-Q͛9Δ ,˪7 + Qk;|HUeyNdzbt5UJYf_Nہ3kheUEY'P㘹4 /]K0>HMlhD8VMzjO3tXɘKvXCxwy-4)\2gۮ#8ضu9hY_kwk^&m% 9VGӆ^iXwu[[Y"wk%_/ᤳOyquȃ;яG,ߟ %Kxzz_Æ Ç<{rʬ~d2SomXiFTulSG#|hS115ӧ?53vѩs-#²=ش{<VJî}SV}F^RE]HԨ&ܐ[{6YngBcGGKTюtҰvZk;K_'mu?_:|fV<*<^$Oϩh:kq[>fu6UU5@o߮" +T<`YV]]¸U\&9/![S-cSSMwzj!V[xj$ 4VLsJWA ړaڿ,Yr@ISO䤊}6A#ZYܭ={o5ZmK{#jcVS]eYyi՝{Uulb,32 JxQSQ)8\cXDIhiu+BҨFwXPݓo7?=T !V.I%k/$V-DxK28H>L?}E뉖i2Jƹ66},}L@-"'譳=YI rutbDUq{@A*.XB}b]ÊΦG6ft4$xz.z`z_P`t\mؙ x<+ U^p]o+jn&3wfG ?Uq,:'MxMөFu"7ÊP9Ҹ&*EL yRTuw.E{gY#4ȥKw.\0o޹MsGV߰qQZOH>ݺht37- uwǞ|rqq&]`DGoݼRpZ: EK3JA0;ˁX3)XIĕ<5-)Fm?wtOXj8<걠7 L />aF͚7' 7G{#'zBHV7!N{Z d%e3_CK >eHHy~ȭle wҸױlЃӨrV k* N8nQ_eH2~,td@){ܕE~SB6ð RY92 X+|JBZ9v}mGϟ?fϞ^ftF'NfaF.OªmM=oJs&E$+YI~nzf]iq=yeY l rU߿a tY[t[ a, ;S/L(tn(,h08sq9:BeӟlYmS ^]_Z.b^2#BKKO>PAlll$)آeA]-_C=dO/[{l@+ufC?yR8$yGN6 ȄUl?/7Ҫac!AOtثG&YQqHnsjdYes/씥3T!Z^QEGWg$Yx h|*Ξ g74-J#/;w`DԬaT;Mh [^} _9wKuٝK .,Ͱ(`n]~,ɣоԇ.n On?|"VQm:pȍSwWJk|><'##=_EZXc5-7ؼ&_ա͓J2E͛_]aЏ~׊AcGG瀀T4hW YdH'zfe'$CGL({Vtꛠ80lt<sPT{eaa,`_5X zk#[j#L>svP1J JYj4\0ʓ~yvlighr dyMGSS{.~C I&wqc$emS[%y:7pQ'V2}bVpqhf|VH OhNE?~LO:2)U&Nwu*n aܼ_kb):)N!aY Xr/ e%j_JURBNxJam^iޮ/l?6~Nnc.\Cc ml ӵ5JYq@u:VqQ2v &<ã} z^{λ|1ßݻdqo"6r2cUsoyv,,Q_q J~q.l V;|bw"~ _,Sg7tʳp}E{2ԡLZlye+KKX iӦX}svl\in])PcIJJ> A@qa-]fKsobH Ibkf,jߙˎ|]Ǧu21ܺj fLxfP;pEBj8 5l>u޹n~+k{Z}w:i κp+w1Q#oJZͭ 5Zo?v!MkjMw77Jo7ٳ.=2qoD5vR1۽P׬OYvn! @54;}p5)PV'y8k>b˹ˮФhze8S,L6%\= |||Ȣ Yjlv»鄡\G [j̤t  @MI"kjc깘Pt}U5C=̀^fܬt*n O?Kh#.rwM$ `=lO2eΛrWYG;%-sj}n]T9k'[)[ :!@|jǒo^6,FN\ܛ"TkΜ Dm8rxCWݕGiLP.#1G?A6 \uzܭ*J֤7NѪ3f散'\}7U۪0 (拔gּ='s_ܓ YR~vڭ^&""R tر* Q܈xt̬AەEVZV+T_xaggNNN?}**9Y.]ZbfYvƌ'P 4& ?iOPp޽/go>y%QH&ӣɤ6ޝ;kS82{1Gu=.|WîyN*Yo$*%F]{64P@E($9<}[o>^HwHN݊~CPBg6e|i_g)7nD_B9`fϙ;p@ gKHHpssκx=I,۳gu֭\MP.]RpQ<{^('(xY׮] $rBq̚zݦrHp9hݺUEԿHUM{cCjj_ ';ҕkvvvdȽ&z^^qECuPQqE"W?KΘB?]|:a@w.;H]yX!VlE!B堈s+7O^~مbHrEyEW!B`"G7K*ݼ&++?y-<!BIՐ|(B!П GП+Cwo/v*JaU_YxS B#Gȵ^׊[PnGy;DB0I"P"p8EZͻUb<~ZZZ)B!*9G173 p8@׎&g' y$$$0 ]ѵF!6rpFFBwqqq]_$IP⢣#*:!Y8! ,0B M4}9B!P~wC!BbWtB[7+  #B!T10#B!T0#B!T8L!BUl#G!B"eQWxT"BMuh]PRg\ qT>IiWfLZS/-EB'193OݻoUOϘ>~ PQج+~KpՍ ZM*痑\Y"mJ+Ub 006P ,0j?@>U{=S"t7Bkc[;W"!HA"16,\v!5Lᬪx(Q+z Iske[;{eW7VܶyC)u5eo6fd·+1N5Х?Xls}x K/X~>4] 4tk9`H۪Ͻ4s0{0Wg۫:n7m?Bɠΰêb =o^Ky߾-^9!KTm=|yN >{G 4A ;nO"2YJժń]xzy΀}WoJޘ5fδlΧOy,jUпW=3t]<. k8ue<"~Q(.W8N3ɲ3kjw3&NH_}" P]??qtxX>ƷR&>>vk׬*Eތ i4Jn]s]CTdIqS!~坳Θ>slnҔ.69ΪE;SG\ni6c#$qg(uucx:25fF&ddo()_73L\_sl}|9;[Z`~4TYvw'BhӸ;Z}n]yUO)ݻ/|D)B?:hAVXƄ5 *sr i/4!4ՂLEg3BDGҤmyƧW"<'5}ˁjޣѢy_}&fZYY?^8|f"L>J߆\VISliej&=>ufD$} f:pIRIHR}R w_ ,WRۏwJ_6.-PeSn\YEB[n]B9Lv-3ulݨ]O˪\&+YC:6nЦ'_~-ys&rJojn\>GE!7aNy=#403{>RL^#zqt^(goSRJׯ_v7]@8 |1=v8,2mܖG [xlM NDW}CPI˦^~E 4Iɻݳ{Ibު Mg. ίW g/O?.46{(k?_߾VmBLGdm1]:&Ȣc{z,~Gd =:66 cŦ#I5}'NBHl3`H @dV}H\BA#ktlHcVch6uњ>nJ2*Vl" T-4귫_–ANkoϜ9,˻w/ʺsǮ6͛ҲY+ㄤש8Y/]N֛A6qlI8kRHWVKMY%ܰq\l_k3m5;?LB[{^:>C`߂Fy ՜N}EM9顗mZ1E{nO;\؄_B+ѳ;@>X;~Emc umIzrh&V!֍yI޺iv-Y7ZGv4[ۖ혳ڑ.JN? 3`h崐K{v|ڪ gkCAX3ZY3 U#͇ {*bvJ9{o\OCw BwǛ0a‚ Bahh9sxbhN祋#?Wsv{/@’$K8ȒB#`n</iY 5wUDtь2mk׳pQ (i=uN5 I g䱏od-[٫:t[fVV&JSs 5;ZpwV{{ݻMR%;Ww{u΀B|Y*E ,|s܋:C72̫qݚB77]}BKvo癤jӶ nENIm7ٵET>=?xsQ]@5K7\ K+܌]B= k+힪lQ=ܫDtzEP-P%Zj9;;ת[ə}+ŸVY+, mh6t˷:Q6ge)-WOC!TABamب;SB%I$/&eAj5ߧ%\yVZ$!Y~u/ѭ]tjBYevF0Qs6J9ŦZpڑ5r/鿕oFBP)eY2W/? Cð,վy5&,=/=|]V2lAVAqH`2l*\K$%$<Σs<~7"SsǮg/[WԾ0ֳ_K3,WH& ,70IAͤP3&`\\9(z jQ\p(;wn~eP'd6N{v,،?ApE|*}Ϳ2|jmG=,gx#ӴjY>*m z00c/蔷!)k^H\U!7ߖvB'8-03 9R՛l*Ji/Jѻ|7r7HN36;s$k4w$%U{=׭q5SppI憒 fM-CpU5W.m;l*(whP#㒖Y9$ |5CGSe u\R];<|~(53fhͅgV!Ԭ _=14Ox-W}ccؚNh1bV߼Ѯ߰k >;i__N-eq~ۢFZP1~b5NGfhL*jcYyp fJǼMJ4Rַe^|)n~Ce%ru͟ڳJ}MLb/$FJ: eӦׅ(A"0!n]SϗejɄ^9Rzپ븚!wVb[l%HjǏ+ם]X^Bw}f)/{z\lcʭ|T<.Nݿ##B"+й蚛jHKVSBN$O\G~!T Ô["om{ZEB!~]cFM+8|]= _ȣNN+dN7F/7A"5Tt%B #pz+k1VU!B!B zt&rB!*?ew2v}Lc;D~c݁//xٻIJ;Z7+d3!BJe5i3FOV7#$ȿIy݁@Fsvm2&34棏 G>xFF#^ݽaeϲXI|SZs7uaqw &+YBo=ޏŮϬ>+zlՔk4Bb+Ӿ^me|Neм Օs#ll1w[_\ lu+ w bgyEփz|bbb뗝Mp8700(4;f-\SY= [wz-hye;sFjUvGI&Mj4b8O'W4CeߺNFszĭa|ex;v /vY6ņO+ʵĚ6"N;fmՆ:MiaoD$#Pk4kIs.\50VY=GžM[NL2YI;6o^YbWgVg['L=)ձNVFKuc?޶i׭H ݛ]ZFQ& VZcloaR.=M;+;Vl:02Tiw*$0YoN^do`#^i*7NeɶAa bv-oAeףr-܄O?.w^#"2eˆgNTEHWJ{}S#{.CY75n|75$o|0$U 2}nj$+|i-^%ʀ׷XNjW8xؖ׷PvE^}Ϣx.mFLȈvV~ء;=7XU?A^.^࠘ԦMjN.j@Zul݇>|tLC>l7d|l]D`HUN7qmBIdž4>`5aZL>:$V߭ŔFƏJqVl" T-4j%=)_8~NJ:ºN?|KΩxv/5tb;yyD1<{6t̹U xz=L8tܗ MjTq-|'s֘=vjPEۃ[P ff3m^r({a_'g7] ]5;f_07u`n^ql9}VʦAݮLehq (2 5뿛/ÆT{nkDYAFͼ{Zoݴkrhn-U&UOڏ^eD>85Wi " &5(>Ӝ5,J"A[L{uwݢ֮:өopϊ;݄n횹n{Zraet읳CT%ܰq\3u2 p¶ 8u̙3r{\(HhVq1[=y}#ҕRMl&SVQʊ vPm8{E_+|m 3 n/[?rwC3.Uy3r"4eṞ*dqAoEK5R q3(87rd<UB`,<-)fYGoeZ k]3 4ݡ=Ŝe=f \[ 4 32iIMHP3;l]u~)7Y#Bcc$IG FNr+׊]5ww)v︕6I#6;~L*":|O5' ՛]k:]S%ߓ*f1xQy{;$Uep-vJn[ϼɮtiyK7&<N=O+EsnNlY#l$س1$]'q} @ã1_Py|ܺ2aHjKbj9*eJC{6Q'<]4c8xC6ܫY|w\ޞHJR5ݪS`q`"jXZY~UL^q9i mHNzI=F~+@٢fm{>W37pKٚ`P~tzl:F5 Ob吗tPg܋MӜbb2@M_%JPdR3iyZ``"ǢcAlϗ/7Z`%2eûntl?|ff@~pUۺ$PY&mw-vxߝg!y-w-q`^= /W`)5%ym/ 9P>vJHc^|˓|F2 VUf\q++1%}2<5=  nsՍ!#>V+w9L5Q-Os|sC' ) psBmZvHD'"Š-׬Mֿ^.]:5uH ׂ8ir'/H:I?g˖{MHU:IWD'ON-[ԶYL 57#\ܔ.Lv˫{.Ot_^} nV|\\TVh׬ujJVSou[<(n92%rec۪UGҘO仗B:P!_ x@G eQ3Z5?i93{ʎgfM>_b}A˰l 5tdQ7P3jѭ,b݄ {L^ZUkPa]:o٨WlȲ,_״LYH`~"μtyں[6r*7OYgYφ7=W=-;Vyt(vJ3OOS3sWR30 UtLdCxog{cPo*<afW) LefXΘˌ ^a#qJ E~g7?q/s!6$WsͫBsg"ڎ֬ށl Kg##eT2} ΘPos&o8^X<_O۷o/<ʦUmTIx8+ L;(D\Mf4jszlnoOqZNQz/{VR^~5݁w`3CngtZ8h5]u}8qMFڪ?:0qb ܫp͸$?̆X1y,I%@*. @Y>Gq1[7q˖vs-1]Ss6JLzBY\H\L89\3շԬ>Iϩ5Y_+SfV3e|LhActp}SWQJ vf93{OXue|L(}kY\ +[#,5v.jB+֢]/þK"# }z;eIGV:woƠZ^>͌8@{l:u߂fcDZz.fh{k>0ODۙkrs8Ӿ%(Yugk*Q:<ϩuN-yŬ|sn?wORSVz.Y0yʍ5Qf9P>w~jQM 9lk{qMԇSOTHL;C W_P>ʭۢG;gYcŚk\1ݏJͲјzTT=e"ݵۏ,hUeTQ;Kn~Y\e>"Ta"z)Rδn'XeS.s jCY88ghy*tzC;ĈZv)l8g mͮ eӴo=esbn3Amߪ] Z|.s'tFSƴG"7\?kkZΪ5 &`5:,RKyg\Jn]LIBEn#w[?osY㯉HS6زaI1npq]*_ggb5f\ kX11@-cv~s&puݺ-޿e\=oZ1lhI H jMY=|Qi{ӻqd9IjZ{Y8Klȳ%3R}Sj1,{hW.ݼzy)GǹUCYх:KWDku6,?~477Y薞Xx˿}޾ZĺWtʥkpS^='*wdz;LIwd] wvh#G+u[8Έ?~N8o$\lFU]iAo$zuQ+L.^Ӭ +}k̈7~`WOc*s.iAow\N@lG3wiق@n.ӂxB/NddDwN>-?&wYsNE! NpC`"GYK?3BW;B*3i -[Q,:ïͺzgRo=3_}PPy(;/EUZU"qd]/bo?ԩUO䙡7Yv ;I@U#3)|ϻ'JY[nCkh&Ƨfï8x P߾fc{dpdCuݽL8>ۿr[ai _ϥ#}d2_;rϧ: wgBղn{i|wl BA|ѼZc~q!60+h4~搜W-)Se*ȃ oΝ@dd_)}6@Yٌgɨ>eV[㕇4otF#trI3Td?1gMѭW69c*be^l;rq ^\;Na#-۾cVmةӄ2BѬ%=̹@pLD ydI//ٴt I X2vS;IXh,oJue&ϸukX:ٕ=YSb%Ij 5j~f拠x WfCRe":'LFȓ[H@x:Ѩea:ye!q"pi]FfuWOnYjPX@][ߟ۰rW 2SFG)}zcS @fmwjͼ9kѹWhKG42)*>rm8iPpb^lOm8H4YI[OF)* {QPeҞZff!744'DɁciݮq >3?칼SseR4gD;wuMG?4DCݱɷ[I{nlͱrI>Hiw}{>՘+ݶ$n-9OH廧,pV͈ЯU9w h^:zP6wwΖNi[1>~9Vٯ jqj'%`Ea]}z׫Ȥs.K7Î{s;Q̲v9M0r|s.xUaC,s9^sg3%cj}6lRmcgQG^/߂Wgm:/w}lǩR̠^vTGjs'wIBU8q]TY1gN0 sWjjBYĭmvXt%6'x먉&KJU1, yܕ%4^UtCRƋ we2t 5(>Ӝ5,J.m<4[tDg ? 'M[&:qLm̸L# .ibɍ:}DdQÙEř{ˆ\i7fq}G׭9ٻ7s>0fKY"o_7wDߴZj,WS66ꦼ_fIBnv'umT\(~S]J]Vu'mK4Ͱ4m'dVT>( ,ۮM}4gɔ fJ)ke*G\._`Μ,~לMY\Pp[RMToC N OLڛ'`5* v VE⣷2\RӵlxDОbNc3y-M؄OЙ 4ɤ&hi  !+# t$[<$i<ܢ&Fp,AƳ2%-j`WT>=?xiփG#"/2qL5 :N2'wާ.Xow|}YeK/wݏE y#yC!%W]۹N-wujS:̻,vS,oÄ.o>v1YRhLjX wRc츜4e6z$@ ' n?1\/iY 5w ]Mu\xw7ovדwsuJcA9f߭!KaR}:iO}m*#tRI.50VTY[Q oA/+&xеExgߎ tzl:F5 Ob吗tP(܋MӜbb2@M_%JPdR3iyZ``"ǢcAlϗ/7Z`%2eûntl?|HXy MgLVB Us_fYRڎμ^E@Id6_eJUFmQCrR>ߵm`Xk8ܦoD$Ky"R b9$YLnMB} }@V]،g1`w/ d2Þǂ@ŜLN=΍S={k.VE^YNAY߲߸?4kiѩټeڶ<;>fe޳Ɏ}yur߅cY}be%t1_CZ :R'^=QJ$ŐBF; OXzٰ U!-rMjg^dmݭiS,+(_,A2-&@"(lhXpqk!Yǧe>h޴=-;B'V'k L_ɑ)NE4MC]J[ڹҼigWsv?߆mlGʠ^aG686'x÷\8j:+ JEO2biş$)6 T TE7JU_r, E*Y ZMNNeHu]eHs +9;w &d%dr껴;7/r/Ȼ!E:\MAt 9'-!!R3z,ӂ8Vy><;C ä I՜_")c$P yŷ<æ3&[?xƜI7"Skuq}fGn!-ԝ^j$;[`TUXi+}[ \9'ߏ8@(;-zxeۙY|;LЀ2HfXNUY@XIA @k"R}iĹ/.[UI.\XqrKW0˟%,Ѽͯ2xnrE1l#L4 ~m*ZGܜ5۟RdUAR6VZ*~C^~؜׻=_nhWbwG!3:-4u."Éo2V%@!Eб!K,O^{.00Vfo&`6ZDpc!Obd,W1X6M-v,k{/Rz {0l%HrE[^PbŮzfIp-W$q܇od.5/"rFf+quO4J1 !r|lٞMEIDATuϱ<5#G/KvB8|jOU3vn`!*)ݦ>{uNl}k4WɫR>+l~RL4~\3.mߪ] {ZZj;a> Rݘzܺ5 GɀTĎ`9RP|kߊ[Oɂ@ϹգDe(b+fKl2/96.t>t"w$.mIΏ۽js:TxV}V,/Zi%S;s乗p .Xo[W,"gM+-Y= Z)'\807ttzw3.,')2ݱ\Mk> Gs-R{qKwΟGjطf2'8m{.uL߱[۫թcS;ȘtbC ǏޙkGYYΝ;?7k{ }a>f?&_q k)x)sug&֭WW.*pd^o? zo=o84Wt-sثmLS4M 4g'6g]qȓ^uh(J_QTPɼH%)!~Mkv\O?I:U\5%+eߒn97jܟ"G2ԯ|*[.A^敶HqkzwGLByDγ̿gEע.(?BS;Ϡg\UJMg PO$rPe5~ʒ(xгg(go!~L_%M"=Ѽ{c|[y$;ͪV#~6gc@4/VV>!D0т l~`q&[vS*a6IJyG~2Ƿ4džD߀(eej/"В { e):3Ķ.uYc%iO8.y6qȎv'z*X6' ҽw,=~?ùU=x3Yԭ7ѿL_bWd^^L<=k{x3׀rE/O,z|x¡IܻW$*@ns 6`Ä+ wlw񎅭5ޮگ0w#>OY<=c4ZM;EMe kκ Aa%^.N~ĺI5ƍF0wl{qD&+sjoҘV܅|s=^.\9ׯ_vv7 p8700( (xkV'z5Zڬ٘c!Ȉ xFro/ :Pc.~ ROk:s⪩ׯz{OE=1痿!@SQfP /7Kh^Huaoz{0I41C7iV|:zǤ*}{Dǜ5qGsFX&_ٰ~$ގKZIuԓZێded`hc%Oؼ{ :{ &Smv݊ddS&h6q*7[U[}"x-u 9o([ᇧM:%} zuEŔ6mڔ> 5\;};{~]uƽ j~ c};/xgˎAsM0}h) ;xq}fn \Rk[<slMۼPh>=$^_:Vʱk&O<}t.=ҘRԮo`BH>np5roSI{kSy+UmPPsZMJK<S0܃qM'*cC?E?¿H 17۹s78zZ Zn9k֬ 0ThWF둎4ק~DTiѩe|XO2.Aq(b Y;taq]Y`VJ[ ގOC0[ Ff'۱[Komp[΄l-l@ `ΊC:@@譥3.nBFz:(H,Tk1rș3gVREgmXV|=ىөQC}/a18,,T8"_ٵZڨmw62&xMQUˠ-1my VF/-}> ()pXi'w]YAeJC@%W% Z fmѭV{Nz<|-aGĝ8Yg/ (7:pc4:5ڞ2~\]=h'S7sҸqӞ=+ x~zXLĂ KE5PMA};9nfldD oд P^X礋A`,иR4ٹ2 R A`$hlX4+8@l ?[Mblnf%4a^Fd$.7maMc|J2b.!.XJ]Ō7抮T hll{*tQBcKRaȴMADvպzt^pi[(}!Ss>^Igۧ".؅/~s4{NF(.eYZn]ښ/"Gmleqw"0z81,} KGY6 jNױԁ+dMdA8>|շw -J32-s>?¦$r(~yΩB!  0ڬU1Z>QzreXʽQq(K=Ϥ.z#eEs0v8;qή::ٻE } s0HUV8hf >riǃI_Cs|~dGF;xƖn h1PNz%,U֤!ˎ8fKg.S[Xpn# Im˷njɏ0@ݚ,iA$z7b@ET+Uα<-om*\+4Y#=ݛ5>ԦէZӉGPQ-"OF?/.oܸiXb4n=?J4 7Om`_{1A?ܺ2),P1bsn:Zyb!o,{m>Snt*)Fj>\X^?;dVK^i(B1)ٖ(e#4k4Y#\b$4qk,{mmUЅf{575dQ+'-|gYWo3&MY{E8ϦcWV-;Fe r8eLiOoJ|B*4uѠTdA\Ҷ9thY55l;)aABPƳ.0#uXLYvzt`{?FvB{oA>jٴ{ m4P徺nbD۹ZiAB1 !#lv.YuJ`z¡RN8u5fܩgS_?.*WʆZ """x=fJSH0m_"[qܫ Yk{Tc=)\ROs9+6n"bՎ S.+=Viz0l6nڞ ^2 i'WxlO# $΍f-aJL@0h#O}'>>{^sM/R [Q%<99 (P=~8]^D(a/_Hj(Drڵ djbA""";OK}54{v%akfFzz@Au Q@.TjS:EXVk^޽z긨dҼ9d25rss#"22Is#7yAeu )(jOMO"5kTJW)Xϝ;?Ҽ˜cb kKJF4/w-׃R5CϮEWME% \S3?wH$"e`0 E Ar5/%#""?%%GTO8R5N:i,_U @^~}HwΜ9Bŋ^3g|~E<{Agͤ7vww4!+yƀRPP|3(ENA}QWkH_Zu؆H$ZBBB4onߺЧ:}AR/_իAޠA;^zU]O,J<ay{ :2kGMuW85k$AJsRC[Nvvv,)5є[7=+Է cd[ c(qO_\lܾwj"DȖv h&ɬGUB嵦] ,pjuݺuK.L~~>D"\߾u+0 >Z R,U 4̉Pl|Ik\w o/3VʣV6kS}l>yY+X1R_,5 dwA,ʩ\ZԿ|εk!!!j]x7772\ ^ kNF4nͭY=9׊ OOL?>_VVK|ϖ5ܓr>hyBWe/e_"ާv,E־muwq{~zaù\ oOӚh eWt>ԟi8βeW9CBB eͫDS .]J5֭#I&s]S[j>UR\\ŷuN >h͖ʒر[MH)VƑ8$ "$!Į$`i1B#,؅QgU0x{&soێcjKm=jDG}wwmfmld¦Z{o FN,AN*[d两עnڬU+] ?Krյ3bum5w^F>|ҏ.E4=soXyX7,Vuy;ey5oJKc*9#"n'PZ>[ 4iȣ  uI3}ֻ<\oݓ|ZX//?0jge]:a:ߕu>?1{䖋ׯw eZ.?x%T>^֌*ٷo8p` 2%K<..Nߺ59h%\P<~8%#8|N zb ܊|TPDfÎr `Gr|'ƠS\ _腫k^4h |%Z2ފ۱S[{4~tFCFqAWg/r3Ϊ2X],Vϗ-Xf)IE.b׌C&f_j9]lrÇk[XXbr9"7'{{{ -[2gΜn iN֠qqq5jLP<޴x~˅,߻1eA*&^ qTqG|*ٳlumuk[\:Iepd'}}&o u=BU)0yc\^PɣR[h1f/GrL\إVs}gqoͿFcmG@!4ZLbB+ݏiUzӕ?2[wJLY|h JaA^R ᙘ eV1Vq n N)W|UGrӢܔon% :x˗a^[jjU*N妦aW)ʐ|H19)?5Ҝ׉AN?{]&:mս"j6oώ[wi[/?s!,p&tUAj>tҹ#:8 {p>yԘ'y,k̨^(rqbYwg'OAhۨgq䟯߼ tHQ @jw 8^Ne4hH3\^înߊvbpוeA઒aQI )"'H;j֐'HADz,xЅӶM\~!%ʿ ?Y^:M+dIpFFF||#G y-)Kk ?t&VKs.߳wɵrA^~Ϲ.&DoO 3s5sr$^zf?.7maMq΢8WR" g)8 3f=(S":Jz\h}B ;L5>d ^/̀]uVMa.l(8%;|I݉O|_+lal-|x}} %W&_q!x|#Tt-\4&d4#xToE4˿^#\;qT֛ ]ӦM ֭zZQ\8pWwZv- H,FܺÇ2WSQr^!C"xރkK #Ϲ2뀸c|4.= =|m/a~U@ڲV,נQփ}rK51eITB-S,˷njɏ0hE-PDy=goȷ]Ѽr ] 7Lmr;R/;,ox(˫/=#ѮW+oof͚uA/^fffԴIu%I=Uv9s9rիW+??ۛl[]ONzR!~wB ݋gl#'3.%93Fl}XGVeoN|s3N|;mnDPĝ~o2%/4che!bZ|h)ϯT`?  M: ┗ظ_kV KQ"͂D#Q֌ϊc&4Ϋֶ6aӄ mpc{T]}QTGgͧ.0kԖL_cc;b^5hW3hW:>v{@Zzuex/Or7¶lZrmSY~zYX5BS7ʃ믿@mrт6`eeeee흐p"##7owjGs˜9sNVjժ׆0L+++6]޽׬Y-y䑬áeJlKfh>Fut%?U ¥Yo8PL<'mhc^8m6oJ6a&믽+&X&~3(ͳGv*F?H=/ sY6߻%(1QVVV߻wozxZزn'YC[)UH +yMpئ]-\ZlBGo޼pႛ1y_~ɒ%]vNdJjժ:kd2:::r;vX0,хNz?mjjjjjڦM2wttxB6r9 A(J?RWswС ty)]~RgC_b1(JhU);ˡ9@%f#rXYY̝;TISHOH9]g=KC.NOMMvZN>Lk0T*  C,(iW!jʸcMD\.bAG}uRPPP)(~H?99rjRJ/\8իW=}ɓ't&tuyXHR_WCYSP{TEPdfGXXgSľ8*e{'Qs xáGnZe:pXT,&Hx „sҜ7:::*Y'&%'ݼdӰS##SjW6ݨQFEDD<}СC&&&G~Bx-hX4XZ󕲤eNݫ,_QƮ_bM2¢w+z==㶡#GE͇C {h_L¬S*9pA!)|ܖ߻?u2˿^z HѪE#oCg-gs U*XOO@˦c(ydCe1A`@Qg/.1vkV#777778q"''gРAn:=a/_F3R@-ҁW"ǿT(˷C!hRk>5^EIc?yfԋsgQ)?8n ù֡|2 TҌkZBXf͝;wGաCI&U'tUAD|pb;CCa{Q2Y6{ʟ P* @pǏ'ʻMcb Pfy5jKUMyuX>?d ku}Tr"Scu%R3e ޿mr~3/v OD$m߱m q߿oժMcORnK%NX.55k<@Դq7=7Y2} &*gdaeiį!'y~<Ղ M`Lnim.~wjcOeP%!Oe٘mЬ|OjÁ{g~ߐIFwwpLx,ZUoJ D۱WR561 ͅ;O|P3t[6uZ_7 ăL|//oiE$/9|r諘|ǷtCn;0I \3ghaȨ}* 0`@;wn| ömۮ]6rH2V"œyޞ[_|9vf'd% (9^'8"K &f녿N% Pwhtň(;m{߻?k:,>j''h4>e+ѳol<Կ>w}ش۬PBcst]U4Y;JB$-3l 0y -L/oT |ţl CiC_'$$,\l#I.{+Wfyz^ kzpׂ E7hkEsێ_:U?܆=3j`y] gpM[d3ʁq;<p!:e~+#4UsdE[]-~+m/|kѮ&~t% 'vmw'HH=uo[#1727^2oL{O^f{vt`FG !lOk%w`_ݨ^R\-|NդOVBqg9;k"Ke5%m"8sJիϟ9sf&M*/ݻyΙ3͛ d/^l߾ߊ+߿pB??rWƜ/@z s0̴\_6E?_4?,].&jM`x#Pup'E$.7arYZ::C+ ht57sltQQnzz\.AwNXTgl9C|sztO @x dw6}BW;.Xƍ5wߏIΓ f.u\$GO<Н/߬çwI*~Eo`Xs!>iƞ:귥~3>pLྸ9ݪU+{{{6v 2B 9[Zwlb;ϒݞ f-B? )׋o$Lx<{l~}iF뾈bn`d,d9۷oT* Y;]o9yu{^qZq`ZtИ3'~qEJ ˑ|f =0mAZfY)_[ucR_H [xz|y̏\MlFoT]` pIwv޳p94Ak2a n+ ǯp8cu#G6E?/}m=j<'4)tٜXX uQfE][p-{vXd.l/~\ۦtT=b \'OzVϘxb̅)OGhww\{lء><qSDvM6K UBeT OŠ೷F4=܉ׄ_ﻧ @|yϝ5Dϥ͐i{8PT̜+Q'O6< TQ6zr_z5tWٳ]Ξ=ٳo߾}:xM6O:6̒[ >$1j9pJYІCpQ݌TQ&PbCur~!W@T`^2Gg@i\|b22"eŅG>Y^03g΄ykFfp،BP03wmnٵeKϯ?J{oXNL-E)ǰdƺ3静+>kzD7ii@'cGsΧO:99&&&eddԉ.yV}V_2Nϫ̉My+ o.͚50#;|'E.?p8ycϲ#~ B2H5gći*P+r08:"!i_}}&og[R쾋5Yώx0c\g7#F]+Nk]Jpټa7.3 f0| X\ ȳ\\\fΜYG|cǎzjOOO3f̦M&Nؽ{JvT4M{"U@A~]?+P|v8{X1T(}U{pW^ЧQdԸc٬ث*KQ*rMj_,`ݲe !,,˫Z)1RUnL˨n;/Oxo5_:&6K%MHt\rgY3 Y"lo߾aÆX,VJe~~>F#"== ++TT;} " ~Jevt lBB >tC+AHb.mrnTRCe'SU[8U:،p"iTB_~(&,?+гӇb웝s +qæ*K`ٮG[_!Ϙ tiek1Hw|'s55F;Scѳh 0h+b/cq 5:uқly3aE-[ IIB$ \\g73R!4&@+@H@8&ZYj8}B Tfy7L}U̖?:p4;5m`l`e0'8+ewsT?X"t dJЄfzt<;[+s._B-G&xpg ^TìTא*tz۶mϞ=[M9NiӦe˖:ujSLWHg%ކsTPӘӟㄊ@Lg'43)UE08u)iii8ڸ\>Nmiid2tuummmsj6᷇{k=[ 8#t*츐jШ =GkFgiKae &BGC{l8lh'_g;{g'Sr<& 7(>܋*"⅑ˆFW UKy?N@Gy{h(B'_#]D>. *4s`d?{s_݋Fv%g(۶֮&FxNz-o,?6&5-W2t4hРA_K>ZV_`U(T?)Cf DױȜʌdR@N%ɢt=O_#ȎQR?rH-]zbZށm uxFk5"12/mt. $:EBhJL#Q |=AUJ8 AAhj~~5s Ftt4XZZsE5.bEn1@X'eeE&*Duaa_޳+o%֦|࠹dX,XnRLHHzy5X(_zʕ++: ij,V zߨoy1U*琾w̟5o#s2;1Cǿ^w<}Ψ<Ⱥc3[;-݃-x\,s>x=ȋjЩJ}]lގ)i>:1mW)m`_{1A?ܺ2)ϒXyb!o,{T5U%[G6aEjDŽ'?S²εdvU=ٵ=Zvuc {O}uבINZaVlEݡ6t322j*W,/˽Att7BS*d9Lj\ˎʶ#s%eK 3-gȚAG9RcؘdJ$32 SSSSS̴4c5kp8бCz֬Y|Jb^P1ߑcgz^TɌ}{=qy -:N2g54a捼MOlR Ϭ=*ސn}7̹l3m?y(c˧mȄ|& Xwx錃|fe6|˺:du >~iʍ^U͚_ی҈!Xpڃ gH>PHX9a<پ&4Ʒi;ypIrl:W/a5pj_-AfnX xzJn ʬ7}q؋<\Қ^#sl}f#V jeY pmXDڱae]ߣc8`cŚ[/? :NiR%TDX^yZHZ[G">>JsL"Iyytsz䋊BPGPVɸo-[vUa_iذ!000('L)#^q󦳳sbbtuue27Noܸq vcԴE)/>]r׳w1yI'^qd2tGnңv9kffիW+oD"IMMU(f߹}kA#﫤TJuys2{v%aϩޓ)5x\jo޳rYfFzz@AuNr ٓ+ Bg0"^ܿq(V_jf]LLڴT lb0j߾aff&W5]he 8,vL\>F[ۉ`2cdҭ6;::ɩT=:::ryay\.rrr=ڻO*')7v\3*Gg)(~,ws̺tA8"y,oT1JS|VpP0 svv{nӫ(_#<@SSS lcc3>SKK+11,<<\[[[[[[ tw;w}<% u9$79ύ7U v):{|EEN`q.-|5APdfG>}8ʉ}q0$TˌbmF!=r]vᅢ!G%NC=0ˆע+LmNߺu̙37ƠOrurrRTyzzV_W1㸁\.׌&'qFaN|u˖!C|Eߺez 'zzzl ,(wjNkKN-FE[3{V gi2c$^{ j X~ Z1Ε] Y̳oȋ~uV/AJdLgCzIp՞kRya)@ 8 Bf@6_خ?Hq[.)j\m@߾}RqHcj%Y-EyHRyzz*!!$ɦMȅ t]UV KXyvXru͛7{Q(lTJru GAQDT*=R9NGQL;hJTRތ2.1tb }L+쩱^*bB3^G8mڈYo&N"K,}({&7ZuVlڭVn)mW*cBo?2Q' _ֺugQ3Qw$U(/|ɚ5x!82Xnw5ukffW(^;:? @SJ"\wBy sLj# *\leeUM"Xv R!=zM׮]5W`ƌ{yyyyyq#$2V/̙3333vݲeVZiEI|v0,77WPzHyizl6͛7ɑ5200h׮-abʕ+}0,$$r*ɒLMM ttt )) RvLt[MR;nhdD E"t:A? /Ry5IKK H$ t#GmrMfloMṍ޴|<[ݲmXzDu^(~PJիϟ9sf&5mrKo[KNokBoὬx_3~d̸0@KOf[ȯzu`YIOztB4͢fZ9*W@ ;:4ko21 \?#xP|_0 KIIٳgAAAϞ=Gh"2XE%r\͗Xk2bWd L//+IMK4!l6 gϞA j9_ "?={6 @$##cܹ ŋ)))ׯ_W7AP\.rrrP&(|1R8'q\(ORӪ ~ ,,{5z,yb?ڋT /;,.P @q0|Ϯ2培#VǷ_kZR*9G; `;Ğƈdw6}BW;.LaЈ\n>KJ`z];Ė <ε;/( ܸG_ 7c Á{3΍ j\۽W^HcLokY )c(~۶e .[cʔ)UH K iU,'iPy -)0D/&x<ȔE}g1'" W*M#dbKo}t;X98A( X#?}={' M^72P(2xгpz;QINNׯB6mZhԩS7o\D+P};JRT2&KӴiնh P(hs={vذa6xP(422ӧ|Onݺ1cԫ?>mRf?^P8rJett4ttt)UG+d2---PhiiIK.PNTߘpOjj^nnJ0`@m+򣟾50ڮkfOvVG^6M[kr6 eӧa_8pF:m\5>~( ~qEJ ˮܐ yڙ RtGB+@"Vdܓ#Wu;:\QǑ bLqhNjɪЗbrW@T`^2Gg@i\|b22"eŅG^ 0LWWO:uڴik֬Jt:n9IEfyTKB"?2䏤Ç ڷoO$bDDDXZZV$'''++ iSiLwf؅+l6+*-ꩯRbS㸎A`xuR R'3:k.'U&v|gz&wM]^o&666>|ؾ}ynT*ULLLF޽[TTDs㥞$Ifff&M藯\qss4mΜ9*W booO&͕H$aB`GN[ZZ_hzJ^&M8::yxx( h,Ë>XvCE!tFDB36Ey$ xةԸxrmvml ʧWily}A###@d2IW[[{ժU7nxuE@~ bQN:^&RpM_}}}򃃃CvWJDFFƶl2))UViiio޼nM6?5jE]^^^jj >}?o޼iٲׯx:ҥ | eAظw^^iN?9rdECk Baܺᯋ.{Vs׃2L.?v䡃'9k͎in5{h(cB7-zM-wnGy*9No۶Q(]PoTn9SgEV(IVPv'EXnQJۉF( z58NTxv2(C8~*95\(_\K!e:^yF[[yya"RAϥ..]zizHJ>\zѱ`j9Çɍ7~h͛"GDD899t:TN֖Jg߾}w%s5޽{d2YaaBqww'7ǢNCu2? xuDtN)Md{PAa +~(ߋ*\(І@9& 21ɻc#9r{ x0OO>mӦM-vdiiiffo>JV377q㦷pL& :쩃PڐphC\WF?<篵}VUy>d;tATv~]m÷{ͬJ[;<S;;7MP z${t]|}%TǗz//HcDݜgldݛ^lU YN^0Fb_^o J2??_Gnݺӧd9yPJJJzzznbbc+'رc۷' jRd0W\ټyƍ޾}֖N2:f#/{6Ꮻ޹]jIx:=)(4)5Sܿ{3#==:39ysN/{r ٓ+ Bg0"^|'\-+Mv)R"Al6 ;v&''D+㡡{fts;wnҤɉ'Ν;G.67b^~]IGZǗ* >IJFB3k#n-"DpYf|bT86fP6OJIWDQ?p.jY^6… FFFA`T*߽{ yyy999_hWD" |>bW\r9H$=zt=s}r߿fUzf9)K.r kѡ(wܕ+W~ۿLlzzzծ͚5+///((HPSBT)˂wu[vx/{ŷR?MwOâN'#GÇpd$;w/ٳg[lYӡՇ`ٳСCnR/ӑ.;nB )((((j)>CR*DQdir55 ך5 >}E{{{/ّT*镤2 wrr5hRð{W,xر}+ԳI((((~D(QE JzfZjJEePШe:_%;Eu!-r4 2?f믿|^FF9̙3׬YS=;v5%%Ţ6mmms6UѣGoܸblPrfKXVm$RPPPPJу{WTðϞ޽ݣwn/O#mJfQk^޻v:p@.]h4Z81JFGGs\ƷJo``-I]aϰ/ǎ ꖣt9B)rO8޹[Jh4~w{7'' Zk]666s  y"`xNr |6(j*&&&>>PPX,\C y!Skw? AB}͕gFx:7qcK ݤwCSJ3PP|-vU/K| x~_Ù%72G4_ש9ɝT9}7F6/5~p:k嚓i. $˗:c$..N___KK̬:uf9Ifͬccc㋊޾} ;vСC힑(]ԠsoaSҽY,,teų6yYDD:֖J]5']߲rňlL`6h֌g~髢 49Ǽo3f&^ xP]}ŭmwkױs&udWx^S?xg)Yci3lx[̛ܳg qm%)#;4ErԸ ht-Ȼ^;P͹ ys{vnK·LYv"hO1sޱ] ~M^EKJիW~YR"u7ƸiAރ6($[{9APӐ8*Ɗ@]ASU@.JDCO5:פze Ndqfur p;HmlBAD=Ϲ6 Aww9UbB)JM5=z[W_ FǕ:45{˗iiii&_ð޿fc++ƍF%''@߾}7lؠYRkqE=SWhՠIۀ!+{^?WGުELr3YNWen֯}-Z:|S@_ޔӣ۵hѢEi8tJϱߒ E6vr?V=.jŽ-dI1O _ѾJژv5 ׆>wp˝bA}I@p ig_۴a'xh%[2pw3Ғ;=~Z}ے#}C[*q׆JRu ךoiC>n<9%:Ëry%A侾Q6EEEӧ͝;W]֓ ׊Cc?2}?֍|sE 9g7_hJYzstS&@i,h`[& ,=}ĪV[|SI[&lhcGd[Z:ω#M ݿeu6'5֢ByғJv~ Tǫ%l}#`=QfE][p-{vXd.lLÊ3q:Z#6}qςq| 0kl%;j0 ,D?OQ.mƒ{:YϾ7<[BZęb˲2 B槟VDSQK:|Rs9]dmDz+qro^3,rNFiqW^ :tiP|@g 0F./z0s @AM\РXyŻ #7\2vzunEViĜ5dШkdP%?'FYhԠI/rc#w֭}-KVXޥ@v<+j-.׃R_/^|4,P^KY-NT*p8׌aZ bl\r C z͛7F%%%eeey{{oڴiɚ)]-Aϋ LYiK--iں8ȃm_a~\ 9CֶD|;{=! 0gC"{6m?o#'o;h0X @(H+VIKhx^f1+L/-#AKψ U`Le2Nhw<)5?*.UHP'T|YyM6Ac9]d"*Ͼb#` F O ܐ BGPxg\Kon|zi,A6rWk! m^n =Ϟ68Ǝ'Ewyfԕ=^c̫Π՟RՁߘjk8'&%Y$O>uh7m4})SB6]Vs\x捏Oo<}}}K ]A ۩81114mڵm˫_6#Vl dr&:@YqiTyn>zp[/صC]EhtOpF$&IC !#V"FoL2@QzaɃ!IX֟~̜'Zڪi9qu(O_% x"fږ&04;WFUAj!\.njfw'euPI_XtT6ҡ 7qA[j[fhgNo۶m2V)abfk(6c:I]#`#noyn|bE;!aҺ ̢na/M夎ZQe>nf'RU&~[\-5!q|)ԔL p\R)-RH]̙3f2\.TJbho,r龍t:i׮]\Rh4Z||޽N tPۭF̲ \=yXgȡisz2zx+ZҀ7P߼4-S[smDža?Rb*yOTH?wS_c~mC`DŽkF66k2|6 @|߾):kr@ѤA^왵Cwm7ڥ@}>TΛxŠCEFٳ3ˋ'a<H@QT[W7>6֮"Qx\;o5oE,/;TfffL&bLLqPUgooou4xz&&%9;;߾}{СEEE`l\\\utttzBBXY{qqq#>떨ׯ_߿2)exUQ o$coapK>m0' c3"V5ch9'CEm&nNs<'l!6m'oٺ$9Qb/5!Ͻ`5&pi~V䅃p@ BP$r` ? IAuZ8u8j;wq\)W'G7|M᪵ΐ2 |/3́ Z)s'+X"͍qYvݓGdG8ЦVvu;w]LУӬ }x?N9zFm"xUJJıdgWBû\'ݛ^lEQB%fZgW4ruƍhn݌Em[VT*߿W qԛ7JR&y&###x֬RiCCC7o5N a UL)d999ׯ_ ;qQ---tRK;oU/HWtw.$<9{R9e毊޳rYjȽ>_3+Q7EfFzz@AT't@BAQ-<ׯfH ŷnRV3 liiSNsE"YfΝQQQ0k֫Wps_K$DLeccm,pMl!CuvG"\v ð˗/W.^ &ա (R2F5^I6=(9^[>>gΜQ*-[400!gff&%%D"_ ͦ6y5Cÿ$ 1kЙn^J 9@%fy tebbѡcGmmǎUb|>tM߾{q={LNNpСCdD~DDc+1 S(89˦e$ 0*a7)(((*R8R8^IEQMH#ϨKzюd)))=zzF<+5{ iLXEem;:k{[Cj>JL[^u벺\RXZZvUR?~\[[;//{ZZZ[YC~(W˶mX,VTTH$ e򜜜w >Ȩ(11QP0 &d2[kRyfˍlD8K$u:**b}}}<9ۨfg:F((((~YD4J:ydϻt-@*^s07!/(zW U⬂ LVůԘ$2 ю9>KPdfG1u3rbd 2cf]}D[n&D###Eqvvvsuu R׿ǡzf9>*;w(woߖBCCCIwލ7UVZCtwsSo{RYPP`eeMBdJST"HR+++>AD"H$mVE M8  cE<r2|`tK%ͿQc_]7檮ʑ氹NZ_i,FWX"'TŬN#*rL¬S*9pA$? B/l̟S$-k{'(xy{x[22 P(D "%%3... 555--M L&ՕFYXXw155%6|8ܺc'!5zaa۷o?~ 778C.J%%%,okȐ!|gguKh[ZZĤFGG[YYؐɒQ*83LSr W("RJSӞ8俏dɀ.m'(34ʐX?mj&Jeeų6yYTҕ"l=s+K=>PeticjuS']߲rňlL`6h֌f$Wfn2Ss=@QPUʠA dV7J)}a h,a57OM(@Cn^q|^QfJ2ֽ2=Ǣ_{<%G<q\J04[/sB..C3.FDFistPl,߳{q㢢 5uԩaÆ:u"KA#J0>?rԨvuʟ>}b%2%o>)ˍ )?xeG`0X,n# ܯT*nҸfK*Y BPdR#>lr}jPa̳fO+ypq^.ܵA9}ЬyDpc\277w)*@.;nݲsssdzjذa-n#LVXXhddJR=3==* P 08N."VZ[ITԲ^,*%Рյ݂ Jv>}zQ~P=l433S$1̂Z_ip(]5yۗMu{l}n3mXwek,ʆՇC#rmVgplpЕ;Muf`tN\!,Wz\.AwNXTgl9C|9=i' j\\uR2 ; >,ƚŻ$MA3g pQ.'t{m oSM>;c^wudUU3fq=MD,ۊ!h_0Qrǟdz[LZ ̬ A...˖-2eJErK0 ٳgRR\|vcX\e֝g @lW>k\+ݴG>TQfط)k9vQDL`X@E{odB?G>Md>K`We \D8xm]N^KNs=R$`q_xivv 2P87={Ȩ7BpAn s@O GA}L+.3fgLL,a^^v͋ ߆  0y޽\oJq8T(NҐH$qr, 0aAbg;,\X\\LFt5B-H( ~Zm(]^͞'ok[P"iulCcΜx۪3?ŭ>r+%,GisyizN_7Jت[EOEBU[f~|}g}q~S! t) 0l:8[U&ٵzm'xmbOO2,:qՍtrڸj|PH'8yD8Ҥ[ZgsbQc_4EYvma@\a= p:u LU<[n;?c>0,0h(%>OK\Wrr9@۷o;v,uwwOJJ}0_~oSP)@<[!u VDG)N\mkX͍ FF#|&ЉV3q^XMQ' s7&&};@`SyQŇI~T8qJE+ztvʵ7,&s`` #)RV\HyPѬYW^}ZسgB5keWx8aCA0 Dѓ*(###99YGGٳg-ʕ$rєXɏa&WiA,dm:::$>ժv1 ̔dm?,_ d0,&;ZT*A4ijJ]y9r0o`U*<ۢz:m3@ۥYfMY::e䇽2S{O& >6'vVYS5VAn-w.'DTz0mlmK,\Cw'H+ƶv%ߺaF,6N}0ߛqƿj2V^ZF#gći*cYG3T邴"i46ecr  zRqqq...3gάI}#Gvr@Eb8333;; //OT/0L h`* -:(dRQ\\ߕvv0+80DK8d4{__R+m[o,>]diPJq(g/!}˱QI &LUnW`3µ$*pmn /?`Cqv1U+ׯ_ Vݻw޵ifʕׯ_OLLdɒ:;;/X`ٲed^ X:Q0jÇiLqR"P"ħB)]_{&|4@~ Wi&+'+W4k̩oAJ "JNM'vl@|zf+ Jߑ۷fhh(kooO&AȔ&j\.AgΜ=ztjjꄉ Ů;w钚* utt Eaa\.Gd#>|dvYyرw-**Bf?{kT7877T*UnnnnnL& -ht?A@@ր(B}jƯ˫2tlMÇcƌqrrϟ5+gZv>'0GR0Z}{#=Ccp`S 0Q -Q*% UJ1i,16mN`;uAh J =(E*5x~:tsk SO Aͬ8(Ȕ.ӻXb9PO6:P}'TB`*<;?hN]/n SH?Ͽ:ߒcǎYZZhׯ]nȑd2IhqBALLL&Lx_ )))[YYRuVVZAF[$tX'3'5PˑҜgM^k*)iLPVy;. P8D|y穒zf-q;i G;{aaK)RV[(e2,PWaJ 섄Nm0N8!lGe{ϱPbՕ\ y!ԳE5믭!p@jԈ."ە tE7q#vzv9cΠ) d9ؽ ;P'2Bb^G#&R6ٸqFBѼys$l6wݻwoX^n//`VFL8qݠ{wo=x0GfS'יm&[ +xkۢk}_{OX{AMgo?7)jԎm T۸Dڼoٲ9l.RgeIq%@4zph;8n3,%vnd-Ր@G}Je0ףGR5j <Gt\`͂?YvPc`Y zʠk" "ۄl|,8Ap@WkO^>VK$l+Og;Jr4^ؓM`b]^@M [6GlݼY۵@Hj7k-ʟ\.\fi7PK}+><2qeSϽulmGZ{xy6^ \0jĔKgO؎[YԦ^NsVqK_}a0ŋ'MtǏ:>KJeΓIV$ݬh- 'C"Or nS,lּ3f16*\|ȑ#"<<PК$IVfi7vriadoժ`0lټ}ELmXdʿ^7bȒ+W ^ '(LiӦ B& 4_qL\Et:^p[jZ(42(jレ55H^^^V|-gN,I}F~=)\]쩳vϸP Cv۶[#iUjP\8{*7'{Ͼ5r|>ܹ͚5/((@L3tLGGǖ-[x_'&*~M5y򤴴靝5 Bi-n0F,OIp4(x 8^PRF{-R»wZ[RcիW}k͚5z7,/ۆ(pZoݺ_m8t333yiͿYjmycŋ ݻwx-!"""99bQڡn0t:mMAvh֛pٳT mEReX_=XV#JjƶfaD%Tih9n+WT u:r@E7eʔǏ~|||D"ӧOGQԬP$Ǽ={Tտr˦XIJJ +Wc~~Gs4Q  8|cOZj8G >pVU'Uy.V 58(/U8ʕ+ыm۶Z# ,wpp@KlllGi0֮YQ 6#4b(rvv.wqx(#-9$I9盧:EQJk|at9Ç(GTCӌ9U?}̢E -YٯQJEZXwpp^GbX,_zz>tӧĂ|0((1UDE~ACBthHܗ(at9Ç(nLf͊JKKGaZtH^_,%'N H OSSSb$7D#WIو5= \APttoMn  48I"fS.g``xa95i/^#J PuQrXp@@+ݻ@FGh4Jb/^D.WrcQBc{wف `9* TLjЊbhP( d O䃣z=/~Uy%9N8S߾/f#|CymzxIswa {OEVEypc0 3gNDDDW'I8l%rԩsƍ&M R4++`0`0 D"F -nntT1EEEe6t% 7 ( JH{H#K'>WՐ޼K  .Ҷ8wY髾SJwc`*]Zѐߚ%[ި͈t\~ܠ::dEfrb}+FĒV}u'\M0Ɓ=zˬzѽsO! 3r9"g`xo=Q(ʬVc]xDVoꊂ̶}6ԪUs("F}RN-G{N lmJKK5P$qVk\ ="4(@W%ЂL/lvAAAZZX,1 BLb+S'K 5$?~ܹɓ'3fx4Y)yxi YB|*yYC׽a 4!إeBdy`\nC@mO];BcG_[[|4^Ͷ{LFOPE4Ƣ+~LשC rO\p᩺3/Ħԋp*=rǎSCy`_مc٤Q5B[fUK˗̻>qݏ>9 /P/  \*.333++h-[bbb*m^KtyBBBڵ۶m+HgEQ/߹sW k HY+2B?|X&% EWW@z!i 0I/ˑa촻Oݻ5  qTjkkK8oq1SuyFn߾٨QY9~vp#E?%a7m\ٱ|n$甂}@T^cu=z|W $+ mu_-7{6.Vp/ӕh(i?E  lt`kr:-.pkP7 D}bx0E^xqUW$I&$$&=Je3i۷ C~tbmm- ׬Y3l0 p74$YzJNH U5jӧO$7jh4&eoDJF@x**(P(.^ղeKPXPP`uHB}_rZF?ccckr1Q'\й]hEEQ#CWj4ۣ׍(d:ceR>r :QZZ*à9"/iZٹ|\^HpV#޽ER ]—Sh9I B$) ,{H%ؓR#""P 8݁CgԬiv̌A6ЯU*2rn?iڕotv/>vܺfnmK˦55k[\Ϛ ='#8&ŕX˅+]9`BwX0jĔKgO؎[YԦ(AĀM[ZM2‰@1nWukgY/^jA5njd^l`}1gN{O |kU3ev|EntxTi\3_p늘89`ϜlҬջ; 55]S,lּśn5DǤٺu+W&OlIcdߍgiZT*qPPj\L(Uˊr\.+)/#G8fU\zA/GD#,{`kcsCLV~]7WXLRq<;;Irrnns\15c  r,ւӠ{wnn ,?<22܃֩S*}~nOgN,I}dqO gOtٗ30wX)XU1AX(`0 6$Eaa@Pyr5(-- YYGe&9E^-ƅwqrrrss0ںI%%RiQn^SDАz uBZFiNQ_ #-fY,-z$fff5hЀ'!--efc+ #wk# , ]T V,-_mb9wC&yϊt;sa3mQ #+T1[VPU {T,_zٳgyBrD9^ /y{{I$++Q D*.d26f9Dԑ5$I$99L222\.ftCJM}@à `XGU⒁L8uՅ>[2Lw_{l([F?Z=lז>b!S=<:1bh`dڴi,K wʺu b(*--_RRf0Q0R>qă|}}}|||>suqh-F7E<77bl;;;/J͎aׯ_ z*i#G凪q6Zr\u܀wStܤw= F30|Bqr9w\tZ,ʹDZ%TEزEiLFR3ծ]5kV'b%3+$qLfeeq\ * EPխ[z'm"WyAAA|^&&OCYE`FۢۻRH1c3˻v7|c&Ribb(tmRJѣG+W|weJNNqz݋- BH$ͤKMMUTjXpS3aY(Jh_^vrk uV:uo;aEEE ˃ 30000]bat|8qD۶m4 IRնivrrܹF4y6EQgΜ&Xqc4h#ІlHNN;{{'?~{(wZ0lO>t钋K {ǏؘᑛfffDk6, ^^0YNp݊hذO&\E3OV/_xfYH>}EQ|D_~ٳj2I=urv+/>rsfk#ɶnW_%$$ԪU+))鯿R;;;4 ]h4L&+,, qwwG ###y|IRCaXe)#Y,Ԟ4g2E6)z}EyP֭[ë6|]$ϝ;wʕןXOHHtҲeː7.iD"jJ.{yyYYYݼySRRh:!JRBQvmGGGGܽ{~A'7EQEEEhHeAIͫtp:iYQ磖lXGɻw1(rc}h7b`xS 9irT:\QN si@iiy9~k׮Y.VA;s;\3g[jQvK6E/߹s'""¸Iv qe烖ܿ$H[;A5ζq)=9YJ_&нC3BgOo/g @lǚb4a[7/.߸`žkG>&W o/Z.Mqr͜_u9 xz ;.}&YFrju^< R?k %x.u qHk7YrNLl۠}Ǝ._k/4'9z o!"ֺ3fm~Q(N2zo9VC`V+{Ƒ_Y<ꗳ^:_f68l)Y|?J|rIuK(E1s>; ncն;絶3>{׍_Քŗ6.X4JasV ?lx>ϟ[fnnP&ƍsܳ1keN8dN\v|ʏEek F30.o&KJJp/[H4i+J&]txy:'mʆss:t@ZxgΘs?_C]Č_D[c9ʱ17 ?N|M܍piYߕ00'6)yjGEB\zzfYVXec(80ᇕҮk6 Oɮn;9`nlhH`=^^k}vA\%W/yI'GH_ +AyrCߴ:s4u'G.V^p1{R܅F*8&ao;7~j…M@qټl%$Ie^hwM*+Wƭ[0 CyS*a'ND3__߀TaM@.Kգ(J(5ZjzHTTNNNDN+r^o|TtNŷChhhVV֜9s"##njcZ'A1PԝG+hôSW.oH,h̶v +rrYnTCVk@@2,hجS_^Uoe܈Xr۪^l4AUƭw̆VL˽T `V-ӷ7*x1I׳<WнrSW[s$7FسҒ=m.S<,5ޓޡzE;H z,s@y5WDpͼ`'^1(U ]~!ɤ\m':KeE1`Y8W'+CT9\`{^)ʉY1y7F (߿*]IiQ(Z2?iӦf:)--qI͉4:$ɲ(Ok׮<&IRAdc`׮]=zs玿Rkja bJoHL(J t+-PUABBB~njNzV֕8jO63Ju'.MUG)=lXTK8׏ u& 8`#7KA/6t\1qϝpzNGؑujmȧ~!\uq?R4 ky/jpEp#[Z9rھ<]%p1GvQVȃFrXKl64XwY(;gf@}1Fymڗ(xQnj_,3+{ܿM[˲K@l|w N@B_lx e|DS*7H ze@ܺ'խnjf.CI, Ig2O脶]%+8&oCո|#(ףxKDDDT*%E{}R4YfCH:9^G8NGQuJWx-,,,..rrrvqMoK0,556ӂi-jDdwV"/۴i۱ksK|/ܨ~ϓvBt b@g焅}]Jd0QHFϵi[^9ɶw҂RVa=lWi؞~e2YiϺw pLq߷H_#˷֪YVX~SVNb1zLr?3^7M.Oܞ=6o֢C'e vγ]|i*Yʩie_8z:^1y01rO*R3,N$O$IΝ;n0!rMxZZZϞ=:~u:EQEɊr'NhРǏCBBBBBKP( juPPq1#ZprcmFWCܹsG̘1"bI8-0pۦ|jcoo9}v65<~`@BX9$GkHi s v} TR5 ,9ńڡ[[ۮCFbqgyNec?&FA=eiAq͔Q/r`s q ])]~>"S1+÷ңyV1[;^}<4mGqy: oq4EW6MnHv.um^_櫻8U6U1y7#g`"8z7оr4 L"G>V\&-? bq8`0;w]vy{{_z0++&M( ___cgy R,((HKKCύ8겂Xt/jݺ,  u. >8,@SmXAscd1j,{'_J>SCUP6~*Y.{gul*. )gPz\svlY׋XMzsG~q:i1ͅ{upMbtnY0f#8сst4\*x5 v.q \ {*{צQrCӇlW9@nQd^ZQŷ-b`D"iii(L$I(EQO<7 srr4@f$mFal'Olx寳(4"$IV:%sܱcG] C"M6rZL\O{+ !orhf ^0s)D~7Fvgڸ"IaQ'R?4 /kBn.rbŶ *m~m^a^0=KM^:7À.qC7g6=|mcd;gR}˼%>_w/ v#w~)D/Ѩ%lkIϦ^k`KOVkPZiZ򳬴GJOY iGxi#-u@pU߁GsN=AcՍYlQng6f`#nsjMC ٴk^$5+c,7 ]kү>95mDcO֕k٨_{PҦGŹD9 >>QN+Wr :^f9z ie@ 0lРAS<yΕ+W^sGpr辢C&XYY>|SϽ<Ο?_v޺uŋ@Q\.th"+WsW F ~NfUP=^_}.]my Hk/gH$'wzƤf8%F=wi q>ڼT[7vuTFƍUrD vk~:7xR7w\],_d *cTϹS4mb~Z6vy#6~/YCSoζ e^PJWRԁ:CH RԀcR* 5&5bTXfob[>IbE ^-NIktyy!"E`|mb[ą"k5Yجyw=.s|ܢٳgkJ2;wiڵC-VVVVJJJ~~G*rв(q;v?k#NnL `0 jG=V\޵k׈V{Ila&bz= EQ,DbcSۻo߾թS'wyi%o0 5LIOWɂ?5UZk@=uʭ'ąrsr<>*>H9Uyuw*3t&oN3 NcwܭY9l6BV薃bm۶-::!L>îvvvNNN#d) H9|Xk4|2xѣW)QiBz5ӶՀH 8)tнF30|l|<%%5ffj*P,+""b%$$X,0HXRR3\^nAHz=(1"ڑ[6iҤl{z75kVRRbggWNLV8[Yyzxs8ٳT4عTV B܂ ¨M]pV5,lI(rRxf>AJrשS'{{{-[T:aaaa&Qt֑[nرMZ.--u9銊RRR.]tܹ/2::ܾ}$ 2^n,yLB Q00000"g`D9(r̬nkkcIR޽{ӯjA vnٲ%==|}}}7n_WcCn%d1)3d)Q oF30||4<000((l4jiˍ0,((e˖ %-^f~LL%7I>|I̷,))INN61IbQ'-EY,M~jv&/҅/(]m?l]OF30||4<==՘._zߣG̬^nݶmJ$$&u:I<}u@>U*+^l6 ggg&1b?CP3 HEʉ6&&&.;x›0B,42MrWAUNl~9g{x{Zna}nӮϤo۸6d3wn櫑KIS}ʔ:BhۼÔ ]كi)[J_9Hţ:4x0,̪1=ZĴ6l'JxĴb2rZ7bbbZ5fٜrܒ%I{g}߹YLLLo&o\ g^}7cbbw0kWQڼC[Rvυ#{{|iDiǗ&&&gmYT;PF30|*|4\P6nܘ(Z ~m  ҥKddH$*;ѸWjph>e*q/ˋ-if>y0 jI0a̘15xo߾۶m31UY|e~ :{Ό1_Y2yקe{Zywo9u˹ q#X1*hN3'm@uWƐsxu~ M[{O1u "_bDO,ߛ#vY6OsO5?~ʫ HE3m_IIqoѨ_W,Xɢ,Ӥ6So7K+&Otz9#vOƤIYcWtp߆):=;1va_˷V~4)n7?)l&7Vn9 f`gzebܘ9Ai7%aC,LO#'aQn݂⼼<sgI=zhmm]n8{xx8::֯_Ν;2ʊ::>n~ԩ԰ZJJOO7 D9ԫZJsݻR M\ ZlY\\lnPP_Mct:ݱc:ۨQ#sM[k qշ< ENc_hi[2^(4բmSww 7◮s&EB_/ږ eWWXq~z7>z_<;K9 l(?Wz55~wQt.f?轛G~eyV-|1G|/{rd0o{E?ء?R캮;T0wPp`+]lĭqC4OEE5!s3@2dV/I> ^Ȱ-blgrq+vlJ0rNoGB/d?jg#[B}~z|yzMfQ9⠠'O?|"Ex<תU+Zprss_J۩ղږ^'R9T*IIEŹy9yyy&JAٳg[n1bʇTS"BCC̙9f̘ 3{*8YlfVr8 |ǐ?^6(*⨑stJn{@mNٽp䟝w^u3oO#^۳r9{~\^>؍ @95fR@~fâM3VcJ-@j8q0zb{EwzOXVzyY;tp$Ko-4{j0_~~kܚK}luJxa1|*EvvAo0G+nBT9u5E;GBqʮn= @h5KORKcb8E@,gOƟAYB쩓INʠ7P\Njl膎\NӴ "JcRF c<ߘHY:AUNbGm780MAU yn„ޑ.pN Mgdd}hƍ(p}--`Y8W'+CT9=/EA0ggg''"D"JkժuZT*9NUP ҕ$I>^b h*yw;T*\&J r jUo6sժUV`  !!_~[n-W 34Qϛrg=o||]GMh&@R+Iktgw@hK]>rC[KTFQʫP8b&<)o5nB 1ztMXyCc$8@QFi>m= @Sq.Dqɺ8S)#1s`,~~ø"-׳Rio8׷Zf;a<},/ldG>;Qzǝk @w귥ZEx9P<ز?\l> [QF W|$CgI$+ւ0jҟ&@,kW \̑hEv!tjǑ_X2F'v27_[B"KO]u wf]0hͮmܷ0  EO~H$2_9y;==޽{?f(2/ǑS]1 yR(7/' O*-,O5i} [ %%%44466sltw/g ʙȲrf *) K)oMҥZW4dirBf .ko=-^iȶw҂RKW ^ K}1,^U :ul̀ N]#];Ňp|SOyGÍoAsf ch![5qz)a>_)cEAUL wnV7)Lϸ?o4k)H8hդf(*YʩWp@%:@UKOR2^{8۰{[l >~_e/WG\T2=Wĩ}uCB/ 9;po<=wKʓ?ھO-^1l:aV )jޙǤC0[+lMzsuh(NPlw\q~ꬻ`_ ]m!sq;XڥgXE!DE{J.Ы|O6. )gPz Hܜu[4<[gw[$mF ɗRP+] =KL3M~T$@8qyyzeΙvL6;?uS=Ax>6Y1óKOtn6gv VXe2 MkٽtŃG 1oاxҎkƴu8!]@]\cH)q%O:,IjVë{Y5Jo<'.aⲑQ?Ο9٤Yw}1RSS(k.=Yf[qQncc#^vyzzb6mtTYq7 ͚5hIT[n1^ja'JW\)**pFC$5$I!!!m۶)JGp$8[[[GEEY~L>h3M$޾z2843v 賧=Br7Cv۶[/v孕צw(ʎS99{eb BrxUTfeer +&VFYpI]BL&;wܣḠBO5 ̣PR9rd|||ff&r8s8@`mmu֎;Qb``эBNr@_x:[kw 86F2;zP%S$>LEYh~-VkeU^6(Dx{ eɞ8C8 g9(\.Zðr`0 L8nuNgr??rFSQ x` Nzk.mM2nݺ2:pG!ǟ ۢ8#8Uh!(rWx?Ey59 z}VVֳgό۠T'z>&&09˵Q*\.J&I(N ɬQR9NQ͛7O:eaj2fk LJJ*WWN|q*Uyʂa*D'O H"WLii3gꞞjL2o>}zXXI)s,^زX,jxyu:&,g9CMߟ`9*O5i(NWPPTqPq>>|hkkkMpp0zP(PҔEpzIqqSNY>`0`1r(+ab 4AR!A,2͛׭[W,ٱX,Xl:DVE3CѣG}̺:رc2cٯ4cᅟ"qA>|oQ?}EWJ*<-)ţCWZBvLKGsN.:3Kn;xO?]e`99Q^=9IiͧO"B4ht:Phoof DwҢEŋ8rY,VnA (HFh^n%l1Ok $0 3ޮs cGidȿuSyʼn{vQh +Gфd@zCPKW2'9{+SM:iYV_-0Ӟ,Iz^qh1iEP \W0FFj4X,xҍ CII J!CQ%KeIIS/**qqZ$)!IZBy`1NFnjČ8%{8n>^v\g"tϚIJ 20!C,ՈkZ\fUPe ),, x<>iFZ`uAJHT銗/_.--5^t(JU#UR"7Ÿ'1W* Y,Ν;]\\,i4aMw'7l^6zף``@07 #fK( ĉ$!錗H$LpÆ ׏?(yY8zURӧO:RLT2l6fG55iw$oq6~-'{K߾}=<<:￷X(Ώi3D1K?sןiŠU.ȏbz,Rַr̗ nl 5_t[v_SI/v>ێޗVö|&F`9$R2Z^Q}ݜHПHje2mҕmyG˅墠5X*4-)J>oݲ[N^z9r$++^*^5?P]oΞ,,( B%/8֤ Xwti.{Vl:co0#s&vE_V.3c95fR@~fâM3VcJ-1Sv 6*L$wl&CVgݺۙ?Փ]ro<{V?/K3 U|qѰY2qʸU|g WS/&/qw2k^ n5}w~UUQH(Mi=#*(r*EyUd2X\&mxר| }^TjWAWZ6qReMb i?7 b~p@_Ҟ]Zak-RGf,"{o̮jwan"ͪT*4 IFfRIavww/,, $QBTlIR@H`@jrW,..&dgo޼YRRBuy&\jdhփK־eͨ4 I aid62q[vˆHsa@QM, $eIA@Vڬn$9{o] 5*!#߻{f,RȡR\]]DJ !nnnm۶E>qNR1L$*GSl6U!˜ɍHp8$IT*M@[AZ r543ypС+WrAvl<]7ViBgձkACo ZMG*'( z-Z:]&ݼy|oZHq_QϾ8Q(r^3k֬3f>:R^iYqޥR9.{|PBPӢhʳg,>q&?s?q:>K2;اaV~Vڳ۷ÛzɔS~}|rX^'K^\ lm)4wQ&;\2p>7kŋv ,!3UZ̖m T۸Dڼo$ Cjպw^ӦMX$ī$rKAڎ;¦բS,]fʯKNGomWo̪޸ lo8xv֣w=ojx5pc,KW\3m94 ~MS5nxY֋׭rP[7Jo'u>`Y9 1{ FL鞻4~uXEmW,C:=ZDWe0|Wղ30T v&Za0RSS ) ruP6k]uT-"EX,VIIX,6y`08wh~5U-(==FV#\./p8RKы;Z ]C=sRxP0?͟Ξ޳/#g`ƵR)Ո∲no6]RRcsVJuVOjS*͚5zqQOcP%Z=(OX,.wh(ͮh/jD+J䄡bμAQ|zh̥ :/Yē=mA*R2KL|B7_w.ὄQ Z!Nc(HȼaFAz`F aaaa)))܊Ehr'''S6݊V5)&%%%9ԑiC?̥ [F?Z=lז>T_ xLGVf< #"g`Gz8/r IpZ[HugXtM*[.Dj:(P(rrr3g4o$LfiZz,.Ʒ4hgiƘ<G|rRP^Ĥ&Qђ *yTm9ƢJbF"W(^~]vʪnݺB… h+&:bQf6mADݺuҌ7 f l6D 3C7qW˙KÛQ Vꙑz|aPj jz ,^R(RDa7n[YY?jҤIIIIbb"Q…M4]v=<+]=068._eۇ0aTgN}rYGW`o }]Ҕ$e߱zFJp]ιm| }6ǡ\\f(rsfʔrWi}x$HIITf8pN$m6WWװboour<gVrrp CIt80&J#E5Kw`+q#ۿ^z*W?锅i7n]5bmSI"޽me26&i PUc}>v^+ƪmwkmm=:sڝWÆǭ))aFN,P?ܳ|oVdؾ[Vmvۻ=s7<6-$ ]᝿YwUCi֧F}?cĪMr-jM;%^zimjn,uc}5%k RXcr-7j<\fلމJOmj.q/qc wř RҰVϜkUQ ljrWQL \\\ r*痔( X\1{zz4`0H$kkk[[ےTڤIcNwm6wڵ[!(j`0DFF*Jz ٜdJ.CB&d1NkRQ(hn1oT',tǎ;tPlllFhaoDd- PQ ma&jLL|I[/ʝ 8p=[ 8U#YcC0wSh:&%_R6#\rO.“"5&m7vb1W1(mG=,͛ M{=l=ټхRE+/8=)q¢qGH_ +Bmc@=#^жzc롵.[x `~?cRD-&O6 G0dӲ=ʏkS'-}S Q CH3;ZhA?R캮;T0wَ7mZr tr)]`ĵ`ur|otLzBՔ'2:~vh9jBKv3L~ƪ|2WU#+(T*%\.r>/_ScV\\leeUi:, R999M6tAH9[,K.FE8.%8$띝)UNNNI#-^"7q8N2D>CCC̙9fKM,OFct;Ǐ^WiC69\>X~a]m'.W8tŭ/Ώށdz9Y|qѰY2qʸUdi>fO o[3qޙ 5&C]h6n[DC={?ǔWRvD`wBgxHF T`UϠxvyd~ѡ" 2*C^2Y:){p#Q71I׳JaN*0IRXB;! \bOLvrJJI.-Th`fblDh1w \jɒO?md/ϒ]"g`y|h,娀6tDtW۲B*- oH;::xnݺ>|P}aqx` ^hhTLAo># =^b?̙3e2WB1Q` !!_~[n5'IVQJSnZ'jȦY#uK6}tWP%G:z0m<2 !Ħԋp*=rǎSkD>7Bt9iX 0*I,$V/m'J 1rnIܺ'խnjfvY}ީߖ^jygڎAI6'n>uN'6Le('`3_]FJ 9re*9r= 1r`,~>k,r=ϻ?=hVfiAjк} hÏ㻅 7=|bש.{y=>}}֤Krua3qc,AT:B@`y<@T*boo_# 6]vݽ{7 HHHp*I%%J7ga QQujLXLQTaa`0D"DErߎ"G|򂂂Jbw|fzrn/p2O=,7{Ȓokk1) |sK_uvYoGHgi{گVe;@iA.zq3=΂_~dѥgc\uw#})<Hֺ9 @۳ecU6'ܦӻO7P2BIw@,m~ϖ 6kUӨE Qj`(GK,M www: Az(*--E3kJOVT*Qti̘1$IN2.!!ϯ~H"IfaDBap^`(;ݓ$iGGzPuiܹhf̘aE$ՖOTm:iΧھ:v7lgSMM7DZB TRyV1[;8,z!lrWV;tkgvxڋ ]\jGӺ~*׮U˱! p 1 j eYrao !'1ȟ_(Ma.biڎ u l{= <*Wjm]Wc&]00|XAPir Np8&6h PTX.[)VXX*{.\8g?zT*H(wʞ=0wM6ݽ{733%[48;;999ZYY9Z$I垞hBYwhʛY)TrպuX$@\!4@}p>tCY停(l۰v3>0j<=/%J|r*(Ğ poիW^ #:]pz&KBU!Ur=үMc~}+M+`]0SHځ0WMp]gH9P?=s5(. ۹N:B*w1P'!sq;XڥgX|Iċ!lmgVoOmSF'c1KoGXH^lp8((0wc"Uu<Wi`+Si&$5M׮]&M=zHP(öдiӌiӦ"##Ʉ.EQ(;V5vdO;z\.0 w"?`Ν;-YZ?}SW$I:,jDPeM%Y6\ ^Veۇ6n?ѿ60[b,vmto] 6o6(P# aW lĽsmnYX$9y&cCۗ2ȢkS{ P<}cK<{;(Y}oC:TRFuQ2lצ^7|ѷ%,1U{~MHgk[U wc,cp@/K?^G Jqww?G.މmg nTd&de>=g2}mT=+ ,Gc=W_)jKWvkf[yl@d!7J~eAIW2mw}10007ƌ( DmpdˍziiZEtR\nggもhDR;h0J(8'O={umgwww"882it3sww/..J h^fD[YYQe_>_חlKW~[?w&ZYs7/Iux4]1-FQ#t]?{v:Ϣ6FnxY֋׭rP[7W Ja(LXkIJ`I "֣Ŷ|>?+I*3)Xin=т4~-]G]m;dkV'MUZLjRK l1Av9w<]R(sm8~.^|OǴ<Oܜ Yi1iM6hHUq~%$zݧcۄ*qЉWN [zN $;g,+ˤ;.ʇP##Ο9٤Y7}1z{{Q\8{*if[q;7W{eGFb+GKvrQ(999 㸏WWJj5%$Z-ǣ!֭[bFrJ *j=}"KLqqqVVVhhBOO~_աC7o"o]$;udq`gxgN,I}dq>؟f̓\m˷-Z򅳧rsr>`>pʍWId2kkkcEN+۷o;99:.55AKII)WN%%Ν3i4&&nMҭ4h ==ںlhlEZ]6 J( /b:az`»wZ*rwQ 7\]e~'EQƦpRiRSX,@ei jǏ5&//ŅޑRMңG7nܨ[.X&s<صkWqȑE $}P"oi"G+Yȧ`a`0`~~J5ˌ"g``1eE9*cɺzH;:5j^9l6`0$YqQm׊\.GJ% hƲ %l~V7NP.#Sv_8NYC E!C9R&͔t{20]f9{j*Ƣ NW"GZS) P</88ظ؍GFF"qE9hZ\nȋ }ƣ˩8[_[Z%Rju:]Yae2Ytt1e:tƑys0rF30|p3Jkv‹4,ݽR&jfB LWWWbz;QtzIII EQe g ZA9͛ QmJIGALJ8na2w,g``a9{'(čE%QVTT >P(P$IB!Ju: UX,ӮnTղlZ(j4r=A0V e8j*=C(GRafȍsQU#a ("g`x|B23-T>p FjZٳX,K|ۦ+a:Β|8RLZdNNN[JM PTl'RT*eczRVPOP(ûQ O ^ P™mڴQTz Zhx<(<$H nr6㓜Ȍ8dy XT*L9:ӓBo߾Jh4%%%*rxQ%)Zf)rd 2^.}y`G{NZ%['Vye4׆Ѯ(M޽F!]a:uNK"S{*|nqE| V*H6kּ0?W,`,^ZZRl6[$8AXRE^6m |>8|ƍr8k4tQR=zdb7F 9z&`9Ir\3NaLv^TT?W竁eSn]E=EWmT]9f5X{Bpb<{o/{kCA~ekL]];V%/GOךT<7c*?wu|&I?7ѻ'tᠸ:˄o;޼sxZ,˃϶lk|ggn>wyc?o˞56){p]'rT tyȏCZȒׯwfd53v\p1gۿ>խԚW\s"y|“b{:[R݆O!Ɖ]1"g`x0B<<-ZVբfr\" J7+*&=x,bX,6Q0d+&+E&b㑗 E[n m@a- ʍjrDR`%۷o{eA_Y6,@{Ӟ8'Z2[36LoXιhsS,37t|&oh=|X6dcew7Ր}xڄQ+=*nj,gӦA\ɝrJj̜âk»tXyaVy>0sCvh'ʴ{7r&WCc7w!.^/+ tz߭9¢Ljk}/w%>V䓛MN+d9wzun{CO:oe\%8ROc⊙^}ipƊJpV>ׂQ o7###L &ݻWV'OQXvmZH*/7 gqRSS"G1u@PRRf?{x+jlLfbQ,+4SXn]UB0?<+O ՋJKK]rE~֭uTujJ<(nN;vءCbcc5jd)UzkY66h۩]x-mQw~K[Cş&صZmox!\F{ΤA1E+NO/TGO.G^@դ)EIM]m޻;~dW\W_@*o-q#:|?~g 'xIF6;Wu(#ŮI#@ q1!/E6P|ق7`吝0tߎ>-ZyIs+Pێ{X:7Rz,z~T+dq_ ajܢO>59M`|5gΜ1cThbQ$qتͬ8p׀Q 5^wE߾}["` $ѣ֭[KQgggݹs'44  dI$E5 TɲRPP` aXXXXu؄6iR˺\mO];BcG_[p]4/U^߇Ȏ+p61M ԏ}wt\6~~(6߯b1 uBD=m>`/O B]%NhO`Y*qEp#[Z9rھ#cYJb\ /iey'J AۡJnnݓcF3;QnOJ>`ݠ_n%n4]]ܺն^P)p6cne ]p k=K6gQz>g f~>TpeXpgvޅ VFT/MuRӦNigN`GMܤr> \ EZ|((b֝%EQEEEHPR%Je2YYY|Ǡ;o5jh4@ `X<kZ$9+#E*ZYY@E.YPP@+r:q8sjƪeE׫T*>c\"qvv6i|+aAAAJJJhhhlll=_'AVnBl^,k/gP"l'>{/]q5ث+9?! =\zZJyҐm`xEvU[$jӥu] L}C>ʅ(q_MQ{X>8hդfFizx׬*?֭<}Iwum}m5~ *;7wgܟKkŒ.d?h9;1J1:0B!KKKP$Dj4x葝D")--UIII"gXz"0 UW(H Looo:7"zP`jT* 4^ǑF/^簨꼼8I϶ᓷ컅NY?1 r5\s+ԟگC]!tNLU^O7 WҮ I矂WBV\'R., n&O:c/HM-*c|Vp~lI9DQ|\.,SYDM&60cݝ&ϛM6[YY۷u9tRRRuFd^^+mغ.Kd vߗ\./))p8j㕔3N$~9]=VthZյgF&M8AHRTJ *Err̬O?TFJZ/Y+9rX?r̬s{?c!:Zqw,+UrYfctiREY}V^QEO3/m]dBnDzn>xyDn~y:a{̊%sOҢޡ ՜~nlN!.]ib7딳k* gfghk~Y~hZ?unX@y￲wQGGrچPQƺ{\8}{sͪavm{)켲9~S}Ȥ ,pD֫`<ۿ;@*U,=v6¯(\v_ws{;a }lˆF3p<>=2Z{D8HyP27.'F ?9V٘?*ƽSy긽ڽq G[/}ձ"G ǏqfX,ZyҐ0EEE@P$$$ r.>b4J&&&l6Z(N0 %77P4o\"X,6-b@ Cu ENNL&#Bb\LVΓ'OvȌ꥓}l*-g`?6TC䋩GmlzܴqۉMNj;٢wU2z͚tcVN^6ZZag^{x񌃸yoWvie\ܼvG5,ka&vaR`{|z \Rs[\ϑ ՛Atu5PlY:΄\?o[v0u ׍]eKm9>X~\3%\l*<. f3uJvjA|J$%%fmёo4ڪS7`M=>$7fge f(#gemXCyb=??)%%d2]aNf|>BRefflR4_?h2дB  Z62˃$Iss2ʦOZ-0[niii|;c #"d|/{y~r@ RT+H#zF?.}f$IV ~޽:г9ݕJeiE...bX*l:.Nۄ):#s69NFt!UTToZBo߾j4DRZ@^^\!hZ:O<ݘu)ǙY@|BN+ϵ6a{=xZ)rQoYA_e0//8A& 655}Z9::r\6]\\RX,Yi]ٹrT* p8yy퍤L&6Z)/MQ])I!#MPKӧOd5nGQ 8ӕ1Fl&H#a>>>k}!Wr\̸5aW^mӦKrr2]j;_zp(jذH$h4 nhLMM+L& &&&Weeek4TZ:1t׮]712*S=,9}aMRR߿3S},G u R?THna隑iNǛoݺBwRRRK[Iω]Jf25 aq8FN' [9::1⃂9k6mڤT*il8n`aDײkzs'''aXRRޭhJ'xzzX$ - ɱde'JR[Ɗ9AL& C:9NQ nUŭ u@ lذÃDc@ۘ镺ǎ#IՕ(xtfffUE"6=:@.HD"*V{ZߵL*V dL477?tN.SxV\_EKh(٫s[7NOwn4ZGs0iO"ݿx:][Q'w$6/=_Q'\ᣓ/F5ZPꌻWJcO({&G%/(k@gΜ13џYz~'TK9*2J$++q8F ^t)"Mj ˣVV%Iu JHyS?"<ڵ5_Ytqs'^B[梱YŠL@@-[~ٰt ݀vήҎ]ֽ{wM^^ZRԴV'//L9bcIIty9VF^+eQ:>00P/N)++5d:#F0xd29b"xƶ>Ot H#:YПPXH_շo_5-..%%KJJX,R^ުV=qDwS̀Bjj5=ZkaaaeeEr0 4o/4mZQ_5jԈ^٫W*KnM1[=֮SKY`v9kZo{ M9?Lz״*⸿wm[=dݔbi75PصaLk;f~.q:5&4q%Ѝ!6{~`ƴm=,PdIk[ݘ5eQe&52t`OCV=zh>lOM{@hs3Ii|Dtsl6s̪$+=Q;l.KwqR NNNc"UM(OIIzlD" l6\*ZXXֱIt2/_^+{7n\kry~~>I;e2 C2L.]K菿[#3X>xilӗ.]jbb`Na G&cN};c;Pg{g,zʪ3uiۥ] @{!Z ff煗 >/-zctTU36_ :d_-LZ}׿{ۖٿ h҇AM2jUcne{1Dѷd k=vso@H#:\70CwލIIIϧub :BA'FT*5NZRRRՄ`0Bavvv\,D۷ܹsu' +`OKܠAȀtfxXBDn[&"G u.^^^ғUtIۿΝ;Ϟ=KII  55Ug béSZ[.+`ixtU Bae. --Nuys:@V3 g0 K)%&&zxx>ݙ5jݻU֭xޝa9axKgW,.h:f?/XppIWÿ͈9ջ[T֣W#3sO3/m]dB 5}V(w֮|uʇ|rhɢfN쬛6Gsۆwe_E0@ąݸ 1,C1-s7 5"G uAH77ׯ_%< gБo>}z޽ȘLwzz:>q ʞ!rLq/ U*A6EQOLBfcǎcdJ.+u'\,6lؐ>c~r7oެ[U:S\,GTC C5wn*3_ͻ?l5lY̚Oۺ\aճwܾg#3~F+[:0\ < :d6ޖG;`}Wr9f|n(*&6nǶm;lnWM9nN;tŲlf䈏+mua ꁤ$WWGW43Xخ}ק_ٴh4^^^"zݿ?"""***11۷[nP*(߉~ ZH,믒J:lI,3.#3$$$WFPIII ڌ Jfϟ?ptqV\)sҥK˳OE=?n\fid,2쨁[֞[¤~kܾq5;+k7CQ@58k4f-,,^~MH*P322߿֭T]zꡮ$XR62̠#BfuЮ/4 xEGǰX8r\["Sk[R,m۶u,eD1 kݺNߧ..iqDʜBA8sס:[Pty9dk'juBBBgϚ5+<<Ç{y-D]NHfkKiT*e2{AA t.iv׃Ay~~~m4 AevJiӦZV笢 ejjJ'}Aq_<|Q>Pn"jtnOeFIQ=KUSNV_|d2uqǏ;iaon;33F uN+ BZNLL0 qzjy5kbZmJJT*mذ' II-oBPhʴʂR7 ݻRaL,V[!+JFWr].sZSe'9ۧgd 9@ RNQED" %%%! srrJJJ+,,lԨNc/7nȥRMJT*5Mrr?ʊ?62221ʢܘ?A$IE177UJjjZ"̬L j@ E@ `aaOQT&M$f3; `Μ9-Zqtt|⅏Dž  *8:G!Hd2eXQT?y"td K[?| 99UQ*I0..NRKm}kkk.SRRR\\T*fd2{;;_Wsgfey & E@ ++\NLLE9 -[Xbǎ7oի4hqy jdlSRRRP&EDD׮]*vo߾r?P&M+LjϞ=Φ–i|WVVVRTTT*RV<=xZzzƍKիWMN,@ )rQy ֖Nn۶mLL ]V$I:88xzzj&ٿ'N4hܹstt|$/^( 3331ZTrZVmmm :_T*+,aþ~zZZ={̬K^^^28iii@Q]TL&윑IiK2+?q>; \D@r߽SٿOU E@ !C^3 ٥1Ǐgffo(Ą믿>u)?s Ubb"I 64p(*77722IukId2T*޽kDkVLfd?2}0L;;;S_9ښb8nog8 `ML36t[]>*DUɬJ;Ȃ+3 yKæ8(Wc:|ؔ I9>sեL]'[hAT߯cHHd06_w mPۇWLާkȂKB q2(+勵} 7XQI٫KFlҡϸU&++CR ~dM5vs$;$iþjҩϨEǣ7={x'K y|j|Ѿ?j CQ" |ZecRRK֭_޺uk[[[hڠ DB{EQT\\.N(**JMM޽nM P(G~m7q 0.СCez4dxEEE敞j9]]\)Mr,֭[82:t#LT!+(ja'G\(((::Aq]'NrB@gxxxh4i@tUSRR^xQaX,^dɬYPJtdO[nS '+!*rkwڶ!e7ܿKY ~Zbu=cd <^jɔm3>(\P>Xc&\ ^Lk#p03^Xn@(ok).tlb@7v]Ⱥh1E8EhA׫"^8mL`Zِ%H-Ah b͹kutw3kS}]NTd=>{)Ȇ 1h9,Pòw1@ǞCv+Y}&9d2\.rt.2I999}))){FaWLLL 4͋/EQ;vu=O>ݘqnnniה2o {aP  r%R)bbb +;[,zxFwM<c`d6?SfJRR-K 133Ett'$8PcDITT8PуRVinBĹ-3qo|6~ewK@PSO<5{_P_,@Ͱk+f@CaY8{xyJn>uy3wOe42С}6ah҇AM2jUc. )4$!18Y#%@VY`&yqĦYGnL{/'imLolFyw_,0)-tNl1yHYnbmB!r ;]V9V 4%82n 5Ugٞ5|W{@{'f2[WD]/^Ѕ-p۶mWFDD4o<***5?Oll鉒-Сf0l6ԩSFnXRRDLLL{DVꫯF_|ELL ˽y&CVv6ҹ9r{ _'`jy333_M Z[(]ҝWƐ[%tڣ?.9U_qrJ z`MZCTæȞ ]LH`ٶ_52c.ƩKwwҍDQ BRq\'R?ð˗/׈ 3J`X\6Xًx8@v+ms=:zpk詃Z͢Ǐ18PJZ׮!+nArV AK78mLf(*~s#Dd 0cr +Y4w,Df^ (*F}.N[[ ;M _+I/9xkcӤm΀G%ћ @)O͞)m3ڿM˜(oCh$$5DG_?E 1 FdduSSS6M+<rlvdd˗/}||bbbi斐& i8pH9aG(b__k׮EDD8p@ަ?|pvb$5H$Jw}T*--U*RH$N:hn:XN=J I&L4pdggW}I+*T3˔!`0T*UAA/j鹪v+ݾ}K." L&sgΜ1Jow7rX־^|[o29ЉYF_^OE|6(%2j9ΐzi[>V(!5o޼yM< oVޣGY fQM)NPP_Mqe/"ޘZ*3332/$7wA' v )wΉqV.5*lܹ0 4ɖMmmm7)rwiZ89 >|hZ rydd$0,&&‚b999%%%5h Z7t:>okko>{7YE;u*ѣGo߶JHH077WմڦC #;;;>>ΖoRp8*I&W^ٳ'2p˗/>(Eʍ OڵkoeeifƯX>}X%uUNmRAVVV.]RP(ٜ$ٺukAY~hcxD9rHkL}upˉyWwo|.쾲-Ŝ=٦986:d:Zp0xn>xyDn~yFuLn:kuv6/ 6 {&'~C]ڻdn)g^UMVvZeJWs+~xF&O&v'&>;G vdv~׼ wkޓ(r}DQml^i,pD֫0+:¯(\v_ws+C\[s,]8|_^ fu-wtqy@@*Ԕ(Zpy}RǏx򥟟qppHHHhԨQddS<$$dҥ;v(,,d0Emڴ)((HSϿsNDDDtttRRR~~J VVV2L"`@oT*)p8 CVT*4iP(ҺuS)AQQQtttycǎ޽{ oa\.̖I*$ -ZTb`B(lmm JP(<|J CG[Xvqd ]n3\× -Izr~Õd^NC ?qF߮Nnzp;>ͽ:M~~ڴiGʡTLϟ+Wpx&

`'''++++++$'ON0!111??_V5JR ~~~eE_ץ/󉁎3^TJw_T*Wzh*wM;2ܾ}[´\`715i-F\D}8IVT$I* P`0RRRLf֭|d2CBB}6),,rwuU3W@OOdϞ=spp077=˓wURR">@ 'H#zFPkqq1˕JrÃd^vbiW^50 ζʢ |^~޼y+VxqllFsuy綶Z4hH$vɣG@ӦM `? oLA-dfe>uO5*JWި:GTj4Xf+NVIHHt钹czzz-^_)rQGN/1XEWq\PD"a0\.=zh4^b2NNN̴~oyxxL8qQQQt:aUK޽ uϪ'O/-,,\nAAAll1*zu38[\\, u)VMMMY,V>-^f"iuV jRMT陙?iڗ/_fddЛ٥T}p.!!!ݾ QHZcJ:NHɪ!ѻhe%ڇGrF)NL2Š.R=ۇt3n՟ҍ5׷L9$$S+.6!K_v!!!݇s/Ocv g̲S,+Jq};tz+ޣ l իWl6LcofH=fOզ:xu~PLqzn?uCguxu{B4YƔ)KΛ 7ڍS#:[UhL81+x&D ;e+ 0ЉkشY-3;=/Ss_}6f631e)Ӂ7a_twdGC,p"^7&g׬i,SFNXYֵO_,P_=#mkcqy/ SLjbNyed0 c2ׇT*511155aIIIVVT*e٩O>x\///چOCL&ba .K> 7L&vx||<\X R[RTTDO,&55u|N=OgFtҐ!C޽[ISJd3ޣwy ;t;j}SJ\{Фjʰ>CBBBB.[uH1Q_tA)vc_ y7O/w;B?bt q2 ώ :!0%e/߿SHHHV]||$?wאv_ wY:E}de߅aC:2|ÿV6̔21sO{dsG.֯]Mkut+nCJl ;[9%r»Q 4h]+?kCzϟg1}u5ߔElwQ^"2̟6ukЯɮOwu?}Ӽϴ9}D gμR 0J>LW%:yE>*lD{SGE!E@ Vc0kUhQnffiQ(H233 MHHE˗/@l6.!dP Lk&/R4hL^Β5}}!KtKg_gddp\~Jrr ~\^O#u|}}b%Kf͚UQ+Ef]& 8_es~ DYn? j׿4TN?۷r߬ErHeƓ)VYޖO]wNٰww`ڶbˎ6}gg7ܿKYWɑsW]f\rz' rRkV-m%qɎ|^m|;xa Iט"Ub5-XI;H'3 Yps ~ տiɢB%i؀Fn_xl_e mc!_Kֿ-!E [ xXQϳ@(85qd LKHy7] g r%%ZtO,F\erlCAFD]#˟?N hxIܼ(\㸙maXAAnnn\.˗,Ej:&&ĄrSB[gwXHJR-RYJ[LIkqeR^AtP(bcciEA>|$IBև+++Ç8pήtM~| _unJ0mӦ#y/{G'tdNwх'Eݻp0t?XYkHr i ilprx㹩' ?B~^6.D41M4oc\LZnÁvwFu5Aժ1?(*3T8VbS,2 #טdPlV!)BfmJlXIVQ*Y_?/\Xc+xܾ>,uֻ~eh@(S YNˑ[?c) ՠUiX6M{=L[)`4,&5NGyHKK9{`ry<ǣӾi= x<ávQQQNNx^|/h4]'l#ZYd)C[Z;ύ i_02%&vN9o/""g_:2!ƔI?g[Շ+I{myqd}$mLP;=v* ]Do:$\; Y@;|&UURdD^sкowwV0&Eg+305f`v~׼ wkޓ(r}N"׎}˺ZԸNW8atTf'Ƨg$F]?{RE峺X]Ps?mË'y~nM@k&(uAr|JF;^ߩ4RiҤ -L&T*&&&AZe tjsssl6]e2l6M_eK Yy纅,y݆ĭՍ hww֭[5fxkq$7mڤVLfIIx3rp{4b}*kzܴqۉMNj;٢wU2z͚tcVN^6ZZag^{x񌃸yoWvi.z C咭WVʣ1. a{tr)Pz9Od%cV2shشCضoYݍ.ʭ[ [pP7&1&'ZoݔSJcATЕ61{3-\|^wpg/Z#ݺ~MNJB|$%%!M,l׾C}36nܘ͍ ,XV6Cq @bbb"d2W_}R̺tRwyei1 /IlHwN0$2}Tt[VQ@X\Z?7N ͭzFՐś6mڿqq._^E`0tOD@wr@lد'$m?1@ > _|ٰaCHDaa!ŢA8T*J%ǣrJ&&&999Ϟ=kҤ ]g+YxuJZ׬qNJ/,C]3Y H$*bRGUojj5ХfD:<זb7i?p>n?1{777SSSHD0L@jJ%EQJRVӊ\Ts\:<-- @h7R:(n@<{鬒Ҏ(:]Z ݀N`Hնv_oܸ@ӃQt ;^]5@ UgV{͟kR#"33fr\.|.P(j5I* x<٥5:`|>?99X[[7lذLu[^ʊфe.f*eJ`y-u]~}nnn6EY@$Iɓ'zC  R"99f BPX\\T*e2r%B2L:BRжh;;;`e9w+Ci`0袛P4-ujKpݎ$HTk~z5S\@Gׯ5jdaaQTTZVP0 ht嚚R%Jh.kff {{&M9)EI$A{o(CquK$AL&6#73jM,oE=}ڵk)))"ʪMANJ;G 1 1+ecc9Z(V}J zf!Bcjj+(EoYff&= TAyL kFwEGwJ9-˫Tnwo޴iÇR)=IH1䚏QmgM^y?Ph,m+@@|h4/_p\Cf].Q"H]]]qW(F&|6f At ˥3Ctڵ0Sܺ3b8eĺ4ij322lv>0~MEjdnذa5"UB9b\d9rθ>pۂHjuʽcd;I+wY@ )rQbJFkyRpc*,K!Υ- iAhzn(S(vMybE'srrlll֟Bj ޏ;{-Y\Lin߾]§СCFK"##{eݚcz]͵ɧ.9(!X56rִ>.M9?Lz״quRu|݆#."->#@rf^K4<&݆MӛOoɺg3Ы3f ldWVV톆/{{tr`45alMΡ#lT2KRҧ~Y2>wnލHcg("F/ me\Ύ(TOC,zo;1ϫ_:ztmԊ90x .dddXYYh,&^>U6sOgfq߻i}xmi75}9#'küq~7-P;8+XHBb/]% 7Z5.A놁,JiKaCl$)t>CS^B[ 5WQ% lyox_m3  JJJ/_niiIߍolj5ŪiqaӧO_tI\\܂ jZTذUp#w߾1(鳽3e=vkWPW}5Y 6nґ AZ(jjqg_WT7Vm1hxo'C\l:0CV&;.p.8ɾwMڍχкiɼoÃdVMCuxn KA&Mvh# y1令cq~}"s [hnfqqF Q]е@ > ^zgccSXX B.X,}QNz1 JwaB+{]Nd9KVa>;wؘa t'Ǒ 4 p%D䖼uXyqsx&yݰǛP &TuB ) &kK_\yR>/9<̗`"׃*Ix ÛXT6%n/y9ǨKJw5᧟~5jThhhmv18= Й..X 7Ro7o:q-pE`@H(-`|9( 0zApxfZR)_+09L7.#7,(uMj 6|R⣦U{˗/HԹ*JτAk>>>F.ih'271 1F2j_~cH_v'riv] UDz_zLjFiAB2׋~r+^2D~ pTJ:*ͽDL6~u"f{6w46vmiVUxq1ۣq'SS"SQZp fU\.0() E@|Z:d2YLLLÆ 5M^^TTl6ol.k>ePSGt"/3p.J3337ohiiT*?IV iX9.y Wcg Y9;e V\݃z_9?r^ b5@ :6)cn=WF. )**JHHpqq!B.q]T/Ͽ{n۶mk2*|Veٺ~1bN={ZYY}P-^z69;j/r˭ C `>et&1򌌌%K8::x~PG QTdX.\ݻw4&hb GGG{{ " 9|xiRiLL*g1lP~Ν6md_tqPoQb9P(O<8= H#ħRA2),,gyB) ò333rIw_LRJJJw j%HG O DmR7A2f$Y:;w za>t{%b6,3 (LVXXxi d2~t8DZQ׏t+ṕMMT9/}}ޘٿ4|zf@ >ۅ@ jIjj*eοqFLK/js13IT2AꛨPEV-QM@Bs"33ΨdY.mz9uG2bgW)@r*|6;sc\4LJzy.F#f~QJ~=&,QCNg LsȩL}ͮOT7Sf 9;zW::!MO'VT\Ǭ{XuyEO\sfm1,'={i]GNʝsZHi)?HnA&'zL0DJ.{ۂ[$Nk H#QA2IHH`eeX۹\{+0C-S$IFٵkAfff"㦁 APG C1blvem YA _S SmZgFPԷƴ6ڜnKs9ņ O )y)okSֽg}U7Y -a-&n-{tE"G Uc Fվ~QFf%%%yyy ٹQFexPTI$GeggKR `Vdy߻w ___ڷ> `ʔ)&0l T*$>yG^]ݽibY+M:smo/,+0t{6`+k떓EwVjgmc(!.,R6z܆Xv c&\`˽8`'s1Xo YveFc^?dKmפǨq]8M}p+^ׄ*yn0Cw#27Gbb-dpis]~.|;}?mroo>Y)y}=$G /v{M5ڥ7o{uຓD* bDr8&0_H#Q(^z왃X,6555EQZ#///;;[P$HJv U*HG$**jHZZHs"m9~kx+[Gz ߬bj_@_1=ȲprxsCnb2uy3wOe42С}6ah҇AM2jUroPB(e I$b7b!)2*/j/@QӭQX)oe$͑M;ޝb׏:4y~==l@irȁ+)n͔ڲ,yq+ Oʹ5eGsGAjr%AsXYqd NV@ȉ PO$0o?wɗvL =-f%w6y$@+FIWsuG7t`t*m%R>x|aÆdXZ6999..0[[[333LL&311%%%A`ڵ<c&n"QZIa9׿|:]GaHvlН kIMbmٞۗZ:U/6@[e5/qY_MLI9(O+(^&Fm VZmyUFeR%$?={R,X`T+C &k;{Д ;xSGn =u] YT*18PD\5v  _q JZE$nncj0'R&=aSFf~cr +Eb;@[ū *x [V~ko۷)pwfs={'&" ˓ ,5;im 8"B%&h%  (C ηld٨ W:|-<-Cd$+vX}w`Hwh^:nttt] "G Defj A B*\+IĽ{?L&sΣG6vSg_?#,k_/ɭxE2y2e}1zi^|c٠(2vq tw u@w+Vc i.po;0țGYQ7e'ϝ>)͢]8l}S/"25MYʌLb!cXo29"Frl'ἙS##&71dH<]e=ø>jY31kk[Oe&~1.lXik BCPv*pmFo?􍖾)J.ma흘~{aOǏB@#E APLRRRhj@QFqvvHH$$IGs}j,DΑ#GY&s~7>v_ŖAblŜQM2-8u|^фi޽nӮۨnZ;{1|&|ǫ0(pe=i-9/ orb{iq=qg7omGAء]tN;wؾ[;klZ1"]Z;A~eKGs$]wTn#;X/Z~@I{A{;ghk~Y~hZ?unXH}rڀ"bSJt﷝IqmrO ]DoLI/v,p㠱^X%tr[p%+M?3M}׀%lĜ&Kok6쌑{o= :k_n(B@|VA2g"]QfJ-VAr6tF Cr_:&X$ WezAX;zng^{x񌃸yoWvy7o=s{[fU^&n:ȥ7q\Xmu)Խ߸nSoԇVmڻ+_>:\Yw>ceڵ;w#k}| Tʼ'Upm|ڎY;q; 7~BjSP3,\7֏@jj3i{k.`~t$*l(ʍ#o߸äM*>-exac]fFkSci5tʥ)<*v6:UZߣ}j@f ۵P5>נxXL+ERVc[}+?*n"Q^ܸ~`뉨u>ٟfˍC>>[4O/ D}jvVQ/Khhr# RNP0H@rQGh󣣕 uv48ȓ: S9cH#!SAW^Uc4Z@@LV-#'sN#7)r?0(^&$66A5::(G ud4]7H#3xUU<@^m7ZrA(^&H# Rg  -˫$)r3ūr$nr8AAASHsJc:GL̦_ӆ҄Ǐ[WHAr^<~բI:8~ 9tF ħJViiE|~KU (oÏZ(咙Y,ycw gZ3bgWir-l&TU25%ޜ*hsomun߆(,oYaCBB:F潕W'fto?lΛ-/ 1{cPʤ1$$}g⦅UDR ~^/,۷cHHH>c1PPC0 8pn߿Y#PcfС#F IܝG׌ɂ]ڔrr:?(]=|::OX<:=smؙ .o<7gho!yuȎGxڳݾ].Z4ĉ +ULiwo7gVu<։]]O#ݮ[?O]8aَffYv,_?]c|aۮM8ē_Z9Sg/$ŁUx4u-Fsҥs΅WԔ>ٶL[b~/W""+ߊN.PXvZ\cFz籩> ڍǯ'߹S†Ĥ+Hǖ&!Us3˝:Hwi3xSc|b¨[֞[}}Ej67ǯz2ְ!<_aPkG&N+&ygf#W -}d-] ?p7Q9ؑI^yS||J#(EJu}|؈ qGF"׎}˺ZUsY> )rc$?Z|}}322,Y0e;;ɞRd%|9l:4{=qQĥ}M5rN>N*i2L_;U؊-JqhBm]t|]7}̆y80ʶB&{lmzrvc{XY3 n?LX`Ȍ-EmX1!yhywR6z܆jjqg_WTsӨb0 H5c%6b-9QU :PPQ QqZnjRNV2^[tncf1 |/P`Vqo|Ƌ5+Jx4>* hdFG&qAnpIry!yRٳ:Zݺ3۽oD?4ve&g.]ODŻwgѲʴ>KiMǿ5zdݍge3zKX; -g/cfxhXCOLyj(0^@X@BQ_ Q3J`Y"6N&Amͪx7ߴa1= k1 NA?4}C~ZS~o֪s1=ǧV%YoI(U~ v=+PR`VQ Ru'>w[]-rn rnUG_|+ ֚eeˀ25/o+,QZL߸mibj԰»uz_x^/ܐz^5K˙'6=oy9ʔjհ/uFuO E@?(;Q Qd2;wEY=p拒nm8YV"1[<,qFfNPqHŅ ̍%][ 0P&z*3kn_Y2]VpCD&(\ =VBd޽U3lm/ Fm_kAK}OҒʮxej`Rx˖ʆ{s{Ü!E@(( ~9rHi*5qn3w;d@_k0⶛;e%&%rYfctiREY|ql [>+n(q.2![IcYxe7w< 7?Ӽ{w=hqfŒۧ miQpІ[jN?76T6!.]ib7딳k* 6[Oei r2ahD rmֿ(pjlR%#Eag"Ĩ[6u6*3GVw۸w?@wأQ7qaU|~/:ւ#"G {'5rp{4b}*φzܴqۉMNj;٢wU2z͚tcVN^6ZZag^{x񌃸yoWvie\ܼvG5,ka&vaR`{|z \Rs[\ϑ ՛Atu5PlY:ޕ΄Ug6]Rt}9JȣEFVtWgx9uM9;>oL-WʴKaEbȻ>nE7w*761{3-\|^wpg/SxI\l!]UxߛANt=حW񟤰Hba.Q|4if]  Hp5%O##ڴTB|n$%%(j6o7~|omUϩcY0V YY,-8DO V@ Y*"^PGijF]qV> ^5 hJ!j #>](G uZy-Ũ)kZ]bCQ $D5fռ9Q83r"G jG| Q@ ? =/9((/D9@|PO##{ KfD((OD9@|8׷@|<IKK=(G D: iiA߄= X>)rj EQ[ )r@T $QRDAr@- G@ rq\kKYQȿ4g%]ۂBuXjfd{1n0>d1WwZ L{ â%SKU$|]T PG&6@9 @胾QUGn@T y[ S $)=::sߨx&fA!UF#6!r|- z J8rn=1hOFEjUA_d"A}#JTSRʸkN$#)AknRȶq.SaPo @d6l%/q),j)4t^Ums]amT{#FY^=М6@ #"'2/o9`?pT{uQJn:L|X>c.VCb ;ҒtF%9^uy aPA!A993Ve}MSsP*L=I\vpҥ_wv*Ⓥ*+KӯW<̛TF>ryq~ذ}10RW@}iV~kb wdv#Z! FI<3m_- ۳"B郟&ܨPEDK => ._hKtNXPx=2V4aEr8P6}ͤXf]Dp"bMs/:uU0s<=&把4OwV~uWV<ύ!pZf.bS~o)û{I J{o]c@-3|Z)K*\ ?;},nzC&P Sr9h!soNL~i"*8HQy-uHF#9}JIUv* Y !X׻ȉ칣_+W{4eiI )~^}@^8"g|7-:R{wK֭YW8'}uw?aݛrgX]vt߽! `5[}KԔMF[nj6 2'n2̈YoCM)f]_/H>C=oPp qc@eڜ?mG[cOnGF+sۻ>aAB͇ BfǓcvHEW^V{ͤA0@El9rPGDž:TZmQs_9i62F!lF /j)[U6^UjO3Kޒ=pG:ɪrXO10c%@$*wV.1IacV-z\K1\Az,HatRВ"ķGʒ>O}̆6|9RC[w/8.zHϷhc&\gk6o`j1rNlZûe?1ih (j/v9zK}'\M{GUW~0jS>b4,oW%mh32*ȩ*yM_|3I-ѥmp#3~X+Zjr2_ސmŖ{-?ąh}6M/M w泏+iم}uH1d!~ ,hV~kb wdv&ҥts^t0'uGW`n5Jd|"ړˇ9&$9wr;Qydvǜ:koܺ!Us`!+?"|j/9^b{v5cDugN4F?W` Dw=ơu=;kJKhwB: ;yBWeMO^.Le=}SH(o%@{}]*xh\Cǭ][!0~ٜ|vM @g';]NgzHgD^'ڬkVz#n @tgע9o5ّ,]@݃%+ߦ[sDM7 3ҫt[nOJpmiSL{̋~³_L(2ԮHh.Z&Upib9׿>#'1]>"nk/^ҽ6h9/V"(q=$ (")ރ٦pDA:lfDd9B²GCF4 GM0b95޶uӢ{#뼈!@jz{$h/w?uU85‘@IC[W{q/gBN2Дio OCDС'.Zhq&M#犮Hu_3\+v5祔aG׏hAkoCޥ9KfGXu }PUwiF˓CRUf^r5AԬl5\ms=-;z;ϸ>[Vo&~ڋ+r;R|XOu/<w$*b"\!kGY])7wp!d#%~mH UC\jC#vbQOF+tXْV^NNLٍY̳R5ĩ3OxgI#%IUu6sp5 ?X~9 T ᗞ6_tڴ*If?7A)ǒhzwGgɗg'{p9~eþ{;F49B'BNGfL5??"SBsGzVRvi$W_޿XF^.Lź E~P%h¼9B!dȱDDX{{}?~;}eDI9J^in7k-zըnA4xHk c]CѽƏ>T=d#FMjjZ(P9~䯜Ŀ;*C{/oW{vWoGl+֜PvԉcoB&B]4qC"t6ܼ7<BF kلj/wf'B!dK*3B;sb!ۂ=7Bپی9BvX rÈ!B3ƛz<B6BwekB s"L!TK%M !d0"G!d17à!d0"GFadIxf!lF. ЃTgB!l]_|x'BȦ`!QGbF !#rBm/l BmώvcԮY !^\j ]6^jK.Euia o,kU+!Z7 WBm#rk/%M !69Bݕ7 rP9B6ux]B#r% ʑMi%!d]ƪBS@< z=M0 ðb't2j{"`&?/?=#iu d2_o7W7_j5U%eyyy*dRWWWWWaqB3!6!X!!ƭ[;wvuuBPJ !RuƒyuR²ҙ^^_^VtvbMtWwMR\\P999q 0GKDs+5-44^95stk179k~!$$$%%% k[g$˫ ޣN9DiCN\.Wo;G8!xc0M~BB*** c00R-Cp!p2)nyC8(zysieE9kItTX0t<ƫV"2MYޠky0RR)7⯸Ru#T_vʍ-e.ѝ= P]~ūZĎ>e9%]yWy8yEDDw3ꁃ:;2@N(P+p='Ro.IPxJLH";2W?XK@D2҂ l As!dE irqb\ixxL"I!}}/Κ17\UlG׬Sz[8q:&Ř7|qˊ pz buܭrʂr{޽z3/gP=zF*Jn]&Kչ':s3+cg'/g1fǟwۯw7͈?Tl,.Ќ^+m2!ѱb{v8)CCHT]z߯wN7rtzb4Gڙ>}a8B%"q݊=Uryg(b^$qo-1cp]8(3r_tVQ:r0E'rjl{i|@V9]UiNiPCIjJ8d ,9ShU\]U"pge?o7)$DfnC͸w''.Jȩ7IBf_.#bp Sie,M Y}<#(BME5⨭:!nn."}bDnNҌciڄ 1` BوzzW^qk2Orȧ_'~x\"v)yKau<ͻ.= w[łAB)GSS! kOm:FpՖk@z|_j+%:5v&X((H 08G/`ɌÑI/)P3 t>>lIF&#\~Aϲv.l%+Y6k&^P +_M*,p|j O`M-jr#M1Z,So8Bn@y[֦;SH,Ϟ<f<3| /Dz陖\i[VMAZXMX2zƒ \ȸtdtyIUعٱ7=[72b9C)ے;SR(0"L2-m޻OE4n|^&Q0_AIDr 0EBczahvBRC\鍳S_D.N2HmL`+NBfC![S#G.ܮ>a͌icH{SD\cGBxp"Fih@nK$^V4M@K s,Z;Bk5 4qBXw}t.%Q w@e7uʛmR޴xĔ /@JrJxR 76.N$DJLܒJVj^MVv,]BRJʵMP+oٺhM&<S<%),4V]˙Z c@3-HUPPuvvO`'^H[PwGIbU$%)];NҤs2 sfRx< ,1R 8zcJ9+.--)442iu''%# 29czh(A,u׈pe sƹK矻N$clgǁi+TPJA6b/ۻ9c˗X|ep\ͪ#7cZGЙwdZT++B&&v!dHUe|IFqBKu,]-VGbri!Fs5peYaXd;w2y^ʊNuj^rBxRe"i:&&d!>ڕёÇj=w=.ѤjkG3~ m̃\h֡l`S‚8B/\!#TX>ƼfRycS(a!yLP `IX!'v!P{htpq^$渶VRsP󬾠|Ե7!` A'1Fk6]`g b,Aa(P!BV iB}Y2p`0:Hݬ zk薗~Ű 5|)!uGO0#T!HkB=Q1??_Rk-X{U7=77ݽޣcF$t:aжZ^PЈw5Ps 0H0!1ph:F.[Үa8Bk"ݺE:uK. zmdiFToߌA֛&gY}iiT&ek̅ngIJ:ZJ(h52777$NH{Ay/Bw"`P9{ӧ=VDz| }=3";8d yQaQII!"].4gBGSBHiI1eB{ݤͣ@Rsdž}mm}<Ҽ iG-aXڃBPQqڣ@m*';;%0x#A!BA7fdQ`pGB!Ѓ(!>DU B!B.BԴdb#-B!#ra32*++;&ad2O1(G!B1"'ܼj1<_PP²ҙ׮!B53R:wPUU%6O)ڱ\^V \">RaPᮃCHHHJJJLO!ViA!B^9rggg^/7}NZFmRYQQFkB!#7 8p|y9q~{%X 0 c0!BC3-< 5$X\xʜ#'p>0`Jc<B!: Q9.2ڕ{kEh"r!}nN[{~B!jEO 7835?baG`~H廪ѥnyXSD.\ɲB!\[dqޠ))Ӟ ܔn6!cּ9WN)exN8hRfB!%Y:Z6ա9S:0Ѕ48,W&aOPpioێ^0?~h_~m/ϩ"3Q~0.CNz<ܑdo?{+@Mβ\EB!-]bY-Ôr漹^ Js͋U=2~N [lp.-w5}R'{}qKs>sw?#ƽ4p_JK}T<ӟF*:rB! bS7𜾲8]S/diOp$:(ր_O1U7ĻǍJcb< vtrg,%f!Bu`R#Gnʍ9q@ֶf|2&wN#0w}DE.$!>?ZqR%g nկu/7b@y2͚IDATgP0 q#G!Bw^qeeAB ӞQr9r>0=y@9qp_ikD⤠ O/<})OG~:Xf޵B] a}-{/╝!Bn5)c~² 8@ syd^'UCXe+dfR*D lWrlSJsok=U2B9HŠ-!!Bu4pR:3{''^:}f98V Bn5;"&Ƚzbgu9sݎ}3.1ʂԋDN1c* Odc;3?}ѣD`BGtW+,kF!B ZRZR dͺu#Gh4Bܢ"5/n>v  ! cBXeYV&رc):ڳB!н+B3~rB B A=wcz.q^8╝!Bc0ԪZa, ˻B0 0wr ڜvaB!P!d-oX#:88T*s,U{jn)s:\؂ 9nnnn!Bk*7,ƈ|nѧNҥX,n' .^8h@L#BvnJV8AfsOYutt8p`B! UްR`af r8B!j-V1ߨjEqn+!BHJcVB!BmL.k!B888<;iDq|~~>´! ukӏa;ò>  .߶sGP#GV%"fz7HJN7P D,VS "5F$2F$S'b%b<I"N6Ĉb gD #lYP{g +VWg< T*: X&:u#wϰR ~PcA8?Z0lnv{rՕ6?]q裍q<阳>Wȸ'?XZÀ߹wx0ΑozKjH~o2]Hg훽jætq|ta)[.QMO_ׯdSռ?V2y*x%tEXtdate:create2012-10-05T17:21:48-07:00%tEXtdate:modify2012-10-05T17:21:48-07:00fKtEXtSoftwaregnome-screenshot>IENDB`rviz-1.12.4/doc/time-panel.png000066400000000000000000000222771300447110700161060ustar00rootroot00000000000000PNG  IHDRE)s܃bKGD oFFs XG pHYs+ vpAgz/#IDATxw\!EZgYVjֺn]uoQpk:uoA{ !G FeO%w='*KlSO7jiڈ B3UB!*V!@!P BU*B!T9@!P!B BU*B!T9@!P`,{픕[>{vM7!B6}ڔZpqeTUJ99c7tjZi%jz B¦O2h/SӧM)]%|K4am> xslߍ`6|aЌ5iB!+M}=:С߽%;4{J RU9y 99gQ?W~د-n^8lk2E֢/ߋPEmC??ȵ,G,i? 1=A!jHt* P/`bEFi9Z)LL48v˹weaqS'w??z۽T)mcosJ?reMoPB ]]L6%$d{E^RxOI,mUG/63"CHəf}Wvjz"B_z)44>(FpE".Ii0247Y0>F ғ| %GXU B5b Ԩff>3 5gZX8!qxwO|hΞ煕RUY;Å,!FE!jgO| 4D3ЬJ)B!J(sidD{^%hLo%U{;: =Bgg6XU BI{eVKʬE!] !B BU*B!T9@!P!B BU*B!T9@!P!B BU*B!T9ʦT(T*%M5ݐ2$IéUZ% >o 0ª Ԕׯ^t[J"I[[ې$Uͩ{0sU#KdZjڛnoul.kcm%6ӌnV%) i46晧T,DO|LRt n-\!Jxnjj~!ab5*:40 CQИoUEI*'ךnKل"@=ssK\ }zd |򕛛L&XSR/Yt*vݣ'j444tuuiЄuձ(ܜȤ>ffyPZ[a>Wu=A+EBHdi2B}T%VU^ͺ|]wu*@4I8$EO}zdJ%I4M78]v $I*JBDz B4eD=BB. uAӴfRwh_Ts娈?q[tۨҮXlxxlx}0Q\FGT*vkU*JbFW0bFs}\U2"o}&U0%n"ac̪L||@֝ꎑ*,}cB&IAM7 Si%ʥ T' -]Y*^ū7y˗;F/+ˏ-X=f Y [^XP}l? yl<:~ؒaW^qCK 6(^6pw_;7[v+㧯"vӠ;4 @pAOfk7ؚvF,:FPqL9gu/~0[\TE1_g]_y{#Fm{}CP陂7׎:us(w`^۸?H}hrU@̜t>meroWTjg@S+k+S^Ef_/;sVT:z05]m*yo5qkӽ[;^%3no_yt.nP?@}6hvY~0__Goщ*G~p{OZ`ST}ۏkQ9[" _;eoV_*I_ =IzfplƱ2g]Z]ςg-Z;s8u<0OwA%ܦ*ȖN?,`@ꛛe&. ֆmUǨAc;Y?N_?`_' Z>‚=a_a߬BttƤ '1Ń'~Pq'V<=.;W5t6Zy޸./?m߾8ZZ8bUAfX}= 3;>NpYr&բa~ɜȱs65@ aʑ|"Ю=ΜP]ڰy }9$\we^j L; P1vh"*zliZRROk$a 弇J-{td+3;cᳬt/4>kAA3W+mK $]ۚYzÃoG z)*^|93ɏIK/ 0[~_y1.оqut`Zcfin [|Ec=d\8kXs#ĉ>07om^Fpٌ?m`[y[=ݴ?ͼm%?$ ݝ"7[eWbTc-S}$pĒFk(@/Eǥ嫀[=ƖΎܣk=~cv#?4oVO= Yfno(hQ 8 3oR{OoE\4XBG/o/<{'O7w'v㰕;&fZ^^|/6Cyvn E}DTwjTLuk);ݫBKe P{A{40azH}p3d}`'M= o/{w]L=3 P\Ih܄T4,y Rg\ߪ WΫl#rk{WE,`)"K,K1c:Y': %pj@@KA4&0n7eV/kNM%PWګPUeb [ ~;Sh/ȼsͷ''ikC=}زWC%\]%ԪGoTI7l==WG)_m߆ۋ):9܃̖S޴=%CQT꒮|KL%Ͷ͊#ש`ĝykμnS--R%kw[⦢R;4#ϖ̲SsmL oܔ\Ef%Y+ޱPKb@yusc>lvY19@>yh7rbCc~qkf?51GZy?x*ғ xᅋmMn|z|kMMmiB>:oU^?~o˒F]8xWU*y@PMKPE9R[w4dq4gB\77+*§{CXKOX2zI @_@Ac;9h#۲U6G~;sQf@ ^+WjDc \ڱsvco 2̏"WT^1I={*ӣ.;EfeM+J}{@%\ۿwęCBZ ȜM2R y<4Ʃyһwcbr PLu ͪiϛ%tQA:p|ȋOJO+͕Y\\ϥW]Ygzs6P"8sii˼턺6=n$BH>Gw,(_~\a{^Ճ7ƿ#~3^q֎zwﱣ[R9oPe'e[#VFp-)[ Pg+Onj[Ko7=wYͺ*7rkbɃIe20 ];<'"4#鉙ߟ(c;p邮~ygթSu /e\i>yڰ xctp b/Dfh_Ͷ?;F>`- ݩEc]nj%"@}جO&m\2X,yD%ykD\h+we;i,>}Gs7_zqJ]}?*eGy1#ࠧ|$KoS$/C\wNifmw#]f^}$\)q}=Ѩms?#</κ Q(/*:}7aqqV;ϗz5lP 7s}7{yzL3~_S!8"beK=5buzV_ hͧ(qiZK#.Ho#¸>㷚دko=LmZplݝl V:qn0j`;O}-?έv4 @,,,ԉ| fEJ\(]?tP!xVы&Io85t0$¶-ܧBy2%W^alĤ( e~"IY2e ΀(υ&Fx߉T ˲҃=Qd\F22/.|i 6C{oO-7r”T%nvTzilXIк(BS?Dׯ*Hkʜ&CpVlÆCC*nF yw,%$6(&A^4b@nN$M+00ໞ_inO4hXȖ,P&1#@  ͜'Ϧ^r7 ?_QE:ZE'e {v5- Z5[hmX K:A6~ά\sIuvf?zx%Mn0 !yUF$88m̪6sMjU|]tbһsLh!$!_-atcZ[r;cA4ډ /5GkUa4,в Hւ d-'OLATЮaס ;v-՟ҸsC8}04|W8:w\p:HN& ÀAos3@—zv_E2;1fKQYOl?fefhQ yAj(02%9Ɉq}hɰM55f]Fh7 b:DwlK?AKgGv' 5E?̥\_oS @Шqn=\&Z]2 ]U9ff }ƵְULںkwܱv+&oZזcb/G0WY"4[ǒXlbU/U Kdk6FJaDp6.e3y/&k29z Dɋ񌱣 I|.3zC3[SY$~r_˪~_K+[Zil&^*P5`Īߺ=mȼȻ  `j<ۍN)) ڞ3oH炔ɷd@ Y2%.*f|W%~b6@SpĮD8B6V4M3c@LdvBLi`Y٢˚!X,(Pץ(q]/Uh]3ޥkG3g{@|4`/9vZ%rby䔤D/* R_ăwEw6Һ-!ke̛nxdEke};yqZPbgg+02z%(@}K- QzvT|2Ό@:PcMt?<&2j^ި-+l;cYi˻7=aHD'ٌH0N^wn`ˎ8zW6 <;eI2 IUַ\kUf$1 :vx2:Č4ukHXHc)Ǯ=˶ُhcJg}81ΝO@vǼ~^|kg~e|eƶdq'L #g1s 6:߳f]|m3sEd{g]y<,PH-5,Tagʧ Ӣ/A+/ӪX^q*}Ugᩚռ'n[w.bѹYگzn0a0Î`/PB;c6ܯExk{j߶[ƍ̥:F>lS-lxDz1KwΞT67o01yJT[Y> .%*Q?;sd %ʷϫFeA 2S# ˡ4ow-*.!aYnm8߀?5aH!KΪc`f#TlB0 ?cX{s Ԙˡ"#3p;s'VRhз^c=0tK*؆6fVp;~(&<$ڼ{q+~^2l;@95xR(ßdCڱ946,xwҨɯ+~c/׹;Z _0VQe`l謾=(`lj>@ lu=8XVD91@u)<@/:.nL=5ىйC I&{m}-=жɠ.|=KT`i3-qՇMK)_sڻ^cǢ<x~7:wݒpNm O.}3;rG>12jg"(6%t`uZ'QD-xhM(*L]_y+ϻzbN]Fšnڷk y X\nv3A 4U:KTe9aaݻwd]C {!VBCb׫($I\c P谫o"BCh]tQZoilfH♥!З 4ץ HQ*474K@Ϊ/It/ψto0&*JͨW*ndK; _$y<4](t[ʕ`,2it n\2 #D"f,4n{ExJtV呒lffaUQE"\ +]?MT))ni@V!*0@YqD"133S|ny4-[]s@0LF4IdnNvM$$y|O\Tts n-\ȲXo^߾}'##[(ltձ(zjT èhVW0@YbQIuWhUXU Br|5B!V!XU Br`UBJJ6 Bs@(8!B?\1%tEXtdate:create2012-10-05T17:41:24-07:00 wG%tEXtdate:modify2012-10-05T17:41:24-07:00xIENDB`rviz-1.12.4/doc/views-panel.png000066400000000000000000000612321300447110700162770ustar00rootroot00000000000000PNG  IHDRYWbKGD oFFsC] pHYs+ vpAgdaIDATxuX] 认("**t7²Ygܹs==HIq4 @@К  C@! h?" ޼`EN?/ZP߭u7#/~~wrlʗfsvS+Q /Z0l[ۺ/ZPWg4A;Sw}0҆VumKCQnJ Aɓ'bcD-GGΜ9% Z$u ;=gU$> /e3uC|Y'VM=dSVN ̾`舵oJqa݅C/a'x/2rؐFNY{#B& Y~O9q)ꛉ]D[3+'UjĊ8Vo򲕋'8bb㨊|^1 [;i;vիo҄A>)/ `kyPk\}gr6Vf6AcU_(Z.1sܴw0 dG|)/>jOa4-k+S ĈWҨEHwZS1xiqSV3ˎM 2tؐQKCiNh61EB^/d^*ioxEoy{s:EקWJضYǛ[7ߙ/GX]-/,5(^gTf%UI{ʮWV+̆zdnxXH d hxaͣb#he~&K"wj=KTٵLG~Xv'Oy(ƣ?}kk$]y;1D+C밴^h证 6TK$j#}U&hn)W'i2{sz>N2ZƵA Э|[n?$Lf f^MRl'+!¢Oʴ4xQLB DB:Gllmaj=)Q@7'-zQ@N^]>yl(J&;B\`e)w~ t]ӇZр PwgA{Cl$ h4Ba0PF@( A#h{EGBp0;@Z (f>6Ƃ(FQWSp0?yTK -Ka)((HHJTSS]q\Sں˳xqˋ'HJ8WQҲVQ{!" qN>j,!_RVVaZ5y4\YYY (8aEbs%#YJIX,^%%%6 eqPG1:a KO\3XZlʿ\;}= x߆g;Opf`yo.{)92q0% 4)%Eż}=\)w/8~O,rh׌2>G"14NJ BaG=piw]2`/,zܵe;S:.[诐p|oj)UM΋7}OcʄH[oܸѳgOSSZvɠJI$'Q}'?鞧*a!Beݸxu|!`}H_m*̧gϿM-IÌ)/yC.5+m)I]4w(Xz ej s[kPQ1]$);/{]Z3ko, P(0 *> /s!U8$ux].[Rcz.EOtU|{<%-dE_-nӆ ɩQ$dύK)9AP+~"cҧE]tTQ˓#2P[7Ű܅B؉Prw-2㨲ĤjN|֭[|>_޻wo###Qѩ[V~GϤ H}ZA=-dqgMa)Wƹ)KQ&y|y VynۉM v}^lL?oQ3"4IZihwsFH<݅e rC*+J%KgGlUg$MF'E6Vl+|;Dfc*/rnE0Dϒf>N)`8Ƽ4A ހ`c#HatSgM_U+V+~\=Kq{E6i"W7KV+@bƩ֒y#c{Z0| K]93Zcw30q@LyX^p9}=Qs#5=Ll7LH՘Ziwlg'ۻ4S:5Jp"*MKPXշ)d/Z30U-P4WO$>((0@L/,o8J*z'8m&-P=RAd~P xr@IV#Cr\V<&CD5e]e׈W˳*1LBjɼd* 9< E*US2~5EχYɿbT*r+p*@!52d7,P.lY2<.OJ>^AR0@sXԣ4e q:Ss҈NG {YsQo)̢:jӨHPrmTCr0ftGk ?7bUWs9ԑVcZ&k)!U7p pJvG.YY%|Ar(Bc1PaPpBaD/[yIgiZ@b[tD"IjBHbcd4@eQ~&ٔ&3&)BtJ>EZUuITbcԔPE e-?tҘ%Dѹ̆30Q*,\I3#|([y-;~~NnZ,Y0Em۹=ͻ"R:]:nP{zϜد\/ϋ4|G!OQ3U;VqS峵\\ɡPB1]EtLr9'cW_h)fg"BCEi 2◬klE% d.HNU-YZuG#ؚ!=8T}U?'nb@*y4 T\:9?9q ,^~W_VMH9:/vr@O9Ǡ%5I@|KAǷ9یEXrV}f4|EsA@M{L 4Gq\lQM̐a!YA߾?ݙB8-'>Eͱ&EI2sq%m:P{amXF2" b>c;V6l#-\u_-rK:4| S+jM4D9Qy1%%y.qY9m^w=AS7_k3EHcep9Яwk>JqOᄒii= ^nǜCԩ&;vx߯?y?4 znݺq85 n͇ܧ E87I3fvj~ 5%%b@QO>$ EQDܹ3lP>W+GP >Kui`gg&$$ǿ}g^}m~~(DbFk9!chV曼l$1712ˑl;uD&Tj^444βw6_<IB&ܶE1Eݮ̙~_)9VsBCj/Tɹ_78`8~z1Dw`y)N~<|G&+{ ̒<K~T-4l&=7Q 9g/c݅0Tũ[_G7ߗPˢƌCPNq ZLZH^O ;q8+((婨0͝VT{T|99RTԚ߫+0999~VCCCGZ6A ayyy:62_5J - )))o߆6wZ!H mڸM@ZD&S[ 8ɣZiY]2BAVm5/PF@( A#  C@jϒ}xI"XYISAP);69G~Ʋc8lﱨ!Mt0P_]|ϯ ˾F}+Iuc-MPc( )-4O]jVM@q/Qy\99z s?<8e ߂CqRns/rZ޽d87/MIX*O(GmP0DAN螳K52|ANӗ9uf|r)_ķe4,"aĦf (Zn-Udm)KH-<9PhDIZ@z8/}i%/Kx f w K~ 7|'Nw 9jԨZds紵o]xT|eE}a~j1KVna^Y *2ާ @DJAI ]tQ[|'8+1~btzѾ}xy}Ȣ:鐁|,?}@ݹ]#kHng2#Z4y:tgkk+ѽ{w8;Ojg@EJ=BTSKy*Gd~|mRVV1 Az[@h{Pnng?u;Ws ާ@װm!{Ŷ߈bG$e[WEXZtB<D% -7SyH|&, &$]"[ gkZɰ|='렡]Z&pvLPRPr2SV~} SC!i~M*(rf0ɣe|DVΣCg' } X ٪V9;\MVPaILL8(yd"Zh!0Ǐ&?#x6g@,77<ԥdcpcԲB_M1k 322x<^VV@ 4h-KMV.=4tm#K#^),-B.'bbrxd2sAbE/K+SeiMxwJX+KNg !SP|zz^  EYBFU|TΎ T.5PvfNsrR<> r@FZ/KMɳsW;-%UNY#SQـ~N+(J&#TZX\&zF3*ho&,"%&*PX en(y6BST`rKr*( 2f*PUB*:{5k/[JF Jr , IendL$N8C q dȘLj"KwvxQ̛,UM_y7P#)u0*u=K\lkP-<Z}"aD Rx<8YI%|zZvYL'쯒5lȧ (ThT909J YO7+jy݋Wy_%[H1R0Bva ZtɡD!/ S=_K@ZhUlgHaQϓg:dSQB?itiii"qY7JFk=H4%ܯq $9ϩ"rn2 b+Ĩtԫ\ގjY)*K#eDaqBF"ZS'D!dC* PiadjXqvF/\Ti%v֊/^gƤ -W:$Ț rWU Ep_ #b޼yƍ;wwUl(O-R}0" MRږ:I*ꔚ !E7qxQT+'7_2qDUOfERdPQSՕIVI\vMd /Zԝ}+^(P.-ƹ\+ņaUt p.,tCPu 0LyX;ԾTjI۬ G"Q2 0P2YGHJELŅUQWЇ_r֮VW; d5 kȰ2yCK%yez?{%Bv$+C#L90ڴ7b YSQT )q{GQA=E)@zIQB6r=у|h_++ y[Pv|8Y߻W_s4+䴵-~u2rDJea[NRqT D4W6L\F যHZ2-Qu<v0QyA%CV1}J3rqeh9H9].0faBˡ1K"[)E`E a}b ʾPv8MwɈ Uta~Ԉd?4@Ǿ(Jԅlڈd?fЭK5Saw54 SWGjhEcEFFF͝ j^>Ba0Pz9b͝02B^ @}wv`[%-oE* {k5bGIS}Yf' 6ŋb|WrBU56SiVq rCb,8P{ dX~f}U!VҜ@q7rZöJ VN:?o =~ ~㷼Z 1L-MyaC*{Wx .:[7yLo7vqfw_] fZ:PeM ݳd.2/A8 `Ѽi uӃZ=\߹ԣ!M˥ExiQ+mz^@Qϒ2K6_M+Y3 3ZvfEGJaw%W2"޿uT\_bb>SiYwÎ<9Q׾e' n3oHLE\3?NrUt~M_j_ӚIUԠ~-l}rddZX{ֈFJrv_[ʋs7< k.3}ոPG~g\ݶrAaνV^:ϛ|o(z}6#sȊ;YMV=|th=W,Ip|ȫ[gn;nIG.wl5J״pL`ܿ[z=Gl7\=3^n?j:|zκ?ڍٲ@ qYǚ-%^62p͢s&_l>Sc?>D76q C@ZAs\rEs' ZF@( A#  C}pNC{&6Ba+K 3[6|m# i=~/-oLqi݉uoX-vpFyOM'iLJ_oRG<.yvӝuZFs9-^,0Ϣ&e/n5Mk~IKHqnUUa%+R6S~Z Tu+uL $i۸Ypc3Btn~E#\QuUz#I8~}bha^$~[_F}F̙϶+IVo.5RhZ9:YJ߱lHS+܊,y0, @r=cos  u ۼV$d uݡ 3d /Tugm' 0m9zc6j8~.4g<X t};%ihX8qǖ-\ g5y2+Pe.Y =;[Om pSUݰΊ*rÛ.|yLyqK7UG--0ֆlk'a^hyKh Qs_\)4si;E uwRBPXi$e^|%!}grl>b ^M)o\L<ۀXu}tl+#+h siFgg):8xz7UNBÑ$b~ K$Z[Ct޵6ߑk_c鼯@F6qǷ[|84X9k'e nܧwbby0/խK K .ُ^~%S_ mt;N7!ݽ+.sT&p}X&(V08;=Gtj)37xiL0\[xO5T_V`RxC)(]OܴGw|[nNW+qYVi &գ;Y-ZF yN?do 7=" vG(`e1`icH,emD @VUBe\JmgF^?Y:b~֣0Ogo|3xz3^qDrKwߨ]Mz]D^9FOgĕ,pyan= @>%+YtNJxd18Ē"^7>kAp !ːSJVIK蓸ٟ]pzH2̐!NY[Qaa\t!͒t+R)W_:z0jd8UV5 dTsP(]z;%"nhb躳ﲃ;[TUźے.2(ICCNXqS7uomKFդsMI/o7QKB^\:Ϊ50Qni|0 +xw3([@[p}(6 ] #( q}J1na]4C) ~ PMl:;SAwBT0PF@( A#h ?z_޼#Lj ~-Ra]Xtg UfhhJ"~K~hxBƹNbu:z2IeN+ Jhٮro:tح{j݄]G; 鞐O{g%}ȳv䨜[5ZXL읜]ܙ'9vzA֮p>~.M]]=buvFeGbN'bxٻ#:{X,W1~)@qEXבK}.Ļ[gXۦcX>&nNj!,k xqة;cVݡ}+g9rCN>L':ԁi#O\ "O]C*y>ʽHJ6cܲBSv,,*7cM[3rKL@8! h4Ba0PF@( A# xi܋9-4-Qdng]u7C>/yPKjX,{R<u%ʣ^>3Wz_95Q7c,st̚_"Kqs_w 2?;"f2@6HnDTPdܦy8`/yn9oE_/մ>B;?ɼmVf9⭊^[o=do.u7_&sh Egx/TkߒRMk~r˴L ,*Be^#2jZ.DPy3έV#6w(Zf hdHդyZ$Aޛŗ8p]f;Wi|Aλ2DZCrB"1NO?40m G*'w1g \u`ʮ$0Efw(w;y?p2ƾmJ4ˠ_oAr=]VVi[;>y2?7x@bh*@iVIn-`8r=oZ<-rqB1VLqkl\N}fp/a+&^[:("_:buKG<={x(#$z53ha{Z0ኙk xIN̛s&XaȺ^\{R혽M(). ›aͱL"B=^3YG3 ({pq wLd2-ɯXә+1nx6i$%%U̞[>qDZWK;1{O YĺU*p1As||8Vdsȉ$Hwx1K׌ӆn;c88.̺>aڣ|a==DV8݊NREreY;yћ! rޒy?l`J--Ncޏ ̌ED% ~PJ 2u@PQTTmJk2Np3[9fj^oH|\@qѡ6Z-Xa0r{1hS'V[2k]PumGw;Y/_fL6i]{53m)r'۷٭9;o76H4yKfn!w# '{ţO܎ge|A?5|s_AxyF-Xa"W_]J-I~\ * Z4~S־{`D9+gaf p5H5OFR#ǧM%:0֒&0yը{&t"dwu: ,vI{Nho@N-XaLnHSPQ)w'qiޏk(`p^3ZYL\n%zD8'ɻ3|V.nRXX:8|>z YTeΛËssIf lc9B}8$0QS\Z9K6vv6&zUR:ޒz?[h928Q/9PeflR?zz7s>읻;=sԫu!O @TEM]M8z`_m+FF$nnAdUт[P[r/iޏ;ž%LٯMyyR\BQ7Ғ3Y`3VA|\*j`&SfA3 (ܜ'.d+̱NJHH|ƒ8Ol.[us `[d])ޏX 6Q^Ƈx]0lC>;nrS&Yű8r~L=&N~rs8S+'jٓL[{SXL~|^+fhvDB(4eA( A#  C@! h4?d\F q=ASaQT霟7n1ub_]?ҟݠX }6ոfjMiYU7usvytp-Xe&MMX2 :tԨQ RfWd4jlת騼BWR!;L^?F[d86ٶ^dwS(M^5SۍG.fݷҍ \i,}ȳv䨜[G/?'>6c{'1f*?_18h'iܪxEݭSX,Vg {, u(̀A7- vܴݳvdX=ƮY`7ư:.yNܱ#zX,˯AꈿbXMY'dAqxGGL*1/e͗666Wvpp1czh8& AH( sk;vD;ٴ'Gv/\"{z"*8ngE9~jMGsȱ.< W&xszo+L;Prk0cX"sF:^ykK5Pi[69-zDW9`BP l CP?[YMMMNNǏ#G++?|~A_{]1A M}U'(۱`cJyoJwc<W=(y҄Yw>,dvwM^33gz-Z͡n֤W=P8Pd MM]&d˾{m``6p:xB5T&ɟI^^^bbܹs˜:M4AdԌ쨸2Ӵ :ՁSe'\xZQq~Wf=y\/ͻo?ʡʡӒr+6:OPX 6ReB%Q3]lCYH p"8iu[c>psHqq ]ICGSI;DBcj?0T&ɟd??ׯ7H[@Q1bC*DG}i¸Bj#]̭t$1LJi&+Y[kKh~ZmaLJ (MCG tٺk;xϱky~RV(m9w d;ua#~Z{ܷ\ (횶T'd]f!tЄ/F@(\d,H;?fEg4k?aOnם L[=Xɗwz]7d>A~d$Ǫ-M詶nPM78a: b Aɍ9@t0PF@( AkW8}y_aЕ=GZudCl+6\7}Ofjf,̸4fĺ7\;Mj)mh(А>Ryr\hg&YAʙٹ.*{+{ՠ>P,<oV<`6vzj>vawGZ׀@b+6 MuGĹEBל} Nq׷nz 7};.9V_mqܘkV~eL_^(!yv%'5ʋ22dH>}^z06tt+>5s?>fBqa۽3G`1LWQKՈxa%Xә9l_^f9Lf_,eoureaK;2G_8 sMdyM*lkxQu+Xq’1vEU.s^Y8,d2;[xu.G0;L"lO=7(3*"`+zaL&du=u3:S##ޕa8~pÓ,ݴuڹգϟ=\җ|4X"y4߰s]xyKs:ge׻n}S"k[/#<%*Bqf[ ?!jPI2YDWSH4zM͝v(ꡉ%p/:b>f@cs;=*V.2x-[7ჾ?[X)X~PVIr9 _XyέykNs8q*71lzZuImo8"}.ݺ}$'o /d#ڔ֩fƵf= ӳa?CJ#d-:> y9ܐI|^۽6aw^xp|GUr~nVxqe $,6*Yi<ăMu 4[1 =z-`Ń(q#}3dG{a|{A 顑E#TK_&T7nZܝ3^I"eN\&Pj!G&nzX h @mj"WmPKv]v1efzJ?M~Q? iF?r.8EǦI.nY]/.0bœCP^6ɑ]Q5kwcջDv5f}97u"VbH'y( v~#1h})ȋ.g*sk(K164!0f[-N h7ݫ-(zYZر1t'͸Uǚ"ODFI - >? ]Ky{wq\D&$uAވ9zeaG)E/7%ymn<S!k K=7G[6^x#@R8tMNc}#7~*cn@NNF}17,*@U1r8vޘTU=C5EJsDVC@D-8;Wrh{.(:|e*v_&XxEK3資•GjLq@H /c6`Z ^<¨5noL9ݻuDڹ{jX+JeQqގ^KoƠ}/ժ<{/۾ߘ^jwlâ=|H)Ut۽Q3 '06X67x}mvz鎹y=̆NhiHs 7;rR^Gq:͚>D$OVg1aΝkmE+xy!e@׵.PE{!v^*LǺBvqR@a"{8:?=v҃NMF\sʋR{2k=qioIȩ3Y1dI{{i {2Ǫ/8f[6K&پKYh߶)<UG@aiϿ&e4>[Wv~?#nP?֞~5Sш",_J&(7= W^$deW,e*S}8&:><(vgYWs9~,O͐4IO[7xh]Auc@1׾н/ݻ&[XaةSm?dp7ձStmU>ǹ"xdmW~Lo.c*KFZ=x}$ɳ;B3jy*:9#[uH~ Yv.NZtFTNzMKvd)`1fH'ŗWFuנVt y, Iǧ{8?=rUSՅuGvwՕ*BDŭ]gҽטYmsZɵ%YV9k߮L 5(ͽkA v'WFj.)o޳帙o?h#rq@m G*31OR4L"㋅j(R%oכŘw0:1FsW`4O[bɴ 7*\JL4)jþ|K{@Vӊ9f.Z([@|mCOxncU5vV&8НٰLȩ{V]Iø-5TPv_&I-j2t'np]}S2 (*h)ɖFee ^l:uv?:"H };tS"ENB7tR~unREբ c{5Mvi㣶>)& dr3wnx>߿cU͢GËhe0~Vtrڥ6Oo *8]}a .6)0z͝*l-M͟g7nN;w05c9=-حr5C71x~\nOnok´`OYP5iSSq!~j\ ӕZ.Vs ;'WSC!UH7 3iPdENvqA# @J%tEXtdate:create2012-10-05T14:21:45-07:00<%tEXtdate:modify2012-10-05T14:21:45-07:00MkEIENDB`rviz-1.12.4/doc/youtube.py000066400000000000000000000063021300447110700154020ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2012, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from docutils import nodes CODE = """\ %(extra)s """ PARAM = """\n """ def youtube(name, args, options, content, lineno, contentOffset, blockText, state, stateMachine): """ Restructured text extension for inserting youtube embedded videos """ if len(content) == 0: return string_vars = { 'yid': content[0], 'width': 425, 'height': 344, 'extra': '' } extra_args = content[1:] # Because content[0] is ID extra_args = [ea.strip().split("=") for ea in extra_args] # key=value extra_args = [ea for ea in extra_args if len(ea) == 2] # drop bad lines extra_args = dict(extra_args) if 'width' in extra_args: string_vars['width'] = extra_args.pop('width') if 'height' in extra_args: string_vars['height'] = extra_args.pop('height') if extra_args: params = [PARAM % (key, extra_args[key]) for key in extra_args] string_vars['extra'] = "".join(params) return [nodes.raw('', CODE % (string_vars), format='html')] youtube.content = True directives.register_directive('youtube', youtube) class .................. this is not done yet... code above copied from internet, needs massaging to become sphinx-ish. def setup(app): app.add_directive('youtube', YoutubeDirective) rviz-1.12.4/help/000077500000000000000000000000001300447110700135165ustar00rootroot00000000000000rviz-1.12.4/help/help.html000066400000000000000000000133051300447110700153360ustar00rootroot00000000000000

Key controls

Switching between tools

These controls work in all modes.
M Switch to the Move-Camera tool.
I Switch to the Interact tool.
S Switch to the Select tool.
G Switch to the 2D Nav Goal tool.
P Switch to the 2D Pose Estimate tool.

Controlling the viewpoint

These controls only work while using the Move Camera and Interact tools.
F Move the focus to the 3D point under the mouse. This does not work for all display objects or all computers (yet).
Z Jump back to looking at the origin, the default view position.

This control only works while using the Select tool.
F Move the focus to the centroid of the currently-selected objects.

Modifying Displays list

Ctrl-A Add a display
Ctrl-X Remove a display
Ctrl-R Rename a display

File operations

Ctrl-O Open a config file
Ctrl-S Save to a config file (opens file chooser)
Ctrl-Q Quit RViz, saving current config into ~/.rviz/display_config first.

Mouse controls

Orbit view controller

In this view, the viewpoint is always aimed at a focal point. You can move around the point (orbit it) or you can move the point itself.
Left Drag to rotate around the focal point.
Middle
or
Shift-Left
Drag to move the focal point.
Scroll Wheel Roll up or down to zoom towards or away from the focal point.
Right Drag up or down to zoom towards or away from the focal point.
Shift-Right Drag up or down to move the focal point forward or backward.

XYOrbit view controller

Similar to the Orbit view controller, but the focal point is kept on the Z=0 (ground) plane.
Left Drag to rotate around the focal point.
Middle
or
Shift-Left
Drag to move the focal point in the ground plane.
Scroll Wheel Roll up or down to zoom towards or away from the focal point.
Right Drag up or down to zoom towards or away from the focal point.

FPS view controller

Inspired by first-person shooter games. Drag to point your head.
Left Dragging rotates the viewpoint in the direction of the drag.
Middle
or
Shift-Left
Drag to strafe (translate) left/right and up/down.
Scroll Wheel Roll up or down to move the viewpoint forwards or back.
Right Drag up or down to move the viewport forwards or back.

TopDownOrtho view controller

Top-down orthographic view.
Left Dragging left/right rotates the view.
Middle
or
Shift-Left
Drag to move the viewpoint in the XY plane.
Scroll Wheel Roll up or down to zoom in or out.
Right Drag up or down to zoom in or out.

rviz-1.12.4/icons/000077500000000000000000000000001300447110700137015ustar00rootroot00000000000000rviz-1.12.4/icons/classes/000077500000000000000000000000001300447110700153365ustar00rootroot00000000000000rviz-1.12.4/icons/classes/Axes.png000066400000000000000000000006011300447110700167410ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME7cIDAT8˥ѿ.QOi q5.dH 撘D,b!ğhR=BҪs=еbB{V)";9c#Td(#傀R}=; O@40 GGOm+mrLe! ɅPݔσJpF̎{r+ !r ‚0SAT~,߬tc٣S4A\PY%Y<۵#kbcXϷ?Ud|b!3>%eߕIENDB`rviz-1.12.4/icons/classes/Camera.png000066400000000000000000000012751300447110700172410ustar00rootroot00000000000000PNG  IHDRabKGD pHYs B(xtIMEI9JIDAT8ˍkSab A-tj:T:9fTZjH n  En iro&+99y9Gcb1Ov\<33i`_|Y_CE{(4y~\E4hRīŗT*>0KKK"344D:4M, ˲(X7\x-@ gG8T 0( llS.R/9sJG*J&nOh4a5M~y ynk۴qi u4M:UVϩ`We|>PZ-RyP@S+Si7,N ,H$8r\YFGiWJ%l&8`g4OW}@ pkm0pOb31Y[_ E]םu޾yws  UB@IENDB`rviz-1.12.4/icons/classes/DepthCloud.png000066400000000000000000000006271300447110700201040ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8ݓJ@ K$eC"eAFKU^!XX V6fMع`psmf M wQ"XC@9ٶ}`YoM,뺾%'cLSq]Wfcd37T($ CɲLybK5qX,~Z)|C!0Xlxݨ}WNQv x[78|? 4I image/svg+xml rviz-1.12.4/icons/classes/Effort.png000066400000000000000000000016401300447110700172720ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME: tEXtCommentCreated with GIMPWIDAT8eOhu?Y4ME; PS;D 9(;HaF?Bjw5Gwy"N:AGХtY6Ҥoޟ׸s~/+gC//:99a`ea0YH&S' K]u4#nr/A=]ZN{,;{8oLgwie`X4,'̍{]!X/@3\! +Jr{2oSk4"q 8qҋ.V* 9#򮱇l`DuVKmN+kTkjt. 1>>+ok3SW[I@' <bnkG^}p:UH";i}SL^׮eY8C 0 j\[Gm M6#~v~~_ܮt]0V ˲h4|>R n.-UP($f۶, 5H^=}%>~@1t!NJ):v]۶q-g2l} h۝1Zǿ ̌FMMM]2MSuVVVxQ_v]K4_AJ$'d}ԙF֯X {ا7w(]j gCDI:A9rRՅ|>x=KNN pt3x'D젍,0<Lkwߡy-2IENDB`rviz-1.12.4/icons/classes/FluidPressure.png000066400000000000000000000005441300447110700206430ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME(,YtEXtCommentCreated with GIMPWIDAT8˥1 0Gqq+Z(bR:v^]xMqB 3;Y_8}h; : k& `Ա$. P-dYWzN_DLt^$9Ro5@)]% =Cy3 <f0&+HIENDB`rviz-1.12.4/icons/classes/FocusCamera.svg000066400000000000000000000331651300447110700202570ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/classes/Grid.png000066400000000000000000000010651300447110700167330ustar00rootroot00000000000000PNG  IHDRasRGBbKGDC pHYs  tIME 1!-tEXtCommentCreated with GIMPWIDAT8ݒj"QQX<IJv/EFBRM_@H-"Nb9V.Lr2E#;$d˅9%ނ$@jB?"nrZF~6a¶mV+h>9, D~!&xNICJ))z6VFH^ W:zBk~dL&T*Nx image/svg+xml rviz-1.12.4/icons/classes/Illuminance.png000066400000000000000000000010061300447110700203010ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME8IDAT8˝OkSAGL_6.nԍ EpU>AA"Pt­B)n H\HM+.1>bL7M *1[ݹ9;|rA r׹<׹OԗYզi /z`R1 |k7Ojh\o~զY57rVSY|©N4M6(ųzᓥRi9w(].'IAZEePnk$N'jqT,H07{zcv9Wq\OE',{oAUPUv!,3"2ӓ+IENDB`rviz-1.12.4/icons/classes/Image.png000066400000000000000000000010561300447110700170700ustar00rootroot00000000000000PNG  IHDRabKGD pHYs B(xtIME 6IDAT8˝MkA4ݘॅ\ĢSɃ@g(1 z @ ՞TD*C"&nٙab !{fgDQ[3ZyBQ3ZjQ31nKVWpf,µM4(HakM0؂33sZ$(l~{?CR@4yò,.1SrzoD'S@)_@JNh'-\̟.@:} b}x{_ʧ|=({hmh9%_}z=oj%1@usIo?GN7.nքaQN&x3iv$ĉqǨLdk&|[Z? Ƚk^CrB0EJXᖋBIENDB`rviz-1.12.4/icons/classes/Interact.png000066400000000000000000000010041300447110700176100ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME+&!=tEXtCommentCreated with GIMPW_IDAT8˕O0B#V"8pG*FQ3<}GL&q=H}}LQIENDB`rviz-1.12.4/icons/classes/InteractiveMarkers.png000066400000000000000000000013711300447110700216500ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME-amyIDAT8˝S[HT=wߦZ*QꦤH\ uIݲ6 CScd=nj(? *B?B0MH2H#{ 朙16_c GW Lc 9\H%8^R+[c(έu0jc t:?OZWK +=r8W22 Y@CHXz-Q,8Dn(HZ Q7O$ 6մ_SS|{=A?̇-K4`m(O#o~qR`# iB̠ݛfg2oN'WMC W?zacc#M&0V*tN'}@L&Bmmzn" *Qޝ #TxШ|_k;5wTII㜢 RXPe*'ur+3!ud [\rSB=VlƔTIɹ4G)nI}YBWLܤR\~g2v¿gZ7bLI;0&C2ø;RB**ann0HU󘗱r8"0uNlIENDB`rviz-1.12.4/icons/classes/LaserScan.png000066400000000000000000000003161300447110700177170ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIMECLNIDAT8; C[k ]d~ /P0p7V5T2BW53WWP;AqV'nIENDB`rviz-1.12.4/icons/classes/Map.png000066400000000000000000000004041300447110700165570ustar00rootroot00000000000000PNG  IHDR7sRGBbKGD̿ pHYs  tIME tEXtCommentCreated with GIMPWcIDAT(ϭ; G-ຖkH'RL+lviB dRKFn` ,<$?+Q]˕OrQڄL3!IENDB`rviz-1.12.4/icons/classes/Marker.png000066400000000000000000000007451300447110700172730ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME ftEXtCommentCreated with GIMPW@IDAT8˕ҽJaG)@JFrils^BUVE !""] Q"1&;gwA3 晙[a% _'d2^ ģ|Ͽd>42e ^~ِO5#|ÆH;8KFJ WV lûMYԳI|>bE.p\V^`PO.pw¿ƿO5 ;RRŭO1"HF׹p\ַ}Ú(|iúv7mLhdS dT7Ք˚$NnIENDB`rviz-1.12.4/icons/classes/MarkerArray.png000066400000000000000000000012251300447110700202640ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME +gtEXtCommentCreated with GIMPWIDAT8˕1hqE$!tڡC&EJ+;t"*uiYT<BMHJ!-]J פ4gr%)bS(;(w  @Ϩp&#\`#G` ՕcDx I1O_=EE=*d`r/Z"UEDn~aH4 p3$pWjXV":*G,?w6S|>OG#,Q> Y4 ׁi=R$QDAy&޶fjN&Jnσ,U+o\N~P]oP WJ""vhQ+ sF,Psz=Lk68![970G}׷PBftll-b^ӛ8X{@2yHy} JX 3 image/svg+xml rviz-1.12.4/icons/classes/MoveCamera.png000066400000000000000000000011711300447110700200630ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8MkQ;b R., jVu՘B7dB/?JZąnta~BE Ա -aN SvR}8WӤ "_1ɋȷRPD.`cc`-KnZ91FZiY庮 @looeYoc۶v:[j~.[[[EA8Ͳ쁈PJ7R8nhcZ8R7K:8 fcl!s~V*;wxxxgg`08,K4+++v[Ci6GEQ襥9l/GI%Ir7jρm\}`q8%cq]`J}0yt(GQ4i%'*׀J)|҉y& "MSIT0,<3?("hnwt>n;Z7/ze666֍12V]-z2)aSNVIENDB`rviz-1.12.4/icons/classes/Odometry.png000066400000000000000000000007531300447110700176530ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME70}tEXtCommentCreated with GIMPWFIDAT8͓+q_%ƶ~7I8+@pєRJDArRvُՏf]<~~ÿCߛb\hr+͖y(aE"H"ѠXJ0ymH_8 0]THbIDɚȅMؤ^M?O!QgLd-k{Ϛґb 3XyyѯpU,LB:#nZ(($s讦цFgJ'Ud5v$DF[-`nz= "0wbcX'~r&"0^; "aChAI`}NhgNA(IENDB`rviz-1.12.4/icons/classes/Path.png000066400000000000000000000006131300447110700167400ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME1FtEXtCommentCreated with GIMPWIDAT8˽ұ+Q}{]?qR7F)eSt FeUnIa5x\zˡpWW luдL˰O U5(:aIENDB`rviz-1.12.4/icons/classes/PointCloud2.png000066400000000000000000000003731300447110700202110ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME';tEXtCommentCreated with GIMPWVIDAT8c`hBʘ@w.6uÇȀCVB Iw*0 h2ɈUHR!LQ,Eze&VELIENDB`rviz-1.12.4/icons/classes/PointStamped.png000066400000000000000000000011451300447110700204540ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME!2x\IDAT8͑OKaƟyT4dRbjSK=1PAzF Q)H nv}mBJyܻ}չӕym6ӛ>gI-g죟gϫW杗9Bu.{jirią#:1Ə $`6m[A.Ϭ5ֶ;;#E-}q" €>@Q" Th7 % C3 !  23K'}tKZ!:pHp8ʡa}8RmW^Wĵxˑ_,PI:td~ns S%ڿ&$R];|]gy`oboЌF` Wd+w:t˓ަ8^hltT懆NST.ot>[aǝK̉ه wzfv3IENDB`rviz-1.12.4/icons/classes/Polygon.png000066400000000000000000000006371300447110700175010ustar00rootroot00000000000000PNG  IHDRasRGB pHYs  tIMETtEXtCommentCreated with GIMPW IDAT8˭?/a}UM-ԟ$5v >ŗ`0,Af`K$FL"A[6vss}ι &D$B2lQi!ڱ; jƃ%7RҮ!)fMtW^س.hb -TQ- zVQw*j`7^T<ͱPBt}wC C"#xŭ#cIspYQc 4W  !A$ >[TnG:mwZ+2?F:8/.IENDB`rviz-1.12.4/icons/classes/Pose.png000066400000000000000000000006761300447110700167630ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME-'NtEXtCommentCreated with GIMPWIDAT8Ւ/J 8zzwI f`D$6t`FE m?2+wL균1C<7=8λSH:L*`[!mU,{c96R"U,V M QE6;?dPM$l vǣ*ճĻS4n?yxuXOs>"̻rDEL4*47]>q/6;Nm# ѯǙ|蠒?g~4e>.lIENDB`rviz-1.12.4/icons/classes/PoseArray.png000066400000000000000000000012271300447110700177530ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME3-z5tEXtCommentCreated with GIMPWIDAT8˕kQ7M61L&*"хXp#E.HqaǦc!ĕE(HDQڂc\5S5|{І˦f6Teޒڕ8 %ۆǺ9bN2Hfu \b,L'RyЊe䰯a[$aDFOolFIv9(i{.R8ՀLMjwp`q:ͬd|I0܀63y3aRd[ɡ#$2ʞ6qnL}UɛL](zIIϛ'&\w89Ȼ8S RZl|c)& I~^ԿO9:őaD)hGׅGMZHA΀bwvt0_TP@OuAsv7f_eM5M3?1QdKcކjK{Vyп>Dzy5e\w?ɽʿаIENDB`rviz-1.12.4/icons/classes/PublishPoint.svg000066400000000000000000000263371300447110700205120ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/classes/Range.png000066400000000000000000000010061300447110700170750ustar00rootroot00000000000000PNG  IHDRasRGB pHYs  tIME1!tEXtCommentCreated with GIMPWsIDAT8œ?A;WE@R.BJ@ $]P&VX US$X0a''c& A@h>x!*vt}4kޔ)gf6؛3l):8IENDB`rviz-1.12.4/icons/classes/RobotLink.png000066400000000000000000000005271300447110700177530ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIMEVkZIDAT8˵ QW$5π [1ɳl&?Ϡkc&t5n{~~mhy 861ozzq*ahn_J|_z՛lιTRIvjϜv)- 퓠T*A ?qve14/@ *bсcc?Os|E@#Rߘuy\٪tx|k&dޗ 0K+#b<*hL8.KTd٬Imiftz)K9 ˷J&zRGj!` sVq$\ ay<|sUqvIENDB`rviz-1.12.4/icons/classes/RobotModel.png000066400000000000000000000013521300447110700201130ustar00rootroot00000000000000PNG  IHDRasRGB pHYs  tIME%E|IDAT8˥S_HSq~ou7&8F CE* 4SjΗ@%ۈ衞WE}(|DE\h#ݮRfm:!'s89H$r"ZyzfFzLa\Qjؑx[}ntivһA "7 ft|sAU& r憓~s#ADwJ[Dz*oeW)˄ "@UճX,^.1006R)tt.k1ǁ[fu 011ÁjtvvbuUȲ@ h"BchllB ؘ099pn3ƔRy^~|4::JDDdP0ﭯx7W$f1Q1<<'oiiLD<Y\a ϣP(ff_1vV0n\nEloob9g8@etuua~~~4$!'Jkk+< ho?t:M)v=!J |L&!b0 {5MC&,(JZzKKb\W `IENDB`rviz-1.12.4/icons/classes/Select.png000066400000000000000000000006231300447110700172640ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME%KȯxtEXtCommentCreated with GIMPWIDAT8ݑJ@ElbAb:,2¶~͔&u0Xu X0~U,DFMouxp/r2HB8:qeb繸M~- 'U9ɯ իK 4%I2G{!Z3PTp`Nhg<_S2 * GEWp55h}pj߃tUU\]4M$K( dIENDB`rviz-1.12.4/icons/classes/Selection.png000066400000000000000000000006231300447110700177720ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME%KȯxtEXtCommentCreated with GIMPWIDAT8ݑJ@ElbAb:,2¶~͔&u0Xu X0~U,DFMouxp/r2HB8:qeb繸M~- 'U9ɯ իK 4%I2G{!Z3PTp`Nhg<_S2 * GEWp55h}pj߃tUU\]4M$K( dIENDB`rviz-1.12.4/icons/classes/SetGoal.png000066400000000000000000000006761300447110700174130ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME+О֥tEXtCommentCreated with GIMPWIDAT8Ւ=Kag%EP,L s[)6Z(tVV`B&!be VBGqcB&VN RIzv !$"%XjCP#t˃ɽB}SDl7VKe]r!TY7qwW@R J=عg1=VTGL;5 нvޱ7JD>qY:J6cP*qlKxI,/ r0;IENDB`rviz-1.12.4/icons/classes/SetInitialPose.png000066400000000000000000000006761300447110700207510ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME+SMSbtEXtCommentCreated with GIMPWIDAT8Ւ=Kag%EP,L s[)6Z(tVV`B&!be VBGqcB&VN RIzv !$"%XjCP#t˃ɽB}SDl7VKe]r!TY7qwW@R J=عg1=VTGL;5 нvޱ7JD>qY:J6cP*qlKxI,/ r0;IENDB`rviz-1.12.4/icons/classes/TF.png000066400000000000000000000006161300447110700163600ustar00rootroot00000000000000PNG  IHDRasRGBbKGD%7ZZP pHYs  tIME,dIDAT8őO+DQst&nfc% llekm-5Z,|ƔA"YFh\{^+;un?w΁,^hd!XT]Xm;;-2xX0{FY/t(4y<@`l< rཔ$T,CgtmBS1JGu` W-8X0LaO0\2=Mm Hf54(N`7 dD^`IENDB`rviz-1.12.4/icons/classes/Temperature.png000066400000000000000000000005341300447110700203430ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIMEtEXtCommentCreated with GIMPWIDAT8˭1 0?s% image/svg+xml rviz-1.12.4/icons/classes/Tool Properties.png000066400000000000000000000011431300447110700210750ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME  9cHIDAT8˥KhaLM JƅE.4bfBp!T-RCBkAte@‰bW6IUiӗ DD:3nf1³{?'#Q X"M4QlRTlb4u#Q ZêEtFZdfx>XBr"2>06א:%Z,1`o %nFa~N(/;+tHRa %Nʿ4J'{( LA0: ԬN Gl6y75 irtI4Mk @ҾB0L8;77TIENDB`rviz-1.12.4/icons/classes/Views.svg000066400000000000000000000320611300447110700171560ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/classes/WrenchStamped.png000066400000000000000000000012451300447110700206120ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME24y!tEXtCommentCreated with GIMPWIDAT8˕KSasulvNQMr{5m䔮d֔J;[J)BM(C0bxDI[)J 7J(0 ޞs(G`&zq6 @.vH128 c" nCj_Je,Vw|䴻 t!<^Cۑ Jlg~7&)LouQJEpU5j TaFE$Ikߟx\h'OI͐%ef'}#HT'JsN$}b\7%8r 0tΎӪ9^Y.C@菇(+EIENDB`rviz-1.12.4/icons/classes/src/000077500000000000000000000000001300447110700161255ustar00rootroot00000000000000rviz-1.12.4/icons/classes/src/Arrow.xcf000066400000000000000000000072671300447110700177350ustar00rootroot00000000000000gimp xcf file@@BB G gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  @5Pasted Layer#1     e@5y@5:855314.괟.1,+.)u' *ӽ& Ѻ$ϼ$ $bmþ$~y{{'~~~}&~|z|yů)~z~ƽ)|{û'}Ȼ)~ؾ)~yٵ~*~~Կ~%ӛ~zѾ%府}$ⴊ}~(Iڤ}]&О~~~$ʔz~~~%豖)ٟ*ϡ6+忠(ᷘB+⭋~)ע*Þ)Ęw,ܵn+է.Ϙ.鹗2Ⳗ1ܨ4ţ~5ʞ65:8 5 5 3 1 ! 4 . ! . !! 1!! , !! + !! !.!! ! ) ! !  ' ! !! *!! ! !&  !$ ! !! ! $ ! !! ! $ !! !! $  ! !!  '  " !! &   ! )  " )  ' ) )  *   % %  $ )  ( $ % )*+ ( + ) * ) , + . . 2 14 56 5Y=k:v&9XD7ih7.v5.4M32)*1L0[e0.S.R ,2*M !* h)! ($ '`&" '~(?)`*J k+$ *; +^ -* *)! W)G r(h(6'OM &)#.{-.(Q--S.w--!.dL-R/. -a/p0#2;5T6}k8E: 7@@Selection Mask [@@o@@ =T<;:99/yrviz-1.12.4/icons/classes/src/Axes.xcf000066400000000000000000000261341300447110700175350ustar00rootroot00000000000000gimp xcf fileBBgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  Pasted Layer     4P,D,P d t a -#*V+2+B## ~~֡~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~~ϣ~ϣ~ϣ~آ~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~梣~~梣梣梣梣梣梣梣梣梣梣梣梣梣梣梣柣⡣⡣#TNNdSNN2(# ]JGGGG                    !!!!!!!!!!!!!!!!!⡣⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣| ⡣|~⡣|~~⡣|~⡣|~⡣|~~㬣|~|~|~~|~|~|~ |~ |~ |~ |~ {~ ~ ~ ~ ~ ~~ ~ ~ ~~ ~ ~ ~~ ~ ~ ~~ ~ ~ ~ ~ ~                   | T T T T T T T T*T'T'T'T'T'T'T'T'T'R' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '!' ' ' ' ' '<:7786521 / 0 / ,++()&$#!"<99#886^5-4S3 2 0 / -!y -+*)'b&@%$"a!   !!B$8740 ( <)Y$! 鸤䴣鬢Ӝܞܢ'꼞~}衢~멣~~ ҥǢ~~~ }~ ˡ|~督~}~ߝ}朣|~~~箥~踣~䳣}~ 鬢~~ Ӝ}~ ݞ~ ۢ~ 꾝}~~z顢}~ꪣ}Ӥ|~ Ǣ~"~~"ˡ#督~#}~$ߝ|~'朣~~(篥}~'蹣}~*䲣{~*ꭢ~+Ԝ,ݞ|~~-~~~.<985553%2 1 0E 0F 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 11458;~ ~ ~ ~  읢H"螣*$Ul8&.3U7!: ' ' '  Ќ!"#O$&(U(6+*, - . +1 3 235D7e9 A:))J:), *;('(F'p$k%D"h" -#!&"("%&'()*,, . / A /;:84 , *&!$(+. 069>?=9532+, % $  $ ()./66<<@+0:Q7h3 s:8/ -&  b1q2 D3Y4w5789:7;*; >     ~!~~"~*/24{~6~  yo$(R +jf B.>16"P x?<rviz-1.12.4/icons/classes/src/GridCells.xcf000066400000000000000000000027531300447110700205060ustar00rootroot00000000000000gimp xcf fileBBG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) New Layer copy     au New Layer     Uiy Pasted Layer     ?Sc                            rviz-1.12.4/icons/classes/src/InteractiveMarker.xcf000066400000000000000000000155421300447110700222550ustar00rootroot00000000000000gimp xcf file@@BBBgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) gamma0.45454999804496765@@ Background     X@@l@@|`;T|;0H7ރ7?g9H9??6~;=??R5e,=??n5z;7=??ʔ3z?759;??_3~L7?c2z3$?g1n+*..~i(~z77~5*(R,~nk]L&553~nYr*#e3J7iY30H%~[aT*33z#VHapL357#;[Y[e]57z~r"37r~ 53i( 7a77az75cCRH̼n]~r73.,9TC7J5i50*5;H~ ?5,?]ѱ?&?HV$R|TH*3aY]z&R~H57p~~r3*gTv730e533..5,9 PC530;zY,5.e~eNN ;335v~~vTz ~35r~.7z~ A,H .n~,55.H k.50 a~e3550 vP7,~~a3. ~zT5?aY ~~],57R9C~ 9,iF&737N75,v i9k|AC(7=553; ~~n_&99=[ gCP~03ƒ~ 0A9*p ? ~z37AT= r~z] RĔ33&Pke[?*~pzP**?5ķT~~rNkNH..33Cv7,9? 9|e3z~e353..e|a533v*7?? H57353;~eP53.;*r5??쩼~,.,z~zti,z*33.]~~PR=?? HNPz& 9(~k 杘 _7Yn335;t  ?T~.5Y~,353 ~z35r.5PL5[ rvH,~~55L~vT.5YzNk.Tt:`;T|;0H7ރ7?g9H9??6~;=??R5e,=??n5z;7=??ʔ3z?759;??_3~L7?c2z3$?g1FNJJ-*".3ir(eF0H~i.3x'5nN~~v337T%JTN~037e~#9~5LzN|L5r~3$T""eC5,PNr~P3.L"9p~75& ARr*5370"=~z37iY[k377i~!FJ5~~rFz~~|rvT0~r]CPPzr.N7.5n$?,&77~0]H̼n ;J7C97] E Y~.$_.0.Y~33.P|TCaY]~~T5?R i~~r3*~&CgT533..535~~~~R PzY,5.e~k73zNN ~~vTz ~0733n~.7z~ A,H=7335a 3|,55.H k.579533= i~e3550 vP73~]353C~a3. ~~a,HxaY ~~v~~z3C~ 95?~~zF.5,v T(]CCHC.53; [ g~L 7*e ]ep L.kp7A cgkYT.ATA5T~T3(ei[]R93&P"3]t[?*]F7F *~~rNk.5;..33[7*_ =z~e353..e533 &&779 _*??5.353;~"P53.;_cJ]0*73L .3.=,.,z~znz*33.&?0.73 A0.z~~z r[3;vk??;03c~z373YL *A ;??0HS~7533v~v97rz&t?nR]kV?c_T30,~v55T~iY~~ zin.7Prv T.5Y/Tt:^%;<7:756 3 4 3 2n|TJJ-*..~vrF.3ir(~z7.?ggC?7H~i.3x'R,~n cikLL~v337T%55*~]ggr9J037e~#e9&]_g37375r~3$~Yc*33nr~P3.L"VHi055c357ar*5370"R ~z37ie]57z~T;77i~!~~rF37r~]~~|753i0F~r]CY.7a7097.=n",az75;.0RR~AP̼~r735;,9TC;豵i50*~5;H7 N5,?]E?Y&?H~.0$R~33.|T~~T5?&R~H5F~&C*gTv730A~~~~9 P&L530;.3zNN "5335v 033n~T35r~~0335a 37.n~ ?533= ia ~]353C~ ~a,HT, ~~],50 ~&Fa=.30 RPC9.x ~~n$N[ g~";Pƒ~ Nrgp LnY|$7A ~z~iYF== 5T7N3(e~z]t*=P7FzP**[ _?[V7*_v7,9? & &779v*7??Y*(L0*73Lr5??.37$z~~P?0.73R=??A0.z~~z ((~]??;03c杘~z,09Yxc.Yn935;nA??0HS~7533v~v3.rz.x0T~.5Y~,353t?nR]kV?c_T30,~v55T~iR35r.5PL5[zin.7PH,~~55L~vzNk.:#;;r9;77{<543 '21&1;-V * ?'`k%C$$"B"]0X[mm mm;m8m4 m2m.m+m(m%m!m"m%m)m+m/m2m 6m7m9m;mmm m;84 2.+(%!"%)+/2 679;<>  w544310/- m6m6m4m2m0m/ m- m+ m*m(m&m$m#m!mmmmm m"m$m%m'm)m*m ,m .m 0m1m3m5m6m7mm5mm3mm2mm1mm/mm.mm-mm+m m6m6m4m2m0m/ m- m+ m*m(m&m$m#m!mmmmm m"m$m%m'm)m*m ,m .m 0m1m3m5m6m7mm5mm3mm2mm1mm/mm.mm-mm+m 66420/ - + *(&$#! "$%')* , . 01356p66666666 5 3 200.-+)(&%#" !!#$&')*,-/02 3 4 5 78:;<<<<<<;;;;;;;;;;;;;::::::::6m 5m 3m 2m0m/m-m,m*m(m'm%m$m"m!mmm m!m#m$m&m'm)m*m,m-m/ m0 m2 m3 m4m5m7m8m:m;m<<<<<<;;;;;;;;;;;;;::::::::6m 5m 3m 2m0m/m-m,m*m(m'm%m$m"m!mmm m!m#m$m&m'm)m*m,m-m/ m0 m2 m3 m4m5m7m8m:m;m<<<<<<;;;;;;;;;;;;;::::::::=========================<<<<<<<<<<<<;;;;;;;;;;;;;::::::::<;:85 2 0,*'$!"$'*-/ 3 58;mmmm m;84 2.+(%!"%)+/2 679;<> ;84 2.+(%!"%)+/2 679;<> m6m6m4m2m0m/ m- m+ m*m(m&m$m#m!mmmmm m"m$m%m'm)m*m ,m .m 0m1m3m5m6m7mm5mm3mm2mm1mm/mm.mm-mm+m 66420/ - + *(&$#! "$%')* , . 013567/5/3/2/1///./-/+ / w544310/- 66420/ - + *(&$#! "$%')* , . 01356p66666666m 5m 3m 2m0m/m-m,m*m(m'm%m$m"m!mmm m!m#m$m&m'm)m*m,m-m/ m0 m2 m3 m4m5m7m8m:m;m<<<<<<;;;;;;;;;;;;;::::::::/6 /5 /3 /2/0////-//,//*//(//'//%//$//"//!///// /!/#/$/&/'/)/*/,/-/// 0/ 2/ 3/ 4/5/7/8/:/;/ ;84 2.+(%!"%)+/2 679;<> ;84 2.+(%!"%)+/2 679;<> 66420/ - + *(&$#! "$%')* , . 01356p6666666 w544310/- 66420/ - + *(&$#! "$%')* , . 01356p666666666420/ - + *(&$#! "$%')* , . 01356p6666666=========================<<<<<<<<<<<<;;;;;;;;;;;;;::::::::6 5 3 200.-+)(&%#" !!#$&')*,-/02 3 4 5 78:;<<<<<<;;;;;;;;;;;;;::::::::=========================<<<<<<<<<<<<;;;;;;;;;;;;;::::::::=========================<<<<<<<<<<<<;;;;;;;;;;;;;::::::::<;:85 2 0,*'$!"$'*-/ 3 58;7666656666666666665555555555555444444444444433333333333332222222+ + )('%%#"! !"#$&'( * + , ./0224444444444443333333333333222222276666566666666666655555555555554444444444444333333333333322222227666656666666666665555555555555444444444444433333333333332222222:::::999999999999888887 5 4 3 10.-,*)(&%#"! "#$&'(*+-./1 2 4 5 689;<=:::::999999999999888887 5 4 3 10.-,*)(&%#"! "#$&'(*+-./1 2 4 5 689;<=:::::999999999999888887 5 4 3 10.-,*)(&%#"! "#$&'(*+-./1 2 4 5 689;<=:::::999999999999888887 5 4 3 10.-,*)(&%#"! "#$&'(*+-./1 2 4 5 689;<=<<;97<<;97<<;97<<;972222211111111111110/. - + * )(&%$#!  !"#%&'( * + , -/0124562222211111111111110/. - + * )(&%$#!  !"#%&'( * + , -/0124562222211111111111110/. - + * )(&%$#!  !"#%&'( * + , -/0124562222211111111111110/. - + * )(&%$#!  !"#%&'( * + , -/012456@@@@5 2 /,*($" "&(*-0 3 57;=5 2 /,*($" "&(*-0 3 57;=5 2 /,*($" "&(*-0 3 57;=5 2 /,*($" "&(*-0 3 57;=\j.5rviz-1.12.4/icons/classes/src/Poly.xcf000066400000000000000000000052051300447110700175540ustar00rootroot00000000000000gimp xcf file@@BBG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) * @@ New Layer#2     j@@~@@;;;;;;;;;f;;;B;;;;;;;;;f;;;B@@ New Layer     @@@@:865 4 3 1 0/., % &) ##,.//..---,,,+++ * * ) ) ) ( ( ( ' ' ' & &   (0/'&3 B@@ New Layer#1      ;@@O@@_8;:9765 4 2 1 0.*!&/78777666 5 5 5 4 5 4 4 4 3 3 3 2 2 2 1 1000///...-, -98U;98I65  4'3g10 /I '- /) 1 7 #8\~@ 8RqK )Ig$U)@\-a5l4yY4 43@322+21 w2 2 1 Y1 1 0 @0 / / +/" .) w.1 .: -C Y-M -X,c@,p+|+++*w* ,=Ri#0@Rg~,0@Rg~8&4@@ Background      U@@ i@@ yrviz-1.12.4/icons/classes/src/Polygon.xcf000066400000000000000000000077541300447110700202730ustar00rootroot00000000000000gimp xcf file@@BB,G gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) .# >wN@@ New Layer#2     n@@@@;;;;;;;;;f;;;B;;;;;;;;;f;;;B@@ New Layer#4      @@@@x:::::::::::) ):::x:::::::::::) ):::@@ New Layer     `@@t@@:865 4 3 1 0/., % &) ##,.//..---,,,+++ * * ) ) ) ( ( ( ' ' ' & &   (0/'&3 B@@ New Layer#1      @@@@8;:9765 4 2 1 0.*!&/78777666 5 5 5 4 5 4 4 4 3 3 3 2 2 2 1 1000///...-, -98U;98I65  4'3g10 /I '- /) 1 7 #8\~@ 8RqK )Ig$U)@\-a5l4yY4 43@322+21 w2 2 1 Y1 1 0 @0 / / +/" .) w.1 .: -C Y-M -X,c@,p+|+++*w* ,=Ri#0@Rg~,0@Rg~8&4@@ New Layer#3      @@ @@ ;l776B532* /k - , +?'   !>h  2h *J'!J|08%9.999F8W8k8776]676866555443]33 2 822 1 1& 11 0< 0L /] ]/o / . 8. 8-+Cd! *>h+ *>Y 7  @@ Background     @@2@@B@@Selection Mask @@@@rviz-1.12.4/icons/classes/src/PoseArray.xcf000066400000000000000000000237071300447110700205450ustar00rootroot00000000000000gimp xcf file__BBG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  v&ROPasted Layer#3      +eRO} RO (;$w+ $~{!~{{x~rz׼wuzy w  ~λ ߠqÿ ü{|Ÿtθ~u˾̿sy~}z¯7}˽I}ǡ ӽmqȲ|h xå񩡛rnoѼo3Ңb[3/   zת ĻT   /& %! !! ! ! !     .W*/7J. $ڽШg`/u5ލM ԥY Ğ" & )'H?Pasted Layer#2      vH?jH?;;65 . * ' (m ӯ'뵠 غȹl!а"u Ÿ} Ҿ ~wuy Ӹ!||ʧX!r{x⿲$u߿vѽ#ĸ|}¼`w~ٺ ٿ{w ܾ~yɲï}~|լx~Öházrê"̯ ׷~%Ģ(î)ֵJ'Խt)߻|+/ׯ.ѿh1w57lt9;(;6!4  . !! ) ) !! ' !! (!! ! $& ! !!  # !! !!)  ! ! ! ! ! ! !! "  !! !! !! #   !! !!   # !! !   " !  !  # $  #           %  &      "   !@ ( ) ' ) + /5.! 1 5\ 7 t (<U}8!`k42\x.$,G{-(7'!9X $ q$$;` T!" ."0"#$'i&E& /&d #&t r $8~ !0f$-x?${ 4" & "8 O!, Luii!| !ZߤB)O I(G H(h (W\)2 X*SZ-l .0I1rB4$x 4q"5=:& xUVU   !&4#VU K-3Wt4(zzW?n$@5Pasted Layer#1     !@55@5E:855314.괟.1,+.)u' *ӽ& Ѻ$ϼ$ $bmþ$~y{{'~~~}&~|z|yů)~z~ƽ)|{û'}Ȼ)~ؾ)~yٵ~*~~Կ~%ӛ~zѾ%府}$ⴊ}~(Iڤ}]&О~~~$ʔz~~~%豖)ٟ*ϡ6+忠(ᷘB+⭋~)ע*Þ)Ęw,ܵn+է.Ϙ.鹗2Ⳗ1ܨ4ţ~5ʞ65:8 5 5 3 1 ! 4 . ! . !! 1!! , !! + !! !.!! ! ) ! !  ' ! !! *!! ! !&  !$ ! !! ! $ ! !! ! $ !! !! $  ! !!  '  " !! &   ! )  " )  ' ) )  *   % %  $ )  ( $ % )*+ ( + ) * ) , + . . 2 14 56 5Y=k:v&9XD7ih7.v5.4M32)*1L0[e0.S.R ,2*M !* h)! ($ '`&" '~(?)`*J k+$ *; +^ -* *)! W)G r(h(6'OM &)#.{-.(Q--S.w--!.dL-R/. -a/p0#2;5T6}k8E: 7_Z New Layer     'G_Z'_'_Z'{'''&&&&/-rviz-1.12.4/icons/classes/src/Range.xcf000066400000000000000000000045421300447110700176700ustar00rootroot00000000000000gimp xcf file BBG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)   New Layer#2      b v Ū[\_ \^ []^ ]]^  ]^]^ p^^]] [^^]] ]^^]^ r\^^ ]^^a^y[]^^]e \^^_m]^^]_ y\^ ^]\^]^ ^]^a^]^ ^]_j^]]^ ^]_|[^^]^Y^^]P]^^_]^\]^^]^]^]^^]^_M]__.*)*&))*)*))**(/)**(/)**"1)**$ ** *)&*)* *% *# *" <)* * *)*)* *$)* *  *) *! *) )* *)  *"  *'  *%$))**%*)"**)("))&«Ñhœgk hk fij Ùiij  đijij jji gjjih hjjij hjj ijjijmj gijjirhjjk{hjjik Éhj jhjij jijĦmjij jikqĢjiij jik»gjjijejji[jjkijhikjjijijijjijmWijkl G}E=b||? 1  ? N   . {A5UD K! FqO &2/.?Rtrj̼  Background      2  F  V   rviz-1.12.4/icons/classes/src/RobotModel.xcf000066400000000000000000000234541300447110700207050ustar00rootroot00000000000000gimp xcf file@@BB gimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) @= Pasted Layer     4@=H@=X }xʷslʭ(XJ\(o4$pn(XwC.V\`\R&~gae_`L#DhcaJ8%iedehfc6'VhgX$WcfbifiV#=badOP%MYffcffdL-'(,,148;R]f`a%NCPccaiag`^UY\Z\\[][`Y`]X%MWf]\b^ae`ihuz&"}m^/, R j$I^ ##&.SX"[W"#$!S߱۫Ҳعչđ֍o̶|dfeNJ&kci=*Xkklb]qbe;$ljkkjkoBpߺpdd"ikklZIxad4,[kkg.E|bfiPOlkjihfie:ʽH̠yff_URgaddece|p—^a\5qkeggwWTddZ_fhh^ҼŹ}cau~dde\XP`ajhcgfeX{gjar7ZliYghf\_cabhcdf`Xe`f[G6$$7'M0W^_Z]dcemz~}wqqjjhcbgȽw32s|ʨplmllmlkjhvekkjbbfήG ! ٮҢ(,*))*)'!P˱vjkkja`jqߎ% MȒpjkkj`^lh{Dӿ  SnjkkjbekkjhmW $ z Srjkkjdikkjim-l> | TvjkjjkkjkkjK CL>| Uvjkjjkjm5J$M | Twjkkjhkkjkhkj&10:UT'.| Rvjkkjfkkhijw/:LQYH L| Rvjkkh_lkkhjgjr1 EEDHGS77d| Rvjkjjh]lkkjkgjjr1VTdV`>Ia| Rrjkjgidkkjkjw.!T^lefcMN]z4-) Pqjkjjiekkji"OY_kaecR[Y݈:J#5OGhpjkkidkkjipqo]$:S JQdcmMXS1݈@U**S@*ytjjkkibkkio*$LLMK<2I;?@QQI1.'܊Nk7Jl_snjjkjfai}՞THMML2 6K#DMLH>!8T݅HpWRQI`kYymjkkjc`hދ5LMLMML? 'J1IMLL< 0GڂInd\hUkjW3wijkkjc_q>MMLMI FMLL8!( 5M?LMFMKlkL.:MIkjkki^iEMMLMMJ2 " >>KA1<mgILKKLJhkjkj_ibJMMHLB'*3+FLD1L }xʸĹ|ʭ(l69981::96\\(oO;<==<==>'j r$V s(, BC1>Dnh"eh"#$!S߱۫Ҳعչđ֍o̶|dfeNJ&kci=*Xkklb]qbe;$ljkkjkoBpߺpdd"ikklZIxad4,[kkg.E|bfiPOlkjihfie:ʽH̠yff_URgaddece|p×^a\5qkeggwWTddZ_fhh^ҼŹ}cau~dde\XP`ajhcgfeX{gjaq7ZliYghf\_cabhcdf`Xe`f[G6$$7'M0W^_Z]dcemz~}wqqjjhcbgȽw32s{ʨplmllmlkjhuekkjbbfήG ! ٮҢ(,*))*)'!P˱vjkkja`jpߎ% MȒpjkkj`^li{Dӿ  SnjkkjbekkjhmW $ z Srjkkjdikkjim-l> | TvjkjjkkjkkjK CL>| Uvjkjjkjm5J$M | Twjkkjhkkjkhkj&10:UT'.| Rvjkkjfkkhijw/:LQYH L| Rvjkkh_lkkhjgjr1 EEDHGS77d| Rvjkjjh]lkkjkgjjr1VTdV`>Ia| Rrjkjgidkkjkjw.!T^lefcMN]z4-) Pqjkjjiekkji"OY_kaecR[Y݈:J#5OGhpjkkidkkjipqo]$:S JQdcmMXS1݈@U**S@*ytjjkkibkkio*$LLMK<2I;?@QQI1.'܊Nk7Jl_snjjkjfai}՞THMML2 6K#DMLH>!8T݅HpWRQI`kYymjkkjc`hދ5LMLMML? 'J1IMLL< 0GڂInd\hUkjW3vijkkjc_q>MMLMI FMLL8!( 5M?LMFMKlkL.:MIkjkki^iEMMLMMJ2 " >>KA1<mgILKKLJhkjkj_ibJMMHLB'*3+FLD1L }xʻ̶ʭ(Ǡp\(on(Xwz_[`\R&~gae_\fnhbaJ8%iedehf`vfhgX$WcfbifgdndadOP%MYffcffaq}|yvuj_f`a%NCPccaiaf`lgijfec`^Z`Y`]X%MWf]\b^`c^hgtzÿ& | TvjkjjkkjkkjK CL>| Uvjkjjkjm5J$M | Twjkkjhkkjkhkj&10:UT'.| Rvjkkjfkkhijw/:LQYH L| Rvjkkh_lkkhjgjr1 EEDHGS77d| Rvjkjjh]lkkjkgjjr1VTdV`>Ia| Rrjkjgidkkjkjw.!T^lefcMN]z4-) Pqjkjjiekkji"PY_kaecR[Y݈:J#5OGipjkkidkkjipqo]$:S JQdcmMXS1݈@U**S@*ytjjkkibkkip*$LLMK<2I;?@QQI1.'܊Nk7Jl_tnjjkjfai}՞THMML2 6K#DMLH>!8T݅HpWRQI`kYymjkkjc`hތ5LMLMML? 'J1IMLL< 0GڂInd\hUkjW4xijkkjc_q>MMLMI FMLL8!( 5M?LMFMKlkL.:MIkjkki^iEMMLMMJ2 " >>KA1<mgILKKLJhkjkj_ibJMMHLB'*3+FLD1L VAX~~b*I "* (l(J',(O'' &')&|A':R%]*$\$-$##,#"8F!`C _ w: *}0K/k -ؙbB#@T "ŧI; E$E+D+H*,'  ,F  Y,R,Q{,P*/,U(>A)o&( ,*T6*7)4"+|!a*A*KhE,$E+lVNE+E,wE+D+ F*<F3rviz-1.12.4/icons/classes/src/TF.xcf000066400000000000000000000122451300447110700171440ustar00rootroot00000000000000gimp xcf file@@BB gimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  </)Pasted Layer copy      A/)U/)e*!(< 'z'{({(z(~}'Ņ}'ʋ}'ϐ~'ԕ}~&ڙ''''&~']&''+~(~~'|$}#!լy# ԛ$$ڴ#d$&*#~)Z((㯋N%Й~#ިo!"ߩ#Ðq!٣~!湒#ӛ#%'**l  N N Q R^$ H {. "1&<SfWN.E :$&&@' +'W(((('''''oE'[w'A'5',(& & 'O) +&Pasted Layer copy#1      +&+&B+####ԓ  ﺄ!Ֆ}!}麋 ؑ|!ᩀ 켆zљ!}~z渋}!ߗ{ "#{l3z\} {w ##$r#Ɖ"ޓ"z"~$Ո$v##ۈ$$s!ɇ$!$~$L$ܻ Rx#$$$-#$$q #0}$$# 0#$$4$z$$_%O$㺼"CZ{at v}K "w"H2! ""tT!,!!Q!f  !ez"$E&%G1$" Pasted Layer      7$" K$" [;DLƑ/洈}䮅}ۧxמН溎z~ௌz~z|~*}6PxTv z ЄЇщҊҊ҈ӇՇ؍ڎڎڎێގߒߓߓ"ſ YfgaRU(, ̍%;Y W. jQOZz1sLlJ"J UTransformation       ~@Cc_9 P5:n\+%F;&(tS`M@7 New Layer     q@7@7    rviz-1.12.4/icons/crosshair.svg000066400000000000000000000331651300447110700164270ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/cursor.svg000066400000000000000000000104541300447110700157430ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/default_class_icon.png000066400000000000000000000010601300447110700202250ustar00rootroot00000000000000PNG  IHDRabKGD pHYs B(xtIME8rJIDAT8˵NaofMH(`; (h aH7Mܰ`p.a4ހѕqB Q i e(.ffvY>ON!Y\ZYxz:IDd9gw=J"bi{vDҸ3>Lbd(T"/]{w]ItM31 ,;sDBO8=Xvf*dk38F 7Pp4Vھ݉\3o"5 egWָ:o]\9P$flX>o,;3`2{50$Lj3 r |C|.[8_.R,LDRxFMIENDB`rviz-1.12.4/icons/default_package_icon.png000066400000000000000000000011051300447110700205130ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT81kQsW,)2v._?VW(Ĺ`Y)$Pi&%߽&6XZw9{yy_v7 w2 nY33 w~?t:ϗ9gBe8~T9gWU& $vxLӪ+bfkvܤjc$h4b<?\YPUS-~H̚??́={U9gO)1m!rx5)_;9x~J)N ˲|@+U%猈u#j9xs3DظiQ ATc;YuiIjAbR7 inPEar6_TRJ/sN ggD FNuk"ERR;'|:uxlQew"E‹G!c1IENDB`rviz-1.12.4/icons/error.png000066400000000000000000000012151300447110700155370ustar00rootroot00000000000000PNG  IHDRabKGDC pHYs  tIME 2SIDAT8˝OQm 壾Mh ĔD2iҁ";2tf#@XD0hc$-M[(=}KOrs9nTR<ƽ,e`z!~; -L&a|*3ef39x7Lr{UE XCwOMRSWt2^,F{sm4@UAEAi|?öj2CX[C*zbŅ1S)>olPkf-`~2rguPqTqy<`>?>|DE+OoA5?JDQ`zpT?P&×AĽQ7<7UD (Y "":'V][x%u7:NCPcG" lZlg w(CO4Fz`VW*H$p }0vrjܺLv_“QEEpM::_΋nOGfXvwIENDB`rviz-1.12.4/icons/failed_display.png000066400000000000000000000014641300447110700173650ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME - kIDAT8mOSasm%@+xij 6X\:8iL q1P$(Ji;&_M{Ua==1DUv \Be3?k.]vͭhRJiY|x23^(X5*FN><}j&1}QPȑ|8v728emZ:M W,JgZg&xccw6ǪG Df8޻w$_r<֍TD"̻w Ծ>Ԗu~ ڷEJJ.hϟ( %BaՑppq]Qpz<8;wu@ y%%}]pzXb1mc6 ;Rww(8vԅB*,e_)D V[Z޺e=gutǃ=<혹Ʒoȕt)冚a ,6\Uxqx4рԝ:iբ)+@[VJ$(~MOnޤP^\$k$oF4|~?%r^S'[AW*gX-kSH c:`C6"Orbizi~inU|^L= 1mv?x.ElBZVO$֧lvƆ(,nƭ"zvWiEay3MR׆IENDB`rviz-1.12.4/icons/forbidden.svg000066400000000000000000000247621300447110700163710ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/left_dock.svg000066400000000000000000000230041300447110700163530ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/menu.svg000066400000000000000000000245441300447110700153770ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/minus.png000066400000000000000000000003671300447110700155500ustar00rootroot00000000000000PNG  IHDRabKGDC pHYs B(xtIME ;"\IDAT8푱 Pi:+#mF stԶ"DO!ʳ3w&H6暺`?S-FIENDB`rviz-1.12.4/icons/move1d.svg000066400000000000000000000241101300447110700156130ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/move2d.svg000066400000000000000000000262451300447110700156270ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/move_z.svg000066400000000000000000000241741300447110700157310ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/moverotate.svg000066400000000000000000000324051300447110700166130ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/ok.png000066400000000000000000000057561300447110700150350ustar00rootroot00000000000000PNG  IHDRa OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-bKGD pHYs  tIME 1Hc IDAT8˕JAwh=8/"*h! ҈iAy žڊXX iRو,lc%,DmVxM2oAsd88 `"5GpMC[b.U&"i&=1ӓ<|8._/t龘~齘Vͦ΀X (4ցs!8&@XI31-n-|g<8lg֭+>c@F\z6f Ǻ ^h/͏"z78$wqӹژ~Ք[JgɺHIENDB`rviz-1.12.4/icons/options.png000066400000000000000000000011141300447110700160770ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME q_ZtEXtCommentCreated with The GIMPd%nIDAT8œJQXNm%0Ţ@2:O(y!:\&8&-3(-vtbM7.zVs9?߅[FbT0nasRGB pHYs  tIME A%tEXtCommentCreated with GIMPW IDATx}{tTEN B$P>##D|sQRG\*@QQ@F #2(bHx!I;s*Tt@g:+>N޿wUb!b!b!b!b!b!b!b!b!b!b! dty?PA/Y!?<@&HU=^ %}rH:_NcL.*}B>FUS܉NjL'g& AXu2} @*45>W!W\Q"?yj2hSDuř8Eи1#a`Aڈ"9h$rJOEY_͌2 &^ s$ )եmGW8EvӧOApb`0hzgʲ\rwMMMS}}}S,=zT8n(A~ٔw4v6̌SvFi[lMVcut`Wb ;۷o_c2IgϞp:=!I:ӵ~p86SB* #qdHw:M,iXUU$I sZ;l T -=;;;77777gb1g(J7oA:c}z.ny, Ie9M6YYYmOtڵb@jjj[o`ۣp/IRK4m&V; =)89z~ K4ЬX,8Nl6 U>`ӽ)V(LFH۬w~w/"L8Q 'POe_6 ߾}2laAѼ< 6$i`Z3  EsbϋȜ صFT g<$r_>sXEQ| tv:sN8kii/))mj#m'Hb*)bt|Mлw8Y-uuuA$A4eA4M z7Ϋt78"i((J0Fkk+222Ds=o޼q>Ϸk./Ꙩ(J۷. ]3XҒ0 :{ꩧn4h@c ظq#~?\.|><ZZZЭ[i"H֭[? $ 5?N B@SS&I~W*++O68_{9F#IJk׮(pw^t:ʄӈy7-z444 (//Ǐ?8߅wȑ<čs+Oҁrݨ,--}2##:;={6hmm9aMw=((%Ihʐ?B2eJE4A}}=jkkq!d΁*0*&?)IB /T\\(zSlR̠%|֟=ĒIĄxw'n O?4 Be]`z.  \&2sM 4j8(AMM 6^K8+i|@Kii6jq`P>V5eIJ"kɔQPPP[zAA&|M-ڷz/)lcǎ8|-[g"kacyi a*R,nh(%EQ( TU]Rۭ?s̹0t߾}|B_z'%Hu6 \X~Waٟ֭|I h4ZpGVZ¶mw\Gʪ6Dhiii=z4O`ډR;+#[D'T٬%wX uuuJ]]ҙ"\.dgg %x饗n[f`UUYYYy$&azWinnn$16K68|D}hTyWv#ϋ>|iśX|Mwޙ'IRtժUGC!OЁ}Kɂd7\avhNJU9~+nX`Zv[G塇v}ѣ{7_ݧO4вm۶OYKܴi. hI&]L,$oˇX >k֭j"W#u @իZj?!B$Ѓp#Htt|}#WB5W?{܊%sfs @Ç/}ׯ7nEz( ѨК4Mòe~;~"ZZZzn[tIwaرo>|]d =,Æ 0"UNS 6P!b28\L`N=PA(opX>|x(jݳJJJ>}Tuuu?Iɳ*Y0Zg>@,U|+|7ٳvyȑCDP-I둟/ۘ1c>yqcݻwȑ#op8 ۍl=49T18/^kɒ%?{ "sRs=}ZW E͛7wyGTUSNIR3fɷ9%%ETXL裏eY>/ˀ>ՈD"޽{_~ݻw߷h"YepR?*P(w5B&QN*nۛjM 4 KGQM&&3++ V"s\UԲ;dfΜ9x,};^p)**|A U$l6 v9i(**#iW@b)@Ye"gʔ)ѱT+ {\{7 :REQqF)*==:nܸB.$4s sĉW:n lٲ=s1?b1y"JD<@[ IR, &̡@ D `ZS x{ܹ3!3/LVbR[󃟙;;wfU4Mbw͝Ox@zL Q,' 1R+K%Yk^| C yr@zAAAo fffR^n~On@u1.cǎE-'NEUUq^C A{z,C:x fwݻ4{ȠجO>yL7M1G"?PnQHss a+$^n+Yk+"bx_\sn6wkg͚姜Q=޿3,%I,m$hcرcCUUN:k֬YE XNU nL&_^/>}:u갮ap~ 4M{ f@ @Ld3Eђ4M3P4@<06Y7n'YJME& ) EWnxꩧ0vX,\ܹssʗ{/e+W\B;.D i-[ _TTT؅n֟#n id4MCmmm`Ϟ=75gJ߱qH`%HKfݻwB+,\pxZZ{ܹо8Bo/>"I"U%"rdªU0sLaa6*f3hq&/zZNYUU-\iVrӧ_/322x„ ?ϗ/袼~K.e^r5kES@,-@cݻ7l6dYNک<3G1г4g< (_G'O붱_~ҫ"e_o1gR@ZCp`߾}*&)14k"MJ /\W@r6*[nJ$  ڔ)SRǍ+Q氢"af^,@KvKQ_ VL揇sl]EjYN-Y"H;qpKp8ہ,#Hɓ$j}AMӰq, ą_PWWe=BҥKGd4eC1EMfs{ǎ?u3f̯KITL!T6gI[VLiO'{pfx%݇UUUUMӤ]vmc8Mm( Iz hѢ}z\YY^>m/@Q!dQ_N:rAZnX=A%.QGI<ӧO_n2fL{eYarg@ѣE]veѾJq+EP =ݺuP(-[tHD _ow@,+]Vh,ok׮-eil:dȐy˖-pf3&di۔Lc}MGW^Uov yo/ ?Pty~<%_k֬-+Wnٳnݺ=*;c򖖖rUU8Jg]X|(@./#H=fM[hNӃdKG1 a2UVZZUoߞp?WaOizb9Ç{FJJ{̘1>7Tiii8p@#3%./ +$t1,QMfzKjkkuBg ͝L1F*( ۷Owñ+V&5^~ׯ_DBl֑/#uuuSN}kرS$I{ذas,Yb0%%%8'}m-;ϗnᆫ d |?+a#HO?$I檫z8p-\E=~~N)}6&==])h~p Kc"ضmNѽM&SSz(QZZ0q)E*A2xu,;EKg@7j hhh7nܣ/މ}yP3mڴEQEz!C.Ͽ 9$umpSo*(@o˖-WԠ?={>_my=zɓ'|g1]xz,1oFZL8mTZZYlߗ,Y1==ۣGlde9%---K/7f̘LBms|g53f$IqQX 6 fYxjiJJvurY+=3KNb7O>e0s-=|h$ZdI*wo*@GyYfݩP jS#Ff01Es]o-D&"evfL҂R d˧TGo׭A|u)bѲ?5qCD u(y*Jm BcY_?LeܸqJ!g12w߳'z>zz4{6&#===]N3aɓ' &hv1 $vFf(+JB?^=a„kE6.009xrbD["[-$mx\9XwV2@@PiAkeRjt&Rȿ&ROXNOӅ43kgO=TrK wIENDB`rviz-1.12.4/icons/right_dock.svg000066400000000000000000000230011300447110700165330ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/rotate.svg000066400000000000000000000357551300447110700157370ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/rotate_cam.svg000066400000000000000000000340301300447110700165400ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/visibility.svg000066400000000000000000000311051300447110700166110ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/icons/warning.png000066400000000000000000000013151300447110700160540ustar00rootroot00000000000000PNG  IHDRabKGDC pHYs B(xtIME  /u)ZIDAT8˭oQscM[2\vEPX`!la%! HD%DEӚNLkAH, image/svg+xml rviz-1.12.4/image_src/000077500000000000000000000000001300447110700145175ustar00rootroot00000000000000rviz-1.12.4/image_src/R.blend000066400000000000000000014050341300447110700157350ustar00rootroot00000000000000BLENDER-v258REND SceneTESTRqs ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWW~eeo@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@KKK?mmsccm@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@KKK?^_gCDH@cccdeqSSZ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWW_`gGHPqqtlly@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWW_`gfgk||aah@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWWoooooomnsQR[@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWWjjp`ajoooMO^@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWW_`gRS[jjqNN[@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWWggkrru}}QQUA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWWttyz{PPSA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@]]b@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `GLOB   0nqsXoqs /work/gossow/rviz/rviz/image_src/R.blendWMhWqsjWMWinManWqsWqsWqsWqs qs qs qsG]qsG]qsG]qsDATAWqskBpsnqsscreent~|+ps!;qs(L0ps(L0psAqsAqsAqsAqs8Nqs.]qsSNWqs%XqsSRAnimation.001hpsWqsWqs8WqsWqsXqsXoqsDATA hpsXe+psDATA Xe+pshQqshpsDATA hQqsDqsXe+ps~DATA DqsvNqshQqs~DATA vNqsj]qsDqsDATA j]qsDqsvNqs~DATA Dqs2]qsj]qs4DATA 2]qsPqsDqs4DATA Pqs8Nqs2]qs4DATA 8NqsNqsPqs~DATA Nqs8]qs8Nqs|DATA 8]qsHAqsNqs4|DATA HAqs\qs8]qs|DATA \qs8AqsHAqsDATA 8AqsPqs\qslDATA PqsWqs8AqslDATA WqsWqsPqs4 DATA WqsWqs~ DATA(WqshWqsXe+pshQqsDATA(hWqsWqsWqsXe+psvNqsDATA(WqsHWqshWqshQqsj]qsDATA(HWqsWqsWqsvNqsj]qsDATA(Wqs(WqsHWqshpsDqsDATA((WqsWqsWqsDqsDqsDATA(WqsWqs(Wqs2]qsj]qsDATA(WqsxWqsWqsDqsPqsDATA(xWqsWqsWqsDqs8NqsDATA(WqsXWqsxWqs8NqsPqsDATA(XWqsWqsWqshpsNqsDATA(Wqs8WqsXWqs2]qs8]qsDATA(8WqsWqsWqsDqs8]qsDATA(WqsWqs8WqsNqs8]qsDATA(WqsWqsWqsHAqsNqsDATA(WqsWqsWqsHAqs8]qsDATA(WqshWqsWqsvNqs\qsDATA(hWqsWqsWqs\qs2]qsDATA(WqsHWqshWqsHAqs\qsDATA(HWqsWqsWqs8AqsNqsDATA(Wqs(WqsHWqsHAqsPqsDATA((WqsWqsWqs8AqsPqsDATA(WqsWqs(WqsPqsWqsDATA(WqsxWqsWqsWqs2]qsDATA(xWqsWqsWqsWqsj]qsDATA(WqsXWqsxWqs8NqsWqsDATA(XWqsWqsWqsWqsWqsDATA(Wqs8WqsXWqs8AqsvNqsDATA(8WqsWqsPqs\qsDATAWqsxWqsvNqsXe+pshQqsj]qs~%Xqs%XqsWqsWqsDATA(WqsWqs DADA~DADA?? ~DATA(WqsWqsmEmEpoo?? pDATAxWqsWqsWqsDqsPqs8NqsDqs5~JWqsWqshWqsWqsDATA(hWqsWqsCACAICACA?? JJ5~JDATA(WqshWqsC=C9J>8?@ J95~JHWqs(WqsDATAXHWqsWqsBUTTONS_PT_contextBUTTONS_PT_contextContext9$DATAXWqsWqsHWqsRENDER_PT_renderRENDER_PT_renderRender9=DATAXWqs(WqsWqsRENDER_PT_layersRENDER_PT_layersLayerso9DATAX(WqsWqsWqsRENDER_PT_dimensionsRENDER_PT_dimensionsDimensions9DATAXWqshWqs(WqsRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:9:DATAXhWqsWqsWqsRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"9DATAXWqsWqshWqsRENDER_PT_shadingRENDER_PT_shadingShading 9DATAXWqsHWqsWqsRENDER_PT_performanceRENDER_PT_performancePerformance9DATAXHWqsWqsWqsRENDER_PT_post_processingRENDER_PT_post_processingPost Processing9DATAXWqsWqsHWqsRENDER_PT_stampRENDER_PT_stampStamp9 DATAXWqs(WqsWqsRENDER_PT_outputRENDER_PT_outputOutput(9 DATAX(WqsWqsRENDER_PT_bakeRENDER_PT_bakeBake9 DATAWqsDATAWqsWqsxWqshpsNqs8]qsDqs3{4|WqsWqsWqshWqsDATA(WqshWqs DADA3`DA`DA?? 4434DATA(hWqsWqs@~CHBpF}CHB33a?HB|HHB= AH4b3{4bDATAWqsDATAWqsXWqsWqsPqsWqsWqs8Nqs5~JgWqsWqsWqsXWqsDATA(WqsXWqsCACAICACA?? JJ5~JDATA(XWqsWqsCC9JL88L?? JM9;5~JMDATAWqs8NqsDATA8Nqs(WqsDATA(WqsXoqsXoqsXoqsXoqsXhoqsHqoqs8doqsjoqshcoqsXoqsDATAXWqs XqsWqsHAqs\qs2]qs8]qs3}m( Xqs( XqsHXqsXqsDATA(HXqsXqs@qDAcDAcDAcDA?? 3}DATA(Xqs(XqsHXqsC@FCF++?@ ,SDATA((XqsXqsXqsCfCww?@ xf3"DATA(XqsXqs(Xqs#C`#C`?@ 33DATA(XqsXqs3SxXqsDATA`xXqs?ޕ? JLD>3;Q?Fwi?JF>#,TY!e?*=>o?E>Fwi?TY5;JF>!e?Q?#,+=>`DAoy@?>{0QQuZ?,h>?>#,>m$?T*= lAoA>tU?pFളZ)>C?4kuPA)ˆy>rB_B@D>3;Q?Fwi?JF>#,TY!e?*=>o?>{0QQuZ?,h>?>#,>m$?T*= lAoA]j@]j@]j@?\>7?8˔oAoAt;?! BVBt~BDATA8( Xqs333?? Ajoqs B?=C DATA XqsHXqsXWqsNqs8AqsPqsHAqs}kXXqsXXqs XqsXqsDATA( XqsXqs@wDA)DA(DA(DA?? }DATA(XqsxXqs XqsHCpHCC?? kDATA(xXqsXqsXqskDATA(XqsxXqsC@zC Ao:o:|HPCGikDATAXXqsXqsDATAhXqsXoqsDATAHXqsXqs Xqs8AqsvNqs\qsPqsm }XqsXqs8XqsXqsDATA(8XqsXqs|DA)DA(DA(DA?? mDATA(XqsXqs8Xqs7CHC@b??cQcDATA(XqsXqs hD hD@bb|H@F #<HBJccDATA@Xqs XoqsDATAXqsHXqsWqs2]qsj]qsWqs5~!J#Xqs#XqsXqsxXqsDATA(XqsxXqsfDAC@AICACA?? JJ5~!!DATA(xXqsXqs5~!JXqsDATA`Xqs9 @!i@AHMݕ/?U~'?3F:?>T8165e?2>Z& 4?ߕ/?7F:?81W~>85e?'?T2>ne@>M@?0?''???T?ļP@l2@11A 4AF>> Ο"o={>3xB ֟&BĭeA(@ݕ/?U~'?3F:?>T8165e?2>Z& 4?0?''???T?ļP@l2@11A 4A~@~@~@?H?N,Z# A3;??ABdZBvBDATA8#Xqs333?? Ajoqs B? #<C SN%XqsXqsWqsSRCompositingg.001&Xqsx,Xqs,Xqs6Xqs6XqsxjXqsXoqsDATA &Xqs8'XqsDATA 8'Xqs'Xqs&XqsDATA 'Xqs(Xqs8'Xqs~DATA (Xqs(Xqs'Xqs~DATA (Xqs(Xqs(XqsDATA (Xqsh)Xqs(Xqs~DATA h)Xqs)Xqs(Xqs \DATA )XqsH*Xqsh)Xqs~\DATA H*Xqs*Xqs)Xqs DATA *Xqs(+XqsH*XqsDATA (+Xqs+Xqs*Xqs DATA +Xqs,Xqs(+XqsDATA ,Xqsx,Xqs+XqsDATA x,Xqs,Xqs DATA(,XqsX-Xqs8'Xqs'XqsDATA(X-Xqs-Xqs,Xqs8'Xqs(XqsDATA(-Xqs8.XqsX-Xqs'Xqs(XqsDATA(8.Xqs.Xqs-Xqs(Xqs(XqsDATA(.Xqs/Xqs8.Xqs(Xqs)XqsDATA(/Xqs/Xqs.Xqsh)Xqs)XqsDATA(/Xqs/Xqs/Xqs(XqsH*XqsDATA(/Xqsh0Xqs/Xqs(XqsH*XqsDATA(h0Xqs0Xqs/Xqsh)XqsH*XqsDATA(0XqsH1Xqsh0Xqs(Xqs)XqsDATA(H1Xqs1Xqs0Xqs(Xqs*XqsDATA(1Xqs(2XqsH1XqsH*Xqs(+XqsDATA((2Xqs2Xqs1Xqs*Xqs(+XqsDATA(2Xqs3Xqs(2Xqs*Xqs+XqsDATA(3Xqsx3Xqs2Xqs(+Xqs+XqsDATA(x3Xqs3Xqs3Xqs&Xqs,XqsDATA(3XqsX4Xqsx3Xqs,Xqsx,XqsDATA(X4Xqs4Xqs3Xqs(Xqsx,XqsDATA(4Xqs85XqsX4Xqsh)Xqsx,XqsDATA(85Xqs5Xqs4Xqs+Xqs,XqsDATA(5Xqs6Xqs85Xqs(+Xqsx,XqsDATA(6Xqs5Xqs&Xqs*XqsDATA6XqsX:Xqs(Xqs8'Xqs'Xqs(Xqs~(Xqs(Xqsx7Xqs8XqsDATA(x7Xqs8Xqs DADA~DADA?? ~DATA(8Xqsx7XqsmEmEpoo?? pDATAX:XqsH?Xqs6Xqsx,Xqsh)Xqs)Xqs(Xqs!~[^\(>Xqs(>XqsH;XqsXqsDATAH?XqsWXqsX:Xqsh)XqsH*Xqs(Xqs)Xqs!~]^VXqsVXqs8@XqsAXqsDATA(8@XqsAXqsCACA]CACA?? ^^!~^DATA(AXqs8@XqsC\C\M^rRLr?@ ^sMs!~]^sCXqsTXqsDATAXCXqsDXqsBUTTONS_PT_contextBUTTONS_PT_contextContextL$DATAXDXqsXFXqsCXqsRENDER_PT_renderRENDER_PT_renderRenderL=DATAXXFXqsGXqsDXqsRENDER_PT_layersRENDER_PT_layersLayersoLDATAXGXqsIXqsXFXqsRENDER_PT_dimensionsRENDER_PT_dimensionsDimensionsLDATAXIXqs8KXqsGXqsRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:L:DATAX8KXqsLXqsIXqsRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"LDATAXLXqsxNXqs8KXqsRENDER_PT_shadingRENDER_PT_shadingShading LDATAXxNXqsPXqsLXqsRENDER_PT_performanceRENDER_PT_performancePerformanceLDATAXPXqsQXqsxNXqsRENDER_PT_post_processingRENDER_PT_post_processingPost ProcessingLDATAXQXqsXSXqsPXqsRENDER_PT_stampRENDER_PT_stampStampL DATAXXSXqsTXqsQXqsRENDER_PT_outputRENDER_PT_outputOutput(L DATAXTXqsXSXqsRENDER_PT_bakeRENDER_PT_bakeBakeL DATAVXqsDATAWXqs(eXqsH?Xqs,Xqs+Xqs(+Xqsx,XqscXqscXqsXXqs^XqsDATA(XXqs8ZXqs@qDAFDAFDAFDA?? DATA(8ZXqs[XqsXXqsC@FCF++?@ ,rDATA([Xqs]Xqs8ZXqsCfCww?@ xf"DATA(]Xqs^Xqs[Xqs#Cl#C?@ pDATA(^Xqs]Xqsr_XqsDATA`_Xqs]e?w@AHMݕ/?U~'?3F:?>T8165e?2>Z& 4?ߕ/?7F:?81W~>85e?'?T2>ne@>M@?*?c''Ӥ?7??T?']@l2zz11A 4A>>Ļ7v=m>3xB֟&BĭeA(@ݕ/?U~'?3F:?>T8165e?2>Z& 4?*?c''Ӥ?7??T?']@l2zz11A 4A>?>?>??H?N,Z#oAoAP1:\>7?8˔?ABdZBvBDATA8cXqs333?? Ajoqs B?=C DATA(eXqsxjXqsWXqs*Xqs(XqsH*Xqs(+Xqs ]hXqshXqsfXqsgXqsDATA(fXqsgXqsBDADADADA??   DATA(gXqsfXqs D DlD`@>C BB??FFQ= @  C1 CDATA0hXqs @Xoqs a?DATAxjXqs(eXqs&Xqs*Xqs+Xqs,XqsoXqsoXqshkXqsHnXqsDATA(hkXqslXqsCAADA@DA@DA?? DATA(lXqsHnXqshkXqsDATA(HnXqslXqsCC@d?rrDATA(!oXqsdA>d>ddd?SNXqsnqs%XqsSRDefaultؒXqsȝXqs8XqsخXqsHXqsXmqsXoqsDATA ؒXqsHXqsDATA HXqsXqsؒXqs*DATA Xqs(XqsHXqs*DATA (XqsXqsXqsDATA XqsXqs(XqsDATA XqsxXqsXqsDATA xXqsXqsXqsDATA XqsXXqsxXqsDATA XXqsȖXqsXqspDATA ȖXqs8XqsXXqspDATA 8XqsXqsȖXqsDATA XqsXqs8XqsDATA XqsXqsXqs@DATA XqsXqsXqs@DATA XqshXqsXqsjDATA hXqsؙXqsXqsjDATA ؙXqsHXqshXqsDATA HXqsXqsؙXqsDATA Xqs(XqsHXqs(DATA (XqsXqsXqs(DATA XqsXqs(XqsDATA XqsxXqsXqsDATA xXqsXqsXqsDATA XqsXXqsxXqsDATA XXqsȝXqsXqsDATA ȝXqsXXqsDATA(8XqsXqsHXqsXqsDATA(XqsXqs8XqsHXqsXqsDATA(XqsXqsXqsXqsXqsDATA(XqsXqsXqsXqsXqsDATA(XqshXqsXqsؒXqsxXqsDATA(hXqsؠXqsXqs(XqsxXqsDATA(ؠXqsHXqshXqsXqsXqsDATA(HXqsXqsؠXqsXqsXqsDATA(Xqs(XqsHXqsxXqsXXqsDATA((XqsXqsXqsXqsXXqsDATA(XqsXqs(XqsXqsȖXqsDATA(XqsxXqsXqs(XqsȖXqsDATA(xXqsXqsXqsXXqsȖXqsDATA(XqsXXqsxXqs8XqsXqsDATA(XXqsȤXqsXqsؒXqsXqsDATA(ȤXqs8XqsXXqsxXqsXqsDATA(8XqsXqsȤXqsXqsXqsDATA(XqsXqs8XqsXqsXqsDATA(XqsXqsXqs8XqsXqsDATA(XqsXqsXqsXqshXqsDATA(XqshXqsXqsXqshXqsDATA(hXqsاXqsXqsXqshXqsDATA(اXqsHXqshXqs8XqsؙXqsDATA(HXqsXqsاXqsXqsHXqsDATA(Xqs(XqsHXqsؙXqsHXqsDATA((XqsXqsXqsXqs(XqsDATA(XqsXqs(XqsXqsXqsDATA(XqsxXqsXqs(XqsXqsDATA(xXqsXqsXqsXqsXqsDATA(XqsXXqsxXqsXqsxXqsDATA(XXqsȫXqsXqsXqsxXqsDATA(ȫXqs8XqsXXqsXqsXqsDATA(8XqsXqsȫXqs(XqsXqsDATA(XqsXqs8XqsxXqsXqsDATA(XqsXqsXqsؙXqsXXqsDATA(XqsXqsXqsXqsXXqsDATA(XqshXqsXqsXqsȝXqsDATA(hXqsخXqsXqsHXqsȝXqsDATA(خXqshXqsXXqsȝXqsDATAHXqsXqsXqsHXqsXqsXqs*nqsnqs8XqsXqsDATA(8XqsXqsDADA`DA`DA?? )DATA(Xqs8XqsmED@poo?? p**DATAXqshXqsHXqsxXqsXXqsȖXqs(Xqsop(Xqs(XqsXqsxXqsDATA(XqsxXqsCAoCAnCAnCA?? VoDATA(xXqsXqsoCU^CUUJU?@ VVUVXqsXqsDATAXXqsXqsBUTTONS_PT_contextBUTTONS_PT_contextContext$DATAXXqs(XqsXqsRENDER_PT_renderRENDER_PT_renderRender=DATAX(XqsȻXqsXqsRENDER_PT_layersRENDER_PT_layersLayersoDATAXȻXqshXqs(XqsRENDER_PT_dimensionsRENDER_PT_dimensionsDimensions DATAXhXqsXqsȻXqsRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:: DATAXXqsXqshXqsRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur" DATAXXqsHXqsXqsRENDER_PT_shadingRENDER_PT_shadingShading  DATAXHXqsXqsXqsRENDER_PT_performanceRENDER_PT_performancePerformance DATAXXqsXqsHXqsRENDER_PT_post_processingRENDER_PT_post_processingPost ProcessingDATAXXqs(XqsXqsRENDER_PT_stampRENDER_PT_stampStampDATAX(XqsXqsXqsRENDER_PT_outputRENDER_PT_outputOutput(DATAXXqshXqs(XqsRENDER_PT_bakeRENDER_PT_bakeBakeDATAXhXqsXqsXqsSCENE_PT_sceneSCENE_PT_sceneScene)=DATAXXqsXqshXqsSCENE_PT_unitSCENE_PT_unitUnits)SDATAXXqsHXqsXqsSCENE_PT_keying_setsSCENE_PT_keying_setsKeying Sets)EDATAXHXqsXqsXqsSCENE_PT_physicsSCENE_PT_physicsGravity)$DATAXXqsXqsHXqsSCENE_PT_simplifySCENE_PT_simplifySimplify)PDATAXXqsXqsSCENE_PT_custom_propsSCENE_PT_custom_propsCustom Properties)$DATA(XqsDATAhXqsXXqsXqsؒXqsXqsXqsxXqs?@8Xqs8XqsXXqsXqsDATA(XXqsXqs DADA`DA`DA?? DATA(XqsXXqs@~CHBXg(CHB%?HB|HHB= AH&?&DATA8XqsDATAXXqshYqshXqsXXqsXqsXqsȖXqsq(Xqs(XqsHXqsXqsDATA(HXqsXqsCAoCAnCAnCA?? DATA(XqsHXqsC^C?? rqDATA(XqsAqsse SculptDATAAqs XqsDATAXqs XoqsXoqsXoqsXoqsXhoqsHqoqs8doqsjoqshcoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqs Xoqs Xoqs Xoqs Xoqs XoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqs Xoqs!Xoqs"Xoqs#Xoqs$Xoqs%Xoqs&Xoqs'Xoqs(Xoqs)Xoqs*Xoqs+Xoqs,Xoqs-Xoqs.Xoqs/Xoqs0XoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqs Xoqs Xoqs Xoqs Xoqs XoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqs Xoqs!Xoqs"Xoqs#Xoqs$Xoqs%Xoqs&Xoqs'Xoqs(XoqsoqsoqsoqshoqsoqsoqsXoqsoqsoqsHoqsoqsoqs8oqspqs pqs(pqsxpqspqspqsh$pqs)pqs/pqsX4pqs9pqs>pqsHDpqsIpqsNpqs8TpqsYpqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqshcoqs8doqsjoqsHqoqsWqs%XqsXqsCnqsnqsHnqs'oqshWqsXhoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqshoqshoqshoqshoqshoqshoqshoqshoqshoqs hoqs hoqs hoqs hoqs hoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqshoqs hoqs!hoqs"hoqs#hoqs$hoqs%hoqs&hoqs'hoqs(hoqs)hoqs*hoqs+hoqs,hoqs-hoqs.hoqs/hoqs0hoqs1hoqs2hoqs3hoqs4hoqs5hoqs6hoqs7hoqs8hoqs9hoqs:hoqs;hoqs<hoqs=hoqs>hoqs?hoqs@hoqsAhoqsBhoqsChoqsDhoqsEhoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqs Xoqs Xoqs Xoqs Xoqs XoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqsXoqs Xoqs!Xoqs"Xoqs#Xoqs$Xoqs%Xoqs&Xoqs'Xoqs(Xoqs)Xoqs*Xoqs+Xoqs,Xoqs-Xoqs.Xoqs/Xoqs0Xoqs1Xoqs2Xoqs3Xoqs4Xoqs5Xoqs6Xoqs7Xoqs8Xoqs9Xoqs:Xoqs;Xoqs<Xoqs=Xoqs>Xoqs?Xoqs@XoqsAXoqsBXoqsCXoqsDXoqsEXoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqs Hoqs Hoqs Hoqs Hoqs HoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqsHoqs Hoqs!Hoqs"Hoqs#Hoqs$Hoqs%Hoqs&Hoqs'Hoqs(Hoqs)Hoqs*Hoqs+Hoqs,Hoqs-Hoqs.Hoqs/Hoqs0Hoqs1Hoqs2Hoqs3Hoqs4Hoqs5Hoqs6Hoqs7Hoqs8Hoqs9Hoqs:Hoqs;Hoqs<Hoqs=Hoqs>Hoqs?Hoqs@HoqsAHoqsBHoqsCHoqsDHoqsEHoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs oqs oqs oqs oqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqsoqs oqs!oqs"oqs#oqs$oqs%oqs&oqs'oqs(oqs)oqs*oqs+oqs,oqs-oqs.oqs/oqs0oqs1oqs2oqs3oqs4oqs5oqs6oqs7oqs8oqs9oqs:oqs;oqs<oqs=oqs>oqs?oqs@oqsAoqsBoqsCoqsDoqsEoqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs 8oqs 8oqs 8oqs 8oqs 8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs8oqs 8oqs!8oqs"8oqs#8oqs$8oqs%8oqs&8oqs'8oqs(8oqs)8oqs*8oqs+8oqs,8oqs-8oqs.8oqs/8oqs08oqs18oqs28oqs38oqs48oqs58oqs68oqs78oqs88oqs98oqs:8oqs;8oqs<8oqs=8oqs>8oqs?8oqs@8oqsA8oqsB8oqsC8oqsD8oqsE8oqspqspqspqspqspqspqspqspqspqs pqs pqs pqs pqs pqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqs pqs!pqs"pqs#pqs$pqs%pqs&pqs'pqs(pqs)pqs*pqs+pqs,pqs-pqs.pqs/pqs0pqs1pqs2pqs3pqs4pqs5pqs6pqs7pqs8pqs9pqs:pqs;pqs<pqs=pqs>pqs?pqs@pqsApqsBpqsCpqsDpqsEpqs pqs pqs pqs pqs pqs pqs pqs pqs pqs  pqs  pqs  pqs  pqs  pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs pqs  pqs! pqs" pqs# pqs$ pqs% pqs& pqs' pqs( pqs) pqs* pqs+ pqs, pqs- pqs. pqs/ pqs0 pqs1 pqs2 pqs3 pqs4 pqs5 pqs6 pqs7 pqs8 pqs9 pqs: pqs; pqs< pqs= pqs> pqs? pqs@ pqsA pqsB pqsC pqsD pqsE pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs (pqs (pqs (pqs (pqs (pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs(pqs (pqs!(pqs"(pqs#(pqs$(pqs%(pqs&(pqs'(pqs((pqs)(pqs*(pqs+(pqs,(pqs-(pqs.(pqs/(pqs0(pqs1(pqs2(pqs3(pqs4(pqs5(pqs6(pqs7(pqs8(pqs9(pqs:(pqs;(pqs<(pqs=(pqs>(pqs?(pqs@(pqsA(pqsB(pqsC(pqsD(pqsE(pqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqs xpqs xpqs xpqs xpqs xpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqsxpqs xpqs!xpqs"xpqs#xpqs$xpqs%xpqs&xpqs'xpqs(xpqs)xpqs*xpqs+xpqs,xpqs-xpqs.xpqs/xpqs0xpqs1xpqs2xpqs3xpqs4xpqs5xpqs6xpqs7xpqs8xpqs9xpqs:xpqs;xpqs<xpqs=xpqs>xpqs?xpqs@xpqsAxpqsBxpqsCxpqsDxpqsExpqspqspqspqspqspqspqspqspqspqs pqs pqs pqs pqs pqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqs pqs!pqs"pqs#pqs$pqs%pqs&pqs'pqs(pqs)pqs*pqs+pqs,pqs-pqs.pqs/pqs0pqs1pqs2pqs3pqs4pqs5pqs6pqs7pqs8pqs9pqs:pqs;pqs<pqs=pqs>pqs?pqs@pqsApqsBpqsCpqsDpqsEpqspqspqspqspqspqspqspqspqspqs pqs pqs pqs pqs pqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqspqs pqs!pqs"pqs#pqs$pqs%pqs&pqs'pqs(pqs)pqs*pqs+pqs,pqs-pqs.pqs/pqs0pqs1pqs2pqs3pqs4pqs5pqs6pqs7pqs8pqs9pqs:pqs;pqs<pqs=pqs>pqs?pqs@pqsApqsBpqsCpqsDpqsEpqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqs h$pqs h$pqs h$pqs h$pqs h$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqsh$pqs h$pqs!h$pqs"h$pqs#h$pqs$h$pqs%h$pqs&h$pqs'h$pqs(h$pqs)h$pqs*h$pqs+h$pqs,h$pqs-h$pqs.h$pqs/h$pqs0h$pqs1h$pqs2h$pqs3h$pqs4h$pqs5h$pqs6h$pqs7h$pqs8h$pqs9h$pqs:h$pqs;h$pqs<h$pqs=h$pqs>h$pqs?h$pqs@h$pqsAh$pqsBh$pqsCh$pqsDh$pqsEh$pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs )pqs )pqs )pqs )pqs )pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs)pqs )pqs!)pqs")pqs#)pqs$)pqs%)pqs&)pqs')pqs()pqs))pqs*)pqs+)pqs,)pqs-)pqs.)pqs/)pqs0)pqs1)pqs2)pqs3)pqs4)pqs5)pqs6)pqs7)pqs8)pqs9)pqs:)pqs;)pqs<)pqs=)pqs>)pqs?)pqs@)pqsA)pqsB)pqsC)pqsD)pqsE)pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs /pqs /pqs /pqs /pqs /pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs/pqs /pqs!/pqs"/pqs#/pqs$/pqs%/pqs&/pqs'/pqs(/pqs)/pqs*/pqs+/pqs,/pqs-/pqs./pqs//pqs0/pqs1/pqs2/pqs3/pqs4/pqs5/pqs6/pqs7/pqs8/pqs9/pqs:/pqs;/pqs</pqs=/pqs>/pqs?/pqs@/pqsA/pqsB/pqsC/pqsD/pqsE/pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqs X4pqs X4pqs X4pqs X4pqs X4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqsX4pqs X4pqs!X4pqs"X4pqs#X4pqs$X4pqs%X4pqs&X4pqs'X4pqs(X4pqs)X4pqs*X4pqs+X4pqs,X4pqs-X4pqs.X4pqs/X4pqs0X4pqs1X4pqs2X4pqs3X4pqs4X4pqs5X4pqs6X4pqs7X4pqs8X4pqs9X4pqs:X4pqs;X4pqs<X4pqs=X4pqs>X4pqs?X4pqs@X4pqsAX4pqsBX4pqsCX4pqsDX4pqsEX4pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs 9pqs 9pqs 9pqs 9pqs 9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs9pqs 9pqs!9pqs"9pqs#9pqs$9pqs%9pqs&9pqs'9pqs(9pqs)9pqs*9pqs+9pqs,9pqs-9pqs.9pqs/9pqs09pqs19pqs29pqs39pqs49pqs59pqs69pqs79pqs89pqs99pqs:9pqs;9pqs<9pqs=9pqs>9pqs?9pqs@9pqsA9pqsB9pqsC9pqsD9pqsE9pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs >pqs >pqs >pqs >pqs >pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs>pqs >pqs!>pqs">pqs#>pqs$>pqs%>pqs&>pqs'>pqs(>pqs)>pqs*>pqs+>pqs,>pqs->pqs.>pqs/>pqs0>pqs1>pqs2>pqs3>pqs4>pqs5>pqs6>pqs7>pqs8>pqs9>pqs:>pqs;>pqs<>pqs=>pqs>>pqs?>pqs@>pqsA>pqsB>pqsC>pqsD>pqsE>pqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqs HDpqs HDpqs HDpqs HDpqs HDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqsHDpqs HDpqs!HDpqs"HDpqs#HDpqs$HDpqs%HDpqs&HDpqs'HDpqs(HDpqs)HDpqs*HDpqs+HDpqs,HDpqs-HDpqs.HDpqs/HDpqs0HDpqs1HDpqs2HDpqs3HDpqs4HDpqs5HDpqs6HDpqs7HDpqs8HDpqs9HDpqs:HDpqs;HDpqs<HDpqs=HDpqs>HDpqs?HDpqs@HDpqsAHDpqsBHDpqsCHDpqsDHDpqsEHDpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqs Ipqs Ipqs Ipqs Ipqs IpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqsIpqs Ipqs!Ipqs"Ipqs#Ipqs$Ipqs%Ipqs&Ipqs'Ipqs(Ipqs)Ipqs*Ipqs+Ipqs,Ipqs-Ipqs.Ipqs/Ipqs0Ipqs1Ipqs2Ipqs3Ipqs4Ipqs5Ipqs6Ipqs7Ipqs8Ipqs9Ipqs:Ipqs;Ipqs<Ipqs=Ipqs>Ipqs?Ipqs@IpqsAIpqsBIpqsCIpqsDIpqsEIpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqs Npqs Npqs Npqs Npqs NpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqsNpqs Npqs!Npqs"Npqs#Npqs$Npqs%Npqs&Npqs'Npqs(Npqs)Npqs*Npqs+Npqs,Npqs-Npqs.Npqs/Npqs0Npqs1Npqs2Npqs3Npqs4Npqs5Npqs6Npqs7Npqs8Npqs9Npqs:Npqs;Npqs<Npqs=Npqs>Npqs?Npqs@NpqsANpqsBNpqsCNpqsDNpqsENpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs 8Tpqs 8Tpqs 8Tpqs 8Tpqs 8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs8Tpqs 8Tpqs!8Tpqs"8Tpqs#8Tpqs$8Tpqs%8Tpqs&8Tpqs'8Tpqs(8Tpqs)8Tpqs*8Tpqs+8Tpqs,8Tpqs-8Tpqs.8Tpqs/8Tpqs08Tpqs18Tpqs28Tpqs38Tpqs48Tpqs58Tpqs68Tpqs78Tpqs88Tpqs98Tpqs:8Tpqs;8Tpqs<8Tpqs=8Tpqs>8Tpqs?8Tpqs@8TpqsA8TpqsB8TpqsC8TpqsD8TpqsE8TpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqs Ypqs Ypqs Ypqs Ypqs YpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqsYpqs Ypqs!Ypqs"Ypqs#Ypqs$Ypqs%Ypqs&Ypqs'Ypqs(Ypqs)Ypqs*Ypqs+Ypqs,Ypqs-Ypqs.Ypqs/Ypqs0Ypqs1Ypqs2Ypqs3Ypqs4Ypqs5Ypqs6Ypqs7Ypqs8Ypqs9Ypqs:Ypqs;Ypqs<Ypqs=Ypqs>Ypqs?Ypqs@YpqsAYpqsBYpqsCYpqsDYpqsEYpqshcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqs hcoqs hcoqs hcoqs hcoqs hcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqshcoqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs 8doqs 8doqs 8doqs 8doqs 8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs8doqs      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRS      !"#$%&'()*+,-./0123joqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqs joqs joqs joqs joqs joqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqsjoqs joqs!joqs"joqs#joqs$joqs%joqs&joqs'joqs(joqs)joqs*joqs+joqs,joqs-joqs.joqs/joqs0joqs1joqs2joqs3joqs4joqs5joqs6joqs7joqs8joqs9joqs:joqs;joqs<joqs=joqs>joqs?joqs@joqsAjoqsBjoqsCjoqsDjoqsEjoqsFjoqsGjoqsHjoqsIjoqsJjoqsKjoqsLjoqsMjoqsNjoqsOjoqsPjoqsQjoqsRjoqsSjoqsTjoqsUjoqsVjoqsWjoqsXjoqsYjoqsZjoqs[joqs\joqs]joqs^joqs_joqs`joqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqs Hqoqs Hqoqs Hqoqs Hqoqs HqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqsHqoqs Hqoqs!Hqoqs"Hqoqs#Hqoqs$Hqoqs%Hqoqs&Hqoqs'Hqoqs(Hqoqs)Hqoqs*Hqoqs+Hqoqs,Hqoqs-Hqoqs.Hqoqs/Hqoqs0Hqoqs1Hqoqs2Hqoqs3Hqoqs4Hqoqs5Hqoqs6Hqoqs7Hqoqs8Hqoqs9Hqoqs:Hqoqs;Hqoqs<Hqoqs=Hqoqs>Hqoqs?Hqoqs@HqoqsAHqoqsBHqoqsCHqoqsDHqoqsEHqoqsFHqoqsGHqoqsHHqoqsIHqoqsJHqoqsKHqoqsLHqoqsMHqoqsNHqoqsOHqoqsPHqoqsQHqoqsRHqoqsSHqoqsTHqoqsUHqoqsVHqoqsWHqoqsXHqoqsYHqoqsZHqoqs[Hqoqs\Hqoqs]Hqoqs^Hqoqs_Hqoqs`HqoqsWqsWqsWqsWqsWqsWqsWqsWqsWqs Wqs%Xqs%Xqs%Xqs%Xqs%Xqs%Xqs%Xqs%Xqs%Xqs %XqsXqsXqsXqsXqsXqsXqsXqsXqsXqs XqsCnqsCnqsCnqsCnqsCnqsCnqsCnqsCnqsCnqs Cnqsnqsnqsnqsnqsnqsnqsnqsnqsnqs nqsHnqsHnqsHnqsHnqsHnqsHnqsHnqsHnqsHnqs Hnqs'oqs'oqs'oqs'oqs'oqs'oqs'oqs'oqs'oqs 'oqs     hWqshWqshWqshWqshWqshWqshWqshWqshWqs hWqs hWqsXhoqsXhoqsXhoqsXhoqsXhoqsXhoqsXhoqsXhoqsXhoqs Xhoqs Xhoqs Xhoqs Xhoqs XhoqsXhoqsXhoqsXhoqsXhoqsXhoqsXhoqsXhoqswoqsDATAhYqsYqsXXqs8XqsؙXqsHXqsXqsYqsYqsXYqsYqsDATA(XYqsȎYqs@qDADAK`DA`DA?? LLDATA(ȎYqsxYqsXYqs CC?@ 28YqsؑYqsDATAX8YqsؑYqsVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXؑYqs8YqsVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(xYqsYqsȎYqs!CvfC^dv?@ "YqsYqsDATAXYqsVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(YqsYqsxYqs4C`#C`ã?@ DATA(YqsYqsDhYqsDATA`hYqs?7B LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?TA5>#,>mv$BH*=!lA!oA'>~tU?`FH!;<81pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?TA5>#,>mv$BH*=$!j?!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8Yqs333?? Ajoqs B?=zD DATAYqsYqshYqsXqsXqshXqsXqsAi)hYqshYqsYqsYqsDATA(YqsYqs DADA`DA`DA?? AZDATA(YqsYqs@~CHBXg(CHB?HB|HHB= AH[iDATAhYqsDATAYqsxYqsYqsXqs8XqsXqshXqskXYqsXYqsxYqsYqsDATA(xYqsYqs DADAK`DA`DA?? LLkkDATA(YqsxYqs@~CHBXg(CHB?HB|HHB= AHkDATAXYqsDATAxYqsYqsYqsؙXqsXXqsȝXqsHXqs+(Yqs(YqshYqsYqsDATA(hYqsتYqs@qDADA`DA`DA?? DATA(تYqsYqshYqs CC?@ 2HYqsYqsDATAXHYqsYqsVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXYqsHYqsVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(YqsYqsتYqs!CvfC^dv?@ "YqsYqsDATAXYqsVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(YqsYqsYqs4C`#C`ã?@ DATA(YqsYqsDxYqsDATA`xYqs?ÃB LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?YA5>#,>m{BH*=!lA!oA'>~tU?`F/_N4;vP<1pu²Aݞ6rB;B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?YA5>#,>m{BH*=$!/I?!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8(Yqs333?? Ajoqs B?=zD DATAYqsmqsxYqsXqsxXqsXqs(Xqs)wXmqsXmqsYqs8mqsDATA(YqsYqs@qDADA`DA`DA?? )BDATA(YqsYqsYqs CChh?@ ii7i2xYqsYqsDATAXxYqsYqsVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXYqsxYqsVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(YqsYqsYqs!CvfC^dv?@ C6"(Yqs(YqsDATAX(YqsVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(Yqs8mqsYqs4C@s#C~ã\\?@ ]]0C]8YqsmqsDATAX8YqsYqsVIEW3D_PT_objectVIEW3D_PT_objectTransformznDATAXYqsxYqs8YqsVIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease PencilPDATAXxYqsYqsYqsVIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView?DATAXYqsYqsxYqsVIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem$DATAXYqsmqsYqsVIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplaygDATAXmqsmqsYqsVIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImagesODATAXmqsmqsVIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform Orientations7DATA(8mqsYqs/C]mqsDATA`mqs?26@ LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQuZ? ?5>#,>mT#@H*=!lA!oAd>ntU?@FR=U>3pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQuZ? ?5>#,>mT#@H*=%!T=!lA!oA@@@@@@mWC <?\>7?8˔!oAoAf;?8 BBj~BDATA8Xmqs333?? Ajoqs B?=zD DATAmqshmqsYqsXqsXqs(XqsXqs'3mqsmqsmqsmqsDATA(mqs8mqs@qDADA`DA`DA?? DATA(8mqsmqsmqs CC?@ '2mqsHmqsDATAXmqsHmqsVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXHmqsmqsVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(mqsmqs8mqs!CvfC^dv?@ "XmqsXmqsDATAXXmqsVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(mqsmqsmqsC@sC=N<?@ N='NNhmqs(mqsDATAXhmqsmqsVIEW3D_PT_objectVIEW3D_PT_objectTransformz=nDATAXmqsmqshmqsVIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease Pencil=PDATAXmqsHmqsmqsVIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView=?DATAXHmqsmqsmqsVIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem=$DATAXmqsmqsHmqsVIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplayg=DATAXmqs(mqsmqsVIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImagesO=DATAX(mqsmqsVIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform Orientations7=DATA(mqsmqs'8mqsDATA`8mqs?fB LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>"*UtQQsZ?~@5>#,>mtAH*=!lA!oA'>~tU?pF{FV;<1pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>F"*UtQQsZ?~@5>#,>mtAH*=$!d?!lA!oA}-@}-@}-@mWC <?\>7?8˔!oAoA;?8 BBj~BDATA8mqs333?? Ajoqs B?=zD DATAhmqsXmqsmqsxXqsXqsXqsXqsXqsnnqsnqsDATAXmqshmqsXXqsXqsXqsȝXqs' nqs nqsHmqsnqsDATA(Hmqsmqs@qDADA`DA`DA?? DATA(mqshnqsHmqs CCP  ?@  2(nqsnqsDATAX(nqsnqsVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXnqs(nqsVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(hnqsxnqsmqs!CvfC^dv?@ "nqsnqsDATAXnqsVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(xnqsnqshnqs4C`#C`ã?@ DATA(nqsxnqsD X nqsDATA`X nqs?B LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?TA5>#,>mvBH*=!lA!oA'>~tU?`FH! ;<0pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?TA5>#,>mvBH*=$!j@!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8 nqs333?? Ajoqs B?=zD SNnqsCnqsXqsSRDefault-fullnqsnqshnqsnqsxnqsX?nqsXoqsPkDATA nqs8nqsDATA 8nqsnqsnqs~DATA nqsnqs8nqst~DATA nqsnqsnqstDATA nqsnqsnqs\DATA nqsnqst\DATA(hnqsnqs8nqsnqsDATA(nqsHnqshnqsnqsnqsDATA(HnqsnqsnqsnqsnqsDATA(nqs(nqsHnqs8nqsnqsDATA((nqsnqsnqsnqsnqsDATA(nqsnqs(nqsnqsnqsDATA(nqsnqsnqsnqsDATAxnqsX?nqsnqsnqsnqsnqsXqst[u\Ƚph7nqs>nqshnqsH2nqsx]qshQqsDATA(hnqsnqsYDADAtDADA?? uutu (p(mPqs(mPqs+ps)1qsDATA(nqs nqshnqsCCm~%l%?@ ~&m&}6[~& ~2p[qs[qsHnqs(nqs86qsNqsDATAXHnqsnqsppsVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Toolsm'DATAXnqsnqsHnqsVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATAXnqs(nqsnqsVIEW3D_PT_tools_mesheditVIEW3D_PT_tools_mesheditMesh ToolsmDATAX(nqsnqsVIEW3D_PT_tools_meshedit_optionsVIEW3D_PT_tools_meshedit_optionsMesh Options@mtDATA( nqs#nqsnqsC@JCRm~l?@ ~m}5~ "p}]qs}]qs8"nqs8"nqsH:ps+psDATAX8"nqspVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorOperatoritmodect All3D Cursorp'DATA(#nqsH2nqs nqs4Cm#CPAA?@ BBt[B ؿpPqsxYqsH%nqs0nqs&BqsPqsDATAXH%nqs&nqspVIEW3D_PT_objectVIEW3D_PT_objectTransformzn&DATAX&nqs(nqsH%nqs(pVIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease PencilPDATAX(nqs(*nqs&nqsQpsVIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView)DATAX(*nqs+nqs(nqsTpsVIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem$DATAX+nqsh-nqs(*nqsxVpsVIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplay}DATAXh-nqs/nqs+nqsxbpsVIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImageseDATAX/nqs0nqsh-nqsdpsVIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform OrientationsMDATAX0nqs/nqsVIEW3D_PT_view3d_meshdisplayVIEW3D_PT_view3d_meshdisplayMesh Display-hDATA(H2nqs#nqs~[CB pMqs(.]qs3nqsDATA`3nqst?? LY~?= =抏>rp?<>!>%=0%?Y~?=>p?=r;>e(p׿!M??[?m== %/>2r?r?Z6?<$B?,=?0%?4r!?A6jQ2?='K>b[??A8ft#@(@Y~?= =p?P>9,r??[?m== Z6?ʋP[49//rr1~F?????mWC <?uP?qnqs333?? Ajoqswoqs B?=zD DATA(8nqsX:nqs@PDADAtDADA?? uutB[upDATA(X:nqs;nqs8nqspCP_CPAA?@ BBABph/]qsEQqsDATA(;nqs8=nqsX:nqsDpB@aDpB;`DlB`DlB?? <<tA<pDATA(8=nqs;nqs0C@@@aD=??t(pDATAh>nqsh7nqs8nqs8=nqsXAqs(]{nqs{nqsxnqsXznqsDATA(xnqsXznqsCADA=@DA@DA?? >>A~>DATA(XznqsxnqsCCDVD=B #<zD >C>CA~>CDATA{nqs DATA~nqsnqswnqsJnqsJnqsInqs8InqsE?]nqsnqsnqshnqsDATA(nqsnqs@qDA~DA~DA~DA?? E?DATA(nqsnqsnqsC@FCF++?@ ,EECDATA(nqsnqsnqsCfCww?@ xfE?"DATA(nqshnqsnqs4Cm#Cmã?@ ??DATA(hnqsnqsE?C؆nqsDATA`؆nqs#=K(=o?????????#=K(=o?5ApykA?????#=K(=o?t@t@t@??5AoA9P=\>7?8˔?BBDATA8nqs333?? Ajoqs B?=zD DATAnqs~nqsxGnqsFnqsJnqsJnqsCD]؏nqs؏nqsnqshnqsDATA(nqshnqsCACACCACA?? DDCDDATA(hnqsnqsCC@ 3DB22B?? DC31CDCDATA؏nqsAqsDATAAqs8nqsDATA8nqsXoqsXoqsXoqsXoqsXhoqsHqoqs8doqsjoqshcoqsXoqsSNnqsHnqsCnqsSRScriptingg.001nqsșnqs8nqshnqsأnqsnqsXoqsDATA nqsnqsDATA nqsnqsnqsDATA nqshnqsnqs~DATA hnqsؕnqsnqs~DATA ؕnqsHnqshnqsDATA Hnqsnqsؕnqs~DATA nqs(nqsHnqsDATA (nqsnqsnqsDATA nqsnqs(nqshDATA nqsxnqsnqshDATA xnqsnqsnqshDATA nqsXnqsxnqsDATA Xnqsșnqsnqs~DATA șnqsXnqsDATA(8nqsnqsnqsnqsDATA(nqsnqs8nqsnqsؕnqsDATA(nqsnqsnqsnqsHnqsDATA(nqsnqsnqsؕnqsHnqsDATA(nqshnqsnqsHnqsnqsDATA(hnqs؜nqsnqshnqs(nqsDATA(؜nqsHnqshnqsnqsnqsDATA(Hnqsnqs؜nqsؕnqsnqsDATA(nqs(nqsHnqsnqsnqsDATA((nqsnqsnqs(nqsnqsDATA(nqsnqs(nqsnqsxnqsDATA(nqsxnqsnqsnqsxnqsDATA(xnqsnqsnqs(nqsnqsDATA(nqsXnqsxnqsnqsnqsDATA(XnqsȠnqsnqsHnqsXnqsDATA(Ƞnqs8nqsXnqshnqsXnqsDATA(8nqsnqsȠnqsnqsXnqsDATA(nqsnqs8nqsؕnqsșnqsDATA(nqsnqsnqsnqsșnqsDATA(nqsnqsnqsxnqsșnqsDATA(nqshnqsnqsnqsnqsDATA(hnqsnqsnqs(nqsDATAأnqsnqsؕnqsnqsnqsHnqs~]nqsnqsȤnqs8nqsDATA(Ȥnqs8nqs DADA~DADA?? ~DATA(8nqsȤnqsDBDBnBomB?? CnC~CDATAnqs8nqsأnqs(nqsnqsXnqshnqs~nqsnqsnqsnqsDATA(nqsnqsCACACACA?? ~DATA(nqsnqsC=C4}~|?@ }~xnqsXnqsDATAXxnqsnqsBUTTONS_PT_contextBUTTONS_PT_contextContext|$DATAXnqsnqsxnqsRENDER_PT_renderRENDER_PT_renderRender|=DATAXnqsXnqsnqsRENDER_PT_layersRENDER_PT_layersLayerso|DATAXXnqsnqsnqsRENDER_PT_dimensionsRENDER_PT_dimensionsDimensions|DATAXnqsnqsXnqsRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:|:DATAXnqs8nqsnqsRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"|DATAX8nqsضnqsnqsRENDER_PT_shadingRENDER_PT_shadingShading |DATAXضnqsxnqs8nqsRENDER_PT_performanceRENDER_PT_performancePerformance|DATAXxnqsnqsضnqsRENDER_PT_post_processingRENDER_PT_post_processingPost Processing|DATAXnqsnqsxnqsRENDER_PT_stampRENDER_PT_stampStamp| DATAXnqsXnqsnqsRENDER_PT_outputRENDER_PT_outputOutput(| DATAXXnqsnqsRENDER_PT_bakeRENDER_PT_bakeBake| DATAnqsDATA8nqsnqsnqsxnqsșnqsnqsnqsi?nqsnqs(nqsnqsDATA((nqsnqs@qDA=DA=DA=DA?? iDATA(nqsnqs(nqsC@FCF++?@ ,%DATA(nqsxnqsnqsCfCww?@ xf"DATA(xnqsnqsnqs#C#Cyy?@ zhDATA(nqsxnqs%XnqsDATA`Xnqs?J?PףD>3;Q?Fwi?JF>#,TY!e?*=>o?E>Fwi?TY5;JF>!e?Q?#,+=>`DAoy@?>ޠQQuZ?> .>#,>m6uU?F +!>?`5hąC% ÈG6DWѦCGBD>3;Q?Fwi?JF>#,TY!e?*=>o?>ޠQQuZ?> .>#,>m7?8˔oAoAk;?! BVBt~BDATA8nqs333?? Ajoqs B? #<C DATAnqsnqs8nqsnqsnqsnqs(nqsghnqsnqsxnqsnqsDATA(xnqsnqsCADADADA?? DATA(nqsxnqsD3CDCMM?? NNgNDATA(XnqsșQqsDATAșQqsDATAnqsXnqsXnqs>>> pythonDATAnqsnqsnqsnqsnqsHnqsXnqs~hnqshnqsnqsnqsDATA(nqsnqsCACACACA?? ~DATA(nqsnqsCC}||?? }~DATAhnqsAqsDATAAqsnqsDATAnqsXoqsXoqsXoqsXoqsXhoqsHqoqs8doqsjoqshcoqsXoqsDATAnqsnqsnqsؕnqsșnqsxnqsi ?nqsnqsnqsXnqsDATA(nqsXnqsCA>DA=DA=DA?? iDATA(XnqsnqsDDD)dD.>CC$ #<zD %%%DATAnqs =z||SNHnqs'oqsnqsSRUV EditinghnqsxnqsnqsHnqsnqsoqsXoqsDATA hnqsnqsDATA nqsHnqshnqsDATA Hnqsnqsnqs~DATA nqs(nqsHnqs~DATA (nqsnqsnqsDATA nqsnqs(nqs~DATA nqsxnqsnqsDATA xnqsnqsDATA(nqsXnqsnqsHnqsDATA(Xnqsnqsnqsnqs(nqsDATA(nqs8nqsXnqsHnqsnqsDATA(8nqsnqsnqs(nqsnqsDATA(nqsnqs8nqs(nqsnqsDATA(nqsnqsnqshnqsxnqsDATA(nqsnqsnqshnqs(nqsDATA(nqshnqsnqsnqsxnqsDATA(hnqsnqsnqsnqsnqsDATA(nqsHnqshnqsnqsxnqsDATA(HnqsnqsnqsnqsDATAnqsnqs(nqsnqsHnqsnqs~h'oqsh'oqsnqsnqsDATA(nqsnqs DADA~DADA?? ~DATA(nqsnqsmEmEpoo?? pDATAnqsoqsnqshnqs(nqsnqsxnqshnqshnqsxnqsnqsDATA(xnqsnqsCArDAqDAqDA?? DATA(nqsnqsxnqs[CsJCs?@ XnqsXnqsDATAXXnqsIMAGE_PT_gpencilIMAGE_PT_gpencilGrease PencilPDATA(nqsnqsCC33+?33@DATA(!hnqsdA>d>ddd?DATAoqsnqsxnqsnqsnqsnqs~%oqs%oqsoqs oqsDATA(oqs8oqs@qDAmDA@mDA@mDA?? ~DATA(8oqsHoqsoqs CVCVWW?@ XXhXoqsoqsDATAXoqsVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject ToolsDATA(HoqsXoqs8oqs!CfC[Zww?@ xxhx"oqsoqsDATAXoqsVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorOperatorDATA(Xoqs oqsHoqs#C~#C~  ?@  ~~DATA( oqsXoqsi~8"oqsDATA`8"oqsH?? JLD>3;Q?Fwi?JF>#,TY!e?*=>_?E>Fwi?TY4;JF>!e?Q?#,+=>6@_?? ?0QQ?X>?>#,>ՒΜz?T*=dbR@_@y\>,? (K5>}Q?sMd@JWA.Xj@-@D>3;Q?Fwi?JF>#,TY!e?*=>_? ?0QQ?X>?>#,>ՒΜz?T*=dbR@_@>>>?\>7?8˔_@_@r:?! BUBt~BDATA8%oqs333?? Ajoqs B?=C SN'oqsHnqsSRVideo Editing)oqs-oqsX.oqs5oqs86oqsOoqsXoqsDATA )oqs)oqsDATA )oqs)oqs)oqsDATA )oqsh*oqs)oqs~DATA h*oqs*oqs)oqs~DATA *oqsH+oqsh*oqsDATA H+oqs+oqs*oqs~DATA +oqs(,oqsH+oqs~DATA (,oqs,oqs+oqs\DATA ,oqs-oqs(,oqsPDATA -oqsx-oqs,oqsDATA x-oqs-oqs-oqsPDATA -oqsx-oqs~\DATA(X.oqs.oqs)oqs)oqsDATA(.oqs8/oqsX.oqs)oqs*oqsDATA(8/oqs/oqs.oqs)oqsH+oqsDATA(/oqs0oqs8/oqs*oqsH+oqsDATA(0oqs0oqs/oqsH+oqs+oqsDATA(0oqs0oqs0oqs)oqs(,oqsDATA(0oqsh1oqs0oqs*oqs,oqsDATA(h1oqs1oqs0oqs(,oqs-oqsDATA(1oqsH2oqsh1oqs-oqsx-oqsDATA(H2oqs2oqs1oqs,oqsx-oqsDATA(2oqs(3oqsH2oqs+oqs-oqsDATA((3oqs3oqs2oqsh*oqs-oqsDATA(3oqs4oqs(3oqs(,oqs-oqsDATA(4oqsx4oqs3oqs)oqsh*oqsDATA(x4oqs4oqs4oqsH+oqs,oqsDATA(4oqsX5oqsx4oqs+oqsx-oqsDATA(X5oqs5oqs4oqs*oqs-oqsDATA(5oqsX5oqs+oqs-oqsDATA86oqs:oqs*oqs)oqs)oqsH+oqs~xWoqsxWoqs(7oqs8oqsDATA((7oqs8oqs DADA~DADA?? ~DATA(8oqs(7oqsmEmEpoo?? pDATA:oqs>oqs86oqs)oqs(,oqs-oqsh*oqs~[\=oqs=oqs:oqshoqsFoqs:oqs(,oqs-oqs+oqs-oqs~]EoqsEoqs?oqs8DoqsDATA(?oqsXAoqsDADA~DADA?? ~]vDATA(XAoqsBoqs?oqs\CKCpp?@ qq~wqDATA(Boqs8DoqsXAoqsppDDppDD;F;F'7PGDATA(8DoqsBoqszCAzCApp A@|HB #<BiqwqDATAEoqs@DATAFoqsOoqs>oqs-oqs*oqs,oqsx-oqsOPMoqsMoqsGoqs(LoqsDATA(GoqsHIoqs@wDATDAOSDASDA?? PPOPDATA(HIoqsJoqsGoqsHCpHC?? DATA(Joqs(LoqsHIoqsOODATA((LoqsJoqsC@zC Avvo:o:|HPCGiwOwDATAMoqsNoqsDATAhNoqsXoqsDATAOoqsFoqsx-oqs,oqsH+oqs+oqsQ~.8Voqs8VoqsxPoqsToqsDATA(xPoqsQoqsCADA-DADA?? ..Q~.DATA(QoqsXSoqsxPoqs~~DATA(XSoqsToqsQoqsCCđDFFD-;F;F'7PG..Q~.DATA(ToqsXSoqszCAzCAKK A@|HB #<BiLDATA8Voqs@SCXoqsSCScenetageain^oqsjoqsXhoqs^oqs_oqs^oqsT?$KmWC ??_??BLENDER_RENDERD?fC?+psPRBXNqsA << ?8=?DATA`^oqsDATA(^oqs(_oqsqywoqsDATA((_oqs_oqs^oqs.HqoqsDATA(_oqs(_oqs.^joqsDATA`oqsBqsQqsboqs?L?B ?o:= ??NpqsP2 HB2 B2 HB2 HB2 HB2 HB2 HB>? #<===ff??AHz?=???C#y??DATA8BqsoqsDATA8QqsoqsDATA`boqs/pqsdd|AJA6V{?DATAXboqsRenderLayerrCAhcoqsCACameraamera.001?=B B@?LA8doqs!LALamp ?????AB>??Xfoqs.?A4B?@@L=@ ???o:??????@?????goqsDATA@XfoqsO????C?55?55?Aqs??????DATAAqsM??DATA(goqs WOXhoqsWOWorldrcP=rcP=rcP=6$<6$<6$<??A @A@pA A?L= ף;>??joqsDATA(joqs OB joqstHqoqsOBCameraamera.001 hcoqs  ne@>N@???*?91<"P?????ޕ/?5F:?81V~>75e?'?T3>ne@>N@??????33?3?5)?ݕ/?V~'?3F:?>T8175e?4>Z& 4?OBd8???>6 ?u=?????hpoqsDATAhpoqsw??=L> ף<OB HqoqstwoqsjoqsOBLamp 8doqs  p@?p@???{&?W+b=?????6씾t? bfE9L"?%?_>oK?p@?p@??????22?3?'4'?6씾fE&?t?9L_> b#?oK? ?Af ?DOBd8?<?>">u=??@???voqsDATAvoqsw??=L> ף<OB woqstHqoqsOBText8@ps}oqs  Q?????????ӻ+?ӻ+Q??????????ӻ+?ӻ+Q>?d8? #=?>=???????@???-\qs8NqsME}oqs.8+psMEMeshHoqsoqsHoqs~oqsoqs oqsZt?W>ף`? >?CDATAh~oqsToqsDATAoqs4*2=0.?II*2=I2R>II2R>d>&is|>d>ZɄ>0>U[>>Gt>&\YD>->Z5b\>=>9h\7>O >5@\}>=V>ɍ\ u> >%ñ[cR>",x>8Gz[Ѽ>R{d>/E[] >L>зl[>L0>ĵZ#> >_δZ?IN"?_mϒF?pw<UI 5Z"?f<\I4Z<?_*=rI4Z?Y=I4Zf?½=I'4Z?nm=2J3Z6?X=J2Z>?=KD2Z?f=K1Z`B?/=L0Z> ?=L0Z ? >L|/Z~?`6>$Mr/rZY?}3>L0_ZJ?NF>\L0IZ@>sY>Ku21Z> j>IJk4Z؃>{>H6Y^>J>oF9Y4 >s>C1=Y}>vߓ>H@@Y>SK>@ ?>7HYٮ>>Y$bzٮ>©>7);Y>h>0(Y,>5> 8*YPm>ہ>0?3 YL>#>E,X >>KXts>h`>QgXl9>Jc>&U=Y/>>=X;YX)?>NZ# Y?RV>l[3Y?;>[Yf??[ XVv>. ?8YIX&>?T %gX>?QNj1[X|`>?E<_X3>xd!? 2L%?b1NX>p(?&SXJ>+?WXGd>,?>ZXTv> .?v[!Y\>0.? [Y2R>*?&is">*?f[I>r?2[>j1?[$[$>D1?Hl-\>,?@s\]>T?\?>?*\r> ?b\">$ ?\5>>$ ?q]޻\t>RH?:8y\w>ܙ?1\V>G>\[>1>WD\+>>B\e>>\ع>t>'\+>a}>S*3\c>>>\>>xlG\}>>خN\3>9>uSy\郡>ɡ>V8\Ob>>X[">r>Y&[2R>r>&&s2R>r>R꽗&&:">r>RYڤOb>>R꽚X郡>ɡ>RVȣ3>9>RuS}>>RخNL>>RxlG c>>R꽠>+>a}>RS*3ع>t>R'Ge>>R+>>R>1>RWDV>G>R\w>ܙ?Rϣt>RH?R:8ꇣ5>>$ ?Rq]E">$ ?Rr> ?R꽌b?>?R*]>T?RJ>,?R@$>D1?RHlӣ>j1?R[$I>r?R2O">*?Rf2R>*?R꽗&i:\>0.?R [$Tv> .?R꽔v[ߦGd>,?R>ZJ>+?RW(>p(?R꽁&SN>2L%?Rb1Nr3>xd!?R ?RE<>?RQNj1&>?RT %Vv>. ?R8YIf??R꽔[ ^?;>R[?RV>Rl[ͦX)?>RNZ#/>>R=X;l9>Jc>R&U=ts>h`>RQg >>RKL>#>RE,Pm>ہ>R0?3,>5>R 8*>h>R꽦0ئٮ>©>R7)Ŧٮ>>RY$bT_> ?>R꽛7Hx>SK>R@vߓ>RH@@T4 >s>R꽬C1=;^>J>RoF9 ؃>{>R꽞H6> j>RIJk4@>sY>R꽃Ku2ϥJ?NF>R\L0Y?}3>RL0~?`6>R$Mr/ ? >RL|/d> ?=R꽈L0_`B?/=RL0[?f=R꽗K1Y>?=RKD2Z6?X=R꽝J2]?nm=R2J3bf?½=RI'4h?Y=R꽜I4o<?_*=RrI4u"?f >R_L>L0>Rĵ] >L>RзlѼ>R{d>R꽌/ǻcR>",x>R8GÆ u> >R%ñF}>=V>R꽢ɍ7>O >R5>=>R꽱9YD>->RZ5>>Gt>R꽧ڣɄ>0>RU?|>d>R꽏2R>d>R꽗&i:2R>RI*2=R*2=0.?RIDATAhoqsTHoqsDATAHoqs1"B"C " C ] ""( ) * + , - . / \ ] "( "' ( "' "'  "& ' " & " % & " $ % " # $ " " # "! " "  ! "  "            """"""""""""" " !"!"""#"#$"$%"%&"&'"'("()")*"*+"+,",-"-."./"/0"/Z /[ /\ 01"0X 0Y 0Z 12"1V 1W 1X 23"2U 2V 34"3T 3U 45"4R 4S 4T 56"5Q 5R 67"6O 6P 6Q 78"7M 7N 7O 89"8J 8K 8L 8M 9:"9G 9H 9I 9J :;":D :E :F :G ;<";C ;D <="<C =>"=C >?">C ?@"?C @A"@C AB"AC BC CD"C]"DE"EF"FG"GH"HI"IJ"JK"KL"LM"MN"NO"OP"PQ"QR"RS"ST"TU"UV"VW"WX"XY"YZ"Z["[\"\]"\_ ^_"]^"[`"_`"Za"`a"Yb"ab"Xc"bc"Wd"cd"Ve"de"Uf"ef"Tg"fg"Sh"gh"Ri"hi"Qj"ij"Pk"jk"Ol"kl"Nm"lm"Mn"mn"Lo"no"Kp"op"Jq"pq"Ir"qr"Hs"rs"Gt"st"Fu"tu"Ev"uv"Dw vw"^x"Cx"wx"Az"yz"By"@{"z{"?|"{|">}"|}"=~"}~"<"~";"":""9""8""7""6""5""4""3""2""1""0""/"".""-"",""+""*"")""(""'""&""% "$ "# "" "! " " " " " " " " " " " " " " """"" " " " "" "" "" "" """""""""" """""""y"""x x xy xz x{ x| x} x~ x x w w ^ v u t t s r q q p o n n m l l k j j i i h g g f f e e d c c b a a ` _ ^ _ DATAhoqsTHoqsDATAHoqs0CBCCABC@AC?@C>?C=>C<=C;<CD;D:;]CE:DF:EG:FG9:H9GI9HJ9IJ89K8JL8KM8LM78N7MO7NO67P6OQ6PQ56R5QR45S4RT4ST34U3TU23V2UV12W1VX1WX01Y0XZ0YZ/0[/Z\/[]\]/\./-.,-+,*+)*()(('('''&' & & %& % $% $ #$ # "#" !"! ! ]\_^\[`_[Za`ZYbaYXcbXWdcWVedVUfeUTgfTShgSRihRQjiQPkjPOlkONmlNMnmMLonLKpoKJqpJIrqIHsrHGtsGFutFEvuEDwvC]^xDCxwBAzyA@{z@?|{?>}|>=~}=<~<;;::99887766554433221100//..--,,++**))((''&&%%$$##""!!  Byxyxyzxz{x{|x|}x}~x~xxwxwx^wvvuutttssrrqqqppoonnnmmlllkkjjjiiihhgggfffeeeddcccbbaaa``_^^__BRoqsSoqsBRAddh.001?8oqs??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAoqs??????????L>?????????????????????????????DATA@8oqsO????C?~6=~.=]qs??????DATA0]qsM?>k?@? ף=?BRoqsSoqsoqsBRBlob001?oqs??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATA0oqs??????????L>?????????????????????????????DATA@oqsO????C?._raxNqs??????DATA0xNqsM?>ףp?@?u=?BRoqsShoqsoqsBRBlur.004?oqs??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAoqs??????????L>?????????????????????????????DATA@oqsO????C?~6=~.=XYqs??????DATA0XYqsM?>k?@? ף=?BRhoqsSoqsoqsBRBrush?oqs??????????L>?????????????????????????????# Kfff?=??????>!?>>>>?DATAoqs??????????L>?????????????????????????????DATA@oqsO????C?._ra8oqs??????DATA08oqsM?>ףp?@?u=?BRoqsSoqshoqsBRClay001?oqs??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATA oqs??????????L>?????????????????????????????DATA@oqsO????C?._raoqs??????DATA0oqsM?>ףp?@?u=?BRoqsSXoqsoqsBRClone001?Hoqs??????????L>?????????????????????????????# Kfff?=???333???>!>???DATApoqs??????????L>?????????????????????????????DATA@HoqsO????C?~6=~.=oqs??????DATA0oqsM?>k?@? ף=?BRXoqsSoqsoqsBRCrease001?oqs??????????L>?????????????????????????????# Kfff?=???>??>!>?>>>>?DATAoqs??????????L>?????????????????????????????DATA@oqsO????C?a2p? (oqs??????DATA0(oqsM?>?@? #=?BRoqsSoqsXoqsBRDarken06?oqs??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAoqs??????????L>?????????????????????????????DATA@oqsO????C?~6=~.=xoqs??????DATA0xoqsM?>k?@? ף=?BRoqsSHoqsoqsBRDraw.001?8oqs??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATA`oqs??????????L>?????????????????????????????DATA@8oqsO????C?._raoqs??????DATA0oqsM?>ףp?@?u=?BRHoqsSoqsoqsBRFill/Deepen001?oqs??????????L>?????????????????????????????# Kfff?=???? ??>!>??>>??DATAoqs??????????L>?????????????????????????????DATA@oqsO????C?._raoqs??????DATA0oqsM?>ףp?@?u=?BRoqsSoqsHoqsBRFlatten/Contrast001?oqs??????????L>?????????????????????????????# Kfff?=??????>!>??>>??DATAoqs??????????L>?????????????????????????????DATA@oqsO????C?._rahoqs??????DATA0hoqsM?>ףp?@?u=?BRoqsS8oqsoqsBRGrab001?(oqs??????????L>?????????????????????????????K Kfff?=???L>??>!>>?>DATAPoqs??????????L>?????????????????????????????DATA@(oqsO????C?._raoqs??????DATA0oqsM?>ףp?@?u=?BR8oqsSpqsoqsBRInflate/Deflate001?xpqs??????????L>?????????????????????????????# Kfff?=??????>!>@?@?@?>>>DATAoqs??????????L>?????????????????????????????DATA@xpqsO????C?._rapqs??????DATA0pqsM?>ףp?@?u=?BRpqsS pqs8oqsBRLayer001?pqs??????????L>?????????????????????????????# Kfff?=??????>!>?>>DATApqs??????????L>?????????????????????????????DATA@pqsO????C?._raX pqs??????DATA0X pqsM?>ףp?@?u=?BR pqsS(pqspqsBRLighten5? pqs??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA@ pqs??????????L>?????????????????????????????DATA@ pqsO????C?~6=~.=pqs??????DATA0pqsM?>k?@? ף=?BR(pqsSxpqs pqsBRMixh?hpqs??????????L>????????????????????????????? # Kfff?=???333???>!>???DATApqs??????????L>?????????????????????????????DATA@hpqsO????C?~6=~.=pqs??????DATA0pqsM?>k?@? ף=?BRxpqsSpqs(pqsBRMultiply?pqs??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATApqs??????????L>?????????????????????????????DATA@pqsO????C?~6=~.=Hpqs??????DATA0HpqsM?>k?@? ף=?BRpqsSpqsxpqsBRNudge001?pqs??????????L>?????????????????????????????# Kfff?=???? ??>!>>?>DATA0pqs??????????L>?????????????????????????????DATA@pqsO????C?._rapqs??????DATA0pqsM?>ףp?@?u=?BRpqsSh$pqspqsBRPinch/Magnify001?X"pqs??????????L>?????????????????????????????# Kfff?=??????>!>@?@?@?>>>DATApqs??????????L>?????????????????????????????DATA@X"pqsO????C?._ra#pqs??????DATA0#pqsM?>ףp?@?u=?BRh$pqsS)pqspqsBRPolish001?'pqs??????????L>?????????????????????????????# Kfff?=???????>!>??>>??DATA$pqs??????????L>?????????????????????????????DATA@'pqsO????C?._ra8)pqs??????DATA08)pqsM?>ףp?@?u=?BR)pqsS/pqsh$pqsBRScrape/Peaks001?,pqs??????????L>?????????????????????????????# Kfff?=???? ??>!>??>>??DATA *pqs??????????L>?????????????????????????????DATA@,pqsO????C?._ra.pqs??????DATA0.pqsM?>ףp?@?u=?BR/pqsSX4pqs)pqsBRSculptDraw?H2pqs??????????L>?????????????????????????????# Kfff?=??????>!wN??>>>>?DATAp/pqs??????????L>?????????????????????????????DATA@H2pqsO????C?._ra3pqs??????DATA03pqsM?>ףp?@?u=?BRX4pqsS9pqs/pqsBRSmear001?7pqs??????????L>?????????????????????????????# Kfff?=???L>??>!>???DATA4pqs??????????L>?????????????????????????????DATA@7pqsO????C?~6=~.=(9pqs??????DATA0(9pqsM?>k?@? ף=?BR9pqsS>pqsX4pqsBRSmooth001??????????????????????????????#Kfff?=??????>!>@?@?@?DATA:pqs??????????L>?????????????????????????????DATA@pqs??????DATA0x>pqsM?>ףp?@?u=?BR>pqsSHDpqs9pqsBRSnake Hook001?8Bpqs??????????L>?????????????????????????????K Kfff?=???? ??>!>>?>DATA`?pqs??????????L>?????????????????????????????DATA@8BpqsO????C?._raCpqs??????DATA0CpqsM?>ףp?@?u=?BRHDpqsSIpqs>pqsBRSoften01?Gpqs??????????L>?????????????????????????????# Kfff?=???L>??>!>???DATADpqs??????????L>?????????????????????????????DATA@GpqsO????C?~6=~.=Ipqs??????DATA0IpqsM?>k?@? ף=?BRIpqsSNpqsHDpqsBRSubtract?Lpqs??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAJpqs??????????L>?????????????????????????????DATA@LpqsO????C?~6=~.=hNpqs??????DATA0hNpqsM?>k?@? ף=?BRNpqsS8TpqsIpqsBRTexDraw?(Rpqs??????????L>?????????????????????????????# Kfff?=???333???>!>???>>?DATAPOpqs??????????L>?????????????????????????????DATA@(RpqsO????C?._raSpqs??????DATA0SpqsM?>ףp?@?u=?BR8TpqsSYpqsNpqsBRThumb001?xWpqs??????????L>?????????????????????????????K Kfff?=???? ??>!>>?>DATATpqs??????????L>?????????????????????????????DATA@xWpqsO????C?._raYpqs??????DATA0YpqsM?>ףp?@?u=?BRYpqsS8TpqsBRTwist001?\pqs??????????L>?????????????????????????????K Kfff?=??????>!>>?>DATAYpqs??????????L>?????????????????????????????DATA@\pqsO????C?._raX^pqs??????DATA0X^pqsM?>ףp?@?u=?DNA1dSqsSDNANAME *next*prev*data*first*lastxyxminxmaxyminymax*pointergroupvalval2typesubtypeflagname[32]saveddatalentotallen*newid*libname[24]usicon_id*propertiesid*idblock*filedataname[240]filepath[240]totpad*parentw[2]h[2]changed[2]changed_timestamp[2]*rect[2]*obblocktypeadrcodename[128]*bp*beztmaxrcttotrctvartypetotvertipoextraprtbitmaskslide_minslide_maxcurval*drivercurvecurshowkeymuteipoposrelativetotelempad2*weightsvgroup[32]sliderminslidermax*adt*refkeyelemstr[32]elemsizeblock*ipo*fromtotkeyslurph*line*formatblenlinenostartendpad1flagscolor[4]pad[4]*namenlineslines*curl*sellcurcselcmarkers*undo_bufundo_posundo_len*compiledmtimesizeseekdtxpassepartalphaclipstaclipendlensortho_scaledrawsizeshiftxshiftyYF_dofdist*dof_ob*sceneframenrframesoffsetsfrafie_imacyclokmulti_indexlayerpassibufs*gputexture*anim*rr*renders[8]render_slotlast_render_slotsourcelastframetpageflagtotbindxrepyreptwstatwendbindcode*repbind*packedfile*previewlastupdatelastusedanimspeedgen_xgen_ygen_typeaspxaspytexcomaptomaptonegblendtype*object*texuvname[32]projxprojyprojzmappingofs[3]size[3]rottexflagcolormodelpmaptopmaptonegnormapspacewhich_outputbrush_map_modepad[7]rgbkdef_varcolfacvarfacnorfacdispfacwarpfaccolspecfacmirrfacalphafacdifffacspecfacemitfachardfacraymirrfactranslfacambfaccolemitfaccolreflfaccoltransfacdensfacscatterfacreflfactimefaclengthfacclumpfacdampfackinkfacroughfacpadensfacgravityfaclifefacsizefacivelfacfieldfacshadowfaczenupfaczendownfacblendfacname[160]*handle*pname*stnamesstypesvars*varstr*result*cfradata[32](*doit)()(*instance_init)()(*callback)()versionaipotype*ima*cube[6]imat[4][4]obimat[3][3]stypeviewscalenotlaycuberesdepthrecalclastsizefalloff_typefalloff_softnessradiuscolor_sourcetotpointspdpadpsyspsys_cache_spaceob_cache_space*point_tree*point_datanoise_sizenoise_depthnoise_influencenoise_basispdpad3[3]noise_facspeed_scalefalloff_speed_scalepdpad2*coba*falloff_curveresol[3]interp_typefile_formatextendsmoked_typeint_multiplierstill_framesource_path[240]*datasetcachedframenoisesizeturbulbrightcontrastsaturationrfacgfacbfacfiltersizemg_Hmg_lacunaritymg_octavesmg_offsetmg_gaindist_amountns_outscalevn_w1vn_w2vn_w3vn_w4vn_mexpvn_distmvn_coltypenoisedepthnoisetypenoisebasisnoisebasis2imaflagcropxmincropymincropxmaxcropymaxtexfilterafmaxxrepeatyrepeatcheckerdistnablaiuser*nodetree*plugin*env*pd*vduse_nodesloc[3]rot[3]mat[4][4]min[3]max[3]modetotexshdwrshdwgshdwbshdwpadenergydistspotsizespotblendhaintatt1att2*curfalloffshadspotsizebiassoftcompressthreshpad5[3]bufsizesampbuffersfiltertypebufflagbuftyperay_sampray_sampyray_sampzray_samp_typearea_shapearea_sizearea_sizeyarea_sizezadapt_threshray_samp_methodtexactshadhalostepsun_effect_typeskyblendtypehorizon_brightnessspreadsun_brightnesssun_sizebackscattered_lightsun_intensityatm_turbidityatm_inscattering_factoratm_extinction_factoratm_distance_factorskyblendfacsky_exposuresky_colorspacepad4[6]*mtex[18]pr_texturepad6[6]densityemissionscatteringreflectionemission_col[3]transmission_col[3]reflection_col[3]density_scaledepth_cutoffasymmetrystepsize_typeshadeflagshade_typeprecache_resolutionstepsizems_diffms_intensityms_spreadmaterial_typespecrspecgspecbmirrmirgmirbambrambbambgambemitangspectraray_mirroralpharefspeczoffsaddtranslucencyvolfresnel_mirfresnel_mir_ifresnel_trafresnel_tra_ifiltertx_limittx_falloffray_depthray_depth_traharseed1seed2gloss_mirgloss_trasamp_gloss_mirsamp_gloss_traadapt_thresh_miradapt_thresh_traaniso_gloss_mirdist_mirfadeto_mirshade_flagmode_lflarecstarclinecringchasizeflaresizesubsizeflarebooststrand_stastrand_endstrand_easestrand_surfnorstrand_minstrand_widthfadestrand_uvname[32]sbiaslbiasshad_alphaseptexrgbselpr_typepr_backpr_lampml_flagdiff_shaderspec_shaderroughnessrefracparam[4]rmsdarkness*ramp_col*ramp_specrampin_colrampin_specrampblend_colrampblend_specramp_showpad3rampfac_colrampfac_spec*groupfrictionfhreflectfhdistxyfrictdynamodesss_radius[3]sss_col[3]sss_errorsss_scalesss_iorsss_colfacsss_texfacsss_frontsss_backsss_flagsss_presetmapto_texturedshadowonly_flaggpumaterialname[256]*bbi1j1k1i2j2k2selcol1selcol2zquat[4]expxexpyexpzradrad2s*mat*imatelemsdisp*editelems**matflag2totcolwiresizerendersizethresh*lastelemvec[3][3]alfaweighth1h2f1f2f3hidevec[4]mat_nrpntsupntsvresoluresolvorderuordervflaguflagv*knotsu*knotsvtilt_interpradius_interpcharidxkernwhnurbs*keyindexshapenrnurb*editnurb*bevobj*taperobj*textoncurve*path*keybevdrawflagtwist_modetwist_smoothsmallcaps_scalepathlenbevresolwidthext1ext2resolu_renresolv_renactnu*lastselspacemodespacinglinedistshearfsizewordspaceulposulheightxofyoflinewidth*str*selboxes*editfontfamily[24]*vfont*vfontb*vfonti*vfontbisepcharctimetotboxactbox*tbselstartselend*strinfocurinfo*mface*mtface*tface*mvert*medge*dvert*mcol*msticky*texcomesh*mselect*edit_meshvdataedatafdatatotedgetotfacetotselectact_facesmoothreshsubdivsubdivrsubsurftypeeditflag*mr*pv*tpageuv[4][2]col[4]transptileunwrapv1v2v3v4edcodecreasebweightdef_nr*dwtotweightco[3]no[3]uv[2]co[2]indexfis[256]totdisp(*disps)()v[4]midpad[2]v[2]*faces*colfaces*edges*vertslevelslevel_countcurrentnewlvledgelvlpinlvlrenderlvluse_col*edge_flags*edge_creases*vert_map*edge_map*old_faces*old_edgesstackindex*errormodifier*texture*map_objectuvlayer_name[32]uvlayer_tmptexmappingsubdivTyperenderLevels*emCache*mCachedefaxispad[6]lengthrandomizeseed*ob_arm*start_cap*end_cap*curve_ob*offset_oboffset[3]scale[3]merge_distfit_typeoffset_typecountaxistolerance*mirror_obsplit_anglevalueresval_flagslim_flagse_flagsbevel_angledefgrp_name[32]*domain*flow*colltimepad10strengthdirectionmidlevel*projectors[10]*imagenum_projectorsaspectxaspectyscalexscaleypercentfaceCountfacrepeat*objectcenterstartxstartyheightnarrowspeeddampfallofftimeoffslifetimedeformflagmulti*prevCossubtarget[32]parentinv[4][4]cent[3]*indexartotindexforce*clothObject*sim_parms*coll_parms*point_cacheptcaches*x*xnew*xold*current_xnew*current_x*current_v*mfacesnumvertsnumfacestime_xtime_xnew*bvhtree*v*dmcfraoperationvertextotinfluencegridsize*bindinfluences*bindoffsets*bindcagecostotcagevert*dyngrid*dyninfluences*dynverts*pad2dyngridsizedyncellmin[3]dyncellwidthbindmat[4][4]*bindweights*bindcos(*bindfunc)()*psystotdmverttotdmedgetotdmfacepositionrandom_position*facepavgroupprotectlvlsculptlvltotlvlsimple*fss*target*auxTargetvgroup_name[32]keepDistshrinkTypeshrinkOptsprojAxissubsurfLevels*originfactorlimit[2]originOptsoffset_faccrease_innercrease_outercrease_rimmat_ofsmat_ofs_rim*ob_axisstepsrender_stepsiterscrew_ofsangle*object_from*object_tofalloff_radius*lattpntswopntsuopntsvopntswtypeutypevtypewfufvfwdudvdw*def*latticedatalatmat[4][4]*editlattvec[8][3]*sculptpartypepar1par2par3parsubstr[32]*track*proxy*proxy_group*proxy_from*action*poselib*pose*gpdavs*mpathconstraintChannelseffectdefbasemodifiersrestore_mode*matbitsactcoldloc[3]orig[3]dsize[3]drot[3]dquat[4]rotAxis[3]drotAxis[3]rotAngledrotAngleobmat[4][4]constinv[4][4]imat_ren[4][4]laycolbitstransflagprotectflagtrackflagupflagnlaflagipoflagipowinscaflagscavisflagboundtypedupondupoffdupstadupendsfmassdampinginertiaformfactorrdampingmarginmax_velmin_velm_contactProcessingThresholdrotmodedtempty_drawtypepad1[3]empty_drawsizedupfacescapropsensorscontrollersactuatorsbbsize[3]actdefgameflaggameflag2*bsoftsoftflaganisotropicFriction[3]constraintsnlastripshooksparticlesystem*soft*dup_groupfluidsimFlagrestrictflagshapeflagrecalcobody_type*fluidsimSettings*derivedDeform*derivedFinallastDataMaskcustomdata_maskstateinit_stategpulamppc_ids*duplilistima_ofs[2]pad3[8]curindexactiveoriglayno_drawanimatedomat[4][4]orco[3]deflectforcefieldshapetex_modekinkkink_axiszdirf_strengthf_dampf_flowf_sizef_powermaxdistmindistf_power_rmaxradminradpdef_damppdef_rdamppdef_permpdef_frictpdef_rfrictpdef_sticknessabsorptionpdef_sbdamppdef_sbiftpdef_sboftclump_facclump_powkink_freqkink_shapekink_ampfree_endtex_nabla*rngf_noiseweight[13]global_gravityrt[3]totdataframetotpointdata_types*data[8]*cur[8]extradatastepsimframestartframeendframeeditframelast_exactcompressionname[64]prev_name[64]info[64]path[240]*cached_framesmem_cache*edit(*free_edit)()linStiffangStiffvolumeviterationspiterationsditerationsciterationskSRHR_CLkSKHR_CLkSSHR_CLkSR_SPLT_CLkSK_SPLT_CLkSS_SPLT_CLkVCFkDPkDGkLFkPRkVCkDFkMTkCHRkKHRkSHRkAHRcollisionflagsnumclusteriterationsweldingtotspring*bpoint*bspringmsg_lockmsg_valuenodemassnamedVG_Mass[32]gravmediafrictrklimitphysics_speedgoalspringgoalfrictmingoalmaxgoaldefgoalvertgroupnamedVG_Softgoal[32]fuzzynessinspringinfrictnamedVG_Spring_K[32]efraintervallocalsolverflags**keystotpointkeysecondspringcolballballdampballstiffsbc_modeaeroedgeminloopsmaxloopschokesolver_IDplasticspringpreload*scratchshearstiffinpush*pointcache*effector_weightslcom[3]lrot[3][3]lscale[3][3]pad4[4]vel[3]*fmdshow_advancedoptionsresolutionxyzpreviewresxyzrealsizeguiDisplayModerenderDisplayModeviscosityValueviscosityModeviscosityExponentgrav[3]animStartanimEndbakeStartbakeEndgstarmaxRefineiniVelxiniVelyiniVelz*orgMesh*meshBBsurfdataPath[240]bbStart[3]bbSize[3]typeFlagsdomainNovecgenvolumeInitTypepartSlipValuegenerateTracersgenerateParticlessurfaceSmoothingsurfaceSubdivsparticleInfSizeparticleInfAlphafarFieldSize*meshVelocitiescpsTimeStartcpsTimeEndcpsQualityattractforceStrengthattractforceRadiusvelocityforceStrengthvelocityforceRadiuslastgoodframemistypehorrhorghorbzenrzengzenbfastcolexposureexprangelinfaclogfacgravityactivityBoxRadiusskytypeocclusionResphysicsEngineticratemaxlogicstepphysubstepmaxphystepmisimiststamistdistmisthistarrstargstarbstarkstarsizestarmindiststardiststarcolnoisedofstadofenddofmindofmaxaodistaodistfacaoenergyaobiasaomodeaosampaomixaocolorao_adapt_threshao_adapt_speed_facao_approx_errorao_approx_correctionao_indirect_energyao_env_energyao_pad2ao_indirect_bouncesao_padao_samp_methodao_gather_methodao_approx_passes*aosphere*aotablespad[3]selcolsxsy*lpFormat*lpParmscbFormatcbParmsfccTypefccHandlerdwKeyFrameEverydwQualitydwBytesPerSeconddwFlagsdwInterleaveEveryavicodecname[128]*cdParms*padcdSizeqtcodecname[128]codecTypecodecSpatialQualitycodeccodecFlagscolorDepthcodecTemporalQualityminSpatialQualityminTemporalQualitykeyFrameRatebitRateaudiocodecTypeaudioSampleRateaudioBitDepthaudioChannelsaudioCodecFlagsaudioBitRateaudio_codecvideo_bitrateaudio_bitrateaudio_mixrateaudio_volumegop_sizerc_min_raterc_max_raterc_buffer_sizemux_packet_sizemux_ratemixratemainspeed_of_sounddoppler_factordistance_model*mat_override*light_overridelay_zmasklayflagpassflagpass_xor*avicodecdata*qtcodecdataqtcodecsettingsffcodecdatasubframepsfrapefraimagesframaptothreadsframelenblurfacedgeRedgeGedgeBfullscreenxplayyplayfreqplayattribframe_stepstereomodedimensionspresetmaximsizexschyschxpartsypartsplanesimtypesubimtypequalitydisplaymodescemoderaytrace_optionsraytrace_structurerendererocrespad4alphamodeosafrs_secedgeintsafetyborderdisprectlayersactlaymblur_samplesxaspyaspfrs_sec_basegausscolor_mgt_flagpostgammaposthuepostsatdither_intensitybake_osabake_filterbake_modebake_flagbake_normal_spacebake_quad_splitbake_maxdistbake_biasdistbake_padpic[240]stampstamp_font_idstamp_udata[160]fg_stamp[4]bg_stamp[4]seq_prev_typeseq_rend_typeseq_flagpad5[5]simplify_flagsimplify_subsurfsimplify_shadowsamplessimplify_particlessimplify_aossscineonwhitecineonblackcineongammajp2_presetjp2_depthrpad3domeresdomemodedomeangledometiltdomeresbuf*dometextengine[32]particle_percsubsurf_maxshadbufsample_maxao_errortiltresbuf*warptextcol[3]matmodeframingrt1rt2domestereoflageyeseparation*camera*brush*paint_cursorpaint_cursor_col[4]paintseam_bleednormal_anglescreen_grab_size[2]*paintcursorinverttotrekeytotaddkeybrushtypebrush[7]emitterdistselectmodeedittypedraw_stepfade_framesname[36]mat[3][3]radial_symm[3]last_xlast_ylast_angledraw_anchoredanchored_sizeanchored_location[3]anchored_initial_mouse[2]draw_pressurepressure_valuespecial_rotation*vpaint_prev*wpaint_prev*vpaint*wpaintvgroup_weightcornertypeeditbutflagjointrilimitdegrturnextr_offsdoublimitnormalsizeautomergesegmentsringsverticesunwrapperuvcalc_radiusuvcalc_cubesizeuvcalc_marginuvcalc_mapdiruvcalc_mapalignuvcalc_flaguv_flaguv_selectmodeuv_padgpencil_flagsautoik_chainlenimapaintparticleproportional_sizeselect_threshclean_threshautokey_modeautokey_flagretopo_moderetopo_paint_toolline_divellipse_divretopo_hotspotmultires_subdiv_typeskgen_resolutionskgen_threshold_internalskgen_threshold_externalskgen_length_ratioskgen_length_limitskgen_angle_limitskgen_correlation_limitskgen_symmetry_limitskgen_retarget_angle_weightskgen_retarget_length_weightskgen_retarget_distance_weightskgen_optionsskgen_postproskgen_postpro_passesskgen_subdivisions[3]skgen_multi_level*skgen_templatebone_sketchingbone_sketching_convertskgen_subdivision_numberskgen_retarget_optionsskgen_retarget_rollskgen_side_string[8]skgen_num_string[8]edge_modeedge_mode_live_unwrapsnap_modesnap_flagsnap_targetproportionalprop_modeproportional_objectsauto_normalizesculpt_paint_settingssculpt_paint_unified_sizesculpt_paint_unified_unprojected_radiussculpt_paint_unified_alphatotobjtotlamptotobjseltotcurvetotmeshtotarmaturescale_lengthsystemsystem_rotationgravity[3]quick_cache_step*world*setbase*basact*obeditcursor[3]twcent[3]twmin[3]twmax[3]layactlay_updatedcustomdata_mask_modal*ed*toolsettings*statsaudiotransform_spaces*sound_scene*sound_scene_handle*sound_scrub_handle*fps_info*theDagdagisvaliddagflagspad6pad5active_keyingsetkeyingsetsgmunitphysics_settingsblendviewwinmat[4][4]viewmat[4][4]viewinv[4][4]persmat[4][4]persinv[4][4]viewmatob[4][4]persmatob[4][4]twmat[4][4]viewquat[4]zfaccamdxcamdypixsizecamzoomtwdrawflagis_persprflagviewlockperspclip[6][4]clip_local[6][4]*clipbb*localvd*ri*depths*sms*smooth_timerlviewquat[4]lpersplviewgridviewtwangle[3]padfregionbasespacetypeblockscaleblockhandler[8]lay_used*ob_centrebgpicbase*bgpicob_centre_bone[32]drawtypeob_centre_cursorscenelockaroundgridnearfarmodeselectgridlinesgridsubdivgridflagtwtypetwmodetwflagpad2[2]afterdraw_transpafterdraw_xrayafterdraw_xraytranspzbufxrayndofmodendoffilter*properties_storageverthormaskmin[2]max[2]minzoommaxzoomscrollscroll_uikeeptotkeepzoomkeepofsalignwinxwinyoldwinxoldwiny*tab_offsettab_numtab_currpt_maskv2d*adsghostCurvesautosnapcursorValmainbmainbomainbuserre_alignpreviewtexture_contextpathflagdataicon*pinidrender_sizechanshownzebrazoomtitle[32]dir[240]file[80]renamefile[80]renameedit[80]filter_glob[64]active_filesel_firstsel_lastsortdisplayf_fpfp_str[8]scroll_offset*params*files*folders_prev*folders_next*op*smoothscroll_timer*layoutrecentnrbookmarknrsystemnrtree*treestoresearch_string[32]search_tseoutlinevisstoreflagsearch_flags*cumapscopessample_line_histcursor[2]centxcentycurtileimtypenrlockpindt_uvstickydt_uvstretch*texttopviewlinesmenunrlheightcwidthlinenrs_totleftshowlinenrstabnumbershowsyntaxline_hlightoverwritelive_editpix_per_linetxtscrolltxtbarwordwrapdopluginsfindstr[256]replacestr[256]margin_column*drawcache*py_draw*py_event*py_button*py_browsercallback*py_globaldictlastspacescriptname[256]scriptarg[256]*script*but_refs*arraycachescache_displayredraws*idaspect*curfontmxmy*edittreetreetypetexfromlinkdragtitle[24]menunumtilesxnumtilesyselstateviewrectbookmarkrectscrollposscrollheightscrollarearetvalactive_bookmarkprv_wprv_h(*returnfunc)()(*returnfunc_event)()(*returnfunc_args)()*arg1*arg2*menup*pupmenu*imglen_alloccursorscrollbackhistoryprompt[256]language[32]sel_startsel_endfilter[64]*area*soundsndnrfilename[256]blf_iduifont_idr_to_lpointskerningitalicboldshadowshadxshadyshadowalphashadowcolorpaneltitlegrouplabelwidgetlabelwidgetpanelzoomminlabelcharsminwidgetcharscolumnspacetemplatespaceboxspacebuttonspacexbuttonspaceypanelspacepanelouterpad[1]outline[4]inner[4]inner_sel[4]item[4]text[4]text_sel[4]shadedshadetopshadedownalpha_checkinner_anim[4]inner_anim_sel[4]inner_key[4]inner_key_sel[4]inner_driven[4]inner_driven_sel[4]wcol_regularwcol_toolwcol_textwcol_radiowcol_optionwcol_togglewcol_numwcol_numsliderwcol_menuwcol_pulldownwcol_menu_backwcol_menu_itemwcol_boxwcol_scrollwcol_progresswcol_list_itemwcol_stateiconfile[80]back[4]title[4]text_hi[4]header[4]header_title[4]header_text[4]header_text_hi[4]button[4]button_title[4]button_text[4]button_text_hi[4]list[4]list_title[4]list_text[4]list_text_hi[4]panel[4]panel_title[4]panel_text[4]panel_text_hi[4]shade1[4]shade2[4]hilite[4]grid[4]wire[4]select[4]lamp[4]active[4]group[4]group_active[4]transform[4]vertex[4]vertex_select[4]edge[4]edge_select[4]edge_seam[4]edge_sharp[4]edge_facesel[4]edge_crease[4]face[4]face_select[4]face_dot[4]extra_edge_len[4]extra_face_angle[4]extra_face_area[4]pad3[4]normal[4]vertex_normal[4]bone_solid[4]bone_pose[4]strip[4]strip_select[4]cframe[4]nurb_uline[4]nurb_vline[4]act_spline[4]nurb_sel_uline[4]nurb_sel_vline[4]lastsel_point[4]handle_free[4]handle_auto[4]handle_vect[4]handle_align[4]handle_sel_free[4]handle_sel_auto[4]handle_sel_vect[4]handle_sel_align[4]ds_channel[4]ds_subchannel[4]console_output[4]console_input[4]console_info[4]console_error[4]console_cursor[4]vertex_sizeoutline_widthfacedot_sizebpadsyntaxl[4]syntaxn[4]syntaxb[4]syntaxv[4]syntaxc[4]movie[4]image[4]scene[4]audio[4]effect[4]plugin[4]transition[4]meta[4]editmesh_active[4]handle_vertex[4]handle_vertex_select[4]handle_vertex_sizehpad[7]preview_back[4]solid[4]tuitbutstv3dtfiletipotinfotsndtacttnlatseqtimatimaseltexttoopsttimetnodetlogictuserpreftconsoletarm[20]active_theme_areamodule[64]spec[4]dupflagsavetimetempdir[160]fontdir[160]renderdir[240]textudir[160]plugtexdir[160]plugseqdir[160]pythondir[160]sounddir[160]image_editor[240]anim_player[240]anim_player_presetv2d_min_gridsizetimecode_styleversionsdbl_click_timegameflagswheellinescrolluiflaglanguageuserprefviewzoommixbufsizeaudiodeviceaudiorateaudioformataudiochannelsdpiencodingtransoptsmenuthreshold1menuthreshold2themesuifontsuistyleskeymapsaddonskeyconfigstr[64]undostepsundomemorygp_manhattendistgp_euclideandistgp_erasergp_settingstb_leftmousetb_rightmouselight[3]tw_hotspottw_flagtw_handlesizetw_sizetextimeouttexcollectratewmdrawmethoddragthresholdmemcachelimitprefetchframesframeserverportpad_rot_angleobcenter_diarvisizervibrightrecent_filessmooth_viewtxglreslimitndof_panndof_rotatecurssizecolor_picker_typeipo_newkeyhandles_newscrcastfpsscrcastwaitwidget_unitanisotropic_filterversemaster[160]verseuser[160]glalphacliptext_renderpad9coba_weightsculpt_paint_overlay_col[3]author[80]vertbaseedgebaseareabase*newsceneredraws_flagfulltempwiniddo_drawdo_refreshdo_draw_gesturedo_draw_paintcursordo_draw_dragswapmainwinsubwinactive*animtimer*contexthandler[8]*newvvec*v1*v2*typepanelname[64]tabname[64]drawname[64]ofsxofsysizexsizeylabelofsruntime_flagcontrolsnapsortorder*paneltab*activedatalist_scrolllist_sizelist_last_lenlist_grip_sizelist_search[64]*v3*v4*fullbutspacetypeheadertypespacedatahandlersactionzoneswinrctdrawrctswinidregiontypealignmentdo_draw_overlayuiblockspanels*headerstr*regiondatasubvstr[4]subversionpadsminversionminsubversionwinpos*curscreen*curscenefileflagsglobalfrevisionfilename[240]name[80]orig_widthorig_heightbottomrightxofsyofslift[3]gamma[3]gain[3]dir[160]donestartstillendstill*stripdata*crop*transform*color_balance*instance_private_data**current_private_data*tmpstartofsendofsmachinestartdispenddispsatmulhandsizeanim_preseek*strip*scene_cameraeffect_faderspeed_fader*seq1*seq2*seq3seqbase*scene_soundlevelpanscenenrmulticam_sourcestrobe*effectdataanim_startofsanim_endofsblend_modeblend_opacity*oldbasep*parseq*seqbasepmetastack*act_seqact_imagedir[256]act_sounddir[256]over_ofsover_cfraover_flagover_borderedgeWidthforwardwipetypefMinifClampfBoostdDistdQualitybNoCompScalexIniScaleyIniScalexFinScaleyFinxInixFinyIniyFinrotInirotFininterpolationuniform_scale*frameMapglobalSpeedlastValidFramebuttypeuserjitstatotpartnormfacobfacrandfactexfacrandlifeforce[3]vectsizemaxlendefvec[3]mult[4]life[4]child[4]mat[4]texmapcurmultstaticstepomattimetexspeedtexflag2negvertgroup_vvgroupname[32]vgroupname_v[32]*keysminfacnrusedusedelem*poinresetdistlastval*makeyqualqual2targetName[32]toggleName[32]value[32]maxvalue[32]delaydurationmaterialName[32]damptimerpropname[32]matname[32]axisflagposechannel[32]constraint[32]*fromObjectsubject[32]body[32]otypepulsefreqtotlinks**linkstapjoyindexaxis_singleaxisfbuttonhathatfprecisionstr[128]*mynewinputstotslinks**slinksvalostate_mask*actframeProp[32]blendinpriorityend_resetstrideaxisstridelengthmin_gainmax_gainreference_distancemax_distancerolloff_factorcone_inner_anglecone_outer_anglecone_outer_gainpad3[2]pitchsound3Dpad6[1]*melinVelocity[3]angVelocity[3]localflagdyn_operationforceloc[3]forcerot[3]linearvelocity[3]angularvelocity[3]*referenceminmaxrotdampminloc[3]maxloc[3]minrot[3]maxrot[3]matprop[32]butstabutenddistributionint_arg_1int_arg_2float_arg_1float_arg_2toPropName[32]*toObjectbodyTypefilename[64]loadaniname[64]int_argfloat_arg*subtargetgo*newpackedfileattenuationdistance*cache*playback_handle*lamprengobjectdupli_ofs[3]*propchildbaserollhead[3]tail[3]bone_mat[3][3]arm_head[3]arm_tail[3]arm_mat[4][4]arm_rollxwidthzwidthease1ease2rad_headrad_tailbonebasechainbase*edbo*act_bone*act_edbone*sketchlayer_usedlayer_protectedghostepghostsizeghosttypepathsizeghostsfghostefpathsfpathefpathbcpathac*pointsstart_frameend_frameghost_sfghost_efghost_bcghost_acghost_typeghost_stepghost_flagpath_typepath_steppath_viewflagpath_bakeflagpath_sfpath_efpath_bcpath_acconstflagikflagselectflagagrp_index*bone*childiktree*custom*custom_txeul[3]chan_mat[4][4]pose_mat[4][4]pose_head[3]pose_tail[3]limitmin[3]limitmax[3]stiffness[3]ikstretchikrotweightiklinweightchanbase*chanhashproxy_layerstride_offset[3]cyclic_offset[3]agroupsactive_groupiksolver*ikdata*ikparamproxy_act_bone[32]numiternumstepminstepmaxstepsolverfeedbackmaxveldampmaxdampepschannelscustomColcscurvesgroupsactive_markeridroot*source*filter_grpsearchstr[64]filterflagadstimeslide*grpname[30]ownspacetarspaceenforceheadtaillin_errorrot_error*tarmatrix[4][4]spacerotOrdertarnumtargetsiterationsrootbonemax_rootbone*poletarpolesubtarget[32]poleangleorientweightgrabtarget[3]numpointschainlenxzScaleModereserved1reserved2minmaxflagstuckcache[3]lockflagfollowflagvolmodeplaneorglengthbulgepivXpivYpivZaxXaxYaxZminLimit[6]maxLimit[6]extraFzinvmat[4][4]fromtomap[3]expofrom_min[3]from_max[3]to_min[3]to_max[3]rotAxiszminzmaxpad[9]channel[32]no_rot_axisstride_axiscurmodactstartactendactoffsstridelenscaleblendoutstridechannel[32]offs_bone[32]hasinputhasoutputdatatypesockettype*new_socknslimitstack_type*stack_ptrstack_indexlocxlocyown_index*groupsockto_index*link*rectxsizeysize*new_nodelastyoutputs*storageminiwidthlabel[32]custom1custom2custom3custom4need_execexec*threaddatatotrbutrprvr*block*typeinfo*fromnode*tonode*fromsock*tosocknodeslinks*stack*threadstackinitstacksizecur_indexalltypes(*progress)()(*stats_draw)()(*test_break)()*tbh*prh*sdhcyclicmoviesamplesmaxspeedminspeedcurvedpercentxpercentybokehgammaimage_in_widthimage_in_heightcenter_xcenter_yspinwrapsigma_colorsigma_spacehuet1t2t3fstrengthfalphakey[4]algorithmchannelx1x2y1y2fac_x1fac_x2fac_y1fac_y2colname[32]bktyperotationgamcono_zbuffstopmaxblurbthresh*dict*nodeangle_ofscolmodmixthresholdfademcjitprojfitslope[3]power[3]lift_lgg[3]gamma_inv[3]limchanunspilllimscaleuspillruspillguspillbshortymintablemaxtableext_in[2]ext_out[2]*curve*table*premultablepresetchanged_timestampcurrcliprcm[4]black[3]white[3]bwmul[3]sample[3]x_resolutiondata_r[256]data_g[256]data_b[256]data_luma[256]sample_fullsample_linesaccuracywavefrm_modewavefrm_alphawavefrm_yfacwavefrm_heightvecscope_alphavecscope_heightminmax[3][2]hist*waveform_1*waveform_2*waveform_3*vecscopewaveform_totoffset[2]clonemtex*icon_imbuficon_filepath[240]normal_weightob_modejittersmooth_stroke_radiussmooth_stroke_factorratergb[3]sculpt_planeplane_offsetsculpt_toolvertexpaint_toolimagepaint_toolpad3[5]autosmooth_factorcrease_pinch_factorplane_trimtexture_sample_biastexture_overlay_alphaunprojected_radiusadd_col[3]sub_col[3]active_rndactive_cloneactive_mask*layerstotlayermaxlayertotsize*pool*externalrot[4]ave[3]*groundwander[3]rest_lengthparticle_index[2]delete_flagnumparentpa[4]w[4]fuv[4]foffsetrt[2]prev_state*hair*boiddietimenum_dmcachehair_indexalivespring_kplasticity_constantyield_ratioplasticity_balanceyield_balanceviscosity_omegaviscosity_betastiffness_kstiffness_knearrest_densitybuoyancyspring_frames*boids*fluiddistrphystypeavemodereacteventdrawdraw_asdraw_sizechildtyperen_assubframesdraw_colren_stephair_stepkeys_stepadapt_angleadapt_pixrotfromintegratorbb_alignbb_uv_splitbb_animbb_split_offsetbb_tiltbb_rand_tiltbb_offset[2]color_vec_maxsimplify_refsizesimplify_ratesimplify_transitionsimplify_viewporttimetweakjitfaceff_hairgrid_randgrid_reseffector_amountpartfactanfactanphasereactfacob_vel[3]avefacphasefacrandrotfacrandphasefacrandsizeacc[3]dragfacbrownfacrandlengthchild_nbrren_child_nbrparentschildsizechildrandsizechildradchildflatclumppowkink_flatkink_amp_clumprough1rough1_sizerough2rough2_sizerough2_thresrough_endrough_end_shapeclengthclength_thresparting_facparting_minparting_maxbranch_thresdraw_line[2]path_startpath_endtrail_countkeyed_loopsdupliweights*eff_group*dup_ob*bb_ob*pd2*part*particles**pathcache**childcachepathcachebufschildcachebufs*clmd*hair_in_dm*hair_out_dm*target_ob*latticetree_framebvhtree_framechild_seedtotunexisttotchildtotcachedtotchildcachetarget_psystotkeyedbakespacebb_uvname[3][32]vgroup[12]vg_negrt3*renderdata*effectors*fluid_springstot_fluidspringsalloc_fluidsprings*tree*pdd*frandCdisCvistructuralbendingmax_bendmax_structmax_shearavg_spring_lentimescaleeff_force_scaleeff_wind_scalesim_time_oldvelocity_smoothcollider_frictionstepsPerFrameprerollmaxspringlensolver_typevgroup_bendvgroup_massvgroup_structshapekey_restpresetsreset*collision_listepsilonself_frictionselfepsilonrepel_forcedistance_repelself_loop_countloop_countpressurethicknessstrokesframenum*actframegstepinfo[128]sbuffer_sizesbuffer_sflag*sbufferlistprintlevelstorelevel*reporttimer*windrawable*winactivewindowsinitializedfile_savedop_undo_depthoperatorsqueuereportsjobspaintcursorsdragskeyconfigs*defaultconftimers*autosavetimer*ghostwingrabcursor*screen*newscreenscreenname[32]posxposywindowstatemonitorlastcursormodalcursoraddmousemove*eventstate*curswin*tweakdrawmethoddrawfail*drawdatamodalhandlerssubwindowsgestureidname[64]propvalueshiftctrlaltoskeykeymodifiermaptype*ptritemsspaceidregionidkmi_id(*poll)()*modal_itemsbasename[64]actkeymap*customdata*py_instance*reportsmacro*opm*edatainfluence*coefficientsarraysizepoly_orderamplitudephase_multiplierphase_offsetvalue_offsetmidvalbefore_modeafter_modebefore_cyclesafter_cyclesrectphasemodificationstep_size*rna_pathpchan_name[32]transChanidtypetargets[8]num_targetsvariablesexpression[256]*expr_compvec[2]*fptarray_indexcolor_modecolor[3]from[128]to[128]mappingsstrips*remapfcurvesstrip_timeblendmodeextendmodegroup[64]groupmodekeyingflagpathstypeinfo[64]active_path*tmpactnla_tracks*actstripdriversoverridesact_blendmodeact_extendmodeact_influenceruleoptionsfear_factorsignal_idlook_aheadoloc[3]queue_sizewanderflee_distancehealthstate_idrulesconditionsactionsruleset_typerule_fuzzinesslast_state_idlanding_smoothnessbankingaggressionair_min_speedair_max_speedair_max_accair_max_aveair_personal_spaceland_jump_speedland_max_speedland_max_accland_max_aveland_personal_spaceland_stick_forcestates*smd*fluid_group*coll_group*wt*tex_wt*tex_shadow*shadowp0[3]p1[3]dxomegatempAmbbetares[3]amplifymaxresviewsettingsnoisediss_percentdiss_speedres_wt[3]dx_wtv3dnumcache_compcache_high_comp*point_cache[2]ptcaches[2]border_collisionstime_scalevorticityvelocity[2]vel_multivgrp_heat_scale[2]vgroup_flowvgroup_densityvgroup_heat*points_old*velmat_old[4][4]TYPEcharucharshortushortintlongulongfloatdoublevoidLinkLinkDataListBasevec2svec2frctirctfIDPropertyDataIDPropertyIDLibraryFileDataPreviewImageIpoDriverObjectIpoCurveBPointBezTripleIpoKeyBlockKeyAnimDataTextLineTextMarkerTextPackedFileCameraImageUserSceneImageGPUTextureanimRenderResultMTexTexPluginTexCBDataColorBandEnvMapImBufPointDensityCurveMappingVoxelDatabNodeTreeTexMappingLampVolumeSettingsMaterialGroupVFontVFontDataMetaElemBoundBoxMetaBallNurbCharInfoTextBoxEditNurbGHashCurvePathSelBoxEditFontMeshMFaceMTFaceTFaceMVertMEdgeMDeformVertMColMStickyMSelectEditMeshCustomDataMultiresPartialVisibilityMDeformWeightMTexPolyMLoopUVMLoopColMFloatPropertyMIntPropertyMStringPropertyOrigSpaceFaceMDispsMultiresColMultiresColFaceMultiresFaceMultiresEdgeMultiresLevelModifierDataMappingInfoModifierDataSubsurfModifierDataLatticeModifierDataCurveModifierDataBuildModifierDataMaskModifierDataArrayModifierDataMirrorModifierDataEdgeSplitModifierDataBevelModifierDataBMeshModifierDataSmokeModifierDataSmokeDomainSettingsSmokeFlowSettingsSmokeCollSettingsDisplaceModifierDataUVProjectModifierDataDecimateModifierDataSmoothModifierDataCastModifierDataWaveModifierDataArmatureModifierDataHookModifierDataSoftbodyModifierDataClothModifierDataClothClothSimSettingsClothCollSettingsPointCacheCollisionModifierDataBVHTreeSurfaceModifierDataDerivedMeshBVHTreeFromMeshBooleanModifierDataMDefInfluenceMDefCellMeshDeformModifierDataParticleSystemModifierDataParticleSystemParticleInstanceModifierDataExplodeModifierDataMultiresModifierDataFluidsimModifierDataFluidsimSettingsShrinkwrapModifierDataSimpleDeformModifierDataShapeKeyModifierDataSolidifyModifierDataScrewModifierDataWarpModifierDataEditLattLatticebDeformGroupSculptSessionbActionbPosebGPdatabAnimVizSettingsbMotionPathBulletSoftBodyPartDeflectSoftBodyObHookDupliObjectRNGEffectorWeightsPTCacheExtraPTCacheMemPTCacheEditSBVertexBodyPointBodySpringSBScratchFluidVertexVelocityWorldBaseAviCodecDataQuicktimeCodecDataQuicktimeCodecSettingsFFMpegCodecDataAudioDataSceneRenderLayerRenderDataRenderProfileGameDomeGameFramingGameDataTimeMarkerPaintBrushImagePaintSettingsParticleBrushDataParticleEditSettingsTransformOrientationSculptVPaintToolSettingsbStatsUnitSettingsPhysicsSettingsEditingSceneStatsDagForestBGpicRegionView3DRenderInfoViewDepthsSmoothViewStorewmTimerView3DSpaceLinkView2DSpaceInfoSpaceIpobDopeSheetSpaceButsSpaceSeqFileSelectParamsSpaceFileFileListwmOperatorFileLayoutSpaceOopsTreeStoreTreeStoreElemSpaceImageScopesHistogramSpaceNlaSpaceTextScriptSpaceScriptSpaceTimeCacheSpaceTimeSpaceNodeSpaceLogicSpaceImaSelConsoleLineSpaceConsoleSpaceUserPrefSpaceSoundScrAreabSounduiFontuiFontStyleuiStyleuiWidgetColorsuiWidgetStateColorsThemeUIThemeSpaceThemeWireColorbThemebAddonSolidLightUserDefbScreenScrVertScrEdgePanelPanelTypeuiLayoutSpaceTypeARegionARegionTypeFileGlobalStripElemStripCropStripTransformStripColorBalanceStripProxyStripPluginSeqSequenceMetaStackWipeVarsGlowVarsTransformVarsSolidColorVarsSpeedControlVarsEffectBuildEffPartEffParticleWaveEffbPropertybNearSensorbMouseSensorbTouchSensorbKeyboardSensorbPropertySensorbActuatorSensorbDelaySensorbCollisionSensorbRadarSensorbRandomSensorbRaySensorbArmatureSensorbMessageSensorbSensorbControllerbJoystickSensorbExpressionContbPythonContbActuatorbAddObjectActuatorbActionActuatorSound3DbSoundActuatorbEditObjectActuatorbSceneActuatorbPropertyActuatorbObjectActuatorbIpoActuatorbCameraActuatorbConstraintActuatorbGroupActuatorbRandomActuatorbMessageActuatorbGameActuatorbVisibilityActuatorbTwoDFilterActuatorbParentActuatorbStateActuatorbArmatureActuatorGroupObjectBonebArmaturebMotionPathVertbPoseChannelbIKParambItascbActionGroupSpaceActionbActionChannelbConstraintChannelbConstraintbConstraintTargetbPythonConstraintbKinematicConstraintbSplineIKConstraintbTrackToConstraintbRotateLikeConstraintbLocateLikeConstraintbSizeLikeConstraintbSameVolumeConstraintbTransLikeConstraintbMinMaxConstraintbActionConstraintbLockTrackConstraintbDampTrackConstraintbFollowPathConstraintbStretchToConstraintbRigidBodyJointConstraintbClampToConstraintbChildOfConstraintbTransformConstraintbPivotConstraintbLocLimitConstraintbRotLimitConstraintbSizeLimitConstraintbDistLimitConstraintbShrinkwrapConstraintbActionModifierbActionStripbNodeStackbNodeSocketbNodeLinkbNodePreviewbNodeuiBlockbNodeTypeNodeImageAnimNodeBlurDataNodeDBlurDataNodeBilateralBlurDataNodeHueSatNodeImageFileNodeChromaNodeTwoXYsNodeTwoFloatsNodeGeometryNodeVertexColNodeDefocusNodeScriptDictNodeGlareNodeTonemapNodeLensDistNodeColorBalanceNodeColorspillTexNodeOutputCurveMapPointCurveMapBrushCloneCustomDataLayerCustomDataExternalHairKeyParticleKeyBoidParticleBoidDataParticleSpringChildParticleParticleTargetParticleDupliWeightParticleDataSPHFluidSettingsParticleSettingsBoidSettingsParticleCacheKeyKDTreeParticleDrawDataLinkNodebGPDspointbGPDstrokebGPDframebGPDlayerReportListwmWindowManagerwmWindowwmKeyConfigwmEventwmSubWindowwmGesturewmKeyMapItemPointerRNAwmKeyMapwmOperatorTypeFModifierFMod_GeneratorFMod_FunctionGeneratorFCM_EnvelopeDataFMod_EnvelopeFMod_CyclesFMod_PythonFMod_LimitsFMod_NoiseFMod_SteppedDriverTargetDriverVarChannelDriverFPointFCurveAnimMapPairAnimMapperNlaStripNlaTrackKS_PathKeyingSetAnimOverrideIdAdtTemplateBoidRuleBoidRuleGoalAvoidBoidRuleAvoidCollisionBoidRuleFollowLeaderBoidRuleAverageSpeedBoidRuleFightBoidStateFLUID_3DWTURBULENCETLEN `HH( p$8p`(0(pxh@(X hXhP 0@ (0 @ @Phx``XXp8XxP0x`0phX`Pp0h0xxH  (@@X@h`0X`8 PX`88@h`h(!x@0H(h pxXP8 (X( X,  4 H@@00Hh(H,(lHH`h<PP` HXPpT `88pX(((x@X8XPx8000(HH008hp`88H(8( ,@  ` 8H88@( <h ((xxh8(h(hp P8P@hH@STRC                  !"#$%&'()*+,-./01+,23456  789:; <=+>?#@:,ABC DEFG HIJK: LMNOP  QRS! !!TUVW XYZ"[X\ ] ^ _`a bcde fg#hi $HjklmnopqrsMt%&uvwxyz{|#}~C'  ()**|#+A,6-   #.@=/"=.0'1lm|2  / 3 4   |,?HC !"#$%&'()*+,-./0123456789zwxy:;W%<5=M'->/ 0?2@4AB6CDEFG*7HHHIJKLMNOPQRST3UClmVWXYZ[\]^_`abcdefghijWklmnopqrstuvwxyz{|M+}~89}H8HkB~//+}5=M:C# ;<#===>     ?H>   M9#CD= 4 !"#$ ##@@@%#&'()*+,-././012A3%#CB45C 6D78ZEDH> 9 C:;<=MF>?9 @CDWABCDE#FGHI()JKL M]@NOPQRSTUVWXYGZH[\;];^;_;`abcdBefgAhAiI'H>M?9JjKkLlMmNnOoPpQqIrRsStTuTvTw3xyz{CDA|}~UVL HJ%NWOWMPX'HYZ#QRK'H[\]^_Z`a`b%cd ddbac3yx#MU MTuTwVJNyx3#e eeH#&ufe,geX  heiejeUkeEHl eXmeneXo e#Xpe#qerstu e,v e'X#wexeyehze,#GW{eC| e}e~e&u  eMMMMM M J   eMM e#xeH#3 !"#$% &e'()*6e*6+,e-./e0123Xe4 e56789:;< e=7>?H@#e exABCDEF# eGHIJKLe,MN3UOP8ZH&'QRSTCUVW#XYZ[\]^M?OoE_`a>b#Hcdefgh$ijklMF>>mno pqr s t  u vHw9xyCz{|D}~bj        @:8|   $E *E(,:     6   $   !"#$%&'6()*#+,-./0123456789:;<=y>?@ABCODEFGHIJKLMNOPQRS TUVWXY2Z[\]^_`abcdefghijklmInIopqrMstuvwxyz{|}~3#LHIkCHM+}~  #  CWX# 9:#iy>     ^hH !"#$%&'()* +,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYC"Z[ \]^W_CHL`aC"bcWCHde  fghijWkl mnXo#pqrW shtuvwx sy6z{|}&u~oX#o#"O sRczW3y6&,Hk& B5= b      ep '%<VWhC&     O>p !"#$%&2 '()*OW+k, -./0123n456789:;<=> ? @ ABCDE Fp"=GHIJKLMNOPQRSTUVW3XYZ '()* '()*[ '()*\] ^H_`3 '()*\abcdSef# >ghi '()*\VWajklm#pnopqrstuvwxyz '({|} ~ C '()*\  '('%<3pVWm3  '()*_#]\ '()*"X       X  '()XW   '()\ # '()*\N VWm&5=5 p  '()*#p* '()*\}opw t#W     1Q '()*#   '(# '()\HVWC# S      # !"#$%&'a() *+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@B###$Y     /    '&u&W#    )#   #    !1("TU##  $ ' % &   \'(TU)*+R,   - . %/ 0 1234567&89:;#< =>? @ABCDEF#Gp)h#6HIJ KGj LMN    O P 0 Q URSIJTUVW#XYyZ[M&u\)]^>_`a b cdefgh ijklm no p b qrstuvw#xyLz{|}~ c#X66y-8VO;#:GB  O#!WC"9O##$#%#&#'HC(L)*HW+,---WC .*td#/ 01"H....C 2- 3#*4 V56 WC5#7 *I8W#&uk9#*: z}; VWC#<*WC= H# > V=  ?     @   WCAV BCZ  "D*EIF5 2 222  * # # M  X#   GGG*  :  ~ HHH H$        ! " O# $ % & ' ( ~IH ) * + H, - . 0g/ ~0 1 2 3 4 5 6 7 8 9 : JJ; < = > ? @ A B C D E F G H I J K L K)KK M N O P E7 8 HQ K$KR S rT KU CV #W X Y Z [ \ ] ^ _ ` > a Db #c Wbd e f g h i j qk Lh M h l m n o p q r s t NNN u v w  x a y bz { #| a :} ~  O  '()*\m H_ PPPN M sQQQM RRR    #M  S SS    T"   U        HOV ;    W   X#X  Y  Z  [\ ]   x WC ^  @UV#_  ` #a xA b     c R          #WCd e # f        g  h    i    j    k OXH#l5O9; m mm u  *nnnH  MUV      vo$     pppp o   o  W   p  Cq r   #s"sss Hd       G          rt u qqqs s p p #5Hp o    #  >  vwy #w   A   ^    x    L mJ #y  J#z W {y>|    R     }       ! ~"  # $ e%  & ' ( )   * +  JL, h- . / 0 x 1 2 3 4 5 #6 7 DEF8 9 : ; < = > ? @  A B C D E F G 3 =H I J K L M N O P u Q R S T U  H|V W X Y Z [ \ ] ^ _ ` a b c d e #'f #"g 3E +h 1i j k l hm On o p q r s t u v w x y z { | } ~   x   Z <T    #  #Y    6         6*H*    O     h               yH  T6  k          |               J    V               h                                 +}: :   M@ 2  R      ~     $                S         % 5 ! " Q# $ % & ' ( 6) * + 734, - . X/ 0 1 2 3 4 5 6 7 T 8 9 : ; < = X> ? :@ ; A  B C   wD A E YF  +G H I  J K L #M N O P Q R S T U V W X Y Z [ \ ]   ^ _ #` a b c d e f g h i Cj k l m n o U % p q r s t  u v w x y z #{   | s } ~   s  s   {        H     !3     "  #h #  x< =      : :  #N ; v/ 3:    5   v  UV      WC     #          m      H *   u     *C      d6      H    u       X            r(q  : : :  (( (           X#         T   Cs q '      Xt q ;   E   #CENDBrviz-1.12.4/image_src/R.stl000066400000000000000000000447041300447110700154550ustar00rootroot00000000000000Exported from blenderxiIʹ*?^U#0.?^Z/ӣU#0.?^U#0.?iIʹ*?iIʹ*?>鴔 .?ӣU#0.?iIʹ*? },?>鴔 .?iIʹ*?@XiIʹ*?ʹr?0=˴?[iIʹ*?x:EW1̴j1?0=˴?ʹr?@ʴD1?0=˴?x:EW1̴j1?@ʴD1?|~>eô?0=˴?iȴ,?|~>eô?@ʴD1?,lƴT?|~>eô?iȴ,?j8eô?,lƴT?j8w. ?|~>eô?Xw. ?j8w. ?Xw. ?<ټ$ ?hb=$ ?ȥ>(W?H >w. ?!=)RH?ȥ>(W?hb=$ ?x+=09ܙ?ȥ>(W?!=)RH?x+=09ܙ?Lv>&;>ȥ>(W?'0=詴G>Lv>&;>x+=09ܙ?@m.= 1>Lv>&;>'0=詴G>@m.= 1>>塴RV>Lv>&;>&=I>>塴RV>@m.= 1>&=I>>>>塴RV>={>>>&=I>?=Rt>>>={>?=Rt> >熕>>>04<=a}> >熕>?=Rt>04<=a}>>яJc> >熕>>яJc>04<=a}>0=qh`>>яJc>g;x->0=qh`>`mQ>0=qh`>g;x->`mQ>@=j>0=qh`> Ѽ9>@=j>`mQ>o6?ɡ>@=j> Ѽ9>o6?ɡ>=߾#>@=j>d6)>=߾#>o6?ɡ>[ȃr>=߾#>d6)>^Z/Kd>ȃr>Kd>[ȃr>ȃr>Kd>=߾#>[ȃr>Kd>m=xہ>=߾#>Kd>= q5>m=xہ>Kd>T=ih>= q5>Kd>B=Mc©>T=ih>Kd>B=Mc©>Kd>@o8=ZV ?>Kd>hr= OSK>@o8=ZV ?>Kd>pi罃Kd>hr= OSK>pi罃Kd> νJ0>hr= OSK> νJ0>(=eFvߓ>hr= OSK>^Z/Z/Kd>2IGt>(=eFvߓ> νJ0><61G->(=eFvߓ>2IGt>3D=>(=eFvߓ><61G->3D=>0=&=s>(=eFvߓ>P/@O >0=&=s>3D=>X49=V>0=&=s>P/@O >X49=V>3=F3J>0=&=s>̽O,1 >3=F3J>X49=V>̽O,1 >=({>3=F3J>@{&",x>=({>̽O,1 >@{&",x>=n j>=({>`<FR{d>=n j>@{&",x>`<FR{d>v>sY>=n j>Pv>sY>`<FR{d>P>/{NF>v>sY>o>=nL0>>/{NF>Po>=nL0> >}3>>/{NF>o>=nL0>V->Dճ`6> >}3>F=+꿳 >V->Dճ`6>o>=nL0>F=+꿳 >_:> >V->Dճ`6>P!>Z/_:> >F=+꿳 >P!>Z/(A>p=_:> >P!>Z/eH>_/=(A>p=P!>Z/O>af=eH>_/=P!>Z/(U>*=O>af=P!>Z/4\>eX=(U>*=P!>Z/c>d*Knm=4\>eX=P!>Z/Uj>Zi/½=c>d*Knm=P!>Z/ r>SY=Uj>Zi/½=P!>Z/ z><_*= r>SY=P!>Z/> Wf< z><_*=P!>Z/8>[%pw<> Wf<P!>Z/͌>Z/8>[%pw<ȃr>[ȃr>[1=r>[1=r>1=r>ȃr>[ȃr>d6)>d1=>d1=>[1=r>[ȃr>d6)>o6?ɡ>o61=ˡ>o61=ˡ>d1=>d6)>o6?ɡ> Ѽ9> Ѽ0=9> Ѽ0=9>o61=ˡ>o6?ɡ> Ѽ9>`mQ>`m0=>`m0=> Ѽ0=9> Ѽ9>`mQ>g;x->g;/=>g;/=>`m0=>`mQ>g;x-><.=><.=>g;/=>g;x->04<=a}>04<-=c}>04<-=c}><.=>04<=a}>?=Rt>?=,=v>?=,=v>04<-=c}>04<=a}>?=Rt>={>=+=>=+=>?=,=v>?=Rt>={>&=I>&=*=>&=*=>=+=>={>&=I>@m.= 1>@m.=)=3>@m.=)=3>&=*=>&=I>@m.= 1>'0=詴G>'0=(=G>'0=(=G>@m.=)=3>@m.= 1>'0=詴G>x+=09ܙ?x+=&=ݙ?x+=&=ݙ?'0=(=G>'0=詴G>x+=09ܙ?!=)RH?!=%=SH?!=%=SH?x+=&=ݙ?x+=09ܙ?!=)RH?hb=$ ?hb=$=% ?hb=$=% ?!=%=SH?!=)RH?hb=$ ?<ټ$ ?<#=% ?<#=% ?hb=$=% ?hb=$ ?<ټ$ ?X1=r>1=r>=+?iIʹ*?[iIʹ*?iIʹ*?=+?=+?[=+?[iIʹ*?ӣU#0.?>鴔 .?>= .?>= .?ӣ=1.?ӣU#0.?>鴔 .? },? }=,? }=,?>= .?>鴔 .? },?@Xeô?|~>!=?|~>!=?0==?0=˴?|~>eô?H >w. ?H >#=/ ?H >#=/ ?|~>!=?|~>eô?H >w. ?ȥ>(W?ȥ>%=?ȥ>%=?H >#=/ ?H >w. ?ȥ>(W?Lv>&;>Lv>(=;>Lv>(=;>ȥ>%=?ȥ>(W?Lv>&;>>塴RV>>*=TV>>*=TV>Lv>(=;>Lv>&;>>塴RV>>>>+=>>+=>>*=TV>>塴RV>>> >熕> >-=> >-=>>+=>>> >熕>>яJc>>.=Lc>>.=Lc> >-=> >熕>>яJc>0=qh`>0=/=j`>0=/=j`>>.=Lc>>яJc>0=qh`>@=j>@=1=>@=1=>0=/=j`>0=qh`>@=j>=߾#>=2=%>=2=%>@=1=>@=j>=߾#>m=xہ>m=3=݁>m=3=݁>=2=%>=߾#>m=xہ>= q5>=4=7>=4=7>m=3=݁>m=xہ>= q5>T=ih>T=5=h>T=5=h>=4=7>= q5>T=ih>B=Mc©>B=6=©>B=6=©>T=5=h>T=ih>B=Mc©><6=><6=>B=6=©>B=Mc©>@o8=ZV ?>@o8=7= ?>@o8=7= ?><6=>@o8=ZV ?>hr= OSK>hr=8=UK>hr=8=UK>@o8=7= ?>@o8=ZV ?>hr= OSK>(=eFvߓ>(=9=xߓ>(=9=xߓ>hr=8=UK>hr= OSK>(=eFvߓ>0=&=s>0=:=u>0=:=u>(=9=xߓ>(=eFvߓ>0=&=s>3=F3J>3=<=L>3=<=L>0=:=u>0=&=s>3=F3J>=({>==={>==={>3=<=L>3=F3J>=({>=n j>=>=j>=>=j>==={>=({>=n j>v>sY>v>@=sY>v>@=sY>=>=j>=n j>v>sY>>/{NF>>A=SF>>A=SF>v>@=sY>v>sY>>/{NF> >}3> >C=3> >C=3>>A=SF>>/{NF> >}3>V->Dճ`6>V->E=e6>V->E=e6> >C=3> >}3>V->Dճ`6>_:> >_:>F= >_:>F= >V->E=e6>V->Dճ`6>_:> >(A>p=(A>G==(A>G==_:>F= >_:> >(A>p=eH>_/=eH>H=/=eH>H=/=(A>G==(A>p=eH>_/=O>af=O>I=p=O>I=p=eH>H=/=eH>_/=O>af=(U>*=(U>J=$=(U>J=$=O>I=p=O>af=(U>*=4\>eX=4\>K=X=4\>K=X=(U>J=$=(U>*=4\>eX=c>d*Knm=c>L=xm=c>L=xm=4\>K=X=4\>eX=c>d*Knm=Uj>Zi/½=Uj>M=̽=Uj>M=̽=c>L=xm=c>d*Knm=Uj>Zi/½= r>SY= r>M=Y= r>M=Y=Uj>M=̽=Uj>Zi/½= r>SY= z><_*= z>N=`*= z>N=`*= r>M=Y= r>SY= z><_*=> Wf<>P=<>P=< z>N=`*= z><_*=> Wf<8>[%pw<8>Q=Ppw<8>Q=Ppw<>P=<> Wf<8>[%pw<͌>Z/͌>R=*ꢹ͌>R=*ꢹ8>Q=Ppw<8>[%pw<͌>Z/P!>Z/P!>R=*ꢹP!>R=*ꢹ͌>R=*ꢹ͌>Z/P!>Z/F=+꿳 >F=F= >F=F= >P!>R=*ꢹP!>Z/F=+꿳 >o>=nL0>o>=C=L0>o>=C=L0>F=F= >F=+꿳 >o>=nL0>PPPo>=C=L0>o>=nL0>P`<FR{d>``PP`<FR{d>@{&",x>@==',x>@==',x>``<FR{d>@{&",x>̽O,1 >̽<= >̽<= >@==',x>@{&",x>̽O,1 >X49=V>X;=?V>X;=?V>̽<= >̽O,1 >X49=V>P/@O >P:=Q >P:=Q >X;=?V>X49=V>P/@O >3D=>9=?>9=?>P:=Q >P/@O >3D=><61G-><69=/><69=/>9=?>3D=><61G->2IGt>29=It>29=It><69=/><61G->2IGt> νJ0> ν9=0> ν9=0>29=It>2IGt> νJ0>pi罃Kd>pi9=d>pi9=d> ν9=0> νJ0>pi罃Kd>Kd>9=d>9=d>pi9=d>pi罃Kd>Kd>Z/R=*ꢹR=*ꢹ9=d>Kd>Z/^Z/^R=*ꢹ^R=*ꢹR=*ꢹZ/^U#0.?ӣU#0.?ӣ=1.?ӣ=1.?^=1.?^U#0.?^Z/^U#0.?^=1.?^=1.?^R=*ꢹ^Z/^=1.?=+?^R=*ꢹ^=1.?ӣ=1.?=+?ӣ=1.?>= .?=+?>= .? }=,?=+? }=,?@X<=+?=+?@X<=+?o!==q(?=+?o!==q(?==3L%?=+?==3L%?@==yd!?=+?@==yd!?P:==?=+?P:==?[=+?=+?P:==?0==?[=+?=+?1=r>^R=*ꢹ[=+?0==?=s?=s?0==?x:E=k1?x:E=k1?0==?@=E1?0==?|~>!=?@=E1?@=E1?|~>!=?i =-?i =-?|~>!=?, =U?, =U?|~>!=?j8!=?H >#=/ ?j8#=/ ?X<"=!?X<"=!?H >#=/ ?<#=% ?<#=% ?H >#=/ ?hb=$=% ?H >#=/ ?ȥ>%=?hb=$=% ?hb=$=% ?ȥ>%=?!=%=SH?!=%=SH?ȥ>%=?x+=&=ݙ?ȥ>%=?Lv>(=;>x+=&=ݙ?x+=&=ݙ?Lv>(=;>'0=(=G>'0=(=G>Lv>(=;>@m.=)=3>Lv>(=;>>*=TV>@m.=)=3>@m.=)=3>>*=TV>&=*=>>*=TV>>+=>&=*=>&=*=>>+=>=+=>=+=>>+=>?=,=v>>+=> >-=>?=,=v>?=,=v> >-=>04<-=c}> >-=>>.=Lc>04<-=c}>04<-=c}>>.=Lc><.=>>.=Lc>0=/=j`><.=><.=>0=/=j`>g;/=>g;/=>0=/=j`>`m0=>0=/=j`>@=1=>`m0=>`m0=>@=1=> Ѽ0=9> Ѽ0=9>@=1=>o61=ˡ>@=1=>=2=%>o61=ˡ>o61=ˡ>=2=%>d1=>d1=>=2=%>[1=r>1=r>9=d>^R=*ꢹ1=r>[1=r>9=d>[1=r>=2=%>9=d>=2=%>m=3=݁>9=d>m=3=݁>=4=7>9=d>=4=7>T=5=h>9=d>T=5=h>B=6=©>9=d>B=6=©><6=>9=d><6=>@o8=7= ?>9=d>@o8=7= ?>hr=8=UK>9=d>hr=8=UK>pi9=d>9=d>hr=8=UK> ν9=0>pi9=d>hr=8=UK>(=9=xߓ> ν9=0>9=d>R=*ꢹ^R=*ꢹ ν9=0>(=9=xߓ>29=It>29=It>(=9=xߓ><69=/><69=/>(=9=xߓ>9=?>(=9=xߓ>0=:=u>9=?>9=?>0=:=u>P:=Q >P:=Q >0=:=u>X;=?V>0=:=u>3=<=L>X;=?V>X;=?V>3=<=L>̽<= >3=<=L>==={>̽<= >̽<= >==={>@==',x>==={>=>=j>@==',x>@==',x>=>=j>`=>=j>v>@=sY>``v>@=sY>Pv>@=sY>>A=SF>PP>A=SF>o>=C=L0>>A=SF> >C=3>o>=C=L0> >C=3>V->E=e6>o>=C=L0>o>=C=L0>V->E=e6>F=F= >V->E=e6>_:>F= >F=F= >F=F= >_:>F= >P!>R=*ꢹ_:>F= >(A>G==P!>R=*ꢹ(A>G==eH>H=/=P!>R=*ꢹeH>H=/=O>I=p=P!>R=*ꢹO>I=p=(U>J=$=P!>R=*ꢹ(U>J=$=4\>K=X=P!>R=*ꢹ4\>K=X=c>L=xm=P!>R=*ꢹc>L=xm=Uj>M=̽=P!>R=*ꢹUj>M=̽= r>M=Y=P!>R=*ꢹ r>M=Y= z>N=`*=P!>R=*ꢹ z>N=`*=>P=R=*ꢹ>P=<8>Q=PpwR=*ꢹ8>Q=Ppw<͌>R=*ꢹP!>R=*ꢹrviz-1.12.4/image_src/RViz.blend000066400000000000000000014306341300447110700164320ustar00rootroot00000000000000BLENDER-v258REND @[SceneTEST. ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@OOS~CDH@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWW~qqtlmuRRY@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@OOS~cccopwklsOOQA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWW_`gST\ooo^`j@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@HIN?HIN@@@@WWW_`gGHPWWWlmsSU_@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@LLP@@@@ooobex@@@WWW_`gGHPWWWoooqs}IJO@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@cccpp}LLL@oooegvHIN@WWW_`gooottyyz]]bOOQ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@WWW~GHOKKK?jjp__iWWX__eijsQS\WWWabl`aj]]b@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@oooNP_ccchhuIIMAcccNNZooobex@@@]]b@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@oooVWcwx~llv@@@^^dKKTWWWijs_`fnozKMU@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@oooooossvdftWWWWW`GGMLLL@llqQS\[\a@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ggkmnxoooSUfcccNNZDDGA@@@]]bWX_@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@^_gKLXjjmHIV^^dNNZ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@fgkfgkzzhho]]bOOQA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@qqtwxnnw@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@NOQ@OOQA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `GLOB `[ 08m;o /work/gossow/rviz/rviz/icons_src/RViz.blendWMZjWMWinManxZxZxZxZ+R+R+R868686DATAxZk;8mscreenxV+;hOhOX66WR6,RXRSNZh8[SRAnimation.001s+HZZZhZ.[;oDATA s++DATA +8Ns+DATA 8N-B+~DATA -BO8N~DATA OxO-BDATA xOh+O~DATA h+)RxO4DATA )RhcRh+4DATA hcRZ)R4DATA Z8ZhcR~DATA 8ZZZ|DATA ZZ8Z4|DATA ZZZ|DATA ZZZDATA ZhZZlDATA hZZZlDATA ZHZhZ4 DATA HZZ~ DATA(Z(Z+8NDATA((ZZZ+ODATA(ZZ(Z8NxODATA(ZxZZOxODATA(xZZZs+h+DATA(ZXZxZh+-BDATA(XZZZxO)RDATA(Z8ZXZh+hcRDATA(8ZZZ-BZDATA(ZZ8ZhcRZDATA(ZZZs+8ZDATA(ZZZ)RZDATA(ZhZZh+ZDATA(hZZZ8ZZDATA(ZHZhZ8ZZDATA(HZZZZZDATA(Z(ZHZOZDATA((ZZZ)RZDATA(ZZ(ZZZDATA(ZxZZ8ZZDATA(xZZZZhZDATA(ZXZxZZhZDATA(XZZZhcRZDATA(Z8ZXZ)RZDATA(8ZZZxOHZDATA(ZZ8ZZHZDATA(ZZZZHZDATA(ZZZOZDATA(ZZZhZDATAhZ8ZO+8NxO~7[7[XZZDATA(XZZ DADA~DADA?? ~DATA(ZXZmEmEpoo?? pDATA8Z[hZh+hcRZ-B5~J[[(ZZDATA((ZZCACAICACA?? JJ5~JDATA(Z(ZC=C9J>8?@ J95~JZ[DATAXZZBUTTONS_PT_contextBUTTONS_PT_contextContext9$DATAXZHZZRENDER_PT_renderRENDER_PT_renderRender9=DATAXHZZZRENDER_PT_layersRENDER_PT_layersLayerso9DATAXZZHZRENDER_PT_dimensionsRENDER_PT_dimensionsDimensions9DATAXZ(ZZRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:9:DATAX(ZZZRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"9DATAXZhZ(ZRENDER_PT_shadingRENDER_PT_shadingShading 9DATAXhZZZRENDER_PT_performanceRENDER_PT_performancePerformance9DATAXZ[hZRENDER_PT_post_processingRENDER_PT_post_processingPost Processing9DATAX[H[ZRENDER_PT_stampRENDER_PT_stampStamp9 DATAXH[[[RENDER_PT_outputRENDER_PT_outputOutput(9 DATAX[H[RENDER_PT_bakeRENDER_PT_bakeBake9 DATA[DATA[ [8Zs+8ZZh+3{4| [ [[( [DATA([( [ DADA3`DA`DA?? 4434DATA(( [[@~CHBpF}CHB33a?HB|HHB= AH4b3{4bDATA [DATA [[[hcRZHZZ5~Jg[[ [[DATA( [[CACAICACA?? JJ5~JDATA([ [CC9JL88L?? JM9;5~JMDATA[SDATAS[DATA[;o;o;o;oKoToGoNoFo;oDATA[h[ [ZZ)RZ3}m[[[[DATA([x[@qDAcDAcDAcDA?? 3}DATA(x[[[C@FCF++?@ ,SDATA([X[x[CfCww?@ xf3"DATA(X[[[#C`#C`?@ 33DATA([X[3S8[DATA`8[?ޕ? JLD>3;Q?Fwi?JF>#,TY!e?*=>o?E>Fwi?TY5;JF>!e?Q?#,+=>`DAoy@?>{0QQuZ?,h>?>#,>m$?T*= lAoA>tU?pFളZ)>C?4kuPA)ˆy>rB_B@D>3;Q?Fwi?JF>#,TY!e?*=>o?>{0QQuZ?,h>?>#,>m$?T*= lAoA]j@]j@]j@?\>7?8˔oAoAt;?! BVBt~BDATA8[333?? ANo B?=C DATAh[([[8ZZhZZ}k&[&[X [$[DATA(X [![@wDA)DA(DA(DA?? }DATA(![8#[X [HCpHCC?? kDATA(8#[$[![kDATA($[8#[C@zC Ao:o:|HPCGikDATA&[X'[DATAhX'[;oDATA([.[h[ZOZhZm }H-[H-[([+[DATA(([h*[|DA)DA(DA(DA?? mDATA(h*[+[([7CHC@b??cQcDATA(+[h*[ hD hD@bb|H@F #<HBJccDATA@H-[ ;oDATA.[([Z)RxOHZ5~!JX6[X6[/[81[DATA(/[81[fDAC@AICACA?? JJ5~!!DATA(81[/[5~!J2[DATA`2[9 @!i@AHMݕ/?U~'?3F:?>T8165e?2>Z& 4?ߕ/?7F:?81W~>85e?'?T2>ne@>M@?0?''???T?ļP@l2@11A 4AF>> Ο"o={>3xB ֟&BĭeA(@ݕ/?U~'?3F:?>T8165e?2>Z& 4?0?''???T?ļP@l2@11A 4A~@~@~@?H?N,Z# A3;??ABdZBvBDATA8X6[333?? ANo B? #<C SNh8[[ZSRCompositingg.0019[8?[?[H[HI[8}[;oDATA 9[9[DATA 9[h:[9[DATA h:[:[9[~DATA :[H;[h:[~DATA H;[;[:[DATA ;[(<[H;[~DATA (<[<[;[ \DATA <[=[(<[~\DATA =[x=[<[ DATA x=[=[=[DATA =[X>[x=[ DATA X>[>[=[DATA >[8?[X>[DATA 8?[>[ DATA(?[@[9[h:[DATA(@[@[?[9[H;[DATA(@[@[@[h:[;[DATA(@[hA[@[H;[;[DATA(hA[A[@[:[<[DATA(A[HB[hA[(<[<[DATA(HB[B[A[;[=[DATA(B[(C[HB[H;[=[DATA((C[C[B[(<[=[DATA(C[D[(C[;[<[DATA(D[xD[C[H;[x=[DATA(xD[D[D[=[=[DATA(D[XE[xD[x=[=[DATA(XE[E[D[x=[X>[DATA(E[8F[XE[=[X>[DATA(8F[F[E[9[>[DATA(F[G[8F[>[8?[DATA(G[G[F[:[8?[DATA(G[G[G[(<[8?[DATA(G[hH[G[X>[>[DATA(hH[H[G[=[8?[DATA(H[hH[9[x=[DATAHI[M[H;[9[h:[;[~XNXN8J[K[DATA(8J[K[ DADA~DADA?? ~DATA(K[8J[mEmEpoo?? pDATAM[R[HI[8?[(<[<[:[!~[^\P[P[N[xO[DATA(N[xO[sDACA]CACA?? ^^!~^DATA(xO[N[@~CHB23JуCHB]]A?HB|HHB= AH^B!~[^BDATAP[DATAR[j[M[(<[=[;[<[!~]^Xi[Xi[R[hT[DATA(R[hT[CACA]CACA?? ^^!~^DATA(hT[R[C\C\M^rRLr?@ ^sMs!~]^sU[g[DATAXU[xW[BUTTONS_PT_contextBUTTONS_PT_contextContextL$DATAXxW[Y[U[RENDER_PT_renderRENDER_PT_renderRenderL=DATAXY[Z[xW[RENDER_PT_layersRENDER_PT_layersLayersoLDATAXZ[X\[Y[RENDER_PT_dimensionsRENDER_PT_dimensionsDimensionsLDATAXX\[][Z[RENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:L:DATAX][_[X\[RENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"LDATAX_[8a[][RENDER_PT_shadingRENDER_PT_shadingShading LDATAX8a[b[_[RENDER_PT_performanceRENDER_PT_performancePerformanceLDATAXb[xd[8a[RENDER_PT_post_processingRENDER_PT_post_processingPost ProcessingLDATAXxd[f[b[RENDER_PT_stampRENDER_PT_stampStampL DATAXf[g[xd[RENDER_PT_outputRENDER_PT_outputOutput(L DATAXg[f[RENDER_PT_bakeRENDER_PT_bakeBakeL DATAXi[DATAj[w[R[>[X>[=[8?[hv[hv[k[Hq[DATA(k[l[@qDAFDAFDAFDA?? DATA(l[hn[k[C@FCF++?@ ,rDATA(hn[o[l[CfCww?@ xf"DATA(o[Hq[hn[#Cl#C?@ pDATA(Hq[o[rr[DATA`r[]e?w@AHMݕ/?U~'?3F:?>T8165e?2>Z& 4?ߕ/?7F:?81W~>85e?'?T2>ne@>M@?*?c''Ӥ?7??T?']@l2zz11A 4A>>Ļ7v=m>3xB֟&BĭeA(@ݕ/?U~'?3F:?>T8165e?2>Z& 4?*?c''Ӥ?7??T?']@l2zz11A 4A>?>?>??H?N,Z#oAoAP1:\>7?8˔?ABdZBvBDATA8hv[333?? ANo B?=C DATAw[8}[j[x=[H;[=[=[ ]{[{[x[Hz[DATA(x[Hz[BDADADADA??   DATA(Hz[x[ D DlD`@>C BB??FFQ= @  C1 CDATA0{[ @;o a?DATA8}[w[9[x=[X>[>[x[x[(~[[DATA((~[[CAADA@DA@DA?? DATA([[(~[DATA([[CC@d?rrDATA(!x[dA>d>ddd?SN[8mh8[SRDefault[[h[[x[m;oDATA [x[DATA x[[[*DATA [X[x[*DATA X[Ȧ[[DATA Ȧ[8[X[DATA 8[[Ȧ[DATA [[8[DATA [[[DATA [[[pDATA [h[[pDATA h[ة[[DATA ة[H[h[DATA H[[ة[@DATA [([H[@DATA ([[[jDATA [[([jDATA [x[[DATA x[[[DATA [X[x[(DATA X[ȭ[[(DATA ȭ[8[X[DATA 8[[ȭ[DATA [[8[DATA [[[DATA [[[DATA [[DATA(h[ذ[x[[DATA(ذ[H[h[x[Ȧ[DATA(H[[ذ[[8[DATA([([H[Ȧ[8[DATA(([[[[[DATA([[([X[[DATA([x[[Ȧ[[DATA(x[[[8[[DATA([X[x[[[DATA(X[ȴ[[[[DATA(ȴ[8[X[8[[DATA(8[[ȴ[X[[DATA([[8[[[DATA([[[h[ة[DATA([[[[H[DATA([h[[[[DATA(h[ط[[H[[DATA(ط[H[h[H[([DATA(H[[ط[h[([DATA([([H[ة[[DATA(([[[[[DATA([[([([[DATA([x[[h[[DATA(x[[[ة[x[DATA([X[x[[x[DATA(X[Ȼ[[[X[DATA(Ȼ[8[X[[ȭ[DATA(8[[Ȼ[X[8[DATA([[8[ȭ[8[DATA([[[[[DATA([[[Ȧ[[DATA([h[[[[DATA(h[ؾ[[X[[DATA(ؾ[H[h[[[DATA(H[[ؾ[[[DATA([([H[ȭ[[DATA(([[[8[[DATA([[([x[[DATA([[[[DATAx[H[Ȧ[x[[8[*mmh[[DATA(h[[DADA`DA`DA?? )DATA([h[mED@poo?? p**DATAH[[x[[[[X[opX[X[8[[DATA(8[[CAoCAnCAnCA?? VoDATA([8[oCU^CUUJU?@ VVUV[[DATAX[[BUTTONS_PT_contextBUTTONS_PT_contextContext$DATAX[X[[RENDER_PT_renderRENDER_PT_renderRender=DATAXX[[[RENDER_PT_layersRENDER_PT_layersLayersoDATAX[[X[RENDER_PT_dimensionsRENDER_PT_dimensionsDimensions DATAX[8[[RENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:: DATAX8[[[RENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur" DATAX[x[8[RENDER_PT_shadingRENDER_PT_shadingShading  DATAXx[[[RENDER_PT_performanceRENDER_PT_performancePerformance DATAX[[x[RENDER_PT_post_processingRENDER_PT_post_processingPost ProcessingDATAX[X[[RENDER_PT_stampRENDER_PT_stampStampDATAXX[[[RENDER_PT_outputRENDER_PT_outputOutput(DATAX[[X[RENDER_PT_bakeRENDER_PT_bakeBakeDATAX[8[[SCENE_PT_sceneSCENE_PT_sceneScene)=DATAX8[[[SCENE_PT_unitSCENE_PT_unitUnits)SDATAX[x[8[SCENE_PT_keying_setsSCENE_PT_keying_setsKeying Sets)EDATAXx[[[SCENE_PT_physicsSCENE_PT_physicsGravity)$DATAX[[x[SCENE_PT_simplifySCENE_PT_simplifySimplify)PDATAX[[SCENE_PT_custom_propsSCENE_PT_custom_propsCustom Properties)$DATAX[DATA[[H[[H[[[?@h[h[[[DATA([[ DADA`DA`DA?? DATA([[@~CHBXg(CHB%?HB|HHB= AH&?&DATAh[DATA[\[[[8[[qX[X[x[[DATA(x[[CAoCAnCAnCA?? DATA([x[C^C?? rqDATAX[+se SculptDATA+ [DATA[ ;o;o;o;oKoToGoNoFo;o;o;o;o;o;o;o;o;o;o;o ;o ;o ;o ;o ;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o ;o!;o";o#;o$;o%;o&;o';o(;o);o*;o+;o,;o-;o.;o/;o0;o;o;o;o;o;o;o;o;o;o;o ;o ;o ;o ;o ;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o;o ;o!;o";o#;o$;o%;o&;o';o(;oooooXoooHooo8pp p(pxpp ph%p*p0pX5p:p?pHEpJpOp8UpZp_p(epooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEoFoGoNoToZh8[[H'nvnn oZKoooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEoooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEoooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEoXoXoXoXoXoXoXoXoXo Xo Xo Xo Xo XoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXo Xo!Xo"Xo#Xo$Xo%Xo&Xo'Xo(Xo)Xo*Xo+Xo,Xo-Xo.Xo/Xo0Xo1Xo2Xo3Xo4Xo5Xo6Xo7Xo8Xo9Xo:Xo;Xo<Xo=Xo>Xo?Xo@XoAXoBXoCXoDXoEXoooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEoooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEoHoHoHoHoHoHoHoHoHo Ho Ho Ho Ho HoHoHoHoHoHoHoHoHoHoHoHoHoHoHoHoHoHoHo Ho!Ho"Ho#Ho$Ho%Ho&Ho'Ho(Ho)Ho*Ho+Ho,Ho-Ho.Ho/Ho0Ho1Ho2Ho3Ho4Ho5Ho6Ho7Ho8Ho9Ho:Ho;Ho<Ho=Ho>Ho?Ho@HoAHoBHoCHoDHoEHoooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEoooooooooo o o o o ooooooooooooooooooo o!o"o#o$o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o5o6o7o8o9o:o;o<o=o>o?o@oAoBoCoDoEo8p8p8p8p8p8p8p8p8p 8p 8p 8p 8p 8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p 8p!8p"8p#8p$8p%8p&8p'8p(8p)8p*8p+8p,8p-8p.8p/8p08p18p28p38p48p58p68p78p88p98p:8p;8p<8p=8p>8p?8p@8pA8pB8pC8pD8pE8pppppppppp p p p p ppppppppppppppppppp p!p"p#p$p%p&p'p(p)p*p+p,p-p.p/p0p1p2p3p4p5p6p7p8p9p:p;p<p=p>p?p@pApBpCpDpEp p p p p p p p p p  p  p  p  p  p p p p p p p p p p p p p p p p p p p  p! p" p# p$ p% p& p' p( p) p* p+ p, p- p. p/ p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p: p; p< p= p> p? p@ pA pB pC pD pE p(p(p(p(p(p(p(p(p(p (p (p (p (p (p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p (p!(p"(p#(p$(p%(p&(p'(p((p)(p*(p+(p,(p-(p.(p/(p0(p1(p2(p3(p4(p5(p6(p7(p8(p9(p:(p;(p<(p=(p>(p?(p@(pA(pB(pC(pD(pE(pxpxpxpxpxpxpxpxpxp xp xp xp xp xpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxpxp xp!xp"xp#xp$xp%xp&xp'xp(xp)xp*xp+xp,xp-xp.xp/xp0xp1xp2xp3xp4xp5xp6xp7xp8xp9xp:xp;xp<xp=xp>xp?xp@xpAxpBxpCxpDxpExpppppppppp p p p p ppppppppppppppppppp p!p"p#p$p%p&p'p(p)p*p+p,p-p.p/p0p1p2p3p4p5p6p7p8p9p:p;p<p=p>p?p@pApBpCpDpEp p p p p p p p p p  p  p  p  p  p p p p p p p p p p p p p p p p p p p  p! p" p# p$ p% p& p' p( p) p* p+ p, p- p. p/ p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p: p; p< p= p> p? p@ pA pB pC pD pE ph%ph%ph%ph%ph%ph%ph%ph%ph%p h%p h%p h%p h%p h%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%ph%p h%p!h%p"h%p#h%p$h%p%h%p&h%p'h%p(h%p)h%p*h%p+h%p,h%p-h%p.h%p/h%p0h%p1h%p2h%p3h%p4h%p5h%p6h%p7h%p8h%p9h%p:h%p;h%p<h%p=h%p>h%p?h%p@h%pAh%pBh%pCh%pDh%pEh%p*p*p*p*p*p*p*p*p*p *p *p *p *p *p*p*p*p*p*p*p*p*p*p*p*p*p*p*p*p*p*p*p *p!*p"*p#*p$*p%*p&*p'*p(*p)*p**p+*p,*p-*p.*p/*p0*p1*p2*p3*p4*p5*p6*p7*p8*p9*p:*p;*p<*p=*p>*p?*p@*pA*pB*pC*pD*pE*p0p0p0p0p0p0p0p0p0p 0p 0p 0p 0p 0p0p0p0p0p0p0p0p0p0p0p0p0p0p0p0p0p0p0p 0p!0p"0p#0p$0p%0p&0p'0p(0p)0p*0p+0p,0p-0p.0p/0p00p10p20p30p40p50p60p70p80p90p:0p;0p<0p=0p>0p?0p@0pA0pB0pC0pD0pE0pX5pX5pX5pX5pX5pX5pX5pX5pX5p X5p X5p X5p X5p X5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5pX5p X5p!X5p"X5p#X5p$X5p%X5p&X5p'X5p(X5p)X5p*X5p+X5p,X5p-X5p.X5p/X5p0X5p1X5p2X5p3X5p4X5p5X5p6X5p7X5p8X5p9X5p:X5p;X5p<X5p=X5p>X5p?X5p@X5pAX5pBX5pCX5pDX5pEX5p:p:p:p:p:p:p:p:p:p :p :p :p :p :p:p:p:p:p:p:p:p:p:p:p:p:p:p:p:p:p:p:p :p!:p":p#:p$:p%:p&:p':p(:p):p*:p+:p,:p-:p.:p/:p0:p1:p2:p3:p4:p5:p6:p7:p8:p9:p::p;:p<:p=:p>:p?:p@:pA:pB:pC:pD:pE:p?p?p?p?p?p?p?p?p?p ?p ?p ?p ?p ?p?p?p?p?p?p?p?p?p?p?p?p?p?p?p?p?p?p?p ?p!?p"?p#?p$?p%?p&?p'?p(?p)?p*?p+?p,?p-?p.?p/?p0?p1?p2?p3?p4?p5?p6?p7?p8?p9?p:?p;?p<?p=?p>?p??p@?pA?pB?pC?pD?pE?pHEpHEpHEpHEpHEpHEpHEpHEpHEp HEp HEp HEp HEp HEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEpHEp HEp!HEp"HEp#HEp$HEp%HEp&HEp'HEp(HEp)HEp*HEp+HEp,HEp-HEp.HEp/HEp0HEp1HEp2HEp3HEp4HEp5HEp6HEp7HEp8HEp9HEp:HEp;HEp<HEp=HEp>HEp?HEp@HEpAHEpBHEpCHEpDHEpEHEpJpJpJpJpJpJpJpJpJp Jp Jp Jp Jp JpJpJpJpJpJpJpJpJpJpJpJpJpJpJpJpJpJpJp Jp!Jp"Jp#Jp$Jp%Jp&Jp'Jp(Jp)Jp*Jp+Jp,Jp-Jp.Jp/Jp0Jp1Jp2Jp3Jp4Jp5Jp6Jp7Jp8Jp9Jp:Jp;Jp<Jp=Jp>Jp?Jp@JpAJpBJpCJpDJpEJpOpOpOpOpOpOpOpOpOp Op Op Op Op OpOpOpOpOpOpOpOpOpOpOpOpOpOpOpOpOpOpOp Op!Op"Op#Op$Op%Op&Op'Op(Op)Op*Op+Op,Op-Op.Op/Op0Op1Op2Op3Op4Op5Op6Op7Op8Op9Op:Op;Op<Op=Op>Op?Op@OpAOpBOpCOpDOpEOp8Up8Up8Up8Up8Up8Up8Up8Up8Up 8Up 8Up 8Up 8Up 8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up8Up 8Up!8Up"8Up#8Up$8Up%8Up&8Up'8Up(8Up)8Up*8Up+8Up,8Up-8Up.8Up/8Up08Up18Up28Up38Up48Up58Up68Up78Up88Up98Up:8Up;8Up<8Up=8Up>8Up?8Up@8UpA8UpB8UpC8UpD8UpE8UpZpZpZpZpZpZpZpZpZp Zp Zp Zp Zp ZpZpZpZpZpZpZpZpZpZpZpZpZpZpZpZpZpZpZp Zp!Zp"Zp#Zp$Zp%Zp&Zp'Zp(Zp)Zp*Zp+Zp,Zp-Zp.Zp/Zp0Zp1Zp2Zp3Zp4Zp5Zp6Zp7Zp8Zp9Zp:Zp;Zp<Zp=Zp>Zp?Zp@ZpAZpBZpCZpDZpEZp_p_p_p_p_p_p_p_p_p _p _p _p _p _p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p _p!_p"_p#_p$_p%_p&_p'_p(_p)_p*_p+_p,_p-_p._p/_p0_p1_p2_p3_p4_p5_p6_p7_p8_p9_p:_p;_p<_p=_p>_p?_p@_pA_pB_pC_pD_pE_p(ep(ep(ep(ep(ep(ep(ep(ep(ep (ep (ep (ep (ep (ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep(ep (ep!(ep"(ep#(ep$(ep%(ep&(ep'(ep((ep)(ep*(ep+(ep,(ep-(ep.(ep/(ep0(ep1(ep2(ep3(ep4(ep5(ep6(ep7(ep8(ep9(ep:(ep;(ep<(ep=(ep>(ep?(ep@(epA(epB(epC(epD(epE(epFoFoFoFoFoFoFoFoFo Fo Fo Fo Fo FoFoFoFoFoFoFoFoFoFoFoFoFoGoGoGoGoGoGoGoGoGo Go Go Go Go GoGoGoGoGoGoGoGoGoGoGoGoGoGoGoGoGoGo      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRS      !"#$%&'()*+,-./0123NoNoNoNoNoNoNoNoNo No No No No NoNoNoNoNoNoNoNoNoNoNoNoNoNoNoNoNoNoNo No!No"No#No$No%No&No'No(No)No*No+No,No-No.No/No0No1No2No3No4No5No6No7No8No9No:No;No<No=No>No?No@NoANoBNoCNoDNoENoFNoGNoHNoINoJNoKNoLNoMNoNNoONoPNoQNoRNoSNoTNoUNoVNoWNoXNoYNoZNo[No\No]No^No_No`NoToToToToToToToToTo To To To To ToToToToToToToToToToToToToToToToToToTo To!To"To#To$To%To&To'To(To)To*To+To,To-To.To/To0To1To2To3To4To5To6To7To8To9To:To;To<To=To>To?To@ToAToBToCToDToEToFToGToHToIToJToKToLToMToNToOToPToQToRToSToTToUToVToWToXToYToZTo[To\To]To^To_To`ToZZZZZZZZZ Zh8[h8[h8[h8[h8[h8[h8[h8[h8[ h8[[[[[[[[[[ [H'nH'nH'nH'nH'nH'nH'nH'nH'n H'nvnvnvnvnvnvnvnvnvn vnnnnnnnnnn n o o o o o o o o o  o     ZZZZZZZZZ Z ZKoKoKoKoKoKoKoKoKo Ko Ko Ko Ko KoKoKoKoKoKoKoKo([oDATA\Ȱ\[h[[x[ة[H\H\\(\DATA(\\@qDADAK`DA`DA?? LLDATA(\\\ CC?@ 2h\\DATAXh\\VIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAX\h\VIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(\\\!CvfC^dv?@ "\\DATAX\VIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(\(\\4C`#C`ã?@ DATA((\\D\DATA`\?7B LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?TA5>#,>mv$BH*=!lA!oA'>~tU?`FH!;<81pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?TA5>#,>mv$BH*=$!j?!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8H\333?? ANo B?=zD DATAȰ\\\H[([[[Ai)\\\(\DATA(\(\ DADA`DA`DA?? AZDATA((\\@~CHBXg(CHB?HB|HHB= AH[iDATA\DATA\\Ȱ\([h[ة[[k\\\\DATA(\\ DADAK`DA`DA?? LLkkDATA(\\@~CHBXg(CHB?HB|HHB= AHkDATA\DATA\\\[[[x[+X\X\\8\DATA(\\@qDADA`DA`DA?? DATA(\\\ CC?@ 2x\\DATAXx\\VIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAX\x\VIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(\\\!CvfC^dv?@ "(\(\DATAX(\VIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(\8\\4C`#C`ã?@ DATA(8\\D\DATA`\?ÃB LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?YA5>#,>m{BH*=!lA!oA'>~tU?`F/_N4;vP<1pu²Aݞ6rB;B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?YA5>#,>m{BH*=$!/I?!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8X\333?? ANo B?=zD DATA\h\\[[[X[)w\\\\DATA(\8\@qDADA`DA`DA?? )BDATA(8\\\ CChh?@ ii7i2\H\DATAX\H\VIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXH\\VIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(\\8\!CvfC^dv?@ C6"X\X\DATAXX\VIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(\\\4C@s#C~ã\\?@ ]]0C]h\(\DATAXh\\VIEW3D_PT_objectVIEW3D_PT_objectTransformznDATAX\\h\VIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease PencilPDATAX\H\\VIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView?DATAXH\\\VIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem$DATAX\\H\VIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplaygDATAX\(\\VIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImagesODATAX(\\VIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform Orientations7DATA(\\/C]8\DATA`8\?26@ LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQuZ? ?5>#,>mT#@H*=!lA!oAd>ntU?@FR=U>3pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQuZ? ?5>#,>mT#@H*=%!T=!lA!oA@@@@@@mWC <?\>7?8˔!oAoAf;?8 BBj~BDATA8\333?? ANo B?=zD DATAh\m\ȭ[[X[8['3xmxmX\XmDATA(X\\@qDADA`DA`DA?? DATA(\x\X\ CC?@ '28\\DATAX8\\VIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAX\8\VIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(x\m\!CvfC^dv?@ "\\DATAX\VIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(mXmx\C@sC=N<?@ N='NNmmDATAXmmVIEW3D_PT_objectVIEW3D_PT_objectTransformz=nDATAXm8mmVIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease Pencil=PDATAX8mmmVIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView=?DATAXmxm8mVIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem=$DATAXxmmmVIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplayg=DATAXmmxmVIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImagesO=DATAXmmVIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform Orientations7=DATA(Xmm'mDATA`m?fB LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>"*UtQQsZ?~@5>#,>mtAH*=!lA!oA'>~tU?pF{FV;<1pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>F"*UtQQsZ?~@5>#,>mtAH*=$!d?!lA!oA}-@}-@}-@mWC <?\>7?8˔!oAoA;?8 BBj~BDATA8xm333?? ANo B?=zD DATAmmh\[Ȧ[[[[nmmDATAmm[ȭ[8[['mmmxmDATA(mHm@qDADA`DA`DA?? DATA(Hmmm CCP  ?@  2mXmDATAXmXmVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXXmmVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(mmHm!CvfC^dv?@ "hmhmDATAXhmVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(mxmm4C`#C`ã?@ DATA(xmmD mDATA`m?B LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?TA5>#,>mvBH*=!lA!oA'>~tU?`FH! ;<0pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?TA5>#,>mvBH*=$!j@!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8m333?? ANo B?=zD SN8mH'n[SRDefault-fullXmmmmm"n;oPkDATA XmmDATA m8mXmDATA 8mmmDATA mm8mDATA mmmhDATA mmhDATA(mhmm8mDATA(hmmmXmmDATA(mHmhmXmmDATA(HmmmmmDATA(m(mHm8mmDATA((mmmmmDATA(m(mmmDATAm"nXmmmm[ghMbn8"nmnLRNDATA(mhmYDA DADADA?? (XbOORNDATA(hmXnmC C m~1l1?@ ~2m2}6g~2~2TbȬNȬNmnNHbBDATAXmxmOVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Toolsm'DATAXxmnmVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATAXnnxmVIEW3D_PT_tools_mesheditVIEW3D_PT_tools_mesheditMesh ToolsmDATAXnnVIEW3D_PT_tools_meshedit_optionsVIEW3D_PT_tools_meshedit_optionsMesh Options@mtDATA(XnhnhmC@JCRm~l?@ ~m}5~"UbOOnncBeBDATAXnVbVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorOperatoritmodect All3D Cursorp'DATA(hnnXn4C#CMM?@ NNgNObURQn8nXfBhBDATAXnx nPbVIEW3D_PT_objectVIEW3D_PT_objectTransformzn&DATAXx n nn(RbVIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease PencilPDATAX n nx nX0VIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView)DATAX nXn n2VIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem$DATAXXnn n85VIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplay}DATAXnnXn8AVIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImageseDATAXn8nnCVIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform OrientationsMDATAX8nnVIEW3D_PT_view3d_meshdisplayVIEW3D_PT_view3d_meshdisplayMesh DisplayhDATA(nhn~gONNbHB NHnDATA`Hn?U? LU|?+NG$>!>Ԡ?\lFsCJ?/k?tn?-B݈?U|?!>s+NԠ?CJ?H$>]lF.k?mg[~3-@?? $G$0>CS?vF?\lF?+I?2s/kg?%eQ~@݈@f?r>&^q>>F??uNAzX;7"+NA@U|?+NG$>s<J?7k?!ܠUlF??? $G$+I?:s7k0CS~vFUlFp\@@???mWC <?*Ge?߾{m@bN@h\:9s?? ! BTBq~BDATA8n8"n333?? ANo([o B?=zD DATA(xnn@PDA DADADA?? VoDATA(nXnxnpC_CUU?@ VVUVDATA(Xn nnDpB DpB;`DlB`DlB?? <<U<DATA( nXn2C D??DATAh8"nnxn nDATA"nmmm8mm[i0yb&n&n#nH%n+;;DATA(#nH%ncDA DADADA?? i|b8R8RN8BDATA(H%n#nD0ADApo?? p{bXAhOSNH'nvn8mSRGame Logic.001h(n.n.nH7n7non;oDATA h(n(nDATA (nH)nh(nDATA H)n)n(n~DATA )n(*nH)n~DATA (*n*n)nDATA *n+n(*n~DATA +nx+n*nDATA x+n+n+n DATA +nX,nx+n DATA X,n,n+n~DATA ,n8-nX,n@DATA 8-n-n,n@DATA -n.n8-nDDATA .n-nDDATA(.n.n(nH)nDATA(.nh/n.n(n(*nDATA(h/n/n.nH)n*nDATA(/nH0nh/n(*n*nDATA(H0n0n/n(*n+nDATA(0n(1nH0n+nx+nDATA((1n1n0n)n+nDATA(1n2n(1nx+n+nDATA(2nx2n1nh(n+nDATA(x2n2n2nh(n+nDATA(2nX3nx2n*nX,nDATA(X3n3n2n)nX,nDATA(3n84nX3nx+nX,nDATA(84n4n3n,n8-nDATA(4n5n84n*n8-nDATA(5n5n4nX,n,nDATA(5n5n5n+n-nDATA(5nh6n5n,n-nDATA(h6n6n5n(*n.nDATA(6nH7nh6n8-n.nDATA(H7n6n-n.nDATA7n;n(*n(nH)n*n~unun8n:nDATA(8n:n DADA~DADA?? ~DATA(:n8nmED@poo?? pDATA;nTn7n+nx+nX,n)n!~^RnRnx]X_nX_nx\n]nDATA(x\n]nCADA=@DA@DA?? >>A~>DATA(]nx\nCCDVD=B #<zD >C>CA~>CDATAX_n DATAHbnon[n-n.n8-n,nE?]nnnn8cnhnDATA(8cndn@qDA~DA~DA~DA?? E?DATA(dnfn8cnC@FCF++?@ ,EECDATA(fngndnCfCww?@ xfE?"DATA(gnhnfn4Cm#Cmã?@ ??DATA(hngnE?ChjnDATA`hjn#=K(=o?????????#=K(=o?5ApykA?????#=K(=o?t@t@t@??5AoA9P=\>7?8˔?BBDATA8nn333?? ANo B?=zD DATAonHbn+n(*n.n-nCD]hsnhsnpnqnDATA(pnqnCACACCACA?? DDCDDATA(qnpnCC@ 3DB22B?? DC31CDCDATAhsnx"NDATAx"NtnDATAtn;o;o;o;oKoToGoNoFo;oSNvnnH'nSRScriptingg.001wnX}n}nnhnn;oDATA wnxnDATA xnxnwnDATA xnxnxn~DATA xnhynxn~DATA hynynxnDATA ynHznhyn~DATA HznznynDATA zn({nHznDATA ({n{nznhDATA {n|n({nhDATA |nx|n{nhDATA x|n|n|nDATA |nX}nx|n~DATA X}n|nDATA(}n8~nxnxnDATA(8~n~n}nxnhynDATA(~nn8~nxnynDATA(nn~nhynynDATA(nnnynHznDATA(nhnnxnznDATA(hn؀nnwn({nDATA(؀nHnhnhyn({nDATA(Hnn؀nHzn{nDATA(n(nHnzn{nDATA((nnn({n|nDATA(nn(n{n|nDATA(nxnnznx|nDATA(xnnnHznx|nDATA(nXnxnyn|nDATA(XnȄnnxn|nDATA(Ȅn8nXnx|n|nDATA(8nnȄnhynX}nDATA(nn8nHznX}nDATA(nnn|nX}nDATA(nnn({n{nDATA(nnwnznDATAhn8nhynxnxnyn~]HnHnXnȉnDATA(Xnȉn DADA~DADA?? ~DATA(ȉnXnDBDBnBomB?? CnC~CDATA8nȣnhnznx|n|nxn~nn(nnDATA((nnCACACACA?? ~DATA(n(nC=C4}~|?@ }~nnDATAXnnBUTTONS_PT_contextBUTTONS_PT_contextContext|$DATAXnHnnRENDER_PT_renderRENDER_PT_renderRender|=DATAXHnnnRENDER_PT_layersRENDER_PT_layersLayerso|DATAXnnHnRENDER_PT_dimensionsRENDER_PT_dimensionsDimensions|DATAXn(nnRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:|:DATAX(nȘnnRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"|DATAXȘnhn(nRENDER_PT_shadingRENDER_PT_shadingShading |DATAXhnnȘnRENDER_PT_performanceRENDER_PT_performancePerformance|DATAXnnhnRENDER_PT_post_processingRENDER_PT_post_processingPost Processing|DATAXnHnnRENDER_PT_stampRENDER_PT_stampStamp| DATAXHnnnRENDER_PT_outputRENDER_PT_outputOutput(| DATAXnHnRENDER_PT_bakeRENDER_PT_bakeBake| DATAnDATAȣnn8n|nX}nHzn{ni?nnnxnDATA(n(n@qDA=DA=DA=DA?? iDATA((nnnC@FCF++?@ ,%DATA(nn(nCfCww?@ xf"DATA(nxnn#C#Cyy?@ zhDATA(xnn%nDATA`n?J?PףD>3;Q?Fwi?JF>#,TY!e?*=>o?E>Fwi?TY5;JF>!e?Q?#,+=>`DAoy@?>ޠQQuZ?> .>#,>m6uU?F +!>?`5hąC% ÈG6DWѦCGBD>3;Q?Fwi?JF>#,TY!e?*=>o?>ޠQQuZ?> .>#,>m7?8˔oAoAk;?! BVBt~BDATA8n333?? ANo B? #<C DATAn(nȣnwn({n{nznghXnXnnxnDATA(nxnCADADADA?? DATA(xnnD3CDCMM?? NNgNDATA(n؅+DATA؅+DATAXnnn>>> pythonDATA(nnnx|nHznyn|n~nnnnDATA(nnCACACACA?? ~DATA(nnCC}||?? }~DATAnfNDATAfNXnDATAXn;o;o;o;oKoToGoNoFo;oDATAn(n({nhynX}n|ni ?XnXnxnnDATA(xnnCA>DA=DA=DA?? iDATA(nxnDDD)dD.>CC$ #<zD %%%DATAXn =z||SNn ovnSRUV EditingnnxnnHnhn;oDATA nhnDATA hnnnDATA nHnhn~DATA Hnnn~DATA n(nHnDATA (nnn~DATA nn(nDATA nnDATA(xnnhnnDATA(nXnxnhnnDATA(Xnnnn(nDATA(n8nXnn(nDATA(8nnnnnDATA(nn8nnnDATA(nnnnnDATA(nnnnnDATA(nhnn(nnDATA(hnnnHnnDATA(nhnHn(nDATAHnnnhnn(n~ o o8nnDATA(8nn DADA~DADA?? ~DATA(n8nmEmEpoo?? pDATAnhnHnnnnnnnnnDATA(nxnCArDAqDAqDA?? DATA(xnnn[CsJCs?@ nnDATAXnIMAGE_PT_gpencilIMAGE_PT_gpencilGrease PencilPDATA(nxnCC33+?33@DATA(!ndA>d>ddd?DATAhnnnn(nHn~x ox oXnXoDATA(Xnn@qDAmDA@mDA@mDA?? ~DATA(nnXn CVCVWW?@ XXhX8n8nDATAX8nVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject ToolsDATA(non!CfC[Zww?@ xxhx"HoHoDATAXHoVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorOperatorDATA(oXon#C~#C~  ?@  ~~DATA(Xooi~oDATA`oH?? JLD>3;Q?Fwi?JF>#,TY!e?*=>_?E>Fwi?TY4;JF>!e?Q?#,+=>6@_?? ?0QQ?X>?>#,>ՒΜz?T*=dbR@_@y\>,? (K5>}Q?sMd@JWA.Xj@-@D>3;Q?Fwi?JF>#,TY!e?*=>_? ?0QQ?X>?>#,>ՒΜz?T*=dbR@_@>>>?\>7?8˔_@_@r:?! BUBt~BDATA8x o333?? ANo B?=C SN onSRVideo Editing oxooXoo3o;oDATA o oDATA  o o oDATA o o o~DATA oho o~DATA hoo oDATA oHoho~DATA Hooo~DATA o(oHo\DATA (oooPDATA oo(oDATA oxooPDATA xoo~\DATA(oXo o oDATA(Xooo ohoDATA(o8oXo ooDATA(8ooohooDATA(oo8ooHoDATA(ooo ooDATA(oooho(oDATA(ohooooDATA(hoooooDATA(oHoho(ooDATA(HoooHoxoDATA(o(oHo oxoDATA((ooooxoDATA(oo(o o oDATA(oxooo(oDATA(xoooHooDATA(oXoxohooDATA(XooHooDATAooho o oo~;o;oo(oDATA(o(o DADA~DADA?? ~DATA((oomEmEpoo?? pDATAo"oo ooxo o~[\h!oh!oooDATA(oo DADA~DADA?? ~DATA(oo@~CHBpF}CHB~~A?HB|HHB= AHB~[BDATAh!oDATA"ox*ooooHoxo~]8)o8)ox#o'oDATA(x#o$oDADA~DADA?? ~]vDATA($oX&ox#o\CKCpp?@ qq~wqDATA(X&o'o$oppDDppDD;F;F'7PGDATA('oX&ozCAzCApp A@|HB #<BiqwqDATA8)o@DATAx*o3o"ooho(ooOP(1o(1oh+o/oDATA(h+o,o@wDATDAOSDASDA?? PPOPDATA(,oH.oh+oHCpHC?? DATA(H.o/o,oOODATA(/oH.oC@zC Avvo:o:|HPCGiwOwDATA(1oh2oDATAhh2o;oDATA3ox*oo(ooHoQ~.9o9o4oX8oDATA(4ox5oCADA-DADA?? ..Q~.DATA(x5o6o4o~~DATA(6oX8ox5oCCđDFFD-;F;F'7PG..Q~.DATA(X8o6ozCAzCAKK A@|HB #<BiLDATA9o@SC;oSCScenetageainAoNoKoHBo(CoHBoС>V??mWC ??_??BLENDER_RENDERD?fC?P+PRBRA << ?8=?DATA`AoDATA(HBoBoh~([oDATA(Bo(CoHBo.ToDATA((CoBo.^NoDATACoBAEo?L?B ?o:= ??ZpP2 HB2 B2 HB2 HB2 HB2 HB2 HB>? #<===ff??AHz?=???C#y??DATA8BoDATA8AoDATA`Eo:pdd|AJA6V{?DATAXXFoRenderLayerrCAFoCACameraamera.001?=B B@?LAGo!LALamp ?????AB>??Io.?A4B?@@L=@ ???o:??????@?????xKoDATA@IoO????C?55?55?(O??????DATA(OM??DATA(xKo WOKoWOWorldrcP=rcP=rcP=6$<6$<6$<??A @A@pA A?L= ף;>??NoDATA(No OB NotToOBCameraamera.001 Fo  ne@>N@???*?91<"P?????ޕ/?5F:?81V~>75e?'?T3>ne@>N@??????33?3?5)?ݕ/?V~'?3F:?>T8175e?4>Z& 4?OBd8???>6 ?u=?????SoDATASow??=L> ף<OB Tot([oNoOBLamp Go  p@?p@???{&?W+b=?????6씾t? bfE9L"?%?_>oK?p@?p@??????22?3?'4'?6씾fE&?t?9L_> b#?oK? ?Af ?DOBd8?<?>">u=??@???HZoDATAHZow??=L> ף<OB ([otToOBTextB`o  q?????????ӻ+?ӻ+q??????????ӻ+?ӻ+q??d8? #=?>=???????@???HQBME`o.MEMesho(doHoxbo}o 8oB Zt?W>ף`? >?CDATAhxboT(doDATA((do4B6^?U>]2FX?U>IIX?>I,?>A?{c?^F~?II~? ף=III? ף=!{V?U>III?U>II?IV?II|??e\Xl?'?[ XG>?W?XX4??T6$Xٍ?ē?O.X_??H8X|?S?:A:AXլ?z ?8HX?u!?.OX|T?@"?6$TX~?"?XX?3#? [X:?S#?e\Xoʧ?3#?o[X?"?CXX?@"?TXK?u!?+тOX’?z ?{HX?S?ƾ:AXX??8Xڢ?“?~.XAu??6$X.*?W?X?%?z X??X??zoX-*?\-?CX@u? ?۪Xڢ?\?~+ѳXX? ?{ǹX?'1 ?ƾƾX?G ?{XK?R ?+~X?D ?X?u?CXnʧ?2Q?ozX:?'1?X?3Q? zX~?v?X{T?D ?6$X?S ?.~Xլ?H ?8X|?(1 ?:AƾX^? ?H{ǹX؍?]?O+ѳX3? ?T۪XF>?]-?XCXl??[oX?.?_X:G@5?.?LUL(1h? |F3?.?M8VUM?.?ej:G$f?ĻǦMCk?Ļ8ѪL*2=0.?II*2=I2R>II2R>d>&is|>d>ZɄ>0>U[>>Gt>&\YD>->Z5b\>=>9h\7>O >5@\}>=V>ɍ\ u> >%ñ[cR>",x>8Gz[Ѽ>R{d>/E[] >L>зl[>L0>ĵZ#> >_δZ?IN"?_mϒF?pw<UI 5Z"?f<\I4Z<?_*=rI4Z?Y=I4Zf?½=I'4Z?nm=2J3Z6?X=J2Z>?=KD2Z?f=K1Z`B?/=L0Z> ?=L0Z ? >L|/Z~?`6>$Mr/rZY?}3>L0_ZJ?NF>\L0IZ@>sY>Ku21Z> j>IJk4Z؃>{>H6Y^>J>oF9Y4 >s>C1=Y}>vߓ>H@@Y>SK>@ ?>7HYٮ>>Y$bzٮ>©>7);Y>h>0(Y,>5> 8*YPm>ہ>0?3 YL>#>E,X >>KXts>h`>QgXl9>Jc>&U=Y/>>=X;YX)?>NZ# Y?RV>l[3Y?;>[Yf??[ XVv>. ?8YIX&>?T %gX>?QNj1[X|`>?E<_X3>xd!? 2L%?b1NX>p(?&SXJ>+?WXGd>,?>ZXTv> .?v[!Y\>0.? [Y2R>*?&is">*?f[I>r?2[>j1?[$[$>D1?Hl-\>,?@s\]>T?\?>?*\r> ?b\">$ ?\5>>$ ?q]޻\t>RH?:8y\w>ܙ?1\V>G>\[>1>WD\+>>B\e>>\ع>t>'\+>a}>S*3\c>>>\>>xlG\}>>خN\3>9>uSy\郡>ɡ>V8\Ob>>X[">r>Y&[2R>r>&&s2R>r>R꽗&&:">r>RYڤOb>>R꽚X郡>ɡ>RVȣ3>9>RuS}>>RخNL>>RxlG c>>R꽠>+>a}>RS*3ع>t>R'Ge>>R+>>R>1>RWDV>G>R\w>ܙ?Rϣt>RH?R:8ꇣ5>>$ ?Rq]E">$ ?Rr> ?R꽌b?>?R*]>T?RJ>,?R@$>D1?RHlӣ>j1?R[$I>r?R2O">*?Rf2R>*?R꽗&i:\>0.?R [$Tv> .?R꽔v[ߦGd>,?R>ZJ>+?RW(>p(?R꽁&SN>2L%?Rb1Nr3>xd!?R ?RE<>?RQNj1&>?RT %Vv>. ?R8YIf??R꽔[ ^?;>R[?RV>Rl[ͦX)?>RNZ#/>>R=X;l9>Jc>R&U=ts>h`>RQg >>RKL>#>RE,Pm>ہ>R0?3,>5>R 8*>h>R꽦0ئٮ>©>R7)Ŧٮ>>RY$bT_> ?>R꽛7Hx>SK>R@vߓ>RH@@T4 >s>R꽬C1=;^>J>RoF9 ؃>{>R꽞H6> j>RIJk4@>sY>R꽃Ku2ϥJ?NF>R\L0Y?}3>RL0~?`6>R$Mr/ ? >RL|/d> ?=R꽈L0_`B?/=RL0[?f=R꽗K1Y>?=RKD2Z6?X=R꽝J2]?nm=R2J3bf?½=RI'4h?Y=R꽜I4o<?_*=RrI4u"?f >R_L>L0>Rĵ] >L>RзlѼ>R{d>R꽌/ǻcR>",x>R8GÆ u> >R%ñF}>=V>R꽢ɍ7>O >R5>=>R꽱9YD>->RZ5>>Gt>R꽧ڣɄ>0>RU?|>d>R꽏2R>d>R꽗&i:2R>RI*2=R*2=0.?RICk?ĻR꽜8Ѫ $f?ĻR꽻Ǧ?.?Rej:tF3?.?RM8VU(1h?R "@5?.?R꽞LU?.?R_X:kl??R꽆[ojF>?]-?RXC`3? ?RTV؍?]?R꽂O+M^? ?RH{G|?(1 ?R:AƾEլ?H ?R꽅8G?S ?R.~M{T?D ?R6$V~?v?R꽽`?3Q?R꽑 zj:?'1?Rmnʧ?2Q?Rozj?u?RC`?D ?RVK?R ?R+~M?G ?R{G?'1 ?RƾƾEX? ?R{Gڢ?\?R~+M@u? ?RV-*?\-?RC`??Rzoj??R꽛m?%?Rz j.*?W?R`Au??R6$Vڢ?“?R~.MX??R8G?S?Rƾ:AE’?z ?R{HGK?u!?R+тOM?@"?RTV?"?RCX`oʧ?3#?Ro[j:?S#?Re\m?3#?R꽑 [j~?"?R꽽X`|T?@"?R6$TV?u!?R.OMլ?z ?R꽅8HG|?S?R:A:AE_??RH8Gٍ?ē?R꽂O.M4??RT6$VG>?W?RX`l?'?R꽆[ j|??Re\mV?RI?R?U>RIV?U>RII? ף=R꽴߄~? ף=RII~?RIc?R^6,?>RA?X?>RX?U>RI6^?U>R꽰]28DATAh}oTHoDATA$Ho1 #!!####!#!!## # ! # # # # #! $! %! ;# # "! #!#!!"!# !!!#! !#!!#!!#!!#!!#!!#!!#!####### # !#!"#"###$#$%#%&#%:!%;!&'#&9!&:!'(#'8!'9!()#(7!(8!)*#)6!)7!*+#*5!*6!+,#+4!+5!,-#,3!,4!-.#-2!-3!./#.1!.2!/0#/1!01#12#23#34#45#56#67#78#89#9:#:;#<=#<>!<B#=>#>?#>A!>B!?@#?A!@A#AB#CD#C#C!DE#DF!D!D!EF#FG#Fk!Fl!Fm!Fn!Fo!Fp!Fq!Fr!F!F!GH#Gk!HI#Hj!Hk!IJ#Ij!JK#Jj!KL#Ki!Kj!LM#Li!MN#Mh!Mi!NO#Ng!Nh!OP#Of!Og!PQ#Pe!Pf!QR#Qd!Qe!RS#Rb!Rc!Rd!ST#Sa!Sb!TU#TV!TW!TX!TY!TZ!T[!T\!T]!T^!T_!T`!Ta!UV#VW#WX#XY#YZ#Z[#[\#\]#]^#^_#_`#`a#ab#bc#cd#de#ef#fg#gh#hi#ij#jk#kl#lm#mn#no#op#pq#qr#rs#r!r!r!st#s!s!s!tu#t!t!t!uv#u!u!vw#v!v!wx#w!w!w!xy#x!x!yz#y!y!y!z{#z!z!z!{|#{!{!{!{!|}#|!|!|!|!}~#}!}!}!}!~#~!~!#!#!#!#!#!#!!###########################!################################################!#################~##}##|##{##z##y##x##w##v##u##t##s##r##q##p##o##n##m##l##k##j##i##h!#g!#f!#e!#d!#c!#b!#a!#`!#_!#^!#]!#\!#[!#Z!#Y!#X!#W!#V!#U##T##S!#R!#Q!#P##O##N##M##L##K##J##I##H##G!#F##E##D###C##A##B#@##?##>##=###<##:##;#9##8 # #7 #  #6 #  #5 #  #4 #  #3# #2##1##0##/##.##-##,##+##*##)##(##'##&##%##$#####"##! # # !# !#"#!"###"##$##$#%#$%#&#%&#'#&'#(#'(#)#()#*#)*#+#*+#,#+,#-#,-#.#-.#/#./#0#/0#1#01#2#12#3#23# 4#34#5# 5#45# 7#67# 6# 8#78#69#9#89#;#:;#:#<#;<#=#<=#>#=>#?#>?#@#?@#:A#A#@A#?A!>A!:>!:=!;=!(*!(+!'+!',!&,!&-!%-!%.!$.!$/!#/!#0!"0!"1!!1!!2! 2! 3!3!4!4!5!5!5!!!!!! ! ! ! ! ! ! ! ! ! !!!!!!!79!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!DATAh8oToDATA|$o0  ! !"!" # "# $ #% $%; %:;&:%&9:'9&'89(8'(78)7()67*6)*56+5*+45,4+,34-3,-23.2-.12/1./01   A?@A>?><=>B<AB>DCC~~}~D}}}|}|||{|{{{z{zzyzyyxyxwxwwvwvuvututtstssrsrrDFFFrFqrFpqFopFnoFmnFlmFklFGkGHkHjkDEFIjHJjIKjJKijLiKMiLMhiNhMNghOgNOfgPfOPefQePQdeRdQRcdRbcSbRSabTaST`aT_`T^_T]^T\]T[\TZ[TYZTXYTWXTVWTUV~~}}||{{zzyyxxwwvvuuttssrrqqppoonnmmllkkjjiihhggffeeddccbbaa``__^^]]\\[[ZZYYXXWWVVUUTTSSRRQQPPOONNMMLLKKJJIIHHGGFFEEDCDCBAA@@??>>=<B=<;::998 87  76  65  54  43 3221100//..--,,++**))((''&&%%$$##""! ! !  "!#"$#%$&%'&(')(*)+*,+-,.-/.0/102132 43 ;5 54 76 87 69 98;:<;=<>=?>@?:AA@@A??A>>A:>:=:;=;<=)*(*+((+'+,'',&,-&&-%-.%%.$./$$/#/0##0"01""1!12!!2 23  334445555               897967BRoSoBRAddh.001?Xo??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA o??????????L>?????????????????????????????DATA@XoO????C?~6=~.=hA??????DATA0hAM?>k?@? ף=?BRoSooBRBlob001?(o??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATAPo??????????L>?????????????????????????????DATA@(oO????C?._raxR??????DATA0xRM?>ףp?@?u=?BRoSooBRBlur.004?o??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA o??????????L>?????????????????????????????DATA@oO????C?~6=~.=o??????DATA0oM?>k?@? ף=?BRoSXooBRBrush?Ho??????????L>?????????????????????????????# Kfff?=??????>!?>>>>?DATApo??????????L>?????????????????????????????DATA@HoO????C?._rao??????DATA0oM?>ףp?@?u=?BRXoSooBRClay001?o??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATAo??????????L>?????????????????????????????DATA@oO????C?._ra(o??????DATA0(oM?>ףp?@?u=?BRoSoXoBRClone001?o??????????L>?????????????????????????????# Kfff?=???333???>!>???DATAo??????????L>?????????????????????????????DATA@oO????C?~6=~.=xo??????DATA0xoM?>k?@? ף=?BRoSHooBRCrease001?8o??????????L>?????????????????????????????# Kfff?=???>??>!>?>>>>?DATA`o??????????L>?????????????????????????????DATA@8oO????C?a2p? o??????DATA0oM?>?@? #=?BRHoSooBRDarken06?o??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAo??????????L>?????????????????????????????DATA@oO????C?~6=~.=o??????DATA0oM?>k?@? ף=?BRoSoHoBRDraw.001?o??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATAo??????????L>?????????????????????????????DATA@oO????C?._raho??????DATA0hoM?>ףp?@?u=?BRoS8poBRFill/Deepen001?(o??????????L>?????????????????????????????# Kfff?=???? ??>!>??>>??DATAPo??????????L>?????????????????????????????DATA@(oO????C?._rao??????DATA0oM?>ףp?@?u=?BR8pSpoBRFlatten/Contrast001?xp??????????L>?????????????????????????????# Kfff?=??????>!>??>>??DATAp??????????L>?????????????????????????????DATA@xpO????C?._rap??????DATA0pM?>ףp?@?u=?BRpS p8pBRGrab001?p??????????L>?????????????????????????????K Kfff?=???L>??>!>>?>DATAp??????????L>?????????????????????????????DATA@pO????C?._raX p??????DATA0X pM?>ףp?@?u=?BR pS(ppBRInflate/Deflate001?p??????????L>?????????????????????????????# Kfff?=??????>!>@?@?@?>>>DATA@ p??????????L>?????????????????????????????DATA@pO????C?._rap??????DATA0pM?>ףp?@?u=?BR(pSxp pBRLayer001?hp??????????L>?????????????????????????????# Kfff?=??????>!>?>>DATAp??????????L>?????????????????????????????DATA@hpO????C?._rap??????DATA0pM?>ףp?@?u=?BRxpSp(pBRLighten5?p??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAp??????????L>?????????????????????????????DATA@pO????C?~6=~.=Hp??????DATA0HpM?>k?@? ף=?BRpS pxpBRMixh?p??????????L>????????????????????????????? # Kfff?=???333???>!>???DATA0p??????????L>?????????????????????????????DATA@pO????C?~6=~.=p??????DATA0pM?>k?@? ף=?BR pSh%ppBRMultiply?X#p??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA p??????????L>?????????????????????????????DATA@X#pO????C?~6=~.=$p??????DATA0$pM?>k?@? ף=?BRh%pS*p pBRNudge001?(p??????????L>?????????????????????????????# Kfff?=???? ??>!>>?>DATA%p??????????L>?????????????????????????????DATA@(pO????C?._ra8*p??????DATA08*pM?>ףp?@?u=?BR*pS0ph%pBRPinch/Magnify001?-p??????????L>?????????????????????????????# Kfff?=??????>!>@?@?@?>>>DATA +p??????????L>?????????????????????????????DATA@-pO????C?._ra/p??????DATA0/pM?>ףp?@?u=?BR0pSX5p*pBRPolish001?H3p??????????L>?????????????????????????????# Kfff?=???????>!>??>>??DATAp0p??????????L>?????????????????????????????DATA@H3pO????C?._ra4p??????DATA04pM?>ףp?@?u=?BRX5pS:p0pBRScrape/Peaks001?8p??????????L>?????????????????????????????# Kfff?=???? ??>!>??>>??DATA5p??????????L>?????????????????????????????DATA@8pO????C?._ra(:p??????DATA0(:pM?>ףp?@?u=?BR:pS?pX5pBRSculptDraw?=p??????????L>?????????????????????????????# Kfff?=??????>!wN??>>>>?DATA;p??????????L>?????????????????????????????DATA@=pO????C?._rax?p??????DATA0x?pM?>ףp?@?u=?BR?pSHEp:pBRSmear001?8Cp??????????L>?????????????????????????????# Kfff?=???L>??>!>???DATA`@p??????????L>?????????????????????????????DATA@8CpO????C?~6=~.=Dp??????DATA0DpM?>k?@? ף=?BRHEpSJp?pBRSmooth001?Hp??????????L>?????????????????????????????#Kfff?=??????>!>@?@?@?DATAEp??????????L>?????????????????????????????DATA@HpO????C?._raJp??????DATA0JpM?>ףp?@?u=?BRJpSOpHEpBRSnake Hook001?Mp??????????L>?????????????????????????????K Kfff?=???? ??>!>>?>DATAKp??????????L>?????????????????????????????DATA@MpO????C?._rahOp??????DATA0hOpM?>ףp?@?u=?BROpS8UpJpBRSoften01?(Sp??????????L>?????????????????????????????# Kfff?=???L>??>!>???DATAPPp??????????L>?????????????????????????????DATA@(SpO????C?~6=~.=Tp??????DATA0TpM?>k?@? ף=?BR8UpSZpOpBRSubtract?xXp??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAUp??????????L>?????????????????????????????DATA@xXpO????C?~6=~.=Zp??????DATA0ZpM?>k?@? ף=?BRZpS_p8UpBRTexDraw?]p??????????L>?????????????????????????????# Kfff?=???333???>!>???>>?DATAZp??????????L>?????????????????????????????DATA@]pO????C?._raX_p??????DATA0X_pM?>ףp?@?u=?BR_pS(epZpBRThumb001?cp??????????L>?????????????????????????????K Kfff?=???? ??>!>>?>DATA@`p??????????L>?????????????????????????????DATA@cpO????C?._radp??????DATA0dpM?>ףp?@?u=?BR(epS_pBRTwist001?hhp??????????L>?????????????????????????????K Kfff?=??????>!>>?>DATAep??????????L>?????????????????????????????DATA@hhpO????C?._raip??????DATA0ipM?>ףp?@?u=?DNA1d8/SDNANAME *next*prev*data*first*lastxyxminxmaxyminymax*pointergroupvalval2typesubtypeflagname[32]saveddatalentotallen*newid*libname[24]usicon_id*propertiesid*idblock*filedataname[240]filepath[240]totpad*parentw[2]h[2]changed[2]changed_timestamp[2]*rect[2]*obblocktypeadrcodename[128]*bp*beztmaxrcttotrctvartypetotvertipoextraprtbitmaskslide_minslide_maxcurval*drivercurvecurshowkeymuteipoposrelativetotelempad2*weightsvgroup[32]sliderminslidermax*adt*refkeyelemstr[32]elemsizeblock*ipo*fromtotkeyslurph*line*formatblenlinenostartendpad1flagscolor[4]pad[4]*namenlineslines*curl*sellcurcselcmarkers*undo_bufundo_posundo_len*compiledmtimesizeseekdtxpassepartalphaclipstaclipendlensortho_scaledrawsizeshiftxshiftyYF_dofdist*dof_ob*sceneframenrframesoffsetsfrafie_imacyclokmulti_indexlayerpassibufs*gputexture*anim*rr*renders[8]render_slotlast_render_slotsourcelastframetpageflagtotbindxrepyreptwstatwendbindcode*repbind*packedfile*previewlastupdatelastusedanimspeedgen_xgen_ygen_typeaspxaspytexcomaptomaptonegblendtype*object*texuvname[32]projxprojyprojzmappingofs[3]size[3]rottexflagcolormodelpmaptopmaptonegnormapspacewhich_outputbrush_map_modepad[7]rgbkdef_varcolfacvarfacnorfacdispfacwarpfaccolspecfacmirrfacalphafacdifffacspecfacemitfachardfacraymirrfactranslfacambfaccolemitfaccolreflfaccoltransfacdensfacscatterfacreflfactimefaclengthfacclumpfacdampfackinkfacroughfacpadensfacgravityfaclifefacsizefacivelfacfieldfacshadowfaczenupfaczendownfacblendfacname[160]*handle*pname*stnamesstypesvars*varstr*result*cfradata[32](*doit)()(*instance_init)()(*callback)()versionaipotype*ima*cube[6]imat[4][4]obimat[3][3]stypeviewscalenotlaycuberesdepthrecalclastsizefalloff_typefalloff_softnessradiuscolor_sourcetotpointspdpadpsyspsys_cache_spaceob_cache_space*point_tree*point_datanoise_sizenoise_depthnoise_influencenoise_basispdpad3[3]noise_facspeed_scalefalloff_speed_scalepdpad2*coba*falloff_curveresol[3]interp_typefile_formatextendsmoked_typeint_multiplierstill_framesource_path[240]*datasetcachedframenoisesizeturbulbrightcontrastsaturationrfacgfacbfacfiltersizemg_Hmg_lacunaritymg_octavesmg_offsetmg_gaindist_amountns_outscalevn_w1vn_w2vn_w3vn_w4vn_mexpvn_distmvn_coltypenoisedepthnoisetypenoisebasisnoisebasis2imaflagcropxmincropymincropxmaxcropymaxtexfilterafmaxxrepeatyrepeatcheckerdistnablaiuser*nodetree*plugin*env*pd*vduse_nodesloc[3]rot[3]mat[4][4]min[3]max[3]modetotexshdwrshdwgshdwbshdwpadenergydistspotsizespotblendhaintatt1att2*curfalloffshadspotsizebiassoftcompressthreshpad5[3]bufsizesampbuffersfiltertypebufflagbuftyperay_sampray_sampyray_sampzray_samp_typearea_shapearea_sizearea_sizeyarea_sizezadapt_threshray_samp_methodtexactshadhalostepsun_effect_typeskyblendtypehorizon_brightnessspreadsun_brightnesssun_sizebackscattered_lightsun_intensityatm_turbidityatm_inscattering_factoratm_extinction_factoratm_distance_factorskyblendfacsky_exposuresky_colorspacepad4[6]*mtex[18]pr_texturepad6[6]densityemissionscatteringreflectionemission_col[3]transmission_col[3]reflection_col[3]density_scaledepth_cutoffasymmetrystepsize_typeshadeflagshade_typeprecache_resolutionstepsizems_diffms_intensityms_spreadmaterial_typespecrspecgspecbmirrmirgmirbambrambbambgambemitangspectraray_mirroralpharefspeczoffsaddtranslucencyvolfresnel_mirfresnel_mir_ifresnel_trafresnel_tra_ifiltertx_limittx_falloffray_depthray_depth_traharseed1seed2gloss_mirgloss_trasamp_gloss_mirsamp_gloss_traadapt_thresh_miradapt_thresh_traaniso_gloss_mirdist_mirfadeto_mirshade_flagmode_lflarecstarclinecringchasizeflaresizesubsizeflarebooststrand_stastrand_endstrand_easestrand_surfnorstrand_minstrand_widthfadestrand_uvname[32]sbiaslbiasshad_alphaseptexrgbselpr_typepr_backpr_lampml_flagdiff_shaderspec_shaderroughnessrefracparam[4]rmsdarkness*ramp_col*ramp_specrampin_colrampin_specrampblend_colrampblend_specramp_showpad3rampfac_colrampfac_spec*groupfrictionfhreflectfhdistxyfrictdynamodesss_radius[3]sss_col[3]sss_errorsss_scalesss_iorsss_colfacsss_texfacsss_frontsss_backsss_flagsss_presetmapto_texturedshadowonly_flaggpumaterialname[256]*bbi1j1k1i2j2k2selcol1selcol2zquat[4]expxexpyexpzradrad2s*mat*imatelemsdisp*editelems**matflag2totcolwiresizerendersizethresh*lastelemvec[3][3]alfaweighth1h2f1f2f3hidevec[4]mat_nrpntsupntsvresoluresolvorderuordervflaguflagv*knotsu*knotsvtilt_interpradius_interpcharidxkernwhnurbs*keyindexshapenrnurb*editnurb*bevobj*taperobj*textoncurve*path*keybevdrawflagtwist_modetwist_smoothsmallcaps_scalepathlenbevresolwidthext1ext2resolu_renresolv_renactnu*lastselspacemodespacinglinedistshearfsizewordspaceulposulheightxofyoflinewidth*str*selboxes*editfontfamily[24]*vfont*vfontb*vfonti*vfontbisepcharctimetotboxactbox*tbselstartselend*strinfocurinfo*mface*mtface*tface*mvert*medge*dvert*mcol*msticky*texcomesh*mselect*edit_meshvdataedatafdatatotedgetotfacetotselectact_facesmoothreshsubdivsubdivrsubsurftypeeditflag*mr*pv*tpageuv[4][2]col[4]transptileunwrapv1v2v3v4edcodecreasebweightdef_nr*dwtotweightco[3]no[3]uv[2]co[2]indexfis[256]totdisp(*disps)()v[4]midpad[2]v[2]*faces*colfaces*edges*vertslevelslevel_countcurrentnewlvledgelvlpinlvlrenderlvluse_col*edge_flags*edge_creases*vert_map*edge_map*old_faces*old_edgesstackindex*errormodifier*texture*map_objectuvlayer_name[32]uvlayer_tmptexmappingsubdivTyperenderLevels*emCache*mCachedefaxispad[6]lengthrandomizeseed*ob_arm*start_cap*end_cap*curve_ob*offset_oboffset[3]scale[3]merge_distfit_typeoffset_typecountaxistolerance*mirror_obsplit_anglevalueresval_flagslim_flagse_flagsbevel_angledefgrp_name[32]*domain*flow*colltimepad10strengthdirectionmidlevel*projectors[10]*imagenum_projectorsaspectxaspectyscalexscaleypercentfaceCountfacrepeat*objectcenterstartxstartyheightnarrowspeeddampfallofftimeoffslifetimedeformflagmulti*prevCossubtarget[32]parentinv[4][4]cent[3]*indexartotindexforce*clothObject*sim_parms*coll_parms*point_cacheptcaches*x*xnew*xold*current_xnew*current_x*current_v*mfacesnumvertsnumfacestime_xtime_xnew*bvhtree*v*dmcfraoperationvertextotinfluencegridsize*bindinfluences*bindoffsets*bindcagecostotcagevert*dyngrid*dyninfluences*dynverts*pad2dyngridsizedyncellmin[3]dyncellwidthbindmat[4][4]*bindweights*bindcos(*bindfunc)()*psystotdmverttotdmedgetotdmfacepositionrandom_position*facepavgroupprotectlvlsculptlvltotlvlsimple*fss*target*auxTargetvgroup_name[32]keepDistshrinkTypeshrinkOptsprojAxissubsurfLevels*originfactorlimit[2]originOptsoffset_faccrease_innercrease_outercrease_rimmat_ofsmat_ofs_rim*ob_axisstepsrender_stepsiterscrew_ofsangle*object_from*object_tofalloff_radius*lattpntswopntsuopntsvopntswtypeutypevtypewfufvfwdudvdw*def*latticedatalatmat[4][4]*editlattvec[8][3]*sculptpartypepar1par2par3parsubstr[32]*track*proxy*proxy_group*proxy_from*action*poselib*pose*gpdavs*mpathconstraintChannelseffectdefbasemodifiersrestore_mode*matbitsactcoldloc[3]orig[3]dsize[3]drot[3]dquat[4]rotAxis[3]drotAxis[3]rotAngledrotAngleobmat[4][4]constinv[4][4]imat_ren[4][4]laycolbitstransflagprotectflagtrackflagupflagnlaflagipoflagipowinscaflagscavisflagboundtypedupondupoffdupstadupendsfmassdampinginertiaformfactorrdampingmarginmax_velmin_velm_contactProcessingThresholdrotmodedtempty_drawtypepad1[3]empty_drawsizedupfacescapropsensorscontrollersactuatorsbbsize[3]actdefgameflaggameflag2*bsoftsoftflaganisotropicFriction[3]constraintsnlastripshooksparticlesystem*soft*dup_groupfluidsimFlagrestrictflagshapeflagrecalcobody_type*fluidsimSettings*derivedDeform*derivedFinallastDataMaskcustomdata_maskstateinit_stategpulamppc_ids*duplilistima_ofs[2]pad3[8]curindexactiveoriglayno_drawanimatedomat[4][4]orco[3]deflectforcefieldshapetex_modekinkkink_axiszdirf_strengthf_dampf_flowf_sizef_powermaxdistmindistf_power_rmaxradminradpdef_damppdef_rdamppdef_permpdef_frictpdef_rfrictpdef_sticknessabsorptionpdef_sbdamppdef_sbiftpdef_sboftclump_facclump_powkink_freqkink_shapekink_ampfree_endtex_nabla*rngf_noiseweight[13]global_gravityrt[3]totdataframetotpointdata_types*data[8]*cur[8]extradatastepsimframestartframeendframeeditframelast_exactcompressionname[64]prev_name[64]info[64]path[240]*cached_framesmem_cache*edit(*free_edit)()linStiffangStiffvolumeviterationspiterationsditerationsciterationskSRHR_CLkSKHR_CLkSSHR_CLkSR_SPLT_CLkSK_SPLT_CLkSS_SPLT_CLkVCFkDPkDGkLFkPRkVCkDFkMTkCHRkKHRkSHRkAHRcollisionflagsnumclusteriterationsweldingtotspring*bpoint*bspringmsg_lockmsg_valuenodemassnamedVG_Mass[32]gravmediafrictrklimitphysics_speedgoalspringgoalfrictmingoalmaxgoaldefgoalvertgroupnamedVG_Softgoal[32]fuzzynessinspringinfrictnamedVG_Spring_K[32]efraintervallocalsolverflags**keystotpointkeysecondspringcolballballdampballstiffsbc_modeaeroedgeminloopsmaxloopschokesolver_IDplasticspringpreload*scratchshearstiffinpush*pointcache*effector_weightslcom[3]lrot[3][3]lscale[3][3]pad4[4]vel[3]*fmdshow_advancedoptionsresolutionxyzpreviewresxyzrealsizeguiDisplayModerenderDisplayModeviscosityValueviscosityModeviscosityExponentgrav[3]animStartanimEndbakeStartbakeEndgstarmaxRefineiniVelxiniVelyiniVelz*orgMesh*meshBBsurfdataPath[240]bbStart[3]bbSize[3]typeFlagsdomainNovecgenvolumeInitTypepartSlipValuegenerateTracersgenerateParticlessurfaceSmoothingsurfaceSubdivsparticleInfSizeparticleInfAlphafarFieldSize*meshVelocitiescpsTimeStartcpsTimeEndcpsQualityattractforceStrengthattractforceRadiusvelocityforceStrengthvelocityforceRadiuslastgoodframemistypehorrhorghorbzenrzengzenbfastcolexposureexprangelinfaclogfacgravityactivityBoxRadiusskytypeocclusionResphysicsEngineticratemaxlogicstepphysubstepmaxphystepmisimiststamistdistmisthistarrstargstarbstarkstarsizestarmindiststardiststarcolnoisedofstadofenddofmindofmaxaodistaodistfacaoenergyaobiasaomodeaosampaomixaocolorao_adapt_threshao_adapt_speed_facao_approx_errorao_approx_correctionao_indirect_energyao_env_energyao_pad2ao_indirect_bouncesao_padao_samp_methodao_gather_methodao_approx_passes*aosphere*aotablespad[3]selcolsxsy*lpFormat*lpParmscbFormatcbParmsfccTypefccHandlerdwKeyFrameEverydwQualitydwBytesPerSeconddwFlagsdwInterleaveEveryavicodecname[128]*cdParms*padcdSizeqtcodecname[128]codecTypecodecSpatialQualitycodeccodecFlagscolorDepthcodecTemporalQualityminSpatialQualityminTemporalQualitykeyFrameRatebitRateaudiocodecTypeaudioSampleRateaudioBitDepthaudioChannelsaudioCodecFlagsaudioBitRateaudio_codecvideo_bitrateaudio_bitrateaudio_mixrateaudio_volumegop_sizerc_min_raterc_max_raterc_buffer_sizemux_packet_sizemux_ratemixratemainspeed_of_sounddoppler_factordistance_model*mat_override*light_overridelay_zmasklayflagpassflagpass_xor*avicodecdata*qtcodecdataqtcodecsettingsffcodecdatasubframepsfrapefraimagesframaptothreadsframelenblurfacedgeRedgeGedgeBfullscreenxplayyplayfreqplayattribframe_stepstereomodedimensionspresetmaximsizexschyschxpartsypartsplanesimtypesubimtypequalitydisplaymodescemoderaytrace_optionsraytrace_structurerendererocrespad4alphamodeosafrs_secedgeintsafetyborderdisprectlayersactlaymblur_samplesxaspyaspfrs_sec_basegausscolor_mgt_flagpostgammaposthuepostsatdither_intensitybake_osabake_filterbake_modebake_flagbake_normal_spacebake_quad_splitbake_maxdistbake_biasdistbake_padpic[240]stampstamp_font_idstamp_udata[160]fg_stamp[4]bg_stamp[4]seq_prev_typeseq_rend_typeseq_flagpad5[5]simplify_flagsimplify_subsurfsimplify_shadowsamplessimplify_particlessimplify_aossscineonwhitecineonblackcineongammajp2_presetjp2_depthrpad3domeresdomemodedomeangledometiltdomeresbuf*dometextengine[32]particle_percsubsurf_maxshadbufsample_maxao_errortiltresbuf*warptextcol[3]matmodeframingrt1rt2domestereoflageyeseparation*camera*brush*paint_cursorpaint_cursor_col[4]paintseam_bleednormal_anglescreen_grab_size[2]*paintcursorinverttotrekeytotaddkeybrushtypebrush[7]emitterdistselectmodeedittypedraw_stepfade_framesname[36]mat[3][3]radial_symm[3]last_xlast_ylast_angledraw_anchoredanchored_sizeanchored_location[3]anchored_initial_mouse[2]draw_pressurepressure_valuespecial_rotation*vpaint_prev*wpaint_prev*vpaint*wpaintvgroup_weightcornertypeeditbutflagjointrilimitdegrturnextr_offsdoublimitnormalsizeautomergesegmentsringsverticesunwrapperuvcalc_radiusuvcalc_cubesizeuvcalc_marginuvcalc_mapdiruvcalc_mapalignuvcalc_flaguv_flaguv_selectmodeuv_padgpencil_flagsautoik_chainlenimapaintparticleproportional_sizeselect_threshclean_threshautokey_modeautokey_flagretopo_moderetopo_paint_toolline_divellipse_divretopo_hotspotmultires_subdiv_typeskgen_resolutionskgen_threshold_internalskgen_threshold_externalskgen_length_ratioskgen_length_limitskgen_angle_limitskgen_correlation_limitskgen_symmetry_limitskgen_retarget_angle_weightskgen_retarget_length_weightskgen_retarget_distance_weightskgen_optionsskgen_postproskgen_postpro_passesskgen_subdivisions[3]skgen_multi_level*skgen_templatebone_sketchingbone_sketching_convertskgen_subdivision_numberskgen_retarget_optionsskgen_retarget_rollskgen_side_string[8]skgen_num_string[8]edge_modeedge_mode_live_unwrapsnap_modesnap_flagsnap_targetproportionalprop_modeproportional_objectsauto_normalizesculpt_paint_settingssculpt_paint_unified_sizesculpt_paint_unified_unprojected_radiussculpt_paint_unified_alphatotobjtotlamptotobjseltotcurvetotmeshtotarmaturescale_lengthsystemsystem_rotationgravity[3]quick_cache_step*world*setbase*basact*obeditcursor[3]twcent[3]twmin[3]twmax[3]layactlay_updatedcustomdata_mask_modal*ed*toolsettings*statsaudiotransform_spaces*sound_scene*sound_scene_handle*sound_scrub_handle*fps_info*theDagdagisvaliddagflagspad6pad5active_keyingsetkeyingsetsgmunitphysics_settingsblendviewwinmat[4][4]viewmat[4][4]viewinv[4][4]persmat[4][4]persinv[4][4]viewmatob[4][4]persmatob[4][4]twmat[4][4]viewquat[4]zfaccamdxcamdypixsizecamzoomtwdrawflagis_persprflagviewlockperspclip[6][4]clip_local[6][4]*clipbb*localvd*ri*depths*sms*smooth_timerlviewquat[4]lpersplviewgridviewtwangle[3]padfregionbasespacetypeblockscaleblockhandler[8]lay_used*ob_centrebgpicbase*bgpicob_centre_bone[32]drawtypeob_centre_cursorscenelockaroundgridnearfarmodeselectgridlinesgridsubdivgridflagtwtypetwmodetwflagpad2[2]afterdraw_transpafterdraw_xrayafterdraw_xraytranspzbufxrayndofmodendoffilter*properties_storageverthormaskmin[2]max[2]minzoommaxzoomscrollscroll_uikeeptotkeepzoomkeepofsalignwinxwinyoldwinxoldwiny*tab_offsettab_numtab_currpt_maskv2d*adsghostCurvesautosnapcursorValmainbmainbomainbuserre_alignpreviewtexture_contextpathflagdataicon*pinidrender_sizechanshownzebrazoomtitle[32]dir[240]file[80]renamefile[80]renameedit[80]filter_glob[64]active_filesel_firstsel_lastsortdisplayf_fpfp_str[8]scroll_offset*params*files*folders_prev*folders_next*op*smoothscroll_timer*layoutrecentnrbookmarknrsystemnrtree*treestoresearch_string[32]search_tseoutlinevisstoreflagsearch_flags*cumapscopessample_line_histcursor[2]centxcentycurtileimtypenrlockpindt_uvstickydt_uvstretch*texttopviewlinesmenunrlheightcwidthlinenrs_totleftshowlinenrstabnumbershowsyntaxline_hlightoverwritelive_editpix_per_linetxtscrolltxtbarwordwrapdopluginsfindstr[256]replacestr[256]margin_column*drawcache*py_draw*py_event*py_button*py_browsercallback*py_globaldictlastspacescriptname[256]scriptarg[256]*script*but_refs*arraycachescache_displayredraws*idaspect*curfontmxmy*edittreetreetypetexfromlinkdragtitle[24]menunumtilesxnumtilesyselstateviewrectbookmarkrectscrollposscrollheightscrollarearetvalactive_bookmarkprv_wprv_h(*returnfunc)()(*returnfunc_event)()(*returnfunc_args)()*arg1*arg2*menup*pupmenu*imglen_alloccursorscrollbackhistoryprompt[256]language[32]sel_startsel_endfilter[64]*area*soundsndnrfilename[256]blf_iduifont_idr_to_lpointskerningitalicboldshadowshadxshadyshadowalphashadowcolorpaneltitlegrouplabelwidgetlabelwidgetpanelzoomminlabelcharsminwidgetcharscolumnspacetemplatespaceboxspacebuttonspacexbuttonspaceypanelspacepanelouterpad[1]outline[4]inner[4]inner_sel[4]item[4]text[4]text_sel[4]shadedshadetopshadedownalpha_checkinner_anim[4]inner_anim_sel[4]inner_key[4]inner_key_sel[4]inner_driven[4]inner_driven_sel[4]wcol_regularwcol_toolwcol_textwcol_radiowcol_optionwcol_togglewcol_numwcol_numsliderwcol_menuwcol_pulldownwcol_menu_backwcol_menu_itemwcol_boxwcol_scrollwcol_progresswcol_list_itemwcol_stateiconfile[80]back[4]title[4]text_hi[4]header[4]header_title[4]header_text[4]header_text_hi[4]button[4]button_title[4]button_text[4]button_text_hi[4]list[4]list_title[4]list_text[4]list_text_hi[4]panel[4]panel_title[4]panel_text[4]panel_text_hi[4]shade1[4]shade2[4]hilite[4]grid[4]wire[4]select[4]lamp[4]active[4]group[4]group_active[4]transform[4]vertex[4]vertex_select[4]edge[4]edge_select[4]edge_seam[4]edge_sharp[4]edge_facesel[4]edge_crease[4]face[4]face_select[4]face_dot[4]extra_edge_len[4]extra_face_angle[4]extra_face_area[4]pad3[4]normal[4]vertex_normal[4]bone_solid[4]bone_pose[4]strip[4]strip_select[4]cframe[4]nurb_uline[4]nurb_vline[4]act_spline[4]nurb_sel_uline[4]nurb_sel_vline[4]lastsel_point[4]handle_free[4]handle_auto[4]handle_vect[4]handle_align[4]handle_sel_free[4]handle_sel_auto[4]handle_sel_vect[4]handle_sel_align[4]ds_channel[4]ds_subchannel[4]console_output[4]console_input[4]console_info[4]console_error[4]console_cursor[4]vertex_sizeoutline_widthfacedot_sizebpadsyntaxl[4]syntaxn[4]syntaxb[4]syntaxv[4]syntaxc[4]movie[4]image[4]scene[4]audio[4]effect[4]plugin[4]transition[4]meta[4]editmesh_active[4]handle_vertex[4]handle_vertex_select[4]handle_vertex_sizehpad[7]preview_back[4]solid[4]tuitbutstv3dtfiletipotinfotsndtacttnlatseqtimatimaseltexttoopsttimetnodetlogictuserpreftconsoletarm[20]active_theme_areamodule[64]spec[4]dupflagsavetimetempdir[160]fontdir[160]renderdir[240]textudir[160]plugtexdir[160]plugseqdir[160]pythondir[160]sounddir[160]image_editor[240]anim_player[240]anim_player_presetv2d_min_gridsizetimecode_styleversionsdbl_click_timegameflagswheellinescrolluiflaglanguageuserprefviewzoommixbufsizeaudiodeviceaudiorateaudioformataudiochannelsdpiencodingtransoptsmenuthreshold1menuthreshold2themesuifontsuistyleskeymapsaddonskeyconfigstr[64]undostepsundomemorygp_manhattendistgp_euclideandistgp_erasergp_settingstb_leftmousetb_rightmouselight[3]tw_hotspottw_flagtw_handlesizetw_sizetextimeouttexcollectratewmdrawmethoddragthresholdmemcachelimitprefetchframesframeserverportpad_rot_angleobcenter_diarvisizervibrightrecent_filessmooth_viewtxglreslimitndof_panndof_rotatecurssizecolor_picker_typeipo_newkeyhandles_newscrcastfpsscrcastwaitwidget_unitanisotropic_filterversemaster[160]verseuser[160]glalphacliptext_renderpad9coba_weightsculpt_paint_overlay_col[3]author[80]vertbaseedgebaseareabase*newsceneredraws_flagfulltempwiniddo_drawdo_refreshdo_draw_gesturedo_draw_paintcursordo_draw_dragswapmainwinsubwinactive*animtimer*contexthandler[8]*newvvec*v1*v2*typepanelname[64]tabname[64]drawname[64]ofsxofsysizexsizeylabelofsruntime_flagcontrolsnapsortorder*paneltab*activedatalist_scrolllist_sizelist_last_lenlist_grip_sizelist_search[64]*v3*v4*fullbutspacetypeheadertypespacedatahandlersactionzoneswinrctdrawrctswinidregiontypealignmentdo_draw_overlayuiblockspanels*headerstr*regiondatasubvstr[4]subversionpadsminversionminsubversionwinpos*curscreen*curscenefileflagsglobalfrevisionfilename[240]name[80]orig_widthorig_heightbottomrightxofsyofslift[3]gamma[3]gain[3]dir[160]donestartstillendstill*stripdata*crop*transform*color_balance*instance_private_data**current_private_data*tmpstartofsendofsmachinestartdispenddispsatmulhandsizeanim_preseek*strip*scene_cameraeffect_faderspeed_fader*seq1*seq2*seq3seqbase*scene_soundlevelpanscenenrmulticam_sourcestrobe*effectdataanim_startofsanim_endofsblend_modeblend_opacity*oldbasep*parseq*seqbasepmetastack*act_seqact_imagedir[256]act_sounddir[256]over_ofsover_cfraover_flagover_borderedgeWidthforwardwipetypefMinifClampfBoostdDistdQualitybNoCompScalexIniScaleyIniScalexFinScaleyFinxInixFinyIniyFinrotInirotFininterpolationuniform_scale*frameMapglobalSpeedlastValidFramebuttypeuserjitstatotpartnormfacobfacrandfactexfacrandlifeforce[3]vectsizemaxlendefvec[3]mult[4]life[4]child[4]mat[4]texmapcurmultstaticstepomattimetexspeedtexflag2negvertgroup_vvgroupname[32]vgroupname_v[32]*keysminfacnrusedusedelem*poinresetdistlastval*makeyqualqual2targetName[32]toggleName[32]value[32]maxvalue[32]delaydurationmaterialName[32]damptimerpropname[32]matname[32]axisflagposechannel[32]constraint[32]*fromObjectsubject[32]body[32]otypepulsefreqtotlinks**linkstapjoyindexaxis_singleaxisfbuttonhathatfprecisionstr[128]*mynewinputstotslinks**slinksvalostate_mask*actframeProp[32]blendinpriorityend_resetstrideaxisstridelengthmin_gainmax_gainreference_distancemax_distancerolloff_factorcone_inner_anglecone_outer_anglecone_outer_gainpad3[2]pitchsound3Dpad6[1]*melinVelocity[3]angVelocity[3]localflagdyn_operationforceloc[3]forcerot[3]linearvelocity[3]angularvelocity[3]*referenceminmaxrotdampminloc[3]maxloc[3]minrot[3]maxrot[3]matprop[32]butstabutenddistributionint_arg_1int_arg_2float_arg_1float_arg_2toPropName[32]*toObjectbodyTypefilename[64]loadaniname[64]int_argfloat_arg*subtargetgo*newpackedfileattenuationdistance*cache*playback_handle*lamprengobjectdupli_ofs[3]*propchildbaserollhead[3]tail[3]bone_mat[3][3]arm_head[3]arm_tail[3]arm_mat[4][4]arm_rollxwidthzwidthease1ease2rad_headrad_tailbonebasechainbase*edbo*act_bone*act_edbone*sketchlayer_usedlayer_protectedghostepghostsizeghosttypepathsizeghostsfghostefpathsfpathefpathbcpathac*pointsstart_frameend_frameghost_sfghost_efghost_bcghost_acghost_typeghost_stepghost_flagpath_typepath_steppath_viewflagpath_bakeflagpath_sfpath_efpath_bcpath_acconstflagikflagselectflagagrp_index*bone*childiktree*custom*custom_txeul[3]chan_mat[4][4]pose_mat[4][4]pose_head[3]pose_tail[3]limitmin[3]limitmax[3]stiffness[3]ikstretchikrotweightiklinweightchanbase*chanhashproxy_layerstride_offset[3]cyclic_offset[3]agroupsactive_groupiksolver*ikdata*ikparamproxy_act_bone[32]numiternumstepminstepmaxstepsolverfeedbackmaxveldampmaxdampepschannelscustomColcscurvesgroupsactive_markeridroot*source*filter_grpsearchstr[64]filterflagadstimeslide*grpname[30]ownspacetarspaceenforceheadtaillin_errorrot_error*tarmatrix[4][4]spacerotOrdertarnumtargetsiterationsrootbonemax_rootbone*poletarpolesubtarget[32]poleangleorientweightgrabtarget[3]numpointschainlenxzScaleModereserved1reserved2minmaxflagstuckcache[3]lockflagfollowflagvolmodeplaneorglengthbulgepivXpivYpivZaxXaxYaxZminLimit[6]maxLimit[6]extraFzinvmat[4][4]fromtomap[3]expofrom_min[3]from_max[3]to_min[3]to_max[3]rotAxiszminzmaxpad[9]channel[32]no_rot_axisstride_axiscurmodactstartactendactoffsstridelenscaleblendoutstridechannel[32]offs_bone[32]hasinputhasoutputdatatypesockettype*new_socknslimitstack_type*stack_ptrstack_indexlocxlocyown_index*groupsockto_index*link*rectxsizeysize*new_nodelastyoutputs*storageminiwidthlabel[32]custom1custom2custom3custom4need_execexec*threaddatatotrbutrprvr*block*typeinfo*fromnode*tonode*fromsock*tosocknodeslinks*stack*threadstackinitstacksizecur_indexalltypes(*progress)()(*stats_draw)()(*test_break)()*tbh*prh*sdhcyclicmoviesamplesmaxspeedminspeedcurvedpercentxpercentybokehgammaimage_in_widthimage_in_heightcenter_xcenter_yspinwrapsigma_colorsigma_spacehuet1t2t3fstrengthfalphakey[4]algorithmchannelx1x2y1y2fac_x1fac_x2fac_y1fac_y2colname[32]bktyperotationgamcono_zbuffstopmaxblurbthresh*dict*nodeangle_ofscolmodmixthresholdfademcjitprojfitslope[3]power[3]lift_lgg[3]gamma_inv[3]limchanunspilllimscaleuspillruspillguspillbshortymintablemaxtableext_in[2]ext_out[2]*curve*table*premultablepresetchanged_timestampcurrcliprcm[4]black[3]white[3]bwmul[3]sample[3]x_resolutiondata_r[256]data_g[256]data_b[256]data_luma[256]sample_fullsample_linesaccuracywavefrm_modewavefrm_alphawavefrm_yfacwavefrm_heightvecscope_alphavecscope_heightminmax[3][2]hist*waveform_1*waveform_2*waveform_3*vecscopewaveform_totoffset[2]clonemtex*icon_imbuficon_filepath[240]normal_weightob_modejittersmooth_stroke_radiussmooth_stroke_factorratergb[3]sculpt_planeplane_offsetsculpt_toolvertexpaint_toolimagepaint_toolpad3[5]autosmooth_factorcrease_pinch_factorplane_trimtexture_sample_biastexture_overlay_alphaunprojected_radiusadd_col[3]sub_col[3]active_rndactive_cloneactive_mask*layerstotlayermaxlayertotsize*pool*externalrot[4]ave[3]*groundwander[3]rest_lengthparticle_index[2]delete_flagnumparentpa[4]w[4]fuv[4]foffsetrt[2]prev_state*hair*boiddietimenum_dmcachehair_indexalivespring_kplasticity_constantyield_ratioplasticity_balanceyield_balanceviscosity_omegaviscosity_betastiffness_kstiffness_knearrest_densitybuoyancyspring_frames*boids*fluiddistrphystypeavemodereacteventdrawdraw_asdraw_sizechildtyperen_assubframesdraw_colren_stephair_stepkeys_stepadapt_angleadapt_pixrotfromintegratorbb_alignbb_uv_splitbb_animbb_split_offsetbb_tiltbb_rand_tiltbb_offset[2]color_vec_maxsimplify_refsizesimplify_ratesimplify_transitionsimplify_viewporttimetweakjitfaceff_hairgrid_randgrid_reseffector_amountpartfactanfactanphasereactfacob_vel[3]avefacphasefacrandrotfacrandphasefacrandsizeacc[3]dragfacbrownfacrandlengthchild_nbrren_child_nbrparentschildsizechildrandsizechildradchildflatclumppowkink_flatkink_amp_clumprough1rough1_sizerough2rough2_sizerough2_thresrough_endrough_end_shapeclengthclength_thresparting_facparting_minparting_maxbranch_thresdraw_line[2]path_startpath_endtrail_countkeyed_loopsdupliweights*eff_group*dup_ob*bb_ob*pd2*part*particles**pathcache**childcachepathcachebufschildcachebufs*clmd*hair_in_dm*hair_out_dm*target_ob*latticetree_framebvhtree_framechild_seedtotunexisttotchildtotcachedtotchildcachetarget_psystotkeyedbakespacebb_uvname[3][32]vgroup[12]vg_negrt3*renderdata*effectors*fluid_springstot_fluidspringsalloc_fluidsprings*tree*pdd*frandCdisCvistructuralbendingmax_bendmax_structmax_shearavg_spring_lentimescaleeff_force_scaleeff_wind_scalesim_time_oldvelocity_smoothcollider_frictionstepsPerFrameprerollmaxspringlensolver_typevgroup_bendvgroup_massvgroup_structshapekey_restpresetsreset*collision_listepsilonself_frictionselfepsilonrepel_forcedistance_repelself_loop_countloop_countpressurethicknessstrokesframenum*actframegstepinfo[128]sbuffer_sizesbuffer_sflag*sbufferlistprintlevelstorelevel*reporttimer*windrawable*winactivewindowsinitializedfile_savedop_undo_depthoperatorsqueuereportsjobspaintcursorsdragskeyconfigs*defaultconftimers*autosavetimer*ghostwingrabcursor*screen*newscreenscreenname[32]posxposywindowstatemonitorlastcursormodalcursoraddmousemove*eventstate*curswin*tweakdrawmethoddrawfail*drawdatamodalhandlerssubwindowsgestureidname[64]propvalueshiftctrlaltoskeykeymodifiermaptype*ptritemsspaceidregionidkmi_id(*poll)()*modal_itemsbasename[64]actkeymap*customdata*py_instance*reportsmacro*opm*edatainfluence*coefficientsarraysizepoly_orderamplitudephase_multiplierphase_offsetvalue_offsetmidvalbefore_modeafter_modebefore_cyclesafter_cyclesrectphasemodificationstep_size*rna_pathpchan_name[32]transChanidtypetargets[8]num_targetsvariablesexpression[256]*expr_compvec[2]*fptarray_indexcolor_modecolor[3]from[128]to[128]mappingsstrips*remapfcurvesstrip_timeblendmodeextendmodegroup[64]groupmodekeyingflagpathstypeinfo[64]active_path*tmpactnla_tracks*actstripdriversoverridesact_blendmodeact_extendmodeact_influenceruleoptionsfear_factorsignal_idlook_aheadoloc[3]queue_sizewanderflee_distancehealthstate_idrulesconditionsactionsruleset_typerule_fuzzinesslast_state_idlanding_smoothnessbankingaggressionair_min_speedair_max_speedair_max_accair_max_aveair_personal_spaceland_jump_speedland_max_speedland_max_accland_max_aveland_personal_spaceland_stick_forcestates*smd*fluid_group*coll_group*wt*tex_wt*tex_shadow*shadowp0[3]p1[3]dxomegatempAmbbetares[3]amplifymaxresviewsettingsnoisediss_percentdiss_speedres_wt[3]dx_wtv3dnumcache_compcache_high_comp*point_cache[2]ptcaches[2]border_collisionstime_scalevorticityvelocity[2]vel_multivgrp_heat_scale[2]vgroup_flowvgroup_densityvgroup_heat*points_old*velmat_old[4][4]TYPEcharucharshortushortintlongulongfloatdoublevoidLinkLinkDataListBasevec2svec2frctirctfIDPropertyDataIDPropertyIDLibraryFileDataPreviewImageIpoDriverObjectIpoCurveBPointBezTripleIpoKeyBlockKeyAnimDataTextLineTextMarkerTextPackedFileCameraImageUserSceneImageGPUTextureanimRenderResultMTexTexPluginTexCBDataColorBandEnvMapImBufPointDensityCurveMappingVoxelDatabNodeTreeTexMappingLampVolumeSettingsMaterialGroupVFontVFontDataMetaElemBoundBoxMetaBallNurbCharInfoTextBoxEditNurbGHashCurvePathSelBoxEditFontMeshMFaceMTFaceTFaceMVertMEdgeMDeformVertMColMStickyMSelectEditMeshCustomDataMultiresPartialVisibilityMDeformWeightMTexPolyMLoopUVMLoopColMFloatPropertyMIntPropertyMStringPropertyOrigSpaceFaceMDispsMultiresColMultiresColFaceMultiresFaceMultiresEdgeMultiresLevelModifierDataMappingInfoModifierDataSubsurfModifierDataLatticeModifierDataCurveModifierDataBuildModifierDataMaskModifierDataArrayModifierDataMirrorModifierDataEdgeSplitModifierDataBevelModifierDataBMeshModifierDataSmokeModifierDataSmokeDomainSettingsSmokeFlowSettingsSmokeCollSettingsDisplaceModifierDataUVProjectModifierDataDecimateModifierDataSmoothModifierDataCastModifierDataWaveModifierDataArmatureModifierDataHookModifierDataSoftbodyModifierDataClothModifierDataClothClothSimSettingsClothCollSettingsPointCacheCollisionModifierDataBVHTreeSurfaceModifierDataDerivedMeshBVHTreeFromMeshBooleanModifierDataMDefInfluenceMDefCellMeshDeformModifierDataParticleSystemModifierDataParticleSystemParticleInstanceModifierDataExplodeModifierDataMultiresModifierDataFluidsimModifierDataFluidsimSettingsShrinkwrapModifierDataSimpleDeformModifierDataShapeKeyModifierDataSolidifyModifierDataScrewModifierDataWarpModifierDataEditLattLatticebDeformGroupSculptSessionbActionbPosebGPdatabAnimVizSettingsbMotionPathBulletSoftBodyPartDeflectSoftBodyObHookDupliObjectRNGEffectorWeightsPTCacheExtraPTCacheMemPTCacheEditSBVertexBodyPointBodySpringSBScratchFluidVertexVelocityWorldBaseAviCodecDataQuicktimeCodecDataQuicktimeCodecSettingsFFMpegCodecDataAudioDataSceneRenderLayerRenderDataRenderProfileGameDomeGameFramingGameDataTimeMarkerPaintBrushImagePaintSettingsParticleBrushDataParticleEditSettingsTransformOrientationSculptVPaintToolSettingsbStatsUnitSettingsPhysicsSettingsEditingSceneStatsDagForestBGpicRegionView3DRenderInfoViewDepthsSmoothViewStorewmTimerView3DSpaceLinkView2DSpaceInfoSpaceIpobDopeSheetSpaceButsSpaceSeqFileSelectParamsSpaceFileFileListwmOperatorFileLayoutSpaceOopsTreeStoreTreeStoreElemSpaceImageScopesHistogramSpaceNlaSpaceTextScriptSpaceScriptSpaceTimeCacheSpaceTimeSpaceNodeSpaceLogicSpaceImaSelConsoleLineSpaceConsoleSpaceUserPrefSpaceSoundScrAreabSounduiFontuiFontStyleuiStyleuiWidgetColorsuiWidgetStateColorsThemeUIThemeSpaceThemeWireColorbThemebAddonSolidLightUserDefbScreenScrVertScrEdgePanelPanelTypeuiLayoutSpaceTypeARegionARegionTypeFileGlobalStripElemStripCropStripTransformStripColorBalanceStripProxyStripPluginSeqSequenceMetaStackWipeVarsGlowVarsTransformVarsSolidColorVarsSpeedControlVarsEffectBuildEffPartEffParticleWaveEffbPropertybNearSensorbMouseSensorbTouchSensorbKeyboardSensorbPropertySensorbActuatorSensorbDelaySensorbCollisionSensorbRadarSensorbRandomSensorbRaySensorbArmatureSensorbMessageSensorbSensorbControllerbJoystickSensorbExpressionContbPythonContbActuatorbAddObjectActuatorbActionActuatorSound3DbSoundActuatorbEditObjectActuatorbSceneActuatorbPropertyActuatorbObjectActuatorbIpoActuatorbCameraActuatorbConstraintActuatorbGroupActuatorbRandomActuatorbMessageActuatorbGameActuatorbVisibilityActuatorbTwoDFilterActuatorbParentActuatorbStateActuatorbArmatureActuatorGroupObjectBonebArmaturebMotionPathVertbPoseChannelbIKParambItascbActionGroupSpaceActionbActionChannelbConstraintChannelbConstraintbConstraintTargetbPythonConstraintbKinematicConstraintbSplineIKConstraintbTrackToConstraintbRotateLikeConstraintbLocateLikeConstraintbSizeLikeConstraintbSameVolumeConstraintbTransLikeConstraintbMinMaxConstraintbActionConstraintbLockTrackConstraintbDampTrackConstraintbFollowPathConstraintbStretchToConstraintbRigidBodyJointConstraintbClampToConstraintbChildOfConstraintbTransformConstraintbPivotConstraintbLocLimitConstraintbRotLimitConstraintbSizeLimitConstraintbDistLimitConstraintbShrinkwrapConstraintbActionModifierbActionStripbNodeStackbNodeSocketbNodeLinkbNodePreviewbNodeuiBlockbNodeTypeNodeImageAnimNodeBlurDataNodeDBlurDataNodeBilateralBlurDataNodeHueSatNodeImageFileNodeChromaNodeTwoXYsNodeTwoFloatsNodeGeometryNodeVertexColNodeDefocusNodeScriptDictNodeGlareNodeTonemapNodeLensDistNodeColorBalanceNodeColorspillTexNodeOutputCurveMapPointCurveMapBrushCloneCustomDataLayerCustomDataExternalHairKeyParticleKeyBoidParticleBoidDataParticleSpringChildParticleParticleTargetParticleDupliWeightParticleDataSPHFluidSettingsParticleSettingsBoidSettingsParticleCacheKeyKDTreeParticleDrawDataLinkNodebGPDspointbGPDstrokebGPDframebGPDlayerReportListwmWindowManagerwmWindowwmKeyConfigwmEventwmSubWindowwmGesturewmKeyMapItemPointerRNAwmKeyMapwmOperatorTypeFModifierFMod_GeneratorFMod_FunctionGeneratorFCM_EnvelopeDataFMod_EnvelopeFMod_CyclesFMod_PythonFMod_LimitsFMod_NoiseFMod_SteppedDriverTargetDriverVarChannelDriverFPointFCurveAnimMapPairAnimMapperNlaStripNlaTrackKS_PathKeyingSetAnimOverrideIdAdtTemplateBoidRuleBoidRuleGoalAvoidBoidRuleAvoidCollisionBoidRuleFollowLeaderBoidRuleAverageSpeedBoidRuleFightBoidStateFLUID_3DWTURBULENCETLEN `HH( p$8p`(0(pxh@(X hXhP 0@ (0 @ @Phx``XXp8XxP0x`0phX`Pp0h0xxH  (@@X@h`0X`8 PX`88@h`h(!x@0H(h pxXP8 (X( X,  4 H@@00Hh(H,(lHH`h<PP` HXPpT `88pX(((x@X8XPx8000(HH008hp`88H(8( ,@  ` 8H88@( <h ((xxh8(h(hp P8P@hH@STRC                  !"#$%&'()*+,-./01+,23456  789:; <=+>?#@:,ABC DEFG HIJK: LMNOP  QRS! !!TUVW XYZ"[X\ ] ^ _`a bcde fg#hi $HjklmnopqrsMt%&uvwxyz{|#}~C'  ()**|#+A,6-   #.@=/"=.0'1lm|2  / 3 4   |,?HC !"#$%&'()*+,-./0123456789zwxy:;W%<5=M'->/ 0?2@4AB6CDEFG*7HHHIJKLMNOPQRST3UClmVWXYZ[\]^_`abcdefghijWklmnopqrstuvwxyz{|M+}~89}H8HkB~//+}5=M:C# ;<#===>     ?H>   M9#CD= 4 !"#$ ##@@@%#&'()*+,-././012A3%#CB45C 6D78ZEDH> 9 C:;<=MF>?9 @CDWABCDE#FGHI()JKL M]@NOPQRSTUVWXYGZH[\;];^;_;`abcdBefgAhAiI'H>M?9JjKkLlMmNnOoPpQqIrRsStTuTvTw3xyz{CDA|}~UVL HJ%NWOWMPX'HYZ#QRK'H[\]^_Z`a`b%cd ddbac3yx#MU MTuTwVJNyx3#e eeH#&ufe,geX  heiejeUkeEHl eXmeneXo e#Xpe#qerstu e,v e'X#wexeyehze,#GW{eC| e}e~e&u  eMMMMM M J   eMM e#xeH#3 !"#$% &e'()*6e*6+,e-./e0123Xe4 e56789:;< e=7>?H@#e exABCDEF# eGHIJKLe,MN3UOP8ZH&'QRSTCUVW#XYZ[\]^M?OoE_`a>b#Hcdefgh$ijklMF>>mno pqr s t  u vHw9xyCz{|D}~bj        @:8|   $E *E(,:     6   $   !"#$%&'6()*#+,-./0123456789:;<=y>?@ABCODEFGHIJKLMNOPQRS TUVWXY2Z[\]^_`abcdefghijklmInIopqrMstuvwxyz{|}~3#LHIkCHM+}~  #  CWX# 9:#iy>     ^hH !"#$%&'()* +,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYC"Z[ \]^W_CHL`aC"bcWCHde  fghijWkl mnXo#pqrW shtuvwx sy6z{|}&u~oX#o#"O sRczW3y6&,Hk& B5= b      ep '%<VWhC&     O>p !"#$%&2 '()*OW+k, -./0123n456789:;<=> ? @ ABCDE Fp"=GHIJKLMNOPQRSTUVW3XYZ '()* '()*[ '()*\] ^H_`3 '()*\abcdSef# >ghi '()*\VWajklm#pnopqrstuvwxyz '({|} ~ C '()*\  '('%<3pVWm3  '()*_#]\ '()*"X       X  '()XW   '()\ # '()*\N VWm&5=5 p  '()*#p* '()*\}opw t#W     1Q '()*#   '(# '()\HVWC# S      # !"#$%&'a() *+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@B###$Y     /    '&u&W#    )#   #    !1("TU##  $ ' % &   \'(TU)*+R,   - . %/ 0 1234567&89:;#< =>? @ABCDEF#Gp)h#6HIJ KGj LMN    O P 0 Q URSIJTUVW#XYyZ[M&u\)]^>_`a b cdefgh ijklm no p b qrstuvw#xyLz{|}~ c#X66y-8VO;#:GB  O#!WC"9O##$#%#&#'HC(L)*HW+,---WC .*td#/ 01"H....C 2- 3#*4 V56 WC5#7 *I8W#&uk9#*: z}; VWC#<*WC= H# > V=  ?     @   WCAV BCZ  "D*EIF5 2 222  * # # M  X#   GGG*  :  ~ HHH H$        ! " O# $ % & ' ( ~IH ) * + H, - . 0g/ ~0 1 2 3 4 5 6 7 8 9 : JJ; < = > ? @ A B C D E F G H I J K L K)KK M N O P E7 8 HQ K$KR S rT KU CV #W X Y Z [ \ ] ^ _ ` > a Db #c Wbd e f g h i j qk Lh M h l m n o p q r s t NNN u v w  x a y bz { #| a :} ~  O  '()*\m H_ PPPN M sQQQM RRR    #M  S SS    T"   U        HOV ;    W   X#X  Y  Z  [\ ]   x WC ^  @UV#_  ` #a xA b     c R          #WCd e # f        g  h    i    j    k OXH#l5O9; m mm u  *nnnH  MUV      vo$     pppp o   o  W   p  Cq r   #s"sss Hd       G          rt u qqqs s p p #5Hp o    #  >  vwy #w   A   ^    x    L mJ #y  J#z W {y>|    R     }       ! ~"  # $ e%  & ' ( )   * +  JL, h- . / 0 x 1 2 3 4 5 #6 7 DEF8 9 : ; < = > ? @  A B C D E F G 3 =H I J K L M N O P u Q R S T U  H|V W X Y Z [ \ ] ^ _ ` a b c d e #'f #"g 3E +h 1i j k l hm On o p q r s t u v w x y z { | } ~   x   Z <T    #  #Y    6         6*H*    O     h               yH  T6  k          |               J    V               h                                 +}: :   M@ 2  R      ~     $                S         % 5 ! " Q# $ % & ' ( 6) * + 734, - . X/ 0 1 2 3 4 5 6 7 T 8 9 : ; < = X> ? :@ ; A  B C   wD A E YF  +G H I  J K L #M N O P Q R S T U V W X Y Z [ \ ]   ^ _ #` a b c d e f g h i Cj k l m n o U % p q r s t  u v w x y z #{   | s } ~   s  s   {        H     !3     "  #h #  x< =      : :  #N ; v/ 3:    5   v  UV      WC     #          m      H *   u     *C      d6      H    u       X            r(q  : : :  (( (           X#         T   Cs q '      Xt q ;   E   #CENDBrviz-1.12.4/image_src/RViz.stl000066400000000000000000000753741300447110700161550ustar00rootroot00000000000000Exported from blendert?z}>b?7U>?7U>";?z}>b?7U>?z}>̡%?[ ף=b?7U>";?z}>j>̡%?[ ף=";?z}>j>pc?[ ף=̡%?[ ף=j>pc?pc?[ ף=R>ڴ3#?>ڴ3#?>!۴S#?R>ڴ3#?H$>yڴ"?>ڴ3#?|Ϸ>yڴ"?H$>yڴ"?R>ڴ3#?|Ϸ>yڴ"?z>Gٴ@"?H$>yڴ"?x>Eٴ@"?z>Gٴ@"?|Ϸ>yڴ"?x>Eٴ@"?H>Mشu!?z>Gٴ@"?|W>Kشu!?H>Mشu!?x>Eٴ@"?|W>Kشu!?>O״z ?H>Mشu!?t>O״z ?>O״z ?|W>Kشu!?t>O״z ?>մS?>O״z ?׫>մS?>մS?t>O״z ?׫>մS?tj>;Դ?>մS?P>8Դ?tj>;Դ?׫>մS?P>8Դ?\`>*Ҵē?tj>;Դ?h>'Ҵ“?\`>*Ҵē?P>8Դ?h>'Ҵ“?>ϴ?\`>*Ҵē?>ϴ?>ϴ?h>'Ҵ“?>ϴ?">CʹW?>ϴ?Ѥ>@ʹW?">CʹW?>ϴ?Ѥ>@ʹW?>a˴'?">CʹW?,>a˴%?>a˴'?Ѥ>@ʹW?,>a˴%?>ȴ?>a˴'?ף>ȴ?>ȴ?,>a˴%?(>Tzƴ?>ȴ?ף>ȴ?(>Tzƴ?>Uzƴ?>ȴ?(>Tzƴ?">Ĵ]-?>Uzƴ?Ѥ>Ĵ\-?">Ĵ]-?(>Tzƴ?Ѥ>Ĵ\-?> ?">Ĵ]-?> ?> ?Ѥ>Ĵ\-?> ?X`>2ȿ]?> ?d>1ȿ\?X`>2ȿ]?> ?d>1ȿ\?pj>!ؽ ?X`>2ȿ]?L> ؽ ?pj>!ؽ ?d>1ȿ\?L> ؽ ?>b(1 ?pj>!ؽ ? ׫>a'1 ?>b(1 ?L> ؽ ? ׫>a'1 ?>‹H ?>b(1 ?s>G ?>‹H ? ׫>a'1 ?s>G ?D>;S ?>‹H ?xW>;R ?D>;S ?s>G ?xW>;R ?z>+D ?D>;S ?x>+D ?z>+D ?xW>;R ?x>+D ?D$>av?z>+D ?xϷ>au?D$>av?x>+D ?xϷ>au? >䶴3Q?D$>av?R>䶴2Q? >䶴3Q?xϷ>au?R>䶴2Q?>'1? >䶴3Q?> >7U>>7U>> > >7U>`j<81Ļx>괎.?>괎.?`j<81Ļr x>괎.?r >>괎.?)>>괎.?r Լ81Ļ>>괎.?`j<81ĻԼ81Ļr ?EVZ/.=iIʹ*??EVU#0.?.=iIʹ*?=*U#0.??EVU#0.?.=iIʹ*?Z!鴔 .?=*U#0.?.=iIʹ*?`,?Z!鴔 .?.=iIʹ*?_K+?`,?.=iIʹ*? "p(?_K+?.=iIʹ*?6Yݴ2L%? "p(?.=iIʹ*?Q شxd!?6Yݴ2L%?.=iIʹ*?vsҴ?Q شxd!?.=iIʹ*? -iIʹ*?vsҴ? -iIʹ*?Tト˴?vsҴ??EVZ/.=ȃr>.=iIʹ*?F'ʹr?Tト˴? -iIʹ*?8"W1̴j1?Tト˴?F'ʹr?rxʴD1?Tト˴?8"W1̴j1?rxʴD1?eô?Tト˴?hȴ,?eô?rxʴD1?VlƴT?eô?hȴ,?fô?eô?VlƴT?fô?`w. ?eô?_! ?`w. ?fô?|Zټ$ ?`w. ?_! ?j $ ?`w. ?|Zټ$ ?j $ ?<(W?`w. ? )RH?<(W?j $ ? 09ܙ?<(W? )RH? 09ܙ?&;><(W? 詴G>&;> 09ܙ? 1>&;> 詴G> 1>@9⾺塴RV>&;>V I>@9⾺塴RV> 1>V I>X㾠>@9⾺塴RV>8 {>X㾠>V I> Rt>X㾠>8 {> Rt>*熕>X㾠>`=a}>*熕> Rt>`=a}>辞яJc>*熕>k>辞яJc>`=a}>k>cqh`>辞яJc>£x->cqh`>k>F(Q>cqh`>£x->F(Q>j>cqh`>Q9>j>F(Q>)!?ɡ>j>Q9>)!?ɡ>M߾#>j>\&6)>M߾#>)!?ɡ> -ȃr>M߾#>\&6)>?EVZ/.=Kd>.=ȃr>.=Kd> -ȃr>.=ȃr>.=Kd>M߾#> -ȃr>.=Kd>ixہ>M߾#>.=Kd>n q5>ixہ>.=Kd>mih>n q5>.=Kd> Mc©>mih>.=Kd>vZ^> Mc©>.=Kd>; ZV ?>vZ^>.=Kd> OSK>; ZV ?>.=Kd>2Kd> OSK>2Kd>/J0> OSK>/J0>,eFvߓ> OSK>?EVZ/.=Z/.=Kd>h,IGt>,eFvߓ>/J0>XI)1G->,eFvߓ>h,IGt>&3D=>,eFvߓ>XI)1G->&3D=>&=s>,eFvߓ>"/@O >&=s>&3D=>[49=V>&=s>"/@O >[49=V>4xF3J>&=s>O,1 >4xF3J>[49=V>O,1 >0S({>4xF3J>R{&",x>0S({>O,1 >R{&",x>|In j>0S({>FR{d>|In j>R{&",x>FR{d>IsY>|In j>I L>IsY>FR{d>I L>B/{NF>IsY> nL0>B/{NF>I L> nL0>@#۾}3>B/{NF> nL0>ԾDճ`6>@#۾}3>Y+꿳 >ԾDճ`6> nL0>Y+꿳 >ԾDճ`6>ھZ/Y+꿳 >ھZ/ʾp=ھZ/HRǾ_/=ʾp=ھZ/Pľaf=HRǾ_/=ھZ/*=Pľaf=ھZ/jeX=*=ھZ/ d*Knm=jeX=ھZ/ -ȃr> -1=r> -1=r>.=1=r>.=ȃr> -ȃr>\&6)>\&1=>\&1=> -1=r> -ȃr>\&6)>)!?ɡ>)!1=ˡ>)!1=ˡ>\&1=>\&6)>)!?ɡ>Q9>Q0=9>Q0=9>)!1=ˡ>)!?ɡ>Q9>F(Q>F(0=>F(0=>Q0=9>Q9>F(Q>£x->£/=>£/=>F(0=>F(Q>£x->k>.=>.=>£/=>£x->k>`=a}>`-=c}>`-=c}>.=>k>`=a}> Rt> ,=v> ,=v>`-=c}>`=a}> Rt>8 {>8 +=>8 +=> ,=v> Rt>8 {>V I>V *=>V *=>8 +=>8 {>V I> 1> )=3> )=3>V *=>V I> 1> 詴G> (=G> (=G> )=3> 1> 詴G> 09ܙ? &=ݙ? &=ݙ? (=G> 詴G> 09ܙ? )RH? %=SH? %=SH? &=ݙ? 09ܙ? )RH?j $ ?j $=% ?j $=% ? %=SH? )RH?j $ ?|Zټ$ ?|Z#=% ?|Z#=% ?j $=% ?j $ ?|Zټ$ ?_! ?_"=!?_"=!?|Z#=% ?|Zټ$ ?_! ?fô?!=?!=?_"=!?_! ?fô?VlƴT?V =U?V =U?!=?fô?VlƴT?hȴ,?h =-?h =-?V =U?VlƴT?hȴ,?rxʴD1?rx=E1?rx=E1?h =-?hȴ,?rxʴD1?8"W1̴j1?8"=k1?8"=k1?rx=E1?rxʴD1?8"W1̴j1?F'ʹr?F'=s?F'=s?8"=k1?8"W1̴j1?F'ʹr? -iIʹ*? -=+? -=+?F'=s?F'ʹr?.=iIʹ*?.=ȃr>.=1=r>.=1=r>.==+?.=iIʹ*? -iIʹ*?.=iIʹ*?.==+?.==+? -=+? -iIʹ*?=*U#0.?Z!鴔 .?Z!= .?Z!= .?=*=1.?=*U#0.?Z!鴔 .?`,?`=,?`=,?Z!= .?Z!鴔 .?`,?_K+?_=+?_=+?`=,?`,?_K+? "p(? =q(? =q(?_=+?_K+? "p(?6Yݴ2L%?6=3L%?6=3L%? =q(? "p(?6Yݴ2L%?Q شxd!?Q=yd!?Q=yd!?6=3L%?6Yݴ2L%?Q شxd!?vsҴ?v=?v=?Q=yd!?Q شxd!?vsҴ?Tト˴?T=?T=?v=?vsҴ?Tト˴?eô?!=?!=?T=?Tト˴?eô?`w. ?`#=/ ?`#=/ ?!=?eô?`w. ?<(W?<%=?<%=?`#=/ ?`w. ?<(W?&;>(=;>(=;><%=?<(W?&;>@9⾺塴RV>@9*=TV>@9*=TV>(=;>&;>@9⾺塴RV>X㾠>X+=>X+=>@9*=TV>@9⾺塴RV>X㾠>*熕>*-=>*-=>X+=>X㾠>*熕>辞яJc>.=Lc>.=Lc>*-=>*熕>辞яJc>cqh`>c/=j`>c/=j`>.=Lc>辞яJc>cqh`>j>1=>1=>c/=j`>cqh`>j>M߾#>M2=%>M2=%>1=>j>M߾#>ixہ>i3=݁>i3=݁>M2=%>M߾#>ixہ>n q5>n4=7>n4=7>i3=݁>ixہ>n q5>mih>m5=h>m5=h>n4=7>n q5>mih> Mc©> 6=©> 6=©>m5=h>mih> Mc©>vZ^>6=>6=> 6=©> Mc©>vZ^>; ZV ?>; 7= ?>; 7= ?>6=>vZ^>; ZV ?> OSK>8=UK>8=UK>; 7= ?>; ZV ?> OSK>,eFvߓ>,9=xߓ>,9=xߓ>8=UK> OSK>,eFvߓ>&=s>:=u>:=u>,9=xߓ>,eFvߓ>&=s>4xF3J>4x<=L>4x<=L>:=u>&=s>4xF3J>0S({>0S=={>0S=={>4x<=L>4xF3J>0S({>|In j>|I>=j>|I>=j>0S=={>0S({>|In j>IsY>I@=sY>I@=sY>|I>=j>|In j>IsY>B/{NF>BA=SF>BA=SF>I@=sY>IsY>B/{NF>@#۾}3>@#۾C=3>@#۾C=3>BA=SF>B/{NF>@#۾}3>ԾDճ`6>ԾE=e6>ԾE=e6>@#۾C=3>@#۾}3>ԾDճ`6>ԾE=e6>ԾDճ`6>ʾp=ʾG==ʾG==ʾp=HRǾ_/=HRǾH=/=HRǾH=/=ʾG==ʾp=HRǾ_/=Pľaf=PľI=p=PľI=p=HRǾH=/=HRǾ_/=Pľaf=*=J=$=J=$=PľI=p=Pľaf=*=jeX=jK=X=jK=X=J=$=*=jeX= d*Knm= L=xm= L=xm=jK=X=jeX= d*Knm=YF= >YF= >ھR=*ꢹھZ/Y+꿳 > nL0> C=L0> C=L0>YF= >Y+꿳 > nL0>I L>A=L>A=L> C=L0> nL0>I L>FR{d>?=W{d>?=W{d>A=L>I L>FR{d>R{&",x>R==',x>R==',x>?=W{d>FR{d>R{&",x>O,1 ><= ><= >R==',x>R{&",x>O,1 >[49=V>[;=?V>[;=?V><= >O,1 >[49=V>"/@O >":=Q >":=Q >[;=?V>[49=V>"/@O >&3D=>&9=?>&9=?>":=Q >"/@O >&3D=>XI)1G->XI)9=/>XI)9=/>&9=?>&3D=>XI)1G->h,IGt>h,9=It>h,9=It>XI)9=/>XI)1G->h,IGt>/J0>/9=0>/9=0>h,9=It>h,IGt>/J0>2Kd>29=d>29=d>/9=0>/J0>2Kd>.=Kd>.=9=d>.=9=d>29=d>2Kd>.=Kd>.=Z/.=R=*ꢹ.=R=*ꢹ.=9=d>.=Kd>.=Z/?EVZ/?EVR=*ꢹ?EVR=*ꢹ.=R=*ꢹ.=Z/?EVU#0.?=*U#0.?=*=1.?=*=1.??EV=1.??EVU#0.??EVZ/?EVU#0.??EV=1.??EV=1.??EVR=*ꢹ?EVZ/Լ81Ļ`j<81Ļ`j괎.?=.?=.?`j괎.?x>괎.?x=.?x=.?=.?>괎.?x>괎.?r A=AO>A=AO>x=.?x>괎.?r )>>괎.?)>=.?)>=.?A=AO>r >>괎.?Լ81ĻԼS= ĻԼS= Ļ>=.?>>괎.?)>>괎.?>>괎.?>=.?>=.?)>=.?)>>괎.?>Uzƴ?">Ĵ]-?">!=^-?">!=^-?> =?>Uzƴ?">Ĵ]-?> ?>"=?>"=?">!=^-?">Ĵ]-?> ?X`>2ȿ]?X`>"=^?X`>"=^?>"=?> ?X`>2ȿ]?pj>!ؽ ?pj>#= ?pj>#= ?X`>"=^?X`>2ȿ]?pj>!ؽ ?>b(1 ?>#=)1 ?>#=)1 ?pj>#= ?pj>!ؽ ?>b(1 ?>‹H ?>#=I ?>#=I ?>#=)1 ?>b(1 ?>‹H ?D>;S ?D>$=T ?D>$=T ?>#=I ?>‹H ?D>;S ?z>+D ?z>$=D ?z>$=D ?D>$=T ?D>;S ?z>+D ?D$>av?D$>$=w?D$>$=w?z>$=D ?z>+D ?D$>av? >䶴3Q? >$=4Q? >$=4Q?D$>$=w?D$>av? >䶴3Q?>'1?>$=(1?>$=(1? >$=4Q? >䶴3Q?>'1?R>䶴2Q?R>$=3Q?R>$=3Q?>$=(1?>'1?R>䶴2Q?xϷ>au?xϷ>$=v?xϷ>$=v?R>$=3Q?R>䶴2Q?xϷ>au?x>+D ?x>$=D ?x>$=D ?xϷ>$=v?xϷ>au?x>+D ?xW>;R ?xW>$=S ?xW>$=S ?x>$=D ?x>+D ?xW>;R ?s>G ?s>#=H ?s>#=H ?xW>$=S ?xW>;R ?s>G ? ׫>a'1 ? ׫>#=(1 ? ׫>#=(1 ?s>#=H ?s>G ? ׫>a'1 ?L> ؽ ?L>#= ?L>#= ? ׫>#=(1 ? ׫>a'1 ?L> ؽ ?d>1ȿ\?d>"=]?d>"=]?L>#= ?L> ؽ ?d>1ȿ\?> ?>"= ?>"= ?d>"=]?d>1ȿ\?> ?Ѥ>Ĵ\-?Ѥ>!=]-?Ѥ>!=]-?>"= ?> ?Ѥ>Ĵ\-?(>Tzƴ?(> =?(> =?Ѥ>!=]-?Ѥ>Ĵ\-?(>Tzƴ?ף>ȴ?ף> =?ף> =?(> =?(>Tzƴ?ף>ȴ?,>a˴%?,>=&?,>=&?ף> =?ף>ȴ?,>a˴%?Ѥ>@ʹW?Ѥ>=W?Ѥ>=W?,>=&?,>a˴%?Ѥ>@ʹW?>ϴ?>=?>=?Ѥ>=W?Ѥ>@ʹW?>ϴ?h>'Ҵ“?h>=Ó?h>=Ó?>=?>ϴ?h>'Ҵ“?P>8Դ?P>=?P>=?h>=Ó?h>'Ҵ“?P>8Դ?׫>մS?׫>=S?׫>=S?P>=?P>8Դ?׫>մS?t>O״z ?t>=z ?t>=z ?׫>=S?׫>մS?t>O״z ?|W>Kشu!?|W>=u!?|W>=u!?t>=z ?t>O״z ?|W>Kشu!?x>Eٴ@"?x>=@"?x>=@"?|W>=u!?|W>Kشu!?x>Eٴ@"?|Ϸ>yڴ"?|Ϸ>="?|Ϸ>="?x>=@"?x>Eٴ@"?|Ϸ>yڴ"?R>ڴ3#?R>=3#?R>=3#?|Ϸ>="?|Ϸ>yڴ"?R>ڴ3#?>!۴S#?>=S#?>=S#?R>=3#?R>ڴ3#?>!۴S#?>ڴ3#?>=3#?>=3#?>=S#?>!۴S#?>ڴ3#?H$>yڴ"?H$>="?H$>="?>=3#?>ڴ3#?H$>yڴ"?z>Gٴ@"?z>=@"?z>=@"?H$>="?H$>yڴ"?z>Gٴ@"?H>Mشu!?H>=u!?H>=u!?z>=@"?z>Gٴ@"?H>Mشu!?>O״z ?>=z ?>=z ?H>=u!?H>Mشu!?>O״z ?>մS?>=S?>=S?>=z ?>O״z ?>մS?tj>;Դ?tj>=?tj>=?>=S?>մS?tj>;Դ?\`>*Ҵē?\`>=œ?\`>=œ?tj>=?tj>;Դ?\`>*Ҵē?>ϴ?>=?>=?\`>=œ?\`>*Ҵē?>ϴ?">CʹW?">=W?">=W?>=?>ϴ?">CʹW?>a˴'?>=(?>=(?">=W?">CʹW?>ȴ?>Uzƴ?> =?> =?> =?>ȴ?>a˴'?>ȴ?> =?> =?>=(?>a˴'? >>>R=[3>R=[3 >R=[3 >>>7U>>+=W>>+=W>>R=[3> >7U> > >R=[3 >R=[3 >+=W> >7U>>7U> >7U> >+=W> >+=W>>+=W>>7U>̡%?[ ף=pc?[ ף=pc?K=ף=pc?K=ף=̡%?K=ף=̡%?[ ף=pc?[ ף=pc?pc?R=[3pc?R=[3pc?K=ף=pc?[ ף=pc?j>j>R=[3j>R=[3pc?R=[3pc?j>";?z}>";?2=>";?2=>j>R=[3j>";?z}>?z}>?2=>?2=>";?2=>";?z}>?z}>?7U>?+=W>?+=W>?2=>?z}>b?7U>̡%?[ ף=̡%?K=ף=̡%?K=ף=b?+=W>b?7U>?7U>b?7U>b?+=W>b?+=W>?+=W>?7U>?+=W>b?+=W>?2=>?2=>b?+=W>";?2=>";?2=>b?+=W>̡%?K=ף=";?2=>̡%?K=ף=j>R=[3̡%?K=ף=pc?K=ף=j>R=[3pc?K=ף=pc?R=[3j>R=[3>=S#?>=3#?R>=3#?>=3#?H$>="?R>=3#?R>=3#?H$>="?|Ϸ>="?H$>="?z>=@"?|Ϸ>="?|Ϸ>="?z>=@"?x>=@"?z>=@"?H>=u!?x>=@"?x>=@"?H>=u!?|W>=u!?H>=u!?>=z ?|W>=u!?|W>=u!?>=z ?t>=z ?>=z ?>=S?t>=z ?t>=z ?>=S?׫>=S?>=S?tj>=?׫>=S?׫>=S?tj>=?P>=?tj>=?\`>=œ?P>=?P>=?\`>=œ?h>=Ó?\`>=œ?>=?h>=Ó?h>=Ó?>=?>=?>=?">=W?>=?>=?">=W?Ѥ>=W?">=W?>=(?Ѥ>=W?Ѥ>=W?>=(?,>=&?>=(?> =?,>=&?,>=&?> =?ף> =?ף> =?> =?(> =?> =?> =?(> =?> =?">!=^-?(> =?(> =?">!=^-?Ѥ>!=]-?">!=^-?>"=?Ѥ>!=]-?Ѥ>!=]-?>"=?>"= ?>"=?X`>"=^?>"= ?>"= ?X`>"=^?d>"=]?X`>"=^?pj>#= ?d>"=]?d>"=]?pj>#= ?L>#= ?pj>#= ?>#=)1 ?L>#= ?L>#= ?>#=)1 ? ׫>#=(1 ?>#=)1 ?>#=I ? ׫>#=(1 ? ׫>#=(1 ?>#=I ?s>#=H ?>#=I ?D>$=T ?s>#=H ?s>#=H ?D>$=T ?xW>$=S ?D>$=T ?z>$=D ?xW>$=S ?xW>$=S ?z>$=D ?x>$=D ?z>$=D ?D$>$=w?x>$=D ?x>$=D ?D$>$=w?xϷ>$=v?D$>$=w? >$=4Q?xϷ>$=v?xϷ>$=v? >$=4Q?R>$=3Q? >$=4Q?>$=(1?R>$=3Q?>+=W> >+=W>>R=[3 >+=W> >R=[3>R=[3=.?x=.?`j`j=.?>=.?A=AO>>=.?ԼS= ĻA=AO>A=AO>ԼS= Ļ`j?EVR=*ꢹ -=+?T=?F'=s?F'=s?T=?8"=k1?8"=k1?T=?rx=E1?T=?!=?rx=E1?rx=E1?!=?h =-?h =-?!=?V =U?V =U?!=?!=?!=?`#=/ ?!=?!=?`#=/ ?_"=!?_"=!?`#=/ ?|Z#=% ?|Z#=% ?`#=/ ?j $=% ?`#=/ ?<%=?j $=% ?j $=% ?<%=? %=SH? %=SH?<%=? &=ݙ?<%=?(=;> &=ݙ? &=ݙ?(=;> (=G> (=G>(=;> )=3>(=;>@9*=TV> )=3> )=3>@9*=TV>V *=>@9*=TV>X+=>V *=>V *=>X+=>8 +=>8 +=>X+=> ,=v>X+=>*-=> ,=v> ,=v>*-=>`-=c}>*-=>.=Lc>`-=c}>`-=c}>.=Lc>.=>.=Lc>c/=j`>.=>.=>c/=j`>£/=>£/=>c/=j`>F(0=>c/=j`>1=>F(0=>F(0=>1=>Q0=9>Q0=9>1=>)!1=ˡ>1=>M2=%>)!1=ˡ>)!1=ˡ>M2=%>\&1=>\&1=>M2=%> -1=r>.=1=r>.=9=d>?EVR=*ꢹ.=1=r> -1=r>.=9=d> -1=r>M2=%>.=9=d>M2=%>i3=݁>.=9=d>i3=݁>n4=7>.=9=d>n4=7>m5=h>.=9=d>m5=h> 6=©>.=9=d> 6=©>6=>.=9=d>6=>; 7= ?>.=9=d>; 7= ?>8=UK>.=9=d>8=UK>29=d>.=9=d>8=UK>/9=0>29=d>8=UK>,9=xߓ>/9=0>.=9=d>.=R=*ꢹ?EVR=*ꢹ/9=0>,9=xߓ>h,9=It>h,9=It>,9=xߓ>XI)9=/>XI)9=/>,9=xߓ>&9=?>,9=xߓ>:=u>&9=?>&9=?>:=u>":=Q >":=Q >:=u>[;=?V>:=u>4x<=L>[;=?V>[;=?V>4x<=L><= >4x<=L>0S=={><= ><= >0S=={>R==',x>0S=={>|I>=j>R==',x>R==',x>|I>=j>?=W{d>|I>=j>I@=sY>?=W{d>?=W{d>I@=sY>A=L>I@=sY>BA=SF>A=L>A=L>BA=SF> C=L0>BA=SF>@#۾C=3> C=L0>@#۾C=3>ԾE=e6> C=L0> C=L0>ԾE=e6>YF= >ԾE=e6>YF= >YF= >ھR=*ꢹʾG==ھR=*ꢹʾG==HRǾH=/=ھR=*ꢹHRǾH=/=PľI=p=ھR=*ꢹPľI=p=J=$=ھR=*ꢹJ=$=jK=X=ھR=*ꢹjK=X= L=xm=ھR=*ꢹ L=xm=8?@ J95~J/ADATAX/1BUTTONS_PT_contextBUTTONS_PT_contextContext9$DATAX183/RENDER_PT_renderRENDER_PT_renderRender9=DATAX8341RENDER_PT_layersRENDER_PT_layersLayerso9DATAX4x683RENDER_PT_dimensionsRENDER_PT_dimensionsDimensions9DATAXx684RENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:9:DATAX89x6RENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"9DATAX9X;8RENDER_PT_shadingRENDER_PT_shadingShading 9DATAXX;<9RENDER_PT_performanceRENDER_PT_performancePerformance9DATAX<>X;RENDER_PT_post_processingRENDER_PT_post_processingPost Processing9DATAX>8@<RENDER_PT_stampRENDER_PT_stampStamp9 DATAX8@A>RENDER_PT_outputRENDER_PT_outputOutput(9 DATAXA8@RENDER_PT_bakeRENDER_PT_bakeBake9 DATAxCDATADI(,UL(nT3{4|HHEGDATA(EG DADA3`DA`DA?? 4434DATA(GE@~CHBpF}CHB33a?HB|HHB= AH4b3{4bDATAHDATAIPDH85~JgxMxMJLDATA(JLCACAICACA?? JJ5~JDATA(LJCC9JL88L?? JM9;5~JMDATAxMhTDATAhTNDATANزȻxDATAPX]IxX3}m[[PVDATA(PhR@qDAcDAcDAcDA?? 3}DATA(hRSPC@FCF++?@ ,SDATA(SHUhRCfCww?@ xf3"DATA(HUVS#C`#C`?@ 33DATA(VHU3S(XDATA`(X?ޕ? JLD>3;Q?Fwi?JF>#,TY!e?*=>o?E>Fwi?TY5;JF>!e?Q?#,+=>`DAoy@?>{0QQuZ?,h>?>#,>m$?T*= lAoA>tU?pFളZ)>C?4kuPA)ˆy>rB_B@D>3;Q?Fwi?JF>#,TY!e?*=>o?>{0QQuZ?,h>?>#,>m$?T*= lAoA]j@]j@]j@?\>7?8˔oAoAt;?! BVBt~BDATA8[333?? Ax B?=C DATAX]eP(X}kddH^bDATA(H^_@wDA)DA(DA(DA?? }DATA(_(aH^HCpHCC?? kDATA((ab_kDATA(b(aC@zC Ao:o:|HPCGikDATAdHeDATAhHeDATAelX]QxXm }8k8kfiDATA(fXh|DA)DA(DA(DA?? mDATA(Xhif7CHC@b??cQcDATA(iXh hD hD@bb|H@F #<HBJccDATA@8k DATAleXxpU85~!JHtHtm(oDATA(m(ofDAC@AICACA?? JJ5~!!DATA((om5~!JpDATA`p9 @!i@AHMݕ/?U~'?3F:?>T8165e?2>Z& 4?ߕ/?7F:?81W~>85e?'?T2>ne@>M@?0?''???T?ļP@l2@11A 4AF>> Ο"o={>3xB ֟&BĭeA(@ݕ/?U~'?3F:?>T8165e?2>Z& 4?0?''???T?ļP@l2@11A 4A~@~@~@?H?N,Z# A3;??ABdZBvBDATA8Ht333?? Ax B? #<C SNXv(SRCompositingg.001xw(}}Ȇ8(DATA xwwDATA wXxxwDATA Xxxw~DATA x8yXx~DATA 8yyxDATA yz8y~DATA zzy \DATA zzz~\DATA zh{z DATA h{{zDATA {H|h{ DATA H||{DATA |(}H|DATA (}| DATA(}~wXxDATA(~x~}w8yDATA(x~~~XxyDATA(~Xx~8yyDATA(X~xzDATA(8XzzDATA(8yzDATA(88yzDATA(zzDATA(yzDATA(h8yh{DATA(h؂z{DATA(؂Hhh{{DATA(H؂h{H|DATA((H{H|DATA((xw|DATA((|(}DATA(xx(}DATA(xz(}DATA(XxH||DATA(XȆ{(}DATA(ȆXxwh{DATA88ywXxy~XX(DATA(( DADA~DADA?? ~DATA((mEmEpoo?? pDATA8(}zzx!~[^\؎؎hDATA(hsDACA]CACA?? ^^!~^DATA(h@~CHB23JуCHB]]A?HB|HHB= AH^B!~[^BDATA؎DATAzzyz!~]^HHXDATA(XCACA]CACA?? ^^!~^DATA(XC\C\M^rRLr?@ ^sMs!~]^sȓDATAXȓhBUTTONS_PT_contextBUTTONS_PT_contextContextL$DATAXhȓRENDER_PT_renderRENDER_PT_renderRenderL=DATAXhRENDER_PT_layersRENDER_PT_layersLayersoLDATAXHRENDER_PT_dimensionsRENDER_PT_dimensionsDimensionsLDATAXHRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:L:DATAXHRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"LDATAX(RENDER_PT_shadingRENDER_PT_shadingShading LDATAX(ȠRENDER_PT_performanceRENDER_PT_performancePerformanceLDATAXȠh(RENDER_PT_post_processingRENDER_PT_post_processingPost ProcessingLDATAXhȠRENDER_PT_stampRENDER_PT_stampStampL DATAXhRENDER_PT_outputRENDER_PT_outputOutput(L DATAXRENDER_PT_bakeRENDER_PT_bakeBakeL DATAHDATAص|H|{(}XXx8DATA(x@qDAFDAFDAFDA?? DATA(XxC@FCF++?@ ,rDATA(XȭCfCww?@ xf"DATA(ȭ8X#Cl#C?@ pDATA(8ȭrDATA`]e?w@AHMݕ/?U~'?3F:?>T8165e?2>Z& 4?ߕ/?7F:?81W~>85e?'?T2>ne@>M@?*?c''Ӥ?7??T?']@l2zz11A 4A>>Ļ7v=m>3xB֟&BĭeA(@ݕ/?U~'?3F:?>T8165e?2>Z& 4?*?c''Ӥ?7??T?']@l2zz11A 4A>?>?>??H?N,Z#oAoAP1:\>7?8˔?ABdZBvBDATA8X333?? Ax B?=C DATAص(h{8yz{ ]ȶ8DATA(ȶ8BDADADADA??   DATA(8ȶ D DlD`@>C BB??FFQ= @  C1 CDATA0 @ a?DATA(صxwh{H||hhDATA(CAADA@DA@DA?? DATA(DATA(CC@d?rrDATA(!hdA>d>ddd?SN(ZXvSRDefaultXhFDATA hDATA h*DATA Hh*DATA HDATA (HDATA (DATA (DATA xDATA xpDATA XxpDATA XDATA 8XDATA 8@DATA 8@DATA jDATA jDATA hDATA hDATA Hh(DATA H(DATA (HDATA (DATA (DATA xDATA xDATA xDATA(XhDATA(8XhDATA(8(DATA(8(DATA(DATA(HDATA(hDATA(h(DATA(HhxDATA(HxDATA((H(DATA((HDATA((xDATA(xXDATA(x8DATA(XxDATA(X8DATA(8X8DATA(8XDATA(8DATA(DATA(DATA(hXDATA(hhDATA(HhhDATA(HHDATA((HDATA((H(DATA(((DATA(xDATA(xDATA(XxDATA(XHDATA(8XDATA(8xDATA(8xDATA((DATA(hDATA(xDATAh8h(*YYXDATA(XDADA`DA`DA?? )DATA(XmED@poo?? p**DATA8%hxHopH$H$(DATA((CAoCAnCAnCA?? VoDATA((oCU^CUUJU?@ VVUV"DATAXBUTTONS_PT_contextBUTTONS_PT_contextContext$DATAXH RENDER_PT_renderRENDER_PT_renderRender=DATAXH  RENDER_PT_layersRENDER_PT_layersLayersoDATAX  H RENDER_PT_dimensionsRENDER_PT_dimensionsDimensions DATAX ( RENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:: DATAX( RENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur" DATAXh(RENDER_PT_shadingRENDER_PT_shadingShading  DATAXhRENDER_PT_performanceRENDER_PT_performancePerformance DATAXhRENDER_PT_post_processingRENDER_PT_post_processingPost ProcessingDATAXHRENDER_PT_stampRENDER_PT_stampStampDATAXHRENDER_PT_outputRENDER_PT_outputOutput(DATAXHRENDER_PT_bakeRENDER_PT_bakeBakeDATAX(SCENE_PT_sceneSCENE_PT_sceneScene)=DATAX(SCENE_PT_unitSCENE_PT_unitUnits)SDATAXh(SCENE_PT_keying_setsSCENE_PT_keying_setsKeying Sets)EDATAXh!SCENE_PT_physicsSCENE_PT_physicsGravity)$DATAX!"hSCENE_PT_simplifySCENE_PT_simplifySimplify)PDATAX"!SCENE_PT_custom_propsSCENE_PT_custom_propsCustom Properties)$DATAH$DATA%x*88?@X)X)x&'DATA(x&' DADA`DA`DA?? DATA('x&@~CHBXg(CHB%?HB|HHB= AH&?&DATAX)DATAx*%x(qH.H.h+,DATA(h+,CAoCAnCAnCA?? DATA(,h+C^C?? rqDATAH.Tse SculptDATAT /DATA/ زȻx      !"#$%&'()*+,-./0      !"#$%&'(17(=xBGMhRW]XbglHrw|8،(xȜhXH111111111 1 1 1 1 1111111111111111111 1!1"1#1$1%1&1'1(1)1*1+1,1-1.1/101112131415161718191:1;1<1=1>1?1@1A1B1C1D1E1xȻ(Xv8x+xrXز777777777 7 7 7 7 7777777777777777777 7!7"7#7$7%7&7'7(7)7*7+7,7-7.7/707172737475767778797:7;7<7=7>7?7@7A7B7C7D7E7(=(=(=(=(=(=(=(=(= (= (= (= (= (=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(= (=!(="(=#(=$(=%(=&(='(=((=)(=*(=+(=,(=-(=.(=/(=0(=1(=2(=3(=4(=5(=6(=7(=8(=9(=:(=;(=<(==(=>(=?(=@(=A(=B(=C(=D(=E(=xBxBxBxBxBxBxBxBxB xB xB xB xB xBxBxBxBxBxBxBxBxBxBxBxBxBxBxBxBxBxBxB xB!xB"xB#xB$xB%xB&xB'xB(xB)xB*xB+xB,xB-xB.xB/xB0xB1xB2xB3xB4xB5xB6xB7xB8xB9xB:xB;xB<xB=xB>xB?xB@xBAxBBxBCxBDxBExBGGGGGGGGG G G G G GGGGGGGGGGGGGGGGGGG G!G"G#G$G%G&G'G(G)G*G+G,G-G.G/G0G1G2G3G4G5G6G7G8G9G:G;G<G=G>G?G@GAGBGCGDGEGMMMMMMMMM M M M M MMMMMMMMMMMMMMMMMMM M!M"M#M$M%M&M'M(M)M*M+M,M-M.M/M0M1M2M3M4M5M6M7M8M9M:M;M<M=M>M?M@MAMBMCMDMEMhRhRhRhRhRhRhRhRhR hR hR hR hR hRhRhRhRhRhRhRhRhRhRhRhRhRhRhRhRhRhRhR hR!hR"hR#hR$hR%hR&hR'hR(hR)hR*hR+hR,hR-hR.hR/hR0hR1hR2hR3hR4hR5hR6hR7hR8hR9hR:hR;hR<hR=hR>hR?hR@hRAhRBhRChRDhREhRWWWWWWWWW W W W W WWWWWWWWWWWWWWWWWWW W!W"W#W$W%W&W'W(W)W*W+W,W-W.W/W0W1W2W3W4W5W6W7W8W9W:W;W<W=W>W?W@WAWBWCWDWEW]]]]]]]]] ] ] ] ] ]]]]]]]]]]]]]]]]]]] ]!]"]#]$]%]&]'](])]*]+],]-].]/]0]1]2]3]4]5]6]7]8]9]:];]<]=]>]?]@]A]B]C]D]E]XbXbXbXbXbXbXbXbXb Xb Xb Xb Xb XbXbXbXbXbXbXbXbXbXbXbXbXbXbXbXbXbXbXb Xb!Xb"Xb#Xb$Xb%Xb&Xb'Xb(Xb)Xb*Xb+Xb,Xb-Xb.Xb/Xb0Xb1Xb2Xb3Xb4Xb5Xb6Xb7Xb8Xb9Xb:Xb;Xb<Xb=Xb>Xb?Xb@XbAXbBXbCXbDXbEXbggggggggg g g g g ggggggggggggggggggg g!g"g#g$g%g&g'g(g)g*g+g,g-g.g/g0g1g2g3g4g5g6g7g8g9g:g;g<g=g>g?g@gAgBgCgDgEglllllllll l l l l lllllllllllllllllll l!l"l#l$l%l&l'l(l)l*l+l,l-l.l/l0l1l2l3l4l5l6l7l8l9l:l;l<l=l>l?l@lAlBlClDlElHrHrHrHrHrHrHrHrHr Hr Hr Hr Hr HrHrHrHrHrHrHrHrHrHrHrHrHrHrHrHrHrHrHr Hr!Hr"Hr#Hr$Hr%Hr&Hr'Hr(Hr)Hr*Hr+Hr,Hr-Hr.Hr/Hr0Hr1Hr2Hr3Hr4Hr5Hr6Hr7Hr8Hr9Hr:Hr;Hr<Hr=Hr>Hr?Hr@HrAHrBHrCHrDHrEHrwwwwwwwww w w w w wwwwwwwwwwwwwwwwwww w!w"w#w$w%w&w'w(w)w*w+w,w-w.w/w0w1w2w3w4w5w6w7w8w9w:w;w<w=w>w?w@wAwBwCwDwEw||||||||| | | | | ||||||||||||||||||| |!|"|#|$|%|&|'|(|)|*|+|,|-|.|/|0|1|2|3|4|5|6|7|8|9|:|;|<|=|>|?|@|A|B|C|D|E|888888888 8 8 8 8 8888888888888888888 8!8"8#8$8%8&8'8(8)8*8+8,8-8.8/808182838485868788898:8;8<8=8>8?8@8A8B8C8D8E8      !"#$%&'()*+,-./0123456789:;<=>?@ABCDE،،،،،،،،، ، ، ، ، ،،،،،،،،،،،،،،،،،،، ،!،"،#،$،%،&،'،(،)،*،+،,،-،.،/،0،1،2،3،4،5،6،7،8،9،:،;،<،=،>،?،@،A،B،C،D،E،((((((((( ( ( ( ( ((((((((((((((((((( (!("(#($(%(&('((()(*(+(,(-(.(/(0(1(2(3(4(5(6(7(8(9(:(;(<(=(>(?(@(A(B(C(D(E(xxxxxxxxx x x x x xxxxxxxxxxxxxxxxxxx x!x"x#x$x%x&x'x(x)x*x+x,x-x.x/x0x1x2x3x4x5x6x7x8x9x:x;x<x=x>x?x@xAxBxCxDxExȜȜȜȜȜȜȜȜȜ Ȝ Ȝ Ȝ Ȝ ȜȜȜȜȜȜȜȜȜȜȜȜȜȜȜȜȜȜȜ Ȝ!Ȝ"Ȝ#Ȝ$Ȝ%Ȝ&Ȝ'Ȝ(Ȝ)Ȝ*Ȝ+Ȝ,Ȝ-Ȝ.Ȝ/Ȝ0Ȝ1Ȝ2Ȝ3Ȝ4Ȝ5Ȝ6Ȝ7Ȝ8Ȝ9Ȝ:Ȝ;Ȝ<Ȝ=Ȝ>Ȝ?Ȝ@ȜAȜBȜCȜDȜEȜ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEhhhhhhhhh h h h h hhhhhhhhhhhhhhhhhhh h!h"h#h$h%h&h'h(h)h*h+h,h-h.h/h0h1h2h3h4h5h6h7h8h9h:h;h<h=h>h?h@hAhBhChDhEh      !"#$%&'()*+,-./0123456789:;<=>?@ABCDE      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEXXXXXXXXX X X X X XXXXXXXXXXXXXXXXXXX X!X"X#X$X%X&X'X(X)X*X+X,X-X.X/X0X1X2X3X4X5X6X7X8X9X:X;X<X=X>X?X@XAXBXCXDXEX      !"#$%&'()*+,-./0123456789:;<=>?@ABCDE      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEHHHHHHHHH H H H H HHHHHHHHHHHHHHHHHHH H!H"H#H$H%H&H'H(H)H*H+H,H-H.H/H0H1H2H3H4H5H6H7H8H9H:H;H<H=H>H?H@HAHBHCHDHEH      !"#$%&'()*+,-./0123456789:;<=>?@ABCDE                !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRS      !"#$%&'()*+,-./0123xxxxxxxxx x x x x xxxxxxxxxxxxxxxxxxx x!x"x#x$x%x&x'x(x)x*x+x,x-x.x/x0x1x2x3x4x5x6x7x8x9x:x;x<x=x>x?x@xAxBxCxDxExFxGxHxIxJxKxLxMxNxOxPxQxRxSxTxUxVxWxXxYxZx[x\x]x^x_x`xȻȻȻȻȻȻȻȻȻ Ȼ Ȼ Ȼ Ȼ ȻȻȻȻȻȻȻȻȻȻȻȻȻȻȻȻȻȻȻ Ȼ!Ȼ"Ȼ#Ȼ$Ȼ%Ȼ&Ȼ'Ȼ(Ȼ)Ȼ*Ȼ+Ȼ,Ȼ-Ȼ.Ȼ/Ȼ0Ȼ1Ȼ2Ȼ3Ȼ4Ȼ5Ȼ6Ȼ7Ȼ8Ȼ9Ȼ:Ȼ;Ȼ<Ȼ=Ȼ>Ȼ?Ȼ@ȻAȻBȻCȻDȻEȻFȻGȻHȻIȻJȻKȻLȻMȻNȻOȻPȻQȻRȻSȻTȻUȻVȻWȻXȻYȻZȻ[Ȼ\Ȼ]Ȼ^Ȼ_Ȼ`Ȼ((((((((( (XvXvXvXvXvXvXvXvXv Xv 888888888 8xxxxxxxxx x+++++++++ +xrxrxrxrxrxrxrxrxr xr     XXXXXXXXX X Xززززززززز ز ز ز ز ززززززززDATAx*Xh88xDATA(x@qDADAK`DA`DA?? LLDATA(x CC?@ 2XDATAXXVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXXVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(!CvfC^dv?@ "DATAXVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(4C`#C`ã?@ DATA(DDATA`?7B LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?TA5>#,>mv$BH*=!lA!oA'>~tU?`FH!;<81pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?TA5>#,>mv$BH*=$!j?!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA88333?? Ax B?=zD DATA8Ai)DATA( DADA`DA`DA?? AZDATA(@~CHBXg(CHB?HB|HHB= AH[iDATADATAXkxxDATA( DADAK`DA`DA?? LLkkDATA(@~CHBXg(CHB?HB|HHB= AHkDATAxDATA xh+H H (DATA(@qDADA`DA`DA?? DATA( CC?@ 2hDATAXhVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXhVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(!CvfC^dv?@ "DATAXVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA((4C`#C`ã?@ DATA((DDATA`?ÃB LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?YA5>#,>m{BH*=!lA!oA'>~tU?`F/_N4;vP<1pu²Aݞ6rB;B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?YA5>#,>m{BH*=$!/I?!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8H 333?? Ax B?=zD DATA X(H)w&& !DATA( ( @qDADA`DA`DA?? )BDATA((   CChh?@ ii7i28DATAX8VIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAX8VIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(( !CvfC^dv?@ C6"HHDATAXHVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(!4C@s#C~ã\\?@ ]]0C]X DATAXXVIEW3D_PT_objectVIEW3D_PT_objectTransformznDATAXXVIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease PencilPDATAX8VIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView?DATAX8VIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem$DATAXx8VIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplaygDATAXx VIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImagesODATAX xVIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform Orientations7DATA(!/C](#DATA`(#?26@ LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQuZ? ?5>#,>mT#@H*=!lA!oAd>ntU?@FR=U>3pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQuZ? ?5>#,>mT#@H*=%!T=!lA!oA@@@@@@mWC <?\>7?8˔!oAoAf;?8 BBj~BDATA8&333?? Ax B?=zD DATAX(E H('3hDhDH)H?DATA(H)*@qDADA`DA`DA?? DATA(*h/H) CC?@ '2(,-DATAX(,-VIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAX-(,VIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(h/x2*!CvfC^dv?@ "00DATAX0VIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(x2H?h/C@sC=N<?@ N='NN3=DATAX35VIEW3D_PT_objectVIEW3D_PT_objectTransformz=nDATAX5(73VIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease Pencil=PDATAX(785VIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView=?DATAX8h:(7VIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem=$DATAXh:<8VIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplayg=DATAX<=h:VIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImagesO=DATAX=<VIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform Orientations7=DATA(H?x2'@DATA`@?fB LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>"*UtQQsZ?~@5>#,>mtAH*=!lA!oA'>~tU?pF{FV;<1pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>F"*UtQQsZ?~@5>#,>mtAH*=$!d?!lA!oA}-@}-@}-@mWC <?\>7?8˔!oAoA;?8 BBj~BDATA8hD333?? Ax B?=zD DATAEFX(nYYDATAFEx('WWGhRDATA(G8I@qDADA`DA`DA?? DATA(8IMG CCP  ?@  2JHLDATAXJHLVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Tools*DATAXHLJVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATA(MP8I!CvfC^dv?@ "XOXODATAXXOVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle EditmodeDATA(PhRM4C`#C`ã?@ DATA(hRPD SDATA`S?B LD>3;Q?Fwi?JF>#,TY!e?*=>!o?D>Fwi?TY4;JF>!e?Q?#,+=>>_DA3xs@?>tQQsZ?TA5>#,>mvBH*=!lA!oA'>~tU?`FH! ;<0pu²Aܞ6rB:B@D>3;Q?Fwi?JF>#,TY!e?*=>FtQQsZ?TA5>#,>mvBH*=$!j@!lA!oAH?H?H?mWC <?\>7?8˔!oAoAq{:?8 BBj~BDATA8W333?? Ax B?=zD SN(Z8SRDefault-fullH[x]]``؉ PkDATA H[[DATA [(\H[DATA (\\[eDATA \](\eDATA ]x]\DATA x]]eDATA(]X^[(\DATA(X^^]H[\DATA(^8_X^H[]DATA(8__^[]DATA(_`8_(\x]DATA(``_\x]DATA(``]x]DATA`؉H[]x]\efȍ(a|URDATA(aXcDADAeDADA?? ffef (h RhKDATA(XcHkaCCm~ele?@ ~fmf}6~f ~2diKWDATAXdhfhOVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject Toolsm'DATAXhfhdVIEW3D_PT_tools_texteditVIEW3D_PT_tools_texteditText Tools7DATAXhihfQVIEW3D_PT_tools_mesheditVIEW3D_PT_tools_mesheditMesh ToolsmDATAXihHTVIEW3D_PT_tools_meshedit_optionsVIEW3D_PT_tools_meshedit_optionsMesh Options@mtDATA(HkXnXcC@JCRm~l?@ ~m}5~ "ؕll2VxDATAXlȖVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorToggle Editmodect All3D Cursorp'DATA(Xn|Hk4Cm#C`?@ e ؏o({(fW TDATAXohqȐVIEW3D_PT_objectVIEW3D_PT_objectTransformzn&DATAXhqso(VIEW3D_PT_gpencilVIEW3D_PT_gpencilGrease PencilPDATAXsthq0VIEW3D_PT_view3d_propertiesVIEW3D_PT_view3d_propertiesView)DATAXtHvs2VIEW3D_PT_view3d_nameVIEW3D_PT_view3d_nameItem$DATAXHvwt4VIEW3D_PT_view3d_displayVIEW3D_PT_view3d_displayDisplay}DATAXwyHv@VIEW3D_PT_background_imageVIEW3D_PT_background_imageBackground ImageseDATAXy({whCVIEW3D_PT_transform_orientationsVIEW3D_PT_transform_orientationsTransform OrientationsMDATAX({yVIEW3D_PT_view3d_meshdisplayVIEW3D_PT_view3d_meshdisplayMesh Display-hDATA(|Xn~4 ZNYN8~DATA`8~,Q?? Luw?yG<9>m>#P3>s1gv|?6*>3?fXy<0W?uw?{>2g zGu|?8>s6*>"r`??v3?W-Z< 9v?>D>s?s?[Ӊ??*6*S@?W\<J@0W@XN?@U>@`4`6<#>Nlf??A`NDkT俕9@@uw?yG<9>\gt|?6*>kMP3s?7l?v3?W-Z< 9\Ӊ??*6*u?Dss1v_@7l@???mWC <?uB?.#G~ҽ1:7l@??r;9s?? ! BTBq~BDATA8(333?? Ax B?=zD XnSDATA(h؄@PDADAeDADA?? ffefDATA(؄HhpC`_C`?@ hVDATA(H؄DpBDpBu;`DlB`DlB?? v<v<eFv<DATA(HC@PDMuuE??vFv4eEvF(DATAh(hHWPUVDATA؉`][(\x]ef%Ȋ8LȱLDATA(Ȋ8cDADAeDADA?? ffefxOxOLLDATA(8ȊD0AD0AUf T ?? f U ef 8LظLSN8x(ZSRGame Logic.001Xx8DATA XȏDATA ȏ8XDATA 8ȏ~DATA 8~DATA DATA ~DATA hDATA hؒ DATA ؒHh DATA Hؒ~DATA (H@DATA (@DATA (DDATA DDATA(xȏ8DATA(XxȏDATA(XȖ8DATA(Ȗ8XDATA(8ȖDATA(8hDATA(ؒDATA(hؒDATA(hXDATA(hؙXؒDATA(ؙHhHDATA(HؙHDATA((HhHDATA(((DATA(((DATA(xHDATA(xDATA(XxDATA(XȝDATA(ȝ8X(DATA(8ȝDATAxȏ8~DATA( DADA~DADA?? ~DATA(mED@poo?? pDATAxؒhH!~^ȹȹhؤDATA(hؤCACA]CACA?? ^^!~r^DATA(ؤhC=CM^qNLq?@ ^rMr!~q^rH(DATAXHBUTTONS_PT_contextBUTTONS_PT_contextContextL$DATAXHRENDER_PT_renderRENDER_PT_renderRenderL=DATAX(RENDER_PT_layersRENDER_PT_layersLayersoLDATAX(ȬRENDER_PT_dimensionsRENDER_PT_dimensionsDimensionsLDATAXȬh(RENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:L:DATAXhȬRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"LDATAXhRENDER_PT_shadingRENDER_PT_shadingShading LDATAXHRENDER_PT_performanceRENDER_PT_performancePerformanceLDATAXHRENDER_PT_post_processingRENDER_PT_post_processingPost ProcessingLDATAXHRENDER_PT_stampRENDER_PT_stampStampL DATAX(RENDER_PT_outputRENDER_PT_outputOutput(L DATAX(RENDER_PT_bakeRENDER_PT_bakeBakeL DATAȹDATAxxXhؒ xDATA(hJCADADADA??   DATA(hx\CKCqq?@ rrrؾؾDATAXؾLOGIC_PT_propertiesLOGIC_PT_propertiesProperties$DATA(xhDpCPDƶ¸C3Dq22q??FF?H? Dr3`DrDATAHDATAx8(HA~ >]HHhDATA(hCADA=@DA@DA?? >>A~>DATA(hCCDVD=B #<zD >C>CA~>CDATAH DATA8x(E?](DATA((@qDA~DA~DA~DA?? E?DATA((C@FCF++?@ ,EECDATA(xCfCww?@ xfE?"DATA(x4Cm#Cmã?@ ??DATA(xE?CXDATA`X#=K(=o?????????#=K(=o?5ApykA?????#=K(=o?t@t@t@??5AoA9P=\>7?8˔?BBDATA8333?? Ax B?=zD DATA8CD]XXxDATA(xCACACCACA?? DDCDDATA(xCC@ 3DB22B?? DC31CDCDATAXRDATARDATAزȻxSNx+8SRScriptingg.001HXx$DATA DATA xDATA x~DATA Xx~DATA XDATA 8X~DATA 8DATA 8DATA hDATA hDATA hhDATA hDATA Hh~DATA HDATA((xDATA((XDATA((xDATA(xXDATA(x8DATA(XxDATA(XDATA(8XXDATA(88DATA(8DATA(DATA(DATA(hhDATA(h8hDATA(HhDATA(HDATA((HhDATA((XHDATA((8HDATA(xHDATA(xDATA(xDATAX(Xx~]8+8+HDATA(H DADA~DADA?? ~DATA(HDBDBnBomB?? CnC~CDATA( Xh~x x DATA(CACACACA?? ~DATA(C=C4}~|?@ }~DATAXBUTTONS_PT_contextBUTTONS_PT_contextContext|$DATAX8RENDER_PT_renderRENDER_PT_renderRender|=DATAX8RENDER_PT_layersRENDER_PT_layersLayerso|DATAXx8RENDER_PT_dimensionsRENDER_PT_dimensionsDimensions|DATAXxRENDER_PT_antialiasingRENDER_PT_antialiasingAnti-Aliasing:|:DATAXxRENDER_PT_motion_blurRENDER_PT_motion_blurSampled Motion Blur"|DATAXXRENDER_PT_shadingRENDER_PT_shadingShading |DATAXXRENDER_PT_performanceRENDER_PT_performancePerformance|DATAXXRENDER_PT_post_processingRENDER_PT_post_processingPost Processing|DATAX8RENDER_PT_stampRENDER_PT_stampStamp| DATAX8RENDER_PT_outputRENDER_PT_outputOutput(| DATAX8RENDER_PT_bakeRENDER_PT_bakeBake| DATAx DATA (H8i? hDATA(  @qDA=DA=DA=DA?? iDATA(  C@FCF++?@ ,%DATA( CfCww?@ xf"DATA(h#C#Cyy?@ zhDATA(h%DATA`?J?PףD>3;Q?Fwi?JF>#,TY!e?*=>o?E>Fwi?TY5;JF>!e?Q?#,+=>`DAoy@?>ޠQQuZ?> .>#,>m6uU?F +!>?`5hąC% ÈG6DWѦCGBD>3;Q?Fwi?JF>#,TY!e?*=>o?>ޠQQuZ?> .>#,>m7?8˔oAoAk;?! BVBt~BDATA8333?? Ax B? #<C DATA ghHHhDATA(hCADADADA?? DATA(hD3CDCMM?? NNgNDATA(1VDATA1VDATAH>>> pythonDATAx$h8~!!x DATA(x CACACACA?? ~DATA(x CC}||?? }~DATA!DATAH#DATAH#زȻxDATAx$XHi ?H(H(h%&DATA(h%&CA>DA=DA=DA?? iDATA(&h%DDD)dD.>CC$ #<zD %%%DATAH( =z||SN+xrxSRUV Editing,/h0485XaDATA ,X-DATA X--,DATA -8.X-~DATA 8..-~DATA ./8.DATA //.~DATA ///DATA //DATA(h00X--DATA(0H1h0X-.DATA(H110-/DATA(1(2H1./DATA((221./DATA(23(2,/DATA(3x32,.DATA(x333//DATA(3X4x3//DATA(X4438./DATA(4X48./DATA859.X--/~qq(67DATA((67 DADA~DADA?? ~DATA(7(6mEmEpoo?? pDATA9Xa85,.//??9x>DATA(9h;CArDAqDAqDA?? DATA(h;x>9[CsJCs?@ <<DATAX<IMAGE_PT_gpencilIMAGE_PT_gpencilGrease PencilPDATA(x>h;CC33+?33@DATA(!?dA>d>ddd?DATAXa9///8.~hphpHbHkDATA(Hbc@qDAmDA@mDA@mDA?? ~DATA(cfHb CVCVWW?@ XXhX(e(eDATAX(eVIEW3D_PT_tools_objectmodeVIEW3D_PT_tools_objectmodeObject ToolsDATA(fic!CfC[Zww?@ xxhx"8h8hDATAX8hVIEW3D_PT_last_operatorVIEW3D_PT_last_operatorOperatorDATA(iHkf#C~#C~  ?@  ~~DATA(Hkii~lDATA`lH?? JLD>3;Q?Fwi?JF>#,TY!e?*=>_?E>Fwi?TY4;JF>!e?Q?#,+=>6@_?? ?0QQ?X>?>#,>ՒΜz?T*=dbR@_@y\>,? (K5>}Q?sMd@JWA.Xj@-@D>3;Q?Fwi?JF>#,TY!e?*=>_? ?0QQ?X>?>#,>ՒΜz?T*=dbR@_@>>>?\>7?8˔_@_@r:?! BUBt~BDATA8hp333?? Ax B?=C SNxr+SRVideo EditingshxxHDATA stDATA txtsDATA xttt~DATA tXuxt~DATA XuutDATA u8vXu~DATA 8vvu~DATA vw8v\DATA wwvPDATA wwwDATA whxwPDATA hxw~\DATA(xHytxtDATA(HyyxtXuDATA(y(zHyxtuDATA((zzyXuuDATA(z{(zu8vDATA({x{zsvDATA(x{{{XuwDATA({X|x{vwDATA(X||{wwDATA(|8}X|wwDATA(8}}|8vhxDATA(}~8}thxDATA(~~}vhxDATA(~~~stDATA(~h~uwDATA(h~8vwDATA(HhXuwDATA(H8vwDATAXutxtu~DATA( DADA~DADA?? ~DATA(mEmEpoo?? pDATAxsvhxt~[\XXxDATA(x DADA~DADA?? ~DATA(x@~CHBpF}CHB~~A?HB|HHB= AHB~[BDATAXDATAxhvw8vhx~]((hDATA(h؋DADA~DADA?? ~]vDATA(؋Hh\CKCpp?@ qq~wqDATA(H؋ppDDppDD;F;F'7PGDATA(HzCAzCApp A@|HB #<BiqwqDATA(@DATAhxwXuwwOPXDATA(Xȓ@wDATDAOSDASDA?? PPOPDATA(ȓ8XHCpHC?? DATA(8ȓOODATA(8C@zC Avvo:o:|HPCGiwOwDATAXDATAhXDATAhwwu8vQ~.HDATA(hCADA-DADA?? ..Q~.DATA(h؝~~DATA(؝HhCCđDFFD-;F;F'7PG..Q~.DATA(H؝zCAzCAKK A@|HB #<BiLDATA@SCSCScenetageainxز88TH?>mWC ??_??BLENDER_RENDERD?fC?`KPRBreA << ?8=?DATA`DATA(8dDATA(8.ȻDATA(.xDATA8VT?L?B ?o:= ??P2 HB2 B2 HB2 HB2 HB2 HB2 HB>? #<===ff??AHz?=???C#y??DATA88V]DATA8T]DATA`dd|AJA6V{?DATAXHRenderLayerrCACACameraamera.001?=B B@?LA!LALamp ?????AB>??ذ.?A4B?@@L=@ ???o:??????@?????hDATA@ذO????C?55?55?R??????DATARM??DATA(h WOزWOWorldrcP=rcP=rcP=6$<6$<6$<??A @A@pA A?L= ף;>??DATA( OB xtȻOBCameraamera.001   ne@>N@???*?91<"P?????ޕ/?5F:?81V~>75e?'?T3>ne@>N@??????33?3?5)?ݕ/?V~'?3F:?>T8175e?4>Z& 4?OBd8???>6 ?u=?????DATAw??=L> ף<OB ȻtxOBLamp   p@?p@???{&?W+b=?????6씾t? bfE9L"?%?_>oK?p@?p@??????22?3?'4'?6씾fE&?t?9L_> b#?oK? ?Af ?DOBd8?<?>">u=??@???8DATA8w??=L> ף<OB tȻOBTextXT  ?????????ӻ+?ӻ+??????????ӻ+?ӻ+??d8? #=?>=???????@???XME.MEMeshVNZRKTh yW7Zt?W>ף`? >?CDATAhKTTNDATAx N46^?U>]2FX?U>IIX?>I,?>A?{c?^F~?II~? ף=III? ף=!{V?U>III?U>II?IV?II|??e\Xl?'?[ XG>?W?XX4??T6$Xٍ?ē?O.X_??H8X|?S?:A:AXլ?z ?8HX?u!?.OX|T?@"?6$TX~?"?XX?3#? [X:?S#?e\Xoʧ?3#?o[X?"?CXX?@"?TXK?u!?+тOX’?z ?{HX?S?ƾ:AXX??8Xڢ?“?~.XAu??6$X.*?W?X?%?z X??X??zoX-*?\-?CX@u? ?۪Xڢ?\?~+ѳXX? ?{ǹX?'1 ?ƾƾX?G ?{XK?R ?+~X?D ?X?u?CXnʧ?2Q?ozX:?'1?X?3Q? zX~?v?X{T?D ?6$X?S ?.~Xլ?H ?8X|?(1 ?:AƾX^? ?H{ǹX؍?]?O+ѳX3? ?T۪XF>?]-?XCXl??[oX?.?_X:G@5?.?LUL(1h? |F3?.?M8VUM?.?ej:G$f?ĻǦMCk?Ļ8ѪLCk?ĻR꽜8Ѫ $f?ĻR꽻Ǧ?.?Rej:tF3?.?RM8VU(1h?R "@5?.?R꽞LU?.?R_X:kl??R꽆[ojF>?]-?RXC`3? ?RTV؍?]?R꽂O+M^? ?RH{G|?(1 ?R:AƾEլ?H ?R꽅8G?S ?R.~M{T?D ?R6$V~?v?R꽽`?3Q?R꽑 zj:?'1?Rmnʧ?2Q?Rozj?u?RC`?D ?RVK?R ?R+~M?G ?R{G?'1 ?RƾƾEX? ?R{Gڢ?\?R~+M@u? ?RV-*?\-?RC`??Rzoj??R꽛m?%?Rz j.*?W?R`Au??R6$Vڢ?“?R~.MX??R8G?S?Rƾ:AE’?z ?R{HGK?u!?R+тOM?@"?RTV?"?RCX`oʧ?3#?Ro[j:?S#?Re\m?3#?R꽑 [j~?"?R꽽X`|T?@"?R6$TV?u!?R.OMլ?z ?R꽅8HG|?S?R:A:AE_??RH8Gٍ?ē?R꽂O.M4??RT6$VG>?W?RX`l?'?R꽆[ j|??Re\mV?RI?R?U>RIV?U>RII? ף=R꽴߄~? ף=RII~?RIc?R^6,?>RA?X?>RX?U>RI6^?U>R꽰]28DATAhhTZRDATAZR17"  """" "  "" "  " " " " # $ % ;" " " # "! " " ! "  "  "  "  "  "  "  " """"""" " !"!"""#"#$"$%"%&"%: %; &'"&9 &: '("'8 '9 ()"(7 (8 )*")6 )7 *+"*5 *6 +,"+4 +5 ,-",3 ,4 -."-2 -3 ./".1 .2 /0"/1 01"12"23"34"45"56"67"78"89"9:":;"<="<> <B"=>">?">A >B ?@"?A @A"AB"AD"CD"BC"@E"DE"?F"EF">G"FG"=H"GH"CI"<I"HI":K"JK";J"9L"KL"8M"LM"7N"MN"6O"NO"5P"OP"4Q"PQ"3R"QR"2S"RS"1T"ST"0U"TU"/V"UV".W"VW"-X"WX",Y"XY"+Z"YZ"*["Z[")\"[\"(]"\]"'^"]^"&_"^_"%`"_`"$a"`a"#b"ab""c"bc"!d"cd" e"de"f"ef"g"fg"h"gh"i"hi"j"ij"k"jk"l"kl"m"lm"n"mn"o"no"p"op"q"pq"r"qr"s"rs"t"st"u"tu"v"uv"w"vw" x"wx"Jy" y"xy" {"z{" z" |"{|"z}"}"|}""~"~"""""""""""~""" ~ ~  ln lo ko kp jp jq iq ir hr hs gs gt ft fu eu ev dv dw cw cx bx by ay `y J` K` K_ L_ L^ M^ M] N] N\ O\ O[ P[ PZ QZ QY RY RX SX SW TW TV {} DF DG GI CG DATAhyWTVDATAtV0  ! !"!" # "# $ #% $%; %:;&:%&9:'9&'89(8'(78)7()67*6)*56+5*+45,4+,34-3,-23.2-.12/1./01  A?@A>?><=>B<AB>BADCA@ED@?FE?>GF>=HG<BCI=<IH;:KJ:9LK98ML87NM76ON65PO54QP43RQ32SR21TS10UT0/VU/.WV.-XW-,YX,+ZY+*[Z*)\[)(]\('^]'&_^&%`_%$a`$#ba#"cb"!dc! ed fegfhgihjikjlkmlnmonpoqprqsrtsutvuwv xw ;Jy yx {z |{ z} }|~~~~~mnlnollokopkkpjpqjjqiqriirhrshhsgstggtftuffueuveevdvwddwcwxccxbxybbyaay`yJ`JK``K_KL__L^LM^^M]MN]]N\NO\\O[OP[[PZPQZZQYQRYYRXRSXXSWSTWWTVTUV|}{}z{EFDFGDHIGICGGCDBR1S7BRAddh.001?H6??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA2??????????L>?????????????????????????????DATA@H6O????C?~6=~.=U??????DATA0UM?>k?@? ף=?BR7S(=1BRBlob001?;??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATA@8??????????L>?????????????????????????????DATA@;O????C?._ra<??????DATA0<M?>ףp?@?u=?BR(=SxB7BRBlur.004?h@??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA=??????????L>?????????????????????????????DATA@h@O????C?~6=~.=A??????DATA0AM?>k?@? ף=?BRxBSG(=BRBrush?E??????????L>?????????????????????????????# Kfff?=??????>!?>>>>?DATAB??????????L>?????????????????????????????DATA@EO????C?._raHG??????DATA0HGM?>ףp?@?u=?BRGSMxBBRClay001?K??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATA0H??????????L>?????????????????????????????DATA@KO????C?._raL??????DATA0LM?>ףp?@?u=?BRMShRGBRClone001?XP??????????L>?????????????????????????????# Kfff?=???333???>!>???DATAM??????????L>?????????????????????????????DATA@XPO????C?~6=~.=Q??????DATA0QM?>k?@? ף=?BRhRSWMBRCrease001?U??????????L>?????????????????????????????# Kfff?=???>??>!>?>>>>?DATAR??????????L>?????????????????????????????DATA@UO????C?a2p? 8W??????DATA08WM?>?@? #=?BRWS]hRBRDarken06?Z??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA X??????????L>?????????????????????????????DATA@ZO????C?~6=~.=\??????DATA0\M?>k?@? ף=?BR]SXbWBRDraw.001?H`??????????L>?????????????????????????????# Kfff?=??????>!>?>>>>?DATAp]??????????L>?????????????????????????????DATA@H`O????C?._raa??????DATA0aM?>ףp?@?u=?BRXbSg]BRFill/Deepen001?e??????????L>?????????????????????????????# Kfff?=???? ??>!>??>>??DATAb??????????L>?????????????????????????????DATA@eO????C?._ra(g??????DATA0(gM?>ףp?@?u=?BRgSlXbBRFlatten/Contrast001?j??????????L>?????????????????????????????# Kfff?=??????>!>??>>??DATAh??????????L>?????????????????????????????DATA@jO????C?._raxl??????DATA0xlM?>ףp?@?u=?BRlSHrgBRGrab001?8p??????????L>?????????????????????????????K Kfff?=???L>??>!>>?>DATA`m??????????L>?????????????????????????????DATA@8pO????C?._raq??????DATA0qM?>ףp?@?u=?BRHrSwlBRInflate/Deflate001?u??????????L>?????????????????????????????# Kfff?=??????>!>@?@?@?>>>DATAr??????????L>?????????????????????????????DATA@uO????C?._raw??????DATA0wM?>ףp?@?u=?BRwS|HrBRLayer001?z??????????L>?????????????????????????????# Kfff?=??????>!>?>>DATAx??????????L>?????????????????????????????DATA@zO????C?._rah|??????DATA0h|M?>ףp?@?u=?BR|S8wBRLighten5?(??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATAP}??????????L>?????????????????????????????DATA@(O????C?~6=~.=??????DATA0M?>k?@? ף=?BR8S|BRMixh?x??????????L>????????????????????????????? # Kfff?=???333???>!>???DATA??????????L>?????????????????????????????DATA@xO????C?~6=~.=??????DATA0M?>k?@? ף=?BRS،8BRMultiply?Ȋ??????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA??????????L>?????????????????????????????DATA@ȊO????C?~6=~.=X??????DATA0XM?>k?@? ף=?BR،S(BRNudge001???????????L>?????????????????????????????# Kfff?=???? ??>!>>?>DATA@??????????L>?????????????????????????????DATA@O????C?._ra??????DATA0M?>ףp?@?u=?BR(Sx،BRPinch/Magnify001?h??????????L>?????????????????????????????# Kfff?=??????>!>@?@?@?>>>DATA??????????L>?????????????????????????????DATA@hO????C?._ra??????DATA0M?>ףp?@?u=?BRxSȜ(BRPolish001???????????L>?????????????????????????????# Kfff?=???????>!>??>>??DATA??????????L>?????????????????????????????DATA@O????C?._raH??????DATA0HM?>ףp?@?u=?BRȜSxBRScrape/Peaks001???????????L>?????????????????????????????# Kfff?=???? ??>!>??>>??DATA0??????????L>?????????????????????????????DATA@O????C?._ra??????DATA0M?>ףp?@?u=?BRShȜBRSculptDraw?X??????????L>?????????????????????????????# Kfff?=??????>!wN??>>>>?DATA??????????L>?????????????????????????????DATA@XO????C?._ra??????DATA0M?>ףp?@?u=?BRhSBRSmear001???????????L>?????????????????????????????# Kfff?=???L>??>!>???DATAЧ??????????L>?????????????????????????????DATA@O????C?~6=~.=8??????DATA08M?>k?@? ף=?BRShBRSmooth001???????????L>?????????????????????????????#Kfff?=??????>!>@?@?@?DATA ??????????L>?????????????????????????????DATA@O????C?._ra??????DATA0M?>ףp?@?u=?BRSXBRSnake Hook001?H??????????L>?????????????????????????????K Kfff?=???? ??>!>>?>DATAp??????????L>?????????????????????????????DATA@HO????C?._raض??????DATA0ضM?>ףp?@?u=?BRXSBRSoften01???????????L>?????????????????????????????# Kfff?=???L>??>!>???DATA??????????L>?????????????????????????????DATA@O????C?~6=~.=(??????DATA0(M?>k?@? ף=?BRSXBRSubtract???????????L>????????????????????????????? # Kfff?=???L>??>!>???DATA??????????L>?????????????????????????????DATA@O????C?~6=~.=x??????DATA0xM?>k?@? ף=?BRSHBRTexDraw?8??????????L>?????????????????????????????# Kfff?=???333???>!>???>>?DATA`??????????L>?????????????????????????????DATA@8O????C?._ra??????DATA0M?>ףp?@?u=?BRHSBRThumb001???????????L>?????????????????????????????K Kfff?=???? ??>!>>?>DATA??????????L>?????????????????????????????DATA@O????C?._ra??????DATA0M?>ףp?@?u=?BRSHBRTwist001???????????L>?????????????????????????????K Kfff?=??????>!>>?>DATA??????????L>?????????????????????????????DATA@O????C?._rah??????DATA0hM?>ףp?@?u=?DNA1d8SDNANAME *next*prev*data*first*lastxyxminxmaxyminymax*pointergroupvalval2typesubtypeflagname[32]saveddatalentotallen*newid*libname[24]usicon_id*propertiesid*idblock*filedataname[240]filepath[240]totpad*parentw[2]h[2]changed[2]changed_timestamp[2]*rect[2]*obblocktypeadrcodename[128]*bp*beztmaxrcttotrctvartypetotvertipoextraprtbitmaskslide_minslide_maxcurval*drivercurvecurshowkeymuteipoposrelativetotelempad2*weightsvgroup[32]sliderminslidermax*adt*refkeyelemstr[32]elemsizeblock*ipo*fromtotkeyslurph*line*formatblenlinenostartendpad1flagscolor[4]pad[4]*namenlineslines*curl*sellcurcselcmarkers*undo_bufundo_posundo_len*compiledmtimesizeseekdtxpassepartalphaclipstaclipendlensortho_scaledrawsizeshiftxshiftyYF_dofdist*dof_ob*sceneframenrframesoffsetsfrafie_imacyclokmulti_indexlayerpassibufs*gputexture*anim*rr*renders[8]render_slotlast_render_slotsourcelastframetpageflagtotbindxrepyreptwstatwendbindcode*repbind*packedfile*previewlastupdatelastusedanimspeedgen_xgen_ygen_typeaspxaspytexcomaptomaptonegblendtype*object*texuvname[32]projxprojyprojzmappingofs[3]size[3]rottexflagcolormodelpmaptopmaptonegnormapspacewhich_outputbrush_map_modepad[7]rgbkdef_varcolfacvarfacnorfacdispfacwarpfaccolspecfacmirrfacalphafacdifffacspecfacemitfachardfacraymirrfactranslfacambfaccolemitfaccolreflfaccoltransfacdensfacscatterfacreflfactimefaclengthfacclumpfacdampfackinkfacroughfacpadensfacgravityfaclifefacsizefacivelfacfieldfacshadowfaczenupfaczendownfacblendfacname[160]*handle*pname*stnamesstypesvars*varstr*result*cfradata[32](*doit)()(*instance_init)()(*callback)()versionaipotype*ima*cube[6]imat[4][4]obimat[3][3]stypeviewscalenotlaycuberesdepthrecalclastsizefalloff_typefalloff_softnessradiuscolor_sourcetotpointspdpadpsyspsys_cache_spaceob_cache_space*point_tree*point_datanoise_sizenoise_depthnoise_influencenoise_basispdpad3[3]noise_facspeed_scalefalloff_speed_scalepdpad2*coba*falloff_curveresol[3]interp_typefile_formatextendsmoked_typeint_multiplierstill_framesource_path[240]*datasetcachedframenoisesizeturbulbrightcontrastsaturationrfacgfacbfacfiltersizemg_Hmg_lacunaritymg_octavesmg_offsetmg_gaindist_amountns_outscalevn_w1vn_w2vn_w3vn_w4vn_mexpvn_distmvn_coltypenoisedepthnoisetypenoisebasisnoisebasis2imaflagcropxmincropymincropxmaxcropymaxtexfilterafmaxxrepeatyrepeatcheckerdistnablaiuser*nodetree*plugin*env*pd*vduse_nodesloc[3]rot[3]mat[4][4]min[3]max[3]modetotexshdwrshdwgshdwbshdwpadenergydistspotsizespotblendhaintatt1att2*curfalloffshadspotsizebiassoftcompressthreshpad5[3]bufsizesampbuffersfiltertypebufflagbuftyperay_sampray_sampyray_sampzray_samp_typearea_shapearea_sizearea_sizeyarea_sizezadapt_threshray_samp_methodtexactshadhalostepsun_effect_typeskyblendtypehorizon_brightnessspreadsun_brightnesssun_sizebackscattered_lightsun_intensityatm_turbidityatm_inscattering_factoratm_extinction_factoratm_distance_factorskyblendfacsky_exposuresky_colorspacepad4[6]*mtex[18]pr_texturepad6[6]densityemissionscatteringreflectionemission_col[3]transmission_col[3]reflection_col[3]density_scaledepth_cutoffasymmetrystepsize_typeshadeflagshade_typeprecache_resolutionstepsizems_diffms_intensityms_spreadmaterial_typespecrspecgspecbmirrmirgmirbambrambbambgambemitangspectraray_mirroralpharefspeczoffsaddtranslucencyvolfresnel_mirfresnel_mir_ifresnel_trafresnel_tra_ifiltertx_limittx_falloffray_depthray_depth_traharseed1seed2gloss_mirgloss_trasamp_gloss_mirsamp_gloss_traadapt_thresh_miradapt_thresh_traaniso_gloss_mirdist_mirfadeto_mirshade_flagmode_lflarecstarclinecringchasizeflaresizesubsizeflarebooststrand_stastrand_endstrand_easestrand_surfnorstrand_minstrand_widthfadestrand_uvname[32]sbiaslbiasshad_alphaseptexrgbselpr_typepr_backpr_lampml_flagdiff_shaderspec_shaderroughnessrefracparam[4]rmsdarkness*ramp_col*ramp_specrampin_colrampin_specrampblend_colrampblend_specramp_showpad3rampfac_colrampfac_spec*groupfrictionfhreflectfhdistxyfrictdynamodesss_radius[3]sss_col[3]sss_errorsss_scalesss_iorsss_colfacsss_texfacsss_frontsss_backsss_flagsss_presetmapto_texturedshadowonly_flaggpumaterialname[256]*bbi1j1k1i2j2k2selcol1selcol2zquat[4]expxexpyexpzradrad2s*mat*imatelemsdisp*editelems**matflag2totcolwiresizerendersizethresh*lastelemvec[3][3]alfaweighth1h2f1f2f3hidevec[4]mat_nrpntsupntsvresoluresolvorderuordervflaguflagv*knotsu*knotsvtilt_interpradius_interpcharidxkernwhnurbs*keyindexshapenrnurb*editnurb*bevobj*taperobj*textoncurve*path*keybevdrawflagtwist_modetwist_smoothsmallcaps_scalepathlenbevresolwidthext1ext2resolu_renresolv_renactnu*lastselspacemodespacinglinedistshearfsizewordspaceulposulheightxofyoflinewidth*str*selboxes*editfontfamily[24]*vfont*vfontb*vfonti*vfontbisepcharctimetotboxactbox*tbselstartselend*strinfocurinfo*mface*mtface*tface*mvert*medge*dvert*mcol*msticky*texcomesh*mselect*edit_meshvdataedatafdatatotedgetotfacetotselectact_facesmoothreshsubdivsubdivrsubsurftypeeditflag*mr*pv*tpageuv[4][2]col[4]transptileunwrapv1v2v3v4edcodecreasebweightdef_nr*dwtotweightco[3]no[3]uv[2]co[2]indexfis[256]totdisp(*disps)()v[4]midpad[2]v[2]*faces*colfaces*edges*vertslevelslevel_countcurrentnewlvledgelvlpinlvlrenderlvluse_col*edge_flags*edge_creases*vert_map*edge_map*old_faces*old_edgesstackindex*errormodifier*texture*map_objectuvlayer_name[32]uvlayer_tmptexmappingsubdivTyperenderLevels*emCache*mCachedefaxispad[6]lengthrandomizeseed*ob_arm*start_cap*end_cap*curve_ob*offset_oboffset[3]scale[3]merge_distfit_typeoffset_typecountaxistolerance*mirror_obsplit_anglevalueresval_flagslim_flagse_flagsbevel_angledefgrp_name[32]*domain*flow*colltimepad10strengthdirectionmidlevel*projectors[10]*imagenum_projectorsaspectxaspectyscalexscaleypercentfaceCountfacrepeat*objectcenterstartxstartyheightnarrowspeeddampfallofftimeoffslifetimedeformflagmulti*prevCossubtarget[32]parentinv[4][4]cent[3]*indexartotindexforce*clothObject*sim_parms*coll_parms*point_cacheptcaches*x*xnew*xold*current_xnew*current_x*current_v*mfacesnumvertsnumfacestime_xtime_xnew*bvhtree*v*dmcfraoperationvertextotinfluencegridsize*bindinfluences*bindoffsets*bindcagecostotcagevert*dyngrid*dyninfluences*dynverts*pad2dyngridsizedyncellmin[3]dyncellwidthbindmat[4][4]*bindweights*bindcos(*bindfunc)()*psystotdmverttotdmedgetotdmfacepositionrandom_position*facepavgroupprotectlvlsculptlvltotlvlsimple*fss*target*auxTargetvgroup_name[32]keepDistshrinkTypeshrinkOptsprojAxissubsurfLevels*originfactorlimit[2]originOptsoffset_faccrease_innercrease_outercrease_rimmat_ofsmat_ofs_rim*ob_axisstepsrender_stepsiterscrew_ofsangle*object_from*object_tofalloff_radius*lattpntswopntsuopntsvopntswtypeutypevtypewfufvfwdudvdw*def*latticedatalatmat[4][4]*editlattvec[8][3]*sculptpartypepar1par2par3parsubstr[32]*track*proxy*proxy_group*proxy_from*action*poselib*pose*gpdavs*mpathconstraintChannelseffectdefbasemodifiersrestore_mode*matbitsactcoldloc[3]orig[3]dsize[3]drot[3]dquat[4]rotAxis[3]drotAxis[3]rotAngledrotAngleobmat[4][4]constinv[4][4]imat_ren[4][4]laycolbitstransflagprotectflagtrackflagupflagnlaflagipoflagipowinscaflagscavisflagboundtypedupondupoffdupstadupendsfmassdampinginertiaformfactorrdampingmarginmax_velmin_velm_contactProcessingThresholdrotmodedtempty_drawtypepad1[3]empty_drawsizedupfacescapropsensorscontrollersactuatorsbbsize[3]actdefgameflaggameflag2*bsoftsoftflaganisotropicFriction[3]constraintsnlastripshooksparticlesystem*soft*dup_groupfluidsimFlagrestrictflagshapeflagrecalcobody_type*fluidsimSettings*derivedDeform*derivedFinallastDataMaskcustomdata_maskstateinit_stategpulamppc_ids*duplilistima_ofs[2]pad3[8]curindexactiveoriglayno_drawanimatedomat[4][4]orco[3]deflectforcefieldshapetex_modekinkkink_axiszdirf_strengthf_dampf_flowf_sizef_powermaxdistmindistf_power_rmaxradminradpdef_damppdef_rdamppdef_permpdef_frictpdef_rfrictpdef_sticknessabsorptionpdef_sbdamppdef_sbiftpdef_sboftclump_facclump_powkink_freqkink_shapekink_ampfree_endtex_nabla*rngf_noiseweight[13]global_gravityrt[3]totdataframetotpointdata_types*data[8]*cur[8]extradatastepsimframestartframeendframeeditframelast_exactcompressionname[64]prev_name[64]info[64]path[240]*cached_framesmem_cache*edit(*free_edit)()linStiffangStiffvolumeviterationspiterationsditerationsciterationskSRHR_CLkSKHR_CLkSSHR_CLkSR_SPLT_CLkSK_SPLT_CLkSS_SPLT_CLkVCFkDPkDGkLFkPRkVCkDFkMTkCHRkKHRkSHRkAHRcollisionflagsnumclusteriterationsweldingtotspring*bpoint*bspringmsg_lockmsg_valuenodemassnamedVG_Mass[32]gravmediafrictrklimitphysics_speedgoalspringgoalfrictmingoalmaxgoaldefgoalvertgroupnamedVG_Softgoal[32]fuzzynessinspringinfrictnamedVG_Spring_K[32]efraintervallocalsolverflags**keystotpointkeysecondspringcolballballdampballstiffsbc_modeaeroedgeminloopsmaxloopschokesolver_IDplasticspringpreload*scratchshearstiffinpush*pointcache*effector_weightslcom[3]lrot[3][3]lscale[3][3]pad4[4]vel[3]*fmdshow_advancedoptionsresolutionxyzpreviewresxyzrealsizeguiDisplayModerenderDisplayModeviscosityValueviscosityModeviscosityExponentgrav[3]animStartanimEndbakeStartbakeEndgstarmaxRefineiniVelxiniVelyiniVelz*orgMesh*meshBBsurfdataPath[240]bbStart[3]bbSize[3]typeFlagsdomainNovecgenvolumeInitTypepartSlipValuegenerateTracersgenerateParticlessurfaceSmoothingsurfaceSubdivsparticleInfSizeparticleInfAlphafarFieldSize*meshVelocitiescpsTimeStartcpsTimeEndcpsQualityattractforceStrengthattractforceRadiusvelocityforceStrengthvelocityforceRadiuslastgoodframemistypehorrhorghorbzenrzengzenbfastcolexposureexprangelinfaclogfacgravityactivityBoxRadiusskytypeocclusionResphysicsEngineticratemaxlogicstepphysubstepmaxphystepmisimiststamistdistmisthistarrstargstarbstarkstarsizestarmindiststardiststarcolnoisedofstadofenddofmindofmaxaodistaodistfacaoenergyaobiasaomodeaosampaomixaocolorao_adapt_threshao_adapt_speed_facao_approx_errorao_approx_correctionao_indirect_energyao_env_energyao_pad2ao_indirect_bouncesao_padao_samp_methodao_gather_methodao_approx_passes*aosphere*aotablespad[3]selcolsxsy*lpFormat*lpParmscbFormatcbParmsfccTypefccHandlerdwKeyFrameEverydwQualitydwBytesPerSeconddwFlagsdwInterleaveEveryavicodecname[128]*cdParms*padcdSizeqtcodecname[128]codecTypecodecSpatialQualitycodeccodecFlagscolorDepthcodecTemporalQualityminSpatialQualityminTemporalQualitykeyFrameRatebitRateaudiocodecTypeaudioSampleRateaudioBitDepthaudioChannelsaudioCodecFlagsaudioBitRateaudio_codecvideo_bitrateaudio_bitrateaudio_mixrateaudio_volumegop_sizerc_min_raterc_max_raterc_buffer_sizemux_packet_sizemux_ratemixratemainspeed_of_sounddoppler_factordistance_model*mat_override*light_overridelay_zmasklayflagpassflagpass_xor*avicodecdata*qtcodecdataqtcodecsettingsffcodecdatasubframepsfrapefraimagesframaptothreadsframelenblurfacedgeRedgeGedgeBfullscreenxplayyplayfreqplayattribframe_stepstereomodedimensionspresetmaximsizexschyschxpartsypartsplanesimtypesubimtypequalitydisplaymodescemoderaytrace_optionsraytrace_structurerendererocrespad4alphamodeosafrs_secedgeintsafetyborderdisprectlayersactlaymblur_samplesxaspyaspfrs_sec_basegausscolor_mgt_flagpostgammaposthuepostsatdither_intensitybake_osabake_filterbake_modebake_flagbake_normal_spacebake_quad_splitbake_maxdistbake_biasdistbake_padpic[240]stampstamp_font_idstamp_udata[160]fg_stamp[4]bg_stamp[4]seq_prev_typeseq_rend_typeseq_flagpad5[5]simplify_flagsimplify_subsurfsimplify_shadowsamplessimplify_particlessimplify_aossscineonwhitecineonblackcineongammajp2_presetjp2_depthrpad3domeresdomemodedomeangledometiltdomeresbuf*dometextengine[32]particle_percsubsurf_maxshadbufsample_maxao_errortiltresbuf*warptextcol[3]matmodeframingrt1rt2domestereoflageyeseparation*camera*brush*paint_cursorpaint_cursor_col[4]paintseam_bleednormal_anglescreen_grab_size[2]*paintcursorinverttotrekeytotaddkeybrushtypebrush[7]emitterdistselectmodeedittypedraw_stepfade_framesname[36]mat[3][3]radial_symm[3]last_xlast_ylast_angledraw_anchoredanchored_sizeanchored_location[3]anchored_initial_mouse[2]draw_pressurepressure_valuespecial_rotation*vpaint_prev*wpaint_prev*vpaint*wpaintvgroup_weightcornertypeeditbutflagjointrilimitdegrturnextr_offsdoublimitnormalsizeautomergesegmentsringsverticesunwrapperuvcalc_radiusuvcalc_cubesizeuvcalc_marginuvcalc_mapdiruvcalc_mapalignuvcalc_flaguv_flaguv_selectmodeuv_padgpencil_flagsautoik_chainlenimapaintparticleproportional_sizeselect_threshclean_threshautokey_modeautokey_flagretopo_moderetopo_paint_toolline_divellipse_divretopo_hotspotmultires_subdiv_typeskgen_resolutionskgen_threshold_internalskgen_threshold_externalskgen_length_ratioskgen_length_limitskgen_angle_limitskgen_correlation_limitskgen_symmetry_limitskgen_retarget_angle_weightskgen_retarget_length_weightskgen_retarget_distance_weightskgen_optionsskgen_postproskgen_postpro_passesskgen_subdivisions[3]skgen_multi_level*skgen_templatebone_sketchingbone_sketching_convertskgen_subdivision_numberskgen_retarget_optionsskgen_retarget_rollskgen_side_string[8]skgen_num_string[8]edge_modeedge_mode_live_unwrapsnap_modesnap_flagsnap_targetproportionalprop_modeproportional_objectsauto_normalizesculpt_paint_settingssculpt_paint_unified_sizesculpt_paint_unified_unprojected_radiussculpt_paint_unified_alphatotobjtotlamptotobjseltotcurvetotmeshtotarmaturescale_lengthsystemsystem_rotationgravity[3]quick_cache_step*world*setbase*basact*obeditcursor[3]twcent[3]twmin[3]twmax[3]layactlay_updatedcustomdata_mask_modal*ed*toolsettings*statsaudiotransform_spaces*sound_scene*sound_scene_handle*sound_scrub_handle*fps_info*theDagdagisvaliddagflagspad6pad5active_keyingsetkeyingsetsgmunitphysics_settingsblendviewwinmat[4][4]viewmat[4][4]viewinv[4][4]persmat[4][4]persinv[4][4]viewmatob[4][4]persmatob[4][4]twmat[4][4]viewquat[4]zfaccamdxcamdypixsizecamzoomtwdrawflagis_persprflagviewlockperspclip[6][4]clip_local[6][4]*clipbb*localvd*ri*depths*sms*smooth_timerlviewquat[4]lpersplviewgridviewtwangle[3]padfregionbasespacetypeblockscaleblockhandler[8]lay_used*ob_centrebgpicbase*bgpicob_centre_bone[32]drawtypeob_centre_cursorscenelockaroundgridnearfarmodeselectgridlinesgridsubdivgridflagtwtypetwmodetwflagpad2[2]afterdraw_transpafterdraw_xrayafterdraw_xraytranspzbufxrayndofmodendoffilter*properties_storageverthormaskmin[2]max[2]minzoommaxzoomscrollscroll_uikeeptotkeepzoomkeepofsalignwinxwinyoldwinxoldwiny*tab_offsettab_numtab_currpt_maskv2d*adsghostCurvesautosnapcursorValmainbmainbomainbuserre_alignpreviewtexture_contextpathflagdataicon*pinidrender_sizechanshownzebrazoomtitle[32]dir[240]file[80]renamefile[80]renameedit[80]filter_glob[64]active_filesel_firstsel_lastsortdisplayf_fpfp_str[8]scroll_offset*params*files*folders_prev*folders_next*op*smoothscroll_timer*layoutrecentnrbookmarknrsystemnrtree*treestoresearch_string[32]search_tseoutlinevisstoreflagsearch_flags*cumapscopessample_line_histcursor[2]centxcentycurtileimtypenrlockpindt_uvstickydt_uvstretch*texttopviewlinesmenunrlheightcwidthlinenrs_totleftshowlinenrstabnumbershowsyntaxline_hlightoverwritelive_editpix_per_linetxtscrolltxtbarwordwrapdopluginsfindstr[256]replacestr[256]margin_column*drawcache*py_draw*py_event*py_button*py_browsercallback*py_globaldictlastspacescriptname[256]scriptarg[256]*script*but_refs*arraycachescache_displayredraws*idaspect*curfontmxmy*edittreetreetypetexfromlinkdragtitle[24]menunumtilesxnumtilesyselstateviewrectbookmarkrectscrollposscrollheightscrollarearetvalactive_bookmarkprv_wprv_h(*returnfunc)()(*returnfunc_event)()(*returnfunc_args)()*arg1*arg2*menup*pupmenu*imglen_alloccursorscrollbackhistoryprompt[256]language[32]sel_startsel_endfilter[64]*area*soundsndnrfilename[256]blf_iduifont_idr_to_lpointskerningitalicboldshadowshadxshadyshadowalphashadowcolorpaneltitlegrouplabelwidgetlabelwidgetpanelzoomminlabelcharsminwidgetcharscolumnspacetemplatespaceboxspacebuttonspacexbuttonspaceypanelspacepanelouterpad[1]outline[4]inner[4]inner_sel[4]item[4]text[4]text_sel[4]shadedshadetopshadedownalpha_checkinner_anim[4]inner_anim_sel[4]inner_key[4]inner_key_sel[4]inner_driven[4]inner_driven_sel[4]wcol_regularwcol_toolwcol_textwcol_radiowcol_optionwcol_togglewcol_numwcol_numsliderwcol_menuwcol_pulldownwcol_menu_backwcol_menu_itemwcol_boxwcol_scrollwcol_progresswcol_list_itemwcol_stateiconfile[80]back[4]title[4]text_hi[4]header[4]header_title[4]header_text[4]header_text_hi[4]button[4]button_title[4]button_text[4]button_text_hi[4]list[4]list_title[4]list_text[4]list_text_hi[4]panel[4]panel_title[4]panel_text[4]panel_text_hi[4]shade1[4]shade2[4]hilite[4]grid[4]wire[4]select[4]lamp[4]active[4]group[4]group_active[4]transform[4]vertex[4]vertex_select[4]edge[4]edge_select[4]edge_seam[4]edge_sharp[4]edge_facesel[4]edge_crease[4]face[4]face_select[4]face_dot[4]extra_edge_len[4]extra_face_angle[4]extra_face_area[4]pad3[4]normal[4]vertex_normal[4]bone_solid[4]bone_pose[4]strip[4]strip_select[4]cframe[4]nurb_uline[4]nurb_vline[4]act_spline[4]nurb_sel_uline[4]nurb_sel_vline[4]lastsel_point[4]handle_free[4]handle_auto[4]handle_vect[4]handle_align[4]handle_sel_free[4]handle_sel_auto[4]handle_sel_vect[4]handle_sel_align[4]ds_channel[4]ds_subchannel[4]console_output[4]console_input[4]console_info[4]console_error[4]console_cursor[4]vertex_sizeoutline_widthfacedot_sizebpadsyntaxl[4]syntaxn[4]syntaxb[4]syntaxv[4]syntaxc[4]movie[4]image[4]scene[4]audio[4]effect[4]plugin[4]transition[4]meta[4]editmesh_active[4]handle_vertex[4]handle_vertex_select[4]handle_vertex_sizehpad[7]preview_back[4]solid[4]tuitbutstv3dtfiletipotinfotsndtacttnlatseqtimatimaseltexttoopsttimetnodetlogictuserpreftconsoletarm[20]active_theme_areamodule[64]spec[4]dupflagsavetimetempdir[160]fontdir[160]renderdir[240]textudir[160]plugtexdir[160]plugseqdir[160]pythondir[160]sounddir[160]image_editor[240]anim_player[240]anim_player_presetv2d_min_gridsizetimecode_styleversionsdbl_click_timegameflagswheellinescrolluiflaglanguageuserprefviewzoommixbufsizeaudiodeviceaudiorateaudioformataudiochannelsdpiencodingtransoptsmenuthreshold1menuthreshold2themesuifontsuistyleskeymapsaddonskeyconfigstr[64]undostepsundomemorygp_manhattendistgp_euclideandistgp_erasergp_settingstb_leftmousetb_rightmouselight[3]tw_hotspottw_flagtw_handlesizetw_sizetextimeouttexcollectratewmdrawmethoddragthresholdmemcachelimitprefetchframesframeserverportpad_rot_angleobcenter_diarvisizervibrightrecent_filessmooth_viewtxglreslimitndof_panndof_rotatecurssizecolor_picker_typeipo_newkeyhandles_newscrcastfpsscrcastwaitwidget_unitanisotropic_filterversemaster[160]verseuser[160]glalphacliptext_renderpad9coba_weightsculpt_paint_overlay_col[3]author[80]vertbaseedgebaseareabase*newsceneredraws_flagfulltempwiniddo_drawdo_refreshdo_draw_gesturedo_draw_paintcursordo_draw_dragswapmainwinsubwinactive*animtimer*contexthandler[8]*newvvec*v1*v2*typepanelname[64]tabname[64]drawname[64]ofsxofsysizexsizeylabelofsruntime_flagcontrolsnapsortorder*paneltab*activedatalist_scrolllist_sizelist_last_lenlist_grip_sizelist_search[64]*v3*v4*fullbutspacetypeheadertypespacedatahandlersactionzoneswinrctdrawrctswinidregiontypealignmentdo_draw_overlayuiblockspanels*headerstr*regiondatasubvstr[4]subversionpadsminversionminsubversionwinpos*curscreen*curscenefileflagsglobalfrevisionfilename[240]name[80]orig_widthorig_heightbottomrightxofsyofslift[3]gamma[3]gain[3]dir[160]donestartstillendstill*stripdata*crop*transform*color_balance*instance_private_data**current_private_data*tmpstartofsendofsmachinestartdispenddispsatmulhandsizeanim_preseek*strip*scene_cameraeffect_faderspeed_fader*seq1*seq2*seq3seqbase*scene_soundlevelpanscenenrmulticam_sourcestrobe*effectdataanim_startofsanim_endofsblend_modeblend_opacity*oldbasep*parseq*seqbasepmetastack*act_seqact_imagedir[256]act_sounddir[256]over_ofsover_cfraover_flagover_borderedgeWidthforwardwipetypefMinifClampfBoostdDistdQualitybNoCompScalexIniScaleyIniScalexFinScaleyFinxInixFinyIniyFinrotInirotFininterpolationuniform_scale*frameMapglobalSpeedlastValidFramebuttypeuserjitstatotpartnormfacobfacrandfactexfacrandlifeforce[3]vectsizemaxlendefvec[3]mult[4]life[4]child[4]mat[4]texmapcurmultstaticstepomattimetexspeedtexflag2negvertgroup_vvgroupname[32]vgroupname_v[32]*keysminfacnrusedusedelem*poinresetdistlastval*makeyqualqual2targetName[32]toggleName[32]value[32]maxvalue[32]delaydurationmaterialName[32]damptimerpropname[32]matname[32]axisflagposechannel[32]constraint[32]*fromObjectsubject[32]body[32]otypepulsefreqtotlinks**linkstapjoyindexaxis_singleaxisfbuttonhathatfprecisionstr[128]*mynewinputstotslinks**slinksvalostate_mask*actframeProp[32]blendinpriorityend_resetstrideaxisstridelengthmin_gainmax_gainreference_distancemax_distancerolloff_factorcone_inner_anglecone_outer_anglecone_outer_gainpad3[2]pitchsound3Dpad6[1]*melinVelocity[3]angVelocity[3]localflagdyn_operationforceloc[3]forcerot[3]linearvelocity[3]angularvelocity[3]*referenceminmaxrotdampminloc[3]maxloc[3]minrot[3]maxrot[3]matprop[32]butstabutenddistributionint_arg_1int_arg_2float_arg_1float_arg_2toPropName[32]*toObjectbodyTypefilename[64]loadaniname[64]int_argfloat_arg*subtargetgo*newpackedfileattenuationdistance*cache*playback_handle*lamprengobjectdupli_ofs[3]*propchildbaserollhead[3]tail[3]bone_mat[3][3]arm_head[3]arm_tail[3]arm_mat[4][4]arm_rollxwidthzwidthease1ease2rad_headrad_tailbonebasechainbase*edbo*act_bone*act_edbone*sketchlayer_usedlayer_protectedghostepghostsizeghosttypepathsizeghostsfghostefpathsfpathefpathbcpathac*pointsstart_frameend_frameghost_sfghost_efghost_bcghost_acghost_typeghost_stepghost_flagpath_typepath_steppath_viewflagpath_bakeflagpath_sfpath_efpath_bcpath_acconstflagikflagselectflagagrp_index*bone*childiktree*custom*custom_txeul[3]chan_mat[4][4]pose_mat[4][4]pose_head[3]pose_tail[3]limitmin[3]limitmax[3]stiffness[3]ikstretchikrotweightiklinweightchanbase*chanhashproxy_layerstride_offset[3]cyclic_offset[3]agroupsactive_groupiksolver*ikdata*ikparamproxy_act_bone[32]numiternumstepminstepmaxstepsolverfeedbackmaxveldampmaxdampepschannelscustomColcscurvesgroupsactive_markeridroot*source*filter_grpsearchstr[64]filterflagadstimeslide*grpname[30]ownspacetarspaceenforceheadtaillin_errorrot_error*tarmatrix[4][4]spacerotOrdertarnumtargetsiterationsrootbonemax_rootbone*poletarpolesubtarget[32]poleangleorientweightgrabtarget[3]numpointschainlenxzScaleModereserved1reserved2minmaxflagstuckcache[3]lockflagfollowflagvolmodeplaneorglengthbulgepivXpivYpivZaxXaxYaxZminLimit[6]maxLimit[6]extraFzinvmat[4][4]fromtomap[3]expofrom_min[3]from_max[3]to_min[3]to_max[3]rotAxiszminzmaxpad[9]channel[32]no_rot_axisstride_axiscurmodactstartactendactoffsstridelenscaleblendoutstridechannel[32]offs_bone[32]hasinputhasoutputdatatypesockettype*new_socknslimitstack_type*stack_ptrstack_indexlocxlocyown_index*groupsockto_index*link*rectxsizeysize*new_nodelastyoutputs*storageminiwidthlabel[32]custom1custom2custom3custom4need_execexec*threaddatatotrbutrprvr*block*typeinfo*fromnode*tonode*fromsock*tosocknodeslinks*stack*threadstackinitstacksizecur_indexalltypes(*progress)()(*stats_draw)()(*test_break)()*tbh*prh*sdhcyclicmoviesamplesmaxspeedminspeedcurvedpercentxpercentybokehgammaimage_in_widthimage_in_heightcenter_xcenter_yspinwrapsigma_colorsigma_spacehuet1t2t3fstrengthfalphakey[4]algorithmchannelx1x2y1y2fac_x1fac_x2fac_y1fac_y2colname[32]bktyperotationgamcono_zbuffstopmaxblurbthresh*dict*nodeangle_ofscolmodmixthresholdfademcjitprojfitslope[3]power[3]lift_lgg[3]gamma_inv[3]limchanunspilllimscaleuspillruspillguspillbshortymintablemaxtableext_in[2]ext_out[2]*curve*table*premultablepresetchanged_timestampcurrcliprcm[4]black[3]white[3]bwmul[3]sample[3]x_resolutiondata_r[256]data_g[256]data_b[256]data_luma[256]sample_fullsample_linesaccuracywavefrm_modewavefrm_alphawavefrm_yfacwavefrm_heightvecscope_alphavecscope_heightminmax[3][2]hist*waveform_1*waveform_2*waveform_3*vecscopewaveform_totoffset[2]clonemtex*icon_imbuficon_filepath[240]normal_weightob_modejittersmooth_stroke_radiussmooth_stroke_factorratergb[3]sculpt_planeplane_offsetsculpt_toolvertexpaint_toolimagepaint_toolpad3[5]autosmooth_factorcrease_pinch_factorplane_trimtexture_sample_biastexture_overlay_alphaunprojected_radiusadd_col[3]sub_col[3]active_rndactive_cloneactive_mask*layerstotlayermaxlayertotsize*pool*externalrot[4]ave[3]*groundwander[3]rest_lengthparticle_index[2]delete_flagnumparentpa[4]w[4]fuv[4]foffsetrt[2]prev_state*hair*boiddietimenum_dmcachehair_indexalivespring_kplasticity_constantyield_ratioplasticity_balanceyield_balanceviscosity_omegaviscosity_betastiffness_kstiffness_knearrest_densitybuoyancyspring_frames*boids*fluiddistrphystypeavemodereacteventdrawdraw_asdraw_sizechildtyperen_assubframesdraw_colren_stephair_stepkeys_stepadapt_angleadapt_pixrotfromintegratorbb_alignbb_uv_splitbb_animbb_split_offsetbb_tiltbb_rand_tiltbb_offset[2]color_vec_maxsimplify_refsizesimplify_ratesimplify_transitionsimplify_viewporttimetweakjitfaceff_hairgrid_randgrid_reseffector_amountpartfactanfactanphasereactfacob_vel[3]avefacphasefacrandrotfacrandphasefacrandsizeacc[3]dragfacbrownfacrandlengthchild_nbrren_child_nbrparentschildsizechildrandsizechildradchildflatclumppowkink_flatkink_amp_clumprough1rough1_sizerough2rough2_sizerough2_thresrough_endrough_end_shapeclengthclength_thresparting_facparting_minparting_maxbranch_thresdraw_line[2]path_startpath_endtrail_countkeyed_loopsdupliweights*eff_group*dup_ob*bb_ob*pd2*part*particles**pathcache**childcachepathcachebufschildcachebufs*clmd*hair_in_dm*hair_out_dm*target_ob*latticetree_framebvhtree_framechild_seedtotunexisttotchildtotcachedtotchildcachetarget_psystotkeyedbakespacebb_uvname[3][32]vgroup[12]vg_negrt3*renderdata*effectors*fluid_springstot_fluidspringsalloc_fluidsprings*tree*pdd*frandCdisCvistructuralbendingmax_bendmax_structmax_shearavg_spring_lentimescaleeff_force_scaleeff_wind_scalesim_time_oldvelocity_smoothcollider_frictionstepsPerFrameprerollmaxspringlensolver_typevgroup_bendvgroup_massvgroup_structshapekey_restpresetsreset*collision_listepsilonself_frictionselfepsilonrepel_forcedistance_repelself_loop_countloop_countpressurethicknessstrokesframenum*actframegstepinfo[128]sbuffer_sizesbuffer_sflag*sbufferlistprintlevelstorelevel*reporttimer*windrawable*winactivewindowsinitializedfile_savedop_undo_depthoperatorsqueuereportsjobspaintcursorsdragskeyconfigs*defaultconftimers*autosavetimer*ghostwingrabcursor*screen*newscreenscreenname[32]posxposywindowstatemonitorlastcursormodalcursoraddmousemove*eventstate*curswin*tweakdrawmethoddrawfail*drawdatamodalhandlerssubwindowsgestureidname[64]propvalueshiftctrlaltoskeykeymodifiermaptype*ptritemsspaceidregionidkmi_id(*poll)()*modal_itemsbasename[64]actkeymap*customdata*py_instance*reportsmacro*opm*edatainfluence*coefficientsarraysizepoly_orderamplitudephase_multiplierphase_offsetvalue_offsetmidvalbefore_modeafter_modebefore_cyclesafter_cyclesrectphasemodificationstep_size*rna_pathpchan_name[32]transChanidtypetargets[8]num_targetsvariablesexpression[256]*expr_compvec[2]*fptarray_indexcolor_modecolor[3]from[128]to[128]mappingsstrips*remapfcurvesstrip_timeblendmodeextendmodegroup[64]groupmodekeyingflagpathstypeinfo[64]active_path*tmpactnla_tracks*actstripdriversoverridesact_blendmodeact_extendmodeact_influenceruleoptionsfear_factorsignal_idlook_aheadoloc[3]queue_sizewanderflee_distancehealthstate_idrulesconditionsactionsruleset_typerule_fuzzinesslast_state_idlanding_smoothnessbankingaggressionair_min_speedair_max_speedair_max_accair_max_aveair_personal_spaceland_jump_speedland_max_speedland_max_accland_max_aveland_personal_spaceland_stick_forcestates*smd*fluid_group*coll_group*wt*tex_wt*tex_shadow*shadowp0[3]p1[3]dxomegatempAmbbetares[3]amplifymaxresviewsettingsnoisediss_percentdiss_speedres_wt[3]dx_wtv3dnumcache_compcache_high_comp*point_cache[2]ptcaches[2]border_collisionstime_scalevorticityvelocity[2]vel_multivgrp_heat_scale[2]vgroup_flowvgroup_densityvgroup_heat*points_old*velmat_old[4][4]TYPEcharucharshortushortintlongulongfloatdoublevoidLinkLinkDataListBasevec2svec2frctirctfIDPropertyDataIDPropertyIDLibraryFileDataPreviewImageIpoDriverObjectIpoCurveBPointBezTripleIpoKeyBlockKeyAnimDataTextLineTextMarkerTextPackedFileCameraImageUserSceneImageGPUTextureanimRenderResultMTexTexPluginTexCBDataColorBandEnvMapImBufPointDensityCurveMappingVoxelDatabNodeTreeTexMappingLampVolumeSettingsMaterialGroupVFontVFontDataMetaElemBoundBoxMetaBallNurbCharInfoTextBoxEditNurbGHashCurvePathSelBoxEditFontMeshMFaceMTFaceTFaceMVertMEdgeMDeformVertMColMStickyMSelectEditMeshCustomDataMultiresPartialVisibilityMDeformWeightMTexPolyMLoopUVMLoopColMFloatPropertyMIntPropertyMStringPropertyOrigSpaceFaceMDispsMultiresColMultiresColFaceMultiresFaceMultiresEdgeMultiresLevelModifierDataMappingInfoModifierDataSubsurfModifierDataLatticeModifierDataCurveModifierDataBuildModifierDataMaskModifierDataArrayModifierDataMirrorModifierDataEdgeSplitModifierDataBevelModifierDataBMeshModifierDataSmokeModifierDataSmokeDomainSettingsSmokeFlowSettingsSmokeCollSettingsDisplaceModifierDataUVProjectModifierDataDecimateModifierDataSmoothModifierDataCastModifierDataWaveModifierDataArmatureModifierDataHookModifierDataSoftbodyModifierDataClothModifierDataClothClothSimSettingsClothCollSettingsPointCacheCollisionModifierDataBVHTreeSurfaceModifierDataDerivedMeshBVHTreeFromMeshBooleanModifierDataMDefInfluenceMDefCellMeshDeformModifierDataParticleSystemModifierDataParticleSystemParticleInstanceModifierDataExplodeModifierDataMultiresModifierDataFluidsimModifierDataFluidsimSettingsShrinkwrapModifierDataSimpleDeformModifierDataShapeKeyModifierDataSolidifyModifierDataScrewModifierDataWarpModifierDataEditLattLatticebDeformGroupSculptSessionbActionbPosebGPdatabAnimVizSettingsbMotionPathBulletSoftBodyPartDeflectSoftBodyObHookDupliObjectRNGEffectorWeightsPTCacheExtraPTCacheMemPTCacheEditSBVertexBodyPointBodySpringSBScratchFluidVertexVelocityWorldBaseAviCodecDataQuicktimeCodecDataQuicktimeCodecSettingsFFMpegCodecDataAudioDataSceneRenderLayerRenderDataRenderProfileGameDomeGameFramingGameDataTimeMarkerPaintBrushImagePaintSettingsParticleBrushDataParticleEditSettingsTransformOrientationSculptVPaintToolSettingsbStatsUnitSettingsPhysicsSettingsEditingSceneStatsDagForestBGpicRegionView3DRenderInfoViewDepthsSmoothViewStorewmTimerView3DSpaceLinkView2DSpaceInfoSpaceIpobDopeSheetSpaceButsSpaceSeqFileSelectParamsSpaceFileFileListwmOperatorFileLayoutSpaceOopsTreeStoreTreeStoreElemSpaceImageScopesHistogramSpaceNlaSpaceTextScriptSpaceScriptSpaceTimeCacheSpaceTimeSpaceNodeSpaceLogicSpaceImaSelConsoleLineSpaceConsoleSpaceUserPrefSpaceSoundScrAreabSounduiFontuiFontStyleuiStyleuiWidgetColorsuiWidgetStateColorsThemeUIThemeSpaceThemeWireColorbThemebAddonSolidLightUserDefbScreenScrVertScrEdgePanelPanelTypeuiLayoutSpaceTypeARegionARegionTypeFileGlobalStripElemStripCropStripTransformStripColorBalanceStripProxyStripPluginSeqSequenceMetaStackWipeVarsGlowVarsTransformVarsSolidColorVarsSpeedControlVarsEffectBuildEffPartEffParticleWaveEffbPropertybNearSensorbMouseSensorbTouchSensorbKeyboardSensorbPropertySensorbActuatorSensorbDelaySensorbCollisionSensorbRadarSensorbRandomSensorbRaySensorbArmatureSensorbMessageSensorbSensorbControllerbJoystickSensorbExpressionContbPythonContbActuatorbAddObjectActuatorbActionActuatorSound3DbSoundActuatorbEditObjectActuatorbSceneActuatorbPropertyActuatorbObjectActuatorbIpoActuatorbCameraActuatorbConstraintActuatorbGroupActuatorbRandomActuatorbMessageActuatorbGameActuatorbVisibilityActuatorbTwoDFilterActuatorbParentActuatorbStateActuatorbArmatureActuatorGroupObjectBonebArmaturebMotionPathVertbPoseChannelbIKParambItascbActionGroupSpaceActionbActionChannelbConstraintChannelbConstraintbConstraintTargetbPythonConstraintbKinematicConstraintbSplineIKConstraintbTrackToConstraintbRotateLikeConstraintbLocateLikeConstraintbSizeLikeConstraintbSameVolumeConstraintbTransLikeConstraintbMinMaxConstraintbActionConstraintbLockTrackConstraintbDampTrackConstraintbFollowPathConstraintbStretchToConstraintbRigidBodyJointConstraintbClampToConstraintbChildOfConstraintbTransformConstraintbPivotConstraintbLocLimitConstraintbRotLimitConstraintbSizeLimitConstraintbDistLimitConstraintbShrinkwrapConstraintbActionModifierbActionStripbNodeStackbNodeSocketbNodeLinkbNodePreviewbNodeuiBlockbNodeTypeNodeImageAnimNodeBlurDataNodeDBlurDataNodeBilateralBlurDataNodeHueSatNodeImageFileNodeChromaNodeTwoXYsNodeTwoFloatsNodeGeometryNodeVertexColNodeDefocusNodeScriptDictNodeGlareNodeTonemapNodeLensDistNodeColorBalanceNodeColorspillTexNodeOutputCurveMapPointCurveMapBrushCloneCustomDataLayerCustomDataExternalHairKeyParticleKeyBoidParticleBoidDataParticleSpringChildParticleParticleTargetParticleDupliWeightParticleDataSPHFluidSettingsParticleSettingsBoidSettingsParticleCacheKeyKDTreeParticleDrawDataLinkNodebGPDspointbGPDstrokebGPDframebGPDlayerReportListwmWindowManagerwmWindowwmKeyConfigwmEventwmSubWindowwmGesturewmKeyMapItemPointerRNAwmKeyMapwmOperatorTypeFModifierFMod_GeneratorFMod_FunctionGeneratorFCM_EnvelopeDataFMod_EnvelopeFMod_CyclesFMod_PythonFMod_LimitsFMod_NoiseFMod_SteppedDriverTargetDriverVarChannelDriverFPointFCurveAnimMapPairAnimMapperNlaStripNlaTrackKS_PathKeyingSetAnimOverrideIdAdtTemplateBoidRuleBoidRuleGoalAvoidBoidRuleAvoidCollisionBoidRuleFollowLeaderBoidRuleAverageSpeedBoidRuleFightBoidStateFLUID_3DWTURBULENCETLEN `HH( p$8p`(0(pxh@(X hXhP 0@ (0 @ @Phx``XXp8XxP0x`0phX`Pp0h0xxH  (@@X@h`0X`8 PX`88@h`h(!x@0H(h pxXP8 (X( X,  4 H@@00Hh(H,(lHH`h<PP` HXPpT `88pX(((x@X8XPx8000(HH008hp`88H(8( ,@  ` 8H88@( <h ((xxh8(h(hp P8P@hH@STRC                  !"#$%&'()*+,-./01+,23456  789:; <=+>?#@:,ABC DEFG HIJK: LMNOP  QRS! !!TUVW XYZ"[X\ ] ^ _`a bcde fg#hi $HjklmnopqrsMt%&uvwxyz{|#}~C'  ()**|#+A,6-   #.@=/"=.0'1lm|2  / 3 4   |,?HC !"#$%&'()*+,-./0123456789zwxy:;W%<5=M'->/ 0?2@4AB6CDEFG*7HHHIJKLMNOPQRST3UClmVWXYZ[\]^_`abcdefghijWklmnopqrstuvwxyz{|M+}~89}H8HkB~//+}5=M:C# ;<#===>     ?H>   M9#CD= 4 !"#$ ##@@@%#&'()*+,-././012A3%#CB45C 6D78ZEDH> 9 C:;<=MF>?9 @CDWABCDE#FGHI()JKL M]@NOPQRSTUVWXYGZH[\;];^;_;`abcdBefgAhAiI'H>M?9JjKkLlMmNnOoPpQqIrRsStTuTvTw3xyz{CDA|}~UVL HJ%NWOWMPX'HYZ#QRK'H[\]^_Z`a`b%cd ddbac3yx#MU MTuTwVJNyx3#e eeH#&ufe,geX  heiejeUkeEHl eXmeneXo e#Xpe#qerstu e,v e'X#wexeyehze,#GW{eC| e}e~e&u  eMMMMM M J   eMM e#xeH#3 !"#$% &e'()*6e*6+,e-./e0123Xe4 e56789:;< e=7>?H@#e exABCDEF# eGHIJKLe,MN3UOP8ZH&'QRSTCUVW#XYZ[\]^M?OoE_`a>b#Hcdefgh$ijklMF>>mno pqr s t  u vHw9xyCz{|D}~bj        @:8|   $E *E(,:     6   $   !"#$%&'6()*#+,-./0123456789:;<=y>?@ABCODEFGHIJKLMNOPQRS TUVWXY2Z[\]^_`abcdefghijklmInIopqrMstuvwxyz{|}~3#LHIkCHM+}~  #  CWX# 9:#iy>     ^hH !"#$%&'()* +,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYC"Z[ \]^W_CHL`aC"bcWCHde  fghijWkl mnXo#pqrW shtuvwx sy6z{|}&u~oX#o#"O sRczW3y6&,Hk& B5= b      ep '%<VWhC&     O>p !"#$%&2 '()*OW+k, -./0123n456789:;<=> ? @ ABCDE Fp"=GHIJKLMNOPQRSTUVW3XYZ '()* '()*[ '()*\] ^H_`3 '()*\abcdSef# >ghi '()*\VWajklm#pnopqrstuvwxyz '({|} ~ C '()*\  '('%<3pVWm3  '()*_#]\ '()*"X       X  '()XW   '()\ # '()*\N VWm&5=5 p  '()*#p* '()*\}opw t#W     1Q '()*#   '(# '()\HVWC# S      # !"#$%&'a() *+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@B###$Y     /    '&u&W#    )#   #    !1("TU##  $ ' % &   \'(TU)*+R,   - . %/ 0 1234567&89:;#< =>? @ABCDEF#Gp)h#6HIJ KGj LMN    O P 0 Q URSIJTUVW#XYyZ[M&u\)]^>_`a b cdefgh ijklm no p b qrstuvw#xyLz{|}~ c#X66y-8VO;#:GB  O#!WC"9O##$#%#&#'HC(L)*HW+,---WC .*td#/ 01"H....C 2- 3#*4 V56 WC5#7 *I8W#&uk9#*: z}; VWC#<*WC= H# > V=  ?     @   WCAV BCZ  "D*EIF5 2 222  * # # M  X#   GGG*  :  ~ HHH H$        ! " O# $ % & ' ( ~IH ) * + H, - . 0g/ ~0 1 2 3 4 5 6 7 8 9 : JJ; < = > ? @ A B C D E F G H I J K L K)KK M N O P E7 8 HQ K$KR S rT KU CV #W X Y Z [ \ ] ^ _ ` > a Db #c Wbd e f g h i j qk Lh M h l m n o p q r s t NNN u v w  x a y bz { #| a :} ~  O  '()*\m H_ PPPN M sQQQM RRR    #M  S SS    T"   U        HOV ;    W   X#X  Y  Z  [\ ]   x WC ^  @UV#_  ` #a xA b     c R          #WCd e # f        g  h    i    j    k OXH#l5O9; m mm u  *nnnH  MUV      vo$     pppp o   o  W   p  Cq r   #s"sss Hd       G          rt u qqqs s p p #5Hp o    #  >  vwy #w   A   ^    x    L mJ #y  J#z W {y>|    R     }       ! ~"  # $ e%  & ' ( )   * +  JL, h- . / 0 x 1 2 3 4 5 #6 7 DEF8 9 : ; < = > ? @  A B C D E F G 3 =H I J K L M N O P u Q R S T U  H|V W X Y Z [ \ ] ^ _ ` a b c d e #'f #"g 3E +h 1i j k l hm On o p q r s t u v w x y z { | } ~   x   Z <T    #  #Y    6         6*H*    O     h               yH  T6  k          |               J    V               h                                 +}: :   M@ 2  R      ~     $                S         % 5 ! " Q# $ % & ' ( 6) * + 734, - . X/ 0 1 2 3 4 5 6 7 T 8 9 : ; < = X> ? :@ ; A  B C   wD A E YF  +G H I  J K L #M N O P Q R S T U V W X Y Z [ \ ]   ^ _ #` a b c d e f g h i Cj k l m n o U % p q r s t  u v w x y z #{   | s } ~   s  s   {        H     !3     "  #h #  x< =      : :  #N ; v/ 3:    5   v  UV      WC     #          m      H *   u     *C      d6      H    u       X            r(q  : : :  (( (           X#         T   Cs q '      Xt q ;   E   #CENDBrviz-1.12.4/image_src/Viz.stl000066400000000000000000000306141300447110700160170ustar00rootroot00000000000000Exported from blenderJ>z}>l?7U>J>7U>>z}>l?7U>J>z}>>[ ף=l?7U>>z}>@>>[ ף=>z}>@>?[ ף=>[ ף=@>??[ ף=My=ڴ3#?`=ڴ3#?C=!۴S#?My=ڴ3#?@=yڴ"?`=ڴ3#? 4]=yڴ"?@=yڴ"?My=ڴ3#? 4]=yڴ"?G=Gٴ@"?@=yڴ"? B=Eٴ@"?G=Gٴ@"? 4]=yڴ"? B=Eٴ@"?@=Mشu!?G=Gٴ@"? t)=Kشu!?@=Mشu!? B=Eٴ@"? t)=Kشu!?0[=O״z ?@=Mشu!?@X=O״z ?0[=O״z ? t)=Kشu!?@X=O״z ?=մS?0[=O״z ?<մS?=մS?@X=O״z ?<մS?=;Դ?=մS?<8Դ?=;Դ?<մS?<8Դ?=*Ҵē?=;Դ?<'Ҵ“?=*Ҵē?<8Դ?<'Ҵ“?@3=ϴ?=*Ҵē?@P<ϴ?@3=ϴ?<'Ҵ“?@P<ϴ?p=CʹW?@3=ϴ?<@ʹW?p=CʹW?@P<ϴ?<@ʹW?=a˴'?p=CʹW?}<a˴%?=a˴'?<@ʹW?}<a˴%?=ȴ?=a˴'?u<ȴ?=ȴ?}<a˴%?}j<7U>j<P`=P`=7U>D81ĻI >괎.?A`%>괎.?D81Ļr I >괎.?r ,>괎.?V>괎.?r x81Ļ ,>괎.?D81Ļx81Ļr x81ĻD81ĻDS= ĻDS= ĻxS= Ļx81ĻD81ĻA`%>괎.?A`%=.?A`%=.?DS= ĻD81ĻA`%>괎.?I >괎.?I =.?I =.?A`%=.?A`%>괎.?I >괎.?r A=AO>A=AO>I =.?I >괎.?r V>괎.?V=.?V=.?A=AO>r ,>괎.?x81ĻxS= ĻxS= Ļ ,=.? ,>괎.?V>괎.? ,>괎.? ,=.? ,=.?V=.?V>괎.?p=Uzƴ?`=Ĵ]-?`=!=^-?`=!=^-?p= =?p=Uzƴ?`=Ĵ]-?03= ?03="=?03="=?`=!=^-?`=Ĵ]-?03= ?=2ȿ]?="=^?="=^?03="=?03= ?=2ȿ]?=!ؽ ?=#= ?=#= ?="=^?=2ȿ]?=!ؽ ?=b(1 ?=#=)1 ?=#=)1 ?=#= ?=!ؽ ?=b(1 ? [=‹H ? [=#=I ? [=#=I ?=#=)1 ?=b(1 ? [=‹H ?0=;S ?0=$=T ?0=$=T ? [=#=I ? [=‹H ?0=;S ?G=+D ?G=$=D ?G=$=D ?0=$=T ?0=;S ?G=+D ?0=av?0=$=w?0=$=w?G=$=D ?G=+D ?0=av?P=䶴3Q?P=$=4Q?P=$=4Q?0=$=w?0=av?P=䶴3Q?C='1?C=$=(1?C=$=(1?P=$=4Q?P=䶴3Q?C='1?My=䶴2Q?My=$=3Q?My=$=3Q?C=$=(1?C='1?My=䶴2Q?4]=au?4]=$=v?4]=$=v?My=$=3Q?My=䶴2Q?4]=au?B=+D ?B=$=D ?B=$=D ?4]=$=v?4]=au?B=+D ?t)=;R ?t)=$=S ?t)=$=S ?B=$=D ?B=+D ?t)=;R ? X=G ? X=#=H ? X=#=H ?t)=$=S ?t)=;R ? X=G ?@j<+=W>j<+=W>jP`=P`=R=[3P`=R=[3P`=+=W>P`=7U>j<7U>P`=7U>P`=+=W>P`=+=W>j<+=W>j<7U>>[ ף=?[ ף=?K=ף=?K=ף=>K=ף=>[ ף=?[ ף=??R=[3?R=[3?K=ף=?[ ף=?@>@>R=[3@>R=[3?R=[3?@>>z}>>2=>>2=>@>R=[3@>>z}>J>z}>J>2=>J>2=>>2=>>z}>J>z}>J>7U>J>+=W>J>+=W>J>2=>J>z}>l?7U>>[ ף=>K=ף=>K=ף=l?+=W>l?7U>J>7U>l?7U>l?+=W>l?+=W>J>+=W>J>7U>J>+=W>l?+=W>J>2=>J>2=>l?+=W>>2=>>2=>l?+=W>>K=ף=>2=>>K=ף=@>R=[3>K=ף=?K=ף=@>R=[3?K=ף=?R=[3@>R=[3C==S#?`==3#?My==3#?`==3#?@=="?My==3#?My==3#?@=="? 4]=="?@=="?G==@"? 4]=="? 4]=="?G==@"? B==@"?G==@"?@==u!? B==@"? B==@"?@==u!? t)==u!?@==u!?0[==z ? t)==u!? t)==u!?0[==z ?@X==z ?0[==z ?==S?@X==z ?@X==z ?==S?<=S?==S?==?<=S?<=S?==?<=?==?==œ?<=?<=?==œ?<=Ó?==œ?@3==?<=Ó?<=Ó?@3==?@P<=?@3==?p==W?@P<=?@P<=?p==W?<=W?p==W?==(?<=W?<=W?==(?}<=&?==(?= =?}<=&?}<=&?= =?u< =?u< =?= =?}< =?= =?p= =?}< =?p= =?`=!=^-?}< =?}< =?`=!=^-?@P`=+=W>jP`=R=[3jDS= ĻV=.? ,=.?A=AO> ,=.?xS= ĻA=AO>A=AO>xS= ĻDS= Ļrviz-1.12.4/image_src/icon_kinect.svg000066400000000000000000000171221300447110700175300ustar00rootroot00000000000000 image/svg+xml rviz-1.12.4/image_src/rviz_isolated.xcf000066400000000000000000004700361300447110700201110ustar00rootroot00000000000000gimp xcf file@BB G gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) @ Pasted Layer     [@{s@', "Z)-u3;?DKHNV]dltxcEFY&@&@&@&@&@&@&@&@&@@ @@!!"&&&&&&&@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$Y&@&@&@&@&@&@&@&@&@@ @@!!"&&&&&&&@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$Y&@&@&@&@&@&@&@&@&@@ @@!!"&&&&&&&@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$%!&&&&&&&&&&%%%%%%%%%%%%%$$$$@@@<@,@"@*@.@2 @, @(@&@%@#@"!#%'(*+,./01 2 3 4 5 6@@@<@,@"@*@.@2 @, @(@&@%@#@"!#%'(*+,./01 2 3 4 5 6@@@<@,@"@*@.@2 @, @(@&@%@#@"!#%'(*+,./01 2 3 4 5 6<,"*.2 5 8:=>@5@ "@ @ @!@ !@"@ "@ #@  #@ #@ $@ #@"@ @ @ @@@@@@@ @@ @@@@@ @@5@ "@ @ @!@ !@"@ "@ #@  #@ #@ $@ #@"@ @ @ @@@@@@@ @@ @@@@@ @@5@ "@ @ @!@ !@"@ "@ #@  #@ #@ $@ #@"@ @ @ @@@@@@@ @@ @@@@@ @u "  !!""###$#"  !""##$$&%&''('@@=@8@ 3@/@.@.@.@-@-@,@,@,@+@+@*@*@*@)@)@(@(@(@'@'@&@&@&@%@%@$@$@@@=@8@ 3@/@.@.@.@-@-@,@,@,@+@+@*@*@*@)@)@(@(@(@'@'@&@&@&@%@%@$@$@@@=@8@ 3@/@.@.@.@-@-@,@,@,@+@+@*@*@*@)@)@(@(@(@'@'@&@&@&@%@%@$@$@@=8 3/...--,,,++***))(((''&&&%%$$@o@-@ -@-@,@,@,@+@+@*@*@*@)@)@)@@'@@'@(@'@'@'@&@&@&@%@%@$@$@$@#@#@#@"@"@"@!@!@!@@o@-@ -@-@,@,@,@+@+@*@*@*@)@)@)@@'@@'@(@'@'@'@&@&@&@%@%@$@$@$@#@#@#@"@"@"@!@!@!@@o@-@ -@-@,@,@,@+@+@*@*@*@)@)@)@@'@@'@(@'@'@'@&@&@&@%@%@$@$@$@#@#@#@"@"@"@!@!@!@---,,,++***)))((('''&&&%%$$$###"""!!!@@6@.@&@$@$@$@%@%@%@&@&@'@@ @@@@ @@ @;@@ @ @ @ @ ) ( ) ) ( ) ) (@ (@ '@(@(@'@&@&@%@@ @@@@6@.@&@$@$@$@%@%@%@&@&@'@@ @@@@ @@ @;@@ @ @ @ @ ) ( ) ) ( ) ) (@ (@ '@(@(@'@&@&@%@@ @@@@6@.@&@$@$@$@%@%@%@&@&@'@@ @@@@ @@ @;@@ @ @ @ @ ) ( ) ) ( ) ) (@ (@ '@(@(@'@&@&@%@@ @@A6.&$$$%%%&&'   ;<=>==<<<;;:9( '@@@=@@=@@=@@=@@=@@=@@=@@=@@=@@~@@@@=@@=@@=@@=@@=@@=@@=@@=@@=@@~@@@@=@@=@@=@@=@@=@@=@@=@@=@@=@@~@ @=========~@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @$@$@$@$@$@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@$@$@$@$@$@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@$@$@$@$@$@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$$$$$$$$#############"""""""""""""!!!!!!!!!!!!!              7889:; 4/,@)@'@'@% @"@ " ..-----------------,,,,,,,,,,,                7889:; 4/,@)@'@'@% @"@ " ..-----------------,,,,,,,,,,,                7889:; 4/,@)@'@'@% @"@ " ..-----------------,,,,,,,,,,,                Q<986 4 3 10/..--,++*))((('''&&'&&&&&&%%%%%%%%%%%&&&&&''''@ @@@@@ @@ @@@ @ @ @ @ @ @ @ @ @ !@ #@% @& @( @)@+@,@,@.@/@/@0@1@2@3@3445545                          @ @@@@@ @@ @@@ @ @ @ @ @ @ @ @ @ !@ #@% @& @( @)@+@,@,@.@/@/@0@1@2@3@3445545                          @ @@@@@ @@ @@@ @ @ @ @ @ @ @ @ @ !@ #@% @& @( @)@+@,@,@.@/@/@0@1@2@3@3445545                          (()))))))*)*)*)*))*))()(()((''''&&&%%$%$$$##############""""""!#@#@#@"@"@!@!@!@ @ @@@@ @1 @6@9@:@9@9@:@9@:998887766 5 5 5 4 4 3 3 2 2 2 1 11 11 1 2 1 11 11 1 2 1 11 11 1 2 1 (#@#@#@"@"@!@!@!@ @ @@@@ @1 @6@9@:@9@9@:@9@:998887766 5 5 5 4 4 3 3 2 2 2 1 11 11 1 2 1 11 11 1 2 1 11 11 1 2 1 (#@#@#@"@"@!@!@!@ @ @@@@ @1 @6@9@:@9@9@:@9@:998887766 5 5 5 4 4 3 3 2 2 2 1 11 11 1 2 1 11 11 1 2 1 11 11 1 2 1 (###""!!!    !!!""###$$%%&&&''((())***++,,+,+,++,+,+,++,+,++++ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @!@@@@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @!@@@@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @!@@@@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @ @ @ @ @ @ @ @      !!!"""###$$%%%&&&'''((()))**+++,,,--,-,,-,--,--,--,--,--@@ @@ @@ @ @ @ @ @ @ @ @!@@@@@@ @@@ @@@ @@@ @@@ @ @$@#@@  @@@ @@@ @@ @@ @@ @@@ @ @ @ @@@@@ @ @ @ @  @  @  @  @  @  @  @  @  @ @@@ @@ @@ @ @ @ @ @ @ @ @!@@@@@@ @@@ @@@ @@@ @@@ @ @$@#@@  @@@ @@@ @@ @@ @@ @@@ @ @ @ @@@@@ @ @ @ @  @  @  @  @  @  @  @  @  @ @@@ @@ @@ @ @ @ @ @ @ @ @!@@@@@@ @@@ @@@ @@@ @@@ @ @$@#@@  @@@ @@@ @@ @@ @@ @@@ @ @ @ @@@@@ @ @ @ @  @  @  @  @  @  @  @  @  @ @% # !    ! 3 3 4 4 4 5 5 5666777883 4 !   !%/...---,,,++++++(((((((((((('(((((@9@7@7@7@8@8@8@9@9@8@@ @@@@@@|@=: 5 1.../////////////)" @ @ @@@@@!@!@ @ @@@@@@@@ @ @ @9@7@7@7@8@8@8@9@9@8@@ @@@@@@|@=: 5 1.../////////////)" @ @ @@@@@!@!@ @ @@@@@@@@ @ @ @9@7@7@7@8@8@8@9@9@8@@ @@@@@@|@=: 5 1.../////////////)" @ @ @@@@@!@!@ @ @@@@@@@@ @ @ 5 ,##, 5>; !!    !!""#@@@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @@@ @ @ @ @ @ @ @ @ @ @@@ @@@@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @@@ @ @ @ @ @ @ @ @ @ @@@ @@@@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @@@ @ @ @ @ @ @ @ @ @ @@@ @* &   !!""##$$ % % & & ' ' ( ( ) )**++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @             !!!!!!!!!!!!!""""""""""""""############ &%$#"! )<<;:96643 1 .,,,(%#"!     !!""##$% &%$#"! )<<;:96643 1 .,,,(%#"!     !!""##$% &%$#"! )<<;:96643 1 .,,,(%#"!     !!""##$%((())-4 < p==<;<;:98                                 @@@ @ @ @ڍ @ @  @  @ @@@@@@@@ @ @ @ @@@@@@@@ @                                       @@@ @ @ @ڍ @ @  @  @ @@@@@@@@ @ @ @ @@@@@@@@ @                                       @@@ @ @ @ڍ @ @  @  @ @@@@@@@@ @ @ @ @@@@@@@@ @      !!!     !!""##$%&&'()*+-./ 1 3 589876 5 4 3 2 10//.-,++*)(('&&%%$##"! 1 11 1 2 1 2 1 11 1 2 1 2 1 1@ 0@ 1 1@ 0@ 0@ /@ /@ .@ .@ .@ -@ -@ ,@ ,@ +@ +@ +@ *@ *@ (@ & @ # @  @  @  @  @   @   @  @  @  @  @@  @ @ @  @  @@ @ @ @  @ @@ @ @ @  @  @  1 11 1 2 1 2 1 11 1 2 1 2 1 1@ 0@ 1 1@ 0@ 0@ /@ /@ .@ .@ .@ -@ -@ ,@ ,@ +@ +@ +@ *@ *@ (@ & @ # @  @  @  @  @   @   @  @  @  @  @@  @ @ @  @  @@ @ @ @  @ @@ @ @ @  @  @  1 11 1 2 1 2 1 11 1 2 1 2 1 1@ 0@ 1 1@ 0@ 0@ /@ /@ .@ .@ .@ -@ -@ ,@ ,@ +@ +@ +@ *@ *@ (@ & @ # @  @  @  @  @   @   @  @  @  @  @@  @ @ @  @  @@ @ @ @  @ @@ @ @ @  @  @  +++++++*++++*+*+*++*+*+**+**))(('''&&%%$$$##""!!     !!!""##$$ @ @ @@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@ @@@ @@ @ @@ @ @@ @ @ @  @ @ @  @ @ @ @@ @  @ @  @  @ @  @  @  @ & @ ' @ ' @ (@ (@ )@ )@)@*@ @ @ @@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@ @@@ @@ @ @@ @ @@ @ @ @  @ @ @  @ @ @ @@ @  @ @  @  @ @  @  @  @ & @ ' @ ' @ (@ (@ )@ )@)@*@ @ @ @@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@ @@@ @@ @ @@ @ @@ @ @ @  @ @ @  @ @ @ @@ @  @ @  @  @ @  @  @  @ & @ ' @ ' @ (@ (@ )@ )@)@*@ ,-,--,--,--,--,--,----,--,-.---,,,+++**)))((('''&&&%%%$$$##"""!!@  @  @  @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@ @ @ @ @ @ @ @ @@  @  @  @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@ @ @ @ @ @ @ @ @@  @  @  @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@ @ @ @ @ @ @ @ @((((((((((((((((((((('''''''''''''''((((((((((('''''''''''''''''@ @ @ @ @@@ @  @ @@@  @@@@@@@@@@@@@@ @ @ @ @ @ @ @@@ @ @  @  @  @ @ @ @ @ @ @ @ @@@ !""##$$%%&&''(())**@ @ @ @ @@@ @  @ @@@  @@@@@@@@@@@@@@ @ @ @ @ @ @ @@@ @ @  @  @  @ @ @ @ @ @ @ @ @@@ !""##$$%%&&''(())**@ @ @ @ @@@ @  @ @@@  @@@@@@@@@@@@@@ @ @ @ @ @ @ @@@ @ @  @  @  @ @ @ @ @ @ @ @ @@@ !""##$$%%&&''(())**#$$%%&&''(())**+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* ::;;<<===~  @  @ @ @@ @ @ @ @ @ @ @ @ @ @@@      @  @ @ @@ @ @ @ @ @ @ @ @ @ @@@      @  @ @ @@ @ @ @ @ @ @ @ @ @ @@@    ,,--..//001110- ) &#  @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@@@@@@@@@@#$$$$$$$$$$$$$%%%%%%%%%%%%%&&&&&&&&&&&&&&'''''''''''''((((((((((%&''''''''''&&&&&&&&&&&           00%&''''''''''&&&&&&&&&&&           00%&''''''''''&&&&&&&&&&&           0076 5 4 4 3 2 2 1000//..-,,+**))(('&'&&%%$$##"!!      !!""#$$$$$$$$%')    @  @ @ @ @ @  @@ @ @ @ @.@.@/@ /@ 0@ 0@ 0@ 0@ 0@ 1@ 1 100//..--,,+**))((''&&%%$$#$#$#$#$#$    @  @ @ @ @ @  @@ @ @ @ @.@.@/@ /@ 0@ 0@ 0@ 0@ 0@ 1@ 1 100//..--,,+**))((''&&%%$$#$#$#$#$#$    @  @ @ @ @ @  @@ @ @ @ @.@.@/@ /@ 0@ 0@ 0@ 0@ 0@ 1@ 1 100//..--,,+**))((''&&%%$$#$#$#$#$#$!    !!""##$%%&&''(())**++,,--..//001 1 2 3 3 4 4 5 5 66778899:::::::::: @  !@  "@  $@  @$@  '@  '@  (@  (@  (@ )@ )@ *@ *@ +@ +@ +@ ,@ ,@ -@ -@ .@ .@ /@ /@ /@ 0@ /@ 0@ /@ /@ .@ .@ .@ -@ .@ -@ .@ -@ -@-@ ,@ ,@ -@ -@ /@ /@ 0@ 1@0@0@/@/@.@.@-@,@,@+@+@*@*@)@)@ @  !@  "@  $@  @$@  '@  '@  (@  (@  (@ )@ )@ *@ *@ +@ +@ +@ ,@ ,@ -@ -@ .@ .@ /@ /@ /@ 0@ /@ 0@ /@ /@ .@ .@ .@ -@ .@ -@ .@ -@ -@-@ ,@ ,@ -@ -@ /@ /@ 0@ 1@0@0@/@/@.@.@-@,@,@+@+@*@*@)@)@ @  !@  "@  $@  @$@  '@  '@  (@  (@  (@ )@ )@ *@ *@ +@ +@ +@ ,@ ,@ -@ -@ .@ .@ /@ /@ /@ 0@ /@ 0@ /@ /@ .@ .@ .@ -@ .@ -@ .@ -@ -@-@ ,@ ,@ -@ -@ /@ /@ 0@ 1@0@0@/@/@.@.@-@,@,@+@+@*@*@)@)@%%%&&''((())**+++,,--..///001 1 2 2 2 3 3 4 4 5 5 666789;<>*@+@+@+@,@,@---..///001 1 2 3 3 5 5 5778#""" ! !       @  @  @  @ @@ @@ @@ @@ @@ @ @ @ @ @ @ @ @ @ @ @ @ *@+@+@+@,@,@---..///001 1 2 3 3 5 5 5778#""" ! !       @  @  @  @ @@ @@ @@ @@ @@ @ @ @ @ @ @ @ @ @ @ @ @ *@+@+@+@,@,@---..///001 1 2 3 3 5 5 5778#""" ! !       @  @  @  @ @@ @@ @@ @@ @@ @ @ @ @ @ @ @ @ @ @ @ @ !      !!"""###$$$%%%&&&'''(()))***+++,,,---/02 5 69 @ @ @   @@@@@@@@@ @@ @@ @@@ @ @ @@@@+@+@,@,@,@-@-@.@.@.@ /@ /@ /@ 0@ 0@ 0@ 1@ 1@ 1@ 2@ 2@ 2@ 3@ 3@4@3@ 3@4@4@4@5@5@5@ @ @ @   @@@@@@@@@ @@ @@ @@@ @ @ @@@@+@+@,@,@,@-@-@.@.@.@ /@ /@ /@ 0@ 0@ 0@ 1@ 1@ 1@ 2@ 2@ 2@ 3@ 3@4@3@ 3@4@4@4@5@5@5@ @ @ @   @@@@@@@@@ @@ @@ @@@ @ @ @@@@+@+@,@,@,@-@-@.@.@.@ /@ /@ /@ 0@ 0@ 0@ 1@ 1@ 1@ 2@ 2@ 2@ 3@ 3@4@3@ 3@4@4@4@5@5@5@'''----------...''''''%#!!#(/ 5W++,,--..///+'@#@ @ @ @ @ @  @  @  @  @  @  @  @  @ @@@@@@@@@@@@@@@@@@@@@@ @  @++,,--..///+'@#@ @ @ @ @ @  @  @  @  @  @  @  @  @ @@@@@@@@@@@@@@@@@@@@@@ @  @++,,--..///+'@#@ @ @ @ @ @  @  @  @  @  @  @  @  @ @@@@@@@@@@@@@@@@@@@@@@ @  @95 1 -($ $*1 7 u                    @@ @ @@@@@                    @@ @ @@@@@                    @@ @ @@@@@# ', )@@@@@@@ @"@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@@@@@@@@ @"@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@@@@@@@@ @"@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@((()+/3 7; @ @ @ @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+-/0 2 468: $#"@"@!@!@ @!@ @ @@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @@@@@ !@ %@'@'@$#"@"@!@!@ @!@ @ @@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @@@@@ !@ %@'@'@$#"@"@!@!@ @!@ @ @@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @@@@@ !@ %@'@'@:9988776 5 5 4 4 3 3 2 2 1 100//..--,++**)%!!%*0 5;(@(@'@'@&@&@%@%@$@$@#@#@"@"@!@!@ @ @@ @ @!@!@"@"@#@#@$@$@%@@@@@ @ @ @ @ @ @(@(@'@'@&@&@%@%@$@$@#@#@"@"@!@!@ @ @@ @ @!@!@"@"@#@#@$@$@%@@@@@ @ @ @ @ @ @(@(@'@'@&@&@%@%@$@$@#@#@"@"@!@!@ @ @@ @ @!@!@"@"@#@#@$@$@%@@@@@ @ @ @ @ @ @====<;;::9987766 5 4 4 3 3 2 2 10 2 3 5689:<@ @ @ @ @ @ @ @ @ @ @ @  @  @ !@ !@ "@ "@ #@ #@ #@  $@  %@  &@  )@  *@  ,@ /@0@2@5@6@9@@@ @ @ @ @ @ @ @ @ @ @ @  @  @ !@ !@ "@ "@ #@ #@ #@  $@  %@  &@  )@  *@  ,@ /@0@2@5@6@9@@@ @ @ @ @ @ @ @ @ @ @ @  @  @ !@ !@ "@ "@ #@ #@ #@  $@  %@  &@  )@  *@  ,@ /@0@2@5@6@9@@6@8@8@9@9@9@:@:@:@;@;@<@<@<@=@=@=@@=@@=@@>@6@8@8@9@9@9@:@:@:@;@;@<@<@<@=@=@=@@=@@=@@>@6@8@8@9@9@9@:@:@:@;@;@<@<@<@=@=@=@@=@@=@@>@ @@@@@@ @ !@ #@(@ /@5@@ @@@@@@ @ !@ #@(@ /@5@@ @@@@@@ @ !@ #@(@ /@5@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ }P>(@ New Layer      E@eopp@5"{cUBE +/?O_inz-H҃Y 8'Y4@INSlYgnooo.%!                          !!"##$$ %  !#$%%&'(()**+,+  "#%&')*+,-../00112232  "$&')+,./1234567889::;<;:  "%'),.024578:;<=>?@ABBCCD DC "%(*-02579;=?ABDEFGHIJKKLLM ML  $'*-0369FOXajt}  $*08@HQZdmw $*19AJS\foy %+2:BKT]gq{  %,3:CLU_is}  %,3;CLV`jt~   %,3;DMV`ju   &,3;DMWakv  %,3;DMWakv  %,3;DMWakv %,3;DMWakv %,3;CMVakv  %+2:CLV`ku $+2:CLV`ju  $*2:BKU_jt  $*19BKT^it #*19AJT^hs~ #)08AJS]hs~ ")08@IS]gr}<,"'                                   $$#"!  ++**)('&%$#"!  22110/.-,+*)('&%$##"!!  ::998876543210/.-,+**)(('&%$#"!  CCBBAA@@??>>==<;;::9988766554332110/.-,+*)('&%#"! LLKKJJIIHHGGFFEDDCCBBA@@??>==<;::987654320/.,+*('%$" VUUTTSSRRQPPOONNMLLKKJIIHHGFEEDCBA@?>=<;:875421/-,*(&%#!`__^^]]\[[ZZYXXWWVUUTSSRQQPOONMLKJIHGFECBA?=<:87531/-+)'%#!jjiihhgffeddccbaa`__^]]\[[ZYXXWVUTSRPONLKIHFDCA?=;86420-+)&$" uuttsrrqqpoonmmlkkjihhgffedcbba`_^][ZYWVTSQOMKIGECA><9742/-*(%# ~}}||{zzyxxwvvutssrqpponmlkjihgfdcb`^][YWUSPNLIGDA?<9641.+)&~~}|{{zyxwvutsrponlkigeca_\ZXURPMJGDA>;852/,~}{zxwusrpnkigdb_\YVSPMJGC@=963~|zxvtqolifc`]ZVSOLHEA>:~|yvspmjgc`\XUQMIEB~{xtqmjfb^ZVRNJ{xtplhd_[WR~zvrmie`[|wsnie}xsn}x¿ÿ     $"!                     !!""##"  !"$%%&'(())*)(   "$%'()+,--.//00/. !#%')+-.0134556778876   #&(+-024679:<=>??@@AA@?  "%(+.1469;=?ABDEFGHIIJJIHG  #&*-047:=@BEGIKLNOPQRSSRQQ  #'*.26:=ADGJMORTUWYZ[\\]]\[Z  #&+/37<@DHKORUXZ]_abdeffggfed  "&*/38=AFJOSWZ^adfiklnopqrrqpo   $).38=BGLQVZ_cfjmpruvxz{||}}|{z#!   #',16:63/+(%"!&+06=CJQY`gnu|ïFB=962.*'$ "',28?FMT\ckrz¸NJEA=840,)%"#(-3:@GOW_gnv~WRMID@;73/+'$!!%)/4;BIQYaiqy`[VQLGB>951-)%""&*/5940,(%# !$'+16=DKS\dmv|wqkf`[UOJE?;62-*'$"  "%(,16=DKS[dmvzuoic]WRLFA<73/+(&$"!!"#&)-16=CKS[dmv叉~xrlf`ZTNHC>940-*'%$$%')-169631//036:?DKRZbku~~woha[TNHC>:742112369>CIPX`ir{Ŀwpib[UNIC?;8533469=BHNU]foxxpib[UNID?;8654579BGMSZbkt}ſ~wog`YSMHD@=;;<>AFKQX_gpy}unf_XRLGC@><<>ADIOU\dmv|tme^WQLGC@>==>@CHMSZair{ſ{skc\VPKFC@>>@CFKPW^fnwſyqib[TOJFB@??@BEINT[ckt}8 3. ,  *(&$"  !         !  '&%$#!  .-,+*)'&$#! 5321/.,*)'$"  >=;:97531/-*(&#  FEDBA?=;9641.+(&#  PNMKJHECA>;852/+(%" YXVTSPNKIFC?<951.*&# cb`^\ZWTQNKGD@<840+'$  nljhfda^[WSPKGC>:51,($  xwuspnkhd`\XTOJEA<72-($  ׃}{xurnjfa\WRMHB=82-($  ׎|xsoje`ZTOIC=82-(# ֘}xsnhb\VPJC=72,'" ֢|vpjd]WPIC<60+&! լyrke^WPIB;5/)$ յzsld]VNG@93-'" վzskd\TLE>71+%  zrjbZRJC;5.(# ¾yph`WOG@82+&  wne]TLD=5/)# þ}tkbYQHA92,&  Ŀypg^UME=6/(# ſvlcZQIA92+%  ľ{qh_VMD=5.(" üvmcZQH@81+% {rh^ULD<4.'" žvlcYPG?80*$  û{qg^TKC;4-&!  ǿukbXOF>6/)#  ûzpf\SJB:2,%   ǿ~tj`WNE=5.("  ûxnd[QI@81*$  ƿ}si_ULD<4-'!  ºwmcYPG?70)#  Ž{qg]TKB:3,&   ukaXNF>6/("  ļyoe[RIA92+%  }si_VMD<5.'!  ûwmcZQH?80*$ ƾ|rh^TKC;3,&  /--(  &  $ #            !!"  !"#$%&&''( !#$&'(*+,,-../  "$&(*,-/01234556  #%(*-/13578:;<==>? "%(+.1468;=?@BCDEFGG  #'*.147:=@BEGIJLMNOPQ !$(,047;?BEHKMPRTUWXYZZ !%)-16:>BFJMPSVY[]_`bcdd !%*.37CHMRV[_cfjmortuwxyz  $).39>DIOTZ_chlpswy|~ #(-38>DJPV\bglquz} "',27>DJQW^djpuz  %*06FOXblv  %+29AJS\fpz  !'-4FOYblw $*19AIR\fpz !&-4GPYcmw %+29AJS]gq{ !'-4=<;:975420.,*'%#  HHGFFECBA?=<97530.+(&#! QRQPOONLKIHFDA?<:741.+)&#  [ZYXWVTRPNLJGDA>;852/+(&#  eeffeedcba_^\ZXURPMIFC?<851.+(%"  pponmkjhfda_\YURNKGC@<851.+(%"  {{zyywvtrpnkheb^[WSOKGC?;740-*(%#! ą}{xurolhd`\XSOKGB?;741.+)'$#! |yuqmie`\WSNJFB>;742/-*)'%$"!  {wrnid`[WRNJFB?;9631/-+*('%$#"  {wrmhc_ZVRMJFC@=:86420/-,*)'&%#" Ů{vqlhc^ZVRNKHEB@><:865310.-+)'&$" ŷzuplgc_[WTQNKIFDB@>=;976420.,*(%#!~yuplhd`]ZWTQOMKIGECA?><97530.,)&$!~yuqmifc`][XVTRPNLJHFDB?=:852/,)&# ~zvsoligdb`][YWUSQOMJHEB?<963/,(%"¿|yvsqnljgeca_][XVSPNJGD@=952.*&¿~{yvtrpnkigdb_]ZVSPLHD@<84/+|zxvtqolifc`\YUPLHC>:50~|ywtpmjfb]YTOJE@;6ÿ~zwsokfa\WRLGA<ÿ}ytoje_YSMGA}xsmgaZTNG{unhaZTM}vohaZR}vng_W|ume]zrjaÿwnf{ri vmſyoý{rſ}s~t~u~tſ}s¼{rĿypvm¾ÿ|sj§xof׾{skb~vnf^@<:9654210/ . . - , + + * *# )'# ),(# (1,(# (61,'" (;60+&! 'A;5/)$ 'F?93-'" 'KD=60*%  'PHA:3-'" &UME>70*$ &YQIA:3,&! &]TLD<5.(" &`WOG?70*$ &dZRIA92+% &f]TKC;3,&  &h_ULD<4-'! &j`WNE=5.'! %jaWNF=5.(" %kaXNF=6.("  jaWNE=5.(" j`WME=5.'!  h_ULD<4-'!  f]TKB:3,&  dZRIA92+%    aXOG?81*$ ^UMD=6/)#  ZRJB:3-'"  VNF?81+&         (                "(/7?HR\fq| "(/6?HQ[fp{ !'.6>GPZepz !'.5=FPZdoz  &-5=FOYcny  &-4GQ[ep{ !'.5>GPZdoz  '-5=FOYdny  &-4GQ[ep{ !'.6>GPZdoz  '-5=FOYdny  &-4GPZeoz !'-5=FOYdny  &-4GPZepz !'.5=FPZdoz  &-5=FOYcny  &-4=>@BFKRY`ir{ļwmd[TMGB?<;;=?CHNU]enwżwmd[SLFA=;99:=@EKRYajt}Žwmc[SKE@<9778:>BHNV^gpzƽwmcZRKD?;86568;@ELS[dmwƽwmcZRJD>:754569>CIPYakt~ƾwmcZRJC>9643357;AGNV_hr|ǾxndZRJC=8532236:?ELT\foyǿxnd[RJC=84211248=CJRZcmwȿynd[RJC=84100137;AHPXakuyoe[RJC=841//026:@GNW`it~zoe[SJC=730/./159?EMU^hr|zpf\SKC=830../148>DLT]gq{{qf]TKD=840/..038=DKS\fpz¹|qg]TLD>841/..037=CJS[eoy¹|rh^ULE>841/..037DLS\eoyƾxne[SKE?:743357;@FMU]gpzǿzpf]UMFA<865569=AGNV_hr||rh_WOIC>;8779;?DJPXajs}~tkbZRKFA=;::;>BFLS[cluúwme\UNIDA>==>AEIOV]foxļyph`XRLHDBAABDHMRY`iq{Ž}tkc\UPLHFEEFILQV]dlu~ǿwog`ZTPMJIIKMQU[ahpy{sle_YURPOOPRVZ_fmt}ļxqjd_[WUTTVX[`ekryƿ}vojea^\[[\^aekpw~ľwog`YSMIEB@@ABDHLRX_gpyý}tle^WQLHDBA@ACFKPV\dlu~»zrjb[UOKGDBAACEINSZaiqzwog`YSNIFCBBCEHLQW^emvſ}tle]WQLHECBBDFJOT[bjr{üzqib[TOJGDCC[EIMRX_fowvnf_XRMIFDCCEGKPU\ckt|ƿ{rjc\UPKGECCDFIMSY`gpyüwog_XRMIFDCDEHLPV]dlu~|skc\UPKGEDCDFJNSZahqzĽwog_XRMIFDCDEHLQW]emv{sjc[UOKGECCDGJOTZbir{žwnf^XRMHFDCDEHLQW^fnw{rjbZTNJFDCCDGJOT[bjs|Žvme]VPKGECBCEHLRX_foxyph`YRMIECBBDFJOU[ckt}Ľ}tkc[UOJFCBBCEHLRX_gpxwnf^WPKGDBAACFJOU\clt}ûzqh`YRLHDB@@BDHLRX`hpyƾ}tkc[TNIEB@@BEJOU\dlu~wne]VOJEB@??ACGLRY`hqzļzqh_XQKFB@>>?AEIOU\dmvǿ}sjaYRLGC@>=>@CGLRYair{vld[TMHC?=<<>@DIOU]enwĻxof]UNHC@=;;<>BFLRYajs|ƾ{qh_WPID@=;:;CHOV^foyļwmd[SLF@<9779<@EKRZbkt~ƾyof]TMFA<96567:=BHOV^gpz{qg^VNGA<864458;?EKRZclu}si_WOHA<8533458=BHOV_hq{útjaXPHB<8532236:?EKS[dmvļvlbYPIB<84200247DKS[dnwǿynd[RJC=730..036;AHOW`is}zoe\SKC=73/-,-.048>DLT\eox{pf]TKC=72/,++,.16;AHPXajt~¹|qg]TLD=72.+**,/38>ELT]fpyú}rh^ULD=72.+)()*-05;AHPYbkuû~si_ULD=71-*(''(+.28>ELU^gqzĻ~ti_VMD=71-)'&%&(,05;AIQZclvżtj`VME=61,(&$$%&)-27>EMU_hr|żuj`VME=60+(%##%'+/4;BIRZdmwŽuk`VME=60+'$"!!#%(,17>FNV`isƽuk`WME=60*&#! !#&*/4;BJR[enƽuk`WME=5/*&" !$',18?FNWajƽuk`VMD<5/)%!"%).4;CKS\fƽuk`VMD<5.)$! #',18?GOXbŽuj`VLD;4.(# !$).5FzoeZQG?7/)#"'-3:BǿxncYOF=5.("$*07?ƾwlbXNE<4-'!"'-4;żuj`VLC;3,& %*18ú~si^TKB:2+%"(.5|qg\RI@81*$   %+2ǿyodZQG?7/("  #(/ŽwmbXOE=5.'!  &,vlbXOF>6/)# Žzpf\SJA92+% ~tj`VME<5.'" ûxndZQH@81*$ ƿ|rh^ULC;4-&! ºvlbXOF>6/)# Žzpf\SJA:2+%  ~tj`WNE=5.(" ĻxndZQH@81*$ ǿ|rh^ULC;4-'! ºvlbYOG>7/)# Žzpf]SJB:2,%  tjaWNE=5.(" ļxnd[QH@81*$ ǿ}si_ULD;4-'! ºwlcYPG?70)# ž{qg]TKB:3,&  ukaWNE=6.(" ļyoe[RI@91+$ ǿ}si_VMD<4-'! úwmcYPG?70)# ƾ{qg]TKB:3,&  ukaXNF>6/(" ļyoe[RIA92+% }si`VMD<5.'! ûwmcZQH?80*$ ƾ|rh^TKC;3,&  vlbXOF>6/)# Žzpf\SJA92+% ~tj`VME<5.'" ﷿ûxndZQH@81*$ ƿ|rh^ULC;4-&! ºvlbXOF>6/)# Žzpf\SJA:2+%  ~tj`WNE=5.(" ûxndZQH@81*$ ǿ|rh^ULC;4-'! ºvlbYOG>70)# Žzpf]SJB:2,&  tjaWNE=5.(" ļxnd[QI@81*% ǿ}si_ULD<4-'" AºwlcYPG?70*$ž{qg]TKB:3,&!}ukaWNF=6/)#xļyoe[RIA92+&!t~ǿ}si_VMD<5.(#pzúwmcZPH@81+&!kuƾ{qg^TKC;4.($ gq{ukaXOG?71+&"cmvļyoe\SJB;4.)$!_hr|~tj`WNF>71,'$!Zdnxûxnd[RIA:4.*&#"!V`is}ƾ|rh_VME>72-)&$#R\eoyvlcYQIA;50,)'&NWakt~Žzpg]ULE>83/,*)KS]fpzukbYPIB<62/-,GPYblvûyof]TLE?:620/CLT^gq{ǿ}tjaYQIC>9643@HQZcmwºxne]UMGA=9766=ENW`jt~ļ{rjaZSNIECB2:BJS\fpzǿwnf_XRMJGF #)07?GPZdnx %+2:BKT]gq| !'.5=ENWaku #)07?HQZdny  %,3:BKT^hr| "(.5=ENXakv $*18@IR[eoy  &,3;CLU_hs} "(/6>FOXblv $*19AIR\fpz !&-4;DLV_is~ "(/6>GPYcmw %+29AJS\fp{ !'-4FOYblwƾ $*19AIR\fpzļ !&-4GPYcmwƾ %+29AJS]gq{û !'-4FOXblvƾ %+19AIR\fpzû !'-4;DLV_is~#)/7>GPYcmwƾ %+29AJS\fp{û"(.5FOXbkvǿ}sj "%).4:BJR[eoyļypf!"$',17=EMV_is}vlc$%'*.3:@HPYclvǿ|ri`&'*-17=DKT]fpzļxoe\)*-04:@GOW`jt~ukbY,-037=CJR[dnxƾ{qh^V/036;@GNV_hr{ûwnd[S346:>DJRZclu~tjaXP67:=BGNU^fpyƾzpg]UL:;=AFKRYajt}ûwmcZQI>?AEIOV]fnx}si`WNGACEIMSZair{Žyof\SKDFGIMRW^fnvúvlbYPHA¼xpiaYľxrkc\U~|{zz{|}כ}xrke^WPü}yvtrqqrtuwy{~ב{vqke_YRLƿzurnljiijlnprtvy{}~{wsnid_YSMGûysnjgdba``aacdfhkmoqsuwy{|}~~~}|zxurokgb]XSNICƿyrlgc_]ZYXXYZ\^_bdfhjlnpqrstuutsqomjgc`\WSNID@üzslfa]YVTRQQRTUWY[]_acefhijkllkjhgeb_\YUQMIEA<|tmf`[VROMKJJKLNOQSUWY[\^_`abccb`_][XVSOLHEA=:ļwoha[VQMJGEDDCDEFGIJLNPQSUVWYZZ[[ZYXVTRPMJHEA>;8{skc\VQLHEB@?>>?@ABDFGIKLNOPQRSTTSRQPNMKIFDA?<:7ƾwnf_XRLGC@><::9::;<=?@BDEFHIJKLMMNNMLKIHFECA?=;97û|sjb[TNHD@=:876678:;<>?ABCEFGGHIIHGGFECBA?><;98xog_WQJEA=:75433456789;<=?@ABCCDEEDCBA@?>=<;:9Ž}tkc[TMHB>:75322345689:<=>?@@ABBCBA@??>>==<ºzqh`XQKEA<96432112345678:;<=>??@@AABA@wne]VOID?;864321223456789:;<=>??@@AA BCDEŽ}tkc[TMHC>;8643345789:;<=>?@AABBCDEFGGHIJKºzqh`YRLGB>;97655678:;<=?@ABBCDDEEFGHIJJKLMOPQǿwnf^WQKFB?<:987889:;<>?@BCDEFGGHHIJKLMNOPQRTUWXļ}tld\VPJFB?=<;:;;<=?@ACDFGHJKKLMMNNOPQRSTUWXZ[]_aº{rjb[UOJFCA?>>?ABDFGIKLNOPQRSSTTUVWXXY[\^_acegixog`ZTOJGDCAABCDFHJLNPRSUVXYYZ[[\]^_`abdfgiknpr~umf_XSOKHFEDEEFHJLNQSUXZ[]_`abccddefghiklnprtwy{{skd]XSOLIHGHHJKNPRUX[]`bdfgijkkllmmnopqrtuwy{~xpib\WROLKJJKLNQSVY\_cehkmoprstuuvvwxyz|}~vng`[VRPNMMOQSVY]`dgknqtvxz|}~ゃ{sle_ZVRPOOPSUX\`dhlpswz}̍xpic]YURQPPRTVY]afjosw|̖~vnga\XUSRRSTWZ^cglqv{ ˠ{ske_[WTSRSTWZ^cgmrx} ͪxpic]YVTSSTVY]bglrx~γ}umfa\XUSSTUX\`ekqw~̻ŝyrjd^ZVTSSTVZ^chou|ʙvoha\XUSRSUX[`flryΖ{ske_ZVSRRSUX]bhnu}֓xphb\XTRQQSUY^cjqxӏ}ume_ZVRQPQRUZ_els{׌zqib\WSQOOPRVZ`fmu}Ԉvnf_ZUQOMNORUZ`gowӄ{sjc\WROMLLNQU[ahpxсxog`ZTPMKJKMQU[aiqy}tld]WQMKIIJLPU[aiqzzqhaZTOKIGGIKOT[bjr{vme]WQLIFEFGJOTZbjs|rjbZTNJFDDFINSZbjs|of^WQKGDBBCEIMSZbjs}ÿlc[TNIEBA@BDHMSZbjt}þh`XQKFB@??@CGLRYbjt~ſe\UNHD@>==?BFKRYajt~aYRKFA><;<>AEKQYajt~ü^VOHC?<::<@DJQYajt~ƿ[SLFA=:889;?DJQXajt~»WPIC>:8778:>CIQYakuTMF@<86557:>CIPXakuĽQJC>9643469=BIPXakuºNGA;74323589521124794/+'#  !!""##;62.*&#  !!"##$%%&&'(())840-*&$! !!"##$%%&''()**+,,-..//00630,*'%#! !""#$$%&''()**+,-../012234556778852/-+(&%#"!  !""##$%&&'())*+,--./011234567899:;<=>>?@@A520.,*)('&%%$$%&'(()*++,-./001234567889:;<=>?@ABCDEFGGHIIJ5320/-,,+**+,-.//01234456789:;<=>?@ABCDEFGHIJKLMNOPQQRSS654321100//012234456789:;<=>?@ABCDEFGHIJKLMNOPRSTUVWXYZZ[\]]987766556789:;<==>?@ABCDFGHIJKLMNOPQRTUVWXYZ[\^_`abcdeffgh<<;;<=>?@ABBCDEFGHIJLMNOPQRSTUWXYZ[\]_`abcdfghijklnoopqrr@AABCDEEFGHIJKKLMOPQRSTUVWXZ[\]^_abcdeghijlmnoprstuvwxyz{|}}EFGGHIIJKLMNOPQRSTUVWXYZ\]^_`acdefgijklnopqstuvxyz{}~KLMNOPQSTUVWXYZ[\^_`abcefghiklmnpqrtuvwyz{|~RTUVXYZ[]^_abcdeghijlmnoqrstvwxy{|}~Z\]_`bcefhiklmopqstuvxyz{}~bdfhjlmoqrtuwxy{|}kmoqsuwy{}~twy{}~‡đšţŬȴȻ ڼٳګ󳯬ڡ򬨤ۘ𦡝َۄ혒}|zyyz{|~둋}zwtrqpoopprsuwz|ꊄzuqnkihgffghjlnqtx|~xrnjfca_^]]^^`bdfimquz~wqkfb^[YWVUUVXZ\_bfjotzyrke`[WTQONMMNOPRUX\`diou{sle_YUPMJHGFFGHILORVZ_ejqwog`YTOJGDB@@ACFIMQU[agnu|jb[TNIEA><;::;<>ADHLRW]dkrzf^WPJD@<9765567:=@DINT[biqyc[SLF@<853112469=AGLSYahqy`XPIB=841/.-./137;?EKQY`hqy]UMF?:51.,+*+,.159>DJQX`iqz[SJC=72/,*(()*-048>DJQYajs|            #$$#"!  *)('&%$#"  10/..-,*)(&$#! 987654310.,*(&$"  ABBA@?>=<:97531/,*'%" JKKJIHGEDBA?<:852/-*'$! TUTSRQPNMKIGDB?<962/,(%" ^]\[YXVTROLJGC@<951-*&" hiihgfeca_][XURNKGC?;72.*&" ssttsrqpomkigda^ZWSNJEA<83.*&! ~~~~}|{ywuspmjgc_ZVQLGB=83.)%  ׆}zwsokgb]XRMGB<71,'# Փ|xsoid^YSMGA;5/*%! ՝{vpke^XRKE?83-(# ԧ}wqjd]VOIB;5/*$  ԰}wpib[SLE>81+&! Һ|umf^WOHA:3-'" yqiaZRJC;5.(# }uld\TLD=6/)# ÿwnf]UME=60)$ ypg_VNF>70*$ þzqh_VNF>60)# zqh_VME=6/)# üzqg^UMD<5.(" Ľypf]TKC;4-'! Ľxne[RJB:3,&  ĽvlcYPH@81*$ ü}sj`WNF>6/)# zqg]TKC;4-'! ǿwmdZQI@91+% Ž}sj`WNF>6/)# ºzpf]TKB;3-&! ƿvlbYPG?81*$ ļ{qh^ULD<5.(" wmcZQH@92+%  Ľ|ri_VME=5/(# wnd[RIA92+%  Ž}si`VNE=6/)# xne[RJA:2,&  Ž}si`WNE>6/)# xne[RJA:3,&  Ž}sj`WNF>6/)# xne[RJA:3,&  ž}sj`WNF>6/)# xne[RJA:3,&! ž}sj`WNF>6/)# xne[RJA:3,&! ž}sj`WNF>6/)#  xne[RJA:3,&!  ž}sj`WNF>6/)#  xne[RJA:3,&!  ž}sj`WNF>6/)#  xne[RJA:3,&!  ž}sj`WNF>6/)#  xne[RJA:3,&!  ž}sj`WNF>6/)#  xne[RJA:3,&!  ž}sj`WNF>6/)# xne[RJA:3,&!  #*19AJT^hs~ #)08@IS]hr} ")07@IR\gr| "(/7?HR\fq| !(.6>GQ[ep{ !'.5>GPZdoz  '-5=FOYdny  &-4GQ[ep{ !'.6>GPZdoz  '-5=FOYdny  &-4GPZeoz !'-5=FOYdny  &-4GPZepz !'.5=FPZdoz  &-5=FOYcny  &-4GQ[ep{  !'.5>GPZdoz   '-5=FOYdny   &-470)#  ƿyof\SKB;3-&!  }tjaXOG?70*$  üxne\SKC;4-'!  ž{ri`WOF?70*$  vmd[RJB;4-'"  ypg^UME>70*$  »{rjaXPHA93,'!  ¼}uld[SKC<5/)#  ýwnf]UMF>81+%  ľyph`XPHA:3-(" žzrjaYRJC<5/)$ ƿ|skc[SLE>71+&! }ume]UMF?92,'" ¼vnf^WOHA:4.)# ľxph`XQIB<5/*%  zrjbZRKD=71+&! Ľ}uld\TMF?92-'# xog_WOHA:4.)$ ž|skbZRKD=60+&! »xog^VNG@93-(#  }tlc[SKD=60*%   ƿ{ri`XPHA:4.(#  ƾypg_VNF?82,&!  žxof]UME>71+%   žxof]ULE=60*%  ƾxof]UME=70*%  zpg^VNF>71+%  |ri`XOG@92,&! ü~ulcZRJB;4.(# žxof]UME=60*%  |sjaXPHA93-'" ļwne\TLD=60*$ |sjaYPHA:3-'" ļxof]UME>71+%  }tkcZRJB;4.(#  Žzqh_WOG@92,&!  »wne]TLD=60*%   }tkbZRJB;4.(#  Ľzqh_WOG?82,&!  »wne]TLD=60*$  }tkbZRJB;4.(#  žzqh`WOG?82,&!  ûwne]TLD=6/*$  }tkbZQIB:4-'" žzqh_WNG?81+%  üwne\TLD<5/)# }tkbYQIA:3-'! ƿzqh_VNF>70*% üvmd[SJC;4.(" |sjaXPG@82+&  ƿypf]ULD=6/)# üulcZQIA:3-'! /6>FOXakuº{skc\WRNLJ,3;CKT]gq{ƾwoha[VSPO*07?GPYclv|tmf`[XUT'-4FOXaku !&,3;CKT]gq{ $*07?GPYclv !'-4FOXaku !&,3;CKT]gq{ $*07?GPYclv !'-4FOXaku !&,3;CKT]gq{ $*07?GPYclv !'-4OPRVZ`gnvŽyoe[RJB;SUWZ_eks{ºukaXOG@9XY\_dipwǿ|rh^ULD=6]^adinu|żxndZQIA:4cdfinsz¹ujaWNF>71hiknsx~ǿ{qg]TKC<5/noqtx}ļxmcZQH@92-stvy~~tj`VME=60+yz|ƾ{pf]SJB;4.)ļwmcYPG?81,'~si_VMD<5/)%ƾzpf\SJA:3-'#ûvlbYOG>70*%!}si_ULD<4.(#ƾzoe[RIA92,&"ûvlbXOF>6/)$ }rh^ULC;4-'"Žyoe[QH@81+% úukaWNE=6/)#|rh^TKB:3,'!ŽxndZQH?80*$ºukaWNE=5.("ǿ|qg]TKB:2,&!ļxncZPG?70)$¹tj`VMD<5.'"ǿ{qf]SJA92+% ļwmcYPG>7/)#~ti_VMD<4-'!ƾzpf\RIA91+%ĻwlbYOF>6/(# }si_ULC;3-&! ƾzoe[RI@81*$ ûvlbXOF=6/(" }sh^ULC;3,&  Žyoe[QH@81*$ úukaXNE=5.(" |rh^TKB:3,%  ŽxndZQH?70)#  ºukaWNE<5.'!  ǿ|qg]TKB:2+%   żxndZPG?70)#  ¹tj`VMD<4-'! ǿ{qg]SJA92+% ļwmcYPG>7/)# ~tj`VMD<4-&!  ƾ{pf\SJA91+$  ļwmcYOF>6/("  ~si_ULC;4-&   ƾzpf\RIA91*$  ûvlbXOF>6/("  }si_ULC;3,&  ƾzoe[RI@81*$ ûvlbXOF=5.("  }rh^UKC:3,&  Žyoe[QH@80*# úukaWNE=5.'" |rh^TKB:3,%  ŽxndZQH?70)# ºukaWNE<5.'! ǿ|qg]TJB:2+% ļxncZPG?70)# ¹tj`VMD<4-'! ǿ{qf]SJA92+% 82.+)(()+/49@HPYcmxżwlc50,)'&'(+.39@HPYcmxļuka3.*'&%&'*.39@HPZcnxĻtj`1,(&$$%&)-29@HPZdnyú~si_.*'$##$&)-28@HPZdnyú}rh^,(%#""#%(-28?HPZdny¹|rg^*&#! !"$(,28?HPZdny¹|qg]($"  !$',18?GPZdoy¹{qg]&#  #'+18?GPZdoy{qf\$! "&+17?GPZdoz{pf\# "&+17?GPZdozzpf\!!%*07?GPZdozzpf\!%*07?GPZdozzpf\ %*07?GPZeozzpf\ $*07?GPZeozzpf] $)07?GPZeozȿzpf]$)/7?GPZeozǿzpf]$)/7>GPZeozǿzpf]#)/6>GQZeozǾzpg^#)/6>GQZepzǾzpg^#)/6>GQ[ep{ƾzpg_#)/6?GQ[ep{ƾzph`#)/6?GQ[ep{ƽzqh`#)/7?HQ[ep{Žzqia#)/7?HQ[fp{Ž{rjb#)/7?HQ[fq{Ž{rjc#)/7?HR\fq|Ž|skd#)07?HR\fq|ż|tlf#)07@IR\gq|ż}ung #)08@IR]gr}ż~voi #)08@IS]gr}żwqk #)08@JS]hs}Žyrl #*18AJT^hs~Žzto $*19AJT^is~Ž|vq $*19BKT_itŽ~xs $*19BKU_jtžzv $+2:BKU_juƾ|x $+2:CLV`juƾ{ %+2:CLV`kvƿ~ %+3;CMVakvǿ %,3;DMWalw %,3;DMWalw  &,4ÿ !'.5=FPZdoz !'.5=FPZdoz !'.5=FPZdoz !'.5>FPZdoz !'.5>GPZdoz !'.5>GPZdoz !'.5>GPZeoz !'.5>GPZeoz !'.6>GPZeoz !'.6>GPZeoz !'.6>GPZeoz !'.6>GPZepzYQIA;50-*(''),/38>DKRZclu~XOG@93/+(&%&'(+/38>ELT\enwWNF>82.*'&%%&),/4:@GNV_hqzžUME=71-)'%%'),16;BIQYbkt~ULD=61,)'%%&'*-27=DKS\enwžTKC<61,)'&&')+/4:@GOW_ir|TKC<61-)'&'(*-1695200259>CJQYbkt~žTLE?:632258CHOV^gpyUNGB=:989:=AFLS[clu~ž}UNHC?<::;=@EJPX_hpzºyVOID@>==>@DINU\dmuƾ~tWPJFB@??ACGLRY`iqz;ºyoWQKGDBABDGKPV]emvƾ~ukXRMIFDDEGJOT[bjr{ûzpgYSNKHGGHJNSY_gowǿvlcZUPLJIIKNRW]cks|ļ{rh_\VRNMLMNRV[ahpxxne[]XSQOOPRUZ_fmt}Ž~tkaX^YVSRRSVY^djryºzqh^V`[XUTUVY]bhov~xne\Sb]ZXXZ]afms{ŽulcZRd`][[^aekqxû|sjaYQfb_^^_bejov}{ri`XPhdbaaceintzǿzqi`YQjgedegjnsyžzqiaYRmjhhiknrw}Ľzrjb[Tomkklorw|ļ{sld]Wrpoopsv{ļ}ung`Zusrsuw{Ľxqkd^xvvwy|ľ|void{zz{}ſztoj~~zupü|wſýÿ¿ȮγԷٻ     ޾}sj`WNF>6/)# ߹xne[RJA:3,&! ߵ}sj`WNF>6/)# ౨xne[RJA:3,&! ୤}sj`WNF>6/)# ᨟xne[RJA:3,&! ᤚ}sj`WNF>6/)# ⟕xne[RJA:3,&! ⚑}sj`WNF>6/)# 㕌xne[RJA:3,&! 㑇}sj`WNF>6/)# 䌂xne[RJA:3,&! }sj`WNF>6/)# xne[RJB:3,&! }sj`WNF>6/)# xne\SJB:3,&! sj`WNF>6/)# oe\SJB:3,&! jaWOF>70)$ f\SKB;3-'! aXOG?71*$ ]TLC<4.(" YQH@92+&  VME=6/)$ SJB;4-'" PH@92,&! ME>70*%  KD<6/*%  JC<5/*%  IB;5/*&! IB<60+'#  JC=72-)%!  KE?940,($!  MGB<83/+(%"   PKE@<730-)'$!  TOJE@<952/,)&$"  YTOJFB>;842/,)'$" ^YUPLIEB>;8520-*'%" e`[WSPLIFB?<9630-*'$" kgc_[XTQMJGDA=:740-*'#  sokgc`\YVROLHEA>:73/,(%! {wsplieb_[XTQMIEA>:62.*&" Ճ|yurokhea]ZVRMIEA<83/+'# Ԍ|xurnjgc^ZVQLHC>940+'" ԕ{xtplgc^YTOJD?:50+&" Ӟ}yupkfa\VQKE?:4/*%! ӧ~ytoic^XQKE?93.)$ ӯ|wqke^XQKD>82,'" ӷysle^WPIB<6/*$  ҿyrkd]UNG@93,'" yqibZRKC<5/)$ ~vnf^VNG?81+%  ¾{skbZRJB;4-'" wnf]ULD=6/(# zri`WOF?70*$ þ}tkbYPH@81+$ vlcZQIA92+%  ½vmd[RJA:2,%  ½wmd[RJA:2,%  ¼vmd[RIA92+%  ~ulcZQH@91+% ½|sjaXOG?70*$ ÿypg_VNE>6/)# þ~umd\SKC<4.("   $+2:CLU`ju  $*19BKU_it  #*19AJT^is~  #)08@JS]hr}  ")07@IR\gr}  "(/7?HR\fq|  !(/6>GQ[ep{  !'.6>GPZdoz   '-5=FOYdny   &-4GPZeoz  !'-5=FOYdny   &-4GPZepz  !'.5=FPZdoz   &-5=FOYcny   &-4GPZeoz  !'.5=FPYdny   &-4=EOXcmx   &,4GPYblu  !'.5==>ADINU\dlt}Žxne\TMGB><::;=@EJPW^foxƽxnd\SLFA=:878:=AFKRYajs|ƾxnd[SLE@;865579=BGMU\emvƾxnd[SKD?:6433469>CIPW`hqzǾxnd[RKD>95210136:?EKS[clu~ǿynd[RJC=841/./036;AGNV^gpyȿyoe[RJC<72/-,,-037=CIQYajt}yoe[RJB<61.,**+-049?ELT]eoxzoe[RJB;50-*)()*-15;AHOX`is|zpe\RJB;50,)'&'(*.27=DKS[dmw{pf\RJB:4/+(&$$&(+/39?GNV_hr{¹{pf\RJA:4.*'$##%(+05;BJRZclv¹{qf\SJA:3.)&#"!!#%)-28>EMU^gqz¹|qf\SJA:3-)%"  !#&*.4:AIQYbluº|qg]SJA:3-($!!#'+06=DLU]gpzº|qg]SJA:3-'# !$(-39@HPXakt~º|rg]SJA92,'#"%*/5FNW`is}{qf\RI@81+% #(-4;BJR[dnx{pf[RH@81*%  %*07>ENV_ir|ƾzoe[QH?70*$"'-3:AIR[dmwŽxndZPG>7/)#$)/6=EMV_hr{ûwmbXOF>6/(#!&,29AIQZcmvukaWNE<5.'"#)/5=DMU^hq{Ľ}si_ULC;3-&!!&+29@HQYclvzpf]SJB:2+%  #(.5FOW}unf^VOG@93-'"  !'-3:BJS}vng_XQIB<5/)$  $)06>FN{rh_VNF>70*$ žwne\SJB;4-'" »}sjaXOG?81+%  ǿyof]TLD<5.(# ļ~ulbYQH@92,&! zqh^UME=6/)# žvmd[RIB:3,'! »|ri`WNF>70*$ ǿxne\SJB;4-'" ü}sjaXOG?70*$ yof]TKC;4.(" Ľ~tkbXPG?81+%  zpg]ULD<5.(" žulbYPH@81+%  º{qg^UMD<5.(# ƿvlcZQH@92+%  û{rh_VME=6/)# ǿwmdZQIA92,&  ü|rh_VME=6/)# wmd[RIA92,&  ļ|ri_VNE=6/)# xnd[RIA:3,&! Ľ}si`WNE>6/)# xne[RJB:3,&! Ž}si`WNF>60)# xne\SJB:3,&! Ž}sj`WNF>70)$ xoe\SJB:3-'! Ž}tjaWOF>70*$ yoe\SKB;3-'! ž~tjaXOF>70*$ ºyof\SKC;4-'"ž~tkaXOG?70*$ºypf]TKC;4-'"ƾ~ukbXPG?81*%ºzpg]TLC<4.("ƾulbYPH@81+% »zqg^ULD<5.("ƿvlcYQH@92+% û{qh^UMD=5/(#ǿvmcZQIA92,& û{rh_VME=6/)#wmd[RIA:3,&ļ|ri_VNE>6/)xne[RJB:3-ļ}si`WNF>70xoe\SJB;4Ľ}tjaXOG?7yof]TKC;Ž~tkaXPG?ºzpg]TLDƾulbYPHºzqg^UMƿvmcZQû{rh_Vǿwnd[zü|si`t~xoeoyļ}tjjt~ypeoyŽu`js}ºz\eoxƾW`is}û #)/6>FOXbku !&,3;CKT]gq{ $*07?GPYcmw !'-4FNXaku   &,3:BKT]gpz  $)07?GPYblv  !'-4;CLU^hr|  $*18@HQZdmw  "(.5GOXblv  !&-4;CKT^gq{  $*18?HQZcmw  "'.4FOXaku  !&,3:BKT]gpz  $*07?GPYblv  !'-4;CLU^hq{  $*18@HQZcmw  "(.5ENV`ir|   !&,3:AIR[dmv   #)/6=EMV_hqz   !&,29AIQYbkt}   #)/5=DLT]fnw   &+28@GOW`hqz   #(.4;BJRZbks|   %*07>ELT\dmu}!   "',39@GOV^fnv}$  #).4;BIPX_gnv}'!   %*06DKRY`gmtz-'"  #(-28>EKRX_elrx}0*$  $(.39?EKQW^diot4.("   $).39>DJPV\afk81+%    %).38>CINTY^c<5.(#  !%).37=BGLQVZ@92+%    $)-26;@DIMRD=5/)#   $(,049=AFJIA92,&!  #'+.26:>BME=6/)$  "%),037:RJB:3-'!   $'*-03WNF>70*$  "$'*-\SKC;4.("  "%'aXOG?81+%    "f]TLD<5.(#   lbYQH@92,&!   qh^UME=6/)#   vmd[RIB:3-'!   |ri`WNF>70*$   ļwmcYPG>6/)# ~ti_VLD;4-&! ƾzpf\RIA91*$ ĻwlbYOF>6/(" }si_ULC;3,&  ƾzoe[RI@81*$ ûvlbXOF=6.(" }sh^ULC;3,&  Žyoe[QH@80*$ úukaXNE=5.(" |rh^TKB:3,%  ŽxndZQH?70)# ºukaWNE<5.'! ǿ|qg]TKB:2+% żxndZPG?70)# ¹tj`VMD<4-'! ǿ{qg]SJA92+% ļwmcYPG>7/)# ~tj`VMD<4-&! ƾ{pf\SJA91+$ ļwmcYOF>6/(" ~si_ULC;4-&  ƾzpf\RIA91*$ ûvlbXOF>6/(" }si_ULC;3,&  Žyoe[RI@81*$ úvlbXOF=5.(" }rh^UKC:3,&  ļyod[QH@80*# ¹ukaWNE=5.'" ƾ|rg^TKB:3,%  ûxndZQH?70)#  tj`WME<5.'!  ü{qg]SJB92+%  ƿwmcYPG>7/)#  ¼}si_VLD<4-'!  ľyoe[RIA91+$  ~tkaXNF>6/(" zpg]TKB:3,&  ¿ulbYPG?80*$ Ӳzqg^ULD<5.'" ۸~ulcZQI@92+% ܲypg^VME=6/(# Ԝ{sjbYQIA:2,&  ԓ}ume]UME=6/)# Ջ}vog`XPHA93,&! Ղ|vpiaZRKD=6/)$ y}~zuoib[TMF?82,&! ptx{}}zvrmhb\UOHA;4.)# gkortvwwvtqnjfa[UOIC<60+%! ^bfhkmnnmkifb^YTOIC=82,'" VY]_bceedb`]ZVRMHC>83.($ MQTVYZ[\\[ZXUROKFB=83.)%  EHKNPQSSRQPMKGD@<73.*%! >@CEGIJKKJIHEC@=952-)%! 69;>?ABBA@><9630,)%! 024689:;;:97530-*'$! ),./123443320/-*(%"  $&')*+,--,+*)'%#!  "#%&&''&%#"   !!      !'.6>GPZepz !'.6>GPZepz !'.6>GPZepz !'.6>GPZeoz !'.6>GPZeoz !'.6>GPZdoz !'.5>GPZdoy !'.5=FPYdny !'.5=FOYcnx  &-5=ENXbmw  &-4GOYblv !'.5EMT\dmu| "'-3:AHOW_gnv}|yw  %*06ELSZahnu{é~zvrokifd $).4:@FMSZ`gmsy~ }yupmieb_]Z  %*/5;@FMSY_ekpuz|xtokgc`\YVTQ "&+05;@FLQW]bglqvz}}zvrnjfb^ZWSPMKI "'+05:@EJOUZ_chlptwz|~~|yvsplhea]YUQNKHEC@ #'+049>CHMQVZ_cfjmprtuwwxxwvusqolifb_[WTPLIFB@=;9 "&+/38<@EINRVY]`cehjklmmlkigeb_\YVROKHDA>;8631 "&)-159>BEIMPTVY\^_abccb`_][YVSPMJFC@=9641/-+ !$(+/36:>ADHKMPRTVWXYYXWUSROMJGDA>;8520-+)'%  #&)-036:=?BEGIKLNNOONMLJIFDB?=:741/,)'%#!  !$'*-0258:=?ABDEFFEDCB@><:8530-+(&$"  !$'),.13578:;<==>>==<;:86420.,*'%#! !#&(*,./123456654321/-,*(&$"   "$&')*+,-..-,+*('%$"   !#$%&&''&%%#"!    !!                      "(P~}{xvs}zwurpmkh~|ywtromjhfca^ͽ}{xvtqoljgec`^[YWTδ}zxuspnkigdb_][YVTROMKʬ~|ywtromkhfca_\ZXVSQOMKHFDBʢ}{yvtqoljgec`^\YWUSPNLJHFDB@><:Ș}zxuspnkigdb`][YVTRPNKIGECA?=;97642ʍ}{ywtromkhfca_\ZXVSQOMKIGDB@>=;975320.-+ȃ~|{ywuspnljgec`^\YWUSPNLJHFDB@><:86531/.,+)'&%~}||{{zyxwvusrpnljhfdb_][YVTRPNKIGECA?=;986421/-,*)'&$#! vtsrrqqpponmlkjigedb`^\ZXUSQOMKIGDB@?=;975320.-+*('%$"! ljihggffedccba`^][YXVTRPNLJHFDB@><:86531/.,+)(&%#"!b`_^]]\\[ZYXWVTSQPNLKIGECA?=;986421/-,*)'&$#" YWVUTSSRRQPONMLKIHGECB@><:975320.-+*('%$"! PNMLKJJIIHHGFFEDCBA?><;986431/.,+)(&%#"! GEDCBAA@@?>=<;:98764310/-,*)'&$#"  ?=<;:9988776543321/.-,*)(&%$"!  754321100/.-,+*)('&%$#"  0.-,++**))('&%$#"!  )('&%$$##"!  #"!                                !&, 4   yqiaXPHA92,&! |tle]UME>70*$ ¿}vog`XPIB;4.(" ӿ}wpibZSLE>71+%  ӷ|vpic\UNG@:4.(# Ӯztohb\UOIB<60*%  Ԥ{vqlfa[UOIC=72,'" Ԛ~zvrmid^YTNIC=83-($ Ԑ{xtqmid`[VRMGB=83.)%  Ն}zwtqnjgc_[WSNJE@<72.)%! {xvspmjgda]ZVROKGB>:61-)%! pnkhfc`]ZWTQMJFC?;730,($! fca^\YVSQNKHEB>;841-*&#  \YWURPMJHEC@=:741.+(%" RPMKIFDB?=:8530-+(%#  IGDB@><:7531.,*'%"  @><:86420.,*(&$"  86420/-+)'&$"   0/-+)(&%#!   )(&%#"   #"               ! &*  %+28@GOW_gow #)/5BFJNRUY\^acefhii !$(,037;?CFIMPRUWY[\^^__  #'*-148;>ADGILNPQSTUU "%(+.1479?ABBCC  "%')+.01356789:: !#%')+,-/01223  !#$&'()**++  !"##$$%%          !"$ '  )-2 9|ung`YRKD=71+&!  !&,3:BJzsmf`YRLE?93-(#  #)/6>E}wqke^XRKE?94.)$   !&,3:Aytnic]WQKE?:4/*%!  #)/6=zupkf`[UOJD?94/*&!   &,29}yuqlgb]XRMHC=83/*&"  #(/5~{wspkgc^YTOJEA<72.)%!   %+2~}|zxvspmjfb^YUPLGC>:51-)%!  #(.ssqpnlifc`\XUPLHD@;73/+'$    %+ihgedb_\YVSOLHD@<851-)&"  "(_^][ZXUSPMJGC@<952.+'$!   %UTSRPNLJGDB?;852/+(%"  "KKJIGECA?<:741.+(%#   BBA@?=;97520-+(%#    ::9875420.,)'%"    2210/.,+)'%#!  ++*)('&$#!   %$$#"!                          " & ) -38:::;<==>?R[enxǿNV`ir|üIR[dmwEMV_hr|ĽAIQZdmw=EMV_hq{ž9@HQZclvº5FOWajs}!'-3;BJS\enx$*07>FNW`ir|!&,3:BJR[dmw#)/6=EMV_hqz!&,29AIQZblu~#)/5FMV^fox "'-3:AHPX`iqz $)/5EMT\dlt|¼ "'-39@GNV]emt{ׄ $)/5;BIPW^emt{¾  %*06CGLPUY]aeilpsvy|Ñ}yup #'+/37;@DHLPTX[_beilortwy|~~{wtpkg "&)-158<@DGKORUY\_bdgjloqsuwyz{||}||{zxvtqmjfb^ !$'+.259ADFILNQSVXZ\^`bcefggfecb_]ZWTPL  #&(+.1369;>@CEHJLNQSTVXY[\\]]\[ZXVTQNKHD  #%(*-/1468;=?ACEGIKMNPQRSSRQPNMJHEB?<  "$&(+-/13579;=?@BDEFHHIJJIHGFDB@=;85  "$&(*,.013578:;=>?@@AA@?=<:8631.  "$%')*,./1235677899875421/-*(  !#$%'(*+,-./00110/.-+*(&$"  !"#$%&'())**)('&%$"!  !"##$#"!!                             $(1xne\SKC;4-'"   }sjaXOG?81+%    yof]TLD<5.(#  ~ukbYPH@92+&  zpg^ULD=5/)# ᜒvlcZQIA92,&! ᡘ{qh_VME=6/)# vmcZQIA92,&  ડ{rh_VME=6/)# ௦vmcZQIA92+%  ೪{qh^ULD<5.(" ߶ulbYPG?81*$ ypf]SKB;3-&! ߽}sj`WNE=6/(# vmcZQH@81*$ ºyof\SJB:3,&  ļ|rh^ULD<4-'! Ž}sj`WNE=6/(" žukaXOF>7/)# žvlbYPG?70*$ ĽvlbYPG?80*$ üukbYPG?80*$ }tjaXOG?70*$ ޾{ri_VNF>6/)# ޺xof]TLD<5.(" ޵~ulc[RJB:3-'! ްzqi`WOG@82+%  ު}umd\TLD=6/)$ ޤxph`XPHA:3-'" ޝzrjbZSKD=60*%  ߕzsld]UNG@93-(" ߍzsle^WPIB;5/*%  ߅yrle^WPJC=71,&" |vpjd^WQJD>82-(# snhb\VPJD>83.)$  ke`ZTOIC>83.)%  b]XRMHB=83.)%! YTOJEA<72-)%! PLHC>:51-($! HD@<73/+'#  @=951-*&" 952.+($!  2/,)%" !+)&#  !&#! "  # $ % & ' ) *+-.01358:             ! "# &(-      }P>(rviz-1.12.4/image_src/splash_shot.png000066400000000000000000002102321300447110700175540ustar00rootroot00000000000000PNG  IHDRPDD@sRGB pHYs  tIMEr^ IDATxm]Ys/cN8B3R\JP٬ʴ.JJ R9 hv@Hlh%dZؤE&'v'3=ܻ.;{9/z97}ґ#G !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ˍGu2tG[;ݦK,r6E*0@O=??oJH Yb]M+p"4M ~/\OVIB ./dں9Wq`+;b?jd d}%@vtlu) " @Fz @hLC@FGGNSNp JGqXT32~:isp4Ƅ/+T2j}NWX @_BoMW rE֜@+X_n; pٱb=~ӏ9ARڻpRvg|h8~Ysѿ˿Y$Suo7 ͷ?wϞs6)MRxCԸm]94<қ ̄/ExH wΟ?[n}?lh3;|(~KcnJ:5ޛMY׻Ϭ  _Hwg~#Mn+#nkl -/Q07Rk&_ #O۷o_;.%_VlσM[Ȃ߮mˬ#\^bDŽ/* @|<'a L[%| wIqx/ ?###BGDʾMȈsLD1Y|!%ݻw;@H/Q_4jȗ6+>uIe 8ywع&@4_z\XwO+{| eyJVܺ-wCSK\a}:G>_h\J0}kX|>N*rDŽ/֊!_x2}|m~h -`C2n &I2HVG|[ǐ/0LO|4q6h:94S@Q 422 G>2 P/OWf*b!_8 `5/拇bsCc_:@M[9`_ 7lu`|[: @h)2krfZDN|̐/6|4ߴ4 ymTZPm#@&):簜|V| +4G< f4S6Hr@lϷI| _ _qc5 趉Ӌ4| 4fGd۵fk!@Fi!_[ Ƶ >_ i ?khHSFfKmu09lLL!;Kph4_{v| 4Ƙjrƻr^_|3­X366k`LZ/5 `7# B=R c鵬!@nsHBnEmiU{N| O4_<k򣵨@ 4kxxAP 9Lǯhn|mMx"hgÇ9}ie_ґ#G:qDǿfܑ~/ ڬ7M^Ԯ2 #LIF9_CڛGgf|^ ;_2jy͔ɔ xtC6-鿵z]+ ܐ|g"YpGGGW{K,[;f!S>H, 1 /RZ|ݷmYE  U~|;,e _"+/gȗ ,|oxxxddddd$7hȷ~|_ cg_:%_C"9d @̾V:9/eڷ4G|(HאoRu6 >|- 21Ҩo ͑`s #_Hh[Y | ɭ\>L|a| >Cd9gBBv`E###'NpZ N|%L.[S:@U{okll)~Ǐ[. 0#Zs?K;?qu3z _ ͗u1[(98h,5 @ p{yl:)bOoē*'@]G`?X$_W_W!:#cs$Bǵ@ |(,U7( #G8 y1WːoM}7G[y9: LP_ʜ/ ρ! b5xRm@ǩe6ZG :S% Cܖ!ߨs#T0j@K и4hL[K$@Su*x$+A(&&Ym@Okfe422/r||#mSr(Xx/m`e 98{k| 6Y %W- =_(aǡ#r4䫹C۞V5@_H!HR@ 9![q-uÿE4Fh`ȗܝͼ} Hr!#ѭ k mȆiN/I|sh'j]]go[nBÿm ++򐯭Ç|Ed|71Nh3tbW h]˼j&|( -f|4O(>Ѽjg'm)y,| }n!/m2%/wkS~6|\K`@h!t?`^LQ:g-L@f3 @ @em{l|=/P4V:@\uõ@Ah Pnඌq/k9G/UT!_@B 5VPM98@N Z:6[ d e Gcܺ-<\%P,M:./)/y7<\|Xcy|FFFxRh mmY`+\5 1Rh3C@@vm][1 @6 [o qou0"E^# _Q /[m1 &&&\2k||A$`m+qX!hÇ s1żdh@%{iϗy|2|>@'߅)]H @ v|h^"k)H}!_Hsj/ Ph98,pTmx/B!hFGGZaqqMu>o+?z2,&|B9q1%;Xx/ H #'Bh "hYnF=]d|dxxx6̭ڬycǎi"/DR!^czV{Sܷmttԃ~'OT{lWbav^xԐo|X^2 üI\|#ߘ fz3 aBБ[;66VV #@`V:PP~[ kAy9@@$&|vat|ݺ%ָ:uL@nC]3 RfSܺm1 </(xoZP |ݺygak}f$ɓ';kΓ}{(  d;(yS466VX4|C.<巃u2 )|(kkipB$ۿ8C_>1(E* 8xoyk-Vm)d6X IDAT^H k)K.^M+js(_Xp{;ysHK!o<_R%N@_hB}͂"ߺm]mwmxojoA_(^2{رtS9dDU=;v̙EvH{_HG{[kC1|?.MƷp/. )P{Ҙnݶ߮U~݂}7[^hU+.!nc]Z:Ƹ]>CNZmXup"|)6lhRo; +!_Za?yS X| ~@иB:30R5PmL^Xۏ؏OO?Py'@ R{yB [lU~Th̪VO>d$/k/2>>><<[صb9yNŐmPnÔ`x/czzzӦMIȾ@ a8qqH]ڻ|oG:P9,n2X~$_ȓO>y$B m4ƨo^d!f<3K oF⠙ߌC0@ ÒTf&l{WmKsޒjyZ0g5KN9@^txrwzz:e7~XC琯IZ$犯~NZ|`8bƔJj_mٲrD 28lMjv{g[{sV%k;==}'xk_ڋ/a|ȢkKe9\]fnd߶m}s}l=t$y饗<@$/\>;;om`}I#g7#78{R_t-۷o?p@$]RA|ȫ5*ln1-{m[Mm@7Zɓ'YgΜvg?ٹ$IPT;{l _,_W-[LNNz\|HmFZ7aN[אo{ѳG7ٳgK?$IKR\NڝӪ]]]D*?#Tտ뿮ZŃ>xZe޳gρܜG e}m뼙fMw׭ۂ1̘e0KfK nuuuUJR*ʳsJRJJtww OL45{С^x}o$6mڰaC->S;w͖-[ܹsΝKdϞ=o`@ Phm [Fj]1ovTzS;]Jgvvv~~~~~>IrW\yn~lm3CCC-y8t>Ͽ+۷o|֭[7mڴu;ŋI$;[nqF$JZ-=՞[m|yϝyuСC_}}}vڱc'''^ZݶmCyW wV.o=ЩSE.eE۶ܾ}S/}{700UPV|eZTzKI|ߵN=xλ7]>PR9sڟcإK~[/ěoqƏ~|"9q@*/_Ndll,/ιڟ8א/Kg^d~虹93?w]]]IԂo$V*|R&I$s޹JdعqභJӧW,O<믿^]1޼yŸC7=&;oM3 a/g%gϞH6Wǿ4?7;ue}\޻w+RVK$I5IRTjR.|JRzcj[>J7oNLL,ooNNN۷/I$IW_}u :~矯~_۸q>ٙ巺 XA*wZoW ch3sˁlgO:33?===33sw~[˾O> ~w~# pwllSmw }رc+>@9Onb7GfK7nqWT$_'?W^t6$yWv]Z--դ4_홞s޼93YȾRi``T*u]{eIIl߾6[ٻw//ݻWBVmކ߿?"wٷC+/p}{Y{wNqƍ$I~鳟;S?r{ٷoΝ;]v}{I ޼qdkoM\kjfˊsc{˥$I~k׮:uСC+֭[w~뭷$ٱcǗ$I^~_~;d\|pڳwll{i_rgg x/Y_|\?=77-AT޼y;;_>99ww۷o߷o_enɝ}go{}WDj4O7M,ON#޽+_U{||ICaE],/ٷCpɅM)/d%J偾S?/zb_Wݶm˗r$۶m{_~[ڵ\ܵi\u.^۵gT*ծ'wvmNS=>v{Ԁ\| {wl.0A[9 jGcZϜ9lWtK?[o;}dpo[͛7/y{ϝ;OO[l)IuC7o~;ޘkn{~ߚuu~'@d ކ;oM~kٗ2{ŧkl}^{ꦾֽ/|z|TI']竕z0_ I5jfnuX<۩}H㒁N+]Ϯm{r-5 }h```ƍצ.V{&Vwӳx I^{ʕ+*6l8ʾMW/Wv;ժ@$/Uxo*&R]`ڗ<9i]3bV7n}o}[gg+}WWWOO϶mۮ^Z**קv޽-$IΝ;wŝ;w^x{5s>s?$ɓ_ ?Ivzx_(;oMڻ kٷnsNT[y7uͅ__rs%???~ӟ^v5??_*$?{ jUVk`Ϟ={|+RT??3$O?$I244t֭m۶^ $bZq7ΛDO nK\ zw&رcrr^xcW_җtʕYwuRsܹs|ӶE<8~{F,Y|vl8΅G@B`*\d%ͻ K^؂7ebI$UlBbMb;ȗ,[u9~xp͌4Ist|?F==3~|}D"N'&&&''d!$>},w۶mvꪫ _8<>Pk䨽y)Z8DY/XLB@V{Auuu~@`R~-!$G?bfǎou]7>>Dx҄,˩T:yMf[7UU3,+VJ&T%>}mll{no/@ID^T{-.u]5uٳo߾ Wݻk׮]ny<-7,YܹsSSSmmmSSS###oXKK[ZZBе^kc=V__Nwzi0E9  EQܰa(>33344bŊ  iZ{{{___:6 dN8AYrZC @3Op8 o[i'n0044ګ:qOgYAd2===_%@<SZwVr+RmVo8Cetpq{k LLLLLL:thdduddg?7,IR__oz0%K,{wZ mxW/_L8nժUT&s(¬#Iƍzzzʇ>ˤcPJ/V{!^RzTI?~z0֯_*=rR9X4M|>5a=Cssٟ:t@[$drXwu[@u |=Pxo7✊;[f!Bt]ߺu?~UE!gxȑ/}KW^y%=GӴcǎB6l@<ե:˲'3glذ!'!Չx̙Ǐކپ};xG}7(R¸뮻6mD.nU>ѡ1|+?N[/YW"3|az5zWovլyn˖-###l6N80`Ȧikl2Bi0ߵknݺb#<[o_ C;_5/V}|09TKw77K?C__?UVBzzz/_L&yemf˖-0L[[ƖKR"2^ z M2Zۺm*sɰV&Eo\Zjff_ɓ{~_BP(tUWeYjq=5B$]lf2@M ^90uoiMzYn=(MFe.9sKVPhʕ$:u?y}% EQx?} :Kmll$455-]z< _S*J5BXrr(S*uNijCߒy}s%|CMN8|e˖-SSSWW$I'YM$(~a0U~nݺe˖h4JgΝ(@-/VRZK[.T/wKh]sG:8Y%z(sD'̨ϥ@iߐ5kۿ~w}ݿ/STWW}BȽk zUV-]R{vd1jo-GTշb݅]X.&{oYEZNTLW{oU( _ڵkW%d2HR~;w#HGG};;;u]7 # m۶]z_><4_0gڽU׺;_b\ p\Q ~ڵk$]wuϟ7/|hn#|{ߓe{]bŲe,E[mV#$DɷT8.{oSkoa`urvnᆻ㸲~J2|饗Or??s-[|ӟ>uMuPS 9>_kM n_<ohȵSQг"I˲p8o߾}[l~}{}jjjkk5kȲrp@M7(F]m.GU%%z'%1[v[vf＀ʯ'|L9rdffLcccuuu9x P KJ%3fkZ[wCܾ_]wUlRH*PkGӴ ׯ?s}gj/!3 }po|/t |ɢm|E_|Դo݆< [d1+B%?sW_}5UU՜ ذaO?Mfsz 8r[/ k!*r[-@ v݄]vuwwo߾kx['&&-[H$r҄~O?[o}_GExCUꭤV@%y V@;NPlwCh>oo}b<ONN;;/w܉U g_ \A(eNڵk}M GoiSo-a;00 BCCC9 n_ʟ699y뭷׿^fͲe%I?<@xF*b͸KnV]h۳g?^jO+nA"5o9$7 477Ox 2a,QʻᄏwN(7e_lezp˷>dn:BΞ=;88X[/iaTUݱcڵk=zPB:;;ߏ>|[nʕ+~2 x Y`|%z|s'2nٺ y Ԛ| %˺T}\' NZw޽˲iR{A8cfMMMX,1 S{h?9;xݻϟ?}OSO=}npp=@Gmfyg/oذ9/͗ pzk@էaUJ{UW k[l?aӦM8N^xafffƍ `K%Di0; -[ 4-Lii|XuUU%Ijkk[jѣG00 O?}_$) xᶶx|t  NS)>Ob:p;p@d*<!P3-R^  8tr;kNV~;6np4M!dɒƗ_~k)0(,ɲ,˲]ve sf>_`p8aFY?]zWk8rȑ#GnwݦiZb+A)&>"R7Jܹ3;@0/nU4aÆÇr q[e*djjOmsǍ={uMw߾}6lBӃb|UUy^QEQ|>M-^%Ps.01MSe]ge[ 8zW_-~((|ސׯ_>k'ɁѱKr /$k_z$ $ 5|k7$o6m8.Lf2$4-wvvرc/.M!~{74|5Vvn0 'kL0ʌ)N*$8p 544=ztݺu !}+e˖H$b{^y啡PzI5M3 R;wJ @%`UUE9zYo (˖-i)Gl 4СǏ˲f4ͺH$w7ҫFlVeEQ xoƇz _,@xYpע`nW~[(j71PVəCb^$w sZZZDQd2---TTek}v֭,=yMu~ro8*ReY@y^ !㸦&4u]-]tffٳbD"!I@_(I=t]40cǎ:042xͲ,;v8{,iʲ|UW@ `+4MkllDgp>|>"[<P~|]i.nw[y<*v:Kt[߶NQiC4]ʕW^o>~Ld/9SO}+_Auj 2҃>2rgyuijj"P6ɘyH$KC~x+Ȼz:VerrѣǎFC{ׯ_/IPOOƍ_{JӴl6 ZZZ~ɓ'iq]]]OF8 ^B/T3u<ߜF]/6@Ux(]t )CCC]}/WZoYT__/}֊zXT4Zz93 C4kYK`EQ.f,,W\q,K Cs$y睓'O^p~:nyƍtl* 477Sl6Hд ܹ-d zԦwW[{WK-'}kp{)K[z !uuu>oxxQ44BnP|T/='( 0 \ m`Y<\/!DE#V%˲hT'OAy/b{{W\nݺ5<___oheEQ_+ pA`j[wT;kFU7R_C ϸK}\ )}}}4ׯ__rll:!,]WW( TJU`0^헿?ABM|E%{_9c~0\)>ٳ0Hz]]]{=}t8͗]vƍeY;_H$jG>gyMX w`Yذa۷ts颷/qaƒÅ6|ɬ Ǫ9Ŵ0:XիgffIE 6m"5\#Ȉ,T -IBg>h4iUr5p,A4agZ9S 67d2<Ϸ_veDža+S8a,>яB8Xy.j<>Z#uV_jGv3Z3bX_`] ҃3$!{-f _u]WU8I|D`0?yddᒧ@ 0<Pn.wY}^dVRTR->8swȕ=.]gϞ@ 055q\$[iZ2TEӴx<>JK{$Y?BXG1PJX Qa0 yeYͶ_~y<O$-pu&VY B] ."+rȻ ýso}5Ncc#!$LXWWdɒs=s+V8x`*2Lj=Ν?h j+5 ĦiRP(`٬<+ @Row.Tho(?.>]:8m,^psކަEQBgΜiii9s(ЇzǏG"l6K. 紐4Mj(woy 2 Xyj1'N.,\ _je=5F, Q]/)Z{}RfgNPq+!444^Wg}kɒ%Y;8qϭ. ,!&!z$cccuuu Z/.{JҥsDLWX}P|7k.BHww7|o eu]3 㶿gŊccc[YjU:.''&!T*TeY>m4×j^"D[[[$)02L6]X`t d [e$b@|g*GXPS&_g:T,@mxm{brre5Mdf qd,p裏w4OPjy^u)SI%DQbMLLHT I"ߙ-, _}DY,D?,PgMx O9n_ǔ$xP-x  \ v}D~''᫯V鉉 8[wi/|&}i˲,J$a%t!Za*CZˏdPN/2Έ|k[].ʂۜ?^Ⱦ){/8CCC+Ae0ZZZfff&&&f70M>.?CCCWnjjZz5k àgvwwGp8,t" s_-2 #˲4AŲnfXKyPN/yLKGhoK-jжƷn.U_o4 ݸ $ AR7}>暆l6k+hӱ+|]Vq SB_4'4+\3*_zw҇[;-"Ǔɤ`꺾}vEQC=bffJ ôB!`9*r&I&˗/^xС@ ]d^ ] ØnkkP?>88~WB1 c)/;d`~+ FTŀ ͼ|K b @5XjoF Ѓ,,[lxxBP:u}͚.|nEQy䑖:YUUE1766 W^y}Dz (|>QAPU0'OjFy~xxꫯ4%7x#JTڻq[av'9èNWKOt`!0VBuQ"FfI  <+̙3ht͚5Gd2!kٰ֬aC,˿˙T*;;w:vGGG뛚%6G-2QgŊA[[[<Eg Bp8G.qq9꼖k!_ETNQ"n%q[EoNA?{ͤ$[ 844%ٳgMdY,iZWWי3gdY$W;7777B Ø!$ ꖍD"aLLLdL&(i566߿zjۚi˲ Qaѣbt:9D^džaȲzl i@51<8ZNB]$[fB@q({m>aBP[[رcǖ/_ >.[{GO}xńn@ 0>>B(th4JMSSSa'NH$K,imm8n,lVQUU0,˲,{r1iD"bŊoYKjL&6X~^RJGF#_+`oߎ<3Y,pϝV-*JW*-9>_W:_!fQJ +*Ƶ7gFWBZʎd {I?a?볲,̜?~ҥKimm]rΝ;'cΥX߯,\sMSS===P8 R͗lmmED"'N~} -W,#|>UUpa . BKއϛd*Εؠ:q\ki{0wq*9 ܷشiSww3'5K[J+fEPB b6P\KAcP{+<`tt <+4f~DӴȲ뺕qܭن cwP(βl57i tWt۹9I4SBӴM蘪(~ p|AA&g&JiuuK[X͎A095O+a VsKl@M{VqhtժUi.[T}}닕!x"5ʲl,˓cXr׿ַ⊿'Ϟ=~#5_VT8E9Y dY299995=66}&!T /(v5_WN|42@ý@MȻP]vUiҽf}ꫯ~׻ޕsprrr >ZkAPӟК5k,Ymʲ2&X{ɲ̲(4O8.1 C Bpt|[[yIت /(e `9y.늢uMb8\u/|I 'u Fgvtt?ltŬ@z à k׮촞=r;;;9zf% !D\i]0 EQi1M0 s## C?CCC_0Ta,`-{`ʴKW9i|)P} .m8ud&5r[m___BCCÛo<4M2 #I=X7EU[[Z^0,!drrJ|0А?йߚK.RZ:8;wIW [vJR PڊTamQ$UUgSO?(ʽޫX2*M4UUMdкǢQUU3L'(,cdKsuOR ^ ]_w?& /c j;՗Gf|5Myqܬ~V\{&JBd_4UUd2%5MWuEUEOQI 2LVY5MS1<<\t0 _X.fZ@ hߪ؉۲|5ւsPUV巩7ޠ;ѴRnVF3!Nq0 8r֭[/g3L×aAt]5kxq(x3 cllFC,:s!cccl _/(< uuӦM]pEE*& 8SEE.z~ "91B-[Vۈm5;@;pq##WI|>>:(O,ONNál&+i sCU@uӌpc](\|*5_|UgJU=&ߒP yPx1Wr%_իW;vlڵLx 8w\ƽ{^y啂 R3 LLr®DU`hjj/CǙ_M |:WH0zbիk2/[ t&X`B6O:mƒ%KhU{),ʯiŠ \bt@Lt~E1 JgO<Į]!Զ)p5㴁lcn9TeYg)֎md^UUS0dR)BՋO嚦ɲL} !x'a,>+0t:0p"5::>v_@i[ 1cJ ɷ,,2H`کx {++,RR?82,>4_絿0t$QUUu'??( M &XvuX|^*)qT4L&#(XrԩǏ/-E/$@4Vz[O_KtpNE1`ob\ 8Cͼ9yN`֭[+WҘTU-[<33c=D"+3jttrۏSyA`u fR)UU3 qa~1 _ o}"{Ev /|/Mww7zUhNAT]Ki0zb`-+ٵzުi뺮<ϲ=oeYMf 8%IRU5__˲(^j"9mL:(d$ɩ^=p3gl"0_ b#=4_1`-9N0\)<h7N%IKUg*""tyEQXoYaY211as.|Ԓ>w_fQ!$$I @z{ l/4K2"Rwp0M krP#&ߊ^( {ՄH*\l~k^4ɲ*B:&ȑ#?y+o ( _O n/V;r]C S.E^;ׯR)0rΤ s2  3 0:|ߐrرkiEQ _-0vح}s0H~?/`P$BL&{С_ȑ#r -^2".*,&ߒSB;^$<^P{YO8xݐ(ńJ$2PyϹ˗B=jߢm."o(*o&l1$)ĢQIR0?rU{ݲ;0jP@-ӄ,J%1`8VA[42%<`Y6ZLpg4:(Tٺ4s…eF\RRےX4 xXg9c Fj3-Lb&"6\.ujsw^|[ڱcGz{/H0 e y>҃4!g6QEɉ;44ddxYR÷\}7D##GǻcUWWK\c jkTLC2 ء2xv&2U`  &J<{]u>z281k(J*e8RS]d2455j*Bi 6_4}Cm399zcٕ? a@`!FN>VZ&`LPxA oHRm(%bD"'''H$$I (Z/8 E^a-˲/ҵ^k ;C6ͿKCW xvA ]vÛ7oƍ*0JN?`]X?"o9k۠Qoj{{{KK,˄d2j*e}> v`Y< b###$//LqFmX,577 )B.Fќ644?~qU~)i lzo.L&ߵm6+ 44\ _Yf Wo) ]BqQ/RXj2UC=idFDC+!ܲeaT|@4MʲLidz|TJUզN*.]T*E__tjF 3334~pV;111::tRI@ hnn>|&!qZosر# r 4M@v-heϞ={yWmۦEzJ9ΝPjhhk e Х)ʻX 7uԬ7t* &.!2j{o tQ%3}?$Ip8ͶdUU5Mknn$IR###,˚6 0 s%իWbL&(ʉ's)~5h&q,Z^j.Mt]߽{ݻ 0y Gc*+hT -(8\JCF$IdFCCCCC!9R)I,}`RifmbbBEz8/r\ ׭[766iZ8VejjʮRML&0=2>>b&o8)o?wc0PL̈́ J[Ux oݔbf&u0 {/Ϊ(^DQbT>V5@ K/544Fd$I4VbiZWsbjoWWDB @ա2rR;opWADҵ1x|98uo{Vz0P.MӔeO䵉,K3}5J<pB,S%dX,6333ץ|>, PnqhtTXSZ5:ȻT|;(;BJi^0΋/}ynժ3EUUgH0 uV_,|#hC\K_fMSSӱcǢԔ+`Ϳ0sZ/(LwTiP *dHuXtPiC~U<_W!>c7olwd22 cɵ<'g҄ Kaz!szHt: o^(9O~/Xv>9c QT |`-gBLWUzECd2ϵ tZuo|]]dk6Mź[WWNw}7vtt?~7M8f2bPZ `&_.*\[0'%B^x'x±eo yd@ LԱѨL*655 `i|掎)UUY=~hCu9D{H$~zbK[Q/q!v0pu#s-|؞0 >Sxx zH`?DSY|]G%3Ⱦ.{[URyk <AejSi`0䉉&` {B;Ss{'=jYit'ߚjw[]$ޛ6mB50bVM,P` -%Ul"ua^m5 ?6$e ÐeR__x<0ai*!DUX,Fhw B]]]hNZ0/ {uq[Q%T^@_*Y *ʗ(oe˖,k&js 8]zMAG֯w㾿/[nrM7=vw12@,a 'Jip /PTrcL&߅-JؗZ5$o"oUd_/5C2^*AK g`0N麞fMӜUD"sgs*PY/̊k4-)@3`NƘ@| ,XF,T}`pnfc|օB,d!: "ݑ=!DuUU98nzzzrrr'OMM577iIFGGW\i^/Rd2􁪪s]#h<?#bF\P-nru"? 8r[k bt"+y ns ΍/HB$sZ;'t:F 0 #b8?9Y /M|UU5M{Y$ivz(˲,=(X)nAU>|1jh&_"SſbUXT w5F'E2 333s;0 M4M5allL$괝9'(T%Ka*dT*E?|AO+9~Aww(G^rժP`MvE^L=/,`d$}Q1HPbl6ddYBgNNN.'f_{io!iZa9|ewMҙS|<kA:^e0tt/A$/Sd_o=Pi-d2 .h?AQYg|n& B4@&Y~A wlڴ@Vu|Ai5L޳&<v_}=3 ]&Y¢bP(,˺KDIJ$IuL&q\9:WVo>SSSp?_2bMsp# ΃nޘra)[Xp˰&_P}^]%]6m% d_%pX9.(+IEQd21ko* sGSDQ@k^'d"U5MLKZEYiLno~9(ǀ @4KH IDAT};A -*Q`65 ak#5;333 tZ@ cUUudo~7st4e2<<<׵_zre9&3^/iV8C- <L${9z…%<@PQL+J2TRA (RT*tR)45Mu=<ҒK#f}ќ#Lf``ɍ+:;;+fhxǢa.fJS[6|(h |W[LpڈI\%|oo/=lk]vBRԧ!D4eaoa(^pahh(HD"xj,9 i_s$N]֊KU%GGOY#-ÖXH@5qDyc gɷ{ 1z5!Zed_4r/ +Y'N\84GGG;q!DӴY}SSSt.2 399YGۭs5R`w5Oi4P(@} o*PvDUqp\R4燆z{{KvTUenf133S'L&c|]B=Ho_@ P>q "}owJJ$ /Y(UW_9RrrK(J}}},ad2 r^(r(KV/Eot1iֵy+y/iVQZG;R[N2}kkV-;#apf!q=xw.\XB~m4MFpl6kծ/71W@|tYo(ɷ[yLo}kY-L:~s333x8,KUl6頪*Íed2iϼ|38,"}@}kLH$vJ"{e <_GO q_?:K2iIMuqg]wݵk.BHww*/n|2%;^\N:qTg[RkobdcHqrx'ˏaB238 9I2C8ɜ8CI8g86c۲-YdY-޻?.^}G=wnÆ hԩSt6ahn' !(ζ_{ܿt~~Rc,Ѩ6 z˩[ m '_17c6(nYv+_HUJP{"3EAkrtknݰa(x\N]iUTKdE Xa|X,SKޟKٙ9Sk 祋/Դ[6KH-C үp`ŢGDEV2alVr@A 2\qKltrr.//JAE1qG"*UڍNOOuͳBI̗&1enA[UrX`Gt+RJtwGyU@|R$_^m0<ȈF[Iᆲd $񏏍iA\JV"5â 2T&+s;GhdE6.C%qn3b=-i\>(-M3L/_^QAZJÍa}{U% 1=, R8v=ß'!.kbb¸=+-PhEB^ A"AieW{9sQf|! UVJ55ʠE2oanOᦦ鶶7xC^ !#㋋UUUWGaY&F"6>>p88s8uuu_WvM_w:@]w^Cdt.IaV/j2$hOƒSN8(kA?oSv. oD"aylo]JTnjuԴ\qM"Z.]tX(RiUV=7p!dddb?4 9`d@(|![ ŇCc1 k\QTz䫔w X,Wo}1s8̌X,c!n& ,&mF 7`2~_p%n3 đD"Jؘbnjj{֮]KziZ竆,[a % ˢ! GtX9ث.N:: I-K/ Rggg0\^^B@aZҗ* ϲ,el2::XLOOs'1VJ*+rﴌCmmmKK_YFz7mb}o%g/D| p3/Q3E{䫔ho2[~VYPyUUCCC0bIxizo0L-@ ^ټ`6~dffFK EnhhXjg?DpyNd1xw@BZU\ {bH`!e=J@Z@_@^m4<<x_XXhnnziEbb8yzo<߽{˗욙q:TQiQؘjinn뮻NO3YAmZ > S+X^$*g?oBUz^vVB khhpb1VSScق띚՚:??_]]-%OLLTUU=S]kll4Yx,466rマPg'ND"0Lh ŕ#_% dqN ^([)- W#Eҽ=SXyKIaVZr5LH$m}p8v^eAhiiZo ߿zjC} "&IB_Z455u]vںu+!dzb|S|^]ZwqqE 5, >A,`x+)<瞟<vFL@e$_9g.S555t6y8d2nUX,B!(fed2l6Q.gnbHTwjjJzyaXʫ._\\L;.UR|+GN'ݒn|h%hfV%EQ`0[W~,X!]\Mel*Q_e˖x( DV]eYgCw}>Eq``eYevr\S2/,y>miD"k#retq[)-8'u{ ! ͈[j)OQcF eRirrFQA|>_mmdhnƲ,ex|݄9KKv\ l*𥢐W*+L -Zo7IkҧT HW~BԼ~ýT~)j 5:%i!(w$>.c "xqwYmm-q~_I* 677Ӥ]a&&&܄$$`E1 ǽ--_; hH?-9L@e Y --{goH/UyJA-UWW799i2m6(Pd2 {%#Njr0L7Auuu\r2/S{Mo6M@~+`4A_j Ax 2::rV?JFPf U2,kL1nCo1bYbj$t뮻v۷F'''C֭[__źjժƦjB@ hpZ-RF'&&2|O<9>>^__OLskkk,W^A~E~ 7HKk@)W8l[9X[H&^(%eA~ N } +,([q8RY^Qh08N7pñcn&a\.»gg`sX,r-}b,]`0 :*d޺|ƍW0+'ԡPBm&K) iq+ [Un"岺0Br$j]ky$Jv!_WPϡl0AC*]W\ZG]]tCC}$suttna&&&nYBb}~߰a0gq8Nrr8X充ښ5,..;w !$MO ]rE`0(_A/EMīt(&J(PO#z]Rj (Ң<2/g)FMݵkFcQe\,^$B+|y:֭r 7 80Nt^reY ^osssSSS}}=J{ک)i4z6MEhSSr !h,-/8X8d2jj<  3ÄgggiD"a6X&"݀08;\lsUPS˴GE gA4KCF+B+T]11@T(Pڶn(qD0dw:^{r{{{]]f!MjWVZ577377 ^oSSsuuZ&s0. _蟞9vm Dbhhc~~6 7`|)y #˻HBNJr,(?)FFL=pO-'yA7s+ *A@N/^===,nذ!>|n ts3L&S0FovSSSmmm$n?]Xxq`xxnsf3Ο?. ܹRO/^D"`tJ&aC}P!FN/Le\KTx0 p |SRa] bX[ !.kݺuDbwqǩShUX,!ԧ!>^b|Gᑑ,I$>6ߕ(H={U,4E\&T_J ׆ XǪ٘7ta͚5V^ BW޴iS{{aqq_tu#uuuSSSSSSt68˔ IDATǴÊ*'O'  4m+ET reVT=8pgѿ W3cKG'`.U!ǡJ:ľp LkmmF"!np8Ng"pKKK[^8#|_N}r^ʩU}Jvv,cM9 =n P}pyO0WyF)Ok$z<{Bow]<-!|sqw%{KXVfk&eZ)6v"###{z^+t5\C_7Xp_t('GЇ~/ l@w=RT.4 7 /,i櫫T ;8fwXk?[@ p 7pGYZZ:~x{{{gg'!a@ p8evl${eZXPE RWσN2>L+Mygrzkoog۷oO$Ǎ/,,u}cc 8NoxT~._)_m s5t}i'=,?RMyu=|,덛| w$ߴ)<+˲sss^nk֬ijjx+x[~I*"q7mo?L*u㴌@0/" h-!drr=S+Q1Ir~Z#)#8=vؿۿ%]3\ƒN CTr _L! DT0ZfR"#WW4þ@$bU=` z6&\reyyv: |I-˲WWYO~֦T}Ֆ 䀹Pއ!&lA* !U$m{ٳGpa<y@ (Z şJƾn: 2_0 Tϕ*R*.=M" ^;EQܿOӂOxRH|7H fΫoNAo dR"0Eo&I|6c(xsQG;Lyjq*Zc/YJi0(o15"b0t\x}O?tIZ{e/+W bTㅮNUT7btu#M[p]Ge(0_WvS6Ղ^j%*RiQA`d2o}kÆ ͭ _9>ycDzIKOd 7)7L:c= iya NV Շa6NO߼ ? p6jƻ|/ "c"MMMDV@h4Jl__xᅪk~h| pĉϟ߿r+l\{D,6| K8dy/rqT SF VY`-. T-7ț$0_L 8S}Es߾}---&NNN677_(Vtzup MMMZ;BZZZ:wŋW_61ɐ Mv`ʡ|1+66jr/oZe:H5Ё:IM;L *|3JbJ7&… Qԃ~޲lMMM^{;lPSSt:M&ӟ:WM6%eC=P);%ƣC3LEԸ~f)eZ^*<"#`eXBX4/앰`fم@ DA*8HCC|7B~^8zҒ/,:o{9#J(dK-n^WѯF4HѠAAK-Є@E 0_L24Ef%8|o|j\ HD˵eӖ{XeY6=bP-_߹sg.Dz/Es@4P?D%ʗt_3@XBMfi##`CZK(Iby_Yd7onoo8naaaiirb<ϋWE'*"%w}oUb+qArӖ֬^#%j܌ϟ_~}*EQ"x7_=*gJװH oQԏ0\,!+ц]Q&Sd5\,` 66\%666~Cz7v{GGƍo^]]-gKc},Jy>r[ZZFL&kZ׮]}-lٲEPՏDQ\XXX\\lkk9pS<311@M0o mFd0(1]3MU4%d^}RƠ]9D0_L4XƔS ưnݺ5k$VKN>}̙QBPZkZv{]]ڵk7o޼}C7(V\MͷC"X^^~衇  J5h`B_zj)#-IgǕ|㼺 `5#3I[0&bs'1|k_.wnnɓgϞ~?X,&?d2Y,r6l@|3Lm5k$(ի-T"$xO775e"*?ٳӡP(qa4^B( !,^|9-=v؍7HbYV:a+E^Zbii~(ԧi%Ъ(L V J34}W/e |Kz%*jl%"b"{w󝦦z镤d^ufv˗/G".K^H ~QGF#W6nx^wu$is*^Wپ/^|9200@1k<O566p)pwi9, ޑH$я~T .LOO?SF\#P`\f4:qGhܕl vU=3߼˞={}b\C+%9{1n疟4k:oK_u86WI#rÑH$H@{c,]Ri1H$맧kjj9rw}c{嗍%(ʻLVQBo ^rԷ$<55n)Z*[ T$SϨWWI J+rvl"$zR&rYBg>H$xVkڃ剷DJʊyĉ^x7|Ba8;; "}wō#rh0loo[#ѣGw]__7F7' OXE &yy8V)˟ o1堌G Ȣ(,'VRR j  k*yaPI;ܱcGGG &)mi9-M}2H$ǟ?񏓓h4_{qכazLr.d,|,˶>(]H$ayL4He \&gX$+/pW8.,$\ WAX[&mF` HeZھ6obnlNlTppȑ^zȑ#sss<|l6IWԂ&LcccCCCH[ZZMkjjNu%:E9&xia@vsi[ 7 |8aϸW'IJIYS,laM:T> oyw\׿5 ,jjjL&1S/'O|x㍹9r8ҧ`n,+.vH|B{{Wj9~%O>Fs!Dn)MBީ D&''N>|@E!\]]],#f,',aAגa_oIho$-Λdcb{ga#JYKJc*xUVZi?,/(x<(B!0L,7)U^ o --Z^pl߾ᙙ\j;BNucfS`#\T0|BMMMcccmmm8F ׯH%D C J5  [NBIbCJ>^\!O{ho&v%C@%_EpP AH2hV=^d hf uuuZ3 d*K55e].j, ˲L&fI%ghOLLꫯڕ+W"H&{E'xqR.Bcc/yR#G+IK^!=J$ό###G|^v֛ov ͛7iWթ)7. BGW᫩cH@NWǩA{ !?5y#^y@+٪||lÀSr s<PA}Up: 35E7ؒ%IbW\9}tuuuWWN=m۶<899I+ʙo d2itd<|n 7oD" Hnb}}}sssIߕH$*9n=ET@Jr$BXzpөD{dz ;qio&=7oX[$_ g7e\Zx`:4וfR+v+ҧ!~nntM C+E$G˂Xl~~~bb^{WGGGt=&IcA|>_mm-ZXJa;o;vyaag###޵kH0ܼysUUUuujԩS7@GDDHH)*frܡ\吂x;J{a & |/—J].a\yhtJI|qY/$bKI$^g $ѳiCЛoꫯ G IDATRm!z1@sw۷o[/]4666>>cǎ/}KN㴂D"ԧ>D~P0H)CIAfoU P/UooUKk\}K*A%7>}ڸW O|_XtAY,~W9I$m&1P8[zU SSS3337|3!&/H$XNu ~^Lޟ,$+E_yw뚚>=f gff;mmmh4:33WW]]]mmmΝ_F²4tN _"LlЌRɒ|%i@{@|6IZHJEeS XH^WڦN+Jl%+,`SJBRBܜlEQy ixOLLxG˦ɿr0Z89sW?D_y啮7>(DD"6miiܹslyySE0*B mk8 )vǀ^ ̗$P I JxMѬ4$ (0~tttPfv.DVAzjts3Vk*-X,ŪyJ馦&,i3 !LkkkggK/tҥM6ڵV=rHWWWccmp8RMM =թSh5HȯfX/ߞR@\0/HJS[LXlCi$:LMU"wyH$bXbbFL6$4LeRW bVS傛Nb6困%}u<7ʹzo&+;|p"غu-rӧO[N}ъ A׻m۶Fzo'b$z ોE8#*ʰ7;8 ? $Ă$_%𕌤WPV U ({֭gfff!}ۨR)W¦$eϷ"=UUUE!VRmmmr+H,jLMMΝz===>l[[[WW~z뭷ғ^x!r-^{mE݄oM68[8;%w+F7$3&$*+oM%dܥ -ok\BL_p8xazeW핔Z6<_" O%EW~0IXGywlleYz/^Ui`BH(r8*Eqbb.//\.BȻᄏqFe̙׻\?t'|r˖-HD;]vI9|q@=C3fvXa:+7Bޕ  o_@޴I,TvbPk͚5v}~~-t[[GsLMHn. $ I;% 3 b8D"׭['\< DQa, 0@Z,nb(B!C9qdr:px``ݺu]]]׭['_tѳgVUU}. %,ar}43,T~䀘\ИBz{{R*}O  ꊈ!ooo|6~I(;%9ﺖ=XJL%\Ǐ;kךL&e-鬪i/!dvvݦ&Q=qD"-V+0o ongggGFFn 6y)y> l6AB0N3 _;Њ$w7PU}aPٛJY<{W$ H^n$_%M*B\_CgA"!fJJݰj %~ #xLxwS?c Zwyyt,.]zZZ7鴉D"a\8Y,#mt=333vfѽ^yڦs~ǎRH$ |Man>>44X__x\ڤH$"[)7oGKӊ֮]Kp磄qNS)NR_8#!G^L7 A: (TʕJ[r.37'UVjߔ&h^!c+KgJ`z`vvAs.//UWWWUUQޚv6A M+9bSSS۶m K([habDV>RI$?񏧦hp8o߾YVZuwL&D*@ګOgD*Za6*q17r {HHGoٳgӧ |5߽'5P[TR#G=eE/?fR"#l].jhhx饗$ftmmm/˲ ä-hP%!U&]CӧtYm6f \ ЭDQeX,4/xsPFG}:#*Zr_*,ƿ*5+#MtttA]R sz{{K|M PI؂fr_o5Ljnn&x> fYʄKN{m=z>N0_Il6L+Vi.ebXsssCCCjZqsa&;{S^YXXomm311A+9Hp2ti)tMuu%OYI,aZ a0*6J:(786« уNd 0.%0vPV*%}/65j*cɤx`0iyk׾{mO}ƞ99 \K:. *Qur _2Fl )h9+uE-BNMy,4 /?CB#< VEYa¸_pM7B?{N w%JRruӹ9W]]mْ6jK¾a$ʣ姕ފD"/_!䴗eY<~e4Z`PnD,OD/Tfd*U1R6[RRJeٹAF?kWx6$_exoъ*ދd^Hcemf>H:T4ƴux`pÆ 555[ɕ&)?~x$yᇷmF <cǎa 7[,M6%cco۵j&÷B~ミlFpQJq%,W1+f{]!0\Woa ECCCn[j677777?ӑHyNEWՃ&cʟKVBq|8Uz{MݟM3K+ gS6nM־믿>Oeڋr___<DQ"-e.D"Ax[O>U^/-KOxF pDzb,&Lv]:s(|@2& Tr)H A/V1UI8CJhLfϞ=LUoooww7!RUM(5&̦_>mA)-L&u7rӒN,{'9s:Ղ <0\0 /6t:DQL$f_oVl6aU[/0ĄA}= @ )Y`r(LE  |ͥFK8I[A2ɭ(웩 / SIÇ !=ЊG<NIqR b üK333 -[C!󈮕ИRfO*d3lT7IJ߼/,G䫸 f##5_nBH1ط,ܳbc2 07ߤ A;v|ʹB<yeY8ӾİT7 /In#hvlllii  M:wO_!zz> QO*$\<UZ!WY|e!N3R}Nd}p=&'b%/ CȲju\&v4Vh4J,Uf]nדH$80??ϲ,06ܹ3Z,azPC45THcZ/PXYć$mio/J6 ! Wq|Ӆ8-R}30_"a_ YRpPEmDl t! LioR(F"eM&Sa6l$ξ[ 8Κ5k0 s̙7+v ؉nW/gR'G &)տbJ|U^7k|Sf('Ӕ ap]ˡ:x ˲Ӥڝ;wBz=\*ǙL9(|EQ ÓN NׯYv*” C૗3aPvkͱUfTVc)pe6kfGi\EIͮ(E1f\ CPwtttiiI. B8B#gF|1UrC؂!Vj*k5'x8-%c&f /*@T}^kVnY]0 Ӛ5k,Ll IDAT -Fhj~K"6 C04 |K0.{Bx!Pٵ2  "j|EYWwwCTIʏ|6*p1~WT"1M8H =yd^s^\o૗b " l2.%2 [tJK~f$_WG̷0;c %(_>|²l{{{SS|,L}}}E[`Kh૯Ű3T ̩dhKr(y-2aK>W=sݤ'J=+&LXg=D@Ϫ*| !3Hܹp|#yW#+Ur!E`K:Q  Syd(E0 shҒ*|sDI?Nz%h 9AJȑ#k,ˊv qXLB0U1 s뭷[aN!R epsSSl|_Qd6UH{SR2_/W(sBӧO/..BDQdYb_z(%ܹS/.mWœ ]ظ58))U24Wq/9A2'ȯ"7 BN%`g1Ae:Dd5(-ӋaNTQD^ X7i t(Г05o17-]q8V-.i|UP&C; ?)A(\k xaQЊ?CL[6|aQ-J)[0AI#**E@Qe5Xˆ|uEo4B/0Iœ|/El$ЍTWԋ0ilQXUBE`9 w, _ V) ֽEJ'74 !ReW7/3;(_E|5S_L!e TZ.ǯPPe)R[% /u*-,7PB]\3<}^M@a[ڋ-a !RqP%:h;!#ۻ֒c [!r < =(hB0d BmMhj6~UUV:Dʕ ;/< eN?ߛYЗ*d3߆it)lHP©tu*zC&*PT:xwg>xM8 t<]R:N؅0Y==49Zzk6eVظFNP]~EЅ  /m7-񮆥|6r3z? 0_!KEBWW*ځ1uEmr!eDox"e_??gU&sd^~q+'i+jFWȡ+6ɢ8&cs7+䶬k[> h9eY^;*Fr%EMW@JTԡZE@Z9y|w2_p9SfAsń|H{-ѢWOZ dEbwfoA]tӐ 2_pi)s7ùh訮I L]bJBJiaX^E\c Ai\7=|B 񷗩 Kk;QY~uO]‰'|of .NҽBUQp.tW_ݪi#q钽 ԵbW{JF6!"w5I߯Ң_|3~Jл u LH]*Ͼ:.J}?~ϝ_oߟ9oVnd ()]0'.רW'|um3+K|=BwD_su{&)p5B]MBoՅ &+$Eo<zHo7qh9P^:Ҙ)XpfAXЉdߞ(}mLvz,n0 gDLmdA iƢ4!p[$Y01[L`+z;|Gzmqj|oi i Ac}!ݿH4s3ćtW؆v.Gĺ2i +| ȩ7&j{C|ᄿaÐ0UV4*?׆h(pEkCywGf's/QEwp!oU,=&+IudMP ͩr]3ۗ*ǓyܥЪdg_2bzK*S\׵ pr7EIn.VDk`G H `S&YkTW_';,e\#r8i囆DkP cՍ91_ڛ.Cu8|8('  L >~8.W6z-TՁ94hxeľ:wFǾRIbnWԱkB O;T_^ڀ&ƒ$< .H[J+*y@wh^+} n玎WŮ,?swW貎CyyMvQWg۝"m ıkKطB̷{vܶ>ogiz=dT+P{ߝ(Ŗٸi91bc[79!o͏6O{s?l%hO0xquecD;+$Dx](xB0! {X_pD;]4EcطxnH?@wz&yt|P~J@/s |K]D4dUnn`?~s FP>זW΋ _zOp7565S`Xfľ?-z[>Zøi7>Gȋ{º6ڙ,}u of967 D ~}>߹_Z_\+4Z}ґ?c yQtL ")0N@ʥmt;o4,0#Dk&=N BgR6h弸70Z uaꃟcD_cј߻_(}r,>xSajmwSE $`\5TL$|G2(nny9!D'˜81+h|U!d8髐~z%#q?76pBCa&xC"dH_sUtDz}ҙec.]"dC!e"e?B~Z1:w&z{{ p-Fvş_cFgMF 5D9n'BjDb3lh|1oDoK~_8Ƹsqϻ"F}YcICV_ 1;ųEקּy?~Qs,"E%")U5~" <= |WDmҧ=e)7HSYijʢA!Yo7#EY,> yH94R]f")ܦD[*H&9=G>'ݐ7i[%\qOJ E.=ќMFJjT [_ZSwn!NM4PnoJ:FfFK"<}"ǻ1SQ2lp0TWУfzbpԈlgo?ޛBw /o4W?j\ւA'tBH_kẻg[ߣ~niCH 'H$FP#h -5U |BOء-?F7k㌡ H$RA"C |=Kj[ 2e0?IǏysHFH,H9/8$C؝];1^tXmss'b|zLC.&9B f D=e#o֙oW$`4 tI-e?-G{5ښ UH~؅$_3iԤCFMyQH-~$Y--kO[AYi,\J{E|#pDd i8D$ dv<{6FB zxX%0o%0_BÞEuҡ׍_XaCfv5QeF\59׺:^Y -Yۋc5Lt13udd G4P 4M˅8##[\j:-W`Hi#O'T kMN^`-D|OO':x4ةtkkھہ8'ߙaԔ_GI>6 AK}DT#jAX'B̄(%т=X&Q(3tOE^8$XzDkΫK ѽE>X@8 E|MؠR*5(BVA ;h`>;TJ뻩JFRX?T *'RlGkuģ}R)](RRܯT%b;/O%NiTJLz,@*gz" ᘪ T5*P 8* */QNB*pX< 8PjG}OM T?9\7!5L UK@9c9?)JO W|M'@Z*P[>VWQ[? GZe,AkkUK@AVWa /q8N|@x $Ԫ\ Ba A$؈8䑫MVB0:7re/Dknyo/ K5\oD@BB+EW] k&9/b +VEpE[B(vIEQ)+,qNbX20X|i0t#(֞ܗ\'RCN{6ɠ\#<[cS ڥ#^6 >D9h'1hlӢ4W łT3`׈ QlՆрVC)-LV5zI轲֢K@ l(+Z!/-j} тv6귯+s_t^0[@k,.~QWO[nA8Nns:dT{+ Ewf;4$psgʛuKt E|b yuQLLo8t 9 ] ;T #-?l)w;k&(U9/=/˓.\2dԌN{8. GE' P//ɑ.TV#5מfཨ6:k!`p;|0쪓E~iPBG*4LN@Qmə WF #R‚ 0Y?!@û׈ ]aɡaa< gK@} Ya aW: g4̂V\;0223Py7esvF`\tE.fB@ƕ?Lg!cp㑍ȹ1JƂ tr8D_=&c_8! W3d\ |-fR]4 <9J.0 a 3NԗQ2x P2/°;9E PAk%"3=%p8: 3[v} u\抮 4\tݎ>%fɓLGXFɽyǺo;cc SƿJ f (aGČLR'fbn |-cC bH f`#Q)1CWĀq\Gİ3 '\ܔ)100gX: ԔwAE=ʋPϜ a"¿U'&[6z=G%DW $,07_ /-:=Z$Sy)9;dsj=[$ zfM i`5UIĆ~Ǜe"zAB@PI{8\,B$1KrKUi| =@5 N0jX뺾wn^_|i@j *`԰S5Jz#k8}tr:cHfPT|F= Vjg:Ȕ ߪ=_Q4AW!*f` ݚ+v杰k' ]Q}鄰1NXª:½IDATI@pQh߂GJ"lI:ͦa1Uv\{kq3*)l6^z i)0m?#հ;aam3F/UJ 6 >2\4@WvmT`hJﴍU2Un(@{!աx60W &+Wwy@ B|WN@pm¬pZ#{ gVH,od^\vUe!%Zϯ@ASjJ$7RW2g y)Ѳы_1tpQ/hWq )HcYP徤@|gY`MJ1\eӟXVVyO@vr:kOVO2"ȑv- v@Z |++ = }v}9893. ƹ806e͛BRk_M9893.9tj"!AB!5\>7(lPs."3G9rDk,Eu.tCzl:Eko`X3]``O Kٮw99ۗssF9($/ܦtj_ (t/:|vH0ΑxMm"b#we_N AtJH7$twFf:Қ8ta~"/!A{]H#;M J0#3A ya_Bܝ:;61ؙ; ->!/X-r^1Jp8\. -]|&!M?c@@Vv:d%P…&F(5 i:qV+vѬL[#|Vf{Ḱ7dD7 &n@|  zhVF6 <`0c}@eeBbXvdnF daİ5@)/P14nd}ǂm;C"W c<ͧ4o. b(k&l'4 >4Cڎ*`:yw/_"@hB=@< O ,7PSp dVy y=Rj(3 {ll|G|͂V(7XH<Ԙ#W%;Ƙ| [@@37X\AT@::L_ @@&y{~HKVGḂ }+M4t:?o?r0|sDo}7Z dՌ Q| TL@2y1 L*b/(jw;O߆. rп"v~; N߷Y087$}EY5XZTjP%G2x`tD%a/^D^ Kɸzk/1\ƕQ]P+*F4\78U"5>U:UEYg嬠 %t `u׷:@ mx.T+/`woPa^xOEU`Tk|tB0׶B.^*#{@!m:"ZNVBB0H!(̾@--02=(>CBPG&9@!9k0j^́ EkB-`@-Ĵ>סq΋#`4{nѬOkE@!LUrXOQ-0,Xr,ގY J,_[=O3zY?}i@I\&D>I?(W:sE &rQ)JP)@e[Z)" fO7C9_`NLKaP)N|oWf>(V-bT  @#)HG% {|wER̖T|`\կ3LX|Ӹ%0XDhWk9 hstӅ /+&Äz$wI7a: 4mkoBP/O=ӱ@[('| @OZ||kl+#xirT nY5-3քO ^G QKZAJ;#€|1 59PA6IQT$6WI쁩:?ņxP+"ۋH hC}RYEPDLObTrx}xr:*#bIhwh{DXDr^@'ByfvU\$҇rIENDB`rviz-1.12.4/images/000077500000000000000000000000001300447110700140335ustar00rootroot00000000000000rviz-1.12.4/images/splash.png000066400000000000000000001467161300447110700160520ustar00rootroot00000000000000PNG  IHDRHb OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-bKGD pHYs  tIME$#QW IDATxypTי>I-v A a1a;3v&IU&TTf&3&S?RdT86L-c؄!V[^nwsEBTw;}λ=j֭9000000F @000000a``````#F @000000a`````#F @0000000a`````#F @000000a`````#F @000000a`````#F @0000000a`````#F @000000a`````-``rf]&A6E&8 8T*#t:D"T*T*ECeTTT@d p֭[\.Jg"  AEpF!%F. @>" $^8A-]ag,8<`ttW^ũS/^D$A&A8F^yj֭9vItR|;߁,8\(BVCV`0 jm,zzzo`<ϳ<\$aժU8X;?,j54*++rJ(q0 lf7ȭxɟl&23 dY?\<7T*p7cGyŧ}ȏr9z_Q5(4v>fy$4^1LdX|D~K>1ipT*V YJ]׮]Cww7$8C(Boo/}yy0j5T*xG64t]$!FVWBdtd;Ʉ)b4vZ χsܹszNhZh4)~#J Hӊ>Rp8 >$Ixh>eg``RH%L6E<Gkk+$v;֭[t:˗T ---0s~ߦM~Ǽv88C$x(Jzppj NSJy~ Xr%x w}l%}c=Fϟɓ'vz!"%}DZqFd2c17\wsѣEEE8vȺʯb``@v؁'|djzގdɒ)}3׮]Z韡P/^,tPs-I>>| mmm-TZ[[ڊx#oPCw;>$= s}+bhmm>1|clٳgq9DQ\zdT Qb!\~e`P5 UXp?8/Bed2#LD2<`0ЗI <\.74n~!y?׮]`^F)KdV.:JP_* 0hooO8&RQ__~O<*++188HJ%r$H03BvŠp;"NC// "dYVKp#(>OI\[[~ŋ&шNiE1iv.!FALLL  "H@ՖH5kj'rX Fv}n\06o\L& ŋj]< 6JW˖-+x/"$BEebxx%<#HRSBBK,##yZ[*V^O|PT8w$IVۚFp:-4 ~ޖ ,{711Ou$IB"eײ,t:MDhfшB׳|ÝK dgm6jEq$2JDZ]VVM6a͚5ǥKJlRTFZ0Lz!\PHQԄ.LLL@V,Jd23̔FKY\T@__&''!2$IB:F<G2D"@"L&!IFb2hiis022Qd3 Bm٬(.dB^,!HnRQWWbxh@1 j9Z[[KW1[0Mx6l֭[F}8u]{[P|2 %IJL&i\"@4lb)8`  c1|7֋% (BXY4:|^/|>S!L%j* F wuOr9@hDS7200|uuuq$ grSJN'OmظqJ[l6 J6$IEןdN7|= \G<G$A<.ed`r[{ hY{=TWWCa$9IfC"&bI'N$k&d=z@L+_7@ H)6Ђ mT\Zmْ>O{Ft`d*x===vˣރT?y$b`<~JM"LNN4Bx<99F˅QӡsQ'Ӊ-[ə3ņ^~eh4iZp3r iٳg? @J&v܋Dʕ7-[yW9r,sNYHRhmmEcc"O)͂8|t:W_}F׮]㹩Ԉ @$)x*zzznNF  "cFoWw!^/~ߧo~555oX{Ts=شiSABs2R X֢vGE(L/_^s#yi Bf&c #^CI#1ࣣ%_[[>ORI %. @`VBJz޽hIYa0ѡZ,U \?QPD"twwܹsrh4tTlQz{7>,\W @B!;$LR oDn!yȲ ]M6)8tn%Ν+=hll\T\.G[+#jb رctflj'pa{8{,]`0Y!"$I«`0x;y 7L1Lqfs Ôy,+|A$2rܼ͠yA}}}i@OǏVi;_dҥy~2Xݻ?OEnذa 9p8 ^wj/tҟB:M&\ߏz Nsw]t >,? (20'br PL7;M&IB!aHl6Krh #>11ZQ>ك'NW^f="%nMMM3]6O~t:(,b͞' [}kM\(|CFf$F Egg'?hTQ 'IϪD+8Μ9STl%Iǃ>ݎP(tbPΝVT!D!2n#cykkkRp8 Yaِfݍp8L?FЁjf`R AEv?~җ6DѢ: 9B Bl(p(PTj8y$nZr_]_ TT pƍ Ru:EW_}hb 9?4j5-_d Rjkkzj$Ittt`ŊHRhkki0zzzӃ~\r.jtPլLr={7n,ڰ{n|jkkԤXy7=87ހ^_+D<|AeR) Jb Ȳ@xhllݻ<|>.\+Wŋ,0& ,˳& ep)c4qeWW466"Ln&L k֬ʕ+188(qqb\./_~ÒR x!d*N$(ϳ,(.\Nj&rArATUUѮ+V Nc뮻fގZh4C9t:t:կ~njF @$$I*y777?qND<ۿF)*Q<;)5TtwwJͼۍe˖|h4?hkk+>`/zjׯWdPWWW9Z$J*IP[[l6 ݎVR)Z +WD:ƚ5kp8npP,ïkbŔ+oB~ш~x'he@hEyf7͗J+`dd 3;v; C;s Ο??g +d(xp8PSSh4Ix^B!$Ec$ oN:Ç޶qXV0@8LLL  ᥗ^3q8DD,JP  e8qO>$ b|r%sN< ɤ@c{<TWWk{V>d}饗d=OL&FwJ<JU43|`㮻–-[}dիzj=.]ɓ'q_;ZT Eh#okkk|~5J/p}w0 ,lT*Ee5l6[Qy#G`xx' jB"K7{&)qu~X,;RHBx˕!]73t$<{!V) 'jKΝ;mAwWZUn;Sy12_vP}066&,2) UL/QSSDQ4MQ/Hf7BH_lPDѲB֯_{キætɆ bԂ ^uTfU^1)H)BCtYe>:OUTSTe^_T2ЬRh}!5N _v<|0`G%R%}`R6ҥKJ_dJLR,ZtXvmQA9%۷b5NQUUfRK^yEʻ34a:nCCCZٶP)qf#\0ABzIjppq\E8C: 9`ӧK_&-s"tl6 QJ*G"tww+!Օzl_2/cB?drϼF 'br T,UMJs ]o*|5t2e:4 .]mgg IDATgْLvэ Jc 166xTFB~aɒ% Q8uZ[[K:֚5kfF-[8|Vx=tL&|W2_BWWjjj`p8`Za6q fO||hjjB6E"U ]f>_zEW10d%9&\;~a(" sϜ9۷'g?gyRXR}~zzEDb|>=z.LpqX,0Ll(SdSb ^>n@e|{T%(QfEӃ=|n}9v|x{ 011nAݍ۷tݻwhrX28Pb^{ $-p,7!BhQdׯGss"&B={07 OB@2 8v ^? /r@D)-!W* faZ\B!2} ^wy( >ڂ)IiիN _sp98$'HL&a0B&AMMMQH9?p򪷷/ ɘċ&Pʱ/^z2X9B 'jjde /dttMMM3lޓ'Ob۶m%{?)t:"BTt*{Wlߞϡhj!"'$L&%[ZZ=#޽{a4199YRy~T*}0Y߯hlq[PR:t: &^u( ʹyH^MMM3v̙3xK:Vgg'~_ J4I[D8VdA(膇vZ >KHRPTSe`Z?l6{K֬Y}Vydޑ/w+^*bI\/P2K&.[@$>l&bH- xP__?kcNDZe˖-[;v7ޠq72u]BJ6"Ez;z}#,f;oY 2CeD"tvvBͫq}ܪhΝx@ Lhkkj"UZw}F}W*B8F<!* F# fcǎZ1U/vS՘ŋK>޽{!IM,q-6yo uhV!”g3۽r@n$֭[WTU!ǹs>,Ey]hPF@<$(RHO"Mjժ(2}!ׅax^|>B!:\̙30>>>gIF'J>֖-[6#_$2ba2h4E?`08 N s΢> >X a-(xիWD T*.%<A8"L&uVpWRg6 x#drJC~q6q|2z{{ynjθNQq%cҥ%kΝя~Z=yk4r9TUUAVc͚5{?2Ls?^z%\.,]J~Zq Η022R9r9qt:t:yfץu)rB4A o$Ν#xj#AVZ{qAL' ^\.NVKe<(f]ZF @ww7֮][}yT:=pZV "BP(MFWVVRth4^Sqʚ466bҥ4z199]vͻq{}\ hZ)jų(PZp8+W?2V- aϐp8L3PՔLz=m#F2HNh4H$h4Jɩ; <' J>#G plD!1{27|Ih7oF8:G)@młT*V YjzjseY.hӑ_èf Ӈ:MNNB$455)"bL&l6:Տg,,},d2g?Y<&8};w-*й{';ߏT*RqS$2 R/_Ʉ~AiE$,0ߨC9=f999I~TjFw I I7! RL!ǡoJ\4 zZ:6cKDXH#pn{h4@IN8pDQn˖-Sr!% kX,E{09#ҝl}>$Iy4]X҂W71"+#K"R#1˖-ömېdׇ`0n$b@<睐Ȯa!e̓!F twwS"C "hX 122X,Fuߓ2[~Ȭ\.TVVȅѣ%ٳ?<88V\IUZEA\|$ȅ188)^\.Lbǎذaz};wd2hZ+*Hq WԆPi U d5MXѶ ,7ހ p:hYk tĨ/1h4 FC89{@:=L&N' 9{)$arr r9hZ8z$II& c /(tlj1֭ݻ100^M6).!ʢEORofkBܹ͗AfNl&\Ɂj'cT2zƗ¬E gَ14/ 6l؀#ѣ0 '`2H9f,&411d2p8LI94$ Gr9\.D"Inj#/FAmm-L&$n4׹' cʕ3 B8z(y䑒ƍ~tvvB#)2 qi455!OY{78CB *$rgGvUTG!ٳgꫯ6p!Hf"Jn7'>jXn8 Ԁ +c[d !m*D"tww˸rʢ>hdZ~\rv @LvqbeY屵hnnF"ULn79UzK&۷faŊ$ C8qGוzi>IEv$D~p8SN/>dhy~{T :O<40b׎mXqRDq!2"PCczc5\\c buAPkxrAy6eR.+ҝbV6U $att<Ӟ2._$G1<<>cx4 l6ӃbL)/^H$ػw6n/'‘($].l&ύ8@(0djs]17-;_vN&~~-'O-$/>!I"rp5B)Pd让|3ajz>ZMt/8 ={$(nTEz-Z@6+T ˗/b||`Xlog Y,n*HNHTpd2)^wªU "&&&hb Cbոx7]D0Tƒ*̕9dCpҥjt,ڍL D@xNÅ  0>###R_'`***PUUj*H$Aj6ba5 .]K.T1C @0iY- _s^J3U*D"z*ϱlTTM7JŦBvS'r*~>H$[bƍ7柏Z.'? ***:jH$S' 때ZZ`Ŋ6D"YDb5vч s;._nzڣAHeppcccS4s Ð(h4|$II`01J"ӓ. Ns֒^[ @uu5Ly#L&St{|>R)?ݣ$ ###Ϥ\pznx TCC۷xgHr5 (N-y˗/_,]k֬鬊xNBuu5j5amPLi 4 h!D$LÞޱd0>>N yS\.g̾ %>v] WUUahhhNd2%)ROJɳ%IxcMM -ϐk(iA"sB$IO?MG$ϗ}yr9b1D"tBR$?6_.2jVMߌIFG}`. ۷oɓ' SF `JRShۭ&=AJp19s;wĺuPWW73(~rJZJz?L&Mf|,&tP30HT*ZTQQJ8~alݺ +}(m={,>n8(<դjl@`JURrK!!’uuuKl6cFWF @7#yNzuC(hmQe\t ׿֛~NE|[B$ jkkQ]]M;` ;WPpGnbb  a||^K.5Wt>o^י$I) ߱cGQx?WY7fZoZt:iƍ&]/dbbb'%2ηz `lvU=x;wb{N$T꺚ퟍ^db!;ݎ<`0P(D;yG<qFGG豑ܖCoo/dYFuu5eYqM|ɇ~6K_{9 Do}[d2ô>:dYٳO>$8C}}=6mFM3,&oDXl$A "F "8nA'j4s!$HF! ,T5REZ)Vl7 |߇ ^!a\rd1###hmm̙3%!j5@v{Q+ߏA IDAT'N(5-?$b0PYYIǴvx۶mæM 6XqaIJeֆuaŊ&_q1ĉ'011NG&$!~KӨ`)k4~J4A@2=:= PR2/'}qql6BeL&9sfQu !1ⲑ.drcHU2$^/m& r9D"TUU禮z!WUUA)/G<;p8| d73lHR>߿t"B]] 9CZ&zdjw'%x555pE&sNjo`0H''`= 2|K*d-'R*K<^Z+W*z&XTCRG, ! 맾vZElݻ{nHw}FWWFGGa4)̶g|##8jkkNj fLd tvvS000@^EJ&{^G"crs=#GuuuXd dY66Fw>oJ!h+Q[[KNNN5D r_2z{{qe:uJBcc#hyuatC$ϓ - HR$Jp\tx<x`tmcҩrD{0Eh^I`0H$BC1$G<#%#x3Ly0 >z![yXPʲeˊ~:v®]Fw{g@ NwÙ bl6crr*Ȳ ^Kmlll޽{a4qijĽEgg'j5qDK&DZ{nlݺtxt:oIgbHVݬ$C|H61³u!Bs||Nt#<)V+V+zDbId$կꯐH$Xsd2jrJXi:#lI5)`H&|Sl20%Kg4jZtww{t:1>>\.Wŋkpn("J!PɹgnThw O&FӧO ޽B jh#H$BZ[[[B]#mJ( NZ:]]]%J@8.:|K/rw$ߐkZԠ>oJxp1hrGHۋҼZl=V$D^zt`l7bާNi~*B0D6!BB$ErEpm!L bj|HO9Y2F9 rvtː<***`٨8hdQR)E8L }tRxn׾~h40LtH H}3g}n!|=wD0#hߏтB6QQQQ顡!\xFqi: 'd=B!y)/,vFO?4>Kj!pU 61<6 Qju9J<dcrrrJtZ)to,ۥ .,2ށ)9:2odn7jjjhB\1yjyK,p}+p!J]RA@}}=(M"qbdɒ 6gsr9LLL󛭜7$ (B-&466ϋ"011łj:h4fG?"6ɓG} 3-2%i+T*J+}-GNt•(ٙd޽8phQiH> tZ|j< ׋)DO>s [TlR4(i{NÁZr9Z&DB6CCCxꩧt:ҼZLG/8* ui^t:D>&*Pı`(KbgW)s=kx<X,vf:sd>B1uuuA=z;vXW^-J.H0p袡l,,CCC:;;it!RHBy444@EMn2( NTaZ,xJ>Yp8ViCRk_]S1883g L`06l6  AZ\Xe !"P7!> {zl6I{ʇ$qOOpl Hl6ћJJ2z@+ 1e뮻 ~aڵ ]p:j ˱{_0::zC_z N ovl62򕕕m-NJ;;;\Tb(=u,:::N066@ @2!?tVJ ~O>#iЂccEH1cMKn$uITJneb 0 ! ,sr#u{TZz=o{ff裏b֭7ۧϙnz衇p7R`dx^Iu`^/"Jbzb x nGCLѶ$|>_k5 LB|0VUUr9efCsn|(L<1ƲZxgvZqec%Gw7DRi͢#8+m4'ڞ0IH*[Az~r-"޽ w")/~l6@Ohɞ:pP<FYqQ fvXVX,d2Y,!+t:kb oQi^|_E0D$ATD6cQx<t8xkD֮AoLbC+U@ZU\~xiӐdvPL&Ng%Vu48q'OYS===p\x뭷yfV˽6n܈~tלSQLMM1?EQR U` 1bfggYkXZyWq̙S%w`!(`vvw:xt:Зdq36#6&A b1x㍰XعsDloo/nFdYw1G\f 06+0Zyfc&щj]K,f9V__c<^x`DYRǵnC= RP(z^("ɰ/*kV,"U]vQHJeE6fU`>VP`.vR}iUIq![Xir`BΏ@C3\2D*dbZQzh7N<G<B>,@seYNo0,2"+i$APNFFFH$ V^$ydZFzygwaj`sss$;77ǪvɄTE-7xZj/oVV(lS~#N/V p` PCR`nnRAΣB$I6Po ;v LfEݻw3ӫVG"QIBмx Z_ ,+:gp:L|r |M8v.YM &@EgFGkiwn鈅B!&6Df0Iύ;wRr1t:ӧO3dҰ|L.JJJ[v l>AAt}5 iN_w. 'O(=h7`$^x<$E^zO[z}i Id2jJ@$yDQ6עvE0d40<<<ƮCz~ms=+: @ӡ*F#{K0;;31AV{%vECUULLL`׮]طo?Z9CUnw8DUUOe###X,r8tck!Z`ȯT*Fyп'M,ٌ\Ռ'G<~E&5W.1??cǃA9t.Q$r9~Vn3njoZsZS] l6<ذanV&T!?/~'OQ,h?0Iƽ@v.+@ vŪWЋLHd2P(0ѶNTv֕qQ8tN>Zhɰa*HIfNUU0ƍtum(t| W,Cq|/M6[}N$A8P!#9jRNm]܍6(HR| qRņLl ‘䉾^,7 *IW_֭[;E@=w;l63 L'RVߑ'l`L6LlNMMa||7tSڡC`ZA& %]IW'ox\o~?OF6e y tw>P(}L&i&t:Ɲ*)RJHTf_*;WBOOv蘆}6hI`"F,}B[UM[V!(oDj@6mڄ{6|hľ}ۭdh +|x<8v4&COOFFFPTWeqdd49{С /v;J Pڈn]t@Vu~Y>|vӧQT,0L-a[$&j2pY\.EEyI6NCTb0Z1$Igrr7g}\nU:i]6x &''rn1M;褟ߏ@ H$rb2L@`Ch4<*=55x<ޑI'b0v}A[fᥗ^͛100@0jm8??5/~W/I}}}E"@\yLOOcƍÛoݻw#cvvJ%Ibs ,ˌr:XiӦb42P.yf&OA$0"?s9sap8rؠs/Ν~xG.C<o7Y5YG:`$Tmj٘%C,TUtލqi00??]v؋AЗj>gѣG&-e3+8Nt\@jh~~ccc-! ] /"J%p@oo/;+з_~زe Qq;x뭷p);whz=F48c(B!EQ6^5hO>$> "( hT癃+Yb1VYPW>̪*.߾9,ˈD" zXF@j L{RaۤaDBdIhBbnKmhuԯ 6oތoɫ{?("u%g>[0+&'M/~:f>4`U)2 BF͛7f1. %="N !P(d25{^\~ǎd갹֊I\ r9dY(ñ f-IӀ&"J1Cmg3.,,ܹsmrdžf@Ra^6`,o;L#+Np8 ӕWBυ^܉ 8vvLOO@ zI>{g_D\n9cҶfff$IZܽ/Z5H`||fqN:;wbƍq׳޽{qQٳX hg ^[/!5ۑ*!ѥf%ڀAj-9jq:`(0H&x/} ΝcZ=9mKyM8/Gyn QhhɲRbP(oi%IjE&a|˵(;/vp [SF"&3cNJh4rދ[n!Vrm"g2 1UPέ;33Çp?ȃ&''!WeɁy=zPanlj*2Rػw/JBfgg_: IDATJH^,s- `2v144XXX@!EuN배QvF#WAN27|3GֺM" "\"p.,Fc]ZOtd^/ o,HӬ_ ߏ˾  Fb3ggw}$|^+?0/v i$f@ bJ . rdB82 ,KKH@83gδ5[j$. g~.h1??@ >AgiuP;YEazIиnf{ΚrY(YQ.ŘmbOҞF6m& Qa6YP"G0M7݄L&f%!EbSVߊFmuy<nF]&ԻJ p\ m?zv(hJ*w )cD"x'i/Ц,31Dt׿՞|Zt5w`b<<20hn(ay9N&&&y掾{>_v#]Ip׮]'>$ra7|3سgEiL&ytØjgt% DZ,177i 7: ftzz㬒R/RM~`K/a˖-z?pq&qr1AȐ70d2yqO`qq;>33Y5G>1r||SSS6MjnmMLLLF"8çy:;U(rx ӧsN=zOfâ(2".u]{BAь󡯯*)XɮB+@^$Im$O2)y^CCClF@5113U\.p8!P(0CS`00i',_hE0gχ~֢K$ &-y j'km;O$-vq9$aϞ=ڃ~)4&"ɡb`00Yvڃ%e8ptrpT*1GK\j Ee _*B,CPhKyZajH$4 I_gNL|ZAxs@/} hy\7ct:\.#9yhfTj+KґZoV+NնGHy,DG݀MA ErPUX4U<{ =8 :-R~Y> uN*@D "XV[ާR)9sIBhNC$ヒ[;v@(bʻ )a!v(JVY)bddjPmouco&A:Nܛ(.4JTbOr7\=t2$P.Ip77PHLI)h}7O|#% ZI0??ƍa4Q(H$pyX!y,p]4Wl- .&H;27a\f/*Y63@yg0NțHY IzTzpJq8 'l|~ wUTYa9wp0t0`0DEtY*@PUWVv[!"4m;w^ngvVVUz6ԒAVA3} 2ͩ$pG HRLP+R`r Ln@-J;7lffy\F8 7M̴5{k럪t:qyV3>J2dhvW\xUۯ#Y -/9ֲ@;B9ͺzJ Cȱ!ScJ%/$1tr?Owju@( D(t$ X=D!YU'2'q%z=ڪ*2z-Ɔ޻VN T$`a}%f +n~@*BXl;Ȳt:Y&k5U,a6a6Y%( *JFGGV$hPbH&IEo^ [k> $N t2Lp80 (Jl z!giDE4evv"ݘ [kNCmo(* _`g _;UwL`뛜P*P,H 0L4L APjg|wBQ 022@,]kaff`Iu3N#]@/H!L"D"$RJ+v.JH&zظq# (jtk Pp8`2P,Y;y|3֭[FAτ·vp1C=??ů4!UUj&%[ H̀(<#H4 WyQ;`6 333f,6Ę Iǎh@UqDY{?btN_=8[/GNY\qA,~*BeǮ-B099B 6i *W]B7fqJӉT*毤ŕͳ -f5/׃'N`J VvTF/ZVU2 NTUU'ty '(2Sahv2@۽}-|LjbZ-FSTpA@T*JEHdN*lNbCQtPUaIgϞe2ڪAER)닪.,,` 脳R#l=Z@лNwTS(4C{ԌzzzԐHZ)՞\/ _:l6֭[ 6 N\.ZY rV.h4V |l8N2 fffX`Ktʻ@aZ=̠"V%\.`(SF;5L={e#RTdZϖa0T`8@ CU!f FXFAD"q8>\ۭBpWf#|_Oa2Ն\o) "pTjH& Σ0CKPE8ݑ#G0??^ 2l;Shٻw/Z])jJfff`6_'%jHZ)΁YM|>[BI&˝8&bZ7H H",׸":v@jɯ#G6qX$E$N (˘bp`hh"F#F#Jrb6s3b1ZzH{)yZ^$a#{VUBv=//\頮՝$ |O=dpԄz12.==AX,sؿW 0f ,[+q8z(a. 0K/q ŁpuV״qCoTzka*k{ɂtkaŸ&|VJ( Izp3DWQ}5f;)S\hLbȄHv Xf aZ1>>~A!(r_=εx I;oO-gƆ@t\;h{!x<|8B4W2[r0 , xD>hB8<ɄH$^fP*ZjirYwu^ό]O`X{ns=Kd2bz~Vx`f VT*~dkD+2-HV22I2!xϔR0N'ĠVr[)Z٫Z,v?R Xa6B;Y3B\SF A!/P>ڵk̂6˧kXD"`vW>TҒ%$I5SheøZȓh4$[Y[T RQr7BC<AP;hdi!3N٠:d۷oc=֑FVpq|x^j ifdYTʃtI2zJmQ43PU'AQ ǯa\.#+\.#2QtxFQ@<~C׳wffAj $r3330zZH$HRlX,XV8Nege(C\Vv3==]{`Z!20ڮ0۰m60B&a-MbB!&KQt:gΜafT:}ixr֭c}6ewb$ @ VKgoVawunnB>`۶m8Z,pxeB^|{g5k֠+jā%8Gr݂l |Hz㠩 (Gz,Qt3_,˘h/{t)G 4H'|?]@VbX슖HYMddI$IDZ~zw܁j>,wߍ;?p'nzȔk֭;PV@I{W =7nhǏgt:|o֮]ˤJ: ݼo*h NE IĭD"3 5i _:@UP dQ*)m_.`(c߾}jKv^d2 ш;R#Nkٙ(geFt~0v{d2 D. yT*y>xWT$ɅR!.da;nXD&dFNJ~5D. }}}LF-""#2Kbzt_4jjaJw6dbU*̑0T*|0<<WO?z. Xf ~?^^*֍a/(٨T*( (Lo-l۶ BH)t:Vˀut0c,r980y-H¨J~HeJV.2,yllXezyD퍩)jKZ`;ߣ{N~ ?q-hjHUIP`3BFUU|׾5|ǵ^ Aw^'?o~w<>/^`A3-7l6[,^rB^xܹsתҢK$&O>dv@j $G:}#6D"(V`0E: BTCC(epIR"x^۽#I#AYbY^ƍ/ߏz /2L*e===*ݬvUH\ƚ5k2 s=$wq4A (VGob_GjwOrUHs6(2;ڛZ VOFTDK$`X OALe8Nl6pǘ旣ޭꑪ^|_]wI4HQb{=kvȂsO~̰$IB˿K|g6Nϑqᶜ0iH֝x|Y6h)(HRx# Ju\رcx衇lGɉ{ex82"a}<2kE[W"`a`TίD`0P;l\[I)ngYg2DTb@j[޼^/LaWz i!~lJ8Y$O/ ϣ*W/x$''ضm[{a@jw,KtK HAw9ka539|& (abVMT*RITRRnm˃|P i|!t2Esssǎ;c~~6 VI(k,#\{9_~ӟ"Lnl6MJRL&lغu+\.$I/LhG(‘#G`46l>g&@LHp0Aa gz} &S~lu&GsӉD"qAKJL&x^&ɑP(p8|>ijIJ0Lk+7@R@ zlM&,>`0T*]`I4 ֕T*PT%g8|> СCC6m~HLB}f7o֭[ꫯ2<3 DbvSm`ьWLFx^F`nΆgmP 88+J%?1.muA0TS0Ґe]Cv*=(X,^x۶mj 7܀͛7kA0  Դz)k8y$\.DQ\Kߞx^&wL;v_FV@ K?>>L&ÂVLlȆa4`$6~}z((H[P H"8uQŕ "VC0DTb4J$*i.^;yb1Ȳ^F[XX` ծHUUflF\F>g$J@ 1yhJr\wWj^B">?!/c||U6[$JJzO#`lIdW+zf/LϮ&>yU[XMdQk2t4$)\Fϻө>@ ީL^p\yx2SU &8r,W@k[Id+Պ͛7kuVN^+Yn_G&t75KnTL,y+ŌF=N&SP.Ʉ`0P(tv&Iqx^~Ȳ"3Fb&{.c6@7*$Ij5JKZrV(h+IdpM7?#Y)"ӹ{nH VEO* ]xq*DLf ՚]_$JrE= o;TUnvXI=hJI0"#~ _Xrf͚N2S0tBUNǃ9PLPIa`Xci81g<@fHW-i3s{՚\.F tq<xǘ] jsb>oTYkV/#0/߿SSSX,D"޽{yf$%- ^ʂqZE>gk&.%j \hlf+ zQTB|?߆,; i 1԰J=jTdtY8Mw=xh着yR ,&''fdKۋ|tr=xgpImΊ`~~: (T p0 Yjם`D?Jann`ff)ߺ\.Bj(@ sssmZ{{{Y kJ@"199'N`ttiW+ z'(Ph2dB>gQkHݎ9rBΝÖ-[z1;;{Y ҂8!DA V f(`P7pL(JLh&E17[(2Zi+]= Pdja4^W͋jf3sf#FRsP.vI nǼQ|k_hP2 72kPyNSuȚD0&+e޶|ݩzv\ TZofGSZA3|oؼJ]asǢUT0<< ׋1_ySr#2Q\[4W*dTUŹsŽ(1>;;`ƙ3g(شi2{ڪy88N{aO70y&Ji$s ̢b2 2 -#bP(A>q[׃Iwtdr#Nի;(`Z8ީS t:DXW{ZGy#DZ-}=֓e% Մ\PYOjA$YJ,P>rQjlF.C4E\f}JkߕX,000<'hyV#I<G4fH%:AZDDWuSV^bX,w8 r{CK-z^Ԣfl)vc߾}8q^~elݺXɠ#gB\Z)|<zLV<6 k]+S*kޚ0Aq(J>(O瞃$IXyVQX wAQbf#XX(JjF$ϟNfh@koAu[ 4zEֲl,CګGD"M\.\.H$|> U$X`X,ePyF  6lɄ(t:!5L*sx<0͘ٳgqRA*]ñYn YҸv q~~/B \.ydYqi%z+Oy( R]Po &FA˵, #  ʠ(L䳩pbtz.diP " پ}{Ǽ:#cH/я~ nw3Qqe[P. %6p|Vk6[W#"A5$XRJVEȲIJAP64H ŠwK$͡( *W!%Edk2AOvV*Z(1<<̂+$X,9۰Z(E?FGG188Nǀ msр:tĉرc89d@4Cm6n7FL֟z'$goZVrH%߶`~~ r`aD@f,d0N.( ? UPBR|GRCHbR?EkljE2lh+`I"vӉѮӧ/|b竐e=B@u)m`| G8+hZZ(EA ^odϞd+ -K性}Zw&KшRĪ -X,֢>-7 R Xn ^/zzz 2Kiv1'?aE_bDYH,eɷΝL&Z`@6얕ij\g?vwߠP*~?AvF 83M/bF?aw7J]Eulll`i8\&Nx"@D79ۋ '˚f~_ȩgYA3L2Uհ/ab9hZB)ﲙ}W<ˡX,b{{N"6E`0˙4JR6-w1!!7Lq&z7|FElB1| Eq)p?E3.} TUp/"-0X[[ӳc{b۶Ȱ*-ۖ/ٵ5hn~센DtmmMf4޼yNOJP-J%J%uxx# y6776))b{Fc64,+ Є#]<%Igٶp((p|}>C|( Hwş?.Zxo~-" OZ< E N`l+g9 ܇p,- :AgAYR)qBsᐨbqt݁kt5-:!Dj'5yޗLY'۬LH4<&cD[ Ed*<[VL}ל6`}};;;Nc1ulo5a2 $Dʂ(ueeE%rqD >C|/Dc0?Ww.0vV1 IDATGP 06 (Qь2a*'4fG8W0ժ(ZλkLMyP(`2`{{GGGfy $Ӏs5QjwBm%FUU 2LĬU;䀁c`vcBT>Z-g!:&hc>mhqL&#/3 j\>@&Ӄk1t$*.Uqf=d2X,bss?gakk r? l  tTՉ>E8:KiZ1 BivP.E&F\(DRZ[Ky$ ,=,1eт/ׅnrϓLrYX7}'YԪ*!w WVVﲈkFƺnc0a1b/נCeV9Z%;\KV΢a#$j[$ai* #Nk3Np1GA*]*+J";<`=DՒmۘL&hۘL&#c>1h I@U8"wf:Iv/ b )gRVO:KжmF#!NHu.(ܹ\(.IuY>ɁDۻV$9hX*P(:FhsW՘ R_wcd4O>סs>=i 0QM(1T wgidc} l>2=pn!4"s.+~e!Ja8u]4X@Q%x`́0<`^9e EeDUz5>B83@A&=r"A. "RI .\PYℍFCeyߗE)gV# J"=yvH,j[/]r8 <`]^cB yty[~UUnbQH4MGb-h*&A-TJLD8+PC+fL{pn5.&TTD,٬Xd28::e"Pၱ p~#zMj z~%PSr)Y :l{F>G#.ԅH}ޔ8E<NGȒr rHC^Y@T#88gp4:Ae"NDcq( qYYH¹߷aYo 쟡i.|ߌPRl$y0 !IQ9e.6 WU;;;w6Gq;-IKe{B2 TJدR/m{-}^j ]tKyby6R?",{ln6rc7vy`ض q_>MRQ} Sxxl!~U08E;ҿ, 8_д6?P TuHQځJR(p'{H0ϋ 7*NxLlE h4Bvt:1ٔǠT!w(y5I!EMz,JɍFC }]8|gh6-g:kJ} En81BI C<nZPUQ+J`iGtR8IsuM )YR- #jE('-Ng;|M@>R^gyM)"NmZ4FK%#+MvfBQEaQmϘ`LyF*Cu-u}Qw81 &hO~f1>l7#P0;v;6{уHℶm# Jh'OR2=~>U*V z]=R8O!#SU Bb@W_|>˲#  ӷ@U'L*h4=P!w7 vK()=Ћ²l(JA4д6L4[PIS{&~oHq3/֘ יE^ lvC^ cAZQL&hQ%Y<餠(Kk<%}&E:A6D:ZО7I~W(QtN%NJ`,Nx.85xhO1eaLٺGT Ul@B_RIhu:'á[}[[[n':c.Z% 6T5R?M_ldpMGU@XfPNeF"9д4ml@Ӛi8,kxS {^Y%cufHIR)nB6Ll0@Q8U0ɤSQme# M?BN(^,pF#;w:܈4# n4b>PƖ`B^uTU3( 6Z*!1{^UkR@@V5g-F=$T*RtR/4:}Ed2ܙ[a ><vU0"{O(ή|"@A!a0KSq{]]p>=ppA=n C&<΋T0LB>v㱇?`L h [h4-+4gH}i 5LpApE62( yX^^F W8::9=%٭8jڝ^4P $eaaaAOA@VVVȴţٳgx=Z8TG0ez _  ƭ(m;ԕF4MQ;jS}sFK/ò 4-pFm|({ |.ɣP*ęQ 2W:8@h:5T. _dXPTBTPӜszjj+c5 Ѳ,xogO6E@I?][kkkbQBF"j.XyBpc<2: 4E:r`#0ȬV^|t6k㤋2Q9yzsBQrPEL(A6SEE(i~,  ʤM,jJ*\םTj4 s2Yo^,ST`ۡx ,4q* P3\xlc421Y}@@-xGay 68/BQQM,/wvohH;<(XE,d\c>8BQM4G0 5e>DnEd$4rsaaPsU0\aYQ}ƇeաihZƠ( |`iz@K[mfEHm}QZ23ư]c^rYh9#(2:T*E qۇ\WfzePnQfY!IC`Ѓ:PU Lyϳy9"kBX)Nj\ZDWEX,15&FYaa4@PX6vG)ѿ_,λ4eC?MжmaT6D:/ߌ*"|>HU,"t](h6Zv/Mt:hFt9a1\.ömދpmeǂ4yZxIF$c}}1T5}U<]c$ 3 s:q ؔ?e/%Fݜǁ Ȭ^R0ww}?uJKv4M}lۆax%zlV)\u߼`wQ'ӷ]4O, \|nFL](>^L.A@r6u7pC硪*ݮo BBUU  钠Z@^S#`Vd2[fKKK}nW=hy|9\t%&+&EF4ضb(&x@eyPwWSkY,NHQ|Fټ f=+>꺎r,6qwbw_j$$ahHދ(˗^LO8EdtEF=/h(x\,i6.^IPΊWWW\|H|xxxm>$D?% $V+f5u/YP~||> =3Y*P(mǗՐE"CZS'b|>My(eP.*TE.xBϫ$&MfY(ױsb4=]Q*`YLӄt:pG TB|ߏI\?5АkR$0W*( vwwcO+I+"c yE bL\YYB2ZɀLK4Xvg%vNJEKF *O-ˊ0HN󠊦AzB~ !+51. {@>T^ hҏwJDk6s~_o*HɌT* *bܙP.Dш ^v/ ThYXX4,Si<<<σm B#Fnq|< $R)4G%NHoIqB*^כ˜cR$l3 ˲DUB9B5ۚ‚`$qE$RFB@"?[+++0 C ]JB^()iB (/`Up?< @UU߁ bii AXu,kEmާ@BV}ooJ)ZSuBt:tFT6@~(i'Si]3DNև> y^8(X(00LT)ZӞr>\ᅬ (ׯ_cgg 94c [[[jLt]8h1y$Pf{;M0JP( (]uOs"ԍi%e}yjP7cL?ia`͛7OJf+++v0Mi % r{!?dw>|ZcX1PRyQ(ʽ˘IqBhZԼ@DLӄrEJjV*d2!˴kWh-Q#I.Cg6JaaaAԥ0LbjjU?ښמi! ixpf ۶Q( t"81N><|ɽ%qBjh @@$eNGLFl43$hiEh P1b*OhVMNczyh.H $ŋqBEM^t:-IjtNmFR`Z~)H KȃՋmR=ȭjUt^/4L2SK,<{@i*+"N %`d}t:rS oℲi@l&wvv@.4:\ryles8Gkg4M,// h`2\3Y* Uj$?) \*4ׯ_4*'NX8LYqsdY1t o߾S+9CY\\D&F8>> $IIex_@*τȮZ^7"#-|ȗ$?hqBpLSDMEQ@iBH˪ZBCGӣIHB5ŋo}͛G~3((J뗊f Mq43 ߲S[&Ͽ^ s4bh^ w~_ܤkIDATZl۶0r#W T8"#!jʃɅp][[[}'g~S.\V <,,˂vhZ}M4ͺbrYTzX^'75޽ O꺎؜]Tdip8>wߟJm@!g]R494l&NHBӉQ;U]㜈I h4tέYɜ?Y>,˂8Z/yUUʊ o,: 5m @he}}_Y+j%Qy."NTnp}ߏ=K ZI\:Xbulp_ MuSk%\#P1}ssz]sΥX(i$I1]%Y]]}ÆI [hZIo0Ģwӗ(in땬UR@H&jf@WG/yFuBTQZDbfy]$MƘhnH+P1Ὲ8!)i@zvuX'}sr}#A^~poAkzMt)I7+ױRĈ<>8qKIENDB`rviz-1.12.4/images/splash_overlay.png000066400000000000000000000054221300447110700175770ustar00rootroot00000000000000PNG  IHDR 1S# OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-bKGD pHYs  tIME' 79)DIDATHQ02v#;Kd#~z ҽ46Tgܛy#{Ӣt(n FnIENDB`rviz-1.12.4/mainpage.dox000066400000000000000000000115741300447110700150730ustar00rootroot00000000000000/** \mainpage \htmlinclude manifest.html \b rviz is a 3d visualization program for robots using ROS. \b rviz can be extended by writing \b plugins. (See
RViz Plugin Tutorials.) \b librviz is a library for including \b rviz visualization capabilities in your own applications. (See Librviz Tutorial.) \section display_plugin_classes Display Plugin Classes The main classes relevant when writing display plugins are: \li rviz::Display This is the superclass of things that can be added to the list of displays. Subclasses generally subscribe to ROS messages and show 3D things in the visualization window. \li rviz::VisualizationManager This is the central manager class of RViz. Most things you write with RViz will access one of these. \li rviz::FrameManager subscribes to TF messages to know where all the coordinate frames are. It has a (settable) "Fixed Frame" and functions for finding the pose of any other frame relative to it. This is the main class to use when you need to know where something is in space. \li The rviz::Property subclasses like rviz::IntProperty, rviz::FloatProperty, rviz::StringProperty, rviz::RosTopicStringProperty, rviz::BoolProperty, etc. are created by rviz::Display subclasses to define user-editable properties which get saved to config files. \li The ogre-helper classes are useful for making some common types of 3D objects show up in the render window: rviz::Arrow, rviz::Axes, rviz::BillboardLine, rviz::Grid, rviz::MovableText, and rviz::PointCloud. \section panel_plugin_classes Panel Plugin Classes The main classes relevant when writing panel plugins are: \li rviz::Panel is the superclass of custom panels defined in plugins. \li rviz::Config represents a config file, which rviz::Panel subclasses need to use in order to save their custom data (since they don't use Property objects). \section librviz_classes Librviz Classes When writing an application using librviz, some additional important classes are: \li rviz::VisualizationFrame is the main RViz window, including the menus, toolbar, dockable sub-windows, etc. \li rviz::VisualizationPanel is a stripped-down RViz window (not used in the actual RViz executable) which has only the rviz::DisplaysPanel on the left and an rviz::RenderPanel on the right. This widget has no menu, no toolbar, and cannot have other widgets "dock" with it. This is a great widget to start with because hide the list of displays to see a "pure" 3D view in your application, but you can still show the display list and add or remove displays interactively if you need to. It also includes an rviz::VisualizationManager and a call to ros::init(), so there is less bookkeeping to do. \li rviz::RenderPanel is the main 3D view widget. Using this directly in your code gives the most flexibility, at the cost of added complexity. If you use this, you will need to create an rviz::VisualizationManager yourself and also call ros::init(). The Librviz Tutorial demonstrates this. \section external_apis External APIs RViz uses several external libraries which show up in its API. Here are some of the major ones: \li ros::NodeHandle is one of the main ROS classes, used for subscribing and publishing on topics. \li ros::init() function, used to initialize a ROS node. Only needed if you want to use an rviz::RenderPanel on its own. \li tf::MessageFilter filters incoming ROS messages based on their coordinate frame header and the frame data currently available from TF. \li Ogre::SceneManager, Ogre::SceneNode, Ogre::Vector3, Ogre::Quaternion, Ogre::ManualObject, Ogre::Entity, and Ogre::Material are just a few of the many classes from the Ogre3D graphics library which you may need when playing inside RViz. */ rviz-1.12.4/ogre_media/000077500000000000000000000000001300447110700146615ustar00rootroot00000000000000rviz-1.12.4/ogre_media/fonts/000077500000000000000000000000001300447110700160125ustar00rootroot00000000000000rviz-1.12.4/ogre_media/fonts/arial.fontdef000066400000000000000000000001071300447110700204470ustar00rootroot00000000000000Arial { type truetype source arial.ttf size 18 resolution 96 } rviz-1.12.4/ogre_media/materials/000077500000000000000000000000001300447110700166425ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/glsl120/000077500000000000000000000000001300447110700200265ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/glsl120/black.frag000066400000000000000000000001261300447110700217420ustar00rootroot00000000000000#version 120 // Returns black. void main() { gl_FragColor = vec4( 0, 0, 0, 0 ); } rviz-1.12.4/ogre_media/materials/glsl120/depth.frag000066400000000000000000000002011300447110700217640ustar00rootroot00000000000000#version 120 // Passes on the packed depth value // includes vec4 packDepth( ); void main() { gl_FragColor = packDepth(); } rviz-1.12.4/ogre_media/materials/glsl120/depth.vert000066400000000000000000000003241300447110700220330ustar00rootroot00000000000000#version 120 // Minimal depth passthrough shader uniform mat4 worldviewproj_matrix; void passDepth( vec4 pos ); void main() { gl_Position = worldviewproj_matrix * gl_Vertex; passDepth( gl_Vertex ); } rviz-1.12.4/ogre_media/materials/glsl120/depth_circle.frag000066400000000000000000000003521300447110700233140ustar00rootroot00000000000000#version 120 // Draws a circle with the packed depth value // includes vec4 packDepth( ); void circleImpl( vec4 color, float ax, float ay ); void main() { circleImpl( packDepth(), gl_TexCoord[0].x-0.5, gl_TexCoord[0].y-0.5 ); } rviz-1.12.4/ogre_media/materials/glsl120/flat_color.frag000066400000000000000000000003711300447110700230140ustar00rootroot00000000000000#version 120 // Passes the fragment color, multiplying a with the alpha param uniform vec4 highlight; uniform float alpha; void main() { vec3 col = gl_Color.xyz + gl_Color.xyz * highlight.xyz; gl_FragColor = vec4(col, gl_Color.a * alpha); } rviz-1.12.4/ogre_media/materials/glsl120/flat_color_circle.frag000066400000000000000000000005421300447110700243350ustar00rootroot00000000000000#version 120 // Draws a circle in the fragment color, multiplying a with the alpha param uniform vec4 highlight; uniform float alpha; void circleImpl( vec4 color, float ax, float ay ); void main() { vec3 col = gl_Color.xyz + gl_Color.xyz * highlight.xyz; circleImpl( vec4(col, alpha * gl_Color.a), gl_TexCoord[0].x-0.5, gl_TexCoord[0].y-0.5 ); } rviz-1.12.4/ogre_media/materials/glsl120/glsl120.program000066400000000000000000000065431300447110700226130ustar00rootroot00000000000000 //includes: fragment_program rviz/glsl120/include/circle_impl.frag glsl { source include/circle_impl.frag } fragment_program rviz/glsl120/include/pack_depth.frag glsl { source include/pack_depth.frag } vertex_program rviz/glsl120/include/pass_depth.vert glsl { source include/pass_depth.vert } //all shaders, sorted by name fragment_program rviz/glsl120/depth_circle.frag glsl { source depth_circle.frag attach rviz/glsl120/include/pack_depth.frag attach rviz/glsl120/include/circle_impl.frag default_params { param_named_auto alpha custom 1 param_named_auto far_clip_distance far_clip_distance } } fragment_program rviz/glsl120/depth.frag glsl { source depth.frag attach rviz/glsl120/include/pack_depth.frag default_params { param_named_auto alpha custom 1 param_named_auto far_clip_distance far_clip_distance } } vertex_program rviz/glsl120/depth.vert glsl { source depth.vert preprocessor_defines WITH_DEPTH=1 attach rviz/glsl120/include/pass_depth.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto worldview_matrix worldview_matrix } } fragment_program rviz/glsl120/flat_color.frag glsl { source flat_color.frag default_params { param_named_auto highlight custom 5 param_named_auto alpha custom 1 } } fragment_program rviz/glsl120/flat_color_circle.frag glsl { source flat_color_circle.frag attach rviz/glsl120/include/circle_impl.frag default_params { param_named_auto highlight custom 5 param_named_auto alpha custom 1 } } fragment_program rviz/glsl120/indexed_8bit_image.frag glsl { source indexed_8bit_image.frag default_params { param_named_auto alpha custom 1 } } vertex_program rviz/glsl120/indexed_8bit_image.vert glsl { source indexed_8bit_image.vert } fragment_program rviz/glsl120/pass_color_circle.frag glsl { source pass_color_circle.frag attach rviz/glsl120/include/circle_impl.frag } fragment_program rviz/glsl120/pass_color.frag glsl { source pass_color.frag } fragment_program rviz/glsl120/pickcolor_circle.frag glsl { source pickcolor_circle.frag attach rviz/glsl120/include/circle_impl.frag default_params { param_named_auto pick_color custom 2 } } fragment_program rviz/glsl120/pickcolor.frag glsl { source pickcolor.frag default_params { param_named_auto pick_color custom 2 } } fragment_program rviz/glsl120/black.frag glsl { source black.frag } vertex_program rviz/glsl120/point.vert glsl { source point.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto size custom 0 } } vertex_program rviz/glsl120/point.vert(with_depth) glsl { source point.vert preprocessor_defines WITH_DEPTH=1 attach rviz/glsl120/include/pass_depth.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto worldview_matrix worldview_matrix param_named_auto size custom 0 } } fragment_program rviz/glsl120/shaded_circle.frag glsl { source shaded_circle.frag default_params { param_named_auto highlight custom 5 param_named_auto alpha custom 1 } } fragment_program rviz/glsl120/smooth_square.frag glsl { source smooth_square.frag default_params { param_named_auto highlight custom 5 param_named_auto alpha custom 1 } } rviz-1.12.4/ogre_media/materials/glsl120/include/000077500000000000000000000000001300447110700214515ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/glsl120/include/circle_impl.frag000066400000000000000000000003431300447110700245740ustar00rootroot00000000000000#version 120 // rasterizes a circle of radius 0.5 void circleImpl( vec4 color, float ax, float ay ) { float rsquared = ax*ax+ay*ay; float a = (0.25 - rsquared) * 4.0; gl_FragColor = vec4(color.rgb, color.a * ceil(a)); } rviz-1.12.4/ogre_media/materials/glsl120/include/pack_depth.frag000066400000000000000000000012411300447110700244120ustar00rootroot00000000000000#version 120 // Splits up a normalized depth value in the range (0..1) // into the vertex RGB values. // Alpha values below 1/255 are rendered transparent. uniform float alpha; uniform float far_clip_distance; const float minimum_alpha = 1.0 / 255.0; varying float depth; vec4 packDepth() { float normalized_depth = depth / far_clip_distance; // split up float into rgb components const vec3 shift = vec3(256.0 * 256.0, 256.0, 1.0); const vec3 mask = vec3(0.0, 1.0 / 256.0, 1.0 / 256.0); vec3 depth_packed = fract(normalized_depth * shift); depth_packed -= depth_packed.xxy * mask; return vec4( depth_packed.zyx, step( minimum_alpha, alpha )); } rviz-1.12.4/ogre_media/materials/glsl120/include/pass_depth.vert000066400000000000000000000002641300447110700245070ustar00rootroot00000000000000#version 120 uniform mat4 worldview_matrix; varying float depth; void passDepth( vec4 pos ) { vec4 pos_rel_view = worldview_matrix * pos; depth = -pos_rel_view.z; } rviz-1.12.4/ogre_media/materials/glsl120/indexed_8bit_image.frag000066400000000000000000000007551300447110700244060ustar00rootroot00000000000000#version 120 // Draws an 8-bit image using RGB values from a 256x1 palette texture. varying vec2 UV; uniform sampler2D eight_bit_image; uniform sampler1D palette; uniform float alpha; void main() { // The 0.999 multiply is needed because brightness value 255 comes // out of texture2D() as 1.0, which wraps around to 0.0 in the // palette texture. vec4 color = texture1D( palette, 0.999 * texture2D( eight_bit_image, UV ).x ); gl_FragColor = vec4( color.rgb, color.a * alpha ); } rviz-1.12.4/ogre_media/materials/glsl120/indexed_8bit_image.vert000066400000000000000000000004551300447110700244440ustar00rootroot00000000000000#version 120 // Draws an 8-bit image using RGB values from a 256x1 palette texture. // This vertex shader just passes through the UV texture coordinates. // I'm not sure if it is necessary or not. attribute vec4 uv0; varying vec2 UV; void main() { gl_Position = ftransform(); UV = vec2(uv0); } rviz-1.12.4/ogre_media/materials/glsl120/nogp/000077500000000000000000000000001300447110700207715ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/glsl120/nogp/billboard.vert000066400000000000000000000020751300447110700236310ustar00rootroot00000000000000#version 120 // Computes the position of a billboard vertex so // the resulting quad will face the camera. // Texture coords are used to determine which corner // of the billboard we compute. uniform mat4 worldviewproj_matrix; uniform vec4 camera_pos; uniform vec4 size; uniform vec4 auto_size; #ifdef WITH_DEPTH //include: void passDepth( vec4 pos ); #endif void main() { vec3 at = camera_pos.xyz - gl_Vertex.xyz; at = normalize(at); vec3 right = cross(vec3( 0.0, 1.0, 0.0 ), at); vec3 up = cross(at, right); right = normalize(right); up = normalize(up); // if auto_size == 1, then size_factor == size*gl_Vertex.z // if auto_size == 0, then size_factor == size vec4 size_factor = (1-auto_size.x+(auto_size.x*gl_Vertex.z))*size; vec4 s = gl_MultiTexCoord0 * (size_factor); vec3 r = s.xxx * right; vec3 u = s.yyy * up; vec4 pos = gl_Vertex + vec4( r + u, 0.0 ); gl_Position = worldviewproj_matrix * pos; gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(0.5,0.5,0.0,0.0); gl_FrontColor = gl_Color; #ifdef WITH_DEPTH passDepth( pos ); #endif } rviz-1.12.4/ogre_media/materials/glsl120/nogp/billboard_tile.vert000066400000000000000000000013721300447110700246450ustar00rootroot00000000000000#version 120 // Computes the position of a billboard vertex so // the resulting quad will face a given direction given by up & normal. // Texture coords are used to determine which corner // of the billboard we compute. uniform mat4 worldviewproj_matrix; uniform vec4 size; uniform vec4 normal; uniform vec4 up; #ifdef WITH_DEPTH //include: void passDepth( vec4 pos ); #endif void main() { vec3 right = cross(up.xyz, normal.xyz); vec4 s = gl_MultiTexCoord0 * size; vec3 r = s.xxx * right; vec3 u = s.yyy * up.xyz; vec4 pos = gl_Vertex + vec4( r + u, 0.0 ); gl_Position = worldviewproj_matrix * pos; gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(0.5,0.5,0.0,0.0); gl_FrontColor = gl_Color; #ifdef WITH_DEPTH passDepth( pos ); #endif } rviz-1.12.4/ogre_media/materials/glsl120/nogp/box.frag000066400000000000000000000031111300447110700224160ustar00rootroot00000000000000#version 120 // rasterizes a smooth square on any face of a box // and creates a fake lighting effect // x,y,z texture coords must be in the interval (-0.5...0.5) uniform vec4 highlight; uniform float alpha; const float lightness[6] = float[] ( 0.9, 0.5, 0.6, 0.6, 1.0, 0.4 ); void main() { float ax; float ay; float l; if ( gl_TexCoord[0].z < -0.4999 ) { ax = gl_TexCoord[0].x; ay = gl_TexCoord[0].y; l = lightness[0]; } else if ( gl_TexCoord[0].z > 0.4999 ) { ax = gl_TexCoord[0].x; ay = gl_TexCoord[0].y; l = lightness[1]; } else if ( gl_TexCoord[0].x > 0.4999 ) { ax = gl_TexCoord[0].y; ay = gl_TexCoord[0].z; l = lightness[2]; } else if ( gl_TexCoord[0].x < -0.4999 ) { ax = gl_TexCoord[0].y; ay = gl_TexCoord[0].z; l = lightness[3]; } else if ( gl_TexCoord[0].y > 0.4999 ) { ax = gl_TexCoord[0].x; ay = gl_TexCoord[0].z; l = lightness[4]; } else { ax = gl_TexCoord[0].x; ay = gl_TexCoord[0].z; l = lightness[5]; } float blend = smoothstep(-0.48, -0.45, ay) * (1.0 - smoothstep(0.45, 0.48, ay)) * smoothstep(-0.48, -0.45, ax) * (1.0 - smoothstep(0.45, 0.48, ax)); float inv_blend = 1.0 - blend; //vec3 col = blend * gl_Color.xyz + (sign(0.5 - length(vec3(gl_Color.xyz))) * vec3(0.2, 0.2, 0.2) + gl_Color.xyz) * inv_blend; //alternative version: make color at edge darker vec3 col = (0.5 + 0.5*blend) * gl_Color.xyz; col = col * l; col = col + col * highlight.xyz; gl_FragColor = vec4(col.r, col.g, col.b, alpha * gl_Color.a ); } rviz-1.12.4/ogre_media/materials/glsl120/nogp/box.vert000066400000000000000000000013371300447110700224670ustar00rootroot00000000000000#version 120 // Computes the position of a box vertex from its texture coords. // Used in case that geometry shaders are not supported. uniform mat4 worldviewproj_matrix; uniform vec4 camera_pos; uniform vec4 size; uniform vec4 auto_size; #ifdef WITH_DEPTH //include: void passDepth( vec4 pos ); #endif void main() { // if auto_size == 1, then size_factor == size*gl_Vertex.z // if auto_size == 0, then size_factor == size vec4 size_factor = (1-auto_size.x+(auto_size.x*gl_Vertex.z))*size; vec4 s = gl_MultiTexCoord0 * size_factor; vec4 pos = gl_Vertex - s; gl_Position = worldviewproj_matrix * pos; gl_TexCoord[0] = gl_MultiTexCoord0; gl_FrontColor = gl_Color; #ifdef WITH_DEPTH passDepth( pos ); #endif } rviz-1.12.4/ogre_media/materials/glsl120/nogp/nogp.program000066400000000000000000000052351300447110700233320ustar00rootroot00000000000000// These shaders are work-arounds in case geometry shaders // are not supported, so vertices can't be created on the graphics card. // Multiple vertices are passed in for each primitive, // and each one is offset according to its texture coords. //includes: vertex_program rviz/glsl120/include/pass_depth.vert glsl { source ../include/pass_depth.vert } vertex_program rviz/glsl120/nogp/billboard_tile.vert glsl { source billboard_tile.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto size custom 0 param_named_auto normal custom 3 param_named_auto up custom 4 } } vertex_program rviz/glsl120/nogp/billboard_tile.vert(with_depth) glsl { source billboard_tile.vert preprocessor_defines WITH_DEPTH=1 attach rviz/glsl120/include/pass_depth.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto worldview_matrix worldview_matrix param_named_auto size custom 0 param_named_auto normal custom 3 param_named_auto up custom 4 } } vertex_program rviz/glsl120/nogp/billboard.vert glsl { source billboard.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto camera_pos camera_position_object_space param_named_auto size custom 0 param_named_auto auto_size custom 6 } } vertex_program rviz/glsl120/nogp/billboard.vert(with_depth) glsl { source billboard.vert preprocessor_defines WITH_DEPTH=1 attach rviz/glsl120/include/pass_depth.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto worldview_matrix worldview_matrix param_named_auto camera_pos camera_position_object_space param_named_auto size custom 0 param_named_auto auto_size custom 6 } } vertex_program rviz/glsl120/nogp/box.vert glsl { source box.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto size custom 0 param_named_auto auto_size custom 6 } } vertex_program rviz/glsl120/nogp/box.vert(with_depth) glsl { source box.vert preprocessor_defines WITH_DEPTH=1 attach rviz/glsl120/include/pass_depth.vert default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto worldview_matrix worldview_matrix param_named_auto size custom 0 param_named_auto auto_size custom 6 } } fragment_program rviz/glsl120/nogp/box.frag glsl { source box.frag default_params { param_named_auto highlight custom 5 param_named_auto alpha custom 1 } } rviz-1.12.4/ogre_media/materials/glsl120/pass_color.frag000066400000000000000000000001421300447110700230300ustar00rootroot00000000000000#version 120 // Passes the fragment color unchanged void main() { gl_FragColor = gl_Color; } rviz-1.12.4/ogre_media/materials/glsl120/pass_color_circle.frag000066400000000000000000000003151300447110700243530ustar00rootroot00000000000000#version 120 // Draws a circle in the fragment color //includes: void circleImpl( vec4 color, float ax, float ay ); void main() { circleImpl( gl_Color, gl_TexCoord[0].x-0.5, gl_TexCoord[0].y-0.5 ); } rviz-1.12.4/ogre_media/materials/glsl120/pickcolor.frag000066400000000000000000000001671300447110700226600ustar00rootroot00000000000000#version 120 // Passes the vertex pick color uniform vec4 pick_color; void main() { gl_FragColor = pick_color; } rviz-1.12.4/ogre_media/materials/glsl120/pickcolor_circle.frag000066400000000000000000000003461300447110700242000ustar00rootroot00000000000000#version 120 // Draws a circle in the pick color //includes: void circleImpl( vec4 color, float ax, float ay ); uniform vec4 pick_color; void main() { circleImpl( pick_color, gl_TexCoord[0].x-0.5, gl_TexCoord[0].y-0.5 ); } rviz-1.12.4/ogre_media/materials/glsl120/point.vert000066400000000000000000000006701300447110700220640ustar00rootroot00000000000000#version 120 // Generic vertex shader for point sprites // sets position and point size. // Works for perspective and orthographic projection. uniform mat4 worldviewproj_matrix; uniform vec4 size; #ifdef WITH_DEPTH //include: void passDepth( vec4 pos ); #endif void main() { gl_Position = worldviewproj_matrix * gl_Vertex; gl_FrontColor = gl_Color; gl_PointSize = size.x; #ifdef WITH_DEPTH passDepth( gl_Vertex ); #endif } rviz-1.12.4/ogre_media/materials/glsl120/shaded_circle.frag000066400000000000000000000007131300447110700234410ustar00rootroot00000000000000#version 120 // rasterizes a circle that is darker at the borders than in the center uniform vec4 highlight; uniform float alpha; void main() { float ax = gl_TexCoord[0].x-0.5; float ay = gl_TexCoord[0].y-0.5; float rsquared = ax*ax+ay*ay; float a = (0.25 - rsquared) * 4.0; vec3 col = mix(vec3(0.8, 0.8, 0.8) * gl_Color.xyz, gl_Color.xyz, a); col = col + col * highlight.xyz; gl_FragColor = vec4(col, alpha * ceil(a) * gl_Color.a); } rviz-1.12.4/ogre_media/materials/glsl120/smooth_square.frag000066400000000000000000000013451300447110700235630ustar00rootroot00000000000000#version 120 // rasterizes a smooth square with ax,ay in [-0.5..0.5] uniform vec4 highlight; uniform float alpha; void main() { float ax = gl_TexCoord[0].x-0.5; float ay = gl_TexCoord[0].y-0.5; float blend = smoothstep(-0.48, -0.45, ay) * (1.0 - smoothstep(0.45, 0.48, ay)) * smoothstep(-0.48, -0.45, ax) * (1.0 - smoothstep(0.45, 0.48, ax)); float inv_blend = 1.0 - blend; vec3 col = blend * gl_Color.xyz + (sign(0.5 - length(vec3(gl_Color.xyz))) * vec3(0.2, 0.2, 0.2) + gl_Color.xyz) * inv_blend; //alternative version: make color at edge darker //vec3 col = (0.5 + 0.5*blend) * gl_Color.xyz; col = col + col * highlight.xyz; gl_FragColor = vec4(col.r, col.g, col.b, alpha * gl_Color.a ); } rviz-1.12.4/ogre_media/materials/glsl120/test_glsl.sh000077500000000000000000000004361300447110700223700ustar00rootroot00000000000000if [[ "$1" == *.vert ]]; then cgc -oglsl -profile arbvp1 -strict -nocode $1 elif [[ "$1" == *.frag ]]; then cgc -oglsl -profile arbfp1 -strict -nocode $1 elif [[ "$1" == *.geom ]]; then cgc -oglsl -profile gs_5_0 -strict -nocode $1 else echo "Unknown shader type!" exit 1 fi rviz-1.12.4/ogre_media/materials/glsl150/000077500000000000000000000000001300447110700200315ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/glsl150/billboard.geom000066400000000000000000000030031300447110700226300ustar00rootroot00000000000000#version 150 // Generates view-facing square (billboard) with a given size // for each input vertex. #ifdef WITH_DEPTH uniform mat4 worldview_matrix; out float depth; void passDepth( vec4 pos ) { vec4 pos_rel_view = worldview_matrix * pos; depth = -pos_rel_view.z; } #endif uniform mat4 inverse_worldview_matrix; uniform mat4 worldviewproj_matrix; uniform vec4 size; uniform vec4 auto_size; in gl_PerVertex { vec4 gl_Position; vec4 gl_FrontColor; } gl_in[]; out vec4 gl_TexCoord[]; layout(points) in; layout(triangle_strip, max_vertices=4) out; void emitVertex( vec3 pos_rel, vec3 tex ) { pos_rel = mat3(inverse_worldview_matrix) * pos_rel; vec4 pos = gl_in[0].gl_Position + vec4(pos_rel,0.0); gl_Position = worldviewproj_matrix * pos; gl_TexCoord[0] = vec4( tex.xy, 0.0, 0.0 ); gl_FrontColor = vec4( gl_in[0].gl_FrontColor ); EmitVertex(); } void main() { // if auto_size == 1, then size_factor == size.x*gl_Vertex.z // if auto_size == 0, then size_factor == size.x float size_factor = (1-auto_size.x+(auto_size.x*gl_in[0].gl_Position.z))*size.x; size_factor = size_factor * 0.5; #ifdef WITH_DEPTH depth = -((worldview_matrix * gl_in[0].gl_Position).z); #endif emitVertex( vec3(-size_factor,-size_factor, 0.0), vec3(0.0, 0.0, 0.0) ); emitVertex( vec3( size_factor,-size_factor, 0.0), vec3(1.0, 0.0, 0.0) ); emitVertex( vec3(-size_factor, size_factor, 0.0), vec3(0.0, 1.0, 0.0) ); emitVertex( vec3( size_factor, size_factor, 0.0), vec3(1.0, 1.0, 0.0) ); EndPrimitive(); } rviz-1.12.4/ogre_media/materials/glsl150/box.geom000066400000000000000000000042031300447110700214710ustar00rootroot00000000000000#version 150 // Generates an axis-aligned box with a given size // for each input vertex. #ifdef WITH_DEPTH uniform mat4 worldview_matrix; out float depth; void passDepth( vec4 pos ) { vec4 pos_rel_view = worldview_matrix * pos; depth = -pos_rel_view.z; } #endif uniform mat4 worldviewproj_matrix; uniform vec4 size; uniform vec4 auto_size; in gl_PerVertex { vec4 gl_Position; vec4 gl_FrontColor; } gl_in[]; out vec4 gl_TexCoord[]; layout(points) in; layout(triangle_strip, max_vertices=24) out; const vec4 axes[3] = vec4[] ( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), vec4(0.0,0.0,1.0,0.0) ); const float lightness[6] = float[] ( 0.9, 0.5, 0.6, 0.6, 1.0, 0.4 ); void emitVertex( int side, vec4 x, vec4 y, vec4 z, vec3 tex ) { // if auto_size == 1, then size_factor == size*gl_Vertex.z // if auto_size == 0, then size_factor == size vec4 size_factor = (1-auto_size.x+(auto_size.x*gl_in[0].gl_Position.z))*size; vec4 pos_rel = tex.x*x + tex.y*y + tex.z*z; vec4 pos = gl_in[0].gl_Position + vec4( pos_rel * size_factor * 0.5 ); gl_Position = worldviewproj_matrix * pos; gl_TexCoord[0] = vec4( tex.x*0.5+0.5, tex.y*0.5+0.5, 0.0, 0.0 ); #ifdef WITH_LIGHTING gl_FrontColor = vec4( gl_in[0].gl_FrontColor.xyz * lightness[side], gl_in[0].gl_FrontColor.a ); #else gl_FrontColor = vec4( gl_in[0].gl_FrontColor.xyz, gl_in[0].gl_FrontColor.a ); #endif #ifdef WITH_DEPTH passDepth( pos ); #endif EmitVertex(); } void main() { for( int side=0; side<3; side++ ) { int side2 = (side+1)%3; int side3 = (side+2)%3; vec4 x=axes[ side ]; vec4 y=axes[ side2 ]; vec4 z=axes[ side3 ]; // face for +z emitVertex( side, x, y, z, vec3(-1, -1, +1) ); emitVertex( side, x, y, z, vec3(+1, -1, +1) ); emitVertex( side, x, y, z, vec3(-1, +1, +1) ); emitVertex( side, x, y, z, vec3(+1, +1, +1) ); EndPrimitive(); // face for -z emitVertex( side+3, x, y, z, vec3(-1, -1, -1) ); emitVertex( side+3, x, y, z, vec3(-1, +1, -1) ); emitVertex( side+3, x, y, z, vec3(+1, -1, -1) ); emitVertex( side+3, x, y, z, vec3(+1, +1, -1) ); EndPrimitive(); } } rviz-1.12.4/ogre_media/materials/glsl150/glsl150.program000066400000000000000000000042131300447110700226110ustar00rootroot00000000000000//all shaders, sorted by name geometry_program rviz/glsl150/billboard.geom glsl { source billboard.geom input_operation_type points output_operation_type triangle_strip max_output_vertices 4 default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto inverse_worldview_matrix inverse_worldview_matrix param_named_auto size custom 0 param_named_auto auto_size custom 6 } } geometry_program rviz/glsl150/billboard.geom(with_depth) glsl { source billboard.geom input_operation_type points output_operation_type triangle_strip max_output_vertices 4 preprocessor_defines WITH_DEPTH=1 default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto inverse_worldview_matrix inverse_worldview_matrix param_named_auto worldview_matrix worldview_matrix param_named_auto size custom 0 param_named_auto auto_size custom 6 } } geometry_program rviz/glsl150/box.geom glsl { source box.geom input_operation_type points output_operation_type triangle_strip max_output_vertices 24 default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto size custom 0 param_named_auto auto_size custom 6 } } geometry_program rviz/glsl150/box.geom(with_depth) glsl { source box.geom input_operation_type points output_operation_type triangle_strip max_output_vertices 24 preprocessor_defines WITH_DEPTH=1 default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto worldview_matrix worldview_matrix param_named_auto size custom 0 param_named_auto auto_size custom 6 } } geometry_program rviz/glsl150/box.geom(with_lighting) glsl { source box.geom input_operation_type points output_operation_type triangle_strip max_output_vertices 24 preprocessor_defines WITH_LIGHTING=1 default_params { param_named_auto worldviewproj_matrix worldviewproj_matrix param_named_auto size custom 0 param_named_auto auto_size custom 6 } } vertex_program rviz/glsl150/pass_pos_color.vert glsl { source pass_pos_color.vert } rviz-1.12.4/ogre_media/materials/glsl150/pass_pos_color.vert000066400000000000000000000003601300447110700237570ustar00rootroot00000000000000#version 150 compatibility // this merely passes over position and color, // as needed by box.geom out gl_PerVertex { vec4 gl_Position; vec4 gl_FrontColor; }; void main() { gl_Position = gl_Vertex; gl_FrontColor = gl_Color; } rviz-1.12.4/ogre_media/materials/scripts/000077500000000000000000000000001300447110700203315ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/scripts/default_pick_and_depth.material000066400000000000000000000022321300447110700265100ustar00rootroot00000000000000material rviz/DefaultPickAndDepth { technique PickCull { pass { lighting off scene_blend one zero cull_hardware clockwise fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique BlackCull { pass { lighting off scene_blend one zero cull_hardware clockwise fragment_program_ref rviz/glsl120/black.frag {} } } technique DepthCull { pass { scene_blend one zero cull_hardware clockwise vertex_program_ref rviz/glsl120/depth.vert {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique Pick { pass { lighting off scene_blend one zero cull_hardware none fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique Black { pass { lighting off scene_blend one zero cull_hardware none fragment_program_ref rviz/glsl120/black.frag {} } } technique Depth { pass { scene_blend one zero cull_hardware none vertex_program_ref rviz/glsl120/depth.vert {} fragment_program_ref rviz/glsl120/depth.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts/indexed_8bit_image.material000066400000000000000000000004521300447110700255620ustar00rootroot00000000000000material rviz/Indexed8BitImage { technique { pass { vertex_program_ref rviz/glsl120/indexed_8bit_image.vert {} fragment_program_ref rviz/glsl120/indexed_8bit_image.frag { param_named eight_bit_image int 0 param_named palette int 1 } } } } rviz-1.12.4/ogre_media/materials/scripts/point_cloud_point.material000066400000000000000000000017221300447110700256030ustar00rootroot00000000000000material rviz/PointCloudPoint { technique gp { pass { alpha_rejection greater_equal 1 point_size_attenuation on point_sprites on vertex_program_ref rviz/glsl120/point.vert {} fragment_program_ref rviz/glsl120/flat_color_circle.frag {} } } technique depth { scheme Depth pass { point_size_attenuation on vertex_program_ref rviz/glsl120/point.vert(with_depth) {} fragment_program_ref rviz/glsl120/depth_circle.frag {} } } technique selection_first_pass { scheme Pick pass { point_size_attenuation on vertex_program_ref rviz/glsl120/point.vert {} fragment_program_ref rviz/glsl120/pickcolor_circle.frag {} } } technique selection_second_pass { scheme Pick1 pass { point_size_attenuation on vertex_program_ref rviz/glsl120/point.vert {} fragment_program_ref rviz/glsl120/pass_color_circle.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts/point_cloud_tile.material000066400000000000000000000022121300447110700254020ustar00rootroot00000000000000material rviz/PointCloudTile { technique nogp { pass { alpha_rejection greater_equal 1 cull_hardware none cull_software none vertex_program_ref rviz/glsl120/nogp/billboard_tile.vert {} fragment_program_ref rviz/glsl120/smooth_square.frag {} } } technique nogp_depth { scheme Depth pass { alpha_rejection greater_equal 1 cull_hardware none cull_software none vertex_program_ref rviz/glsl120/nogp/billboard_tile.vert(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique nogp_selection_first_pass { scheme Pick pass { alpha_rejection greater_equal 1 cull_hardware none cull_software none vertex_program_ref rviz/glsl120/nogp/billboard_tile.vert {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique nogp_selection_second_pass { scheme Pick1 pass { alpha_rejection greater_equal 1 cull_hardware none cull_software none vertex_program_ref rviz/glsl120/nogp/billboard_tile.vert {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } }rviz-1.12.4/ogre_media/materials/scripts120/000077500000000000000000000000001300447110700205545ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/scripts120/point_cloud_box.material000066400000000000000000000016271300447110700254710ustar00rootroot00000000000000material rviz/PointCloudBox { /* This material should only be used with glsl < 1.50 */ /* the 'nogp' techniques require the full box geometry as input */ technique nogp { pass { vertex_program_ref rviz/glsl120/nogp/box.vert {} fragment_program_ref rviz/glsl120/nogp/box.frag {} } } technique nogp_depth { scheme Depth pass { vertex_program_ref rviz/glsl120/nogp/box.vert(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique nogp_selection_first_pass { scheme Pick pass { vertex_program_ref rviz/glsl120/nogp/box.vert {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique nogp_selection_second_pass { scheme Pick1 pass { vertex_program_ref rviz/glsl120/nogp/box.vert {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts120/point_cloud_flat_square.material000066400000000000000000000016331300447110700272040ustar00rootroot00000000000000material rviz/PointCloudFlatSquare { technique nogp { pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/flat_color.frag {} } } technique nogp_depth { scheme Depth pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique nogp_selection_first_pass { scheme Pick pass { vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique nogp_selection_second_pass { scheme Pick1 pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts120/point_cloud_sphere.material000066400000000000000000000017301300447110700261620ustar00rootroot00000000000000material rviz/PointCloudSphere { technique nogp { pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/shaded_circle.frag {} } } technique nogp_depth { scheme Depth pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert(with_depth) {} fragment_program_ref rviz/glsl120/depth_circle.frag {} } } technique nogp_selection_first_pass { scheme Pick pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/pickcolor_circle.frag {} } } technique nogp_selection_second_pass { scheme Pick1 pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/pass_color_circle.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts120/point_cloud_square.material000066400000000000000000000016321300447110700261750ustar00rootroot00000000000000material rviz/PointCloudSquare { technique nogp { pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/smooth_square.frag {} } } technique nogp_depth { scheme Depth pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique nogp_selection_first_pass { scheme Pick pass { vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique nogp_selection_second_pass { scheme Pick1 pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl120/nogp/billboard.vert {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts150/000077500000000000000000000000001300447110700205575ustar00rootroot00000000000000rviz-1.12.4/ogre_media/materials/scripts150/point_cloud_box.material000066400000000000000000000022741300447110700254730ustar00rootroot00000000000000material rviz/PointCloudBox { /* This material should only be used with glsl < 1.50 */ // the 'gp' techniques need one input vertex per box // and use geometry shaders to create the geometry technique gp { pass { vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/box.geom(with_lighting) {} fragment_program_ref rviz/glsl120/smooth_square.frag {} } } technique gp_depth { scheme Depth pass { vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/box.geom(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique gp_selection_first_pass { scheme Pick pass { vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/box.geom {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique gp_selection_second_pass { scheme Pick1 pass { vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/box.geom {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts150/point_cloud_flat_square.material000066400000000000000000000022321300447110700272030ustar00rootroot00000000000000material rviz/PointCloudFlatSquare { technique gp { pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/flat_color.frag {} } } technique gp_depth { scheme Depth pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique gp_selection_first_pass { scheme Pick pass { vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique gp_selection_second_pass { scheme Pick1 pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts150/point_cloud_sphere.material000066400000000000000000000022311300447110700261620ustar00rootroot00000000000000material rviz/PointCloudSphere { technique gp { pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/shaded_circle.frag {} } } technique gp_depth { scheme Depth pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique gp_selection_first_pass { scheme Pick pass { vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique gp_selection_second_pass { scheme Pick1 pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } } rviz-1.12.4/ogre_media/materials/scripts150/point_cloud_square.material000066400000000000000000000022311300447110700261740ustar00rootroot00000000000000material rviz/PointCloudSquare { technique gp { pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/smooth_square.frag {} } } technique gp_depth { scheme Depth pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom(with_depth) {} fragment_program_ref rviz/glsl120/depth.frag {} } } technique gp_selection_first_pass { scheme Pick pass { vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/pickcolor.frag {} } } technique gp_selection_second_pass { scheme Pick1 pass { alpha_rejection greater_equal 1 vertex_program_ref rviz/glsl150/pass_pos_color.vert {} geometry_program_ref rviz/glsl150/billboard.geom {} fragment_program_ref rviz/glsl120/pass_color.frag {} } } } rviz-1.12.4/ogre_media/models/000077500000000000000000000000001300447110700161445ustar00rootroot00000000000000rviz-1.12.4/ogre_media/models/rviz_cone.mesh000066400000000000000000000133461300447110700210270ustar00rootroot00000000000000[MeshSerializer_v1.8] 0@ BaseWhiteNoLighting Z  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYP ZQ6QQ QRP RF ^>=vC>۲9@?*>>,:>۲9@?5>>YJA۲9I@?>^>=vC>K3 9@?*>>YJAK3 9I@?>^>FCK3 9@?=^>=vC>1R5 9@?*>^>FC1R5 9@?=?BB>71R5 9s@?>,:>cQ9@?5>C>7>cQ9@?>C>LcQ9&@?X>>,:>T9@?5>C>LT9&@?X>>YJAT9I@?>C>7>!9@?>i$6X?!9r@??-TMN!9t@??C>7>+,39@?>-TMN+,39t@??C>L+,39&@?X>i$6X?+,39r@??C7>+,39@??CL+,39&@?T ?i$6X?!9r@??CL!9&@?T ?-TMN!9t@??C7>U39@??,:>U39@?f??YJAU39I@?@?C7>49@??YJA49I@?@?CL쾑49&@?T ?,:>K3 9@?f??^=vC>K3 9@?5_?^쾣FCK3 9@?`?,:>۲9@?f??^쾣FC۲9@?`?YJA۲9I@?@?^=vC>1R 9@?5_?BB>71R 9s@??^쾣FC1R 9@?`??BB>7na?v>l53>s@?R$z{>>na?v>l53>!{f9?^>=vC>na?v>l53>@?*>^>=vC>??>Q>@?*>R$z{>>??>Q>!{f9?>,:>??>Q>@?5>>,:>Ae>>??@?5>R$z{>>Ae>>??!{f9?C>7>Ae>>??@?>C>7>]3>9>da?@?>R$z{>>]3>9>da?!{f9?i$6X?]3>9>da?r@??i$6X?]39>da?r@??R$z{>>]39>da?!{f9?C7>]39>da?@??C7>Ae>??@??R$z{>>Ae>??!{f9?,:>Ae>??@?f??,:>?>Q>@?f??R$z{>>?>Q>!{f9?^=vC>?>Q>@?5_?^=vC>nav>l53>@?5_?R$z{>>nav>l53>!{f9?BB>7nav>l53>s@??BB>7naf>3s@??R$z{>>naf>3!{f9?^쾣FCnaf>3@?`?^쾣FC?X>ay@?`?R$z{>>?X>ay!{f9?YJA?X>ayI@?@?YJACeL>'?I@?@?R$z{>>CeL>'?!{f9?CLCeL>'?&@?T ?CL쾨]3F>ya&@?T ?R$z{>>]3F>ya!{f9?-TMN]3F>yat@??-TMN]3>F>yat@??R$z{>>]3>F>ya!{f9?C>L쾠]3>F>ya&@?X>C>LCe>L>'?&@?X>R$z{>>Ce>L>'?!{f9?>YJACe>L>'?I@?>>YJA??X>ayI@?>R$z{>>??X>ay!{f9?^>FC??X>ay@?=^>FCna?f>3@?=R$z{>>na?f>3!{f9??BB>7na?f>3s@?@"\+\?6M??ئ6?3 - i71{)r7㬼C2$n6? u+d[8<+ V'8 opC8=dǽ15e86 p15e86 C8=dǽ =2V'8 o !3u+d[8<+!"# 1|)r7䬼$%&  i7'() C$n6?*+,C> ==s@-./&>=)=h@012= =&>6_@345 ==SC>iZ@678 =SC>gZ@9:;  ݽ =&>6_@<=>  &=)=h@?@A C ==s@BCDC=2@EFG &==. ޽Ƌ@HIJ  ݽf=#&@KLM =Cs@NOP==Ct@QRS=e=#&@TUV&>==. ޽Nj@WXYC>=2@{-              !" "#  #! %& '(  ()*++,./124578 :; => @ACDFG IJ LMOPRSUVrviz-1.12.4/ogre_media/models/rviz_cube.mesh000066400000000000000000000046671300447110700210270ustar00rootroot00000000000000[MeshSerializer_v1.8] 0 @`BaseWhiteNoLighting $  !"#P$Q6QQ QR R_'2?@??_'2?>??_'2?>??_'2?>?_'2?@?_'2?@???_'2?>???A>>???_'2?>???A>>????A>>???_'2?>_'2?@??A>@??_'2?>?A>@???A>>?_'2?>???_'2?>????A>>??_'2?@?????A>>???A>@???_'2?@????A>@?????A>>???A>>???A>@????A>>??A>@??_'2?@???A>@?_'2?@???A>@??A>@?_'2?@?@"\\\\?\?\?׳]?0* ? ? ???? !"#            rviz-1.12.4/ogre_media/models/rviz_cylinder.mesh000066400000000000000000000263371300447110700217200ustar00rootroot00000000000000[MeshSerializer_v1.8] 0,@BaseWhiteNoLighting   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~PQ6QQ QR R??#?>!{8^>?C?>>^>?C>?>>^>?C?>>>??>>>?>?>>^>?C?>>>?>?>>^>?C>?>>>??>>C>?^?>>C>?^>?>>>??>>C>?^>?>>>?>?>>C>?^?>>??>?"???>?C>?^?>>"???>?C>?^>?>>??>?C?^?> ?C?^>?> ???>?C?^>?> ?"???>?C?^?> ???>@??>?>@?C?^?> ??>?>@?C?^>?> ???>@?^?C?>_?^?C>?>_???>@?^?C>?>_??>?>@?^?C?>_??$?>?^?C>?>_?^>C>@?>>>@?>>@?>^>C>@?>>@?>^>C@?>^>C>@?>^>C@?>?H@?>>@?>C>^>@?>C>^@?>>>@?>C>^@?>>@?>C>^>@?>"?@??@??C>^>@?>@??C>^@?>"?@??C^>@? ?C^@? ?"?@??C^@? ?@??C^>@? ?>@?@?@?@?C^>@? ?@?@?C^@? ?>@?@?^C>@?_?^C@?_?>@?@?^C@?_?@?@?^C>@?_?#@??^C@?_??H{?G@?^>C{?G@?>^>?C{?G>>^>?C{?Z\#G>>??#{?Z\#G>!{8?H{?Z\#G@?^>C2T?9@?>>2T?9@?>>?2T?9>>>?2T?9>>^>?C2T?9>>^>C2T?9@?>>9?2T@?>C>^9?2T@?>C>?^9?2T>>C>?^9?2T>>>?9?2T>>>9?2T@?>C>^G>{@?>G>{@???G>{>??G>{>?C>?^G>{>>C>^G>{@?>G{@??C^G{@? ?C?^G{> ?C?^G{> ??G{>?G{@??C^92T@? ?92T@?@??92T>@??92T>@?C?^92T> ?C^92T@? ?2T9@?@?^C2T9@?_?^?C2T9>_?^?C2T9>_??2T9>@?2T9@?@?^C{Z\#G@?_?#{Z\#G@???${Z\#G>??${G>?^?C{G>_?^C{G@?_?#{G>@??^C>{G>@?_?^?C>{G>>_?^?C>{Z\G>>_??${Z\G>>?#{Z\G>@??^C>2T9?@?_?>2T9?@?@??>2T9?>@??>2T9?>@?^?C>2T9?>_?^C>2T9?@?_?>92T?@?@?C^>92T?@? ?C?^>92T?> ?C?^>92T?> ??>92T?>@?>92T?@?@?C^>G{?@? ?"?G{?@??"??G{?>?"??G{?>?C?^>G{?> ?C^>G{?@? ?"?G>{?@??C>^>G>{?@?>C>?^>G>{?>>C>?^>G>{?>>"??G>{?>?"?G>{?@??C>?^>9?2T?>>C>^>9?2T?@?>>>9?2T?@?>>>9?2T?@?>>?>9?2T?>>C>?^>9?2T?>>>>2T?9?@?>^>C>2T?9?@?>^>?C>2T?9?>>^>?C>2T?9?>>>?>2T?9?>>>>2T?9?@?>^>C>{?Z\G>@?>?H{?Z\G>@???#{?Z\G>>!{8??#{?G>>!{8^>?C>{?G>>>^>C>{?G>@?>@"\\\\?\?\?5?82<&n<&=|)=|䩼 u>u X=XjC>ý5> 5> C>ý V=Vj u>u!"# })=}䩼$%&  ='() &n<&*+,-./|)|䩼012&n&345uu678XXj9:;Cý<=>5?@A5BCDCýEFGVVjHIJuuKLM})}䩼NOPQRS&n&TUVC>ýWXYC>ýZ[\&>ݽý]^_&>ݽý`ab=&ýcde=&ýfgh=Cýijk=Cýlmn Cýopq Cýrst ݽ&ýuvw ݽ&ýxyz &ݽý{|} &ݽý~Cý CýC=ýC=ý &=ý &=ý ݽ&>ý ݽ&>ýC>ý C>ý=C>ý=C>ý=&>ý=&>ý&>=ý&>=ýC>=ýC>=ý<Z;9!   7 #5%    3  '   1 )!" "#  #! /%& +'(  -()8*++,,*.//-12:206344553 7849::;;9"=>2?@@AA?$CD0EFFGGE&IJ.KLLMMK(OP,QR*RSUVVT:XY![\\Z #ab !b`"%gh"#hf$'mn $%nl &)st &'tr (+yz ()zx *-*+~,/,-.1 ./ 03 01 2523464567798;89:;rviz-1.12.4/ogre_media/models/rviz_sphere.mesh000066400000000000000000001223751300447110700213740ustar00rootroot00000000000000[MeshSerializer_v1.8] 0@YBaseWhiteNoLighting   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~PPTQ6QQ QRT RTC>Hp#^>PG>Rgz??>1ţHp#?PG>Rgz???5>^>PG>Rgz? ?6o>5>^>L;)>f'gz? ?6o>1ţHp#?L;)>f'gz???ԋ >ԋ ^>L;)>f'gz?$T?>ԋ >ԋ ^>f'=L;)gz?$T?>1ţHp#?f'=L;)gz???=5^>f'=L;)gz?dr?.a>=5^>R=PGgz?dr?.a>1ţHp#?R=PGgz???3C^>R=PGgz? ??3C^>RPGgz? ??1ţHp#?RPGgz???5^>RPGgz?dr?h ?5^>f'L;)gz?dr?h ?1ţHp#?f'L;)gz???ԋ ԋ ^>f'L;)gz?$T?7?ԋ ԋ ^>L;)f'gz?$T?7?1ţHp#?L;)f'gz???5^>L;)f'gz? ?d?5^>PGRgz? ?d?1ţHp#?PGRgz???Cf^>PGRgz?? ?Cf^>PGR=gz?? ?1ţHp#?PGR=gz???5=^>PGR=gz? >d?5=^>L;)f'=gz? >d?1ţHp#?L;)f'=gz???ԋ ԋ >^>L;)f'=gz?W>7?ԋ ԋ >^>f'L;)>gz?W>7?1ţHp#?f'L;)>gz???5>^>f'L;)>gz?8>h ?5>^>RPG>gz?8>h ?1ţHp#?RPG>gz???rC>^>RPG>gz?>?rC>^>R=PG>gz?>?1ţHp#?R=PG>gz???=5>^>R=PG>gz?8>.a>=5>^>f'=L;)>gz?8>.a>1ţHp#?f'=L;)>gz???ԋ >ԋ >^>f'=L;)>gz?W>>ԋ >ԋ >^>L;)>f'=gz?W>>1ţHp#?L;)>f'=gz???5>=^>L;)>f'=gz? >6o>5>=^>PG>R=gz? >6o>1ţHp#?PG>R=gz???C>Hp#^>PG>R=gz??>5>^PG>Rgz ?6o>1ţHp#PG>Rgz??C>Hp#^PG>Rgz?>ԋ >ԋ ^L;)>f'gz$T?>1ţHp#L;)>f'gz??5>^L;)>f'gz ?6o>=5^f'=L;)gzdr?.a>1ţHp#f'=L;)gz??ԋ >ԋ ^f'=L;)gz$T?>3C^R=PGgz ??1ţHp#R=PGgz??=5^R=PGgzdr?.a>5^RPGgzdr?h ?1ţHp#RPGgz??3C^RPGgz ??ԋ ԋ ^f'L;)gz$T?7?1ţHp#f'L;)gz??5^f'L;)gzdr?h ?5^L;)f'gz ?d?1ţHp#L;)f'gz??ԋ ԋ ^L;)f'gz$T?7?Cf^PGRgz? ?1ţHp#PGRgz??5^PGRgz ?d?5=^PGR=gz >d?1ţHp#PGR=gz??Cf^PGR=gz? ?ԋ ԋ >^L;)f'=gzW>7?1ţHp#L;)f'=gz??5=^L;)f'=gz >d?5>^f'L;)>gz8>h ?1ţHp#f'L;)>gz??ԋ ԋ >^f'L;)>gzW>7?rC>^RPG>gz>?1ţHp#RPG>gz??5>^RPG>gz8>h ?=5>^R=PG>gz8>.a>1ţHp#R=PG>gz??rC>^R=PG>gz>?ԋ >ԋ >^f'=L;)>gzW>>1ţHp#f'=L;)>gz??=5>^f'=L;)>gz8>.a>5>=^L;)>f'=gz >6o>1ţHp#L;)>f'=gz??ԋ >ԋ >^L;)>f'=gzW>>C>Hp#^PG>R=gz?>1ţHp#PG>R=gz??5>=^PG>R=gz >6o>5>^>] ?^zS? ?6o>u=>ԋ >] ?^zS?$T?q>C>Hp#^>] ?^zS??>u=>ԋ >] ?UzS?$T?q>>Hp#>] ?UzS??>C>Hp#^>] ?UzS??>ԋ >ԋ ^>>v'zS?$T?>>>>v'zS?*?A>u=>ԋ >>v'zS?$T?q>u=>ԋ >>s'zS?$T?q>5>^>>s'zS? ?6o>ԋ >ԋ ^>>s'zS?$T?>ԋ >u=>v'>zS?:?6o>>>v'>zS?*?A>ԋ >ԋ ^>v'>zS?$T?>ԋ >ԋ ^>s'>zS?$T?>=5^>s'>zS?dr?.a>ԋ >u=>s'>zS?:?6o> >U=] zS?@??ԋ >u=>U=] zS?:?6o>=5^>U=] zS?dr?.a>=5^>_=] zS?dr?.a>3C^>_=] zS? ?? >_=] zS?@??5^>Uཊ] zS?dr?h ?ԋ u=>Uཊ] zS?:?d? >Uཊ] zS?@??5^>_ཊ] zS?dr?h ? >_ཊ] zS?@??3C^>_ཊ] zS? ??ԋ ԋ ^>v'zS?$T?7?>v'zS?*?_'2?ԋ u=>v'zS?:?d?ԋ ԋ ^>s'zS?$T?7?ԋ u=>s'zS?:?d?5^>s'zS?dr?h ?u=ԋ >v'zS?$T? v'zS?*?_'2?ԋ ԋ ^>v'zS?$T?7?ԋ ԋ ^>s'zS?$T?7?5^>s'zS? ?d?u=ԋ >s'zS?$T? ] UzS??@?u=ԋ >] UzS?$T? ] UzS? ?d?5^>] _zS? ?d?Cf^>] _zS?? ?D>] _zS??@?5=^>] U=zS? >d?u=ԋ >>] U=zS?W> ] U=zS??@?5=^>] _=zS? >d?D>] _=zS??@?Cf^>] _=zS?? ?ԋ ԋ >^>v'>zS?W>7?>>v'>zS?>_'2?u=ԋ >>v'>zS?W> ^>s'>zS?W>7?u=ԋ >>s'>zS?W> s'>zS? >d?5>^>s'>zS?8>h ?ԋ u=>>s'>zS?>d?ԋ ԋ >^>s'>zS?W>7?ԋ u=>>v'>zS?>d?>>v'>zS?>_'2?ԋ ԋ >^>v'>zS?W>7?rC>^>_ཊ] ?zS?>?'Ǥ>>_ཊ] ?zS?>?5>^>_ཊ] ?zS?8>h ?'Ǥ>>Uཊ] ?zS?>?ԋ u=>>Uཊ] ?zS?>d?5>^>Uཊ] ?zS?8>h ?=5>^>^=] ?zS?8>.a>ԋ >u=>>^=] ?zS?>6o>rC>^>^=] ?zS?>?ԋ >u=>>U=] ?zS?>6o>'Ǥ>>U=] ?zS?>?rC>^>U=] ?zS?>?ԋ >ԋ >^>v'>>zS?W>>>>>v'>>zS?>A>ԋ >u=>>v'>>zS?>6o>ԋ >u=>>s'>>zS?>6o>=5>^>s'>>zS?8>.a>ԋ >ԋ >^>s'>>zS?W>>5>=^>>s'>zS? >6o>u=>ԋ >>>s'>zS?W>q>ԋ >ԋ >^>>s'>zS?W>>u=>ԋ >>>v'>zS?W>q>>>>>v'>zS?>A>ԋ >ԋ >^>>v'>zS?W>>C>Hp#^>] ?_=zS??>>Hp#>] ?_=zS??>5>=^>] ?_=zS? >6o>>Hp#>] ?U=zS??>u=>ԋ >>] ?U=zS?W>q>5>=^>] ?U=zS? >6o>u=>ԋ >R?'Q ?$T?q>z>5C>R?'Q ?dr?a >^>Hp#C>R?'Q ??>^>Hp#C>R?'Q ??>>Hp#>R?'Q ??>u=>ԋ >R?'Q ?$T?q>>>D2?+Q ?*?A>u=>u=C>D2?+Q ?:?,>z>5C>D2?+Q ?dr?a >z>5C>D2?0Q ?dr?a >u=>ԋ >D2?0Q ?$T?q>>>D2?0Q ?*?A>5>zھC>+>D2Q ?WS?q>u=>u=C>+>D2Q ?:?,>>>+>D2Q ?*?A>>>0>D2Q ?*?A>ԋ >u=>0>D2Q ?:?6o>5>zھC>0>D2Q ?WS?q> >'>RQ ?@??"^C>'>RQ ?_??5>zھC>'>RQ ?WS?q> >'>RQ ?@??5>zھC>'>RQ ?WS?q>ԋ >u=>'>RQ ?:?6o>ԋ u=>'RQ ?:?d?5zھC>'RQ ?WS? 'RQ ?_??ԋ u=>'RQ ?:?d?"^C>'RQ ?_?? >'RQ ?@??>+D2Q ?*?_'2?u=u=C>+D2Q ?:?T?5zھC>+D2Q ?WS? 0D2Q ?*?_'2?5zھC>0D2Q ?WS? 0D2Q ?:?d?zھ5C>D2+Q ?dr?]?u=u=C>D2+Q ?:?T?>D2+Q ?*?_'2?>D20Q ?*?_'2?u=ԋ >D20Q ?$T? D20Q ?dr?]?^U]C>R'Q ??_?zھ5C>R'Q ?dr?]?u=ԋ >R'Q ?$T? R'Q ?$T? R'Q ??@?^U]C>R'Q ??_?u=ԋ >>R'>Q ?W> C>R'>Q ?8>]?^U]C>R'>Q ??_?u=ԋ >>R'>Q ?W> R'>Q ??_?D>R'>Q ??@?>>D2+>Q ?>_'2?u=u=>C>D2+>Q ?>T?zھ5>C>D2+>Q ?8>]?>>D20>Q ?>_'2?zھ5>C>D20>Q ?8>]?u=ԋ >>D20>Q ?W> >0D2?Q ?>d?5z>C>0D2?Q ?%2> >0D2?Q ?>_'2?5z>C>+D2?Q ?%2> C>+D2?Q ?>T?>>+D2?Q ?>_'2?'Ǥ>>'R?Q ?>?Z^>C>'R?Q ?>?ԋ u=>>'R?Q ?>d?Z^>C>'R?Q ?>?5z>C>'R?Q ?%2> >'R?Q ?>d?ԋ >u=>>'>R?Q ?>6o>5>z>C>'>R?Q ?%2>q>'Ǥ>>'>R?Q ?>?5>z>C>'>R?Q ?%2>q>Z^>C>'>R?Q ?>?'Ǥ>>'>R?Q ?>?>>>+>D2?Q ?>A>u=>u=>C>+>D2?Q ?>,>5>z>C>+>D2?Q ?%2>q>5>z>C>0>D2?Q ?%2>q>ԋ >u=>>0>D2?Q ?>6o>>>>0>D2?Q ?>A>u=>ԋ >>D2?0>Q ?W>q>z>5>C>D2?0>Q ?8>a >>>>D2?0>Q ?>A>z>5>C>D2?+>Q ?8>a >u=>u=>C>D2?+>Q ?>,>>>>D2?+>Q ?>A>>Hp#>R?'>Q ??>^>Hp#C>R?'>Q ??>u=>ԋ >>R?'>Q ?W>q>^>Hp#C>R?'>Q ??>z>5>C>R?'>Q ?8>a >u=>ԋ >>R?'>Q ?W>q>z>5C>eov?yDlD>dr?a >^>CӉY$eov?yDlD> ?!{8?Hp#ӉY$eov?yDlD>??Hp#ӉY$eov?kDyD>?^>Hp#C>eov?kDyD>?>z>5C>eov?kDyD>dr?a >>ӉY$P?# mD>@?^>CӉY$P?# mD> ?!{8z>5C>P?# mD>dr?a >z>5C>P?# kD>dr?a >u=>u=C>P?# kD>:?,>>ӉY$P?# kD>@?C>^ӉY$# ?PkD>_?6G9>ӉY$# ?PkD>@?u=>u=C># ?PkD>:?,>u=>u=C># ?PmD>:?,>5>zھC># ?PmD>WS?q>C>^ӉY$# ?PmD>_?6G9)#ӉY$yD>eovlD>??C>^ӉY$yD>eovlD>_?6G95>zھC>yD>eovlD>WS?q>5>zھC>kD>eovyD>WS?q>"^C>kD>eovyD>_??)#ӉY$kD>eovyD>??5zھC>yDeovlD>WS? _??)#ӉY$yDeovlD>??5zھC>kDeovyD>WS? ??"^C>kDeovyD>_??u=u=C># PkD>:?T?ӉY$# PkD>@??C^ӉY$# PkD>_??C^ӉY$# PmD>_??5zھC># PmD>WS? # PmD>:?T?^CӉY$P# kD> ??ӉY$P# kD>@??u=u=C>P# kD>:?T?u=u=C>P# mD>:?T?zھ5C>P# mD>dr?]?^CӉY$P# mD> ??rӉY$eovyDlD>??^CӉY$eovyDlD> ??zھ5C>eovyDlD>dr?]?zھ5C>eovkDyD>dr?]?^U]C>eovkDyD>?_?rӉY$eovkDyD>??zھ5>C>eovyD>lD>8>]?^C>ӉY$eovyD>lD>>?rӉY$eovyD>lD>??zھ5>C>eovkD>yD>8>]?rӉY$eovkD>yD>??^U]C>eovkD>yD>?_?>ӉY$P# ?mD>>?^C>ӉY$P# ?mD>>?zھ5>C>P# ?mD>8>]?zھ5>C>P# ?kD>8>]?u=u=>C>P# ?kD>>T?>ӉY$P# ?kD>>?C^>ӉY$# P?kD>>?>ӉY$# P?kD>>?u=u=>C># P?kD>>T?u=u=>C># P?mD>>T?5z>C># P?mD>%2> ӉY$# P?mD>>??ӉY$yDeov?lD>C^>ӉY$yDeov?lD>>?5z>C>yDeov?lD>%2> C>kDeov?yD>%2> C>kDeov?yD>>??ӉY$kDeov?yD>5>z>C>yD>eov?lD>%2>q>C>^>ӉY$yD>eov?lD>>6G9?ӉY$yD>eov?lD>?ӉY$kD>eov?yD>Z^>C>kD>eov?yD>>?5>z>C>kD>eov?yD>%2>q>>>ӉY$# ?P?mD>>!{8C>^>ӉY$# ?P?mD>>6G95>z>C># ?P?mD>%2>q>5>z>C># ?P?kD>%2>q>u=>u=>C># ?P?kD>>,>>>ӉY$# ?P?kD>>!{8z>5>C>P?# ?mD>8>a >^>C>ӉY$P?# ?mD>>!{8>>ӉY$P?# ?mD>>!{8>>ӉY$P?# ?kD>>!{8u=>u=>C>P?# ?kD>>,>z>5>C>P?# ?kD>8>a >?Hp#ӉY$eov?yD>lD>?^>C>ӉY$eov?yD>lD>>!{8z>5>C>eov?yD>lD>8>a >z>5>C>eov?kD>yD>8>a >^>Hp#C>eov?kD>yD>?>?Hp#ӉY$eov?kD>yD>?^>CӉY$fov?kDkD ?!{8z>5Cfov?kDkDdr?a >^>Hp#Cfov?kDkD?>^>Hp#Ceov?xDxD?>?Hp#ӉY$eov?xDxD?^>CӉY$eov?xDxD ?!{8u=>u=CP?# mD:?,>z>5CP?# mDdr?a >^>CӉY$P?# mD ?!{8^>CӉY$P?# kD ?!{8>ӉY$P?# kD@?u=>u=CP?# kD:?,>5>zھC# ?PkDWS?q>u=>u=C# ?PkD:?,>>ӉY$# ?PkD@?>ӉY$# ?PmD@?C>^ӉY$# ?PmD_?6G95>zھC# ?PmDWS?q>)#ӉY$kD>eovyD??"^CkD>eovyD_??5>zھCkD>eovyDWS?q>5>zھCyD>eovlDWS?q>C>^ӉY$yD>eovlD_?6G9)#ӉY$yD>eovlD??5zھCkDeovyDWS? CeovkD>yD8>]?^U]CeovkD>yD?_?rӉY$eovkD>yD??rӉY$eovyD>lD??^C>ӉY$eovyD>lD>?zھ5>CeovyD>lD8>]?u=u=>CP# ?mD>T?zھ5>CP# ?mD8>]?^C>ӉY$P# ?mD>?^C>ӉY$P# ?kD>?>ӉY$P# ?kD>?u=u=>CP# ?kD>T?5z>C# P?kD%2> C# P?kD>T?>ӉY$# P?kD>?>ӉY$# P?mD>?C^>ӉY$# P?mD>?5z>C# P?mD%2> CkDfov?kD>?5z>CkDfov?kD%2> ӉY$kDfov?kD>?C^>ӉY$xDeov?xD>??ӉY$xDeov?xDZ^>CxDeov?xD>?5>z>CkD>eov?yD%2>q>Z^>CkD>eov?yD>??ӉY$kD>eov?yD?ӉY$yD>eov?lDC>^>ӉY$yD>eov?lD>6G95>z>CyD>eov?lD%2>q>u=>u=>C# ?P?mD>,>5>z>C# ?P?mD%2>q>C>^>ӉY$# ?P?mD>6G9C>^>ӉY$# ?P?kD>6G9>>ӉY$# ?P?kD>!{8u=>u=>C# ?P?kD>,>z>5>CP?# ?kD8>a >u=>u=>CP?# ?kD>,>>>ӉY$P?# ?kD>!{8>>ӉY$P?# ?mD>!{8^>C>ӉY$P?# ?mD>!{8z>5>CP?# ?mD8>a >^>Hp#Cfov?kD>kD?>z>5>Cfov?kD>kD8>a >^>C>ӉY$fov?kD>kD>!{8^>C>ӉY$eov?xD>xD>!{8?Hp#ӉY$eov?xD>xD?^>Hp#Ceov?xD>xD?>z>5CR?'Q dr?a >u=>ԋ R?'Q $T?q>^>Hp#CR?'Q ?>u=>ԋ R?'Q $T?q>>Hp#R?'Q ?>^>Hp#CR?'Q ?>u=>u=CD2?+Q :?,>>D2?+Q *?A>z>5CD2?+Q dr?a >>D2?0Q *?A>u=>ԋ D2?0Q $T?q>z>5CD2?0Q dr?a >5>zھC0>D2Q WS?q>ԋ >u=0>D2Q :?6o>>0>D2Q *?A>5>zھC+>D2Q WS?q>>+>D2Q *?A>u=>u=C+>D2Q :?,>"^C'>RQ _?? '>RQ @??ԋ >u='>RQ :?6o>"^C'>RQ _??ԋ >u='>RQ :?6o>5>zھC'>RQ WS?q>ԋ u='RQ :?d? 'RQ @??"^C'RQ _??"^C'RQ _??5zھC'RQ WS? R'>Q W> Q ?@?^U]CR'>Q ?_?^U]CR'>Q ?_?zھ5>CR'>Q 8>]?u=ԋ >R'>Q W> D20>Q >_'2?u=ԋ >D20>Q W> CD20>Q 8>]?zھ5>CD2+>Q 8>]?u=u=>CD2+>Q >T?>D2+>Q >_'2?5z>C0D2?Q %2> 0D2?Q >d?>0D2?Q >_'2?>+D2?Q >_'2?u=u=>C+D2?Q >T?5z>C+D2?Q %2> C'R?Q >?'Ǥ>'R?Q >?ԋ u=>'R?Q >d?ԋ u=>'R?Q >d?5z>C'R?Q %2> C'R?Q >?5>z>C'>R?Q %2>q>ԋ >u=>'>R?Q >6o>'Ǥ>'>R?Q >?'Ǥ>'>R?Q >?Z^>C'>R?Q >?5>z>C'>R?Q %2>q>u=>u=>C+>D2?Q >,>>>+>D2?Q >A>5>z>C+>D2?Q %2>q>>>0>D2?Q >A>ԋ >u=>0>D2?Q >6o>5>z>C0>D2?Q %2>q>z>5>CD2?0>Q 8>a >u=>ԋ >D2?0>Q W>q>>>D2?0>Q >A>>>D2?+>Q >A>u=>u=>CD2?+>Q >,>z>5>CD2?+>Q 8>a >^>Hp#CR?'>Q ?>>Hp#R?'>Q ?>u=>ԋ >R?'>Q W>q>u=>ԋ >R?'>Q W>q>z>5>CR?'>Q 8>a >^>Hp#CR?'>Q ?>u=>ԋ ] ?^zS$T?q>5>^쾉] ?^zS ?6o>C>Hp#^쾉] ?^zS?>C>Hp#^쾊] ?UzS?>>Hp#] ?UzS?>u=>ԋ ] ?UzS$T?q>>>v'zS*?A>ԋ >ԋ ^>v'zS$T?>u=>ԋ >v'zS$T?q>ԋ >ԋ ^>s'zS$T?>5>^>s'zS ?6o>u=>ԋ >s'zS$T?q>ԋ >u=s'>zS:?6o>=5^s'>zSdr?.a>ԋ >ԋ ^s'>zS$T?>ԋ >u=v'>zS:?6o>ԋ >ԋ ^v'>zS$T?>>v'>zS*?A> _=] zS@??3C^_=] zS ??=5^_=] zSdr?.a> U=] zS@??=5^U=] zSdr?.a>ԋ >u=U=] zS:?6o>5^_ཊ] zSdr?h ?3C^_ཊ] zS ?? _ཊ] zS@?? Uཊ] zS@??ԋ u=Uཊ] zS:?d?5^Uཊ] zSdr?h ?ԋ ԋ ^s'zS$T?7?5^s'zSdr?h ?ԋ u=s'zS:?d?ԋ u=v'zS:?d?v'zS*?_'2?ԋ ԋ ^v'zS$T?7?u=ԋ s'zS$T? d?Cf^쾊] _=zS? ?D] _=zS?@?D] U=zS?@?u=ԋ >] U=zSW> d?ԋ ԋ >^s'>zSW>7?5=^s'>zS >d?u=ԋ >s'>zSW> v'>zSW> v'>zS>_'2?ԋ ԋ >^v'>zSW>7?ԋ u=>s'>zS>d?5>^s'>zS8>h ?ԋ ԋ >^s'>zSW>7?ԋ ԋ >^v'>zSW>7?>v'>zS>_'2?ԋ u=>v'>zS>d?'Ǥ>_ཊ] ?zS>?rC>^_ཊ] ?zS>?5>^_ཊ] ?zS8>h ?5>^Uཊ] ?zS8>h ?ԋ u=>Uཊ] ?zS>d?'Ǥ>Uཊ] ?zS>?ԋ >u=>^=] ?zS>6o>=5>^^=] ?zS8>.a>rC>^^=] ?zS>?rC>^U=] ?zS>?'Ǥ>U=] ?zS>?ԋ >u=>U=] ?zS>6o>>>v'>>zS>A>ԋ >ԋ >^v'>>zSW>>ԋ >u=>v'>>zS>6o>ԋ >ԋ >^s'>>zSW>>=5>^s'>>zS8>.a>ԋ >u=>s'>>zS>6o>u=>ԋ >>s'>zSW>q>5>=^>s'>zS >6o>ԋ >ԋ >^>s'>zSW>>ԋ >ԋ >^>v'>zSW>>>>>v'>zS>A>u=>ԋ >>v'>zSW>q>>Hp#] ?_=zS?>C>Hp#^쾊] ?_=zS?>5>=^쾊] ?_=zS >6o>5>=^쾊] ?U=zS >6o>u=>ԋ >] ?U=zSW>q>>Hp#] ?U=zS?>@"\\\\?\?\??JJa6;Qe<$;κe<:$e< Q:a6e< Qa6e<κ$e<$κe< a6Qe<  a6Q:e<  $:e<  κ$;e<!"#  Qa6;e<$%& Q:a6;e<'():$;e<*+,$;:e<-./a6;Q:e<012a6;Qe345$;κe678:$e9:;Q:a6e<=>Qa6e?@Aκ$eBCD$κeEFGa6QeHIJa6Q:eKLM$:eNOPκ$;eQRSQa6;eTUVQ:a6;eWXY :$;eZ[\! $;:e]^_!a6;Q:e`ab"<κB<cde"#Cp<*?^ʳ<Tfgh$"K- ^ʳ=-j纻X<<Ӌ  /?. ;^ʳ.j;X<<Ӌ0@?<#%<<Ջ?/0K?@8HG|䩼C;ABCG78Yw;ԋDEFIH8C|䩼;GHI89IZw;ԋJKLJI9&;MNO9:Jԋ wܻw;ԋPQR;KJ&;;STU;J:ԋ w;w;ԋVWXLK;C|<;YZ[;<LZNwܻԋ =w;ԋhij?ON&;=;klmN>?w;ԋ =w;ԋnopPO?|<C<;qrs?@P?qaSX/-011220345367869:;9<=><?@A?BCDBEFGEHIJHKLMKNOPNQRSQTUVTWX YW Z[!\Z !_]! #`a" !ab"!Acd"#!>de#"$fg$"Cgh$""#hf"$Elm%$$%nl%%&pq%&Grs&%&'tr&')vw&(+xy'(Iyz'&()zx&*,~(*K('*+~',M)(,-)-.).O*)./*/1 *03 +0Q+*01* 25 ,2S,+23+ 47 -45- 5T-,69 .67. 7V.-8;/89/ 9X/.:=0:[0/:;/<?1<=1=\10>?#?^#1@C"2@a23@A3"A^3#BD$4Bc42BC2$De54DE$5EG%5FI&6Fg65FG5&HK'7Hi76HI6'JL(8Jk87JK7(Lm98LM(9MN)9No:9NO):OQ*:PS+;Pq;:PQ:+RU,<Rs<;RS;,TW-=TU=,Uu=<VY.>VW>-Ww>=X[ /?XY  ?.Yy  ?>Z]0@Z{@?Z[?0\_1A\]A0]}A@^_31_3A`b !2B`!"BC`a" C2a#$C3b&'DBbc(&2Dcd*+4Dd,-EDde.,4Eef015Ef23FEfg425Fgi676Fhk897Gh9:GFhi:8F7jl>?8Hj?@HGjk@>G8lDEIHlmFD8ImnHI9InJKJInoLJ9JoqNO:JprPQ;KpQRKJpqRPJ;rVWLKrsXV;LstZ[<Lt\]MLtu^\<Muv`a=MvbcNMvwdb=Nwyfg>Nxzhi?OxijONxyjhN?znoPOz{pn?P{}rs@P|~tuAQ|uvQP|}vtPA~z{CQ~|zACBRRSSBSCTRBTDTUTDUEUFVVUUFWVFWGWXWGXHXIYYXXIJZZYYJ[ZJ[K[\[K\L\]\L]M]^]M^N^_^N_O_`_O`P`a`PaQaSaQSRbbSbccSTddRdbUeeddUVffeeVgfVgWghgWhXhYiihhY  Zj  ji  iZkjZk[klk[l\l]mmll]"#^n#$nm$"m^()_o)*on*(n_./`p/0p_12po45aq56qp64pa;<cq<:qS@AbB@bCDcFGdGHbLMeNLeRSfTRfZXf\]g`^gbchdeifdijkjljjrpjtukxvkz{l|}m~|mnnoop  oq! q!crviz-1.12.4/ogre_media/plugins.cfg000066400000000000000000000000771300447110700170270ustar00rootroot00000000000000# dummy plugins.cfg, needed so Ogre does not throw an exceptionrviz-1.12.4/ogre_media/textures/000077500000000000000000000000001300447110700165445ustar00rootroot00000000000000rviz-1.12.4/ogre_media/textures/no_image.png000066400000000000000000000204251300447110700210330ustar00rootroot00000000000000PNG  IHDR,ǀsRGBbKGD pHYs  tIME :&tEXtCommentCreated with GIMPW IDATxixELnr @ Ӏj@Q# CևE9֭[G/aRVVVieggKtt4[ +wfKԴ*++矗"H$~~~v˒dŊl- }/jbbbu㹻KTT~v333eڵVqu?QqqqgR-7f7ATTl߾]nj|Μ92bo+R:$ riIII)**'''򒀀曥O>rJ޽ku(d2e۶mrA9udggK~~Jv$,,LNyG$((˛"wÇKRRIaaJǎ{)=iӦ3gr 9wKnnxzzJ۶msҳgOeذa, "}$$$ȩS$==]d2K߾};ѣG7hj 999 sɅ $??_JJJYSNr7ˀn4"馛wIމ'6xY/_<r:HJJRk׮UC m_~ .(99Y3Μ9afϟWk׮U{Ӷ޽Zvxbѣj…* N 8Pƪng k?{?I%$$F~'~z5p:/wddUW\޵kjݼyYf̘:vXmﯢվ}Taaa<64@RJUV)٬O>E?>۠/@5eue~~~ R5|ծ]ty+55U 6Lyzz6ݻGMrrrʕ+U߾}U G\\\Tn(ܹsU```sjÆ {ݺu_tX͛7OuEL&C S? RJW7@P/a;W۶m֭[UUUT@:뮻  .TV2(wwwC۵kaDѯH}̙3gϞ/SO=-*++U||CN}s=ufׄ R^ 5rFL&5gUQQA RJ>}Zu!aٲej!M-DDuweк{@*))QO>dm`_H5RJ꫚Ӻukm۶fCV ᡦMvء2URRRRRT\\7nrrrU]WC@_wNN%Pl2233UyyUOV6lP սիWk :tZfoUNN*//W?:zZr g233H]vUԚ5k_|U^^ZDedd'NX5{lչsZ*))ɐ}oUnnnj7 @͟?_۷OeddreX֭[դIݿ>|Z~jZI^?ۧ~GTVV/ŋUhhh; HVUxl@*//W#Fq'P7nY7/ՃWC7r 㺓huZ՝to*ժ+֭zk}o߾}'6&I1ۤk׮JD>|Zxڿ%Ț={V-[LuMw[? ^cI5d6bbbmv݁SN O}xʕҥKѣW...dI/Rȑ#<-[֬iΜ95^^{5jСfzjW޽=8_-M>ԩStddܸqmiӦ\"##Ն TVVV#\tI͝;Ww;| jꭷ޲;²6=3fԺҐ@;j媴mݻWy{{kuF HjѢE۩S:رc5= t.u={^_gy=@5s苊4Gf5uza,Xy5jTG]>ժU+o7x̚5ˡpB{iv֭lÇk^ /HzFEEDDhUQQQү~ 2Đu;l6)SHv^>>>*11#55V#GUUU6mڤƠATNNN[,?~xIt9s ÇwH 9rA6{1t{ݻ}k}5O\*3fМVh˖-w&]?\Μ9Y$!mnZvܩY^UU%$oYfI߾}\OHH}ݺ Yfid_[&I  7tl}jJq͙KlusY$oa!..Nf[lT%KHddm>\&Nhw6bz sK:L6M 9Ǵiʕ+M|7nr3fH۶m k/""BFY* $5ew}8PFeH[~~~a,77WҚ5jf } $"fypp!3ksvJKK姟~T[7oN:-ʒgyFF[L)--,4hC=zhrCϜ[Csss,3͆?~Al.= -r1Yp|7mHRVVh'ZԧtymۊVeL&-ZE VPPYF~i_̝;wJ||h\rE >@X,bXHkp#.9ҦM7ސo/k~~n;ꈳn/.***$##Co={:|]LN)u`&LмF/oύ,zgkL&iݺ{Ԁ<2iҤF9ZfIeeeK^ވa???YdjnyBBFyxx8Fq)7;v2j(ygwߕ9wHeeG5BCC ;k!>5qqn஻Yfw_eȑ-w/AD$//amtQtZJmۦY)V.]H6mhoBUW\]:7QPP(ԚRfL>]yyy|rF~Q_lnp8r䈼ۚ˗//B/@]XQɪ0,t3N>=OGgXaaa2sLKw~aSh =kKIIqHeeerE6mx =VU>s{'OEfVVaCŃtJ nbݑqu*钓ӤIc7l2x`8qDvA5\]8(**ǏkwСSXX9eM``<<~xj{C/'N0.www ~i>̺u4dVTTȄ v^t{"  <ݳP-Sii52x`ܷoa'_ΜR_iiilH]^^^SO:uʐHM$$$D^yO?Tbbbv׮]u5f۷^ѣGXjj м]_.]oưKv[}jξ]UU%W63s+WWW4hU&b;Cs']h8d1c x mb~dС}q޺#L~?i$񫯾jܹsgg[uaa9vԒؽᩔ y+3f(11Q^uڛ?\|Y<<<\ tSWOիWCx@whwQQ<Æ(zȵ:w,G ֪*6mG H,?4 w![l1]OOO={{,YbMя>H.ɓD9dzz|駆)f24வfJϟv~kN`PQQQ2p@d$&&6(&N!CSO=ővyyyi\())7xAȉ'd̘1522RN۳y$::^?NOJJۡl۶KN8!Ç;l98 sΕ[ov|^<3n2O?T鶫:tP=sLiFթު*5|[*..VUrrϜ9Amsfg)**l+88u~z,YRbccuC``:x`sҥյN߹zU\\WcڵSk׮U駟V^^^Wvmm,]6&&&O _y\\\(//&;6ЁRfj@RJ>@999Nddھ}:{*((.rssթS;CnQ}jH/^Tw}wԄ Ԟ={GRbtuab ծ];̙3GHJ)k6LP/U;wT;vPZ`;4vjӦMRUURJիW*ȝ֭[UbbxIjUyyy*--M%&&]vKjxS aw^~;P[=Kttm۶/sϕKqq\|VӕkNv%j$=r%JlljJ\\\d2IeeJAA\|Ysf#Gk&;wtcqwQ>!::Z֬Y#6lоb]Cyӧ7Nw=l6ٲelٲEW]\\\l6RJl6KYYX,),,loRJ[5^2t:uT^Z]^}Uɪ%#پ}栦7n:tH,XPZL&aС޽[nڨǮ޽{ܹs!9RctZ999jʔ)ŸKrCj^=kc;ã>Vum8t-ͦOQO6m$5>b8dyڴi#ׯ7|Sm& "'JE|}}_:v(={{W{V-cƌ;Yee 0A?i^,=݉uҮ]رc;ZҧOm2dԩ2eټyٳGΜ9#s#M&tA$22R}Q͙njcvf֭lܸQ6n(>^d׮]_ٳg˗/W7xyyK%<<\*C qNⱅMƲ2Zb٪c6Y]xb?+**OfsݥUVȑ#̙3vC?[nQRJJJTVTTTHUUUd28;;Kq9o'~k|%T<==u[ . #%6Y|||Yfv3f+W-sqq~9d jᣏ>}-3l"W ied2I޽<DBB[׻j*;vsR5: oŋe̙ /$&&b^r6l< yŋ%<< `}!lܸQ|;;;K.]$$$Dz%}JI͕ILLɓ'5>r=**J{;þܐ*++%99Ye޽ʺu#&\]]eɒ%yf)@ o J^X=$7L ;vL6o,G4ʒz&!!!!'O{wM @핕I^^KJJ|wӥHxzzJPPH߾}eРAҽ{wi׮C&h @@HH  @ @ $$ @@HH  @ @ $$ @@HH  @ @ $$ @@HH  @ @ $$ @@HH  @ @ $$ @@HH  @ @ $$$=!dIDAT @@HH  @ @ $$ @@H46eMIENDB`rviz-1.12.4/package.xml000066400000000000000000000065131300447110700147100ustar00rootroot00000000000000 rviz 1.12.4 3D visualization tool for ROS. David Gossow William Woodall BSD Creative Commons Dave Hershberger David Gossow Josh Faust http://ros.org/wiki/rviz https://github.com/ros-visualization/rviz https://github.com/ros-visualization/rviz/issues catkin assimp-dev cmake_modules eigen geometry_msgs image_transport interactive_markers laser_geometry libogre-dev qtbase5-dev libqt5-opengl-dev map_msgs message_filters nav_msgs pluginlib python_qt_binding resource_retriever rosbag rosconsole roscpp roslib rospy sensor_msgs std_msgs std_srvs tf tinyxml urdf visualization_msgs yaml-cpp opengl liburdfdom-headers-dev assimp eigen geometry_msgs image_transport interactive_markers laser_geometry libogre-dev libqt5-core libqt5-gui libqt5-widgets libqt5-opengl map_msgs media_export message_filters nav_msgs pluginlib python_qt_binding resource_retriever rosbag rosconsole roscpp roslib rospy sensor_msgs std_msgs std_srvs tf tinyxml urdf visualization_msgs yaml-cpp opengl liburdfdom-headers-dev rviz-1.12.4/plugin_description.xml000066400000000000000000000340271300447110700172170ustar00rootroot00000000000000 Displays an axis at the Target Frame's origin. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Axes">More Information</a>. Displays point clouds based on depth maps. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/DepthCloud">More Information</a>. sensor_msgs/Image sensor_msgs/CompressedImage theora_image_transport/Packet Displays from sensor_msgs/JointState/effort messages. sensor_msgs/JointState Displays from sensor_msgs/FluidPressure messages. sensor_msgs/FluidPressure Displays a grid along the ground plane, centered at the origin of the target frame of reference. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Grid">More Information</a>. Displays data from a nav_msgs::GridCells message as billboards. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/GridCells">More Information</a>. nav_msgs/GridCells Displays illuminance values from a sensor_msgs/Illuminance topic. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Illuminance">More Information</a>. sensor_msgs/Illuminance Displays an image from a sensor_msgs/Image topic, similar to image_view. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Image">More Information</a>. sensor_msgs/Image sensor_msgs/CompressedImage theora_image_transport/Packet Connects to one or more Interactive Marker servers, allowing you to interact with the provided 3D objects. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/InteractiveMarker">More Information</a>. visualization_msgs/InteractiveMarkerUpdate Displays the data from a sensor_msgs::LaserScan message as points in the world, drawn as points, billboards, or cubes. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/LaserScan">More Information</a>. sensor_msgs/LaserScan Displays an occupancy grid on the ground plane from a nav_msgs::OccupancyGrid. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Map">More Information</a>. nav_msgs/OccupancyGrid Displays visualization_msgs::Marker messages. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Marker">More Information</a>. visualization_msgs/Marker Displays visualization_msgs::MarkerArray messages without presuming the topic name ends in "_array". <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Marker">More Information</a>. visualization_msgs/MarkerArray Accumulates and displays poses from a nav_msgs::Odometry message. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Odometry">More Information</a> nav_msgs/Odometry Displays data from a nav_msgs::Path message as lines. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Path">More Information</a>. nav_msgs/Path Displays from geometry_msgs/PointStamped message geometry_msgs/PointStamped Displays a point cloud from a sensor_msgs::PointCloud message as points in the world, drawn as points, billboards, or cubes. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/PointCloud">More Information</a>. sensor_msgs/PointCloud Displays a point cloud from a sensor_msgs::PointCloud2 message as points in the world, drawn as points, billboards, or cubes. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/PointCloud2">More Information</a>. sensor_msgs/PointCloud2 Displays data from a geometry_msgs::PolygonStamped message as lines. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Polygon">More Information</a>. geometry_msgs/PolygonStamped Displays a geometry_msgs::PoseStamped message. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Pose">More Information</a>. geometry_msgs/PoseStamped Displays the poses from a geometry_msgs::PoseArray message as a cloud of arrows on the ground plane. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/PoseArray">More Information</a> geometry_msgs/PoseArray Displays the data from sensor_msgs::Range messages as cones. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Range">More Information</a> sensor_msgs/Range Displays the data from sensor_msgs::RelativeHumidity. sensor_msgs/RelativeHumidity Displays a visual representation of a robot in the correct pose (as defined by the current TF transforms). <a href="http://www.ros.org/wiki/rviz/DisplayTypes/RobotModel">More Information</a>. Displays an image from a camera, with the visualized world rendered behind it. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/Camera">More Information</a>. sensor_msgs/Image sensor_msgs/CompressedImage theora_image_transport/Packet Transforms the point cloud data into XYZ coordinates to position each point. Transforms the color of each point based on its "intensity" value. Sets the color of each point based on RGB8 data. Sets the color of each point based on RGBF32 data. Sets the color of each point to be a single flat color. Sets the color of each point based on its position along one of the X, Y, or Z axes. Displays from sensor_msgs/Temperature message sensor_msgs/Temperature Displays the TF transform hierarchy. <a href="http://www.ros.org/wiki/rviz/DisplayTypes/TF">More Information</a>. Displays from geometry_msgs/WrenchStamped message geometry_msgs/WrenchStamped Allows you to click on a point and publish it as a PointStamped message. Click onto any object to focus the camera there. Click onto two locations to measure their distance. Drag the mouse with left, middle, or right buttons to change your viewpoint. Drag with the left button to select objects in the 3D scene. Hold the Alt key to change viewpoint as in the Move tool. Publish a goal pose for the robot. After one use, reverts to default tool. Publish an initial pose for the robot. After one use, reverts to default tool. Interact with interactive markers. Mouse actions not on interactive markers fall back to moving the camera. Makes it easy to move around a given point in space, looking at it from any angle. Makes it easy to move around a given point on the XY plane, looking at it from any angle. Follow a target frame and turn the viewing direction with the yaw of the target frame. Control the camera like in a First Person Shooter game: drag left to look left, etc. Orthographic projection, seen from the top. rviz-1.12.4/rosdoc.yaml000066400000000000000000000002571300447110700147470ustar00rootroot00000000000000- builder: doxygen name: C++ API output_dir: c++ file_patterns: '*.cpp *.h *.dox' - builder: sphinx name: User's Guide sphinx_root_dir: doc output_dir: user_guide rviz-1.12.4/rviz.sublime-project000066400000000000000000000031311300447110700166040ustar00rootroot00000000000000{ "folders": [ { "path": "." } ], "settings": { "sublimeclang_options": [ "-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1", "-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/7.3.0/include", "-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", "-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include", "-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks", // "-framework QtCore", // "-framework QtGui", // "-I/usr/local/Cellar/qt/4.8.6/lib/QtCore.framework/Versions/4/Headers", // "-I/usr/local/Cellar/qt/4.8.6/lib/QtGui.framework/Versions/4/Headers", "-I/usr/local/Cellar/qt5/5.5.1_2/include", "-I/usr/local/Cellar/qt5/5.5.1_2/Frameworks/QtCore.framework/Versions/Current/Headers", "-I/usr/local/Cellar/qt5/5.5.1_2/Frameworks/QtGui.framework/Versions/Current/Headers", "-I/usr/local/Cellar/qt5/5.5.1_2/Frameworks/QtWidgets.framework/Versions/Current/Headers", "-I/usr/local/Cellar/ogre-1.9/1.9.0/include", "-I/usr/local/Cellar/ogre-1.9/1.9.0/include/OGRE", "-I/usr/local/Cellar/ogre-1.9/1.9.0/include/OGRE/Overlay", "-I/Users/william/rviz_ws/install_isolated/include", "-I${folder:${project_path:rviz.sublime-project}}/src", "-I${folder:${project_path:rviz.sublime-project}}/src/rviz", "-DROS_PACKAGE_NAME=\"rviz\"", "-Wno-deprecated-register", ] } } rviz-1.12.4/scripts/000077500000000000000000000000001300447110700142555ustar00rootroot00000000000000rviz-1.12.4/scripts/choose-master.py000077500000000000000000000320531300447110700174060ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2008, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Willow Garage, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import sys import os import os.path import xmlrpclib import signal import subprocess from PySide.QtGui import * from PySide.QtCore import * def sigintHandler( signal, frame ): QApplication.quit() # Return an array of node names, or None on error (like if the master doesn't exist). def getNodesOnMaster( master_uri ): try: proxy = xmlrpclib.ServerProxy( master_uri ) state = proxy.getSystemState("") if state[0] != 1: return None nodes = [] for s in state[2]: for t, l in s: nodes.extend(l) return list(set(nodes)) except: return None # Return an array of recently-used master URIs read from a file, or empty array if none. def readRecentMasters(): masters = set() try: filename = os.path.expanduser('~/.ros/recent_masters') if os.path.exists( filename ): with open( filename ) as file: for line in file: line = line.strip() if len( line ) > 0: masters.add( line ) except: pass return masters # Replace the recent_masters file with the contents of master_uris, # which should be a set of strings. def writeRecentMasters( master_uris ): try: filename = os.path.expanduser('~/.ros/recent_masters') dirname = os.path.dirname( filename ); if not os.path.isdir( dirname ): os.makedirs( dirname ) with open( filename, 'w' ) as file: for master_uri in master_uris: file.write( master_uri + '\n' ) except: pass # Thread continually runs, checking for a given master over and over # while self.scan is True. When self.scan is False, keeps looping but # does not check for the master. # # When it gets an answer for a master, emits signal foundValidMaster # or foundInvalidMaster. class ScannerThread( QThread ): foundValidMaster = Signal( str, object ) foundInvalidMaster = Signal( str ) def __init__( self, master_uri ): super(ScannerThread, self).__init__() self.master_uri = master_uri self.scan = True def run( self ): while True: if self.scan: nodes = getNodesOnMaster( self.master_uri ) if( nodes ): self.foundValidMaster.emit( self.master_uri, nodes ) else: self.foundInvalidMaster.emit( self.master_uri ) QThread.msleep( 500 ) class MasterURIItem(QTableWidgetItem): def __init__( self, text, valid ): super(MasterURIItem, self).__init__( text ) self.valid = valid self.my_text = text def __lt__( self, other ): if self.valid == other.valid: return (self.my_text < other.my_text) elif self.valid: return True else: return False class DeleteButton( QToolButton ): masterClicked = Signal( str ) def __init__( self, master_uri, parent=None ): super( DeleteButton, self ).__init__( parent ) self.setIcon( QIcon( ":/trolltech/styles/commonstyle/images/standardbutton-close-32.png" )) self.master_uri = master_uri self.clicked.connect( self.onClick ) def onClick( self ): self.masterClicked.emit( self.master_uri ) class ChooserDialog(QDialog): def __init__(self, program, master_from_environ, parent=None): super(ChooserDialog, self).__init__(parent) self.program = program program_name = os.path.basename( program ) main_layout = QVBoxLayout() main_layout.addWidget( QLabel( "Choose a ROS master to start " + program_name )) self.table = QTableWidget( 0, 3, self ) self.table.setHorizontalHeaderLabels( ["Master URI", "Nodes", ""] ) self.table.horizontalHeader().setResizeMode( 0, QHeaderView.Stretch ) self.table.horizontalHeader().setResizeMode( 1, QHeaderView.Fixed ) self.table.horizontalHeader().resizeSection( 1, 60 ) self.table.horizontalHeader().setResizeMode( 2, QHeaderView.Fixed ) self.table.horizontalHeader().resizeSection( 2, 30 ) self.table.itemSelectionChanged.connect( self.onSelectionChange ) self.table.itemActivated.connect( self.start ) main_layout.addWidget( self.table ) start_program_layout = QHBoxLayout() start_program_layout.addStretch( 1000 ) self.start_button = QPushButton( "Start " + program_name ) self.start_button.setEnabled( False ) self.start_button.clicked.connect( self.start ) start_program_layout.addWidget( self.start_button ) main_layout.addLayout( start_program_layout ) bottom_layout = QHBoxLayout() add_label = QLabel( "http://" ) self.host_entry = QLineEdit("localhost") self.host_entry.setMinimumSize( 150, 10 ) self.host_entry.returnPressed.connect( self.addMaster ) colon_label = QLabel( ":" ) self.port_entry = QLineEdit("11311") self.port_entry.setMinimumSize( 100, 10 ) self.port_entry.returnPressed.connect( self.addMaster ) bottom_layout.addWidget( add_label ) bottom_layout.addWidget( self.host_entry ) bottom_layout.addWidget( colon_label ) bottom_layout.addWidget( self.port_entry ) add_button = QPushButton( "Add Master" ) add_button.clicked.connect( self.addMaster ) bottom_layout.addWidget( add_button ) main_layout.addLayout( bottom_layout ) self.setLayout( main_layout ) self.master_from_env = master_from_environ masters = readRecentMasters() self.master_to_scanner_map = {} for master in masters: self.addScanner( master ) self.show_timer = QTimer() self.show_timer.setSingleShot( True ) self.show_timer.timeout.connect( self.show ) self.show_timer.start( 200 ) def addScanner( self, master_uri ): if master_uri not in self.master_to_scanner_map: thread = ScannerThread( master_uri ) thread.foundValidMaster.connect( self.insertValidMaster, Qt.QueuedConnection ) thread.foundInvalidMaster.connect( self.insertInvalidMaster, Qt.QueuedConnection ) thread.start() self.master_to_scanner_map[ master_uri ] = thread def removeScanner( self, master_uri ): if master_uri in self.master_to_scanner_map: thread = self.master_to_scanner_map[ master_uri ] thread.scan = False thread.foundValidMaster.disconnect( self.insertValidMaster ) thread.foundInvalidMaster.disconnect( self.insertInvalidMaster ) del self.master_to_scanner_map[ master_uri ] print "waiting for thread", thread.master_uri, "to die." thread.wait(0) def setScanning( self, scanning ): for master, scanner in self.master_to_scanner_map.iteritems(): scanner.scan = scanning def onSelectionChange( self ): selection = self.table.selectedItems() self.start_button.setEnabled( len( selection ) == 1 ) def start( self ): selection = self.table.selectedItems() if len( selection ): self.setScanning( False ) self.hide() master = selection[0].text() print "running", self.program, "with master", master program_result = subprocess.call( [self.program, "--in-mc-wrapper", "__master:=" + master] ) if program_result == 255: selection[0].setSelected( False ) self.master_from_env = None self.show() self.setScanning( True ) else: self.close() def addMaster( self ): host = self.host_entry.text() port = self.port_entry.text() if len( host ) and len( port ): self.addScanner( 'http://' + host + ':' + port ) writeRecentMasters( self.master_to_scanner_map.keys() ) def addRow( self, master_uri, valid ): row = self.table.rowCount() self.table.insertRow( row ) items = [] # master URI item item = MasterURIItem( master_uri, valid ) self.table.setItem( row, 0, item ) items.append( item ) # node count item item = QTableWidgetItem() self.table.setItem( row, 1, item ) items.append( item ) # delete master item item = QTableWidgetItem() item.setFlags( Qt.NoItemFlags ) self.table.setItem( row, 2, item ) delete_button = DeleteButton( master_uri ) self.table.setCellWidget( row, 2, delete_button ) delete_button.masterClicked.connect( self.deleteMaster ) return items def insertValidMaster( self, master_uri, nodes ): old_item = self.itemForMaster( master_uri ) if old_item: if old_item.valid: return else: self.removeMasterFromTable( master_uri ) items = self.addRow( master_uri, True ) # master URI item items[0].setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable ) items[0].setSelected( self.master_from_env == master_uri ) if self.master_from_env == master_uri and not self.isVisible(): self.start() # node count item items[1].setFlags( Qt.NoItemFlags ) items[1].setBackground( Qt.white ) items[1].setText( str( len( nodes ))) self.table.sortItems( 0 ) def insertInvalidMaster( self, master_uri ): old_item = self.itemForMaster( master_uri ) if old_item: if old_item.valid: self.removeMasterFromTable( master_uri ) else: return items = self.addRow( master_uri, False ) # master URI item items[0].setFlags( Qt.NoItemFlags ) # node count item items[1].setFlags( Qt.NoItemFlags ) self.table.sortItems( 0 ) def itemForMaster( self, master_uri ): row = 0 while row < self.table.rowCount(): item = self.table.item( row, 0 ) if item.text() == master_uri: return item row += 1 return None def removeMasterFromTable( self, master_uri ): row = 0 while row < self.table.rowCount(): if self.table.item( row, 0 ).text() == master_uri: self.table.removeRow( row ) else: row += 1 def deleteMaster( self, master_uri ): self.removeScanner( master_uri ) writeRecentMasters( self.master_to_scanner_map.keys() ) self.removeMasterFromTable( master_uri ) if __name__ == '__main__': signal.signal(signal.SIGINT, sigintHandler) app = QApplication( sys.argv ) if len( sys.argv ) < 2: print "USAGE: choose-master.py " sys.exit( 1 ) program = sys.argv[1] # Borrowed from rxlaunch: # Sets up signal handling so SIGINT closes the application, # following the solution given at [1]. Sets up a custom signal # handler, and ensures that the Python interpreter runs # occasionally so the signal is handled. The email thread at [2] # explains why this is necessary. # # [1] http://stackoverflow.com/questions/4938723/#4939113 # [2] http://www.mail-archive.com/pyqt@riverbankcomputing.com/msg13757.html timer = QTimer() timer.start(250) timer.timeout.connect(lambda: None) # Forces the interpreter to run every 250ms dialog = ChooserDialog( program, os.environ[ 'ROS_MASTER_URI' ]) app.exec_() rviz-1.12.4/scripts/system_info.sh000077500000000000000000000007321300447110700171550ustar00rootroot00000000000000#!/bin/sh # # Shell script to print information about the computer, for use in reporting rviz bugs. echo "Graphics card" lspci | grep VGA echo echo "OS" cat /etc/issue echo "Machine" uname -a echo if [ -x /usr/bin/glxinfo ]; then echo "OpenGL driver info" glxinfo echo else echo "ERROR: glxinfo command not found. To find opengl driver info, please install it with this command:" echo " sudo apt-get install mesa-utils" echo "and re-run $0" fi rviz-1.12.4/setup.py000066400000000000000000000004361300447110700143030ustar00rootroot00000000000000#!/usr/bin/env python from distutils.core import setup from catkin_pkg.python_setup import generate_distutils_setup d = generate_distutils_setup( packages=['rviz'], package_dir={'': 'src/python_bindings'}, requires=['roslib', 'rospkg', 'python_qt_bindings'] ) setup(**d) rviz-1.12.4/src/000077500000000000000000000000001300447110700133555ustar00rootroot00000000000000rviz-1.12.4/src/CMakeLists.txt000066400000000000000000000003661300447110700161220ustar00rootroot00000000000000add_subdirectory(rviz) add_subdirectory(image_view) if (CATKIN_ENABLE_TESTING) add_subdirectory(test) endif() # Python bindings are only support with Qt5, PyQt5, and PySide2 for Kinetic+. if (UseQt5) add_subdirectory(python_bindings) endif() rviz-1.12.4/src/image_view/000077500000000000000000000000001300447110700154715ustar00rootroot00000000000000rviz-1.12.4/src/image_view/CMakeLists.txt000066400000000000000000000006271300447110700202360ustar00rootroot00000000000000add_executable(rviz_image_view image_view.cpp main.cpp ) if(NOT WIN32) set_target_properties(rviz_image_view PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(rviz_image_view ${OGRE_OV_LIBRARIES_ABS} ${rviz_ADDITIONAL_LIBRARIES} ${PROJECT_NAME} ) set_target_properties(rviz_image_view PROPERTIES OUTPUT_NAME image_view PREFIX "") rviz-1.12.4/src/image_view/image_view.cpp000066400000000000000000000120321300447110700203070ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/ogre_helpers/qt_ogre_render_window.h" #include "rviz/ogre_helpers/initialization.h" #include "rviz/image/ros_image_texture.h" #include "ros/ros.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "image_view.h" using namespace rviz; ImageView::ImageView( QWidget* parent ) : QtOgreRenderWindow( parent ) , texture_it_(nh_) { setAutoRender(false); scene_manager_ = ogre_root_->createSceneManager( Ogre::ST_GENERIC, "TestSceneManager" ); } ImageView::~ImageView() { delete texture_; } void ImageView::showEvent( QShowEvent* event ) { QtOgreRenderWindow::showEvent( event ); V_string paths; paths.push_back(ros::package::getPath(ROS_PACKAGE_NAME) + "/ogre_media/textures"); initializeResources(paths); setCamera( scene_manager_->createCamera( "Camera" )); std::string resolved_image = nh_.resolveName("image"); if( resolved_image == "/image" ) { ROS_WARN("image topic has not been remapped"); } std::stringstream title; title << "rviz Image Viewer [" << resolved_image << "]"; setWindowTitle( QString::fromStdString( title.str() )); texture_ = new ROSImageTexture(); try { texture_->clear(); texture_sub_.reset(new image_transport::SubscriberFilter()); texture_sub_->subscribe(texture_it_, "image", 1, image_transport::TransportHints("raw")); texture_sub_->registerCallback(boost::bind(&ImageView::textureCallback, this, _1)); } catch (ros::Exception& e) { ROS_ERROR("%s", (std::string("Error subscribing: ") + e.what()).c_str()); } Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( "Material", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); material->setCullingMode(Ogre::CULL_NONE); material->getTechnique(0)->getPass(0)->setDepthWriteEnabled(true); material->getTechnique(0)->setLightingEnabled(false); Ogre::TextureUnitState* tu = material->getTechnique(0)->getPass(0)->createTextureUnitState(); tu->setTextureName(texture_->getTexture()->getName()); tu->setTextureFiltering( Ogre::TFO_NONE ); Ogre::Rectangle2D* rect = new Ogre::Rectangle2D(true); rect->setCorners(-1.0f, 1.0f, 1.0f, -1.0f); rect->setMaterial(material->getName()); rect->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - 1); Ogre::AxisAlignedBox aabb; aabb.setInfinite(); rect->setBoundingBox(aabb); Ogre::SceneNode* node = scene_manager_->getRootSceneNode()->createChildSceneNode(); node->attachObject(rect); node->setVisible(true); QTimer* timer = new QTimer( this ); connect( timer, SIGNAL( timeout() ), this, SLOT( onTimer() )); timer->start( 33 ); } void ImageView::onTimer() { ros::spinOnce(); static bool first = true; try { if( texture_->update() ) { if( first ) { first = false; resize( texture_->getWidth(), texture_->getHeight() ); } } ogre_root_->renderOneFrame(); } catch( UnsupportedImageEncoding& e ) { ROS_ERROR("%s", e.what()); } if( !nh_.ok() ) { close(); } } void ImageView::textureCallback(const sensor_msgs::Image::ConstPtr& msg) { if (texture_) { texture_->addMessage(msg); } } rviz-1.12.4/src/image_view/image_view.h000066400000000000000000000053721300447110700177650ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include "rviz/ogre_helpers/qt_ogre_render_window.h" # include "rviz/ogre_helpers/initialization.h" # include "rviz/image/ros_image_texture.h" # include "ros/ros.h" # include # include # include # include # include # include # include # include # include # include #endif #ifdef Q_OS_MAC # include #endif using namespace rviz; class ImageView: public QtOgreRenderWindow { Q_OBJECT public: ImageView( QWidget* parent = 0 ); ~ImageView(); protected: void showEvent( QShowEvent* event ); private Q_SLOTS: void onTimer(); private: void textureCallback(const sensor_msgs::Image::ConstPtr& msg); Ogre::SceneManager* scene_manager_; Ogre::Camera* camera_; ROSImageTexture* texture_; ros::NodeHandle nh_; image_transport::ImageTransport texture_it_; boost::shared_ptr texture_sub_; }; rviz-1.12.4/src/image_view/main.cpp000066400000000000000000000044031300447110700171220ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ // This has to be included before with Boost 1.48.0 see: // https://code.ros.org/trac/ros-pkg/ticket/5285 #include #include #include #ifdef Q_OS_MAC #include #endif #include "image_view.h" int main( int argc, char** argv ) { QApplication qapp( argc, argv ); #ifdef Q_OS_MAC ProcessSerialNumber PSN; GetCurrentProcess(&PSN); TransformProcessType(&PSN,kProcessTransformToForegroundApplication); SetFrontProcess(&PSN); #endif ros::init( argc, argv, "rviz_image_view", ros::init_options::AnonymousName ); ImageView window; window.show(); return qapp.exec(); } rviz-1.12.4/src/python_bindings/000077500000000000000000000000001300447110700165535ustar00rootroot00000000000000rviz-1.12.4/src/python_bindings/CMakeLists.txt000066400000000000000000000004321300447110700213120ustar00rootroot00000000000000set(rviz_BINDINGS "") # TODO(wjwwood): re-enabled PySide2 support when it is fixed. # add_subdirectory(shiboken) add_subdirectory(sip) message("Python binding generators: ${rviz_BINDINGS}") if(NOT rviz_BINDINGS) message(FATAL_ERROR "No Python binding generator found.") endif() rviz-1.12.4/src/python_bindings/rviz/000077500000000000000000000000001300447110700175455ustar00rootroot00000000000000rviz-1.12.4/src/python_bindings/rviz/__init__.py000066400000000000000000000020641300447110700216600ustar00rootroot00000000000000# Python package 'rviz' initialization. # # The actual implementations are defined in C++ and wrapped by # shiboken or sip. This wrapper finds which binding is available and # presents it as package rviz. import sys # Can use the following setattr() call to force one binding or the other. # setattr(sys, 'SELECT_QT_BINDING', 'pyside') from python_qt_binding import QT_BINDING if QT_BINDING == 'pyside': # Import the shared library generated by the shiboken binding-generator. # This depends on rviz/manifest.xml listing ${prefix}/lib in the python path. import librviz_shiboken # Expose the contained rviz namespace directly sys.modules['rviz'] = librviz_shiboken.rviz elif QT_BINDING == 'pyqt': # Import the shared library generated by the sip binding-generator. # This depends on rviz/manifest.xml listing ${prefix}/lib in the python path. import librviz_sip # Expose the contained rviz namespace directly sys.modules['rviz'] = librviz_sip.rviz else: raise ImportError('Qt binding name "%s" is unknown.' % QT_BINDING) rviz-1.12.4/src/python_bindings/shiboken/000077500000000000000000000000001300447110700203555ustar00rootroot00000000000000rviz-1.12.4/src/python_bindings/shiboken/CMakeLists.txt000066400000000000000000000104171300447110700231200ustar00rootroot00000000000000# Build file for Python bindings via shiboken and pyside. set(rviz_shiboken_QT_COMPONENTS QtCore QtGui ) find_package(python_qt_binding REQUIRED) include(${python_qt_binding_EXTRAS_DIR}/shiboken_helper.cmake) if(shiboken_helper_FOUND) set(_configure_shiboken TRUE) if(Shiboken_VERSION VERSION_GREATER "1.1.1") if(APPLE AND Shiboken_VERSION VERSION_GREATER "1.2.1") # This appears to no longer be a problem at least with Shiboken 1.2.2 on OS X and Boost 1.57. set(_configure_shiboken TRUE) else() # shiboken 1.1.2 and higher will segfault until https://bugreports.qt-project.org/browse/PYSIDE-218 is fixed set(_configure_shiboken FALSE) message(WARNING "Shiboken version ${Shiboken_VERSION} would segfault when trying to process rviz (see https://bugreports.qt-project.org/browse/PYSIDE-218). Therefore shiboken bindings are being skipped.") endif() endif() if(_configure_shiboken) list(APPEND rviz_BINDINGS "shiboken") set(rviz_BINDINGS "${rviz_BINDINGS}" PARENT_SCOPE) # To add a new rviz class to the bindings, add it: # - in rviz_shiboken_SRCS below, like rviz_myclass_wrapper.cpp # - in rviz_HDRS below, like ../rviz/my_class.h # - in global.h, like #include # - in typesystem.xml, like set(rviz_shiboken_SRCS librviz_shiboken/librviz_shiboken_module_wrapper.cpp librviz_shiboken/rviz_visualizationframe_wrapper.cpp librviz_shiboken/rviz_visualizationmanager_wrapper.cpp librviz_shiboken/rviz_display_wrapper.cpp librviz_shiboken/rviz_displaygroup_wrapper.cpp librviz_shiboken/rviz_ogrelogging_wrapper.cpp librviz_shiboken/rviz_property_wrapper.cpp librviz_shiboken/rviz_boolproperty_wrapper.cpp librviz_shiboken/rviz_paneldockwidget_wrapper.cpp librviz_shiboken/rviz_viewmanager_wrapper.cpp librviz_shiboken/rviz_viewcontroller_wrapper.cpp librviz_shiboken/rviz_tool_wrapper.cpp librviz_shiboken/rviz_toolmanager_wrapper.cpp librviz_shiboken/rviz_config_wrapper.cpp librviz_shiboken/rviz_config_mapiterator_wrapper.cpp librviz_shiboken/rviz_yamlconfigreader_wrapper.cpp librviz_shiboken/rviz_yamlconfigwriter_wrapper.cpp librviz_shiboken/rviz_wrapper.cpp ) set(rviz_shiboken_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/src) set(rviz_HDRS ${rviz_shiboken_INCLUDE_DIR}/rviz/visualization_frame.h ${rviz_shiboken_INCLUDE_DIR}/rviz/visualization_manager.h ${rviz_shiboken_INCLUDE_DIR}/rviz/view_manager.h ${rviz_shiboken_INCLUDE_DIR}/rviz/view_controller.h ${rviz_shiboken_INCLUDE_DIR}/rviz/display.h ${rviz_shiboken_INCLUDE_DIR}/rviz/display_group.h ${rviz_shiboken_INCLUDE_DIR}/rviz/properties/property.h ${rviz_shiboken_INCLUDE_DIR}/rviz/properties/bool_property.h ${rviz_shiboken_INCLUDE_DIR}/rviz/panel_dock_widget.h ${rviz_shiboken_INCLUDE_DIR}/rviz/tool.h ${rviz_shiboken_INCLUDE_DIR}/rviz/tool_manager.h ${rviz_shiboken_INCLUDE_DIR}/rviz/ogre_helpers/ogre_logging.h ${rviz_shiboken_INCLUDE_DIR}/rviz/config.h ${rviz_shiboken_INCLUDE_DIR}/rviz/yaml_config_reader.h ${rviz_shiboken_INCLUDE_DIR}/rviz/yaml_config_writer.h ) shiboken_generator( librviz global.h typesystem.xml ${PROJECT_SOURCE_DIR}/src/python_bindings/shiboken "${rviz_shiboken_SRCS}" "${rviz_HDRS}" "${rviz_shiboken_INCLUDE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" ) include_directories(rviz_shiboken ${rviz_shiboken_INCLUDE_DIR}/rviz ${rviz_shiboken_INCLUDE_DIR}/rviz/properties ${rviz_shiboken_INCLUDE_DIR}/rviz/ogre_helpers ) shiboken_include_directories(rviz_shiboken "${rviz_shiboken_QT_COMPONENTS}") add_library(rviz_shiboken ${rviz_shiboken_SRCS}) if(NOT WIN32) set_target_properties(rviz_shiboken PROPERTIES COMPILE_FLAGS "-std=c++11") endif() set_target_properties(rviz_shiboken PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${PYTHON_INSTALL_DIR}/rviz) target_link_libraries(rviz_shiboken ${PROJECT_NAME}) shiboken_target_link_libraries(rviz_shiboken "${rviz_shiboken_QT_COMPONENTS}") install(TARGETS rviz_shiboken LIBRARY DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION}) endif() endif() rviz-1.12.4/src/python_bindings/shiboken/global.h000066400000000000000000000044651300447110700217770ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PYTHON_GLOBAL_H #define PYTHON_GLOBAL_H #undef QT_NO_STL #undef QT_NO_STL_WCHAR #ifndef NULL #define NULL 0 #endif #include "pyside_global.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif // PYTHON_GLOBAL_H rviz-1.12.4/src/python_bindings/shiboken/typesystem.xml000066400000000000000000000017001300447110700233230ustar00rootroot00000000000000 rviz-1.12.4/src/python_bindings/sip/000077500000000000000000000000001300447110700173465ustar00rootroot00000000000000rviz-1.12.4/src/python_bindings/sip/CMakeLists.txt000066400000000000000000000044541300447110700221150ustar00rootroot00000000000000# Build file for Python bindings via sip and pyqt. set(rviz_HDRS_DIR ${PROJECT_SOURCE_DIR}/src/rviz) set(SIP_BUILD_DIR ${PROJECT_SOURCE_DIR}/build/sip/rviz_sip) set(SIP_SRC_DIR ${PROJECT_SOURCE_DIR}/src/python_bindings/sip) set(rviz_sip_DEPENDENT_FILES rviz.sip visualization_frame.sip visualization_manager.sip display.sip display_group.sip panel_dock_widget.sip property.sip bool_property.sip view_controller.sip view_manager.sip tool.sip tool_manager.sip config.sip yaml_config_reader.sip yaml_config_writer.sip ${rviz_HDRS_DIR}/visualization_frame.h ${rviz_HDRS_DIR}/visualization_manager.h ${rviz_HDRS_DIR}/display.h ${rviz_HDRS_DIR}/display_group.h ${rviz_HDRS_DIR}/panel_dock_widget.h ${rviz_HDRS_DIR}/properties/property.h ${rviz_HDRS_DIR}/properties/bool_property.h ${rviz_HDRS_DIR}/view_controller.h ${rviz_HDRS_DIR}/view_manager.h ${rviz_HDRS_DIR}/tool.h ${rviz_HDRS_DIR}/tool_manager.h ${rviz_HDRS_DIR}/config.h ${rviz_HDRS_DIR}/yaml_config_reader.h ${rviz_HDRS_DIR}/yaml_config_writer.h ) find_package(python_qt_binding REQUIRED) include(${python_qt_binding_EXTRAS_DIR}/sip_helper.cmake) # maintain context for different named target set(rviz_sip_INCLUDE_DIRS ${rviz_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/src" ${catkin_INCLUDE_DIRS}) set(rviz_sip_LIBRARIES ${rviz_LIBRARIES} ${PROJECT_NAME}) set(rviz_sip_LIBRARY_DIRS ${rviz_LIBRARY_DIRS} ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_LIB_DESTINATION}) set(rviz_sip_LDFLAGS_OTHER ${rviz_LDFLAGS_OTHER} -Wl,-rpath,\\"${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_LIB_DESTINATION}\\") if(sip_helper_FOUND) list(APPEND rviz_BINDINGS "sip") set(rviz_BINDINGS "${rviz_BINDINGS}" PARENT_SCOPE) build_sip_binding(rviz_sip rviz.sip SIP_CONFIGURE ${python_qt_binding_EXTRAS_DIR}/sip_configure.py SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/python_bindings/sip LIBRARY_DIR ${CATKIN_DEVEL_PREFIX}/${PYTHON_INSTALL_DIR}/rviz BINARY_DIR ${CATKIN_DEVEL_PREFIX}/bin DEPENDS ${rviz_sip_DEPENDENT_FILES} DEPENDENCIES rviz ) if(APPLE) set(rviz_sip_LIBRARY_FILE librviz_sip.so) else() set(rviz_sip_LIBRARY_FILE librviz_sip${CMAKE_SHARED_LIBRARY_SUFFIX}) endif() install(FILES ${CATKIN_DEVEL_PREFIX}/${PYTHON_INSTALL_DIR}/rviz/${rviz_sip_LIBRARY_FILE} DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION}) endif() rviz-1.12.4/src/python_bindings/sip/bool_property.sip000066400000000000000000000010721300447110700227620ustar00rootroot00000000000000namespace rviz { class BoolProperty: rviz::Property /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: BoolProperty( const QString& name = QString(), bool default_value = false, const QString& description = QString(), rviz::Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual ~BoolProperty(); virtual bool getBool() const; public slots: bool setBool( bool value ); }; }; rviz-1.12.4/src/python_bindings/sip/config.sip000066400000000000000000000036201300447110700213310ustar00rootroot00000000000000namespace rviz { class Config /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** @brief Default constructor. Creates an empty config object. */ Config(); /** @brief Copy constructor. Copies only the reference to the data, so creates a shallow copy. */ Config( const rviz::Config& source ); /** @brief Convenience constructor, makes a Value type Config object with the given value. */ Config( QVariant value ); enum Type { Map, List, Value, Empty, Invalid }; rviz::Config::Type getType() const; void setType( rviz::Config::Type ); /** @brief Returns getType() != Invalid. */ bool isValid() const; void mapSetValue( const QString& key, QVariant value ); rviz::Config mapMakeChild( const QString& key ); rviz::Config mapGetChild( const QString& key ) const; /** @brief Return a new iterator for looping over key/value pairs. */ rviz::Config::MapIterator mapIterator() const; /** @brief Ensures this is a valid Config object, sets the type to Value then sets the value. */ void setValue( const QVariant& value ); /** @brief If this config object is valid, this returns its value. If not, it returns an invalid QVariant. */ QVariant getValue() const; int listLength() const; rviz::Config listChildAt( int i ) const; rviz::Config listAppendNew(); class MapIterator /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** @brief Advance iterator to next entry. */ void advance(); /** @brief Return true if there is a next entry, false if not. */ bool isValid(); /** @brief Resets the iterator to the start of the map. */ void start(); /** @brief Return the name of the current map entry. */ QString currentKey(); /** @brief Return the config reference of the current map entry. */ rviz::Config currentChild(); }; }; }; rviz-1.12.4/src/python_bindings/sip/display.sip000066400000000000000000000066221300447110700215360ustar00rootroot00000000000000namespace rviz { class Display: rviz::Property /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** @brief Main initialization, called after constructor, before load() or setEnabled(). */ // void initialize( DisplayContext* context ); /** @brief Return data appropriate for the given column (0 or 1) and * role for this Display. */ // virtual QVariant getViewData( int column, int role ) const; /** @brief Return item flags appropriate for the given column (0 or * 1) for this Display. */ // virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Return the class identifier which was used to create this * instance. This version just returns whatever was set with * setClassId(). */ virtual QString getClassId() const; /** @brief Set the class identifier used to create this instance. * Typically this will be set by the factory object which created it. */ virtual void setClassId( const QString& class_id ); virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; /** @brief Return true if this Display is enabled, false if not. */ bool isEnabled() const; /** @brief Set the fixed frame in this display. */ void setFixedFrame( const QString& fixed_frame ); /** @brief Called periodically by the visualization manager. * @param wall_dt Wall-clock time, in seconds, since the last time the update list was run through. * @param ros_dt ROS time, in seconds, since the last time the update list was run through. */ virtual void update( float wall_dt, float ros_dt ); /** @brief Called to tell the display to clear its state */ virtual void reset(); /** @brief Show status level and text. * @param level One of StatusProperty::Ok, StatusProperty::Warn, or StatusProperty::Error. * @param name The name of the child entry to set. * @param text Description of the child's state. * * Every Display has a StatusList to indicate how it is doing. The * StatusList has StatusPropertychildren indicating the status of * various subcomponents of the Display. Each child of the status * has a level, a name, and descriptive text. The top-level * StatusList has a level which is set to the worst of all the * children's levels. */ // virtual void setStatus( StatusProperty::Level level, const QString& name, const QString& text ); /** @brief Show status level and text, using a std::string. * Convenience function which converts std::string to QString * and calls setStatus(). */ // void setStatusStd( StatusProperty::Level level, const std::string& name, const std::string& text ) // { // setStatus( level, QString::fromStdString( name ), QString::fromStdString( text )); // } /** @brief Delete the status entry with the given name. */ virtual void deleteStatus( const QString& name ); /** @brief Delete the status entry with the given std::string name. */ // void deleteStatusStd( const std::string& name ) { deleteStatus( QString::fromStdString( name )); } void setIcon( const QIcon& icon ); public slots: /** @brief Enable or disable this Display. * * SetEnabled is called after initialize() and at the end of load(), * if the Display settings are being loaded from a file. */ void setEnabled( bool enabled ); /** @brief Convenience function which calls context_->queueRender(). */ void queueRender(); }; }; rviz-1.12.4/src/python_bindings/sip/display_group.sip000066400000000000000000000067131300447110700227530ustar00rootroot00000000000000namespace rviz { class DisplayGroup: rviz::Display /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: DisplayGroup(); virtual ~DisplayGroup(); rviz::Display* createDisplay( const QString& class_id ); /** @brief Return the number of child objects (Property and Display). * * Overridden from Property to include the number of child Displays. */ virtual int numChildren() const; /** @brief Return the child with the given index, without * checking whether the index is within bounds. * * Overridden from Property to include Display children. */ virtual rviz::Property* childAtUnchecked( int index ) const; /** @brief Take a child out of the child list, but don't destroy it. * @return Returns the child property at the given index, or NULL if the index is out of bounds. * * This notifies the model about the removal. * * This is overridden from Property to include Display children. */ virtual rviz::Property* takeChildAt( int index ); /** @brief Add a child Property or Display. * @param child The child to add. * @param index [optional] The index at which to add the child. If * less than 0 or greater than the number of child properties, the * child will be added at the end. * * This notifies the model about the addition. * * This is overridden from Property to keep non-Display child * Properties in Property's list of children and Display children in * DisplayGroup's list of child Displays. */ virtual void addChild( rviz::Property* child, int index = -1 ); /** @brief Return data appropriate for the given column (0 or 1) and * role for this DisplayGroup. */ virtual QVariant getViewData( int column, int role ) const; /** @brief Return item flags appropriate for the given column (0 or * 1) for this DisplayGroup. */ virtual Qt::ItemFlags getViewFlags( int column ) const; virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; /** @brief Add a child Display to the end of the list of Displays. * * This also tells the model that we are adding a child, so it can * update widgets. * * @note This does @e not remove @a child from its parent. That * must be done first to avoid problems. */ virtual void addDisplay( rviz::Display* child ); /** @brief Remove a child Display from the the list of Displays, but * don't destroy it. * @return Returns child if it is found, or NULL if child is not found. * * This also tells the model that we are removing a child, so it can * update widgets. */ virtual rviz::Display* takeDisplay( rviz::Display* child ); /** @brief Remove and destroy all child Displays, but preserve any * non-Display children. */ virtual void removeAllDisplays(); /** @brief Return the number of child Displays. */ virtual int numDisplays() const; /** @brief Return the index-th Display in this group, or NULL if the * index is invalid. */ virtual rviz::Display* getDisplayAt( int index ) const; /** @brief Find the index-th child Display in this group. If the * child is itself a DisplayGroup, return the pointer to it. If it * is not, return NULL. */ virtual rviz::DisplayGroup* getGroupAt( int index ) const; /** @brief Call update() on all child Displays. */ virtual void update( float wall_dt, float ros_dt ); /** @brief Reset this and all child Displays. */ virtual void reset(); }; }; rviz-1.12.4/src/python_bindings/sip/ogre_logging.sip000066400000000000000000000012131300447110700225220ustar00rootroot00000000000000namespace rviz { class OgreLogging /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** @brief Configure Ogre to write output using the ROS logger. */ static void useRosLog(); /** @brief Configure Ogre to write output to the given log file * name. If file name is a relative path, it will be relative to * the directory which is current when the program is run. Default * is "Ogre.log". */ static void useLogFile( const QString& filename = "Ogre.log" ); /** @brief Disable Ogre logging entirely. This is the default. */ static void noLog(); }; }; rviz-1.12.4/src/python_bindings/sip/panel_dock_widget.sip000066400000000000000000000004251300447110700235260ustar00rootroot00000000000000namespace rviz { class PanelDockWidget: QDockWidget /NoDefaultCtors/ { %TypeHeaderCode #include %End public: PanelDockWidget( const QString& name ); void setContentWidget( QWidget* child ); signals: void visibilityChanged( bool ); }; }; rviz-1.12.4/src/python_bindings/sip/property.sip000066400000000000000000000320051300447110700217470ustar00rootroot00000000000000namespace rviz { class Property: QObject /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** @brief Constructor. * @param name The name of this property. Appears in the left column of a PropertyTreeWidget. * @param default_value The initial value to store in the property. Appears in the right column of a PropertyTreeWidget. * @param description Text describing the property. Is shown in the "help" area of a PropertyTreeWithHelp widget. * @param parent The parent Property, or NULL if there is no parent at this time. * @param changed_slot This should be a Qt slot specification, * generated by Qt's @c SLOT() macro. It should be a slot on * the @a receiver object, or if @a receiver is not specified, * it should be a slot on the @a parent. * @param receiver If receiver is non-NULL, the changed() signal is * connected to the @a changed_slot on the @a receiver object. * * All parameters to the constructor are optional and can all be set * after construction as well. * * If a parent is given, this constructor calls @c * parent->addChild(this) to add itself to the parent's list of * children. * * If @a changed_slot is given and either @a parent or @a receiver is * also, then the changed() signal is connected via * QObject::connect() to the slot described by @a changed_slot on the * parent or the receiver. If both parent and receiver are * specified, receiver is the one which gets connected. If receiver * is not specified, parent is used instead. */ Property( const QString& name = QString(), const QVariant default_value = QVariant(), const QString& description = QString(), rviz::Property* parent = 0 ); /** @brief Destructor. Removes this property from its parent's list * of children. */ virtual ~Property(); /** @brief Remove and delete some or all child Properties. Does not change * the value of this Property. * @param start_index The index of the first child to delete. * @param count The number of children to delete, or -1 to delete from start_index to the end of the list. * * Does not use numChildren() or takeChildAt(), operates directly on internal children_ list. */ virtual void removeChildren( int start_index = 0, int count = -1 ); /** @brief Set the new value for this property. Returns true if the * new value is different from the old value, false if same. * @param new_value The new value to store. * @return Returns true if @a new_value is different from current value, false if they are the same. * * If the new value is different from the old value, this emits * aboutToChange() before changing the value and emits changed() after. * * If the value set is an invalid QVariant (QVariant::isValid() * returns false), the value will not be editable in a * PropertyTreeWidget. */ virtual bool setValue( const QVariant& new_value ); /** @brief Return the value of this Property as a QVariant. If the * value has never been set, an invalid QVariant is returned. */ virtual QVariant getValue() const; /** @brief Set the name. * @param name the new name. * * Internally, the name is stored with QObject::setObjectName(). */ virtual void setName( const QString& name ); /** @brief Return the name of this Property as a QString. */ virtual QString getName() const; /** @brief Return the name of this Property as a std::string. */ // std::string getNameStd() const { return getName().toStdString(); } /** @brief Set the description. * @param description the new description. */ virtual void setDescription( const QString& description ); /** @brief Return the description. */ virtual QString getDescription() const; /** @brief Return the first child Property with the given name, or * the FailureProperty if no child has the name. * * If no child is found with the given name, an instance of a * special Property subclass named FailureProperty is returned and * an error message is printed to stdout. * FailureProperty::subProp() always returns itself, which means you * can safely chain a bunch of subProp() calls together and not have * a crash even if one of the sub-properties does not actually * exist. For instance: * * float width = prop->subProp( "Dimenshons" )->subProp( "Width" )->getValue().toFloat(); * * If the first property @c prop has a "Dimensions" property but not * a "Dimenshons" one, @c width will end up set to 0 and an error * message will be printed, but the program will not crash here. * * This is an Order(N) operation in the number of subproperties. */ rviz::Property* subProp( const QString& sub_name ); /** @brief Return the number of child objects (Property or otherwise). * * You can override this in a subclass to implement different child * storage. */ virtual int numChildren() const; /** @brief Return the child Property with the given index, or NULL * if the index is out of bounds or if the child at that index is * not a Property. * * This just checks the index against 0 and numChildren() and then * calls childAtUnchecked(), so it does not need to be overridden in * a subclass. */ rviz::Property* childAt( int index ) const; /** @brief Return the child Property with the given index, without * checking whether the index is within bounds. * * You can override this in a subclass to implement different child * storage. */ virtual rviz::Property* childAtUnchecked( int index ) const; /** @brief Return the parent Property. */ rviz::Property* getParent() const; /** @brief Set parent property, without telling the parent. * * Unlike specifying the parent property to the constructor, * setParent() does not have any immediate side effects, like adding * itself to be a child of the parent. It should only be used by * implementations of addChild() and takeChild() and such. */ void setParent( rviz::Property* new_parent ); /** @brief Return data appropriate for the given column (0 or 1) and role for this Property. * @param column 0 for left column, 1 for right column. * @param role is a Qt::ItemDataRole * * When overriding to add new data (like a color for example), check * the role for the thing you know about, and if it matches, return * your data. If it does not match, call the parent class version * of this function and return its result. * * Return values from this function or overridden versions of it are * where background and foreground colors, check-box checked-state * values, text, and fonts all come from. */ virtual QVariant getViewData( int column, int role ) const; /** @brief Return item flags appropriate for the given column (0 or * 1) for this Property. * @param column 0 for left column, 1 for right column. * @return The Qt::ItemFlags for the given column of this property, including Qt::ItemIsSelectable, Qt::ItemIsEditable, etc. */ virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Hook to provide custom painting of the value data (right-hand column) in a subclass. * @param painter The QPainter to use. * @param option A QStyleOptionViewItem with parameters of the paint job, like the rectangle, alignments, etc. * @return true if painting has been done, false if not. The default implementation always returns false. * * To implement a custom appearance of a Property value, override * this function to do the painting and return true. * * If this function returns false, a QStyledItemDelegate will do the painting. */ virtual bool paint( QPainter* painter, const QStyleOptionViewItem& option ) const; /** @brief Create an editor widget to edit the value of this property. * @param parent The QWidget to set as the parent of the returned QWidget. * @param option A QStyleOptionViewItem with parameters of the editor widget, like the rectangle, alignments, etc. * * @return the newly-created editor widget. The default * implementation creates a QSpinBox for integer values, a * FloatEdit for float or double values, or a QLineEdit for * anything else. * * If this function returns NULL, a QStyledItemDelegate will make an editor widget. * * The widget returned by createEditor() must have one @c Q_PROPERTY * with @c USER set to @c true. The PropertyTreeDelegate finds it, * sets it with the results of PropertyTreeModel::data() after * creation, and after editing is finished it reads it and calls * PropertyTreeModel::setData() with the contents. */ virtual QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option ); /** @brief Returns true if @c this is an ancestor of * @a possible_child, meaning is the parent or parent of parent * etc. */ bool isAncestorOf( rviz::Property* possible_child ) const; /** @brief Remove a given child object and return a pointer to it. * @return If child is contained here, it is returned; otherwise NULL. * * This performs a linear search through all the children. * * This uses only virtual functions, numChildren(), * childAtUnchecked(), and takeChildAt(), so it does not need to be * virtual itself. */ rviz::Property* takeChild( rviz::Property* child ); /** @brief Take a child out of the child list, but don't destroy it. * @return Returns the child property at the given index, or NULL if the index is out of bounds. * * This notifies the model about the removal. */ virtual rviz::Property* takeChildAt( int index ); /** @brief Add a child property. * @param child The child property to add. * @param index [optional] The index at which to add the child. If * less than 0 or greater than the number of child properties, the * child will be added at the end. */ virtual void addChild( rviz::Property* child, int index = -1 ); /** @brief Set the model managing this Property and all its child properties, recursively. */ // void setModel( PropertyTreeModel* model ); /** @brief Return the model managing this Property and its childrent. */ // PropertyTreeModel* getModel() const { return model_; } /** @brief Return the row number of this property within its parent, * or -1 if it has no parent. * * This checks child_indexes_valid_ in the parent Property, and if * it is false calls reindexChildren(). Then returns * row_number_within_parent_ regardless.*/ int rowNumberInParent() const; /** @brief Move the child at from_index to to_index. */ virtual void moveChild( int from_index, int to_index ); virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; /** @brief Returns true if the property is not read-only AND has data worth saving. */ bool shouldBeSaved() const; /** @brief If @a save is true and getReadOnly() is false, * shouldBeSaved will return true; otherwise false. Default is true. */ void setShouldBeSaved( bool save ); /** @brief Hide this Property in any PropertyTreeWidgets. * * This is a convenience function which calls setHidden( true ). * @sa show(), setHidden(), getHidden() */ void hide(); /** @brief Show this Property in any PropertyTreeWidgets. * * This is a convenience function which calls setHidden( false ). * @sa show(), setHidden(), getHidden() */ void show(); /** @brief Hide or show this property in any PropertyTreeWidget * viewing its parent. * * The hidden/shown state is not saved or loaded, it is expected to * be managed by the owner of the property. */ virtual void setHidden( bool hidden ); /** @brief Return the hidden/shown state. True means hidden, false * means visible. */ virtual bool getHidden() const; /** @brief Prevent or allow users to edit this property from a PropertyTreeWidget. * * This only applies to user edits. Calling setValue() will still change the value. * * This is not inherently recursive. Parents which need this to * propagate to their children must override this to implement * that. */ virtual void setReadOnly( bool read_only ); /** @brief Return the read-only-ness of this property. * @sa setReadOnly() */ virtual bool getReadOnly(); /** @brief Collapse (hide the children of) this Property. * * @note Properties start out collapsed by default. * @sa expand() */ virtual void collapse(); /** @brief Expand (show the children of) this Property. * * @note Properties start out collapsed by default. * * This function only works if the property is already owned by a * PropertyTreeModel connected to a PropertyTreeWidget. If this is * called and the model is subsequently attached to a widget, it * will not have any effect. * @sa collapse() */ virtual void expand(); signals: /** @brief Emitted by setValue() just before the value has changed. */ void aboutToChange(); /** @brief Emitted by setValue() just after the value has changed. */ void changed(); }; }; rviz-1.12.4/src/python_bindings/sip/rviz.sip000066400000000000000000000010531300447110700210540ustar00rootroot00000000000000%Module librviz_sip %Import QtCore/QtCoremod.sip %Import QtGui/QtGuimod.sip %Import QtWidgets/QtWidgetsmod.sip %DefaultSupertype sip.simplewrapper %Include visualization_frame.sip %Include visualization_manager.sip %Include display.sip %Include display_group.sip %Include property.sip %Include bool_property.sip %Include panel_dock_widget.sip %Include view_controller.sip %Include view_manager.sip %Include tool.sip %Include tool_manager.sip %Include ogre_logging.sip %Include config.sip %Include yaml_config_writer.sip %Include yaml_config_reader.sip rviz-1.12.4/src/python_bindings/sip/tool.sip000066400000000000000000000053151300447110700210440ustar00rootroot00000000000000namespace rviz { class Tool /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** Default constructor. Pluginlib only instantiates classes via * default constructors. Subclasses of Tool should shortcut_key_ * field in their constructors. * * Properties to appear in the Tool Properties panel are typically * created in the constructor, as children of the property from * getPropertyContainer(), which is set up in this Tool * constructor. */ // Tool(); // virtual ~Tool(); /** Initialize the tool. Sets the DisplayContext and calls * onInitialize(). */ // void initialize( DisplayContext* context ); /** @brief Return the container for properties of this Tool.. */ virtual rviz::Property* getPropertyContainer(); char getShortcutKey(); virtual void activate() = 0; virtual void deactivate() = 0; virtual void update(float wall_dt, float ros_dt); enum { Render = 1, Finished = 2 }; /** Process a mouse event. This is the central function of all the * tools, as it defines how the mouse is used. */ // virtual int processMouseEvent( ViewportMouseEvent& event ) = 0; /** Process a key event. Override if your tool should handle any other keypresses than the tool shortcuts, which are handled separately. */ // virtual int processKeyEvent( QKeyEvent* event, RenderPanel* panel ); QString getName() const; /** @brief Set the name of the tool. * * This is called by ToolManager during tool initialization. If you * want a different name than it gives you, call this from * onInitialize() (or thereafter). */ void setName( const QString& name ); /** @brief Set the description of the tool. This is called by * ToolManager during tool initialization. */ QString getDescription() const; void setDescription( const QString& description ); /** @brief Return the class identifier which was used to create this * instance. This version just returns whatever was set with * setClassId(). */ virtual QString getClassId() const; /** @brief Set the class identifier used to create this instance. * Typically this will be set by the factory object which created it. */ virtual void setClassId( const QString& class_id ); virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; /** @brief Set the toolbar icon for this tool (will also set its cursor). */ void setIcon( const QIcon& icon ); /** @brief Get the icon of this tool. */ const QIcon& getIcon(); /** @brief Set the cursor for this tool. */ void setCursor( const QCursor& cursor ); /** @brief Get current cursor of this tool. */ const QCursor& getCursor(); }; }; rviz-1.12.4/src/python_bindings/sip/tool_manager.sip000066400000000000000000000047201300447110700225350ustar00rootroot00000000000000namespace rviz { class ToolManager: QObject /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: // ToolManager( DisplayContext* context ); // virtual ~ToolManager(); /** @brief Initialization for after the DisplayContext is created. * Loads standard RViz tools. */ void initialize(); virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; // PropertyTreeModel* getPropertyModel() const { return property_tree_model_; } /** @brief Create a tool by class lookup name, add it to the list, and return it. */ rviz::Tool* addTool( const QString& tool_class_lookup_name ); /** * \brief Return the tool currently in use. * \sa setCurrentTool() */ rviz::Tool* getCurrentTool(); /** * \brief Return the tool at a given index in the Tool list. * If index is less than 0 or greater than the number of tools, this * will fail an assertion. */ rviz::Tool* getTool( int index ); int numTools(); void removeTool( int index ); void removeAll(); /** * \brief Set the current tool. * The current tool is given all mouse and keyboard events which * VisualizationManager receives via handleMouseEvent() and * handleChar(). * \sa getCurrentTool() */ void setCurrentTool( rviz::Tool* tool ); /** * \brief Set the default tool. * * The default tool is selected directly by pressing the Escape key. * The default tool is indirectly selected when a Tool returns * Finished in the bit field result of Tool::processMouseEvent(). * This is how control moves from the InitialPoseTool back to * MoveCamera when InitialPoseTool receives a left mouse button * release event. * \sa getDefaultTool() */ void setDefaultTool( rviz::Tool* tool ); /** * \brief Get the default tool. * \sa setDefaultTool() */ rviz::Tool* getDefaultTool(); QStringList getToolClasses(); // void handleChar( QKeyEvent* event, RenderPanel* panel ); // PluginlibFactory* getFactory() { return factory_; } signals: /** @brief Emitted when anything changes which will change the saved config file contents. */ void configChanged(); /** @brief Emitted by addTool() after the tool is added to the list of tools. */ void toolAdded( rviz::Tool* ); /** @brief Emitted by setCurrentTool() after the newly chosen tool * is activated. */ void toolChanged( rviz::Tool* ); void toolRemoved( rviz::Tool* ); }; }; rviz-1.12.4/src/python_bindings/sip/view_controller.sip000066400000000000000000000061241300447110700233030ustar00rootroot00000000000000namespace rviz { class ViewController: rviz::Property /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: // ViewController(); // virtual ~ViewController(); /** @brief Do all setup that can't be done in the constructor. * * Creates camera_ and attaches it to the root scene node. * * Calls onInitialize() just before returning. */ // void initialize( DisplayContext* context ); static QString formatClassId( const QString& class_id ); /** @brief Overridden from Property to give a different background * color and bold font if this view is active. */ virtual QVariant getViewData( int column, int role ) const; /** @brief Overridden from Property to make this draggable if it is not active. */ virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Called by RenderPanel when this view controller is about to be used. * * There is no deactivate() because ViewControllers leaving * "current" are destroyed. Put any cleanup in the destructor. */ void activate(); /** @brief Called at 30Hz by ViewManager::update() while this view * is active. Override with code that needs to run repeatedly. */ virtual void update(float dt, float ros_dt); // virtual void handleMouseEvent(ViewportMouseEvent& evt); void lookAt( float x, float y, float z ); /** Reset the view controller to some sane initial state, like * looking at 0,0,0 from a few meters away. */ virtual void reset() = 0; /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). * * This base class implementation does nothing. */ virtual void mimic( rviz::ViewController* source_view ); /** @brief Called by ViewManager when this ViewController is being made current. * @param previous_view is the previous "current" view, and will not be NULL. * * This gives ViewController subclasses an opportunity to implement * a smooth transition from a previous viewpoint to the new * viewpoint. * * This base class implementation does nothing. */ virtual void transitionFrom( rviz::ViewController* previous_view ); /** @brief Subclasses should call this whenever a change is made which would change the results of toString(). */ void emitConfigChanged(); // Ogre::Camera* getCamera() const; /** @brief Return the class identifier which was used to create this * instance. This version just returns whatever was set with * setClassId(). */ virtual QString getClassId() const; /** @brief Set the class identifier used to create this instance. * Typically this will be set by the factory object which created it. */ virtual void setClassId( const QString& class_id ); virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; bool isActive() const; /** @return A mouse cursor representing the current state */ virtual QCursor getCursor(); signals: void configChanged(); }; }; rviz-1.12.4/src/python_bindings/sip/view_manager.sip000066400000000000000000000041541300447110700225330ustar00rootroot00000000000000namespace rviz { class ViewManager: QObject /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: // ViewManager( DisplayContext* context ); // ~ViewManager(); void initialize(); void update( float wall_dt, float ros_dt ); /** @brief Return the current ViewController in use for the main * RenderWindow. */ rviz::ViewController* getCurrent() const; rviz::ViewController* create( const QString& type ); int getNumViews() const; rviz::ViewController* getViewAt( int index ) const; void add( rviz::ViewController* view, int index = -1 ); /** @brief Remove the given ViewController from the list and return * it. If it is not in the list, NULL is returned and nothing * changes. */ rviz::ViewController* take( rviz::ViewController* view ); /** @brief Remove the ViewController at the given index from the * list and return it. If the index is not valid, NULL is returned * and nothing changes. */ rviz::ViewController* takeAt( int index ); // PropertyTreeModel* getPropertyModel() { return property_model_; } virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; /** @brief Make a copy of @a view_to_copy and install that as the new current ViewController. */ void setCurrentFrom( rviz::ViewController* view_to_copy ); /** @brief Return a copy of source, made by serializing source to * YAML and instantiating and loading a new one from that YAML. */ rviz::ViewController* copy( rviz::ViewController* source ); // PluginlibFactory* getFactory() const { return factory_; } public slots: /** @brief Make a copy of the current ViewController and add it to the end of the list of saved views. */ void copyCurrentToList(); /** @brief Create a new view controller of the given type and set it * up to mimic and replace the previous current view. */ void setCurrentViewControllerType( const QString& new_class_id ); signals: void configChanged(); /** @brief Emitted just after the current view controller changes. */ void currentChanged(); }; }; rviz-1.12.4/src/python_bindings/sip/visualization_frame.sip000066400000000000000000000052301300447110700241360ustar00rootroot00000000000000namespace rviz { class VisualizationFrame: QMainWindow /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: VisualizationFrame( QWidget* parent = 0 ); virtual ~VisualizationFrame(); /** @brief Call this @e before initialize() to have it take effect. */ void setShowChooseNewMaster( bool show ); /** @brief Set the path to the help file. Should contain HTML. * Default is a file in the RViz package. */ void setHelpPath( const QString& help_path ); /** @brief Set the path to the "splash" image file. This image is * shown during initialization and loading of the first config file. * Default is a file in the RViz package. To prevent splash image * from showing, set this to an empty string. */ void setSplashPath( const QString& splash_path ); void initialize( const QString& display_config_file = "" ); rviz::VisualizationManager* getManager(); // overrides from WindowManagerInterface virtual QWidget* getParentWindow(); virtual rviz::PanelDockWidget* addPane( const QString& name, QWidget* panel, Qt::DockWidgetArea area = Qt::LeftDockWidgetArea, bool floating = true ); /** @brief Load the "general" config file, which has just the few * things which should not be saved with a display config. * * Loads from the file named in persistent_settings_file_. */ void loadPersistentSettings(); /** @brief Save the "general" config file, which has just the few * things which should not be saved with a display config. * * Saves to the file named in persistent_settings_file_. */ void savePersistentSettings(); /** @brief Load display and other settings from the given file. * @param path The full path of the config file to load from. */ void loadDisplayConfig( const QString& path ); /** @brief Save display and other settings to the given file. * @param path The full path of the config file to save into. */ bool saveDisplayConfig( const QString& path ); QString getErrorMessage() const; /** @brief Load the properties of all subsystems from the given Config. * * This is called by loadDisplayConfig(). * * @param config Must have type Config::Map. * @sa save() */ virtual void load( const rviz::Config& config ); /** @brief Save the properties of each subsystem and most editable rviz * data. * * This is called by saveDisplayConfig(). * * @param config The Config node to write into. * @sa load() */ virtual void save( rviz::Config config ); void setHideButtonVisibility( bool visible ); }; }; rviz-1.12.4/src/python_bindings/sip/visualization_manager.sip000066400000000000000000000142451300447110700244640ustar00rootroot00000000000000namespace rviz { class VisualizationManager: QObject /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** * \brief Constructor * Creates managers and sets up global properties. * @param render_panel a pointer to the main render panel widget of the app. * @param wm a pointer to the window manager (which is really just a * VisualizationFrame, the top-level container widget of rviz). */ // VisualizationManager( RenderPanel* render_panel, WindowManagerInterface* wm = 0 ); /** * \brief Destructor * Stops update timers and destroys all displays, tools, and managers. */ virtual ~VisualizationManager(); /** * \brief Do initialization that wasn't done in constructor. * Initializes tool manager, view manager, selection manager. */ void initialize(); /** * \brief Start timers. * Creates and starts the update and idle timers, both set to 30Hz (33ms). */ void startUpdate(); /* * \brief Stop the update timers. No Displays will be updated and no ROS * callbacks will be called during this period. */ void stopUpdate(); /** * \brief Create and add a display to this panel, by class lookup name * @param class_lookup_name "lookup name" of the Display subclass, for pluginlib. * Should be of the form "packagename/displaynameofclass", like "rviz/Image". * @param name The name of this display instance shown on the GUI, like "Left arm camera". * @param enabled Whether to start enabled * @return A pointer to the new display. */ rviz::Display* createDisplay( const QString& class_lookup_name, const QString& name, bool enabled ); /** * \brief Add a display to be managed by this panel * @param display The display to be added */ void addDisplay( rviz::Display* display, bool enabled ); /** * \brief Remove and delete all displays */ void removeAllDisplays(); virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; /** @brief Return the fixed frame name. * @sa setFixedFrame() */ QString getFixedFrame() const; /** @brief Set the coordinate frame we should be transforming all fixed data into. * @param frame The name of the frame -- must match the frame name broadcast to libTF * @sa getFixedFrame() */ void setFixedFrame( const QString& frame ); /** * @brief Convenience function: returns getFrameManager()->getTFClient(). */ // tf::TransformListener* getTFClient() const; /** * @brief Returns the Ogre::SceneManager used for the main RenderPanel. */ // Ogre::SceneManager* getSceneManager() const; /** * @brief Return the main RenderPanel. */ // RenderPanel* getRenderPanel() const; /** * @brief Return the wall clock time, in seconds since 1970. */ double getWallClock(); /** * @brief Return the ROS time, in seconds. */ double getROSTime(); /** * @brief Return the wall clock time in seconds since the last reset. */ double getWallClockElapsed(); /** * @brief Return the ROS time in seconds since the last reset. */ double getROSTimeElapsed(); /** * @brief Handle a single key event for a given RenderPanel. * * If the key is Escape, switches to the default Tool (via * getDefaultTool()). All other key events are passed to the * current Tool (via getCurrentTool()). */ // void handleChar( QKeyEvent* event, RenderPanel* panel ); /** * @brief Handle a mouse event. * * This just copies the given event into an event queue. The events * in the queue are processed by onUpdate() which is called from the * main thread by a timer every 33ms. */ // void handleMouseEvent( const ViewportMouseEvent& event ); /** * @brief Resets the wall and ROS elapsed time to zero and calls resetDisplays(). */ void resetTime(); /** * @brief Return a pointer to the SelectionManager. */ // SelectionManager* getSelectionManager() const; /** @brief Return a pointer to the ToolManager. */ virtual rviz::ToolManager* getToolManager() const; /** @brief Return a pointer to the ViewManager. */ virtual rviz::ViewManager* getViewManager() const; /** * @brief Lock a mutex to delay calls to Ogre::Root::renderOneFrame(). */ void lockRender(); /** * @brief Unlock a mutex, allowing calls to Ogre::Root::renderOneFrame(). */ void unlockRender(); /** * \brief Queues a render. Multiple calls before a render happens will only cause a single render. * \note This function can be called from any thread. */ void queueRender(); /** * @brief Return the window manager, if any. */ // WindowManagerInterface* getWindowManager() const; /** * @brief Return the CallbackQueue using the main GUI thread. */ // ros::CallbackQueueInterface* getUpdateQueue(); /** * @brief Return a CallbackQueue using a different thread than the main GUI one. */ // ros::CallbackQueueInterface* getThreadedQueue(); /** @brief Return the FrameManager instance. */ // FrameManager* getFrameManager() const; /** @brief Return the current value of the frame count. * * The frame count is just a number which increments each time a * frame is rendered. This lets clients check if a new frame has * been rendered since the last time they did something. */ unsigned long long getFrameCount() const; /** @brief Notify this VisualizationManager that something about its * display configuration has changed. */ void notifyConfigChanged(); /** @brief Return a factory for creating Display subclasses based on a class id string. */ // virtual DisplayFactory* getDisplayFactory() const; // PropertyTreeModel* getDisplayTreeModel() const; /** @brief Emits statusUpdate() signal with the given @a message. */ void emitStatusUpdate( const QString& message ); rviz::DisplayGroup* getRootDisplayGroup() const; signals: /** * @brief Emitted at most once every 100ms. */ void timeChanged(); /** @brief Emitted whenever the display configuration changes. */ void configChanged(); /** @brief Emitted during file-loading and initialization to indicate progress. */ void statusUpdate( const QString& message ); }; }; rviz-1.12.4/src/python_bindings/sip/yaml_config_reader.sip000066400000000000000000000023551300447110700237010ustar00rootroot00000000000000namespace rviz { class YamlConfigReader /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** @brief Constructor. YamlConfigReader begins in an error state until a file or data string has been read successfully. */ YamlConfigReader(); /** @brief Read config data from a file. This potentially changes the return value sof error(), statusMessage(), and config(). */ void readFile( rviz::Config& config, const QString& filename ); /** @brief Read config data from a string. This potentially changes the return value sof error(), statusMessage(), and config(). */ void readString( rviz::Config& config, const QString& data, const QString& filename = "data string" ); /** @brief Read config data from a std::istream. This potentially changes the return value sof error(), statusMessage(), and config(). */ // void readStream( rviz::Config& config, std::istream& in, const QString& filename = "data stream" ); /** @brief Return true if the latest readFile() or readString() call had an error. */ bool error(); /** @brief Return an error message if the latest read call had an * error, or the empty string if there was no error. */ QString errorMessage(); }; }; rviz-1.12.4/src/python_bindings/sip/yaml_config_writer.sip000066400000000000000000000022721300447110700237510ustar00rootroot00000000000000namespace rviz { class YamlConfigWriter /NoDefaultCtors/ { %TypeHeaderCode #define ROS_PACKAGE_NAME "rviz" #include %End public: /** @brief Constructor. Writer starts in a non-error state with no status message. */ YamlConfigWriter(); /** @brief Write config data to a file. This potentially changes * the return values of error() and statusMessage(). */ void writeFile( const rviz::Config& config, const QString& filename ); /** @brief Write config data to a string, and return it. This * potentially changes the return values of error() and * statusMessage(). */ QString writeString( const rviz::Config& config, const QString& filename = "data string" ); /** @brief Write config data to a std::ostream. This potentially * changes the return values of error() and statusMessage(). */ // void writeStream( const rviz::Config& config, std::ostream& out, const QString& filename = "data stream" ); /** @brief Return true if the latest write operation had an error. */ bool error(); /** @brief Return an error message if the latest write call had an * error, or the empty string if there was no error. */ QString errorMessage(); }; }; rviz-1.12.4/src/rviz/000077500000000000000000000000001300447110700143475ustar00rootroot00000000000000rviz-1.12.4/src/rviz/CMakeLists.txt000066400000000000000000000110021300447110700171010ustar00rootroot00000000000000find_package(PkgConfig) pkg_check_modules(NEW_YAMLCPP yaml-cpp>=0.5) if(NEW_YAMLCPP_FOUND) add_definitions(-DRVIZ_HAVE_YAMLCPP_05) endif(NEW_YAMLCPP_FOUND) if(UNIX AND NOT APPLE) find_package(X11 REQUIRED) endif() add_subdirectory(default_plugin) include_directories(.) # Build the version number and other build-time constants into the # source for access at run-time. set(ENV_CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/env_config.cpp) set(RVIZ_VERSION ${rviz_VERSION}) message("making version ${RVIZ_VERSION}.") set(ROS_DISTRO $ENV{ROS_DISTRO}) configure_file(env_config.cpp.in ${ENV_CONFIG_FILE} @ONLY) # We create one lib with the C++... add_library(${PROJECT_NAME} bit_allocator.cpp config.cpp display.cpp display.cpp display_context.h display_factory.cpp display_group.cpp displays_panel.cpp failed_display.cpp failed_panel.cpp failed_tool.cpp failed_view_controller.cpp frame_manager.cpp load_resource.cpp frame_position_tracking_view_controller.cpp geometry.cpp help_panel.cpp image/ros_image_texture.cpp image/image_display_base.cpp loading_dialog.cpp message_filter_display.h mesh_loader.cpp new_object_dialog.cpp add_display_dialog.cpp ogre_helpers/apply_visibility_bits.cpp ogre_helpers/arrow.cpp ogre_helpers/axes.cpp ogre_helpers/billboard_line.cpp ogre_helpers/camera_base.cpp ogre_helpers/grid.cpp ogre_helpers/initialization.cpp ogre_helpers/line.cpp ogre_helpers/movable_text.cpp ogre_helpers/object.cpp ogre_helpers/ogre_logging.cpp ogre_helpers/ogre_render_queue_clearer.cpp ogre_helpers/orthographic.cpp ogre_helpers/point_cloud.cpp ogre_helpers/qt_ogre_render_window.cpp ogre_helpers/render_system.cpp ogre_helpers/render_widget.cpp ogre_helpers/shape.cpp ogre_helpers/mesh_shape.cpp ogre_helpers/stl_loader.cpp panel.cpp panel_dock_widget.cpp panel_factory.cpp properties/bool_property.cpp properties/color_editor.cpp properties/color_property.cpp properties/combo_box.cpp properties/display_visibility_property.cpp properties/display_group_visibility_property.cpp properties/editable_combo_box.cpp properties/editable_enum_property.cpp properties/enum_property.cpp properties/float_edit.cpp properties/float_property.cpp properties/int_property.cpp properties/line_edit_with_button.cpp properties/parse_color.cpp properties/property.cpp properties/property_tree_delegate.cpp properties/property_tree_model.cpp properties/property_tree_widget.cpp properties/property_tree_with_help.cpp properties/quaternion_property.cpp properties/ros_topic_property.cpp properties/splitter_handle.cpp properties/status_list.cpp properties/status_property.cpp properties/string_property.cpp properties/tf_frame_property.cpp properties/vector_property.cpp render_panel.cpp robot/robot_link.cpp robot/robot_joint.cpp robot/robot.cpp robot/tf_link_updater.cpp scaled_image_widget.cpp screenshot_dialog.cpp selection_panel.cpp selection/selection_handler.cpp selection/selection_manager.cpp splash_screen.cpp time_panel.cpp tool.cpp tool_manager.cpp uniform_string_stream.cpp view_controller.cpp view_manager.cpp views_panel.cpp visualization_frame.cpp visualization_manager.cpp visualizer_app.cpp wait_for_master_dialog.cpp widget_geometry_change_detector.cpp tool_properties_panel.cpp yaml_config_reader.cpp yaml_config_writer.cpp ${ENV_CONFIG_FILE} ) if(NOT WIN32) set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} ${catkin_LIBRARIES} ${QT_LIBRARIES} ${OGRE_OV_LIBRARIES_ABS} ${OPENGL_LIBRARIES} ${rviz_ADDITIONAL_LIBRARIES} ${X11_X11_LIB} assimp yaml-cpp ) if(APPLE) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") endif(APPLE) ########### The rviz executable ########### add_executable(executable main.cpp) if(NOT WIN32) set_target_properties(executable PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(executable ${PROJECT_NAME} ${QT_LIBRARIES} ${OGRE_OV_LIBRARIES_ABS}) set_target_properties(executable PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) install(TARGETS executable ${PROJECT_NAME} RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} ) install(DIRECTORY ./ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} FILES_MATCHING PATTERN "*.h") install(TARGETS executable DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}) rviz-1.12.4/src/rviz/add_display_dialog.cpp000066400000000000000000000453361300447110700206620ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "add_display_dialog.h" #include "rviz/load_resource.h" #include "display_factory.h" namespace rviz { // Utilities for grouping topics together struct LexicalTopicInfo { bool operator()(const ros::master::TopicInfo &a, const ros::master::TopicInfo &b) { return a.name < b.name; } }; /** * Return true if one topic is a subtopic of the other. * * A topic is a subtopic of another if a subset of its path exactly matches the * other. For example, /camera/image_raw/compressed is a subtopic of * /camera/image_raw but not /camera/image. * * @param base A valid ROS topic * * @param topic A valid ROS topic * * @return True if topic is a subtopic of base. False otherwise or if either * argument is an invalid ROS topic. */ bool isSubtopic( const std::string &base, const std::string &topic ) { std::string error; if ( !ros::names::validate(base, error) ) { ROS_ERROR_STREAM("isSubtopic() Invalid basename: " << error); return false; } if ( !ros::names::validate(topic, error) ) { ROS_ERROR_STREAM("isSubtopic() Invalid topic: " << error); return false; } std::string query = topic; while ( query != "/" ) { if ( query == base ) { return true; } query = ros::names::parentNamespace( query ); } return false; } struct PluginGroup { struct Info { QStringList topic_suffixes; QStringList datatypes; }; QString base_topic; // Map from plugin name to plugin data QMap plugins; }; void getPluginGroups( const QMap &datatype_plugins, QList *groups, QList *unvisualizable ) { ros::master::V_TopicInfo all_topics; ros::master::getTopics( all_topics ); std::sort( all_topics.begin(), all_topics.end(), LexicalTopicInfo() ); ros::master::V_TopicInfo::iterator topic_it; for ( topic_it = all_topics.begin(); topic_it != all_topics.end(); ++topic_it ) { QString topic = QString::fromStdString( topic_it->name ); QString datatype = QString::fromStdString( topic_it->datatype ); if ( datatype_plugins.contains( datatype ) ) { if ( groups->size() == 0 || !isSubtopic(groups->back().base_topic.toStdString(), topic.toStdString()) ) { PluginGroup pi; pi.base_topic = topic; groups->append( pi ); } PluginGroup &group = groups->back(); QString topic_suffix( "raw" ); if ( topic != group.base_topic ) { // Remove base_topic and leading slash topic_suffix = topic.right( topic.size() - group.base_topic.size() - 1 ); } const QList &plugin_names = datatype_plugins.values( datatype ); for ( int i = 0; i < plugin_names.size(); ++i ) { const QString &name = plugin_names[i]; PluginGroup::Info &info = group.plugins[name]; info.topic_suffixes.append( topic_suffix ); info.datatypes.append( datatype ); } } else { unvisualizable->append( *topic_it ); } } } // Dialog implementation AddDisplayDialog::AddDisplayDialog( DisplayFactory* factory, const QString& object_type, const QStringList& disallowed_display_names, const QStringList& disallowed_class_lookup_names, QString* lookup_name_output, QString* display_name_output, QString* topic_output, QString* datatype_output, QWidget* parent ) : QDialog( parent ) , factory_( factory ) , disallowed_display_names_( disallowed_display_names ) , disallowed_class_lookup_names_( disallowed_class_lookup_names ) , lookup_name_output_( lookup_name_output ) , display_name_output_( display_name_output ) , topic_output_( topic_output ) , datatype_output_( datatype_output ) { //***** Layout // Display Type group QGroupBox* type_box = new QGroupBox( "Create visualization" ); QLabel* description_label = new QLabel( "Description:" ); description_ = new QTextBrowser; description_->setMaximumHeight( 100 ); description_->setOpenExternalLinks( true ); DisplayTypeTree *display_tree = new DisplayTypeTree; display_tree->fillTree(factory); TopicDisplayWidget *topic_widget = new TopicDisplayWidget; topic_widget->fill(factory); tab_widget_ = new QTabWidget; display_tab_ = tab_widget_->addTab( display_tree, tr("By display type") ); topic_tab_ = tab_widget_->addTab( topic_widget, tr("By topic") ); QVBoxLayout *type_layout = new QVBoxLayout; type_layout->addWidget( tab_widget_ ); type_layout->addWidget( description_label ); type_layout->addWidget( description_ ); type_box->setLayout( type_layout ); // Display Name group QGroupBox* name_box; if( display_name_output_ ) { name_box = new QGroupBox( "Display Name" ); name_editor_ = new QLineEdit; QVBoxLayout* name_layout = new QVBoxLayout; name_layout->addWidget( name_editor_ ); name_box->setLayout( name_layout ); } // Buttons button_box_ = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal ); QVBoxLayout* main_layout = new QVBoxLayout; main_layout->addWidget( type_box ); if( display_name_output_ ) { main_layout->addWidget( name_box ); } main_layout->addWidget( button_box_ ); setLayout( main_layout ); //***** Connections connect( display_tree, SIGNAL( itemChanged( SelectionData* )), this, SLOT( onDisplaySelected( SelectionData* ))); connect( display_tree, SIGNAL( itemActivated( QTreeWidgetItem*, int )), this, SLOT( accept() )); connect( topic_widget, SIGNAL( itemChanged( SelectionData* )), this, SLOT( onTopicSelected( SelectionData* ))); connect( topic_widget, SIGNAL( itemActivated( QTreeWidgetItem*, int )), this, SLOT( accept() )); connect( button_box_, SIGNAL( accepted() ), this, SLOT( accept() )); connect( button_box_, SIGNAL( rejected() ), this, SLOT( reject() )); connect( tab_widget_, SIGNAL( currentChanged( int ) ), this, SLOT( onTabChanged( int ) )); if( display_name_output_ ) { connect( name_editor_, SIGNAL( textEdited( const QString& )), this, SLOT( onNameChanged() )); } button_box_->button( QDialogButtonBox::Ok )->setEnabled( isValid() ); } QSize AddDisplayDialog::sizeHint () const { return( QSize(500,660) ); } void AddDisplayDialog::onTabChanged( int index ) { updateDisplay(); } void AddDisplayDialog::onDisplaySelected( SelectionData *data) { display_data_ = *data; updateDisplay(); } void AddDisplayDialog::onTopicSelected( SelectionData *data ) { topic_data_ = *data; updateDisplay(); } void AddDisplayDialog::updateDisplay() { SelectionData *data = NULL; if ( tab_widget_->currentIndex() == topic_tab_ ) { data = &topic_data_; } else if ( tab_widget_->currentIndex() == display_tab_ ) { data = &display_data_; } else { ROS_WARN("Unknown tab index: %i", tab_widget_->currentIndex()); return; } QString html = "" + data->whats_this + ""; description_->setHtml( html ); lookup_name_ = data->lookup_name; if( display_name_output_ ) { name_editor_->setText( data->display_name ); } *topic_output_ = data->topic; *datatype_output_ = data->datatype; button_box_->button( QDialogButtonBox::Ok )->setEnabled( isValid() ); } bool AddDisplayDialog::isValid() { if( lookup_name_.size() == 0 ) { setError( "Select a Display type." ); return false; } if( display_name_output_ ) { QString display_name = name_editor_->text(); if( display_name.size() == 0 ) { setError( "Enter a name for the display." ); return false; } if( disallowed_display_names_.contains( display_name )) { setError( "Name in use. Display names must be unique." ); return false; } } setError( "" ); return true; } void AddDisplayDialog::setError( const QString& error_text ) { button_box_->button( QDialogButtonBox::Ok )->setToolTip( error_text ); } void AddDisplayDialog::onNameChanged() { button_box_->button( QDialogButtonBox::Ok )->setEnabled( isValid() ); } void AddDisplayDialog::accept() { if( isValid() ) { *lookup_name_output_ = lookup_name_; if( display_name_output_ ) { *display_name_output_ = name_editor_->text(); } QDialog::accept(); } } DisplayTypeTree::DisplayTypeTree() { setHeaderHidden( true ); connect(this, SIGNAL( currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* )), this, SLOT( onCurrentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* ))); } void DisplayTypeTree::onCurrentItemChanged(QTreeWidgetItem *curr, QTreeWidgetItem *prev) { // If display is selected, populate selection data. Otherwise, clear data. SelectionData sd; if ( curr->parent() != NULL ) { // Leave topic and datatype blank sd.whats_this = curr->whatsThis( 0 ); sd.lookup_name = curr->data( 0, Qt::UserRole).toString(); sd.display_name = curr->text( 0 ); } Q_EMIT itemChanged( &sd ); } void DisplayTypeTree::fillTree( Factory *factory ) { QIcon default_package_icon = loadPixmap( "package://rviz/icons/default_package_icon.png" ); QStringList classes = factory->getDeclaredClassIds(); classes.sort(); // Map from package names to the corresponding top-level tree widget items. std::map package_items; for( int i = 0; i < classes.size(); i++ ) { QString lookup_name = classes[ i ]; QString package = factory->getClassPackage( lookup_name ); QString description = factory->getClassDescription( lookup_name ); QString name = factory->getClassName( lookup_name ); QTreeWidgetItem* package_item; std::map::iterator mi; mi = package_items.find( package ); if( mi == package_items.end() ) { package_item = new QTreeWidgetItem( this ); package_item->setText( 0, package ); package_item->setIcon( 0, default_package_icon ); package_item->setExpanded( true ); package_items[ package ] = package_item; } else { package_item = (*mi).second; } QTreeWidgetItem* class_item = new QTreeWidgetItem( package_item ); class_item->setIcon( 0, factory->getIcon( lookup_name ) ); class_item->setText( 0, name ); class_item->setWhatsThis( 0, description ); // Store the lookup name for each class in the UserRole of the item. class_item->setData( 0, Qt::UserRole, lookup_name ); } } TopicDisplayWidget::TopicDisplayWidget() { tree_ = new QTreeWidget; tree_->setHeaderHidden( true ); tree_->setColumnCount( 2 ); tree_->header()->setStretchLastSection( false ); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) tree_->header()->setResizeMode( 0, QHeaderView::Stretch ); #else tree_->header()->setSectionResizeMode(0, QHeaderView::Stretch); #endif enable_hidden_box_ = new QCheckBox( "Show unvisualizable topics" ); enable_hidden_box_->setCheckState( Qt::Unchecked ); QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins( QMargins( 0, 0, 0, 0 ) ); layout->addWidget( tree_ ); layout->addWidget( enable_hidden_box_ ); connect( tree_, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(onCurrentItemChanged(QTreeWidgetItem*))); // Forward signals from tree_ connect( tree_, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SIGNAL(itemActivated(QTreeWidgetItem*, int)) ); // Connect signal from checkbox connect( enable_hidden_box_, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)) ); setLayout( layout ); } void TopicDisplayWidget::onCurrentItemChanged( QTreeWidgetItem* curr ) { // If plugin is selected, populate selection data. Otherwise, clear data. SelectionData sd; if ( curr->data( 1, Qt::UserRole ).isValid() ) { QTreeWidgetItem *parent = curr->parent(); sd.whats_this = curr->whatsThis( 0 ); sd.topic = parent->data( 0, Qt::UserRole ).toString(); sd.lookup_name = curr->data( 0, Qt::UserRole ).toString(); sd.display_name = curr->text( 0 ); QComboBox *combo = qobject_cast( tree_->itemWidget( curr, 1 ) ); if ( combo != NULL ) { QString combo_text = combo->currentText(); if ( combo_text != "raw" ) { sd.topic += "/" + combo_text; } sd.datatype = combo->itemData( combo->currentIndex() ).toString(); } else { sd.datatype = curr->data( 1, Qt::UserRole ).toString(); } } Q_EMIT itemChanged( &sd ); } void TopicDisplayWidget::onComboBoxClicked( QTreeWidgetItem *curr ) { tree_->setCurrentItem( curr ); } void TopicDisplayWidget::stateChanged( int state ) { bool hide_disabled = state == Qt::Unchecked; QTreeWidgetItemIterator it( tree_, QTreeWidgetItemIterator::Disabled ); for ( ; *it; ++it ) { QTreeWidgetItem *item = *it; item->setHidden( hide_disabled ); } } void TopicDisplayWidget::fill( DisplayFactory *factory ) { findPlugins( factory ); QList groups; QList unvisualizable; getPluginGroups( datatype_plugins_, &groups, &unvisualizable ); // Insert visualizable topics along with their plugins QList::const_iterator pg_it; for( pg_it = groups.begin(); pg_it < groups.end(); ++pg_it) { const PluginGroup &pg = *pg_it; QTreeWidgetItem *item = insertItem( pg.base_topic, false ); item->setData( 0, Qt::UserRole, pg.base_topic ); QMap::const_iterator it; for (it = pg.plugins.begin(); it != pg.plugins.end(); ++it) { const QString plugin_name = it.key(); const PluginGroup::Info &info = it.value(); QTreeWidgetItem *row = new QTreeWidgetItem( item ); row->setText( 0, factory->getClassName( plugin_name ) ); row->setIcon( 0, factory->getIcon( plugin_name ) ); row->setWhatsThis( 0, factory->getClassDescription( plugin_name ) ); row->setData( 0, Qt::UserRole, plugin_name ); row->setData( 1, Qt::UserRole, info.datatypes[0] ); if ( info.topic_suffixes.size() > 1 ) { EmbeddableComboBox *box = new EmbeddableComboBox( row, 1 ); connect( box, SIGNAL( itemClicked( QTreeWidgetItem*, int )), this, SLOT( onComboBoxClicked( QTreeWidgetItem* ))); for ( int i = 0; i < info.topic_suffixes.size(); ++i) { box->addItem( info.topic_suffixes[i], info.datatypes[i] ); } tree_->setItemWidget( row, 1, box ); tree_->setColumnWidth( 1, std::max( tree_->columnWidth( 1 ), box->width() )); } } } // Insert unvisualizable topics for ( int i = 0; i < unvisualizable.size(); ++i ) { const ros::master::TopicInfo &ti = unvisualizable.at( i ); QTreeWidgetItem *item = insertItem( QString::fromStdString( ti.name ), true ); } // Hide unvisualizable topics if necessary stateChanged( enable_hidden_box_->isChecked() ); } void TopicDisplayWidget::findPlugins( DisplayFactory *factory ) { // Build map from topic type to plugin by instantiating every plugin we have. QStringList lookup_names = factory->getDeclaredClassIds(); QStringList::iterator it; for (it = lookup_names.begin(); it != lookup_names.end(); ++it) { const QString &lookup_name = *it; // ROS_INFO("Class: %s", lookup_name.toStdString().c_str()); QSet topic_types = factory->getMessageTypes( lookup_name ); Q_FOREACH( QString topic_type, topic_types ) { // ROS_INFO("Type: %s", topic_type.toStdString().c_str()); datatype_plugins_.insertMulti( topic_type, lookup_name ); } } } QTreeWidgetItem* TopicDisplayWidget::insertItem( const QString &topic, bool disabled ) { QTreeWidgetItem *current = tree_->invisibleRootItem();; QStringList parts = topic.split( "/" ); for ( int part_ind = 1; part_ind < parts.size(); ++part_ind ) { QString part = "/" + parts[part_ind]; // If any child matches, use that one. bool match = false; for ( int c = 0; c < current->childCount(); ++c ) { QTreeWidgetItem *child = current->child( c ); if ( child->text( 0 ) == part && !child->data( 1, Qt::UserRole ).isValid() ) { match = true; current = child; break; } } // If no match, create a new child. if ( !match ) { QTreeWidgetItem *new_child = new QTreeWidgetItem( current ); // Only expand first few levels of the tree new_child->setExpanded( 3 > part_ind ); new_child->setText( 0, part ); new_child->setDisabled( disabled ); current = new_child; } } return current; } } // rviz rviz-1.12.4/src/rviz/add_display_dialog.h000066400000000000000000000156001300447110700203160ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ADD_DISPLAY_DIALOG_H #define RVIZ_ADD_DISPLAY_DIALOG_H #include #include #include #include #include "rviz/factory.h" class QTextBrowser; class QLineEdit; class QDialogButtonBox; class QLabel; class QCheckBox; namespace rviz { class DisplayFactory; class Display; /** * Meta-data needed to pick a plugin and optionally a topic. */ struct SelectionData { QString whats_this; QString lookup_name; QString display_name; QString topic; QString datatype; }; class AddDisplayDialog : public QDialog { Q_OBJECT public: /** Dialog for choosing a new object to load with a pluginlib ClassLoader. * * @param disallowed_display_names set of display names to prevent * the user from using. * * @param disallowed_class_lookup_names set of class lookup names to * prevent the user from selecting. Names found in the class loader * which are in this list will appear disabled. * * @param lookup_name_output Pointer to a string where dialog will * put the class lookup name chosen. * * @param display_name_output Pointer to a string where dialog will * put the display name entered, or NULL (default) if display * name entry field should not be shown. */ AddDisplayDialog( DisplayFactory* factory, const QString& object_type, const QStringList& disallowed_display_names, const QStringList& disallowed_class_lookup_names, QString* lookup_name_output, QString* display_name_output = 0, QString* topic_output = 0, QString* datatype_output = 0, QWidget* parent = 0 ); virtual QSize sizeHint () const; public Q_SLOTS: virtual void accept(); private Q_SLOTS: void onDisplaySelected( SelectionData *data); void onTopicSelected( SelectionData *data ); void onTabChanged( int index ); void onNameChanged(); private: /** Fill the tree widget with classes from the class loader. */ void fillTree( QTreeWidget* tree ); /** Returns true if entered display name is non-empty and unique and * if lookup name is non-empty. */ bool isValid(); /** Display an error message to the user, or clear the previous * error message if error_text is empty. */ void setError( const QString& error_text ); /** Populate text boxes based on current tab and selection */ void updateDisplay(); Factory* factory_; const QStringList& disallowed_display_names_; const QStringList& disallowed_class_lookup_names_; QString* lookup_name_output_; QString* display_name_output_; QString* topic_output_; QString* datatype_output_; /** Widget holding tabs */ QTabWidget *tab_widget_; /** Index of tab for selection by topic */ int topic_tab_; /** Index of tab for selection by display */ int display_tab_; /** Current data for display tab */ SelectionData display_data_; /** Current data for topic tab */ SelectionData topic_data_; /** Widget showing description of the class. */ QTextBrowser* description_; QLineEdit* name_editor_; /** Widget with OK and CANCEL buttons. */ QDialogButtonBox* button_box_; /** Current value of selected class-lookup name. Copied to * *lookup_name_output_ when "ok" is clicked. */ QString lookup_name_; }; /** @brief Widget for selecting a display by display type */ class DisplayTypeTree : public QTreeWidget { Q_OBJECT public: DisplayTypeTree(); void fillTree(Factory *factory); Q_SIGNALS: void itemChanged( SelectionData *selection ); private Q_SLOTS: void onCurrentItemChanged(QTreeWidgetItem *curr, QTreeWidgetItem *prev); }; /** @brief Widget for selecting a display by topic */ class TopicDisplayWidget : public QWidget { Q_OBJECT public: TopicDisplayWidget(); void fill(DisplayFactory *factory); Q_SIGNALS: void itemChanged( SelectionData *selection ); void itemActivated( QTreeWidgetItem *item, int column ); private Q_SLOTS: void stateChanged(int state); void onCurrentItemChanged( QTreeWidgetItem *curr ); void onComboBoxClicked( QTreeWidgetItem *curr ); private: void findPlugins( DisplayFactory* ); /** Insert a topic into the tree * * @param topic Topic to be inserted * @param disabled If true, set all created widgets as disabled */ QTreeWidgetItem* insertItem ( const QString &topic, bool disabled ); QTreeWidget *tree_; QCheckBox *enable_hidden_box_; // Map from ROS topic type to all displays that can visualize it. // One key may have multiple values. QMap datatype_plugins_; }; /** A combo box that can be inserted into a QTreeWidgetItem * * Identical to QComboBox except that when it clicks it emits a signal * containing the QTreeWidgetItem that it's given at construction. */ class EmbeddableComboBox : public QComboBox { Q_OBJECT public: EmbeddableComboBox(QTreeWidgetItem *parent, int col) : parent_( parent ), column_(col) { connect(this, SIGNAL( activated( int )), this, SLOT( onActivated( int ))); } Q_SIGNALS: void itemClicked( QTreeWidgetItem *item, int column ); private Q_SLOTS: void onActivated( int index ) { Q_EMIT itemClicked( parent_, column_ ); } private: QTreeWidgetItem *parent_; int column_; }; } //namespace rviz #endif // RVIZ_ADD_DISPLAY_DIALOG_H rviz-1.12.4/src/rviz/bit_allocator.cpp000066400000000000000000000040061300447110700176710ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/bit_allocator.h" namespace rviz { BitAllocator::BitAllocator() : allocated_bits_( 0 ) {} uint32_t BitAllocator::allocBit() { uint32_t mask = 1; for( int i = 0; i < 32; i++ ) { if( (mask & allocated_bits_) == 0 ) { allocated_bits_ |= mask; return mask; } mask <<= 1; } return 0; } void BitAllocator::freeBits( uint32_t bits ) { allocated_bits_ &= ~bits; } } // end namespace rviz rviz-1.12.4/src/rviz/bit_allocator.h000066400000000000000000000042161300447110700173410ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef BIT_ALLOCATOR_H #define BIT_ALLOCATOR_H #include namespace rviz { /** @brief Allocation manager for bit positions within a 32-bit word. */ class BitAllocator { public: /** @brief Constructor. All bits are free initially. */ BitAllocator(); /** @brief Return a uint32 with a single bit "on" (previously * unused), or a 0 if all bits are already allocated. */ uint32_t allocBit(); /** @brief Free the given bits. */ void freeBits( uint32_t bits ); private: uint32_t allocated_bits_; }; } // end namespace rviz #endif // BIT_ALLOCATOR_H rviz-1.12.4/src/rviz/class_id_recording_factory.h000066400000000000000000000060661300447110700220740ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef CLASS_ID_RECORDING_FACTORY_H #define CLASS_ID_RECORDING_FACTORY_H #include "rviz/factory.h" namespace rviz { template /** @brief Templated factory which informs objects created by it what their class identifier string was. calls a setClassId() function on * any instances created by a protected makeRaw() function (pure * virtual in this class).*/ class ClassIdRecordingFactory: public Factory { public: /** @brief Instantiate and return a instance of a subclass of Type using makeRaw(). * @param class_id A string identifying the class uniquely among * classes of its parent class. rviz::GridDisplay might be * rviz/Grid, for example. * @param error_return If non-NULL and there is an error, *error_return is set to a description of the problem. * @return A new instance of the class identified by class_id, or NULL if there was an error. * * If make() returns NULL and error_return is not NULL, * *error_return will be set. On success, *error_return will not be * changed. */ virtual Type* make( const QString& class_id, QString* error_return = NULL ) { Type* obj = makeRaw( class_id, error_return ); if( obj != NULL ) { obj->setClassId( class_id ); obj->setDescription( getClassDescription( class_id )); } return obj; } protected: virtual Type* makeRaw( const QString& class_id, QString* error_return = NULL ) = 0; }; } // end namespace rviz #endif // CLASS_ID_RECORDING_FACTORY_H rviz-1.12.4/src/rviz/config.cpp000066400000000000000000000220031300447110700163150ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/config.h" namespace rviz { //////////////////////////////////////////////////////////////////////////////////// // Config::Node internal data storage class //////////////////////////////////////////////////////////////////////////////////// class Config::Node { public: Node(); ~Node(); void setType( Config::Type new_type ); void deleteData(); typedef QMap ChildMap; typedef QList ChildList; Config::Type type_; union { ChildMap* map; ChildList* list; QVariant* value; } data_; }; Config::Node::Node() : type_( Empty ) { data_.map = NULL; } Config::Node::~Node() { deleteData(); } void Config::Node::deleteData() { switch( type_ ) { case Map: delete data_.map; break; case List: delete data_.list; break; case Value: delete data_.value; break; default: break; } data_.map = NULL; } void Config::Node::setType( Config::Type new_type ) { if( type_ == new_type ) { return; } deleteData(); type_ = new_type; switch( type_ ) { case Map: data_.map = new ChildMap; break; case List: data_.list = new ChildList; break; case Value: data_.value = new QVariant; break; default: break; } } //////////////////////////////////////////////////////////////////////////////////// // Config wrapper class //////////////////////////////////////////////////////////////////////////////////// Config::Config() : node_( new Config::Node() ) {} Config::Config( const Config& source ) : node_( source.node_ ) {} Config::Config( QVariant value ) : node_( new Config::Node() ) { setValue( value ); } Config::Config( NodePtr node ) : node_( node ) {} void Config::copy( const Config& source ) { if( !source.isValid() ) { node_ = NodePtr(); return; } setType( source.getType() ); switch( source.getType() ) { case Map: { MapIterator iter = source.mapIterator(); while( iter.isValid() ) { mapMakeChild( iter.currentKey() ).copy( iter.currentChild() ); iter.advance(); } break; } case List: { int num_children = source.listLength(); for( int i = 0; i < num_children; i++ ) { listAppendNew().copy( source.listChildAt( i )); } } case Value: setValue( source.getValue() ); break; default: break; } } Config Config::invalidConfig() { return Config( NodePtr() ); } Config::Type Config::getType() const { return isValid() ? node_->type_ : Invalid; } void Config::setType( Type new_type ) { if( new_type == Invalid ) { node_ = NodePtr(); } else { makeValid(); node_->setType( new_type ); } } void Config::mapSetValue( const QString& key, QVariant value ) { mapMakeChild( key ).setValue( value ); } Config Config::mapMakeChild( const QString& key ) { Config child; makeValid(); node_->setType( Map ); (*node_->data_.map)[ key ] = child.node_; return child; } Config Config::mapGetChild( const QString& key ) const { if( node_.get() == NULL || node_->type_ != Map ) { return invalidConfig(); } Node::ChildMap::const_iterator iter = node_->data_.map->find( key ); if( iter == node_->data_.map->end() ) { return invalidConfig(); } else { return Config( iter.value() ); } } bool Config::mapGetValue( const QString& key, QVariant *value_out ) const { Config child = mapGetChild( key ); if( child.getType() == Value ) // getType() checks for validity as well. { *value_out = child.getValue(); return true; } return false; } bool Config::mapGetInt( const QString& key, int *value_out ) const { QVariant v; if( mapGetValue( key, &v ) && (v.type() == QVariant::Int || v.type() == QVariant::String )) { bool ok; int i = v.toInt( &ok ); if( ok ) { *value_out = i; return true; } } return false; } bool Config::mapGetFloat( const QString& key, float *value_out ) const { QVariant v; if( mapGetValue( key, &v ) && (int(v.type()) == int(QMetaType::Float) || v.type() == QVariant::Double || v.type() == QVariant::String )) { bool ok; float f = v.toFloat( &ok ); if( ok ) { *value_out = f; return true; } QString as_string = v.toString(); // Try as European, e.g. 1.234,56 rather than 1,234.56 QLocale german(QLocale::German); f = german.toFloat(as_string, &ok); if ( ok ) { *value_out = f; return true; } } return false; } bool Config::mapGetBool( const QString& key, bool *value_out ) const { QVariant v; if( mapGetValue( key, &v ) && (v.type() == QVariant::Bool || v.type() == QVariant::String )) { *value_out = v.toBool(); return true; } return false; } bool Config::mapGetString( const QString& key, QString *value_out ) const { QVariant v; if( mapGetValue( key, &v ) && v.type() == QVariant::String ) { *value_out = v.toString(); return true; } return false; } void Config::makeValid() { if( node_.get() == NULL ) { node_.reset( new Node() ); } } bool Config::isValid() const { return node_.get() != NULL; } void Config::setValue( const QVariant& value ) { makeValid(); node_->setType( Value ); *node_->data_.value = value; } QVariant Config::getValue() const { return ( isValid() && node_->type_ == Value ) ? *node_->data_.value : QVariant(); } int Config::listLength() const { return ( isValid() && node_->type_ == List ) ? node_->data_.list->size() : 0; } Config Config::listChildAt( int i ) const { if( isValid() && node_->type_ == List && i >= 0 && i < node_->data_.list->size() ) { return Config( node_->data_.list->at( i )); } else { return invalidConfig(); } } Config Config::listAppendNew() { Config child; setType( List ); node_->data_.list->append( child.node_ ); return child; } Config::MapIterator Config::mapIterator() const { // Create a new (invalid) iterator. Config::MapIterator iter; if( node_.get() == NULL || node_->type_ != Map ) { // Force the node to be invalid, since this node does not have a map. iter.node_.reset(); } else { // Copy this config's node reference into the iterator's node reference. iter.node_ = node_; iter.start(); } return iter; } Config::MapIterator::MapIterator() : iterator_valid_( false ) {} void Config::MapIterator::advance() { if( node_.get() == NULL || node_->type_ != Config::Map ) { iterator_valid_ = false; return; } if( !iterator_valid_ ) { iterator_ = node_->data_.map->begin(); iterator_valid_ = true; } else { iterator_++; } } bool Config::MapIterator::isValid() { if( node_.get() == NULL || node_->type_ != Config::Map ) { iterator_valid_ = false; return false; } if( !iterator_valid_ ) { return false; } else { return iterator_ != node_->data_.map->end(); } } void Config::MapIterator::start() { if( node_.get() == NULL || node_->type_ != Config::Map ) { iterator_valid_ = false; return; } iterator_ = node_->data_.map->begin(); iterator_valid_ = true; } QString Config::MapIterator::currentKey() { if( node_.get() == NULL || node_->type_ != Config::Map || !iterator_valid_ ) { iterator_valid_ = false; return QString(); } return iterator_.key(); } Config Config::MapIterator::currentChild() { if( node_.get() == NULL || node_->type_ != Config::Map || !iterator_valid_ ) { iterator_valid_ = false; return Config(); } return Config( iterator_.value() ); } } // end namespace rviz rviz-1.12.4/src/rviz/config.h000066400000000000000000000303431300447110700157700ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef CONFIG_H #define CONFIG_H #include #include #include #include #include #include namespace rviz { /** @brief Configuration data storage class. * * The purpose of the Config class is to provide a flexible place to * store configuration data during saving and loading which is * independent of the particular storage format (like YAML or XML or * INI). The data is stored in a tree structure, supporting both * named and numerically-indexed children. Leaves in the tree store * QVariants, with convenience functions for int, float, QString, and * bool types. * * Config instances are references to an internal "Node" class which * actually stores the data and the tree structure. Nodes are * reference-counted and deletion is handled automatically. This * makes it safe to hold a reference to a portion of a Config tree to * use later, because the internal Nodes beneath the saved reference * will not be destroyed when the root of the tree goes out of scope. * * Config objects can be used on their own for generic hierarchical * data storage, but they are intended to be used with reader and * writer classes. Currently there is just YAML support, as that is * all that RViz supports right now. Those classes are * YamlConfigReader and YamlConfigWriter. * * Typical use for reading looks like this: * * YamlConfigReader reader; * Config config; * reader.readFile( config, "my_file.yaml" ); * if( !reader.error() ) * { * int height, width; * if( config.mapGetString( "Height", &height ) && * config.mapGetString( "Width", &width )) * { * resize( width, height ); * } * * Config file_list_config = config.mapGetChild( "Files" ); * filenames_.clear(); * int num_files = file_list_config.listLength(); * for( int i = 0; i < num_files; i++ ) * { * filenames_.push_back( file_list_config.listChildAt( i ).getValue().toString() ); * } * } * else * { * printf( "%s", qPrintable( reader.errorMessage() )); * } * * For writing, the same program might use this: * * Config config; * config.mapSetValue( "Height", height() ); * config.mapSetValue( "Width", width() ); * Config file_list_config = config.mapMakeChild( "Files" ); * for( int i = 0; i < filenames_.size(); i++ ) * { * file_list_config.listAppendNew().setValue( filenames_[ i ]); * } * * YamlConfigWriter writer; * writer.writeFile( config, "my_file.yaml" ); * * if( writer.error() ) * { * printf( "%s", qPrintable( writer.errorMessage() )); * } * * setType() can be used to set the type of a given node (Map, List, * Value, or Empty), but it is often unnecessary. All functions which * add or change data (mapSetValue(), mapMakeChild(), setValue(), and * listAppendNew()) internally call setType() to ensure the node has * the right type for the operation. If setType() is called with the * same type that the node already has, nothing happens. If it needs * to change the type of the node, any data stored in the node is * destroyed (except for child nodes which are referenced by other * existing Config objects). */ class Config { private: class Node; typedef boost::shared_ptr NodePtr; public: /** @brief Default constructor. Creates an empty config object. */ Config(); /** @brief Copy constructor. Copies only the reference to the data, not the data itself. */ Config( const Config& source ); /** @brief Convenience constructor, makes a Value type Config object with the given value. */ Config( QVariant value ); /** @brief Make this a deep copy of source. */ void copy( const Config& source ); /** @brief Possible types a Config Node can have are Map, List, * Value, and Empty. Invalid means the Config object does not * point to a Node at all. * * Invalid Config objects are returned by data access functions when * the data does not exist, like listChildAt(7) on a list of length * 3, or mapGetChild("foo") on a Value Node. */ enum Type { Map, List, Value, Empty, Invalid }; /** @brief Return the Type of the referenced Node, or Invalid if this Config does not refer to a Node at all. */ Type getType() const; /** @brief Set the type of this Config Node. * * If @a new_type is Invalid, this de-references the node and makes * the Config object invalid. If the new type is different from the * old type, this deletes the existing data in the Node and changes * the Node's type to @new_type. If this does not change the type * of the Node, no data is deleted and nothing is changed. * * If this Config is currently invalid and @a new_type is not * Invalid, this will create a new Node and reference it. */ void setType( Type new_type ); /** @brief Returns true if the internal Node reference is valid, false if not. Same as (getType() != Invalid). */ bool isValid() const; /** @brief Set a named child to the given value. * * Since QVariant has constructors for int, float, bool, QString, * and other supported types, you can call mapSetValue() directly * with your data in most cases: * * config.mapSetValue( "Size", 13 ); * config.mapSetValue( "Name", "Humphrey" ); * * mapSetValue( key, value ) is the same as mapMakeChild( key ).setValue( value ). * * This forces the referenced Node to have type Map. */ void mapSetValue( const QString& key, QVariant value ); /** @brief Create a child node stored with the given @a key, and return the child. * * This forces the referenced Node to have type Map. */ Config mapMakeChild( const QString& key ); /** @brief If the referenced Node is a Map and it has a child with * the given key, return a reference to the child. If the reference * is invalid or the Node has a different Type, return an invalid * Config. */ Config mapGetChild( const QString& key ) const; /** @brief Convenience function for looking up a named value. * * If a Value Node with the given @key is a child of this Node, set * value_out to the given value and return true. * * If the Config is invalid or the Node is not a Map, returns an * Invalid Config. */ bool mapGetValue( const QString& key, QVariant *value_out ) const; /** @brief Convenience function for looking up a named integer. * * If a Value Node with the given @key is a child of this Node, and * the Value is either an int or a string-ified int, set value_out * to the integer and return true. * * If the Config is invalid or the Node is not a Map, returns an * Invalid Config. */ bool mapGetInt( const QString& key, int *value_out ) const; /** @brief Convenience function for looking up a named float. * * If a Value Node with the given @key is a child of this Node, and * the Value is either a float, a double or a string-ified float or * double, set value_out to the float and return true. * * If the Config is invalid or the Node is not a Map, returns an * Invalid Config. */ bool mapGetFloat( const QString& key, float *value_out ) const; /** @brief Convenience function for looking up a named boolean. * * If a Value Node with the given @key is a child of this Node, and * the Value is either a bool or a string-ified bool, set value_out * to the bool and return true. * * If the Config is invalid or the Node is not a Map, returns an * Invalid Config. */ bool mapGetBool( const QString& key, bool *value_out ) const; /** @brief Convenience function for looking up a named string. * * If a Value Node with the given @key is a child of this Node, and * the Value is a string, set value_out to the string and return * true. * * If the Config is invalid or the Node is not a Map, returns an * Invalid Config. */ bool mapGetString( const QString& key, QString *value_out ) const; /** @brief Ensures this is a valid Config object, sets the type to * Value then sets the value. */ void setValue( const QVariant& value ); /** @brief If this config object is valid and is a Value type, this returns its value. * Otherwise it returns an invalid QVariant. */ QVariant getValue() const; /** @brief Returns the length of the List in this Node, or 0 if this * Node does not have type List. */ int listLength() const; /** @brief Return the @a i'th child in the list, if the referenced * Node has type List. Returns an Invalid Config if the type is not * List or if @a i is not a valid index into it. */ Config listChildAt( int i ) const; /** @brief Ensure the referenced Node is of type List, append a new * Empty Node to the end of the list, and return a reference to the * new Node. */ Config listAppendNew(); /** @brief Iterator class for looping over all entries in a Map type Config Node. * * Typical usage: * * Config config; * display->save( config ); // Write display's data into config. * for( Config::MapIterator iter = config.mapIterator(); iter.isValid(); iter.advance() ) * { * QString key = iter.currentKey(); * Config child = iter.currentChild(); * printf( "key %s has value %s.\n", qPrintable( key ), qPrintable( child.getValue().toString() )); * } * * Maps are stored in alphabetical order of their keys, and * MapIterator uses this same order. */ class MapIterator { public: /** @brief Advance iterator to next entry. */ void advance(); /** @brief Return true if the iterator currently points to a valid entry, false if not. * * This is how you tell if your loop over entries is at the end. */ bool isValid(); /** @brief Resets the iterator to the start of the map. */ void start(); /** @brief Return the name of the current map entry. */ QString currentKey(); /** @brief Return a Config reference to the current map entry. */ Config currentChild(); private: /** @brief Private constructor enforces that MapIterators are only * made by their friend the Config class. */ MapIterator(); Config::NodePtr node_; QMap::const_iterator iterator_; bool iterator_valid_; friend class Config; }; /** @brief Return a new iterator for looping over key/value pairs. * * The returned MapIterator is initialized to point at the start of the map. * * If this Config is Invalid or if its Node is not a Map, this * returns a MapIterator for which isValid() always returns * false. */ MapIterator mapIterator() const; private: Config( NodePtr node ); static Config invalidConfig(); /** @brief If the node pointer is NULL, this sets it to a new empty node. */ void makeValid(); NodePtr node_; friend class MapIterator; }; } // end namespace rviz #endif // CONFIG_H rviz-1.12.4/src/rviz/default_plugin/000077500000000000000000000000001300447110700173515ustar00rootroot00000000000000rviz-1.12.4/src/rviz/default_plugin/CMakeLists.txt000066400000000000000000000055151300447110700221170ustar00rootroot00000000000000include_directories(.) set(SOURCE_FILES axes_display.cpp camera_display.cpp depth_cloud_display.cpp depth_cloud_mld.cpp effort_display.cpp effort_visual.cpp fluid_pressure_display.cpp grid_cells_display.cpp grid_display.cpp illuminance_display.cpp image_display.cpp interactive_marker_display.cpp interactive_markers/integer_action.cpp interactive_markers/interactive_marker_control.cpp interactive_markers/interactive_marker.cpp laser_scan_display.cpp map_display.cpp marker_array_display.cpp marker_display.cpp markers/arrow_marker.cpp markers/line_list_marker.cpp markers/line_strip_marker.cpp markers/marker_base.cpp markers/marker_selection_handler.cpp markers/mesh_resource_marker.cpp markers/points_marker.cpp markers/shape_marker.cpp markers/text_view_facing_marker.cpp markers/triangle_list_marker.cpp odometry_display.cpp path_display.cpp point_display.cpp point_visual.cpp point_cloud2_display.cpp point_cloud_common.cpp point_cloud_display.cpp point_cloud_transformer.h point_cloud_transformers.cpp polygon_display.cpp pose_array_display.cpp pose_display.cpp range_display.cpp relative_humidity_display.cpp robot_model_display.cpp temperature_display.cpp tf_display.cpp tools/focus_tool.cpp tools/measure_tool.cpp tools/move_tool.cpp tools/point_tool.cpp tools/pose_tool.cpp tools/goal_tool.cpp tools/initial_pose_tool.cpp tools/selection_tool.cpp tools/interaction_tool.cpp view_controllers/orbit_view_controller.cpp view_controllers/xy_orbit_view_controller.cpp view_controllers/third_person_follower_view_controller.cpp view_controllers/fixed_orientation_ortho_view_controller.cpp view_controllers/fps_view_controller.cpp wrench_display.cpp wrench_visual.cpp ) add_library(${rviz_DEFAULT_PLUGIN_LIBRARY_TARGET_NAME} ${SOURCE_FILES}) if(NOT WIN32) set_target_properties(${rviz_DEFAULT_PLUGIN_LIBRARY_TARGET_NAME} PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(${rviz_DEFAULT_PLUGIN_LIBRARY_TARGET_NAME} ${PROJECT_NAME} ${Boost_LIBRARIES} ${catkin_LIBRARIES} ${OGRE_OV_LIBRARIES_ABS} ${QT_LIBRARIES} ) install(TARGETS ${rviz_DEFAULT_PLUGIN_LIBRARY_TARGET_NAME} ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}) # Generate to the devel space so the extras file can include it from the devel space. file(GENERATE OUTPUT "${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_SHARE_DESTINATION}/cmake/default_plugin_location.cmake" CONTENT "set(rviz_DEFAULT_PLUGIN_FILE_NAME $)" ) # Install from the devel space to the install space. install(FILES "${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_SHARE_DESTINATION}/cmake/default_plugin_location.cmake" DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/cmake ) rviz-1.12.4/src/rviz/default_plugin/axes_display.cpp000066400000000000000000000103761300447110700225510ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/properties/float_property.h" #include "rviz/properties/tf_frame_property.h" #include "axes_display.h" namespace rviz { AxesDisplay::AxesDisplay() : Display() , axes_( 0 ) { frame_property_ = new TfFrameProperty( "Reference Frame", TfFrameProperty::FIXED_FRAME_STRING, "The TF frame these axes will use for their origin.", this, NULL, true ); length_property_ = new FloatProperty( "Length", 1.0, "Length of each axis, in meters.", this, SLOT( updateShape() )); length_property_->setMin( 0.0001 ); radius_property_ = new FloatProperty( "Radius", 0.1, "Radius of each axis, in meters.", this, SLOT( updateShape() )); radius_property_->setMin( 0.0001 ); } AxesDisplay::~AxesDisplay() { delete axes_; } void AxesDisplay::onInitialize() { frame_property_->setFrameManager( context_->getFrameManager() ); axes_ = new Axes( scene_manager_, 0, length_property_->getFloat(), radius_property_->getFloat() ); axes_->getSceneNode()->setVisible( isEnabled() ); } void AxesDisplay::onEnable() { axes_->getSceneNode()->setVisible( true ); } void AxesDisplay::onDisable() { axes_->getSceneNode()->setVisible( false ); } void AxesDisplay::updateShape() { axes_->set( length_property_->getFloat(), radius_property_->getFloat() ); context_->queueRender(); } void AxesDisplay::update( float dt, float ros_dt ) { QString qframe = frame_property_->getFrame(); std::string frame = qframe.toStdString(); Ogre::Vector3 position; Ogre::Quaternion orientation; if( context_->getFrameManager()->getTransform( frame, ros::Time(), position, orientation )) { axes_->setPosition( position ); axes_->setOrientation( orientation ); setStatus( StatusProperty::Ok, "Transform", "Transform OK" ); } else { std::string error; if( context_->getFrameManager()->transformHasProblems( frame, ros::Time(), error )) { setStatus( StatusProperty::Error, "Transform", QString::fromStdString( error )); } else { setStatus( StatusProperty::Error, "Transform", "Could not transform from [" + qframe + "] to Fixed Frame [" + fixed_frame_ + "] for an unknown reason" ); } } } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::AxesDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/axes_display.h000066400000000000000000000051301300447110700222060ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_AXES_DISPLAY_H #define RVIZ_AXES_DISPLAY_H #include "rviz/display.h" namespace rviz { class Axes; class FloatProperty; class TfFrameProperty; /** @brief Displays a set of XYZ axes at the origin of a chosen frame. */ class AxesDisplay: public Display { Q_OBJECT public: AxesDisplay(); virtual ~AxesDisplay(); void onInitialize(); /** * \brief Set the parameters for the axes * @param length Length of each axis * @param radius Radius of each axis */ void set( float length, float radius ); // Overrides from Display virtual void update(float dt, float ros_dt); protected: // overrides from Display virtual void onEnable(); virtual void onDisable(); private Q_SLOTS: /** @brief Update the length and radius of the axes object from property values. */ void updateShape(); private: Axes* axes_; ///< Handles actually drawing the axes FloatProperty* length_property_; FloatProperty* radius_property_; TfFrameProperty* frame_property_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/camera_display.cpp000066400000000000000000000414431300447110700230400ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rviz/bit_allocator.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/int_property.h" #include "rviz/properties/ros_topic_property.h" #include "rviz/render_panel.h" #include "rviz/uniform_string_stream.h" #include "rviz/validate_floats.h" #include "rviz/display_context.h" #include "rviz/properties/display_group_visibility_property.h" #include "rviz/load_resource.h" #include #include "camera_display.h" namespace rviz { const QString CameraDisplay::BACKGROUND( "background" ); const QString CameraDisplay::OVERLAY( "overlay" ); const QString CameraDisplay::BOTH( "background and overlay" ); bool validateFloats(const sensor_msgs::CameraInfo& msg) { bool valid = true; valid = valid && validateFloats( msg.D ); valid = valid && validateFloats( msg.K ); valid = valid && validateFloats( msg.R ); valid = valid && validateFloats( msg.P ); return valid; } CameraDisplay::CameraDisplay() : ImageDisplayBase() , texture_() , render_panel_( 0 ) , caminfo_tf_filter_( 0 ) , new_caminfo_( false ) , force_render_( false ) , caminfo_ok_(false) { image_position_property_ = new EnumProperty( "Image Rendering", BOTH, "Render the image behind all other geometry or overlay it on top, or both.", this, SLOT( forceRender() )); image_position_property_->addOption( BACKGROUND ); image_position_property_->addOption( OVERLAY ); image_position_property_->addOption( BOTH ); alpha_property_ = new FloatProperty( "Overlay Alpha", 0.5, "The amount of transparency to apply to the camera image when rendered as overlay.", this, SLOT( updateAlpha() )); alpha_property_->setMin( 0 ); alpha_property_->setMax( 1 ); zoom_property_ = new FloatProperty( "Zoom Factor", 1.0, "Set a zoom factor below 1 to see a larger part of the world, above 1 to magnify the image.", this, SLOT( forceRender() )); zoom_property_->setMin( 0.00001 ); zoom_property_->setMax( 100000 ); } CameraDisplay::~CameraDisplay() { if ( initialized() ) { render_panel_->getRenderWindow()->removeListener( this ); unsubscribe(); caminfo_tf_filter_->clear(); //workaround. delete results in a later crash render_panel_->hide(); //delete render_panel_; delete bg_screen_rect_; delete fg_screen_rect_; bg_scene_node_->getParentSceneNode()->removeAndDestroyChild( bg_scene_node_->getName() ); fg_scene_node_->getParentSceneNode()->removeAndDestroyChild( fg_scene_node_->getName() ); delete caminfo_tf_filter_; context_->visibilityBits()->freeBits(vis_bit_); } } void CameraDisplay::onInitialize() { ImageDisplayBase::onInitialize(); caminfo_tf_filter_ = new tf::MessageFilter( *context_->getTFClient(), fixed_frame_.toStdString(), queue_size_property_->getInt(), update_nh_ ); bg_scene_node_ = scene_node_->createChildSceneNode(); fg_scene_node_ = scene_node_->createChildSceneNode(); { static int count = 0; UniformStringStream ss; ss << "CameraDisplayObject" << count++; //background rectangle bg_screen_rect_ = new Ogre::Rectangle2D(true); bg_screen_rect_->setCorners(-1.0f, 1.0f, 1.0f, -1.0f); ss << "Material"; bg_material_ = Ogre::MaterialManager::getSingleton().create( ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); bg_material_->setDepthWriteEnabled(false); bg_material_->setReceiveShadows(false); bg_material_->setDepthCheckEnabled(false); bg_material_->getTechnique(0)->setLightingEnabled(false); Ogre::TextureUnitState* tu = bg_material_->getTechnique(0)->getPass(0)->createTextureUnitState(); tu->setTextureName(texture_.getTexture()->getName()); tu->setTextureFiltering( Ogre::TFO_NONE ); tu->setAlphaOperation( Ogre::LBX_SOURCE1, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, 0.0 ); bg_material_->setCullingMode(Ogre::CULL_NONE); bg_material_->setSceneBlending( Ogre::SBT_REPLACE ); Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); bg_screen_rect_->setRenderQueueGroup(Ogre::RENDER_QUEUE_BACKGROUND); bg_screen_rect_->setBoundingBox(aabInf); bg_screen_rect_->setMaterial(bg_material_->getName()); bg_scene_node_->attachObject(bg_screen_rect_); bg_scene_node_->setVisible(false); //overlay rectangle fg_screen_rect_ = new Ogre::Rectangle2D(true); fg_screen_rect_->setCorners(-1.0f, 1.0f, 1.0f, -1.0f); fg_material_ = bg_material_->clone( ss.str()+"fg" ); fg_screen_rect_->setBoundingBox(aabInf); fg_screen_rect_->setMaterial(fg_material_->getName()); fg_material_->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); fg_screen_rect_->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - 1); fg_scene_node_->attachObject(fg_screen_rect_); fg_scene_node_->setVisible(false); } updateAlpha(); render_panel_ = new RenderPanel(); render_panel_->getRenderWindow()->addListener( this ); render_panel_->getRenderWindow()->setAutoUpdated(false); render_panel_->getRenderWindow()->setActive( false ); render_panel_->resize( 640, 480 ); render_panel_->initialize( context_->getSceneManager(), context_ ); setAssociatedWidget( render_panel_ ); render_panel_->setAutoRender(false); render_panel_->setOverlaysEnabled(false); render_panel_->getCamera()->setNearClipDistance( 0.01f ); caminfo_tf_filter_->connectInput(caminfo_sub_); caminfo_tf_filter_->registerCallback(boost::bind(&CameraDisplay::caminfoCallback, this, _1)); //context_->getFrameManager()->registerFilterForTransformStatusCheck(caminfo_tf_filter_, this); vis_bit_ = context_->visibilityBits()->allocBit(); render_panel_->getViewport()->setVisibilityMask( vis_bit_ ); visibility_property_ = new DisplayGroupVisibilityProperty( vis_bit_, context_->getRootDisplayGroup(), this, "Visibility", true, "Changes the visibility of other Displays in the camera view."); visibility_property_->setIcon( loadPixmap("package://rviz/icons/visibility.svg",true) ); this->addChild( visibility_property_, 0 ); } void CameraDisplay::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { QString image_position = image_position_property_->getString(); bg_scene_node_->setVisible( caminfo_ok_ && (image_position == BACKGROUND || image_position == BOTH) ); fg_scene_node_->setVisible( caminfo_ok_ && (image_position == OVERLAY || image_position == BOTH) ); // set view flags on all displays visibility_property_->update(); } void CameraDisplay::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { bg_scene_node_->setVisible( false ); fg_scene_node_->setVisible( false ); } void CameraDisplay::onEnable() { subscribe(); render_panel_->getRenderWindow()->setActive(true); } void CameraDisplay::onDisable() { render_panel_->getRenderWindow()->setActive(false); unsubscribe(); clear(); } void CameraDisplay::subscribe() { if ( (!isEnabled()) || (topic_property_->getTopicStd().empty()) ) { return; } std::string target_frame = fixed_frame_.toStdString(); ImageDisplayBase::enableTFFilter(target_frame); ImageDisplayBase::subscribe(); std::string topic = topic_property_->getTopicStd(); std::string caminfo_topic = image_transport::getCameraInfoTopic(topic_property_->getTopicStd()); try { caminfo_sub_.subscribe( update_nh_, caminfo_topic, 1 ); setStatus( StatusProperty::Ok, "Camera Info", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Camera Info", QString( "Error subscribing: ") + e.what() ); } } void CameraDisplay::unsubscribe() { ImageDisplayBase::unsubscribe(); caminfo_sub_.unsubscribe(); } void CameraDisplay::updateAlpha() { float alpha = alpha_property_->getFloat(); Ogre::Pass* pass = fg_material_->getTechnique( 0 )->getPass( 0 ); if( pass->getNumTextureUnitStates() > 0 ) { Ogre::TextureUnitState* tex_unit = pass->getTextureUnitState( 0 ); tex_unit->setAlphaOperation( Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, alpha ); } else { fg_material_->setAmbient( Ogre::ColourValue( 0.0f, 1.0f, 1.0f, alpha )); fg_material_->setDiffuse( Ogre::ColourValue( 0.0f, 1.0f, 1.0f, alpha )); } force_render_ = true; context_->queueRender(); } void CameraDisplay::forceRender() { force_render_ = true; context_->queueRender(); } void CameraDisplay::updateQueueSize() { caminfo_tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); ImageDisplayBase::updateQueueSize(); } void CameraDisplay::clear() { texture_.clear(); force_render_ = true; context_->queueRender(); new_caminfo_ = false; current_caminfo_.reset(); setStatus( StatusProperty::Warn, "Camera Info", "No CameraInfo received on [" + QString::fromStdString( caminfo_sub_.getTopic() ) + "]. Topic may not exist."); setStatus( StatusProperty::Warn, "Image", "No Image received"); render_panel_->getCamera()->setPosition( Ogre::Vector3( 999999, 999999, 999999 )); } void CameraDisplay::update( float wall_dt, float ros_dt ) { try { if( texture_.update() || force_render_ ) { caminfo_ok_ = updateCamera(); force_render_ = false; } } catch( UnsupportedImageEncoding& e ) { setStatus( StatusProperty::Error, "Image", e.what() ); } render_panel_->getRenderWindow()->update(); } bool CameraDisplay::updateCamera() { sensor_msgs::CameraInfo::ConstPtr info; sensor_msgs::Image::ConstPtr image; { boost::mutex::scoped_lock lock( caminfo_mutex_ ); info = current_caminfo_; image = texture_.getImage(); } if( !info || !image ) { return false; } if( !validateFloats( *info )) { setStatus( StatusProperty::Error, "Camera Info", "Contains invalid floating point values (nans or infs)" ); return false; } // if we're in 'exact' time mode, only show image if the time is exactly right ros::Time rviz_time = context_->getFrameManager()->getTime(); if ( context_->getFrameManager()->getSyncMode() == FrameManager::SyncExact && rviz_time != image->header.stamp ) { std::ostringstream s; s << "Time-syncing active and no image at timestamp " << rviz_time.toSec() << "."; setStatus( StatusProperty::Warn, "Time", s.str().c_str() ); return false; } Ogre::Vector3 position; Ogre::Quaternion orientation; context_->getFrameManager()->getTransform( image->header.frame_id, image->header.stamp, position, orientation ); //printf( "CameraDisplay:updateCamera(): pos = %.2f, %.2f, %.2f.\n", position.x, position.y, position.z ); // convert vision (Z-forward) frame to ogre frame (Z-out) orientation = orientation * Ogre::Quaternion( Ogre::Degree( 180 ), Ogre::Vector3::UNIT_X ); float img_width = info->width; float img_height = info->height; // If the image width is 0 due to a malformed caminfo, try to grab the width from the image. if( img_width == 0 ) { ROS_DEBUG( "Malformed CameraInfo on camera [%s], width = 0", qPrintable( getName() )); img_width = texture_.getWidth(); } if (img_height == 0) { ROS_DEBUG( "Malformed CameraInfo on camera [%s], height = 0", qPrintable( getName() )); img_height = texture_.getHeight(); } if( img_height == 0.0 || img_width == 0.0 ) { setStatus( StatusProperty::Error, "Camera Info", "Could not determine width/height of image due to malformed CameraInfo (either width or height is 0)" ); return false; } double fx = info->P[0]; double fy = info->P[5]; float win_width = render_panel_->width(); float win_height = render_panel_->height(); float zoom_x = zoom_property_->getFloat(); float zoom_y = zoom_x; // Preserve aspect ratio if( win_width != 0 && win_height != 0 ) { float img_aspect = (img_width/fx) / (img_height/fy); float win_aspect = win_width / win_height; if ( img_aspect > win_aspect ) { zoom_y = zoom_y / img_aspect * win_aspect; } else { zoom_x = zoom_x / win_aspect * img_aspect; } } // Add the camera's translation relative to the left camera (from P[3]); double tx = -1 * (info->P[3] / fx); Ogre::Vector3 right = orientation * Ogre::Vector3::UNIT_X; position = position + (right * tx); double ty = -1 * (info->P[7] / fy); Ogre::Vector3 down = orientation * Ogre::Vector3::UNIT_Y; position = position + (down * ty); if( !validateFloats( position )) { setStatus( StatusProperty::Error, "Camera Info", "CameraInfo/P resulted in an invalid position calculation (nans or infs)" ); return false; } render_panel_->getCamera()->setPosition( position ); render_panel_->getCamera()->setOrientation( orientation ); // calculate the projection matrix double cx = info->P[2]; double cy = info->P[6]; double far_plane = 100; double near_plane = 0.01; Ogre::Matrix4 proj_matrix; proj_matrix = Ogre::Matrix4::ZERO; proj_matrix[0][0]= 2.0 * fx/img_width * zoom_x; proj_matrix[1][1]= 2.0 * fy/img_height * zoom_y; proj_matrix[0][2]= 2.0 * (0.5 - cx/img_width) * zoom_x; proj_matrix[1][2]= 2.0 * (cy/img_height - 0.5) * zoom_y; proj_matrix[2][2]= -(far_plane+near_plane) / (far_plane-near_plane); proj_matrix[2][3]= -2.0*far_plane*near_plane / (far_plane-near_plane); proj_matrix[3][2]= -1; render_panel_->getCamera()->setCustomProjectionMatrix( true, proj_matrix ); setStatus( StatusProperty::Ok, "Camera Info", "OK" ); #if 0 static Axes* debug_axes = new Axes(scene_manager_, 0, 0.2, 0.01); debug_axes->setPosition(position); debug_axes->setOrientation(orientation); #endif //adjust the image rectangles to fit the zoom & aspect ratio bg_screen_rect_->setCorners( -1.0f*zoom_x, 1.0f*zoom_y, 1.0f*zoom_x, -1.0f*zoom_y ); fg_screen_rect_->setCorners( -1.0f*zoom_x, 1.0f*zoom_y, 1.0f*zoom_x, -1.0f*zoom_y ); Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); bg_screen_rect_->setBoundingBox( aabInf ); fg_screen_rect_->setBoundingBox( aabInf ); setStatus( StatusProperty::Ok, "Time", "ok" ); setStatus( StatusProperty::Ok, "Camera Info", "ok" ); return true; } void CameraDisplay::processMessage(const sensor_msgs::Image::ConstPtr& msg) { texture_.addMessage(msg); } void CameraDisplay::caminfoCallback( const sensor_msgs::CameraInfo::ConstPtr& msg ) { boost::mutex::scoped_lock lock( caminfo_mutex_ ); current_caminfo_ = msg; new_caminfo_ = true; } void CameraDisplay::fixedFrameChanged() { std::string targetFrame = fixed_frame_.toStdString(); caminfo_tf_filter_->setTargetFrame(targetFrame); ImageDisplayBase::fixedFrameChanged(); } void CameraDisplay::reset() { ImageDisplayBase::reset(); clear(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::CameraDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/camera_display.h000066400000000000000000000101271300447110700225000ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_CAMERA_DISPLAY_H #define RVIZ_CAMERA_DISPLAY_H #include #ifndef Q_MOC_RUN #include #include #include # include # include # include # include "rviz/image/image_display_base.h" # include "rviz/image/ros_image_texture.h" # include "rviz/render_panel.h" #endif namespace Ogre { class SceneNode; class ManualObject; class Rectangle2D; class Camera; } namespace rviz { class EnumProperty; class FloatProperty; class IntProperty; class RenderPanel; class RosTopicProperty; class DisplayGroupVisibilityProperty; /** * \class CameraDisplay * */ class CameraDisplay: public ImageDisplayBase, public Ogre::RenderTargetListener { Q_OBJECT public: CameraDisplay(); virtual ~CameraDisplay(); // Overrides from Display virtual void onInitialize(); virtual void fixedFrameChanged(); virtual void update( float wall_dt, float ros_dt ); virtual void reset(); // Overrides from Ogre::RenderTargetListener virtual void preRenderTargetUpdate( const Ogre::RenderTargetEvent& evt ); virtual void postRenderTargetUpdate( const Ogre::RenderTargetEvent& evt ); static const QString BACKGROUND; static const QString OVERLAY; static const QString BOTH; protected: // overrides from Display virtual void onEnable(); virtual void onDisable(); ROSImageTexture texture_; RenderPanel* render_panel_; private Q_SLOTS: void forceRender(); void updateAlpha(); virtual void updateQueueSize(); private: void subscribe(); void unsubscribe(); virtual void processMessage(const sensor_msgs::Image::ConstPtr& msg); void caminfoCallback( const sensor_msgs::CameraInfo::ConstPtr& msg ); bool updateCamera(); void clear(); void updateStatus(); Ogre::SceneNode* bg_scene_node_; Ogre::SceneNode* fg_scene_node_; Ogre::Rectangle2D* bg_screen_rect_; Ogre::MaterialPtr bg_material_; Ogre::Rectangle2D* fg_screen_rect_; Ogre::MaterialPtr fg_material_; message_filters::Subscriber caminfo_sub_; tf::MessageFilter* caminfo_tf_filter_; FloatProperty* alpha_property_; EnumProperty* image_position_property_; FloatProperty* zoom_property_; DisplayGroupVisibilityProperty* visibility_property_; sensor_msgs::CameraInfo::ConstPtr current_caminfo_; boost::mutex caminfo_mutex_; bool new_caminfo_; bool caminfo_ok_; bool force_render_; uint32_t vis_bit_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/depth_cloud_display.cpp000066400000000000000000000515161300447110700241040ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "depth_cloud_display.h" #include "rviz/visualization_manager.h" #include "rviz/properties/property.h" #include "rviz/validate_floats.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/bool_property.h" #include "rviz/properties/int_property.h" #include "rviz/frame_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "depth_cloud_mld.h" #include #include #include namespace enc = sensor_msgs::image_encodings; namespace rviz { DepthCloudDisplay::DepthCloudDisplay() : rviz::Display() , messages_received_(0) , depthmap_sub_() , rgb_sub_() , cam_info_sub_() , queue_size_(5) , ml_depth_data_(new MultiLayerDepth()) , angular_thres_(0.5f) , trans_thres_(0.01f) { // Depth map properties QRegExp depth_filter("depth"); depth_filter.setCaseSensitivity(Qt::CaseInsensitive); topic_filter_property_ = new Property("Topic Filter", true, "List only topics with names that relate to depth and color images", this, SLOT (updateTopicFilter() )); depth_topic_property_ = new RosFilteredTopicProperty("Depth Map Topic", "", QString::fromStdString(ros::message_traits::datatype()), "sensor_msgs::Image topic to subscribe to.", depth_filter, this, SLOT( updateTopic() )); depth_transport_property_ = new EnumProperty("Depth Map Transport Hint", "raw", "Preferred method of sending images.", this, SLOT( updateTopic() )); connect(depth_transport_property_, SIGNAL( requestOptions( EnumProperty* )), this, SLOT( fillTransportOptionList( EnumProperty* ))); depth_transport_property_->setStdString("raw"); // color image properties QRegExp color_filter("color|rgb|bgr|gray|mono"); color_filter.setCaseSensitivity(Qt::CaseInsensitive); color_topic_property_ = new RosFilteredTopicProperty("Color Image Topic", "", QString::fromStdString(ros::message_traits::datatype()), "sensor_msgs::Image topic to subscribe to.", color_filter, this, SLOT( updateTopic() )); color_transport_property_ = new EnumProperty("Color Transport Hint", "raw", "Preferred method of sending images.", this, SLOT( updateTopic() )); connect(color_transport_property_, SIGNAL( requestOptions( EnumProperty* )), this, SLOT( fillTransportOptionList( EnumProperty* ))); color_transport_property_->setStdString("raw"); // Queue size property queue_size_property_ = new IntProperty( "Queue Size", queue_size_, "Advanced: set the size of the incoming message queue. Increasing this " "is useful if your incoming TF data is delayed significantly from your" " image data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); queue_size_property_->setMin( 1 ); use_auto_size_property_ = new BoolProperty( "Auto Size", true, "Automatically scale each point based on its depth value and the camera parameters.", this, SLOT( updateUseAutoSize() ), this ); auto_size_factor_property_ = new FloatProperty( "Auto Size Factor", 1, "Scaling factor to be applied to the auto size.", use_auto_size_property_, SLOT( updateAutoSizeFactor() ), this ); auto_size_factor_property_->setMin( 0.0001 ); use_occlusion_compensation_property_ = new BoolProperty( "Occlusion Compensation", false, "Keep points alive after they have been occluded by a closer point. Points are removed after a timeout or when the camera frame moves.", this, SLOT( updateUseOcclusionCompensation() ), this ); occlusion_shadow_timeout_property_ = new FloatProperty( "Occlusion Time-Out", 30.0f, "Amount of seconds before removing occluded points from the depth cloud", use_occlusion_compensation_property_, SLOT( updateOcclusionTimeOut() ), this ); } void DepthCloudDisplay::onInitialize() { depthmap_it_.reset( new image_transport::ImageTransport( threaded_nh_ )); rgb_it_.reset( new image_transport::ImageTransport( threaded_nh_ )); // Instantiate PointCloudCommon class for displaying point clouds pointcloud_common_ = new PointCloudCommon(this); updateUseAutoSize(); updateUseOcclusionCompensation(); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. threaded_nh_.setCallbackQueue( pointcloud_common_->getCallbackQueue() ); // Scan for available transport plugins scanForTransportSubscriberPlugins(); pointcloud_common_->initialize(context_, scene_node_); pointcloud_common_->xyz_transformer_property_->hide(); } DepthCloudDisplay::~DepthCloudDisplay() { if ( initialized() ) { unsubscribe(); delete pointcloud_common_; } if (ml_depth_data_) { delete ml_depth_data_; } } void DepthCloudDisplay::setTopic( const QString &topic, const QString &datatype ) { // Copied from ImageDisplayBase::setTopic() if ( datatype == ros::message_traits::datatype() ) { depth_transport_property_->setStdString( "raw" ); depth_topic_property_->setString( topic ); } else { int index = topic.lastIndexOf("/"); if ( index == -1 ) { ROS_WARN("DepthCloudDisplay::setTopic() Invalid topic name: %s", topic.toStdString().c_str()); return; } QString transport = topic.mid(index + 1); QString base_topic = topic.mid(0, index); depth_transport_property_->setString( transport ); depth_topic_property_->setString( base_topic ); } } void DepthCloudDisplay::updateQueueSize() { queue_size_ = queue_size_property_->getInt(); } void DepthCloudDisplay::updateUseAutoSize() { bool use_auto_size = use_auto_size_property_->getBool(); pointcloud_common_->point_world_size_property_->setReadOnly( use_auto_size ); pointcloud_common_->setAutoSize( use_auto_size ); auto_size_factor_property_->setHidden(!use_auto_size); if (use_auto_size) use_auto_size_property_->expand(); } void DepthCloudDisplay::updateAutoSizeFactor() { } void DepthCloudDisplay::updateTopicFilter() { bool enabled = topic_filter_property_->getValue().toBool(); depth_topic_property_->enableFilter(enabled); color_topic_property_->enableFilter(enabled); } void DepthCloudDisplay::updateUseOcclusionCompensation() { bool use_occlusion_compensation = use_occlusion_compensation_property_->getBool(); occlusion_shadow_timeout_property_->setHidden(!use_occlusion_compensation); if (use_occlusion_compensation) { updateOcclusionTimeOut(); ml_depth_data_->enableOcclusionCompensation(true); use_occlusion_compensation_property_->expand(); } else { ml_depth_data_->enableOcclusionCompensation(false); } } void DepthCloudDisplay::updateOcclusionTimeOut() { float occlusion_timeout = occlusion_shadow_timeout_property_->getFloat(); ml_depth_data_->setShadowTimeOut(occlusion_timeout); } void DepthCloudDisplay::onEnable() { subscribe(); } void DepthCloudDisplay::onDisable() { unsubscribe(); ml_depth_data_->reset(); clear(); } void DepthCloudDisplay::subscribe() { if ( !isEnabled() ) { return; } try { // reset all message filters sync_depth_color_.reset(new SynchronizerDepthColor(SyncPolicyDepthColor(queue_size_))); depthmap_tf_filter_.reset(); depthmap_sub_.reset(new image_transport::SubscriberFilter()); rgb_sub_.reset(new image_transport::SubscriberFilter()); cam_info_sub_.reset(new message_filters::Subscriber()); std::string depthmap_topic = depth_topic_property_->getTopicStd(); std::string color_topic = color_topic_property_->getTopicStd(); std::string depthmap_transport = depth_transport_property_->getStdString(); std::string color_transport = color_transport_property_->getStdString(); if (!depthmap_topic.empty() && !depthmap_transport.empty()) { // subscribe to depth map topic depthmap_sub_->subscribe(*depthmap_it_, depthmap_topic, queue_size_, image_transport::TransportHints(depthmap_transport)); depthmap_tf_filter_.reset( new tf::MessageFilter(*depthmap_sub_, *context_->getTFClient(), fixed_frame_.toStdString(), queue_size_, threaded_nh_)); // subscribe to CameraInfo topic std::string info_topic = image_transport::getCameraInfoTopic(depthmap_topic); cam_info_sub_->subscribe(threaded_nh_, info_topic, queue_size_); cam_info_sub_->registerCallback(boost::bind(&DepthCloudDisplay::caminfoCallback, this, _1)); if (!color_topic.empty() && !color_transport.empty()) { // subscribe to color image topic rgb_sub_->subscribe(*rgb_it_, color_topic, queue_size_, image_transport::TransportHints(color_transport)); // connect message filters to synchronizer sync_depth_color_->connectInput(*depthmap_tf_filter_, *rgb_sub_); sync_depth_color_->setInterMessageLowerBound(0, ros::Duration(0.5)); sync_depth_color_->setInterMessageLowerBound(1, ros::Duration(0.5)); sync_depth_color_->registerCallback(boost::bind(&DepthCloudDisplay::processMessage, this, _1, _2)); pointcloud_common_->color_transformer_property_->setValue("RGB8"); } else { depthmap_tf_filter_->registerCallback(boost::bind(&DepthCloudDisplay::processMessage, this, _1)); } } } catch (ros::Exception& e) { setStatus( StatusProperty::Error, "Message", QString("Error subscribing: ") + e.what() ); } catch (image_transport::TransportLoadException& e) { setStatus( StatusProperty::Error, "Message", QString("Error subscribing: ") + e.what() ); } } void DepthCloudDisplay::caminfoCallback( sensor_msgs::CameraInfo::ConstPtr msg ) { boost::mutex::scoped_lock lock(cam_info_mutex_); cam_info_ = msg; } void DepthCloudDisplay::unsubscribe() { clear(); try { // reset all filters sync_depth_color_.reset(new SynchronizerDepthColor(SyncPolicyDepthColor(queue_size_))); depthmap_tf_filter_.reset(); depthmap_sub_.reset(); rgb_sub_.reset(); cam_info_sub_.reset(); } catch (ros::Exception& e) { setStatus( StatusProperty::Error, "Message", QString("Error unsubscribing: ") + e.what() ); } } void DepthCloudDisplay::clear() { boost::mutex::scoped_lock lock(mutex_); pointcloud_common_->reset(); } void DepthCloudDisplay::update(float wall_dt, float ros_dt) { boost::mutex::scoped_lock lock(mutex_); pointcloud_common_->update(wall_dt, ros_dt); } void DepthCloudDisplay::reset() { clear(); messages_received_ = 0; setStatus( StatusProperty::Ok, "Depth Map", "0 depth maps received" ); setStatus( StatusProperty::Ok, "Message", "Ok" ); } void DepthCloudDisplay::processMessage(sensor_msgs::ImageConstPtr depth_msg) { processMessage(depth_msg, sensor_msgs::ImageConstPtr()); } void DepthCloudDisplay::processMessage(sensor_msgs::ImageConstPtr depth_msg, sensor_msgs::ImageConstPtr rgb_msg) { if (context_->getFrameManager()->getPause() ) { return; } std::ostringstream s; ++messages_received_; setStatus( StatusProperty::Ok, "Depth Map", QString::number(messages_received_) + " depth maps received"); setStatus( StatusProperty::Ok, "Message", "Ok" ); sensor_msgs::CameraInfo::ConstPtr cam_info; { boost::mutex::scoped_lock lock(cam_info_mutex_); cam_info = cam_info_; } if ( !cam_info || !depth_msg ) { return; } s.str(""); s << depth_msg->width << " x " << depth_msg->height; setStatusStd( StatusProperty::Ok, "Depth Image Size", s.str() ); if (rgb_msg) { s.str(""); s << rgb_msg->width << " x " << rgb_msg->height; setStatusStd( StatusProperty::Ok, "Image Size", s.str() ); if (depth_msg->header.frame_id != rgb_msg->header.frame_id) { std::stringstream errorMsg; errorMsg << "Depth image frame id [" << depth_msg->header.frame_id.c_str() << "] doesn't match color image frame id [" << rgb_msg->header.frame_id.c_str() << "]"; setStatusStd( StatusProperty::Warn, "Message", errorMsg.str() ); } } if ( use_auto_size_property_->getBool() ) { float f = cam_info->K[0]; float bx = cam_info->binning_x > 0 ? cam_info->binning_x : 1.0; float s = auto_size_factor_property_->getFloat(); pointcloud_common_->point_world_size_property_->setFloat( s / f * bx ); } bool use_occlusion_compensation = use_occlusion_compensation_property_->getBool(); if (use_occlusion_compensation) { // reset depth cloud display if camera moves Ogre::Quaternion orientation; Ogre::Vector3 position; if (!context_->getFrameManager()->getTransform(depth_msg->header, position, orientation)) { setStatus( StatusProperty::Error, "Message", QString("Failed to transform from frame [") + depth_msg->header.frame_id.c_str() + QString("] to frame [") + context_->getFrameManager()->getFixedFrame().c_str() + QString("]")); return; } else { Ogre::Radian angle; Ogre::Vector3 axis; (current_orientation_.Inverse() * orientation).ToAngleAxis(angle, axis); float angle_deg = angle.valueDegrees(); if (angle_deg >= 180.0f) angle_deg -= 180.0f; if (angle_deg < -180.0f) angle_deg += 180.0f; if (trans_thres_ == 0.0 || angular_thres_ == 0.0 || (position - current_position_).length() > trans_thres_ || angle_deg > angular_thres_) { // camera orientation/position changed current_position_ = position; current_orientation_ = orientation; // reset multi-layered depth image ml_depth_data_->reset(); } } } try { sensor_msgs::PointCloud2Ptr cloud_msg = ml_depth_data_->generatePointCloudFromDepth(depth_msg, rgb_msg, cam_info); if ( !cloud_msg.get() ) { throw MultiLayerDepthException("generatePointCloudFromDepth() returned zero."); } cloud_msg->header = depth_msg->header; // add point cloud message to pointcloud_common to be visualized pointcloud_common_->addMessage(cloud_msg); } catch (MultiLayerDepthException& e) { setStatus(StatusProperty::Error, "Message", QString("Error updating depth cloud: ") + e.what()); } } void DepthCloudDisplay::scanForTransportSubscriberPlugins() { pluginlib::ClassLoader sub_loader("image_transport", "image_transport::SubscriberPlugin"); BOOST_FOREACH( const std::string& lookup_name, sub_loader.getDeclaredClasses() ) { // lookup_name is formatted as "pkg/transport_sub", for instance // "image_transport/compressed_sub" for the "compressed" // transport. This code removes the "_sub" from the tail and // everything up to and including the "/" from the head, leaving // "compressed" (for example) in transport_name. std::string transport_name = boost::erase_last_copy(lookup_name, "_sub"); transport_name = transport_name.substr(lookup_name.find('/') + 1); // If the plugin loads without throwing an exception, add its // transport name to the list of valid plugins, otherwise ignore // it. try { boost::shared_ptr sub = sub_loader.createInstance(lookup_name); transport_plugin_types_.insert(transport_name); } catch (const pluginlib::LibraryLoadException& e) { } catch (const pluginlib::CreateClassException& e) { } } } void DepthCloudDisplay::updateTopic() { unsubscribe(); reset(); subscribe(); context_->queueRender(); } void DepthCloudDisplay::fillTransportOptionList(EnumProperty* property) { property->clearOptions(); std::vector choices; choices.push_back("raw"); // Loop over all current ROS topic names ros::master::V_TopicInfo topics; ros::master::getTopics(topics); ros::master::V_TopicInfo::iterator it = topics.begin(); ros::master::V_TopicInfo::iterator end = topics.end(); for (; it != end; ++it) { // If the beginning of this topic name is the same as topic_, // and the whole string is not the same, // and the next character is / // and there are no further slashes from there to the end, // then consider this a possible transport topic. const ros::master::TopicInfo& ti = *it; const std::string& topic_name = ti.name; const std::string& topic = depth_topic_property_->getStdString(); if (topic_name.find(topic) == 0 && topic_name != topic && topic_name[topic.size()] == '/' && topic_name.find('/', topic.size() + 1) == std::string::npos) { std::string transport_type = topic_name.substr(topic.size() + 1); // If the transport type string found above is in the set of // supported transport type plugins, add it to the list. if (transport_plugin_types_.find(transport_type) != transport_plugin_types_.end()) { choices.push_back(transport_type); } } } for (size_t i = 0; i < choices.size(); i++) { property->addOptionStd(choices[i]); } } void DepthCloudDisplay::fixedFrameChanged() { Display::reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::DepthCloudDisplay, rviz::Display) rviz-1.12.4/src/rviz/default_plugin/depth_cloud_display.h000066400000000000000000000157021300447110700235460ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_DEPTH_CLOUD_DISPLAY_H #define RVIZ_DEPTH_CLOUD_DISPLAY_H #ifndef Q_MOC_RUN # include # include # include # include # include # include # include # include # include # include "rviz/properties/enum_property.h" # include "rviz/properties/float_property.h" # include "rviz/properties/bool_property.h" # include "rviz/properties/int_property.h" # include "rviz/properties/ros_topic_property.h" # include # include #endif #include using namespace message_filters::sync_policies; // Forward declarations namespace image_transport { class SubscriberFilter; } namespace rviz { class EnumProperty; class FloatProperty; class BoolProperty; class IntProperty; class MultiLayerDepth; class RosFilteredTopicProperty: public RosTopicProperty { Q_OBJECT public: RosFilteredTopicProperty( const QString& name = QString(), const QString& default_value = QString(), const QString& message_type = QString(), const QString& description = QString(), const QRegExp& filter = QRegExp(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0) : RosTopicProperty(name, default_value, message_type, description, parent, changed_slot, receiver), filter_(filter), filter_enabled_(true) { } public: void enableFilter (bool enabled) { filter_enabled_ = enabled; fillTopicList(); } QRegExp filter() const { return filter_; } protected Q_SLOTS: virtual void fillTopicList() { QStringList filtered_strings_; // Obtain list of available topics RosTopicProperty::fillTopicList(); // Apply filter if (filter_enabled_) strings_ = strings_.filter(filter_); } private: QRegExp filter_; bool filter_enabled_; }; /** * \class DepthCloudDisplay * */ class DepthCloudDisplay : public rviz::Display { Q_OBJECT public: DepthCloudDisplay(); virtual ~DepthCloudDisplay(); virtual void onInitialize(); // Overrides from Display virtual void update(float wall_dt, float ros_dt); virtual void reset(); virtual void setTopic( const QString &topic, const QString &datatype ); protected Q_SLOTS: void updateQueueSize(); /** @brief Fill list of available and working transport options */ void fillTransportOptionList(EnumProperty* property); // Property callbacks virtual void updateTopic(); virtual void updateTopicFilter(); virtual void updateUseAutoSize(); virtual void updateAutoSizeFactor(); virtual void updateUseOcclusionCompensation(); virtual void updateOcclusionTimeOut(); protected: void scanForTransportSubscriberPlugins(); typedef std::vector V_Point; virtual void processMessage(sensor_msgs::Image::ConstPtr msg); virtual void processMessage(sensor_msgs::ImageConstPtr depth_msg, sensor_msgs::ImageConstPtr rgb_msg); void caminfoCallback( sensor_msgs::CameraInfo::ConstPtr msg ); // overrides from Display virtual void onEnable(); virtual void onDisable(); virtual void fixedFrameChanged(); void subscribe(); void unsubscribe(); void clear(); // thread-safe status updates // add status update to global status list void updateStatus( StatusProperty::Level level, const QString& name, const QString& text ); // use global status list to update rviz plugin status void setStatusList( ); uint32_t messages_received_; boost::mutex mutex_; // ROS image subscription & synchronization boost::scoped_ptr depthmap_it_; boost::shared_ptr depthmap_sub_; boost::shared_ptr > depthmap_tf_filter_; boost::scoped_ptr rgb_it_; boost::shared_ptr rgb_sub_; boost::shared_ptr > cam_info_sub_; sensor_msgs::CameraInfo::ConstPtr cam_info_; boost::mutex cam_info_mutex_; typedef ApproximateTime SyncPolicyDepthColor; typedef message_filters::Synchronizer SynchronizerDepthColor; boost::shared_ptr sync_depth_color_; // RVIZ properties Property* topic_filter_property_; IntProperty* queue_size_property_; BoolProperty* use_auto_size_property_; FloatProperty* auto_size_factor_property_; RosFilteredTopicProperty* depth_topic_property_; EnumProperty* depth_transport_property_; RosFilteredTopicProperty* color_topic_property_; EnumProperty* color_transport_property_; BoolProperty* use_occlusion_compensation_property_; FloatProperty* occlusion_shadow_timeout_property_; u_int32_t queue_size_; MultiLayerDepth* ml_depth_data_; Ogre::Quaternion current_orientation_; Ogre::Vector3 current_position_; float angular_thres_; float trans_thres_; PointCloudCommon* pointcloud_common_; std::set transport_plugin_types_; }; } // namespace rviz #endif //RVIZ_DEPTHMAP_TO_POINTCLOUD_DISPLAY_H rviz-1.12.4/src/rviz/default_plugin/depth_cloud_mld.cpp000066400000000000000000000453071300447110700232140ustar00rootroot00000000000000/* * Copyright (c) 20013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * * Created on: Jan 22, 2013 * Author: jkammerl */ #include #include #include #include #include "depth_cloud_mld.h" namespace enc = sensor_msgs::image_encodings; #define POINT_STEP (sizeof(float)*4) namespace rviz { // Encapsulate differences between processing float and uint16_t depths template struct DepthTraits { }; template<> struct DepthTraits { static inline bool valid(float depth) { return depth != 0.0; } static inline float toMeters(uint16_t depth) { return depth * 0.001f; } // originally mm }; template<> struct DepthTraits { static inline bool valid(float depth) { return std::isfinite(depth); } static inline float toMeters(float depth) { return depth; } }; struct RGBA { uint8_t red; uint8_t green; uint8_t blue; uint8_t alpha; }; void MultiLayerDepth::initializeConversion(const sensor_msgs::ImageConstPtr& depth_msg, sensor_msgs::CameraInfoConstPtr& camera_info_msg) { if (!depth_msg || !camera_info_msg) { std::string error_msg ("Waiting for CameraInfo message.."); throw( MultiLayerDepthException (error_msg)); } // do some sanity checks int binning_x = camera_info_msg->binning_x > 1 ? camera_info_msg->binning_x : 1; int binning_y = camera_info_msg->binning_y > 1 ? camera_info_msg->binning_y : 1; int roi_width = camera_info_msg->roi.width > 0 ? camera_info_msg->roi.width : camera_info_msg->width; int roi_height = camera_info_msg->roi.height > 0 ? camera_info_msg->roi.height : camera_info_msg->height; int expected_width = roi_width / binning_x; int expected_height = roi_height / binning_y; if ( expected_width != depth_msg->width || expected_height != depth_msg->height ) { std::ostringstream s; s << "Depth image size and camera info don't match: "; s << depth_msg->width << " x " << depth_msg->height; s << " vs " << expected_width << " x " << expected_height; s << "(binning: " << binning_x << " x " << binning_y; s << ", ROI size: " << roi_width << " x " << roi_height << ")"; throw( MultiLayerDepthException (s.str())); } int width = depth_msg->width; int height = depth_msg->height; std::size_t size = width * height; if (size != shadow_depth_.size()) { // Allocate memory for shadow processing shadow_depth_.resize(size, 0.0f); shadow_timestamp_.resize(size, 0.0); shadow_buffer_.resize(size * POINT_STEP, 0); // Procompute 3D projection matrix // // The following computation of center_x,y and fx,fy duplicates // code in the image_geometry package, but this avoids dependency // on OpenCV, which simplifies releasing rviz. // Combine unit conversion (if necessary) with scaling by focal length for computing (X,Y) double scale_x = camera_info_msg->binning_x > 1 ? (1.0 / camera_info_msg->binning_x) : 1.0; double scale_y = camera_info_msg->binning_y > 1 ? (1.0 / camera_info_msg->binning_y) : 1.0; // Use correct principal point from calibration float center_x = (camera_info_msg->P[2] - camera_info_msg->roi.x_offset)*scale_x; float center_y = (camera_info_msg->P[6] - camera_info_msg->roi.y_offset)*scale_y; double fx = camera_info_msg->P[0] * scale_x; double fy = camera_info_msg->P[5] * scale_y; float constant_x = 1.0f / fx; float constant_y = 1.0f / fy; projection_map_x_.resize(width); projection_map_y_.resize(height); std::vector::iterator projX = projection_map_x_.begin(); std::vector::iterator projY = projection_map_y_.begin(); // precompute 3D projection matrix for (int v = 0; v < height; ++v, ++projY) *projY = (v - center_y) * constant_y; for (int u = 0; u < width; ++u, ++projX) *projX = (u - center_x) * constant_x; // reset shadow vectors reset(); } } template sensor_msgs::PointCloud2Ptr MultiLayerDepth::generatePointCloudSL(const sensor_msgs::ImageConstPtr& depth_msg, std::vector& rgba_color_raw) { int width = depth_msg->width; int height = depth_msg->height; sensor_msgs::PointCloud2Ptr cloud_msg = initPointCloud(); cloud_msg->data.resize(height * width * cloud_msg->point_step); uint32_t* color_img_ptr = 0; if (rgba_color_raw.size()) color_img_ptr = &rgba_color_raw[0]; //////////////////////////////////////////////// // depth map to point cloud conversion //////////////////////////////////////////////// float* cloud_data_ptr = reinterpret_cast(&cloud_msg->data[0]); const std::size_t point_step = cloud_msg->point_step; std::size_t point_count = 0; std::size_t point_idx = 0; double time_now = ros::Time::now().toSec(); double time_expire = time_now+shadow_time_out_; const T* depth_img_ptr = (T*)&depth_msg->data[0]; std::vector::iterator proj_x; std::vector::const_iterator proj_x_end = projection_map_x_.end(); std::vector::iterator proj_y ; std::vector::const_iterator proj_y_end = projection_map_y_.end(); // iterate over projection matrix for (proj_y = projection_map_y_.begin(); proj_y !=proj_y_end; ++proj_y) { for (proj_x = projection_map_x_.begin(); proj_x !=proj_x_end; ++proj_x, ++point_idx, ++depth_img_ptr) { T depth_raw = *depth_img_ptr; if (DepthTraits::valid(depth_raw)) { float depth = DepthTraits::toMeters(depth_raw); // define point color uint32_t color; if (color_img_ptr) { color = *color_img_ptr; } else { color = ((uint32_t)255 << 16 | (uint32_t)255 << 8 | (uint32_t)255); } // fill in X,Y,Z and color *cloud_data_ptr = (*proj_x) * depth; ++cloud_data_ptr; *cloud_data_ptr = (*proj_y) * depth; ++cloud_data_ptr; *cloud_data_ptr = depth; ++cloud_data_ptr; *cloud_data_ptr = *reinterpret_cast(&color); ++cloud_data_ptr; ++point_count; } // increase color iterator pointer if (color_img_ptr) ++color_img_ptr; } } finalizingPointCloud(cloud_msg, point_count); return cloud_msg; } template sensor_msgs::PointCloud2Ptr MultiLayerDepth::generatePointCloudML(const sensor_msgs::ImageConstPtr& depth_msg, std::vector& rgba_color_raw) { int width = depth_msg->width; int height = depth_msg->height; sensor_msgs::PointCloud2Ptr cloud_msg = initPointCloud(); cloud_msg->data.resize(height * width * cloud_msg->point_step * 2); uint32_t* color_img_ptr = 0; if (rgba_color_raw.size()) color_img_ptr = &rgba_color_raw[0]; //////////////////////////////////////////////// // depth map to point cloud conversion //////////////////////////////////////////////// float* cloud_data_ptr = reinterpret_cast(&cloud_msg->data[0]); uint8_t* cloud_shadow_buffer_ptr = &shadow_buffer_[0]; const std::size_t point_step = cloud_msg->point_step; std::size_t point_count = 0; std::size_t point_idx = 0; double time_now = ros::Time::now().toSec(); double time_expire = time_now-shadow_time_out_; const T* depth_img_ptr = (T*)&depth_msg->data[0]; std::vector::iterator proj_x; std::vector::const_iterator proj_x_end = projection_map_x_.end(); std::vector::iterator proj_y ; std::vector::const_iterator proj_y_end = projection_map_y_.end(); // iterate over projection matrix for (proj_y = projection_map_y_.begin(); proj_y !=proj_y_end; ++proj_y) { for (proj_x = projection_map_x_.begin(); proj_x !=proj_x_end; ++proj_x, ++point_idx, ++depth_img_ptr, cloud_shadow_buffer_ptr += point_step) { // lookup shadow depth float shadow_depth = shadow_depth_[point_idx]; // check for time-outs if ( (shadow_depth!=0.0f) && (shadow_timestamp_[point_idx]::valid(depth_raw)) { float depth = DepthTraits::toMeters(depth_raw); // pointer to current point data float* cloud_data_pixel_ptr = cloud_data_ptr; // define point color uint32_t color; if (color_img_ptr) { color = *color_img_ptr; } else { color = ((uint32_t)255 << 16 | (uint32_t)255 << 8 | (uint32_t)255); } // fill in X,Y,Z and color *cloud_data_ptr = (*proj_x) * depth; ++cloud_data_ptr; *cloud_data_ptr = (*proj_y) * depth; ++cloud_data_ptr; *cloud_data_ptr = depth; ++cloud_data_ptr; *cloud_data_ptr = *reinterpret_cast(&color); ++cloud_data_ptr; ++point_count; // if shadow point exists -> display it if (depth < shadow_depth - shadow_distance_) { // copy point data from shadow buffer to point cloud memcpy(cloud_data_ptr, cloud_shadow_buffer_ptr, point_step); cloud_data_ptr += 4; ++point_count; } else { // save a copy of current point to shadow buffer memcpy(cloud_shadow_buffer_ptr, cloud_data_pixel_ptr, point_step); // reduce color intensity in shadow buffer RGBA* color = reinterpret_cast(cloud_shadow_buffer_ptr + sizeof(float) * 3); color->red /= 2; color->green /= 2; color->blue /= 2; // update shadow depth & time out shadow_depth_[point_idx] = depth; shadow_timestamp_[point_idx] = time_now; } } else { // current depth pixel is invalid -> check shadow buffer if (shadow_depth != 0) { // copy shadow point to point cloud memcpy(cloud_data_ptr, cloud_shadow_buffer_ptr, point_step); cloud_data_ptr += 4; ++point_count; } } // increase color iterator pointer if (color_img_ptr) ++color_img_ptr; } } finalizingPointCloud(cloud_msg, point_count); return cloud_msg; } template void MultiLayerDepth::convertColor(const sensor_msgs::ImageConstPtr& color_msg, std::vector& rgba_color_raw) { size_t i; size_t num_pixel = color_msg->width * color_msg->height; // query image properties int num_channels = enc::numChannels(color_msg->encoding); bool rgb_encoding = false; if (color_msg->encoding.find("rgb")!=std::string::npos) rgb_encoding = true; bool has_alpha = enc::hasAlpha(color_msg->encoding); // prepare output vector rgba_color_raw.clear(); rgba_color_raw.reserve(num_pixel); uint8_t* img_ptr = (uint8_t*)&color_msg->data[sizeof(T) - 1];// pointer to most significant byte // color conversion switch (num_channels) { case 1: // grayscale image for (i = 0; i < num_pixel; ++i) { uint8_t gray_value = *img_ptr; img_ptr += sizeof(T); rgba_color_raw.push_back((uint32_t)gray_value << 16 | (uint32_t)gray_value << 8 | (uint32_t)gray_value); } break; case 3: case 4: // rgb/bgr encoding for (i = 0; i < num_pixel; ++i) { uint8_t color1 = *((uint8_t*)img_ptr); img_ptr += sizeof(T); uint8_t color2 = *((uint8_t*)img_ptr); img_ptr += sizeof(T); uint8_t color3 = *((uint8_t*)img_ptr); img_ptr += sizeof(T); if (has_alpha) img_ptr += sizeof(T); // skip alpha values if (rgb_encoding) { // rgb encoding rgba_color_raw.push_back((uint32_t)color1 << 16 | (uint32_t)color2 << 8 | (uint32_t)color3 << 0); } else { // bgr encoding rgba_color_raw.push_back((uint32_t)color3 << 16 | (uint32_t)color2 << 8 | (uint32_t)color1 << 0); } } break; default: break; } } sensor_msgs::PointCloud2Ptr MultiLayerDepth::generatePointCloudFromDepth(sensor_msgs::ImageConstPtr depth_msg, sensor_msgs::ImageConstPtr color_msg, sensor_msgs::CameraInfoConstPtr camera_info_msg) { // Add data to multi depth image sensor_msgs::PointCloud2Ptr point_cloud_out; // Bit depth of image encoding int bitDepth = enc::bitDepth(depth_msg->encoding); int numChannels = enc::numChannels(depth_msg->encoding); if (!camera_info_msg) { throw MultiLayerDepthException("Camera info missing!"); } // precompute projection matrix and initialize shadow buffer initializeConversion(depth_msg, camera_info_msg); std::vector rgba_color_raw_; if (color_msg) { if (depth_msg->width != color_msg->width || depth_msg->height != color_msg->height) { std::stringstream error_msg; error_msg << "Depth image resolution (" << (int)depth_msg->width << "x" << (int)depth_msg->height << ") " "does not match color image resolution (" << (int)color_msg->width << "x" << (int)color_msg->height << ")"; throw( MultiLayerDepthException ( error_msg.str() ) ); } // convert color coding to 8-bit rgb data switch (enc::bitDepth(color_msg->encoding)) { case 8: convertColor(color_msg, rgba_color_raw_); break; case 16: convertColor(color_msg, rgba_color_raw_); break; default: std::string error_msg ("Color image has invalid bit depth"); throw( MultiLayerDepthException (error_msg)); break; } } if (!occlusion_compensation_) { // generate single layer depth cloud if ((bitDepth == 32) && (numChannels == 1)) { // floating point encoded depth map point_cloud_out = generatePointCloudSL(depth_msg, rgba_color_raw_); } else if ((bitDepth == 16) && (numChannels == 1)) { // 32bit integer encoded depth map point_cloud_out = generatePointCloudSL(depth_msg, rgba_color_raw_); } } else { // generate two layered depth cloud (depth+shadow) if ((bitDepth == 32) && (numChannels == 1)) { // floating point encoded depth map point_cloud_out = generatePointCloudML(depth_msg, rgba_color_raw_); } else if ((bitDepth == 16) && (numChannels == 1)) { // 32bit integer encoded depth map point_cloud_out = generatePointCloudML(depth_msg, rgba_color_raw_); } } if ( !point_cloud_out ) { std::string error_msg ("Depth image has invalid format (only 16 bit and float are supported)!"); throw( MultiLayerDepthException (error_msg)); } return point_cloud_out; } sensor_msgs::PointCloud2Ptr MultiLayerDepth::initPointCloud() { sensor_msgs::PointCloud2Ptr point_cloud_out = sensor_msgs::PointCloud2Ptr(new sensor_msgs::PointCloud2()); point_cloud_out->fields.resize(4); std::size_t point_offset = 0; point_cloud_out->fields[0].name = "x"; point_cloud_out->fields[0].datatype = sensor_msgs::PointField::FLOAT32; point_cloud_out->fields[0].count = 1; point_cloud_out->fields[0].offset = point_offset; point_offset += sizeof(float); point_cloud_out->fields[1].name = "y"; point_cloud_out->fields[1].datatype = sensor_msgs::PointField::FLOAT32; point_cloud_out->fields[1].count = 1; point_cloud_out->fields[1].offset = point_offset; point_offset += sizeof(float); point_cloud_out->fields[2].name = "z"; point_cloud_out->fields[2].datatype = sensor_msgs::PointField::FLOAT32; point_cloud_out->fields[2].count = 1; point_cloud_out->fields[2].offset = point_offset; point_offset += sizeof(float); point_cloud_out->fields[3].name = "rgb"; point_cloud_out->fields[3].datatype = sensor_msgs::PointField::FLOAT32; point_cloud_out->fields[3].count = 1; point_cloud_out->fields[3].offset = point_offset; point_offset += sizeof(float); point_cloud_out->point_step = point_offset; point_cloud_out->is_bigendian = false; point_cloud_out->is_dense = false; return point_cloud_out; } void MultiLayerDepth::finalizingPointCloud(sensor_msgs::PointCloud2Ptr& point_cloud, std::size_t size) { point_cloud->width = size; point_cloud->height = 1; point_cloud->data.resize(point_cloud->height * point_cloud->width * point_cloud->point_step); point_cloud->row_step = point_cloud->point_step * point_cloud->width; } } rviz-1.12.4/src/rviz/default_plugin/depth_cloud_mld.h000066400000000000000000000113171300447110700226530ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Created on: Jan 22, 2013 * Author: jkammerl */ #ifndef RVIZ_MULTI_LAYER_DEPTH_H_ #define RVIZ_MULTI_LAYER_DEPTH_H_ #include #include #include #include #include #include namespace rviz { class MultiLayerDepthException: public std::exception { public: MultiLayerDepthException(const std::string& error_msg) : std::exception(), error_msg_(error_msg) { } virtual ~MultiLayerDepthException() throw () {} virtual const char * what() const throw () { return error_msg_.c_str(); } protected: std::string error_msg_; }; class MultiLayerDepth { public: MultiLayerDepth() : shadow_time_out_(30.0), shadow_distance_(0.01) {}; virtual ~MultiLayerDepth() { } void setShadowTimeOut(double time_out) { shadow_time_out_ = time_out; } void enableOcclusionCompensation(bool occlusion_compensation) { occlusion_compensation_ = occlusion_compensation; reset(); } sensor_msgs::PointCloud2Ptr generatePointCloudFromDepth (sensor_msgs::ImageConstPtr depth_msg, sensor_msgs::ImageConstPtr color_msg, sensor_msgs::CameraInfoConstPtr camera_info_msg); void reset() { if (occlusion_compensation_) { // reset shadow buffer memset(&shadow_depth_[0], 0, sizeof(float)*shadow_depth_.size()); memset(&shadow_buffer_[0], 0, sizeof(uint8_t)*shadow_buffer_.size()); memset(&shadow_timestamp_[0], 0, sizeof(double)*shadow_timestamp_.size()); } } protected: /** @brief Precompute projection matrix, initialize buffers */ void initializeConversion(const sensor_msgs::ImageConstPtr& depth_msg, sensor_msgs::CameraInfoConstPtr& camera_info_msg); /** @brief Convert color data to RGBA format */ template void convertColor(const sensor_msgs::ImageConstPtr& color_msg, std::vector& rgba_color_raw); /** @brief Generate single-layered depth cloud (depth only) */ template sensor_msgs::PointCloud2Ptr generatePointCloudSL(const sensor_msgs::ImageConstPtr& depth_msg, std::vector& rgba_color_raw); /** @brief Generate multi-layered depth cloud (depth+shadow) */ template sensor_msgs::PointCloud2Ptr generatePointCloudML(const sensor_msgs::ImageConstPtr& depth_msg, std::vector& rgba_color_raw); // Helpers to generate pointcloud2 message sensor_msgs::PointCloud2Ptr initPointCloud(); void finalizingPointCloud(sensor_msgs::PointCloud2Ptr& point_cloud, std::size_t size); std::vector projection_map_x_; std::vector projection_map_y_; // shadow buffers std::vector< float > shadow_depth_; std::vector< double > shadow_timestamp_; std::vector< uint8_t > shadow_buffer_; // configuration bool occlusion_compensation_; double shadow_time_out_; float shadow_distance_; }; } #endif /* MULTI_LAYER_DEPTH_H_ */ rviz-1.12.4/src/rviz/default_plugin/effort_display.cpp000066400000000000000000000272051300447110700230750ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "effort_visual.h" #include "effort_display.h" #include namespace rviz { JointInfo::JointInfo(const std::string name, rviz::Property* parent_category) { name_ = name; effort_ = 0; max_effort_ = 0; last_update_ = ros::Time::now(); //info->category_ = new Property( QString::fromStdString( info->name_ ) , QVariant(), "", joints_category_); category_ = new rviz::Property( QString::fromStdString( name_ ) , true, "", parent_category, SLOT( updateVisibility() ), this); effort_property_ = new rviz::FloatProperty( "Effort", 0, "Effort value of this joint.", category_); effort_property_->setReadOnly( true ); max_effort_property_ = new rviz::FloatProperty( "Max Effort", 0, "Max Effort value of this joint.", category_); max_effort_property_->setReadOnly( true ); } JointInfo::~JointInfo() { } void JointInfo::updateVisibility() { bool enabled = getEnabled(); } void JointInfo::setEffort(double e) { effort_property_->setFloat(e); effort_ = e; } double JointInfo::getEffort() { return effort_; } void JointInfo::setMaxEffort(double m) { max_effort_property_->setFloat(m); max_effort_ = m; } double JointInfo::getMaxEffort() { return max_effort_; } bool JointInfo::getEnabled() const { return category_->getValue().toBool(); } JointInfo* EffortDisplay::getJointInfo( const std::string& joint) { M_JointInfo::iterator it = joints_.find( joint ); if ( it == joints_.end() ) { return NULL; } return it->second; } JointInfo* EffortDisplay::createJoint(const std::string &joint) { JointInfo *info = new JointInfo(joint, this); joints_.insert( std::make_pair( joint, info ) ); return info; } /// EffortDisplay::EffortDisplay() { alpha_property_ = new rviz::FloatProperty( "Alpha", 1.0, "0 is fully transparent, 1.0 is fully opaque.", this, SLOT( updateColorAndAlpha() )); width_property_ = new rviz::FloatProperty( "Width", 0.02, "Width to drow effort circle", this, SLOT( updateColorAndAlpha() )); scale_property_ = new rviz::FloatProperty( "Scale", 1.0, "Scale to drow effort circle", this, SLOT( updateColorAndAlpha() )); history_length_property_ = new rviz::IntProperty( "History Length", 1, "Number of prior measurements to display.", this, SLOT( updateHistoryLength() )); history_length_property_->setMin( 1 ); history_length_property_->setMax( 100000 ); robot_description_property_ = new rviz::StringProperty( "Robot Description", "robot_description", "Name of the parameter to search for to load the robot description.", this, SLOT( updateRobotDescription() ) ); joints_category_ = new rviz::Property("Joints", QVariant(), "", this); } void EffortDisplay::onInitialize() { MFDClass::onInitialize(); updateHistoryLength(); } EffortDisplay::~EffortDisplay() { //delete robot_model_; // sharead pointer } // Clear the visuals by deleting their objects. void EffortDisplay::reset() { MFDClass::reset(); visuals_.clear(); } void EffortDisplay::clear() { clearStatuses(); robot_description_.clear(); } // Set the current color and alpha values for each visual. void EffortDisplay::updateColorAndAlpha() { float width = width_property_->getFloat(); float scale = scale_property_->getFloat(); for( size_t i = 0; i < visuals_.size(); i++ ) { visuals_[ i ]->setWidth( width ); visuals_[ i ]->setScale( scale ); } } void EffortDisplay::updateRobotDescription() { if( isEnabled() ) { load(); context_->queueRender(); } } // Set the number of past visuals to show. void EffortDisplay::updateHistoryLength( ) { visuals_.rset_capacity(history_length_property_->getInt()); } void EffortDisplay::load() { // get robot_description std::string content; if (!update_nh_.getParam( robot_description_property_->getStdString(), content) ) { std::string loc; if( update_nh_.searchParam( robot_description_property_->getStdString(), loc )) { update_nh_.getParam( loc, content ); } else { clear(); setStatus( rviz::StatusProperty::Error, "URDF", "Parameter [" + robot_description_property_->getString() + "] does not exist, and was not found by searchParam()" ); return; } } if( content.empty() ) { clear(); setStatus( rviz::StatusProperty::Error, "URDF", "URDF is empty" ); return; } if( content == robot_description_ ) { return; } robot_description_ = content; robot_model_ = boost::shared_ptr(new urdf::Model()); if (!robot_model_->initString(content)) { ROS_ERROR("Unable to parse URDF description!"); setStatus( rviz::StatusProperty::Error, "URDF", "Unable to parse robot model description!"); return; } setStatus(rviz::StatusProperty::Ok, "URDF", "Robot model parserd Ok"); for (std::map::iterator it = robot_model_->joints_.begin(); it != robot_model_->joints_.end(); it ++ ) { urdf::JointSharedPtr joint = it->second; if ( joint->type == urdf::Joint::REVOLUTE ) { std::string joint_name = it->first; urdf::JointLimitsSharedPtr limit = joint->limits; joints_[joint_name] = createJoint(joint_name); //joints_[joint_name]->max_effort_property_->setFloat(limit->effort); //joints_[joint_name]->max_effort_property_->setReadOnly( true ); joints_[joint_name]->setMaxEffort(limit->effort); } } } void EffortDisplay::onEnable() { load(); } void EffortDisplay::onDisable() { clear(); } #if 0 void EffortDisplay::setRobotDescription( const std::string& description_param ) { description_param_ = description_param; propertyChanged(robot_description_property_); if ( isEnabled() ) { load(); unsubscribe(); subscribe(); causeRender(); } } void EffortDisplay::setAllEnabled(bool enabled) { all_enabled_ = enabled; M_JointInfo::iterator it = joints_.begin(); M_JointInfo::iterator end = joints_.end(); for (; it != end; ++it) { JointInfo* joint = it->second; setJointEnabled(joint, enabled); } propertyChanged(all_enabled_property_); } #endif // This is our callback to handle an incoming message. void EffortDisplay::processMessage( const sensor_msgs::JointState::ConstPtr& msg ) { // We are keeping a circular buffer of visual pointers. This gets // the next one, or creates and stores it if the buffer is not full boost::shared_ptr visual; if (visuals_.full()) { visual = visuals_.front(); } else { visual.reset(new EffortVisual(context_->getSceneManager(), scene_node_, robot_model_)); } V_string joints; int joint_num = msg->name.size(); if (joint_num != msg->effort.size()) { std::string tmp_error = "Received a joint state msg with different joint names and efforts size!"; ROS_ERROR("%s", tmp_error.c_str()); setStatus(rviz::StatusProperty::Error, "TOPIC", QString::fromStdString(tmp_error)); return; } for (int i = 0; i < joint_num; ++i) { std::string joint_name = msg->name[i]; JointInfo* joint_info = getJointInfo(joint_name); if ( !joint_info ) continue; // skip joints.. // set effort joint_info->setEffort(msg->effort[i]); // update effort property ??? if ((ros::Time::now() - joint_info->last_update_) > ros::Duration(0.2)) { joint_info->last_update_ = ros::Time::now(); } const urdf::Joint* joint = robot_model_->getJoint(joint_name).get(); int joint_type = joint->type; if ( joint_type == urdf::Joint::REVOLUTE ) { // we expects that parent_link_name equals to frame_id. std::string parent_link_name = joint->child_link_name; Ogre::Quaternion orientation; Ogre::Vector3 position; // Here we call the rviz::FrameManager to get the transform from the // fixed frame to the frame in the header of this Effort message. If // it fails, we can't do anything else so we return. if( !context_->getFrameManager()->getTransform( parent_link_name, ros::Time(), //msg->header.stamp, // ??? position, orientation )) { ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'", parent_link_name.c_str(), qPrintable( fixed_frame_) ); continue; } ; tf::Vector3 axis_joint(joint->axis.x, joint->axis.y, joint->axis.z); tf::Vector3 axis_z(0,0,1); tf::Quaternion axis_rotation(tf::tfCross(axis_joint, axis_z), tf::tfAngle(axis_joint, axis_z)); if ( std::isnan(axis_rotation.x()) || std::isnan(axis_rotation.y()) || std::isnan(axis_rotation.z()) ) axis_rotation = tf::Quaternion::getIdentity(); tf::Quaternion axis_orientation(orientation.x, orientation.y, orientation.z, orientation.w); tf::Quaternion axis_rot = axis_orientation * axis_rotation; Ogre::Quaternion joint_orientation(Ogre::Real(axis_rot.w()), Ogre::Real(axis_rot.x()), Ogre::Real(axis_rot.y()), Ogre::Real(axis_rot.z())); visual->setFramePosition( joint_name, position ); visual->setFrameOrientation( joint_name, joint_orientation ); visual->setFrameEnabled( joint_name, joint_info->getEnabled() ); } } // Now set or update the contents of the chosen visual. float scale = scale_property_->getFloat(); float width = width_property_->getFloat(); visual->setWidth( width ); visual->setScale( scale ); visual->setMessage( msg ); visuals_.push_back(visual); } } // end namespace rviz // Tell pluginlib about this class. It is important to do this in // global scope, outside our package's namespace. #include PLUGINLIB_EXPORT_CLASS( rviz::EffortDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/effort_display.h000066400000000000000000000544441300447110700225470ustar00rootroot00000000000000#ifndef EFFORT_DISPLAY_H #define EFFORT_DISPLAY_H #ifndef Q_MOC_RUN #include #endif #include #include namespace Ogre { class SceneNode; } namespace rviz { class FloatProperty; class IntProperty; class StringProperty; class CategoryProperty; class BoolProperty; class RosTopicProperty; } namespace urdf { class Model; } // MessageFilter to support message with out frame_id // https://code.ros.org/trac/ros-pkg/ticket/5467 namespace tf { #ifdef TF_MESSAGEFILTER_DEBUG # undef TF_MESSAGEFILTER_DEBUG #endif #define TF_MESSAGEFILTER_DEBUG(fmt, ...) \ ROS_DEBUG_NAMED("message_filter", "MessageFilter [target=%s]: " fmt, getTargetFramesString().c_str(), __VA_ARGS__) #ifdef TF_MESSAGEFILTER_WARN # undef TF_MESSAGEFILTER_WARN #endif #define TF_MESSAGEFILTER_WARN(fmt, ...) \ ROS_WARN_NAMED("message_filter", "MessageFilter [target=%s]: " fmt, getTargetFramesString().c_str(), __VA_ARGS__) class MessageFilterJointState : public MessageFilter { typedef sensor_msgs::JointState M; public: typedef boost::shared_ptr MConstPtr; typedef ros::MessageEvent MEvent; typedef boost::function FailureCallback; #ifdef RVIZ_USE_BOOST_SIGNAL_1 typedef boost::signal FailureSignal; #else typedef boost::signals2::signal FailureSignal; #endif // If you hit this assert your message does not have a header, or does not have the HasHeader trait defined for it ROS_STATIC_ASSERT(ros::message_traits::HasHeader::value); /** * \brief Constructor * * \param tf The tf::Transformer this filter should use * \param target_frame The frame this filter should attempt to transform to. To use multiple frames, pass an empty string here and use the setTargetFrames() function. * \param queue_size The number of messages to queue up before throwing away old ones. 0 means infinite (dangerous). * \param nh The NodeHandle to use for any necessary operations * \param max_rate The maximum rate to check for newly transformable messages */ MessageFilterJointState(Transformer& tf, const std::string& target_frame, uint32_t queue_size, ros::NodeHandle nh = ros::NodeHandle(), ros::Duration max_rate = ros::Duration(0.01)) : MessageFilter(tf, target_frame, queue_size, nh, max_rate) , tf_(tf) , nh_(nh) , max_rate_(max_rate) , queue_size_(queue_size) { init(); setTargetFrame(target_frame); } /** * \brief Constructor * * \param f The filter to connect this filter's input to. Often will be a message_filters::Subscriber. * \param tf The tf::Transformer this filter should use * \param target_frame The frame this filter should attempt to transform to. To use multiple frames, pass an empty string here and use the setTargetFrames() function. * \param queue_size The number of messages to queue up before throwing away old ones. 0 means infinite (dangerous). * \param nh The NodeHandle to use for any necessary operations * \param max_rate The maximum rate to check for newly transformable messages */ template MessageFilterJointState(F& f, Transformer& tf, const std::string& target_frame, uint32_t queue_size, ros::NodeHandle nh = ros::NodeHandle(), ros::Duration max_rate = ros::Duration(0.01)) : tf_(tf) , nh_(nh) , max_rate_(max_rate) , queue_size_(queue_size) , MessageFilter(f, tf, target_frame, queue_size, nh, max_rate) { init(); setTargetFrame(target_frame); connectInput(f); } /** * \brief Connect this filter's input to another filter's output. If this filter is already connected, disconnects first. */ template void connectInput(F& f) { message_connection_.disconnect(); message_connection_ = f.registerCallback(&MessageFilterJointState::incomingMessage, this); } /** * \brief Destructor */ ~MessageFilterJointState() { message_connection_.disconnect(); tf_.removeTransformsChangedListener(tf_connection_); clear(); TF_MESSAGEFILTER_DEBUG("Successful Transforms: %llu, Failed Transforms: %llu, Discarded due to age: %llu, Transform messages received: %llu, Messages received: %llu, Total dropped: %llu", (long long unsigned int)successful_transform_count_, (long long unsigned int)failed_transform_count_, (long long unsigned int)failed_out_the_back_count_, (long long unsigned int)transform_message_count_, (long long unsigned int)incoming_message_count_, (long long unsigned int)dropped_message_count_); } /** * \brief Set the frame you need to be able to transform to before getting a message callback */ void setTargetFrame(const std::string& target_frame) { std::vector frames; frames.push_back(target_frame); setTargetFrames(frames); } /** * \brief Set the frames you need to be able to transform to before getting a message callback */ void setTargetFrames(const std::vector& target_frames) { boost::mutex::scoped_lock list_lock(messages_mutex_); boost::mutex::scoped_lock string_lock(target_frames_string_mutex_); target_frames_ = target_frames; std::stringstream ss; for (std::vector::iterator it = target_frames_.begin(); it != target_frames_.end(); ++it) { *it = tf::resolve(tf_.getTFPrefix(), *it); ss << *it << " "; } target_frames_string_ = ss.str(); } /** * \brief Get the target frames as a string for debugging */ std::string getTargetFramesString() { boost::mutex::scoped_lock lock(target_frames_string_mutex_); return target_frames_string_; }; /** * \brief Set the required tolerance for the notifier to return true */ void setTolerance(const ros::Duration& tolerance) { time_tolerance_ = tolerance; } /** * \brief Clear any messages currently in the queue */ void clear() { boost::mutex::scoped_lock lock(messages_mutex_); TF_MESSAGEFILTER_DEBUG("%s", "Cleared"); messages_.clear(); message_count_ = 0; warned_about_unresolved_name_ = false; warned_about_empty_frame_id_ = false; } void add(const MEvent& evt) { boost::mutex::scoped_lock lock(messages_mutex_); testMessages(); if (!testMessage(evt)) { // If this message is about to push us past our queue size, erase the oldest message if (queue_size_ != 0 && message_count_ + 1 > queue_size_) { ++dropped_message_count_; const MEvent& front = messages_.front(); TF_MESSAGEFILTER_DEBUG("Removed oldest message because buffer is full, count now %d (frame_id=%s, stamp=%f)", message_count_, front.getMessage()->header.frame_id.c_str(), front.getMessage()->header.stamp.toSec()); signalFailure(messages_.front(), filter_failure_reasons::Unknown); messages_.pop_front(); --message_count_; } // Add the message to our list messages_.push_back(evt); ++message_count_; } TF_MESSAGEFILTER_DEBUG("Added message in frame %s at time %.3f, count now %d", evt.getMessage()->header.frame_id.c_str(), evt.getMessage()->header.stamp.toSec(), message_count_); ++incoming_message_count_; } /** * \brief Manually add a message into this filter. * \note If the message (or any other messages in the queue) are immediately transformable this will immediately call through to the output callback, possibly * multiple times */ void add(const MConstPtr& message) { boost::shared_ptr > header(new std::map); (*header)["callerid"] = "unknown"; add(MEvent(message, header, ros::Time::now())); } /** * \brief Register a callback to be called when a message is about to be dropped * \param callback The callback to call */ message_filters::Connection registerFailureCallback(const FailureCallback& callback) { boost::mutex::scoped_lock lock(failure_signal_mutex_); return message_filters::Connection(boost::bind(&MessageFilterJointState::disconnectFailure, this, _1), failure_signal_.connect(callback)); } virtual void setQueueSize( uint32_t new_queue_size ) { queue_size_ = new_queue_size; } virtual uint32_t getQueueSize() { return queue_size_; } private: void init() { message_count_ = 0; new_transforms_ = false; successful_transform_count_ = 0; failed_transform_count_ = 0; failed_out_the_back_count_ = 0; transform_message_count_ = 0; incoming_message_count_ = 0; dropped_message_count_ = 0; time_tolerance_ = ros::Duration(0.0); warned_about_unresolved_name_ = false; warned_about_empty_frame_id_ = false; tf_connection_ = tf_.addTransformsChangedListener(boost::bind(&MessageFilterJointState::transformsChanged, this)); max_rate_timer_ = nh_.createTimer(max_rate_, &MessageFilterJointState::maxRateTimerCallback, this); } typedef std::list L_Event; bool testMessage(const MEvent& evt) { const MConstPtr& message = evt.getMessage(); std::string callerid = evt.getPublisherName(); std::string frame_id = ros::message_traits::FrameId::value(*message); ros::Time stamp = ros::message_traits::TimeStamp::value(*message); // FIXED if (frame_id.empty()) frame_id = * (target_frames_.begin()); //Throw out messages which have an empty frame_id if (frame_id.empty()) { if (!warned_about_empty_frame_id_) { warned_about_empty_frame_id_ = true; TF_MESSAGEFILTER_WARN("Discarding message from [%s] due to empty frame_id. This message will only print once.", callerid.c_str()); } signalFailure(evt, filter_failure_reasons::EmptyFrameID); return true; } if (frame_id[0] != '/') { std::string unresolved = frame_id; frame_id = tf::resolve(tf_.getTFPrefix(), frame_id); if (!warned_about_unresolved_name_) { warned_about_unresolved_name_ = true; ROS_WARN("Message from [%s] has a non-fully-qualified frame_id [%s]. Resolved locally to [%s]. This is will likely not work in multi-robot systems. This message will only print once.", callerid.c_str(), unresolved.c_str(), frame_id.c_str()); } } //Throw out messages which are too old //! \todo combine getLatestCommonTime call with the canTransform call for (std::vector::iterator target_it = target_frames_.begin(); target_it != target_frames_.end(); ++target_it) { const std::string& target_frame = *target_it; if (target_frame != frame_id && stamp != ros::Time(0)) { ros::Time latest_transform_time ; tf_.getLatestCommonTime(frame_id, target_frame, latest_transform_time, 0) ; if (stamp + tf_.getCacheLength() < latest_transform_time) { ++failed_out_the_back_count_; ++dropped_message_count_; TF_MESSAGEFILTER_DEBUG("Discarding Message, in frame %s, Out of the back of Cache Time(stamp: %.3f + cache_length: %.3f < latest_transform_time %.3f. Message Count now: %d", message->header.frame_id.c_str(), message->header.stamp.toSec(), tf_.getCacheLength().toSec(), latest_transform_time.toSec(), message_count_); last_out_the_back_stamp_ = stamp; last_out_the_back_frame_ = frame_id; signalFailure(evt, filter_failure_reasons::OutTheBack); return true; } } } bool ready = !target_frames_.empty(); for (std::vector::iterator target_it = target_frames_.begin(); ready && target_it != target_frames_.end(); ++target_it) { std::string& target_frame = *target_it; if (time_tolerance_ != ros::Duration(0.0)) { ready = ready && (tf_.canTransform(target_frame, frame_id, stamp) && tf_.canTransform(target_frame, frame_id, stamp + time_tolerance_) ); } else { ready = ready && tf_.canTransform(target_frame, frame_id, stamp); } } if (ready) { TF_MESSAGEFILTER_DEBUG("Message ready in frame %s at time %.3f, count now %d", frame_id.c_str(), stamp.toSec(), message_count_); ++successful_transform_count_; signalMessage(evt); } else { ++failed_transform_count_; } return ready; } void testMessages() { if (!messages_.empty() && getTargetFramesString() == " ") { ROS_WARN_NAMED("message_notifier", "MessageFilter [target=%s]: empty target frame", getTargetFramesString().c_str()); } int i = 0; L_Event::iterator it = messages_.begin(); for (; it != messages_.end(); ++i) { MEvent& evt = *it; if (testMessage(evt)) { --message_count_; it = messages_.erase(it); } else { ++it; } } } void maxRateTimerCallback(const ros::TimerEvent&) { boost::mutex::scoped_lock list_lock(messages_mutex_); if (new_transforms_) { testMessages(); new_transforms_ = false; } checkFailures(); } /** * \brief Callback that happens when we receive a message on the message topic */ void incomingMessage(const ros::MessageEvent& evt) { add(evt); } void transformsChanged() { new_transforms_ = true; ++transform_message_count_; } void checkFailures() { if (next_failure_warning_.isZero()) { next_failure_warning_ = ros::Time::now() + ros::Duration(15); } if (ros::Time::now() >= next_failure_warning_) { if (incoming_message_count_ - message_count_ == 0) { return; } double dropped_pct = (double)dropped_message_count_ / (double)(incoming_message_count_ - message_count_); if (dropped_pct > 0.95) { TF_MESSAGEFILTER_WARN("Dropped %.2f%% of messages so far. Please turn the [%s.message_notifier] rosconsole logger to DEBUG for more information.", dropped_pct*100, ROSCONSOLE_DEFAULT_NAME); next_failure_warning_ = ros::Time::now() + ros::Duration(60); if ((double)failed_out_the_back_count_ / (double)dropped_message_count_ > 0.5) { TF_MESSAGEFILTER_WARN(" The majority of dropped messages were due to messages growing older than the TF cache time. The last message's timestamp was: %f, and the last frame_id was: %s", last_out_the_back_stamp_.toSec(), last_out_the_back_frame_.c_str()); } } } } void disconnectFailure(const message_filters::Connection& c) { boost::mutex::scoped_lock lock(failure_signal_mutex_); c.getBoostConnection().disconnect(); } void signalFailure(const MEvent& evt, FilterFailureReason reason) { boost::mutex::scoped_lock lock(failure_signal_mutex_); failure_signal_(evt.getMessage(), reason); } Transformer& tf_; ///< The Transformer used to determine if transformation data is available ros::NodeHandle nh_; ///< The node used to subscribe to the topic ros::Duration max_rate_; ros::Timer max_rate_timer_; std::vector target_frames_; ///< The frames we need to be able to transform to before a message is ready std::string target_frames_string_; boost::mutex target_frames_string_mutex_; uint32_t queue_size_; ///< The maximum number of messages we queue up L_Event messages_; ///< The message list uint32_t message_count_; ///< The number of messages in the list. Used because messages_.size() has linear cost boost::mutex messages_mutex_; ///< The mutex used for locking message list operations bool new_messages_; ///< Used to skip waiting on new_data_ if new messages have come in while calling back volatile bool new_transforms_; ///< Used to skip waiting on new_data_ if new transforms have come in while calling back or transforming data bool warned_about_unresolved_name_; bool warned_about_empty_frame_id_; uint64_t successful_transform_count_; uint64_t failed_transform_count_; uint64_t failed_out_the_back_count_; uint64_t transform_message_count_; uint64_t incoming_message_count_; uint64_t dropped_message_count_; ros::Time last_out_the_back_stamp_; std::string last_out_the_back_frame_; ros::Time next_failure_warning_; ros::Duration time_tolerance_; ///< Provide additional tolerance on time for messages which are stamped but can have associated duration #ifdef RVIZ_USE_BOOST_SIGNAL_1 boost::signals::connection tf_connection_; #else boost::signals2::connection tf_connection_; #endif message_filters::Connection message_connection_; FailureSignal failure_signal_; boost::mutex failure_signal_mutex_; }; } #ifndef Q_MOC_RUN #include #include #endif #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/properties/ros_topic_property.h" namespace rviz { /** @brief Display subclass using a tf::MessageFilter, templated on the ROS message type. * * This class brings together some common things used in many Display * types. It has a tf::MessageFilter to filter incoming messages, and * it handles subscribing and unsubscribing when the display is * enabled or disabled. It also has an Ogre::SceneNode which */ class MessageFilterJointStateDisplay: public _RosTopicDisplay { // No Q_OBJECT macro here, moc does not support Q_OBJECT in a templated class. public: /** @brief Convenience typedef so subclasses don't have to use * the long templated class name to refer to their super class. */ typedef MessageFilterJointStateDisplay MFDClass; MessageFilterJointStateDisplay() : tf_filter_( NULL ) , messages_received_( 0 ) { QString message_type = QString::fromStdString( ros::message_traits::datatype() ); topic_property_->setMessageType( message_type ); topic_property_->setDescription( message_type + " topic to subscribe to." ); } virtual void onInitialize() { tf_filter_ = new tf::MessageFilterJointState( *context_->getTFClient(), fixed_frame_.toStdString(), 10, update_nh_ ); tf_filter_->connectInput( sub_ ); tf_filter_->registerCallback( boost::bind( &MessageFilterJointStateDisplay::incomingMessage, this, _1 )); context_->getFrameManager()->registerFilterForTransformStatusCheck( tf_filter_, this ); } virtual ~MessageFilterJointStateDisplay() { unsubscribe(); delete tf_filter_; } virtual void reset() { Display::reset(); tf_filter_->clear(); messages_received_ = 0; } protected: virtual void updateTopic() { unsubscribe(); reset(); subscribe(); context_->queueRender(); } virtual void subscribe() { if( !isEnabled() ) { return; } try { sub_.subscribe( update_nh_, topic_property_->getTopicStd(), 10 ); setStatus( StatusProperty::Ok, "Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Topic", QString( "Error subscribing: " ) + e.what() ); } } virtual void unsubscribe() { sub_.unsubscribe(); } virtual void onEnable() { subscribe(); } virtual void onDisable() { unsubscribe(); reset(); } virtual void fixedFrameChanged() { tf_filter_->setTargetFrame( fixed_frame_.toStdString() ); reset(); } /** @brief Incoming message callback. Checks if the message pointer * is valid, increments messages_received_, then calls * processMessage(). */ void incomingMessage( const sensor_msgs::JointState::ConstPtr& msg ) { if( !msg ) { return; } ++messages_received_; setStatus( StatusProperty::Ok, "Topic", QString::number( messages_received_ ) + " messages received" ); processMessage( msg ); } /** @brief Implement this to process the contents of a message. * * This is called by incomingMessage(). */ virtual void processMessage( const sensor_msgs::JointState::ConstPtr& msg ) = 0; message_filters::Subscriber sub_; tf::MessageFilterJointState* tf_filter_; uint32_t messages_received_; }; } // rviz namespace rviz { class JointInfo: public QObject { Q_OBJECT public: JointInfo(const std::string name, rviz::Property* parent_category); ~JointInfo(); void setEffort(double e); double getEffort(); void setMaxEffort(double m); double getMaxEffort(); bool getEnabled() const; ros::Time last_update_; public Q_SLOTS: void updateVisibility(); private: std::string name_; double effort_, max_effort_; rviz::Property* category_; rviz::FloatProperty* effort_property_; rviz::FloatProperty* max_effort_property_; }; typedef std::set S_JointInfo; typedef std::vector V_string; class EffortVisual; class EffortDisplay: public rviz::MessageFilterJointStateDisplay { Q_OBJECT public: // Constructor. pluginlib::ClassLoader creates instances by calling // the default constructor, so make sure you have one. EffortDisplay(); virtual ~EffortDisplay(); // Overrides of public virtual functions from the Display class. virtual void onInitialize(); virtual void reset(); private Q_SLOTS: // Helper function to apply color and alpha to all visuals. void updateColorAndAlpha(); void updateHistoryLength(); void updateRobotDescription(); JointInfo* getJointInfo( const std::string& joint); JointInfo* createJoint(const std::string &joint); protected: // overrides from Display virtual void onEnable(); virtual void onDisable(); // load void load(); void clear(); // The object for urdf model boost::shared_ptr robot_model_; // std::string robot_description_; private: void processMessage( const sensor_msgs::JointState::ConstPtr& msg ); // Storage for the list of visuals. It is a circular buffer where // data gets popped from the front (oldest) and pushed to the back (newest) boost::circular_buffer > visuals_; typedef std::map M_JointInfo; M_JointInfo joints_; // Property objects for user-editable properties. rviz::FloatProperty *alpha_property_,* width_property_,* scale_property_; rviz::IntProperty *history_length_property_; rviz::StringProperty *robot_description_property_; rviz::Property *joints_category_; rviz::BoolProperty *all_enabled_property_; }; } // end namespace rviz_plugin_tutorials #endif // EFFORT_DISPLAY_H rviz-1.12.4/src/rviz/default_plugin/effort_visual.cpp000066400000000000000000000146611300447110700227350ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "effort_visual.h" namespace rviz { EffortVisual::EffortVisual( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node, boost::shared_ptr urdf_model ) { scene_manager_ = scene_manager; // Ogre::SceneNode s form a tree, with each node storing the // transform (position and orientation) of itself relative to its // parent. Ogre does the math of combining those transforms when it // is time to render. // // Here we create a node to store the pose of the Effort's header frame // relative to the RViz fixed frame. frame_node_ = parent_node->createChildSceneNode(); // urdf_model_ = urdf_model; // We create the arrow object within the frame node so that we can // set its position and direction relative to its header frame. for (std::map::iterator it = urdf_model_->joints_.begin(); it != urdf_model_->joints_.end(); it ++ ) { if ( it->second->type == urdf::Joint::REVOLUTE ) { std::string joint_name = it->first; effort_enabled_[joint_name] = true; } } } EffortVisual::~EffortVisual() { // Delete the arrow to make it disappear. for (std::map::iterator it = effort_circle_.begin(); it != effort_circle_.end(); it ++ ) { delete (it->second); } for (std::map::iterator it = effort_arrow_.begin(); it != effort_arrow_.end(); it ++ ) { delete (it->second); } // Destroy the frame node since we don't need it anymore. scene_manager_->destroySceneNode( frame_node_ ); } void EffortVisual::getRainbowColor(float value, Ogre::ColourValue& color) { value = std::min(value, 1.0f); value = std::max(value, 0.0f); float h = value * 5.0f + 1.0f; int i = floor(h); float f = h - i; if ( !(i&1) ) f = 1 - f; // if i is even float n = 1 - f; if (i <= 1) color[0] = n, color[1] = 0, color[2] = 1; else if (i == 2) color[0] = 0, color[1] = n, color[2] = 1; else if (i == 3) color[0] = 0, color[1] = 1, color[2] = n; else if (i == 4) color[0] = n, color[1] = 1, color[2] = 0; else if (i >= 5) color[0] = 1, color[1] = n, color[2] = 0; } void EffortVisual::setMessage( const sensor_msgs::JointStateConstPtr& msg ) { // for all joints... int joint_num = msg->name.size(); for (int i = 0; i < joint_num; i++ ) { std::string joint_name = msg->name[i]; double effort = msg->effort[i]; const urdf::Joint* joint = urdf_model_->getJoint(joint_name).get(); int joint_type = joint->type; if ( joint_type == urdf::Joint::REVOLUTE ) { // enable or disable draw if ( effort_circle_.find(joint_name) != effort_circle_.end() && !effort_enabled_[joint_name] ) // enable->disable { delete(effort_circle_[joint_name]); delete(effort_arrow_[joint_name]); effort_circle_.erase(joint_name); effort_arrow_.erase(joint_name); } if ( effort_circle_.find(joint_name) == effort_circle_.end() && effort_enabled_[joint_name] ) // disable -> enable { effort_circle_[joint_name] = new rviz::BillboardLine( scene_manager_, frame_node_ ); effort_arrow_[joint_name] = new rviz::Arrow( scene_manager_, frame_node_ ); } if ( ! effort_enabled_[joint_name] ) continue; //tf::Transform offset = poseFromJoint(joint); urdf::JointLimitsSharedPtr limit = joint->limits; double max_effort = limit->effort, effort_value = 0.05; if ( max_effort != 0.0 ) { effort_value = std::min(fabs(effort) / max_effort, 1.0) + 0.05; } else { effort_value = fabs(effort) + 0.05; } effort_arrow_[joint_name]->set(0, width_*2, width_*2*1.0, width_*2*2.0); if ( effort > 0 ) { effort_arrow_[joint_name]->setDirection(orientation_[joint_name] * Ogre::Vector3(-1,0,0)); } else { effort_arrow_[joint_name]->setDirection(orientation_[joint_name] * Ogre::Vector3( 1,0,0)); } effort_arrow_[joint_name]->setPosition(orientation_[joint_name] * Ogre::Vector3(0, 0.05+effort_value*scale_*0.5, 0) + position_[joint_name]); effort_circle_[joint_name]->clear(); effort_circle_[joint_name]->setLineWidth(width_); for (int i = 0; i < 30; i++) { Ogre::Vector3 point = Ogre::Vector3((0.05+effort_value*scale_*0.5)*sin(i*2*M_PI/32), (0.05+effort_value*scale_*0.5)*cos(i*2*M_PI/32), 0); if ( effort < 0 ) point.x = -point.x; effort_circle_[joint_name]->addPoint(orientation_[joint_name] * point + position_[joint_name]); } Ogre::ColourValue color; getRainbowColor(effort_value, color); effort_arrow_[joint_name]->setColor(color.r, color.g, color.b, color.a); effort_circle_[joint_name]->setColor(color.r, color.g, color.b, color.a); } } } void EffortVisual::setFrameEnabled( const std::string joint_name, const bool e ) { effort_enabled_[joint_name] = e; } // Position and orientation are passed through to the SceneNode. void EffortVisual::setFramePosition( const Ogre::Vector3& position ) { frame_node_->setPosition( position ); } void EffortVisual::setFrameOrientation( const Ogre::Quaternion& orientation ) { frame_node_->setOrientation( orientation ); } // Position and orientation are passed through to the SceneNode. void EffortVisual::setFramePosition( const std::string joint_name, const Ogre::Vector3& position ) { position_[joint_name] = position; } void EffortVisual::setFrameOrientation( const std::string joint_name, const Ogre::Quaternion& orientation ) { orientation_[joint_name] = orientation; } void EffortVisual::setWidth( float w ) { width_ = w; } void EffortVisual::setScale( float s ) { scale_ = s; } } // end namespace rviz rviz-1.12.4/src/rviz/default_plugin/effort_visual.h000066400000000000000000000055701300447110700224010ustar00rootroot00000000000000#ifndef EFFORT_VISUAL_H #define EFFORT_VISUAL_H #include namespace Ogre { class Vector3; class Quaternion; } namespace urdf { class Model; } namespace rviz { class Arrow; class BillboardLine; } namespace rviz { // Each instance of EffortVisual represents the visualization of a single // sensor_msgs::Effort message. Currently it just shows an arrow with // the direction and magnitude of the acceleration vector, but could // easily be expanded to include more of the message data. class EffortVisual { public: // Constructor. Creates the visual stuff and puts it into the // scene, but in an unconfigured state. EffortVisual( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node, boost::shared_ptr urdf_model ); // Destructor. Removes the visual stuff from the scene. virtual ~EffortVisual(); // set rainbow color void getRainbowColor(float value, Ogre::ColourValue& color); // Configure the visual to show the data in the message. void setMessage( const sensor_msgs::JointStateConstPtr& msg ); // Set the pose of the coordinate frame the message refers to. // These could be done inside setMessage(), but that would require // calls to FrameManager and error handling inside setMessage(), // which doesn't seem as clean. This way EffortVisual is only // responsible for visualization. void setFramePosition( const Ogre::Vector3& position ); void setFrameOrientation( const Ogre::Quaternion& orientation ); // set the pose of coordinates frame the each joint refers to. void setFramePosition( const std::string joint_name, const Ogre::Vector3& position ); void setFrameOrientation( const std::string joint_name, const Ogre::Quaternion& orientation ); void setFrameEnabled( const std::string joint_name, const bool e ); // Set the color and alpha of the visual, which are user-editable // parameters and therefore don't come from the Effort message. void setColor( float r, float g, float b, float a ); void setWidth( float w ); void setScale( float s ); private: // The object implementing the effort circle std::map effort_circle_; std::map effort_arrow_; std::map effort_enabled_; // A SceneNode whose pose is set to match the coordinate frame of // the Effort message header. Ogre::SceneNode* frame_node_; // The SceneManager, kept here only so the destructor can ask it to // destroy the ``frame_node_``. Ogre::SceneManager* scene_manager_; std::map position_; std::map orientation_; float width_, scale_; // The object for urdf model boost::shared_ptr urdf_model_; }; } // end namespace rviz #endif // EFFORT_VISUAL_H rviz-1.12.4/src/rviz/default_plugin/fluid_pressure_display.cpp000066400000000000000000000133531300447110700246420ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/default_plugin/point_cloud_common.h" #include "rviz/default_plugin/point_cloud_transformers.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/int_property.h" #include "rviz/validate_floats.h" #include "fluid_pressure_display.h" namespace rviz { FluidPressureDisplay::FluidPressureDisplay() : point_cloud_common_( new PointCloudCommon( this )) { queue_size_property_ = new IntProperty( "Queue Size", 10, "Advanced: set the size of the incoming FluidPressure message queue. " " Increasing this is useful if your incoming TF data is delayed significantly " "from your FluidPressure data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. update_nh_.setCallbackQueue( point_cloud_common_->getCallbackQueue() ); } FluidPressureDisplay::~FluidPressureDisplay() { delete point_cloud_common_; } void FluidPressureDisplay::onInitialize() { MFDClass::onInitialize(); point_cloud_common_->initialize( context_, scene_node_ ); // Set correct initial values subProp("Channel Name")->setValue("fluid_pressure"); subProp("Autocompute Intensity Bounds")->setValue(false); subProp("Min Intensity")->setValue(98000); // Typical 'low' atmosphereic pressure in Pascal subProp("Max Intensity")->setValue(105000); // Typica 'high' atmosphereic pressure in Pascal } void FluidPressureDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void FluidPressureDisplay::processMessage( const sensor_msgs::FluidPressureConstPtr& msg ) { // Filter any nan values out of the cloud. Any nan values that make it through to PointCloudBase // will get their points put off in lala land, but it means they still do get processed/rendered // which can be a big performance hit sensor_msgs::PointCloud2Ptr filtered(new sensor_msgs::PointCloud2); // Create fields sensor_msgs::PointField x; x.name = "x"; x.offset = 0; x.datatype = sensor_msgs::PointField::FLOAT32; x.count = 1; sensor_msgs::PointField y; y.name = "y"; y.offset = 4; y.datatype = sensor_msgs::PointField::FLOAT32; y.count = 1; sensor_msgs::PointField z; z.name = "z"; z.offset = 8; z.datatype = sensor_msgs::PointField::FLOAT32; z.count = 1; sensor_msgs::PointField fluid_pressure; fluid_pressure.name = "fluid_pressure"; fluid_pressure.offset = 12; fluid_pressure.datatype = sensor_msgs::PointField::FLOAT64; fluid_pressure.count = 1; // Create pointcloud from message filtered->header = msg->header; filtered->fields.push_back(x); filtered->fields.push_back(y); filtered->fields.push_back(z); filtered->fields.push_back(fluid_pressure); filtered->data.resize(20); const float zero_float = 0.0; // FluidPressure is always on its tf frame memcpy(&filtered->data[x.offset], &zero_float, 4); memcpy(&filtered->data[y.offset], &zero_float, 4); memcpy(&filtered->data[z.offset], &zero_float, 4); memcpy(&filtered->data[fluid_pressure.offset], &msg->fluid_pressure, 8); filtered->height = 1; filtered->width = 1; filtered->is_bigendian = false; filtered->point_step = 20; filtered->row_step = 1; // Give to point_cloud_common to draw point_cloud_common_->addMessage( filtered ); } void FluidPressureDisplay::update( float wall_dt, float ros_dt ) { point_cloud_common_->update( wall_dt, ros_dt ); // Hide unneeded properties subProp("Position Transformer")->hide(); subProp("Color Transformer")->hide(); subProp("Channel Name")->hide(); subProp("Autocompute Intensity Bounds")->hide(); } void FluidPressureDisplay::reset() { MFDClass::reset(); point_cloud_common_->reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::FluidPressureDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/fluid_pressure_display.h000066400000000000000000000051451300447110700243070ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_FLUID_PRESSURE_DISPLAY_H #define RVIZ_FLUID_PRESSURE_DISPLAY_H #include #include #include "rviz/message_filter_display.h" namespace rviz { class IntProperty; class PointCloudCommon; /** * \class FluidPressureDisplay * \brief Displays an FluidPressure message of type sensor_msgs::FluidPressure * */ class FluidPressureDisplay: public MessageFilterDisplay { Q_OBJECT public: FluidPressureDisplay(); ~FluidPressureDisplay(); virtual void reset(); virtual void update( float wall_dt, float ros_dt ); private Q_SLOTS: void updateQueueSize(); protected: /** @brief Do initialization. Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Process a single message. Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::FluidPressureConstPtr& msg ); IntProperty* queue_size_property_; PointCloudCommon* point_cloud_common_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/grid_cells_display.cpp000066400000000000000000000163701300447110700237200ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/color_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/parse_color.h" #include "rviz/properties/ros_topic_property.h" #include "rviz/validate_floats.h" #include "rviz/display_context.h" #include "grid_cells_display.h" namespace rviz { GridCellsDisplay::GridCellsDisplay() : Display() , messages_received_(0) , last_frame_count_( uint64_t( -1 )) { color_property_ = new ColorProperty( "Color", QColor( 25, 255, 0 ), "Color of the grid cells.", this ); alpha_property_ = new FloatProperty( "Alpha", 1.0, "Amount of transparency to apply to the cells.", this, SLOT( updateAlpha() )); alpha_property_->setMin( 0 ); alpha_property_->setMax( 1 ); topic_property_ = new RosTopicProperty( "Topic", "", QString::fromStdString( ros::message_traits::datatype() ), "nav_msgs::GridCells topic to subscribe to.", this, SLOT( updateTopic() )); } void GridCellsDisplay::onInitialize() { tf_filter_ = new tf::MessageFilter( *context_->getTFClient(), fixed_frame_.toStdString(), 10, update_nh_ ); static int count = 0; std::stringstream ss; ss << "PolyLine" << count++; cloud_ = new PointCloud(); cloud_->setRenderMode( PointCloud::RM_TILES ); cloud_->setCommonDirection( Ogre::Vector3::UNIT_Z ); cloud_->setCommonUpVector( Ogre::Vector3::UNIT_Y ); scene_node_->attachObject( cloud_ ); updateAlpha(); tf_filter_->connectInput( sub_ ); tf_filter_->registerCallback( boost::bind( &GridCellsDisplay::incomingMessage, this, _1 )); context_->getFrameManager()->registerFilterForTransformStatusCheck( tf_filter_, this ); } GridCellsDisplay::~GridCellsDisplay() { if ( initialized() ) { unsubscribe(); clear(); scene_node_->detachObject( cloud_ ); delete cloud_; delete tf_filter_; } } void GridCellsDisplay::clear() { cloud_->clear(); messages_received_ = 0; setStatus( StatusProperty::Warn, "Topic", "No messages received" ); } void GridCellsDisplay::updateTopic() { unsubscribe(); subscribe(); context_->queueRender(); } void GridCellsDisplay::updateAlpha() { cloud_->setAlpha( alpha_property_->getFloat() ); context_->queueRender(); } void GridCellsDisplay::subscribe() { if ( !isEnabled() ) { return; } try { sub_.subscribe( update_nh_, topic_property_->getTopicStd(), 10 ); setStatus( StatusProperty::Ok, "Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Topic", QString("Error subscribing: ") + e.what() ); } } void GridCellsDisplay::unsubscribe() { sub_.unsubscribe(); } void GridCellsDisplay::onEnable() { subscribe(); } void GridCellsDisplay::onDisable() { unsubscribe(); clear(); } void GridCellsDisplay::fixedFrameChanged() { clear(); tf_filter_->setTargetFrame( fixed_frame_.toStdString() ); } bool validateFloats(const nav_msgs::GridCells& msg) { bool valid = true; valid = valid && validateFloats( msg.cell_width ); valid = valid && validateFloats( msg.cell_height ); valid = valid && validateFloats( msg.cells ); return valid; } void GridCellsDisplay::incomingMessage( const nav_msgs::GridCells::ConstPtr& msg ) { if( !msg ) { return; } ++messages_received_; if( context_->getFrameCount() == last_frame_count_ ) { return; } last_frame_count_ = context_->getFrameCount(); cloud_->clear(); if( !validateFloats( *msg )) { setStatus( StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } setStatus( StatusProperty::Ok, "Topic", QString::number( messages_received_ ) + " messages received" ); Ogre::Vector3 position; Ogre::Quaternion orientation; if( !context_->getFrameManager()->getTransform( msg->header, position, orientation )) { ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable( fixed_frame_ )); } scene_node_->setPosition( position ); scene_node_->setOrientation( orientation ); if( msg->cell_width == 0 ) { setStatus(StatusProperty::Error, "Topic", "Cell width is zero, cells will be invisible."); } else if( msg->cell_height == 0 ) { setStatus(StatusProperty::Error, "Topic", "Cell height is zero, cells will be invisible."); } cloud_->setDimensions(msg->cell_width, msg->cell_height, 0.0); Ogre::ColourValue color_int = qtToOgre( color_property_->getColor() ); uint32_t num_points = msg->cells.size(); typedef std::vector< PointCloud::Point > V_Point; V_Point points; points.resize( num_points ); for(uint32_t i = 0; i < num_points; i++) { PointCloud::Point& current_point = points[ i ]; current_point.position.x = msg->cells[i].x; current_point.position.y = msg->cells[i].y; current_point.position.z = msg->cells[i].z; current_point.color = color_int; } cloud_->clear(); if ( !points.empty() ) { cloud_->addPoints( &points.front(), points.size() ); } } void GridCellsDisplay::reset() { Display::reset(); clear(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::GridCellsDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/grid_cells_display.h000066400000000000000000000057231300447110700233650ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_GRID_CELLS_DISPLAY_H #define RVIZ_GRID_CELLS_DISPLAY_H #include "rviz/display.h" #include #include #ifndef Q_MOC_RUN #include #include #endif #include namespace Ogre { class ManualObject; } namespace rviz { class ColorProperty; class FloatProperty; class PointCloud; class RosTopicProperty; /** * \class GridCellsDisplay * \brief Displays a nav_msgs::GridCells message */ class GridCellsDisplay : public Display { Q_OBJECT public: GridCellsDisplay(); virtual ~GridCellsDisplay(); virtual void onInitialize(); // Overrides from Display virtual void fixedFrameChanged(); virtual void reset(); protected: // overrides from Display virtual void onEnable(); virtual void onDisable(); private Q_SLOTS: void updateAlpha(); void updateTopic(); private: void subscribe(); void unsubscribe(); void clear(); void incomingMessage( const nav_msgs::GridCells::ConstPtr& msg ); PointCloud* cloud_; message_filters::Subscriber sub_; tf::MessageFilter* tf_filter_; ColorProperty* color_property_; RosTopicProperty* topic_property_; FloatProperty* alpha_property_; uint32_t messages_received_; uint64_t last_frame_count_; }; } // namespace rviz #endif /* RVIZ_GRID_CELLS_DISPLAY_H */ rviz-1.12.4/src/rviz/default_plugin/grid_display.cpp000066400000000000000000000201401300447110700225240ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/grid.h" #include "rviz/properties/parse_color.h" #include "rviz/properties/property.h" #include "rviz/selection/selection_manager.h" #include "grid_display.h" namespace rviz { GridDisplay::GridDisplay() : Display() { frame_property_ = new TfFrameProperty( "Reference Frame", TfFrameProperty::FIXED_FRAME_STRING, "The TF frame this grid will use for its origin.", this, 0, true ); cell_count_property_ = new IntProperty( "Plane Cell Count", 10, "The number of cells to draw in the plane of the grid.", this, SLOT( updateCellCount() )); cell_count_property_->setMin( 1 ); height_property_ = new IntProperty( "Normal Cell Count", 0, "The number of cells to draw along the normal vector of the grid. " " Setting to anything but 0 makes the grid 3D.", this, SLOT( updateHeight() )); height_property_->setMin( 0 ); cell_size_property_ = new FloatProperty( "Cell Size", 1.0f, "The length, in meters, of the side of each cell.", this, SLOT( updateCellSize() )); cell_size_property_->setMin( 0.0001 ); style_property_ = new EnumProperty( "Line Style", "Lines", "The rendering operation to use to draw the grid lines.", this, SLOT( updateStyle() )); style_property_->addOption( "Lines", Grid::Lines ); style_property_->addOption( "Billboards", Grid::Billboards ); line_width_property_ = new FloatProperty( "Line Width", 0.03, "The width, in meters, of each grid line.", style_property_, SLOT( updateLineWidth() ), this ); line_width_property_->setMin( 0.001 ); line_width_property_->hide(); color_property_ = new ColorProperty( "Color", Qt::gray, "The color of the grid lines.", this, SLOT( updateColor() )); alpha_property_ = new FloatProperty( "Alpha", 0.5f, "The amount of transparency to apply to the grid lines.", this, SLOT( updateColor() )); alpha_property_->setMin( 0.0f ); alpha_property_->setMax( 1.0f ); plane_property_ = new EnumProperty( "Plane", "XY", "The plane to draw the grid along.", this, SLOT( updatePlane() )); plane_property_->addOption( "XY", XY ); plane_property_->addOption( "XZ", XZ ); plane_property_->addOption( "YZ", YZ ); offset_property_ = new VectorProperty( "Offset", Ogre::Vector3::ZERO, "Allows you to offset the grid from the origin of the reference frame. In meters.", this, SLOT( updateOffset() )); } GridDisplay::~GridDisplay() { if ( initialized() ) { delete grid_; } } void GridDisplay::onInitialize() { QColor color = color_property_->getColor(); color.setAlphaF( alpha_property_->getFloat() ); frame_property_->setFrameManager( context_->getFrameManager() ); grid_ = new Grid( scene_manager_, scene_node_, (Grid::Style) style_property_->getOptionInt(), cell_count_property_->getInt(), cell_size_property_->getFloat(), line_width_property_->getFloat(), qtToOgre( color )); grid_->getSceneNode()->setVisible( false ); updatePlane(); } void GridDisplay::update(float dt, float ros_dt) { QString qframe = frame_property_->getFrame(); std::string frame = qframe.toStdString(); Ogre::Vector3 position; Ogre::Quaternion orientation; if( context_->getFrameManager()->getTransform( frame, ros::Time(), position, orientation )) { scene_node_->setPosition( position ); scene_node_->setOrientation( orientation ); setStatus( StatusProperty::Ok, "Transform", "Transform OK" ); } else { std::string error; if( context_->getFrameManager()->transformHasProblems( frame, ros::Time(), error )) { setStatus( StatusProperty::Error, "Transform", QString::fromStdString( error )); } else { setStatus( StatusProperty::Error, "Transform", "Could not transform from [" + qframe + "] to [" + fixed_frame_ + "]" ); } } } void GridDisplay::updateColor() { QColor color = color_property_->getColor(); color.setAlphaF( alpha_property_->getFloat() ); grid_->setColor( qtToOgre( color )); context_->queueRender(); } void GridDisplay::updateCellSize() { grid_->setCellLength( cell_size_property_->getFloat() ); context_->queueRender(); } void GridDisplay::updateCellCount() { grid_->setCellCount( cell_count_property_->getInt() ); context_->queueRender(); } void GridDisplay::updateLineWidth() { grid_->setLineWidth( line_width_property_->getFloat() ); context_->queueRender(); } void GridDisplay::updateHeight() { grid_->setHeight( height_property_->getInt() ); context_->queueRender(); } void GridDisplay::updateStyle() { Grid::Style style = (Grid::Style) style_property_->getOptionInt(); grid_->setStyle( style ); switch( style ) { case Grid::Billboards: line_width_property_->show(); break; case Grid::Lines: default: line_width_property_->hide(); break; } context_->queueRender(); } void GridDisplay::updateOffset() { grid_->getSceneNode()->setPosition( offset_property_->getVector() ); context_->queueRender(); } void GridDisplay::updatePlane() { Ogre::Quaternion orient; switch( (Plane) plane_property_->getOptionInt() ) { case XZ: orient = Ogre::Quaternion( 1, 0, 0, 0 ); break; case YZ: orient = Ogre::Quaternion( Ogre::Vector3( 0, -1, 0 ), Ogre::Vector3( 0, 0, 1 ), Ogre::Vector3( 1, 0, 0 )); break; case XY: default: orient = Ogre::Quaternion( Ogre::Vector3( 1, 0, 0 ), Ogre::Vector3( 0, 0, -1 ), Ogre::Vector3( 0, 1, 0 )); break; } grid_->getSceneNode()->setOrientation( orient ); context_->queueRender(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::GridDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/grid_display.h000066400000000000000000000057351300447110700222060ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_GRID_DISPLAY_H #define RVIZ_GRID_DISPLAY_H #include "rviz/properties/color_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/int_property.h" #include "rviz/properties/vector_property.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/tf_frame_property.h" #include "rviz/display.h" namespace rviz { class Grid; /** * \class GridDisplay * \brief Displays a grid in either the XY, YZ, or XZ plane. * * For more information see Grid */ class GridDisplay : public Display { Q_OBJECT public: enum Plane { XY, XZ, YZ, }; GridDisplay(); virtual ~GridDisplay(); // Overrides from Display virtual void onInitialize(); virtual void update(float dt, float ros_dt); private Q_SLOTS: void updateCellCount(); void updateCellSize(); void updateColor(); void updateHeight(); void updateLineWidth(); void updateOffset(); void updatePlane(); void updateStyle(); private: Grid* grid_; ///< Handles actually drawing the grid TfFrameProperty* frame_property_; IntProperty* cell_count_property_; IntProperty* height_property_; FloatProperty* cell_size_property_; FloatProperty* line_width_property_; EnumProperty* style_property_; ColorProperty* color_property_; FloatProperty* alpha_property_; EnumProperty* plane_property_; VectorProperty* offset_property_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/illuminance_display.cpp000066400000000000000000000131061300447110700241030ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/default_plugin/point_cloud_common.h" #include "rviz/default_plugin/point_cloud_transformers.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/int_property.h" #include "rviz/validate_floats.h" #include "illuminance_display.h" namespace rviz { IlluminanceDisplay::IlluminanceDisplay() : point_cloud_common_( new PointCloudCommon( this )) { queue_size_property_ = new IntProperty( "Queue Size", 10, "Advanced: set the size of the incoming Illuminance message queue. " " Increasing this is useful if your incoming TF data is delayed significantly " "from your Illuminance data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. update_nh_.setCallbackQueue( point_cloud_common_->getCallbackQueue() ); } IlluminanceDisplay::~IlluminanceDisplay() { delete point_cloud_common_; } void IlluminanceDisplay::onInitialize() { MFDClass::onInitialize(); point_cloud_common_->initialize( context_, scene_node_ ); // Set correct initial values subProp("Channel Name")->setValue("illuminance"); subProp("Autocompute Intensity Bounds")->setValue(false); subProp("Min Intensity")->setValue(0); subProp("Max Intensity")->setValue(1000); } void IlluminanceDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void IlluminanceDisplay::processMessage( const sensor_msgs::IlluminanceConstPtr& msg ) { // Filter any nan values out of the cloud. Any nan values that make it through to PointCloudBase // will get their points put off in lala land, but it means they still do get processed/rendered // which can be a big performance hit sensor_msgs::PointCloud2Ptr filtered(new sensor_msgs::PointCloud2); // Create fields sensor_msgs::PointField x; x.name = "x"; x.offset = 0; x.datatype = sensor_msgs::PointField::FLOAT32; x.count = 1; sensor_msgs::PointField y; y.name = "y"; y.offset = 4; y.datatype = sensor_msgs::PointField::FLOAT32; y.count = 1; sensor_msgs::PointField z; z.name = "z"; z.offset = 8; z.datatype = sensor_msgs::PointField::FLOAT32; z.count = 1; sensor_msgs::PointField illuminance; illuminance.name = "illuminance"; illuminance.offset = 12; illuminance.datatype = sensor_msgs::PointField::FLOAT64; illuminance.count = 1; // Create pointcloud from message filtered->header = msg->header; filtered->fields.push_back(x); filtered->fields.push_back(y); filtered->fields.push_back(z); filtered->fields.push_back(illuminance); filtered->data.resize(20); const float zero_float = 0.0; // Illuminance is always on its tf frame memcpy(&filtered->data[x.offset], &zero_float, 4); memcpy(&filtered->data[y.offset], &zero_float, 4); memcpy(&filtered->data[z.offset], &zero_float, 4); memcpy(&filtered->data[illuminance.offset], &msg->illuminance, 8); filtered->height = 1; filtered->width = 1; filtered->is_bigendian = false; filtered->point_step = 20; filtered->row_step = 1; // Give to point_cloud_common to draw point_cloud_common_->addMessage( filtered ); } void IlluminanceDisplay::update( float wall_dt, float ros_dt ) { point_cloud_common_->update( wall_dt, ros_dt ); // Hide unneeded properties subProp("Position Transformer")->hide(); subProp("Color Transformer")->hide(); subProp("Channel Name")->hide(); subProp("Autocompute Intensity Bounds")->hide(); } void IlluminanceDisplay::reset() { MFDClass::reset(); point_cloud_common_->reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::IlluminanceDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/illuminance_display.h000066400000000000000000000051151300447110700235510ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ILLUMINANCE_DISPLAY_H #define RVIZ_ILLUMINANCE_DISPLAY_H #include #include #include "rviz/message_filter_display.h" namespace rviz { class IntProperty; class PointCloudCommon; /** * \class IlluminanceDisplay * \brief Displays an Illuminance message of type sensor_msgs::Illuminance * */ class IlluminanceDisplay: public MessageFilterDisplay { Q_OBJECT public: IlluminanceDisplay(); ~IlluminanceDisplay(); virtual void reset(); virtual void update( float wall_dt, float ros_dt ); private Q_SLOTS: void updateQueueSize(); protected: /** @brief Do initialization. Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Process a single message. Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::IlluminanceConstPtr& msg ); IntProperty* queue_size_property_; PointCloudCommon* point_cloud_common_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/image_display.cpp000066400000000000000000000177351300447110700227010ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/render_panel.h" #include "rviz/validate_floats.h" #include #include "image_display.h" namespace rviz { ImageDisplay::ImageDisplay() : ImageDisplayBase() , texture_() { normalize_property_ = new BoolProperty( "Normalize Range", true, "If set to true, will try to estimate the range of possible values from the received images.", this, SLOT( updateNormalizeOptions() )); min_property_ = new FloatProperty( "Min Value", 0.0, "Value which will be displayed as black.", this, SLOT( updateNormalizeOptions() )); max_property_ = new FloatProperty( "Max Value", 1.0, "Value which will be displayed as white.", this, SLOT( updateNormalizeOptions() )); median_buffer_size_property_ = new IntProperty( "Median window", 5, "Window size for median filter used for computin min/max.", this, SLOT( updateNormalizeOptions() ) ); got_float_image_ = false; } void ImageDisplay::onInitialize() { ImageDisplayBase::onInitialize(); { static uint32_t count = 0; std::stringstream ss; ss << "ImageDisplay" << count++; img_scene_manager_ = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC, ss.str()); } img_scene_node_ = img_scene_manager_->getRootSceneNode()->createChildSceneNode(); { static int count = 0; std::stringstream ss; ss << "ImageDisplayObject" << count++; screen_rect_ = new Ogre::Rectangle2D(true); screen_rect_->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - 1); screen_rect_->setCorners(-1.0f, 1.0f, 1.0f, -1.0f); ss << "Material"; material_ = Ogre::MaterialManager::getSingleton().create( ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); material_->setSceneBlending( Ogre::SBT_REPLACE ); material_->setDepthWriteEnabled(false); material_->setReceiveShadows(false); material_->setDepthCheckEnabled(false); material_->getTechnique(0)->setLightingEnabled(false); Ogre::TextureUnitState* tu = material_->getTechnique(0)->getPass(0)->createTextureUnitState(); tu->setTextureName(texture_.getTexture()->getName()); tu->setTextureFiltering( Ogre::TFO_NONE ); material_->setCullingMode(Ogre::CULL_NONE); Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); screen_rect_->setBoundingBox(aabInf); screen_rect_->setMaterial(material_->getName()); img_scene_node_->attachObject(screen_rect_); } render_panel_ = new RenderPanel(); render_panel_->getRenderWindow()->setAutoUpdated(false); render_panel_->getRenderWindow()->setActive( false ); render_panel_->resize( 640, 480 ); render_panel_->initialize(img_scene_manager_, context_); setAssociatedWidget( render_panel_ ); render_panel_->setAutoRender(false); render_panel_->setOverlaysEnabled(false); render_panel_->getCamera()->setNearClipDistance( 0.01f ); updateNormalizeOptions(); } ImageDisplay::~ImageDisplay() { if ( initialized() ) { delete render_panel_; delete screen_rect_; img_scene_node_->getParentSceneNode()->removeAndDestroyChild( img_scene_node_->getName() ); } } void ImageDisplay::onEnable() { ImageDisplayBase::subscribe(); render_panel_->getRenderWindow()->setActive(true); } void ImageDisplay::onDisable() { render_panel_->getRenderWindow()->setActive(false); ImageDisplayBase::unsubscribe(); clear(); } void ImageDisplay::updateNormalizeOptions() { if (got_float_image_) { bool normalize = normalize_property_->getBool(); normalize_property_->setHidden(false); min_property_->setHidden(normalize); max_property_->setHidden(normalize); median_buffer_size_property_->setHidden(!normalize); texture_.setNormalizeFloatImage( normalize, min_property_->getFloat(), max_property_->getFloat()); texture_.setMedianFrames( median_buffer_size_property_->getInt() ); } else { normalize_property_->setHidden(true); min_property_->setHidden(true); max_property_->setHidden(true); median_buffer_size_property_->setHidden(true); } } void ImageDisplay::clear() { texture_.clear(); if( render_panel_->getCamera() ) { render_panel_->getCamera()->setPosition(Ogre::Vector3(999999, 999999, 999999)); } } void ImageDisplay::update( float wall_dt, float ros_dt ) { try { texture_.update(); //make sure the aspect ratio of the image is preserved float win_width = render_panel_->width(); float win_height = render_panel_->height(); float img_width = texture_.getWidth(); float img_height = texture_.getHeight(); if ( img_width != 0 && img_height != 0 && win_width !=0 && win_height != 0 ) { float img_aspect = img_width / img_height; float win_aspect = win_width / win_height; if ( img_aspect > win_aspect ) { screen_rect_->setCorners(-1.0f, 1.0f * win_aspect/img_aspect, 1.0f, -1.0f * win_aspect/img_aspect, false); } else { screen_rect_->setCorners(-1.0f * img_aspect/win_aspect, 1.0f, 1.0f * img_aspect/win_aspect, -1.0f, false); } } render_panel_->getRenderWindow()->update(); } catch( UnsupportedImageEncoding& e ) { setStatus(StatusProperty::Error, "Image", e.what()); } } void ImageDisplay::reset() { ImageDisplayBase::reset(); clear(); } /* This is called by incomingMessage(). */ void ImageDisplay::processMessage(const sensor_msgs::Image::ConstPtr& msg) { bool got_float_image = msg->encoding == sensor_msgs::image_encodings::TYPE_32FC1 || msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1 || msg->encoding == sensor_msgs::image_encodings::TYPE_16SC1 || msg->encoding == sensor_msgs::image_encodings::MONO16; if ( got_float_image != got_float_image_ ) { got_float_image_ = got_float_image; updateNormalizeOptions(); } texture_.addMessage(msg); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::ImageDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/image_display.h000066400000000000000000000062131300447110700223330ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_IMAGE_DISPLAY_H #define RVIZ_IMAGE_DISPLAY_H #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include # include # include # include # include "rviz/image/image_display_base.h" # include "rviz/image/ros_image_texture.h" # include "rviz/render_panel.h" # include "rviz/properties/bool_property.h" # include "rviz/properties/float_property.h" # include "rviz/properties/int_property.h" #endif namespace Ogre { class SceneNode; class Rectangle2D; } namespace rviz { /** * \class ImageDisplay * */ class ImageDisplay: public ImageDisplayBase { Q_OBJECT public: ImageDisplay(); virtual ~ImageDisplay(); // Overrides from Display virtual void onInitialize(); virtual void update( float wall_dt, float ros_dt ); virtual void reset(); public Q_SLOTS: virtual void updateNormalizeOptions(); protected: // overrides from Display virtual void onEnable(); virtual void onDisable(); /* This is called by incomingMessage(). */ virtual void processMessage(const sensor_msgs::Image::ConstPtr& msg); private: void clear(); void updateStatus(); Ogre::SceneManager* img_scene_manager_; Ogre::SceneNode* img_scene_node_; Ogre::Rectangle2D* screen_rect_; Ogre::MaterialPtr material_; ROSImageTexture texture_; RenderPanel* render_panel_; BoolProperty* normalize_property_; FloatProperty* min_property_; FloatProperty* max_property_; IntProperty* median_buffer_size_property_; bool got_float_image_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/interactive_marker_display.cpp000066400000000000000000000317001300447110700254610ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/frame_manager.h" #include "rviz/properties/bool_property.h" #include "rviz/properties/ros_topic_property.h" #include "rviz/selection/selection_manager.h" #include "rviz/validate_floats.h" #include "rviz/display_context.h" #include "rviz/default_plugin/interactive_marker_display.h" namespace rviz { ////////////// bool validateFloats(const visualization_msgs::InteractiveMarker& msg) { bool valid = true; valid = valid && validateFloats(msg.pose); valid = valid && validateFloats(msg.scale); for ( unsigned c=0; c(), "visualization_msgs::InteractiveMarkerUpdate topic to subscribe to.", this, SLOT( updateTopic() )); show_descriptions_property_ = new BoolProperty( "Show Descriptions", true, "Whether or not to show the descriptions of each Interactive Marker.", this, SLOT( updateShowDescriptions() )); show_axes_property_ = new BoolProperty( "Show Axes", false, "Whether or not to show the axes of each Interactive Marker.", this, SLOT( updateShowAxes() )); show_visual_aids_property_ = new BoolProperty( "Show Visual Aids", false, "Whether or not to show visual helpers while moving/rotating Interactive Markers.", this, SLOT( updateShowVisualAids() )); enable_transparency_property_ = new BoolProperty( "Enable Transparency", true, "Whether or not to allow transparency for auto-completed markers (e.g. rings and arrows).", this, SLOT( updateEnableTransparency() )); } void InteractiveMarkerDisplay::onInitialize() { tf::Transformer* tf = context_->getFrameManager()->getTFClient(); im_client_.reset( new interactive_markers::InteractiveMarkerClient( *tf, fixed_frame_.toStdString() ) ); im_client_->setInitCb( boost::bind( &InteractiveMarkerDisplay::initCb, this, _1 ) ); im_client_->setUpdateCb( boost::bind( &InteractiveMarkerDisplay::updateCb, this, _1 ) ); im_client_->setResetCb( boost::bind( &InteractiveMarkerDisplay::resetCb, this, _1 ) ); im_client_->setStatusCb( boost::bind( &InteractiveMarkerDisplay::statusCb, this, _1, _2, _3 ) ); client_id_ = ros::this_node::getName() + "/" + getNameStd(); onEnable(); } void InteractiveMarkerDisplay::setTopic( const QString &topic, const QString &datatype ) { marker_update_topic_property_->setString( topic ); } void InteractiveMarkerDisplay::onEnable() { subscribe(); } void InteractiveMarkerDisplay::onDisable() { unsubscribe(); } void InteractiveMarkerDisplay::updateTopic() { unsubscribe(); std::string update_topic = marker_update_topic_property_->getTopicStd(); size_t idx = update_topic.find( "/update" ); if ( idx != std::string::npos ) { topic_ns_ = update_topic.substr( 0, idx ); subscribe(); } else { setStatusStd( StatusProperty::Error, "Topic", "Invalid topic name: " + update_topic ); } } void InteractiveMarkerDisplay::subscribe() { if ( isEnabled() ) { im_client_->subscribe(topic_ns_); std::string feedback_topic = topic_ns_+"/feedback"; feedback_pub_ = update_nh_.advertise( feedback_topic, 100, false ); } } void InteractiveMarkerDisplay::publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback) { feedback.client_id = client_id_; feedback_pub_.publish( feedback ); } void InteractiveMarkerDisplay::onStatusUpdate( StatusProperty::Level level, const std::string& name, const std::string& text ) { setStatusStd(level,name,text); } void InteractiveMarkerDisplay::unsubscribe() { if (im_client_) { im_client_->shutdown(); } feedback_pub_.shutdown(); Display::reset(); } void InteractiveMarkerDisplay::update(float wall_dt, float ros_dt) { im_client_->update(); M_StringToStringToIMPtr::iterator server_it; for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ ) { M_StringToIMPtr::iterator im_it; for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ ) { im_it->second->update( wall_dt ); } } } InteractiveMarkerDisplay::M_StringToIMPtr& InteractiveMarkerDisplay::getImMap( std::string server_id ) { M_StringToStringToIMPtr::iterator im_map_it = interactive_markers_.find( server_id ); if ( im_map_it == interactive_markers_.end() ) { im_map_it = interactive_markers_.insert( std::make_pair( server_id, M_StringToIMPtr() ) ).first; } return im_map_it->second; } void InteractiveMarkerDisplay::updateMarkers( const std::string& server_id, const std::vector& markers ) { M_StringToIMPtr& im_map = getImMap( server_id ); for ( size_t i=0; i::iterator int_marker_entry = im_map.find( marker.name ); if ( int_marker_entry == im_map.end() ) { int_marker_entry = im_map.insert( std::make_pair(marker.name, IMPtr ( new InteractiveMarker(getSceneNode(), context_) ) ) ).first; connect( int_marker_entry->second.get(), SIGNAL( userFeedback(visualization_msgs::InteractiveMarkerFeedback&) ), this, SLOT( publishFeedback(visualization_msgs::InteractiveMarkerFeedback&) )); connect( int_marker_entry->second.get(), SIGNAL( statusUpdate(StatusProperty::Level, const std::string&, const std::string&) ), this, SLOT( onStatusUpdate(StatusProperty::Level, const std::string&, const std::string&) ) ); } if ( int_marker_entry->second->processMessage( marker ) ) { int_marker_entry->second->setShowAxes( show_axes_property_->getBool() ); int_marker_entry->second->setShowVisualAids( show_visual_aids_property_->getBool() ); int_marker_entry->second->setShowDescription( show_descriptions_property_->getBool() ); } else { unsubscribe(); return; } } } void InteractiveMarkerDisplay::eraseMarkers( const std::string& server_id, const std::vector& erases ) { M_StringToIMPtr& im_map = getImMap( server_id ); for ( size_t i=0; i& marker_poses ) { M_StringToIMPtr& im_map = getImMap( server_id ); for ( size_t i=0; i::iterator int_marker_entry = im_map.find( marker_pose.name ); if ( int_marker_entry != im_map.end() ) { int_marker_entry->second->processMessage( marker_pose ); } else { setStatusStd( StatusProperty::Error, marker_pose.name, "Pose received for non-existing marker '" + marker_pose.name ); unsubscribe(); return; } } } void InteractiveMarkerDisplay::initCb( visualization_msgs::InteractiveMarkerInitConstPtr msg ) { resetCb( msg->server_id ); updateMarkers( msg->server_id, msg->markers ); } void InteractiveMarkerDisplay::updateCb( visualization_msgs::InteractiveMarkerUpdateConstPtr msg ) { updateMarkers( msg->server_id, msg->markers ); updatePoses( msg->server_id, msg->poses ); eraseMarkers( msg->server_id, msg->erases ); } void InteractiveMarkerDisplay::resetCb( std::string server_id ) { interactive_markers_.erase( server_id ); deleteStatusStd(server_id); } void InteractiveMarkerDisplay::statusCb( interactive_markers::InteractiveMarkerClient::StatusT status, const std::string& server_id, const std::string& msg ) { setStatusStd( static_cast(status), server_id, msg ); } void InteractiveMarkerDisplay::fixedFrameChanged() { if (im_client_) im_client_->setTargetFrame( fixed_frame_.toStdString() ); reset(); } void InteractiveMarkerDisplay::reset() { Display::reset(); unsubscribe(); subscribe(); } void InteractiveMarkerDisplay::updateShowDescriptions() { bool show = show_descriptions_property_->getBool(); M_StringToStringToIMPtr::iterator server_it; for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ ) { M_StringToIMPtr::iterator im_it; for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ ) { im_it->second->setShowDescription( show ); } } } void InteractiveMarkerDisplay::updateShowAxes() { bool show = show_axes_property_->getBool(); M_StringToStringToIMPtr::iterator server_it; for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ ) { M_StringToIMPtr::iterator im_it; for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ ) { im_it->second->setShowAxes( show ); } } } void InteractiveMarkerDisplay::updateShowVisualAids() { bool show = show_visual_aids_property_->getBool(); M_StringToStringToIMPtr::iterator server_it; for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ ) { M_StringToIMPtr::iterator im_it; for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ ) { im_it->second->setShowVisualAids( show ); } } } void InteractiveMarkerDisplay::updateEnableTransparency() { // This is not very efficient... but it should do the trick. unsubscribe(); im_client_->setEnableAutocompleteTransparency( enable_transparency_property_->getBool() ); subscribe(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::InteractiveMarkerDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/interactive_marker_display.h000066400000000000000000000120231300447110700251230ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_INTERACTIVE_MARKER_DISPLAY_H #define RVIZ_INTERACTIVE_MARKER_DISPLAY_H #include #include #include #include #include #ifndef Q_MOC_RUN #include #include #include #endif #include "rviz/display.h" #include "rviz/selection/forwards.h" #include "rviz/default_plugin/interactive_markers/interactive_marker.h" namespace rviz { class BoolProperty; class Object; class RosTopicProperty; class MarkerBase; typedef boost::shared_ptr MarkerBasePtr; typedef std::pair MarkerID; /** * \class InteractiveMarkerDisplay * \brief Displays Interactive Markers */ class InteractiveMarkerDisplay : public Display { Q_OBJECT public: InteractiveMarkerDisplay(); virtual void onInitialize(); virtual void update(float wall_dt, float ros_dt); virtual void fixedFrameChanged(); virtual void reset(); virtual void setTopic( const QString &topic, const QString &datatype ); protected: virtual void onEnable(); virtual void onDisable(); protected Q_SLOTS: void updateTopic(); void updateShowDescriptions(); void updateShowAxes(); void updateShowVisualAids(); void updateEnableTransparency(); void publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback); void onStatusUpdate( StatusProperty::Level level, const std::string& name, const std::string& text ); private: // Subscribe to all message topics void subscribe(); // Unsubscribe from all message topics void unsubscribe(); void initCb( visualization_msgs::InteractiveMarkerInitConstPtr msg ); void updateCb( visualization_msgs::InteractiveMarkerUpdateConstPtr msg ); void resetCb( std::string server_id ); void statusCb( interactive_markers::InteractiveMarkerClient::StatusT, const std::string& server_id, const std::string& msg ); void updateMarkers( const std::string& server_id, const std::vector& markers ); void updatePoses( const std::string& server_id, const std::vector& marker_poses ); void eraseMarkers( const std::string& server_id, const std::vector& names ); // Update the display's versions of the markers. void processMarkerChanges( const std::vector* markers = NULL, const std::vector* poses = NULL, const std::vector* erases = NULL ); typedef boost::shared_ptr IMPtr; typedef std::map< std::string, IMPtr > M_StringToIMPtr; typedef std::map< std::string, M_StringToIMPtr > M_StringToStringToIMPtr; M_StringToStringToIMPtr interactive_markers_; M_StringToIMPtr& getImMap( std::string server_id ); std::string client_id_; // Properties RosTopicProperty* marker_update_topic_property_; BoolProperty* show_descriptions_property_; BoolProperty* show_axes_property_; BoolProperty* show_visual_aids_property_; BoolProperty* enable_transparency_property_; boost::shared_ptr im_client_; ros::Publisher feedback_pub_; std::string topic_ns_; }; } // namespace rviz #endif /* RVIZ_MARKER_DISPLAY_H */ rviz-1.12.4/src/rviz/default_plugin/interactive_markers/000077500000000000000000000000001300447110700234125ustar00rootroot00000000000000rviz-1.12.4/src/rviz/default_plugin/interactive_markers/integer_action.cpp000066400000000000000000000036221300447110700271130ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "integer_action.h" namespace rviz { IntegerAction::IntegerAction( const QString& text, QObject* parent, int id ) : QAction( text, parent ) , id_( id ) { connect( this, SIGNAL( triggered( bool )), this, SLOT( emitId() )); } void IntegerAction::emitId() { Q_EMIT triggered( id_ ); } } // end namespace rviz rviz-1.12.4/src/rviz/default_plugin/interactive_markers/integer_action.h000066400000000000000000000042311300447110700265550ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef INTEGER_ACTION_H #define INTEGER_ACTION_H #include namespace rviz { /** A simple subclass of QAction which keeps an ID number and emits a * signal with that number when it is triggered. */ class IntegerAction: public QAction { Q_OBJECT public: IntegerAction(const QString& text, QObject* parent, int id ); int id_; // The menu id number from the visualization_msgs/MenuEntry Q_SIGNALS: void triggered( int id ); // emitted when action is triggered, sends id passed in. private Q_SLOTS: void emitId(); }; } // end namespace rviz #endif // INTEGER_ACTION_H rviz-1.12.4/src/rviz/default_plugin/interactive_markers/interactive_marker.cpp000066400000000000000000000562401300447110700300030ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include "rviz/frame_manager.h" #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include "rviz/frame_manager.h" #include "rviz/render_panel.h" #include "rviz/geometry.h" #include "rviz/default_plugin/interactive_markers/integer_action.h" #include "rviz/default_plugin/interactive_markers/interactive_marker.h" namespace rviz { InteractiveMarker::InteractiveMarker( Ogre::SceneNode* scene_node, DisplayContext* context ) : context_(context) , pose_changed_(false) , time_since_last_feedback_(0) , dragging_(false) , pose_update_requested_(false) , heart_beat_t_(0) , show_visual_aids_(false) { reference_node_ = scene_node->createChildSceneNode(); axes_ = new Axes( context->getSceneManager(), reference_node_, 1, 0.05 ); } InteractiveMarker::~InteractiveMarker() { delete axes_; context_->getSceneManager()->destroySceneNode( reference_node_ ); } void InteractiveMarker::processMessage( const visualization_msgs::InteractiveMarkerPose& message ) { boost::recursive_mutex::scoped_lock lock(mutex_); Ogre::Vector3 position( message.pose.position.x, message.pose.position.y, message.pose.position.z ); Ogre::Quaternion orientation( message.pose.orientation.w, message.pose.orientation.x, message.pose.orientation.y, message.pose.orientation.z ); if ( orientation.w == 0 && orientation.x == 0 && orientation.y == 0 && orientation.z == 0 ) { orientation.w = 1; } reference_time_ = message.header.stamp; reference_frame_ = message.header.frame_id; frame_locked_ = (message.header.stamp == ros::Time(0)); requestPoseUpdate( position, orientation ); context_->queueRender(); } bool InteractiveMarker::processMessage( const visualization_msgs::InteractiveMarker& message ) { boost::recursive_mutex::scoped_lock lock(mutex_); // copy values name_ = message.name; description_ = message.description; if ( message.controls.size() == 0 ) { Q_EMIT statusUpdate( StatusProperty::Ok, name_, "Marker empty."); return false; } scale_ = message.scale; reference_frame_ = message.header.frame_id; reference_time_ = message.header.stamp; frame_locked_ = (message.header.stamp == ros::Time(0)); position_ = Ogre::Vector3( message.pose.position.x, message.pose.position.y, message.pose.position.z ); orientation_ = Ogre::Quaternion( message.pose.orientation.w, message.pose.orientation.x, message.pose.orientation.y, message.pose.orientation.z ); pose_changed_ =false; time_since_last_feedback_ = 0; // setup axes axes_->setPosition(position_); axes_->setOrientation(orientation_); axes_->set( scale_, scale_*0.05 ); has_menu_ = message.menu_entries.size() > 0; updateReferencePose(); // Instead of just erasing all the old controls and making new ones // here, we want to preserve as much as possible from the old ones, // so that we don't lose the drag action in progress if a control is // being dragged when this update comes in. // // Controls are stored in a map from control name to control // pointer, so we loop over the incoming control messages looking // for names we already know about. When we find them, we just call // the control's processMessage() function to update it. When we // don't find them, we create a new Control. We also keep track of // which control names we used to have but which are not present in // the incoming message, which we use to delete the unwanted // controls. // Make set of old-names called old-names-to-delete. std::set old_names_to_delete; M_ControlPtr::const_iterator ci; for( ci = controls_.begin(); ci != controls_.end(); ci++ ) { old_names_to_delete.insert( (*ci).first ); } // Loop over new array: for ( unsigned i = 0; i < message.controls.size(); i++ ) { const visualization_msgs::InteractiveMarkerControl& control_message = message.controls[ i ]; M_ControlPtr::iterator search_iter = controls_.find( control_message.name ); InteractiveMarkerControlPtr control; // If message->name in map, if( search_iter != controls_.end() ) { // Use existing control control = (*search_iter).second; } else { // Else make new control control = boost::make_shared( context_, reference_node_, this ); controls_[ control_message.name ] = control; } // Update the control with the message data control->processMessage( control_message ); control->setShowVisualAids( show_visual_aids_ ); // Remove message->name from old-names-to-delete old_names_to_delete.erase( control_message.name ); } // Loop over old-names-to-delete std::set::iterator si; for( si = old_names_to_delete.begin(); si != old_names_to_delete.end(); si++ ) { // Remove Control object from map for name-to-delete controls_.erase( *si ); } description_control_ = boost::make_shared( context_, reference_node_, this ); description_control_->processMessage( interactive_markers::makeTitle( message )); //create menu menu_entries_.clear(); menu_.reset(); if ( has_menu_ ) { menu_.reset( new QMenu() ); top_level_menu_ids_.clear(); // Put all menu entries into the menu_entries_ map and create the // tree of menu entry ids. for ( unsigned m=0; m < message.menu_entries.size(); m++ ) { const visualization_msgs::MenuEntry& entry = message.menu_entries[ m ]; MenuNode node; node.entry = entry; menu_entries_[ entry.id ] = node; if( entry.parent_id == 0 ) { top_level_menu_ids_.push_back( entry.id ); } else { // Find the parent node and add this entry to the parent's list of children. std::map< uint32_t, MenuNode >::iterator parent_it = menu_entries_.find( entry.parent_id ); if( parent_it == menu_entries_.end() ) { ROS_ERROR("interactive marker menu entry %u found before its parent id %u. Ignoring.", entry.id, entry.parent_id); } else { (*parent_it).second.child_ids.push_back( entry.id ); } } } populateMenu( menu_.get(), top_level_menu_ids_ ); } if ( frame_locked_ ) { std::ostringstream s; s << "Locked to frame " << reference_frame_; Q_EMIT statusUpdate( StatusProperty::Ok, name_, s.str() ); } else { Q_EMIT statusUpdate( StatusProperty::Ok, name_, "Position is fixed." ); } return true; } // Recursively append menu and submenu entries to menu, based on a // vector of menu entry id numbers describing the menu entries at the // current level. void InteractiveMarker::populateMenu( QMenu* menu, std::vector& ids ) { for( size_t id_index = 0; id_index < ids.size(); id_index++ ) { uint32_t id = ids[ id_index ]; std::map< uint32_t, MenuNode >::iterator node_it = menu_entries_.find( id ); ROS_ASSERT_MSG(node_it != menu_entries_.end(), "interactive marker menu entry %u not found during populateMenu().", id); MenuNode node = (*node_it).second; if ( node.child_ids.empty() ) { IntegerAction* action = new IntegerAction( makeMenuString( node.entry.title ), menu, (int) node.entry.id ); connect( action, SIGNAL( triggered( int )), this, SLOT( handleMenuSelect( int ))); menu->addAction( action ); } else { // make sub-menu QMenu* sub_menu = menu->addMenu( makeMenuString( node.entry.title )); populateMenu( sub_menu, node.child_ids ); } } } QString InteractiveMarker::makeMenuString( const std::string &entry ) { QString menu_entry; if ( entry.find( "[x]" ) == 0 ) { menu_entry = QChar( 0x2611 ) + QString::fromStdString( entry.substr( 3 ) ); } else if ( entry.find( "[ ]" ) == 0 ) { menu_entry = QChar( 0x2610 ) + QString::fromStdString( entry.substr( 3 ) ); } else { menu_entry = QChar( 0x3000 ) + QString::fromStdString( entry ); } return menu_entry; } void InteractiveMarker::updateReferencePose() { boost::recursive_mutex::scoped_lock lock(mutex_); Ogre::Vector3 reference_position; Ogre::Quaternion reference_orientation; // if we're frame-locked, we need to find out what the most recent transformation time // actually is so we send back correct feedback if ( frame_locked_ ) { std::string fixed_frame = context_->getFrameManager()->getFixedFrame(); if ( reference_frame_ == fixed_frame ) { // if the two frames are identical, we don't need to do anything. // This should be ros::Time::now(), but then the computer running // RViz has to be time-synced with the server reference_time_ = ros::Time(); } else { std::string error; int retval = context_->getFrameManager()->getTFClient()->getLatestCommonTime( reference_frame_, fixed_frame, reference_time_, &error ); if ( retval != tf::NO_ERROR ) { std::ostringstream s; s <<"Error getting time of latest transform between " << reference_frame_ << " and " << fixed_frame << ": " << error << " (error code: " << retval << ")"; Q_EMIT statusUpdate( StatusProperty::Error, name_, s.str() ); reference_node_->setVisible( false ); return; } } } if (!context_->getFrameManager()->getTransform( reference_frame_, ros::Time(), reference_position, reference_orientation )) { std::string error; context_->getFrameManager()->transformHasProblems(reference_frame_, ros::Time(), error); Q_EMIT statusUpdate( StatusProperty::Error, name_, error); reference_node_->setVisible( false ); return; } reference_node_->setPosition( reference_position ); reference_node_->setOrientation( reference_orientation ); reference_node_->setVisible( true, false ); context_->queueRender(); } void InteractiveMarker::update(float wall_dt) { boost::recursive_mutex::scoped_lock lock(mutex_); time_since_last_feedback_ += wall_dt; if ( frame_locked_ ) { updateReferencePose(); } M_ControlPtr::iterator it; for ( it = controls_.begin(); it != controls_.end(); it++ ) { (*it).second->update(); } if( description_control_ ) { description_control_->update(); } if ( dragging_ ) { if ( pose_changed_ ) { publishPose(); } else if ( time_since_last_feedback_ > 0.25 ) { //send keep-alive so we don't use control over the marker visualization_msgs::InteractiveMarkerFeedback feedback; feedback.event_type = visualization_msgs::InteractiveMarkerFeedback::KEEP_ALIVE; publishFeedback( feedback ); } } } void InteractiveMarker::publishPose() { boost::recursive_mutex::scoped_lock lock(mutex_); visualization_msgs::InteractiveMarkerFeedback feedback; feedback.event_type = visualization_msgs::InteractiveMarkerFeedback::POSE_UPDATE; feedback.control_name = last_control_name_; publishFeedback( feedback ); pose_changed_ = false; } void InteractiveMarker::requestPoseUpdate( Ogre::Vector3 position, Ogre::Quaternion orientation ) { boost::recursive_mutex::scoped_lock lock(mutex_); if ( dragging_ ) { pose_update_requested_ = true; requested_position_ = position; requested_orientation_ = orientation; } else { updateReferencePose(); setPose( position, orientation, "" ); } } void InteractiveMarker::setPose( Ogre::Vector3 position, Ogre::Quaternion orientation, const std::string &control_name ) { boost::recursive_mutex::scoped_lock lock(mutex_); position_ = position; orientation_ = orientation; pose_changed_ = true; last_control_name_ = control_name; axes_->setPosition(position_); axes_->setOrientation(orientation_); M_ControlPtr::iterator it; for ( it = controls_.begin(); it != controls_.end(); it++ ) { (*it).second->interactiveMarkerPoseChanged( position_, orientation_ ); } if( description_control_ ) { description_control_->interactiveMarkerPoseChanged( position_, orientation_ ); } } void InteractiveMarker::setShowDescription( bool show ) { boost::recursive_mutex::scoped_lock lock(mutex_); if ( description_control_.get() ) { description_control_->setVisible( show ); } } void InteractiveMarker::setShowAxes( bool show ) { boost::recursive_mutex::scoped_lock lock(mutex_); axes_->getSceneNode()->setVisible( show ); } void InteractiveMarker::setShowVisualAids( bool show ) { boost::recursive_mutex::scoped_lock lock(mutex_); M_ControlPtr::iterator it; for ( it = controls_.begin(); it != controls_.end(); it++ ) { (*it).second->setShowVisualAids( show ); } show_visual_aids_ = show; } void InteractiveMarker::translate( Ogre::Vector3 delta_position, const std::string &control_name ) { boost::recursive_mutex::scoped_lock lock(mutex_); setPose( position_+delta_position, orientation_, control_name ); } void InteractiveMarker::rotate( Ogre::Quaternion delta_orientation, const std::string &control_name ) { boost::recursive_mutex::scoped_lock lock(mutex_); setPose( position_, delta_orientation * orientation_, control_name ); } void InteractiveMarker::startDragging() { boost::recursive_mutex::scoped_lock lock(mutex_); dragging_ = true; pose_changed_ = false; } void InteractiveMarker::stopDragging() { boost::recursive_mutex::scoped_lock lock(mutex_); dragging_ = false; if ( pose_update_requested_ ) { updateReferencePose(); setPose( requested_position_, requested_orientation_, "" ); pose_update_requested_ = false; } } bool InteractiveMarker::handle3DCursorEvent(ViewportMouseEvent& event, const Ogre::Vector3& cursor_pos, const Ogre::Quaternion& cursor_rot, const std::string &control_name) { boost::recursive_mutex::scoped_lock lock(mutex_); if( event.acting_button == Qt::LeftButton ) { Ogre::Vector3 point_rel_world = cursor_pos; bool got_3D_point = true; visualization_msgs::InteractiveMarkerFeedback feedback; feedback.control_name = control_name; feedback.marker_name = name_; // make sure we've published a last pose update feedback.event_type = ((uint8_t)visualization_msgs::InteractiveMarkerFeedback::POSE_UPDATE); publishFeedback( feedback, got_3D_point, point_rel_world ); feedback.event_type = (event.type == QEvent::MouseButtonPress ? (uint8_t)visualization_msgs::InteractiveMarkerFeedback::MOUSE_DOWN : (uint8_t)visualization_msgs::InteractiveMarkerFeedback::MOUSE_UP); publishFeedback( feedback, got_3D_point, point_rel_world ); } if( !dragging_ && menu_.get() ) { // Event.right() will be false during a right-button-up event. We // want to swallow (with the "return true") all other // right-button-related mouse events. if( event.right() ) { return true; } if( event.rightUp() && event.buttons_down == Qt::NoButton ) { // Save the 3D mouse point to send with the menu feedback, if any. Ogre::Vector3 three_d_point = cursor_pos; bool valid_point = true; Ogre::Vector2 mouse_pos = project3DPointToViewportXY(event.viewport, cursor_pos); QCursor::setPos(event.panel->mapToGlobal(QPoint(mouse_pos.x, mouse_pos.y))); showMenu( event, control_name, three_d_point, valid_point ); return true; } } return false; } bool InteractiveMarker::handleMouseEvent(ViewportMouseEvent& event, const std::string &control_name) { boost::recursive_mutex::scoped_lock lock(mutex_); if( event.acting_button == Qt::LeftButton ) { Ogre::Vector3 point_rel_world; bool got_3D_point = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, point_rel_world ); visualization_msgs::InteractiveMarkerFeedback feedback; feedback.control_name = control_name; feedback.marker_name = name_; // make sure we've published a last pose update feedback.event_type = ((uint8_t)visualization_msgs::InteractiveMarkerFeedback::POSE_UPDATE); publishFeedback( feedback, got_3D_point, point_rel_world ); feedback.event_type = (event.type == QEvent::MouseButtonPress ? (uint8_t)visualization_msgs::InteractiveMarkerFeedback::MOUSE_DOWN : (uint8_t)visualization_msgs::InteractiveMarkerFeedback::MOUSE_UP); publishFeedback( feedback, got_3D_point, point_rel_world ); } if( !dragging_ && menu_.get() ) { // Event.right() will be false during a right-button-up event. We // want to swallow (with the "return true") all other // right-button-related mouse events. if( event.right() ) { return true; } if( event.rightUp() && event.buttons_down == Qt::NoButton ) { // Save the 3D mouse point to send with the menu feedback, if any. Ogre::Vector3 three_d_point; bool valid_point = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, three_d_point ); showMenu( event, control_name, three_d_point, valid_point ); return true; } } return false; } void InteractiveMarker::showMenu( ViewportMouseEvent& event, const std::string &control_name, const Ogre::Vector3 &three_d_point, bool valid_point ) { // Save the 3D mouse point to send with the menu feedback, if any. got_3d_point_for_menu_ = valid_point; three_d_point_for_menu_ = three_d_point; event.panel->showContextMenu( menu_ ); last_control_name_ = control_name; } void InteractiveMarker::handleMenuSelect( int menu_item_id ) { boost::recursive_mutex::scoped_lock lock(mutex_); std::map< uint32_t, MenuNode >::iterator it = menu_entries_.find( menu_item_id ); if ( it != menu_entries_.end() ) { visualization_msgs::MenuEntry& entry = it->second.entry; std::string command = entry.command; uint8_t command_type = entry.command_type; if ( command_type == visualization_msgs::MenuEntry::FEEDBACK ) { visualization_msgs::InteractiveMarkerFeedback feedback; feedback.event_type = visualization_msgs::InteractiveMarkerFeedback::MENU_SELECT; feedback.menu_entry_id = entry.id; feedback.control_name = last_control_name_; publishFeedback( feedback, got_3d_point_for_menu_, three_d_point_for_menu_ ); } else if ( command_type == visualization_msgs::MenuEntry::ROSRUN ) { std::string sys_cmd = "rosrun " + command; ROS_INFO_STREAM( "Running system command: " << sys_cmd ); sys_thread_ = boost::shared_ptr( new boost::thread( boost::bind( &system, sys_cmd.c_str() ) ) ); //system( sys_cmd.c_str() ); } else if ( command_type == visualization_msgs::MenuEntry::ROSLAUNCH ) { std::string sys_cmd = "roslaunch " + command; ROS_INFO_STREAM( "Running system command: " << sys_cmd ); sys_thread_ = boost::shared_ptr( new boost::thread( boost::bind( &system, sys_cmd.c_str() ) ) ); //system( sys_cmd.c_str() ); } } } void InteractiveMarker::publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback, bool mouse_point_valid, const Ogre::Vector3& mouse_point_rel_world ) { boost::recursive_mutex::scoped_lock lock(mutex_); feedback.marker_name = name_; if ( frame_locked_ ) { // frame-locked IMs will return their pose in the same coordinate frame // as they were set up with (the "reference frame"). // The transformation's timestamp will be the one used for placing // the reference frame into the fixed frame feedback.header.frame_id = reference_frame_; feedback.header.stamp = reference_time_; feedback.pose.position.x = position_.x; feedback.pose.position.y = position_.y; feedback.pose.position.z = position_.z; feedback.pose.orientation.x = orientation_.x; feedback.pose.orientation.y = orientation_.y; feedback.pose.orientation.z = orientation_.z; feedback.pose.orientation.w = orientation_.w; feedback.mouse_point_valid = mouse_point_valid; if( mouse_point_valid ) { Ogre::Vector3 mouse_rel_reference = reference_node_->convertWorldToLocalPosition( mouse_point_rel_world ); feedback.mouse_point.x = mouse_rel_reference.x; feedback.mouse_point.y = mouse_rel_reference.y; feedback.mouse_point.z = mouse_rel_reference.z; } } else { // Timestamped IMs will return feedback in RViz's fixed frame feedback.header.frame_id = context_->getFixedFrame().toStdString(); // This should be ros::Time::now(), but then the computer running // RViz has to be time-synced with the server feedback.header.stamp = ros::Time(); Ogre::Vector3 world_position = reference_node_->convertLocalToWorldPosition( position_ ); Ogre::Quaternion world_orientation = reference_node_->convertLocalToWorldOrientation( orientation_ ); feedback.pose.position.x = world_position.x; feedback.pose.position.y = world_position.y; feedback.pose.position.z = world_position.z; feedback.pose.orientation.x = world_orientation.x; feedback.pose.orientation.y = world_orientation.y; feedback.pose.orientation.z = world_orientation.z; feedback.pose.orientation.w = world_orientation.w; feedback.mouse_point_valid = mouse_point_valid; feedback.mouse_point.x = mouse_point_rel_world.x; feedback.mouse_point.y = mouse_point_rel_world.y; feedback.mouse_point.z = mouse_point_rel_world.z; } Q_EMIT userFeedback( feedback ); time_since_last_feedback_ = 0; } } // end namespace rviz rviz-1.12.4/src/rviz/default_plugin/interactive_markers/interactive_marker.h000066400000000000000000000204741300447110700274500ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_INTERACTIVE_MARKER_H_ #define RVIZ_INTERACTIVE_MARKER_H_ #ifndef Q_MOC_RUN #include #include #include #include #include #include #endif #include #include #include #include #include #include "rviz/selection/forwards.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/default_plugin/interactive_markers/interactive_marker_control.h" #include "rviz/properties/status_property.h" namespace Ogre { class SceneNode; } class QMenu; namespace rviz { class DisplayContext; class InteractiveMarkerDisplay; class InteractiveMarker : public QObject { Q_OBJECT public: InteractiveMarker( Ogre::SceneNode* scene_node, DisplayContext* context ); virtual ~InteractiveMarker(); // reset contents to reflect the data from a new message // @return success bool processMessage( const visualization_msgs::InteractiveMarker& message ); // reset contents to reflect the data from a new message // @return success void processMessage( const visualization_msgs::InteractiveMarkerPose& message ); // called every frame update void update(float wall_dt); // directly set the pose, relative to parent frame // if publish is set to true, publish the change void setPose( Ogre::Vector3 position, Ogre::Quaternion orientation, const std::string &control_name ); void translate( Ogre::Vector3 delta_position, const std::string &control_name ); void rotate( Ogre::Quaternion delta_orientation, const std::string &control_name ); // schedule a pose reset once dragging is finished void requestPoseUpdate( Ogre::Vector3 position, Ogre::Quaternion orientation ); void startDragging(); void stopDragging(); const Ogre::Vector3& getPosition() { return position_; } const Ogre::Quaternion& getOrientation() { return orientation_; } float getSize() { return scale_; } const std::string &getReferenceFrame() { return reference_frame_; } const std::string& getName() { return name_; } // show name above marker void setShowDescription( bool show ); // show axes in origin void setShowAxes( bool show ); // show visual helpers while dragging void setShowVisualAids( bool show ); // @return true if the mouse event was intercepted, false if it was ignored bool handleMouseEvent(ViewportMouseEvent& event, const std::string &control_name ); /** * Supports selection and menu events from a 3D cursor. * * @param event A struct holding certain event data (see full description InteractiveMarkerControl::handle3DCursorEvent) * @param cursor_pos The world-relative position of the 3D cursor. * @param cursor_rot The world-relative orientation of the 3D cursor. * @param control_name The name of the child InteractiveMarkerControl calling this function. * @return true if the cursor event was intercepted, false if it was ignored */ bool handle3DCursorEvent(ViewportMouseEvent& event, const Ogre::Vector3& cursor_pos, const Ogre::Quaternion& cursor_rot, const std::string &control_name); /** * Pop up the context menu for this marker. * * @param event A struct holding certain event data (see full description on InteractiveMarkerControl::handle3DCursorEvent) * @param control_name The name of the InteractiveMarkerControl that was selected. * @param three_d_point The world-relative position associated with this mouse-click or cursor event. * @param valid_point True if three_d_point is valid (e.g. if the mouse ray was successfully intersected with marker geometry). */ void showMenu( ViewportMouseEvent& event, const std::string &control_name, const Ogre::Vector3 &three_d_point, bool valid_point ); // fill in current marker pose & name, publish void publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback, bool mouse_point_valid = false, const Ogre::Vector3& mouse_point_rel_world = Ogre::Vector3(0,0,0) ); bool hasMenu() { return has_menu_; } /** @return A shared_ptr to the QMenu owned by this InteractiveMarker. */ boost::shared_ptr getMenu() { return menu_; } Q_SIGNALS: void userFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback); void statusUpdate( StatusProperty::Level level, const std::string& name, const std::string& text ); protected Q_SLOTS: void handleMenuSelect( int menu_item_id ); protected: void publishPose(); void reset(); // set the pose of the parent frame, relative to the fixed frame void updateReferencePose(); QString makeMenuString( const std::string &entry ); // Recursively append menu and submenu entries to menu, based on a // vector of menu entry id numbers describing the menu entries at the // current level. void populateMenu( QMenu* menu, std::vector& ids ); DisplayContext* context_; // pose of parent coordinate frame std::string reference_frame_; ros::Time reference_time_; bool frame_locked_; // node representing reference frame in tf, like /map, /base_link, /head, etc. Ogre::SceneNode *reference_node_; // pose being controlled, relative to reference frame Ogre::Vector3 position_; Ogre::Quaternion orientation_; // has the pose changed since the last feedback was sent? bool pose_changed_; double time_since_last_feedback_; typedef boost::shared_ptr InteractiveMarkerControlPtr; typedef std::map M_ControlPtr; M_ControlPtr controls_; std::string name_; std::string description_; bool dragging_; // pose being controlled bool pose_update_requested_; Ogre::Vector3 requested_position_; Ogre::Quaternion requested_orientation_; float scale_; boost::shared_ptr menu_; bool has_menu_; // Helper to more simply represent the menu tree. struct MenuNode { visualization_msgs::MenuEntry entry; std::vector child_ids; }; // maps menu index to menu entry and item std::map< uint32_t, MenuNode > menu_entries_; // Helper to store the top level of the menu tree. std::vector top_level_menu_ids_; // which control has popped up the menu std::string last_control_name_; double heart_beat_t_; // visual aids Axes *axes_; InteractiveMarkerControlPtr description_control_; std::string topic_ns_; std::string client_id_; boost::recursive_mutex mutex_; boost::shared_ptr< boost::thread > sys_thread_; bool got_3d_point_for_menu_; Ogre::Vector3 three_d_point_for_menu_; bool show_visual_aids_; }; } #endif /* INTERACTIVE_MARKER_H_ */ rviz-1.12.4/src/rviz/default_plugin/interactive_markers/interactive_marker_control.cpp000066400000000000000000001657051300447110700315520ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include "rviz/render_panel.h" #include "rviz/load_resource.h" #include "rviz/window_manager_interface.h" #include "rviz/geometry.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/line.h" #include "rviz/default_plugin/markers/shape_marker.h" #include "rviz/default_plugin/markers/arrow_marker.h" #include "rviz/default_plugin/markers/line_list_marker.h" #include "rviz/default_plugin/markers/line_strip_marker.h" #include "rviz/default_plugin/markers/points_marker.h" #include "rviz/default_plugin/markers/text_view_facing_marker.h" #include "rviz/default_plugin/markers/mesh_resource_marker.h" #include "rviz/default_plugin/markers/triangle_list_marker.h" #include "rviz/default_plugin/markers/marker_base.h" #include "rviz/default_plugin/interactive_markers/interactive_marker_control.h" #include "rviz/default_plugin/interactive_markers/interactive_marker.h" #define NO_HIGHLIGHT_VALUE 0.0 #define ACTIVE_HIGHLIGHT_VALUE 0.5 #define HOVER_HIGHLIGHT_VALUE 0.3 namespace rviz { InteractiveMarkerControl::InteractiveMarkerControl( DisplayContext* context, Ogre::SceneNode *reference_node, InteractiveMarker *parent ) : mouse_dragging_(false) , drag_viewport_( NULL ) , context_( context ) , reference_node_(reference_node) , control_frame_node_(reference_node_->createChildSceneNode()) , markers_node_(reference_node_->createChildSceneNode()) , parent_(parent) , rotation_(0) , grab_point_in_reference_frame_(0,0,0) , interaction_enabled_(false) , visible_(true) , view_facing_( false ) , mouse_down_(false) , show_visual_aids_(false) , line_(new Line(context->getSceneManager(),control_frame_node_)) { line_->setVisible(false); } void InteractiveMarkerControl::makeMarkers( const visualization_msgs::InteractiveMarkerControl& message ) { for (unsigned i = 0; i < message.markers.size(); i++) { MarkerBasePtr marker; // create a marker with the given type switch (message.markers[i].type) { case visualization_msgs::Marker::CUBE: case visualization_msgs::Marker::CYLINDER: case visualization_msgs::Marker::SPHERE: { marker.reset(new ShapeMarker(0, context_, markers_node_)); } break; case visualization_msgs::Marker::ARROW: { marker.reset(new ArrowMarker(0, context_, markers_node_)); } break; case visualization_msgs::Marker::LINE_STRIP: { marker.reset(new LineStripMarker(0, context_, markers_node_)); } break; case visualization_msgs::Marker::LINE_LIST: { marker.reset(new LineListMarker(0, context_, markers_node_)); } break; case visualization_msgs::Marker::SPHERE_LIST: case visualization_msgs::Marker::CUBE_LIST: case visualization_msgs::Marker::POINTS: { PointsMarkerPtr points_marker; points_marker.reset(new PointsMarker(0, context_, markers_node_)); points_markers_.push_back( points_marker ); marker = points_marker; } break; case visualization_msgs::Marker::TEXT_VIEW_FACING: { marker.reset(new TextViewFacingMarker(0, context_, markers_node_)); } break; case visualization_msgs::Marker::MESH_RESOURCE: { marker.reset(new MeshResourceMarker(0, context_, markers_node_)); } break; case visualization_msgs::Marker::TRIANGLE_LIST: { marker.reset(new TriangleListMarker(0, context_, markers_node_)); } break; default: ROS_ERROR( "Unknown marker type: %d", message.markers[i].type ); break; } visualization_msgs::MarkerPtr marker_msg( new visualization_msgs::Marker(message.markers[ i ]) ); if ( marker_msg->header.frame_id.empty() ) { // Put Marker into fixed frame, so the constructor does not apply any tf transform. // This effectively discards any tf information in the Marker and interprets its pose // as relative to the Interactive Marker. marker_msg->header.frame_id = context_->getFrameManager()->getFixedFrame(); marker->setMessage( marker_msg ); } else { marker->setMessage( marker_msg ); // The marker will set its position relative to the fixed frame, // but we have attached it our own scene node, so we will have to // correct for that. marker->setPosition( markers_node_->convertWorldToLocalPosition( marker->getPosition() ) ); marker->setOrientation( markers_node_->convertWorldToLocalOrientation( marker->getOrientation() ) ); } marker->setInteractiveObject( shared_from_this() ); addHighlightPass(marker->getMaterials()); markers_.push_back(marker); } } InteractiveMarkerControl::~InteractiveMarkerControl() { context_->getSceneManager()->destroySceneNode(control_frame_node_); context_->getSceneManager()->destroySceneNode(markers_node_); if( view_facing_ ) { context_->getSceneManager()->removeListener(this); } } void InteractiveMarkerControl::processMessage( const visualization_msgs::InteractiveMarkerControl &message ) { name_ = message.name; description_ = QString::fromStdString( message.description ); interaction_mode_ = message.interaction_mode; always_visible_ = message.always_visible; orientation_mode_ = message.orientation_mode; control_orientation_ = Ogre::Quaternion(message.orientation.w, message.orientation.x, message.orientation.y, message.orientation.z); control_orientation_.normalise(); bool new_view_facingness = (message.orientation_mode == visualization_msgs::InteractiveMarkerControl::VIEW_FACING); if( new_view_facingness != view_facing_ ) { if( new_view_facingness ) { context_->getSceneManager()->addListener(this); } else { context_->getSceneManager()->removeListener(this); } view_facing_ = new_view_facingness; } independent_marker_orientation_ = message.independent_marker_orientation; // highlight_passes_ have raw pointers into the markers_, so must // clear them at the same time. highlight_passes_.clear(); markers_.clear(); points_markers_.clear(); // Initially, the pose of this marker's node and the interactive // marker are identical, but that may change. control_frame_node_->setPosition(parent_->getPosition()); markers_node_->setPosition(parent_->getPosition()); if ( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::INHERIT ) { control_frame_node_->setOrientation(parent_->getOrientation()); markers_node_->setOrientation(parent_->getOrientation()); } else { control_frame_node_->setOrientation( Ogre::Quaternion::IDENTITY ); markers_node_->setOrientation( Ogre::Quaternion::IDENTITY ); } makeMarkers( message ); status_msg_ = description_+" "; Ogre::Vector3 control_dir = control_orientation_.xAxis()*10000.0; line_->setPoints( control_dir, -1*control_dir ); line_->setVisible(false); // Create our own custom cursor switch( interaction_mode_ ) { case visualization_msgs::InteractiveMarkerControl::NONE: cursor_ = rviz::getDefaultCursor(); break; case visualization_msgs::InteractiveMarkerControl::MENU: cursor_ = rviz::makeIconCursor( "package://rviz/icons/menu.svg" ); status_msg_ += "Left-Click: Show menu."; break; case visualization_msgs::InteractiveMarkerControl::BUTTON: cursor_ = rviz::getDefaultCursor(); status_msg_ += "Left-Click: Activate. "; break; case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS: cursor_ = rviz::makeIconCursor( "package://rviz/icons/move1d.svg" ); status_msg_ += "Left-Click: Move. "; break; case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE: cursor_ = rviz::makeIconCursor( "package://rviz/icons/move2d.svg" ); status_msg_ += "Left-Click: Move. "; break; case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS: cursor_ = rviz::makeIconCursor( "package://rviz/icons/rotate.svg" ); status_msg_ += "Left-Click: Rotate. "; break; case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE: cursor_ = rviz::makeIconCursor( "package://rviz/icons/moverotate.svg" ); status_msg_ += "Left-Click: Move / Rotate. "; break; case visualization_msgs::InteractiveMarkerControl::MOVE_3D: cursor_ = rviz::makeIconCursor( "package://rviz/icons/move2d.svg" ); status_msg_ += "Left-Click: Move X/Y. Shift + Left-Click / Left-Click + Wheel: Move Z. "; break; case visualization_msgs::InteractiveMarkerControl::ROTATE_3D: cursor_ = rviz::makeIconCursor( "package://rviz/icons/rotate.svg" ); status_msg_ += "Left-Click: Rotate around X/Y. Shift-Left-Click: Rotate around Z. "; break; case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D: cursor_ = rviz::makeIconCursor( "package://rviz/icons/moverotate.svg" ); status_msg_ += "Left-Click: Move X/Y. Shift + Left-Click / Left-Click + Wheel: Move Z. Ctrl + Left-Click: Rotate around X/Y. Ctrl + Shift + Left-Click: Rotate around Z. "; break; } if ( parent_->hasMenu() && interaction_mode_ != visualization_msgs::InteractiveMarkerControl::MENU ) { status_msg_ += "Right-Click: Show context menu."; } // It's not clear to me why this one setOrientation() call needs to // be here and not above makeMarkers() with the other // setOrientation() calls, but it works correctly when here and // incorrectly when there. Sorry. -hersh if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && independent_marker_orientation_ ) { markers_node_->setOrientation( parent_->getOrientation() ); } enableInteraction(context_->getSelectionManager()->getInteractionEnabled()); } // This is an Ogre::SceneManager::Listener function, and is configured // to be called only if this is a VIEW_FACING control. void InteractiveMarkerControl::preFindVisibleObjects( Ogre::SceneManager *source, Ogre::SceneManager::IlluminationRenderStage irs, Ogre::Viewport *v ) { updateControlOrientationForViewFacing( v ); } void InteractiveMarkerControl::updateControlOrientationForViewFacing( Ogre::Viewport* v ) { Ogre::Quaternion x_view_facing_rotation = control_orientation_.xAxis().getRotationTo( v->getCamera()->getDerivedDirection()); // rotate so z axis is up Ogre::Vector3 z_axis_2 = x_view_facing_rotation * control_orientation_.zAxis(); Ogre::Quaternion align_yz_rotation = z_axis_2.getRotationTo(v->getCamera()->getDerivedUp()); // rotate Ogre::Quaternion rotate_around_x = Ogre::Quaternion(rotation_, v->getCamera()->getDerivedDirection()); Ogre::Quaternion rotation = reference_node_->convertWorldToLocalOrientation( rotate_around_x * align_yz_rotation * x_view_facing_rotation ); control_frame_node_->setOrientation( rotation ); if ( !independent_marker_orientation_ ) { markers_node_->setOrientation( rotation ); // we need to refresh the node manually, since the scene manager will only do this one frame // later otherwise markers_node_->_update(true, false); } } bool InteractiveMarkerControl::getVisible() { return visible_ || always_visible_; } void InteractiveMarkerControl::setVisible( bool visible ) { visible_ = visible; if (always_visible_) { markers_node_->setVisible(visible_); } else { markers_node_->setVisible(interaction_enabled_ && visible_); } } void InteractiveMarkerControl::update() { if( mouse_dragging_ ) { handleMouseMovement( dragging_in_place_event_ ); } } void InteractiveMarkerControl::enableInteraction( bool enable ) { if (mouse_down_) { return; } interaction_enabled_ = enable; setVisible(visible_); if (!enable) { setHighlight(NO_HIGHLIGHT_VALUE); } } void InteractiveMarkerControl::interactiveMarkerPoseChanged( Ogre::Vector3 int_marker_position, Ogre::Quaternion int_marker_orientation ) { control_frame_node_->setPosition(int_marker_position); markers_node_->setPosition(int_marker_position); switch (orientation_mode_) { case visualization_msgs::InteractiveMarkerControl::INHERIT: control_frame_node_->setOrientation(int_marker_orientation); markers_node_->setOrientation(control_frame_node_->getOrientation()); break; case visualization_msgs::InteractiveMarkerControl::FIXED: { control_frame_node_->setOrientation( Ogre::Quaternion( rotation_, control_orientation_.xAxis() )); markers_node_->setOrientation(control_frame_node_->getOrientation()); break; } case visualization_msgs::InteractiveMarkerControl::VIEW_FACING: if( drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } if ( independent_marker_orientation_ ) { markers_node_->setOrientation(int_marker_orientation); } break; default: break; } } Ogre::Vector3 InteractiveMarkerControl::closestPointOnLineToPoint( const Ogre::Vector3& line_start, const Ogre::Vector3& line_dir, const Ogre::Vector3& test_point ) { // Find closest point on projected ray to mouse point // Math: if P is the start of the ray, v is the direction vector of // the ray (not normalized), and X is the test point, then the // closest point on the line to X is given by: // // (X-P).v // P + v * ------- // v.v // where "." is the dot product. double factor = ( test_point - line_start ).dotProduct( line_dir ) / line_dir.dotProduct( line_dir ); Ogre::Vector3 closest_point = line_start + line_dir * factor; return closest_point; } void InteractiveMarkerControl::rotate( Ogre::Ray &mouse_ray ) { Ogre::Vector3 intersection_3d; Ogre::Vector2 intersection_2d; float ray_t; Ogre::Vector3 rotation_axis = control_frame_orientation_at_mouse_down_ * control_orientation_.xAxis(); // Find rotation_center = 3D point closest to grab_point_ which is // on the rotation axis, relative to the reference frame. Ogre::Vector3 rotation_center = closestPointOnLineToPoint( control_frame_node_->getPosition(), rotation_axis, grab_point_in_reference_frame_ ); // Find intersection of mouse_ray with plane centered at rotation_center. if( intersectSomeYzPlane( mouse_ray, rotation_center, control_frame_orientation_at_mouse_down_, intersection_3d, intersection_2d, ray_t )) { // Not that efficient, but reduces code duplication... rotate(intersection_3d); } } void InteractiveMarkerControl::rotate( const Ogre::Vector3& cursor_in_reference_frame ) { Ogre::Vector3 rotation_axis = control_frame_orientation_at_mouse_down_ * control_orientation_.xAxis(); // Find rotation_center = 3D point closest to grab_point_ which is // on the rotation axis, relative to the reference frame. Ogre::Vector3 rotation_center = closestPointOnLineToPoint( control_frame_node_->getPosition(), rotation_axis, grab_point_in_reference_frame_ ); Ogre::Vector3 grab_rel_center = grab_point_in_reference_frame_ - rotation_center; Ogre::Vector3 center_to_cursor = cursor_in_reference_frame - rotation_center; Ogre::Vector3 center_to_cursor_radial = center_to_cursor - center_to_cursor.dotProduct(rotation_axis)*rotation_axis; Ogre::Quaternion orientation_change_since_mouse_down = grab_rel_center.getRotationTo( center_to_cursor_radial, rotation_axis ); Ogre::Radian rot; Ogre::Vector3 axis; orientation_change_since_mouse_down.ToAngleAxis( rot, axis ); // Quaternion::ToAngleAxis() always gives a positive angle. The // axis it emits (in this case) will either be equal to // rotation_axis or will be the negative of it. Doing the // dot-product then gives either 1.0 or -1.0, which is just what // we need to get the sign for our angle. Ogre::Radian rotation_since_mouse_down = rot * axis.dotProduct( rotation_axis ); rotation_ = rotation_at_mouse_down_ + rotation_since_mouse_down; parent_->setPose( parent_->getPosition(), orientation_change_since_mouse_down * parent_orientation_at_mouse_down_, name_ ); } Ogre::Ray InteractiveMarkerControl::getMouseRayInReferenceFrame( const ViewportMouseEvent& event, int x, int y ) { float width = event.viewport->getActualWidth() - 1; float height = event.viewport->getActualHeight() - 1; Ogre::Ray mouse_ray = event.viewport->getCamera()->getCameraToViewportRay( (x + .5) / width, (y + .5) / height ); // convert ray into reference frame mouse_ray.setOrigin( reference_node_->convertWorldToLocalPosition( mouse_ray.getOrigin() ) ); mouse_ray.setDirection( reference_node_->convertWorldToLocalOrientation( Ogre::Quaternion::IDENTITY ) * mouse_ray.getDirection() ); return mouse_ray; } void InteractiveMarkerControl::beginRelativeMouseMotion( const ViewportMouseEvent& event ) { mouse_x_at_drag_begin_ = event.x; mouse_y_at_drag_begin_ = event.y; modifiers_at_drag_begin_ = event.modifiers; mouse_ray_at_drag_begin_ = getMouseRayInReferenceFrame( event, event.x, event.y ); // ensure direction is unit vector mouse_ray_at_drag_begin_.setDirection(mouse_ray_at_drag_begin_.getDirection().normalisedCopy()); } bool InteractiveMarkerControl::getRelativeMouseMotion( const ViewportMouseEvent& event, int& dx, int& dy ) { dx = event.x - mouse_x_at_drag_begin_; dy = event.y - mouse_y_at_drag_begin_; if (dx == 0 && dy == 0) return false; QCursor::setPos( mouse_x_at_drag_begin_ + mouse_relative_to_absolute_x_, mouse_y_at_drag_begin_ + mouse_relative_to_absolute_y_ ); return true; } void InteractiveMarkerControl::rotateXYRelative( const ViewportMouseEvent& event ) { int dx; int dy; if (!getRelativeMouseMotion( event, dx, dy )) return; static const double MOUSE_SCALE = 2 * 3.14 / 300; // 300 pixels = 360deg Ogre::Radian rx(dx * MOUSE_SCALE); Ogre::Radian ry(dy * MOUSE_SCALE); Ogre::Quaternion up_rot(rx, event.viewport->getCamera()->getRealUp()); Ogre::Quaternion right_rot(ry, event.viewport->getCamera()->getRealRight()); parent_->setPose( parent_->getPosition(), up_rot * right_rot * parent_->getOrientation(), name_ ); } void InteractiveMarkerControl::rotateZRelative( const ViewportMouseEvent& event ) { int dx; int dy; getRelativeMouseMotion( event, dx, dy ); if (std::abs(dy) > std::abs(dx)) dx = dy; if (dx == 0) return; static const double MOUSE_SCALE = 2 * 3.14 / 300; // 300 pixels = 360deg Ogre::Radian rx(dx * MOUSE_SCALE); Ogre::Quaternion rot(rx, event.viewport->getCamera()->getRealDirection()); parent_->setPose( parent_->getPosition(), rot * parent_->getOrientation(), name_ ); } void InteractiveMarkerControl::moveZAxisRelative( const ViewportMouseEvent& event ) { int dx; int dy; getRelativeMouseMotion( event, dx, dy ); if (std::abs(dx) > std::abs(dy)) dy = -dx; if (dy == 0) return; double distance = -dy * mouse_z_scale_; Ogre::Vector3 delta = distance * mouse_ray_at_drag_begin_.getDirection(); parent_->setPose( parent_->getPosition() + delta, parent_->getOrientation(), name_ ); parent_position_at_mouse_down_ = parent_->getPosition(); } void InteractiveMarkerControl::moveZAxisWheel( const ViewportMouseEvent& event ) { // wheel_delta is in 1/8 degree and usually jumps 15 degrees at a time static const double WHEEL_TO_PIXEL_SCALE = (1.0/8.0) * (2.0/15.0); // 2 pixels per click double distance = event.wheel_delta * WHEEL_TO_PIXEL_SCALE; Ogre::Vector3 delta = distance * mouse_ray_at_drag_begin_.getDirection(); parent_->setPose( parent_->getPosition() + delta, parent_->getOrientation(), name_ ); parent_position_at_mouse_down_ = parent_->getPosition(); } void InteractiveMarkerControl::moveViewPlane( Ogre::Ray &mouse_ray, const ViewportMouseEvent& event ) { // find plane on which mouse is moving Ogre::Plane plane( event.viewport->getCamera()->getRealDirection(), grab_point_in_reference_frame_); // find intersection of mouse with the plane std::pair intersection = mouse_ray.intersects(plane); if (!intersection.first) return; Ogre::Vector3 mouse_position_on_plane = mouse_ray.getPoint(intersection.second); // move parent so grab position relative to parent coincides with new mouse position. parent_->setPose( mouse_position_on_plane - grab_point_in_reference_frame_ + parent_position_at_mouse_down_, parent_->getOrientation(), name_ ); } void InteractiveMarkerControl::movePlane( Ogre::Ray &mouse_ray ) { if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } Ogre::Vector3 intersection_3d; Ogre::Vector2 intersection_2d; float ray_t; if( intersectSomeYzPlane( mouse_ray, grab_point_in_reference_frame_, control_frame_node_->getOrientation(), intersection_3d, intersection_2d, ray_t )) { parent_->setPose( intersection_3d - grab_point_in_reference_frame_ + parent_position_at_mouse_down_, parent_->getOrientation(), name_ ); } } void InteractiveMarkerControl::movePlane( const Ogre::Vector3& cursor_position_in_reference_frame ) { if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } Ogre::Vector3 plane_normal = (control_frame_node_->getOrientation() * control_orientation_.xAxis()); Ogre::Vector3 displacement = (cursor_position_in_reference_frame - grab_point_in_reference_frame_); Ogre::Vector3 displacement_on_plane = displacement - displacement.dotProduct(plane_normal) * plane_normal; // set position of parent to parent_position_at_mouse_down_ + displacement_on_plane. parent_->setPose( parent_position_at_mouse_down_ + displacement_on_plane, parent_->getOrientation(), name_ ); } /** Project a world position onto the viewport to find screen coordinates in pixels. * @param screen_pos the resultant screen position, in pixels. */ void InteractiveMarkerControl::worldToScreen( const Ogre::Vector3& pos_rel_reference, const Ogre::Viewport* viewport, Ogre::Vector2& screen_pos ) { Ogre::Vector3 world_pos = reference_node_->convertLocalToWorldPosition( pos_rel_reference ); const Ogre::Camera* cam = viewport->getCamera(); Ogre::Vector3 homogeneous_screen_position = cam->getProjectionMatrix() * (cam->getViewMatrix() * world_pos); double half_width = viewport->getActualWidth() / 2.0; double half_height = viewport->getActualHeight() / 2.0; screen_pos.x = half_width + (half_width * homogeneous_screen_position.x) - .5; screen_pos.y = half_height + (half_height * -homogeneous_screen_position.y) - .5; } /** Find the closest point on target_ray to mouse_ray. * @returns false if rays are effectively parallel, true otherwise. */ bool InteractiveMarkerControl::findClosestPoint( const Ogre::Ray& target_ray, const Ogre::Ray& mouse_ray, Ogre::Vector3& closest_point ) { // Find the closest point on target_ray to any point on mouse_ray. // // Math taken from http://paulbourke.net/geometry/lineline3d/ // line P1->P2 is target_ray // line P3->P4 is mouse_ray Ogre::Vector3 v13 = target_ray.getOrigin() - mouse_ray.getOrigin(); Ogre::Vector3 v43 = mouse_ray.getDirection(); Ogre::Vector3 v21 = target_ray.getDirection(); double d1343 = v13.dotProduct( v43 ); double d4321 = v43.dotProduct( v21 ); double d1321 = v13.dotProduct( v21 ); double d4343 = v43.dotProduct( v43 ); double d2121 = v21.dotProduct( v21 ); double denom = d2121 * d4343 - d4321 * d4321; if( fabs( denom ) <= Ogre::Matrix3::EPSILON ) { return false; } double numer = d1343 * d4321 - d1321 * d4343; double mua = numer / denom; closest_point = target_ray.getPoint( mua ); return true; } void InteractiveMarkerControl::moveAxis( const Ogre::Ray& mouse_ray, const ViewportMouseEvent& event ) { // compute control-axis ray based on grab_point_, etc. Ogre::Ray control_ray; control_ray.setOrigin( grab_point_in_reference_frame_ ); control_ray.setDirection( control_frame_node_->getOrientation() * control_orientation_.xAxis() ); // project control-axis ray onto screen. Ogre::Vector2 control_ray_screen_start, control_ray_screen_end; worldToScreen( control_ray.getOrigin(), event.viewport, control_ray_screen_start ); worldToScreen( control_ray.getPoint( 1 ), event.viewport, control_ray_screen_end ); Ogre::Vector2 mouse_point( event.x, event.y ); // Find closest point on projected ray to mouse point // Math: if P is the start of the ray, v is the direction vector of // the ray (not normalized), and X is the test point, then the // closest point on the line to X is given by: // // (X-P).v // P + v * ------- // v.v // where "." is the dot product. Ogre::Vector2 control_ray_screen_dir = control_ray_screen_end - control_ray_screen_start; double denominator = control_ray_screen_dir.dotProduct( control_ray_screen_dir ); if( fabs( denominator ) > Ogre::Matrix3::EPSILON ) // If the control ray is not straight in line with the view. { double factor = ( mouse_point - control_ray_screen_start ).dotProduct( control_ray_screen_dir ) / denominator; Ogre::Vector2 closest_screen_point = control_ray_screen_start + control_ray_screen_dir * factor; // make a new "mouse ray" for the point on the projected ray Ogre::Ray new_mouse_ray = getMouseRayInReferenceFrame( event, closest_screen_point.x, closest_screen_point.y ); // find closest point on control-axis ray to new mouse ray (should intersect actually) Ogre::Vector3 closest_point; if( findClosestPoint( control_ray, new_mouse_ray, closest_point )) { // set position of parent to closest_point - grab_point_ + parent_position_at_mouse_down_. parent_->setPose( closest_point - grab_point_in_reference_frame_ + parent_position_at_mouse_down_, parent_->getOrientation(), name_ ); } } } void InteractiveMarkerControl::moveAxis( const Ogre::Vector3& cursor_position_in_reference_frame ) { Ogre::Vector3 control_unit_direction = (control_frame_node_->getOrientation() * control_orientation_.xAxis()); Ogre::Vector3 displacement_along_axis = (cursor_position_in_reference_frame - grab_point_in_reference_frame_).dotProduct(control_unit_direction) * control_unit_direction; // set position of parent to closest_point - grab_point_ + parent_position_at_mouse_down_. parent_->setPose( parent_position_at_mouse_down_ + displacement_along_axis, parent_->getOrientation(), name_ ); } void InteractiveMarkerControl::moveRotate( Ogre::Ray &mouse_ray ) { if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } Ogre::Vector3 new_drag_rel_ref; Ogre::Vector2 intersection_2d; float ray_t; // get rotation axis rel ref (constant for entire drag) // - rotation_axis_ // get current rotation center rel ref // - compute rotation center rel control frame at mouse-down (constant for entire drag) // - current rotation center rel ref = current control frame * above Ogre::Matrix4 control_rel_ref; control_rel_ref.makeTransform( control_frame_node_->getPosition(), Ogre::Vector3::UNIT_SCALE, control_frame_node_->getOrientation() ); Ogre::Vector3 rotation_center = control_rel_ref * rotation_center_rel_control_; // get previous 3D drag point rel ref // - compute grab point rel control frame at mouse-down (constant for entire drag) // - prev_drag_rel_ref = current control frame + above Ogre::Vector3 prev_drag_rel_ref = control_rel_ref * grab_point_rel_control_; // get new 3D drag point rel ref (this is "intersection_3d" in rotate().) // - intersectSomeYzPlane( mouse_ray, rotation_center, control_frame_orientation ) if( intersectSomeYzPlane( mouse_ray, rotation_center, control_frame_node_->getOrientation(), new_drag_rel_ref, intersection_2d, ray_t )) { // compute rotation angle from old drag point to new. // - prev_rel_center = prev_drag_rel_ref - rotation_center // - new_rel_center = new_drag_rel_ref - rotation_center // - rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis ) // - get Radians of angle change // - rotation_ += angle_change // - parent_->rotate(rotation_change) Ogre::Vector3 prev_rel_center = prev_drag_rel_ref - rotation_center; Ogre::Vector3 new_rel_center = new_drag_rel_ref - rotation_center; if( new_rel_center.length() > Ogre::Matrix3::EPSILON ) { Ogre::Quaternion rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis_ ); Ogre::Radian rot; Ogre::Vector3 axis; rotation_change.ToAngleAxis( rot, axis ); // Quaternion::ToAngleAxis() always gives a positive angle. The // axis it emits (in this case) will either be equal to // rotation_axis or will be the negative of it. Doing the // dot-product then gives either 1.0 or -1.0, which is just what // we need to get the sign for our angle. Ogre::Radian angle_change = rot * axis.dotProduct( rotation_axis_ ); rotation_ += angle_change; parent_->rotate( rotation_change, name_ ); // compute translation from rotated old drag point to new drag point. // - pos_change = new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length()) // - parent_->translate(pos_change) parent_->translate( new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length()), name_ ); } } } void InteractiveMarkerControl::moveRotate( const Ogre::Vector3& cursor_position_in_reference_frame, bool lock_axis ) { if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } // get rotation axis rel ref (constant for entire drag) // - rotation_axis_ // get current rotation center rel ref // - compute rotation center rel control frame at mouse-down (constant for entire drag) // - current rotation center rel ref = current control frame * above Ogre::Matrix4 control_rel_ref; control_rel_ref.makeTransform( control_frame_node_->getPosition(), Ogre::Vector3::UNIT_SCALE, control_frame_node_->getOrientation() ); Ogre::Vector3 rotation_center = control_rel_ref * rotation_center_rel_control_; // get previous 3D drag point rel ref // - compute grab point rel control frame at mouse-down (constant for entire drag) // - prev_drag_rel_ref = current control frame + above Ogre::Vector3 prev_drag_rel_ref = control_rel_ref * grab_point_rel_control_; Ogre::Vector3 new_drag_rel_ref = cursor_position_in_reference_frame; if (lock_axis) { Ogre::Vector3 plane_normal = (control_frame_node_->getOrientation() * control_orientation_.xAxis()); Ogre::Vector3 perpendicular_offset = (new_drag_rel_ref - prev_drag_rel_ref) .dotProduct(plane_normal)*plane_normal; new_drag_rel_ref -= perpendicular_offset; } //Ogre::Vector3 new_drag_rel_ref = cursor_position_in_reference_frame; // compute rotation angle from old drag point to new. // - prev_rel_center = prev_drag_rel_ref - rotation_center // - new_rel_center = new_drag_rel_ref - rotation_center // - rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis ) // - get Radians of angle change // - rotation_ += angle_change // - parent_->rotate(rotation_change) Ogre::Vector3 prev_rel_center = prev_drag_rel_ref - rotation_center; Ogre::Vector3 new_rel_center = new_drag_rel_ref - rotation_center; if( new_rel_center.length() > Ogre::Matrix3::EPSILON ) { Ogre::Quaternion rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis_ ); Ogre::Radian rot; Ogre::Vector3 axis; rotation_change.ToAngleAxis( rot, axis ); // Quaternion::ToAngleAxis() always gives a positive angle. The // axis it emits (in this case) will either be equal to // rotation_axis or will be the negative of it. Doing the // dot-product then gives either 1.0 or -1.0, which is just what // we need to get the sign for our angle. Ogre::Radian angle_change = rot * axis.dotProduct( rotation_axis_ ); rotation_ += angle_change; parent_->rotate( rotation_change, name_ ); // compute translation from rotated old drag point to new drag point. // - pos_change = new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length()) // - parent_->translate(pos_change) parent_->translate( new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length()), name_ ); } } void InteractiveMarkerControl::move3D( const Ogre::Vector3& cursor_position_in_reference_frame, const Ogre::Quaternion& cursor_orientation_in_reference_frame ) { if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } //parent_to_cursor_in_cursor_frame_at_grab_ = cursor_3D_orientation.Inverse()*(cursor_3D_pos - parent_->getPosition()); //rotation_cursor_to_parent_at_grab_ = cursor_3D_orientation.Inverse()*parent->getOrientation(); Ogre::Vector3 world_to_cursor_in_world_frame = reference_node_->convertLocalToWorldPosition(cursor_position_in_reference_frame); Ogre::Quaternion rotation_world_to_cursor = reference_node_->convertLocalToWorldOrientation(cursor_orientation_in_reference_frame); //Ogre::Vector3 marker_to_cursor_in_cursor_frame = orientation_world_to_cursor.Inverse()*reference_node_->getOrientation()*grab_point_in_reference_frame_; Ogre::Vector3 world_to_cursor_in_cursor_frame = rotation_world_to_cursor.Inverse()*world_to_cursor_in_world_frame; Ogre::Vector3 world_to_marker_in_world_frame = rotation_world_to_cursor*(world_to_cursor_in_cursor_frame - parent_to_cursor_in_cursor_frame_at_grab_); Ogre::Vector3 marker_position_in_reference_frame = reference_node_->convertWorldToLocalPosition(world_to_marker_in_world_frame); //Ogre::Quaternion marker_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation(rotation_world_to_cursor*rotation_cursor_to_parent_at_grab_); parent_->setPose( marker_position_in_reference_frame, parent_->getOrientation(), name_ ); } void InteractiveMarkerControl::rotate3D( const Ogre::Vector3& cursor_position_in_reference_frame, const Ogre::Quaternion& cursor_orientation_in_reference_frame ) { if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } //parent_to_cursor_in_cursor_frame_at_grab_ = cursor_3D_orientation.Inverse()*(cursor_3D_pos - parent_->getPosition()); //rotation_cursor_to_parent_at_grab_ = cursor_3D_orientation.Inverse()*parent->getOrientation(); Ogre::Vector3 world_to_cursor_in_world_frame = reference_node_->convertLocalToWorldPosition(cursor_position_in_reference_frame); Ogre::Quaternion rotation_world_to_cursor = reference_node_->convertLocalToWorldOrientation(cursor_orientation_in_reference_frame); //Ogre::Vector3 marker_to_cursor_in_cursor_frame = orientation_world_to_cursor.Inverse()*reference_node_->getOrientation()*grab_point_in_reference_frame_; Ogre::Vector3 world_to_cursor_in_cursor_frame = rotation_world_to_cursor.Inverse()*world_to_cursor_in_world_frame; Ogre::Vector3 world_to_marker_in_world_frame = rotation_world_to_cursor*(world_to_cursor_in_cursor_frame - parent_to_cursor_in_cursor_frame_at_grab_); Ogre::Vector3 marker_position_in_reference_frame = reference_node_->convertWorldToLocalPosition(world_to_marker_in_world_frame); Ogre::Quaternion marker_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation(rotation_world_to_cursor*rotation_cursor_to_parent_at_grab_); parent_->setPose( parent_->getPosition(), marker_orientation_in_reference_frame, name_ ); } void InteractiveMarkerControl::moveRotate3D( const Ogre::Vector3& cursor_position_in_reference_frame, const Ogre::Quaternion& cursor_orientation_in_reference_frame ) { if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } //parent_to_cursor_in_cursor_frame_at_grab_ = cursor_3D_orientation.Inverse()*(cursor_3D_pos - parent_->getPosition()); //rotation_cursor_to_parent_at_grab_ = cursor_3D_orientation.Inverse()*parent->getOrientation(); Ogre::Vector3 world_to_cursor_in_world_frame = reference_node_->convertLocalToWorldPosition(cursor_position_in_reference_frame); Ogre::Quaternion rotation_world_to_cursor = reference_node_->convertLocalToWorldOrientation(cursor_orientation_in_reference_frame); //Ogre::Vector3 marker_to_cursor_in_cursor_frame = orientation_world_to_cursor.Inverse()*reference_node_->getOrientation()*grab_point_in_reference_frame_; Ogre::Vector3 world_to_cursor_in_cursor_frame = rotation_world_to_cursor.Inverse()*world_to_cursor_in_world_frame; Ogre::Vector3 world_to_marker_in_world_frame = rotation_world_to_cursor*(world_to_cursor_in_cursor_frame - parent_to_cursor_in_cursor_frame_at_grab_); Ogre::Vector3 marker_position_in_reference_frame = reference_node_->convertWorldToLocalPosition(world_to_marker_in_world_frame); Ogre::Quaternion marker_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation(rotation_world_to_cursor*rotation_cursor_to_parent_at_grab_); parent_->setPose( marker_position_in_reference_frame, marker_orientation_in_reference_frame, name_ ); } void InteractiveMarkerControl::setHighlight( const ControlHighlight &hl ){ if(hl == NO_HIGHLIGHT) setHighlight(NO_HIGHLIGHT_VALUE); if(hl == HOVER_HIGHLIGHT) setHighlight(HOVER_HIGHLIGHT_VALUE); if(hl == ACTIVE_HIGHLIGHT) setHighlight(ACTIVE_HIGHLIGHT_VALUE); } void InteractiveMarkerControl::setHighlight( float a ) { std::set::iterator it; for (it = highlight_passes_.begin(); it != highlight_passes_.end(); it++) { (*it)->setAmbient(a,a,a); } std::vector::iterator pm_it; for( pm_it = points_markers_.begin(); pm_it != points_markers_.end(); pm_it++ ) { (*pm_it)->setHighlightColor( a, a, a ); } } void InteractiveMarkerControl::recordDraggingInPlaceEvent( ViewportMouseEvent& event ) { dragging_in_place_event_ = event; dragging_in_place_event_.type = QEvent::MouseMove; } void InteractiveMarkerControl::stopDragging( bool force ) { // aleeper: Why is this check here? What happens when this mouse_dragging_ check isn't done at all? // Or as an alternative to this minor API change, we could just manually set mouse_dragging_ // to true before calling this function from the 3D cursor code. // BUT that would be a hack... if ( mouse_dragging_ || force ) { line_->setVisible(false); mouse_dragging_ = false; drag_viewport_ = NULL; parent_->stopDragging(); } } // Almost a wholesale copy of the mouse event code... can these be combined? void InteractiveMarkerControl::handle3DCursorEvent( ViewportMouseEvent event, const Ogre::Vector3& cursor_3D_pos, const Ogre::Quaternion& cursor_3D_orientation) { // change dragging state switch( interaction_mode_ ) { case visualization_msgs::InteractiveMarkerControl::BUTTON: if( event.leftUp() ) { Ogre::Vector3 point_rel_world = cursor_3D_pos; bool got_3D_point = true; visualization_msgs::InteractiveMarkerFeedback feedback; feedback.event_type = visualization_msgs::InteractiveMarkerFeedback::BUTTON_CLICK; feedback.control_name = name_; feedback.marker_name = parent_->getName(); parent_->publishFeedback( feedback, got_3D_point, point_rel_world ); } break; case visualization_msgs::InteractiveMarkerControl::MENU: if( event.leftUp() ) { // Save the 3D mouse point to send with the menu feedback, if any. Ogre::Vector3 three_d_point = cursor_3D_pos; bool valid_point = true; Ogre::Vector2 mouse_pos = project3DPointToViewportXY(event.viewport, three_d_point); QCursor::setPos(event.panel->mapToGlobal(QPoint(mouse_pos.x, mouse_pos.y))); parent_->showMenu( event, name_, three_d_point, valid_point ); } break; case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS: case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE: case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE: case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS: case visualization_msgs::InteractiveMarkerControl::MOVE_3D: case visualization_msgs::InteractiveMarkerControl::ROTATE_3D: case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D: if( event.leftDown() ) { parent_->startDragging(); drag_viewport_ = event.viewport; //recordDraggingInPlaceEvent( event ); grab_point_in_reference_frame_ = reference_node_->convertWorldToLocalPosition( cursor_3D_pos ); grab_orientation_in_reference_frame_ = reference_node_->convertWorldToLocalOrientation( cursor_3D_orientation ); parent_to_cursor_in_cursor_frame_at_grab_ = cursor_3D_orientation.Inverse()*(cursor_3D_pos - reference_node_->convertLocalToWorldPosition(parent_->getPosition())); rotation_cursor_to_parent_at_grab_ = cursor_3D_orientation.Inverse()*reference_node_->convertLocalToWorldOrientation(parent_->getOrientation()); parent_position_at_mouse_down_ = parent_->getPosition(); parent_orientation_at_mouse_down_ = parent_->getOrientation(); if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } control_frame_orientation_at_mouse_down_ = control_frame_node_->getOrientation(); rotation_at_mouse_down_ = rotation_; rotation_axis_ = control_frame_node_->getOrientation() * control_orientation_.xAxis(); // Find rotation_center = 3D point closest to grab_point_ which is // on the rotation axis, relative to the reference frame. Ogre::Vector3 rotation_center_rel_ref = closestPointOnLineToPoint( parent_->getPosition(), rotation_axis_, grab_point_in_reference_frame_ ); Ogre::Matrix4 reference_rel_control_frame; reference_rel_control_frame.makeInverseTransform( control_frame_node_->getPosition(), Ogre::Vector3::UNIT_SCALE, control_frame_node_->getOrientation() ); rotation_center_rel_control_ = reference_rel_control_frame * rotation_center_rel_ref; grab_point_rel_control_ = reference_rel_control_frame * grab_point_in_reference_frame_; } if( event.leftUp() ) { // Alternatively, could just manually set mouse_dragging_ to true. stopDragging( true ); } break; default: break; } if( event.leftDown() ) { setHighlight( ACTIVE_HIGHLIGHT_VALUE ); } else if( event.leftUp() ) { setHighlight( HOVER_HIGHLIGHT_VALUE ); } if (!parent_->handle3DCursorEvent(event, cursor_3D_pos, cursor_3D_orientation, name_)) { if( event.type == QEvent::MouseMove && event.left()) // && mouse_dragging_) { Ogre::Vector3 cursor_position_in_reference_frame = reference_node_->convertWorldToLocalPosition( cursor_3D_pos ); Ogre::Quaternion cursor_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation( cursor_3D_orientation ); switch (interaction_mode_) { case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS: rotate( cursor_position_in_reference_frame ); break; case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS: moveAxis( cursor_position_in_reference_frame ); break; case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE: movePlane( cursor_position_in_reference_frame ); break; case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE: moveRotate( cursor_position_in_reference_frame, true ); break; case visualization_msgs::InteractiveMarkerControl::MOVE_3D: move3D( cursor_position_in_reference_frame, cursor_orientation_in_reference_frame ); break; case visualization_msgs::InteractiveMarkerControl::ROTATE_3D: rotate3D( cursor_position_in_reference_frame, cursor_orientation_in_reference_frame ); break; case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D: moveRotate3D( cursor_position_in_reference_frame, cursor_orientation_in_reference_frame ); break; default: break; } } } } void InteractiveMarkerControl::handleMouseEvent( ViewportMouseEvent& event ) { // REMOVE ME ROS_INFO("Mouse event!"); // * check if this is just a receive/lost focus event // * try to hand over the mouse event to the parent interactive marker // * otherwise, execute mouse move handling // handle receive/lose focus if( event.type == QEvent::FocusIn ) { has_focus_ = true; std::set::iterator it; setHighlight( HOVER_HIGHLIGHT_VALUE ); context_->setStatus( status_msg_ ); } else if( event.type == QEvent::FocusOut ) { stopDragging(); has_focus_ = false; setHighlight(0.0); return; } mouse_down_ = event.left() || event.middle() || event.right(); // change dragging state switch( interaction_mode_ ) { case visualization_msgs::InteractiveMarkerControl::BUTTON: if( event.leftUp() ) { Ogre::Vector3 point_rel_world; bool got_3D_point = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, point_rel_world ); visualization_msgs::InteractiveMarkerFeedback feedback; feedback.event_type = visualization_msgs::InteractiveMarkerFeedback::BUTTON_CLICK; feedback.control_name = name_; feedback.marker_name = parent_->getName(); parent_->publishFeedback( feedback, got_3D_point, point_rel_world ); } break; case visualization_msgs::InteractiveMarkerControl::MENU: if( event.leftUp() ) { Ogre::Vector3 point_rel_world; bool got_3D_point = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, point_rel_world ); parent_->showMenu( event, name_, point_rel_world, got_3D_point ); } break; case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS: case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE: case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS: if ( event.leftDown() ) beginMouseMovement( event, show_visual_aids_ && orientation_mode_ != visualization_msgs::InteractiveMarkerControl::VIEW_FACING); break; case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE: if( event.leftDown() ) beginMouseMovement( event, false); break; case visualization_msgs::InteractiveMarkerControl::MOVE_3D: case visualization_msgs::InteractiveMarkerControl::ROTATE_3D: case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D: if ( event.leftDown() ) { // aleeper: This line was causing badness //orientation_mode_ = visualization_msgs::InteractiveMarkerControl::VIEW_FACING; beginMouseMovement( event, false ); } else if ( event.left() && ((modifiers_at_drag_begin_ ^ event.modifiers) & (Qt::ShiftModifier | Qt::ControlModifier)) ) { // modifier buttons changed. Restart the drag. beginRelativeMouseMotion( event ); } break; default: break; } if (!parent_->handleMouseEvent(event, name_)) { if( event.type == QEvent::MouseMove && event.left() && mouse_dragging_) { recordDraggingInPlaceEvent( event ); handleMouseMovement( event ); } else if( event.type == QEvent::Wheel && event.left() && mouse_dragging_) { handleMouseWheelMovement( event ); } } if( event.leftDown() ) { setHighlight( ACTIVE_HIGHLIGHT_VALUE ); } else if( event.leftUp() ) { setHighlight( HOVER_HIGHLIGHT_VALUE ); stopDragging(); } } void InteractiveMarkerControl::beginMouseMovement( ViewportMouseEvent& event, bool line_visible ) { line_->setVisible(line_visible); parent_->startDragging(); mouse_dragging_ = true; drag_viewport_ = event.viewport; recordDraggingInPlaceEvent( event ); Ogre::Vector3 grab_point_in_world_frame; if( ! context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, grab_point_in_world_frame )) { // If we couldn't get a 3D point for the grab, just use the // current relative position of the control frame. grab_point_in_reference_frame_ = control_frame_node_->getPosition(); } else { // If we could get a 3D point for the grab, convert it from // the world frame to the reference frame (in case those are different). grab_point_in_reference_frame_ = reference_node_->convertWorldToLocalPosition(grab_point_in_world_frame); } parent_position_at_mouse_down_ = parent_->getPosition(); parent_orientation_at_mouse_down_ = parent_->getOrientation(); QPoint absolute_mouse = QCursor::pos(); mouse_relative_to_absolute_x_ = absolute_mouse.x() - event.x; mouse_relative_to_absolute_y_ = absolute_mouse.y() - event.y; beginRelativeMouseMotion( event ); if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING && drag_viewport_ ) { updateControlOrientationForViewFacing( drag_viewport_ ); } control_frame_orientation_at_mouse_down_ = control_frame_node_->getOrientation(); rotation_at_mouse_down_ = rotation_; rotation_axis_ = control_frame_node_->getOrientation() * control_orientation_.xAxis(); // Find rotation_center = 3D point closest to grab_point_ which is // on the rotation axis, relative to the reference frame. Ogre::Vector3 rotation_center_rel_ref = closestPointOnLineToPoint( parent_->getPosition(), rotation_axis_, grab_point_in_reference_frame_ ); Ogre::Matrix4 reference_rel_control_frame; reference_rel_control_frame.makeInverseTransform( control_frame_node_->getPosition(), Ogre::Vector3::UNIT_SCALE, control_frame_node_->getOrientation() ); rotation_center_rel_control_ = reference_rel_control_frame * rotation_center_rel_ref; grab_point_rel_control_ = reference_rel_control_frame * grab_point_in_reference_frame_; // find mouse_z_scale_ static const double DEFAULT_MOUSE_Z_SCALE = 0.001; // default to 1mm per pixel mouse_z_scale_ = DEFAULT_MOUSE_Z_SCALE; Ogre::Ray mouse_ray = getMouseRayInReferenceFrame( event, event.x, event.y ); Ogre::Ray mouse_ray_10 = getMouseRayInReferenceFrame( event, event.x, event.y + 10 ); Ogre::Vector3 intersection_3d; Ogre::Vector3 intersection_3d_10; Ogre::Vector2 intersection_2d; float ray_t; if( intersectSomeYzPlane( mouse_ray, grab_point_in_reference_frame_, control_frame_node_->getOrientation(), intersection_3d, intersection_2d, ray_t )) { if( intersectSomeYzPlane( mouse_ray_10, grab_point_in_reference_frame_, control_frame_node_->getOrientation(), intersection_3d_10, intersection_2d, ray_t )) { mouse_z_scale_ = (intersection_3d_10 - intersection_3d).length() / 10.0; if (mouse_z_scale_ < std::numeric_limits::min() * 100.0) mouse_z_scale_ = DEFAULT_MOUSE_Z_SCALE; } } } void InteractiveMarkerControl::handleMouseMovement( ViewportMouseEvent& event ) { Ogre::Ray mouse_ray = getMouseRayInReferenceFrame( event, event.x, event.y ); Ogre::Ray last_mouse_ray = getMouseRayInReferenceFrame( event, event.last_x, event.last_y ); bool do_rotation = false; switch (interaction_mode_) { case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS: moveAxis( mouse_ray, event ); break; case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE: movePlane( mouse_ray ); break; case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE: moveRotate( mouse_ray ); break; case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS: rotate( mouse_ray ); break; case visualization_msgs::InteractiveMarkerControl::ROTATE_3D: do_rotation = true; // fall through case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D: if ( event.control() ) do_rotation = true; // fall through case visualization_msgs::InteractiveMarkerControl::MOVE_3D: if ( do_rotation ) { if (event.shift()) rotateZRelative( event ); else rotateXYRelative( event ); } else { if (event.shift()) moveZAxisRelative( event ); else moveViewPlane( mouse_ray, event ); } break; default: break; } } void InteractiveMarkerControl::handleMouseWheelMovement( ViewportMouseEvent& event ) { switch (interaction_mode_) { case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D: case visualization_msgs::InteractiveMarkerControl::MOVE_3D: moveZAxisWheel( event ); break; default: break; } } bool InteractiveMarkerControl::intersectYzPlane( const Ogre::Ray& mouse_ray, Ogre::Vector3& intersection_3d, Ogre::Vector2& intersection_2d, float &ray_t ) { return intersectSomeYzPlane( mouse_ray, control_frame_node_->getPosition(), control_frame_node_->getOrientation(), intersection_3d, intersection_2d, ray_t ); } bool InteractiveMarkerControl::intersectSomeYzPlane( const Ogre::Ray& mouse_ray, const Ogre::Vector3& point_on_plane, const Ogre::Quaternion& plane_orientation, Ogre::Vector3& intersection_3d, Ogre::Vector2& intersection_2d, float& ray_t ) { Ogre::Vector3 normal = plane_orientation * control_orientation_.xAxis(); Ogre::Vector3 axis_1 = plane_orientation * control_orientation_.yAxis(); Ogre::Vector3 axis_2 = plane_orientation * control_orientation_.zAxis(); Ogre::Plane plane(normal, point_on_plane); Ogre::Vector2 origin_2d(point_on_plane.dotProduct(axis_1), point_on_plane.dotProduct(axis_2)); std::pair intersection = mouse_ray.intersects(plane); if (intersection.first) { intersection_3d = mouse_ray.getPoint(intersection.second); intersection_2d = Ogre::Vector2(intersection_3d.dotProduct(axis_1), intersection_3d.dotProduct(axis_2)); intersection_2d -= origin_2d; ray_t = intersection.second; return true; } ray_t = 0; return false; } void InteractiveMarkerControl::addHighlightPass( S_MaterialPtr materials ) { S_MaterialPtr::iterator it; for (it = materials.begin(); it != materials.end(); it++) { Ogre::MaterialPtr material = *it; Ogre::Pass *original_pass = material->getTechnique(0)->getPass(0); Ogre::Pass *pass = material->getTechnique(0)->createPass(); pass->setSceneBlending(Ogre::SBT_ADD); pass->setDepthWriteEnabled(false); pass->setDepthCheckEnabled(true); pass->setLightingEnabled(true); pass->setAmbient(0, 0, 0); pass->setDiffuse(0, 0, 0, 0); pass->setSpecular(0, 0, 0, 0); pass->setCullingMode(original_pass->getCullingMode()); highlight_passes_.insert(pass); } } } rviz-1.12.4/src/rviz/default_plugin/interactive_markers/interactive_marker_control.h000066400000000000000000000432411300447110700312050ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef INTERACTIVE_MARKER_CONTROL_H_ #define INTERACTIVE_MARKER_CONTROL_H_ #ifndef Q_MOC_RUN #include #include #include #include #include #include #endif #include #include #include "rviz/default_plugin/markers/marker_base.h" #include "rviz/selection/forwards.h" #include "rviz/viewport_mouse_event.h" #include "rviz/interactive_object.h" namespace Ogre { class SceneNode; } namespace rviz { class DisplayContext; class InteractiveMarker; class PointsMarker; class Line; /** * A single control element of an InteractiveMarker. */ class InteractiveMarkerControl: public Ogre::SceneManager::Listener, public InteractiveObject, public boost::enable_shared_from_this { public: /** @brief Constructor. * * Just creates Ogre::SceneNodes and sets some defaults. To * actually make it look like a * visualization_msgs::InteractiveMarkerControl message specifies, * call processMessage(). */ InteractiveMarkerControl( DisplayContext* context, Ogre::SceneNode *reference_node, InteractiveMarker *parent ); virtual ~InteractiveMarkerControl(); /** @brief Set up or update the contents of this control to match the * specification in the message. */ void processMessage( const visualization_msgs::InteractiveMarkerControl &message ); // called when interactive mode is globally switched on/off virtual void enableInteraction(bool enable); // will receive all mouse events while the handler has focus virtual void handleMouseEvent(ViewportMouseEvent& event); /** * This is the main entry-point for interaction using a 3D cursor. *

* The ViewportMouseEvent struct is used to "fake" a mouse event. * An event must have the panel, viewport, and type members filled in. * The acting_button and buttons_down members can be specified as well, if appropriate. * All other fields are currently ignored. *

* A sample construction of a "right-button mouse-up" event: * @code * ViewportMouseEvent event; * event.panel = context_->getViewManager()->getRenderPanel(); * event.viewport = context_->getViewManager()->getRenderPanel()->getRenderWindow()->getViewport(0); * event.type = QEvent::MouseButtonRelease; * event.acting_button = Qt::RightButton; * event.buttons_down = Qt::NoButton; * @endcode *

* For more examples, see the implementation in the interaction_cursor_rviz package. * * @param event A struct holding certain event data (see description above). * @param cursor_pos The world-relative position of the 3D cursor. * @param cursor_rot The world-relative orientation of the 3D cursor. * @param control_name The name of the child InteractiveMarkerControl calling this function. */ virtual void handle3DCursorEvent( ViewportMouseEvent event, const Ogre::Vector3& cursor_3D_pos, const Ogre::Quaternion& cursor_3D_orientation); /** Update the pose of the interactive marker being controlled, * relative to the reference frame. Each InteractiveMarkerControl * maintains its pose relative to the reference frame independently, * so when the parent InteractiveMarker mvoes, it calls this * function on all its child controls. */ void interactiveMarkerPoseChanged( Ogre::Vector3 int_marker_position, Ogre::Quaternion int_marker_orientation ); bool isInteractive() { return interaction_mode_ != visualization_msgs::InteractiveMarkerControl::NONE; } // Called every frame by parent's update() function. void update(); void setVisible( bool visible ); bool getVisible(); // Highlight types enum ControlHighlight { NO_HIGHLIGHT = 0, HOVER_HIGHLIGHT = 3, ACTIVE_HIGHLIGHT = 5}; // Public access to highlight controls void setHighlight( const ControlHighlight &hl ); /** * @return pointer to the parent InteractiveMarker */ InteractiveMarker* getParent() { return parent_ ;} /** * @return the name of this control */ const std::string& getName() { return name_; } /** * @return the description for this control */ const QString& getDescription() { return description_; } /** * @return the visualization_msgs::InteractiveMarkerControl interaction_mode for this control */ int getInteractionMode() { return interaction_mode_; } /** * @return the visualization_msgs::InteractiveMarkerControl orientation_mode for this control */ int getOrientationMode() { return orientation_mode_; } /** * @brief If true, will show some geometric helpers while dragging */ void setShowVisualAids( bool show ) { show_visual_aids_ = show; } protected: // when this is called, we will face the camera virtual void preFindVisibleObjects(Ogre::SceneManager *source, Ogre::SceneManager::IlluminationRenderStage irs, Ogre::Viewport *v); void updateControlOrientationForViewFacing( Ogre::Viewport* v ); /** calculate a mouse ray in the reference frame. * A mouse ray is a ray starting at the camera and pointing towards the mouse position. */ Ogre::Ray getMouseRayInReferenceFrame( const ViewportMouseEvent& event, int x, int y ); /** begin a relative-motion drag. */ void beginRelativeMouseMotion( const ViewportMouseEvent& event ); /** get the relative motion of the mouse, and put the mouse back * where it was when beginRelativeMouseMotion() was called. */ bool getRelativeMouseMotion( const ViewportMouseEvent& event, int& dx, int& dy ); /** Rotate the pose around the camera-frame XY (right/up) axes, based on relative mouse movement. */ void rotateXYRelative( const ViewportMouseEvent& event ); /** Rotate the pose around the camera-frame Z (look) axis, based on relative mouse movement. */ void rotateZRelative( const ViewportMouseEvent& event ); /** Move the pose along the mouse ray, based on relative mouse movement. */ void moveZAxisRelative( const ViewportMouseEvent& event ); /** Move the pose along the mouse ray, based on mouse wheel movement. */ void moveZAxisWheel( const ViewportMouseEvent& event ); /** Move the pose around the XY view plane (perpendicular to the camera direction). */ void moveViewPlane( Ogre::Ray &mouse_ray, const ViewportMouseEvent& event ); /** Rotate the pose around the local X-axis, following the mouse movement. * mouse_ray is relative to the reference frame. */ void rotate( Ogre::Ray &mouse_ray ); /** Rotate the pose around the local X axis, following the 3D cursor movement. */ void rotate(const Ogre::Vector3& cursor_position_in_reference_frame); /** Rotate about, and translate perpendicular to, the local X-axis, following the mouse movement. * mouse_ray is relative to the reference frame. */ void moveRotate( Ogre::Ray &mouse_ray ); /** Rotate about, and translate perpendicular to, the local X-axis, following the 3D cursor movement. */ void moveRotate( const Ogre::Vector3& cursor_position_in_reference_frame, bool lock_axis = true); /** Translate in the plane perpendicular to the local X-axis, following the mouse movement. * mouse_ray is relative to the reference frame. */ void movePlane( Ogre::Ray &mouse_ray ); /** Translate in the plane perpendicular to the local X-axis, following the 3D cursor movement. */ void movePlane( const Ogre::Vector3& cursor_position_in_reference_frame ); /** Translate along the local X-axis, following the mouse movement. * mouse_ray is relative to the reference frame. */ void moveAxis( const Ogre::Ray& mouse_ray, const ViewportMouseEvent& event ); /** Translate along the local X-axis, following the 3D cursor movement. */ void moveAxis( const Ogre::Vector3& cursor_position_in_reference_frame ); /** Translate in 3-degrees-of-freedom, following the 3D cursor translation. */ void move3D( const Ogre::Vector3& cursor_position_in_reference_frame, const Ogre::Quaternion &cursor_orientation_in_reference_frame ); /** Rotate in 3-degrees-of-freedom, following the 3D cursor rotation. */ void rotate3D( const Ogre::Vector3& cursor_position_in_reference_frame, const Ogre::Quaternion &cursor_orientation_in_reference_frame ); /** Rotate and translate in full 6-DOF, following the 3D cursor movement. */ void moveRotate3D( const Ogre::Vector3& cursor_position_in_reference_frame, const Ogre::Quaternion& cursor_orientation_in_reference_frame ); /// compute intersection between mouse ray and y-z plane given in local coordinates bool intersectYzPlane( const Ogre::Ray& mouse_ray, Ogre::Vector3& intersection_3d, Ogre::Vector2& intersection_2d, float& ray_t ); /// compute intersection between mouse ray and a y-z plane. bool intersectSomeYzPlane( const Ogre::Ray& mouse_ray, const Ogre::Vector3& point_in_plane, const Ogre::Quaternion& plane_orientation, Ogre::Vector3& intersection_3d, Ogre::Vector2& intersection_2d, float& ray_t ); /** Find the closest point on target_ray to mouse_ray. * @param closest_point contains result point on target_ray if rays are not effectively parallel. * @returns false if rays are effectively parallel, true otherwise. */ bool findClosestPoint( const Ogre::Ray& target_ray, const Ogre::Ray& mouse_ray, Ogre::Vector3& closest_point ); /** Project a reference position onto the viewport to find screen coordinates in pixels. * @param screen_pos the resultant screen position, in pixels. */ void worldToScreen( const Ogre::Vector3& pos_rel_reference, const Ogre::Viewport* viewport, Ogre::Vector2& screen_pos ); /// take all the materials, add a highlight pass and store a pointer to the pass for later use void addHighlightPass( S_MaterialPtr materials ); // set the highlight color to (a,a,a) void setHighlight( float a ); // Save a copy of the latest mouse event with the event type set to // QEvent::MouseMove, so that update() can resend the mouse event during // drag actions to maintain consistent behavior. void recordDraggingInPlaceEvent( ViewportMouseEvent& event ); // Begin a new mouse motion. Called when left button is pressed to begin a drag. void beginMouseMovement( ViewportMouseEvent& event, bool line_visible ); // Motion part of mouse event handling. void handleMouseMovement( ViewportMouseEvent& event ); // Mouse wheel part of mouse event handling. void handleMouseWheelMovement( ViewportMouseEvent& event ); // Return closest point on a line to a test point. Ogre::Vector3 closestPointOnLineToPoint( const Ogre::Vector3& line_start, const Ogre::Vector3& line_dir, const Ogre::Vector3& test_point ); /** @brief Create marker objects from the message and add them to the internal marker arrays. */ void makeMarkers( const visualization_msgs::InteractiveMarkerControl &message ); void stopDragging( bool force = false ); virtual const QCursor& getCursor() const { return cursor_; } bool mouse_dragging_; Ogre::Viewport* drag_viewport_; ViewportMouseEvent dragging_in_place_event_; DisplayContext* context_; CollObjectHandle coll_object_handle_; /** Node representing reference frame in tf, like /map, /base_link, * /head, etc. Same as the field in InteractiveMarker. */ Ogre::SceneNode *reference_node_; /** Represents the local frame of this control relative to reference * node/frame. There is no intermediate InteractiveMarker node or * frame, each control keeps track of its pose relative to the * reference frame independently. In INHERIT mode, this will have * an identical pose as the rest of the interactive marker, * otherwise its orientation might be different. */ Ogre::SceneNode *control_frame_node_; // this is a child of scene_node, but might be oriented differently Ogre::SceneNode *markers_node_; // interaction mode int interaction_mode_; int orientation_mode_; // if in view facing mode, the markers should be // view facing as well // if set to false, they will follow the parent's transformations bool independent_marker_orientation_; /** Defines the axis / plane along which to transform. This is not * keeping track of rotations applied to the control by the user, * this is just a copy of the "orientation" parameter from the * InteractiveMarkerControl message. */ Ogre::Quaternion control_orientation_; bool always_visible_; QString description_; std::string name_; typedef boost::shared_ptr MarkerBasePtr; std::vector< MarkerBasePtr > markers_; InteractiveMarker *parent_; std::set highlight_passes_; // PointsMarkers are rendered by special shader programs, so the // regular highlighting method does not work for them. Keep a // vector of them so we can call their setHighlightColor() function. typedef boost::shared_ptr PointsMarkerPtr; std::vector< PointsMarkerPtr > points_markers_; /** Stores the rotation around the x axis of the control. Only * relevant for fixed-orientation rotation controls. */ Ogre::Radian rotation_; /** Stores the rotation around the x axis of the control as it was * when the mouse-down event happened. Only relevant for * fixed-orientation rotation controls. */ Ogre::Radian rotation_at_mouse_down_; /** The 3D position of the mouse click/cursor when the 'grab' button is * pressed, relative to the reference frame. */ Ogre::Vector3 grab_point_in_reference_frame_; /** The orientation of the cursor when the 'grab' button is * pressed, relative to the reference frame. */ Ogre::Quaternion grab_orientation_in_reference_frame_; /** Records the 3D position of the cursor relative to the parent marker, * expressed in the cursor frame, when the 'grab' button is pressed. */ Ogre::Vector3 parent_to_cursor_in_cursor_frame_at_grab_; /** Records the rotation of the parent from the cursor frame, * when the 'grab' button is pressed. */ Ogre::Quaternion rotation_cursor_to_parent_at_grab_; /** The modifier state when drag begins. */ Qt::KeyboardModifiers modifiers_at_drag_begin_; /** position of mouse when drag begins. */ int mouse_x_at_drag_begin_; int mouse_y_at_drag_begin_; /* mouse ray when drag begins. */ Ogre::Ray mouse_ray_at_drag_begin_; /* how far to move in Z when mouse moves 1 pixel. */ double mouse_z_scale_; /** offset of the absolute mouse position from the relative mouse position */ int mouse_relative_to_absolute_x_; int mouse_relative_to_absolute_y_; /** position of grab relative to parent in world coordinates. */ Ogre::Vector3 parent_to_grab_position_; // obsolete now, but left for ABI compatibility /** The position of the parent when the mouse button is pressed. */ Ogre::Vector3 parent_position_at_mouse_down_; /** The orientation of the control_frame_node_ when the mouse button * is pressed. */ Ogre::Quaternion control_frame_orientation_at_mouse_down_; /** The orientation of the parent when the mouse button * is pressed. */ Ogre::Quaternion parent_orientation_at_mouse_down_; /** The direction vector of the axis of rotation during a mouse * drag, relative to the reference frame. Computed on mouse down * event. */ Ogre::Vector3 rotation_axis_; /** The center of rotation during a mouse drag, relative to the * control frame. Computed on mouse down event. */ Ogre::Vector3 rotation_center_rel_control_; /** The grab point during a mouse drag, relative to the control * frame. Computed on mouse down event. */ Ogre::Vector3 grab_point_rel_control_; bool has_focus_; bool interaction_enabled_; bool visible_; bool view_facing_; QCursor cursor_; QString status_msg_; bool mouse_down_; boost::shared_ptr line_; bool show_visual_aids_; }; } #endif /* INTERACTIVE_MARKER_CONTROL_H_ */ rviz-1.12.4/src/rviz/default_plugin/laser_scan_display.cpp000066400000000000000000000107011300447110700237130ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/default_plugin/point_cloud_common.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/int_property.h" #include "rviz/validate_floats.h" #include "laser_scan_display.h" namespace rviz { LaserScanDisplay::LaserScanDisplay() : point_cloud_common_( new PointCloudCommon( this )) , projector_( new laser_geometry::LaserProjection() ) { queue_size_property_ = new IntProperty( "Queue Size", 10, "Advanced: set the size of the incoming LaserScan message queue. " " Increasing this is useful if your incoming TF data is delayed significantly " "from your LaserScan data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. update_nh_.setCallbackQueue( point_cloud_common_->getCallbackQueue() ); } LaserScanDisplay::~LaserScanDisplay() { delete point_cloud_common_; delete projector_; } void LaserScanDisplay::onInitialize() { MFDClass::onInitialize(); point_cloud_common_->initialize( context_, scene_node_ ); } void LaserScanDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void LaserScanDisplay::processMessage( const sensor_msgs::LaserScanConstPtr& scan ) { sensor_msgs::PointCloudPtr cloud( new sensor_msgs::PointCloud ); std::string frame_id = scan->header.frame_id; // Compute tolerance necessary for this scan ros::Duration tolerance(scan->time_increment * scan->ranges.size()); if (tolerance > filter_tolerance_) { filter_tolerance_ = tolerance; tf_filter_->setTolerance(filter_tolerance_); } try { projector_->transformLaserScanToPointCloud( fixed_frame_.toStdString(), *scan, *cloud, *context_->getTFClient(), laser_geometry::channel_option::Intensity ); } catch (tf::TransformException& e) { ROS_DEBUG( "LaserScan [%s]: failed to transform scan: %s. This message should not repeat (tolerance should now be set on our tf::MessageFilter).", qPrintable( getName() ), e.what() ); return; } point_cloud_common_->addMessage( cloud ); } void LaserScanDisplay::update( float wall_dt, float ros_dt ) { point_cloud_common_->update( wall_dt, ros_dt ); } void LaserScanDisplay::reset() { MFDClass::reset(); point_cloud_common_->reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::LaserScanDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/laser_scan_display.h000066400000000000000000000051751300447110700233710ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_LASER_SCAN_DISPLAY_H #define RVIZ_LASER_SCAN_DISPLAY_H #include #include "rviz/message_filter_display.h" namespace laser_geometry { class LaserProjection; } namespace rviz { class IntProperty; class PointCloudCommon; /** @brief Visualizes a laser scan, received as a sensor_msgs::LaserScan. */ class LaserScanDisplay: public MessageFilterDisplay { Q_OBJECT public: LaserScanDisplay(); ~LaserScanDisplay(); virtual void reset(); virtual void update( float wall_dt, float ros_dt ); private Q_SLOTS: void updateQueueSize(); protected: /** @brief Do initialization. Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Process a single message. Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::LaserScanConstPtr& scan ); IntProperty* queue_size_property_; PointCloudCommon* point_cloud_common_; laser_geometry::LaserProjection* projector_; ros::Duration filter_tolerance_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/map_display.cpp000066400000000000000000000552311300447110700223650ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/custom_parameter_indices.h" #include "rviz/ogre_helpers/grid.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/int_property.h" #include "rviz/properties/property.h" #include "rviz/properties/quaternion_property.h" #include "rviz/properties/ros_topic_property.h" #include "rviz/properties/vector_property.h" #include "rviz/validate_floats.h" #include "rviz/display_context.h" #include "map_display.h" namespace rviz { MapDisplay::MapDisplay() : Display() , manual_object_( NULL ) , loaded_( false ) , resolution_( 0.0f ) , width_( 0 ) , height_( 0 ) { connect(this, SIGNAL( mapUpdated() ), this, SLOT( showMap() )); topic_property_ = new RosTopicProperty( "Topic", "", QString::fromStdString( ros::message_traits::datatype() ), "nav_msgs::OccupancyGrid topic to subscribe to.", this, SLOT( updateTopic() )); alpha_property_ = new FloatProperty( "Alpha", 0.7, "Amount of transparency to apply to the map.", this, SLOT( updateAlpha() )); alpha_property_->setMin( 0 ); alpha_property_->setMax( 1 ); color_scheme_property_ = new EnumProperty( "Color Scheme", "map", "How to color the occupancy values.", this, SLOT( updatePalette() )); // Option values here must correspond to indices in palette_textures_ array in onInitialize() below. color_scheme_property_->addOption( "map", 0 ); color_scheme_property_->addOption( "costmap", 1 ); color_scheme_property_->addOption( "raw", 2 ); draw_under_property_ = new Property( "Draw Behind", false, "Rendering option, controls whether or not the map is always" " drawn behind everything else.", this, SLOT( updateDrawUnder() )); resolution_property_ = new FloatProperty( "Resolution", 0, "Resolution of the map. (not editable)", this ); resolution_property_->setReadOnly( true ); width_property_ = new IntProperty( "Width", 0, "Width of the map, in meters. (not editable)", this ); width_property_->setReadOnly( true ); height_property_ = new IntProperty( "Height", 0, "Height of the map, in meters. (not editable)", this ); height_property_->setReadOnly( true ); position_property_ = new VectorProperty( "Position", Ogre::Vector3::ZERO, "Position of the bottom left corner of the map, in meters. (not editable)", this ); position_property_->setReadOnly( true ); orientation_property_ = new QuaternionProperty( "Orientation", Ogre::Quaternion::IDENTITY, "Orientation of the map. (not editable)", this ); orientation_property_->setReadOnly( true ); unreliable_property_ = new BoolProperty( "Unreliable", false, "Prefer UDP topic transport", this, SLOT( updateTopic() )); } MapDisplay::~MapDisplay() { unsubscribe(); clear(); } unsigned char* makeMapPalette() { unsigned char* palette = new unsigned char[256*4]; unsigned char* palette_ptr = palette; // Standard gray map palette values for( int i = 0; i <= 100; i++ ) { unsigned char v = 255 - (255 * i) / 100; *palette_ptr++ = v; // red *palette_ptr++ = v; // green *palette_ptr++ = v; // blue *palette_ptr++ = 255; // alpha } // illegal positive values in green for( int i = 101; i <= 127; i++ ) { *palette_ptr++ = 0; // red *palette_ptr++ = 255; // green *palette_ptr++ = 0; // blue *palette_ptr++ = 255; // alpha } // illegal negative (char) values in shades of red/yellow for( int i = 128; i <= 254; i++ ) { *palette_ptr++ = 255; // red *palette_ptr++ = (255*(i-128))/(254-128); // green *palette_ptr++ = 0; // blue *palette_ptr++ = 255; // alpha } // legal -1 value is tasteful blueish greenish grayish color *palette_ptr++ = 0x70; // red *palette_ptr++ = 0x89; // green *palette_ptr++ = 0x86; // blue *palette_ptr++ = 255; // alpha return palette; } unsigned char* makeCostmapPalette() { unsigned char* palette = new unsigned char[256*4]; unsigned char* palette_ptr = palette; // zero values have alpha=0 *palette_ptr++ = 0; // red *palette_ptr++ = 0; // green *palette_ptr++ = 0; // blue *palette_ptr++ = 0; // alpha // Blue to red spectrum for most normal cost values for( int i = 1; i <= 98; i++ ) { unsigned char v = (255 * i) / 100; *palette_ptr++ = v; // red *palette_ptr++ = 0; // green *palette_ptr++ = 255 - v; // blue *palette_ptr++ = 255; // alpha } // inscribed obstacle values (99) in cyan *palette_ptr++ = 0; // red *palette_ptr++ = 255; // green *palette_ptr++ = 255; // blue *palette_ptr++ = 255; // alpha // lethal obstacle values (100) in purple *palette_ptr++ = 255; // red *palette_ptr++ = 0; // green *palette_ptr++ = 255; // blue *palette_ptr++ = 255; // alpha // illegal positive values in green for( int i = 101; i <= 127; i++ ) { *palette_ptr++ = 0; // red *palette_ptr++ = 255; // green *palette_ptr++ = 0; // blue *palette_ptr++ = 255; // alpha } // illegal negative (char) values in shades of red/yellow for( int i = 128; i <= 254; i++ ) { *palette_ptr++ = 255; // red *palette_ptr++ = (255*(i-128))/(254-128); // green *palette_ptr++ = 0; // blue *palette_ptr++ = 255; // alpha } // legal -1 value is tasteful blueish greenish grayish color *palette_ptr++ = 0x70; // red *palette_ptr++ = 0x89; // green *palette_ptr++ = 0x86; // blue *palette_ptr++ = 255; // alpha return palette; } unsigned char* makeRawPalette() { unsigned char* palette = new unsigned char[256*4]; unsigned char* palette_ptr = palette; // Standard gray map palette values for( int i = 0; i < 256; i++ ) { *palette_ptr++ = i; // red *palette_ptr++ = i; // green *palette_ptr++ = i; // blue *palette_ptr++ = 255; // alpha } return palette; } Ogre::TexturePtr makePaletteTexture( unsigned char *palette_bytes ) { Ogre::DataStreamPtr palette_stream; palette_stream.bind( new Ogre::MemoryDataStream( palette_bytes, 256*4 )); static int palette_tex_count = 0; std::stringstream ss; ss << "MapPaletteTexture" << palette_tex_count++; return Ogre::TextureManager::getSingleton().loadRawData( ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, palette_stream, 256, 1, Ogre::PF_BYTE_RGBA, Ogre::TEX_TYPE_1D, 0 ); } void MapDisplay::onInitialize() { // Order of palette textures here must match option indices for color_scheme_property_ above. palette_textures_.push_back( makePaletteTexture( makeMapPalette() )); color_scheme_transparency_.push_back( false ); palette_textures_.push_back( makePaletteTexture( makeCostmapPalette() )); color_scheme_transparency_.push_back( true ); palette_textures_.push_back( makePaletteTexture( makeRawPalette() )); color_scheme_transparency_.push_back( true ); // Set up map material static int material_count = 0; std::stringstream ss; ss << "MapMaterial" << material_count++; material_ = Ogre::MaterialManager::getSingleton().getByName("rviz/Indexed8BitImage"); material_ = material_->clone( ss.str() ); material_->setReceiveShadows(false); material_->getTechnique(0)->setLightingEnabled(false); material_->setDepthBias( -16.0f, 0.0f ); material_->setCullingMode( Ogre::CULL_NONE ); material_->setDepthWriteEnabled(false); static int map_count = 0; std::stringstream ss2; ss2 << "MapObject" << map_count++; manual_object_ = scene_manager_->createManualObject( ss2.str() ); scene_node_->attachObject( manual_object_ ); manual_object_->begin(material_->getName(), Ogre::RenderOperation::OT_TRIANGLE_LIST); { // First triangle { // Bottom left manual_object_->position( 0.0f, 0.0f, 0.0f ); manual_object_->textureCoord(0.0f, 0.0f); manual_object_->normal( 0.0f, 0.0f, 1.0f ); // Top right manual_object_->position( 1.0f, 1.0f, 0.0f ); manual_object_->textureCoord(1.0f, 1.0f); manual_object_->normal( 0.0f, 0.0f, 1.0f ); // Top left manual_object_->position( 0.0f, 1.0f, 0.0f ); manual_object_->textureCoord(0.0f, 1.0f); manual_object_->normal( 0.0f, 0.0f, 1.0f ); } // Second triangle { // Bottom left manual_object_->position( 0.0f, 0.0f, 0.0f ); manual_object_->textureCoord(0.0f, 0.0f); manual_object_->normal( 0.0f, 0.0f, 1.0f ); // Bottom right manual_object_->position( 1.0f, 0.0f, 0.0f ); manual_object_->textureCoord(1.0f, 0.0f); manual_object_->normal( 0.0f, 0.0f, 1.0f ); // Top right manual_object_->position( 1.0f, 1.0f, 0.0f ); manual_object_->textureCoord(1.0f, 1.0f); manual_object_->normal( 0.0f, 0.0f, 1.0f ); } } manual_object_->end(); if( draw_under_property_->getValue().toBool() ) { manual_object_->setRenderQueueGroup(Ogre::RENDER_QUEUE_4); } // don't show map until the plugin is actually enabled manual_object_->setVisible( false ); updateAlpha(); } void MapDisplay::onEnable() { subscribe(); } void MapDisplay::onDisable() { unsubscribe(); clear(); } void MapDisplay::subscribe() { if ( !isEnabled() ) { return; } if( !topic_property_->getTopic().isEmpty() ) { try { if(unreliable_property_->getBool()) { map_sub_ = update_nh_.subscribe( topic_property_->getTopicStd(), 1, &MapDisplay::incomingMap, this, ros::TransportHints().unreliable()); }else{ map_sub_ = update_nh_.subscribe( topic_property_->getTopicStd(), 1, &MapDisplay::incomingMap, this, ros::TransportHints().reliable() ); } setStatus( StatusProperty::Ok, "Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Topic", QString( "Error subscribing: " ) + e.what() ); } try { update_sub_ = update_nh_.subscribe( topic_property_->getTopicStd() + "_updates", 1, &MapDisplay::incomingUpdate, this ); setStatus( StatusProperty::Ok, "Update Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Update Topic", QString( "Error subscribing: " ) + e.what() ); } } } void MapDisplay::unsubscribe() { map_sub_.shutdown(); update_sub_.shutdown(); } // helper class to set alpha parameter on all renderables. class AlphaSetter: public Ogre::Renderable::Visitor { public: AlphaSetter( float alpha ) : alpha_vec_( alpha, alpha, alpha, alpha ) {} void visit( Ogre::Renderable *rend, ushort lodIndex, bool isDebug, Ogre::Any *pAny=0) { rend->setCustomParameter( ALPHA_PARAMETER, alpha_vec_ ); } private: Ogre::Vector4 alpha_vec_; }; void MapDisplay::updateAlpha() { float alpha = alpha_property_->getFloat(); Ogre::Pass* pass = material_->getTechnique( 0 )->getPass( 0 ); Ogre::TextureUnitState* tex_unit = NULL; if( alpha < 0.9998 || color_scheme_transparency_[ color_scheme_property_->getOptionInt() ]) { material_->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); material_->setDepthWriteEnabled( false ); } else { material_->setSceneBlending( Ogre::SBT_REPLACE ); material_->setDepthWriteEnabled( !draw_under_property_->getValue().toBool() ); } AlphaSetter alpha_setter( alpha ); if( manual_object_ ) { manual_object_->visitRenderables( &alpha_setter ); } } void MapDisplay::updateDrawUnder() { bool draw_under = draw_under_property_->getValue().toBool(); if( alpha_property_->getFloat() >= 0.9998 ) { material_->setDepthWriteEnabled( !draw_under ); } if( manual_object_ ) { if( draw_under ) { manual_object_->setRenderQueueGroup( Ogre::RENDER_QUEUE_4 ); } else { manual_object_->setRenderQueueGroup( Ogre::RENDER_QUEUE_MAIN ); } } } void MapDisplay::updateTopic() { unsubscribe(); subscribe(); clear(); } void MapDisplay::clear() { setStatus( StatusProperty::Warn, "Message", "No map received" ); if( !loaded_ ) { return; } if( manual_object_ ) { manual_object_->setVisible( false ); } if( !texture_.isNull() ) { Ogre::TextureManager::getSingleton().remove( texture_->getName() ); texture_.setNull(); } loaded_ = false; } bool validateFloats(const nav_msgs::OccupancyGrid& msg) { bool valid = true; valid = valid && validateFloats( msg.info.resolution ); valid = valid && validateFloats( msg.info.origin ); return valid; } void MapDisplay::incomingMap(const nav_msgs::OccupancyGrid::ConstPtr& msg) { current_map_ = *msg; // updated via signal in case ros spinner is in a different thread Q_EMIT mapUpdated(); loaded_ = true; } void MapDisplay::incomingUpdate(const map_msgs::OccupancyGridUpdate::ConstPtr& update) { // Only update the map if we have gotten a full one first. if( !loaded_ ) { return; } // Reject updates which have any out-of-bounds data. if( update->x < 0 || update->y < 0 || current_map_.info.width < update->x + update->width || current_map_.info.height < update->y + update->height ) { setStatus( StatusProperty::Error, "Update", "Update area outside of original map area." ); return; } // Copy the incoming data into current_map_'s data. for( size_t y = 0; y < update->height; y++ ) { memcpy( ¤t_map_.data[ (update->y + y) * current_map_.info.width + update->x ], &update->data[ y * update->width ], update->width ); } // updated via signal in case ros spinner is in a different thread Q_EMIT mapUpdated(); } void MapDisplay::showMap() { if (current_map_.data.empty()) { return; } if( !validateFloats( current_map_ )) { setStatus( StatusProperty::Error, "Map", "Message contained invalid floating point values (nans or infs)" ); return; } if( current_map_.info.width * current_map_.info.height == 0 ) { std::stringstream ss; ss << "Map is zero-sized (" << current_map_.info.width << "x" << current_map_.info.height << ")"; setStatus( StatusProperty::Error, "Map", QString::fromStdString( ss.str() )); return; } setStatus( StatusProperty::Ok, "Message", "Map received" ); ROS_DEBUG( "Received a %d X %d map @ %.3f m/pix\n", current_map_.info.width, current_map_.info.height, current_map_.info.resolution ); float resolution = current_map_.info.resolution; int width = current_map_.info.width; int height = current_map_.info.height; Ogre::Vector3 position( current_map_.info.origin.position.x, current_map_.info.origin.position.y, current_map_.info.origin.position.z ); Ogre::Quaternion orientation( current_map_.info.origin.orientation.w, current_map_.info.origin.orientation.x, current_map_.info.origin.orientation.y, current_map_.info.origin.orientation.z ); frame_ = current_map_.header.frame_id; if (frame_.empty()) { frame_ = "/map"; } unsigned int pixels_size = width * height; unsigned char* pixels = new unsigned char[pixels_size]; memset(pixels, 255, pixels_size); bool map_status_set = false; unsigned int num_pixels_to_copy = pixels_size; if( pixels_size != current_map_.data.size() ) { std::stringstream ss; ss << "Data size doesn't match width*height: width = " << width << ", height = " << height << ", data size = " << current_map_.data.size(); setStatus( StatusProperty::Error, "Map", QString::fromStdString( ss.str() )); map_status_set = true; // Keep going, but don't read past the end of the data. if( current_map_.data.size() < pixels_size ) { num_pixels_to_copy = current_map_.data.size(); } } memcpy( pixels, ¤t_map_.data[0], num_pixels_to_copy ); Ogre::DataStreamPtr pixel_stream; pixel_stream.bind( new Ogre::MemoryDataStream( pixels, pixels_size )); if( !texture_.isNull() ) { Ogre::TextureManager::getSingleton().remove( texture_->getName() ); texture_.setNull(); } static int tex_count = 0; std::stringstream ss; ss << "MapTexture" << tex_count++; try { texture_ = Ogre::TextureManager::getSingleton().loadRawData( ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, pixel_stream, width, height, Ogre::PF_L8, Ogre::TEX_TYPE_2D, 0); if( !map_status_set ) { setStatus( StatusProperty::Ok, "Map", "Map OK" ); } } catch(Ogre::RenderingAPIException&) { Ogre::Image image; pixel_stream->seek(0); float fwidth = width; float fheight = height; if( width > height ) { float aspect = fheight / fwidth; fwidth = 2048; fheight = fwidth * aspect; } else { float aspect = fwidth / fheight; fheight = 2048; fwidth = fheight * aspect; } { std::stringstream ss; ss << "Map is larger than your graphics card supports. Downsampled from [" << width << "x" << height << "] to [" << fwidth << "x" << fheight << "]"; setStatus(StatusProperty::Warn, "Map", QString::fromStdString( ss.str() )); } ROS_WARN("Failed to create full-size map texture, likely because your graphics card does not support textures of size > 2048. Downsampling to [%d x %d]...", (int)fwidth, (int)fheight); //ROS_INFO("Stream size [%d], width [%f], height [%f], w * h [%f]", pixel_stream->size(), width, height, width * height); image.loadRawData(pixel_stream, width, height, Ogre::PF_L8); image.resize(fwidth, fheight, Ogre::Image::FILTER_NEAREST); ss << "Downsampled"; texture_ = Ogre::TextureManager::getSingleton().loadImage(ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image); } delete [] pixels; Ogre::Pass* pass = material_->getTechnique(0)->getPass(0); Ogre::TextureUnitState* tex_unit = NULL; if (pass->getNumTextureUnitStates() > 0) { tex_unit = pass->getTextureUnitState(0); } else { tex_unit = pass->createTextureUnitState(); } tex_unit->setTextureName(texture_->getName()); tex_unit->setTextureFiltering( Ogre::TFO_NONE ); updatePalette(); resolution_property_->setValue( resolution ); width_property_->setValue( width ); height_property_->setValue( height ); position_property_->setVector( position ); orientation_property_->setQuaternion( orientation ); transformMap(); manual_object_->setVisible( true ); scene_node_->setScale( resolution * width, resolution * height, 1.0 ); context_->queueRender(); } void MapDisplay::updatePalette() { int palette_index = color_scheme_property_->getOptionInt(); Ogre::Pass* pass = material_->getTechnique(0)->getPass(0); Ogre::TextureUnitState* palette_tex_unit = NULL; if( pass->getNumTextureUnitStates() > 1 ) { palette_tex_unit = pass->getTextureUnitState( 1 ); } else { palette_tex_unit = pass->createTextureUnitState(); } palette_tex_unit->setTextureName( palette_textures_[ palette_index ]->getName() ); palette_tex_unit->setTextureFiltering( Ogre::TFO_NONE ); updateAlpha(); } void MapDisplay::transformMap() { if (!loaded_) { return; } Ogre::Vector3 position; Ogre::Quaternion orientation; if (!context_->getFrameManager()->transform(frame_, ros::Time(), current_map_.info.origin, position, orientation)) { ROS_DEBUG( "Error transforming map '%s' from frame '%s' to frame '%s'", qPrintable( getName() ), frame_.c_str(), qPrintable( fixed_frame_ )); setStatus( StatusProperty::Error, "Transform", "No transform from [" + QString::fromStdString( frame_ ) + "] to [" + fixed_frame_ + "]" ); } else { setStatus(StatusProperty::Ok, "Transform", "Transform OK"); } scene_node_->setPosition( position ); scene_node_->setOrientation( orientation ); } void MapDisplay::fixedFrameChanged() { transformMap(); } void MapDisplay::reset() { Display::reset(); clear(); // Force resubscription so that the map will be re-sent updateTopic(); } void MapDisplay::setTopic( const QString &topic, const QString &datatype ) { topic_property_->setString( topic ); } void MapDisplay::update( float wall_dt, float ros_dt ) { transformMap(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::MapDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/map_display.h000066400000000000000000000103111300447110700220200ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MAP_DISPLAY_H #define RVIZ_MAP_DISPLAY_H #ifndef Q_MOC_RUN #include #include #include #include #include #endif #include #include #include #include #include "rviz/display.h" namespace Ogre { class ManualObject; } namespace rviz { class EnumProperty; class FloatProperty; class IntProperty; class Property; class QuaternionProperty; class RosTopicProperty; class VectorProperty; /** * \class MapDisplay * \brief Displays a map along the XY plane. */ class MapDisplay: public Display { Q_OBJECT public: MapDisplay(); virtual ~MapDisplay(); // Overrides from Display virtual void onInitialize(); virtual void fixedFrameChanged(); virtual void reset(); float getResolution() { return resolution_; } int getWidth() { return width_; } int getHeight() { return height_; } virtual void setTopic( const QString &topic, const QString &datatype ); Q_SIGNALS: /** @brief Emitted when a new map is received*/ void mapUpdated(); protected Q_SLOTS: void updateAlpha(); void updateTopic(); void updateDrawUnder(); void updatePalette(); /** @brief Show current_map_ in the scene. */ void showMap(); protected: // overrides from Display virtual void onEnable(); virtual void onDisable(); virtual void subscribe(); virtual void unsubscribe(); virtual void update( float wall_dt, float ros_dt ); /** @brief Copy msg into current_map_ and call showMap(). */ void incomingMap(const nav_msgs::OccupancyGrid::ConstPtr& msg); /** @brief Copy update's data into current_map_ and call showMap(). */ void incomingUpdate(const map_msgs::OccupancyGridUpdate::ConstPtr& update); void clear(); void transformMap(); Ogre::ManualObject* manual_object_; Ogre::TexturePtr texture_; std::vector palette_textures_; std::vector color_scheme_transparency_; Ogre::MaterialPtr material_; bool loaded_; std::string topic_; float resolution_; int width_; int height_; std::string frame_; nav_msgs::OccupancyGrid current_map_; ros::Subscriber map_sub_; ros::Subscriber update_sub_; RosTopicProperty* topic_property_; FloatProperty* resolution_property_; IntProperty* width_property_; IntProperty* height_property_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; FloatProperty* alpha_property_; Property* draw_under_property_; EnumProperty* color_scheme_property_; BoolProperty* unreliable_property_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/marker_array_display.cpp000066400000000000000000000064711300447110700242710ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/properties/ros_topic_property.h" #include "rviz/properties/int_property.h" #include "marker_array_display.h" namespace rviz { MarkerArrayDisplay::MarkerArrayDisplay() : MarkerDisplay() { marker_topic_property_->setMessageType( QString::fromStdString( ros::message_traits::datatype() )); marker_topic_property_->setValue( "visualization_marker_array" ); marker_topic_property_->setDescription( "visualization_msgs::MarkerArray topic to subscribe to." ); queue_size_property_->setDescription( "Advanced: set the size of the incoming Marker message queue. " " This should generally be at least a few times larger than the number of Markers in each MarkerArray." ); } void MarkerArrayDisplay::subscribe() { if ( !isEnabled() ) { return; } std::string topic = marker_topic_property_->getTopicStd(); if( !topic.empty() ) { array_sub_.shutdown(); try { array_sub_ = update_nh_.subscribe( topic, queue_size_property_->getInt(), &MarkerArrayDisplay::handleMarkerArray, this ); setStatus( StatusProperty::Ok, "Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Topic", QString( "Error subscribing: " ) + e.what() ); } } } void MarkerArrayDisplay::unsubscribe() { array_sub_.shutdown(); } // I seem to need this wrapper function to make the compiler like my // function pointer in the .subscribe() call above. void MarkerArrayDisplay::handleMarkerArray( const visualization_msgs::MarkerArray::ConstPtr& array ) { incomingMarkerArray( array ); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::MarkerArrayDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/marker_array_display.h000066400000000000000000000046021300447110700237300ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MARKER_ARRAY_DISPLAY_H #define RVIZ_MARKER_ARRAY_DISPLAY_H #include "marker_display.h" namespace rviz { /** * @brief Display for an array of markers. The MarkerDisplay class handles * MarkerArray messages. This is just a wrapper to let MarkerArray * topics get selected in the topic browser. */ class MarkerArrayDisplay: public MarkerDisplay { Q_OBJECT public: MarkerArrayDisplay(); protected: /** @brief Overridden from MarkerDisplay. Subscribes to the marker * array topic. */ virtual void subscribe(); /** @brief Overridden from MarkerDisplay. Unsubscribes to the * marker array topic. */ virtual void unsubscribe(); private: void handleMarkerArray( const visualization_msgs::MarkerArray::ConstPtr& array ); }; } // end namespace rviz #endif // RVIZ_MARKER_ARRAY_DISPLAY_H rviz-1.12.4/src/rviz/default_plugin/marker_display.cpp000066400000000000000000000374531300447110700230770ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/default_plugin/markers/arrow_marker.h" #include "rviz/default_plugin/markers/line_list_marker.h" #include "rviz/default_plugin/markers/line_strip_marker.h" #include "rviz/default_plugin/markers/mesh_resource_marker.h" #include "rviz/default_plugin/markers/points_marker.h" #include "rviz/default_plugin/markers/shape_marker.h" #include "rviz/default_plugin/markers/text_view_facing_marker.h" #include "rviz/default_plugin/markers/triangle_list_marker.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/billboard_line.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/int_property.h" #include "rviz/properties/property.h" #include "rviz/properties/ros_topic_property.h" #include "rviz/selection/selection_manager.h" #include "rviz/validate_floats.h" #include "rviz/default_plugin/marker_display.h" namespace rviz { //////////////////////////////////////////////////////////////////////////////////////////////////////////////// MarkerDisplay::MarkerDisplay() : Display() { marker_topic_property_ = new RosTopicProperty( "Marker Topic", "visualization_marker", QString::fromStdString( ros::message_traits::datatype() ), "visualization_msgs::Marker topic to subscribe to. _array will also" " automatically be subscribed with type visualization_msgs::MarkerArray.", this, SLOT( updateTopic() )); queue_size_property_ = new IntProperty( "Queue Size", 100, "Advanced: set the size of the incoming Marker message queue. Increasing this is" " useful if your incoming TF data is delayed significantly from your Marker data, " "but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); queue_size_property_->setMin( 0 ); namespaces_category_ = new Property( "Namespaces", QVariant(), "", this ); } void MarkerDisplay::onInitialize() { tf_filter_ = new tf::MessageFilter( *context_->getTFClient(), fixed_frame_.toStdString(), queue_size_property_->getInt(), update_nh_ ); tf_filter_->connectInput(sub_); tf_filter_->registerCallback(boost::bind(&MarkerDisplay::incomingMarker, this, _1)); tf_filter_->registerFailureCallback(boost::bind(&MarkerDisplay::failedMarker, this, _1, _2)); namespace_config_enabled_state_.clear(); } MarkerDisplay::~MarkerDisplay() { if ( initialized() ) { unsubscribe(); clearMarkers(); delete tf_filter_; } } void MarkerDisplay::load(const Config& config) { Display::load(config); Config c = config.mapGetChild("Namespaces"); for( Config::MapIterator iter = c.mapIterator(); iter.isValid(); iter.advance() ) { QString key = iter.currentKey(); const Config& child = iter.currentChild(); namespace_config_enabled_state_[key] = child.getValue().toBool(); } } void MarkerDisplay::clearMarkers() { markers_.clear(); markers_with_expiration_.clear(); frame_locked_markers_.clear(); tf_filter_->clear(); namespaces_category_->removeChildren(); namespaces_.clear(); } void MarkerDisplay::onEnable() { subscribe(); } void MarkerDisplay::onDisable() { unsubscribe(); tf_filter_->clear(); clearMarkers(); } void MarkerDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void MarkerDisplay::updateTopic() { unsubscribe(); subscribe(); } void MarkerDisplay::subscribe() { if( !isEnabled() ) { return; } std::string marker_topic = marker_topic_property_->getTopicStd(); if( !marker_topic.empty() ) { array_sub_.shutdown(); sub_.unsubscribe(); try { sub_.subscribe( update_nh_, marker_topic, queue_size_property_->getInt() ); array_sub_ = update_nh_.subscribe( marker_topic + "_array", queue_size_property_->getInt(), &MarkerDisplay::incomingMarkerArray, this ); setStatus( StatusProperty::Ok, "Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Topic", QString("Error subscribing: ") + e.what() ); } } } void MarkerDisplay::unsubscribe() { sub_.unsubscribe(); array_sub_.shutdown(); } void MarkerDisplay::deleteMarker(MarkerID id) { deleteMarkerStatus( id ); M_IDToMarker::iterator it = markers_.find( id ); if( it != markers_.end() ) { markers_with_expiration_.erase(it->second); frame_locked_markers_.erase(it->second); markers_.erase(it); } } void MarkerDisplay::deleteMarkersInNamespace( const std::string& ns ) { std::vector to_delete; // TODO: this is inefficient, should store every in-use id per namespace and lookup by that M_IDToMarker::iterator marker_it = markers_.begin(); M_IDToMarker::iterator marker_end = markers_.end(); for (; marker_it != marker_end; ++marker_it) { if (marker_it->first.first == ns) { to_delete.push_back(marker_it->first); } } { std::vector::iterator it = to_delete.begin(); std::vector::iterator end = to_delete.end(); for (; it != end; ++it) { deleteMarker(*it); } } } void MarkerDisplay::deleteAllMarkers() { std::vector to_delete; M_IDToMarker::iterator marker_it = markers_.begin(); for (; marker_it != markers_.end(); ++marker_it) { to_delete.push_back(marker_it->first); } for (std::vector::iterator it = to_delete.begin(); it != to_delete.end(); ++it) { deleteMarker( *it ); } } void MarkerDisplay::setMarkerStatus(MarkerID id, StatusLevel level, const std::string& text) { std::stringstream ss; ss << id.first << "/" << id.second; std::string marker_name = ss.str(); setStatusStd(level, marker_name, text); } void MarkerDisplay::deleteMarkerStatus(MarkerID id) { std::stringstream ss; ss << id.first << "/" << id.second; std::string marker_name = ss.str(); deleteStatusStd(marker_name); } void MarkerDisplay::incomingMarkerArray(const visualization_msgs::MarkerArray::ConstPtr& array) { std::vector::const_iterator it = array->markers.begin(); std::vector::const_iterator end = array->markers.end(); for (; it != end; ++it) { const visualization_msgs::Marker& marker = *it; tf_filter_->add(visualization_msgs::Marker::Ptr(new visualization_msgs::Marker(marker))); } } void MarkerDisplay::incomingMarker( const visualization_msgs::Marker::ConstPtr& marker ) { boost::mutex::scoped_lock lock(queue_mutex_); message_queue_.push_back(marker); } void MarkerDisplay::failedMarker(const ros::MessageEvent& marker_evt, tf::FilterFailureReason reason) { visualization_msgs::Marker::ConstPtr marker = marker_evt.getConstMessage(); if (marker->action == visualization_msgs::Marker::DELETE || marker->action == 3) // TODO: visualization_msgs::Marker::DELETEALL when message changes in a future version of ROS { return this->processMessage(marker); } std::string authority = marker_evt.getPublisherName(); std::string error = context_->getFrameManager()->discoverFailureReason(marker->header.frame_id, marker->header.stamp, authority, reason); setMarkerStatus(MarkerID(marker->ns, marker->id), StatusProperty::Error, error); } bool validateFloats(const visualization_msgs::Marker& msg) { bool valid = true; valid = valid && validateFloats(msg.pose); valid = valid && validateFloats(msg.scale); valid = valid && validateFloats(msg.color); valid = valid && validateFloats(msg.points); return valid; } void MarkerDisplay::processMessage( const visualization_msgs::Marker::ConstPtr& message ) { if (!validateFloats(*message)) { setMarkerStatus(MarkerID(message->ns, message->id), StatusProperty::Error, "Contains invalid floating point values (nans or infs)"); return; } switch ( message->action ) { case visualization_msgs::Marker::ADD: processAdd( message ); break; case visualization_msgs::Marker::DELETE: processDelete( message ); break; case 3: // TODO: visualization_msgs::Marker::DELETEALL when message changes in a future version of ROS deleteAllMarkers(); break; default: ROS_ERROR( "Unknown marker action: %d\n", message->action ); } } void MarkerDisplay::processAdd( const visualization_msgs::Marker::ConstPtr& message ) { QString namespace_name = QString::fromStdString( message->ns ); M_Namespace::iterator ns_it = namespaces_.find( namespace_name ); if( ns_it == namespaces_.end() ) { ns_it = namespaces_.insert( namespace_name, new MarkerNamespace( namespace_name, namespaces_category_, this )); // Adding a new namespace, determine if it's configured to be disabled if( namespace_config_enabled_state_.count(namespace_name) > 0 && !namespace_config_enabled_state_[namespace_name] ) { ns_it.value()->setValue(false); // Disable the namespace } } if( !ns_it.value()->isEnabled() ) { return; } deleteMarkerStatus( MarkerID( message->ns, message->id )); bool create = true; MarkerBasePtr marker; M_IDToMarker::iterator it = markers_.find( MarkerID(message->ns, message->id) ); if ( it != markers_.end() ) { marker = it->second; markers_with_expiration_.erase(marker); if ( message->type == marker->getMessage()->type ) { create = false; } else { markers_.erase( it ); } } if ( create ) { switch ( message->type ) { case visualization_msgs::Marker::CUBE: case visualization_msgs::Marker::CYLINDER: case visualization_msgs::Marker::SPHERE: { marker.reset(new ShapeMarker(this, context_, scene_node_)); } break; case visualization_msgs::Marker::ARROW: { marker.reset(new ArrowMarker(this, context_, scene_node_)); } break; case visualization_msgs::Marker::LINE_STRIP: { marker.reset(new LineStripMarker(this, context_, scene_node_)); } break; case visualization_msgs::Marker::LINE_LIST: { marker.reset(new LineListMarker(this, context_, scene_node_)); } break; case visualization_msgs::Marker::SPHERE_LIST: case visualization_msgs::Marker::CUBE_LIST: case visualization_msgs::Marker::POINTS: { marker.reset(new PointsMarker(this, context_, scene_node_)); } break; case visualization_msgs::Marker::TEXT_VIEW_FACING: { marker.reset(new TextViewFacingMarker(this, context_, scene_node_)); } break; case visualization_msgs::Marker::MESH_RESOURCE: { marker.reset(new MeshResourceMarker(this, context_, scene_node_)); } break; case visualization_msgs::Marker::TRIANGLE_LIST: { marker.reset(new TriangleListMarker(this, context_, scene_node_)); } break; default: ROS_ERROR( "Unknown marker type: %d", message->type ); } markers_.insert(std::make_pair(MarkerID(message->ns, message->id), marker)); } if (marker) { marker->setMessage(message); if (message->lifetime.toSec() > 0.0001f) { markers_with_expiration_.insert(marker); } if (message->frame_locked) { frame_locked_markers_.insert(marker); } context_->queueRender(); } } void MarkerDisplay::processDelete( const visualization_msgs::Marker::ConstPtr& message ) { deleteMarker(MarkerID(message->ns, message->id)); context_->queueRender(); } void MarkerDisplay::update(float wall_dt, float ros_dt) { V_MarkerMessage local_queue; { boost::mutex::scoped_lock lock(queue_mutex_); local_queue.swap( message_queue_ ); } if ( !local_queue.empty() ) { V_MarkerMessage::iterator message_it = local_queue.begin(); V_MarkerMessage::iterator message_end = local_queue.end(); for ( ; message_it != message_end; ++message_it ) { visualization_msgs::Marker::ConstPtr& marker = *message_it; processMessage( marker ); } } { S_MarkerBase::iterator it = markers_with_expiration_.begin(); S_MarkerBase::iterator end = markers_with_expiration_.end(); for (; it != end;) { MarkerBasePtr marker = *it; if (marker->expired()) { ++it; deleteMarker(marker->getID()); } else { ++it; } } } { S_MarkerBase::iterator it = frame_locked_markers_.begin(); S_MarkerBase::iterator end = frame_locked_markers_.end(); for (; it != end; ++it) { MarkerBasePtr marker = *it; marker->updateFrameLocked(); } } } void MarkerDisplay::fixedFrameChanged() { tf_filter_->setTargetFrame( fixed_frame_.toStdString() ); clearMarkers(); } void MarkerDisplay::reset() { Display::reset(); clearMarkers(); } void MarkerDisplay::setTopic( const QString &topic, const QString &datatype ) { marker_topic_property_->setString( topic ); } ///////////////////////////////////////////////////////////////////////////////// // MarkerNamespace MarkerNamespace::MarkerNamespace( const QString& name, Property* parent_property, MarkerDisplay* owner ) : BoolProperty( name, true, "Enable/disable all markers in this namespace.", parent_property ) , owner_( owner ) { // Can't do this connect in chained constructor above because at // that point it doesn't really know that "this" is a // MarkerNamespace*, so the signal doesn't get connected. connect( this, SIGNAL( changed() ), this, SLOT( onEnableChanged() )); } void MarkerNamespace::onEnableChanged() { if( !isEnabled() ) { owner_->deleteMarkersInNamespace( getName().toStdString() ); } // Update the configuration that stores the enabled state of all markers owner_->namespace_config_enabled_state_[getName()] = isEnabled(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::MarkerDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/marker_display.h000066400000000000000000000143761300447110700225430ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MARKER_DISPLAY_H #define RVIZ_MARKER_DISPLAY_H #include #include #include #include #ifndef Q_MOC_RUN #include #include #endif #include #include #include "rviz/display.h" #include "rviz/properties/bool_property.h" #include "rviz/selection/forwards.h" namespace rviz { class IntProperty; class MarkerBase; class MarkerNamespace; class MarkerSelectionHandler; class Object; class RosTopicProperty; typedef boost::shared_ptr MarkerSelectionHandlerPtr; typedef boost::shared_ptr MarkerBasePtr; typedef std::pair MarkerID; /** * \class MarkerDisplay * \brief Displays "markers" sent in by other ROS nodes on the "visualization_marker" topic * * Markers come in as visualization_msgs::Marker messages. See the Marker message for more information. */ class MarkerDisplay: public Display { Q_OBJECT public: MarkerDisplay(); virtual ~MarkerDisplay(); virtual void onInitialize(); virtual void update(float wall_dt, float ros_dt); virtual void fixedFrameChanged(); virtual void reset(); void deleteMarker(MarkerID id); /** @brief Delete all known markers to this plugin, regardless of id or namespace **/ void deleteAllMarkers(); void setMarkerStatus(MarkerID id, StatusLevel level, const std::string& text); void deleteMarkerStatus(MarkerID id); virtual void setTopic( const QString &topic, const QString &datatype ); protected: virtual void onEnable(); virtual void onDisable(); virtual void load( const Config& config); /** @brief Subscribes to the "visualization_marker" and * "visualization_marker_array" topics. */ virtual void subscribe(); /** @brief Unsubscribes from the "visualization_marker" * "visualization_marker_array" topics. */ virtual void unsubscribe(); /** @brief Process a MarkerArray message. */ void incomingMarkerArray( const visualization_msgs::MarkerArray::ConstPtr& array ); ros::Subscriber array_sub_; RosTopicProperty* marker_topic_property_; IntProperty* queue_size_property_; private Q_SLOTS: void updateQueueSize(); void updateTopic(); private: /** @brief Delete all the markers within the given namespace. */ void deleteMarkersInNamespace( const std::string& ns ); /** * \brief Removes all the markers */ void clearMarkers(); /** * \brief Processes a marker message * @param message The message to process */ void processMessage( const visualization_msgs::Marker::ConstPtr& message ); /** * \brief Processes an "Add" marker message * @param message The message to process */ void processAdd( const visualization_msgs::Marker::ConstPtr& message ); /** * \brief Processes a "Delete" marker message * @param message The message to process */ void processDelete( const visualization_msgs::Marker::ConstPtr& message ); /** * \brief ROS callback notifying us of a new marker */ void incomingMarker(const visualization_msgs::Marker::ConstPtr& marker); void failedMarker(const ros::MessageEvent& marker_evt, tf::FilterFailureReason reason); typedef std::map M_IDToMarker; typedef std::set S_MarkerBase; M_IDToMarker markers_; ///< Map of marker id to the marker info structure S_MarkerBase markers_with_expiration_; S_MarkerBase frame_locked_markers_; typedef std::vector V_MarkerMessage; V_MarkerMessage message_queue_; ///< Marker message queue. Messages are added to this as they are received, and then processed ///< in our update() function boost::mutex queue_mutex_; message_filters::Subscriber sub_; tf::MessageFilter* tf_filter_; typedef QHash M_Namespace; M_Namespace namespaces_; Property* namespaces_category_; typedef std::map M_EnabledState; M_EnabledState namespace_config_enabled_state_; friend class MarkerNamespace; }; /** @brief Manager of a single marker namespace. Keeps a hash from * marker IDs to MarkerBasePtr, and creates or destroys them when . */ class MarkerNamespace: public BoolProperty { Q_OBJECT public: MarkerNamespace( const QString& name, Property* parent_property, MarkerDisplay* owner ); bool isEnabled() const { return getBool(); } public Q_SLOTS: void onEnableChanged(); private: MarkerDisplay* owner_; }; } // namespace rviz #endif /* RVIZ_MARKER_DISPLAY_H */ rviz-1.12.4/src/rviz/default_plugin/markers/000077500000000000000000000000001300447110700210155ustar00rootroot00000000000000rviz-1.12.4/src/rviz/default_plugin/markers/arrow_marker.cpp000066400000000000000000000131671300447110700242240ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "rviz/default_plugin/marker_display.h" #include "rviz/default_plugin/markers/marker_selection_handler.h" #include "rviz/display_context.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/selection/selection_manager.h" #include "rviz/default_plugin/markers/arrow_marker.h" namespace rviz { ArrowMarker::ArrowMarker( MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node ) : MarkerBase( owner, context, parent_node ) , arrow_( 0 ), last_arrow_set_from_points_(false) { child_scene_node_ = scene_node_->createChildSceneNode(); } ArrowMarker::~ArrowMarker() { delete arrow_; context_->getSceneManager()->destroySceneNode( child_scene_node_ ); } void ArrowMarker::setDefaultProportions() { arrow_->set(0.77, 1.0, 0.23, 2.0); } void ArrowMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) { ROS_ASSERT(new_message->type == visualization_msgs::Marker::ARROW); if (!new_message->points.empty() && new_message->points.size() < 2) { std::stringstream ss; ss << "Arrow marker [" << getStringID() << "] only specified one point of a point to point arrow."; if ( owner_ ) { owner_->setMarkerStatus(getID(), StatusProperty::Error, ss.str()); } ROS_DEBUG("%s", ss.str().c_str()); delete arrow_; arrow_ = 0; return; } if (!arrow_) { arrow_ = new Arrow(context_->getSceneManager(), child_scene_node_); setDefaultProportions(); handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ )); handler_->addTrackedObjects( arrow_->getSceneNode() ); } Ogre::Vector3 pos, scale; Ogre::Quaternion orient; transform(new_message, pos, orient, scale); setPosition(pos); setOrientation( orient ); arrow_->setColor(new_message->color.r, new_message->color.g, new_message->color.b, new_message->color.a); // compute translation & rotation from the two points if (new_message->points.size() == 2) { last_arrow_set_from_points_ = true; Ogre::Vector3 point1( new_message->points[0].x, new_message->points[0].y, new_message->points[0].z ); Ogre::Vector3 point2( new_message->points[1].x, new_message->points[1].y, new_message->points[1].z ); Ogre::Vector3 direction = point2 - point1; float distance = direction.length(); float head_length_proportion = 0.23; // Seems to be a good value based on default in arrow.h of shaft:head ratio of 1:0.3 float head_length = head_length_proportion*distance; if ( new_message->scale.z != 0.0 ) { float length = new_message->scale.z; head_length = std::max(0.0, std::min(length, distance)); // clamp } float shaft_length = distance - head_length; arrow_->set(shaft_length, new_message->scale.x, head_length, new_message->scale.y); direction.normalise(); // for some reason the arrow goes into the y direction by default Ogre::Quaternion orient = Ogre::Vector3::NEGATIVE_UNIT_Z.getRotationTo( direction ); arrow_->setPosition(point1); arrow_->setOrientation( orient ); } else { if(last_arrow_set_from_points_) { // Reset arrow to default proportions if we previously set it from points setDefaultProportions(); last_arrow_set_from_points_ = false; } if ( owner_ && (new_message->scale.x * new_message->scale.y * new_message->scale.z == 0.0f) ) { owner_->setMarkerStatus(getID(), StatusProperty::Warn, "Scale of 0 in one of x/y/z"); } arrow_->setScale(scale); Ogre::Quaternion orient = Ogre::Vector3::NEGATIVE_UNIT_Z.getRotationTo( Ogre::Vector3(1,0,0) ); arrow_->setOrientation( orient ); } } S_MaterialPtr ArrowMarker::getMaterials() { S_MaterialPtr materials; extractMaterials( arrow_->getHead()->getEntity(), materials ); extractMaterials( arrow_->getShaft()->getEntity(), materials ); return materials; } } rviz-1.12.4/src/rviz/default_plugin/markers/arrow_marker.h000066400000000000000000000043311300447110700236620ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ARROW_MARKER_H #define RVIZ_ARROW_MARKER_H #include "marker_base.h" namespace Ogre { class SceneNode; } namespace rviz { class Arrow; class DisplayContext; class ArrowMarker: public MarkerBase { public: ArrowMarker( MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node ); ~ArrowMarker(); virtual S_MaterialPtr getMaterials(); protected: virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message); virtual void setDefaultProportions(); Arrow *arrow_; Ogre::SceneNode *child_scene_node_; bool last_arrow_set_from_points_; }; } // end namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/markers/line_list_marker.cpp000066400000000000000000000107521300447110700250510ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "line_list_marker.h" #include "marker_selection_handler.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/display_context.h" #include #include #include #include namespace rviz { LineListMarker::LineListMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node) : MarkerBase(owner, context, parent_node) , lines_(0) { } LineListMarker::~LineListMarker() { delete lines_; } void LineListMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) { ROS_ASSERT(new_message->type == visualization_msgs::Marker::LINE_LIST); if (!lines_) { lines_ = new BillboardLine(context_->getSceneManager(), scene_node_); } Ogre::Vector3 pos, scale; Ogre::Quaternion orient; transform(new_message, pos, orient, scale); setPosition(pos); setOrientation(orient); lines_->setScale(scale); lines_->setColor(new_message->color.r, new_message->color.g, new_message->color.b, new_message->color.a); lines_->clear(); if (new_message->points.empty()) { return; } bool has_per_point_color = new_message->colors.size() == new_message->points.size(); if (new_message->points.size() % 2 == 0) { lines_->setLineWidth( new_message->scale.x ); lines_->setMaxPointsPerLine(2); lines_->setNumLines(new_message->points.size() / 2); size_t i = 0; std::vector::const_iterator it = new_message->points.begin(); std::vector::const_iterator end = new_message->points.end(); for ( ; it != end; ) { if (it != new_message->points.begin()) { lines_->newLine(); } for (uint32_t j = 0; j < 2; ++j, ++it, ++i) { const geometry_msgs::Point& p = *it; Ogre::ColourValue c; if (has_per_point_color) { const std_msgs::ColorRGBA& color = new_message->colors[i]; c.r = color.r; c.g = color.g; c.b = color.b; c.a = color.a; } else { c.r = new_message->color.r; c.g = new_message->color.g; c.b = new_message->color.b; c.a = new_message->color.a; } Ogre::Vector3 v( p.x, p.y, p.z ); lines_->addPoint( v, c ); } } handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ )); handler_->addTrackedObjects( lines_->getSceneNode() ); } else { std::stringstream ss; ss << "Line list marker [" << getStringID() << "] has an odd number of points."; if ( owner_ ) { owner_->setMarkerStatus(getID(), StatusProperty::Error, ss.str()); } ROS_DEBUG("%s", ss.str().c_str()); } } S_MaterialPtr LineListMarker::getMaterials() { S_MaterialPtr materials; materials.insert( lines_->getMaterial() ); return materials; } } rviz-1.12.4/src/rviz/default_plugin/markers/line_list_marker.h000066400000000000000000000041111300447110700245060ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_LINE_LIST_MARKER_H #define RVIZ_LINE_LIST_MARKER_H #include "marker_base.h" namespace rviz { class BillboardLine; } namespace rviz { class LineListMarker : public MarkerBase { public: LineListMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node); ~LineListMarker(); virtual S_MaterialPtr getMaterials(); protected: virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message); BillboardLine* lines_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/markers/line_strip_marker.cpp000066400000000000000000000076411300447110700252420ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "line_strip_marker.h" #include "marker_selection_handler.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/display_context.h" #include #include #include #include namespace rviz { LineStripMarker::LineStripMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node) : MarkerBase(owner, context, parent_node) , lines_(0) { } LineStripMarker::~LineStripMarker() { delete lines_; } void LineStripMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) { ROS_ASSERT(new_message->type == visualization_msgs::Marker::LINE_STRIP); if (!lines_) { lines_ = new BillboardLine(context_->getSceneManager(), scene_node_); } Ogre::Vector3 pos, scale; Ogre::Quaternion orient; transform(new_message, pos, orient, scale); setPosition(pos); setOrientation(orient); lines_->setScale(scale); lines_->setColor(new_message->color.r, new_message->color.g, new_message->color.b, new_message->color.a); lines_->clear(); if (new_message->points.empty()) { return; } lines_->setLineWidth(new_message->scale.x); lines_->setMaxPointsPerLine(new_message->points.size()); bool has_per_point_color = new_message->colors.size() == new_message->points.size(); size_t i = 0; std::vector::const_iterator it = new_message->points.begin(); std::vector::const_iterator end = new_message->points.end(); for ( ; it != end; ++it, ++i ) { const geometry_msgs::Point& p = *it; Ogre::Vector3 v( p.x, p.y, p.z ); Ogre::ColourValue c; if (has_per_point_color) { const std_msgs::ColorRGBA& color = new_message->colors[i]; c.r = color.r; c.g = color.g; c.b = color.b; c.a = color.a; } else { c.r = new_message->color.r; c.g = new_message->color.g; c.b = new_message->color.b; c.a = new_message->color.a; } lines_->addPoint( v, c ); } handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ )); handler_->addTrackedObjects( lines_->getSceneNode() ); } S_MaterialPtr LineStripMarker::getMaterials() { S_MaterialPtr materials; materials.insert( lines_->getMaterial() ); return materials; } } rviz-1.12.4/src/rviz/default_plugin/markers/line_strip_marker.h000066400000000000000000000041161300447110700247010ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_LINE_STRIP_MARKER_H #define RVIZ_LINE_STRIP_MARKER_H #include "marker_base.h" namespace rviz { class BillboardLine; } namespace rviz { class LineStripMarker : public MarkerBase { public: LineStripMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node); ~LineStripMarker(); virtual S_MaterialPtr getMaterials(); protected: virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message); BillboardLine* lines_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/markers/marker_base.cpp000066400000000000000000000107151300447110700240000ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "marker_base.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include "marker_selection_handler.h" #include "rviz/frame_manager.h" #include #include #include #include #include #include #include namespace rviz { MarkerBase::MarkerBase( MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node ) : owner_( owner ) , context_( context ) , scene_node_( parent_node->createChildSceneNode() ) {} MarkerBase::~MarkerBase() { context_->getSceneManager()->destroySceneNode(scene_node_); } void MarkerBase::setMessage(const Marker& message) { // copy and save to shared pointer MarkerConstPtr message_ptr( new Marker(message) ); setMessage( message_ptr ); } void MarkerBase::setMessage(const MarkerConstPtr& message) { MarkerConstPtr old = message_; message_ = message; expiration_ = ros::Time::now() + message->lifetime; onNewMessage(old, message); } void MarkerBase::updateFrameLocked() { ROS_ASSERT(message_ && message_->frame_locked); onNewMessage(message_, message_); } bool MarkerBase::expired() { return ros::Time::now() >= expiration_; } bool MarkerBase::transform(const MarkerConstPtr& message, Ogre::Vector3& pos, Ogre::Quaternion& orient, Ogre::Vector3& scale) { ros::Time stamp = message->header.stamp; if (message->frame_locked) { stamp = ros::Time(); } if (!context_->getFrameManager()->transform(message->header.frame_id, stamp, message->pose, pos, orient)) { std::string error; context_->getFrameManager()->transformHasProblems(message->header.frame_id, message->header.stamp, error); if ( owner_ ) { owner_->setMarkerStatus(getID(), StatusProperty::Error, error); } return false; } scale = Ogre::Vector3(message->scale.x, message->scale.y, message->scale.z); return true; } void MarkerBase::setInteractiveObject( InteractiveObjectWPtr control ) { if( handler_ ) { handler_->setInteractiveObject( control ); } } void MarkerBase::setPosition( const Ogre::Vector3& position ) { scene_node_->setPosition( position ); } void MarkerBase::setOrientation( const Ogre::Quaternion& orientation ) { scene_node_->setOrientation( orientation ); } const Ogre::Vector3& MarkerBase::getPosition() { return scene_node_->getPosition(); } const Ogre::Quaternion& MarkerBase::getOrientation() { return scene_node_->getOrientation(); } void MarkerBase::extractMaterials( Ogre::Entity *entity, S_MaterialPtr &materials ) { uint32_t num_sub_entities = entity->getNumSubEntities(); for (uint32_t i = 0; i < num_sub_entities; ++i) { Ogre::SubEntity* sub = entity->getSubEntity(i); Ogre::MaterialPtr material = sub->getMaterial(); materials.insert( material ); } } } // namespace rviz rviz-1.12.4/src/rviz/default_plugin/markers/marker_base.h000066400000000000000000000072561300447110700234530ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MARKER_BASE_H #define RVIZ_MARKER_BASE_H #include "rviz/selection/forwards.h" #include "rviz/interactive_object.h" #include #include #include namespace Ogre { class SceneNode; class Vector3; class Quaternion; class Entity; } namespace rviz { class DisplayContext; class MarkerDisplay; class MarkerSelectionHandler; typedef std::pair MarkerID; typedef std::set S_MaterialPtr; class MarkerBase { public: typedef visualization_msgs::Marker Marker; typedef visualization_msgs::Marker::ConstPtr MarkerConstPtr; MarkerBase( MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node ); virtual ~MarkerBase(); void setMessage(const Marker& message); void setMessage(const MarkerConstPtr& message); bool expired(); void updateFrameLocked(); const MarkerConstPtr& getMessage() const { return message_; } MarkerID getID() { return MarkerID(message_->ns, message_->id); } std::string getStringID() { std::stringstream ss; ss << message_->ns << "/" << message_->id; return ss.str(); } /** @brief Associate an InteractiveObject with this MarkerBase. */ void setInteractiveObject( InteractiveObjectWPtr object ); virtual void setPosition( const Ogre::Vector3& position ); virtual void setOrientation( const Ogre::Quaternion& orientation ); const Ogre::Vector3& getPosition(); const Ogre::Quaternion& getOrientation(); virtual S_MaterialPtr getMaterials() { return S_MaterialPtr(); } protected: bool transform(const MarkerConstPtr& message, Ogre::Vector3& pos, Ogre::Quaternion& orient, Ogre::Vector3& scale); virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) = 0; void extractMaterials( Ogre::Entity *entity, S_MaterialPtr &materials ); MarkerDisplay* owner_; DisplayContext* context_; Ogre::SceneNode* scene_node_; MarkerConstPtr message_; ros::Time expiration_; boost::shared_ptr handler_; }; typedef boost::shared_ptr MarkerBasePtr; } #endif rviz-1.12.4/src/rviz/default_plugin/markers/marker_selection_handler.cpp000066400000000000000000000071401300447110700265460ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/default_plugin/interactive_markers/interactive_marker_control.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/default_plugin/markers/marker_base.h" #include "rviz/properties/property.h" #include "rviz/properties/quaternion_property.h" #include "rviz/properties/vector_property.h" #include "rviz/default_plugin/markers/marker_selection_handler.h" namespace rviz { MarkerSelectionHandler::MarkerSelectionHandler( const MarkerBase* marker, MarkerID id, DisplayContext* context ) : SelectionHandler( context ) , marker_( marker ) , marker_id_( QString::fromStdString( id.first ) + "/" + QString::number( id.second )) { } MarkerSelectionHandler::~MarkerSelectionHandler() { } Ogre::Vector3 MarkerSelectionHandler::getPosition() { return Ogre::Vector3( marker_->getMessage()->pose.position.x, marker_->getMessage()->pose.position.y, marker_->getMessage()->pose.position.z ); } Ogre::Quaternion MarkerSelectionHandler::getOrientation() { return Ogre::Quaternion( marker_->getMessage()->pose.orientation.w, marker_->getMessage()->pose.orientation.x, marker_->getMessage()->pose.orientation.y, marker_->getMessage()->pose.orientation.z ); } void MarkerSelectionHandler::createProperties( const Picked& obj, Property* parent_property ) { Property* group = new Property( "Marker " + marker_id_, QVariant(), "", parent_property ); properties_.push_back( group ); position_property_ = new VectorProperty( "Position", getPosition(), "", group ); position_property_->setReadOnly( true ); orientation_property_ = new QuaternionProperty( "Orientation", getOrientation(), "", group ); orientation_property_->setReadOnly( true ); group->expand(); } void MarkerSelectionHandler::updateProperties() { position_property_->setVector( getPosition() ); orientation_property_->setQuaternion( getOrientation() ); } } // end namespace rviz rviz-1.12.4/src/rviz/default_plugin/markers/marker_selection_handler.h000066400000000000000000000047071300447110700262210ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MARKER_SELECTION_HANDLER_H #define RVIZ_MARKER_SELECTION_HANDLER_H #include "rviz/selection/forwards.h" #include "rviz/selection/selection_manager.h" namespace rviz { class InteractiveMarkerControl; class MarkerBase; class QuaternionProperty; class VectorProperty; typedef std::pair MarkerID; class MarkerSelectionHandler: public SelectionHandler { public: MarkerSelectionHandler( const MarkerBase* marker, MarkerID id, DisplayContext* context ); virtual ~MarkerSelectionHandler(); Ogre::Vector3 getPosition(); Ogre::Quaternion getOrientation(); virtual void createProperties( const Picked& obj, Property* parent_property ); virtual void updateProperties(); private: const MarkerBase* marker_; QString marker_id_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; }; } // end namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/markers/mesh_resource_marker.cpp000066400000000000000000000176071300447110700257400ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "mesh_resource_marker.h" #include "marker_selection_handler.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/selection/selection_manager.h" #include "rviz/display_context.h" #include "rviz/mesh_loader.h" #include "marker_display.h" #include #include #include #include #include #include #include #include namespace rviz { MeshResourceMarker::MeshResourceMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node) : MarkerBase(owner, context, parent_node) , entity_(0) { } MeshResourceMarker::~MeshResourceMarker() { reset(); } void MeshResourceMarker::reset() { //destroy entity if (entity_) { context_->getSceneManager()->destroyEntity(entity_); entity_ = 0; } // destroy all the materials we've created S_MaterialPtr::iterator it; for (it = materials_.begin(); it != materials_.end(); it++) { Ogre::MaterialPtr material = *it; if (!material.isNull()) { material->unload(); Ogre::MaterialManager::getSingleton().remove(material->getName()); } } materials_.clear(); } void MeshResourceMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) { ROS_ASSERT(new_message->type == visualization_msgs::Marker::MESH_RESOURCE); // flag indicating if the mesh material color needs to be updated bool update_color = false; scene_node_->setVisible(false); // Get the color information from the message float r = new_message->color.r; float g = new_message->color.g; float b = new_message->color.b; float a = new_message->color.a; Ogre::SceneBlendType blending; bool depth_write; if (a < 0.9998) { blending = Ogre::SBT_TRANSPARENT_ALPHA; depth_write = false; } else { blending = Ogre::SBT_REPLACE; depth_write = true; } if (!entity_ || old_message->mesh_resource != new_message->mesh_resource || old_message->mesh_use_embedded_materials != new_message->mesh_use_embedded_materials) { reset(); if (new_message->mesh_resource.empty()) { return; } if (loadMeshFromResource(new_message->mesh_resource).isNull()) { std::stringstream ss; ss << "Mesh resource marker [" << getStringID() << "] could not load [" << new_message->mesh_resource << "]"; if (owner_) { owner_->setMarkerStatus(getID(), StatusProperty::Error, ss.str()); } ROS_DEBUG("%s", ss.str().c_str()); return; } static uint32_t count = 0; std::stringstream ss; ss << "mesh_resource_marker_" << count++; std::string id = ss.str(); entity_ = context_->getSceneManager()->createEntity(id, new_message->mesh_resource); scene_node_->attachObject(entity_); // create a default material for any sub-entities which don't have their own. ss << "Material"; Ogre::MaterialPtr default_material = Ogre::MaterialManager::getSingleton().create(ss.str(), ROS_PACKAGE_NAME); default_material->setReceiveShadows(false); default_material->getTechnique(0)->setLightingEnabled(true); default_material->getTechnique(0)->setAmbient(0.5, 0.5, 0.5); materials_.insert(default_material); if (new_message->mesh_use_embedded_materials) { // make clones of all embedded materials so selection works correctly S_MaterialPtr materials = getMaterials(); S_MaterialPtr::iterator it; for (it = materials.begin(); it != materials.end(); it++) { if ((*it)->getName() != "BaseWhiteNoLighting") { Ogre::MaterialPtr new_material = (*it)->clone(id + (*it)->getName()); materials_.insert(new_material); } } // make sub-entities use cloned materials for (uint32_t i = 0; i < entity_->getNumSubEntities(); ++i) { std::string mat_name = entity_->getSubEntity(i)->getMaterialName(); if (mat_name != "BaseWhiteNoLighting") { entity_->getSubEntity(i)->setMaterialName(id + mat_name); } else { // BaseWhiteNoLighting is the default material Ogre uses // when it sees a mesh with no material. Here we replace // that with our default_material which gets colored with // new_message->color. entity_->getSubEntity(i)->setMaterial(default_material); } } } else { entity_->setMaterial(default_material); } // always update color on resource change update_color = true; handler_.reset(new MarkerSelectionHandler(this, MarkerID(new_message->ns, new_message->id), context_)); handler_->addTrackedObject(entity_); } else { // underlying mesh resource has not changed but if the color has // then we need to update the materials color if (!old_message || old_message->color.r != new_message->color.r || old_message->color.g != new_message->color.g || old_message->color.b != new_message->color.b || old_message->color.a != new_message->color.a) { update_color = true; } } // update material color // if the mesh_use_embedded_materials is true and color is non-zero // then the color will be used to tint the embedded materials if (update_color) { if( new_message->mesh_use_embedded_materials && r == 0 && g == 0 && b == 0 && a == 0 ) { blending = Ogre::SBT_REPLACE; depth_write = true; r = 1; g = 1; b = 1; a = 1; } S_MaterialPtr::iterator material_it; for (material_it = materials_.begin(); material_it != materials_.end(); material_it++) { Ogre::Technique* technique = (*material_it)->getTechnique(0); technique->setAmbient( r*0.5, g*0.5, b*0.5 ); technique->setDiffuse( r, g, b, a ); technique->setSceneBlending( blending ); technique->setDepthWriteEnabled( depth_write ); technique->setLightingEnabled( true ); } } Ogre::Vector3 pos, scale; Ogre::Quaternion orient; transform(new_message, pos, orient, scale); scene_node_->setVisible(true); setPosition(pos); setOrientation(orient); scene_node_->setScale(scale); } S_MaterialPtr MeshResourceMarker::getMaterials() { S_MaterialPtr materials; if (entity_) { extractMaterials(entity_, materials); } return materials; } } rviz-1.12.4/src/rviz/default_plugin/markers/mesh_resource_marker.h000066400000000000000000000045111300447110700253730ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MESH_RESOURCE_MARKER_H #define RVIZ_MESH_RESOURCE_MARKER_H #include "marker_base.h" #include #include namespace Ogre { class SceneNode; class Entity; } namespace rviz { class MeshResourceMarker : public MarkerBase { public: MeshResourceMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node); ~MeshResourceMarker(); virtual S_MaterialPtr getMaterials(); protected: virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message); void reset(); Ogre::Entity* entity_; S_MaterialPtr materials_; //! Scaling factor to convert units. Currently relevant for Collada only. float unit_rescale_; }; } #endif // RVIZ_MESH_RESOURCE_MARKER_H rviz-1.12.4/src/rviz/default_plugin/markers/points_marker.cpp000066400000000000000000000121611300447110700243770ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "points_marker.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include "marker_selection_handler.h" #include #include #include #include #include namespace rviz { PointsMarker::PointsMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node) : MarkerBase(owner, context, parent_node) , points_(0) { } PointsMarker::~PointsMarker() { delete points_; } void PointsMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) { ROS_ASSERT(new_message->type == visualization_msgs::Marker::POINTS || new_message->type == visualization_msgs::Marker::CUBE_LIST || new_message->type == visualization_msgs::Marker::SPHERE_LIST); if (!points_) { points_ = new PointCloud(); scene_node_->attachObject(points_); } Ogre::Vector3 pos, scale; Ogre::Quaternion orient; transform(new_message, pos, orient, scale); switch (new_message->type) { case visualization_msgs::Marker::POINTS: points_->setRenderMode(PointCloud::RM_SQUARES); points_->setDimensions(new_message->scale.x, new_message->scale.y, 0.0f); break; case visualization_msgs::Marker::CUBE_LIST: points_->setRenderMode(PointCloud::RM_BOXES); points_->setDimensions(scale.x, scale.y, scale.z); break; case visualization_msgs::Marker::SPHERE_LIST: points_->setRenderMode(PointCloud::RM_SPHERES); points_->setDimensions(scale.x, scale.y, scale.z); break; } setPosition(pos); setOrientation(orient); points_->clear(); if (new_message->points.empty()) { return; } float r = new_message->color.r; float g = new_message->color.g; float b = new_message->color.b; float a = new_message->color.a; bool has_per_point_color = new_message->colors.size() == new_message->points.size(); bool has_nonzero_alpha = false; bool has_per_point_alpha = false; typedef std::vector< PointCloud::Point > V_Point; V_Point points; points.resize(new_message->points.size()); std::vector::const_iterator it = new_message->points.begin(); std::vector::const_iterator end = new_message->points.end(); for (int i = 0; it != end; ++it, ++i) { const geometry_msgs::Point& p = *it; PointCloud::Point& point = points[i]; Ogre::Vector3 v(p.x, p.y, p.z); point.position.x = v.x; point.position.y = v.y; point.position.z = v.z; if (has_per_point_color) { const std_msgs::ColorRGBA& color = new_message->colors[i]; r = color.r; g = color.g; b = color.b; a = color.a; has_nonzero_alpha = has_nonzero_alpha || a != 0.0; has_per_point_alpha = has_per_point_alpha || a != 1.0; } point.setColor(r, g, b, a); } if (has_per_point_color) { if (!has_nonzero_alpha && owner_) { owner_->setMarkerStatus(getID(), StatusProperty::Warn, "All points have a zero alpha value."); } points_->setAlpha(1.0, has_per_point_alpha); } else { points_->setAlpha(a); } points_->addPoints(&points.front(), points.size()); handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ )); points_->setPickColor( SelectionManager::handleToColor( handler_->getHandle() )); } void PointsMarker::setHighlightColor( float r, float g, float b ) { points_->setHighlightColor( r, g, b ); } } // end namespace rviz rviz-1.12.4/src/rviz/default_plugin/markers/points_marker.h000066400000000000000000000041541300447110700240470ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POINTS_MARKER_H #define RVIZ_POINTS_MARKER_H #include "marker_base.h" namespace Ogre { class SceneNode; } namespace rviz { class PointCloud; } namespace rviz { class PointsMarker : public MarkerBase { public: PointsMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node); ~PointsMarker(); void setHighlightColor( float r, float g, float b ); protected: virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message); PointCloud* points_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/markers/shape_marker.cpp000066400000000000000000000074201300447110700241650ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "shape_marker.h" #include "marker_selection_handler.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include #include #include namespace rviz { ShapeMarker::ShapeMarker( MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node ) : MarkerBase( owner, context, parent_node ) , shape_( 0 ) { } ShapeMarker::~ShapeMarker() { delete shape_; } void ShapeMarker::onNewMessage( const MarkerConstPtr& old_message, const MarkerConstPtr& new_message ) { if (!shape_ || old_message->type != new_message->type) { delete shape_; shape_ = 0; Shape::Type shape_type = Shape::Cube; switch( new_message->type ) { case visualization_msgs::Marker::CUBE: shape_type = Shape::Cube; break; case visualization_msgs::Marker::CYLINDER: shape_type = Shape::Cylinder; break; case visualization_msgs::Marker::SPHERE: shape_type = Shape::Sphere; break; default: ROS_BREAK(); break; } shape_ = new Shape( shape_type, context_->getSceneManager(), scene_node_ ); handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ )); handler_->addTrackedObjects( shape_->getRootNode() ); } Ogre::Vector3 pos, scale, scale_correct; Ogre::Quaternion orient; transform(new_message, pos, orient, scale); if (owner_ && (new_message->scale.x * new_message->scale.y * new_message->scale.z == 0.0f)) { owner_->setMarkerStatus(getID(), StatusProperty::Warn, "Scale of 0 in one of x/y/z"); } setPosition(pos); setOrientation( orient * Ogre::Quaternion( Ogre::Degree(90), Ogre::Vector3(1,0,0) ) ); scale_correct = Ogre::Quaternion( Ogre::Degree(90), Ogre::Vector3(1,0,0) ) * scale; shape_->setScale(scale_correct); shape_->setColor(new_message->color.r, new_message->color.g, new_message->color.b, new_message->color.a); } S_MaterialPtr ShapeMarker::getMaterials() { S_MaterialPtr materials; extractMaterials(shape_->getEntity(), materials); return materials; } } rviz-1.12.4/src/rviz/default_plugin/markers/shape_marker.h000066400000000000000000000040531300447110700236310ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SHAPE_MARKER_H #define RVIZ_SHAPE_MARKER_H #include "marker_base.h" namespace rviz { class Shape; } namespace rviz { class ShapeMarker: public MarkerBase { public: ShapeMarker( MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node ); ~ShapeMarker(); virtual S_MaterialPtr getMaterials(); protected: virtual void onNewMessage( const MarkerConstPtr& old_message, const MarkerConstPtr& new_message ); Shape* shape_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/markers/text_view_facing_marker.cpp000066400000000000000000000063221300447110700264120ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/default_plugin/markers/marker_selection_handler.h" #include "rviz/display_context.h" #include "rviz/ogre_helpers/movable_text.h" #include "rviz/selection/selection_manager.h" #include "rviz/default_plugin/markers/text_view_facing_marker.h" namespace rviz { TextViewFacingMarker::TextViewFacingMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node) : MarkerBase(owner, context, parent_node) , text_(0) { } TextViewFacingMarker::~TextViewFacingMarker() { delete text_; } void TextViewFacingMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) { ROS_ASSERT(new_message->type == visualization_msgs::Marker::TEXT_VIEW_FACING); if (!text_) { text_ = new MovableText(new_message->text); text_->setTextAlignment(MovableText::H_CENTER, MovableText::V_CENTER); scene_node_->attachObject(text_); handler_.reset( new MarkerSelectionHandler(this, MarkerID(new_message->ns, new_message->id ), context_ )); handler_->addTrackedObject( text_ ); } Ogre::Vector3 pos, scale; Ogre::Quaternion orient; transform(new_message, pos, orient, scale); setPosition(pos); text_->setCharacterHeight(new_message->scale.z); text_->setColor(Ogre::ColourValue(new_message->color.r, new_message->color.g, new_message->color.b, new_message->color.a)); text_->setCaption(new_message->text); } S_MaterialPtr TextViewFacingMarker::getMaterials() { S_MaterialPtr materials; if ( text_->getMaterial().get() ) { materials.insert( text_->getMaterial() ); } return materials; } } rviz-1.12.4/src/rviz/default_plugin/markers/text_view_facing_marker.h000066400000000000000000000043671300447110700260660ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TEXT_VIEW_FACING_MARKER_H #define RVIZ_TEXT_VIEW_FACING_MARKER_H #include "marker_base.h" namespace Ogre { class SceneNode; } namespace rviz { class MovableText; } namespace rviz { class TextViewFacingMarker : public MarkerBase { public: TextViewFacingMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node); ~TextViewFacingMarker(); virtual void setOrientation( const Ogre::Quaternion& orientation ) {} virtual S_MaterialPtr getMaterials(); protected: virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message); MovableText* text_; }; } #endif // RVIZ_TEXT_VIEW_FACING_MARKER_H rviz-1.12.4/src/rviz/default_plugin/markers/triangle_list_marker.cpp000066400000000000000000000164771300447110700257410ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "triangle_list_marker.h" #include "marker_selection_handler.h" #include "rviz/default_plugin/marker_display.h" #include "rviz/selection/selection_manager.h" #include "rviz/uniform_string_stream.h" #include "rviz/display_context.h" #include "rviz/mesh_loader.h" #include "marker_display.h" #include #include #include #include #include #include namespace rviz { TriangleListMarker::TriangleListMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node) : MarkerBase(owner, context, parent_node) , manual_object_(0) { } TriangleListMarker::~TriangleListMarker() { context_->getSceneManager()->destroyManualObject(manual_object_); material_->unload(); Ogre::MaterialManager::getSingleton().remove(material_->getName()); } void TriangleListMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message) { ROS_ASSERT(new_message->type == visualization_msgs::Marker::TRIANGLE_LIST); size_t num_points = new_message->points.size(); if( (num_points % 3) != 0 || num_points == 0 ) { std::stringstream ss; if( num_points == 0 ) { ss << "TriMesh marker [" << getStringID() << "] has no points."; } else { ss << "TriMesh marker [" << getStringID() << "] has a point count which is not divisible by 3 [" << num_points <<"]"; } if ( owner_ ) { owner_->setMarkerStatus(getID(), StatusProperty::Error, ss.str()); } ROS_DEBUG("%s", ss.str().c_str()); scene_node_->setVisible( false ); return; } else { scene_node_->setVisible( true ); } if (!manual_object_) { static uint32_t count = 0; UniformStringStream ss; ss << "Triangle List Marker" << count++; manual_object_ = context_->getSceneManager()->createManualObject(ss.str()); scene_node_->attachObject(manual_object_); ss << "Material"; material_name_ = ss.str(); material_ = Ogre::MaterialManager::getSingleton().create( material_name_, ROS_PACKAGE_NAME ); material_->setReceiveShadows(false); material_->getTechnique(0)->setLightingEnabled(true); material_->setCullingMode(Ogre::CULL_NONE); handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ )); } Ogre::Vector3 pos, scale; Ogre::Quaternion orient; if (!transform(new_message, pos, orient, scale)) { ROS_DEBUG("Unable to transform marker message"); scene_node_->setVisible( false ); return; } if ( owner_ && (new_message->scale.x * new_message->scale.y * new_message->scale.z == 0.0f) ) { owner_->setMarkerStatus(getID(), StatusProperty::Warn, "Scale of 0 in one of x/y/z"); } setPosition(pos); setOrientation(orient); scene_node_->setScale(scale); // If we have the same number of tris as previously, just update the object if (old_message && num_points == old_message->points.size()) { manual_object_->beginUpdate(0); } else // Otherwise clear it and begin anew { manual_object_->clear(); manual_object_->estimateVertexCount(num_points); manual_object_->begin(material_name_, Ogre::RenderOperation::OT_TRIANGLE_LIST); } bool has_vertex_colors = new_message->colors.size() == num_points; bool has_face_colors = new_message->colors.size() == num_points / 3; bool any_vertex_has_alpha = false; const std::vector& points = new_message->points; for(size_t i = 0; i < num_points; i += 3) { std::vector corners(3); for(size_t c = 0; c < 3; c++) { corners[c] = Ogre::Vector3(points[i+c].x, points[i+c].y, points[i+c].z); } Ogre::Vector3 normal = (corners[1] - corners[0]).crossProduct(corners[2] - corners[0]); normal.normalise(); for(size_t c = 0; c < 3; c++) { manual_object_->position(corners[c]); manual_object_->normal(normal); if(has_vertex_colors) { any_vertex_has_alpha = any_vertex_has_alpha || (new_message->colors[i+c].a < 0.9998); manual_object_->colour(new_message->colors[i+c].r, new_message->colors[i+c].g, new_message->colors[i+c].b, new_message->color.a * new_message->colors[i+c].a); } else if (has_face_colors) { any_vertex_has_alpha = any_vertex_has_alpha || (new_message->colors[i/3].a < 0.9998); manual_object_->colour(new_message->colors[i/3].r, new_message->colors[i/3].g, new_message->colors[i/3].b, new_message->color.a * new_message->colors[i/3].a); } } } manual_object_->end(); if (has_vertex_colors || has_face_colors) { material_->getTechnique(0)->setLightingEnabled(false); } else { material_->getTechnique(0)->setLightingEnabled(true); float r,g,b,a; r = new_message->color.r; g = new_message->color.g; b = new_message->color.b; a = new_message->color.a; material_->getTechnique(0)->setAmbient( r/2,g/2,b/2 ); material_->getTechnique(0)->setDiffuse( r,g,b,a ); } if( (!has_vertex_colors && new_message->color.a < 0.9998) || (has_vertex_colors && any_vertex_has_alpha)) { material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); material_->getTechnique(0)->setDepthWriteEnabled( false ); } else { material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE ); material_->getTechnique(0)->setDepthWriteEnabled( true ); } handler_->addTrackedObject( manual_object_ ); } S_MaterialPtr TriangleListMarker::getMaterials() { S_MaterialPtr materials; materials.insert( material_ ); return materials; } } rviz-1.12.4/src/rviz/default_plugin/markers/triangle_list_marker.h000066400000000000000000000044521300447110700253740ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TRIANGLE_LIST_MARKER_H #define RVIZ_TRIANGLE_LIST_MARKER_H #include #include #include "rviz/default_plugin/markers/marker_base.h" namespace Ogre { class SceneNode; class ManualObject; } namespace rviz { class TriangleListMarker : public MarkerBase { public: TriangleListMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node); ~TriangleListMarker(); virtual S_MaterialPtr getMaterials(); protected: virtual void onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message); Ogre::ManualObject* manual_object_; Ogre::MaterialPtr material_; std::string material_name_; }; } #endif // RVIZ_TRIANGLE_LIST_MARKER_H rviz-1.12.4/src/rviz/default_plugin/odometry_display.cpp000066400000000000000000000226261300447110700234540ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/properties/color_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/int_property.h" #include "rviz/properties/ros_topic_property.h" #include "rviz/validate_floats.h" #include "rviz/display_context.h" #include "odometry_display.h" namespace rviz { OdometryDisplay::OdometryDisplay() : Display() , messages_received_(0) { topic_property_ = new RosTopicProperty( "Topic", "", QString::fromStdString( ros::message_traits::datatype() ), "nav_msgs::Odometry topic to subscribe to.", this, SLOT( updateTopic() )); color_property_ = new ColorProperty( "Color", QColor( 255, 25, 0 ), "Color of the arrows.", this, SLOT( updateColor() )); position_tolerance_property_ = new FloatProperty( "Position Tolerance", .1, "Distance, in meters from the last arrow dropped, " "that will cause a new arrow to drop.", this ); position_tolerance_property_->setMin( 0 ); angle_tolerance_property_ = new FloatProperty( "Angle Tolerance", .1, "Angular distance from the last arrow dropped, " "that will cause a new arrow to drop.", this ); angle_tolerance_property_->setMin( 0 ); keep_property_ = new IntProperty( "Keep", 100, "Number of arrows to keep before removing the oldest. 0 means keep all of them.", this ); keep_property_->setMin( 0 ); length_property_ = new FloatProperty( "Length", 1.0, "Length of each arrow.", this, SLOT( updateLength() )); } OdometryDisplay::~OdometryDisplay() { if ( initialized() ) { unsubscribe(); clear(); delete tf_filter_; } } void OdometryDisplay::onInitialize() { tf_filter_ = new tf::MessageFilter( *context_->getTFClient(), fixed_frame_.toStdString(), 5, update_nh_ ); tf_filter_->connectInput( sub_ ); tf_filter_->registerCallback( boost::bind( &OdometryDisplay::incomingMessage, this, _1 )); context_->getFrameManager()->registerFilterForTransformStatusCheck( tf_filter_, this ); } void OdometryDisplay::clear() { D_Arrow::iterator it = arrows_.begin(); D_Arrow::iterator end = arrows_.end(); for ( ; it != end; ++it ) { delete *it; } arrows_.clear(); if( last_used_message_ ) { last_used_message_.reset(); } tf_filter_->clear(); messages_received_ = 0; setStatus( StatusProperty::Warn, "Topic", "No messages received" ); } void OdometryDisplay::updateTopic() { unsubscribe(); clear(); subscribe(); context_->queueRender(); } void OdometryDisplay::updateColor() { QColor color = color_property_->getColor(); float red = color.redF(); float green = color.greenF(); float blue = color.blueF(); D_Arrow::iterator it = arrows_.begin(); D_Arrow::iterator end = arrows_.end(); for( ; it != end; ++it ) { Arrow* arrow = *it; arrow->setColor( red, green, blue, 1.0f ); } context_->queueRender(); } void OdometryDisplay::updateLength() { float length = length_property_->getFloat(); D_Arrow::iterator it = arrows_.begin(); D_Arrow::iterator end = arrows_.end(); Ogre::Vector3 scale( length, length, length ); for ( ; it != end; ++it ) { Arrow* arrow = *it; arrow->setScale( scale ); } context_->queueRender(); } void OdometryDisplay::subscribe() { if ( !isEnabled() ) { return; } try { sub_.subscribe( update_nh_, topic_property_->getTopicStd(), 5 ); setStatus( StatusProperty::Ok, "Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Topic", QString( "Error subscribing: " ) + e.what() ); } } void OdometryDisplay::unsubscribe() { sub_.unsubscribe(); } void OdometryDisplay::onEnable() { subscribe(); } void OdometryDisplay::onDisable() { unsubscribe(); clear(); } bool validateFloats(const nav_msgs::Odometry& msg) { bool valid = true; valid = valid && validateFloats( msg.pose.pose ); valid = valid && validateFloats( msg.twist.twist ); return valid; } void OdometryDisplay::incomingMessage( const nav_msgs::Odometry::ConstPtr& message ) { ++messages_received_; if( !validateFloats( *message )) { setStatus( StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } setStatus( StatusProperty::Ok, "Topic", QString::number( messages_received_ ) + " messages received" ); if( last_used_message_ ) { Ogre::Vector3 last_position(last_used_message_->pose.pose.position.x, last_used_message_->pose.pose.position.y, last_used_message_->pose.pose.position.z); Ogre::Vector3 current_position(message->pose.pose.position.x, message->pose.pose.position.y, message->pose.pose.position.z); Ogre::Quaternion last_orientation(last_used_message_->pose.pose.orientation.w, last_used_message_->pose.pose.orientation.x, last_used_message_->pose.pose.orientation.y, last_used_message_->pose.pose.orientation.z); Ogre::Quaternion current_orientation(message->pose.pose.orientation.w, message->pose.pose.orientation.x, message->pose.pose.orientation.y, message->pose.pose.orientation.z); if( (last_position - current_position).length() < position_tolerance_property_->getFloat() && (last_orientation - current_orientation).normalise() < angle_tolerance_property_->getFloat() ) { return; } } Arrow* arrow = new Arrow( scene_manager_, scene_node_, 0.8f, 0.05f, 0.2f, 0.2f ); transformArrow( message, arrow ); QColor color = color_property_->getColor(); arrow->setColor( color.redF(), color.greenF(), color.blueF(), 1.0f ); float length = length_property_->getFloat(); Ogre::Vector3 scale( length, length, length ); arrow->setScale( scale ); arrows_.push_back( arrow ); last_used_message_ = message; context_->queueRender(); } void OdometryDisplay::transformArrow( const nav_msgs::Odometry::ConstPtr& message, Arrow* arrow ) { Ogre::Vector3 position; Ogre::Quaternion orientation; if( !context_->getFrameManager()->transform( message->header, message->pose.pose, position, orientation )) { ROS_ERROR( "Error transforming odometry '%s' from frame '%s' to frame '%s'", qPrintable( getName() ), message->header.frame_id.c_str(), qPrintable( fixed_frame_ )); } arrow->setPosition( position ); // Arrow points in -Z direction, so rotate the orientation before display. // TODO: is it safe to change Arrow to point in +X direction? arrow->setOrientation( orientation * Ogre::Quaternion( Ogre::Degree( -90 ), Ogre::Vector3::UNIT_Y )); } void OdometryDisplay::fixedFrameChanged() { tf_filter_->setTargetFrame( fixed_frame_.toStdString() ); clear(); } void OdometryDisplay::update( float wall_dt, float ros_dt ) { size_t keep = keep_property_->getInt(); if( keep > 0 ) { while( arrows_.size() > keep ) { delete arrows_.front(); arrows_.pop_front(); } } } void OdometryDisplay::reset() { Display::reset(); clear(); } void OdometryDisplay::setTopic( const QString &topic, const QString &datatype ) { topic_property_->setString( topic ); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::OdometryDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/odometry_display.h000066400000000000000000000065761300447110700231270ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ODOMETRY_DISPLAY_H_ #define RVIZ_ODOMETRY_DISPLAY_H_ #include #include #include #ifndef Q_MOC_RUN #include #include #endif #include #include "rviz/display.h" namespace rviz { class Arrow; class ColorProperty; class FloatProperty; class IntProperty; class RosTopicProperty; /** * \class OdometryDisplay * \brief Accumulates and displays the pose from a nav_msgs::Odometry message */ class OdometryDisplay: public Display { Q_OBJECT public: OdometryDisplay(); virtual ~OdometryDisplay(); // Overrides from Display virtual void onInitialize(); virtual void fixedFrameChanged(); virtual void update( float wall_dt, float ros_dt ); virtual void reset(); virtual void setTopic( const QString &topic, const QString &datatype ); protected: // overrides from Display virtual void onEnable(); virtual void onDisable(); private Q_SLOTS: void updateColor(); void updateTopic(); void updateLength(); private: void subscribe(); void unsubscribe(); void clear(); void incomingMessage( const nav_msgs::Odometry::ConstPtr& message ); void transformArrow( const nav_msgs::Odometry::ConstPtr& message, Arrow* arrow ); typedef std::deque D_Arrow; D_Arrow arrows_; uint32_t messages_received_; nav_msgs::Odometry::ConstPtr last_used_message_; message_filters::Subscriber sub_; tf::MessageFilter* tf_filter_; ColorProperty* color_property_; RosTopicProperty* topic_property_; FloatProperty* position_tolerance_property_; FloatProperty* angle_tolerance_property_; IntProperty* keep_property_; FloatProperty* length_property_; }; } // namespace rviz #endif /* RVIZ_ODOMETRY_DISPLAY_H_ */ rviz-1.12.4/src/rviz/default_plugin/path_display.cpp000066400000000000000000000442721300447110700225470ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/color_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/int_property.h" #include "rviz/properties/vector_property.h" #include "rviz/validate_floats.h" #include "rviz/ogre_helpers/billboard_line.h" #include "rviz/default_plugin/path_display.h" namespace rviz { PathDisplay::PathDisplay() { style_property_ = new EnumProperty( "Line Style", "Lines", "The rendering operation to use to draw the grid lines.", this, SLOT( updateStyle() )); style_property_->addOption( "Lines", LINES ); style_property_->addOption( "Billboards", BILLBOARDS ); line_width_property_ = new FloatProperty( "Line Width", 0.03, "The width, in meters, of each path line." "Only works with the 'Billboards' style.", this, SLOT( updateLineWidth() ), this ); line_width_property_->setMin( 0.001 ); line_width_property_->hide(); color_property_ = new ColorProperty( "Color", QColor( 25, 255, 0 ), "Color to draw the path.", this ); alpha_property_ = new FloatProperty( "Alpha", 1.0, "Amount of transparency to apply to the path.", this ); buffer_length_property_ = new IntProperty( "Buffer Length", 1, "Number of paths to display.", this, SLOT( updateBufferLength() )); buffer_length_property_->setMin( 1 ); offset_property_ = new VectorProperty( "Offset", Ogre::Vector3::ZERO, "Allows you to offset the path from the origin of the reference frame. In meters.", this, SLOT( updateOffset() )); pose_style_property_ = new EnumProperty( "Pose Style", "None", "Shape to display the pose as.", this, SLOT( updatePoseStyle() )); pose_style_property_->addOption( "None", NONE ); pose_style_property_->addOption( "Axes", AXES ); pose_style_property_->addOption( "Arrows", ARROWS ); pose_axes_length_property_ = new rviz::FloatProperty( "Length", 0.3, "Length of the axes.", this, SLOT(updatePoseAxisGeometry()) ); pose_axes_radius_property_ = new rviz::FloatProperty( "Radius", 0.03, "Radius of the axes.", this, SLOT(updatePoseAxisGeometry()) ); pose_arrow_color_property_ = new ColorProperty( "Color", QColor( 255, 85, 255 ), "Color to draw the poses.", this, SLOT(updatePoseArrowColor())); pose_arrow_shaft_length_property_ = new rviz::FloatProperty( "Shaft Length", 0.1, "Length of the arrow shaft.", this, SLOT(updatePoseArrowGeometry())); pose_arrow_head_length_property_ = new rviz::FloatProperty( "Head Length", 0.2, "Length of the arrow head.", this, SLOT(updatePoseArrowGeometry())); pose_arrow_shaft_diameter_property_ = new rviz::FloatProperty( "Shaft Diameter", 0.1, "Diameter of the arrow shaft.", this, SLOT(updatePoseArrowGeometry())); pose_arrow_head_diameter_property_ = new rviz::FloatProperty( "Head Diameter", 0.3, "Diameter of the arrow head.", this, SLOT(updatePoseArrowGeometry())); pose_axes_length_property_->hide(); pose_axes_radius_property_->hide(); pose_arrow_color_property_->hide(); pose_arrow_shaft_length_property_->hide(); pose_arrow_head_length_property_->hide(); pose_arrow_shaft_diameter_property_->hide(); pose_arrow_head_diameter_property_->hide(); } PathDisplay::~PathDisplay() { destroyObjects(); destroyPoseAxesChain(); destroyPoseArrowChain(); } void PathDisplay::onInitialize() { MFDClass::onInitialize(); updateBufferLength(); } void PathDisplay::reset() { MFDClass::reset(); updateBufferLength(); } void PathDisplay::allocateAxesVector(std::vector& axes_vect, int num) { if (num > axes_vect.size()) { for (size_t i = axes_vect.size(); i < num; i++) { rviz::Axes* axes = new rviz::Axes( scene_manager_, scene_node_, pose_axes_length_property_->getFloat(), pose_axes_radius_property_->getFloat()); axes_vect.push_back(axes); } } else if (num < axes_vect.size()) { for (int i = axes_vect.size() - 1; num <= i; i--) { delete axes_vect[i]; } axes_vect.resize(num); } } void PathDisplay::allocateArrowVector(std::vector& arrow_vect, int num) { if (num > arrow_vect.size()) { for (size_t i = arrow_vect.size(); i < num; i++) { rviz::Arrow* arrow = new rviz::Arrow( scene_manager_, scene_node_ ); arrow_vect.push_back(arrow); } } else if (num < arrow_vect.size()) { for (int i = arrow_vect.size() - 1; num <= i; i--) { delete arrow_vect[i]; } arrow_vect.resize(num); } } void PathDisplay::destroyPoseAxesChain() { for( size_t i = 0; i < axes_chain_.size(); i++ ) { allocateAxesVector(axes_chain_[i], 0); } axes_chain_.resize(0); } void PathDisplay::destroyPoseArrowChain() { for( size_t i = 0; i < arrow_chain_.size(); i++ ) { allocateArrowVector(arrow_chain_[i], 0); } arrow_chain_.resize(0); } void PathDisplay::updateStyle() { LineStyle style = (LineStyle) style_property_->getOptionInt(); switch( style ) { case LINES: default: line_width_property_->hide(); break; case BILLBOARDS: line_width_property_->show(); break; } updateBufferLength(); } void PathDisplay::updateLineWidth() { LineStyle style = (LineStyle) style_property_->getOptionInt(); float line_width = line_width_property_->getFloat(); if(style == BILLBOARDS) { for( size_t i = 0; i < billboard_lines_.size(); i++ ) { rviz::BillboardLine* billboard_line = billboard_lines_[ i ]; if( billboard_line ) billboard_line->setLineWidth( line_width ); } } context_->queueRender(); } void PathDisplay::updateOffset() { scene_node_->setPosition( offset_property_->getVector() ); context_->queueRender(); } void PathDisplay::updatePoseStyle() { PoseStyle pose_style = (PoseStyle) pose_style_property_->getOptionInt(); switch (pose_style) { case AXES: pose_axes_length_property_->show(); pose_axes_radius_property_->show(); pose_arrow_color_property_->hide(); pose_arrow_shaft_length_property_->hide(); pose_arrow_head_length_property_->hide(); pose_arrow_shaft_diameter_property_->hide(); pose_arrow_head_diameter_property_->hide(); break; case ARROWS: pose_axes_length_property_->hide(); pose_axes_radius_property_->hide(); pose_arrow_color_property_->show(); pose_arrow_shaft_length_property_->show(); pose_arrow_head_length_property_->show(); pose_arrow_shaft_diameter_property_->show(); pose_arrow_head_diameter_property_->show(); break; default: pose_axes_length_property_->hide(); pose_axes_radius_property_->hide(); pose_arrow_color_property_->hide(); pose_arrow_shaft_length_property_->hide(); pose_arrow_head_length_property_->hide(); pose_arrow_shaft_diameter_property_->hide(); pose_arrow_head_diameter_property_->hide(); } updateBufferLength(); } void PathDisplay::updatePoseAxisGeometry() { for(size_t i = 0; i < axes_chain_.size() ; i++) { std::vector& axes_vect = axes_chain_[i]; for(size_t j = 0; j < axes_vect.size() ; j++) { axes_vect[j]->set( pose_axes_length_property_->getFloat(), pose_axes_radius_property_->getFloat() ); } } context_->queueRender(); } void PathDisplay::updatePoseArrowColor() { QColor color = pose_arrow_color_property_->getColor(); for( size_t i = 0; i < arrow_chain_.size(); i++ ) { std::vector& arrow_vect = arrow_chain_[i]; for( size_t j = 0; j < arrow_vect.size(); j++ ) { arrow_vect[j]->setColor( color.redF(), color.greenF(), color.blueF(), 1.0f ); } } context_->queueRender(); } void PathDisplay::updatePoseArrowGeometry() { for( size_t i = 0; i < arrow_chain_.size(); i++ ) { std::vector& arrow_vect = arrow_chain_[i]; for( size_t j = 0; j < arrow_vect.size(); j++ ) { arrow_vect[j]->set(pose_arrow_shaft_length_property_->getFloat(), pose_arrow_shaft_diameter_property_->getFloat(), pose_arrow_head_length_property_->getFloat(), pose_arrow_head_diameter_property_->getFloat()); } } context_->queueRender(); } void PathDisplay::destroyObjects() { // Destroy all simple lines, if any for( size_t i = 0; i < manual_objects_.size(); i++ ) { Ogre::ManualObject*& manual_object = manual_objects_[ i ]; if( manual_object ) { manual_object->clear(); scene_manager_->destroyManualObject( manual_object ); manual_object = NULL; // ensure it doesn't get destroyed again } } // Destroy all billboards, if any for( size_t i = 0; i < billboard_lines_.size(); i++ ) { rviz::BillboardLine*& billboard_line = billboard_lines_[ i ]; if( billboard_line ) { delete billboard_line; // also destroys the corresponding scene node billboard_line = NULL; // ensure it doesn't get destroyed again } } } void PathDisplay::updateBufferLength() { // Delete old path objects destroyObjects(); // Destroy all axes and arrows destroyPoseAxesChain(); destroyPoseArrowChain(); // Read options int buffer_length = buffer_length_property_->getInt(); LineStyle style = (LineStyle) style_property_->getOptionInt(); // Create new path objects switch(style) { case LINES: // simple lines with fixed width of 1px manual_objects_.resize( buffer_length ); for( size_t i = 0; i < manual_objects_.size(); i++ ) { Ogre::ManualObject* manual_object = scene_manager_->createManualObject(); manual_object->setDynamic( true ); scene_node_->attachObject( manual_object ); manual_objects_[ i ] = manual_object; } break; case BILLBOARDS: // billboards with configurable width billboard_lines_.resize( buffer_length ); for( size_t i = 0; i < billboard_lines_.size(); i++ ) { rviz::BillboardLine* billboard_line = new rviz::BillboardLine(scene_manager_, scene_node_); billboard_lines_[ i ] = billboard_line; } break; } axes_chain_.resize( buffer_length ); arrow_chain_.resize( buffer_length ); } bool validateFloats( const nav_msgs::Path& msg ) { bool valid = true; valid = valid && validateFloats( msg.poses ); return valid; } void PathDisplay::processMessage( const nav_msgs::Path::ConstPtr& msg ) { // Calculate index of oldest element in cyclic buffer size_t bufferIndex = messages_received_ % buffer_length_property_->getInt(); LineStyle style = (LineStyle) style_property_->getOptionInt(); Ogre::ManualObject* manual_object = NULL; rviz::BillboardLine* billboard_line = NULL; // Delete oldest element switch(style) { case LINES: manual_object = manual_objects_[ bufferIndex ]; manual_object->clear(); break; case BILLBOARDS: billboard_line = billboard_lines_[ bufferIndex ]; billboard_line->clear(); break; } // Check if path contains invalid coordinate values if( !validateFloats( *msg )) { setStatus( StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } // Lookup transform into fixed frame Ogre::Vector3 position; Ogre::Quaternion orientation; if( !context_->getFrameManager()->getTransform( msg->header, position, orientation )) { ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable( fixed_frame_ )); } Ogre::Matrix4 transform( orientation ); transform.setTrans( position ); // scene_node_->setPosition( position ); // scene_node_->setOrientation( orientation ); Ogre::ColourValue color = color_property_->getOgreColor(); color.a = alpha_property_->getFloat(); uint32_t num_points = msg->poses.size(); float line_width = line_width_property_->getFloat(); switch(style) { case LINES: manual_object->estimateVertexCount( num_points ); manual_object->begin( "BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_STRIP ); for( uint32_t i=0; i < num_points; ++i) { const geometry_msgs::Point& pos = msg->poses[ i ].pose.position; Ogre::Vector3 xpos = transform * Ogre::Vector3( pos.x, pos.y, pos.z ); manual_object->position( xpos.x, xpos.y, xpos.z ); manual_object->colour( color ); } manual_object->end(); break; case BILLBOARDS: billboard_line->setNumLines( 1 ); billboard_line->setMaxPointsPerLine( num_points ); billboard_line->setLineWidth( line_width ); for( uint32_t i=0; i < num_points; ++i) { const geometry_msgs::Point& pos = msg->poses[ i ].pose.position; Ogre::Vector3 xpos = transform * Ogre::Vector3( pos.x, pos.y, pos.z ); billboard_line->addPoint( xpos, color ); } break; } // process pose markers PoseStyle pose_style = (PoseStyle) pose_style_property_->getOptionInt(); std::vector& arrow_vect = arrow_chain_[ bufferIndex ]; std::vector& axes_vect = axes_chain_[ bufferIndex ]; switch(pose_style) { case AXES: allocateAxesVector(axes_vect, num_points); for( uint32_t i=0; i < num_points; ++i) { const geometry_msgs::Point& pos = msg->poses[ i ].pose.position; Ogre::Vector3 xpos = transform * Ogre::Vector3( pos.x, pos.y, pos.z ); axes_vect[i]->setPosition(xpos); Ogre::Quaternion orientation(msg->poses[ i ].pose.orientation.w, msg->poses[ i ].pose.orientation.x, msg->poses[ i ].pose.orientation.y, msg->poses[ i ].pose.orientation.z); axes_vect[i]->setOrientation(orientation); } break; case ARROWS: allocateArrowVector(arrow_vect, num_points); for( uint32_t i=0; i < num_points; ++i) { const geometry_msgs::Point& pos = msg->poses[ i ].pose.position; Ogre::Vector3 xpos = transform * Ogre::Vector3( pos.x, pos.y, pos.z ); QColor color = pose_arrow_color_property_->getColor(); arrow_vect[i]->setColor( color.redF(), color.greenF(), color.blueF(), 1.0f ); arrow_vect[i]->set(pose_arrow_shaft_length_property_->getFloat(), pose_arrow_shaft_diameter_property_->getFloat(), pose_arrow_head_length_property_->getFloat(), pose_arrow_head_diameter_property_->getFloat()); arrow_vect[i]->setPosition(xpos); Ogre::Quaternion orientation(msg->poses[ i ].pose.orientation.w, msg->poses[ i ].pose.orientation.x, msg->poses[ i ].pose.orientation.y, msg->poses[ i ].pose.orientation.z); Ogre::Vector3 dir(1, 0, 0); dir = orientation * dir; arrow_vect[i]->setDirection(dir); } break; default: break; } context_->queueRender(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::PathDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/path_display.h000066400000000000000000000075741300447110700222200ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_PATH_DISPLAY_H #define RVIZ_PATH_DISPLAY_H #include #include "rviz/message_filter_display.h" #include #include namespace Ogre { class ManualObject; } namespace rviz { class ColorProperty; class FloatProperty; class IntProperty; class EnumProperty; class BillboardLine; class VectorProperty; /** * \class PathDisplay * \brief Displays a nav_msgs::Path message */ class PathDisplay: public MessageFilterDisplay { Q_OBJECT public: PathDisplay(); virtual ~PathDisplay(); /** @brief Overridden from Display. */ virtual void reset(); protected: /** @brief Overridden from Display. */ virtual void onInitialize(); /** @brief Overridden from MessageFilterDisplay. */ void processMessage( const nav_msgs::Path::ConstPtr& msg ); private Q_SLOTS: void updateBufferLength(); void updateStyle(); void updateLineWidth(); void updateOffset(); void updatePoseStyle(); void updatePoseAxisGeometry(); void updatePoseArrowColor(); void updatePoseArrowGeometry(); private: void destroyObjects(); void allocateArrowVector(std::vector& arrow_vect, int num); void allocateAxesVector(std::vector& axes_vect, int num); void destroyPoseAxesChain(); void destroyPoseArrowChain(); std::vector manual_objects_; std::vector billboard_lines_; std::vector >axes_chain_; std::vector >arrow_chain_; EnumProperty* style_property_; ColorProperty* color_property_; FloatProperty* alpha_property_; FloatProperty* line_width_property_; IntProperty* buffer_length_property_; VectorProperty* offset_property_; enum LineStyle { LINES, BILLBOARDS }; // pose marker property EnumProperty* pose_style_property_; FloatProperty* pose_axes_length_property_; FloatProperty* pose_axes_radius_property_; ColorProperty* pose_arrow_color_property_; FloatProperty* pose_arrow_shaft_length_property_; FloatProperty* pose_arrow_head_length_property_; FloatProperty* pose_arrow_shaft_diameter_property_; FloatProperty* pose_arrow_head_diameter_property_; enum PoseStyle { NONE, AXES, ARROWS, }; }; } // namespace rviz #endif /* RVIZ_PATH_DISPLAY_H */ rviz-1.12.4/src/rviz/default_plugin/point_cloud2_display.cpp000066400000000000000000000144111300447110700242040ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/default_plugin/point_cloud_common.h" #include "rviz/default_plugin/point_cloud_transformers.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/int_property.h" #include "rviz/validate_floats.h" #include "point_cloud2_display.h" namespace rviz { PointCloud2Display::PointCloud2Display() : point_cloud_common_( new PointCloudCommon( this )) { queue_size_property_ = new IntProperty( "Queue Size", 10, "Advanced: set the size of the incoming PointCloud2 message queue. " " Increasing this is useful if your incoming TF data is delayed significantly " "from your PointCloud2 data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. update_nh_.setCallbackQueue( point_cloud_common_->getCallbackQueue() ); } PointCloud2Display::~PointCloud2Display() { delete point_cloud_common_; } void PointCloud2Display::onInitialize() { MFDClass::onInitialize(); point_cloud_common_->initialize( context_, scene_node_ ); } void PointCloud2Display::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void PointCloud2Display::processMessage( const sensor_msgs::PointCloud2ConstPtr& cloud ) { // Filter any nan values out of the cloud. Any nan values that make it through to PointCloudBase // will get their points put off in lala land, but it means they still do get processed/rendered // which can be a big performance hit sensor_msgs::PointCloud2Ptr filtered(new sensor_msgs::PointCloud2); int32_t xi = findChannelIndex(cloud, "x"); int32_t yi = findChannelIndex(cloud, "y"); int32_t zi = findChannelIndex(cloud, "z"); if (xi == -1 || yi == -1 || zi == -1) { return; } const uint32_t xoff = cloud->fields[xi].offset; const uint32_t yoff = cloud->fields[yi].offset; const uint32_t zoff = cloud->fields[zi].offset; const uint32_t point_step = cloud->point_step; const size_t point_count = cloud->width * cloud->height; if( point_count * point_step != cloud->data.size() ) { std::stringstream ss; ss << "Data size (" << cloud->data.size() << " bytes) does not match width (" << cloud->width << ") times height (" << cloud->height << ") times point_step (" << point_step << "). Dropping message."; setStatusStd( StatusProperty::Error, "Message", ss.str() ); return; } filtered->data.resize(cloud->data.size()); if (point_count == 0) { return; } uint8_t* output_ptr = &filtered->data.front(); const uint8_t* ptr = &cloud->data.front(), *ptr_end = &cloud->data.back(), *ptr_init; size_t points_to_copy = 0; for (; ptr < ptr_end; ptr += point_step) { float x = *reinterpret_cast(ptr + xoff); float y = *reinterpret_cast(ptr + yoff); float z = *reinterpret_cast(ptr + zoff); if (validateFloats(x) && validateFloats(y) && validateFloats(z)) { if (points_to_copy == 0) { // Only memorize where to start copying from ptr_init = ptr; points_to_copy = 1; } else { ++points_to_copy; } } else { if (points_to_copy) { // Copy all the points that need to be copied memcpy(output_ptr, ptr_init, point_step*points_to_copy); output_ptr += point_step*points_to_copy; points_to_copy = 0; } } } // Don't forget to flush what needs to be copied if (points_to_copy) { memcpy(output_ptr, ptr_init, point_step*points_to_copy); output_ptr += point_step*points_to_copy; } uint32_t output_count = (output_ptr - &filtered->data.front()) / point_step; filtered->header = cloud->header; filtered->fields = cloud->fields; filtered->data.resize(output_count * point_step); filtered->height = 1; filtered->width = output_count; filtered->is_bigendian = cloud->is_bigendian; filtered->point_step = point_step; filtered->row_step = output_count; point_cloud_common_->addMessage( filtered ); } void PointCloud2Display::update( float wall_dt, float ros_dt ) { point_cloud_common_->update( wall_dt, ros_dt ); } void PointCloud2Display::reset() { MFDClass::reset(); point_cloud_common_->reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::PointCloud2Display, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/point_cloud2_display.h000066400000000000000000000054271300447110700236600ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POINT_CLOUD2_DISPLAY_H #define RVIZ_POINT_CLOUD2_DISPLAY_H #include #include "rviz/message_filter_display.h" namespace rviz { class IntProperty; class PointCloudCommon; /** * \class PointCloud2Display * \brief Displays a point cloud of type sensor_msgs::PointCloud2 * * By default it will assume channel 0 of the cloud is an intensity value, and will color them by intensity. * If you set the channel's name to "rgb", it will interpret the channel as an integer rgb value, with r, g and b * all being 8 bits. */ class PointCloud2Display: public MessageFilterDisplay { Q_OBJECT public: PointCloud2Display(); ~PointCloud2Display(); virtual void reset(); virtual void update( float wall_dt, float ros_dt ); private Q_SLOTS: void updateQueueSize(); protected: /** @brief Do initialization. Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Process a single message. Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::PointCloud2ConstPtr& cloud ); IntProperty* queue_size_property_; PointCloudCommon* point_cloud_common_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/point_cloud_common.cpp000066400000000000000000000756361300447110700237650ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "rviz/default_plugin/point_cloud_transformer.h" #include "rviz/default_plugin/point_cloud_transformers.h" #include "rviz/display.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/bool_property.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/vector_property.h" #include "rviz/uniform_string_stream.h" #include "rviz/validate_floats.h" #include "rviz/default_plugin/point_cloud_common.h" namespace rviz { struct IndexAndMessage { IndexAndMessage( int _index, const void* _message ) : index( _index ) , message( (uint64_t) _message ) {} int index; uint64_t message; }; uint qHash( IndexAndMessage iam ) { return ((uint) iam.index) + ((uint) (iam.message >> 32)) + ((uint) (iam.message & 0xffffffff)); } bool operator==( IndexAndMessage a, IndexAndMessage b ) { return a.index == b.index && a.message == b.message; } PointCloudSelectionHandler::PointCloudSelectionHandler( float box_size, PointCloudCommon::CloudInfo *cloud_info, DisplayContext* context ) : SelectionHandler( context ) , cloud_info_( cloud_info ) , box_size_(box_size) { } PointCloudSelectionHandler::~PointCloudSelectionHandler() { // delete all the Property objects on our way out. QHash::const_iterator iter; for( iter = property_hash_.begin(); iter != property_hash_.end(); iter++ ) { delete iter.value(); } } void PointCloudSelectionHandler::preRenderPass(uint32_t pass) { SelectionHandler::preRenderPass(pass); switch( pass ) { case 0: cloud_info_->cloud_->setPickColor( SelectionManager::handleToColor( getHandle() )); break; case 1: cloud_info_->cloud_->setColorByIndex(true); break; default: break; } } void PointCloudSelectionHandler::postRenderPass(uint32_t pass) { SelectionHandler::postRenderPass(pass); if (pass == 1) { cloud_info_->cloud_->setColorByIndex(false); } } Ogre::Vector3 pointFromCloud(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t index) { int32_t xi = findChannelIndex(cloud, "x"); int32_t yi = findChannelIndex(cloud, "y"); int32_t zi = findChannelIndex(cloud, "z"); const uint32_t xoff = cloud->fields[xi].offset; const uint32_t yoff = cloud->fields[yi].offset; const uint32_t zoff = cloud->fields[zi].offset; const uint8_t type = cloud->fields[xi].datatype; const uint32_t point_step = cloud->point_step; float x = valueFromCloud(cloud, xoff, type, point_step, index); float y = valueFromCloud(cloud, yoff, type, point_step, index); float z = valueFromCloud(cloud, zoff, type, point_step, index); return Ogre::Vector3(x, y, z); } void PointCloudSelectionHandler::createProperties( const Picked& obj, Property* parent_property ) { typedef std::set S_int; S_int indices; { S_uint64::const_iterator it = obj.extra_handles.begin(); S_uint64::const_iterator end = obj.extra_handles.end(); for (; it != end; ++it) { uint64_t handle = *it; indices.insert((handle & 0xffffffff) - 1); } } { S_int::iterator it = indices.begin(); S_int::iterator end = indices.end(); for (; it != end; ++it) { int index = *it; const sensor_msgs::PointCloud2ConstPtr& message = cloud_info_->message_; IndexAndMessage hash_key( index, message.get() ); if( !property_hash_.contains( hash_key )) { Property* cat = new Property( QString( "Point %1 [cloud 0x%2]" ).arg( index ).arg( (uint64_t) message.get() ), QVariant(), "", parent_property ); property_hash_.insert( hash_key, cat ); // First add the position. VectorProperty* pos_prop = new VectorProperty( "Position", cloud_info_->transformed_points_[index].position, "", cat ); pos_prop->setReadOnly( true ); // Then add all other fields as well. for( size_t field = 0; field < message->fields.size(); ++field ) { const sensor_msgs::PointField& f = message->fields[ field ]; const std::string& name = f.name; if( name == "x" || name == "y" || name == "z" || name == "X" || name == "Y" || name == "Z" ) { continue; } if( name == "rgb" || name == "rgba") { float float_val = valueFromCloud( message, f.offset, f.datatype, message->point_step, index ); // Convertion hack because rgb are stored int float (datatype=7) and valueFromCloud can't cast float to uint32_t uint32_t val = *((uint32_t*) &float_val); ColorProperty* prop = new ColorProperty( QString( "%1: %2" ).arg( field ).arg( QString::fromStdString( name )), QColor( (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff), "", cat ); prop->setReadOnly( true ); FloatProperty* aprop = new FloatProperty( QString( "alpha" ), ((val >> 24) / 255.0), "", cat ); aprop->setReadOnly( true ); } else { float val = valueFromCloud( message, f.offset, f.datatype, message->point_step, index ); FloatProperty* prop = new FloatProperty( QString( "%1: %2" ).arg( field ).arg( QString::fromStdString( name )), val, "", cat ); prop->setReadOnly( true ); } } } } } } void PointCloudSelectionHandler::destroyProperties( const Picked& obj, Property* parent_property ) { typedef std::set S_int; S_int indices; { S_uint64::const_iterator it = obj.extra_handles.begin(); S_uint64::const_iterator end = obj.extra_handles.end(); for (; it != end; ++it) { uint64_t handle = *it; indices.insert((handle & 0xffffffff) - 1); } } { S_int::iterator it = indices.begin(); S_int::iterator end = indices.end(); for (; it != end; ++it) { int index = *it; const sensor_msgs::PointCloud2ConstPtr& message = cloud_info_->message_; IndexAndMessage hash_key( index, message.get() ); Property* prop = property_hash_.take( hash_key ); delete prop; } } } void PointCloudSelectionHandler::getAABBs(const Picked& obj, V_AABB& aabbs) { S_uint64::iterator it = obj.extra_handles.begin(); S_uint64::iterator end = obj.extra_handles.end(); for (; it != end; ++it) { M_HandleToBox::iterator find_it = boxes_.find(std::make_pair(obj.handle, *it - 1)); if (find_it != boxes_.end()) { Ogre::WireBoundingBox* box = find_it->second.second; aabbs.push_back(box->getWorldBoundingBox()); } } } void PointCloudSelectionHandler::onSelect(const Picked& obj) { S_uint64::iterator it = obj.extra_handles.begin(); S_uint64::iterator end = obj.extra_handles.end(); for (; it != end; ++it) { int index = (*it & 0xffffffff) - 1; sensor_msgs::PointCloud2ConstPtr message = cloud_info_->message_; Ogre::Vector3 pos = cloud_info_->transformed_points_[index].position; pos = cloud_info_->scene_node_->convertLocalToWorldPosition( pos ); float size = box_size_ * 0.5f; Ogre::AxisAlignedBox aabb(pos - size, pos + size); createBox(std::make_pair(obj.handle, index), aabb, "RVIZ/Cyan" ); } } void PointCloudSelectionHandler::onDeselect(const Picked& obj) { S_uint64::iterator it = obj.extra_handles.begin(); S_uint64::iterator end = obj.extra_handles.end(); for (; it != end; ++it) { int global_index = (*it & 0xffffffff) - 1; destroyBox(std::make_pair(obj.handle, global_index)); } } PointCloudCommon::CloudInfo::CloudInfo() : manager_(0) , scene_node_(0) {} PointCloudCommon::CloudInfo::~CloudInfo() { clear(); } void PointCloudCommon::CloudInfo::clear() { if ( scene_node_ ) { manager_->destroySceneNode( scene_node_ ); scene_node_=0; } } PointCloudCommon::PointCloudCommon( Display* display ) : spinner_(1, &cbqueue_) , new_xyz_transformer_(false) , new_color_transformer_(false) , needs_retransform_(false) , transformer_class_loader_(NULL) , display_( display ) , auto_size_(false) { selectable_property_ = new BoolProperty( "Selectable", true, "Whether or not the points in this point cloud are selectable.", display_, SLOT( updateSelectable() ), this ); style_property_ = new EnumProperty( "Style", "Flat Squares", "Rendering mode to use, in order of computational complexity.", display_, SLOT( updateStyle() ), this ); style_property_->addOption( "Points", PointCloud::RM_POINTS ); style_property_->addOption( "Squares", PointCloud::RM_SQUARES ); style_property_->addOption( "Flat Squares", PointCloud::RM_FLAT_SQUARES ); style_property_->addOption( "Spheres", PointCloud::RM_SPHERES ); style_property_->addOption( "Boxes", PointCloud::RM_BOXES ); point_world_size_property_ = new FloatProperty( "Size (m)", 0.01, "Point size in meters.", display_, SLOT( updateBillboardSize() ), this ); point_world_size_property_->setMin( 0.0001 ); point_pixel_size_property_ = new FloatProperty( "Size (Pixels)", 3, "Point size in pixels.", display_, SLOT( updateBillboardSize() ), this ); point_pixel_size_property_->setMin( 1 ); alpha_property_ = new FloatProperty( "Alpha", 1.0, "Amount of transparency to apply to the points. Note that this is experimental and does not always look correct.", display_, SLOT( updateAlpha() ), this ); alpha_property_->setMin( 0 ); alpha_property_->setMax( 1 ); decay_time_property_ = new FloatProperty( "Decay Time", 0, "Duration, in seconds, to keep the incoming points. 0 means only show the latest points.", display_, SLOT( queueRender() )); decay_time_property_->setMin( 0 ); xyz_transformer_property_ = new EnumProperty( "Position Transformer", "", "Set the transformer to use to set the position of the points.", display_, SLOT( updateXyzTransformer() ), this ); connect( xyz_transformer_property_, SIGNAL( requestOptions( EnumProperty* )), this, SLOT( setXyzTransformerOptions( EnumProperty* ))); color_transformer_property_ = new EnumProperty( "Color Transformer", "", "Set the transformer to use to set the color of the points.", display_, SLOT( updateColorTransformer() ), this ); connect( color_transformer_property_, SIGNAL( requestOptions( EnumProperty* )), this, SLOT( setColorTransformerOptions( EnumProperty* ))); } void PointCloudCommon::initialize( DisplayContext* context, Ogre::SceneNode* scene_node ) { transformer_class_loader_ = new pluginlib::ClassLoader( "rviz", "rviz::PointCloudTransformer" ); loadTransformers(); context_ = context; scene_node_ = scene_node; updateStyle(); updateBillboardSize(); updateAlpha(); updateSelectable(); spinner_.start(); } PointCloudCommon::~PointCloudCommon() { spinner_.stop(); if ( transformer_class_loader_ ) { delete transformer_class_loader_; } } void PointCloudCommon::loadTransformers() { std::vector classes = transformer_class_loader_->getDeclaredClasses(); std::vector::iterator ci; for( ci = classes.begin(); ci != classes.end(); ci++ ) { const std::string& lookup_name = *ci; std::string name = transformer_class_loader_->getName( lookup_name ); if( transformers_.count( name ) > 0 ) { ROS_ERROR( "Transformer type [%s] is already loaded.", name.c_str() ); continue; } PointCloudTransformerPtr trans( transformer_class_loader_->createUnmanagedInstance( lookup_name )); trans->init(); connect( trans.get(), SIGNAL( needRetransform() ), this, SLOT( causeRetransform() )); TransformerInfo info; info.transformer = trans; info.readable_name = name; info.lookup_name = lookup_name; info.transformer->createProperties( display_, PointCloudTransformer::Support_XYZ, info.xyz_props ); setPropertiesHidden( info.xyz_props, true ); info.transformer->createProperties( display_, PointCloudTransformer::Support_Color, info.color_props ); setPropertiesHidden( info.color_props, true ); transformers_[ name ] = info; } } void PointCloudCommon::setAutoSize( bool auto_size ) { auto_size_ = auto_size; for ( unsigned i=0; icloud_->setAutoSize( auto_size ); } } void PointCloudCommon::updateAlpha() { for ( unsigned i=0; imessage_, "rgba") != -1; cloud_infos_[i]->cloud_->setAlpha( alpha_property_->getFloat(), per_point_alpha ); } } void PointCloudCommon::updateSelectable() { bool selectable = selectable_property_->getBool(); if( selectable ) { for ( unsigned i=0; iselection_handler_.reset( new PointCloudSelectionHandler( getSelectionBoxSize(), cloud_infos_[i].get(), context_ )); cloud_infos_[i]->cloud_->setPickColor( SelectionManager::handleToColor( cloud_infos_[i]->selection_handler_->getHandle() )); } } else { for ( unsigned i=0; iselection_handler_.reset( ); cloud_infos_[i]->cloud_->setPickColor( Ogre::ColourValue( 0.0f, 0.0f, 0.0f, 0.0f ) ); } } } void PointCloudCommon::updateStyle() { PointCloud::RenderMode mode = (PointCloud::RenderMode) style_property_->getOptionInt(); if( mode == PointCloud::RM_POINTS ) { point_world_size_property_->hide(); point_pixel_size_property_->show(); } else { point_world_size_property_->show(); point_pixel_size_property_->hide(); } for( unsigned int i = 0; i < cloud_infos_.size(); i++ ) { cloud_infos_[i]->cloud_->setRenderMode( mode ); } updateBillboardSize(); } void PointCloudCommon::updateBillboardSize() { PointCloud::RenderMode mode = (PointCloud::RenderMode) style_property_->getOptionInt(); float size; if( mode == PointCloud::RM_POINTS ) { size = point_pixel_size_property_->getFloat(); } else { size = point_world_size_property_->getFloat(); } for ( unsigned i=0; icloud_->setDimensions( size, size, size ); cloud_infos_[i]->selection_handler_->setBoxSize( getSelectionBoxSize() ); } context_->queueRender(); } void PointCloudCommon::reset() { boost::mutex::scoped_lock lock(new_clouds_mutex_); cloud_infos_.clear(); new_cloud_infos_.clear(); } void PointCloudCommon::causeRetransform() { needs_retransform_ = true; } void PointCloudCommon::update(float wall_dt, float ros_dt) { PointCloud::RenderMode mode = (PointCloud::RenderMode) style_property_->getOptionInt(); float point_decay_time = decay_time_property_->getFloat(); if (needs_retransform_) { retransform(); needs_retransform_ = false; } // instead of deleting cloud infos, we just clear them // and put them into obsolete_cloud_infos, so active selections // are preserved ros::Time now = ros::Time::now(); // if decay time == 0, clear the old cloud when we get a new one // otherwise, clear all the outdated ones { boost::mutex::scoped_lock lock(new_clouds_mutex_); if ( point_decay_time > 0.0 || !new_cloud_infos_.empty() ) { while( !cloud_infos_.empty() && now.toSec() - cloud_infos_.front()->receive_time_.toSec() > point_decay_time ) { cloud_infos_.front()->clear(); obsolete_cloud_infos_.push_back( cloud_infos_.front() ); cloud_infos_.pop_front(); context_->queueRender(); } } } // garbage-collect old point clouds that don't have an active selection L_CloudInfo::iterator it = obsolete_cloud_infos_.begin(); L_CloudInfo::iterator end = obsolete_cloud_infos_.end(); for (; it != end; ++it) { if ( !(*it)->selection_handler_.get() || !(*it)->selection_handler_->hasSelections() ) { it = obsolete_cloud_infos_.erase(it); } } { boost::mutex::scoped_lock lock(new_clouds_mutex_); if( !new_cloud_infos_.empty() ) { float size; if( mode == PointCloud::RM_POINTS ) { size = point_pixel_size_property_->getFloat(); } else { size = point_world_size_property_->getFloat(); } V_CloudInfo::iterator it = new_cloud_infos_.begin(); V_CloudInfo::iterator end = new_cloud_infos_.end(); for (; it != end; ++it) { CloudInfoPtr cloud_info = *it; V_CloudInfo::iterator next = it; next++; // ignore point clouds that are too old, but keep at least one if ( next != end && now.toSec() - cloud_info->receive_time_.toSec() > point_decay_time ) { continue; } bool per_point_alpha = findChannelIndex(cloud_info->message_, "rgba") != -1; cloud_info->cloud_.reset( new PointCloud() ); cloud_info->cloud_->addPoints( &(cloud_info->transformed_points_.front()), cloud_info->transformed_points_.size() ); cloud_info->cloud_->setRenderMode( mode ); cloud_info->cloud_->setAlpha( alpha_property_->getFloat(), per_point_alpha); cloud_info->cloud_->setDimensions( size, size, size ); cloud_info->cloud_->setAutoSize(auto_size_); cloud_info->manager_ = context_->getSceneManager(); cloud_info->scene_node_ = scene_node_->createChildSceneNode( cloud_info->position_, cloud_info->orientation_ ); cloud_info->scene_node_->attachObject( cloud_info->cloud_.get() ); cloud_info->selection_handler_.reset( new PointCloudSelectionHandler( getSelectionBoxSize(), cloud_info.get(), context_ )); cloud_infos_.push_back(*it); } new_cloud_infos_.clear(); } } { boost::recursive_mutex::scoped_try_lock lock( transformers_mutex_ ); if( lock.owns_lock() ) { if( new_xyz_transformer_ || new_color_transformer_ ) { M_TransformerInfo::iterator it = transformers_.begin(); M_TransformerInfo::iterator end = transformers_.end(); for (; it != end; ++it) { const std::string& name = it->first; TransformerInfo& info = it->second; setPropertiesHidden( info.xyz_props, name != xyz_transformer_property_->getStdString() ); setPropertiesHidden( info.color_props, name != color_transformer_property_->getStdString() ); } } } new_xyz_transformer_ = false; new_color_transformer_ = false; } updateStatus(); } void PointCloudCommon::setPropertiesHidden( const QList& props, bool hide ) { for( int i = 0; i < props.size(); i++ ) { props[ i ]->setHidden( hide ); } } void PointCloudCommon::updateTransformers( const sensor_msgs::PointCloud2ConstPtr& cloud ) { std::string xyz_name = xyz_transformer_property_->getStdString(); std::string color_name = color_transformer_property_->getStdString(); xyz_transformer_property_->clearOptions(); color_transformer_property_->clearOptions(); // Get the channels that we could potentially render typedef std::set > S_string; S_string valid_xyz, valid_color; bool cur_xyz_valid = false; bool cur_color_valid = false; bool has_rgb_transformer = false; M_TransformerInfo::iterator trans_it = transformers_.begin(); M_TransformerInfo::iterator trans_end = transformers_.end(); for(;trans_it != trans_end; ++trans_it) { const std::string& name = trans_it->first; const PointCloudTransformerPtr& trans = trans_it->second.transformer; uint32_t mask = trans->supports(cloud); if (mask & PointCloudTransformer::Support_XYZ) { valid_xyz.insert(std::make_pair(trans->score(cloud), name)); if (name == xyz_name) { cur_xyz_valid = true; } xyz_transformer_property_->addOptionStd( name ); } if (mask & PointCloudTransformer::Support_Color) { valid_color.insert(std::make_pair(trans->score(cloud), name)); if (name == color_name) { cur_color_valid = true; } if (name == "RGB8") { has_rgb_transformer = true; } color_transformer_property_->addOptionStd( name ); } } if( !cur_xyz_valid ) { if( !valid_xyz.empty() ) { xyz_transformer_property_->setStringStd( valid_xyz.rbegin()->second ); } } if( !cur_color_valid ) { if( !valid_color.empty() ) { if (has_rgb_transformer) { color_transformer_property_->setStringStd( "RGB8" ); } else { color_transformer_property_->setStringStd( valid_color.rbegin()->second ); } } } } void PointCloudCommon::updateStatus() { std::stringstream ss; //ss << "Showing [" << total_point_count_ << "] points from [" << clouds_.size() << "] messages"; display_->setStatusStd(StatusProperty::Ok, "Points", ss.str()); } void PointCloudCommon::processMessage(const sensor_msgs::PointCloud2ConstPtr& cloud) { CloudInfoPtr info(new CloudInfo); info->message_ = cloud; info->receive_time_ = ros::Time::now(); if (transformCloud(info, true)) { boost::mutex::scoped_lock lock(new_clouds_mutex_); new_cloud_infos_.push_back(info); display_->emitTimeSignal( cloud->header.stamp ); } } void PointCloudCommon::updateXyzTransformer() { boost::recursive_mutex::scoped_lock lock( transformers_mutex_ ); if( transformers_.count( xyz_transformer_property_->getStdString() ) == 0 ) { return; } new_xyz_transformer_ = true; causeRetransform(); } void PointCloudCommon::updateColorTransformer() { boost::recursive_mutex::scoped_lock lock( transformers_mutex_ ); if( transformers_.count( color_transformer_property_->getStdString() ) == 0 ) { return; } new_color_transformer_ = true; causeRetransform(); } PointCloudTransformerPtr PointCloudCommon::getXYZTransformer( const sensor_msgs::PointCloud2ConstPtr& cloud ) { boost::recursive_mutex::scoped_lock lock( transformers_mutex_); M_TransformerInfo::iterator it = transformers_.find( xyz_transformer_property_->getStdString() ); if( it != transformers_.end() ) { const PointCloudTransformerPtr& trans = it->second.transformer; if( trans->supports( cloud ) & PointCloudTransformer::Support_XYZ ) { return trans; } } return PointCloudTransformerPtr(); } PointCloudTransformerPtr PointCloudCommon::getColorTransformer( const sensor_msgs::PointCloud2ConstPtr& cloud ) { boost::recursive_mutex::scoped_lock lock( transformers_mutex_ ); M_TransformerInfo::iterator it = transformers_.find( color_transformer_property_->getStdString() ); if( it != transformers_.end() ) { const PointCloudTransformerPtr& trans = it->second.transformer; if( trans->supports( cloud ) & PointCloudTransformer::Support_Color ) { return trans; } } return PointCloudTransformerPtr(); } void PointCloudCommon::retransform() { boost::recursive_mutex::scoped_lock lock(transformers_mutex_); D_CloudInfo::iterator it = cloud_infos_.begin(); D_CloudInfo::iterator end = cloud_infos_.end(); for (; it != end; ++it) { const CloudInfoPtr& cloud_info = *it; transformCloud(cloud_info, false); cloud_info->cloud_->clear(); cloud_info->cloud_->addPoints(&cloud_info->transformed_points_.front(), cloud_info->transformed_points_.size()); } } bool PointCloudCommon::transformCloud(const CloudInfoPtr& cloud_info, bool update_transformers) { if ( !cloud_info->scene_node_ ) { if (!context_->getFrameManager()->getTransform(cloud_info->message_->header, cloud_info->position_, cloud_info->orientation_)) { std::stringstream ss; ss << "Failed to transform from frame [" << cloud_info->message_->header.frame_id << "] to frame [" << context_->getFrameManager()->getFixedFrame() << "]"; display_->setStatusStd(StatusProperty::Error, "Message", ss.str()); return false; } } Ogre::Matrix4 transform; transform.makeTransform( cloud_info->position_, Ogre::Vector3(1,1,1), cloud_info->orientation_ ); V_PointCloudPoint& cloud_points = cloud_info->transformed_points_; cloud_points.clear(); size_t size = cloud_info->message_->width * cloud_info->message_->height; PointCloud::Point default_pt; default_pt.color = Ogre::ColourValue(1, 1, 1); default_pt.position = Ogre::Vector3::ZERO; cloud_points.resize(size, default_pt); { boost::recursive_mutex::scoped_lock lock(transformers_mutex_); if( update_transformers ) { updateTransformers( cloud_info->message_ ); } PointCloudTransformerPtr xyz_trans = getXYZTransformer(cloud_info->message_); PointCloudTransformerPtr color_trans = getColorTransformer(cloud_info->message_); if (!xyz_trans) { std::stringstream ss; ss << "No position transformer available for cloud"; display_->setStatusStd(StatusProperty::Error, "Message", ss.str()); return false; } if (!color_trans) { std::stringstream ss; ss << "No color transformer available for cloud"; display_->setStatusStd(StatusProperty::Error, "Message", ss.str()); return false; } xyz_trans->transform(cloud_info->message_, PointCloudTransformer::Support_XYZ, transform, cloud_points); color_trans->transform(cloud_info->message_, PointCloudTransformer::Support_Color, transform, cloud_points); } for (V_PointCloudPoint::iterator cloud_point = cloud_points.begin(); cloud_point != cloud_points.end(); ++cloud_point) { if (!validateFloats(cloud_point->position)) { cloud_point->position.x = 999999.0f; cloud_point->position.y = 999999.0f; cloud_point->position.z = 999999.0f; } } return true; } bool convertPointCloudToPointCloud2(const sensor_msgs::PointCloud& input, sensor_msgs::PointCloud2& output) { output.header = input.header; output.width = input.points.size (); output.height = 1; output.fields.resize (3 + input.channels.size ()); // Convert x/y/z to fields output.fields[0].name = "x"; output.fields[1].name = "y"; output.fields[2].name = "z"; int offset = 0; // All offsets are *4, as all field data types are float32 for (size_t d = 0; d < output.fields.size (); ++d, offset += 4) { output.fields[d].offset = offset; output.fields[d].datatype = sensor_msgs::PointField::FLOAT32; } output.point_step = offset; output.row_step = output.point_step * output.width; // Convert the remaining of the channels to fields for (size_t d = 0; d < input.channels.size (); ++d) output.fields[3 + d].name = input.channels[d].name; output.data.resize (input.points.size () * output.point_step); output.is_bigendian = false; // @todo ? output.is_dense = false; // Copy the data points for (size_t cp = 0; cp < input.points.size (); ++cp) { memcpy (&output.data[cp * output.point_step + output.fields[0].offset], &input.points[cp].x, sizeof (float)); memcpy (&output.data[cp * output.point_step + output.fields[1].offset], &input.points[cp].y, sizeof (float)); memcpy (&output.data[cp * output.point_step + output.fields[2].offset], &input.points[cp].z, sizeof (float)); for (size_t d = 0; d < input.channels.size (); ++d) { if (input.channels[d].values.size() == input.points.size()) { memcpy (&output.data[cp * output.point_step + output.fields[3 + d].offset], &input.channels[d].values[cp], sizeof (float)); } } } return (true); } void PointCloudCommon::addMessage(const sensor_msgs::PointCloudConstPtr& cloud) { sensor_msgs::PointCloud2Ptr out(new sensor_msgs::PointCloud2); convertPointCloudToPointCloud2(*cloud, *out); addMessage(out); } void PointCloudCommon::addMessage(const sensor_msgs::PointCloud2ConstPtr& cloud) { processMessage(cloud); } void PointCloudCommon::fixedFrameChanged() { reset(); } void PointCloudCommon::setXyzTransformerOptions( EnumProperty* prop ) { fillTransformerOptions( prop, PointCloudTransformer::Support_XYZ ); } void PointCloudCommon::setColorTransformerOptions( EnumProperty* prop ) { fillTransformerOptions( prop, PointCloudTransformer::Support_Color ); } void PointCloudCommon::fillTransformerOptions( EnumProperty* prop, uint32_t mask ) { prop->clearOptions(); if (cloud_infos_.empty()) { return; } boost::recursive_mutex::scoped_lock tlock(transformers_mutex_); const sensor_msgs::PointCloud2ConstPtr& msg = cloud_infos_.front()->message_; M_TransformerInfo::iterator it = transformers_.begin(); M_TransformerInfo::iterator end = transformers_.end(); for (; it != end; ++it) { const PointCloudTransformerPtr& trans = it->second.transformer; if ((trans->supports(msg) & mask) == mask) { prop->addOption( QString::fromStdString( it->first )); } } } float PointCloudCommon::getSelectionBoxSize() { if( style_property_->getOptionInt() != PointCloud::RM_POINTS ) { return point_world_size_property_->getFloat(); } else { return 0.004; } } } // namespace rviz rviz-1.12.4/src/rviz/default_plugin/point_cloud_common.h000066400000000000000000000173751300447110700234260ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POINT_CLOUD_COMMON_H #define RVIZ_POINT_CLOUD_COMMON_H #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include "rviz/selection/selection_manager.h" # include "rviz/default_plugin/point_cloud_transformer.h" # include "rviz/properties/color_property.h" # include "rviz/ogre_helpers/point_cloud.h" # include "rviz/selection/forwards.h" #endif namespace rviz { class BoolProperty; class Display; class DisplayContext; class EnumProperty; class FloatProperty; struct IndexAndMessage; class PointCloudSelectionHandler; typedef boost::shared_ptr PointCloudSelectionHandlerPtr; class PointCloudTransformer; typedef boost::shared_ptr PointCloudTransformerPtr; typedef std::vector V_string; /** * \class PointCloudCommon * \brief Displays a point cloud of type sensor_msgs::PointCloud * * By default it will assume channel 0 of the cloud is an intensity value, and will color them by intensity. * If you set the channel's name to "rgb", it will interpret the channel as an integer rgb value, with r, g and b * all being 8 bits. */ class PointCloudCommon: public QObject { Q_OBJECT public: struct CloudInfo { CloudInfo(); ~CloudInfo(); // clear the point cloud, but keep selection handler around void clear(); ros::Time receive_time_; Ogre::SceneManager *manager_; sensor_msgs::PointCloud2ConstPtr message_; Ogre::SceneNode *scene_node_; boost::shared_ptr cloud_; PointCloudSelectionHandlerPtr selection_handler_; std::vector transformed_points_; Ogre::Quaternion orientation_; Ogre::Vector3 position_; }; typedef boost::shared_ptr CloudInfoPtr; typedef std::deque D_CloudInfo; typedef std::vector V_CloudInfo; typedef std::queue Q_CloudInfo; typedef std::list L_CloudInfo; PointCloudCommon( Display* display ); ~PointCloudCommon(); void initialize( DisplayContext* context, Ogre::SceneNode* scene_node ); void fixedFrameChanged(); void reset(); void update(float wall_dt, float ros_dt); void addMessage(const sensor_msgs::PointCloudConstPtr& cloud); void addMessage(const sensor_msgs::PointCloud2ConstPtr& cloud); ros::CallbackQueueInterface* getCallbackQueue() { return &cbqueue_; } Display* getDisplay() { return display_; } bool auto_size_; BoolProperty* selectable_property_; FloatProperty* point_world_size_property_; FloatProperty* point_pixel_size_property_; FloatProperty* alpha_property_; EnumProperty* xyz_transformer_property_; EnumProperty* color_transformer_property_; EnumProperty* style_property_; FloatProperty* decay_time_property_; void setAutoSize( bool auto_size ); public Q_SLOTS: void causeRetransform(); private Q_SLOTS: void updateSelectable(); void updateStyle(); void updateBillboardSize(); void updateAlpha(); void updateXyzTransformer(); void updateColorTransformer(); void setXyzTransformerOptions( EnumProperty* prop ); void setColorTransformerOptions( EnumProperty* prop ); private: /** * \brief Transforms the cloud into the correct frame, and sets up our renderable cloud */ bool transformCloud(const CloudInfoPtr& cloud, bool fully_update_transformers); void processMessage(const sensor_msgs::PointCloud2ConstPtr& cloud); void updateStatus(); PointCloudTransformerPtr getXYZTransformer(const sensor_msgs::PointCloud2ConstPtr& cloud); PointCloudTransformerPtr getColorTransformer(const sensor_msgs::PointCloud2ConstPtr& cloud); void updateTransformers( const sensor_msgs::PointCloud2ConstPtr& cloud ); void retransform(); void onTransformerOptions(V_string& ops, uint32_t mask); void loadTransformers(); float getSelectionBoxSize(); void setPropertiesHidden( const QList& props, bool hide ); void fillTransformerOptions( EnumProperty* prop, uint32_t mask ); ros::AsyncSpinner spinner_; ros::CallbackQueue cbqueue_; D_CloudInfo cloud_infos_; Ogre::SceneNode* scene_node_; V_CloudInfo new_cloud_infos_; boost::mutex new_clouds_mutex_; L_CloudInfo obsolete_cloud_infos_; struct TransformerInfo { PointCloudTransformerPtr transformer; QList xyz_props; QList color_props; std::string readable_name; std::string lookup_name; }; typedef std::map M_TransformerInfo; boost::recursive_mutex transformers_mutex_; M_TransformerInfo transformers_; bool new_xyz_transformer_; bool new_color_transformer_; bool needs_retransform_; pluginlib::ClassLoader* transformer_class_loader_; Display* display_; DisplayContext* context_; friend class PointCloudSelectionHandler; }; class PointCloudSelectionHandler: public SelectionHandler { public: PointCloudSelectionHandler( float box_size, PointCloudCommon::CloudInfo* cloud_info, DisplayContext* context ); virtual ~PointCloudSelectionHandler(); virtual void createProperties( const Picked& obj, Property* parent_property ); virtual void destroyProperties( const Picked& obj, Property* parent_property ); virtual bool needsAdditionalRenderPass(uint32_t pass) { if (pass < 2) { return true; } return false; } virtual void preRenderPass(uint32_t pass); virtual void postRenderPass(uint32_t pass); virtual void onSelect(const Picked& obj); virtual void onDeselect(const Picked& obj); virtual void getAABBs(const Picked& obj, V_AABB& aabbs); void setBoxSize( float size ) { box_size_=size; } bool hasSelections() { return !boxes_.empty(); } private: PointCloudCommon::CloudInfo* cloud_info_; QHash property_hash_; float box_size_; }; } // namespace rviz #endif // RVIZ_POINT_CLOUD_COMMON_H rviz-1.12.4/src/rviz/default_plugin/point_cloud_display.cpp000066400000000000000000000070071300447110700241250ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/default_plugin/point_cloud_common.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/int_property.h" #include "point_cloud_display.h" namespace rviz { PointCloudDisplay::PointCloudDisplay() : point_cloud_common_( new PointCloudCommon( this )) { queue_size_property_ = new IntProperty( "Queue Size", 10, "Advanced: set the size of the incoming PointCloud message queue. " " Increasing this is useful if your incoming TF data is delayed significantly " "from your PointCloud data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. update_nh_.setCallbackQueue( point_cloud_common_->getCallbackQueue() ); } PointCloudDisplay::~PointCloudDisplay() { delete point_cloud_common_; } void PointCloudDisplay::onInitialize() { MFDClass::onInitialize(); point_cloud_common_->initialize( context_, scene_node_ ); } void PointCloudDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void PointCloudDisplay::processMessage( const sensor_msgs::PointCloudConstPtr& cloud ) { point_cloud_common_->addMessage( cloud ); } void PointCloudDisplay::update( float wall_dt, float ros_dt ) { point_cloud_common_->update( wall_dt, ros_dt ); } void PointCloudDisplay::reset() { MFDClass::reset(); point_cloud_common_->reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::PointCloudDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/point_cloud_display.h000066400000000000000000000055021300447110700235700ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POINT_CLOUD_DISPLAY_H #define RVIZ_POINT_CLOUD_DISPLAY_H #include #include #include #include #include "rviz/message_filter_display.h" namespace rviz { class IntProperty; class PointCloudCommon; /** * \class PointCloudDisplay * \brief Displays a point cloud of type sensor_msgs::PointCloud * * By default it will assume channel 0 of the cloud is an intensity value, and will color them by intensity. * If you set the channel's name to "rgb", it will interpret the channel as an integer rgb value, with r, g and b * all being 8 bits. */ class PointCloudDisplay: public MessageFilterDisplay { Q_OBJECT public: PointCloudDisplay(); ~PointCloudDisplay(); virtual void reset(); virtual void update( float wall_dt, float ros_dt ); private Q_SLOTS: void updateQueueSize(); protected: /** @brief Do initialization. Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Process a single message. Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::PointCloudConstPtr& cloud ); IntProperty* queue_size_property_; PointCloudCommon* point_cloud_common_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/point_cloud_transformer.h000066400000000000000000000103201300447110700244570ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POINT_CLOUD_TRANSFORMER_H #define RVIZ_POINT_CLOUD_TRANSFORMER_H #include #include #ifndef Q_MOC_RUN #include #include #include #endif namespace Ogre { class Matrix4; } namespace sensor_msgs { ROS_DECLARE_MESSAGE(PointCloud2); } namespace rviz { class Property; typedef std::vector V_PointCloudPoint; class PointCloudTransformer: public QObject { Q_OBJECT public: virtual void init() {} /** * \brief Enumeration of support levels. Basic levels (Support_None, Support_XYZ, Support_Color) can be * ored together to form a mask, Support_Both is provided as a convenience. */ enum SupportLevel { Support_None = 0, Support_XYZ = 1 << 1, Support_Color = 1 << 2, Support_Both = Support_XYZ|Support_Color, }; /** * \brief Returns a level of support for a specific cloud. This level of support is a mask using the SupportLevel enum. */ virtual uint8_t supports(const sensor_msgs::PointCloud2ConstPtr& cloud) = 0; /** * \brief Transforms a PointCloud2 into an rviz::PointCloud. The rviz::PointCloud is assumed to have been preallocated into the correct * size. The mask determines which part of the cloud should be output (xyz or color). This method will only be called if supports() of the same * cloud has returned a non-zero mask, and will only be called with masks compatible with the one returned from supports() */ virtual bool transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& out) = 0; /** * \brief "Score" a message for how well supported the message is. For example, a "flat color" transformer can support any cloud, but will * return a score of 0 here since it should not be preferred over others that explicitly support fields in the message. This allows that * "flat color" transformer to still be selectable, but generally not chosen automatically. */ virtual uint8_t score(const sensor_msgs::PointCloud2ConstPtr& cloud) { return 0; } /** * \brief Create any properties necessary for this transformer. * Will be called once when the transformer is loaded. All * properties must be added to the out_props vector. */ virtual void createProperties( Property* parent_property, uint32_t mask, QList& out_props ) {} Q_SIGNALS: /** @brief Subclasses should emit this signal whenever they think the points should be re-transformed. */ void needRetransform(); }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/point_cloud_transformers.cpp000066400000000000000000000553201300447110700252060ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/properties/bool_property.h" #include "rviz/properties/color_property.h" #include "rviz/properties/editable_enum_property.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/float_property.h" #include "rviz/validate_floats.h" #include "point_cloud_transformers.h" namespace rviz { static void getRainbowColor(float value, Ogre::ColourValue& color) { // this is HSV color palette with hue values going only from 0.0 to 0.833333. value = std::min(value, 1.0f); value = std::max(value, 0.0f); float h = value * 5.0f + 1.0f; int i = floor(h); float f = h - i; if ( !(i&1) ) f = 1 - f; // if i is even float n = 1 - f; if (i <= 1) color[0] = n, color[1] = 0, color[2] = 1; else if (i == 2) color[0] = 0, color[1] = n, color[2] = 1; else if (i == 3) color[0] = 0, color[1] = 1, color[2] = n; else if (i == 4) color[0] = n, color[1] = 1, color[2] = 0; else if (i >= 5) color[0] = 1, color[1] = n, color[2] = 0; } uint8_t IntensityPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud) { updateChannels(cloud); return Support_Color; } uint8_t IntensityPCTransformer::score(const sensor_msgs::PointCloud2ConstPtr& cloud) { return 255; } bool IntensityPCTransformer::transform( const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out ) { if( !( mask & Support_Color )) { return false; } int32_t index = findChannelIndex( cloud, channel_name_property_->getStdString() ); if( index == -1 ) { if( channel_name_property_->getStdString() == "intensity" ) { index = findChannelIndex( cloud, "intensities" ); if( index == -1 ) { return false; } } else { return false; } } const uint32_t offset = cloud->fields[index].offset; const uint8_t type = cloud->fields[index].datatype; const uint32_t point_step = cloud->point_step; const uint32_t num_points = cloud->width * cloud->height; float min_intensity = 999999.0f; float max_intensity = -999999.0f; if( auto_compute_intensity_bounds_property_->getBool() ) { for( uint32_t i = 0; i < num_points; ++i ) { float val = valueFromCloud(cloud, offset, type, point_step, i); min_intensity = std::min(val, min_intensity); max_intensity = std::max(val, max_intensity); } min_intensity = std::max(-999999.0f, min_intensity); max_intensity = std::min(999999.0f, max_intensity); min_intensity_property_->setFloat( min_intensity ); max_intensity_property_->setFloat( max_intensity ); } else { min_intensity = min_intensity_property_->getFloat(); max_intensity = max_intensity_property_->getFloat(); } float diff_intensity = max_intensity - min_intensity; if( diff_intensity == 0 ) { // If min and max are equal, set the diff to something huge so // when we divide by it, we effectively get zero. That way the // point cloud coloring will be predictably uniform when min and // max are equal. diff_intensity = 1e20; } Ogre::ColourValue max_color = max_color_property_->getOgreColor(); Ogre::ColourValue min_color = min_color_property_->getOgreColor(); if( use_rainbow_property_->getBool() ) { for (uint32_t i = 0; i < num_points; ++i) { float val = valueFromCloud(cloud, offset, type, point_step, i); float value = 1.0 - (val - min_intensity)/diff_intensity; if(invert_rainbow_property_->getBool() ){ value = 1.0 - value; } getRainbowColor(value, points_out[i].color); } } else { for (uint32_t i = 0; i < num_points; ++i) { float val = valueFromCloud(cloud, offset, type, point_step, i); float normalized_intensity = ( val - min_intensity ) / diff_intensity; normalized_intensity = std::min(1.0f, std::max(0.0f, normalized_intensity)); points_out[i].color.r = max_color.r * normalized_intensity + min_color.r * (1.0f - normalized_intensity); points_out[i].color.g = max_color.g * normalized_intensity + min_color.g * (1.0f - normalized_intensity); points_out[i].color.b = max_color.b * normalized_intensity + min_color.b * (1.0f - normalized_intensity); } } return true; } void IntensityPCTransformer::createProperties( Property* parent_property, uint32_t mask, QList& out_props ) { if( mask & Support_Color ) { channel_name_property_ = new EditableEnumProperty( "Channel Name", "intensity", "Select the channel to use to compute the intensity", parent_property, SIGNAL( needRetransform() ), this ); use_rainbow_property_ = new BoolProperty( "Use rainbow", true, "Whether to use a rainbow of colors or interpolate between two", parent_property, SLOT( updateUseRainbow() ), this ); invert_rainbow_property_ = new BoolProperty( "Invert Rainbow", false, "Whether to invert rainbow colors", parent_property, SLOT( updateUseRainbow() ), this ); min_color_property_ = new ColorProperty( "Min Color", Qt::black, "Color to assign the points with the minimum intensity. " "Actual color is interpolated between this and Max Color.", parent_property, SIGNAL( needRetransform() ), this ); max_color_property_ = new ColorProperty( "Max Color", Qt::white, "Color to assign the points with the maximum intensity. " "Actual color is interpolated between this and Min Color.", parent_property, SIGNAL( needRetransform() ), this ); auto_compute_intensity_bounds_property_ = new BoolProperty( "Autocompute Intensity Bounds", true, "Whether to automatically compute the intensity min/max values.", parent_property, SLOT( updateAutoComputeIntensityBounds() ), this ); min_intensity_property_ = new FloatProperty( "Min Intensity", 0, "Minimum possible intensity value, used to interpolate from Min Color to Max Color for a point.", parent_property ); max_intensity_property_ = new FloatProperty( "Max Intensity", 4096, "Maximum possible intensity value, used to interpolate from Min Color to Max Color for a point.", parent_property ); out_props.push_back( channel_name_property_ ); out_props.push_back( use_rainbow_property_ ); out_props.push_back( invert_rainbow_property_ ); out_props.push_back( min_color_property_ ); out_props.push_back( max_color_property_ ); out_props.push_back( auto_compute_intensity_bounds_property_ ); out_props.push_back( min_intensity_property_ ); out_props.push_back( max_intensity_property_ ); updateUseRainbow(); updateAutoComputeIntensityBounds(); } } void IntensityPCTransformer::updateChannels( const sensor_msgs::PointCloud2ConstPtr& cloud ) { V_string channels; for(size_t i = 0; i < cloud->fields.size(); ++i ) { channels.push_back(cloud->fields[i].name ); } std::sort(channels.begin(), channels.end()); if( channels != available_channels_ ) { channel_name_property_->clearOptions(); for( V_string::const_iterator it = channels.begin(); it != channels.end(); ++it ) { const std::string& channel = *it; if( channel.empty() ) { continue; } channel_name_property_->addOptionStd( channel ); } available_channels_ = channels; } } void IntensityPCTransformer::updateAutoComputeIntensityBounds() { bool auto_compute = auto_compute_intensity_bounds_property_->getBool(); min_intensity_property_->setHidden( auto_compute ); max_intensity_property_->setHidden( auto_compute ); if( auto_compute ) { disconnect( min_intensity_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); disconnect( max_intensity_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); } else { connect( min_intensity_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); connect( max_intensity_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); } Q_EMIT needRetransform(); } void IntensityPCTransformer::updateUseRainbow() { bool use_rainbow = use_rainbow_property_->getBool(); invert_rainbow_property_->setHidden( !use_rainbow ); min_color_property_->setHidden( use_rainbow ); max_color_property_->setHidden( use_rainbow ); Q_EMIT needRetransform(); } uint8_t XYZPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud) { int32_t xi = findChannelIndex(cloud, "x"); int32_t yi = findChannelIndex(cloud, "y"); int32_t zi = findChannelIndex(cloud, "z"); if (xi == -1 || yi == -1 || zi == -1) { return Support_None; } if (cloud->fields[xi].datatype == sensor_msgs::PointField::FLOAT32) { return Support_XYZ; } return Support_None; } bool XYZPCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out) { if (!(mask & Support_XYZ)) { return false; } int32_t xi = findChannelIndex(cloud, "x"); int32_t yi = findChannelIndex(cloud, "y"); int32_t zi = findChannelIndex(cloud, "z"); const uint32_t xoff = cloud->fields[xi].offset; const uint32_t yoff = cloud->fields[yi].offset; const uint32_t zoff = cloud->fields[zi].offset; const uint32_t point_step = cloud->point_step; const uint32_t num_points = cloud->width * cloud->height; uint8_t const* point_x = &cloud->data.front() + xoff; uint8_t const* point_y = &cloud->data.front() + yoff; uint8_t const* point_z = &cloud->data.front() + zoff; for (V_PointCloudPoint::iterator iter = points_out.begin(); iter != points_out.end(); ++iter, point_x += point_step, point_y += point_step, point_z += point_step) { iter->position.x = *reinterpret_cast(point_x); iter->position.y = *reinterpret_cast(point_y); iter->position.z = *reinterpret_cast(point_z); } return true; } uint8_t RGB8PCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud) { int32_t index = std::max(findChannelIndex(cloud, "rgb"), findChannelIndex(cloud, "rgba")); if (index == -1) { return Support_None; } if (cloud->fields[index].datatype == sensor_msgs::PointField::INT32 || cloud->fields[index].datatype == sensor_msgs::PointField::UINT32 || cloud->fields[index].datatype == sensor_msgs::PointField::FLOAT32) { return Support_Color; } return Support_None; } bool RGB8PCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out) { if (!(mask & Support_Color)) { return false; } const int32_t rgb = findChannelIndex(cloud, "rgb"); const int32_t rgba = findChannelIndex(cloud, "rgba"); const int32_t index = std::max(rgb, rgba); const uint32_t off = cloud->fields[index].offset; uint8_t const* rgb_ptr = &cloud->data.front() + off; const uint32_t point_step = cloud->point_step; // Create a look-up table for colors float rgb_lut[256]; for(int i = 0; i < 256; ++i) { rgb_lut[i] = float(i)/255.0f; } if (rgb != -1) // rgb { for (V_PointCloudPoint::iterator iter = points_out.begin(); iter != points_out.end(); ++iter, rgb_ptr += point_step) { uint32_t rgb = *reinterpret_cast(rgb_ptr); iter->color.r = rgb_lut[(rgb >> 16) & 0xff]; iter->color.g = rgb_lut[(rgb >> 8) & 0xff]; iter->color.b = rgb_lut[rgb & 0xff]; iter->color.a = 1.0f; } } else // rgba { for (V_PointCloudPoint::iterator iter = points_out.begin(); iter != points_out.end(); ++iter, rgb_ptr += point_step) { uint32_t rgb = *reinterpret_cast(rgb_ptr); iter->color.r = rgb_lut[(rgb >> 16) & 0xff]; iter->color.g = rgb_lut[(rgb >> 8) & 0xff]; iter->color.b = rgb_lut[rgb & 0xff]; iter->color.a = rgb_lut[rgb >> 24]; } } return true; } uint8_t RGBF32PCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud) { int32_t ri = findChannelIndex(cloud, "r"); int32_t gi = findChannelIndex(cloud, "g"); int32_t bi = findChannelIndex(cloud, "b"); if (ri == -1 || gi == -1 || bi == -1) { return Support_None; } if (cloud->fields[ri].datatype == sensor_msgs::PointField::FLOAT32) { return Support_Color; } return Support_None; } bool RGBF32PCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out) { if (!(mask & Support_Color)) { return false; } int32_t ri = findChannelIndex(cloud, "r"); int32_t gi = findChannelIndex(cloud, "g"); int32_t bi = findChannelIndex(cloud, "b"); const uint32_t roff = cloud->fields[ri].offset; const uint32_t goff = cloud->fields[gi].offset; const uint32_t boff = cloud->fields[bi].offset; const uint32_t point_step = cloud->point_step; const uint32_t num_points = cloud->width * cloud->height; uint8_t const* point = &cloud->data.front(); for (uint32_t i = 0; i < num_points; ++i, point += point_step) { float r = *reinterpret_cast(point + roff); float g = *reinterpret_cast(point + goff); float b = *reinterpret_cast(point + boff); points_out[i].color = Ogre::ColourValue(r, g, b); } return true; } uint8_t FlatColorPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud) { return Support_Color; } uint8_t FlatColorPCTransformer::score(const sensor_msgs::PointCloud2ConstPtr& cloud) { return 0; } bool FlatColorPCTransformer::transform( const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out ) { if( !( mask & Support_Color )) { return false; } Ogre::ColourValue color = color_property_->getOgreColor(); const uint32_t num_points = cloud->width * cloud->height; for( uint32_t i = 0; i < num_points; ++i ) { points_out[i].color = color; } return true; } void FlatColorPCTransformer::createProperties( Property* parent_property, uint32_t mask, QList& out_props ) { if( mask & Support_Color ) { color_property_ = new ColorProperty( "Color", Qt::white, "Color to assign to every point.", parent_property, SIGNAL( needRetransform() ), this ); out_props.push_back( color_property_ ); } } uint8_t AxisColorPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud) { return Support_Color; } uint8_t AxisColorPCTransformer::score(const sensor_msgs::PointCloud2ConstPtr& cloud) { return 255; } bool AxisColorPCTransformer::transform( const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out ) { if( !( mask & Support_Color )) { return false; } int32_t xi = findChannelIndex( cloud, "x" ); int32_t yi = findChannelIndex( cloud, "y" ); int32_t zi = findChannelIndex( cloud, "z" ); const uint32_t xoff = cloud->fields[xi].offset; const uint32_t yoff = cloud->fields[yi].offset; const uint32_t zoff = cloud->fields[zi].offset; const uint32_t point_step = cloud->point_step; const uint32_t num_points = cloud->width * cloud->height; uint8_t const* point = &cloud->data.front(); // Fill a vector of floats with values based on the chosen axis. int axis = axis_property_->getOptionInt(); std::vector values; values.reserve( num_points ); Ogre::Vector3 pos; if( use_fixed_frame_property_->getBool() ) { for (uint32_t i = 0; i < num_points; ++i, point += point_step) { // TODO: optimize this by only doing the multiplication needed // for the desired output value, instead of doing all of them // and then throwing most away. pos.x = *reinterpret_cast(point + xoff); pos.y = *reinterpret_cast(point + yoff); pos.z = *reinterpret_cast(point + zoff); pos = transform * pos; values.push_back( pos[ axis ]); } } else { const uint32_t offsets[ 3 ] = { xoff, yoff, zoff }; const uint32_t off = offsets[ axis ]; for (uint32_t i = 0; i < num_points; ++i, point += point_step) { values.push_back( *reinterpret_cast( point + off )); } } float min_value_current = 9999.0f; float max_value_current = -9999.0f; if( auto_compute_bounds_property_->getBool() ) { for( uint32_t i = 0; i < num_points; i++ ) { float val = values[ i ]; min_value_current = std::min( min_value_current, val ); max_value_current = std::max( max_value_current, val ); } min_value_property_->setFloat( min_value_current ); max_value_property_->setFloat( max_value_current ); } else { min_value_current = min_value_property_->getFloat(); max_value_current = max_value_property_->getFloat(); } float range = max_value_current - min_value_current; if( range == 0 ) { range = 0.001f; } for( uint32_t i = 0; i < num_points; ++i ) { float value = 1.0 - ( values[ i ] - min_value_current ) / range; getRainbowColor( value, points_out[i].color ); } return true; } void AxisColorPCTransformer::createProperties( Property* parent_property, uint32_t mask, QList& out_props ) { if( mask & Support_Color ) { axis_property_ = new EnumProperty( "Axis", "Z", "The axis to interpolate the color along.", parent_property, SIGNAL( needRetransform() ), this ); axis_property_->addOption( "X", AXIS_X ); axis_property_->addOption( "Y", AXIS_Y ); axis_property_->addOption( "Z", AXIS_Z ); auto_compute_bounds_property_ = new BoolProperty( "Autocompute Value Bounds", true, "Whether to automatically compute the value min/max values.", parent_property, SLOT( updateAutoComputeBounds() ), this ); min_value_property_ = new FloatProperty( "Min Value", -10, "Minimum value value, used to interpolate the color of a point.", auto_compute_bounds_property_ ); max_value_property_ = new FloatProperty( "Max Value", 10, "Maximum value value, used to interpolate the color of a point.", auto_compute_bounds_property_ ); use_fixed_frame_property_ = new BoolProperty( "Use Fixed Frame", true, "Whether to color the cloud based on its fixed frame position or its local frame position.", parent_property, SIGNAL( needRetransform() ), this ); out_props.push_back( axis_property_ ); out_props.push_back( auto_compute_bounds_property_ ); out_props.push_back( use_fixed_frame_property_ ); updateAutoComputeBounds(); } } void AxisColorPCTransformer::updateAutoComputeBounds() { bool auto_compute = auto_compute_bounds_property_->getBool(); min_value_property_->setHidden( auto_compute ); max_value_property_->setHidden( auto_compute ); if( auto_compute ) { disconnect( min_value_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); disconnect( max_value_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); } else { connect( min_value_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); connect( max_value_property_, SIGNAL( changed() ), this, SIGNAL( needRetransform() )); auto_compute_bounds_property_->expand(); } Q_EMIT needRetransform(); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::AxisColorPCTransformer, rviz::PointCloudTransformer ) PLUGINLIB_EXPORT_CLASS( rviz::FlatColorPCTransformer, rviz::PointCloudTransformer ) PLUGINLIB_EXPORT_CLASS( rviz::IntensityPCTransformer, rviz::PointCloudTransformer ) PLUGINLIB_EXPORT_CLASS( rviz::RGB8PCTransformer, rviz::PointCloudTransformer ) PLUGINLIB_EXPORT_CLASS( rviz::RGBF32PCTransformer, rviz::PointCloudTransformer ) PLUGINLIB_EXPORT_CLASS( rviz::XYZPCTransformer, rviz::PointCloudTransformer ) rviz-1.12.4/src/rviz/default_plugin/point_cloud_transformers.h000066400000000000000000000152401300447110700246500ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef POINT_CLOUD_TRANSFORMERS_H #define POINT_CLOUD_TRANSFORMERS_H #include #include "point_cloud_transformer.h" namespace rviz { class BoolProperty; class ColorProperty; class EditableEnumProperty; class EnumProperty; class FloatProperty; typedef std::vector V_string; inline int32_t findChannelIndex(const sensor_msgs::PointCloud2ConstPtr& cloud, const std::string& channel) { for (size_t i = 0; i < cloud->fields.size(); ++i) { if (cloud->fields[i].name == channel) { return i; } } return -1; } template inline T valueFromCloud(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t offset, uint8_t type, uint32_t point_step, uint32_t index) { const uint8_t* data = &cloud->data[(point_step * index) + offset]; T ret = 0; switch (type) { case sensor_msgs::PointField::INT8: case sensor_msgs::PointField::UINT8: { uint8_t val = *reinterpret_cast(data); ret = static_cast(val); break; } case sensor_msgs::PointField::INT16: case sensor_msgs::PointField::UINT16: { uint16_t val = *reinterpret_cast(data); ret = static_cast(val); break; } case sensor_msgs::PointField::INT32: case sensor_msgs::PointField::UINT32: { uint32_t val = *reinterpret_cast(data); ret = static_cast(val); break; } case sensor_msgs::PointField::FLOAT32: { float val = *reinterpret_cast(data); ret = static_cast(val); break; } case sensor_msgs::PointField::FLOAT64: { double val = *reinterpret_cast(data); ret = static_cast(val); break; } default: break; } return ret; } class IntensityPCTransformer : public PointCloudTransformer { Q_OBJECT public: virtual uint8_t supports(const sensor_msgs::PointCloud2ConstPtr& cloud); virtual bool transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out); virtual uint8_t score(const sensor_msgs::PointCloud2ConstPtr& cloud); virtual void createProperties( Property* parent_property, uint32_t mask, QList& out_props ); void updateChannels(const sensor_msgs::PointCloud2ConstPtr& cloud); private Q_SLOTS: void updateUseRainbow(); void updateAutoComputeIntensityBounds(); private: V_string available_channels_; ColorProperty* min_color_property_; ColorProperty* max_color_property_; BoolProperty* auto_compute_intensity_bounds_property_; BoolProperty* use_rainbow_property_; BoolProperty* invert_rainbow_property_; FloatProperty* min_intensity_property_; FloatProperty* max_intensity_property_; EditableEnumProperty* channel_name_property_; }; class XYZPCTransformer : public PointCloudTransformer { Q_OBJECT public: virtual uint8_t supports(const sensor_msgs::PointCloud2ConstPtr& cloud); virtual bool transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out); }; class RGB8PCTransformer : public PointCloudTransformer { Q_OBJECT public: virtual uint8_t supports(const sensor_msgs::PointCloud2ConstPtr& cloud); virtual bool transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out); }; class RGBF32PCTransformer : public PointCloudTransformer { Q_OBJECT public: virtual uint8_t supports(const sensor_msgs::PointCloud2ConstPtr& cloud); virtual bool transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out); }; class FlatColorPCTransformer : public PointCloudTransformer { Q_OBJECT public: virtual uint8_t supports(const sensor_msgs::PointCloud2ConstPtr& cloud); virtual bool transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out); virtual void createProperties( Property* parent_property, uint32_t mask, QList& out_props ); virtual uint8_t score(const sensor_msgs::PointCloud2ConstPtr& cloud); private: ColorProperty* color_property_; }; class AxisColorPCTransformer : public PointCloudTransformer { Q_OBJECT public: virtual uint8_t supports(const sensor_msgs::PointCloud2ConstPtr& cloud); virtual bool transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, V_PointCloudPoint& points_out); virtual void createProperties( Property* parent_property, uint32_t mask, QList& out_props ); virtual uint8_t score(const sensor_msgs::PointCloud2ConstPtr& cloud); enum Axis { AXIS_X, AXIS_Y, AXIS_Z }; private Q_SLOTS: void updateAutoComputeBounds(); private: BoolProperty* auto_compute_bounds_property_; FloatProperty* min_value_property_; FloatProperty* max_value_property_; EnumProperty* axis_property_; BoolProperty* use_fixed_frame_property_; }; } #endif // POINT_CLOUD_TRANSFORMERS_H rviz-1.12.4/src/rviz/default_plugin/point_display.cpp000066400000000000000000000112301300447110700227300ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "point_visual.h" #include "point_display.h" namespace rviz { PointStampedDisplay::PointStampedDisplay() { color_property_ = new rviz::ColorProperty( "Color", QColor(204, 41, 204), "Color of a point", this, SLOT( updateColorAndAlpha() )); alpha_property_ = new rviz::FloatProperty( "Alpha", 1.0, "0 is fully transparent, 1.0 is fully opaque.", this, SLOT( updateColorAndAlpha() )); radius_property_ = new rviz::FloatProperty( "Radius", 0.2, "Radius of a point", this, SLOT( updateColorAndAlpha() )); history_length_property_ = new rviz::IntProperty( "History Length", 1, "Number of prior measurements to display.", this, SLOT( updateHistoryLength() )); history_length_property_->setMin( 1 ); history_length_property_->setMax( 100000 ); } void PointStampedDisplay::onInitialize() { MFDClass::onInitialize(); updateHistoryLength(); } PointStampedDisplay::~PointStampedDisplay() { } // Clear the visuals by deleting their objects. void PointStampedDisplay::reset() { MFDClass::reset(); visuals_.clear(); } // Set the current color and alpha values for each visual. void PointStampedDisplay::updateColorAndAlpha() { float alpha = alpha_property_->getFloat(); float radius = radius_property_->getFloat(); Ogre::ColourValue color = color_property_->getOgreColor(); for( size_t i = 0; i < visuals_.size(); i++ ) { visuals_[i]->setColor( color.r, color.g, color.b, alpha ); visuals_[i]->setRadius( radius ); } } // Set the number of past visuals to show. void PointStampedDisplay::updateHistoryLength() { visuals_.rset_capacity(history_length_property_->getInt()); } // This is our callback to handle an incoming message. void PointStampedDisplay::processMessage( const geometry_msgs::PointStamped::ConstPtr& msg ) { if( !rviz::validateFloats( msg->point )) { setStatus( rviz::StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } // Here we call the rviz::FrameManager to get the transform from the // fixed frame to the frame in the header of this Point message. If // it fails, we can't do anything else so we return. Ogre::Quaternion orientation; Ogre::Vector3 position; if( !context_->getFrameManager()->getTransform( msg->header.frame_id, msg->header.stamp, position, orientation )) { ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable( fixed_frame_ ) ); return; } // We are keeping a circular buffer of visual pointers. This gets // the next one, or creates and stores it if the buffer is not full boost::shared_ptr visual; if( visuals_.full() ) { visual = visuals_.front(); } else { visual.reset(new PointStampedVisual( context_->getSceneManager(), scene_node_ )); } // Now set or update the contents of the chosen visual. visual->setMessage( msg ); visual->setFramePosition( position ); visual->setFrameOrientation( orientation ); float alpha = alpha_property_->getFloat(); float radius = radius_property_->getFloat(); Ogre::ColourValue color = color_property_->getOgreColor(); visual->setColor( color.r, color.g, color.b, alpha); visual->setRadius( radius ); // And send it to the end of the circular buffer visuals_.push_back(visual); } } // end namespace rviz // Tell pluginlib about this class. It is important to do this in // global scope, outside our package's namespace. #include PLUGINLIB_EXPORT_CLASS( rviz::PointStampedDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/point_display.h000066400000000000000000000031311300447110700223760ustar00rootroot00000000000000#ifndef POINT_DISPLAY_H #define POINT_DISPLAY_H #ifndef Q_MOC_RUN #include #endif #include #include namespace Ogre { class SceneNode; } namespace rviz { class ColorProperty; class FloatProperty; class IntProperty; } namespace rviz { class PointStampedVisual; class PointStampedDisplay: public rviz::MessageFilterDisplay { Q_OBJECT public: // Constructor. pluginlib::ClassLoader creates instances by calling // the default constructor, so make sure you have one. PointStampedDisplay(); virtual ~PointStampedDisplay(); protected: // Overrides of public virtual functions from the Display class. virtual void onInitialize(); virtual void reset(); private Q_SLOTS: // Helper function to apply color and alpha to all visuals. void updateColorAndAlpha(); void updateHistoryLength(); // Function to handle an incoming ROS message. private: void processMessage( const geometry_msgs::PointStamped::ConstPtr& msg ); // Storage for the list of visuals. It is a circular buffer where // data gets popped from the front (oldest) and pushed to the back (newest) boost::circular_buffer > visuals_; // Property objects for user-editable properties. rviz::ColorProperty *color_property_; rviz::FloatProperty *alpha_property_, *radius_property_; rviz::IntProperty *history_length_property_; }; } // end namespace rviz_plugin_tutorials #endif // POINT_DISPLAY_H rviz-1.12.4/src/rviz/default_plugin/point_visual.cpp000066400000000000000000000042451300447110700225760ustar00rootroot00000000000000#include #include #include #include #include #include "point_visual.h" namespace rviz { PointStampedVisual::PointStampedVisual( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ) { scene_manager_ = scene_manager; // Ogre::SceneNode s form a tree, with each node storing the // transform (position and orientation) of itself relative to its // parent. Ogre does the math of combining those transforms when it // is time to render. // // Here we create a node to store the pose of the Point's header frame // relative to the RViz fixed frame. frame_node_ = parent_node->createChildSceneNode(); // We create the arrow object within the frame node so that we can // set its position and direction relative to its header frame. point_ = new rviz::Shape( rviz::Shape::Sphere, scene_manager_, frame_node_ ); } PointStampedVisual::~PointStampedVisual() { // Delete the arrow to make it disappear. delete point_; // Destroy the frame node since we don't need it anymore. scene_manager_->destroySceneNode( frame_node_ ); } void PointStampedVisual::setMessage( const geometry_msgs::PointStamped::ConstPtr& msg ) { Ogre::Vector3 scale( radius_, radius_, radius_ ); point_->setScale( scale ); // Set the orientation of the arrow to match the direction of the // acceleration vector. Ogre::Vector3 point( msg->point.x, msg->point.y, msg->point.z); point_->setPosition( point ); } // Position and orientation are passed through to the SceneNode. void PointStampedVisual::setFramePosition( const Ogre::Vector3& position ) { frame_node_->setPosition( position ); } void PointStampedVisual::setFrameOrientation( const Ogre::Quaternion& orientation ) { frame_node_->setOrientation( orientation ); } // Color is passed through to the rviz object. void PointStampedVisual::setColor( float r, float g, float b, float a ) { point_->setColor( r, g, b, a ); } void PointStampedVisual::setRadius( float r ) { radius_ = r; } } // end namespace rviz rviz-1.12.4/src/rviz/default_plugin/point_visual.h000066400000000000000000000041631300447110700222420ustar00rootroot00000000000000#ifndef POINT_VISUAL_H #define POINT_VISUAL_H #include namespace Ogre { class Vector3; class Quaternion; } namespace rviz { class Shape; } namespace rviz { // Each instance of PointStampedVisual represents the visualization of a single // sensor_msgs::Point message. Currently it just shows an arrow with // the direction and magnitude of the acceleration vector, but could // easily be expanded to include more of the message data. class PointStampedVisual { public: // Constructor. Creates the visual stuff and puts it into the // scene, but in an unconfigured state. PointStampedVisual( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ); // Destructor. Removes the visual stuff from the scene. virtual ~PointStampedVisual(); // set rainbow color void getRainbowColor(float value, Ogre::ColourValue& color); // Configure the visual to show the data in the message. void setMessage( const geometry_msgs::PointStamped::ConstPtr& msg ); // Set the pose of the coordinate frame the message refers to. // These could be done inside setMessage(), but that would require // calls to FrameManager and error handling inside setMessage(), // which doesn't seem as clean. This way PointStampedVisual is only // responsible for visualization. void setFramePosition( const Ogre::Vector3& position ); void setFrameOrientation( const Ogre::Quaternion& orientation ); // Set the color and alpha of the visual, which are user-editable // parameters and therefore don't come from the Point message. void setColor( float r, float g, float b, float a ); void setRadius( float r ); private: // The object implementing the point circle rviz::Shape* point_; // A SceneNode whose pose is set to match the coordinate frame of // the Point message header. Ogre::SceneNode* frame_node_; // The SceneManager, kept here only so the destructor can ask it to // destroy the ``frame_node_``. Ogre::SceneManager* scene_manager_; float radius_; }; } // end namespace rviz #endif // POINT_VISUAL_H rviz-1.12.4/src/rviz/default_plugin/polygon_display.cpp000066400000000000000000000110751300447110700232750ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/properties/color_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/parse_color.h" #include "rviz/validate_floats.h" #include "polygon_display.h" namespace rviz { PolygonDisplay::PolygonDisplay() { color_property_ = new ColorProperty( "Color", QColor( 25, 255, 0 ), "Color to draw the polygon.", this, SLOT( queueRender() )); alpha_property_ = new FloatProperty( "Alpha", 1.0, "Amount of transparency to apply to the polygon.", this, SLOT( queueRender() )); alpha_property_->setMin( 0 ); alpha_property_->setMax( 1 ); } PolygonDisplay::~PolygonDisplay() { if ( initialized() ) { scene_manager_->destroyManualObject( manual_object_ ); } } void PolygonDisplay::onInitialize() { MFDClass::onInitialize(); manual_object_ = scene_manager_->createManualObject(); manual_object_->setDynamic( true ); scene_node_->attachObject( manual_object_ ); } void PolygonDisplay::reset() { MFDClass::reset(); manual_object_->clear(); } bool validateFloats( const geometry_msgs::PolygonStamped& msg ) { return validateFloats(msg.polygon.points); } void PolygonDisplay::processMessage(const geometry_msgs::PolygonStamped::ConstPtr& msg) { if( !validateFloats( *msg )) { setStatus( StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } Ogre::Vector3 position; Ogre::Quaternion orientation; if( !context_->getFrameManager()->getTransform( msg->header, position, orientation )) { ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable( fixed_frame_ )); } scene_node_->setPosition( position ); scene_node_->setOrientation( orientation ); manual_object_->clear(); Ogre::ColourValue color = qtToOgre( color_property_->getColor() ); color.a = alpha_property_->getFloat(); // TODO: this does not actually support alpha as-is. The // "BaseWhiteNoLighting" material ends up ignoring the alpha // component of the color values we set at each point. Need to make // a material and do the whole setSceneBlending() rigamarole. uint32_t num_points = msg->polygon.points.size(); if( num_points > 0 ) { manual_object_->estimateVertexCount( num_points ); manual_object_->begin( "BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_STRIP ); for( uint32_t i=0; i < num_points + 1; ++i ) { const geometry_msgs::Point32& msg_point = msg->polygon.points[ i % num_points ]; manual_object_->position( msg_point.x, msg_point.y, msg_point.z ); manual_object_->colour( color ); } manual_object_->end(); } } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::PolygonDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/polygon_display.h000066400000000000000000000050351300447110700227410ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POLYGON_DISPLAY_H #define RVIZ_POLYGON_DISPLAY_H #include #include "rviz/message_filter_display.h" namespace Ogre { class ManualObject; } namespace rviz { class ColorProperty; class FloatProperty; /** * \class PolygonDisplay * \brief Displays a geometry_msgs::PolygonStamped message */ class PolygonDisplay: public MessageFilterDisplay { Q_OBJECT public: PolygonDisplay(); virtual ~PolygonDisplay(); /** @brief Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Overridden from MessageFilterDisplay. */ virtual void reset(); protected: /** @brief Overridden from MessageFilterDisplay. */ virtual void processMessage( const geometry_msgs::PolygonStamped::ConstPtr& msg ); Ogre::ManualObject* manual_object_; ColorProperty* color_property_; FloatProperty* alpha_property_; }; } // namespace rviz #endif /* RVIZ_POLYGON_DISPLAY_H */ rviz-1.12.4/src/rviz/default_plugin/pose_array_display.cpp000066400000000000000000000272211300447110700237520ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/color_property.h" #include "rviz/properties/float_property.h" #include "rviz/validate_floats.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/default_plugin/pose_array_display.h" namespace rviz { namespace { struct ShapeType { enum { Arrow2d, Arrow3d, Axes, }; }; Ogre::Vector3 vectorRosToOgre( geometry_msgs::Point const & point ) { return Ogre::Vector3( point.x, point.y, point.z ); } Ogre::Quaternion quaternionRosToOgre( geometry_msgs::Quaternion const & quaternion ) { return Ogre::Quaternion( quaternion.w, quaternion.x, quaternion.y, quaternion.z ); } } PoseArrayDisplay::PoseArrayDisplay() : manual_object_( NULL ) { shape_property_ = new EnumProperty( "Shape", "Arrow (Flat)", "Shape to display the pose as.", this, SLOT( updateShapeChoice() ) ); arrow_color_property_ = new ColorProperty( "Color", QColor( 255, 25, 0 ), "Color to draw the arrows.", this, SLOT( updateArrowColor() ) ); arrow_alpha_property_ = new FloatProperty( "Alpha", 1, "Amount of transparency to apply to the displayed poses.", this, SLOT( updateArrowColor() ) ); arrow2d_length_property_ = new FloatProperty( "Arrow Length", 0.3, "Length of the arrows.", this, SLOT( updateArrow2dGeometry() ) ); arrow3d_head_radius_property_ = new FloatProperty( "Head Radius", 0.03, "Radius of the arrow's head, in meters.", this, SLOT( updateArrow3dGeometry() ) ); arrow3d_head_length_property_ = new FloatProperty( "Head Length", 0.07, "Length of the arrow's head, in meters.", this, SLOT( updateArrow3dGeometry() ) ); arrow3d_shaft_radius_property_ = new FloatProperty( "Shaft Radius", 0.01, "Radius of the arrow's shaft, in meters.", this, SLOT( updateArrow3dGeometry() ) ); arrow3d_shaft_length_property_ = new FloatProperty( "Shaft Length", 0.23, "Length of the arrow's shaft, in meters.", this, SLOT( updateArrow3dGeometry() ) ); axes_length_property_ = new FloatProperty( "Axes Length", 0.3, "Length of each axis, in meters.", this, SLOT( updateAxesGeometry() ) ); axes_radius_property_ = new FloatProperty( "Axes Radius", 0.01, "Radius of each axis, in meters.", this, SLOT( updateAxesGeometry() ) ); shape_property_->addOption( "Arrow (Flat)", ShapeType::Arrow2d ); shape_property_->addOption( "Arrow (3D)", ShapeType::Arrow3d ); shape_property_->addOption( "Axes", ShapeType::Axes ); arrow_alpha_property_->setMin( 0 ); arrow_alpha_property_->setMax( 1 ); } PoseArrayDisplay::~PoseArrayDisplay() { if ( initialized() ) { scene_manager_->destroyManualObject( manual_object_ ); } } void PoseArrayDisplay::onInitialize() { MFDClass::onInitialize(); manual_object_ = scene_manager_->createManualObject(); manual_object_->setDynamic( true ); scene_node_->attachObject( manual_object_ ); arrow_node_ = scene_node_->createChildSceneNode(); axes_node_ = scene_node_->createChildSceneNode(); updateShapeChoice(); } bool validateFloats( const geometry_msgs::PoseArray& msg ) { return validateFloats( msg.poses ); } void PoseArrayDisplay::processMessage( const geometry_msgs::PoseArray::ConstPtr& msg ) { if( !validateFloats( *msg )) { setStatus( StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } if( !setTransform( msg->header ) ) { setStatus( StatusProperty::Error, "Topic", "Failed to look up transform" ); return; } poses_.resize( msg->poses.size() ); for (std::size_t i = 0; i < msg->poses.size(); ++i) { poses_[i].position = vectorRosToOgre( msg->poses[i].position ); poses_[i].orientation = quaternionRosToOgre( msg->poses[i].orientation ); } updateDisplay(); context_->queueRender(); } bool PoseArrayDisplay::setTransform( std_msgs::Header const & header ) { Ogre::Vector3 position; Ogre::Quaternion orientation; if( !context_->getFrameManager()->getTransform( header, position, orientation ) ) { ROS_ERROR( "Error transforming pose '%s' from frame '%s' to frame '%s'", qPrintable( getName() ), header.frame_id.c_str(), qPrintable( fixed_frame_ ) ); return false; } scene_node_->setPosition( position ); scene_node_->setOrientation( orientation ); return true; } void PoseArrayDisplay::updateArrows2d() { manual_object_->clear(); Ogre::ColourValue color = arrow_color_property_->getOgreColor(); color.a = arrow_alpha_property_->getFloat(); float length = arrow2d_length_property_->getFloat(); size_t num_poses = poses_.size(); manual_object_->estimateVertexCount( num_poses * 6 ); manual_object_->begin( "BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_LIST ); for( size_t i=0; i < num_poses; ++i ) { const Ogre::Vector3 & pos = poses_[i].position; const Ogre::Quaternion & orient = poses_[i].orientation; Ogre::Vector3 vertices[6]; vertices[0] = pos; // back of arrow vertices[1] = pos + orient * Ogre::Vector3( length, 0, 0 ); // tip of arrow vertices[2] = vertices[ 1 ]; vertices[3] = pos + orient * Ogre::Vector3( 0.75*length, 0.2*length, 0 ); vertices[4] = vertices[ 1 ]; vertices[5] = pos + orient * Ogre::Vector3( 0.75*length, -0.2*length, 0 ); for( int i = 0; i < 6; ++i ) { manual_object_->position( vertices[i] ); manual_object_->colour( color ); } } manual_object_->end(); } void PoseArrayDisplay::updateDisplay() { int shape = shape_property_->getOptionInt(); switch (shape) { case ShapeType::Arrow2d: updateArrows2d(); arrows3d_.clear(); axes_.clear(); break; case ShapeType::Arrow3d: updateArrows3d(); manual_object_->clear(); axes_.clear(); break; case ShapeType::Axes: updateAxes(); manual_object_->clear(); arrows3d_.clear(); break; } } void PoseArrayDisplay::updateArrows3d() { while (arrows3d_.size() < poses_.size()) arrows3d_.push_back(makeArrow3d()); while (arrows3d_.size() > poses_.size()) arrows3d_.pop_back(); Ogre::Quaternion adjust_orientation( Ogre::Degree(-90), Ogre::Vector3::UNIT_Y ); for (std::size_t i = 0; i < poses_.size(); ++i) { arrows3d_[i].setPosition( poses_[i].position ); arrows3d_[i].setOrientation( poses_[i].orientation * adjust_orientation ); } } void PoseArrayDisplay::updateAxes() { while (axes_.size() < poses_.size()) axes_.push_back(makeAxes()); while (axes_.size() > poses_.size()) axes_.pop_back(); for (std::size_t i = 0; i < poses_.size(); ++i) { axes_[i].setPosition( poses_[i].position ); axes_[i].setOrientation( poses_[i].orientation ); } } Arrow * PoseArrayDisplay::makeArrow3d() { Ogre::ColourValue color = arrow_color_property_->getOgreColor(); color.a = arrow_alpha_property_->getFloat(); Arrow * arrow = new Arrow( scene_manager_, arrow_node_, arrow3d_shaft_length_property_->getFloat(), arrow3d_shaft_radius_property_->getFloat(), arrow3d_head_length_property_->getFloat(), arrow3d_head_radius_property_->getFloat() ); arrow->setColor(color); return arrow; } Axes * PoseArrayDisplay::makeAxes() { return new Axes( scene_manager_, axes_node_, axes_length_property_->getFloat(), axes_radius_property_->getFloat() ); } void PoseArrayDisplay::reset() { MFDClass::reset(); if( manual_object_ ) { manual_object_->clear(); } arrows3d_.clear(); axes_.clear(); } void PoseArrayDisplay::updateShapeChoice() { int shape = shape_property_->getOptionInt(); bool use_arrow2d = shape == ShapeType::Arrow2d; bool use_arrow3d = shape == ShapeType::Arrow3d; bool use_arrow = use_arrow2d || use_arrow3d; bool use_axes = shape == ShapeType::Axes; arrow_color_property_->setHidden( !use_arrow ); arrow_alpha_property_->setHidden( !use_arrow ); arrow2d_length_property_->setHidden(!use_arrow2d); arrow3d_shaft_length_property_->setHidden( !use_arrow3d ); arrow3d_shaft_radius_property_->setHidden( !use_arrow3d ); arrow3d_head_length_property_->setHidden( !use_arrow3d ); arrow3d_head_radius_property_->setHidden( !use_arrow3d ); axes_length_property_->setHidden( !use_axes ); axes_radius_property_->setHidden( !use_axes ); if (initialized()) updateDisplay(); } void PoseArrayDisplay::updateArrowColor() { int shape = shape_property_->getOptionInt(); Ogre::ColourValue color = arrow_color_property_->getOgreColor(); color.a = arrow_alpha_property_->getFloat(); if (shape == ShapeType::Arrow2d) { updateArrows2d(); } else if (shape == ShapeType::Arrow3d) { for (std::size_t i = 0; i < arrows3d_.size(); ++i) { arrows3d_[i].setColor( color ); } } context_->queueRender(); } void PoseArrayDisplay::updateArrow2dGeometry() { updateArrows2d(); context_->queueRender(); } void PoseArrayDisplay::updateArrow3dGeometry() { for (std::size_t i = 0; i < poses_.size(); ++i) { arrows3d_[i].set( arrow3d_shaft_length_property_->getFloat(), arrow3d_shaft_radius_property_->getFloat(), arrow3d_head_length_property_->getFloat(), arrow3d_head_radius_property_->getFloat() ); } context_->queueRender(); } void PoseArrayDisplay::updateAxesGeometry() { for (std::size_t i = 0; i < poses_.size(); ++i) { axes_[i].set( axes_length_property_->getFloat(), axes_radius_property_->getFloat() ); } context_->queueRender(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::PoseArrayDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/pose_array_display.h000066400000000000000000000072211300447110700234150ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POSE_ARRAY_DISPLAY_H_ #define RVIZ_POSE_ARRAY_DISPLAY_H_ #include #include "rviz/message_filter_display.h" #include namespace Ogre { class ManualObject; } namespace rviz { class EnumProperty; class ColorProperty; class FloatProperty; class Arrow; class Axes; /** @brief Displays a geometry_msgs/PoseArray message as a bunch of line-drawn arrows. */ class PoseArrayDisplay: public MessageFilterDisplay { Q_OBJECT public: PoseArrayDisplay(); virtual ~PoseArrayDisplay(); protected: virtual void onInitialize(); virtual void reset(); virtual void processMessage( const geometry_msgs::PoseArray::ConstPtr& msg ); private: bool setTransform(std_msgs::Header const & header); void updateArrows2d(); void updateArrows3d(); void updateAxes(); void updateDisplay(); Axes * makeAxes(); Arrow * makeArrow3d(); struct OgrePose { Ogre::Vector3 position; Ogre::Quaternion orientation; }; std::vector poses_; boost::ptr_vector arrows3d_; boost::ptr_vector axes_; Ogre::SceneNode * arrow_node_; Ogre::SceneNode * axes_node_; Ogre::ManualObject* manual_object_; EnumProperty* shape_property_; ColorProperty* arrow_color_property_; FloatProperty* arrow_alpha_property_; FloatProperty* arrow2d_length_property_; FloatProperty* arrow3d_head_radius_property_; FloatProperty* arrow3d_head_length_property_; FloatProperty* arrow3d_shaft_radius_property_; FloatProperty* arrow3d_shaft_length_property_; FloatProperty* axes_length_property_; FloatProperty* axes_radius_property_; private Q_SLOTS: /// Update the interface and visible shapes based on the selected shape type. void updateShapeChoice(); /// Update the arrow color. void updateArrowColor(); /// Update the flat arrow geometry. void updateArrow2dGeometry(); /// Update the 3D arrow geometry. void updateArrow3dGeometry(); /// Update the axes geometry. void updateAxesGeometry(); }; } // namespace rviz #endif /* RVIZ_POSE_ARRAY_DISPLAY_H_ */ rviz-1.12.4/src/rviz/default_plugin/pose_display.cpp000066400000000000000000000250541300447110700225560ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/color_property.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/quaternion_property.h" #include "rviz/properties/string_property.h" #include "rviz/properties/vector_property.h" #include "rviz/selection/selection_manager.h" #include "rviz/validate_floats.h" #include "rviz/default_plugin/pose_display.h" namespace rviz { class PoseDisplaySelectionHandler: public SelectionHandler { public: PoseDisplaySelectionHandler( PoseDisplay* display, DisplayContext* context ) : SelectionHandler( context ) , display_( display ) {} void createProperties( const Picked& obj, Property* parent_property ) { Property* cat = new Property( "Pose " + display_->getName(), QVariant(), "", parent_property ); properties_.push_back( cat ); frame_property_ = new StringProperty( "Frame", "", "", cat ); frame_property_->setReadOnly( true ); position_property_ = new VectorProperty( "Position", Ogre::Vector3::ZERO, "", cat ); position_property_->setReadOnly( true ); orientation_property_ = new QuaternionProperty( "Orientation", Ogre::Quaternion::IDENTITY, "", cat ); orientation_property_->setReadOnly( true ); } void getAABBs( const Picked& obj, V_AABB& aabbs ) { if( display_->pose_valid_ ) { if( display_->shape_property_->getOptionInt() == PoseDisplay::Arrow ) { aabbs.push_back( display_->arrow_->getHead()->getEntity()->getWorldBoundingBox() ); aabbs.push_back( display_->arrow_->getShaft()->getEntity()->getWorldBoundingBox() ); } else { aabbs.push_back( display_->axes_->getXShape()->getEntity()->getWorldBoundingBox() ); aabbs.push_back( display_->axes_->getYShape()->getEntity()->getWorldBoundingBox() ); aabbs.push_back( display_->axes_->getZShape()->getEntity()->getWorldBoundingBox() ); } } } void setMessage(const geometry_msgs::PoseStampedConstPtr& message) { // properties_.size() should only be > 0 after createProperties() // and before destroyProperties(), during which frame_property_, // position_property_, and orientation_property_ should be valid // pointers. if( properties_.size() > 0 ) { frame_property_->setStdString( message->header.frame_id ); position_property_->setVector( Ogre::Vector3( message->pose.position.x, message->pose.position.y, message->pose.position.z )); orientation_property_->setQuaternion( Ogre::Quaternion( message->pose.orientation.w, message->pose.orientation.x, message->pose.orientation.y, message->pose.orientation.z )); } } private: PoseDisplay* display_; StringProperty* frame_property_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; }; PoseDisplay::PoseDisplay() : pose_valid_( false ) { shape_property_ = new EnumProperty( "Shape", "Arrow", "Shape to display the pose as.", this, SLOT( updateShapeChoice() )); shape_property_->addOption( "Arrow", Arrow ); shape_property_->addOption( "Axes", Axes ); color_property_ = new ColorProperty( "Color", QColor( 255, 25, 0 ), "Color to draw the arrow.", this, SLOT( updateColorAndAlpha() )); alpha_property_ = new FloatProperty( "Alpha", 1, "Amount of transparency to apply to the arrow.", this, SLOT( updateColorAndAlpha() )); alpha_property_->setMin( 0 ); alpha_property_->setMax( 1 ); shaft_length_property_ = new FloatProperty( "Shaft Length", 1, "Length of the arrow's shaft, in meters.", this, SLOT( updateArrowGeometry() )); // aleeper: default changed from 0.1 to match change in arrow.cpp shaft_radius_property_ = new FloatProperty( "Shaft Radius", 0.05, "Radius of the arrow's shaft, in meters.", this, SLOT( updateArrowGeometry() )); head_length_property_ = new FloatProperty( "Head Length", 0.3, "Length of the arrow's head, in meters.", this, SLOT( updateArrowGeometry() )); // aleeper: default changed from 0.2 to match change in arrow.cpp head_radius_property_ = new FloatProperty( "Head Radius", 0.1, "Radius of the arrow's head, in meters.", this, SLOT( updateArrowGeometry() )); axes_length_property_ = new FloatProperty( "Axes Length", 1, "Length of each axis, in meters.", this, SLOT( updateAxisGeometry() )); axes_radius_property_ = new FloatProperty( "Axes Radius", 0.1, "Radius of each axis, in meters.", this, SLOT( updateAxisGeometry() )); } void PoseDisplay::onInitialize() { MFDClass::onInitialize(); arrow_ = new rviz::Arrow( scene_manager_, scene_node_, shaft_length_property_->getFloat(), shaft_radius_property_->getFloat(), head_length_property_->getFloat(), head_radius_property_->getFloat() ); // Arrow points in -Z direction, so rotate the orientation before display. // TODO: is it safe to change Arrow to point in +X direction? arrow_->setOrientation( Ogre::Quaternion( Ogre::Degree( -90 ), Ogre::Vector3::UNIT_Y )); axes_ = new rviz::Axes( scene_manager_, scene_node_, axes_length_property_->getFloat(), axes_radius_property_->getFloat() ); updateShapeChoice(); updateColorAndAlpha(); coll_handler_.reset( new PoseDisplaySelectionHandler( this, context_ )); coll_handler_->addTrackedObjects( arrow_->getSceneNode() ); coll_handler_->addTrackedObjects( axes_->getSceneNode() ); } PoseDisplay::~PoseDisplay() { if ( initialized() ) { delete arrow_; delete axes_; } } void PoseDisplay::onEnable() { MFDClass::onEnable(); updateShapeVisibility(); } void PoseDisplay::updateColorAndAlpha() { Ogre::ColourValue color = color_property_->getOgreColor(); color.a = alpha_property_->getFloat(); arrow_->setColor( color ); context_->queueRender(); } void PoseDisplay::updateArrowGeometry() { arrow_->set( shaft_length_property_->getFloat(), shaft_radius_property_->getFloat(), head_length_property_->getFloat(), head_radius_property_->getFloat() ); context_->queueRender(); } void PoseDisplay::updateAxisGeometry() { axes_->set( axes_length_property_->getFloat(), axes_radius_property_->getFloat() ); context_->queueRender(); } void PoseDisplay::updateShapeChoice() { bool use_arrow = ( shape_property_->getOptionInt() == Arrow ); color_property_->setHidden( !use_arrow ); alpha_property_->setHidden( !use_arrow ); shaft_length_property_->setHidden( !use_arrow ); shaft_radius_property_->setHidden( !use_arrow ); head_length_property_->setHidden( !use_arrow ); head_radius_property_->setHidden( !use_arrow ); axes_length_property_->setHidden( use_arrow ); axes_radius_property_->setHidden( use_arrow ); updateShapeVisibility(); context_->queueRender(); } void PoseDisplay::updateShapeVisibility() { if( !pose_valid_ ) { arrow_->getSceneNode()->setVisible( false ); axes_->getSceneNode()->setVisible( false ); } else { bool use_arrow = (shape_property_->getOptionInt() == Arrow); arrow_->getSceneNode()->setVisible( use_arrow ); axes_->getSceneNode()->setVisible( !use_arrow ); } } void PoseDisplay::processMessage( const geometry_msgs::PoseStamped::ConstPtr& message ) { if( !validateFloats( *message )) { setStatus( StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } Ogre::Vector3 position; Ogre::Quaternion orientation; if( !context_->getFrameManager()->transform( message->header, message->pose, position, orientation )) { ROS_ERROR( "Error transforming pose '%s' from frame '%s' to frame '%s'", qPrintable( getName() ), message->header.frame_id.c_str(), qPrintable( fixed_frame_ )); return; } pose_valid_ = true; updateShapeVisibility(); scene_node_->setPosition( position ); scene_node_->setOrientation( orientation ); coll_handler_->setMessage( message ); context_->queueRender(); } void PoseDisplay::reset() { MFDClass::reset(); pose_valid_ = false; updateShapeVisibility(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::PoseDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/pose_display.h000066400000000000000000000064471300447110700222300ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POSE_DISPLAY_H_ #define RVIZ_POSE_DISPLAY_H_ #include #include #include "rviz/message_filter_display.h" #include "rviz/selection/forwards.h" namespace rviz { class Arrow; class Axes; class ColorProperty; class EnumProperty; class FloatProperty; class Shape; class PoseDisplaySelectionHandler; typedef boost::shared_ptr PoseDisplaySelectionHandlerPtr; /** @brief Accumulates and displays the pose from a geometry_msgs::PoseStamped message. */ class PoseDisplay: public MessageFilterDisplay { Q_OBJECT public: enum Shape { Arrow, Axes, }; PoseDisplay(); virtual ~PoseDisplay(); virtual void onInitialize(); virtual void reset(); protected: /** @brief Overridden from MessageFilterDisplay to get arrow/axes visibility correct. */ virtual void onEnable(); private Q_SLOTS: void updateShapeVisibility(); void updateColorAndAlpha(); void updateShapeChoice(); void updateAxisGeometry(); void updateArrowGeometry(); private: void clear(); virtual void processMessage( const geometry_msgs::PoseStamped::ConstPtr& message ); rviz::Arrow* arrow_; rviz::Axes* axes_; bool pose_valid_; PoseDisplaySelectionHandlerPtr coll_handler_; EnumProperty* shape_property_; ColorProperty* color_property_; FloatProperty* alpha_property_; FloatProperty* head_radius_property_; FloatProperty* head_length_property_; FloatProperty* shaft_radius_property_; FloatProperty* shaft_length_property_; FloatProperty* axes_length_property_; FloatProperty* axes_radius_property_; friend class PoseDisplaySelectionHandler; }; } // namespace rviz #endif /* RVIZ_POSE_DISPLAY_H_ */ rviz-1.12.4/src/rviz/default_plugin/range_display.cpp000066400000000000000000000136731300447110700227100ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/color_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/int_property.h" #include "rviz/properties/parse_color.h" #include "range_display.h" #include namespace rviz { RangeDisplay::RangeDisplay() { color_property_ = new ColorProperty( "Color", Qt::white, "Color to draw the range.", this, SLOT( updateColorAndAlpha() )); alpha_property_ = new FloatProperty( "Alpha", 0.5, "Amount of transparency to apply to the range.", this, SLOT( updateColorAndAlpha() )); buffer_length_property_ = new IntProperty( "Buffer Length", 1, "Number of prior measurements to display.", this, SLOT( updateBufferLength() )); buffer_length_property_->setMin( 1 ); queue_size_property_ = new IntProperty( "Queue Size", 100, "Size of the tf message filter queue. It usually needs to be set at least as high as the number of sonar frames.", this, SLOT( updateQueueSize() )); } void RangeDisplay::onInitialize() { MFDClass::onInitialize(); updateBufferLength(); updateColorAndAlpha(); } RangeDisplay::~RangeDisplay() { for( size_t i = 0; i < cones_.size(); i++ ) { delete cones_[ i ]; } } void RangeDisplay::reset() { MFDClass::reset(); updateBufferLength(); } void RangeDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void RangeDisplay::updateColorAndAlpha() { Ogre::ColourValue oc = color_property_->getOgreColor(); float alpha = alpha_property_->getFloat(); for( size_t i = 0; i < cones_.size(); i++ ) { cones_[i]->setColor( oc.r, oc.g, oc.b, alpha ); } context_->queueRender(); } void RangeDisplay::updateBufferLength() { int buffer_length = buffer_length_property_->getInt(); QColor color = color_property_->getColor(); for( size_t i = 0; i < cones_.size(); i++ ) { delete cones_[i]; } cones_.resize( buffer_length ); for( size_t i = 0; i < cones_.size(); i++ ) { Shape* cone = new Shape( Shape::Cone, context_->getSceneManager(), scene_node_ ); cones_[ i ] = cone; Ogre::Vector3 position; Ogre::Quaternion orientation; geometry_msgs::Pose pose; pose.orientation.w = 1; Ogre::Vector3 scale( 0, 0, 0 ); cone->setScale( scale ); cone->setColor( color.redF(), color.greenF(), color.blueF(), 0 ); } } void RangeDisplay::processMessage( const sensor_msgs::Range::ConstPtr& msg ) { Shape* cone = cones_[ messages_received_ % buffer_length_property_->getInt() ]; Ogre::Vector3 position; Ogre::Quaternion orientation; geometry_msgs::Pose pose; float displayed_range = 0.0; if(msg->min_range <= msg->range && msg->range <= msg->max_range){ displayed_range = msg->range; } else if(msg->min_range == msg->max_range){ // Fixed distance ranger if(msg->range < 0 && !std::isfinite(msg->range)){ // NaNs and +Inf return false here: both of those should have 0.0 as the range displayed_range = msg->min_range; // -Inf, display the detectable range } } pose.position.x = displayed_range/2 - .008824 * displayed_range; // .008824 fudge factor measured, must be inaccuracy of cone model. pose.orientation.z = 0.707; pose.orientation.w = 0.707; if( !context_->getFrameManager()->transform( msg->header.frame_id, msg->header.stamp, pose, position, orientation )) { ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable( fixed_frame_ )); } cone->setPosition( position ); cone->setOrientation( orientation ); double cone_width = 2.0 * displayed_range * tan( msg->field_of_view / 2.0 ); Ogre::Vector3 scale( cone_width, displayed_range, cone_width ); cone->setScale( scale ); QColor color = color_property_->getColor(); cone->setColor( color.redF(), color.greenF(), color.blueF(), alpha_property_->getFloat() ); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::RangeDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/range_display.h000066400000000000000000000052731300447110700223520ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RANGE_DISPLAY_H #define RANGE_DISPLAY_H #include #include "rviz/message_filter_display.h" namespace rviz { class Shape; } namespace rviz { class ColorProperty; class FloatProperty; class IntProperty; /** * \class RangeDisplay * \brief Displays a sensor_msgs::Range message as a cone. */ class RangeDisplay: public MessageFilterDisplay { Q_OBJECT public: RangeDisplay(); virtual ~RangeDisplay(); /** @brief Overridden from Display. */ virtual void reset(); protected: /** @brief Overridden from Display. */ virtual void onInitialize(); /** @brief Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::Range::ConstPtr& msg ); private Q_SLOTS: void updateBufferLength(); void updateColorAndAlpha(); void updateQueueSize(); private: std::vector cones_; ///< Handles actually drawing the cones ColorProperty* color_property_; FloatProperty* alpha_property_; IntProperty* buffer_length_property_; IntProperty* queue_size_property_; }; } // namespace range_plugin #endif /* RANGE_DISPLAY_H */ rviz-1.12.4/src/rviz/default_plugin/relative_humidity_display.cpp000066400000000000000000000130221300447110700253270ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/default_plugin/point_cloud_common.h" #include "rviz/default_plugin/point_cloud_transformers.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/int_property.h" #include "rviz/validate_floats.h" #include "relative_humidity_display.h" namespace rviz { RelativeHumidityDisplay::RelativeHumidityDisplay() : point_cloud_common_( new PointCloudCommon( this )) { queue_size_property_ = new IntProperty( "Queue Size", 10, "Advanced: set the size of the incoming RelativeHumidity message queue. " " Increasing this is useful if your incoming TF data is delayed significantly " "from your RelativeHumidity data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. update_nh_.setCallbackQueue( point_cloud_common_->getCallbackQueue() ); } RelativeHumidityDisplay::~RelativeHumidityDisplay() { delete point_cloud_common_; } void RelativeHumidityDisplay::onInitialize() { MFDClass::onInitialize(); point_cloud_common_->initialize( context_, scene_node_ ); // Set correct initial values subProp("Channel Name")->setValue("relative_humidity"); subProp("Autocompute Intensity Bounds")->setValue(false); subProp("Min Intensity")->setValue(0.0); // 0% relative humidity subProp("Max Intensity")->setValue(1.0); // 100% relative humidity } void RelativeHumidityDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void RelativeHumidityDisplay::processMessage( const sensor_msgs::RelativeHumidityConstPtr& msg ) { sensor_msgs::PointCloud2Ptr filtered(new sensor_msgs::PointCloud2); // Create fields sensor_msgs::PointField x; x.name = "x"; x.offset = 0; x.datatype = sensor_msgs::PointField::FLOAT32; x.count = 1; sensor_msgs::PointField y; y.name = "y"; y.offset = 4; y.datatype = sensor_msgs::PointField::FLOAT32; y.count = 1; sensor_msgs::PointField z; z.name = "z"; z.offset = 8; z.datatype = sensor_msgs::PointField::FLOAT32; z.count = 1; sensor_msgs::PointField relative_humidity; relative_humidity.name = "relative_humidity"; relative_humidity.offset = 12; relative_humidity.datatype = sensor_msgs::PointField::FLOAT64; relative_humidity.count = 1; // Create pointcloud from message filtered->header = msg->header; filtered->fields.push_back(x); filtered->fields.push_back(y); filtered->fields.push_back(z); filtered->fields.push_back(relative_humidity); filtered->data.resize(20); const float zero_float = 0.0; // RelativeHumidity is always on its tf frame memcpy(&filtered->data[x.offset], &zero_float, 4); memcpy(&filtered->data[y.offset], &zero_float, 4); memcpy(&filtered->data[z.offset], &zero_float, 4); memcpy(&filtered->data[relative_humidity.offset], &msg->relative_humidity, 8); filtered->height = 1; filtered->width = 1; filtered->is_bigendian = false; filtered->point_step = 20; filtered->row_step = 1; // Give to point_cloud_common to draw point_cloud_common_->addMessage( filtered ); } void RelativeHumidityDisplay::update( float wall_dt, float ros_dt ) { point_cloud_common_->update( wall_dt, ros_dt ); // Hide unneeded properties subProp("Position Transformer")->hide(); subProp("Color Transformer")->hide(); subProp("Channel Name")->hide(); subProp("Autocompute Intensity Bounds")->hide(); } void RelativeHumidityDisplay::reset() { MFDClass::reset(); point_cloud_common_->reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::RelativeHumidityDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/relative_humidity_display.h000066400000000000000000000052051300447110700250000ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_RELATIVE_HUMIDITY_DISPLAY_H #define RVIZ_RELATIVE_HUMIDITY_DISPLAY_H #include #include #include "rviz/message_filter_display.h" namespace rviz { class IntProperty; class PointCloudCommon; /** * \class RelativeHumidityDisplay * \brief Displays a RelativeHumidity message of type sensor_msgs::RelativeHumidity * */ class RelativeHumidityDisplay: public MessageFilterDisplay { Q_OBJECT public: RelativeHumidityDisplay(); ~RelativeHumidityDisplay(); virtual void reset(); virtual void update( float wall_dt, float ros_dt ); private Q_SLOTS: void updateQueueSize(); protected: /** @brief Do initialization. Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Process a single message. Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::RelativeHumidityConstPtr& msg ); IntProperty* queue_size_property_; PointCloudCommon* point_cloud_common_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/robot_model_display.cpp000066400000000000000000000173721300447110700241210ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/display_context.h" #include "rviz/robot/robot.h" #include "rviz/robot/tf_link_updater.h" #include "rviz/properties/float_property.h" #include "rviz/properties/property.h" #include "rviz/properties/string_property.h" #include "robot_model_display.h" namespace rviz { void linkUpdaterStatusFunction( StatusProperty::Level level, const std::string& link_name, const std::string& text, RobotModelDisplay* display ) { display->setStatus( level, QString::fromStdString( link_name ), QString::fromStdString( text )); } RobotModelDisplay::RobotModelDisplay() : Display() , has_new_transforms_( false ) , time_since_last_transform_( 0.0f ) { visual_enabled_property_ = new Property( "Visual Enabled", true, "Whether to display the visual representation of the robot.", this, SLOT( updateVisualVisible() )); collision_enabled_property_ = new Property( "Collision Enabled", false, "Whether to display the collision representation of the robot.", this, SLOT( updateCollisionVisible() )); update_rate_property_ = new FloatProperty( "Update Interval", 0, "Interval at which to update the links, in seconds. " " 0 means to update every update cycle.", this ); update_rate_property_->setMin( 0 ); alpha_property_ = new FloatProperty( "Alpha", 1, "Amount of transparency to apply to the links.", this, SLOT( updateAlpha() )); alpha_property_->setMin( 0.0 ); alpha_property_->setMax( 1.0 ); robot_description_property_ = new StringProperty( "Robot Description", "robot_description", "Name of the parameter to search for to load the robot description.", this, SLOT( updateRobotDescription() )); tf_prefix_property_ = new StringProperty( "TF Prefix", "", "Robot Model normally assumes the link name is the same as the tf frame name. " " This option allows you to set a prefix. Mainly useful for multi-robot situations.", this, SLOT( updateTfPrefix() )); } RobotModelDisplay::~RobotModelDisplay() { if ( initialized() ) { delete robot_; } } void RobotModelDisplay::onInitialize() { robot_ = new Robot( scene_node_, context_, "Robot: " + getName().toStdString(), this ); updateVisualVisible(); updateCollisionVisible(); updateAlpha(); } void RobotModelDisplay::updateAlpha() { robot_->setAlpha( alpha_property_->getFloat() ); context_->queueRender(); } void RobotModelDisplay::updateRobotDescription() { if( isEnabled() ) { load(); context_->queueRender(); } } void RobotModelDisplay::updateVisualVisible() { robot_->setVisualVisible( visual_enabled_property_->getValue().toBool() ); context_->queueRender(); } void RobotModelDisplay::updateCollisionVisible() { robot_->setCollisionVisible( collision_enabled_property_->getValue().toBool() ); context_->queueRender(); } void RobotModelDisplay::updateTfPrefix() { clearStatuses(); context_->queueRender(); } void RobotModelDisplay::load() { std::string content; if( !update_nh_.getParam( robot_description_property_->getStdString(), content )) { std::string loc; if( update_nh_.searchParam( robot_description_property_->getStdString(), loc )) { update_nh_.getParam( loc, content ); } else { clear(); setStatus( StatusProperty::Error, "URDF", "Parameter [" + robot_description_property_->getString() + "] does not exist, and was not found by searchParam()" ); return; } } if( content.empty() ) { clear(); setStatus( StatusProperty::Error, "URDF", "URDF is empty" ); return; } if( content == robot_description_ ) { return; } robot_description_ = content; TiXmlDocument doc; doc.Parse( robot_description_.c_str() ); if( !doc.RootElement() ) { clear(); setStatus( StatusProperty::Error, "URDF", "URDF failed XML parse" ); return; } urdf::Model descr; if( !descr.initXml( doc.RootElement() )) { clear(); setStatus( StatusProperty::Error, "URDF", "URDF failed Model parse" ); return; } setStatus( StatusProperty::Ok, "URDF", "URDF parsed OK" ); robot_->load( descr ); robot_->update( TFLinkUpdater( context_->getFrameManager(), boost::bind( linkUpdaterStatusFunction, _1, _2, _3, this ), tf_prefix_property_->getStdString() )); } void RobotModelDisplay::onEnable() { load(); robot_->setVisible( true ); } void RobotModelDisplay::onDisable() { robot_->setVisible( false ); clear(); } void RobotModelDisplay::update( float wall_dt, float ros_dt ) { time_since_last_transform_ += wall_dt; float rate = update_rate_property_->getFloat(); bool update = rate < 0.0001f || time_since_last_transform_ >= rate; if( has_new_transforms_ || update ) { robot_->update( TFLinkUpdater( context_->getFrameManager(), boost::bind( linkUpdaterStatusFunction, _1, _2, _3, this ), tf_prefix_property_->getStdString() )); context_->queueRender(); has_new_transforms_ = false; time_since_last_transform_ = 0.0f; } } void RobotModelDisplay::fixedFrameChanged() { has_new_transforms_ = true; } void RobotModelDisplay::clear() { robot_->clear(); clearStatuses(); robot_description_.clear(); } void RobotModelDisplay::reset() { Display::reset(); has_new_transforms_ = true; } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::RobotModelDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/robot_model_display.h000066400000000000000000000064351300447110700235640ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ROBOT_MODEL_DISPLAY_H #define RVIZ_ROBOT_MODEL_DISPLAY_H #include "rviz/display.h" #include #include namespace Ogre { class Entity; class SceneNode; } namespace rviz { class Axes; } namespace rviz { class FloatProperty; class Property; class Robot; class StringProperty; /** * \class RobotModelDisplay * \brief Uses a robot xml description to display the pieces of a robot at the transforms broadcast by rosTF */ class RobotModelDisplay: public Display { Q_OBJECT public: RobotModelDisplay(); virtual ~RobotModelDisplay(); // Overrides from Display virtual void onInitialize(); virtual void update( float wall_dt, float ros_dt ); virtual void fixedFrameChanged(); virtual void reset(); void clear(); private Q_SLOTS: void updateVisualVisible(); void updateCollisionVisible(); void updateTfPrefix(); void updateAlpha(); void updateRobotDescription(); protected: /** @brief Loads a URDF from the ros-param named by our * "Robot Description" property, iterates through the links, and * loads any necessary models. */ virtual void load(); // overrides from Display virtual void onEnable(); virtual void onDisable(); Robot* robot_; ///< Handles actually drawing the robot bool has_new_transforms_; ///< Callback sets this to tell our update function it needs to update the transforms float time_since_last_transform_; std::string robot_description_; Property* visual_enabled_property_; Property* collision_enabled_property_; FloatProperty* update_rate_property_; StringProperty* robot_description_property_; FloatProperty* alpha_property_; StringProperty* tf_prefix_property_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/temperature_display.cpp000066400000000000000000000127201300447110700241410ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/default_plugin/point_cloud_common.h" #include "rviz/default_plugin/point_cloud_transformers.h" #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/properties/int_property.h" #include "rviz/validate_floats.h" #include "temperature_display.h" namespace rviz { TemperatureDisplay::TemperatureDisplay() : point_cloud_common_( new PointCloudCommon( this )) { queue_size_property_ = new IntProperty( "Queue Size", 10, "Advanced: set the size of the incoming Temperature message queue. " " Increasing this is useful if your incoming TF data is delayed significantly " "from your Temperature data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); // PointCloudCommon sets up a callback queue with a thread for each // instance. Use that for processing incoming messages. update_nh_.setCallbackQueue( point_cloud_common_->getCallbackQueue() ); } TemperatureDisplay::~TemperatureDisplay() { delete point_cloud_common_; } void TemperatureDisplay::onInitialize() { MFDClass::onInitialize(); point_cloud_common_->initialize( context_, scene_node_ ); // Set correct initial values subProp("Channel Name")->setValue("temperature"); subProp("Autocompute Intensity Bounds")->setValue(false); subProp("Invert Rainbow")->setValue(true); subProp("Min Intensity")->setValue(0); // Water Freezing subProp("Max Intensity")->setValue(100); // Water Boiling } void TemperatureDisplay::updateQueueSize() { tf_filter_->setQueueSize( (uint32_t) queue_size_property_->getInt() ); } void TemperatureDisplay::processMessage( const sensor_msgs::TemperatureConstPtr& msg ) { sensor_msgs::PointCloud2Ptr filtered(new sensor_msgs::PointCloud2); // Create fields sensor_msgs::PointField x; x.name = "x"; x.offset = 0; x.datatype = sensor_msgs::PointField::FLOAT32; x.count = 1; sensor_msgs::PointField y; y.name = "y"; y.offset = 4; y.datatype = sensor_msgs::PointField::FLOAT32; y.count = 1; sensor_msgs::PointField z; z.name = "z"; z.offset = 8; z.datatype = sensor_msgs::PointField::FLOAT32; z.count = 1; sensor_msgs::PointField temperature; temperature.name = "temperature"; temperature.offset = 12; temperature.datatype = sensor_msgs::PointField::FLOAT64; temperature.count = 1; // Create pointcloud from message filtered->header = msg->header; filtered->fields.push_back(x); filtered->fields.push_back(y); filtered->fields.push_back(z); filtered->fields.push_back(temperature); filtered->data.resize(20); const float zero_float = 0.0; // RelativeHumidity is always on its tf frame memcpy(&filtered->data[x.offset], &zero_float, 4); memcpy(&filtered->data[y.offset], &zero_float, 4); memcpy(&filtered->data[z.offset], &zero_float, 4); memcpy(&filtered->data[temperature.offset], &msg->temperature, 8); filtered->height = 1; filtered->width = 1; filtered->is_bigendian = false; filtered->point_step = 20; filtered->row_step = 1; // Give to point_cloud_common to draw point_cloud_common_->addMessage( filtered ); } void TemperatureDisplay::update( float wall_dt, float ros_dt ) { point_cloud_common_->update( wall_dt, ros_dt ); // Hide unneeded properties subProp("Position Transformer")->hide(); subProp("Color Transformer")->hide(); subProp("Channel Name")->hide(); subProp("Invert Rainbow")->hide(); subProp("Autocompute Intensity Bounds")->hide(); } void TemperatureDisplay::reset() { MFDClass::reset(); point_cloud_common_->reset(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::TemperatureDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/temperature_display.h000066400000000000000000000051141300447110700236050ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TEMPERATURE_DISPLAY_H #define RVIZ_TEMPERATURE_DISPLAY_H #include #include #include "rviz/message_filter_display.h" namespace rviz { class IntProperty; class PointCloudCommon; /** * \class TemperatureDisplay * \brief Displays a Temperature message of type sensor_msgs::Temperature * */ class TemperatureDisplay: public MessageFilterDisplay { Q_OBJECT public: TemperatureDisplay(); ~TemperatureDisplay(); virtual void reset(); virtual void update( float wall_dt, float ros_dt ); private Q_SLOTS: void updateQueueSize(); protected: /** @brief Do initialization. Overridden from MessageFilterDisplay. */ virtual void onInitialize(); /** @brief Process a single message. Overridden from MessageFilterDisplay. */ virtual void processMessage( const sensor_msgs::TemperatureConstPtr& msg ); IntProperty* queue_size_property_; PointCloudCommon* point_cloud_common_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/default_plugin/tf_display.cpp000066400000000000000000000644641300447110700222310ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/ogre_helpers/movable_text.h" #include "rviz/properties/bool_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/quaternion_property.h" #include "rviz/properties/string_property.h" #include "rviz/properties/vector_property.h" #include "rviz/selection/forwards.h" #include "rviz/selection/selection_manager.h" #include "rviz/default_plugin/tf_display.h" namespace rviz { class FrameSelectionHandler: public SelectionHandler { public: FrameSelectionHandler( FrameInfo* frame, TFDisplay* display, DisplayContext* context ); virtual ~FrameSelectionHandler() {} virtual void createProperties( const Picked& obj, Property* parent_property ); virtual void destroyProperties( const Picked& obj, Property* parent_property ); bool getEnabled(); void setEnabled( bool enabled ); void setParentName( std::string parent_name ); void setPosition( const Ogre::Vector3& position ); void setOrientation( const Ogre::Quaternion& orientation ); private: FrameInfo* frame_; TFDisplay* display_; Property* category_property_; BoolProperty* enabled_property_; StringProperty* parent_property_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; }; FrameSelectionHandler::FrameSelectionHandler(FrameInfo* frame, TFDisplay* display, DisplayContext* context ) : SelectionHandler( context ) , frame_( frame ) , display_( display ) , category_property_( NULL ) , enabled_property_( NULL ) , parent_property_( NULL ) , position_property_( NULL ) , orientation_property_( NULL ) { } void FrameSelectionHandler::createProperties( const Picked& obj, Property* parent_property ) { category_property_ = new Property( "Frame " + QString::fromStdString( frame_->name_ ), QVariant(), "", parent_property ); enabled_property_ = new BoolProperty( "Enabled", true, "", category_property_, SLOT( updateVisibilityFromSelection() ), frame_ ); parent_property_ = new StringProperty( "Parent", "", "", category_property_ ); parent_property_->setReadOnly( true ); position_property_ = new VectorProperty( "Position", Ogre::Vector3::ZERO, "", category_property_ ); position_property_->setReadOnly( true ); orientation_property_ = new QuaternionProperty( "Orientation", Ogre::Quaternion::IDENTITY, "", category_property_ ); orientation_property_->setReadOnly( true ); } void FrameSelectionHandler::destroyProperties( const Picked& obj, Property* parent_property ) { delete category_property_; // This deletes its children as well. category_property_ = NULL; enabled_property_ = NULL; parent_property_ = NULL; position_property_ = NULL; orientation_property_ = NULL; } bool FrameSelectionHandler::getEnabled() { if( enabled_property_ ) { return enabled_property_->getBool(); } return false; // should never happen, but don't want to crash if it does. } void FrameSelectionHandler::setEnabled( bool enabled ) { if( enabled_property_ ) { enabled_property_->setBool( enabled ); } } void FrameSelectionHandler::setParentName( std::string parent_name ) { if( parent_property_ ) { parent_property_->setStdString( parent_name ); } } void FrameSelectionHandler::setPosition( const Ogre::Vector3& position ) { if( position_property_ ) { position_property_->setVector( position ); } } void FrameSelectionHandler::setOrientation( const Ogre::Quaternion& orientation ) { if( orientation_property_ ) { orientation_property_->setQuaternion( orientation ); } } typedef std::set S_FrameInfo; TFDisplay::TFDisplay() : Display() , update_timer_( 0.0f ) , changing_single_frame_enabled_state_( false ) { show_names_property_ = new BoolProperty( "Show Names", true, "Whether or not names should be shown next to the frames.", this, SLOT( updateShowNames() )); show_axes_property_ = new BoolProperty( "Show Axes", true, "Whether or not the axes of each frame should be shown.", this, SLOT( updateShowAxes() )); show_arrows_property_ = new BoolProperty( "Show Arrows", true, "Whether or not arrows from child to parent should be shown.", this, SLOT( updateShowArrows() )); scale_property_ = new FloatProperty( "Marker Scale", 1, "Scaling factor for all names, axes and arrows.", this ); update_rate_property_ = new FloatProperty( "Update Interval", 0, "The interval, in seconds, at which to update the frame transforms. 0 means to do so every update cycle.", this ); update_rate_property_->setMin( 0 ); frame_timeout_property_ = new FloatProperty( "Frame Timeout", 15, "The length of time, in seconds, before a frame that has not been updated is considered \"dead\"." " For 1/3 of this time the frame will appear correct, for the second 1/3rd it will fade to gray," " and then it will fade out completely.", this ); frame_timeout_property_->setMin( 1 ); frames_category_ = new Property( "Frames", QVariant(), "The list of all frames.", this ); all_enabled_property_ = new BoolProperty( "All Enabled", true, "Whether all the frames should be enabled or not.", frames_category_, SLOT( allEnabledChanged() ), this ); tree_category_ = new Property( "Tree", QVariant(), "A tree-view of the frames, showing the parent/child relationships.", this ); } TFDisplay::~TFDisplay() { if ( initialized() ) { root_node_->removeAndDestroyAllChildren(); scene_manager_->destroySceneNode( root_node_->getName() ); } } void TFDisplay::onInitialize() { frame_config_enabled_state_.clear(); root_node_ = scene_node_->createChildSceneNode(); names_node_ = root_node_->createChildSceneNode(); arrows_node_ = root_node_->createChildSceneNode(); axes_node_ = root_node_->createChildSceneNode(); } void TFDisplay::load(const Config& config) { Display::load(config); // Load the enabled state for all frames specified in the config, and store // the values in a map so that the enabled state can be properly set once // the frame is created Config c = config.mapGetChild("Frames"); for( Config::MapIterator iter = c.mapIterator(); iter.isValid(); iter.advance() ) { QString key = iter.currentKey(); if( key != "All Enabled" ) { const Config& child = iter.currentChild(); bool enabled = child.mapGetChild("Value").getValue().toBool(); frame_config_enabled_state_[key.toStdString()] = enabled; } } } void TFDisplay::clear() { // Clear the tree. tree_category_->removeChildren(); // Clear the frames category, except for the "All enabled" property, which is first. frames_category_->removeChildren( 1 ); S_FrameInfo to_delete; M_FrameInfo::iterator frame_it = frames_.begin(); M_FrameInfo::iterator frame_end = frames_.end(); for ( ; frame_it != frame_end; ++frame_it ) { to_delete.insert( frame_it->second ); } S_FrameInfo::iterator delete_it = to_delete.begin(); S_FrameInfo::iterator delete_end = to_delete.end(); for ( ; delete_it != delete_end; ++delete_it ) { deleteFrame( *delete_it, false ); } frames_.clear(); update_timer_ = 0.0f; clearStatuses(); } void TFDisplay::onEnable() { root_node_->setVisible( true ); names_node_->setVisible( show_names_property_->getBool() ); arrows_node_->setVisible( show_arrows_property_->getBool() ); axes_node_->setVisible( show_axes_property_->getBool() ); } void TFDisplay::onDisable() { root_node_->setVisible( false ); clear(); } void TFDisplay::updateShowNames() { names_node_->setVisible( show_names_property_->getBool() ); M_FrameInfo::iterator it = frames_.begin(); M_FrameInfo::iterator end = frames_.end(); for (; it != end; ++it) { FrameInfo* frame = it->second; frame->updateVisibilityFromFrame(); } } void TFDisplay::updateShowAxes() { axes_node_->setVisible( show_axes_property_->getBool() ); M_FrameInfo::iterator it = frames_.begin(); M_FrameInfo::iterator end = frames_.end(); for (; it != end; ++it) { FrameInfo* frame = it->second; frame->updateVisibilityFromFrame(); } } void TFDisplay::updateShowArrows() { arrows_node_->setVisible( show_arrows_property_->getBool() ); M_FrameInfo::iterator it = frames_.begin(); M_FrameInfo::iterator end = frames_.end(); for (; it != end; ++it) { FrameInfo* frame = it->second; frame->updateVisibilityFromFrame(); } } void TFDisplay::allEnabledChanged() { if( changing_single_frame_enabled_state_ ) { return; } bool enabled = all_enabled_property_->getBool(); M_FrameInfo::iterator it = frames_.begin(); M_FrameInfo::iterator end = frames_.end(); for (; it != end; ++it) { FrameInfo* frame = it->second; frame->enabled_property_->setBool( enabled ); } } void TFDisplay::update(float wall_dt, float ros_dt) { update_timer_ += wall_dt; float update_rate = update_rate_property_->getFloat(); if( update_rate < 0.0001f || update_timer_ > update_rate ) { updateFrames(); update_timer_ = 0.0f; } } FrameInfo* TFDisplay::getFrameInfo( const std::string& frame ) { M_FrameInfo::iterator it = frames_.find( frame ); if ( it == frames_.end() ) { return NULL; } return it->second; } void TFDisplay::updateFrames() { typedef std::vector V_string; V_string frames; context_->getTFClient()->getFrameStrings( frames ); std::sort(frames.begin(), frames.end()); S_FrameInfo current_frames; { V_string::iterator it = frames.begin(); V_string::iterator end = frames.end(); for ( ; it != end; ++it ) { const std::string& frame = *it; if ( frame.empty() ) { continue; } FrameInfo* info = getFrameInfo( frame ); if (!info) { info = createFrame(frame); } else { updateFrame(info); } current_frames.insert( info ); } } { S_FrameInfo to_delete; M_FrameInfo::iterator frame_it = frames_.begin(); M_FrameInfo::iterator frame_end = frames_.end(); for ( ; frame_it != frame_end; ++frame_it ) { if ( current_frames.find( frame_it->second ) == current_frames.end() ) { to_delete.insert( frame_it->second ); } } S_FrameInfo::iterator delete_it = to_delete.begin(); S_FrameInfo::iterator delete_end = to_delete.end(); for ( ; delete_it != delete_end; ++delete_it ) { deleteFrame( *delete_it, true ); } } context_->queueRender(); } static const Ogre::ColourValue ARROW_HEAD_COLOR(1.0f, 0.1f, 0.6f, 1.0f); static const Ogre::ColourValue ARROW_SHAFT_COLOR(0.8f, 0.8f, 0.3f, 1.0f); FrameInfo* TFDisplay::createFrame(const std::string& frame) { FrameInfo* info = new FrameInfo( this ); frames_.insert( std::make_pair( frame, info ) ); info->name_ = frame; info->last_update_ = ros::Time::now(); info->axes_ = new Axes( scene_manager_, axes_node_, 0.2, 0.02 ); info->axes_->getSceneNode()->setVisible( show_axes_property_->getBool() ); info->selection_handler_.reset( new FrameSelectionHandler( info, this, context_ )); info->selection_handler_->addTrackedObjects( info->axes_->getSceneNode() ); info->name_text_ = new MovableText( frame, "Arial", 0.1 ); info->name_text_->setTextAlignment(MovableText::H_CENTER, MovableText::V_BELOW); info->name_node_ = names_node_->createChildSceneNode(); info->name_node_->attachObject( info->name_text_ ); info->name_node_->setVisible( show_names_property_->getBool() ); info->parent_arrow_ = new Arrow( scene_manager_, arrows_node_, 1.0f, 0.01, 1.0f, 0.08 ); info->parent_arrow_->getSceneNode()->setVisible( false ); info->parent_arrow_->setHeadColor(ARROW_HEAD_COLOR); info->parent_arrow_->setShaftColor(ARROW_SHAFT_COLOR); info->enabled_property_ = new BoolProperty( QString::fromStdString( info->name_ ), true, "Enable or disable this individual frame.", frames_category_, SLOT( updateVisibilityFromFrame() ), info ); info->parent_property_ = new StringProperty( "Parent", "", "Parent of this frame. (Not editable)", info->enabled_property_ ); info->parent_property_->setReadOnly( true ); info->position_property_ = new VectorProperty( "Position", Ogre::Vector3::ZERO, "Position of this frame, in the current Fixed Frame. (Not editable)", info->enabled_property_ ); info->position_property_->setReadOnly( true ); info->orientation_property_ = new QuaternionProperty( "Orientation", Ogre::Quaternion::IDENTITY, "Orientation of this frame, in the current Fixed Frame. (Not editable)", info->enabled_property_ ); info->orientation_property_->setReadOnly( true ); info->rel_position_property_ = new VectorProperty( "Relative Position", Ogre::Vector3::ZERO, "Position of this frame, relative to it's parent frame. (Not editable)", info->enabled_property_ ); info->rel_position_property_->setReadOnly( true ); info->rel_orientation_property_ = new QuaternionProperty( "Relative Orientation", Ogre::Quaternion::IDENTITY, "Orientation of this frame, relative to it's parent frame. (Not editable)", info->enabled_property_ ); info->rel_orientation_property_->setReadOnly( true ); // If the current frame was specified as disabled in the config file // then its enabled state must be updated accordingly if( frame_config_enabled_state_.count(frame) > 0 && !frame_config_enabled_state_[frame] ) { info->enabled_property_->setBool(false); } updateFrame( info ); return info; } Ogre::ColourValue lerpColor(const Ogre::ColourValue& start, const Ogre::ColourValue& end, float t) { return start * t + end * (1 - t); } void TFDisplay::updateFrame( FrameInfo* frame ) { tf::TransformListener* tf = context_->getTFClient(); // Check last received time so we can grey out/fade out frames that have stopped being published ros::Time latest_time; tf->getLatestCommonTime( fixed_frame_.toStdString(), frame->name_, latest_time, 0 ); if(( latest_time != frame->last_time_to_fixed_ ) || ( latest_time == ros::Time() )) { frame->last_update_ = ros::Time::now(); frame->last_time_to_fixed_ = latest_time; } // Fade from color -> grey, then grey -> fully transparent ros::Duration age = ros::Time::now() - frame->last_update_; float frame_timeout = frame_timeout_property_->getFloat(); float one_third_timeout = frame_timeout * 0.3333333f; if( age > ros::Duration( frame_timeout )) { frame->parent_arrow_->getSceneNode()->setVisible(false); frame->axes_->getSceneNode()->setVisible(false); frame->name_node_->setVisible(false); return; } else if (age > ros::Duration(one_third_timeout)) { Ogre::ColourValue grey(0.7, 0.7, 0.7, 1.0); if (age > ros::Duration(one_third_timeout * 2)) { float a = std::max(0.0, (frame_timeout - age.toSec())/one_third_timeout); Ogre::ColourValue c = Ogre::ColourValue(grey.r, grey.g, grey.b, a); frame->axes_->setXColor(c); frame->axes_->setYColor(c); frame->axes_->setZColor(c); frame->name_text_->setColor(c); frame->parent_arrow_->setColor(c.r, c.g, c.b, c.a); } else { float t = std::max(0.0, (one_third_timeout * 2 - age.toSec())/one_third_timeout); frame->axes_->setXColor(lerpColor(frame->axes_->getDefaultXColor(), grey, t)); frame->axes_->setYColor(lerpColor(frame->axes_->getDefaultYColor(), grey, t)); frame->axes_->setZColor(lerpColor(frame->axes_->getDefaultZColor(), grey, t)); frame->name_text_->setColor(lerpColor(Ogre::ColourValue::White, grey, t)); frame->parent_arrow_->setShaftColor(lerpColor(ARROW_SHAFT_COLOR, grey, t)); frame->parent_arrow_->setHeadColor(lerpColor(ARROW_HEAD_COLOR, grey, t)); } } else { frame->axes_->setToDefaultColors(); frame->name_text_->setColor(Ogre::ColourValue::White); frame->parent_arrow_->setHeadColor(ARROW_HEAD_COLOR); frame->parent_arrow_->setShaftColor(ARROW_SHAFT_COLOR); } setStatusStd(StatusProperty::Ok, frame->name_, "Transform OK"); Ogre::Vector3 position; Ogre::Quaternion orientation; if( !context_->getFrameManager()->getTransform( frame->name_, ros::Time(), position, orientation )) { std::stringstream ss; ss << "No transform from [" << frame->name_ << "] to frame [" << fixed_frame_.toStdString() << "]"; setStatusStd(StatusProperty::Warn, frame->name_, ss.str()); ROS_DEBUG( "Error transforming frame '%s' to frame '%s'", frame->name_.c_str(), qPrintable( fixed_frame_ )); frame->name_node_->setVisible( false ); frame->axes_->getSceneNode()->setVisible( false ); frame->parent_arrow_->getSceneNode()->setVisible( false ); return; } frame->selection_handler_->setPosition( position ); frame->selection_handler_->setOrientation( orientation ); bool frame_enabled = frame->enabled_property_->getBool(); frame->axes_->setPosition( position ); frame->axes_->setOrientation( orientation ); frame->axes_->getSceneNode()->setVisible( show_axes_property_->getBool() && frame_enabled); float scale = scale_property_->getFloat(); frame->axes_->setScale( Ogre::Vector3( scale, scale, scale )); frame->name_node_->setPosition( position ); frame->name_node_->setVisible( show_names_property_->getBool() && frame_enabled ); frame->name_node_->setScale( scale, scale, scale ); frame->position_property_->setVector( position ); frame->orientation_property_->setQuaternion( orientation ); std::string old_parent = frame->parent_; frame->parent_.clear(); bool has_parent = tf->getParent( frame->name_, ros::Time(), frame->parent_ ); if( has_parent ) { // If this frame has no tree property or the parent has changed, if( !frame->tree_property_ || old_parent != frame->parent_ ) { // Look up the new parent. M_FrameInfo::iterator parent_it = frames_.find( frame->parent_ ); if( parent_it != frames_.end() ) { FrameInfo* parent = parent_it->second; // If the parent has a tree property, make a new tree property for this frame. if( parent->tree_property_ ) { if(!frame->tree_property_) { frame->tree_property_ = new Property( QString::fromStdString( frame->name_ ), QVariant(), "", parent->tree_property_ ); } else { frame->tree_property_->setParent(parent->tree_property_); frame->tree_property_->setName(QString::fromStdString( frame->name_ )); frame->tree_property_->setValue(QVariant()); frame->tree_property_->setDescription(""); } } } } tf::StampedTransform transform; try { context_->getFrameManager()->getTFClientPtr()->lookupTransform(frame->parent_,frame->name_,ros::Time(0),transform); } catch(tf::TransformException& e) { ROS_DEBUG( "Error transforming frame '%s' (parent of '%s') to frame '%s'", frame->parent_.c_str(), frame->name_.c_str(), qPrintable( fixed_frame_ )); } // get the position/orientation relative to the parent frame Ogre::Vector3 relative_position( transform.getOrigin().x(), transform.getOrigin().y(), transform.getOrigin().z() ); Ogre::Quaternion relative_orientation( transform.getRotation().w(), transform.getRotation().x(), transform.getRotation().y(), transform.getRotation().z() ); frame->rel_position_property_->setVector( relative_position ); frame->rel_orientation_property_->setQuaternion( relative_orientation ); if( show_arrows_property_->getBool() ) { Ogre::Vector3 parent_position; Ogre::Quaternion parent_orientation; if (!context_->getFrameManager()->getTransform(frame->parent_, ros::Time(), parent_position, parent_orientation)) { ROS_DEBUG( "Error transforming frame '%s' (parent of '%s') to frame '%s'", frame->parent_.c_str(), frame->name_.c_str(), qPrintable( fixed_frame_ )); } Ogre::Vector3 direction = parent_position - position; float distance = direction.length(); direction.normalise(); Ogre::Quaternion orient = Ogre::Vector3::NEGATIVE_UNIT_Z.getRotationTo( direction ); frame->distance_to_parent_ = distance; float head_length = ( distance < 0.1*scale ) ? (0.1*scale*distance) : 0.1*scale; float shaft_length = distance - head_length; // aleeper: This was changed from 0.02 and 0.08 to 0.01 and 0.04 to match proper radius handling in arrow.cpp frame->parent_arrow_->set( shaft_length, 0.01*scale, head_length, 0.04*scale ); if ( distance > 0.001f ) { frame->parent_arrow_->getSceneNode()->setVisible( show_arrows_property_->getBool() && frame_enabled ); } else { frame->parent_arrow_->getSceneNode()->setVisible( false ); } frame->parent_arrow_->setPosition( position ); frame->parent_arrow_->setOrientation( orient ); } else { frame->parent_arrow_->getSceneNode()->setVisible( false ); } } else { if ( !frame->tree_property_ || old_parent != frame->parent_ ) { if(!frame->tree_property_) { frame->tree_property_ = new Property( QString::fromStdString( frame->name_ ), QVariant(), "", tree_category_ ); } else { frame->tree_property_->setName(QString::fromStdString( frame->name_ )); frame->tree_property_->setValue(QVariant()); frame->tree_property_->setDescription(""); frame->tree_property_->setParent(tree_category_); } } frame->parent_arrow_->getSceneNode()->setVisible( false ); } frame->parent_property_->setStdString( frame->parent_ ); frame->selection_handler_->setParentName( frame->parent_ ); } void TFDisplay::deleteFrame( FrameInfo* frame, bool delete_properties ) { M_FrameInfo::iterator it = frames_.find( frame->name_ ); ROS_ASSERT( it != frames_.end() ); frames_.erase( it ); delete frame->axes_; context_->getSelectionManager()->removeObject( frame->axes_coll_ ); delete frame->parent_arrow_; delete frame->name_text_; scene_manager_->destroySceneNode( frame->name_node_->getName() ); if( delete_properties ) { delete frame->enabled_property_; delete frame->tree_property_; } delete frame; } void TFDisplay::fixedFrameChanged() { update_timer_ = update_rate_property_->getFloat(); } void TFDisplay::reset() { Display::reset(); clear(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // FrameInfo FrameInfo::FrameInfo( TFDisplay* display ) : display_( display ) , axes_( NULL ) , axes_coll_( 0 ) , parent_arrow_( NULL ) , name_text_( NULL ) , distance_to_parent_( 0.0f ) , arrow_orientation_(Ogre::Quaternion::IDENTITY) , tree_property_( NULL ) {} void FrameInfo::updateVisibilityFromFrame() { bool enabled = enabled_property_->getBool(); selection_handler_->setEnabled( enabled ); setEnabled( enabled ); } void FrameInfo::updateVisibilityFromSelection() { bool enabled = selection_handler_->getEnabled(); enabled_property_->setBool( enabled ); setEnabled( enabled ); } void FrameInfo::setEnabled( bool enabled ) { if( name_node_ ) { name_node_->setVisible( display_->show_names_property_->getBool() && enabled ); } if( axes_ ) { axes_->getSceneNode()->setVisible( display_->show_axes_property_->getBool() && enabled ); } if( parent_arrow_ ) { if( distance_to_parent_ > 0.001f ) { parent_arrow_->getSceneNode()->setVisible( display_->show_arrows_property_->getBool() && enabled ); } else { parent_arrow_->getSceneNode()->setVisible( false ); } } if( display_->all_enabled_property_->getBool() && !enabled) { display_->changing_single_frame_enabled_state_ = true; display_->all_enabled_property_->setBool( false ); display_->changing_single_frame_enabled_state_ = false; } // Update the configuration that stores the enabled state of all frames display_->frame_config_enabled_state_[this->name_] = enabled; display_->context_->queueRender(); } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::TFDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/tf_display.h000066400000000000000000000116211300447110700216610ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TF_DISPLAY_H #define RVIZ_TF_DISPLAY_H #include #include #include #include #include "rviz/selection/forwards.h" #include "rviz/display.h" namespace Ogre { class SceneNode; } namespace rviz { class Arrow; class Axes; class BoolProperty; class FloatProperty; class MovableText; class QuaternionProperty; class StringProperty; class VectorProperty; class FrameInfo; class FrameSelectionHandler; typedef boost::shared_ptr FrameSelectionHandlerPtr; /** @brief Displays a visual representation of the TF hierarchy. */ class TFDisplay: public Display { Q_OBJECT public: TFDisplay(); virtual ~TFDisplay(); virtual void update(float wall_dt, float ros_dt); protected: // Overrides from Display virtual void onInitialize(); virtual void load(const Config& config); virtual void fixedFrameChanged(); virtual void reset(); private Q_SLOTS: void updateShowAxes(); void updateShowArrows(); void updateShowNames(); void allEnabledChanged(); private: void updateFrames(); FrameInfo* createFrame(const std::string& frame); void updateFrame(FrameInfo* frame); void deleteFrame(FrameInfo* frame, bool delete_properties); FrameInfo* getFrameInfo(const std::string& frame); void clear(); // overrides from Display virtual void onEnable(); virtual void onDisable(); Ogre::SceneNode* root_node_; Ogre::SceneNode* names_node_; Ogre::SceneNode* arrows_node_; Ogre::SceneNode* axes_node_; typedef std::map M_FrameInfo; M_FrameInfo frames_; typedef std::map M_EnabledState; M_EnabledState frame_config_enabled_state_; float update_timer_; BoolProperty* show_names_property_; BoolProperty* show_arrows_property_; BoolProperty* show_axes_property_; FloatProperty* update_rate_property_; FloatProperty* frame_timeout_property_; BoolProperty* all_enabled_property_; FloatProperty* scale_property_; Property* frames_category_; Property* tree_category_; bool changing_single_frame_enabled_state_; friend class FrameInfo; }; /** @brief Internal class needed only by TFDisplay. */ class FrameInfo: public QObject { Q_OBJECT public: FrameInfo( TFDisplay* display ); /** @brief Set this frame to be visible or invisible. */ void setEnabled( bool enabled ); public Q_SLOTS: /** @brief Update whether the frame is visible or not, based on the enabled_property_ in this FrameInfo. */ void updateVisibilityFromFrame(); /** @brief Update whether the frame is visible or not, based on the enabled_property_ in the selection handler. */ void updateVisibilityFromSelection(); public: TFDisplay* display_; std::string name_; std::string parent_; Axes* axes_; CollObjectHandle axes_coll_; FrameSelectionHandlerPtr selection_handler_; Arrow* parent_arrow_; MovableText* name_text_; Ogre::SceneNode* name_node_; float distance_to_parent_; Ogre::Quaternion arrow_orientation_; ros::Time last_update_; ros::Time last_time_to_fixed_; VectorProperty* rel_position_property_; QuaternionProperty* rel_orientation_property_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; StringProperty* parent_property_; BoolProperty* enabled_property_; Property* tree_property_; }; } // end namespace rviz #endif // RVIZ_TF_DISPLAY_H rviz-1.12.4/src/rviz/default_plugin/tools/000077500000000000000000000000001300447110700205115ustar00rootroot00000000000000rviz-1.12.4/src/rviz/default_plugin/tools/focus_tool.cpp000066400000000000000000000064711300447110700234010ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/viewport_mouse_event.h" #include "rviz/load_resource.h" #include "rviz/render_panel.h" #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include "rviz/view_controller.h" #include "rviz/default_plugin/tools/focus_tool.h" #include namespace rviz { FocusTool::FocusTool() : Tool() { } FocusTool::~FocusTool() { } void FocusTool::onInitialize() { std_cursor_ = getDefaultCursor(); hit_cursor_ = makeIconCursor( "package://rviz/icons/crosshair.svg" ); } void FocusTool::activate() { } void FocusTool::deactivate() { } int FocusTool::processMouseEvent( ViewportMouseEvent& event ) { int flags = 0; Ogre::Vector3 pos; bool success = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, pos ); setCursor( success ? hit_cursor_ : std_cursor_ ); if ( !success ) { Ogre::Ray mouse_ray = event.viewport->getCamera()->getCameraToViewportRay( (float)event.x / (float)event.viewport->getActualWidth(), (float)event.y / (float)event.viewport->getActualHeight() ); pos = mouse_ray.getPoint(1.0); setStatus( "Left-Click: Look in this direction." ); } else { std::ostringstream s; s << "Left-Click: Focus on this point."; s.precision(3); s << " [" << pos.x << "," << pos.y << "," << pos.z << "]"; setStatus( s.str().c_str() ); } if( event.leftUp() ) { if ( event.panel->getViewController() ) { event.panel->getViewController()->lookAt( pos ); } flags |= Finished; } return flags; } } #include PLUGINLIB_EXPORT_CLASS( rviz::FocusTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/focus_tool.h000066400000000000000000000041471300447110700230440ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_FOCUS_TOOL_H #define RVIZ_FOCUS_TOOL_H #include "rviz/tool.h" #include namespace rviz { //! The Focus Tool allows the user to set the focal point of the current //! view controller with a single mouse click. class FocusTool: public Tool { public: FocusTool(); virtual ~FocusTool(); virtual void onInitialize(); virtual void activate(); virtual void deactivate(); virtual int processMouseEvent( ViewportMouseEvent& event ); protected: QCursor std_cursor_; QCursor hit_cursor_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/tools/goal_tool.cpp000066400000000000000000000062051300447110700231770ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/display_context.h" #include "rviz/properties/string_property.h" #include "rviz/default_plugin/tools/goal_tool.h" namespace rviz { GoalTool::GoalTool() { shortcut_key_ = 'g'; topic_property_ = new StringProperty( "Topic", "goal", "The topic on which to publish navigation goals.", getPropertyContainer(), SLOT( updateTopic() ), this ); } void GoalTool::onInitialize() { PoseTool::onInitialize(); setName( "2D Nav Goal" ); updateTopic(); } void GoalTool::updateTopic() { pub_ = nh_.advertise( topic_property_->getStdString(), 1 ); } void GoalTool::onPoseSet(double x, double y, double theta) { std::string fixed_frame = context_->getFixedFrame().toStdString(); tf::Quaternion quat; quat.setRPY(0.0, 0.0, theta); tf::Stamped p = tf::Stamped(tf::Pose(quat, tf::Point(x, y, 0.0)), ros::Time::now(), fixed_frame); geometry_msgs::PoseStamped goal; tf::poseStampedTFToMsg(p, goal); ROS_INFO("Setting goal: Frame:%s, Position(%.3f, %.3f, %.3f), Orientation(%.3f, %.3f, %.3f, %.3f) = Angle: %.3f\n", fixed_frame.c_str(), goal.pose.position.x, goal.pose.position.y, goal.pose.position.z, goal.pose.orientation.x, goal.pose.orientation.y, goal.pose.orientation.z, goal.pose.orientation.w, theta); pub_.publish(goal); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::GoalTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/goal_tool.h000066400000000000000000000043251300447110700226450ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_GOAL_TOOL_H #define RVIZ_GOAL_TOOL_H #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include # include # include "rviz/default_plugin/tools/pose_tool.h" #endif namespace rviz { class Arrow; class DisplayContext; class StringProperty; class GoalTool: public PoseTool { Q_OBJECT public: GoalTool(); virtual ~GoalTool() {} virtual void onInitialize(); protected: virtual void onPoseSet(double x, double y, double theta); private Q_SLOTS: void updateTopic(); private: ros::NodeHandle nh_; ros::Publisher pub_; StringProperty* topic_property_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/tools/initial_pose_tool.cpp000066400000000000000000000063351300447110700247400ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/display_context.h" #include "rviz/properties/string_property.h" #include "rviz/default_plugin/tools/initial_pose_tool.h" namespace rviz { InitialPoseTool::InitialPoseTool() { shortcut_key_ = 'p'; topic_property_ = new StringProperty( "Topic", "initialpose", "The topic on which to publish initial pose estimates.", getPropertyContainer(), SLOT( updateTopic() ), this ); } void InitialPoseTool::onInitialize() { PoseTool::onInitialize(); setName( "2D Pose Estimate" ); updateTopic(); } void InitialPoseTool::updateTopic() { pub_ = nh_.advertise( topic_property_->getStdString(), 1 ); } void InitialPoseTool::onPoseSet(double x, double y, double theta) { std::string fixed_frame = context_->getFixedFrame().toStdString(); geometry_msgs::PoseWithCovarianceStamped pose; pose.header.frame_id = fixed_frame; pose.header.stamp = ros::Time::now(); pose.pose.pose.position.x = x; pose.pose.pose.position.y = y; tf::Quaternion quat; quat.setRPY(0.0, 0.0, theta); tf::quaternionTFToMsg(quat, pose.pose.pose.orientation); pose.pose.covariance[6*0+0] = 0.5 * 0.5; pose.pose.covariance[6*1+1] = 0.5 * 0.5; pose.pose.covariance[6*5+5] = M_PI/12.0 * M_PI/12.0; ROS_INFO("Setting pose: %.3f %.3f %.3f [frame=%s]", x, y, theta, fixed_frame.c_str()); pub_.publish(pose); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::InitialPoseTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/initial_pose_tool.h000066400000000000000000000043721300447110700244040ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_INITIAL_POSE_TOOL_H #define RVIZ_INITIAL_POSE_TOOL_H #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include # include # include "rviz/default_plugin/tools/pose_tool.h" #endif namespace rviz { class Arrow; class DisplayContext; class StringProperty; class InitialPoseTool: public PoseTool { Q_OBJECT public: InitialPoseTool(); virtual ~InitialPoseTool() {} virtual void onInitialize(); protected: virtual void onPoseSet(double x, double y, double theta); private Q_SLOTS: void updateTopic(); private: ros::NodeHandle nh_; ros::Publisher pub_; StringProperty* topic_property_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/tools/interaction_tool.cpp000066400000000000000000000145651300447110700246040ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "rviz/render_panel.h" #include "rviz/selection/selection_handler.h" #include "rviz/selection/selection_manager.h" #include "rviz/view_controller.h" #include "rviz/viewport_mouse_event.h" #include "rviz/viewport_mouse_event.h" #include "rviz/visualization_manager.h" #include "rviz/load_resource.h" #include "rviz/properties/bool_property.h" #include "rviz/default_plugin/tools/interaction_tool.h" namespace rviz { InteractionTool::InteractionTool() { shortcut_key_ = 'i'; hide_inactive_property_ = new BoolProperty("Hide Inactive Objects", true, "While holding down a mouse button, hide all other Interactive Objects.", getPropertyContainer(), SLOT( hideInactivePropertyChanged() ), this ); } InteractionTool::~InteractionTool() { } void InteractionTool::onInitialize() { move_tool_.initialize( context_ ); last_selection_frame_count_ = context_->getFrameCount(); deactivate(); } void InteractionTool::activate() { context_->getSelectionManager()->enableInteraction(true); context_->getSelectionManager()->setTextureSize(1); } void InteractionTool::deactivate() { context_->getSelectionManager()->enableInteraction(false); } void InteractionTool::updateFocus( const ViewportMouseEvent& event ) { M_Picked results; // Pick exactly 1 pixel context_->getSelectionManager()->pick( event.viewport, event.x, event.y, event.x + 1, event.y + 1, results, true ); last_selection_frame_count_ = context_->getFrameCount(); InteractiveObjectPtr new_focused_object; // look for a valid handle in the result. M_Picked::iterator result_it = results.begin(); if( result_it != results.end() ) { Picked pick = result_it->second; SelectionHandler* handler = context_->getSelectionManager()->getHandler( pick.handle ); if ( pick.pixel_count > 0 && handler ) { InteractiveObjectPtr object = handler->getInteractiveObject().lock(); if( object && object->isInteractive() ) { new_focused_object = object; } } } // If the mouse has gone from one object to another, defocus the old // and focus the new. InteractiveObjectPtr new_obj = new_focused_object; InteractiveObjectPtr old_obj = focused_object_.lock(); if( new_obj != old_obj ) { // Only copy the event contents here, once we know we need to use // a modified version of it. ViewportMouseEvent event_copy = event; if( old_obj ) { event_copy.type = QEvent::FocusOut; old_obj->handleMouseEvent( event_copy ); } if( new_obj ) { event_copy.type = QEvent::FocusIn; new_obj->handleMouseEvent( event_copy ); } } focused_object_ = new_focused_object; } int InteractionTool::processMouseEvent( ViewportMouseEvent& event ) { int flags = 0; if ( event.panel->contextMenuVisible() ) { return flags; } // make sure we let the vis. manager render at least one frame between selection updates bool need_selection_update = context_->getFrameCount() > last_selection_frame_count_; // We are dragging if a button was down and is still down Qt::MouseButtons buttons = event.buttons_down & ( Qt::LeftButton | Qt::RightButton | Qt::MidButton ); if ( event.type == QEvent::MouseButtonPress ) buttons &= ~event.acting_button; bool dragging = buttons != 0; // unless we're dragging, check if there's a new object under the mouse if( need_selection_update && !dragging && event.type != QEvent::MouseButtonRelease ) { updateFocus( event ); flags = Render; } { InteractiveObjectPtr focused_object = focused_object_.lock(); if( focused_object ) { focused_object->handleMouseEvent( event ); setCursor( focused_object->getCursor() ); // this will disable everything but the current interactive object if ( hide_inactive_property_->getBool() ) { context_->getSelectionManager()->enableInteraction(!dragging); } } else if( event.panel->getViewController() ) { move_tool_.processMouseEvent( event ); setCursor( move_tool_.getCursor() ); if ( hide_inactive_property_->getBool() ) { context_->getSelectionManager()->enableInteraction(true); } } } if( event.type == QEvent::MouseButtonRelease ) { updateFocus( event ); } return flags; } int InteractionTool::processKeyEvent( QKeyEvent* event, RenderPanel* panel ) { return move_tool_.processKeyEvent( event, panel ); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::InteractionTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/interaction_tool.h000066400000000000000000000051161300447110700242410ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_INTERACTION_TOOL_H #define RVIZ_INTERACTION_TOOL_H #include #include #include #include "move_tool.h" namespace rviz { class BoolProperty; class InteractionTool : public Tool { Q_OBJECT public: InteractionTool(); virtual ~InteractionTool(); virtual void onInitialize(); virtual void activate(); virtual void deactivate(); virtual int processMouseEvent( ViewportMouseEvent& event ); virtual int processKeyEvent( QKeyEvent* event, RenderPanel* panel ); public Q_SLOTS: void hideInactivePropertyChanged() {}; protected: /** @brief Check if the mouse has moved from one object to another, * and update focused_object_ if so. */ void updateFocus( const ViewportMouseEvent& event ); /** @brief The object (control) which currently has the mouse focus. */ InteractiveObjectWPtr focused_object_; uint64_t last_selection_frame_count_; MoveTool move_tool_; BoolProperty *hide_inactive_property_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/tools/measure_tool.cpp000066400000000000000000000067741300447110700237310ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * measure_tool.cpp * * Created on: Aug 8, 2012 * Author: gossow */ #include "measure_tool.h" #include "rviz/ogre_helpers/line.h" #include "rviz/viewport_mouse_event.h" #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include "rviz/load_resource.h" #include #include namespace rviz { MeasureTool::MeasureTool() : state_(START), length_(-1) { } MeasureTool::~MeasureTool() { delete line_; } void MeasureTool::onInitialize() { line_ = new Line(context_->getSceneManager()); std_cursor_ = getDefaultCursor(); hit_cursor_ = makeIconCursor( "package://rviz/icons/crosshair.svg" ); } void MeasureTool::activate() { state_ = START; } void MeasureTool::deactivate() { } int MeasureTool::processMouseEvent( ViewportMouseEvent& event ) { int flags = 0; Ogre::Vector3 pos; std::stringstream ss; bool success = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, pos ); setCursor( success ? hit_cursor_ : std_cursor_ ); switch ( state_ ) { case START: break; case END: if ( success ) { line_->setPoints(start_,pos); length_ = (start_-pos).length(); } break; } if ( length_ > 0.0 ) { ss << "[Length: " << length_ << "m] "; } ss << "Click on two points to measure their distance. Right-click to reset."; setStatus( QString( ss.str().c_str() ) ); if( event.leftUp() && success ) { switch ( state_ ) { case START: start_ = pos; state_ = END; break; case END: end_ = pos; state_ = START; line_->setPoints(start_,end_); break; } flags |= Render; } if ( event.rightUp() ) { state_ = START; line_->setVisible(false); } return flags; } } /* namespace rviz */ #include PLUGINLIB_EXPORT_CLASS( rviz::MeasureTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/measure_tool.h000066400000000000000000000043651300447110700233700ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * measure_tool.h * * Created on: Aug 8, 2012 * Author: gossow */ #ifndef MEASURE_TOOL_H_ #define MEASURE_TOOL_H_ #include "rviz/tool.h" #include namespace rviz { class Line; class MeasureTool : public Tool { public: MeasureTool(); virtual ~MeasureTool(); virtual void onInitialize(); virtual void activate(); virtual void deactivate(); virtual int processMouseEvent( ViewportMouseEvent& event ); private: enum { START, END } state_; Line* line_; Ogre::Vector3 start_; Ogre::Vector3 end_; float length_; QCursor std_cursor_; QCursor hit_cursor_; }; } /* namespace rviz */ #endif /* MEASURE_TOOL_H_ */ rviz-1.12.4/src/rviz/default_plugin/tools/move_tool.cpp000066400000000000000000000052301300447110700232200ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/display_context.h" #include "rviz/render_panel.h" #include "rviz/viewport_mouse_event.h" #include "rviz/selection/selection_manager.h" #include "rviz/view_controller.h" #include "rviz/view_manager.h" #include "rviz/load_resource.h" #include "rviz/default_plugin/tools/move_tool.h" namespace rviz { MoveTool::MoveTool() { shortcut_key_ = 'm'; // this is needed as the move tool is instantiated by other tools setIcon( loadPixmap("package://rviz/icons/classes/MoveCamera.png") ); } int MoveTool::processMouseEvent( ViewportMouseEvent& event ) { if (event.panel->getViewController()) { event.panel->getViewController()->handleMouseEvent(event); setCursor( event.panel->getViewController()->getCursor() ); } return 0; } int MoveTool::processKeyEvent( QKeyEvent* event, RenderPanel* panel ) { if( context_->getViewManager()->getCurrent() ) { context_->getViewManager()->getCurrent()->handleKeyEvent( event, panel ); } return Render; } } // namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::MoveTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/move_tool.h000066400000000000000000000037061300447110700226730ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MOVE_TOOL_H #define RVIZ_MOVE_TOOL_H #include "rviz/tool.h" namespace rviz { class DisplayContext; class MoveTool: public Tool { public: MoveTool(); virtual void activate() {} virtual void deactivate() {} virtual int processMouseEvent( ViewportMouseEvent& event ); virtual int processKeyEvent( QKeyEvent* event, RenderPanel* panel ); }; } #endif rviz-1.12.4/src/rviz/default_plugin/tools/point_tool.cpp000066400000000000000000000100011300447110700233730ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/viewport_mouse_event.h" #include "rviz/load_resource.h" #include "rviz/render_panel.h" #include "rviz/display_context.h" #include "rviz/selection/selection_manager.h" #include "rviz/view_controller.h" #include "rviz/default_plugin/tools/point_tool.h" #include "rviz/properties/bool_property.h" #include "rviz/properties/string_property.h" #include #include namespace rviz { PointTool::PointTool() : Tool() { topic_property_ = new StringProperty( "Topic", "/clicked_point", "The topic on which to publish points.", getPropertyContainer(), SLOT( updateTopic() ), this ); auto_deactivate_property_ = new BoolProperty( "Single click", true, "Switch away from this tool after one click.", getPropertyContainer(), SLOT( updateAutoDeactivate() ), this ); updateTopic(); } PointTool::~PointTool() { } void PointTool::onInitialize() { hit_cursor_ = cursor_; std_cursor_ = getDefaultCursor(); } void PointTool::activate() { } void PointTool::deactivate() { } void PointTool::updateTopic() { pub_ = nh_.advertise( topic_property_->getStdString(), 1 ); } void PointTool::updateAutoDeactivate() { } int PointTool::processMouseEvent( ViewportMouseEvent& event ) { int flags = 0; Ogre::Vector3 pos; bool success = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, pos ); setCursor( success ? hit_cursor_ : std_cursor_ ); if ( success ) { std::ostringstream s; s << "Left-Click: Select this point."; s.precision(3); s << " [" << pos.x << "," << pos.y << "," << pos.z << "]"; setStatus( s.str().c_str() ); if( event.leftUp() ) { geometry_msgs::PointStamped ps; ps.point.x = pos.x; ps.point.y = pos.y; ps.point.z = pos.z; ps.header.frame_id = context_->getFixedFrame().toStdString(); ps.header.stamp = ros::Time::now(); pub_.publish( ps ); if ( auto_deactivate_property_->getBool() ) { flags |= Finished; } } } else { setStatus( "Move over an object to select the target point." ); } return flags; } } #include PLUGINLIB_EXPORT_CLASS( rviz::PointTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/point_tool.h000066400000000000000000000047741300447110700230640ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POINT_TOOL_H #define RVIZ_POINT_TOOL_H #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include # include # include "rviz/tool.h" # include # include #endif namespace rviz { class StringProperty; class BoolProperty; //! The Point Tool allows the user to click on a point which //! gets published as a PointStamped message. class PointTool: public Tool { Q_OBJECT public: PointTool(); virtual ~PointTool(); virtual void onInitialize(); virtual void activate(); virtual void deactivate(); virtual int processMouseEvent( ViewportMouseEvent& event ); public Q_SLOTS: void updateTopic(); void updateAutoDeactivate(); protected: QCursor std_cursor_; QCursor hit_cursor_; ros::NodeHandle nh_; ros::Publisher pub_; StringProperty* topic_property_; BoolProperty* auto_deactivate_property_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/tools/pose_tool.cpp000066400000000000000000000106001300447110700232150ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/geometry.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/viewport_mouse_event.h" #include "rviz/load_resource.h" #include "rviz/render_panel.h" #include "rviz/default_plugin/tools/pose_tool.h" namespace rviz { PoseTool::PoseTool() : Tool() , arrow_( NULL ) { } PoseTool::~PoseTool() { delete arrow_; } void PoseTool::onInitialize() { arrow_ = new Arrow( scene_manager_, NULL, 2.0f, 0.2f, 0.5f, 0.35f ); arrow_->setColor( 0.0f, 1.0f, 0.0f, 1.0f ); arrow_->getSceneNode()->setVisible( false ); } void PoseTool::activate() { setStatus( "Click and drag mouse to set position/orientation." ); state_ = Position; } void PoseTool::deactivate() { arrow_->getSceneNode()->setVisible( false ); } int PoseTool::processMouseEvent( ViewportMouseEvent& event ) { int flags = 0; if( event.leftDown() ) { ROS_ASSERT( state_ == Position ); Ogre::Vector3 intersection; Ogre::Plane ground_plane( Ogre::Vector3::UNIT_Z, 0.0f ); if( getPointOnPlaneFromWindowXY( event.viewport, ground_plane, event.x, event.y, intersection )) { pos_ = intersection; arrow_->setPosition( pos_ ); state_ = Orientation; flags |= Render; } } else if( event.type == QEvent::MouseMove && event.left() ) { if( state_ == Orientation ) { //compute angle in x-y plane Ogre::Vector3 cur_pos; Ogre::Plane ground_plane( Ogre::Vector3::UNIT_Z, 0.0f ); if( getPointOnPlaneFromWindowXY( event.viewport, ground_plane, event.x, event.y, cur_pos )) { double angle = atan2( cur_pos.y - pos_.y, cur_pos.x - pos_.x ); arrow_->getSceneNode()->setVisible( true ); //we need base_orient, since the arrow goes along the -z axis by default (for historical reasons) Ogre::Quaternion orient_x = Ogre::Quaternion( Ogre::Radian(-Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_Y ); arrow_->setOrientation( Ogre::Quaternion( Ogre::Radian(angle), Ogre::Vector3::UNIT_Z ) * orient_x ); flags |= Render; } } } else if( event.leftUp() ) { if( state_ == Orientation ) { //compute angle in x-y plane Ogre::Vector3 cur_pos; Ogre::Plane ground_plane( Ogre::Vector3::UNIT_Z, 0.0f ); if( getPointOnPlaneFromWindowXY( event.viewport, ground_plane, event.x, event.y, cur_pos )) { double angle = atan2( cur_pos.y - pos_.y, cur_pos.x - pos_.x ); onPoseSet(pos_.x, pos_.y, angle); flags |= (Finished|Render); } } } return flags; } } rviz-1.12.4/src/rviz/default_plugin/tools/pose_tool.h000066400000000000000000000042771300447110700226770ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_POSE_TOOL_H #define RVIZ_POSE_TOOL_H #include #include #include #include "rviz/tool.h" namespace rviz { class Arrow; class DisplayContext; class PoseTool: public Tool { public: PoseTool(); virtual ~PoseTool(); virtual void onInitialize(); virtual void activate(); virtual void deactivate(); virtual int processMouseEvent( ViewportMouseEvent& event ); protected: virtual void onPoseSet( double x, double y, double theta ) = 0; Arrow* arrow_; enum State { Position, Orientation }; State state_; Ogre::Vector3 pos_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/tools/selection_tool.cpp000066400000000000000000000114051300447110700242400ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "move_tool.h" #include "rviz/ogre_helpers/camera_base.h" #include "rviz/ogre_helpers/qt_ogre_render_window.h" #include "rviz/selection/selection_manager.h" #include "rviz/visualization_manager.h" #include "rviz/render_panel.h" #include "rviz/display.h" #include "rviz/viewport_mouse_event.h" #include "rviz/load_resource.h" #include "selection_tool.h" namespace rviz { SelectionTool::SelectionTool() : Tool() , move_tool_( new MoveTool() ) , selecting_( false ) , sel_start_x_( 0 ) , sel_start_y_( 0 ) , moving_( false ) { shortcut_key_ = 's'; access_all_keys_ = true; } SelectionTool::~SelectionTool() { delete move_tool_; } void SelectionTool::onInitialize() { move_tool_->initialize( context_ ); } void SelectionTool::activate() { setStatus( "Click and drag to select objects on the screen." ); context_->getSelectionManager()->setTextureSize(512); selecting_ = false; moving_ = false; // context_->getSelectionManager()->enableInteraction(true); } void SelectionTool::deactivate() { context_->getSelectionManager()->removeHighlight(); } void SelectionTool::update(float wall_dt, float ros_dt) { SelectionManager* sel_manager = context_->getSelectionManager(); if (!selecting_) { sel_manager->removeHighlight(); } } int SelectionTool::processMouseEvent( ViewportMouseEvent& event ) { SelectionManager* sel_manager = context_->getSelectionManager(); int flags = 0; if( event.alt() ) { moving_ = true; selecting_ = false; } else { moving_ = false; if( event.leftDown() ) { selecting_ = true; sel_start_x_ = event.x; sel_start_y_ = event.y; } } if( selecting_ ) { sel_manager->highlight( event.viewport, sel_start_x_, sel_start_y_, event.x, event.y ); if( event.leftUp() ) { SelectionManager::SelectType type = SelectionManager::Replace; M_Picked selection; if( event.shift() ) { type = SelectionManager::Add; } else if( event.control() ) { type = SelectionManager::Remove; } sel_manager->select( event.viewport, sel_start_x_, sel_start_y_, event.x, event.y, type ); selecting_ = false; } flags |= Render; } else if( moving_ ) { sel_manager->removeHighlight(); flags = move_tool_->processMouseEvent( event ); if( event.type == QEvent::MouseButtonRelease ) { moving_ = false; } } else { sel_manager->highlight( event.viewport, event.x, event.y, event.x, event.y ); } return flags; } int SelectionTool::processKeyEvent( QKeyEvent* event, RenderPanel* panel ) { SelectionManager* sel_manager = context_->getSelectionManager(); if( event->key() == Qt::Key_F ) { sel_manager->focusOnSelection(); } return Render; } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::SelectionTool, rviz::Tool ) rviz-1.12.4/src/rviz/default_plugin/tools/selection_tool.h000066400000000000000000000044461300447110700237140ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SELECTION_TOOL_H #define RVIZ_SELECTION_TOOL_H #include "rviz/tool.h" #include "rviz/selection/forwards.h" #include namespace Ogre { class Viewport; } namespace rviz { class MoveTool; class SelectionTool : public Tool { public: SelectionTool(); virtual ~SelectionTool(); virtual void onInitialize(); virtual void activate(); virtual void deactivate(); virtual int processMouseEvent( ViewportMouseEvent& event ); virtual int processKeyEvent( QKeyEvent* event, RenderPanel* panel ); virtual void update(float wall_dt, float ros_dt); private: MoveTool* move_tool_; bool selecting_; int sel_start_x_; int sel_start_y_; M_Picked highlight_; bool moving_; }; } #endif rviz-1.12.4/src/rviz/default_plugin/view_controllers/000077500000000000000000000000001300447110700227515ustar00rootroot00000000000000rviz-1.12.4/src/rviz/default_plugin/view_controllers/fixed_orientation_ortho_view_controller.cpp000066400000000000000000000162041300447110700337020ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/ogre_helpers/orthographic.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/float_property.h" #include "rviz/viewport_mouse_event.h" #include "rviz/default_plugin/view_controllers/fixed_orientation_ortho_view_controller.h" namespace rviz { FixedOrientationOrthoViewController::FixedOrientationOrthoViewController() : dragging_( false ) { scale_property_ = new FloatProperty( "Scale", 10, "How much to scale up the size of things in the scene.", this ); angle_property_ = new FloatProperty( "Angle", 0, "Angle around the Z axis to rotate.", this ); x_property_ = new FloatProperty( "X", 0, "X component of camera position.", this ); y_property_ = new FloatProperty( "Y", 0, "Y component of camera position.", this ); } FixedOrientationOrthoViewController::~FixedOrientationOrthoViewController() { } void FixedOrientationOrthoViewController::onInitialize() { FramePositionTrackingViewController::onInitialize(); camera_->setProjectionType( Ogre::PT_ORTHOGRAPHIC ); camera_->setFixedYawAxis( false ); } void FixedOrientationOrthoViewController::reset() { scale_property_->setFloat( 10 ); angle_property_->setFloat( 0 ); x_property_->setFloat( 0 ); y_property_->setFloat( 0 ); } void FixedOrientationOrthoViewController::handleMouseEvent(ViewportMouseEvent& event) { if ( event.shift() ) { setStatus( "Left-Click: Move X/Y." ); } else { setStatus( "Left-Click: Rotate. Middle-Click: Move X/Y. Right-Click:: Zoom. Shift: More options." ); } bool moved = false; int32_t diff_x = 0; int32_t diff_y = 0; if( event.type == QEvent::MouseButtonPress ) { dragging_ = true; } else if( event.type == QEvent::MouseButtonRelease ) { dragging_ = false; } else if( dragging_ && event.type == QEvent::MouseMove ) { diff_x = event.x - event.last_x; diff_y = event.y - event.last_y; moved = true; } if( event.left() && !event.shift() ) { setCursor( Rotate2D ); angle_property_->add( diff_x * 0.005 ); orientCamera(); } else if( event.middle() || ( event.shift() && event.left() )) { setCursor( MoveXY ); float scale = scale_property_->getFloat(); move( -diff_x / scale, diff_y / scale ); } else if( event.right() ) { setCursor( Zoom ); scale_property_->multiply( 1.0 - diff_y * 0.01 ); } else { setCursor( event.shift() ? MoveXY : Rotate2D ); } if ( event.wheel_delta != 0 ) { int diff = event.wheel_delta; scale_property_->multiply( 1.0 - (-diff) * 0.001 ); moved = true; } if (moved) { context_->queueRender(); emitConfigChanged(); } } void FixedOrientationOrthoViewController::orientCamera() { camera_->setOrientation( Ogre::Quaternion( Ogre::Radian( angle_property_->getFloat() ), Ogre::Vector3::UNIT_Z )); } void FixedOrientationOrthoViewController::mimic( ViewController* source_view ) { FramePositionTrackingViewController::mimic( source_view ); if( FixedOrientationOrthoViewController* source_ortho = qobject_cast( source_view )) { scale_property_->setFloat( source_ortho->scale_property_->getFloat() ); angle_property_->setFloat( source_ortho->angle_property_->getFloat() ); x_property_->setFloat( source_ortho->x_property_->getFloat() ); y_property_->setFloat( source_ortho->y_property_->getFloat() ); } else { Ogre::Camera* source_camera = source_view->getCamera(); setPosition( source_camera->getPosition() ); } } void FixedOrientationOrthoViewController::update(float dt, float ros_dt) { FramePositionTrackingViewController::update( dt, ros_dt ); updateCamera(); } void FixedOrientationOrthoViewController::lookAt( const Ogre::Vector3& point ) { setPosition( point - target_scene_node_->getPosition() ); } void FixedOrientationOrthoViewController::onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation) { move( old_reference_position.x - reference_position_.x, old_reference_position.y - reference_position_.y ); } void FixedOrientationOrthoViewController::updateCamera() { orientCamera(); float width = camera_->getViewport()->getActualWidth(); float height = camera_->getViewport()->getActualHeight(); float scale = scale_property_->getFloat(); Ogre::Matrix4 proj; buildScaledOrthoMatrix( proj, -width / scale / 2, width / scale / 2, -height / scale / 2, height / scale / 2, camera_->getNearClipDistance(), camera_->getFarClipDistance() ); camera_->setCustomProjectionMatrix(true, proj); // For Z, we use half of the far-clip distance set in // selection_context.cpp, so that the shader program which computes // depth can see equal distances above and below the Z=0 plane. camera_->setPosition( x_property_->getFloat(), y_property_->getFloat(), 500 ); } void FixedOrientationOrthoViewController::setPosition( const Ogre::Vector3& pos_rel_target ) { x_property_->setFloat( pos_rel_target.x ); y_property_->setFloat( pos_rel_target.y ); } void FixedOrientationOrthoViewController::move( float dx, float dy ) { float angle = angle_property_->getFloat(); x_property_->add( dx*cos(angle)-dy*sin(angle) ); y_property_->add( dx*sin(angle)+dy*cos(angle) ); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::FixedOrientationOrthoViewController, rviz::ViewController ) rviz-1.12.4/src/rviz/default_plugin/view_controllers/fixed_orientation_ortho_view_controller.h000066400000000000000000000061051300447110700333460ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_FIXED_ORIENTATION_ORTHO_VIEW_CONTROLLER_H #define RVIZ_FIXED_ORIENTATION_ORTHO_VIEW_CONTROLLER_H #include "rviz/frame_position_tracking_view_controller.h" #include namespace rviz { class FloatProperty; class SceneNode; class Shape; class FixedOrientationOrthoViewController : public FramePositionTrackingViewController { Q_OBJECT public: FixedOrientationOrthoViewController(); virtual ~FixedOrientationOrthoViewController(); virtual void onInitialize(); virtual void handleMouseEvent(ViewportMouseEvent& evt); virtual void lookAt( const Ogre::Vector3& point_rel_world ); virtual void reset(); /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). */ virtual void mimic( ViewController* source_view ); virtual void update(float dt, float ros_dt); protected: virtual void onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation); /** Set the camera orientation based on angle_. */ void orientCamera(); void setPosition( const Ogre::Vector3& pos_rel_target ); void move( float x, float y ); void updateCamera(); FloatProperty* scale_property_; FloatProperty* angle_property_; FloatProperty* x_property_; FloatProperty* y_property_; bool dragging_; }; } // end namespace rviz #endif // RVIZ_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/default_plugin/view_controllers/fps_view_controller.cpp000066400000000000000000000165601300447110700275520ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "rviz/uniform_string_stream.h" #include "rviz/display_context.h" #include "rviz/viewport_mouse_event.h" #include "rviz/geometry.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/float_property.h" #include "rviz/properties/vector_property.h" #include "fps_view_controller.h" namespace rviz { static const Ogre::Quaternion ROBOT_TO_CAMERA_ROTATION = Ogre::Quaternion( Ogre::Radian( -Ogre::Math::HALF_PI ), Ogre::Vector3::UNIT_Y ) * Ogre::Quaternion( Ogre::Radian( -Ogre::Math::HALF_PI ), Ogre::Vector3::UNIT_Z ); static const float PITCH_LIMIT_LOW = -Ogre::Math::HALF_PI + 0.001; static const float PITCH_LIMIT_HIGH = Ogre::Math::HALF_PI - 0.001; FPSViewController::FPSViewController() { yaw_property_ = new FloatProperty( "Yaw", 0, "Rotation of the camera around the Z (up) axis.", this ); pitch_property_ = new FloatProperty( "Pitch", 0, "How much the camera is tipped downward.", this ); pitch_property_->setMax( Ogre::Math::HALF_PI - 0.001 ); pitch_property_->setMin( -pitch_property_->getMax() ); position_property_ = new VectorProperty( "Position", Ogre::Vector3( 5, 5, 10 ), "Position of the camera.", this ); } FPSViewController::~FPSViewController() { } void FPSViewController::onInitialize() { FramePositionTrackingViewController::onInitialize(); camera_->setProjectionType( Ogre::PT_PERSPECTIVE ); } void FPSViewController::reset() { camera_->setPosition( Ogre::Vector3( 5, 5, 10 )); camera_->lookAt( 0, 0, 0 ); setPropertiesFromCamera( camera_ ); // Hersh says: why is the following junk necessary? I don't know. // However, without this you need to call reset() twice after // switching from TopDownOrtho to FPS. After the first call the // camera is in the right position but pointing the wrong way. updateCamera(); camera_->lookAt( 0, 0, 0 ); setPropertiesFromCamera( camera_ ); } void FPSViewController::handleMouseEvent(ViewportMouseEvent& event) { if ( event.shift() ) { setStatus( "Left-Click: Move X/Y. Right-Click:: Move Z." ); } else { setStatus( "Left-Click: Rotate. Middle-Click: Move X/Y. Right-Click:: Zoom. Shift: More options." ); } bool moved = false; int32_t diff_x = 0; int32_t diff_y = 0; if( event.type == QEvent::MouseMove ) { diff_x = event.x - event.last_x; diff_y = event.y - event.last_y; moved = true; } if( event.left() && !event.shift() ) { setCursor( Rotate3D ); yaw( -diff_x*0.005 ); pitch( diff_y*0.005 ); } else if( event.middle() || ( event.shift() && event.left() )) { setCursor( MoveXY ); move( diff_x*0.01, -diff_y*0.01, 0.0f ); } else if( event.right() ) { setCursor( MoveZ ); move( 0.0f, 0.0f, diff_y*0.1 ); } else { setCursor( event.shift() ? MoveXY : Rotate3D ); } if ( event.wheel_delta != 0 ) { int diff = event.wheel_delta; move( 0.0f, 0.0f, -diff * 0.01 ); moved = true; } if (moved) { context_->queueRender(); } } void FPSViewController::setPropertiesFromCamera( Ogre::Camera* source_camera ) { Ogre::Quaternion quat = source_camera->getOrientation() * ROBOT_TO_CAMERA_ROTATION.Inverse(); float yaw = quat.getRoll( false ).valueRadians(); // OGRE camera frame looks along -Z, so they call rotation around Z "roll". float pitch = quat.getYaw( false ).valueRadians(); // OGRE camera frame has +Y as "up", so they call rotation around Y "yaw". Ogre::Vector3 direction = quat * Ogre::Vector3::NEGATIVE_UNIT_Z; if ( direction.dotProduct( Ogre::Vector3::NEGATIVE_UNIT_Z ) < 0 ) { if ( pitch > Ogre::Math::HALF_PI ) { pitch -= Ogre::Math::PI; } else if ( pitch < -Ogre::Math::HALF_PI ) { pitch += Ogre::Math::PI; } yaw = -yaw; if ( direction.dotProduct( Ogre::Vector3::UNIT_X ) < 0 ) { yaw -= Ogre::Math::PI; } else { yaw += Ogre::Math::PI; } } pitch_property_->setFloat( pitch ); yaw_property_->setFloat( mapAngleTo0_2Pi( yaw )); position_property_->setVector( source_camera->getPosition() ); } void FPSViewController::mimic( ViewController* source_view ) { FramePositionTrackingViewController::mimic( source_view ); setPropertiesFromCamera( source_view->getCamera() ); } void FPSViewController::update(float dt, float ros_dt) { FramePositionTrackingViewController::update( dt, ros_dt ); updateCamera(); } void FPSViewController::lookAt( const Ogre::Vector3& point ) { camera_->lookAt( point ); setPropertiesFromCamera( camera_ ); } void FPSViewController::onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation) { position_property_->add( old_reference_position - reference_position_ ); } void FPSViewController::updateCamera() { camera_->setOrientation( getOrientation() ); camera_->setPosition( position_property_->getVector() ); } void FPSViewController::yaw( float angle ) { yaw_property_->setFloat( mapAngleTo0_2Pi( yaw_property_->getFloat() + angle )); } void FPSViewController::pitch( float angle ) { pitch_property_->add( angle ); } Ogre::Quaternion FPSViewController::getOrientation() { Ogre::Quaternion pitch, yaw; yaw.FromAngleAxis( Ogre::Radian( yaw_property_->getFloat() ), Ogre::Vector3::UNIT_Z ); pitch.FromAngleAxis( Ogre::Radian( pitch_property_->getFloat() ), Ogre::Vector3::UNIT_Y ); return yaw * pitch * ROBOT_TO_CAMERA_ROTATION; } void FPSViewController::move( float x, float y, float z ) { Ogre::Vector3 translate( x, y, z ); position_property_->add( getOrientation() * translate ); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::FPSViewController, rviz::ViewController ) rviz-1.12.4/src/rviz/default_plugin/view_controllers/fps_view_controller.h000066400000000000000000000064751300447110700272230ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_FPS_VIEW_CONTROLLER_H #define RVIZ_FPS_VIEW_CONTROLLER_H #include #include #include "rviz/frame_position_tracking_view_controller.h" namespace rviz { class FloatProperty; class SceneNode; class Shape; class VectorProperty; /** @brief A first-person camera, controlled by yaw, pitch, and position. */ class FPSViewController : public FramePositionTrackingViewController { Q_OBJECT public: FPSViewController(); virtual ~FPSViewController(); virtual void onInitialize(); void yaw( float angle ); void pitch( float angle ); void move( float x, float y, float z ); virtual void handleMouseEvent(ViewportMouseEvent& evt); virtual void lookAt( const Ogre::Vector3& point ); virtual void reset(); /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). */ virtual void mimic( ViewController* source_view ); virtual void update(float dt, float ros_dt); protected: virtual void onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation); void setPropertiesFromCamera( Ogre::Camera* source_camera ); void updateCamera(); Ogre::Quaternion getOrientation(); ///< Return a Quaternion based on the yaw and pitch properties. FloatProperty* yaw_property_; ///< The camera's yaw (rotation around the y-axis), in radians FloatProperty* pitch_property_; ///< The camera's pitch (rotation around the x-axis), in radians VectorProperty* position_property_; }; } // end namespace rviz #endif // RVIZ_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/default_plugin/view_controllers/orbit_view_controller.cpp000066400000000000000000000247441300447110700301040ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/geometry.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/bool_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/vector_property.h" #include "rviz/uniform_string_stream.h" #include "rviz/viewport_mouse_event.h" #include "rviz/load_resource.h" #include "rviz/render_panel.h" #include "rviz/default_plugin/view_controllers/orbit_view_controller.h" static const float PITCH_START = Ogre::Math::HALF_PI / 2.0; static const float YAW_START = Ogre::Math::HALF_PI * 0.5; static const float DISTANCE_START = 10; static const float FOCAL_SHAPE_SIZE_START = 0.05; static const bool FOCAL_SHAPE_FIXED_SIZE = true; namespace rviz { OrbitViewController::OrbitViewController() : dragging_( false ) { distance_property_ = new FloatProperty( "Distance", DISTANCE_START, "Distance from the focal point.", this ); distance_property_->setMin( 0.01 ); focal_shape_size_property_ = new FloatProperty( "Focal Shape Size", FOCAL_SHAPE_SIZE_START, "Focal shape size.", this ); focal_shape_size_property_->setMin( 0.001 ); focal_shape_fixed_size_property_ = new BoolProperty ( "Focal Shape Fixed Size", FOCAL_SHAPE_FIXED_SIZE, "Focal shape size.", this ); yaw_property_ = new FloatProperty( "Yaw", YAW_START, "Rotation of the camera around the Z (up) axis.", this ); pitch_property_ = new FloatProperty( "Pitch", PITCH_START, "How much the camera is tipped downward.", this ); pitch_property_->setMax( Ogre::Math::HALF_PI - 0.001 ); pitch_property_->setMin( -pitch_property_->getMax() ); focal_point_property_ = new VectorProperty( "Focal Point", Ogre::Vector3::ZERO, "The center point which the camera orbits.", this ); } void OrbitViewController::onInitialize() { FramePositionTrackingViewController::onInitialize(); camera_->setProjectionType( Ogre::PT_PERSPECTIVE ); focal_shape_ = new Shape(Shape::Sphere, context_->getSceneManager(), target_scene_node_); updateFocalShapeSize(); focal_shape_->setColor(1.0f, 1.0f, 0.0f, 0.5f); focal_shape_->getRootNode()->setVisible(false); } OrbitViewController::~OrbitViewController() { delete focal_shape_; } void OrbitViewController::reset() { dragging_ = false; yaw_property_->setFloat( YAW_START ); pitch_property_->setFloat( PITCH_START ); distance_property_->setFloat( DISTANCE_START ); focal_shape_size_property_->setFloat( FOCAL_SHAPE_SIZE_START ); focal_shape_fixed_size_property_->setBool( false ); updateFocalShapeSize(); focal_point_property_->setVector( Ogre::Vector3::ZERO ); } void OrbitViewController::handleMouseEvent(ViewportMouseEvent& event) { if ( event.shift() ) { setStatus( "Left-Click: Move X/Y. Right-Click:: Move Z. Mouse Wheel:: Zoom. " ); } else { setStatus( "Left-Click: Rotate. Middle-Click: Move X/Y. Right-Click/Mouse Wheel:: Zoom. Shift: More options." ); } float distance = distance_property_->getFloat(); updateFocalShapeSize(); int32_t diff_x = 0; int32_t diff_y = 0; bool moved = false; if( event.type == QEvent::MouseButtonPress ) { focal_shape_->getRootNode()->setVisible(true); moved = true; dragging_ = true; } else if( event.type == QEvent::MouseButtonRelease ) { focal_shape_->getRootNode()->setVisible(false); moved = true; dragging_ = false; } else if( dragging_ && event.type == QEvent::MouseMove ) { diff_x = event.x - event.last_x; diff_y = event.y - event.last_y; moved = true; } // regular left-button drag if( event.left() && !event.shift() ) { setCursor( Rotate3D ); yaw( diff_x*0.005 ); pitch( -diff_y*0.005 ); } // middle or shift-left drag else if( event.middle() || (event.shift() && event.left()) ) { setCursor( MoveXY ); float fovY = camera_->getFOVy().valueRadians(); float fovX = 2.0f * atan( tan( fovY / 2.0f ) * camera_->getAspectRatio() ); int width = camera_->getViewport()->getActualWidth(); int height = camera_->getViewport()->getActualHeight(); move( -((float)diff_x / (float)width) * distance * tan( fovX / 2.0f ) * 2.0f, ((float)diff_y / (float)height) * distance * tan( fovY / 2.0f ) * 2.0f, 0.0f ); } else if( event.right() ) { if( event.shift() ) { // move in z direction setCursor( MoveZ ); move(0.0f, 0.0f, diff_y * 0.1 * (distance / 10.0f)); } else { // zoom setCursor( Zoom ); zoom( -diff_y * 0.1 * (distance / 10.0f) ); } } else { setCursor( event.shift() ? MoveXY : Rotate3D ); } moved = true; if( event.wheel_delta != 0 ) { int diff = event.wheel_delta; if( event.shift() ) { move( 0, 0, -diff * 0.001 * distance ); } else { zoom( diff * 0.001 * distance ); } moved = true; } if( moved ) { context_->queueRender(); } } void OrbitViewController::mimic( ViewController* source_view ) { FramePositionTrackingViewController::mimic( source_view ); Ogre::Camera* source_camera = source_view->getCamera(); Ogre::Vector3 position = source_camera->getPosition(); Ogre::Quaternion orientation = source_camera->getOrientation(); if( source_view->getClassId() == "rviz/Orbit" ) { // If I'm initializing from another instance of this same class, get the distance exactly. distance_property_->setFloat( source_view->subProp( "Distance" )->getValue().toFloat() ); updateFocalShapeSize(); } else { // Determine the distance from here to the reference frame, and use // that as the distance our focal point should be at. distance_property_->setFloat( position.length() ); updateFocalShapeSize(); } Ogre::Vector3 direction = orientation * (Ogre::Vector3::NEGATIVE_UNIT_Z * distance_property_->getFloat() ); focal_point_property_->setVector( position + direction ); calculatePitchYawFromPosition( position ); } void OrbitViewController::update(float dt, float ros_dt) { FramePositionTrackingViewController::update( dt, ros_dt ); updateCamera(); } void OrbitViewController::lookAt( const Ogre::Vector3& point ) { Ogre::Vector3 camera_position = camera_->getPosition(); focal_point_property_->setVector( target_scene_node_->getOrientation().Inverse() * (point - target_scene_node_->getPosition()) ); distance_property_->setFloat( focal_point_property_->getVector().distance( camera_position )); updateFocalShapeSize(); calculatePitchYawFromPosition(camera_position); } void OrbitViewController::onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation) { focal_point_property_->add( old_reference_position - reference_position_ ); } void OrbitViewController::updateCamera() { float distance = distance_property_->getFloat(); float yaw = yaw_property_->getFloat(); float pitch = pitch_property_->getFloat(); Ogre::Vector3 focal_point = focal_point_property_->getVector(); float x = distance * cos( yaw ) * cos( pitch ) + focal_point.x; float y = distance * sin( yaw ) * cos( pitch ) + focal_point.y; float z = distance * sin( pitch ) + focal_point.z; Ogre::Vector3 pos( x, y, z ); camera_->setPosition(pos); camera_->setFixedYawAxis(true, target_scene_node_->getOrientation() * Ogre::Vector3::UNIT_Z); camera_->setDirection(target_scene_node_->getOrientation() * (focal_point - pos)); focal_shape_->setPosition( focal_point ); } void OrbitViewController::yaw( float angle ) { yaw_property_->setFloat( mapAngleTo0_2Pi( yaw_property_->getFloat() - angle )); } void OrbitViewController::pitch( float angle ) { pitch_property_->add( -angle ); } void OrbitViewController::calculatePitchYawFromPosition( const Ogre::Vector3& position ) { Ogre::Vector3 diff = position - focal_point_property_->getVector(); pitch_property_->setFloat( asin( diff.z / distance_property_->getFloat() )); yaw_property_->setFloat( atan2( diff.y, diff.x )); } void OrbitViewController::updateFocalShapeSize() { const double fshape_size( focal_shape_size_property_->getFloat() ); double distance_property( distance_property_->getFloat() ); if( focal_shape_fixed_size_property_->getBool() ) distance_property = 1; focal_shape_->setScale( Ogre::Vector3( fshape_size * distance_property, fshape_size * distance_property, fshape_size * distance_property / 5.0 ) ); } void OrbitViewController::zoom( float amount ) { distance_property_->add( -amount ); updateFocalShapeSize(); } void OrbitViewController::move( float x, float y, float z ) { focal_point_property_->add( camera_->getOrientation() * Ogre::Vector3( x, y, z )); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::OrbitViewController, rviz::ViewController ) rviz-1.12.4/src/rviz/default_plugin/view_controllers/orbit_view_controller.h000066400000000000000000000110041300447110700275320ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ORBIT_VIEW_CONTROLLER_H #define RVIZ_ORBIT_VIEW_CONTROLLER_H #include #include #include "rviz/frame_position_tracking_view_controller.h" namespace rviz { class BoolProperty; class FloatProperty; class Shape; class SceneNode; class VectorProperty; /** * \brief An orbital camera, controlled by yaw, pitch, distance, and focal point * * This camera is based on the equation of a sphere in spherical coordinates: @verbatim x = d*cos(theta)sin(phi) y = d*cos(phi) z = d*sin(theta)sin(phi) @endverbatim * Where:
* d = #distance_
* theta = #yaw_
* phi = #pitch_ */ class OrbitViewController: public FramePositionTrackingViewController { Q_OBJECT public: OrbitViewController(); virtual ~OrbitViewController(); /** @brief Do subclass-specific initialization. Called by * ViewController::initialize after context_, target_scene_node_, * and camera_ are set. */ virtual void onInitialize(); /** * \brief Move in/out from the focal point, ie. adjust #distance_ by amount * @param amount The distance to move. Positive amount moves towards the focal point, negative moves away */ void zoom( float amount ); void yaw( float angle ); void pitch( float angle ); void move( float x, float y, float z ); virtual void handleMouseEvent(ViewportMouseEvent& evt); virtual void lookAt( const Ogre::Vector3& point ); virtual void reset(); /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). */ virtual void mimic( ViewController* source_view ); protected: virtual void update(float dt, float ros_dt); virtual void onTargetFrameChanged(const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation); /** * \brief Calculates pitch and yaw values given a new position and the current focal point * @param position Position to calculate the pitch/yaw for */ void calculatePitchYawFromPosition( const Ogre::Vector3& position ); /** * \brief Calculates the focal shape size and update it's geometry */ void updateFocalShapeSize(); virtual void updateCamera(); FloatProperty* yaw_property_; ///< The camera's yaw (rotation around the y-axis), in radians FloatProperty* pitch_property_; ///< The camera's pitch (rotation around the x-axis), in radians FloatProperty* distance_property_; ///< The camera's distance from the focal point VectorProperty* focal_point_property_; ///< The point around which the camera "orbits". BoolProperty* focal_shape_fixed_size_property_; ///< Whether the focal shape size is fixed or not FloatProperty* focal_shape_size_property_; ///< The focal shape size Shape* focal_shape_; bool dragging_; }; } #endif // RVIZ_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/default_plugin/view_controllers/third_person_follower_view_controller.cpp000066400000000000000000000201711300447110700333640ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/float_property.h" #include "rviz/properties/vector_property.h" #include "rviz/viewport_mouse_event.h" #include "rviz/default_plugin/view_controllers/third_person_follower_view_controller.h" namespace rviz { // move camera up so the focal point appears in the lower image half static const float CAMERA_OFFSET = 0.2; void ThirdPersonFollowerViewController::onInitialize() { OrbitViewController::onInitialize(); focal_shape_->setColor(0.0f, 1.0f, 1.0f, 0.5f); } bool ThirdPersonFollowerViewController::intersectGroundPlane( Ogre::Ray mouse_ray, Ogre::Vector3 &intersection_3d ) { //convert rays into reference frame mouse_ray.setOrigin( target_scene_node_->convertWorldToLocalPosition( mouse_ray.getOrigin() ) ); mouse_ray.setDirection( target_scene_node_->convertWorldToLocalOrientation( Ogre::Quaternion::IDENTITY ) * mouse_ray.getDirection() ); Ogre::Plane ground_plane( Ogre::Vector3::UNIT_Z, 0 ); std::pair intersection = mouse_ray.intersects(ground_plane); if (!intersection.first) { return false; } intersection_3d = mouse_ray.getPoint(intersection.second); return true; } void ThirdPersonFollowerViewController::handleMouseEvent(ViewportMouseEvent& event) { if ( event.shift() ) { setStatus( "Left-Click: Move X/Y. Right-Click:: Zoom." ); } else { setStatus( "Left-Click: Rotate. Middle-Click: Move X/Y. Right-Click:: Move Z. Shift: More options." ); } int32_t diff_x = 0; int32_t diff_y = 0; bool moved = false; if( event.type == QEvent::MouseButtonPress ) { focal_shape_->getRootNode()->setVisible(true); moved = true; } else if( event.type == QEvent::MouseButtonRelease ) { focal_shape_->getRootNode()->setVisible(false); moved = true; } else if( event.type == QEvent::MouseMove ) { diff_x = event.x - event.last_x; diff_y = event.y - event.last_y; moved = true; } if( event.left() && !event.shift() ) { setCursor( Rotate3D ); yaw( diff_x*0.005 ); pitch( -diff_y*0.005 ); } else if( event.middle() || (event.left() && event.shift()) ) { setCursor( MoveXY ); // handle mouse movement int width = event.viewport->getActualWidth(); int height = event.viewport->getActualHeight(); Ogre::Ray mouse_ray = event.viewport->getCamera()->getCameraToViewportRay( event.x / (float) width, event.y / (float) height ); Ogre::Ray last_mouse_ray = event.viewport->getCamera()->getCameraToViewportRay( event.last_x / (float) width, event.last_y / (float) height ); Ogre::Vector3 last_intersect, intersect; if( intersectGroundPlane( last_mouse_ray, last_intersect ) && intersectGroundPlane( mouse_ray, intersect )) { Ogre::Vector3 motion = last_intersect - intersect; // When dragging near the horizon, the motion can get out of // control. This throttles it to an arbitrary limit per mouse // event. float motion_distance_limit = 1; /*meter*/ if( motion.length() > motion_distance_limit ) { motion.normalise(); motion *= motion_distance_limit; } focal_point_property_->add( motion ); emitConfigChanged(); } } else if( event.right() ) { setCursor( Zoom ); zoom( -diff_y * 0.1 * (distance_property_->getFloat() / 10.0f) ); } else { setCursor( event.shift() ? MoveXY : Rotate3D ); } if( event.wheel_delta != 0 ) { int diff = event.wheel_delta; zoom( diff * 0.001 * distance_property_->getFloat() ); moved = true; } if( moved ) { context_->queueRender(); } } void ThirdPersonFollowerViewController::mimic( ViewController* source_view ) { FramePositionTrackingViewController::mimic( source_view ); Ogre::Camera* source_camera = source_view->getCamera(); // do some trigonometry Ogre::Ray camera_dir_ray( source_camera->getRealPosition(), source_camera->getRealDirection() ); Ogre::Ray camera_down_ray( source_camera->getRealPosition(), -1.0 * source_camera->getRealUp() ); Ogre::Vector3 a,b; if( intersectGroundPlane( camera_dir_ray, b ) && intersectGroundPlane( camera_down_ray, a ) ) { float l_a = source_camera->getPosition().distance( b ); float l_b = source_camera->getPosition().distance( a ); distance_property_->setFloat(( l_a * l_b ) / ( CAMERA_OFFSET * l_a + l_b )); float distance = distance_property_->getFloat(); camera_dir_ray.setOrigin( source_camera->getRealPosition() - source_camera->getRealUp() * distance * CAMERA_OFFSET ); Ogre::Vector3 new_focal_point; intersectGroundPlane( camera_dir_ray, new_focal_point ); focal_point_property_->setVector( new_focal_point ); calculatePitchYawFromPosition( source_camera->getPosition() - source_camera->getUp() * distance * CAMERA_OFFSET ); } } void ThirdPersonFollowerViewController::updateCamera() { OrbitViewController::updateCamera(); camera_->setPosition( camera_->getPosition() + camera_->getUp() * distance_property_->getFloat() * CAMERA_OFFSET ); } void ThirdPersonFollowerViewController::updateTargetSceneNode() { if ( FramePositionTrackingViewController::getNewTransform() ) { target_scene_node_->setPosition( reference_position_ ); Ogre::Radian ref_yaw = reference_orientation_.getRoll( false ); // OGRE camera frame looks along -Z, so they call rotation around Z "roll". Ogre::Quaternion ref_yaw_quat(Ogre::Math::Cos(ref_yaw/2), 0, 0, Ogre::Math::Sin(ref_yaw/2)); target_scene_node_->setOrientation( ref_yaw_quat ); context_->queueRender(); } } void ThirdPersonFollowerViewController::lookAt( const Ogre::Vector3& point ) { Ogre::Vector3 camera_position = camera_->getPosition(); Ogre::Vector3 new_focal_point = target_scene_node_->getOrientation().Inverse() * (point - target_scene_node_->getPosition()); new_focal_point.z = 0; distance_property_->setFloat( new_focal_point.distance( camera_position )); focal_point_property_->setVector( new_focal_point ); calculatePitchYawFromPosition(camera_position); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::ThirdPersonFollowerViewController, rviz::ViewController ) rviz-1.12.4/src/rviz/default_plugin/view_controllers/third_person_follower_view_controller.h000066400000000000000000000052201300447110700330270ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_THIRD_PERSON_VIEW_CONTROLLER_H #define RVIZ_THIRD_PERSON_VIEW_CONTROLLER_H #include "rviz/default_plugin/view_controllers/orbit_view_controller.h" #include namespace Ogre { class SceneNode; } namespace rviz { class TfFrameProperty; /** * \brief Like the orbit view controller, but focal point moves only in the x-y plane. */ class ThirdPersonFollowerViewController : public OrbitViewController { Q_OBJECT public: virtual void onInitialize(); virtual void handleMouseEvent(ViewportMouseEvent& evt); virtual void lookAt( const Ogre::Vector3& point ); /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). */ virtual void mimic( ViewController* source_view ); protected: virtual void updateCamera(); virtual void updateTargetSceneNode(); bool intersectGroundPlane( Ogre::Ray mouse_ray, Ogre::Vector3 &intersection_3d ); }; } #endif // RVIZ_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/default_plugin/view_controllers/xy_orbit_view_controller.cpp000066400000000000000000000167621300447110700306250ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/float_property.h" #include "rviz/properties/vector_property.h" #include "rviz/viewport_mouse_event.h" #include "rviz/default_plugin/view_controllers/xy_orbit_view_controller.h" namespace rviz { // move camera up so the focal point appears in the lower image half static const float CAMERA_OFFSET = 0.2; void XYOrbitViewController::onInitialize() { OrbitViewController::onInitialize(); focal_shape_->setColor(0.0f, 1.0f, 1.0f, 0.5f); } bool XYOrbitViewController::intersectGroundPlane( Ogre::Ray mouse_ray, Ogre::Vector3 &intersection_3d ) { //convert rays into reference frame mouse_ray.setOrigin( target_scene_node_->convertWorldToLocalPosition( mouse_ray.getOrigin() ) ); mouse_ray.setDirection( target_scene_node_->convertWorldToLocalOrientation( Ogre::Quaternion::IDENTITY ) * mouse_ray.getDirection() ); Ogre::Plane ground_plane( Ogre::Vector3::UNIT_Z, 0 ); std::pair intersection = mouse_ray.intersects(ground_plane); if (!intersection.first) { return false; } intersection_3d = mouse_ray.getPoint(intersection.second); return true; } void XYOrbitViewController::handleMouseEvent(ViewportMouseEvent& event) { if ( event.shift() ) { setStatus( "Left-Click: Move X/Y. Right-Click:: Zoom." ); } else { setStatus( "Left-Click: Rotate. Middle-Click: Move X/Y. Right-Click:: Move Z. Shift: More options." ); } int32_t diff_x = 0; int32_t diff_y = 0; bool moved = false; if( event.type == QEvent::MouseButtonPress ) { focal_shape_->getRootNode()->setVisible(true); moved = true; } else if( event.type == QEvent::MouseButtonRelease ) { focal_shape_->getRootNode()->setVisible(false); moved = true; } else if( event.type == QEvent::MouseMove ) { diff_x = event.x - event.last_x; diff_y = event.y - event.last_y; moved = true; } if( event.left() && !event.shift() ) { setCursor( Rotate3D ); yaw( diff_x*0.005 ); pitch( -diff_y*0.005 ); } else if( event.middle() || (event.left() && event.shift()) ) { setCursor( MoveXY ); // handle mouse movement int width = event.viewport->getActualWidth(); int height = event.viewport->getActualHeight(); Ogre::Ray mouse_ray = event.viewport->getCamera()->getCameraToViewportRay( event.x / (float) width, event.y / (float) height ); Ogre::Ray last_mouse_ray = event.viewport->getCamera()->getCameraToViewportRay( event.last_x / (float) width, event.last_y / (float) height ); Ogre::Vector3 last_intersect, intersect; if( intersectGroundPlane( last_mouse_ray, last_intersect ) && intersectGroundPlane( mouse_ray, intersect )) { Ogre::Vector3 motion = last_intersect - intersect; // When dragging near the horizon, the motion can get out of // control. This throttles it to an arbitrary limit per mouse // event. float motion_distance_limit = 1; /*meter*/ if( motion.length() > motion_distance_limit ) { motion.normalise(); motion *= motion_distance_limit; } focal_point_property_->add( motion ); emitConfigChanged(); } } else if( event.right() ) { setCursor( Zoom ); zoom( -diff_y * 0.1 * (distance_property_->getFloat() / 10.0f) ); } else { setCursor( event.shift() ? MoveXY : Rotate3D ); } if( event.wheel_delta != 0 ) { int diff = event.wheel_delta; zoom( diff * 0.001 * distance_property_->getFloat() ); moved = true; } if( moved ) { context_->queueRender(); } } void XYOrbitViewController::mimic( ViewController* source_view ) { FramePositionTrackingViewController::mimic( source_view ); Ogre::Camera* source_camera = source_view->getCamera(); // do some trigonometry Ogre::Ray camera_dir_ray( source_camera->getRealPosition(), source_camera->getRealDirection() ); Ogre::Ray camera_down_ray( source_camera->getRealPosition(), -1.0 * source_camera->getRealUp() ); Ogre::Vector3 a,b; if( intersectGroundPlane( camera_dir_ray, b ) && intersectGroundPlane( camera_down_ray, a ) ) { float l_a = source_camera->getPosition().distance( b ); float l_b = source_camera->getPosition().distance( a ); distance_property_->setFloat(( l_a * l_b ) / ( CAMERA_OFFSET * l_a + l_b )); float distance = distance_property_->getFloat(); camera_dir_ray.setOrigin( source_camera->getRealPosition() - source_camera->getRealUp() * distance * CAMERA_OFFSET ); Ogre::Vector3 new_focal_point; intersectGroundPlane( camera_dir_ray, new_focal_point ); focal_point_property_->setVector( new_focal_point ); calculatePitchYawFromPosition( source_camera->getPosition() - source_camera->getUp() * distance * CAMERA_OFFSET ); } } void XYOrbitViewController::updateCamera() { OrbitViewController::updateCamera(); camera_->setPosition( camera_->getPosition() + camera_->getUp() * distance_property_->getFloat() * CAMERA_OFFSET ); } void XYOrbitViewController::lookAt( const Ogre::Vector3& point ) { Ogre::Vector3 camera_position = camera_->getPosition(); Ogre::Vector3 new_focal_point = target_scene_node_->getOrientation().Inverse() * (point - target_scene_node_->getPosition()); new_focal_point.z = 0; distance_property_->setFloat( new_focal_point.distance( camera_position )); focal_point_property_->setVector( new_focal_point ); calculatePitchYawFromPosition(camera_position); } } // end namespace rviz #include PLUGINLIB_EXPORT_CLASS( rviz::XYOrbitViewController, rviz::ViewController ) rviz-1.12.4/src/rviz/default_plugin/view_controllers/xy_orbit_view_controller.h000066400000000000000000000051031300447110700302550ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SIMPLE_ORBIT_VIEW_CONTROLLER_H #define RVIZ_SIMPLE_ORBIT_VIEW_CONTROLLER_H #include "rviz/default_plugin/view_controllers/orbit_view_controller.h" #include namespace Ogre { class SceneNode; } namespace rviz { /** * \brief Like the orbit view controller, but focal point moves only in the x-y plane. */ class XYOrbitViewController : public OrbitViewController { Q_OBJECT public: virtual void onInitialize(); virtual void handleMouseEvent(ViewportMouseEvent& evt); virtual void lookAt( const Ogre::Vector3& point ); /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). */ virtual void mimic( ViewController* source_view ); protected: virtual void updateCamera(); bool intersectGroundPlane( Ogre::Ray mouse_ray, Ogre::Vector3 &intersection_3d ); }; } #endif // RVIZ_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/default_plugin/wrench_display.cpp000066400000000000000000000143651300447110700231010ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "wrench_visual.h" #include "wrench_display.h" namespace rviz { WrenchStampedDisplay::WrenchStampedDisplay() { force_color_property_ = new rviz::ColorProperty( "Force Color", QColor( 204, 51, 51 ), "Color to draw the force arrows.", this, SLOT( updateColorAndAlpha() )); torque_color_property_ = new rviz::ColorProperty( "Torque Color", QColor( 204, 204, 51), "Color to draw the torque arrows.", this, SLOT( updateColorAndAlpha() )); alpha_property_ = new rviz::FloatProperty( "Alpha", 1.0, "0 is fully transparent, 1.0 is fully opaque.", this, SLOT( updateColorAndAlpha() )); force_scale_property_ = new rviz::FloatProperty( "Force Arrow Scale", 2.0, "force arrow scale", this, SLOT( updateColorAndAlpha() )); torque_scale_property_ = new rviz::FloatProperty( "Torque Arrow Scale", 2.0, "torque arrow scale", this, SLOT( updateColorAndAlpha() )); width_property_ = new rviz::FloatProperty( "Arrow Width", 0.5, "arrow width", this, SLOT( updateColorAndAlpha() )); history_length_property_ = new rviz::IntProperty( "History Length", 1, "Number of prior measurements to display.", this, SLOT( updateHistoryLength() )); history_length_property_->setMin( 1 ); history_length_property_->setMax( 100000 ); } void WrenchStampedDisplay::onInitialize() { MFDClass::onInitialize(); updateHistoryLength( ); } WrenchStampedDisplay::~WrenchStampedDisplay() { } // Override rviz::Display's reset() function to add a call to clear(). void WrenchStampedDisplay::reset() { MFDClass::reset(); visuals_.clear(); } void WrenchStampedDisplay::updateColorAndAlpha() { float alpha = alpha_property_->getFloat(); float force_scale = force_scale_property_->getFloat(); float torque_scale = torque_scale_property_->getFloat(); float width = width_property_->getFloat(); Ogre::ColourValue force_color = force_color_property_->getOgreColor(); Ogre::ColourValue torque_color = torque_color_property_->getOgreColor(); for( size_t i = 0; i < visuals_.size(); i++ ) { visuals_[i]->setForceColor( force_color.r, force_color.g, force_color.b, alpha ); visuals_[i]->setTorqueColor( torque_color.r, torque_color.g, torque_color.b, alpha ); visuals_[i]->setForceScale( force_scale ); visuals_[i]->setTorqueScale( torque_scale ); visuals_[i]->setWidth( width ); } } // Set the number of past visuals to show. void WrenchStampedDisplay::updateHistoryLength() { visuals_.rset_capacity(history_length_property_->getInt()); } bool validateFloats( const geometry_msgs::WrenchStamped& msg ) { return rviz::validateFloats(msg.wrench.force) && rviz::validateFloats(msg.wrench.torque) ; } // This is our callback to handle an incoming message. void WrenchStampedDisplay::processMessage( const geometry_msgs::WrenchStamped::ConstPtr& msg ) { if( !validateFloats( *msg )) { setStatus( rviz::StatusProperty::Error, "Topic", "Message contained invalid floating point values (nans or infs)" ); return; } // Here we call the rviz::FrameManager to get the transform from the // fixed frame to the frame in the header of this Imu message. If // it fails, we can't do anything else so we return. Ogre::Quaternion orientation; Ogre::Vector3 position; if( !context_->getFrameManager()->getTransform( msg->header.frame_id, msg->header.stamp, position, orientation )) { ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable( fixed_frame_ )); return; } if ( position.isNaN() ) { ROS_ERROR_THROTTLE(1.0, "Wrench position contains NaNs. Skipping render as long as the position is invalid"); return; } // We are keeping a circular buffer of visual pointers. This gets // the next one, or creates and stores it if the buffer is not full boost::shared_ptr visual; if( visuals_.full() ) { visual = visuals_.front(); } else { visual.reset(new WrenchVisual( context_->getSceneManager(), scene_node_ )); } // Now set or update the contents of the chosen visual. visual->setWrench( msg->wrench ); visual->setFramePosition( position ); visual->setFrameOrientation( orientation ); float alpha = alpha_property_->getFloat(); float force_scale = force_scale_property_->getFloat(); float torque_scale = torque_scale_property_->getFloat(); float width = width_property_->getFloat(); Ogre::ColourValue force_color = force_color_property_->getOgreColor(); Ogre::ColourValue torque_color = torque_color_property_->getOgreColor(); visual->setForceColor( force_color.r, force_color.g, force_color.b, alpha ); visual->setTorqueColor( torque_color.r, torque_color.g, torque_color.b, alpha ); visual->setForceScale( force_scale ); visual->setTorqueScale( torque_scale ); visual->setWidth( width ); // And send it to the end of the circular buffer visuals_.push_back(visual); } } // end namespace rviz // Tell pluginlib about this class. It is important to do this in // global scope, outside our package's namespace. #include PLUGINLIB_EXPORT_CLASS( rviz::WrenchStampedDisplay, rviz::Display ) rviz-1.12.4/src/rviz/default_plugin/wrench_display.h000066400000000000000000000033671300447110700225460ustar00rootroot00000000000000#ifndef WRENCHSTAMPED_DISPLAY_H #define WRENCHSTAMPED_DISPLAY_H #ifndef Q_MOC_RUN #include #endif #include #include namespace Ogre { class SceneNode; } namespace rviz { class ColorProperty; class ROSTopicStringProperty; class FloatProperty; class IntProperty; } namespace rviz { class WrenchVisual; class WrenchStampedDisplay: public rviz::MessageFilterDisplay { Q_OBJECT public: // Constructor. pluginlib::ClassLoader creates instances by calling // the default constructor, so make sure you have one. WrenchStampedDisplay(); virtual ~WrenchStampedDisplay(); protected: // Overrides of public virtual functions from the Display class. virtual void onInitialize(); virtual void reset(); private Q_SLOTS: // Helper function to apply color and alpha to all visuals. void updateColorAndAlpha(); void updateHistoryLength(); private: // Function to handle an incoming ROS message. void processMessage( const geometry_msgs::WrenchStamped::ConstPtr& msg ); // Storage for the list of visuals par each joint intem // Storage for the list of visuals. It is a circular buffer where // data gets popped from the front (oldest) and pushed to the back (newest) boost::circular_buffer > visuals_; // Property objects for user-editable properties. rviz::ColorProperty *force_color_property_, *torque_color_property_; rviz::FloatProperty *alpha_property_, *force_scale_property_, *torque_scale_property_, *width_property_; rviz::IntProperty *history_length_property_; }; } // end namespace rviz_plugin_tutorials #endif // WRENCHSTAMPED_DISPLAY_H rviz-1.12.4/src/rviz/default_plugin/wrench_visual.cpp000066400000000000000000000111751300447110700227330ustar00rootroot00000000000000#include #include #include #include #include #include #include "wrench_visual.h" namespace rviz { WrenchVisual::WrenchVisual( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ) { scene_manager_ = scene_manager; // Ogre::SceneNode s form a tree, with each node storing the // transform (position and orientation) of itself relative to its // parent. Ogre does the math of combining those transforms when it // is time to render. // // Here we create a node to store the pose of the WrenchStamped's header frame // relative to the RViz fixed frame. frame_node_ = parent_node->createChildSceneNode(); force_node_ = frame_node_->createChildSceneNode(); torque_node_ = frame_node_->createChildSceneNode(); // We create the arrow object within the frame node so that we can // set its position and direction relative to its header frame. arrow_force_ = new rviz::Arrow( scene_manager_, force_node_ ); arrow_torque_ = new rviz::Arrow( scene_manager_, torque_node_ ); circle_torque_ = new rviz::BillboardLine( scene_manager_, torque_node_ ); circle_arrow_torque_ = new rviz::Arrow( scene_manager_, torque_node_ ); } WrenchVisual::~WrenchVisual() { // Delete the arrow to make it disappear. delete arrow_force_; delete arrow_torque_; delete circle_torque_; delete circle_arrow_torque_; // Destroy the frame node since we don't need it anymore. scene_manager_->destroySceneNode( frame_node_ ); } void WrenchVisual::setWrench( const geometry_msgs::Wrench& wrench ) { Ogre::Vector3 force(wrench.force.x, wrench.force.y, wrench.force.z); Ogre::Vector3 torque(wrench.torque.x, wrench.torque.y, wrench.torque.z); setWrench(force, torque); } void WrenchVisual::setWrench( const Ogre::Vector3 &force, const Ogre::Vector3 &torque ) { double force_length = force.length() * force_scale_; double torque_length = torque.length() * torque_scale_; // hide markers if they get too short bool show_force = (force_length > width_); bool show_torque = (torque_length > width_); if (show_force) { arrow_force_->setScale(Ogre::Vector3(force_length, width_, width_)); arrow_force_->setDirection(force); } force_node_->setVisible(show_force); if (show_torque) { arrow_torque_->setScale(Ogre::Vector3(torque_length, width_, width_)); arrow_torque_->setDirection(torque); Ogre::Vector3 axis_z(0,0,1); Ogre::Quaternion orientation = axis_z.getRotationTo(torque); if ( std::isnan(orientation.x) || std::isnan(orientation.y) || std::isnan(orientation.z) ) orientation = Ogre::Quaternion::IDENTITY; //circle_arrow_torque_->setScale(Ogre::Vector3(width_, width_, 0.05)); circle_arrow_torque_->set(0, width_*0.1, width_*0.1*1.0, width_*0.1*2.0); circle_arrow_torque_->setDirection(orientation * Ogre::Vector3(0,1,0)); circle_arrow_torque_->setPosition(orientation * Ogre::Vector3(torque_length/4, 0, torque_length/2)); circle_torque_->clear(); circle_torque_->setLineWidth(width_*0.05); for (int i = 4; i <= 32; i++) { Ogre::Vector3 point = Ogre::Vector3((torque_length/4)*cos(i*2*M_PI/32), (torque_length/4)*sin(i*2*M_PI/32), torque_length/2); circle_torque_->addPoint(orientation * point); } } torque_node_->setVisible(show_torque); } // Position and orientation are passed through to the SceneNode. void WrenchVisual::setFramePosition( const Ogre::Vector3& position ) { frame_node_->setPosition( position ); } void WrenchVisual::setFrameOrientation( const Ogre::Quaternion& orientation ) { frame_node_->setOrientation( orientation ); } // Color is passed through to the rviz object. void WrenchVisual::setForceColor( float r, float g, float b, float a ) { arrow_force_->setColor( r, g, b, a ); } // Color is passed through to the rviz object. void WrenchVisual::setTorqueColor( float r, float g, float b, float a ) { arrow_torque_->setColor( r, g, b, a ); circle_torque_->setColor( r, g, b, a ); circle_arrow_torque_->setColor( r, g, b, a ); } void WrenchVisual::setForceScale( float s ) { force_scale_ = s; } void WrenchVisual::setTorqueScale( float s ) { torque_scale_ = s; } void WrenchVisual::setWidth( float w ) { width_ = w; } void WrenchVisual::setVisible(bool visible) { frame_node_->setVisible(visible); } } // end namespace rviz rviz-1.12.4/src/rviz/default_plugin/wrench_visual.h000066400000000000000000000052241300447110700223760ustar00rootroot00000000000000#ifndef WRENCHSTAMPED_VISUAL_H #define WRENCHSTAMPED_VISUAL_H #include namespace Ogre { class Vector3; class Quaternion; } namespace rviz { class Arrow; class BillboardLine; } namespace rviz { // Each instance of WrenchStampedVisual represents the visualization of a single // sensor_msgs::WrenchStamped message. Currently it just shows an arrow with // the direction and magnitude of the acceleration vector, but could // easily be expanded to include more of the message data. class WrenchVisual { public: // Constructor. Creates the visual stuff and puts it into the // scene, but in an unconfigured state. WrenchVisual( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ); // Destructor. Removes the visual stuff from the scene. virtual ~WrenchVisual(); // Configure the visual to show the given force and torque vectors void setWrench( const Ogre::Vector3 &force, const Ogre::Vector3 &torque ); // Configure the visual to show the data in the message. void setWrench( const geometry_msgs::Wrench& wrench ); // Set the pose of the coordinate frame the message refers to. // These could be done inside setMessage(), but that would require // calls to FrameManager and error handling inside setMessage(), // which doesn't seem as clean. This way WrenchStampedVisual is only // responsible for visualization. void setFramePosition( const Ogre::Vector3& position ); void setFrameOrientation( const Ogre::Quaternion& orientation ); // Set the color and alpha of the visual, which are user-editable // parameters and therefore don't come from the WrenchStamped message. void setForceColor( float r, float g, float b, float a ); void setTorqueColor( float r, float g, float b, float a ); void setForceScale( float s ); void setTorqueScale( float s ); void setWidth( float w ); void setVisible( bool visible ); private: // The object implementing the wrenchStamped circle rviz::Arrow* arrow_force_; rviz::Arrow* arrow_torque_; rviz::BillboardLine* circle_torque_; rviz::Arrow* circle_arrow_torque_; float force_scale_, torque_scale_, width_; // A SceneNode whose pose is set to match the coordinate frame of // the WrenchStamped message header. Ogre::SceneNode* frame_node_; // allow showing/hiding of force / torque arrows Ogre::SceneNode* force_node_; Ogre::SceneNode* torque_node_; // The SceneManager, kept here only so the destructor can ask it to // destroy the ``frame_node_``. Ogre::SceneManager* scene_manager_; }; } // end namespace rviz #endif // WRENCHSTAMPED_VISUAL_H rviz-1.12.4/src/rviz/display.cpp000066400000000000000000000241571300447110700165310ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/ogre_helpers/apply_visibility_bits.h" #include "rviz/properties/property_tree_model.h" #include "rviz/properties/status_list.h" #include "rviz/window_manager_interface.h" #include "rviz/panel_dock_widget.h" #include "display.h" #include namespace rviz { Display::Display() : context_( 0 ) , scene_node_( NULL ) , status_( 0 ) , initialized_( false ) , visibility_bits_( 0xFFFFFFFF ) , associated_widget_( NULL ) , associated_widget_panel_( NULL ) { // Needed for timeSignal (see header) to work across threads qRegisterMetaType(); // Make the display-enable checkbox show up, and make it unchecked by default. setValue( false ); connect( this, SIGNAL( changed() ), this, SLOT( onEnableChanged() )); setDisableChildrenIfFalse(true); } Display::~Display() { if( scene_node_ ) { scene_manager_->destroySceneNode( scene_node_ ); } } void Display::initialize( DisplayContext* context ) { context_ = context; scene_manager_ = context_->getSceneManager(); scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode(); update_nh_.setCallbackQueue( context_->getUpdateQueue() ); threaded_nh_.setCallbackQueue( context_->getThreadedQueue() ); fixed_frame_ = context_->getFixedFrame(); onInitialize(); initialized_ = true; } void Display::queueRender() { if( context_ ) { context_->queueRender(); } } QVariant Display::getViewData( int column, int role ) const { switch( role ) { case Qt::BackgroundRole: { /* QLinearGradient q( 0,0, 0,5 ); q.setColorAt( 0.0, QColor(230,230,230) ); q.setColorAt( 1.0, Qt::white ); return QBrush( q ); */ return QColor( Qt::white ); } case Qt::ForegroundRole: { // if we're item-enabled (not greyed out) and in warn/error state, set appropriate color if ( getViewFlags( column ) & Qt::ItemIsEnabled ) { if ( isEnabled() ) { if ( status_ && status_->getLevel() != StatusProperty::Ok ) { return StatusProperty::statusColor( status_->getLevel() ); } else { // blue means that the enabled checkmark is set return QColor( 40, 120, 197 ); } } else { return QColor( Qt::black ); } } break; } case Qt::FontRole: { QFont font; if ( isEnabled() ) { font.setBold( true ); } return font; } case Qt::DecorationRole: { if( column == 0 ) { if ( isEnabled() ) { StatusProperty::Level level = status_ ? status_->getLevel() : StatusProperty::Ok; switch( level ) { case StatusProperty::Ok: return getIcon(); case StatusProperty::Warn: case StatusProperty::Error: return status_->statusIcon( status_->getLevel() ); } } else { return getIcon(); } } break; } } return BoolProperty::getViewData( column, role ); } Qt::ItemFlags Display::getViewFlags( int column ) const { return BoolProperty::getViewFlags( column ) | Qt::ItemIsDragEnabled; } void Display::setStatus( StatusProperty::Level level, const QString& name, const QString& text ) { QMetaObject::invokeMethod( this, "setStatusInternal", Qt::QueuedConnection, Q_ARG( int, level ), Q_ARG( QString, name ), Q_ARG( QString, text )); } void Display::setStatusInternal( int level, const QString& name, const QString& text ) { if( !status_ ) { status_ = new StatusList( "Status" ); addChild( status_, 0 ); } StatusProperty::Level old_level = status_->getLevel(); status_->setStatus( (StatusProperty::Level) level, name, text ); if( model_ && old_level != status_->getLevel() ) { model_->emitDataChanged( this ); } } void Display::deleteStatus( const QString& name ) { QMetaObject::invokeMethod( this, "deleteStatusInternal", Qt::QueuedConnection, Q_ARG( QString, name )); } void Display::deleteStatusInternal( const QString& name ) { if( status_ ) { status_->deleteStatus( name ); } } void Display::clearStatuses() { QMetaObject::invokeMethod( this, "clearStatusesInternal", Qt::QueuedConnection ); } void Display::clearStatusesInternal() { if( status_ ) { StatusProperty::Level old_level = status_->getLevel(); status_->clear(); if( model_ && old_level != StatusProperty::Ok ) { model_->emitDataChanged( this ); } } } void Display::load( const Config& config ) { // Base class loads sub-properties. BoolProperty::load( config ); QString name; if( config.mapGetString( "Name", &name )) { setObjectName( name ); } bool enabled; if( config.mapGetBool( "Enabled", &enabled )) { setEnabled( enabled ); } } void Display::save( Config config ) const { // Base class saves sub-properties. BoolProperty::save( config ); config.mapSetValue( "Class", getClassId() ); config.mapSetValue( "Name", getName() ); config.mapSetValue( "Enabled", getBool() ); } void Display::setEnabled( bool enabled ) { if ( enabled == isEnabled() ) return; setValue( enabled ); } void Display::disable() { setEnabled( false ); } bool Display::isEnabled() const { return getBool() && (getViewFlags( 0 ) & Qt::ItemIsEnabled); } void Display::setFixedFrame( const QString& fixed_frame ) { fixed_frame_ = fixed_frame; if( initialized_ ) { fixedFrameChanged(); } } void Display::emitTimeSignal( ros::Time time ) { Q_EMIT( timeSignal( this, time ) ); } void Display::reset() { clearStatuses(); } void Display::onEnableChanged() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); queueRender(); if( isEnabled() ) { scene_node_->setVisible( true ); if( associated_widget_panel_ ) { associated_widget_panel_->show(); } else if( associated_widget_ ) { associated_widget_->show(); } onEnable(); } else { onDisable(); if( associated_widget_panel_ ) { if( associated_widget_panel_->isVisible() ) { associated_widget_panel_->hide(); } } else if( associated_widget_ && associated_widget_->isVisible() ) { associated_widget_->hide(); } scene_node_->setVisible( false ); } QApplication::restoreOverrideCursor(); } void Display::setVisibilityBits( uint32_t bits ) { visibility_bits_ |= bits; applyVisibilityBits( visibility_bits_, scene_node_ ); } void Display::unsetVisibilityBits( uint32_t bits ) { visibility_bits_ &= ~bits; applyVisibilityBits( visibility_bits_, scene_node_ ); } void Display::setAssociatedWidget( QWidget* widget ) { if( associated_widget_panel_ ) { disconnect( associated_widget_panel_, SIGNAL( visibilityChanged( bool ) ), this, SLOT( associatedPanelVisibilityChange( bool ) )); disconnect( associated_widget_panel_, SIGNAL( closed( ) ), this, SLOT( disable( ))); } associated_widget_ = widget; if( associated_widget_ ) { WindowManagerInterface* wm = context_->getWindowManager(); if( wm ) { associated_widget_panel_ = wm->addPane( getName(), associated_widget_ ); connect( associated_widget_panel_, SIGNAL( visibilityChanged( bool ) ), this, SLOT( associatedPanelVisibilityChange( bool ) )); connect( associated_widget_panel_, SIGNAL( closed( ) ), this, SLOT( disable( ))); associated_widget_panel_->setIcon( getIcon() ); } else { associated_widget_panel_ = NULL; associated_widget_->setWindowTitle( getName() ); } } else { associated_widget_panel_ = NULL; } } void Display::associatedPanelVisibilityChange( bool visible ) { // if something external makes the panel visible, make sure we're enabled if ( visible ) { setEnabled( true ); } else { setEnabled( false ); } } void Display::setIcon( const QIcon& icon ) { icon_=icon; if ( associated_widget_panel_ ) { associated_widget_panel_->setIcon( getIcon() ); } } void Display::setName( const QString& name ) { BoolProperty::setName( name ); if( associated_widget_panel_ ) { associated_widget_panel_->setWindowTitle( name ); associated_widget_panel_->setObjectName( name ); // QMainWindow::saveState() needs objectName to be set. } else if( associated_widget_ ) { associated_widget_->setWindowTitle( name ); } } } // end namespace rviz rviz-1.12.4/src/rviz/display.h000066400000000000000000000261161300447110700161730ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef DISPLAY_H #define DISPLAY_H #include #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include #endif #include "rviz/properties/status_property.h" #include "rviz/properties/bool_property.h" #include #include class QDockWidget; class QWidget; namespace Ogre { class SceneManager; class SceneNode; } // needed for timeSignal Q_DECLARE_METATYPE(ros::Time); namespace rviz { class StatusList; class DisplayContext; class PanelDockWidget; class Display: public BoolProperty { Q_OBJECT public: Display(); virtual ~Display(); /** @brief Main initialization, called after constructor, before load() or setEnabled(). */ void initialize( DisplayContext* context ); /** @brief Return data appropriate for the given column (0 or 1) and * role for this Display. */ virtual QVariant getViewData( int column, int role ) const; /** @brief Return item flags appropriate for the given column (0 or * 1) for this Display. */ virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Return the class identifier which was used to create this * instance. This version just returns whatever was set with * setClassId(). */ virtual QString getClassId() const { return class_id_; } /** @brief Set the class identifier used to create this instance. * Typically this will be set by the factory object which created it. */ virtual void setClassId( const QString& class_id ) { class_id_ = class_id; } /** @brief Load the settings for this display from the given Config * node, which must be a map. * * Overridden from Property::load() to load the Display's * name and enabled state, then call Property::load(). * * load() is called after initialize(). */ virtual void load( const Config& config ); /** @brief Write this display to the given Config node. * * Overridden from Property::save(). */ virtual void save( Config config ) const; /** @brief Set the ROS topic to listen to for this display. * * By default, do nothing. Subclasses should override this method if they * subscribe to a single ROS topic. * * setTopic() is used by the "New display by topic" window; it is called * with a user selected topic and its type. * * @param topic The published topic to be visualized. * @param datatype The datatype of the topic. */ virtual void setTopic( const QString &topic, const QString &datatype ) { (void) topic; (void) datatype; } /** @brief Return true if this Display is enabled, false if not. */ bool isEnabled() const; /** @brief Set the fixed frame in this display. */ void setFixedFrame( const QString& fixed_frame ); /** @brief Called periodically by the visualization manager. * @param wall_dt Wall-clock time, in seconds, since the last time the update list was run through. * @param ros_dt ROS time, in seconds, since the last time the update list was run through. */ virtual void update( float wall_dt, float ros_dt ) { (void) wall_dt; (void) ros_dt; } /** @brief Called to tell the display to clear its state */ virtual void reset(); /** @brief Show status level and text. This is thread-safe. * @param level One of StatusProperty::Ok, StatusProperty::Warn, or StatusProperty::Error. * @param name The name of the child entry to set. * @param text Description of the child's state. * * Every Display has a StatusList to indicate how it is doing. The * StatusList has StatusPropertychildren indicating the status of * various subcomponents of the Display. Each child of the status * has a level, a name, and descriptive text. The top-level * StatusList has a level which is set to the worst of all the * children's levels. */ virtual void setStatus( StatusProperty::Level level, const QString& name, const QString& text ); /** @brief Show status level and text, using a std::string. * Convenience function which converts std::string to QString * and calls setStatus(). This is thread-safe. */ void setStatusStd( StatusProperty::Level level, const std::string& name, const std::string& text ) { setStatus( level, QString::fromStdString( name ), QString::fromStdString( text )); } /** @brief Delete the status entry with the given name. This is thread-safe. */ virtual void deleteStatus( const QString& name ); /** @brief Delete the status entry with the given std::string name. This is thread-safe. */ void deleteStatusStd( const std::string& name ) { deleteStatus( QString::fromStdString( name )); } /** Default is all bits ON. */ void setVisibilityBits( uint32_t bits ); void unsetVisibilityBits( uint32_t bits ); uint32_t getVisibilityBits() { return visibility_bits_; } /** @brief Return the Ogre::SceneNode holding all 3D scene elements shown by this Display. */ Ogre::SceneNode* getSceneNode() const { return scene_node_; } /** @brief Associate the given @a widget with this Display. * * Each Display can have one QWidget which is shown when the Display * is enabled and hidden when the Display is disabled. If there is * a WindowManagerInterface registered with the * VisualizationManager, like if you are using a VisualizationFrame, * this also adds widget as a pane within it (with * WindowManagerInterface::addPane() ). * * Since there is only one slot for such a widget, this * dis-associates any previously associated widget. * * Call this with NULL to disassociate the current associated widget. */ void setAssociatedWidget( QWidget* widget ); /** @brief Return the current associated widget, or NULL if there is none. * @sa setAssociatedWidget() */ QWidget* getAssociatedWidget() const { return associated_widget_; } /** @brief Return the panel containing the associated widget, or NULL if there is none. * @sa setAssociatedWidget() */ PanelDockWidget* getAssociatedWidgetPanel() { return associated_widget_panel_; } /** @brief Overridden from Property to set associated widget title to the new name. */ void setName( const QString& name ); /** @brief Emit a time signal that other Displays can synchronize to. */ void emitTimeSignal( ros::Time time ); Q_SIGNALS: void timeSignal( rviz::Display* display, ros::Time time ); public Q_SLOTS: /** @brief Enable or disable this Display. * * SetEnabled is called after initialize() and at the end of load(), * if the Display settings are being loaded from a file. */ void setEnabled( bool enabled ); /** @brief Convenience function which calls context_->queueRender(). */ void queueRender(); /** @brief Set the Display's icon. */ virtual void setIcon( const QIcon& icon ); protected: /** @brief Override this function to do subclass-specific initialization. * * This is called after vis_manager_ and scene_manager_ are set, and * before load() or setEnabled(). * * setName() may or may not have been called before this. */ virtual void onInitialize() {} /** @brief Derived classes override this to do the actual work of enabling themselves. */ virtual void onEnable() {} /** @brief Derived classes override this to do the actual work of disabling themselves. */ virtual void onDisable() {} /** @brief Delete all status children. This is thread-safe. * * This removes all status children and updates the top-level status. */ virtual void clearStatuses(); /** @brief Called by setFixedFrame(). Override to respond to changes to fixed_frame_. */ virtual void fixedFrameChanged() {} /** @brief Returns true if the display has been initialized */ bool initialized() const { return initialized_; } /** @brief This DisplayContext pointer is the main connection a * Display has into the rest of rviz. This is how the FrameManager * is accessed, the SelectionManager, etc. When a Display subclass * wants to signal that a new render should be done right away, call * context_->queueRender(). * * This is set after the constructor and before onInitialize() is called. */ DisplayContext* context_; /** @brief A convenience variable equal to context_->getSceneManager(). * * This is set after the constructor and before onInitialize() is called. */ Ogre::SceneManager* scene_manager_; /** @brief The Ogre::SceneNode to hold all 3D scene elements shown by this Display. */ Ogre::SceneNode* scene_node_; /** @brief A NodeHandle whose CallbackQueue is run from the main GUI thread (the "update" thread). * * This is configured after the constructor and before onInitialize() is called. */ ros::NodeHandle update_nh_; /** @brief A NodeHandle whose CallbackQueue is run from a different thread than the GUI. * * This is configured after the constructor and before onInitialize() is called. */ ros::NodeHandle threaded_nh_; /** @brief A convenience variable equal to context_->getFixedFrame(). * * This is set after the constructor and before onInitialize() is * called. Every time it is updated (via setFixedFrame()), * fixedFrameChanged() is called. */ QString fixed_frame_; public Q_SLOTS: virtual void onEnableChanged(); private Q_SLOTS: void setStatusInternal( int level, const QString& name, const QString& text ); void deleteStatusInternal( const QString& name ); void clearStatusesInternal(); void associatedPanelVisibilityChange( bool visible ); void disable(); private: StatusList* status_; QString class_id_; bool initialized_; uint32_t visibility_bits_; QWidget* associated_widget_; PanelDockWidget* associated_widget_panel_; }; } // end namespace rviz #endif // DISPLAY_H rviz-1.12.4/src/rviz/display_context.h000066400000000000000000000116211300447110700177320ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef DISPLAY_CONTEXT_H #define DISPLAY_CONTEXT_H #include // for uint64_t #include #include class QKeyEvent; namespace Ogre { class SceneManager; } namespace ros { class CallbackQueueInterface; } namespace tf { class TransformListener; } namespace rviz { class BitAllocator; class DisplayFactory; class DisplayGroup; class FrameManager; class RenderPanel; class SelectionManager; class ToolManager; class ViewController; class ViewportMouseEvent; class ViewManager; class WindowManagerInterface; /** @brief Pure-virtual base class for objects which give Display * subclasses context in which to work. * * This interface class mainly exists to enable more isolated unit * tests by enabling small mock objects to take the place of the large * VisualizationManager implementation class. It also serves to * define a narrower, more maintainable API for Display plugins. */ class DisplayContext: public QObject { Q_OBJECT public: /** @brief Returns the Ogre::SceneManager used for the main RenderPanel. */ virtual Ogre::SceneManager* getSceneManager() const = 0; /** @brief Return the window manager, if any. */ virtual WindowManagerInterface* getWindowManager() const = 0; /** @brief Return a pointer to the SelectionManager. */ virtual SelectionManager* getSelectionManager() const = 0; /** @brief Return the FrameManager instance. */ virtual FrameManager* getFrameManager() const = 0; /** @brief Convenience function: returns getFrameManager()->getTFClient(). */ virtual tf::TransformListener* getTFClient() const = 0; /** @brief Return the fixed frame name. */ virtual QString getFixedFrame() const = 0; /** @brief Return the current value of the frame count. * * The frame count is just a number which increments each time a * frame is rendered. This lets clients check if a new frame has * been rendered since the last time they did something. */ virtual uint64_t getFrameCount() const = 0; /** @brief Return a factory for creating Display subclasses based on a class id string. */ virtual DisplayFactory* getDisplayFactory() const = 0; /** @brief Return the CallbackQueue using the main GUI thread. */ virtual ros::CallbackQueueInterface* getUpdateQueue() = 0; /** @brief Return a CallbackQueue using a different thread than the main GUI one. */ virtual ros::CallbackQueueInterface* getThreadedQueue() = 0; /** @brief Handle a single key event for a given RenderPanel. */ virtual void handleChar( QKeyEvent* event, RenderPanel* panel ) = 0; /** @brief Handle a mouse event. */ virtual void handleMouseEvent( const ViewportMouseEvent& event ) = 0; /** @brief Return the ToolManager. */ virtual ToolManager* getToolManager() const = 0; /** @brief Return the ViewManager. */ virtual ViewManager* getViewManager() const = 0; virtual DisplayGroup* getRootDisplayGroup() const = 0; virtual uint32_t getDefaultVisibilityBit() const = 0; virtual BitAllocator* visibilityBits() = 0; /** Set the message displayed in the status bar */ virtual void setStatus( const QString & message ) = 0; public Q_SLOTS: /** @brief Queues a render. Multiple calls before a render happens will only cause a single render. * @note This function can be called from any thread. */ virtual void queueRender() = 0; }; } // end namespace rviz #endif // DISPLAY_CONTEXT_H rviz-1.12.4/src/rviz/display_factory.cpp000066400000000000000000000127061300447110700202550ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/display_group.h" #include "rviz/display_factory.h" #include namespace rviz { static Display* newDisplayGroup() { return new DisplayGroup(); } DisplayFactory::DisplayFactory() : PluginlibFactory( "rviz", "rviz::Display" ) { addBuiltInClass( "rviz", "Group", "A container for Displays", &newDisplayGroup ); } Display* DisplayFactory::makeRaw( const QString& class_id, QString* error_return ) { Display* display = PluginlibFactory::makeRaw( class_id, error_return ); if ( display ) { display->setIcon( getIcon( class_id )); } return display; } QSet DisplayFactory::getMessageTypes( const QString& class_id ) { // lookup in cache if ( message_type_cache_.find( class_id ) != message_type_cache_.end() ) { return message_type_cache_[class_id]; } // Always initialize cache as empty so if we don't find it, next time // we won't look for it anymore either. message_type_cache_[ class_id ] = QSet(); // parse xml plugin description to find out message types of all displays in it. QString xml_file = getPluginManifestPath( class_id ); if ( !xml_file.isEmpty() ) { ROS_DEBUG_STREAM("Parsing " << xml_file.toStdString()); TiXmlDocument document; document.LoadFile(xml_file.toStdString()); TiXmlElement * config = document.RootElement(); if (config == NULL) { ROS_ERROR("Skipping XML Document \"%s\" which had no Root Element. This likely means the XML is malformed or missing.", xml_file.toStdString().c_str()); return QSet(); } if (config->ValueStr() != "library" && config->ValueStr() != "class_libraries") { ROS_ERROR("The XML document \"%s\" given to add must have either \"library\" or \ \"class_libraries\" as the root tag", xml_file.toStdString().c_str()); return QSet(); } //Step into the filter list if necessary if (config->ValueStr() == "class_libraries") { config = config->FirstChildElement("library"); } TiXmlElement* library = config; while ( library != NULL) { TiXmlElement* class_element = library->FirstChildElement("class"); while (class_element) { std::string derived_class = class_element->Attribute("type"); std::string current_class_id; if(class_element->Attribute("name") != NULL) { current_class_id = class_element->Attribute("name"); ROS_DEBUG("XML file specifies lookup name (i.e. magic name) = %s.", current_class_id.c_str()); } else { ROS_DEBUG("XML file has no lookup name (i.e. magic name) for class %s, assuming class_id == real class name.", derived_class.c_str()); current_class_id = derived_class; } QSet message_types; TiXmlElement* message_type = class_element->FirstChildElement("message_type"); while ( message_type ) { if ( message_type->GetText() ) { const char* message_type_str = message_type->GetText(); ROS_DEBUG_STREAM(current_class_id << " supports message type " << message_type_str ); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) message_types.insert( QString::fromAscii( message_type_str ) ); #else message_types.insert( QString(message_type_str) ); #endif } message_type = message_type->NextSiblingElement("message_type"); } message_type_cache_[ QString::fromStdString(current_class_id) ] = message_types; //step to next class_element class_element = class_element->NextSiblingElement( "class" ); } library = library->NextSiblingElement( "library" ); } } // search cache again. if ( message_type_cache_.find( class_id ) != message_type_cache_.end() ) { return message_type_cache_[class_id]; } return QSet(); } } // end namespace rviz rviz-1.12.4/src/rviz/display_factory.h000066400000000000000000000044431300447110700177210ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef DISPLAY_FACTORY_H #define DISPLAY_FACTORY_H #include "rviz/display.h" #include "rviz/pluginlib_factory.h" #include #include #include #include namespace rviz { class DisplayFactory: public PluginlibFactory { public: DisplayFactory(); /** @brief Get all supported message types for the given class id. */ virtual QSet getMessageTypes( const QString& class_id ); protected: /** @brief Overridden from PluginlibFactory to set the icon of the Display. */ virtual Display* makeRaw( const QString& class_id, QString* error_return = NULL ); QMap< QString, QSet > message_type_cache_; }; } // end namespace rviz #endif // DISPLAY_FACTORY_H rviz-1.12.4/src/rviz/display_group.cpp000066400000000000000000000222721300447110700177410ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include // for debug-write printf #include #include "rviz/display_context.h" #include "rviz/display_factory.h" #include "rviz/failed_display.h" #include "rviz/properties/property_tree_model.h" #include "display_group.h" namespace rviz { DisplayGroup::DisplayGroup() { } DisplayGroup::~DisplayGroup() { removeAllDisplays(); } Qt::ItemFlags DisplayGroup::getViewFlags( int column ) const { return Display::getViewFlags( column ) | Qt::ItemIsDropEnabled; } void DisplayGroup::load( const Config& config ) { removeAllDisplays(); // Only remove Display children, property children must stay. // Load Property values, plus name and enabled/disabled. Display::load( config ); // Now load Displays. Config display_list_config = config.mapGetChild( "Displays" ); int num_displays = display_list_config.listLength(); if( num_displays == 0 ) return; if( model_ ) { model_->beginInsert( this, Display::numChildren(), num_displays ); } std::map display_config_map; // The following two-step loading procedure was motivated by the // 'display group visibility' property, which needs all other displays // to be created and named before it can load its settings. // hersh says: Is this really necessary? Can't we make // DisplayGroupVisibilityProperty self-sufficient in this regard? // Also, does it really work? What about saving and loading a // hierarchy of Displays, will they really all have the right // visibility settings? // first, create all displays and set their names for( int i = 0; i < num_displays; i++ ) { Config display_config = display_list_config.listChildAt( i ); QString display_class = "(no class name found)"; display_config.mapGetString( "Class", &display_class ); Display* disp = createDisplay( display_class ); addDisplayWithoutSignallingModel( disp ); QString display_name; display_config.mapGetString( "Name", &display_name ); disp->setObjectName( display_name ); display_config_map[ disp ] = display_config; } // now, initialize all displays and load their properties. for( std::map::iterator it = display_config_map.begin(); it != display_config_map.end(); ++it ) { Config display_config = it->second; Display* disp = it->first; disp->initialize( context_ ); disp->load( display_config ); } if( model_ ) { model_->endInsert(); } } Display* DisplayGroup::createDisplay( const QString& class_id ) { DisplayFactory* factory = context_->getDisplayFactory(); QString error; Display* disp = factory->make( class_id, &error ); if( !disp ) { return new FailedDisplay( class_id, error ); } return disp; } void DisplayGroup::onEnableChanged() { Display::onEnableChanged(); for( int i = displays_.size() - 1; i >= 0; i-- ) { displays_[ i ]->onEnableChanged(); } } void DisplayGroup::save( Config config ) const { Display::save( config ); // Save Displays in a sequence under the key "Displays". Config display_list_config = config.mapMakeChild( "Displays" ); int num_displays = displays_.size(); for( int i = 0; i < num_displays; i++ ) { displays_.at( i )->save( display_list_config.listAppendNew() ); } } void DisplayGroup::removeAllDisplays() { if(displays_.size() == 0) return; int num_non_display_children = Display::numChildren(); if( model_ ) { model_->beginRemove( this, num_non_display_children, displays_.size() ); } for( int i = displays_.size() - 1; i >= 0; i-- ) { Display* child = displays_.takeAt( i ); Q_EMIT displayRemoved( child ); child->setParent( NULL ); // prevent child destructor from calling getParent()->takeChild(). child->setModel( NULL ); child_indexes_valid_ = false; delete child; } if( model_ ) { model_->endRemove(); } Q_EMIT childListChanged( this ); } Display* DisplayGroup::takeDisplay( Display* child ) { Display* result = NULL; int num_displays = displays_.size(); for( int i = 0; i < num_displays; i++ ) { if( displays_.at( i ) == child ) { if( model_ ) { model_->beginRemove( this, Display::numChildren() + i, 1 ); } result = displays_.takeAt( i ); Q_EMIT displayRemoved( result ); result->setParent( NULL ); result->setModel( NULL ); child_indexes_valid_ = false; if( model_ ) { model_->endRemove(); } Q_EMIT childListChanged( this ); break; } } return result; } Display* DisplayGroup::getDisplayAt( int index ) const { if( 0 <= index && index < displays_.size() ) { return displays_.at( index ); } return NULL; } DisplayGroup* DisplayGroup::getGroupAt( int index ) const { return qobject_cast( getDisplayAt( index )); } void DisplayGroup::fixedFrameChanged() { int num_children = displays_.size(); for( int i = 0; i < num_children; i++ ) { displays_.at( i )->setFixedFrame( fixed_frame_ ); } } void DisplayGroup::update( float wall_dt, float ros_dt ) { int num_children = displays_.size(); for( int i = 0; i < num_children; i++ ) { Display* display = displays_.at( i ); if( display->isEnabled() ) { display->update( wall_dt, ros_dt ); } } } void DisplayGroup::reset() { Display::reset(); int num_children = displays_.size(); for( int i = 0; i < num_children; i++ ) { displays_.at( i )->reset(); } } void DisplayGroup::addDisplayWithoutSignallingModel( Display* child ) { // printf(" displaygroup4 displays_.append( child )\n" ); displays_.append( child ); child_indexes_valid_ = false; child->setModel( model_ ); child->setParent( this ); Q_EMIT displayAdded( child ); } void DisplayGroup::addDisplay( Display* child ) { if( model_ ) { model_->beginInsert( this, numChildren(), 1 ); } addDisplayWithoutSignallingModel( child ); if( model_ ) { model_->endInsert(); } Q_EMIT childListChanged( this ); } void DisplayGroup::addChild( Property* child, int index ) { Display* display = qobject_cast( child ); if( !display ) { Display::addChild( child, index ); return; } if( index < 0 || index > numChildren() ) { index = numChildren(); } int disp_index = index - Display::numChildren(); if( disp_index < 0 ) { disp_index = 0; } if( model_ ) { model_->beginInsert( this, index ); } displays_.insert( disp_index, display ); Q_EMIT displayAdded( display ); child_indexes_valid_ = false; display->setModel( model_ ); display->setParent( this ); if( model_ ) { model_->endInsert(); } Q_EMIT childListChanged( this ); } Property* DisplayGroup::takeChildAt( int index ) { if( index < Display::numChildren() ) { return Display::takeChildAt( index ); } int disp_index = index - Display::numChildren(); if( model_ ) { model_->beginRemove( this, index, 1 ); } // printf(" displaygroup5 displays_.takeAt( %d ) ( index = %d )\n", disp_index, index ); Display* child = displays_.takeAt( disp_index ); Q_EMIT displayRemoved( child ); child->setModel( NULL ); child->setParent( NULL ); child_indexes_valid_ = false; if( model_ ) { model_->endRemove(); } Q_EMIT childListChanged( this ); return child; } int DisplayGroup::numDisplays() const { return displays_.size(); } int DisplayGroup::numChildren() const { return Display::numChildren() + displays_.size(); } Property* DisplayGroup::childAtUnchecked( int index ) const { int first_child_count = Display::numChildren(); if( index < first_child_count ) { return Display::childAtUnchecked( index ); } index -= first_child_count; return displays_.at( index ); } } // end namespace rviz rviz-1.12.4/src/rviz/display_group.h000066400000000000000000000137371300447110700174140ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef DISPLAY_GROUP_H #define DISPLAY_GROUP_H #include "display.h" namespace rviz { class DisplayFactory; /** @brief A Display object which stores other Displays as children. * * A DisplayGroup can have non-Display child properties as well as * Display children, but they are kept separate. Non-display * properties come first, and Display children come after. The * Property superclass stores the non-Display properties and this * class stores the Display objects in a separate list. The * separation is enforced in addChild(). */ class DisplayGroup: public Display { Q_OBJECT public: DisplayGroup(); virtual ~DisplayGroup(); Display* createDisplay( const QString& class_id ); /** @brief Return the number of child objects (Property and Display). * * Overridden from Property to include the number of child Displays. */ virtual int numChildren() const; /** @brief Return the child with the given index, without * checking whether the index is within bounds. * * Overridden from Property to include Display children. */ virtual Property* childAtUnchecked( int index ) const; /** @brief Take a child out of the child list, but don't destroy it. * @return Returns the child property at the given index, or NULL if the index is out of bounds. * * This notifies the model about the removal. * * This is overridden from Property to include Display children. */ virtual Property* takeChildAt( int index ); /** @brief Add a child Property or Display. * @param child The child to add. * @param index [optional] The index at which to add the child. If * less than 0 or greater than the number of child properties, the * child will be added at the end. * * This notifies the model about the addition. * * This is overridden from Property to keep non-Display child * Properties in Property's list of children and Display children in * DisplayGroup's list of child Displays. */ virtual void addChild( Property* child, int index = -1 ); /** @brief Return item flags appropriate for the given column (0 or * 1) for this DisplayGroup. */ virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Load subproperties and the list of displays in this group * from the given Config node, which must be a map. */ virtual void load( const Config& config ); /** @brief Save subproperties and the list of displays in this group * to the given Config node. */ virtual void save( Config config ) const; /** @brief Add a child Display to the end of the list of Displays. * * This also tells the model that we are adding a child, so it can * update widgets. * * @note This does @e not remove @a child from its parent. That * must be done first to avoid problems. */ virtual void addDisplay( Display* child ); /** @brief Remove a child Display from the the list of Displays, but * don't destroy it. * @return Returns child if it is found, or NULL if child is not found. * * This also tells the model that we are removing a child, so it can * update widgets. */ virtual Display* takeDisplay( Display* child ); /** @brief Remove and destroy all child Displays, but preserve any * non-Display children. */ virtual void removeAllDisplays(); /** @brief Return the number of child Displays. */ virtual int numDisplays() const; /** @brief Return the index-th Display in this group, or NULL if the * index is invalid. */ virtual Display* getDisplayAt( int index ) const; /** @brief Find the index-th child Display in this group. If the * child is itself a DisplayGroup, return the pointer to it. If it * is not, return NULL. */ virtual DisplayGroup* getGroupAt( int index ) const; /** @brief Call update() on all child Displays. */ virtual void update( float wall_dt, float ros_dt ); /** @brief Reset this and all child Displays. */ virtual void reset(); public Q_SLOTS: virtual void onEnableChanged(); protected: /** @brief Update the fixed frame in all contained displays. */ virtual void fixedFrameChanged(); /** @brief Add a child Display to the end of the list of Displays, * but without telling the model. */ virtual void addDisplayWithoutSignallingModel( Display* child ); Q_SIGNALS: void displayAdded( rviz::Display* display ); void displayRemoved( rviz::Display* display ); private: QList displays_; }; } // end namespace rviz #endif // DISPLAY_GROUP_H rviz-1.12.4/src/rviz/displays_panel.cpp000066400000000000000000000205611300447110700200660ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "rviz/display_factory.h" #include "rviz/display.h" #include "rviz/add_display_dialog.h" #include "rviz/properties/property.h" #include "rviz/properties/property_tree_widget.h" #include "rviz/properties/property_tree_with_help.h" #include "rviz/visualization_manager.h" #include "rviz/displays_panel.h" namespace rviz { DisplaysPanel::DisplaysPanel( QWidget* parent ) : Panel( parent ) { tree_with_help_ = new PropertyTreeWithHelp; property_grid_ = tree_with_help_->getTree(); QPushButton* add_button = new QPushButton( "Add" ); add_button->setShortcut( QKeySequence( QString( "Ctrl+N" ))); add_button->setToolTip( "Add a new display, Ctrl+N" ); duplicate_button_ = new QPushButton( "Duplicate" ); duplicate_button_->setShortcut( QKeySequence( QString( "Ctrl+D" ))); duplicate_button_->setToolTip( "Duplicate a display, Ctrl+D" ); duplicate_button_->setEnabled( false ); remove_button_ = new QPushButton( "Remove" ); remove_button_->setShortcut( QKeySequence( QString( "Ctrl+X" ))); remove_button_->setToolTip( "Remove displays, Ctrl+X" ); remove_button_->setEnabled( false ); rename_button_ = new QPushButton( "Rename" ); rename_button_->setShortcut( QKeySequence( QString( "Ctrl+R" ))); rename_button_->setToolTip( "Rename a display, Ctrl+R" ); rename_button_->setEnabled( false ); QHBoxLayout* button_layout = new QHBoxLayout; button_layout->addWidget( add_button ); button_layout->addWidget( duplicate_button_ ); button_layout->addWidget( remove_button_ ); button_layout->addWidget( rename_button_ ); button_layout->setContentsMargins( 2, 0, 2, 2 ); QVBoxLayout* layout = new QVBoxLayout; layout->setContentsMargins( 0, 0, 0, 2 ); layout->addWidget( tree_with_help_ ); layout->addLayout( button_layout ); setLayout( layout ); connect( add_button, SIGNAL( clicked( bool )), this, SLOT( onNewDisplay() )); connect( duplicate_button_, SIGNAL( clicked( bool )), this, SLOT( onDuplicateDisplay() )); connect( remove_button_, SIGNAL( clicked( bool )), this, SLOT( onDeleteDisplay() )); connect( rename_button_, SIGNAL( clicked( bool )), this, SLOT( onRenameDisplay() )); connect( property_grid_, SIGNAL( selectionHasChanged() ), this, SLOT( onSelectionChanged() )); } DisplaysPanel::~DisplaysPanel() { } void DisplaysPanel::onInitialize() { property_grid_->setModel( vis_manager_->getDisplayTreeModel() ); } void DisplaysPanel::onNewDisplay() { QString lookup_name; QString display_name; QString topic; QString datatype; QStringList empty; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); AddDisplayDialog* dialog = new AddDisplayDialog( vis_manager_->getDisplayFactory(), "Display", empty, empty, &lookup_name, &display_name, &topic, &datatype ); QApplication::restoreOverrideCursor(); vis_manager_->stopUpdate(); if( dialog->exec() == QDialog::Accepted ) { Display *disp = vis_manager_->createDisplay( lookup_name, display_name, true ); if ( !topic.isEmpty() && !datatype.isEmpty() ) { disp->setTopic( topic, datatype ); } } vis_manager_->startUpdate(); activateWindow(); // Force keyboard focus back on main window. delete dialog; } void DisplaysPanel::onDuplicateDisplay() { QList displays_to_duplicate = property_grid_->getSelectedObjects(); QList duplicated_displays; for( int i = 0; i < displays_to_duplicate.size(); i++ ) { // initialize display QString lookup_name = displays_to_duplicate[ i ]->getClassId(); QString display_name = displays_to_duplicate[ i ]->getName(); Display *disp = vis_manager_->createDisplay( lookup_name, display_name, true ); // duplicate config Config config; displays_to_duplicate[ i ]->save(config); disp->load(config); duplicated_displays.push_back(disp); } // make sure the newly duplicated displays are selected. if (duplicated_displays.size() > 0) { QModelIndex first = property_grid_->getModel()->indexOf(duplicated_displays.front()); QModelIndex last = property_grid_->getModel()->indexOf(duplicated_displays.back()); QItemSelection selection(first, last); property_grid_->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect); } vis_manager_->startUpdate(); activateWindow(); // Force keyboard focus back on main window. } void DisplaysPanel::onDeleteDisplay() { QList displays_to_delete = property_grid_->getSelectedObjects(); QModelIndex new_selected; for( int i = 0; i < displays_to_delete.size(); i++ ) { if (i == 0) { QModelIndex first = property_grid_->getModel()->indexOf(displays_to_delete[i]); // This is safe because the first few rows cannot be deleted (they aren't "displays"). new_selected = first.sibling(first.row() - 1, first.column()); } // Displays can emit signals from other threads with self pointers. We're // freeing the display now, so ensure no one is listening to those signals. displays_to_delete[ i ]->disconnect(); // Delete display later in case there are pending signals to it. displays_to_delete[ i ]->deleteLater(); } QItemSelection selection(new_selected, new_selected); property_grid_->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect); vis_manager_->notifyConfigChanged(); } void DisplaysPanel::onSelectionChanged() { QList displays = property_grid_->getSelectedObjects(); int num_displays_selected = displays.size(); duplicate_button_->setEnabled( num_displays_selected > 0 ); remove_button_->setEnabled( num_displays_selected > 0 ); rename_button_->setEnabled( num_displays_selected == 1 ); } void DisplaysPanel::onRenameDisplay() { QList displays = property_grid_->getSelectedObjects(); if( displays.size() == 0 ) { return; } Display* display_to_rename = displays[ 0 ]; if( !display_to_rename ) { return; } QString old_name = display_to_rename->getName(); QString new_name = QInputDialog::getText( this, "Rename Display", "New Name?", QLineEdit::Normal, old_name ); if( new_name.isEmpty() || new_name == old_name ) { return; } display_to_rename->setName( new_name ); } void DisplaysPanel::save( Config config ) const { Panel::save( config ); tree_with_help_->save( config ); } void DisplaysPanel::load( const Config& config ) { Panel::load( config ); tree_with_help_->load( config ); } } // namespace rviz rviz-1.12.4/src/rviz/displays_panel.h000066400000000000000000000055141300447110700175340ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_DISPLAYS_PANEL_H #define RVIZ_DISPLAYS_PANEL_H #include #include #include #include #include "rviz/config.h" #include "rviz/panel.h" class QPushButton; namespace rviz { class PropertyTreeWidget; class PropertyTreeWithHelp; class VisualizationManager; class Display; /** * \class DisplaysPanel * */ class DisplaysPanel: public Panel { Q_OBJECT public: DisplaysPanel( QWidget* parent = 0); virtual ~DisplaysPanel(); virtual void onInitialize(); /** @brief Write state to the given Config object. */ virtual void save( Config config ) const; /** @brief Read state from the given Config. */ virtual void load( const Config& config ); protected Q_SLOTS: /// Called when the "Add" button is pressed void onNewDisplay(); /// Called when the "copy" button is pressed void onDuplicateDisplay(); /// Called when the "Remove" button is pressed void onDeleteDisplay(); /// Called when the "Rename" button is pressed void onRenameDisplay(); void onSelectionChanged(); protected: PropertyTreeWidget* property_grid_; QPushButton* duplicate_button_; QPushButton* remove_button_; QPushButton* rename_button_; PropertyTreeWithHelp* tree_with_help_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/env_config.cpp.in000066400000000000000000000041261300447110700176000ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "env_config.h" namespace rviz { std::string get_version() { // The return string here is replaced at compile time by // CMakeLists.txt in this directory. return "@RVIZ_VERSION@"; } std::string get_distro() { // The return string here is replaced at compile time by // CMakeLists.txt in this directory. return "@ROS_DISTRO@"; } std::string get_ogre_plugin_path() { // The return string here is replaced at compile time by // CMakeLists.txt in this directory. return "@OGRE_PLUGIN_PATH@"; } } rviz-1.12.4/src/rviz/env_config.h000066400000000000000000000034341300447110700166410ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ENV_CONFIG_H #define RVIZ_ENV_CONFIG_H #include namespace rviz { std::string get_version(); std::string get_distro(); std::string get_ogre_plugin_path(); } #endif // RVIZ_ENV_CONFIG_H rviz-1.12.4/src/rviz/factory.h000066400000000000000000000045711300447110700161760ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_FACTORY_H #define RVIZ_FACTORY_H #include #include #include namespace rviz { /** @brief Abstract superclass representing the ability to get a list * of class IDs and the ability to get name, description, and package * strings for each. Actually instantiating objects must be done by * subclasses specialized for specific types. */ class Factory { public: virtual ~Factory() {} virtual QStringList getDeclaredClassIds() = 0; virtual QString getClassDescription( const QString& class_id ) const = 0; virtual QString getClassName( const QString& class_id ) const = 0; virtual QString getClassPackage( const QString& class_id ) const = 0; virtual QIcon getIcon( const QString& class_id ) const = 0; }; } // end namespace rviz #endif // RVIZ_FACTORY_H rviz-1.12.4/src/rviz/failed_display.cpp000066400000000000000000000053701300447110700200310ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/status_property.h" #include "rviz/display_context.h" #include "rviz/load_resource.h" #include "failed_display.h" namespace rviz { FailedDisplay::FailedDisplay( const QString& desired_class_id, const QString& error_message ) : error_message_( error_message ) { setClassId( desired_class_id ); setIcon( loadPixmap( "package://rviz/icons/failed_display.png" ) ); } QVariant FailedDisplay::getViewData( int column, int role ) const { if( column == 0 ) { switch( role ) { case Qt::BackgroundRole: return QColor( Qt::white ); case Qt::ForegroundRole: return StatusProperty::statusColor( StatusProperty::Error ); default: break; } } return Display::getViewData( column, role ); } QString FailedDisplay::getDescription() const { return "The class required for this display, '" + getClassId() + "', could not be loaded.
Error:
" + error_message_; } void FailedDisplay::load( const Config& config ) { saved_config_ = config; Display::load( config ); } void FailedDisplay::save( Config config ) { if( saved_config_.isValid() ) { config.copy( saved_config_ ); } } } // end namespace rviz rviz-1.12.4/src/rviz/failed_display.h000066400000000000000000000054031300447110700174730ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef FAILED_DISPLAY_H #define FAILED_DISPLAY_H #include "display.h" namespace rviz { /** @brief A FailedDisplay instance represents a Display class we * tried and failed to instantiate. * * FailedDisplay stores the class id which it was supposed to be, and * an error message describing the failure. * * The load() and save() functions work together to ensure that loaded * configuration data is saved out again without modification. This * ensures that running rviz with a missing plugin library won't * damage config files which refer to it. */ class FailedDisplay: public Display { public: FailedDisplay( const QString& desired_class_id, const QString& error_message ); virtual QVariant getViewData( int column, int role ) const; virtual QString getDescription() const; /** @brief Store the given Config data for later, so we can return it * with save() when someone writes this back to a file. */ virtual void load( const Config& config ); /** @brief Save Config equivalent to the last which was sent to load(). */ virtual void save( Config config ); private: Config saved_config_; QString error_message_; }; } // end namespace rviz #endif // FAILED_DISPLAY_H rviz-1.12.4/src/rviz/failed_panel.cpp000066400000000000000000000046741300447110700174710ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/failed_panel.h" namespace rviz { FailedPanel::FailedPanel( const QString& desired_class_id, const QString& error_message ) : error_message_( error_message ) { setClassId( desired_class_id ); QTextBrowser* error_display = new QTextBrowser; error_display->setHtml( "The class required for this panel, '" + getClassId() + "', could not be loaded.
Error:
" + error_message_ ); QHBoxLayout* layout = new QHBoxLayout; layout->addWidget( error_display ); setLayout( layout ); } void FailedPanel::load( const Config& config ) { saved_config_ = config; Panel::load( config ); } void FailedPanel::save( Config config ) const { if( saved_config_.isValid() ) { config.copy( saved_config_ ); } else { Panel::save( config ); } } } // end namespace rviz rviz-1.12.4/src/rviz/failed_panel.h000066400000000000000000000043531300447110700171300ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef FAILED_PANEL_H #define FAILED_PANEL_H #include #include "rviz/panel.h" namespace rviz { class FailedPanel: public Panel { Q_OBJECT public: FailedPanel( const QString& desired_class_id, const QString& error_message ); /** @brief Store the given Config data for later, so we can return it * with save() when someone writes this back to a file. */ virtual void load( const Config& config ); /** @brief Copy Config data into config equivalent to the last which was sent to load(). */ virtual void save( Config config ) const; private: Config saved_config_; QString error_message_; }; } // end namespace rviz #endif // FAILED_PANEL_H rviz-1.12.4/src/rviz/failed_tool.cpp000066400000000000000000000050331300447110700173350ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/display_context.h" #include "rviz/window_manager_interface.h" #include "rviz/failed_tool.h" namespace rviz { FailedTool::FailedTool( const QString& desired_class_id, const QString& error_message ) : error_message_( error_message ) { setClassId( desired_class_id ); } QString FailedTool::getDescription() const { return "The class required for this tool, '" + getClassId() + "', could not be loaded.
Error:
" + error_message_; } void FailedTool::load( const Config& config ) { saved_config_ = config; } void FailedTool::save( Config config ) const { if( saved_config_.isValid() ) { config.copy( saved_config_ ); } } void FailedTool::activate() { QWidget* parent = NULL; if( context_->getWindowManager() ) { parent = context_->getWindowManager()->getParentWindow(); } QMessageBox::critical( parent, "Tool '" + getName() + "'unavailable.", getDescription() ); } } // end namespace rviz rviz-1.12.4/src/rviz/failed_tool.h000066400000000000000000000054631300447110700170110ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef FAILED_TOOL_H #define FAILED_TOOL_H #include "tool.h" namespace rviz { /** @brief A FailedTool instance represents a Tool class we * tried and failed to instantiate. * * FailedTool stores the class id which it was supposed to be, and * an error message describing the failure. * * The load() and save() functions work together to ensure that loaded * configuration data is saved out again without modification. This * ensures that running rviz with a missing plugin library won't * damage config files which refer to it. */ class FailedTool: public Tool { public: FailedTool( const QString& desired_class_id, const QString& error_message ); virtual QString getDescription() const; virtual void activate(); virtual void deactivate() {} virtual int processMouseEvent( ViewportMouseEvent& event ) { return 0; } /** @brief Store the given config data for later, so we can return it * with save() when someone writes this back to a file. */ virtual void load( const Config& config ); /** @brief Copy saved config data from last call to load() into config. */ virtual void save( Config config ) const; private: Config saved_config_; QString error_message_; }; } // end namespace rviz #endif // FAILED_TOOL_H rviz-1.12.4/src/rviz/failed_view_controller.cpp000066400000000000000000000053161300447110700216010ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/display_context.h" #include "rviz/window_manager_interface.h" #include "rviz/failed_view_controller.h" namespace rviz { FailedViewController::FailedViewController( const QString& desired_class_id, const QString& error_message ) : error_message_( error_message ) { setClassId( desired_class_id ); } QString FailedViewController::getDescription() const { return "The class required for this view controller, '" + getClassId() + "', could not be loaded.
Error:
" + error_message_; } void FailedViewController::load( const Config& config ) { saved_config_ = config; ViewController::load( config ); } void FailedViewController::save( Config config ) const { if( saved_config_.isValid() ) { config.copy( saved_config_ ); } else { ViewController::save( config ); } } void FailedViewController::onActivate() { QWidget* parent = NULL; if( context_->getWindowManager() ) { parent = context_->getWindowManager()->getParentWindow(); } QMessageBox::critical( parent, "ViewController '" + getName() + "'unavailable.", getDescription() ); } } // end namespace rviz rviz-1.12.4/src/rviz/failed_view_controller.h000066400000000000000000000057301300447110700212460ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef FAILED_VIEW_CONTROLLER_H #define FAILED_VIEW_CONTROLLER_H #include "view_controller.h" namespace rviz { /** @brief A FailedViewController instance represents a ViewController class we * tried and failed to instantiate. * * FailedViewController stores the class id which it was supposed to be, and * an error message describing the failure. * * The load() and save() functions work together to ensure that loaded * configuration data is saved out again without modification. This * ensures that running rviz with a missing plugin library won't * damage config files which refer to it. */ class FailedViewController: public ViewController { public: FailedViewController( const QString& desired_class_id, const QString& error_message ); virtual QString getDescription() const; virtual void onActivate(); virtual int processMouseEvent( ViewportMouseEvent& event ) { return 0; } /** @brief Store the given Config data for later, so we can return it * with save() when someone writes this back to a file. */ virtual void load( const Config& config ); /** @brief Write into config data equivalent to the last config sent to load(). */ virtual void save( Config config ) const; virtual void lookAt( const Ogre::Vector3& point ) {} virtual void reset() {} private: Config saved_config_; QString error_message_; }; } // end namespace rviz #endif // FAILED_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/frame_manager.cpp000066400000000000000000000226201300447110700176410ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "frame_manager.h" #include "display.h" #include "properties/property.h" #include #include #include namespace rviz { FrameManager::FrameManager(boost::shared_ptr tf) { if (!tf) tf_.reset(new tf::TransformListener(ros::NodeHandle(), ros::Duration(10*60), true)); else tf_ = tf; setSyncMode( SyncOff ); setPause(false); } FrameManager::~FrameManager() { } void FrameManager::update() { boost::mutex::scoped_lock lock(cache_mutex_); if ( !pause_ ) { cache_.clear(); } if ( !pause_ ) { switch ( sync_mode_ ) { case SyncOff: sync_time_ = ros::Time::now(); break; case SyncExact: break; case SyncApprox: // adjust current time offset to sync source current_delta_ = 0.7*current_delta_ + 0.3*sync_delta_; try { sync_time_ = ros::Time::now()-ros::Duration(current_delta_); } catch (...) { sync_time_ = ros::Time::now(); } break; } } } void FrameManager::setFixedFrame(const std::string& frame) { bool emit = false; { boost::mutex::scoped_lock lock(cache_mutex_); if( fixed_frame_ != frame ) { fixed_frame_ = frame; cache_.clear(); emit = true; } } if( emit ) { // This emission must be kept outside of the mutex lock to avoid deadlocks. Q_EMIT fixedFrameChanged(); } } void FrameManager::setPause( bool pause ) { pause_ = pause; } void FrameManager::setSyncMode( SyncMode mode ) { sync_mode_ = mode; sync_time_ = ros::Time(0); current_delta_ = 0; sync_delta_ = 0; } void FrameManager::syncTime( ros::Time time ) { switch ( sync_mode_ ) { case SyncOff: break; case SyncExact: sync_time_ = time; break; case SyncApprox: if ( time == ros::Time(0) ) { sync_delta_ = 0; return; } // avoid exception due to negative time if ( ros::Time::now() >= time ) { sync_delta_ = (ros::Time::now() - time).toSec(); } else { setSyncMode( SyncApprox ); } break; } } bool FrameManager::adjustTime( const std::string &frame, ros::Time& time ) { // we only need to act if we get a zero timestamp, which means "latest" if ( time != ros::Time() ) { return true; } switch ( sync_mode_ ) { case SyncOff: break; case SyncExact: time = sync_time_; break; case SyncApprox: { // if we don't have tf info for the given timestamp, use the latest available ros::Time latest_time; std::string error_string; int error_code; error_code = tf_->getLatestCommonTime( fixed_frame_, frame, latest_time, &error_string ); if ( error_code != 0 ) { ROS_ERROR("Error getting latest time from frame '%s' to frame '%s': %s (Error code: %d)", frame.c_str(), fixed_frame_.c_str(), error_string.c_str(), error_code); return false; } if ( latest_time > sync_time_ ) { time = sync_time_; } } break; } return true; } bool FrameManager::getTransform(const std::string& frame, ros::Time time, Ogre::Vector3& position, Ogre::Quaternion& orientation) { if ( !adjustTime(frame, time) ) { return false; } boost::mutex::scoped_lock lock(cache_mutex_); position = Ogre::Vector3(9999999, 9999999, 9999999); orientation = Ogre::Quaternion::IDENTITY; if (fixed_frame_.empty()) { return false; } M_Cache::iterator it = cache_.find(CacheKey(frame, time)); if (it != cache_.end()) { position = it->second.position; orientation = it->second.orientation; return true; } geometry_msgs::Pose pose; pose.orientation.w = 1.0f; if (!transform(frame, time, pose, position, orientation)) { return false; } cache_.insert(std::make_pair(CacheKey(frame, time), CacheEntry(position, orientation))); return true; } bool FrameManager::transform(const std::string& frame, ros::Time time, const geometry_msgs::Pose& pose_msg, Ogre::Vector3& position, Ogre::Quaternion& orientation) { if ( !adjustTime(frame, time) ) { return false; } position = Ogre::Vector3::ZERO; orientation = Ogre::Quaternion::IDENTITY; // put all pose data into a tf stamped pose tf::Quaternion bt_orientation(pose_msg.orientation.x, pose_msg.orientation.y, pose_msg.orientation.z, pose_msg.orientation.w); tf::Vector3 bt_position(pose_msg.position.x, pose_msg.position.y, pose_msg.position.z); if (bt_orientation.x() == 0.0 && bt_orientation.y() == 0.0 && bt_orientation.z() == 0.0 && bt_orientation.w() == 0.0) { bt_orientation.setW(1.0); } tf::Stamped pose_in(tf::Transform(bt_orientation,bt_position), time, frame); tf::Stamped pose_out; // convert pose into new frame try { tf_->transformPose( fixed_frame_, pose_in, pose_out ); } catch(std::runtime_error& e) { ROS_DEBUG("Error transforming from frame '%s' to frame '%s': %s", frame.c_str(), fixed_frame_.c_str(), e.what()); return false; } bt_position = pose_out.getOrigin(); position = Ogre::Vector3(bt_position.x(), bt_position.y(), bt_position.z()); bt_orientation = pose_out.getRotation(); orientation = Ogre::Quaternion( bt_orientation.w(), bt_orientation.x(), bt_orientation.y(), bt_orientation.z() ); return true; } bool FrameManager::frameHasProblems(const std::string& frame, ros::Time time, std::string& error) { if (!tf_->frameExists(frame)) { error = "Frame [" + frame + "] does not exist"; if (frame == fixed_frame_) { error = "Fixed " + error; } return true; } return false; } bool FrameManager::transformHasProblems(const std::string& frame, ros::Time time, std::string& error) { if ( !adjustTime(frame, time) ) { return false; } std::string tf_error; bool transform_succeeded = tf_->canTransform(fixed_frame_, frame, time, &tf_error); if (transform_succeeded) { return false; } bool ok = true; ok = ok && !frameHasProblems(fixed_frame_, time, error); ok = ok && !frameHasProblems(frame, time, error); if (ok) { std::stringstream ss; ss << "No transform to fixed frame [" << fixed_frame_ << "]. TF error: [" << tf_error << "]"; error = ss.str(); ok = false; } { std::stringstream ss; ss << "For frame [" << frame << "]: " << error; error = ss.str(); } return !ok; } std::string getTransformStatusName(const std::string& caller_id) { std::stringstream ss; ss << "Transform [sender=" << caller_id << "]"; return ss.str(); } std::string FrameManager::discoverFailureReason(const std::string& frame_id, const ros::Time& stamp, const std::string& caller_id, tf::FilterFailureReason reason) { if (reason == tf::filter_failure_reasons::OutTheBack) { std::stringstream ss; ss << "Message removed because it is too old (frame=[" << frame_id << "], stamp=[" << stamp << "])"; return ss.str(); } else { std::string error; if (transformHasProblems(frame_id, stamp, error)) { return error; } } return "Unknown reason for transform failure"; } void FrameManager::messageArrived( const std::string& frame_id, const ros::Time& stamp, const std::string& caller_id, Display* display ) { display->setStatusStd( StatusProperty::Ok, getTransformStatusName( caller_id ), "Transform OK" ); } void FrameManager::messageFailed( const std::string& frame_id, const ros::Time& stamp, const std::string& caller_id, tf::FilterFailureReason reason, Display* display ) { std::string status_name = getTransformStatusName( caller_id ); std::string status_text = discoverFailureReason( frame_id, stamp, caller_id, reason ); display->setStatusStd(StatusProperty::Error, status_name, status_text ); } } rviz-1.12.4/src/rviz/frame_manager.h000066400000000000000000000253241300447110700173120ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_FRAME_MANAGER_H #define RVIZ_FRAME_MANAGER_H #include #include #include #include #include #include #include #ifndef Q_MOC_RUN #include #endif namespace tf { class TransformListener; } namespace rviz { class Display; /** @brief Helper class for transforming data into Ogre's world frame (the fixed frame). * * During one frame update (nominally 33ms), the tf tree stays consistent and queries are cached for speedup. */ class FrameManager: public QObject { Q_OBJECT public: enum SyncMode { SyncOff = 0, SyncExact, SyncApprox }; /** @brief Constructor * @param tf a pointer to tf::TransformListener (should not be used anywhere else because of thread safety) */ FrameManager(boost::shared_ptr tf = boost::shared_ptr()); /** @brief Destructor. * * FrameManager should not need to be destroyed by hand, just * destroy the boost::shared_ptr returned by instance(), and it will * be deleted when the last reference is removed. */ ~FrameManager(); /** @brief Set the frame to consider "fixed", into which incoming data is transformed. * * The fixed frame serves as the reference for all getTransform() * and transform() functions in FrameManager. */ void setFixedFrame(const std::string& frame); /** @brief Enable/disable pause mode */ void setPause( bool pause ); bool getPause() { return pause_; } /** @brief Set synchronization mode (off/exact/approximate) */ void setSyncMode( SyncMode mode ); SyncMode getSyncMode() { return sync_mode_; } /** @brief Synchronize with given time. */ void syncTime( ros::Time time ); /** @brief Get current time, depending on the sync mode. */ ros::Time getTime() { return sync_time_; } /** @brief Return the pose for a header, relative to the fixed frame, in Ogre classes. * @param[in] header The source of the frame name and time. * @param[out] position The position of the header frame relative to the fixed frame. * @param[out] orientation The orientation of the header frame relative to the fixed frame. * @return true on success, false on failure. */ template bool getTransform(const Header& header, Ogre::Vector3& position, Ogre::Quaternion& orientation) { return getTransform(header.frame_id, header.stamp, position, orientation); } /** @brief Return the pose for a frame relative to the fixed frame, in Ogre classes, at a given time. * @param[in] frame The frame to find the pose of. * @param[in] time The time at which to get the pose. * @param[out] position The position of the frame relative to the fixed frame. * @param[out] orientation The orientation of the frame relative to the fixed frame. * @return true on success, false on failure. */ bool getTransform(const std::string& frame, ros::Time time, Ogre::Vector3& position, Ogre::Quaternion& orientation); /** @brief Transform a pose from a frame into the fixed frame. * @param[in] header The source of the input frame and time. * @param[in] pose The input pose, relative to the header frame. * @param[out] position Position part of pose relative to the fixed frame. * @param[out] orientation: Orientation part of pose relative to the fixed frame. * @return true on success, false on failure. */ template bool transform(const Header& header, const geometry_msgs::Pose& pose, Ogre::Vector3& position, Ogre::Quaternion& orientation) { return transform(header.frame_id, header.stamp, pose, position, orientation); } /** @brief Transform a pose from a frame into the fixed frame. * @param[in] frame The input frame. * @param[in] time The time at which to get the pose. * @param[in] pose The input pose, relative to the input frame. * @param[out] position Position part of pose relative to the fixed frame. * @param[out] orientation: Orientation part of pose relative to the fixed frame. * @return true on success, false on failure. */ bool transform(const std::string& frame, ros::Time time, const geometry_msgs::Pose& pose, Ogre::Vector3& position, Ogre::Quaternion& orientation); /** @brief Clear the internal cache. */ void update(); /** @brief Check to see if a frame exists in the tf::TransformListener. * @param[in] frame The name of the frame to check. * @param[in] time Dummy parameter, not actually used. * @param[out] error If the frame does not exist, an error message is stored here. * @return true if the frame does not exist, false if it does exist. */ bool frameHasProblems(const std::string& frame, ros::Time time, std::string& error); /** @brief Check to see if a transform is known between a given frame and the fixed frame. * @param[in] frame The name of the frame to check. * @param[in] time The time at which the transform is desired. * @param[out] error If the transform is not known, an error message is stored here. * @return true if the transform is not known, false if it is. */ bool transformHasProblems(const std::string& frame, ros::Time time, std::string& error); /** @brief Connect a tf::MessageFilter's callbacks to success and failure handler functions in this FrameManager. * @param filter The tf::MessageFilter to connect to. * @param display The Display using the filter. * * FrameManager has internal functions for handling success and * failure of tf::MessageFilters which call Display::setStatus() * based on success or failure of the filter, including appropriate * error messages. */ template void registerFilterForTransformStatusCheck(tf::MessageFilter* filter, Display* display) { filter->registerCallback(boost::bind(&FrameManager::messageCallback, this, _1, display)); filter->registerFailureCallback(boost::bind(&FrameManager::failureCallback, this, _1, _2, display)); } /** @brief Return the current fixed frame name. */ const std::string& getFixedFrame() { return fixed_frame_; } /** @brief Return the tf::TransformListener used to receive transform data. */ tf::TransformListener* getTFClient() { return tf_.get(); } /** @brief Return a boost shared pointer to the tf::TransformListener used to receive transform data. */ const boost::shared_ptr& getTFClientPtr() { return tf_; } /** @brief Create a description of a transform problem. * @param frame_id The name of the frame with issues. * @param stamp The time for which the problem was detected. * @param caller_id Dummy parameter, not used. * @param reason The reason given by the tf::MessageFilter in its failure callback. * @return An error message describing the problem. * * Once a problem has been detected with a given frame or transform, * call this to get an error message describing the problem. */ std::string discoverFailureReason(const std::string& frame_id, const ros::Time& stamp, const std::string& caller_id, tf::FilterFailureReason reason); Q_SIGNALS: /** @brief Emitted whenever the fixed frame changes. */ void fixedFrameChanged(); private: bool adjustTime( const std::string &frame, ros::Time &time ); template void messageCallback(const ros::MessageEvent& msg_evt, Display* display) { boost::shared_ptr const &msg = msg_evt.getConstMessage(); std::string authority = msg_evt.getPublisherName(); messageArrived(msg->header.frame_id, msg->header.stamp, authority, display); } template void failureCallback(const ros::MessageEvent& msg_evt, tf::FilterFailureReason reason, Display* display) { boost::shared_ptr const &msg = msg_evt.getConstMessage(); std::string authority = msg_evt.getPublisherName(); messageFailed(msg->header.frame_id, msg->header.stamp, authority, reason, display); } void messageArrived(const std::string& frame_id, const ros::Time& stamp, const std::string& caller_id, Display* display); void messageFailed(const std::string& frame_id, const ros::Time& stamp, const std::string& caller_id, tf::FilterFailureReason reason, Display* display); struct CacheKey { CacheKey(const std::string& f, ros::Time t) : frame(f) , time(t) {} bool operator<(const CacheKey& rhs) const { if (frame != rhs.frame) { return frame < rhs.frame; } return time < rhs.time; } std::string frame; ros::Time time; }; struct CacheEntry { CacheEntry(const Ogre::Vector3& p, const Ogre::Quaternion& o) : position(p) , orientation(o) {} Ogre::Vector3 position; Ogre::Quaternion orientation; }; typedef std::map M_Cache; boost::mutex cache_mutex_; M_Cache cache_; boost::shared_ptr tf_; std::string fixed_frame_; bool pause_; SyncMode sync_mode_; // the current synchronized time, used to overwrite ros:Time(0) ros::Time sync_time_; // used for approx. syncing double sync_delta_; double current_delta_; }; } #endif // RVIZ_FRAME_MANAGER_H rviz-1.12.4/src/rviz/frame_position_tracking_view_controller.cpp000066400000000000000000000121451300447110700252530ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/tf_frame_property.h" #include "rviz/viewport_mouse_event.h" #include "rviz/view_manager.h" #include "rviz/frame_position_tracking_view_controller.h" namespace rviz { FramePositionTrackingViewController::FramePositionTrackingViewController() : target_scene_node_( NULL ) { target_frame_property_ = new TfFrameProperty( "Target Frame", TfFrameProperty::FIXED_FRAME_STRING, "TF frame whose motion this view will follow.", this, NULL, true ); } void FramePositionTrackingViewController::onInitialize() { target_frame_property_->setFrameManager( context_->getFrameManager() ); target_scene_node_ = context_->getSceneManager()->getRootSceneNode()->createChildSceneNode(); camera_->detachFromParent(); target_scene_node_->attachObject( camera_ ); } FramePositionTrackingViewController::~FramePositionTrackingViewController() { context_->getSceneManager()->destroySceneNode( target_scene_node_ ); } void FramePositionTrackingViewController::onActivate() { updateTargetSceneNode(); // Before activation, changes to target frame property should have // no side-effects. After activation, changing target frame // property has the side effect (typically) of changing an offset // property so that the view does not jump. Therefore we make the // signal/slot connection from the property here in onActivate() // instead of in the constructor. connect( target_frame_property_, SIGNAL( changed() ), this, SLOT( updateTargetFrame() )); } void FramePositionTrackingViewController::update(float dt, float ros_dt) { updateTargetSceneNode(); } void FramePositionTrackingViewController::updateTargetFrame() { Ogre::Vector3 old_position = target_scene_node_->getPosition(); Ogre::Quaternion old_orientation = target_scene_node_->getOrientation(); updateTargetSceneNode(); onTargetFrameChanged( old_position, old_orientation ); } bool FramePositionTrackingViewController::getNewTransform() { Ogre::Vector3 new_reference_position; Ogre::Quaternion new_reference_orientation; bool got_transform = context_->getFrameManager()->getTransform( target_frame_property_->getFrameStd(), ros::Time(), new_reference_position, new_reference_orientation ); if( got_transform ) { reference_position_ = new_reference_position; reference_orientation_ = new_reference_orientation; } return got_transform; } void FramePositionTrackingViewController::updateTargetSceneNode() { if ( getNewTransform() ) { target_scene_node_->setPosition( reference_position_ ); context_->queueRender(); } // Need to incorporate this functionality somehow.... Maybe right into TfFrameProperty itself. ///// if( frame_manager_->transformHasProblems( getTargetFrame().toStdString(), ros::Time(), error )) ///// { ///// // target_prop->setToError(); ///// global_status_->setStatus( StatusProperty::Error, "Target Frame", QString::fromStdString( error )); ///// } ///// else ///// { ///// // target_prop->setToOK(); ///// global_status_->setStatus( StatusProperty::Ok, "Target Frame", "OK" ); ///// } } void FramePositionTrackingViewController::mimic( ViewController* source_view ) { QVariant target_frame = source_view->subProp( "Target Frame" )->getValue(); if( target_frame.isValid() ) { target_frame_property_->setValue( target_frame ); } } } // end namespace rviz rviz-1.12.4/src/rviz/frame_position_tracking_view_controller.h000066400000000000000000000077001300447110700247210ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_FRAME_POSITION_TRACKING_VIEW_CONTROLLER_H #define RVIZ_FRAME_POSITION_TRACKING_VIEW_CONTROLLER_H #include #include #include "rviz/view_controller.h" namespace rviz { class TfFrameProperty; /** @brief Base class of ViewControllers which have a "Target Frame" * which is a TF frame whose position they track. */ class FramePositionTrackingViewController: public ViewController { Q_OBJECT public: FramePositionTrackingViewController(); virtual ~FramePositionTrackingViewController(); /** @brief Do subclass-specific initialization. Called by * ViewController::initialize after context_, target_scene_node_, * and camera_ are set. This version calls * updateTargetSceneNode(). */ virtual void onInitialize(); /** @brief called by activate(). * * Override to implement view-specific activation. This version * calls updateTargetSceneNode(). */ virtual void onActivate(); virtual void update(float dt, float ros_dt); /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). * * This base class implementation does nothing. */ virtual void mimic( ViewController* source_view ); protected Q_SLOTS: /** @brief Called when Target Frame property changes while view is * active. Purpose is to change values in the view controller (like * a position offset) such that the actual viewpoint does not * change. Calls updateTargetSceneNode() and * onTargetFrameChanged(). */ virtual void updateTargetFrame(); protected: /** @brief Override to implement the change in properties which * nullifies the change in target frame. * @see updateTargetFrame() */ virtual void onTargetFrameChanged( const Ogre::Vector3& old_reference_position, const Ogre::Quaternion& old_reference_orientation ) {} bool getNewTransform(); /** @brief Update the position of the target_scene_node_ from the TF * frame specified in the Target Frame property. */ virtual void updateTargetSceneNode(); TfFrameProperty* target_frame_property_; Ogre::SceneNode* target_scene_node_; Ogre::Quaternion reference_orientation_; Ogre::Vector3 reference_position_; }; } // end namespace rviz #endif // RVIZ_FRAME_POSITION_TRACKING_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/geometry.cpp000066400000000000000000000063711300447110700167150ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "geometry.h" namespace rviz { /** Given a viewport and an x,y position in window-pixel coordinates, * find the point on a plane directly behind it, if any. * @return true if the intersection exists, false if it does not. */ bool getPointOnPlaneFromWindowXY( Ogre::Viewport* viewport, Ogre::Plane& plane, int window_x, int window_y, Ogre::Vector3& intersection_out ) { int width = viewport->getActualWidth(); int height = viewport->getActualHeight(); Ogre::Ray mouse_ray = viewport->getCamera()->getCameraToViewportRay( (float)window_x / (float)width, (float)window_y / (float)height ); std::pair intersection = mouse_ray.intersects( plane ); if ( !intersection.first ) { return false; } intersection_out = mouse_ray.getPoint( intersection.second ); return true; } float mapAngleTo0_2Pi( float angle ) { angle = fmod( angle, Ogre::Math::TWO_PI ); if( angle < 0.0f ) { angle = Ogre::Math::TWO_PI + angle; } return angle; } Ogre::Vector2 project3DPointToViewportXY(const Ogre::Viewport* view, const Ogre::Vector3& pos) { Ogre::Camera* cam = view->getCamera(); Ogre::Vector3 pos2D = cam->getProjectionMatrix() * (cam->getViewMatrix() * pos); Ogre::Real x = ((pos2D.x * 0.5) + 0.5); Ogre::Real y = 1 - ((pos2D.y * 0.5) + 0.5); return Ogre::Vector2(x * view->getActualWidth(), y * view->getActualHeight()); } } // end namespace rviz rviz-1.12.4/src/rviz/geometry.h000066400000000000000000000050561300447110700163610ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef GEOMETRY_H #define GEOMETRY_H namespace Ogre { class Plane; class Vector3; class Vector2; } namespace rviz { /** @brief Given a viewport and an x,y position in window-pixel coordinates, * find the point on a plane directly behind it, if any. * @return true if the intersection exists, false if it does not. */ bool getPointOnPlaneFromWindowXY( Ogre::Viewport* viewport, Ogre::Plane& plane, int window_x, int window_y, Ogre::Vector3& intersection_out ); /** @brief Return the input angle mapped back to the range 0 to 2*PI. */ float mapAngleTo0_2Pi( float angle ); /** @brief Given a viewport and a 3D position in world coordinates, * project that point into the view plane. * @return The 2D floating-point pixel position of the projection. */ Ogre::Vector2 project3DPointToViewportXY(const Ogre::Viewport* view, const Ogre::Vector3& pos); } // end namespace rviz #endif rviz-1.12.4/src/rviz/help_panel.cpp000066400000000000000000000052521300447110700171660ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/visualization_manager.h" #include "rviz/help_panel.h" namespace fs = boost::filesystem; namespace rviz { HelpPanel::HelpPanel( QWidget* parent ) : Panel( parent ) , browser_( NULL ) { QVBoxLayout* layout = new QVBoxLayout( this ); browser_ = new QTextBrowser(); layout->addWidget( browser_ ); } HelpPanel::~HelpPanel() { } void HelpPanel::onInitialize() { setHelpFile( vis_manager_->getHelpPath() ); } void HelpPanel::setHelpFile( const QString& qfile_path ) { std::string file_path = qfile_path.toStdString(); if( !fs::exists( file_path )) { browser_->setText( "Help file '" + qfile_path + "' does not exist." ); } else if( fs::is_directory( file_path )) { browser_->setText( "Help file '" + qfile_path + "' is a directory, not a file." ); } else { QUrl url = QUrl::fromLocalFile( qfile_path ); if( browser_->source() == url ) { browser_->reload(); } else { browser_->setSource( url ); } } } } // end namespace rviz rviz-1.12.4/src/rviz/help_panel.h000066400000000000000000000040111300447110700166230ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef HELP_PANEL_H #define HELP_PANEL_H #include #include "rviz/panel.h" class QTextBrowser; namespace rviz { class HelpPanel: public Panel { Q_OBJECT public: HelpPanel( QWidget* parent = 0 ); virtual ~HelpPanel(); virtual void onInitialize(); /** @brief Load the given html file. */ void setHelpFile( const QString& file_path ); private: QTextBrowser* browser_; }; } // end namespace rviz #endif // HELP_PANEL_H rviz-1.12.4/src/rviz/helpers/000077500000000000000000000000001300447110700160115ustar00rootroot00000000000000rviz-1.12.4/src/rviz/helpers/color.h000066400000000000000000000035671300447110700173130ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_COLOR_H #define RVIZ_COLOR_H namespace rviz { struct Color { Color() : r_( 0.0f ) , g_( 0.0f ) , b_( 0.0f ) {} Color( float r, float g, float b ) : r_( r ) , g_( g ) , b_( b ) {} ~Color() {} float r_; float g_; float b_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/helpers/color.i000066400000000000000000000001021300447110700172720ustar00rootroot00000000000000%{ #include "helpers/color.h" %} %include "color.h" %init %{ %}rviz-1.12.4/src/rviz/image/000077500000000000000000000000001300447110700154315ustar00rootroot00000000000000rviz-1.12.4/src/rviz/image/image_display_base.cpp000066400000000000000000000232041300447110700217370ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "rviz/validate_floats.h" #include "rviz/image/image_display_base.h" namespace rviz { ImageDisplayBase::ImageDisplayBase() : Display() , sub_() , tf_filter_() , messages_received_(0) { topic_property_ = new RosTopicProperty("Image Topic", "", QString::fromStdString(ros::message_traits::datatype()), "sensor_msgs::Image topic to subscribe to.", this, SLOT( updateTopic() )); transport_property_ = new EnumProperty("Transport Hint", "raw", "Preferred method of sending images.", this, SLOT( updateTopic() )); connect(transport_property_, SIGNAL( requestOptions( EnumProperty* )), this, SLOT( fillTransportOptionList( EnumProperty* ))); queue_size_property_ = new IntProperty( "Queue Size", 2, "Advanced: set the size of the incoming message queue. Increasing this " "is useful if your incoming TF data is delayed significantly from your" " image data, but it can greatly increase memory usage if the messages are big.", this, SLOT( updateQueueSize() )); queue_size_property_->setMin( 1 ); transport_property_->setStdString("raw"); unreliable_property_ = new BoolProperty( "Unreliable", false, "Prefer UDP topic transport", this, SLOT( updateTopic() )); } ImageDisplayBase::~ImageDisplayBase() { unsubscribe(); } void ImageDisplayBase::onInitialize() { it_.reset( new image_transport::ImageTransport( update_nh_ )); scanForTransportSubscriberPlugins(); } void ImageDisplayBase::setTopic( const QString &topic, const QString &datatype ) { if ( datatype == ros::message_traits::datatype() ) { transport_property_->setStdString( "raw" ); topic_property_->setString( topic ); } else { int index = topic.lastIndexOf("/"); if ( index == -1 ) { ROS_WARN("ImageDisplayBase::setTopic() Invalid topic name: %s", topic.toStdString().c_str()); return; } QString transport = topic.mid(index + 1); QString base_topic = topic.mid(0, index); transport_property_->setString( transport ); topic_property_->setString( base_topic ); } } void ImageDisplayBase::incomingMessage(const sensor_msgs::Image::ConstPtr& msg) { if (!msg || context_->getFrameManager()->getPause() ) { return; } ++messages_received_; setStatus(StatusProperty::Ok, "Image", QString::number(messages_received_) + " images received"); emitTimeSignal( msg->header.stamp ); processMessage(msg); } void ImageDisplayBase::reset() { Display::reset(); if (tf_filter_) tf_filter_->clear(); messages_received_ = 0; } void ImageDisplayBase::updateQueueSize() { uint32_t size = queue_size_property_->getInt(); if (tf_filter_) tf_filter_->setQueueSize(size); } void ImageDisplayBase::subscribe() { if (!isEnabled()) { return; } try { tf_filter_.reset(); sub_.reset(new image_transport::SubscriberFilter()); if (!topic_property_->getTopicStd().empty() && !transport_property_->getStdString().empty() ) { // Determine UDP vs TCP transport for user selection. if (unreliable_property_->getBool()) { sub_->subscribe(*it_, topic_property_->getTopicStd(), (uint32_t)queue_size_property_->getInt(), image_transport::TransportHints(transport_property_->getStdString(), ros::TransportHints().unreliable())); } else{ sub_->subscribe(*it_, topic_property_->getTopicStd(), (uint32_t)queue_size_property_->getInt(), image_transport::TransportHints(transport_property_->getStdString())); } if (targetFrame_.empty()) { sub_->registerCallback(boost::bind(&ImageDisplayBase::incomingMessage, this, _1)); } else { tf_filter_.reset( new tf::MessageFilter(*sub_, (tf::Transformer&)*(context_->getTFClient()), targetFrame_, (uint32_t)queue_size_property_->getInt(), update_nh_)); tf_filter_->registerCallback(boost::bind(&ImageDisplayBase::incomingMessage, this, _1)); } } setStatus(StatusProperty::Ok, "Topic", "OK"); } catch (ros::Exception& e) { setStatus(StatusProperty::Error, "Topic", QString("Error subscribing: ") + e.what()); } catch (image_transport::Exception& e) { setStatus( StatusProperty::Error, "Topic", QString("Error subscribing: ") + e.what()); } messages_received_ = 0; setStatus(StatusProperty::Warn, "Image", "No Image received"); } void ImageDisplayBase::unsubscribe() { tf_filter_.reset(); sub_.reset(new image_transport::SubscriberFilter()); } void ImageDisplayBase::fixedFrameChanged() { if (tf_filter_) { tf_filter_->setTargetFrame(fixed_frame_.toStdString()); reset(); } } void ImageDisplayBase::scanForTransportSubscriberPlugins() { pluginlib::ClassLoader sub_loader("image_transport", "image_transport::SubscriberPlugin"); BOOST_FOREACH( const std::string& lookup_name, sub_loader.getDeclaredClasses() ) { // lookup_name is formatted as "pkg/transport_sub", for instance // "image_transport/compressed_sub" for the "compressed" // transport. This code removes the "_sub" from the tail and // everything up to and including the "/" from the head, leaving // "compressed" (for example) in transport_name. std::string transport_name = boost::erase_last_copy(lookup_name, "_sub"); transport_name = transport_name.substr(lookup_name.find('/') + 1); // If the plugin loads without throwing an exception, add its // transport name to the list of valid plugins, otherwise ignore // it. try { boost::shared_ptr sub = sub_loader.createInstance(lookup_name); transport_plugin_types_.insert(transport_name); } catch (const pluginlib::LibraryLoadException& e) { } catch (const pluginlib::CreateClassException& e) { } } } void ImageDisplayBase::updateTopic() { unsubscribe(); reset(); subscribe(); context_->queueRender(); } void ImageDisplayBase::fillTransportOptionList(EnumProperty* property) { property->clearOptions(); std::vector choices; choices.push_back("raw"); // Loop over all current ROS topic names ros::master::V_TopicInfo topics; ros::master::getTopics(topics); ros::master::V_TopicInfo::iterator it = topics.begin(); ros::master::V_TopicInfo::iterator end = topics.end(); for (; it != end; ++it) { // If the beginning of this topic name is the same as topic_, // and the whole string is not the same, // and the next character is / // and there are no further slashes from there to the end, // then consider this a possible transport topic. const ros::master::TopicInfo& ti = *it; const std::string& topic_name = ti.name; const std::string& topic = topic_property_->getStdString(); if (topic_name.find(topic) == 0 && topic_name != topic && topic_name[topic.size()] == '/' && topic_name.find('/', topic.size() + 1) == std::string::npos) { std::string transport_type = topic_name.substr(topic.size() + 1); // If the transport type string found above is in the set of // supported transport type plugins, add it to the list. if (transport_plugin_types_.find(transport_type) != transport_plugin_types_.end()) { choices.push_back(transport_type); } } } for (size_t i = 0; i < choices.size(); i++) { property->addOptionStd(choices[i]); } } } // end namespace rviz rviz-1.12.4/src/rviz/image/image_display_base.h000066400000000000000000000107041300447110700214050ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef IMAGE_DISPLAY_BASE_H #define IMAGE_DISPLAY_BASE_H #include #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include # include # include # include # include # include "rviz/display_context.h" # include "rviz/frame_manager.h" # include "rviz/properties/ros_topic_property.h" # include "rviz/properties/enum_property.h" # include "rviz/properties/int_property.h" # include "rviz/display.h" #endif namespace rviz { /** @brief Display subclass for subscribing and displaying to image messages. * * This class brings together some common things used for subscribing and displaying image messages in Display * types. It has a tf::MessageFilter and image_tranport::SubscriberFilter to filter incoming image messages, and * it handles subscribing and unsubscribing when the display is * enabled or disabled. */ class ImageDisplayBase : public Display { Q_OBJECT public: /** @brief Constructor. */ ImageDisplayBase(); virtual ~ImageDisplayBase(); virtual void setTopic( const QString &topic, const QString &datatype ); protected Q_SLOTS: /** @brief Update topic and resubscribe */ virtual void updateTopic(); /** @brief Update queue size of tf filter */ virtual void updateQueueSize(); /** @brief Fill list of available and working transport options */ void fillTransportOptionList(EnumProperty* property); protected: virtual void onInitialize(); /** @brief Reset display. */ virtual void reset(); /** @brief Enabling TF filtering by defining a target frame. */ void enableTFFilter(std::string& targetFrame) { targetFrame_ = targetFrame; reset(); } /** @brief ROS topic management. */ virtual void subscribe(); virtual void unsubscribe(); virtual void fixedFrameChanged(); /** @brief Incoming message callback. Checks if the message pointer * is valid, increments messages_received_, then calls * processMessage(). */ void incomingMessage(const sensor_msgs::Image::ConstPtr& msg); /** @brief Implement this to process the contents of a message. * * This is called by incomingMessage(). */ virtual void processMessage(const sensor_msgs::Image::ConstPtr& msg) = 0; void scanForTransportSubscriberPlugins(); boost::scoped_ptr it_; boost::shared_ptr sub_; boost::shared_ptr > tf_filter_; std::string targetFrame_; uint32_t messages_received_; RosTopicProperty* topic_property_; EnumProperty* transport_property_; IntProperty* queue_size_property_; std::string transport_; std::set transport_plugin_types_; BoolProperty* unreliable_property_; }; } // end namespace rviz #endif // IMAGE_DISPLAY_BASE_H rviz-1.12.4/src/rviz/image/ros_image_texture.cpp000066400000000000000000000171431300447110700216700ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "rviz/image/ros_image_texture.h" namespace rviz { ROSImageTexture::ROSImageTexture() : new_image_(false) , width_(0) , height_(0) , median_frames_(5) { empty_image_.load("no_image.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); static uint32_t count = 0; std::stringstream ss; ss << "ROSImageTexture" << count++; texture_ = Ogre::TextureManager::getSingleton().loadImage(ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, empty_image_, Ogre::TEX_TYPE_2D, 0); setNormalizeFloatImage(true); } ROSImageTexture::~ROSImageTexture() { current_image_.reset(); } void ROSImageTexture::clear() { boost::mutex::scoped_lock lock(mutex_); texture_->unload(); texture_->loadImage(empty_image_); new_image_ = false; current_image_.reset(); } const sensor_msgs::Image::ConstPtr& ROSImageTexture::getImage() { boost::mutex::scoped_lock lock(mutex_); return current_image_; } void ROSImageTexture::setMedianFrames( unsigned median_frames ) { median_frames_ = median_frames; } double ROSImageTexture::updateMedian( std::deque& buffer, double value ) { //update buffer while(buffer.size() > median_frames_-1) { buffer.pop_back(); } buffer.push_front(value); // get median std::deque buffer2 = buffer; std::nth_element( buffer2.begin(), buffer2.begin()+buffer2.size()/2, buffer2.end() ); return *( buffer2.begin()+buffer2.size()/2 ); } void ROSImageTexture::setNormalizeFloatImage( bool normalize, double min, double max ) { normalize_ = normalize; min_ = min; max_ = max; } template void ROSImageTexture::normalize( T* image_data, size_t image_data_size, std::vector &buffer ) { // Prepare output buffer buffer.resize(image_data_size, 0); T minValue; T maxValue; if ( normalize_ ) { T* input_ptr = image_data; // Find min. and max. pixel value minValue = std::numeric_limits::max(); maxValue = std::numeric_limits::min(); for( unsigned i = 0; i < image_data_size; ++i ) { minValue = std::min( minValue, *input_ptr ); maxValue = std::max( maxValue, *input_ptr ); input_ptr++; } if ( median_frames_ > 1 ) { minValue = updateMedian( min_buffer_, minValue ); maxValue = updateMedian( max_buffer_, maxValue ); } } else { // set fixed min/max minValue = min_; maxValue = max_; } // Rescale floating point image and convert it to 8-bit double range = maxValue - minValue; if( range > 0.0 ) { T* input_ptr = image_data; // Pointer to output buffer uint8_t* output_ptr = &buffer[0]; // Rescale and quantize for( size_t i = 0; i < image_data_size; ++i, ++output_ptr, ++input_ptr ) { double val = (double(*input_ptr - minValue) / range); if ( val < 0 ) val = 0; if ( val > 1 ) val = 1; *output_ptr = val * 255u; } } } bool ROSImageTexture::update() { sensor_msgs::Image::ConstPtr image; bool new_image = false; { boost::mutex::scoped_lock lock(mutex_); image = current_image_; new_image = new_image_; } if (!image || !new_image) { return false; } new_image_ = false; if (image->data.empty()) { return false; } Ogre::PixelFormat format = Ogre::PF_R8G8B8; Ogre::Image ogre_image; std::vector buffer; uint8_t* imageDataPtr = (uint8_t*)&image->data[0]; size_t imageDataSize = image->data.size(); if (image->encoding == sensor_msgs::image_encodings::RGB8) { format = Ogre::PF_BYTE_RGB; } else if (image->encoding == sensor_msgs::image_encodings::RGBA8) { format = Ogre::PF_BYTE_RGBA; } else if (image->encoding == sensor_msgs::image_encodings::TYPE_8UC4 || image->encoding == sensor_msgs::image_encodings::TYPE_8SC4 || image->encoding == sensor_msgs::image_encodings::BGRA8) { format = Ogre::PF_BYTE_BGRA; } else if (image->encoding == sensor_msgs::image_encodings::TYPE_8UC3 || image->encoding == sensor_msgs::image_encodings::TYPE_8SC3 || image->encoding == sensor_msgs::image_encodings::BGR8) { format = Ogre::PF_BYTE_BGR; } else if (image->encoding == sensor_msgs::image_encodings::TYPE_8UC1 || image->encoding == sensor_msgs::image_encodings::TYPE_8SC1 || image->encoding == sensor_msgs::image_encodings::MONO8) { format = Ogre::PF_BYTE_L; } else if (image->encoding == sensor_msgs::image_encodings::TYPE_16UC1 || image->encoding == sensor_msgs::image_encodings::TYPE_16SC1 || image->encoding == sensor_msgs::image_encodings::MONO16) { imageDataSize /= sizeof(uint16_t); normalize( (uint16_t*)&image->data[0], imageDataSize, buffer ); format = Ogre::PF_BYTE_L; imageDataPtr = &buffer[0]; } else if (image->encoding.find("bayer") == 0) { format = Ogre::PF_BYTE_L; } else if (image->encoding == sensor_msgs::image_encodings::TYPE_32FC1) { imageDataSize /= sizeof(float); normalize( (float*)&image->data[0], imageDataSize, buffer ); format = Ogre::PF_BYTE_L; imageDataPtr = &buffer[0]; } else { throw UnsupportedImageEncoding(image->encoding); } width_ = image->width; height_ = image->height; // TODO: Support different steps/strides Ogre::DataStreamPtr pixel_stream; pixel_stream.bind(new Ogre::MemoryDataStream(imageDataPtr, imageDataSize)); try { ogre_image.loadRawData(pixel_stream, width_, height_, 1, format, 1, 0); } catch (Ogre::Exception& e) { // TODO: signal error better ROS_ERROR("Error loading image: %s", e.what()); return false; } texture_->unload(); texture_->loadImage(ogre_image); return true; } void ROSImageTexture::addMessage(const sensor_msgs::Image::ConstPtr& msg) { boost::mutex::scoped_lock lock(mutex_); current_image_ = msg; new_image_ = true; } } // end of namespace rviz rviz-1.12.4/src/rviz/image/ros_image_texture.h000066400000000000000000000062661300447110700213410ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ROS_IMAGE_TEXTURE_H #define RVIZ_ROS_IMAGE_TEXTURE_H #include #include #include #include #include #include #include #include namespace rviz { class UnsupportedImageEncoding : public std::runtime_error { public: UnsupportedImageEncoding(const std::string& encoding) : std::runtime_error("Unsupported image encoding [" + encoding + "]") {} }; class ROSImageTexture { public: ROSImageTexture(); ~ROSImageTexture(); void addMessage(const sensor_msgs::Image::ConstPtr& image); bool update(); void clear(); const Ogre::TexturePtr& getTexture() { return texture_; } const sensor_msgs::Image::ConstPtr& getImage(); uint32_t getWidth() { return width_; } uint32_t getHeight() { return height_; } // automatic range normalization void setNormalizeFloatImage( bool normalize, double min=0.0, double max=1.0 ); void setMedianFrames( unsigned median_frames ); private: double updateMedian( std::deque& buffer, double new_value ); template void normalize( T* image_data, size_t image_data_size, std::vector &buffer ); sensor_msgs::Image::ConstPtr current_image_; boost::mutex mutex_; bool new_image_; Ogre::TexturePtr texture_; Ogre::Image empty_image_; uint32_t width_; uint32_t height_; // fields for float image running median computation bool normalize_; double min_; double max_; unsigned median_frames_; std::deque min_buffer_; std::deque max_buffer_; }; } #endif rviz-1.12.4/src/rviz/interactive_object.h000066400000000000000000000051101300447110700203600ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef INTERACTIVE_OBJECT_H #define INTERACTIVE_OBJECT_H #include #include #include namespace rviz { class ViewportMouseEvent; /** @brief Abstract base class of things in the scene which handle mouse events. * * Currently (visualization-1.8) this is only needed as a bridge * between interactive markers in the default plugin and the * interaction tool in the main executable. Once the interaction tool * is plugin-ized and put into the default plugin, this can probably * be removed. */ class InteractiveObject { public: virtual ~InteractiveObject() {}; virtual bool isInteractive() = 0; virtual void enableInteraction( bool enable ) = 0; virtual void handleMouseEvent( ViewportMouseEvent& event ) = 0; virtual const QCursor& getCursor() const = 0; }; typedef boost::shared_ptr InteractiveObjectPtr; typedef boost::weak_ptr InteractiveObjectWPtr; } // end namespace rviz #endif // INTERACTIVE_OBJECT_H rviz-1.12.4/src/rviz/load_resource.cpp000066400000000000000000000107711300447110700177070ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "load_resource.h" #include #include #include #include #include namespace rviz { boost::filesystem::path getPath( QString url ) { boost::filesystem::path path; if ( url.indexOf("package://", 0, Qt::CaseInsensitive) == 0 ) { QString package_name = url.section('/',2,2); QString file_name = url.section('/',3); path = ros::package::getPath(package_name.toStdString()); path = path / file_name.toStdString(); } else if ( url.indexOf("file://", 0, Qt::CaseInsensitive) == 0 ) { path = url.section('/',2).toStdString(); } else { ROS_ERROR( "Invalid or unsupported URL: '%s'", url.toStdString().c_str() ); } return path; } QPixmap loadPixmap( QString url, bool fill_cache ) { QPixmap pixmap; // if it's in the cache, no need to locate if ( QPixmapCache::find( url, &pixmap ) ) { return pixmap; } boost::filesystem::path path = getPath( url ); // If something goes wrong here, we go on and store the empty pixmap, // so the error won't appear again anytime soon. if ( boost::filesystem::exists( path ) ) { ROS_DEBUG_NAMED( "load_resource", "Loading '%s'", path.string().c_str() ); if ( !pixmap.load( QString::fromStdString( path.string() ) ) ) { ROS_ERROR( "Could not load pixmap '%s'", path.string().c_str() ); } } if ( fill_cache ) { QPixmapCache::insert( url, pixmap ); } return pixmap; } QCursor getDefaultCursor( bool fill_cache ) { return QCursor(Qt::ArrowCursor); } QCursor makeIconCursor( QString url, bool fill_cache ) { QPixmap icon = loadPixmap( url, fill_cache ); if (icon.width() == 0 || icon.height() == 0) { ROS_ERROR( "Could not load pixmap '%s' -- using default cursor instead.", url.toStdString().c_str() ); return getDefaultCursor(); } QString cache_key = url + ".cursor"; return makeIconCursor( icon, cache_key, fill_cache ); } QCursor makeIconCursor( QPixmap icon, QString cache_key, bool fill_cache ) { // if it's in the cache, no need to locate QPixmap cursor_img; if ( QPixmapCache::find( cache_key, &cursor_img ) ) { return QCursor( cursor_img, 0, 0 ); } QPixmap base_cursor = loadPixmap( "package://rviz/icons/cursor.svg", fill_cache ); const int cursor_size = 32; cursor_img = QPixmap( cursor_size, cursor_size ); cursor_img.fill( QColor(0,0,0,0) ); // copy base cursor & icon into one image QPainter painter(&cursor_img); int draw_x = 12; int draw_y = 16; // if the icon is too large, move it to the left if( draw_x+icon.width() > cursor_size ) { draw_x = cursor_size-icon.width(); } if( draw_y+icon.height() > cursor_size ) { draw_y = cursor_size-icon.height(); } painter.drawPixmap( 0, 0, base_cursor ); painter.drawPixmap( draw_x, draw_y, icon ); if ( fill_cache ) { QPixmapCache::insert( cache_key, cursor_img ); } return QCursor( cursor_img, 1, 1 ); } } rviz-1.12.4/src/rviz/load_resource.h000066400000000000000000000057041300447110700173540ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RESOURCE_RETRIEVING_H_ #define RESOURCE_RETRIEVING_H_ #include #include #include namespace rviz { // Helper functions to load resources based on their resource url, // e.g. "package://rviz/icons/package.png", // or "file:///home/user/.ros/config.yaml". /* @brief Try to load the pixmap url from disk or the cache. * In case of a failure, the result will be an empty QPixmap. * If fill_cache is set to true (default), the image will be * stored in the cache after loading it from disk. */ QPixmap loadPixmap( QString url, bool fill_cache=true ); /* @brief Load the default cursor: an arrow. * The fill_cache parameter is ignored. */ QCursor getDefaultCursor( bool fill_cache=true ); /* @brief Create a cursor using a shape in a file/url. * In case of a failure, the result will be the default arrow cursor. * If fill_cache is set to true (default), the image will be * stored in the cache after loading it from disk. */ QCursor makeIconCursor( QString icon_url, bool fill_cache=true ); /* @brief Create a cursor using the shape in the icon QPixmap. * If fill_cache is set to true (default), the image will be * stored in the cache using \e cache_key. */ QCursor makeIconCursor( QPixmap icon, QString cache_key="", bool fill_cache=true ); } #endif /* RESOURCE_RETRIEVING_H_ */ rviz-1.12.4/src/rviz/loading_dialog.cpp000066400000000000000000000041301300447110700200050ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "loading_dialog.h" namespace rviz { LoadingDialog::LoadingDialog( QWidget* parent ) : QDialog( parent ) { setModal( true ); label_ = new QLabel; QVBoxLayout* layout = new QVBoxLayout; layout->addWidget( label_ ); setLayout( layout ); } void LoadingDialog::showMessage( const QString& message ) { label_->setText( message ); QApplication::processEvents(); QWidget::repaint(); QApplication::flush(); } } // end namespace rviz rviz-1.12.4/src/rviz/loading_dialog.h000066400000000000000000000036671300447110700174700ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_LOADING_DIALOG_H #define RVIZ_LOADING_DIALOG_H #include class QLabel; namespace rviz { class LoadingDialog: public QDialog { Q_OBJECT public: LoadingDialog( QWidget* parent = 0 ); public Q_SLOTS: void showMessage( const QString& message ); protected: QLabel* label_; }; } // end namespace rviz #endif // RVIZ_LOADING_DIALOG_H rviz-1.12.4/src/rviz/main.cpp000066400000000000000000000035411300447110700160020ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/visualizer_app.h" int main( int argc, char** argv ) { QApplication qapp( argc, argv ); rviz::VisualizerApp vapp; vapp.setApp( &qapp ); if( vapp.init( argc, argv )) { return qapp.exec(); } else { return 1; } } rviz-1.12.4/src/rviz/mesh_loader.cpp000066400000000000000000000522611300447110700173430ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "mesh_loader.h" #include #include #include "ogre_helpers/stl_loader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(ASSIMP_UNIFIED_HEADER_NAMES) #include #include #include #include #include #else #include #include #include #include #include #endif namespace fs = boost::filesystem; namespace rviz { class ResourceIOStream : public Assimp::IOStream { public: ResourceIOStream(const resource_retriever::MemoryResource& res) : res_(res) , pos_(res.data.get()) {} ~ResourceIOStream() {} size_t Read(void* buffer, size_t size, size_t count) { size_t to_read = size * count; if (pos_ + to_read > res_.data.get() + res_.size) { to_read = res_.size - (pos_ - res_.data.get()); } memcpy(buffer, pos_, to_read); pos_ += to_read; return to_read; } size_t Write( const void* buffer, size_t size, size_t count) { ROS_BREAK(); return 0; } aiReturn Seek( size_t offset, aiOrigin origin) { uint8_t* new_pos = 0; switch (origin) { case aiOrigin_SET: new_pos = res_.data.get() + offset; break; case aiOrigin_CUR: new_pos = pos_ + offset; // TODO is this right? can offset really not be negative break; case aiOrigin_END: new_pos = res_.data.get() + res_.size - offset; // TODO is this right? break; default: ROS_BREAK(); } if (new_pos < res_.data.get() || new_pos > res_.data.get() + res_.size) { return aiReturn_FAILURE; } pos_ = new_pos; return aiReturn_SUCCESS; } size_t Tell() const { return pos_ - res_.data.get(); } size_t FileSize() const { return res_.size; } void Flush() {} private: resource_retriever::MemoryResource res_; uint8_t* pos_; }; class ResourceIOSystem : public Assimp::IOSystem { public: ResourceIOSystem() { } ~ResourceIOSystem() { } // Check whether a specific file exists bool Exists(const char* file) const { // Ugly -- two retrievals where there should be one (Exists + Open) // resource_retriever needs a way of checking for existence // TODO: cache this resource_retriever::MemoryResource res; try { res = retriever_.get(file); } catch (resource_retriever::Exception& e) { return false; } return true; } // Get the path delimiter character we'd like to see char getOsSeparator() const { return '/'; } // ... and finally a method to open a custom stream Assimp::IOStream* Open(const char* file, const char* mode = "rb") { ROS_ASSERT(mode == std::string("r") || mode == std::string("rb")); // Ugly -- two retrievals where there should be one (Exists + Open) // resource_retriever needs a way of checking for existence resource_retriever::MemoryResource res; try { res = retriever_.get(file); } catch (resource_retriever::Exception& e) { return 0; } return new ResourceIOStream(res); } void Close(Assimp::IOStream* stream); private: mutable resource_retriever::Retriever retriever_; }; void ResourceIOSystem::Close(Assimp::IOStream* stream) { delete stream; } // Mostly stolen from gazebo /** @brief Recursive mesh-building function. * @param scene is the assimp scene containing the whole mesh. * @param node is the current assimp node, which is part of a tree of nodes being recursed over. * @param material_table is indexed the same as scene->mMaterials[], and should have been filled out already by loadMaterials(). */ void buildMesh( const aiScene* scene, const aiNode* node, const Ogre::MeshPtr& mesh, Ogre::AxisAlignedBox& aabb, float& radius, const float scale, std::vector& material_table ) { if (!node) { return; } aiMatrix4x4 transform = node->mTransformation; aiNode *pnode = node->mParent; while (pnode) { // Don't convert to y-up orientation, which is what the root node in // Assimp does if (pnode->mParent != NULL) transform = pnode->mTransformation * transform; pnode = pnode->mParent; } aiMatrix3x3 rotation(transform); aiMatrix3x3 inverse_transpose_rotation(rotation); inverse_transpose_rotation.Inverse(); inverse_transpose_rotation.Transpose(); for (uint32_t i = 0; i < node->mNumMeshes; i++) { aiMesh* input_mesh = scene->mMeshes[node->mMeshes[i]]; Ogre::SubMesh* submesh = mesh->createSubMesh(); submesh->useSharedVertices = false; submesh->vertexData = new Ogre::VertexData(); Ogre::VertexData* vertex_data = submesh->vertexData; Ogre::VertexDeclaration* vertex_decl = vertex_data->vertexDeclaration; size_t offset = 0; // positions vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); // normals if (input_mesh->HasNormals()) { vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); } // texture coordinates (only support 1 for now) if (input_mesh->HasTextureCoords(0)) { vertex_decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); } // todo vertex colors // allocate the vertex buffer vertex_data->vertexCount = input_mesh->mNumVertices; Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertex_decl->getVertexSize(0), vertex_data->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); vertex_data->vertexBufferBinding->setBinding(0, vbuf); float* vertices = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); // Add the vertices for (uint32_t j = 0; j < input_mesh->mNumVertices; j++) { aiVector3D p = input_mesh->mVertices[j]; p *= transform; p *= scale; *vertices++ = p.x; *vertices++ = p.y; *vertices++ = p.z; Ogre::Vector3 v(p.x, p.y, p.z); aabb.merge(v); float dist = v.length(); if (dist > radius) { radius = dist; } if (input_mesh->HasNormals()) { aiVector3D n = inverse_transpose_rotation * input_mesh->mNormals[j]; n.Normalize(); *vertices++ = n.x; *vertices++ = n.y; *vertices++ = n.z; } if (input_mesh->HasTextureCoords(0)) { *vertices++ = input_mesh->mTextureCoords[0][j].x; *vertices++ = input_mesh->mTextureCoords[0][j].y; } } // calculate index count submesh->indexData->indexCount = 0; for (uint32_t j = 0; j < input_mesh->mNumFaces; j++) { aiFace& face = input_mesh->mFaces[j]; submesh->indexData->indexCount += face.mNumIndices; } // If we have less than 65536 (2^16) vertices, we can use a 16-bit index buffer. if( vertex_data->vertexCount < (1<<16) ) { // allocate index buffer submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer( Ogre::HardwareIndexBuffer::IT_16BIT, submesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer; uint16_t* indices = static_cast(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); // add the indices for (uint32_t j = 0; j < input_mesh->mNumFaces; j++) { aiFace& face = input_mesh->mFaces[j]; for (uint32_t k = 0; k < face.mNumIndices; ++k) { *indices++ = face.mIndices[k]; } } ibuf->unlock(); } else { // Else we have more than 65536 (2^16) vertices, so we must // use a 32-bit index buffer (or subdivide the mesh, which // I'm too impatient to do right now) // allocate index buffer submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer( Ogre::HardwareIndexBuffer::IT_32BIT, submesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer; uint32_t* indices = static_cast(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); // add the indices for (uint32_t j = 0; j < input_mesh->mNumFaces; j++) { aiFace& face = input_mesh->mFaces[j]; for (uint32_t k = 0; k < face.mNumIndices; ++k) { *indices++ = face.mIndices[k]; } } ibuf->unlock(); } vbuf->unlock(); submesh->setMaterialName(material_table[input_mesh->mMaterialIndex]->getName()); } for (uint32_t i=0; i < node->mNumChildren; ++i) { buildMesh(scene, node->mChildren[i], mesh, aabb, radius, scale, material_table); } } void loadTexture(const std::string& resource_path) { if (!Ogre::TextureManager::getSingleton().resourceExists(resource_path)) { resource_retriever::Retriever retriever; resource_retriever::MemoryResource res; try { res = retriever.get(resource_path); } catch (resource_retriever::Exception& e) { ROS_ERROR("%s", e.what()); } if (res.size != 0) { Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size)); Ogre::Image image; std::string extension = fs::extension(fs::path(resource_path)); if (extension[0] == '.') { extension = extension.substr(1, extension.size() - 1); } try { image.load(stream, extension); Ogre::TextureManager::getSingleton().loadImage(resource_path, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image); } catch (Ogre::Exception& e) { ROS_ERROR("Could not load texture [%s]: %s", resource_path.c_str(), e.what()); } } } } // Mostly cribbed from gazebo /** @brief Load all materials needed by the given scene. * @param resource_path the path to the resource from which this scene is being loaded. * loadMaterials() assumes textures for this scene are relative to the same directory that this scene is in. * @param scene the assimp scene to load materials for. * @param material_table_out Reference to the resultant material table, filled out by this function. Is indexed the same as scene->mMaterials[]. */ void loadMaterials(const std::string& resource_path, const aiScene* scene, std::vector& material_table_out ) { for (uint32_t i = 0; i < scene->mNumMaterials; i++) { std::stringstream ss; ss << resource_path << "Material" << i; Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(ss.str(), ROS_PACKAGE_NAME, true); material_table_out.push_back(mat); Ogre::Technique* tech = mat->getTechnique(0); Ogre::Pass* pass = tech->getPass(0); aiMaterial *amat = scene->mMaterials[i]; Ogre::ColourValue diffuse(1.0, 1.0, 1.0, 1.0); Ogre::ColourValue specular(1.0, 1.0, 1.0, 1.0); Ogre::ColourValue ambient(0, 0, 0, 1.0); for (uint32_t j=0; j < amat->mNumProperties; j++) { aiMaterialProperty *prop = amat->mProperties[j]; std::string propKey = prop->mKey.data; if (propKey == "$tex.file") { aiString texName; aiTextureMapping mapping; uint32_t uvIndex; amat->GetTexture(aiTextureType_DIFFUSE,0, &texName, &mapping, &uvIndex); // Assume textures are in paths relative to the mesh std::string texture_path = fs::path(resource_path).parent_path().string() + "/" + texName.data; loadTexture(texture_path); Ogre::TextureUnitState* tu = pass->createTextureUnitState(); tu->setTextureName(texture_path); } else if (propKey == "$clr.diffuse") { aiColor3D clr; amat->Get(AI_MATKEY_COLOR_DIFFUSE, clr); diffuse = Ogre::ColourValue(clr.r, clr.g, clr.b); } else if (propKey == "$clr.ambient") { aiColor3D clr; amat->Get(AI_MATKEY_COLOR_AMBIENT, clr); ambient = Ogre::ColourValue(clr.r, clr.g, clr.b); } else if (propKey == "$clr.specular") { aiColor3D clr; amat->Get(AI_MATKEY_COLOR_SPECULAR, clr); specular = Ogre::ColourValue(clr.r, clr.g, clr.b); } else if (propKey == "$clr.emissive") { aiColor3D clr; amat->Get(AI_MATKEY_COLOR_EMISSIVE, clr); mat->setSelfIllumination(clr.r, clr.g, clr.b); } else if (propKey == "$clr.opacity") { float o; amat->Get(AI_MATKEY_OPACITY, o); diffuse.a = o; } else if (propKey == "$mat.shininess") { float s; amat->Get(AI_MATKEY_SHININESS, s); mat->setShininess(s); } else if (propKey == "$mat.shadingm") { int model; amat->Get(AI_MATKEY_SHADING_MODEL, model); switch(model) { case aiShadingMode_Flat: mat->setShadingMode(Ogre::SO_FLAT); break; case aiShadingMode_Phong: mat->setShadingMode(Ogre::SO_PHONG); break; case aiShadingMode_Gouraud: default: mat->setShadingMode(Ogre::SO_GOURAUD); break; } } } int mode = aiBlendMode_Default; amat->Get(AI_MATKEY_BLEND_FUNC, mode); switch(mode) { case aiBlendMode_Additive: mat->setSceneBlending(Ogre::SBT_ADD); break; case aiBlendMode_Default: default: { if (diffuse.a < 0.99) { pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); } else { pass->setSceneBlending(Ogre::SBT_REPLACE); } } break; } mat->setAmbient(ambient * 0.5); mat->setDiffuse(diffuse); specular.a = diffuse.a; mat->setSpecular(specular); } } /*@brief - Get the scaling from units used in this mesh file to meters. This function applies only to Collada files. It is necessary because ASSIMP does not currently expose an api to retrieve the scaling factor. @Param[in] resource_path - The url of a resource containing a mesh. @Returns The scaling factor that converts the mesh to meters. Returns 1.0 for meshes which do not explicitly encode such a scaling. */ float getMeshUnitRescale(const std::string& resource_path) { static std::map rescale_cache; // Try to read unit to meter conversion ratio from mesh. Only valid in Collada XML formats. TiXmlDocument xmlDoc; float unit_scale(1.0); resource_retriever::Retriever retriever; resource_retriever::MemoryResource res; try { res = retriever.get(resource_path); } catch (resource_retriever::Exception& e) { ROS_ERROR("%s", e.what()); return unit_scale; } if (res.size == 0) { return unit_scale; } // Use the resource retriever to get the data. const char * data = reinterpret_cast (res.data.get()); xmlDoc.Parse(data); // Find the appropriate element if it exists if(!xmlDoc.Error()) { TiXmlElement * colladaXml = xmlDoc.FirstChildElement("COLLADA"); if(colladaXml) { TiXmlElement *assetXml = colladaXml->FirstChildElement("asset"); if(assetXml) { TiXmlElement *unitXml = assetXml->FirstChildElement("unit"); if (unitXml && unitXml->Attribute("meter")) { // Failing to convert leaves unit_scale as the default. if(unitXml->QueryFloatAttribute("meter", &unit_scale) != 0) ROS_WARN_STREAM("getMeshUnitRescale::Failed to convert unit element meter attribute to determine scaling. unit element: " << *unitXml); } } } } return unit_scale; } Ogre::MeshPtr meshFromAssimpScene(const std::string& name, const aiScene* scene) { if (!scene->HasMeshes()) { ROS_ERROR("No meshes found in file [%s]", name.c_str()); return Ogre::MeshPtr(); } std::vector material_table; loadMaterials(name, scene, material_table); Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(name, ROS_PACKAGE_NAME); Ogre::AxisAlignedBox aabb(Ogre::AxisAlignedBox::EXTENT_NULL); float radius = 0.0f; float scale = getMeshUnitRescale(name); buildMesh(scene, scene->mRootNode, mesh, aabb, radius, scale, material_table); mesh->_setBounds(aabb); mesh->_setBoundingSphereRadius(radius); mesh->buildEdgeList(); mesh->load(); return mesh; } Ogre::MeshPtr loadMeshFromResource(const std::string& resource_path) { if (Ogre::MeshManager::getSingleton().resourceExists(resource_path)) { return Ogre::MeshManager::getSingleton().getByName(resource_path); } else { fs::path model_path(resource_path); #if BOOST_FILESYSTEM_VERSION == 3 std::string ext = model_path.extension().string(); #else std::string ext = model_path.extension(); #endif if (ext == ".mesh" || ext == ".MESH") { resource_retriever::Retriever retriever; resource_retriever::MemoryResource res; try { res = retriever.get(resource_path); } catch (resource_retriever::Exception& e) { ROS_ERROR("%s", e.what()); return Ogre::MeshPtr(); } if (res.size == 0) { return Ogre::MeshPtr(); } Ogre::MeshSerializer ser; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size)); Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(resource_path, "rviz"); ser.importMesh(stream, mesh.get()); return mesh; } else if (ext == ".stl" || ext == ".STL" || ext == ".stlb" || ext == ".STLB") { resource_retriever::Retriever retriever; resource_retriever::MemoryResource res; try { res = retriever.get(resource_path); } catch (resource_retriever::Exception& e) { ROS_ERROR("%s", e.what()); return Ogre::MeshPtr(); } if (res.size == 0) { return Ogre::MeshPtr(); } ogre_tools::STLLoader loader; if (!loader.load(res.data.get(), res.size, resource_path)) { ROS_ERROR("Failed to load file [%s]", resource_path.c_str()); return Ogre::MeshPtr(); } return loader.toMesh(resource_path); } else { Assimp::Importer importer; importer.SetIOHandler(new ResourceIOSystem()); const aiScene* scene = importer.ReadFile(resource_path, aiProcess_SortByPType|aiProcess_GenNormals|aiProcess_Triangulate|aiProcess_GenUVCoords|aiProcess_FlipUVs); if (!scene) { ROS_ERROR("Could not load resource [%s]: %s", resource_path.c_str(), importer.GetErrorString()); return Ogre::MeshPtr(); } return meshFromAssimpScene(resource_path, scene); } } return Ogre::MeshPtr(); } } rviz-1.12.4/src/rviz/mesh_loader.h000066400000000000000000000034461300447110700170110ustar00rootroot00000000000000/* * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_MESH_LOADER_H #define RVIZ_MESH_LOADER_H #include namespace rviz { Ogre::MeshPtr loadMeshFromResource(const std::string& resource_path); } // namespace rviz #endif // RVIZ_MESH_LOADER_H rviz-1.12.4/src/rviz/message_filter_display.h000066400000000000000000000150751300447110700212460ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef MESSAGE_FILTER_DISPLAY_H #define MESSAGE_FILTER_DISPLAY_H #ifndef Q_MOC_RUN #include #include #include #include #endif #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/properties/ros_topic_property.h" #include "rviz/display.h" namespace rviz { /** @brief Helper superclass for MessageFilterDisplay, needed because * Qt's moc and c++ templates don't work nicely together. Not * intended to be used directly. */ class _RosTopicDisplay: public Display { Q_OBJECT public: _RosTopicDisplay() { topic_property_ = new RosTopicProperty( "Topic", "", "", "", this, SLOT( updateTopic() )); unreliable_property_ = new BoolProperty( "Unreliable", false, "Prefer UDP topic transport", this, SLOT( updateTopic() )); } protected Q_SLOTS: virtual void updateTopic() = 0; protected: RosTopicProperty* topic_property_; BoolProperty* unreliable_property_; }; /** @brief Display subclass using a tf::MessageFilter, templated on the ROS message type. * * This class brings together some common things used in many Display * types. It has a tf::MessageFilter to filter incoming messages, and * it handles subscribing and unsubscribing when the display is * enabled or disabled. It also has an Ogre::SceneNode which */ template class MessageFilterDisplay: public _RosTopicDisplay { // No Q_OBJECT macro here, moc does not support Q_OBJECT in a templated class. public: /** @brief Convenience typedef so subclasses don't have to use * the long templated class name to refer to their super class. */ typedef MessageFilterDisplay MFDClass; MessageFilterDisplay() : tf_filter_( NULL ) , messages_received_( 0 ) { QString message_type = QString::fromStdString( ros::message_traits::datatype() ); topic_property_->setMessageType( message_type ); topic_property_->setDescription( message_type + " topic to subscribe to." ); } virtual void onInitialize() { tf_filter_ = new tf::MessageFilter( *context_->getTFClient(), fixed_frame_.toStdString(), 10, update_nh_ ); tf_filter_->connectInput( sub_ ); tf_filter_->registerCallback( boost::bind( &MessageFilterDisplay::incomingMessage, this, _1 )); context_->getFrameManager()->registerFilterForTransformStatusCheck( tf_filter_, this ); } virtual ~MessageFilterDisplay() { unsubscribe(); delete tf_filter_; } virtual void reset() { Display::reset(); tf_filter_->clear(); messages_received_ = 0; } virtual void setTopic( const QString &topic, const QString &datatype ) { topic_property_->setString( topic ); } protected: virtual void updateTopic() { unsubscribe(); reset(); subscribe(); context_->queueRender(); } virtual void subscribe() { if( !isEnabled() ) { return; } try { ros::TransportHints transport_hint = ros::TransportHints().reliable(); // Determine UDP vs TCP transport for user selection. if (unreliable_property_->getBool()) { transport_hint = ros::TransportHints().unreliable(); } sub_.subscribe( update_nh_, topic_property_->getTopicStd(), 10, transport_hint); setStatus( StatusProperty::Ok, "Topic", "OK" ); } catch( ros::Exception& e ) { setStatus( StatusProperty::Error, "Topic", QString( "Error subscribing: " ) + e.what() ); } } virtual void unsubscribe() { sub_.unsubscribe(); } virtual void onEnable() { subscribe(); } virtual void onDisable() { unsubscribe(); reset(); } virtual void fixedFrameChanged() { tf_filter_->setTargetFrame( fixed_frame_.toStdString() ); reset(); } /** @brief Incoming message callback. Checks if the message pointer * is valid, increments messages_received_, then calls * processMessage(). */ void incomingMessage( const typename MessageType::ConstPtr& msg ) { if( !msg ) { return; } ++messages_received_; setStatus( StatusProperty::Ok, "Topic", QString::number( messages_received_ ) + " messages received" ); processMessage( msg ); } /** @brief Implement this to process the contents of a message. * * This is called by incomingMessage(). */ virtual void processMessage( const typename MessageType::ConstPtr& msg ) = 0; message_filters::Subscriber sub_; tf::MessageFilter* tf_filter_; uint32_t messages_received_; }; } // end namespace rviz #endif // MESSAGE_FILTER_DISPLAY_H rviz-1.12.4/src/rviz/msg_conversions.h000066400000000000000000000100271300447110700177360ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef MSG_CONVERSIONS_H #define MSG_CONVERSIONS_H #include "OgreVector3.h" #include "OgreQuaternion.h" #include #include #include namespace rviz { // This file contains some convenience functions for Ogre / geometry_msgs conversions. // pointMsgToOgre - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // static inline Ogre::Vector3 pointMsgToOgre(const geometry_msgs::Point& m) { return Ogre::Vector3(m.x, m.y, m.z); } static inline void pointMsgToOgre(const geometry_msgs::Point &m, Ogre::Vector3& o) { o.x = m.x; o.y = m.y; o.z = m.z; } // vector3MsgToOgre - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // static inline Ogre::Vector3 vector3MsgToOgre(const geometry_msgs::Vector3& m) { return Ogre::Vector3(m.x, m.y, m.z); } static inline void vector3MsgToOgre(const geometry_msgs::Vector3 &m, Ogre::Vector3& o) { o.x = m.x; o.y = m.y; o.z = m.z; } // quaternionMsgToOgre - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // static inline Ogre::Quaternion quaternionMsgToOgre(const geometry_msgs::Quaternion& m) { return Ogre::Quaternion(m.w, m.x, m.y, m.z); } static inline void quaternionMsgToOgre(const geometry_msgs::Quaternion &m, Ogre::Quaternion& o) { o.w = m.w; o.x = m.x; o.y = m.y; o.z = m.z; } // pointOgreToMsg - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // static inline void pointOgreToMsg(const Ogre::Vector3 &o, geometry_msgs::Point &m) { m.x = o.x; m.y = o.y; m.z = o.z; } static inline geometry_msgs::Point pointOgreToMsg(const Ogre::Vector3 &o) { geometry_msgs::Point m; pointOgreToMsg(o, m); return m; } // vectorOgreToMsg - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // static inline void vector3OgreToMsg(const Ogre::Vector3 &o, geometry_msgs::Vector3 &m) { m.x = o.x; m.y = o.y; m.z = o.z; } static inline geometry_msgs::Vector3 vector3OgreToMsg(const Ogre::Vector3 &o) { geometry_msgs::Vector3 m; vector3OgreToMsg(o, m); return m; } // quaternionOgreToMsg - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // static inline void quaternionOgreToMsg(const Ogre::Quaternion &o, geometry_msgs::Quaternion &m) { m.w = o.w; m.x = o.x; m.y = o.y; m.z = o.z; } static inline geometry_msgs::Quaternion quaternionOgreToMsg(const Ogre::Quaternion &o) { geometry_msgs::Quaternion m; quaternionOgreToMsg(o, m); return m; } } // namespace rviz #endif rviz-1.12.4/src/rviz/new_object_dialog.cpp000066400000000000000000000200511300447110700205070ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "new_object_dialog.h" #include "rviz/load_resource.h" namespace rviz { NewObjectDialog::NewObjectDialog( Factory* factory, const QString& object_type, const QStringList& disallowed_display_names, const QStringList& disallowed_class_lookup_names, QString* lookup_name_output, QString* display_name_output, QWidget* parent ) : QDialog( parent ) , factory_( factory ) , disallowed_display_names_( disallowed_display_names ) , disallowed_class_lookup_names_( disallowed_class_lookup_names ) , lookup_name_output_( lookup_name_output ) , display_name_output_( display_name_output ) { //***** Layout // Display Type group QGroupBox* type_box = new QGroupBox( object_type + " Type" ); QTreeWidget* tree = new QTreeWidget; tree->setHeaderHidden( true ); fillTree( tree ); QLabel* description_label = new QLabel( "Description:" ); description_ = new QTextBrowser; description_->setMaximumHeight( 100 ); description_->setOpenExternalLinks( true ); QVBoxLayout* type_layout = new QVBoxLayout; type_layout->addWidget( tree ); type_layout->addWidget( description_label ); type_layout->addWidget( description_ ); type_box->setLayout( type_layout ); // Display Name group QGroupBox* name_box; if( display_name_output_ ) { name_box = new QGroupBox( object_type + " Name" ); name_editor_ = new QLineEdit; QVBoxLayout* name_layout = new QVBoxLayout; name_layout->addWidget( name_editor_ ); name_box->setLayout( name_layout ); } // Buttons button_box_ = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal ); QVBoxLayout* main_layout = new QVBoxLayout; main_layout->addWidget( type_box ); if( display_name_output_ ) { main_layout->addWidget( name_box ); } main_layout->addWidget( button_box_ ); setLayout( main_layout ); //***** Connections connect( tree, SIGNAL( currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* )), this, SLOT( onDisplaySelected( QTreeWidgetItem* ))); connect( tree, SIGNAL( itemActivated( QTreeWidgetItem*, int )), this, SLOT( accept() )); connect( button_box_, SIGNAL( accepted() ), this, SLOT( accept() )); connect( button_box_, SIGNAL( rejected() ), this, SLOT( reject() )); if( display_name_output_ ) { connect( name_editor_, SIGNAL( textEdited( const QString& )), this, SLOT( onNameChanged() )); } } QSize NewObjectDialog::sizeHint () const { return( QSize(500,660) ); } void NewObjectDialog::fillTree( QTreeWidget* tree ) { QIcon default_package_icon = loadPixmap( "package://rviz/icons/default_package_icon.png" ); QStringList classes = factory_->getDeclaredClassIds(); classes.sort(); // Map from package names to the corresponding top-level tree widget items. std::map package_items; for( int i = 0; i < classes.size(); i++ ) { QString lookup_name = classes[ i ]; QString package = factory_->getClassPackage( lookup_name ); QString description = factory_->getClassDescription( lookup_name ); QString name = factory_->getClassName( lookup_name ); QTreeWidgetItem* package_item; std::map::iterator mi; mi = package_items.find( package ); if( mi == package_items.end() ) { package_item = new QTreeWidgetItem( tree ); package_item->setText( 0, package ); package_item->setIcon( 0, default_package_icon ); package_item->setExpanded( true ); package_items[ package ] = package_item; } else { package_item = (*mi).second; } QTreeWidgetItem* class_item = new QTreeWidgetItem( package_item ); class_item->setIcon( 0, factory_->getIcon( lookup_name ) ); class_item->setText( 0, name ); class_item->setWhatsThis( 0, description ); // Store the lookup name for each class in the UserRole of the item. class_item->setData( 0, Qt::UserRole, lookup_name ); class_item->setDisabled( disallowed_class_lookup_names_.contains( lookup_name )); } } void NewObjectDialog::onDisplaySelected( QTreeWidgetItem* selected_item ) { QString html = "" + selected_item->whatsThis( 0 ) + ""; description_->setHtml( html ); // We stored the lookup name for the class in the UserRole of the items. QVariant user_data = selected_item->data( 0, Qt::UserRole ); bool selection_is_valid = user_data.isValid(); if( selection_is_valid ) { lookup_name_ = user_data.toString(); if( display_name_output_ ) { QString display_name = selected_item->text( 0 ); int counter = 1; QString name; do { name = display_name; if( counter > 1 ) { name += QString::number( counter ); } ++counter; } while( disallowed_display_names_.contains( name )); name_editor_->setText( name ); } } else { lookup_name_ = ""; if( display_name_output_ ) { name_editor_->setText( "" ); } } button_box_->button( QDialogButtonBox::Ok )->setEnabled( isValid() ); } bool NewObjectDialog::isValid() { if( lookup_name_.size() == 0 ) { setError( "Select a Display type." ); return false; } if( display_name_output_ ) { QString display_name = name_editor_->text(); if( display_name.size() == 0 ) { setError( "Enter a name for the display." ); return false; } if( disallowed_display_names_.contains( display_name )) { setError( "Name in use. Display names must be unique." ); return false; } } setError( "" ); return true; } void NewObjectDialog::setError( const QString& error_text ) { button_box_->button( QDialogButtonBox::Ok )->setToolTip( error_text ); } void NewObjectDialog::onNameChanged() { button_box_->button( QDialogButtonBox::Ok )->setEnabled( isValid() ); } void NewObjectDialog::accept() { if( isValid() ) { *lookup_name_output_ = lookup_name_; if( display_name_output_ ) { *display_name_output_ = name_editor_->text(); } QDialog::accept(); } } } // rviz rviz-1.12.4/src/rviz/new_object_dialog.h000066400000000000000000000100631300447110700201560ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_NEW_OBJECT_DIALOG_H #define RVIZ_NEW_OBJECT_DIALOG_H #include #include "rviz/factory.h" class QTreeWidget; class QTreeWidgetItem; class QTextBrowser; class QLineEdit; class QDialogButtonBox; class QLabel; namespace rviz { class NewObjectDialog : public QDialog { Q_OBJECT public: /** Dialog for choosing a new object to load with a pluginlib ClassLoader. * * @param disallowed_display_names set of display names to prevent * the user from using. * * @param disallowed_class_lookup_names set of class lookup names to * prevent the user from selecting. Names found in the class loader * which are in this list will appear disabled. * * @param lookup_name_output Pointer to a string where dialog will * put the class lookup name chosen. * * @param display_name_output Pointer to a string where dialog will * put the display name entered, or NULL (default) if display * name entry field should not be shown. */ NewObjectDialog( Factory* factory, const QString& object_type, const QStringList& disallowed_display_names, const QStringList& disallowed_class_lookup_names, QString* lookup_name_output, QString* display_name_output = 0, QWidget* parent = 0 ); virtual QSize sizeHint () const; public Q_SLOTS: virtual void accept(); private Q_SLOTS: void onDisplaySelected( QTreeWidgetItem* selected_item ); void onNameChanged(); private: /** Fill the tree widget with classes from the class loader. */ void fillTree( QTreeWidget* tree ); /** Returns true if entered display name is non-empty and unique and * if lookup name is non-empty. */ bool isValid(); /** Display an error message to the user, or clear the previous * error message if error_text is empty. */ void setError( const QString& error_text ); Factory* factory_; const QStringList& disallowed_display_names_; const QStringList& disallowed_class_lookup_names_; QString* lookup_name_output_; QString* display_name_output_; /** Widget showing description of the class. */ QTextBrowser* description_; QLineEdit* name_editor_; /** Widget with OK and CANCEL buttons. */ QDialogButtonBox* button_box_; /** Current value of selected class-lookup name. Copied to * *lookup_name_output_ when "ok" is clicked. */ QString lookup_name_; }; } //namespace rviz #endif // RVIZ_NEW_OBJECT_DIALOG_H rviz-1.12.4/src/rviz/ogre_helpers/000077500000000000000000000000001300447110700170255ustar00rootroot00000000000000rviz-1.12.4/src/rviz/ogre_helpers/apply_visibility_bits.cpp000066400000000000000000000045231300447110700241520ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include namespace rviz { void applyVisibilityBits( uint32_t bits, Ogre::SceneNode* node ) { if (!node) { return; } // Loop over all objects attached to this node. Ogre::SceneNode::ObjectIterator obj_it = node->getAttachedObjectIterator(); while( obj_it.hasMoreElements() ) { Ogre::MovableObject* obj = obj_it.getNext(); obj->setVisibilityFlags( bits ); } // Loop over and recurse into all child nodes. Ogre::SceneNode::ChildNodeIterator child_it = node->getChildIterator(); while( child_it.hasMoreElements() ) { Ogre::SceneNode* child = dynamic_cast( child_it.getNext() ); applyVisibilityBits( bits, child ); } } } // end namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/apply_visibility_bits.h000066400000000000000000000035011300447110700236120ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef APPLY_VISIBILITY_BITS_H #define APPLY_VISIBILITY_BITS_H namespace Ogre { class SceneNode; } namespace rviz { void applyVisibilityBits( uint32_t bits, Ogre::SceneNode* node ); } // end namespace rviz #endif // APPLY_VISIBILITY_BITS_H rviz-1.12.4/src/rviz/ogre_helpers/arrow.cpp000066400000000000000000000111561300447110700206670ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "arrow.h" #include "shape.h" #include #include #include #include #include namespace rviz { Arrow::Arrow( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node, float shaft_length, float shaft_diameter, float head_length, float head_diameter ) : Object( scene_manager ) { if ( !parent_node ) { parent_node = scene_manager_->getRootSceneNode(); } scene_node_ = parent_node->createChildSceneNode(); shaft_ = new Shape( Shape::Cylinder, scene_manager_, scene_node_ ); head_ = new Shape( Shape::Cone, scene_manager_, scene_node_ ); head_->setOffset(Ogre::Vector3(0.0f, 0.5f, 0.0f)); set( shaft_length, shaft_diameter, head_length, head_diameter ); setOrientation( Ogre::Quaternion::IDENTITY ); } Arrow::~Arrow() { delete shaft_; delete head_; scene_manager_->destroySceneNode( scene_node_->getName() ); } void Arrow::set( float shaft_length, float shaft_diameter, float head_length, float head_diameter ) { shaft_->setScale(Ogre::Vector3(shaft_diameter, shaft_length, shaft_diameter)); shaft_->setPosition( Ogre::Vector3( 0.0f, shaft_length/2.0f, 0.0f ) ); head_->setScale( Ogre::Vector3( head_diameter, head_length, head_diameter ) ); head_->setPosition( Ogre::Vector3( 0.0f, shaft_length, 0.0f ) ); } void Arrow::setColor(const Ogre::ColourValue& c) { setShaftColor(c); setHeadColor(c); } void Arrow::setColor( float r, float g, float b, float a ) { setColor(Ogre::ColourValue(r, g, b, a)); } void Arrow::setShaftColor(const Ogre::ColourValue& c) { shaft_->setColor(c); } void Arrow::setHeadColor(const Ogre::ColourValue& c) { head_->setColor(c); } void Arrow::setShaftColor( float r, float g, float b, float a ) { setShaftColor( Ogre::ColourValue(r, g, b, a )); } void Arrow::setHeadColor( float r, float g, float b, float a ) { setHeadColor( Ogre::ColourValue(r, g, b, a )); } void Arrow::setPosition( const Ogre::Vector3& position ) { scene_node_->setPosition( position ); } void Arrow::setOrientation( const Ogre::Quaternion& orientation ) { // "forward" (negative z) should always be our identity orientation // ... wouldn't need to mangle the orientation if we just fix the cylinders! scene_node_->setOrientation( orientation * Ogre::Quaternion( Ogre::Degree( -90 ), Ogre::Vector3::UNIT_X ) ); } void Arrow::setDirection( const Ogre::Vector3& direction ) { if( !direction.isZeroLength() ) { setOrientation( Ogre::Vector3::NEGATIVE_UNIT_Z.getRotationTo( direction )); } } void Arrow::setScale( const Ogre::Vector3& scale ) { // Have to mangle the scale because of the default orientation of the cylinders :( scene_node_->setScale( Ogre::Vector3( scale.z, scale.x, scale.y ) ); } const Ogre::Vector3& Arrow::getPosition() { return scene_node_->getPosition(); } const Ogre::Quaternion& Arrow::getOrientation() { return scene_node_->getOrientation(); } void Arrow::setUserData( const Ogre::Any& data ) { head_->setUserData( data ); shaft_->setUserData( data ); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/arrow.h000066400000000000000000000132001300447110700203240ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "object.h" #ifndef OGRE_TOOLS_ARROW_H #define OGRE_TOOLS_ARROW_H namespace Ogre { class SceneManager; class SceneNode; class Vector3; class Quaternion; class ColourValue; class Any; } namespace rviz { class Shape; /** * \class Arrow * \brief An arrow consisting of a cylinder and a cone. * * The base of the arrow is at the position sent to setPosition(). * The arrow points in the direction of the negative Z axis by * default, and -Z is the identity direction of it. To set a * different direction, call setOrientation() with a rotation from -Z * to the desired vector. */ class Arrow : public Object { public: /** * \brief Constructor * * @param scene_manager The scene manager to use to construct any necessary objects * @param parent_node A scene node to use as the parent of this object. If NULL, uses the root scene node. * @param shaft_length Length of the arrow's shaft * @param shaft_diameter Diameter of the arrow's shaft * @param head_length Length of the arrow's head * @param head_diameter Diameter of the arrow's head */ Arrow( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node = 0, float shaft_length = 1.0f, float shaft_diameter = 0.1f, float head_length = 0.3f, float head_diameter = 0.2f ); virtual ~Arrow(); /** * \brief Set the parameters for this arrow * * @param shaft_length Length of the arrow's shaft * @param shaft_diameter Diameter of the arrow's shaft * @param head_length Length of the arrow's head * @param head_diameter Diameter of the arrow's head */ void set( float shaft_length, float shaft_diameter, float head_length, float head_diameter ); /** * \brief Set the color of this arrow. Sets both the head and shaft color to the same value. Values are in the range [0, 1] * * @param r Red component * @param g Green component * @param b Blue component */ virtual void setColor( float r, float g, float b, float a ); void setColor(const Ogre::ColourValue& color); /** * \brief Set the color of the arrow's head. Values are in the range [0, 1] * * @param r Red component * @param g Green component * @param b Blue component */ void setHeadColor( float r, float g, float b, float a = 1.0f ); void setHeadColor(const Ogre::ColourValue& color); /** * \brief Set the color of the arrow's shaft. Values are in the range [0, 1] * * @param r Red component * @param g Green component * @param b Blue component */ void setShaftColor( float r, float g, float b, float a = 1.0f ); void setShaftColor(const Ogre::ColourValue& color); /** @brief Set the orientation. * * Note that negative Z is the identity orientation. * * Both setOrientation() and setDirection() change the direction the arrow points. */ virtual void setOrientation( const Ogre::Quaternion& orientation ); /** @brief Set the position of the base of the arrow */ virtual void setPosition( const Ogre::Vector3& position ); /** @brief Set the direction of the arrow. * * @param direction The direction the arrow should point, in the * coordinate frame of the parent Ogre::SceneNode. * * If direction is zero, this does not change the arrow. * * Both setOrientation() and setDirection() change the direction the arrow points. */ void setDirection( const Ogre::Vector3& direction ); virtual void setScale( const Ogre::Vector3& scale ); virtual const Ogre::Vector3& getPosition(); virtual const Ogre::Quaternion& getOrientation(); /** * \brief Get the scene node associated with this arrow * @return the scene node associated with this arrow */ Ogre::SceneNode* getSceneNode() { return scene_node_; } /** * \brief Sets user data on all ogre objects we own */ void setUserData( const Ogre::Any& data ); Shape* getShaft() { return shaft_; } Shape* getHead() { return head_; } private: Ogre::SceneNode* scene_node_; Shape* shaft_; ///< Cylinder used for the shaft of the arrow Shape* head_; ///< Cone used for the head of the arrow }; } // namespace rviz #endif /* OGRE_TOOLS_ARROW_H */ rviz-1.12.4/src/rviz/ogre_helpers/axes.cpp000066400000000000000000000113131300447110700204700ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "axes.h" #include "shape.h" #include #include #include #include #include namespace rviz { Axes::Axes( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node, float length, float radius ) : Object( scene_manager ) { if ( !parent_node ) { parent_node = scene_manager_->getRootSceneNode(); } scene_node_ = parent_node->createChildSceneNode(); x_axis_ = new Shape( Shape::Cylinder, scene_manager_, scene_node_ ); y_axis_ = new Shape( Shape::Cylinder, scene_manager_, scene_node_ ); z_axis_ = new Shape( Shape::Cylinder, scene_manager_, scene_node_ ); set( length, radius ); } Axes::~Axes() { delete x_axis_; delete y_axis_; delete z_axis_; scene_manager_->destroySceneNode( scene_node_->getName() ); } void Axes::set( float length, float radius ) { x_axis_->setScale(Ogre::Vector3( radius, length, radius )); y_axis_->setScale(Ogre::Vector3( radius, length, radius )); z_axis_->setScale(Ogre::Vector3( radius, length, radius )); x_axis_->setPosition( Ogre::Vector3( length/2.0f, 0.0f, 0.0f ) ); x_axis_->setOrientation( Ogre::Quaternion( Ogre::Degree( -90 ), Ogre::Vector3::UNIT_Z ) ); y_axis_->setPosition( Ogre::Vector3( 0.0f, length/2.0f, 0.0f ) ); z_axis_->setPosition( Ogre::Vector3( 0.0, 0.0f, length/2.0f ) ); z_axis_->setOrientation( Ogre::Quaternion( Ogre::Degree( 90 ), Ogre::Vector3::UNIT_X ) ); setToDefaultColors(); } void Axes::setPosition( const Ogre::Vector3& position ) { scene_node_->setPosition( position ); } void Axes::setOrientation( const Ogre::Quaternion& orientation ) { scene_node_->setOrientation( orientation ); } void Axes::setScale( const Ogre::Vector3& scale ) { scene_node_->setScale( scale ); } void Axes::setColor( float r, float g, float b, float a ) { // for now, do nothing /// \todo should anything be done here? } const Ogre::Vector3& Axes::getPosition() { return scene_node_->getPosition(); } const Ogre::Quaternion& Axes::getOrientation() { return scene_node_->getOrientation(); } void Axes::setUserData( const Ogre::Any& data ) { x_axis_->setUserData( data ); y_axis_->setUserData( data ); z_axis_->setUserData( data ); } void Axes::setXColor(const Ogre::ColourValue& col) { x_axis_->setColor(col.r, col.g, col.b, col.a); } void Axes::setYColor(const Ogre::ColourValue& col) { y_axis_->setColor(col.r, col.g, col.b, col.a); } void Axes::setZColor(const Ogre::ColourValue& col) { z_axis_->setColor(col.r, col.g, col.b, col.a); } void Axes::setToDefaultColors() { x_axis_->setColor( 1.0f, 0.0f, 0.0f, 1.0f ); y_axis_->setColor( 0.0f, 1.0f, 0.0f, 1.0f ); z_axis_->setColor( 0.0f, 0.0f, 1.0f, 1.0f ); } const Ogre::ColourValue Axes::default_x_color_( 1, 0, 0, 1 ); const Ogre::ColourValue Axes::default_y_color_( 0, 1, 0, 1 ); const Ogre::ColourValue Axes::default_z_color_( 0, 0, 1, 1 ); const Ogre::ColourValue& Axes::getDefaultXColor() { return default_x_color_; } const Ogre::ColourValue& Axes::getDefaultYColor() { return default_y_color_; } const Ogre::ColourValue& Axes::getDefaultZColor() { return default_z_color_; } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/axes.h000066400000000000000000000102371300447110700201410ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_AXES_H #define OGRE_TOOLS_AXES_H #include "object.h" #include #include #include namespace Ogre { class SceneManager; class SceneNode; class Vector3; class Quaternion; class Any; class ColourValue; } namespace rviz { class Shape; /** * \class Axes * \brief An object that displays a set of X/Y/Z axes, with X=Red, Y=Green, Z=Blue */ class Axes : public Object { public: /** * \brief Constructor * @param manager Scene manager this object is a part of * @param parent_node A scene node to use as the parent of this object. If NULL, uses the root scene node. * @param length Length of the axes * @param radius Radius of the axes */ Axes( Ogre::SceneManager* manager, Ogre::SceneNode* parent_node = NULL, float length = 1.0f, float radius = 0.1f ); virtual ~Axes(); /** * \brief Set the parameters on this object * * @param length Length of the axes * @param radius Radius of the axes */ void set( float length, float radius ); virtual void setOrientation( const Ogre::Quaternion& orientation ); virtual void setPosition( const Ogre::Vector3& position ); virtual void setScale( const Ogre::Vector3& scale ); virtual void setColor( float r, float g, float b, float a ); virtual const Ogre::Vector3& getPosition(); virtual const Ogre::Quaternion& getOrientation(); /** * \brief Get the scene node associated with this object * @return The scene node associated with this object */ Ogre::SceneNode* getSceneNode() { return scene_node_; } /** * \brief Sets user data on all ogre objects we own */ void setUserData( const Ogre::Any& data ); Shape* getXShape() { return x_axis_; } Shape* getYShape() { return y_axis_; } Shape* getZShape() { return z_axis_; } void setXColor(const Ogre::ColourValue& col); void setYColor(const Ogre::ColourValue& col); void setZColor(const Ogre::ColourValue& col); void setToDefaultColors(); static const Ogre::ColourValue& getDefaultXColor(); static const Ogre::ColourValue& getDefaultYColor(); static const Ogre::ColourValue& getDefaultZColor(); private: // prohibit copying Axes( const Axes &other ): Object(0) {} Axes& operator=( const Axes &other ) { return *this; } Ogre::SceneNode* scene_node_; Shape* x_axis_; ///< Cylinder for the X-axis Shape* y_axis_; ///< Cylinder for the Y-axis Shape* z_axis_; ///< Cylinder for the Z-axis static const Ogre::ColourValue default_x_color_; static const Ogre::ColourValue default_y_color_; static const Ogre::ColourValue default_z_color_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/ogre_helpers/billboard_line.cpp000066400000000000000000000173111300447110700224750ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "billboard_line.h" #include #include #include #include #include #include #include #include #include #define MAX_ELEMENTS (65536/4) namespace rviz { BillboardLine::BillboardLine( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ) : Object( scene_manager ) , width_( 0.1f ) , current_line_(0) , total_elements_(0) , num_lines_(1) , max_points_per_line_(100) , lines_per_chain_(0) , current_chain_(0) , elements_in_current_chain_(0) { if ( !parent_node ) { parent_node = scene_manager_->getRootSceneNode(); } scene_node_ = parent_node->createChildSceneNode(); static int count = 0; std::stringstream ss; ss << "BillboardLineMaterial" << count++; material_ = Ogre::MaterialManager::getSingleton().create( ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); material_->setReceiveShadows(false); material_->getTechnique(0)->setLightingEnabled(false); setNumLines(num_lines_); setMaxPointsPerLine(max_points_per_line_); } BillboardLine::~BillboardLine() { V_Chain::iterator it = chains_.begin(); V_Chain::iterator end = chains_.end(); for (;it != end; ++it) { scene_manager_->destroyBillboardChain(*it); } scene_manager_->destroySceneNode( scene_node_->getName() ); Ogre::MaterialManager::getSingleton().remove(material_->getName()); } Ogre::BillboardChain* BillboardLine::createChain() { std::stringstream ss; static int count = 0; ss << "BillboardLine chain" << count++; Ogre::BillboardChain* chain = scene_manager_->createBillboardChain(ss.str()); chain->setMaterialName( material_->getName() ); scene_node_->attachObject( chain ); chains_.push_back(chain); return chain; } void BillboardLine::clear() { V_Chain::iterator it = chains_.begin(); V_Chain::iterator end = chains_.end(); for (; it != end; ++it) { (*it)->clearAllChains(); } current_line_ = 0; total_elements_ = 0; current_chain_ = 0; elements_in_current_chain_ = 0; for (V_uint32::iterator it = num_elements_.begin(); it != num_elements_.end(); ++it) { *it = 0; } } void BillboardLine::setupChains() { uint32_t total_points = max_points_per_line_ * num_lines_; uint32_t num_chains = total_points / MAX_ELEMENTS; if (total_points % MAX_ELEMENTS != 0) { ++num_chains; } for (uint32_t i = chains_.size(); i < num_chains; ++i) { createChain(); } lines_per_chain_ = max_points_per_line_ > 0 ? MAX_ELEMENTS / max_points_per_line_ : 1; V_Chain::iterator it = chains_.begin(); V_Chain::iterator end = chains_.end(); for (;it != end; ++it) { (*it)->setMaxChainElements(max_points_per_line_); // shorten the number of chains in the last bbchain, to avoid memory wasteage if (it + 1 == end) { uint32_t lines_left = num_lines_ % lines_per_chain_; // Handle the case where num_lines_ is a multiple of lines_per_chain if (lines_left == 0) { (*it)->setNumberOfChains(lines_per_chain_); } else { (*it)->setNumberOfChains(lines_left); } } else { (*it)->setNumberOfChains(lines_per_chain_); } } } void BillboardLine::setMaxPointsPerLine(uint32_t max) { max_points_per_line_ = max; setupChains(); } void BillboardLine::setNumLines(uint32_t num) { num_lines_ = num; setupChains(); num_elements_.resize(num); for (V_uint32::iterator it = num_elements_.begin(); it != num_elements_.end(); ++it) { *it = 0; } } void BillboardLine::newLine() { ++current_line_; ROS_ASSERT(current_line_ < num_lines_); } void BillboardLine::addPoint( const Ogre::Vector3& point ) { addPoint(point, color_); } void BillboardLine::addPoint( const Ogre::Vector3& point, const Ogre::ColourValue& color ) { ++num_elements_[current_line_]; ++total_elements_; ROS_ASSERT(num_elements_[current_line_] <= max_points_per_line_); ++elements_in_current_chain_; if (elements_in_current_chain_ > MAX_ELEMENTS) { ++current_chain_; elements_in_current_chain_ = 1; } Ogre::BillboardChain::Element e; e.position = point; e.width = width_; e.colour = color; chains_[current_chain_]->addChainElement(current_line_ % lines_per_chain_ , e); } void BillboardLine::setLineWidth( float width ) { width_ = width; for (uint32_t line = 0; line < num_lines_; ++line) { uint32_t element_count = num_elements_[line]; for ( uint32_t i = 0; i < element_count; ++i ) { Ogre::BillboardChain* c = chains_[line / lines_per_chain_]; Ogre::BillboardChain::Element e = c->getChainElement(line % lines_per_chain_, i); e.width = width_; c->updateChainElement(line % lines_per_chain_, i, e); } } } void BillboardLine::setPosition( const Ogre::Vector3& position ) { scene_node_->setPosition( position ); } void BillboardLine::setOrientation( const Ogre::Quaternion& orientation ) { scene_node_->setOrientation( orientation ); } void BillboardLine::setScale( const Ogre::Vector3& scale ) { // Setting scale doesn't really make sense here } void BillboardLine::setColor( float r, float g, float b, float a ) { if ( a < 0.9998 ) { material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); material_->getTechnique(0)->setDepthWriteEnabled( false ); } else { material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE ); material_->getTechnique(0)->setDepthWriteEnabled( true ); } color_ = Ogre::ColourValue( r, g, b, a ); for (uint32_t line = 0; line < num_lines_; ++line) { uint32_t element_count = num_elements_[line]; for ( uint32_t i = 0; i < element_count; ++i ) { Ogre::BillboardChain* c = chains_[line / lines_per_chain_]; Ogre::BillboardChain::Element e = c->getChainElement(line % lines_per_chain_, i); e.colour = color_; c->updateChainElement(line % lines_per_chain_, i, e); } } } const Ogre::Vector3& BillboardLine::getPosition() { return scene_node_->getPosition(); } const Ogre::Quaternion& BillboardLine::getOrientation() { return scene_node_->getOrientation(); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/billboard_line.h000066400000000000000000000077621300447110700221530ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_BILLBOARD_LINE_H #define OGRE_TOOLS_BILLBOARD_LINE_H #include "object.h" #include #include #include #include #include #include namespace Ogre { class SceneManager; class SceneNode; class Quaternion; class Any; class BillboardChain; } namespace rviz { /** * \class BillboardLine * \brief An object that displays a multi-segment line strip rendered as billboards */ class BillboardLine : public Object { public: /** * \brief Constructor * @param manager Scene manager this object is a part of * @param parent_node A scene node to use as the parent of this object. If NULL, uses the root scene node. */ BillboardLine( Ogre::SceneManager* manager, Ogre::SceneNode* parent_node = NULL ); virtual ~BillboardLine(); void clear(); void newLine(); void addPoint(const Ogre::Vector3& point); void addPoint(const Ogre::Vector3& point, const Ogre::ColourValue& color); void setLineWidth( float width ); void setMaxPointsPerLine(uint32_t max); void setNumLines(uint32_t num); // overrides from Object virtual void setOrientation( const Ogre::Quaternion& orientation ); virtual void setPosition( const Ogre::Vector3& position ); virtual void setScale( const Ogre::Vector3& scale ); virtual void setColor( float r, float g, float b, float a ); virtual const Ogre::Vector3& getPosition(); virtual const Ogre::Quaternion& getOrientation(); /** * \brief Get the scene node associated with this object * @return The scene node associated with this object */ Ogre::SceneNode* getSceneNode() { return scene_node_; } /** * \brief We have no objects that we can set user data on */ void setUserData( const Ogre::Any& data ) {} Ogre::MaterialPtr getMaterial() { return material_; } private: void setupChains(); Ogre::BillboardChain* createChain(); Ogre::SceneNode* scene_node_; typedef std::vector V_Chain; V_Chain chains_; Ogre::MaterialPtr material_; Ogre::ColourValue color_; float width_; uint32_t current_line_; // Ogre 1.4 doesn't have getNumChainElements() typedef std::vector V_uint32; V_uint32 num_elements_; uint32_t total_elements_; uint32_t num_lines_; uint32_t max_points_per_line_; uint32_t lines_per_chain_; uint32_t current_chain_; uint32_t elements_in_current_chain_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/ogre_helpers/camera_base.cpp000066400000000000000000000050411300447110700217530ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "camera_base.h" #include #include #include #include #include #include #include namespace rviz { CameraBase::CameraBase( Ogre::SceneManager* scene_manager ) : scene_manager_( scene_manager ) , relative_node_( NULL ) { std::stringstream ss; static uint32_t count = 0; ss << "CameraBase" << count++; camera_ = scene_manager_->createCamera( ss.str() ); } CameraBase::~CameraBase() { scene_manager_->destroyCamera( camera_ ); } void CameraBase::setRelativeNode( Ogre::SceneNode* node ) { relative_node_ = node; relativeNodeChanged(); update(); } void CameraBase::setPosition( const Ogre::Vector3& position ) { setPosition( position.x, position.y, position.z ); } void CameraBase::setOrientation( const Ogre::Quaternion& orientation ) { setOrientation( orientation.x, orientation.y, orientation.z, orientation.w ); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/camera_base.h000066400000000000000000000157721300447110700214340ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_CAMERA_BASE_H_ #define OGRE_TOOLS_CAMERA_BASE_H_ #include #include namespace Ogre { class Camera; class SceneNode; class SceneManager; } namespace rviz { /** * \class CameraBase * \brief Generic interface for a camera * * Provides a interface that a camera can override, providing interchangeability between different camera types. * Specific implementation is left to the child class. */ class CameraBase { public: /** * \brief Constructor * @param scene_manager Scene manager this camera is displaying */ CameraBase( Ogre::SceneManager* scene_manager ); virtual ~CameraBase(); /** * \brief Get the Ogre camera associated with this camera object * @return The Ogre camera associated with this camera object */ Ogre::Camera* getOgreCamera() { return camera_; } /** * \brief Set a scene node that all camera transformations should be relative to * @param node The node */ void setRelativeNode( Ogre::SceneNode* node ); /** * \brief Called when the relative node changes */ virtual void relativeNodeChanged() {} virtual void update() = 0; /** * \brief Set the position of the camera */ virtual void setPosition( const Ogre::Vector3& position ); /** * \brief Set the orientation of the camera */ virtual void setOrientation( const Ogre::Quaternion& orientation ); /** * \brief Yaw the camera. * * Calls to yaw are cumulative, so: * yaw(PI); * yaw(PI); * * is equivalent to * yaw(2*PI); * * @param angle Angle to yaw, in radians */ virtual void yaw( float angle ) = 0; /** * \brief Pitch the camera. * * Calls to pitch are cumulative, so: * pitch(PI); * pitch(PI); * * is equivalent to * pitch(2*PI); * * @param angle Angle to pitch, in radians */ virtual void pitch( float angle ) = 0; /** * \brief Roll the camera. * * Calls to roll are cumulative, so: * roll(PI); * roll(PI); * * is equivalent to * roll(2*PI); * * @param angle Angle to roll, in radians */ virtual void roll( float angle ) = 0; /** * \brief Set the orientation of the camera from a quaternion */ virtual void setOrientation( float x, float y, float z, float w ) = 0; /** * \brief Set the position of the camera */ virtual void setPosition( float x, float y, float z ) = 0; /** * \brief Set the position/orientation of this camera from another camera. * * @param camera The camera to set from */ virtual void setFrom( CameraBase* camera ) = 0; /** * \brief Get the position of this camera * @return The position of this camera */ virtual Ogre::Vector3 getPosition() = 0; /** * \brief Get the orientation of this camera * @return The orientation of this camera */ virtual Ogre::Quaternion getOrientation() = 0; /** * \brief Point the camera at the specified point * @param point The point to look at */ virtual void lookAt( const Ogre::Vector3& point ) = 0; /** * \brief Move the camera relative to its orientation * * @param x Distance to move along the X-axis * @param y Distance to move along the Y-axis * @param z Distance to move along the Z-axis */ virtual void move( float x, float y, float z ) = 0; virtual void mouseLeftDown( int x, int y ) {} virtual void mouseMiddleDown( int x, int y ) {} virtual void mouseRightDown( int x, int y ) {} virtual void mouseLeftUp( int x, int y ) {} virtual void mouseMiddleUp( int x, int y ) {} virtual void mouseRightUp( int x, int y ) {} /** * \brief Handle a left mouse button drag * * @param diff_x Pixels the mouse has moved in the (window space) x direction * @param diff_y Pixels the mouse has moved in the (window space) y direction */ virtual void mouseLeftDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ) = 0; /** * \brief Handle a middle mouse button drag * * @param diff_x Pixels the mouse has moved in the (window space) x direction * @param diff_y Pixels the mouse has moved in the (window space) y direction */ virtual void mouseMiddleDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ) = 0; /** * \brief Handle a right mouse button drag * * @param diff_x Pixels the mouse has moved in the (window space) x direction * @param diff_y Pixels the mouse has moved in the (window space) y direction */ virtual void mouseRightDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ) = 0; /** * \brief Handle a scrollwheel change * * @param diff Number of "units" the scrollwheel has moved * @todo Probably need to pass in how many units there are in a "click" of the wheel */ virtual void scrollWheel( int diff, bool ctrl, bool alt, bool shift ) = 0; /** * \brief Loads the camera's configure from the supplied string (generated through toString()) * @param str The string to load from */ virtual void fromString(const std::string& str) = 0; /** * \brief Returns a string representation of the camera's configuration */ virtual std::string toString() = 0; protected: Ogre::Camera* camera_; ///< Ogre camera associated with this camera object Ogre::SceneManager* scene_manager_; ///< Scene manager this camera is part of Ogre::SceneNode* relative_node_; }; } // namespace rviz #endif /*OGRE_TOOLS_CAMERA_BASE_H_*/ rviz-1.12.4/src/rviz/ogre_helpers/custom_parameter_indices.h000066400000000000000000000044461300447110700242560ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef CUSTOM_PARAMETER_INDICES_H #define CUSTOM_PARAMETER_INDICES_H // These are custom parameter indexes for the shader programs. Keep // them all here, so they stay consistent across the app. // // These need to agree with the values in the shader programs, which // are defined here: ogre_media/materials/glsl/*.program. // In there, look for lines like: // param_named_auto custom // They are spread out across the files, appearing just // where they are needed. #define SIZE_PARAMETER 0 #define ALPHA_PARAMETER 1 #define PICK_COLOR_PARAMETER 2 #define NORMAL_PARAMETER 3 #define UP_PARAMETER 4 #define HIGHLIGHT_PARAMETER 5 #define AUTO_SIZE_PARAMETER 6 #endif // CUSTOM_PARAMETER_INDICES_H rviz-1.12.4/src/rviz/ogre_helpers/grid.cpp000066400000000000000000000150261300447110700204620ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "grid.h" #include "billboard_line.h" #include #include #include #include #include #include #include #include namespace rviz { Grid::Grid( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node, Style style, uint32_t cell_count, float cell_length, float line_width, const Ogre::ColourValue& color ) : scene_manager_( scene_manager ) , style_(style) , cell_count_(cell_count) , cell_length_(cell_length) , line_width_(line_width) , height_(0) , color_(color) { static uint32_t gridCount = 0; std::stringstream ss; ss << "Grid" << gridCount++; manual_object_ = scene_manager_->createManualObject( ss.str() ); if ( !parent_node ) { parent_node = scene_manager_->getRootSceneNode(); } scene_node_ = parent_node->createChildSceneNode(); scene_node_->attachObject( manual_object_ ); billboard_line_ = new BillboardLine(scene_manager, scene_node_); ss << "Material"; material_ = Ogre::MaterialManager::getSingleton().create( ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); material_->setReceiveShadows(false); material_->getTechnique(0)->setLightingEnabled(false); setColor(color_); } Grid::~Grid() { delete billboard_line_; scene_manager_->destroySceneNode( scene_node_->getName() ); scene_manager_->destroyManualObject( manual_object_ ); material_->unload(); } void Grid::setCellCount(uint32_t count) { cell_count_ = count; create(); } void Grid::setCellLength(float len) { cell_length_ = len; create(); } void Grid::setLineWidth(float width) { line_width_ = width; create(); } void Grid::setColor(const Ogre::ColourValue& color) { color_ = color; if ( color_.a < 0.9998 ) { material_->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); material_->setDepthWriteEnabled( false ); } else { material_->setSceneBlending( Ogre::SBT_REPLACE ); material_->setDepthWriteEnabled( true ); } create(); } void Grid::setStyle(Style style) { style_ = style; create(); } void Grid::setHeight(uint32_t height) { height_ = height; create(); } void Grid::create() { manual_object_->clear(); billboard_line_->clear(); float extent = (cell_length_*((double)cell_count_))/2; if (style_ == Billboards) { billboard_line_->setColor(color_.r, color_.g, color_.b, color_.a); billboard_line_->setLineWidth(line_width_); billboard_line_->setMaxPointsPerLine(2); billboard_line_->setNumLines((cell_count_+1) * 2 * (height_ + 1) + ((cell_count_ + 1) * (cell_count_ + 1)) * height_); } else { manual_object_->estimateVertexCount( cell_count_ * 4 * (height_ + 1) + ((cell_count_ + 1) * (cell_count_ + 1) * height_)); manual_object_->begin( material_->getName(), Ogre::RenderOperation::OT_LINE_LIST ); } for (uint32_t h = 0; h <= height_; ++h) { float h_real = (height_ / 2.0f - (float)h) * cell_length_; for( uint32_t i = 0; i <= cell_count_; i++ ) { float inc = extent - ( i * cell_length_ ); Ogre::Vector3 p1(inc, h_real, -extent); Ogre::Vector3 p2(inc, h_real, extent); Ogre::Vector3 p3(-extent, h_real, inc); Ogre::Vector3 p4(extent, h_real, inc); if (style_ == Billboards) { if (h != 0 || i != 0) { billboard_line_->newLine(); } billboard_line_->addPoint(p1); billboard_line_->addPoint(p2); billboard_line_->newLine(); billboard_line_->addPoint(p3); billboard_line_->addPoint(p4); } else { manual_object_->position(p1); manual_object_->colour( color_ ); manual_object_->position(p2); manual_object_->colour( color_ ); manual_object_->position(p3); manual_object_->colour( color_ ); manual_object_->position(p4); manual_object_->colour( color_ ); } } } if (height_ > 0) { for (uint32_t x = 0; x <= cell_count_; ++x) { for (uint32_t z = 0; z <= cell_count_; ++z) { float x_real = extent - x * cell_length_; float z_real = extent - z * cell_length_; float y_top = (height_ / 2.0f) * cell_length_; float y_bottom = -y_top; if (style_ == Billboards) { billboard_line_->newLine(); billboard_line_->addPoint( Ogre::Vector3(x_real, y_bottom, z_real) ); billboard_line_->addPoint( Ogre::Vector3(x_real, y_top, z_real) ); } else { manual_object_->position( x_real, y_bottom, z_real ); manual_object_->colour( color_ ); manual_object_->position(x_real, y_top, z_real); manual_object_->colour( color_ ); } } } } if (style_ == Lines) { manual_object_->end(); } } void Grid::setUserData( const Ogre::Any& data ) { manual_object_->getUserObjectBindings().setUserAny( data ); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/grid.h000066400000000000000000000076551300447110700201400ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_GRID_H #define OGRE_TOOLS_GRID_H #include #include #include #include #include namespace Ogre { class SceneManager; class ManualObject; class SceneNode; class Any; } namespace rviz { class BillboardLine; /** * \class Grid * \brief Displays a grid of cells, drawn with lines * * Displays a grid of cells, drawn with lines. A grid with an identity orientation is drawn along the XZ plane. */ class Grid { public: enum Style { Lines, Billboards, }; /** * \brief Constructor * * @param manager The scene manager this object is part of * @param cell_count The number of cells to draw * @param cell_length The size of each cell * @param r Red color component, in the range [0, 1] * @param g Green color component, in the range [0, 1] * @param b Blue color component, in the range [0, 1] */ Grid( Ogre::SceneManager* manager, Ogre::SceneNode* parent_node, Style style, uint32_t cell_count, float cell_length, float line_width, const Ogre::ColourValue& color ); ~Grid(); void create(); /** * \brief Get the Ogre scene node associated with this grid * * @return The Ogre scene node associated with this grid */ Ogre::SceneNode* getSceneNode() { return scene_node_; } /** * \brief Sets user data on all ogre objects we own */ void setUserData( const Ogre::Any& data ); void setStyle(Style style); Style getStyle() { return style_; } void setColor(const Ogre::ColourValue& color); Ogre::ColourValue getColor() { return color_; } void setCellCount(uint32_t count); float getCellCount() { return cell_count_; } void setCellLength(float len); float getCellLength() { return cell_length_; } void setLineWidth(float width); float getLineWidth() { return line_width_; } void setHeight(uint32_t count); uint32_t getHeight() { return height_; } private: Ogre::SceneManager* scene_manager_; Ogre::SceneNode* scene_node_; ///< The scene node that this grid is attached to Ogre::ManualObject* manual_object_; ///< The manual object used to draw the grid BillboardLine* billboard_line_; Ogre::MaterialPtr material_; Style style_; uint32_t cell_count_; float cell_length_; float line_width_; uint32_t height_; Ogre::ColourValue color_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/ogre_helpers/initialization.cpp000066400000000000000000000014651300447110700225660ustar00rootroot00000000000000#include "initialization.h" #include #include #include #include #include namespace rviz { void cleanupOgre() { delete Ogre::Root::getSingletonPtr(); } // This should be folded into RenderSystem, but it should work fine as // is, so I'm leaving it for now. void initializeResources( const V_string& resource_paths ) { V_string::const_iterator path_it = resource_paths.begin(); V_string::const_iterator path_end = resource_paths.end(); for( ; path_it != path_end; ++path_it ) { Ogre::ResourceGroupManager::getSingleton().addResourceLocation( *path_it, "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); } Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/initialization.h000066400000000000000000000035701300447110700222320ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_INITIALIZATION_H #define OGRE_TOOLS_INITIALIZATION_H #include #include #include namespace rviz { typedef std::vector V_string; void cleanupOgre(); void initializeResources( const V_string& resource_paths ); } // namespace rviz #endif rviz-1.12.4/src/rviz/ogre_helpers/line.cpp000066400000000000000000000115141300447110700204620ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "line.h" #include #include #include #include #include #include namespace rviz { Line::Line( Ogre::SceneManager* manager, Ogre::SceneNode* parent_node ) : Object( manager ) { if (!parent_node) { parent_node = manager->getRootSceneNode(); } manual_object_ = manager->createManualObject(); scene_node_ = parent_node->createChildSceneNode(); static int count = 0; std::stringstream ss; ss << "LineMaterial" << count++; // NOTE: The second parameter to the create method is the resource group the material will be added to. // If the group you name does not exist (in your resources.cfg file) the library will assert() and your program will crash manual_object_material_ = Ogre::MaterialManager::getSingleton().create(ss.str(),"rviz"); manual_object_material_->setReceiveShadows(false); manual_object_material_->getTechnique(0)->setLightingEnabled(true); manual_object_material_->getTechnique(0)->getPass(0)->setDiffuse(0,0,0,0); manual_object_material_->getTechnique(0)->getPass(0)->setAmbient(1,1,1); scene_node_->attachObject(manual_object_); } Line::~Line() { if ( scene_node_->getParentSceneNode() ) { scene_node_->getParentSceneNode()->removeChild(scene_node_); } scene_manager_->destroySceneNode(scene_node_); scene_manager_->destroyManualObject( manual_object_ ); Ogre::MaterialManager::getSingleton().remove(manual_object_material_->getName()); } void Line::setPoints( Ogre::Vector3 start, Ogre::Vector3 end ) { manual_object_->clear(); manual_object_->begin(manual_object_material_->getName(), Ogre::RenderOperation::OT_LINE_LIST); manual_object_->position(start); manual_object_->position(end); manual_object_->end(); setVisible(true); } void Line::setVisible( bool visible ) { scene_node_->setVisible(visible,true); } void Line::setPosition( const Ogre::Vector3& position ) { scene_node_->setPosition( position ); } void Line::setOrientation( const Ogre::Quaternion& orientation ) { scene_node_->setOrientation( orientation ); } void Line::setScale( const Ogre::Vector3& scale ) { scene_node_->setScale( scale ); } void Line::setColor( const Ogre::ColourValue& c ) { // this is consistent with the behaviour in the Shape class. manual_object_material_->getTechnique(0)->setAmbient( c * 0.5 ); manual_object_material_->getTechnique(0)->setDiffuse( c ); if ( c.a < 0.9998 ) { manual_object_material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); manual_object_material_->getTechnique(0)->setDepthWriteEnabled( false ); } else { manual_object_material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE ); manual_object_material_->getTechnique(0)->setDepthWriteEnabled( true ); } } void Line::setColor( float r, float g, float b, float a ) { setColor(Ogre::ColourValue(r, g, b, a)); } // where are the void Line::setColour(...) convenience methods??? ;) const Ogre::Vector3& Line::getPosition() { return scene_node_->getPosition(); } const Ogre::Quaternion& Line::getOrientation() { return scene_node_->getOrientation(); } void Line::setUserData( const Ogre::Any& data ) { manual_object_->getUserObjectBindings().setUserAny( data ); } } rviz-1.12.4/src/rviz/ogre_helpers/line.h000066400000000000000000000077301300447110700201340ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef LINE_H_ #define LINE_H_ #include "object.h" #include #include #include namespace Ogre { class SceneManager; class SceneNode; class Vector3; class Quaternion; class Any; class ColourValue; } namespace rviz { /* Represents a straight wireframe line between two points. */ class Line: public Object { public: /** * \brief Constructor * @param manager Scene manager this object is a part of * @param parent_node A scene node to use as the parent of this object. If NULL, uses the root scene node. */ Line( Ogre::SceneManager* manager, Ogre::SceneNode* parent_node = NULL ); virtual ~Line(); /** * \brief Set the start and end point of the line. * @param start The start point. * @param end The end point. */ void setPoints( Ogre::Vector3 start, Ogre::Vector3 end ); void setVisible( bool visible ); /** * \brief Set the position of this object * @param Position vector position to set to. */ virtual void setPosition( const Ogre::Vector3& position ); /** * \brief Set the orientation of the object * @param Orientation quaternion orientation to set to. */ virtual void setOrientation( const Ogre::Quaternion& orientation ); /** * \brief Set the scale of the object. Always relative to the identity orientation of the object. * @param Scale vector scale to set to. */ virtual void setScale( const Ogre::Vector3& scale ); /** * \brief Set the color of the object. Values are in the range [0, 1] * @param r Red component * @param g Green component * @param b Blue component */ virtual void setColor( float r, float g, float b, float a ); /** * \brief Set the color of the object using ogre colour definitions. * * @param c : ogre colour type. */ virtual void setColor( const Ogre::ColourValue& c ); /** * \brief Get the local position of this object * @return The position */ virtual const Ogre::Vector3& getPosition(); /** * \brief Get the local orientation of this object * @return The orientation */ virtual const Ogre::Quaternion& getOrientation(); /** * \brief Set the user data on this object * @param data */ virtual void setUserData( const Ogre::Any& data ); protected: Ogre::SceneNode* scene_node_; Ogre::ManualObject* manual_object_; Ogre::MaterialPtr manual_object_material_; }; } #endif /* LINE_H_ */ rviz-1.12.4/src/rviz/ogre_helpers/mesh_shape.cpp000066400000000000000000000106071300447110700216510ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "mesh_shape.h" #include #include #include #include #include #include #include #include namespace rviz { MeshShape::MeshShape(Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ) : Shape( Shape::Mesh, scene_manager, parent_node ) , started_(false) { static uint32_t count = 0; manual_object_ = scene_manager->createManualObject("MeshShape_ManualObject" + boost::lexical_cast(count++)); material_->setCullingMode(Ogre::CULL_NONE); } MeshShape::~MeshShape() { clear(); scene_manager_->destroyManualObject(manual_object_); } void MeshShape::estimateVertexCount(size_t vcount) { if (entity_ == NULL && started_ == false) manual_object_->estimateVertexCount(vcount); } void MeshShape::beginTriangles() { if (!started_ && entity_) { ROS_WARN("Cannot modify mesh once construction is complete"); return; } if (!started_) { started_ = true; manual_object_->begin(material_name_, Ogre::RenderOperation::OT_TRIANGLE_LIST); } } void MeshShape::addVertex(const Ogre::Vector3& position) { beginTriangles(); manual_object_->position(position); } void MeshShape::addVertex(const Ogre::Vector3& position, const Ogre::Vector3& normal) { beginTriangles(); manual_object_->position(position); manual_object_->normal(normal); } void MeshShape::addVertex(const Ogre::Vector3& position, const Ogre::Vector3& normal, const Ogre::ColourValue &color) { beginTriangles(); manual_object_->position(position); manual_object_->normal(normal); manual_object_->colour(color); } void MeshShape::addNormal(const Ogre::Vector3& normal) { manual_object_->normal(normal); } void MeshShape::addColor(const Ogre::ColourValue &color) { manual_object_->colour(color); } void MeshShape::addTriangle(unsigned int v1, unsigned int v2, unsigned int v3) { manual_object_->triangle(v1, v2, v3); } void MeshShape::endTriangles() { if (started_) { started_ = false; manual_object_->end(); static uint32_t count = 0; std::string name = "ConvertedMeshShape@" + boost::lexical_cast(count++); manual_object_->convertToMesh(name); entity_ = scene_manager_->createEntity(name); if (entity_) { entity_->setMaterialName(material_name_); offset_node_->attachObject(entity_); } else ROS_ERROR("Unable to construct triangle mesh"); } else ROS_ERROR("No triangles added"); } void MeshShape::clear() { if (entity_) { entity_->detachFromParent(); Ogre::MeshManager::getSingleton().remove(entity_->getMesh()->getName()); scene_manager_->destroyEntity( entity_ ); entity_ = NULL; } manual_object_->clear(); started_ = false; } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/mesh_shape.h000066400000000000000000000127361300447110700213230ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_MESH_SHAPE_H #define OGRE_TOOLS_MESH_SHAPE_H #include "shape.h" namespace Ogre { class ManualObject; } namespace rviz { /** \brief This class allows constructing Ogre shapes manually, from triangle lists. For example: Assuming we have a set of mesh triangles represented like this: \verbatim struct Triangle { unsigned v1, v2, v3; // index for the 3 vertices that make up a triangle }; std::vector triangles; std::vector vertices; std::vector normals; // normal at every vertex \endverbatim we can use this class to render the mesh as follows: \verbatim rviz::MeshShape *shape = new MeshShape(scene_manager); mesh->estimateVertexCount(vertices.size()); mesh->beginTriangles(); for (std::size_t i = 0 ; i < vertices.size() ; ++i) mesh->addVertex(vertices[i], normals[i]); for (std::size_t i = 0 ; i < triangles.size() ; ++i) mesh->addTriangle(triangles[i].v1, triangles[i].v2, triangles[i].v3); mesh->endTriangles(); \endverbatim */ class MeshShape : public Shape { public: /** * \brief Constructor * * @param scene_manager The scene manager this object is associated with * @param parent_node A scene node to use as the parent of this object. If NULL, uses the root scene node. */ MeshShape(Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node = NULL); virtual ~MeshShape(); /* \brief Estimate the number of vertices ahead of time. */ void estimateVertexCount(size_t vcount); /** \brief Start adding triangles to the mesh */ void beginTriangles(); /** \brief Add a vertex to the mesh (no normal defined). If using this function only (not using addTriangle()) it is assumed that triangles are added by specifying the 3 vertices in order (3 consecutive calls to this function). This means there must be 3*n calls to this function to add n triangles. If addTriangle() is used, indexing in the defined vertices is done. */ void addVertex(const Ogre::Vector3& position); /** \brief Add a vertex to the mesh with a normal defined. If using this function only (not using addTriangle()) it is assumed that triangles are added by specifying the 3 vertices in order (3 consecutive calls to this function). This means there must be 3*n calls to this function to add n triangles.If addTriangle() is used, indexing in the defined vertices is done. */ void addVertex(const Ogre::Vector3& position, const Ogre::Vector3& normal); /** \brief Add a vertex to the mesh with normal and color defined. If using this function only (not using addTriangle()) it is assumed that triangles are added by specifying the 3 vertices in order (3 consecutive calls to this function). This means there must be 3*n calls to this function to add n triangles.If addTriangle() is used, indexing in the defined vertices is done. */ void addVertex(const Ogre::Vector3& position, const Ogre::Vector3& normal, const Ogre::ColourValue &color); /** \brief Add normal for a vertex */ void addNormal(const Ogre::Vector3 &normal); /** \brief Add color for a vertex */ void addColor(const Ogre::ColourValue &color); /** \brief Add a triangle by indexing in the defined vertices. */ void addTriangle(unsigned int p1, unsigned int p2, unsigned int p3); /** \brief Notify that the set of triangles to add is complete. No more triangles can be added, beginTriangles() can no longer be called unless clear() was called. */ void endTriangles(); /** \brief Clear the mesh */ void clear(); /** \brief Get the manual object created for the mesh */ Ogre::ManualObject* getManualObject() { return manual_object_; } private: // true in between calls to beginTriangles() and endTriangles() bool started_; Ogre::ManualObject *manual_object_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/ogre_helpers/movable_text.cpp000066400000000000000000000371371300447110700222350ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ // Adapted from: http://www.ogre3d.org/wiki/index.php/MovableText // now: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableText // Original authors: /* * File: MovableText.cpp * * description: This create create a billboarding object that display a text. * * @author 2003 by cTh see gavocanov@rambler.ru * @update 2006 by barraq see nospam@barraquand.com */ #include "movable_text.h" #include #include #include #include #include #include #include #include #include #include using namespace Ogre; #define POS_TEX_BINDING 0 #define COLOUR_BINDING 1 namespace rviz { MovableText::MovableText(const String &caption, const String &fontName, Real charHeight, const ColourValue &color) : mFontName(fontName) , mType("MovableText") , mCaption(caption) , mHorizontalAlignment(H_LEFT) , mVerticalAlignment(V_BELOW) , mColor(color) , mCharHeight(charHeight) , mLineSpacing(0.01) , mSpaceWidth(0) , mUpdateColors(true) , mOnTop(false) , mTimeUntilNextToggle(0) , mGlobalTranslation(0.0) , mLocalTranslation(0.0) , mpCam(NULL) , mpWin(NULL) , mpFont(NULL) { static int count = 0; std::stringstream ss; ss << "MovableText" << count++; mName = ss.str(); mRenderOp.vertexData = NULL; this->setFontName(mFontName); this->_setupGeometry(); } MovableText::~MovableText() { if (mRenderOp.vertexData) delete mRenderOp.vertexData; // May cause crashing... check this and comment if it does if (!mpMaterial.isNull()) MaterialManager::getSingletonPtr()->remove(mpMaterial->getName()); } void MovableText::setFontName(const String &fontName) { if ((Ogre::MaterialManager::getSingletonPtr()->resourceExists(mName + "Material"))) { Ogre::MaterialManager::getSingleton().remove(mName + "Material"); } if (mFontName != fontName || mpMaterial.isNull() || !mpFont) { mFontName = fontName; mpFont = (Font *) FontManager::getSingleton().getByName(mFontName).getPointer(); if (!mpFont) throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font " + fontName, "MovableText::setFontName"); mpFont->load(); if (!mpMaterial.isNull()) { MaterialManager::getSingletonPtr()->remove(mpMaterial->getName()); mpMaterial.setNull(); } mpMaterial = mpFont->getMaterial()->clone(mName + "Material"); if (!mpMaterial->isLoaded()) mpMaterial->load(); mpMaterial->setDepthCheckEnabled(!mOnTop); mpMaterial->setDepthBias(1.0, 1.0); mpMaterial->setDepthWriteEnabled(mOnTop); mpMaterial->setLightingEnabled(false); mNeedUpdate = true; } } void MovableText::setCaption(const String &caption) { if (caption != mCaption) { mCaption = caption; mNeedUpdate = true; } } void MovableText::setColor(const ColourValue &color) { if (color != mColor) { mColor = color; mUpdateColors = true; } } void MovableText::setCharacterHeight(Real height) { if (height != mCharHeight) { mCharHeight = height; mNeedUpdate = true; } } void MovableText::setLineSpacing(Real height) { if (height != mLineSpacing) { mLineSpacing = height; mNeedUpdate = true; } } void MovableText::setSpaceWidth(Real width) { if (width != mSpaceWidth) { mSpaceWidth = width; mNeedUpdate = true; } } void MovableText::setTextAlignment( const HorizontalAlignment& horizontalAlignment, const VerticalAlignment& verticalAlignment) { if (mHorizontalAlignment != horizontalAlignment) { mHorizontalAlignment = horizontalAlignment; mNeedUpdate = true; } if (mVerticalAlignment != verticalAlignment) { mVerticalAlignment = verticalAlignment; mNeedUpdate = true; } } void MovableText::setGlobalTranslation(Vector3 trans) { mGlobalTranslation = trans; } void MovableText::setLocalTranslation(Vector3 trans) { mLocalTranslation = trans; } void MovableText::showOnTop(bool show) { if (mOnTop != show && !mpMaterial.isNull()) { mOnTop = show; mpMaterial->setDepthBias(1.0, 1.0); mpMaterial->setDepthCheckEnabled(!mOnTop); mpMaterial->setDepthWriteEnabled(mOnTop); } } void MovableText::_setupGeometry() { assert(mpFont); assert(!mpMaterial.isNull()); unsigned int vertexCount = 0; //count letters to determine how many vertices are needed std::string::iterator i = mCaption.begin(); std::string::iterator iend = mCaption.end(); for ( ; i != iend; ++i ) { if ((*i != ' ') && (*i != '\n')) { vertexCount += 6; } } if (mRenderOp.vertexData) { delete mRenderOp.vertexData; mRenderOp.vertexData = NULL; mUpdateColors = true; } if (mCaption.empty()) { return; } if (!mRenderOp.vertexData) mRenderOp.vertexData = new VertexData(); mRenderOp.indexData = 0; mRenderOp.vertexData->vertexStart = 0; mRenderOp.vertexData->vertexCount = vertexCount; mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST; mRenderOp.useIndexes = false; VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration; VertexBufferBinding *bind = mRenderOp.vertexData->vertexBufferBinding; size_t offset = 0; // create/bind positions/tex.ccord. buffer if (!decl->findElementBySemantic(VES_POSITION)) decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); if (!decl->findElementBySemantic(VES_TEXTURE_COORDINATES)) decl->addElement(POS_TEX_BINDING, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0); HardwareVertexBufferSharedPtr ptbuf = HardwareBufferManager::getSingleton().createVertexBuffer( decl->getVertexSize(POS_TEX_BINDING), mRenderOp.vertexData->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); bind->setBinding(POS_TEX_BINDING, ptbuf); // Colours - store these in a separate buffer because they change less often if (!decl->findElementBySemantic(VES_DIFFUSE)) decl->addElement(COLOUR_BINDING, 0, VET_COLOUR, VES_DIFFUSE); HardwareVertexBufferSharedPtr cbuf = HardwareBufferManager::getSingleton().createVertexBuffer( decl->getVertexSize(COLOUR_BINDING), mRenderOp.vertexData->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); bind->setBinding(COLOUR_BINDING, cbuf); float *pPCBuff = static_cast (ptbuf->lock(HardwareBuffer::HBL_DISCARD)); Real spaceWidth = mSpaceWidth; // Derive space width from a capital A if (spaceWidth == 0) spaceWidth = mpFont->getGlyphAspectRatio('A') * mCharHeight * 2.0; float total_height = mCharHeight; float total_width = 0.0f; float current_width = 0.0f; i = mCaption.begin(); iend = mCaption.end(); for ( ; i != iend; ++i ) { if (*i == '\n') { total_height += mCharHeight + 0.01; if ( current_width > total_width ) { total_width = current_width; current_width = 0.0; } } else { current_width += mpFont->getGlyphAspectRatio(*i) * mCharHeight * 2.0; } } if ( current_width > total_width ) { total_width = current_width; } float top = 0.0f; switch (mVerticalAlignment) { case MovableText::V_ABOVE: top = total_height * 2; break; case MovableText::V_CENTER: top = 0.5 * total_height * 2; break; case MovableText::V_BELOW: top = 0.0f; break; } float starting_left = 0.0f; switch (mHorizontalAlignment) { case MovableText::H_LEFT: starting_left = 0.0f; break; case MovableText::H_CENTER: starting_left = -total_width / 2.0f; break; } float left = starting_left; bool newLine = true; Real len = 0.0f; // for calculation of AABB Ogre::Vector3 min(9999999.0f), max(-9999999.0f), currPos(0.0f); Ogre::Real maxSquaredRadius = -99999999.0f; float largestWidth = 0.0f; for (i = mCaption.begin(); i != iend; ++i) { if (newLine) { len = 0.0f; for (String::iterator j = i; j != iend && *j != '\n'; j++) { if (*j == ' ') len += spaceWidth; else len += mpFont->getGlyphAspectRatio(*j) * mCharHeight * 2.0; } newLine = false; } if (*i == '\n') { left = starting_left; top -= mCharHeight * 2.0; newLine = true; continue; } if (*i == ' ') { // Just leave a gap, no tris left += spaceWidth; continue; } Real horiz_height = mpFont->getGlyphAspectRatio(*i); Real u1, u2, v1, v2; Ogre::Font::UVRect utmp; utmp = mpFont->getGlyphTexCoords(*i); u1 = utmp.left; u2 = utmp.right; v1 = utmp.top; v2 = utmp.bottom; // each vert is (x, y, z, u, v) //------------------------------------------------------------------------------------- // First tri // // Upper left currPos = Ogre::Vector3(left, top, 0.0); *pPCBuff++ = currPos.x; *pPCBuff++ = currPos.y; *pPCBuff++ = currPos.z; *pPCBuff++ = u1; *pPCBuff++ = v1; // Deal with bounds min.makeFloor(currPos); max.makeCeil(currPos); maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength()); top -= mCharHeight * 2.0; // Bottom left currPos = Ogre::Vector3(left, top, 0.0); *pPCBuff++ = currPos.x; *pPCBuff++ = currPos.y; *pPCBuff++ = currPos.z; *pPCBuff++ = u1; *pPCBuff++ = v2; // Deal with bounds min.makeFloor(currPos); max.makeCeil(currPos); maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength()); top += mCharHeight * 2.0; left += horiz_height * mCharHeight * 2.0; // Top right currPos = Ogre::Vector3(left, top, 0.0); *pPCBuff++ = currPos.x; *pPCBuff++ = currPos.y; *pPCBuff++ = currPos.z; *pPCBuff++ = u2; *pPCBuff++ = v1; //------------------------------------------------------------------------------------- // Deal with bounds min.makeFloor(currPos); max.makeCeil(currPos); maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength()); //------------------------------------------------------------------------------------- // Second tri // // Top right (again) currPos = Ogre::Vector3(left, top, 0.0); *pPCBuff++ = currPos.x; *pPCBuff++ = currPos.y; *pPCBuff++ = currPos.z; *pPCBuff++ = u2; *pPCBuff++ = v1; min.makeFloor(currPos); max.makeCeil(currPos); maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength()); top -= mCharHeight * 2.0; left -= horiz_height * mCharHeight * 2.0; // Bottom left (again) currPos = Ogre::Vector3(left, top, 0.0); *pPCBuff++ = currPos.x; *pPCBuff++ = currPos.y; *pPCBuff++ = currPos.z; *pPCBuff++ = u1; *pPCBuff++ = v2; min.makeFloor(currPos); max.makeCeil(currPos); maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength()); left += horiz_height * mCharHeight * 2.0; // Bottom right currPos = Ogre::Vector3(left, top, 0.0); *pPCBuff++ = currPos.x; *pPCBuff++ = currPos.y; *pPCBuff++ = currPos.z; *pPCBuff++ = u2; *pPCBuff++ = v2; //------------------------------------------------------------------------------------- min.makeFloor(currPos); max.makeCeil(currPos); maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength()); // Go back up with top top += mCharHeight * 2.0; float currentWidth = (left + 1) / 2 - 0; if (currentWidth > largestWidth) largestWidth = currentWidth; } // Unlock vertex buffer ptbuf->unlock(); // update AABB/Sphere radius mAABB = Ogre::AxisAlignedBox(min, max); mRadius = Ogre::Math::Sqrt(maxSquaredRadius); if (mUpdateColors) this->_updateColors(); mNeedUpdate = false; } void MovableText::_updateColors(void) { assert(mpFont); assert(!mpMaterial.isNull()); // Convert to system-specific RGBA color; Root::getSingleton().convertColourValue(mColor, &color); HardwareVertexBufferSharedPtr vbuf = mRenderOp.vertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING); RGBA *pDest = static_cast (vbuf->lock(HardwareBuffer::HBL_DISCARD)); for (int i = 0; i < (int) mRenderOp.vertexData->vertexCount; ++i) *pDest++ = color; vbuf->unlock(); mUpdateColors = false; } const Quaternion& MovableText::getWorldOrientation(void) const { assert(mpCam); return const_cast (mpCam->getDerivedOrientation()); } #if( (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) || OGRE_VERSION_MAJOR >= 2 ) void MovableText::visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables) { visitor->visit( this, 0, false ); } #endif const Vector3& MovableText::getWorldPosition(void) const { assert(mParentNode); return mParentNode->_getDerivedPosition(); } void MovableText::getWorldTransforms(Matrix4 *xform) const { if (this->isVisible() && mpCam) { Matrix3 rot3x3, scale3x3 = Matrix3::IDENTITY; // store rotation in a matrix mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3); // parent node position Vector3 ppos = mParentNode->_getDerivedPosition() + Vector3::UNIT_Y * mGlobalTranslation; ppos += rot3x3 * mLocalTranslation; // apply scale scale3x3[0][0] = mParentNode->_getDerivedScale().x / 2; scale3x3[1][1] = mParentNode->_getDerivedScale().y / 2; scale3x3[2][2] = mParentNode->_getDerivedScale().z / 2; // apply all transforms to xform *xform = (rot3x3 * scale3x3); xform->setTrans(ppos); } } void MovableText::getRenderOperation(RenderOperation &op) { if (this->isVisible()) { if (mNeedUpdate) this->_setupGeometry(); if (mUpdateColors) this->_updateColors(); op = mRenderOp; } } void MovableText::_notifyCurrentCamera(Camera *cam) { mpCam = cam; } void MovableText::_updateRenderQueue(RenderQueue* queue) { if (this->isVisible()) { if (mNeedUpdate) this->_setupGeometry(); if (mUpdateColors) this->_updateColors(); queue->addRenderable(this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY); //queue->addRenderable(this, mRenderQueueID, RENDER_QUEUE_SKIES_LATE); } } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/movable_text.h000066400000000000000000000140731300447110700216740ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ // Adapted from: http://www.ogre3d.org/wiki/index.php/MovableText // now: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableText // Original authors: /* * File: MovableText.h * * description: This create create a billboarding object that display a text. * * @author 2003 by cTh see gavocanov@rambler.ru * @update 2006 by barraq see nospam@barraquand.com */ #ifndef OGRE_TOOLS_MOVABLE_TEXT_H #define OGRE_TOOLS_MOVABLE_TEXT_H #include #include #include #include #include namespace Ogre { class RenderQueue; class Camera; class Font; } namespace rviz { class MovableText : public Ogre::MovableObject, public Ogre::Renderable { /******************************** MovableText data ****************************/ public: enum HorizontalAlignment { H_LEFT, H_CENTER }; enum VerticalAlignment { V_BELOW, V_ABOVE, V_CENTER }; protected: Ogre::String mFontName; Ogre::String mType; Ogre::String mName; Ogre::String mCaption; HorizontalAlignment mHorizontalAlignment; VerticalAlignment mVerticalAlignment; Ogre::ColourValue mColor; Ogre::RenderOperation mRenderOp; Ogre::AxisAlignedBox mAABB; Ogre::LightList mLList; Ogre::Real mCharHeight; Ogre::Real mLineSpacing; Ogre::Real mSpaceWidth; bool mNeedUpdate; bool mUpdateColors; bool mOnTop; Ogre::Real mTimeUntilNextToggle; Ogre::Real mRadius; Ogre::Vector3 mGlobalTranslation; Ogre::Vector3 mLocalTranslation; Ogre::Camera *mpCam; Ogre::RenderWindow *mpWin; Ogre::Font *mpFont; Ogre::MaterialPtr mpMaterial; Ogre::MaterialPtr mpBackgroundMaterial; /******************************** public methods ******************************/ public: MovableText(const Ogre::String &caption, const Ogre::String &fontName = "Arial", Ogre::Real charHeight = 1.0, const Ogre::ColourValue &color = Ogre::ColourValue::White); virtual ~MovableText(); #if (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) virtual void visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables = false); #endif // Set settings void setFontName(const Ogre::String &fontName); void setCaption(const Ogre::String &caption); void setColor(const Ogre::ColourValue &color); void setCharacterHeight(Ogre::Real height); void setLineSpacing(Ogre::Real height); void setSpaceWidth(Ogre::Real width); void setTextAlignment(const HorizontalAlignment& horizontalAlignment, const VerticalAlignment& verticalAlignment); void setGlobalTranslation(Ogre::Vector3 trans); void setLocalTranslation(Ogre::Vector3 trans); void showOnTop(bool show = true); // Get settings const Ogre::String &getFontName() const { return mFontName; } const Ogre::String &getCaption() const { return mCaption; } const Ogre::ColourValue &getColor() const { return mColor; } Ogre::Real getCharacterHeight() const { return mCharHeight; } Ogre::Real getSpaceWidth() const { return mSpaceWidth; } Ogre::Vector3 getGlobalTranslation() const { return mGlobalTranslation; } Ogre::Vector3 getLocalTranslation() const { return mLocalTranslation; } bool getShowOnTop() const { return mOnTop; } Ogre::AxisAlignedBox GetAABB(void) { return mAABB; } const Ogre::MaterialPtr &getMaterial(void) const { assert(!mpMaterial.isNull()); return mpMaterial; } ; /******************************** protected methods and overload **************/ protected: // from MovableText, create the object void _setupGeometry(); void _updateColors(); // from Ogre::MovableObject void getWorldTransforms(Ogre::Matrix4 *xform) const; Ogre::Real getBoundingRadius(void) const { return mRadius; } ; Ogre::Real getSquaredViewDepth(const Ogre::Camera *cam) const { return 0; } ; const Ogre::Quaternion &getWorldOrientation(void) const; const Ogre::Vector3 &getWorldPosition(void) const; const Ogre::AxisAlignedBox &getBoundingBox(void) const { return mAABB; } ; const Ogre::String &getName(void) const { return mName; } ; const Ogre::String &getMovableType(void) const { static Ogre::String movType = "MovableText"; return movType; } ; void _notifyCurrentCamera(Ogre::Camera *cam); void _updateRenderQueue(Ogre::RenderQueue* queue); // from renderable void getRenderOperation(Ogre::RenderOperation &op); const Ogre::LightList &getLights(void) const { return mLList; } ; }; } #endif rviz-1.12.4/src/rviz/ogre_helpers/object.cpp000066400000000000000000000033421300447110700210010ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "object.h" namespace rviz { Object::Object( Ogre::SceneManager* scene_manager ) : scene_manager_( scene_manager ) { } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/object.h000066400000000000000000000066201300447110700204500ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_OBJECT_H #define OGRE_TOOLS_OBJECT_H namespace Ogre { class SceneManager; class SceneNode; class Vector3; class Quaternion; class Any; } namespace rviz { /** * \class Object * \brief Base class for visible objects, providing a minimal generic interface. */ class Object { public: /** * * @param scene_manager The scene manager this object should be part of. */ Object( Ogre::SceneManager* scene_manager ); virtual ~Object() {} /** * \brief Set the position of this object * @param Position vector position to set to. */ virtual void setPosition( const Ogre::Vector3& position ) = 0; /** * \brief Set the orientation of the object * @param Orientation quaternion orientation to set to. */ virtual void setOrientation( const Ogre::Quaternion& orientation ) = 0; /** * \brief Set the scale of the object. Always relative to the identity orientation of the object. * @param Scale vector scale to set to. */ virtual void setScale( const Ogre::Vector3& scale ) = 0; /** * \brief Set the color of the object. Values are in the range [0, 1] * @param r Red component * @param g Green component * @param b Blue component */ virtual void setColor( float r, float g, float b, float a ) = 0; /** * \brief Get the local position of this object * @return The position */ virtual const Ogre::Vector3& getPosition() = 0; /** * \brief Get the local orientation of this object * @return The orientation */ virtual const Ogre::Quaternion& getOrientation() = 0; /** * \brief Set the user data on this object * @param data */ virtual void setUserData( const Ogre::Any& data ) = 0; protected: Ogre::SceneManager* scene_manager_; ///< Ogre scene manager this object is part of }; } // namespace rviz #endif /* OGRE_TOOLS_OBJECT_H */ rviz-1.12.4/src/rviz/ogre_helpers/ogre_logging.cpp000066400000000000000000000100061300447110700221700ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/ogre_helpers/ogre_logging.h" namespace rviz { class RosLogListener: public Ogre::LogListener { public: RosLogListener(): min_lml(Ogre::LML_CRITICAL) {}; virtual ~RosLogListener() {} #if OGRE_VERSION >= ((1 << 16) | (8 << 8)) virtual void messageLogged( const Ogre::String& message, Ogre::LogMessageLevel lml, bool maskDebug, const Ogre::String &logName, bool& skipThisMessage ) { if ( !skipThisMessage ) { if ( lml >= min_lml ) { ROS_LOG((ros::console::levels::Level)(lml-1), ROSCONSOLE_DEFAULT_NAME, "%s", message.c_str() ); } } } #else virtual void messageLogged( const Ogre::String& message, Ogre::LogMessageLevel lml, bool maskDebug, const Ogre::String &logName ) { if ( lml >= min_lml ) { ROS_LOG((ros::console::levels::Level)(lml-1), ROSCONSOLE_DEFAULT_NAME, "%s", message.c_str() ); } } #endif Ogre::LogMessageLevel min_lml; }; OgreLogging::Preference OgreLogging::preference_ = OgreLogging::NoLogging; QString OgreLogging::filename_; /** @brief Configure Ogre to write output to standard out. */ void OgreLogging::useRosLog() { preference_ = StandardOut; } /** @brief Configure Ogre to write output to the given log file * name. If file name is a relative path, it will be relative to * the directory which is current when the program is run. Default * is "Ogre.log". */ void OgreLogging::useLogFile( const QString& filename ) { preference_ = FileLogging; filename_ = filename; } /** @brief Disable Ogre logging entirely. This is the default. */ void OgreLogging::noLog() { preference_ = NoLogging; } /** @brief Configure the Ogre::LogManager to give the behavior * selected by the most recent call to enableStandardOut(), * setLogFile(), or disable(). This must be called before * Ogre::Root is instantiated! Called inside RenderSystem * constructor. */ void OgreLogging::configureLogging() { static RosLogListener ll; Ogre::LogManager* log_manager = Ogre::LogManager::getSingletonPtr(); if( log_manager == NULL ) { log_manager = new Ogre::LogManager(); } Ogre::Log* l = log_manager->createLog( filename_.toStdString(), false, false, preference_==NoLogging ); l->addListener( &ll ); // Printing to standard out is what Ogre does if you don't do any LogManager calls. if( preference_ == StandardOut ) { ll.min_lml=Ogre::LML_NORMAL; } } } // end namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/ogre_logging.h000066400000000000000000000060431300447110700216430ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_LOGGING_H #define OGRE_LOGGING_H #include namespace rviz { /** @brief Convenience interface to Ogre logging. * * This all-static class wraps Ogre::LogManager into 3 easy options: * no logging, standard out, or file logging. The option-selection * calls (useStandardOut(), useLogFile(), and noLog() must be called * before configureLogging(). configureLogging(), in turn, must be * called before any Ogre::Root object is instantiated. * configureLogging() is called at the right time by the RenderSystem * constructor, so you generally won't need to call it explicitly. */ class OgreLogging { public: /** @brief Configure Ogre to write output to the ROS logger. */ static void useRosLog(); /** @brief Configure Ogre to write output to the given log file * name. If file name is a relative path, it will be relative to * the directory which is current when the program is run. Default * is "Ogre.log". */ static void useLogFile( const QString& filename = "Ogre.log" ); /** @brief Disable Ogre logging entirely. This is the default. */ static void noLog(); /** @brief Configure the Ogre::LogManager to give the * currently selected behavior. * This must be called before Ogre::Root is instantiated! */ static void configureLogging(); private: typedef enum { StandardOut, FileLogging, NoLogging } Preference; static Preference preference_; static QString filename_; }; } // end namespace rviz #endif // OGRE_LOGGING_H rviz-1.12.4/src/rviz/ogre_helpers/ogre_render_queue_clearer.cpp000066400000000000000000000053641300447110700247350ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ogre_render_queue_clearer.h" #include #include namespace rviz { OgreRenderQueueClearer::OgreRenderQueueClearer() { // TODO Auto-generated constructor stub } OgreRenderQueueClearer::~OgreRenderQueueClearer() { // TODO Auto-generated destructor stub } bool OgreRenderQueueClearer::frameStarted (const Ogre::FrameEvent &evt) { // Workaround taken from http://www.ogre3d.org/mantis/view.php?id=130 // in case a plugin creates its own scene manager. // // Has the following modifications: // 1. Need to pass 'true' to RenderQueue::clear( bool destroyPassMaps ). // 2. Don't need to call Ogre::Pass::processPendingPassUpdates(), // since this is done within RenderQueue::clear(). // This workaround is only necessary if there is more than one // scene manager present, so check for that Ogre::SceneManagerEnumerator::SceneManagerIterator it = Ogre::Root::getSingletonPtr()->getSceneManagerIterator(); it.getNext(); if ( !it.hasMoreElements() ) { return true; } it = Ogre::Root::getSingletonPtr()->getSceneManagerIterator(); while ( it.hasMoreElements() ) { it.getNext()->getRenderQueue()->clear( true ); } return true; } } rviz-1.12.4/src/rviz/ogre_helpers/ogre_render_queue_clearer.h000066400000000000000000000042221300447110700243720ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRERENDERQUEUECLEARER_H_ #define OGRERENDERQUEUECLEARER_H_ #include namespace rviz { /* * Helper class for fixing the bug described under http://www.ogre3d.org/mantis/view.php?id=130 * This bug happens in Ogre 1.7.x when multiple scene managers are being used, * but might be fixed in Ogre 1.8.0 and above. */ class OgreRenderQueueClearer: public Ogre::FrameListener { public: OgreRenderQueueClearer(); virtual ~OgreRenderQueueClearer(); virtual bool frameStarted (const Ogre::FrameEvent &evt); }; } #endif /* OGRERENDERQUEUECLEARER_H_ */ rviz-1.12.4/src/rviz/ogre_helpers/orbit_camera.cpp000066400000000000000000000220311300447110700221560ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "orbit_camera.h" #include "shape.h" #include #include #include #include #include #include #include #include #define MIN_DISTANCE 0.01 namespace rviz { static const float PITCH_LIMIT_LOW = 0.001; static const float PITCH_LIMIT_HIGH = Ogre::Math::PI - 0.001; static const float YAW_START = Ogre::Math::PI;// - 0.001; static const float PITCH_START = Ogre::Math::HALF_PI; OrbitCamera::OrbitCamera( Ogre::SceneManager* scene_manager ) : CameraBase( scene_manager ) , focal_point_( Ogre::Vector3::ZERO ) , yaw_( YAW_START ) , pitch_( PITCH_START ) , distance_( 10.0f ) { focal_point_object_ = new Shape( Shape::Sphere, scene_manager ); focal_point_object_->setScale( Ogre::Vector3( 0.05f, 0.01f, 0.05f ) ); focal_point_object_->setColor( 1.0f, 1.0f, 0.0f, 0.5f ); focal_point_object_->getRootNode()->setVisible( false ); update(); } OrbitCamera::~OrbitCamera() { delete focal_point_object_; } void OrbitCamera::normalizePitch() { if ( pitch_ < PITCH_LIMIT_LOW ) { pitch_ = PITCH_LIMIT_LOW; } else if ( pitch_ > PITCH_LIMIT_HIGH ) { pitch_ = PITCH_LIMIT_HIGH; } } void OrbitCamera::normalizeYaw() { yaw_ = fmod( yaw_, Ogre::Math::TWO_PI ); if ( yaw_ < 0.0f ) { yaw_ = Ogre::Math::TWO_PI + yaw_; } } Ogre::Vector3 OrbitCamera::getGlobalFocalPoint() { Ogre::Vector3 global_focal_point = focal_point_; if ( relative_node_ ) { global_focal_point = relative_node_->getOrientation() * focal_point_ + relative_node_->getPosition(); } return global_focal_point; } void OrbitCamera::update() { Ogre::Vector3 global_focal_point = getGlobalFocalPoint(); float x = distance_ * cos( yaw_ ) * sin( pitch_ ) + global_focal_point.x; float y = distance_ * cos( pitch_ ) + global_focal_point.y; float z = distance_ * sin( yaw_ ) * sin( pitch_ ) + global_focal_point.z; Ogre::Vector3 pos( x, y, z ); if ( relative_node_ ) { Ogre::Vector3 vec = pos - global_focal_point; pos = relative_node_->getOrientation() * vec + global_focal_point; camera_->setFixedYawAxis(true, relative_node_->getOrientation() * Ogre::Vector3::UNIT_Y); } camera_->setPosition( pos ); camera_->lookAt( global_focal_point ); focal_point_object_->setPosition( global_focal_point ); } void OrbitCamera::yaw( float angle ) { yaw_ += angle; normalizeYaw(); update(); } void OrbitCamera::pitch( float angle ) { pitch_ += angle; normalizePitch(); update(); } void OrbitCamera::roll( float angle ) { } Ogre::Vector3 OrbitCamera::getPosition() { return camera_->getPosition(); } Ogre::Quaternion OrbitCamera::getOrientation() { return camera_->getOrientation(); } void OrbitCamera::calculatePitchYawFromPosition( const Ogre::Vector3& position ) { float x = position.x - focal_point_.x; float y = position.y - focal_point_.y; pitch_ = acos( y / distance_ ); normalizePitch(); float val = x / ( distance_ * sin( pitch_ ) ); yaw_ = acos( val ); Ogre::Vector3 direction = focal_point_ - position; if ( direction.dotProduct( Ogre::Vector3::NEGATIVE_UNIT_Z ) < 0 ) { yaw_ = Ogre::Math::TWO_PI - yaw_; } } void OrbitCamera::setFrom( CameraBase* camera ) { Ogre::Vector3 position = camera->getPosition(); Ogre::Quaternion orientation = camera->getOrientation(); Ogre::Vector3 direction = orientation * (Ogre::Vector3::NEGATIVE_UNIT_Z * distance_); focal_point_ = position + direction; calculatePitchYawFromPosition( position ); update(); } void OrbitCamera::setOrientation( float x, float y, float z, float w ) { Ogre::Vector3 position = camera_->getPosition(); Ogre::Quaternion orientation( w, x, y, z ); Ogre::Vector3 direction = orientation * (Ogre::Vector3::NEGATIVE_UNIT_Z * distance_); focal_point_ = position + direction; calculatePitchYawFromPosition( position ); update(); } void OrbitCamera::zoom( float amount ) { distance_ -= amount; if ( distance_ <= MIN_DISTANCE ) { distance_ = MIN_DISTANCE; } update(); } void OrbitCamera::setFocalPoint( const Ogre::Vector3& focal_point ) { focal_point_ = focal_point; update(); } void OrbitCamera::move( float x, float y, float z ) { Ogre::Quaternion orientation = camera_->getOrientation(); if ( relative_node_ ) { orientation = relative_node_->getOrientation().Inverse() * orientation; } focal_point_ += orientation * Ogre::Vector3( x, y, z ); update(); } void OrbitCamera::setPosition( float x, float y, float z ) { Ogre::Vector3 pos( x, y, z ); distance_ = (pos - getGlobalFocalPoint()).length(); calculatePitchYawFromPosition( Ogre::Vector3( x, y, z ) ); update(); } void OrbitCamera::lookAt( const Ogre::Vector3& point ) { Ogre::Vector3 focal_point = point; Ogre::Vector3 camera_position = camera_->getPosition(); if ( relative_node_ ) { Ogre::Vector3 rel_pos = relative_node_->getPosition(); Ogre::Quaternion rel_orient = relative_node_->getOrientation(); focal_point = rel_orient.Inverse() * ( focal_point - rel_pos ); camera_position = rel_orient.Inverse() * ( camera_position - rel_pos ); } distance_ = focal_point.distance( camera_position ); focal_point_ = focal_point; update(); } void OrbitCamera::mouseLeftDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ) { yaw( diff_x*0.005 ); pitch( -diff_y*0.005 ); } void OrbitCamera::mouseMiddleDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ) { float fovY = camera_->getFOVy().valueRadians(); float fovX = 2.0f * atan( tan( fovY / 2.0f ) * camera_->getAspectRatio() ); int width = camera_->getViewport()->getActualWidth(); int height = camera_->getViewport()->getActualHeight(); move( -((float)diff_x / (float)width) * distance_ * tan( fovX / 2.0f ) * 2.0f, ((float)diff_y / (float)height) * distance_ * tan( fovY / 2.0f ) * 2.0f, 0.0f ); } void OrbitCamera::mouseRightDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ) { if (shift) { move(0.0f, 0.0f, diff_y * 0.1 * (distance_ / 10.0f)); } else { zoom( -diff_y * 0.1 * (distance_ / 10.0f) ); } } void OrbitCamera::scrollWheel( int diff, bool ctrl, bool alt, bool shift ) { if (shift) { move(0.0f, 0.0f, -diff * 0.01 * (distance_ / 10.0f)); } else { zoom( diff * 0.01 * (distance_ / 10.0f) ); } } void OrbitCamera::mouseLeftDown( int x, int y ) { focal_point_object_->getRootNode()->setVisible( true ); } void OrbitCamera::mouseMiddleDown( int x, int y ) { focal_point_object_->getRootNode()->setVisible( true ); } void OrbitCamera::mouseRightDown( int x, int y ) { focal_point_object_->getRootNode()->setVisible( true ); } void OrbitCamera::mouseLeftUp( int x, int y ) { focal_point_object_->getRootNode()->setVisible( false ); } void OrbitCamera::mouseMiddleUp( int x, int y ) { focal_point_object_->getRootNode()->setVisible( false ); } void OrbitCamera::mouseRightUp( int x, int y ) { focal_point_object_->getRootNode()->setVisible( false ); } void OrbitCamera::fromString(const std::string& str) { std::istringstream iss(str); iss >> pitch_; iss.ignore(); iss >> yaw_; iss.ignore(); iss >> distance_; iss.ignore(); iss >> focal_point_.x; iss.ignore(); iss >> focal_point_.y; iss.ignore(); iss >> focal_point_.z; update(); } std::string OrbitCamera::toString() { std::ostringstream oss; oss << pitch_ << " " << yaw_ << " " << distance_ << " " << focal_point_.x << " " << focal_point_.y << " " << focal_point_.z; return oss.str(); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/orbit_camera.h000066400000000000000000000121431300447110700216260ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_ORBIT_CAMERA_H_ #define OGRE_TOOLS_ORBIT_CAMERA_H_ #include "camera_base.h" #include namespace Ogre { class Camera; class SceneNode; class SceneManager; } namespace rviz { class Shape; /** * \brief An orbital camera, controlled by yaw, pitch, distance, and focal point * * This camera is based on the equation of a sphere in spherical coordinates: @verbatim x = d*cos(theta)sin(phi) y = d*cos(phi) z = d*sin(theta)sin(phi) @endverbatim * Where:
* d = #distance_
* theta = #yaw_
* phi = #pitch_ */ class OrbitCamera : public CameraBase { public: OrbitCamera( Ogre::SceneManager* scene_manager ); virtual ~OrbitCamera(); /** * \brief Move in/out from the focal point, ie. adjust #distance_ by amount * @param amount The distance to move. Positive amount moves towards the focal point, negative moves away */ void zoom( float amount ); /** * \brief Set the focal point of the camera. Keeps the pitch/yaw/distance the same * @param focal_point The new focal point */ void setFocalPoint( const Ogre::Vector3& focal_point ); float getPitch() { return pitch_; } float getYaw() { return yaw_; } float getDistance() { return distance_; } const Ogre::Vector3& getFocalPoint() { return focal_point_; } virtual void setFrom( CameraBase* camera ); virtual void yaw( float angle ); virtual void pitch( float angle ); virtual void roll( float angle ); virtual void setOrientation( float x, float y, float z, float w ); virtual void setPosition( float x, float y, float z ); virtual void move( float x, float y, float z ); virtual Ogre::Vector3 getPosition(); virtual Ogre::Quaternion getOrientation(); virtual void lookAt( const Ogre::Vector3& point ); virtual void mouseLeftDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ); virtual void mouseMiddleDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ); virtual void mouseRightDrag( int diff_x, int diff_y, bool ctrl, bool alt, bool shift ); virtual void scrollWheel( int diff, bool ctrl, bool alt, bool shift ); /** * \brief Calculates the camera's position and orientation from the yaw, pitch, distance and focal point */ virtual void update(); virtual void mouseLeftDown( int x, int y ); virtual void mouseMiddleDown( int x, int y ); virtual void mouseRightDown( int x, int y ); virtual void mouseLeftUp( int x, int y ); virtual void mouseMiddleUp( int x, int y ); virtual void mouseRightUp( int x, int y ); virtual void fromString(const std::string& str); virtual std::string toString(); private: Ogre::Vector3 getGlobalFocalPoint(); /** * \brief Calculates pitch and yaw values given a new position and the current focal point * @param position Position to calculate the pitch/yaw for */ void calculatePitchYawFromPosition( const Ogre::Vector3& position ); /** * \brief Normalizes the camera's pitch, preventing it from reaching vertical (or turning upside down) */ void normalizePitch(); /** * \brief Normalizes the camera's yaw in the range [0, 2*pi) */ void normalizeYaw(); Ogre::Vector3 focal_point_; ///< The camera's focal point float yaw_; ///< The camera's yaw (rotation around the y-axis), in radians float pitch_; ///< The camera's pitch (rotation around the x-axis), in radians float distance_; ///< The camera's distance from the focal point Shape* focal_point_object_; }; } // namespace rviz #endif /*OGRE_TOOLS_ORBIT_CAMERA_H_*/ rviz-1.12.4/src/rviz/ogre_helpers/orthographic.cpp000066400000000000000000000041531300447110700222250ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "orthographic.h" #include namespace rviz { void buildScaledOrthoMatrix(Ogre::Matrix4& proj, float left, float right, float bottom, float top, float near, float far) { float invw = 1 / (right - left); float invh = 1 / (top - bottom); float invd = 1 / (far - near); proj = Ogre::Matrix4::ZERO; proj[0][0] = 2 * invw; proj[0][3] = -(right + left) * invw; proj[1][1] = 2 * invh; proj[1][3] = -(top + bottom) * invh; proj[2][2] = -2 * invd; proj[2][3] = -(far + near) * invd; proj[3][3] = 1; } } rviz-1.12.4/src/rviz/ogre_helpers/orthographic.h000066400000000000000000000035141300447110700216720ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_ORTHOGRAPHIC_H #define OGRE_TOOLS_ORTHOGRAPHIC_H namespace Ogre { class Matrix4; } namespace rviz { void buildScaledOrthoMatrix(Ogre::Matrix4& proj, float left, float right, float bottom, float top, float near, float far); } #endif rviz-1.12.4/src/rviz/ogre_helpers/point_cloud.cpp000066400000000000000000000552221300447110700220560ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "point_cloud.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rviz/ogre_helpers/custom_parameter_indices.h" #include "rviz/selection/forwards.h" #define VERTEX_BUFFER_CAPACITY (36 * 1024 * 10) namespace rviz { static float g_point_vertices[3] = { 0.0f, 0.0f, 0.0f }; static float g_billboard_vertices[6*3] = { -0.5f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, 0.5f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, }; static float g_billboard_sphere_vertices[3*3] = { 0.0f, 1.0f, 0.0f, -0.866025404f, -0.5f, 0.0f, 0.866025404f, -0.5f, 0.0f, }; static float g_box_vertices[6*6*3] = { // front -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, // back -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, // right 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, // left -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, // top -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, // bottom -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, }; Ogre::String PointCloud::sm_Type = "PointCloud"; PointCloud::PointCloud() : bounding_radius_( 0.0f ) , point_count_( 0 ) , common_direction_( Ogre::Vector3::NEGATIVE_UNIT_Z ) , common_up_vector_( Ogre::Vector3::UNIT_Y ) , color_by_index_(false) , current_mode_supports_geometry_shader_(false) { std::stringstream ss; static int count = 0; ss << "PointCloudMaterial" << count++; point_material_ = Ogre::MaterialManager::getSingleton().getByName("rviz/PointCloudPoint"); square_material_ = Ogre::MaterialManager::getSingleton().getByName("rviz/PointCloudSquare"); flat_square_material_ = Ogre::MaterialManager::getSingleton().getByName("rviz/PointCloudFlatSquare"); sphere_material_ = Ogre::MaterialManager::getSingleton().getByName("rviz/PointCloudSphere"); tile_material_ = Ogre::MaterialManager::getSingleton().getByName("rviz/PointCloudTile"); box_material_ = Ogre::MaterialManager::getSingleton().getByName("rviz/PointCloudBox"); point_material_ = Ogre::MaterialPtr(point_material_)->clone(ss.str() + "Point"); square_material_ = Ogre::MaterialPtr(square_material_)->clone(ss.str() + "Square"); flat_square_material_ = Ogre::MaterialPtr(flat_square_material_)->clone(ss.str() + "FlatSquare"); sphere_material_ = Ogre::MaterialPtr(sphere_material_)->clone(ss.str() + "Sphere"); tile_material_ = Ogre::MaterialPtr(tile_material_)->clone(ss.str() + "Tiles"); box_material_ = Ogre::MaterialPtr(box_material_)->clone(ss.str() + "Box"); point_material_->load(); square_material_->load(); flat_square_material_->load(); sphere_material_->load(); tile_material_->load(); box_material_->load(); setAlpha( 1.0f ); setRenderMode(RM_SPHERES); setDimensions(0.01f, 0.01f, 0.01f); clear(); } static void removeMaterial(Ogre::MaterialPtr& material) { Ogre::ResourcePtr resource(material); Ogre::MaterialManager::getSingleton().remove(resource); } PointCloud::~PointCloud() { clear(); point_material_->unload(); square_material_->unload(); flat_square_material_->unload(); sphere_material_->unload(); tile_material_->unload(); box_material_->unload(); removeMaterial(point_material_); removeMaterial(square_material_); removeMaterial(flat_square_material_); removeMaterial(sphere_material_); removeMaterial(tile_material_); removeMaterial(box_material_); } const Ogre::AxisAlignedBox& PointCloud::getBoundingBox() const { return bounding_box_; } float PointCloud::getBoundingRadius() const { return bounding_radius_; } void PointCloud::getWorldTransforms(Ogre::Matrix4* xform) const { *xform = _getParentNodeFullTransform(); } void PointCloud::clear() { point_count_ = 0; bounding_box_.setNull(); bounding_radius_ = 0.0f; if (getParentSceneNode()) { V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { getParentSceneNode()->detachObject(it->get()); } getParentSceneNode()->needUpdate(); } renderables_.clear(); } void PointCloud::regenerateAll() { if (point_count_ == 0) { return; } V_Point points; points.swap(points_); uint32_t count = point_count_; clear(); addPoints(&points.front(), count); } void PointCloud::setColorByIndex(bool set) { color_by_index_ = set; regenerateAll(); } void PointCloud::setHighlightColor( float r, float g, float b ) { Ogre::Vector4 highlight( r, g, b, 0.0f ); V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setCustomParameter(HIGHLIGHT_PARAMETER, highlight); } } void PointCloud::setRenderMode(RenderMode mode) { render_mode_ = mode; if (mode == RM_POINTS) { current_material_ = Ogre::MaterialPtr(point_material_); } else if (mode == RM_SQUARES) { current_material_ = Ogre::MaterialPtr(square_material_); } else if (mode == RM_FLAT_SQUARES) { current_material_ = Ogre::MaterialPtr(flat_square_material_); } else if (mode == RM_SPHERES) { current_material_ = Ogre::MaterialPtr(sphere_material_); } else if (mode == RM_TILES) { current_material_ = Ogre::MaterialPtr(tile_material_); } else if (mode == RM_BOXES) { current_material_ = Ogre::MaterialPtr(box_material_); } current_material_->load(); //ROS_INFO("Best technique [%s] [gp=%s]", current_material_->getBestTechnique()->getName().c_str(), current_material_->getBestTechnique()->getPass(0)->getGeometryProgramName().c_str()); bool geom_support_changed = false; Ogre::Technique* best = current_material_->getBestTechnique(); if (best) { if (current_material_->getBestTechnique()->getName() == "gp") { if (!current_mode_supports_geometry_shader_) { geom_support_changed = true; } current_mode_supports_geometry_shader_ = true; //ROS_INFO("Using geometry shader"); } else { if (current_mode_supports_geometry_shader_) { geom_support_changed = true; } current_mode_supports_geometry_shader_ = false; } } else { geom_support_changed = true; current_mode_supports_geometry_shader_ = false; ROS_ERROR("No techniques available for material [%s]", current_material_->getName().c_str()); } if (geom_support_changed) { renderables_.clear(); } V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setMaterial(current_material_->getName()); } regenerateAll(); } void PointCloud::setDimensions(float width, float height, float depth) { width_ = width; height_ = height; depth_ = depth; Ogre::Vector4 size(width_, height_, depth_, 0.0f); V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setCustomParameter(SIZE_PARAMETER, size); } } void PointCloud::setAutoSize(bool auto_size) { V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setCustomParameter(AUTO_SIZE_PARAMETER, Ogre::Vector4(auto_size)); } } void PointCloud::setCommonDirection(const Ogre::Vector3& vec) { common_direction_ = vec; V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setCustomParameter(NORMAL_PARAMETER, Ogre::Vector4(vec)); } } void PointCloud::setCommonUpVector(const Ogre::Vector3& vec) { common_up_vector_ = vec; V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setCustomParameter(UP_PARAMETER, Ogre::Vector4(vec)); } } void setAlphaBlending(const Ogre::MaterialPtr& mat) { if (mat->getBestTechnique()) { mat->getBestTechnique()->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); mat->getBestTechnique()->setDepthWriteEnabled( false ); } } void setReplace(const Ogre::MaterialPtr& mat) { if (mat->getBestTechnique()) { mat->getBestTechnique()->setSceneBlending( Ogre::SBT_REPLACE ); mat->getBestTechnique()->setDepthWriteEnabled( true ); } } void PointCloud::setAlpha(float alpha, bool per_point_alpha) { alpha_ = alpha; if ( alpha < 0.9998 || per_point_alpha ) { setAlphaBlending(point_material_); setAlphaBlending(square_material_); setAlphaBlending(flat_square_material_); setAlphaBlending(sphere_material_); setAlphaBlending(tile_material_); setAlphaBlending(box_material_); } else { setReplace(point_material_); setReplace(square_material_); setReplace(flat_square_material_); setReplace(sphere_material_); setReplace(tile_material_); setReplace(box_material_); } Ogre::Vector4 alpha4(alpha_, alpha_, alpha_, alpha_); V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setCustomParameter(ALPHA_PARAMETER, alpha4); } } void PointCloud::addPoints(Point* points, uint32_t num_points) { if (num_points == 0) { return; } Ogre::Root* root = Ogre::Root::getSingletonPtr(); if ( points_.size() < point_count_ + num_points ) { points_.resize( point_count_ + num_points ); } Point* begin = &points_.front() + point_count_; memcpy( begin, points, sizeof( Point ) * num_points ); uint32_t vpp = getVerticesPerPoint(); Ogre::RenderOperation::OperationType op_type; if (current_mode_supports_geometry_shader_) { op_type = Ogre::RenderOperation::OT_POINT_LIST; } else { if (render_mode_ == RM_POINTS) { op_type = Ogre::RenderOperation::OT_POINT_LIST; } else { op_type = Ogre::RenderOperation::OT_TRIANGLE_LIST; } } float* vertices = 0; if (current_mode_supports_geometry_shader_) { vertices = g_point_vertices; } else { if (render_mode_ == RM_POINTS) { vertices = g_point_vertices; } else if (render_mode_ == RM_SQUARES) { vertices = g_billboard_vertices; } else if (render_mode_ == RM_FLAT_SQUARES) { vertices = g_billboard_vertices; } else if (render_mode_ == RM_SPHERES) { vertices = g_billboard_sphere_vertices; } else if (render_mode_ == RM_TILES) { vertices = g_billboard_vertices; } else if (render_mode_ == RM_BOXES) { vertices = g_box_vertices; } } PointCloudRenderablePtr rend; Ogre::HardwareVertexBufferSharedPtr vbuf; void* vdata = 0; Ogre::RenderOperation* op = 0; float* fptr = 0; Ogre::AxisAlignedBox aabb; aabb.setNull(); uint32_t current_vertex_count = 0; bounding_radius_ = 0.0f; uint32_t vertex_size = 0; uint32_t buffer_size = 0; for (uint32_t current_point = 0; current_point < num_points; ++current_point) { // if we didn't create a renderable yet, // or we've reached the vertex limit for the current renderable, // create a new one. while (!rend || current_vertex_count >= buffer_size) { if (rend) { ROS_ASSERT(current_vertex_count == buffer_size); op->vertexData->vertexCount = rend->getBuffer()->getNumVertices() - op->vertexData->vertexStart; ROS_ASSERT(op->vertexData->vertexCount + op->vertexData->vertexStart <= rend->getBuffer()->getNumVertices()); vbuf->unlock(); rend->setBoundingBox(aabb); bounding_box_.merge(aabb); } buffer_size = std::min( VERTEX_BUFFER_CAPACITY, (num_points - current_point)*vpp ); rend = createRenderable( buffer_size ); vbuf = rend->getBuffer(); vdata = vbuf->lock(Ogre::HardwareBuffer::HBL_NO_OVERWRITE); op = rend->getRenderOperation(); op->operationType = op_type; current_vertex_count = 0; vertex_size = op->vertexData->vertexDeclaration->getVertexSize(0); fptr = (float*)((uint8_t*)vdata); aabb.setNull(); } const Point& p = points[current_point]; uint32_t color; if (color_by_index_) { // convert to ColourValue, so we can then convert to the rendersystem-specific color type color = (current_point + point_count_ + 1); Ogre::ColourValue c; c.a = 1.0f; c.r = ((color >> 16) & 0xff) / 255.0f; c.g = ((color >> 8) & 0xff) / 255.0f; c.b = (color & 0xff) / 255.0f; root->convertColourValue(c, &color); } else { root->convertColourValue( p.color, &color ); } aabb.merge(p.position); bounding_radius_ = std::max( bounding_radius_, p.position.squaredLength() ); float x = p.position.x; float y = p.position.y; float z = p.position.z; for (uint32_t j = 0; j < vpp; ++j, ++current_vertex_count) { *fptr++ = x; *fptr++ = y; *fptr++ = z; if (!current_mode_supports_geometry_shader_) { *fptr++ = vertices[(j*3)]; *fptr++ = vertices[(j*3) + 1]; *fptr++ = vertices[(j*3) + 2]; } uint32_t* iptr = (uint32_t*)fptr; *iptr = color; ++fptr; ROS_ASSERT((uint8_t*)fptr <= (uint8_t*)vdata + rend->getBuffer()->getNumVertices() * vertex_size); } } op->vertexData->vertexCount = current_vertex_count - op->vertexData->vertexStart; rend->setBoundingBox(aabb); bounding_box_.merge(aabb); ROS_ASSERT(op->vertexData->vertexCount + op->vertexData->vertexStart <= rend->getBuffer()->getNumVertices()); vbuf->unlock(); point_count_ += num_points; shrinkRenderables(); if (getParentSceneNode()) { getParentSceneNode()->needUpdate(); } } void PointCloud::popPoints(uint32_t num_points) { uint32_t vpp = getVerticesPerPoint(); ROS_ASSERT(num_points <= point_count_); points_.erase(points_.begin(), points_.begin() + num_points); point_count_ -= num_points; // Now clear out popped points uint32_t popped_count = 0; while (popped_count < num_points * vpp) { PointCloudRenderablePtr rend = renderables_.front(); Ogre::RenderOperation* op = rend->getRenderOperation(); uint32_t popped = std::min((size_t)(num_points * vpp - popped_count), op->vertexData->vertexCount); op->vertexData->vertexStart += popped; op->vertexData->vertexCount -= popped; popped_count += popped; if (op->vertexData->vertexCount == 0) { renderables_.erase(renderables_.begin(), renderables_.begin() + 1); op->vertexData->vertexStart = 0; renderables_.push_back(rend); } } ROS_ASSERT(popped_count == num_points * vpp); // reset bounds bounding_box_.setNull(); bounding_radius_ = 0.0f; for (uint32_t i = 0; i < point_count_; ++i) { Point& p = points_[i]; bounding_box_.merge(p.position); bounding_radius_ = std::max(bounding_radius_, p.position.squaredLength()); } shrinkRenderables(); if (getParentSceneNode()) { getParentSceneNode()->needUpdate(); } } void PointCloud::shrinkRenderables() { while (!renderables_.empty()) { PointCloudRenderablePtr rend = renderables_.back(); Ogre::RenderOperation* op = rend->getRenderOperation(); if (op->vertexData->vertexCount == 0) { renderables_.pop_back(); } else { break; } } } void PointCloud::_notifyCurrentCamera(Ogre::Camera* camera) { MovableObject::_notifyCurrentCamera( camera ); } void PointCloud::_updateRenderQueue(Ogre::RenderQueue* queue) { V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { queue->addRenderable((*it).get()); } } void PointCloud::_notifyAttached(Ogre::Node *parent, bool isTagPoint) { MovableObject::_notifyAttached(parent, isTagPoint); } uint32_t PointCloud::getVerticesPerPoint() { if (current_mode_supports_geometry_shader_) { return 1; } if (render_mode_ == RM_POINTS) { return 1; } if (render_mode_ == RM_SQUARES) { return 6; } if (render_mode_ == RM_FLAT_SQUARES) { return 6; } if (render_mode_ == RM_TILES) { return 6; } if (render_mode_ == RM_SPHERES) { return 3; } if (render_mode_ == RM_BOXES) { return 36; } return 1; } void PointCloud::setPickColor(const Ogre::ColourValue& color) { pick_color_ = color; Ogre::Vector4 pick_col(pick_color_.r, pick_color_.g, pick_color_.b, pick_color_.a); V_PointCloudRenderable::iterator it = renderables_.begin(); V_PointCloudRenderable::iterator end = renderables_.end(); for (; it != end; ++it) { (*it)->setCustomParameter(PICK_COLOR_PARAMETER, pick_col); } getUserObjectBindings().setUserAny( "pick_handle", Ogre::Any( colorToHandle( color ))); } PointCloudRenderablePtr PointCloud::createRenderable( int num_points ) { PointCloudRenderablePtr rend(new PointCloudRenderable(this, num_points, !current_mode_supports_geometry_shader_)); rend->setMaterial(current_material_->getName()); Ogre::Vector4 size(width_, height_, depth_, 0.0f); Ogre::Vector4 alpha(alpha_, 0.0f, 0.0f, 0.0f); Ogre::Vector4 highlight(0.0f, 0.0f, 0.0f, 0.0f); Ogre::Vector4 pick_col(pick_color_.r, pick_color_.g, pick_color_.b, pick_color_.a); rend->setCustomParameter(SIZE_PARAMETER, size); rend->setCustomParameter(ALPHA_PARAMETER, alpha); rend->setCustomParameter(HIGHLIGHT_PARAMETER, highlight); rend->setCustomParameter(PICK_COLOR_PARAMETER, pick_col); rend->setCustomParameter(NORMAL_PARAMETER, Ogre::Vector4(common_direction_)); rend->setCustomParameter(UP_PARAMETER, Ogre::Vector4(common_up_vector_)); if (getParentSceneNode()) { getParentSceneNode()->attachObject(rend.get()); } renderables_.push_back(rend); return rend; } #if (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) void PointCloud::visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables) { } #endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// PointCloudRenderable::PointCloudRenderable(PointCloud* parent, int num_points, bool use_tex_coords) : parent_(parent) { // Initialize render operation mRenderOp.operationType = Ogre::RenderOperation::OT_POINT_LIST; mRenderOp.useIndexes = false; mRenderOp.vertexData = new Ogre::VertexData; mRenderOp.vertexData->vertexStart = 0; mRenderOp.vertexData->vertexCount = 0; Ogre::VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration; size_t offset = 0; decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); if (use_tex_coords) { decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_TEXTURE_COORDINATES, 0); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); } decl->addElement(0, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( mRenderOp.vertexData->vertexDeclaration->getVertexSize(0), num_points, Ogre::HardwareBuffer::HBU_DYNAMIC); // Bind buffer mRenderOp.vertexData->vertexBufferBinding->setBinding(0, vbuf); } PointCloudRenderable::~PointCloudRenderable() { delete mRenderOp.vertexData; delete mRenderOp.indexData; } Ogre::HardwareVertexBufferSharedPtr PointCloudRenderable::getBuffer() { return mRenderOp.vertexData->vertexBufferBinding->getBuffer(0); } void PointCloudRenderable::_notifyCurrentCamera(Ogre::Camera* camera) { SimpleRenderable::_notifyCurrentCamera( camera ); } Ogre::Real PointCloudRenderable::getBoundingRadius(void) const { return Ogre::Math::Sqrt(std::max(mBox.getMaximum().squaredLength(), mBox.getMinimum().squaredLength())); } Ogre::Real PointCloudRenderable::getSquaredViewDepth(const Ogre::Camera* cam) const { Ogre::Vector3 vMin, vMax, vMid, vDist; vMin = mBox.getMinimum(); vMax = mBox.getMaximum(); vMid = ((vMax - vMin) * 0.5) + vMin; vDist = cam->getDerivedPosition() - vMid; return vDist.squaredLength(); } void PointCloudRenderable::getWorldTransforms(Ogre::Matrix4* xform) const { parent_->getWorldTransforms(xform); } const Ogre::LightList& PointCloudRenderable::getLights() const { return parent_->queryLights(); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/point_cloud.h000066400000000000000000000177701300447110700215310ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_OGRE_POINT_CLOUD_H #define OGRE_TOOLS_OGRE_POINT_CLOUD_H #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Ogre { class SceneManager; class ManualObject; class SceneNode; class RenderQueue; class Camera; class RenderSystem; class Matrix4; } namespace rviz { class PointCloud; class PointCloudRenderable : public Ogre::SimpleRenderable { public: PointCloudRenderable(PointCloud* parent, int num_points, bool use_tex_coords); ~PointCloudRenderable(); Ogre::RenderOperation* getRenderOperation() { return &mRenderOp; } Ogre::HardwareVertexBufferSharedPtr getBuffer(); virtual Ogre::Real getBoundingRadius(void) const; virtual Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const; virtual void _notifyCurrentCamera(Ogre::Camera* camera); virtual unsigned short getNumWorldTransforms() const { return 1; } virtual void getWorldTransforms(Ogre::Matrix4* xform) const; virtual const Ogre::LightList& getLights() const; private: Ogre::MaterialPtr material_; PointCloud* parent_; }; typedef boost::shared_ptr PointCloudRenderablePtr; typedef std::vector V_PointCloudRenderable; /** * \class PointCloud * \brief A visual representation of a set of points. * * Displays a set of points using any number of Ogre BillboardSets. PointCloud is optimized for sets of points that change * rapidly, rather than for large clouds that never change. * * Most of the functions in PointCloud are not safe to call from any thread but the render thread. Exceptions are clear() and addPoints(), which * are safe as long as we are not in the middle of a render (ie. Ogre::Root::renderOneFrame, or Ogre::RenderWindow::update) */ class PointCloud : public Ogre::MovableObject { public: enum RenderMode { RM_POINTS, RM_SQUARES, RM_FLAT_SQUARES, RM_SPHERES, RM_TILES, RM_BOXES, }; PointCloud(); ~PointCloud(); /** * \brief Clear all the points */ void clear(); /** * \struct Point * \brief Representation of a point, with x/y/z position and r/g/b color */ struct Point { inline void setColor(float r, float g, float b, float a=1.0) { color=Ogre::ColourValue(r, g, b, a); } Ogre::Vector3 position; Ogre::ColourValue color; }; /** * \brief Add points to this point cloud * * @param points An array of Point structures * @param num_points The number of points in the array */ void addPoints( Point* points, uint32_t num_points ); /** * \brief Remove a number of points from this point cloud * \param num_points The number of points to pop */ void popPoints( uint32_t num_points ); /** * \brief Set what type of rendering primitives should be used, currently points, billboards and boxes are supported */ void setRenderMode(RenderMode mode); /** * \brief Set the dimensions of the billboards used to render each point * @param width Width * @param height Height * @note width/height are only applicable to billboards and boxes, depth is only applicable to boxes */ void setDimensions( float width, float height, float depth ); /* * If set to true, the size of each point will be multiplied by it z component. * (Used for depth image based point clouds) */ void setAutoSize(bool auto_size); /// See Ogre::BillboardSet::setCommonDirection void setCommonDirection( const Ogre::Vector3& vec ); /// See Ogre::BillboardSet::setCommonUpVector void setCommonUpVector( const Ogre::Vector3& vec ); /// set alpha blending /// @param alpha global alpha value /// @param per_point_alpha indicates that each point will have an individual alpha value. /// if true, enables alpha blending regardless of the global alpha. void setAlpha( float alpha, bool per_point_alpha = false ); void setPickColor(const Ogre::ColourValue& color); void setColorByIndex(bool set); void setHighlightColor( float r, float g, float b ); virtual const Ogre::String& getMovableType() const { return sm_Type; } virtual const Ogre::AxisAlignedBox& getBoundingBox() const; virtual float getBoundingRadius() const; virtual void getWorldTransforms( Ogre::Matrix4* xform ) const; virtual unsigned short getNumWorldTransforms() const { return 1; } virtual void _updateRenderQueue( Ogre::RenderQueue* queue ); virtual void _notifyCurrentCamera( Ogre::Camera* camera ); virtual void _notifyAttached(Ogre::Node *parent, bool isTagPoint=false); #if (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) virtual void visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables); #endif virtual void setName ( const std::string& name ) { mName = name; } private: uint32_t getVerticesPerPoint(); PointCloudRenderablePtr createRenderable( int num_points ); void regenerateAll(); void shrinkRenderables(); Ogre::AxisAlignedBox bounding_box_; ///< The bounding box of this point cloud float bounding_radius_; ///< The bounding radius of this point cloud typedef std::vector V_Point; V_Point points_; ///< The list of points we're displaying. Allocates to a high-water-mark. uint32_t point_count_; ///< The number of points currently in #points_ RenderMode render_mode_; float width_; ///< width float height_; ///< height float depth_; ///< depth Ogre::Vector3 common_direction_; ///< See Ogre::BillboardSet::setCommonDirection Ogre::Vector3 common_up_vector_; ///< See Ogre::BillboardSet::setCommonUpVector Ogre::MaterialPtr point_material_; Ogre::MaterialPtr square_material_; Ogre::MaterialPtr flat_square_material_; Ogre::MaterialPtr sphere_material_; Ogre::MaterialPtr tile_material_; Ogre::MaterialPtr box_material_; Ogre::MaterialPtr current_material_; float alpha_; bool color_by_index_; V_PointCloudRenderable renderables_; bool current_mode_supports_geometry_shader_; Ogre::ColourValue pick_color_; static Ogre::String sm_Type; ///< The "renderable type" used by Ogre }; } // namespace rviz #endif rviz-1.12.4/src/rviz/ogre_helpers/qt_ogre_render_window.cpp000066400000000000000000000225751300447110700241320ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "qt_ogre_render_window.h" #include "orthographic.h" #include "render_system.h" #include #include #include #include #include #include #include #include #include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX #include #endif namespace rviz { QtOgreRenderWindow::QtOgreRenderWindow( QWidget* parent ) : RenderWidget( RenderSystem::get(), parent ) , viewport_( 0 ) , ogre_root_( RenderSystem::get()->root() ) , ortho_scale_( 1.0f ) , auto_render_( true ) , camera_( 0 ) , overlays_enabled_( true ) // matches the default of Ogre::Viewport. , background_color_( Ogre::ColourValue::Black ) // matches the default of Ogre::Viewport. , stereo_enabled_( false ) , rendering_stereo_( false ) , left_camera_( 0 ) , right_camera_( 0 ) , right_viewport_( 0 ) { render_window_->setVisible(true); render_window_->setAutoUpdated(true); viewport_ = render_window_->addViewport( camera_ ); viewport_->setOverlaysEnabled( overlays_enabled_ ); viewport_->setBackgroundColour( background_color_ ); #if OGRE_STEREO_ENABLE viewport_->setDrawBuffer(Ogre::CBT_BACK); #endif enableStereo(true); setCameraAspectRatio(); } QtOgreRenderWindow::~QtOgreRenderWindow() { enableStereo(false); // free stereo resources } //------------------------------------------------------------------------------ bool QtOgreRenderWindow::enableStereo (bool enable) { bool was_enabled = stereo_enabled_; stereo_enabled_ = enable; setupStereo(); return was_enabled; } void QtOgreRenderWindow::setupStereo() { bool render_stereo = stereo_enabled_ && RenderSystem::get()->isStereoSupported(); if (render_stereo == rendering_stereo_) return; rendering_stereo_ = render_stereo; if (rendering_stereo_) { right_viewport_ = render_window_->addViewport( NULL, 1 ); #if OGRE_STEREO_ENABLE right_viewport_->setDrawBuffer(Ogre::CBT_BACK_RIGHT); viewport_->setDrawBuffer(Ogre::CBT_BACK_LEFT); #endif setOverlaysEnabled(overlays_enabled_); setBackgroundColor(background_color_); if (camera_) setCamera(camera_); // addListener causes preViewportUpdate() to be called when rendering. render_window_->addListener(this); } else { render_window_->removeListener(this); render_window_->removeViewport(1); right_viewport_ = NULL; #if OGRE_STEREO_ENABLE viewport_->setDrawBuffer(Ogre::CBT_BACK); #endif if (left_camera_) left_camera_->getSceneManager()->destroyCamera( left_camera_ ); left_camera_ = NULL; if (right_camera_) right_camera_->getSceneManager()->destroyCamera( right_camera_ ); right_camera_ = NULL; } } // this is called just before rendering either viewport when stereo is enabled. void QtOgreRenderWindow::preViewportUpdate( const Ogre::RenderTargetViewportEvent& evt) { Ogre::Viewport* viewport = evt.source; const Ogre::Vector2& offset = camera_->getFrustumOffset(); const Ogre::Vector3 pos = camera_->getPosition(); const Ogre::Vector3 right = camera_->getRight(); const Ogre::Vector3 up = camera_->getUp(); if (viewport == right_viewport_) { if (camera_->getProjectionType() != Ogre::PT_PERSPECTIVE || !right_camera_) { viewport->setCamera( camera_ ); return; } Ogre::Vector3 newpos = pos + right * offset.x + up * offset.y; right_camera_->synchroniseBaseSettingsWith(camera_); right_camera_->setFrustumOffset(-offset); right_camera_->setPosition(newpos); viewport->setCamera(right_camera_); } else if (viewport == viewport_) { if (camera_->getProjectionType() != Ogre::PT_PERSPECTIVE || !left_camera_) { viewport->setCamera( camera_ ); return; } Ogre::Vector3 newpos = pos - right * offset.x - up * offset.y; left_camera_->synchroniseBaseSettingsWith(camera_); left_camera_->setFrustumOffset(offset); left_camera_->setPosition(newpos); viewport->setCamera(left_camera_); } else { ROS_WARN("Begin rendering to unknown viewport."); } } void QtOgreRenderWindow::postViewportUpdate( const Ogre::RenderTargetViewportEvent& evt) { Ogre::Viewport* viewport = evt.source; if (viewport == right_viewport_) { // nothing to do here } else if (viewport == viewport_) { viewport->setCamera(camera_); } else { ROS_WARN("End rendering to unknown viewport."); } if(!right_camera_->isCustomProjectionMatrixEnabled()) { right_camera_->synchroniseBaseSettingsWith(camera_); right_camera_->setFrustumOffset(-camera_->getFrustumOffset()); } right_viewport_->setCamera(right_camera_); } Ogre::Viewport* QtOgreRenderWindow::getViewport () const { return viewport_; } void QtOgreRenderWindow::setCamera( Ogre::Camera* camera ) { if (camera) { camera_ = camera; viewport_->setCamera( camera ); setCameraAspectRatio(); if (camera_ && rendering_stereo_ && !left_camera_) { left_camera_ = camera_->getSceneManager()->createCamera(camera_->getName() + "-left"); } if (camera_ && rendering_stereo_ && !right_camera_) { right_camera_ = camera_->getSceneManager()->createCamera(camera_->getName() + "-right"); } update(); } } void QtOgreRenderWindow::setOverlaysEnabled( bool overlays_enabled ) { overlays_enabled_ = overlays_enabled; viewport_->setOverlaysEnabled( overlays_enabled ); if (right_viewport_) { right_viewport_->setOverlaysEnabled( overlays_enabled ); } } void QtOgreRenderWindow::setBackgroundColor( Ogre::ColourValue background_color ) { background_color_ = background_color; viewport_->setBackgroundColour( background_color ); if (right_viewport_) { right_viewport_->setBackgroundColour( background_color ); } } void QtOgreRenderWindow::setCameraAspectRatio() { if ( camera_ ) { camera_->setAspectRatio( Ogre::Real( width() ) / Ogre::Real( height() ) ); if (right_camera_ ) { right_camera_->setAspectRatio( Ogre::Real( width() ) / Ogre::Real( height() ) ); } if ( camera_->getProjectionType() == Ogre::PT_ORTHOGRAPHIC ) { Ogre::Matrix4 proj; buildScaledOrthoMatrix( proj, -width() / ortho_scale_ / 2, width() / ortho_scale_ / 2, -height() / ortho_scale_ / 2, height() / ortho_scale_ / 2, camera_->getNearClipDistance(), camera_->getFarClipDistance() ); camera_->setCustomProjectionMatrix(true, proj); } } } void QtOgreRenderWindow::setOrthoScale( float scale ) { ortho_scale_ = scale; setCameraAspectRatio(); } void QtOgreRenderWindow::setPreRenderCallback( boost::function func ) { pre_render_callback_ = func; } void QtOgreRenderWindow::setPostRenderCallback( boost::function func ) { post_render_callback_ = func; } //------------------------------------------------------------------------------ void QtOgreRenderWindow::paintEvent( QPaintEvent* e ) { if( auto_render_ && render_window_ ) { if( pre_render_callback_ ) { pre_render_callback_(); } if( ogre_root_->_fireFrameStarted() ) { #if (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) ogre_root_->_fireFrameRenderingQueued(); #endif render_window_->update(); ogre_root_->_fireFrameEnded(); } if ( post_render_callback_ ) { post_render_callback_(); } } } //------------------------------------------------------------------------------ void QtOgreRenderWindow::resizeEvent( QResizeEvent* event ) { RenderWidget::resizeEvent( event ); if( render_window_ ) { setCameraAspectRatio(); if( auto_render_ ) { update(); } } } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/qt_ogre_render_window.h000066400000000000000000000131621300447110700235670ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef QT_OGRE_RENDER_WINDOW_OGRE_RENDER_WINDOW_H_ #define QT_OGRE_RENDER_WINDOW_OGRE_RENDER_WINDOW_H_ #include #include "render_widget.h" #include #include namespace Ogre { class Root; class RenderWindow; class Viewport; class Camera; } namespace rviz { /** Qt Ogre render window widget. Similar in API to * wxOgreRenderWindow from ogre_tools release 1.6, but with much of * the guts replaced by new RenderSystem and RenderWidget classes * inspired by the initialization sequence of Gazebo's renderer. */ class QtOgreRenderWindow : public RenderWidget, public Ogre::RenderTargetListener { public: /** Constructor. @param parent The parent wxWindow component. */ QtOgreRenderWindow( QWidget* parent = 0 ); /** Destructor. */ virtual ~QtOgreRenderWindow(); /** * Set a callback which is called before each render * @param func The callback functor */ virtual void setPreRenderCallback( boost::function func ); /** * Set a callback which is called after each render * @param func The callback functor */ virtual void setPostRenderCallback( boost::function func ); /** Overrides the default implementation. This override is here for convenience. Returns a symbolic 320x240px size. @return A size of 320x240 (just a symbolic 4:3 size). */ virtual QSize sizeHint () const { return QSize( 320, 240 ); } /** Gets the associated Ogre viewport. If this is called before * QWidget::show() on this widget, it will fail an assertion. * Several functions of Ogre::Viewport are duplicated in this class * which can be called before QWidget::show(), and their effects are * propagated to the viewport when it is created. */ Ogre::Viewport* getViewport() const; /** Set the camera associated with this render window's viewport. */ void setCamera( Ogre::Camera* camera ); Ogre::Camera* getCamera() const { return camera_; } /** * \brief Set the scale of the orthographic window. Only valid for an orthographic camera. * @param scale The scale */ void setOrthoScale( float scale ); /** \brief Enable or disable stereo rendering * If stereo is not supported this is ignored. * @return the old setting (whether stereo was enabled before) */ bool enableStereo(bool enable); /** \brief Prepare to render in stereo if enabled and supported. */ void setupStereo(); void setAutoRender(bool auto_render) { auto_render_ = auto_render; } ////// Functions mimicked from Ogre::Viewport to satisfy timing of ////// after-constructor creation of Ogre::RenderWindow. void setOverlaysEnabled( bool overlays_enabled ); void setBackgroundColor( Ogre::ColourValue color ); protected: virtual void paintEvent( QPaintEvent* e ); virtual void resizeEvent( QResizeEvent* event ); // When stereo is enabled, these are called before/after rendering each // viewport. virtual void preViewportUpdate(const Ogre::RenderTargetViewportEvent& evt); virtual void postViewportUpdate(const Ogre::RenderTargetViewportEvent& evt); /** * Sets the aspect ratio on the camera */ void setCameraAspectRatio(); /** * prepare a viewport's camera for stereo rendering. * This should only be called from StereoRenderTargetListener */ void prepareStereoViewport(Ogre::Viewport*); Ogre::Viewport* viewport_; Ogre::Root* ogre_root_; boost::function pre_render_callback_; ///< Functor which is called before each render boost::function post_render_callback_; ///< Functor which is called after each render float ortho_scale_; bool auto_render_; Ogre::Camera* camera_; bool overlays_enabled_; Ogre::ColourValue background_color_; // stereo rendering bool stereo_enabled_; // true if we were asked to render stereo bool rendering_stereo_; // true if we are actually rendering stereo Ogre::Camera* left_camera_; Ogre::Camera* right_camera_; Ogre::Viewport* right_viewport_; }; } // namespace rviz #endif // QT_OGRE_RENDER_WINDOW_OGRE_RENDER_WINDOW_H_ rviz-1.12.4/src/rviz/ogre_helpers/render_system.cpp000066400000000000000000000357741300447110700224340ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include // This is required for QT_MAC_USE_COCOA to be set #include #ifndef Q_OS_MAC #include #include #include #endif // X.h #defines CursorShape to be "0". Qt uses CursorShape in normal // C++ way. This wasn't an issue until ogre_logging.h (below) // introduced a #include of . #ifdef CursorShape #undef CursorShape #endif #include // This dependency should be moved out of here, it is just used for a search path. #include #include #include #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 ) #include #endif #include "rviz/env_config.h" #include "rviz/ogre_helpers/ogre_logging.h" #include "rviz/ogre_helpers/render_system.h" #include namespace rviz { RenderSystem* RenderSystem::instance_ = 0; int RenderSystem::force_gl_version_ = 0; bool RenderSystem::use_anti_aliasing_ = true; bool RenderSystem::force_no_stereo_ = false; RenderSystem* RenderSystem::get() { if( instance_ == 0 ) { instance_ = new RenderSystem(); } return instance_; } void RenderSystem::forceGlVersion( int version ) { force_gl_version_ = version; ROS_INFO_STREAM( "Forcing OpenGl version " << (float)version / 100.0 << "." ); } void RenderSystem::disableAntiAliasing() { use_anti_aliasing_ = false; ROS_INFO("Disabling Anti-Aliasing"); } void RenderSystem::forceNoStereo() { force_no_stereo_ = true; ROS_INFO("Forcing Stereo OFF"); } RenderSystem::RenderSystem() : ogre_overlay_system_(NULL) , stereo_supported_(false) { OgreLogging::configureLogging(); std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME); setupDummyWindowId(); ogre_root_ = new Ogre::Root( rviz_path+"/ogre_media/plugins.cfg" ); #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 ) ogre_overlay_system_ = new Ogre::OverlaySystem(); #endif loadOgrePlugins(); setupRenderSystem(); ogre_root_->initialise(false); makeRenderWindow( dummy_window_id_, 1, 1 ); detectGlVersion(); setupResources(); Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); } void RenderSystem::prepareOverlays(Ogre::SceneManager* scene_manager) { #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 ) if (ogre_overlay_system_) scene_manager->addRenderQueueListener(ogre_overlay_system_); #endif } void RenderSystem::setupDummyWindowId() { #ifdef Q_OS_MAC dummy_window_id_ = 0; #else Display *display = XOpenDisplay(0); assert( display ); int screen = DefaultScreen( display ); int attribList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 8, None }; XVisualInfo *visual = glXChooseVisual( display, screen, (int*)attribList ); dummy_window_id_ = XCreateSimpleWindow( display, RootWindow( display, screen ), 0, 0, 1, 1, 0, 0, 0 ); GLXContext context = glXCreateContext( display, visual, NULL, 1 ); glXMakeCurrent( display, dummy_window_id_, context ); #endif } void RenderSystem::loadOgrePlugins() { std::string plugin_prefix = get_ogre_plugin_path() + "/"; #ifdef Q_OS_MAC plugin_prefix += "lib"; #endif ogre_root_->loadPlugin( plugin_prefix + "RenderSystem_GL" ); ogre_root_->loadPlugin( plugin_prefix + "Plugin_OctreeSceneManager" ); ogre_root_->loadPlugin( plugin_prefix + "Plugin_ParticleFX" ); } void RenderSystem::detectGlVersion() { if ( force_gl_version_ ) { gl_version_ = force_gl_version_; } else { Ogre::RenderSystem *renderSys = ogre_root_->getRenderSystem(); renderSys->createRenderSystemCapabilities(); const Ogre::RenderSystemCapabilities* caps = renderSys->getCapabilities(); int major = caps->getDriverVersion().major; int minor = caps->getDriverVersion().minor; gl_version_ = major * 100 + minor*10; } switch ( gl_version_ ) { case 200: glsl_version_ = 110; break; case 210: glsl_version_ = 120; break; case 300: glsl_version_ = 130; break; case 310: glsl_version_ = 140; break; case 320: glsl_version_ = 150; break; default: if ( gl_version_ > 320 ) { glsl_version_ = gl_version_; } else { glsl_version_ = 0; } break; } ROS_INFO_STREAM( "OpenGl version: " << (float)gl_version_ / 100.0 << " (GLSL " << (float)glsl_version_ / 100.0 << ")." ); } void RenderSystem::setupRenderSystem() { Ogre::RenderSystem *renderSys; const Ogre::RenderSystemList *rsList; // Get the list of available renderers. #if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 6 rsList = ogre_root_->getAvailableRenderers(); #else rsList = &(ogre_root_->getAvailableRenderers()); #endif // Look for the OpenGL one, which we require. renderSys = NULL; for( unsigned int i = 0; i < rsList->size(); i++ ) { renderSys = rsList->at( i ); if( renderSys->getName().compare("OpenGL Rendering Subsystem")== 0 ) { break; } } if( renderSys == NULL ) { throw std::runtime_error( "Could not find the opengl rendering subsystem!\n" ); } // We operate in windowed mode renderSys->setConfigOption("Full Screen","No"); /// We used to allow the user to set the RTT mode to PBuffer, FBO, or Copy. /// Copy is slow, and there doesn't seem to be a good reason to use it /// PBuffer limits the size of the renderable area of the RTT to the /// size of the first window created. /// FBO seem to be the only good option // renderSys->setConfigOption("RTT Preferred Mode", "FBO"); // Set the Full Screen Anti-Aliasing factor. if (use_anti_aliasing_) { renderSys->setConfigOption("FSAA", "4"); } ogre_root_->setRenderSystem(renderSys); } void RenderSystem::setupResources() { std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/textures", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/fonts", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/models", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl120", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl120/nogp", "FileSystem", ROS_PACKAGE_NAME ); // Add resources that depend on a specific glsl version. // Unfortunately, Ogre doesn't have a notion of glsl versions so we can't go // the 'official' way of defining multiple schemes per material and let Ogre decide which one to use. if ( getGlslVersion() >= 150 ) { Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl150", "FileSystem", ROS_PACKAGE_NAME ); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts150", "FileSystem", ROS_PACKAGE_NAME ); } else if ( getGlslVersion() >= 120 ) { Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts120", "FileSystem", ROS_PACKAGE_NAME ); } else { std::string s = "Your graphics driver does not support OpenGL 2.1. Please enable software rendering before running RViz (e.g. type 'export LIBGL_ALWAYS_SOFTWARE=1')."; QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); throw std::runtime_error( s ); } // Add paths exported to the "media_export" package. std::vector media_paths; ros::package::getPlugins( "media_export", "ogre_media_path", media_paths ); std::string delim(":"); for( std::vector::iterator iter = media_paths.begin(); iter != media_paths.end(); ++iter ) { if( !iter->empty() ) { std::string path; int pos1 = 0; int pos2 = iter->find(delim); while( pos2 != (int)std::string::npos ) { path = iter->substr( pos1, pos2 - pos1 ); ROS_DEBUG("adding resource location: '%s'\n", path.c_str()); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( path, "FileSystem", ROS_PACKAGE_NAME ); pos1 = pos2 + 1; pos2 = iter->find( delim, pos2 + 1 ); } path = iter->substr( pos1, iter->size() - pos1 ); ROS_DEBUG("adding resource location: '%s'\n", path.c_str()); Ogre::ResourceGroupManager::getSingleton().addResourceLocation( path, "FileSystem", ROS_PACKAGE_NAME ); } } } // On Intel graphics chips under X11, there sometimes comes a // BadDrawable error during Ogre render window creation. It is not // consistent, happens sometimes but not always. Underlying problem // seems to be a driver bug. My workaround here is to notice when // that specific BadDrawable error happens on request 136 minor 3 // (which is what the problem looks like when it happens) and just try // over and over again until it works (or until 100 failures, which // makes it seem like it is a different bug). static bool x_baddrawable_error = false; #ifdef Q_WS_X11 static int (*old_error_handler)( Display*, XErrorEvent* ); int checkBadDrawable( Display* display, XErrorEvent* error ) { if( error->error_code == BadDrawable && error->request_code == 136 && error->minor_code == 3 ) { x_baddrawable_error = true; return 0; } else { // If the error does not exactly match the one from the driver bug, // handle it the normal way so we see it. return old_error_handler( display, error ); } } #endif // Q_WS_X11 Ogre::RenderWindow* RenderSystem::makeRenderWindow( intptr_t window_id, unsigned int width, unsigned int height ) { static int windowCounter = 0; // Every RenderWindow needs a unique name, oy. Ogre::NameValuePairList params; Ogre::RenderWindow *window = NULL; std::stringstream window_handle_stream; window_handle_stream << window_id; #ifdef Q_OS_MAC params["externalWindowHandle"] = window_handle_stream.str(); #else params["parentWindowHandle"] = window_handle_stream.str(); #endif params["externalGLControl"] = true; // Enable antialiasing if (use_anti_aliasing_) { params["FSAA"] = "4"; } // Set the macAPI for Ogre based on the Qt implementation #ifdef QT_MAC_USE_COCOA params["macAPI"] = "cocoa"; params["macAPICocoaUseNSView"] = "true"; #else params["macAPI"] = "carbon"; #endif std::ostringstream stream; stream << "OgreWindow(" << windowCounter++ << ")"; // don't bother trying stereo if Ogre does not support it. #if !OGRE_STEREO_ENABLE force_no_stereo_ = true; #endif // attempt to create a stereo window bool is_stereo = false; if (!force_no_stereo_) { params["stereoMode"] = "Frame Sequential"; window = tryMakeRenderWindow( stream.str(), width, height, ¶ms, 100); params.erase("stereoMode"); if (window) { #if OGRE_STEREO_ENABLE is_stereo = window->isStereoEnabled(); #endif if (!is_stereo) { // Created a non-stereo window. Discard it and try again (below) // without the stereo parameter. ogre_root_->detachRenderTarget(window); window->destroy(); window = NULL; stream << "x"; is_stereo = false; } } } if ( window == NULL ) { window = tryMakeRenderWindow( stream.str(), width, height, ¶ms, 100); } if( window == NULL ) { ROS_ERROR( "Unable to create the rendering window after 100 tries." ); assert(false); } if (window) { window->setActive(true); //window->setVisible(true); window->setAutoUpdated(false); } stereo_supported_ = is_stereo; ROS_INFO_ONCE("Stereo is %s", stereo_supported_ ? "SUPPORTED" : "NOT SUPPORTED"); return window; } Ogre::RenderWindow* RenderSystem::tryMakeRenderWindow( const std::string& name, unsigned int width, unsigned int height, const Ogre::NameValuePairList* params, int max_attempts ) { Ogre::RenderWindow *window = NULL; int attempts = 0; #ifdef Q_WS_X11 old_error_handler = XSetErrorHandler( &checkBadDrawable ); #endif while (window == NULL && (attempts++) < max_attempts) { try { window = ogre_root_->createRenderWindow( name, width, height, false, params ); // If the driver bug happened, tell Ogre we are done with that // window and then try again. if( x_baddrawable_error ) { ogre_root_->detachRenderTarget( window ); window = NULL; x_baddrawable_error = false; } } catch( const std::exception & ex ) { std::cerr << "rviz::RenderSystem: error creating render window: " << ex.what() << std::endl; window = NULL; } } #ifdef Q_WS_X11 XSetErrorHandler( old_error_handler ); #endif if( window && attempts > 1 ) { ROS_INFO( "Created render window after %d attempts.", attempts ); } return window; } } // end namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/render_system.h000066400000000000000000000073521300447110700220700ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RENDER_SYSTEM_H #define RENDER_SYSTEM_H #include #include namespace Ogre { class OverlaySystem; class SceneManager; } namespace rviz { class RenderSystem { public: static RenderSystem* get(); Ogre::RenderWindow* makeRenderWindow( intptr_t window_id, unsigned int width, unsigned int height ); Ogre::Root* root() { return ogre_root_; } // Prepare a scene_manager to render overlays. // Needed for Ogre >= 1.9 to use fonts; does nothing for prior versions. void prepareOverlays(Ogre::SceneManager* scene_manager); // @brief return OpenGl Version as integer, e.g. 320 for OpenGl 3.20 int getGlVersion() { return gl_version_; } // @brief return GLSL Version as integer, e.g. 150 for GLSL 1.50 int getGlslVersion() { return glsl_version_; } // @brief Disables the use of Anti Aliasing static void disableAntiAliasing(); // @brief Force to use the provided OpenGL version on startup static void forceGlVersion( int version ); // @brief Disable stereo rendering even if supported in HW. static void forceNoStereo(); // @brief True if we can render stereo on this device. bool isStereoSupported() { return stereo_supported_; } private: RenderSystem(); void setupDummyWindowId(); void loadOgrePlugins(); // helper for makeRenderWindow() Ogre::RenderWindow* tryMakeRenderWindow(const std::string& name, unsigned int width, unsigned int height, const Ogre::NameValuePairList* params, int max_attempts); // Find and configure the render system. void setupRenderSystem(); void setupResources(); void detectGlVersion(); static RenderSystem* instance_; // ID for a dummy window of size 1x1, used to keep Ogre happy. unsigned long dummy_window_id_; Ogre::Root* ogre_root_; Ogre::OverlaySystem* ogre_overlay_system_; int gl_version_; int glsl_version_; static bool use_anti_aliasing_; static int force_gl_version_; bool stereo_supported_; static bool force_no_stereo_; }; } // end namespace rviz #endif // RENDER_SYSTEM_H rviz-1.12.4/src/rviz/ogre_helpers/render_widget.cpp000066400000000000000000000101511300447110700223510ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ogre_helpers/render_widget.h" #include "ogre_helpers/render_system.h" #include #include #include #include #include #include #include namespace rviz { RenderWidget::RenderWidget( RenderSystem* render_system, QWidget *parent ) : QWidget( parent ) , render_system_( render_system ) , render_window_( 0 ) { setAttribute(Qt::WA_OpaquePaintEvent,true); setAttribute(Qt::WA_PaintOnScreen,true); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) // It is not clear to me why, but having this frame sub-widget // inside the main widget makes an important difference (under X at // least). Without the frame and using this widget's winId() // below causes trouble when using RenderWidget as a child // widget. The frame graphics are completely covered up by the 3D // render, so using it does not affect the appearance at all. this->renderFrame = new QFrame; this->renderFrame->setLineWidth(1); this->renderFrame->setFrameShadow(QFrame::Sunken); this->renderFrame->setFrameShape(QFrame::Box); this->renderFrame->show(); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->setContentsMargins( 0, 0, 0, 0 ); mainLayout->addWidget(this->renderFrame); this->setLayout(mainLayout); #endif #ifdef Q_OS_MAC uintptr_t win_id = winId(); #else # if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) unsigned int win_id = renderFrame->winId(); # else unsigned int win_id = winId(); # endif #endif QApplication::flush(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QApplication::syncX(); #endif render_window_ = render_system_->makeRenderWindow( win_id, width(), height() ); } RenderWidget::~RenderWidget() { if( render_window_ ) { render_window_->removeViewport( 0 ); render_window_->destroy(); } render_window_ = 0; } void RenderWidget::moveEvent(QMoveEvent *e) { QWidget::moveEvent(e); if(e->isAccepted() && render_window_) { render_window_->windowMovedOrResized(); } } void RenderWidget::paintEvent(QPaintEvent *e) { if( render_window_ ) { render_window_->update(); } e->accept(); } void RenderWidget::resizeEvent(QResizeEvent *e) { if( render_window_ ) { // render_window_->writeContentsToFile() (used in // VisualizationFrame::onSaveImage()) does not work right for // window with an odd width, so here I just always force it to be // even. render_window_->resize( width() + (width() % 2), height() ); render_window_->windowMovedOrResized(); } } } // end namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/render_widget.h000066400000000000000000000045111300447110700220210ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RENDER_WIDGET_H #define RENDER_WIDGET_H #include #include namespace Ogre { class RenderWindow; } namespace rviz { class RenderSystem; class RenderWidget: public QWidget { public: RenderWidget( RenderSystem* render_system, QWidget *parent = 0 ); virtual ~RenderWidget(); Ogre::RenderWindow* getRenderWindow() { return render_window_; } protected: virtual void moveEvent(QMoveEvent *e); virtual void paintEvent(QPaintEvent *e); virtual void resizeEvent(QResizeEvent *e); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) QPaintEngine *paintEngine() const { return 0; } #endif RenderSystem* render_system_; Ogre::RenderWindow* render_window_; QFrame* renderFrame; }; } // end namespace rviz #endif // RENDER_WIDGET_H rviz-1.12.4/src/rviz/ogre_helpers/shape.cpp000066400000000000000000000122161300447110700206330ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "shape.h" #include #include #include #include #include #include #include #include #include #include namespace rviz { Ogre::Entity* Shape::createEntity(const std::string& name, Type type, Ogre::SceneManager* scene_manager) { if (type == Mesh) return NULL; // the entity is initialized after the vertex data was specified std::string mesh_name; switch (type) { case Cone: mesh_name = "rviz_cone.mesh"; break; case Cube: mesh_name = "rviz_cube.mesh"; break; case Cylinder: mesh_name = "rviz_cylinder.mesh"; break; case Sphere: mesh_name = "rviz_sphere.mesh"; break; default: ROS_BREAK(); } return scene_manager->createEntity(name, mesh_name); } Shape::Shape( Type type, Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ) : Object( scene_manager ) , type_(type) { static uint32_t count = 0; std::stringstream ss; ss << "Shape" << count++; entity_ = createEntity(ss.str(), type, scene_manager); if ( !parent_node ) { parent_node = scene_manager_->getRootSceneNode(); } scene_node_ = parent_node->createChildSceneNode(); offset_node_ = scene_node_->createChildSceneNode(); if (entity_) offset_node_->attachObject( entity_ ); ss << "Material"; material_name_ = ss.str(); material_ = Ogre::MaterialManager::getSingleton().create( material_name_, ROS_PACKAGE_NAME ); material_->setReceiveShadows(false); material_->getTechnique(0)->setLightingEnabled(true); material_->getTechnique(0)->setAmbient( 0.5, 0.5, 0.5 ); if (entity_) entity_->setMaterialName(material_name_); #if (OGRE_VERSION_MAJOR <= 1 && OGRE_VERSION_MINOR <= 4) if (entity_) entity_->setNormaliseNormals(true); #endif } Shape::~Shape() { scene_manager_->destroySceneNode( scene_node_->getName() ); scene_manager_->destroySceneNode( offset_node_->getName() ); if (entity_) scene_manager_->destroyEntity( entity_ ); material_->unload(); Ogre::MaterialManager::getSingleton().remove(material_->getName()); } void Shape::setColor(const Ogre::ColourValue& c) { material_->getTechnique(0)->setAmbient( c * 0.5 ); material_->getTechnique(0)->setDiffuse( c ); if ( c.a < 0.9998 ) { material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); material_->getTechnique(0)->setDepthWriteEnabled( false ); } else { material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE ); material_->getTechnique(0)->setDepthWriteEnabled( true ); } } void Shape::setColor( float r, float g, float b, float a ) { setColor(Ogre::ColourValue(r, g, b, a)); } void Shape::setOffset( const Ogre::Vector3& offset ) { offset_node_->setPosition( offset ); } void Shape::setPosition( const Ogre::Vector3& position ) { scene_node_->setPosition( position ); } void Shape::setOrientation( const Ogre::Quaternion& orientation ) { scene_node_->setOrientation( orientation ); } void Shape::setScale( const Ogre::Vector3& scale ) { scene_node_->setScale( scale ); } const Ogre::Vector3& Shape::getPosition() { return scene_node_->getPosition(); } const Ogre::Quaternion& Shape::getOrientation() { return scene_node_->getOrientation(); } void Shape::setUserData( const Ogre::Any& data ) { if (entity_) entity_->getUserObjectBindings().setUserAny( data ); else ROS_ERROR("Shape not yet fully constructed. Cannot set user data. Did you add triangles to the mesh already?"); } } // namespace rviz rviz-1.12.4/src/rviz/ogre_helpers/shape.h000066400000000000000000000073171300447110700203060ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_SHAPE_H #define OGRE_TOOLS_SHAPE_H #include "object.h" #include #include #include namespace Ogre { class SceneManager; class SceneNode; class Any; class Entity; } namespace rviz { /** */ class Shape : public Object { public: enum Type { Cone, Cube, Cylinder, Sphere, Mesh, }; /** * \brief Constructor * * @param scene_manager The scene manager this object is associated with * @param parent_node A scene node to use as the parent of this object. If NULL, uses the root scene node. */ Shape(Type shape_type, Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node = NULL); virtual ~Shape(); Type getType() { return type_; } /** * \brief Set the offset for this shape * * The default is no offset, which puts the pivot point directly in the center of the object. * * @param offset Amount to offset the center of the object from the pivot point */ void setOffset( const Ogre::Vector3& offset ); virtual void setColor( float r, float g, float b, float a ); void setColor( const Ogre::ColourValue& c ); virtual void setPosition( const Ogre::Vector3& position ); virtual void setOrientation( const Ogre::Quaternion& orientation ); virtual void setScale( const Ogre::Vector3& scale ); virtual const Ogre::Vector3& getPosition(); virtual const Ogre::Quaternion& getOrientation(); /** * \brief Get the root scene node (pivot node) for this object * * @return The root scene node of this object */ Ogre::SceneNode* getRootNode() { return scene_node_; } /** * \brief Sets user data on all ogre objects we own */ void setUserData( const Ogre::Any& data ); Ogre::Entity* getEntity() { return entity_; } Ogre::MaterialPtr getMaterial() { return material_; } static Ogre::Entity* createEntity(const std::string& name, Type shape_type, Ogre::SceneManager* scene_manager); protected: Ogre::SceneNode* scene_node_; Ogre::SceneNode* offset_node_; Ogre::Entity* entity_; Ogre::MaterialPtr material_; std::string material_name_; Type type_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/ogre_helpers/stl_loader.cpp000066400000000000000000000232301300447110700216610ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "stl_loader.h" #include #include namespace ogre_tools { STLLoader::STLLoader() { } STLLoader::~STLLoader() { } bool STLLoader::load(const std::string& path) { FILE* input = fopen( path.c_str(), "r" ); if ( !input ) { ROS_ERROR( "Could not open '%s' for read", path.c_str() ); return false; } /* from wikipedia: * Because ASCII STL files can become very large, a binary version of STL exists. A binary STL file has an 80 character header * (which is generally ignored - but which should never begin with 'solid' because that will lead most software to assume that * this is an ASCII STL file). Following the header is a 4 byte unsigned integer indicating the number of triangular facets in * the file. Following that is data describing each triangle in turn. The file simply ends after the last triangle. * * Each triangle is described by twelve 32-bit-floating point numbers: three for the normal and then three for the X/Y/Z coordinate * of each vertex - just as with the ASCII version of STL. After the twelve floats there is a two byte unsigned 'short' integer that * is the 'attribute byte count' - in the standard format, this should be zero because most software does not understand anything else. * * Floating point numbers are represented as IEEE floating point numbers and the endianness is assumed to be little endian although this * is not stated in documentation. */ // find the file size fseek( input, 0, SEEK_END ); long fileSize = ftell( input ); rewind( input ); std::vector buffer_vec(fileSize); uint8_t* buffer = &buffer_vec[0]; long num_bytes_read = fread( buffer, 1, fileSize, input ); if ( num_bytes_read != fileSize ) { ROS_ERROR("STLLoader::load( \"%s\" ) only read %ld bytes out of total %ld.", path.c_str(), num_bytes_read, fileSize); fclose( input ); return false; } fclose( input ); return this->load(buffer, num_bytes_read, path); } bool STLLoader::load(uint8_t* buffer, const size_t num_bytes, const std::string& origin) { // check for ascii since we can only load binary types with this class std::string buffer_str = std::string(reinterpret_cast(buffer), num_bytes); if (buffer_str.substr(0, 5) == std::string("solid")) { // file says that it is ascii, but why should we trust it? // check for "endsolid" as well if (buffer_str.find("endsolid", 5) != std::string::npos) { ROS_ERROR_STREAM("The STL file '" << origin << "' is malformed. It " "starts with the word 'solid' and also contains the " "word 'endsolid', indicating that it's an ASCII STL " "file, but rviz can only load binary STL files so it " "will not be loaded. Please convert it to a " "binary STL file."); return false; } // chastise the user for malformed files ROS_WARN_STREAM("The STL file '" << origin << "' is malformed. It starts " "with the word 'solid', indicating that it's an ASCII " "STL file, but it does not contain the word 'endsolid' so " "it is either a malformed ASCII STL file or it is actually " "a binary STL file. Trying to interpret it as a binary " "STL file instead."); } // make sure there's enough data for a binary STL header and triangle count static const size_t binary_stl_header_len = 84; if (num_bytes <= binary_stl_header_len) { ROS_ERROR_STREAM("The STL file '" << origin << "' is malformed. It " "appears to be a binary STL file but does not contain " "enough data for the 80 byte header and 32-bit integer " "triangle count."); return false; } // one last check to make sure that the size matches the number of triangles unsigned int num_triangles = *(reinterpret_cast(buffer + 80)); static const size_t number_of_bytes_per_triangle = 50; size_t expected_size = binary_stl_header_len + num_triangles * number_of_bytes_per_triangle; if (num_bytes < expected_size) { ROS_ERROR_STREAM("The STL file '" << origin << "' is malformed. According " "to the binary STL header it should have '" << num_triangles << "' triangles, but it has too little" << " data for that to be the case."); return false; } else if (num_bytes > expected_size) { ROS_WARN_STREAM("The STL file '" << origin << "' is malformed. According " "to the binary STL header it should have '" << num_triangles << "' triangles, but it has too much" << " data for that to be the case. The extra data will be" << " ignored."); } // load the binary STL data return this->load_binary(buffer); } bool STLLoader::load_binary(uint8_t* buffer) { uint8_t* pos = buffer; pos += 80; // skip the 80 byte header unsigned int numTriangles = *(unsigned int*)pos; pos += 4; for ( unsigned int currentTriangle = 0; currentTriangle < numTriangles; ++currentTriangle ) { Triangle tri; tri.normal_.x = *(float*)pos; pos += 4; tri.normal_.y = *(float*)pos; pos += 4; tri.normal_.z = *(float*)pos; pos += 4; tri.vertices_[0].x = *(float*)pos; pos += 4; tri.vertices_[0].y = *(float*)pos; pos += 4; tri.vertices_[0].z = *(float*)pos; pos += 4; tri.vertices_[1].x = *(float*)pos; pos += 4; tri.vertices_[1].y = *(float*)pos; pos += 4; tri.vertices_[1].z = *(float*)pos; pos += 4; tri.vertices_[2].x = *(float*)pos; pos += 4; tri.vertices_[2].y = *(float*)pos; pos += 4; tri.vertices_[2].z = *(float*)pos; pos += 4; // Blender was writing a large number into this short... am I misinterpreting what the attribute byte count is supposed to do? //unsigned short attributeByteCount = *(unsigned short*)pos; pos += 2; //pos += attributeByteCount; if (tri.normal_.squaredLength() < 0.001) { Ogre::Vector3 side1 = tri.vertices_[0] - tri.vertices_[1]; Ogre::Vector3 side2 = tri.vertices_[1] - tri.vertices_[2]; tri.normal_ = side1.crossProduct(side2); } tri.normal_.normalise(); triangles_.push_back(tri); } return true; } void calculateUV(const Ogre::Vector3& vec, float& u, float& v) { Ogre::Vector3 pos(vec); pos.normalise(); u = acos( pos.y / pos.length() ); float val = pos.x / ( sin( u ) ); v = acos( val ); u /= Ogre::Math::PI; v /= Ogre::Math::PI; } Ogre::MeshPtr STLLoader::toMesh(const std::string& name) { Ogre::ManualObject* object = new Ogre::ManualObject( "the one and only" ); object->begin( "BaseWhiteNoLighting", Ogre::RenderOperation::OT_TRIANGLE_LIST ); unsigned int vertexCount = 0; V_Triangle::const_iterator it = triangles_.begin(); V_Triangle::const_iterator end = triangles_.end(); for (; it != end; ++it ) { if( vertexCount >= 2004 ) { // Subdivide large meshes into submeshes with at most 2004 // vertices to prevent problems on some graphics cards. object->end(); object->begin( "BaseWhiteNoLighting", Ogre::RenderOperation::OT_TRIANGLE_LIST ); vertexCount = 0; } const STLLoader::Triangle& tri = *it; float u, v; u = v = 0.0f; object->position( tri.vertices_[0] ); object->normal( tri.normal_); calculateUV( tri.vertices_[0], u, v ); object->textureCoord( u, v ); object->position( tri.vertices_[1] ); object->normal( tri.normal_); calculateUV( tri.vertices_[1], u, v ); object->textureCoord( u, v ); object->position( tri.vertices_[2] ); object->normal( tri.normal_); calculateUV( tri.vertices_[2], u, v ); object->textureCoord( u, v ); object->triangle( vertexCount + 0, vertexCount + 1, vertexCount + 2 ); vertexCount += 3; } object->end(); Ogre::MeshPtr mesh = object->convertToMesh( name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); mesh->buildEdgeList(); delete object; return mesh; } } rviz-1.12.4/src/rviz/ogre_helpers/stl_loader.h000066400000000000000000000043631300447110700213340ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OGRE_TOOLS_STL_LOADER_H #define OGRE_TOOLS_STL_LOADER_H #include #include #include #include namespace ogre_tools { class STLLoader { public: STLLoader(); ~STLLoader(); bool load(const std::string& path); bool load(uint8_t* buffer, const size_t num_bytes, const std::string& origin); Ogre::MeshPtr toMesh(const std::string& name); struct Triangle { Ogre::Vector3 vertices_[3]; Ogre::Vector3 normal_; }; typedef std::vector V_Triangle; V_Triangle triangles_; protected: //! Load a binary STL file bool load_binary(uint8_t* buffer); }; } #endif // OGRE_TOOLS_STL_LOADER_H rviz-1.12.4/src/rviz/panel.cpp000066400000000000000000000041451300447110700161560ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "panel.h" namespace rviz { Panel::Panel( QWidget* parent ) : QWidget( parent ) { } Panel::~Panel() { } void Panel::initialize( VisualizationManager* manager ) { vis_manager_ = manager; onInitialize(); } void Panel::save( Config config ) const { config.mapSetValue( "Class", getClassId() ); config.mapSetValue( "Name", getName() ); } void Panel::load( const Config& config ) { QString name; if( config.mapGetString( "Name", &name )) { setName( name ); } } } // end namespace rviz rviz-1.12.4/src/rviz/panel.h000066400000000000000000000073031300447110700156220ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_PANEL_H #define RVIZ_PANEL_H #include #include "rviz/config.h" namespace rviz { class VisualizationManager; class Panel: public QWidget { Q_OBJECT public: Panel( QWidget* parent = 0 ); virtual ~Panel(); /** Initialize the panel with a VisualizationManager. Called by * VisualizationFrame during setup. */ void initialize( VisualizationManager* manager ); /** * Override to do initialization which depends on the * VisualizationManager being available. This base implementation * does nothing. */ virtual void onInitialize() {} virtual QString getName() const { return name_; } virtual void setName( const QString& name ) { name_ = name; } /** @brief Return a description of this Panel. */ virtual QString getDescription() const { return description_; } /** @brief Set a description of this Panel. Called by the factory which creates it. */ virtual void setDescription( const QString& description ) { description_ = description; } /** @brief Return the class identifier which was used to create this * instance. This version just returns whatever was set with * setClassId(). */ virtual QString getClassId() const { return class_id_; } /** @brief Set the class identifier used to create this instance. * Typically this will be set by the factory object which created it. */ virtual void setClassId( const QString& class_id ) { class_id_ = class_id; } /** @brief Override to load configuration data. This version loads the name of the panel. */ virtual void load( const Config& config ); /** @brief Override to save configuration data. This version saves the name and class ID of the panel. */ virtual void save( Config config ) const; Q_SIGNALS: /** @brief Subclasses must emit this whenever a configuration change * happens. * * This is used to let the system know that changes have been made * since the last time the config was saved. */ void configChanged(); protected: VisualizationManager* vis_manager_; private: QString class_id_; QString name_; QString description_; }; } // end namespace rviz #endif // RVIZ_PANEL_H rviz-1.12.4/src/rviz/panel_dock_widget.cpp000066400000000000000000000101331300447110700205130ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "rviz/panel_dock_widget.h" namespace rviz { PanelDockWidget::PanelDockWidget( const QString& name ) : QDockWidget( name ) , collapsed_(false) { QWidget *title_bar = new QWidget(this); QPalette pal(palette()); pal.setColor(QPalette::Background, QColor( 200,200,200 ) ); title_bar->setAutoFillBackground(true); title_bar->setPalette(pal); title_bar->setContentsMargins(0,0,0,0); QToolButton *close_button = new QToolButton(); close_button->setIcon(QIcon::fromTheme("window-close")); close_button->setIconSize( QSize(10,10) ); connect( close_button, SIGNAL( clicked() ), this, SLOT(close()) ); title_label_ = new QLabel( name, this ); icon_label_ = new QLabel( this ); icon_label_->setContentsMargins(2,2,0,0); setIcon( QIcon() ); QHBoxLayout *title_layout = new QHBoxLayout(); title_layout->setContentsMargins(2,2,2,2); title_layout->addWidget( icon_label_, 0 ); title_layout->addWidget( title_label_, 1 ); title_layout->addWidget( close_button, 0 ); title_bar->setLayout(title_layout); setTitleBarWidget( title_bar ); } void PanelDockWidget::setWindowTitle( QString title ) { QDockWidget::setWindowTitle( title ); title_label_->setText( title ); } void PanelDockWidget::setIcon( QIcon icon ) { if ( icon.isNull() ) { icon_label_->setVisible( false ); } else { icon_label_->setVisible( true ); icon_label_->setPixmap( icon.pixmap(16,16) ); } } void PanelDockWidget::setCollapsed( bool collapse ) { if ( collapsed_ == collapse || isFloating() ) return; if ( collapse ) { if ( isVisible() ) { QDockWidget::setVisible( false ); collapsed_ = collapse; } } else { QDockWidget::setVisible( true ); collapsed_ = collapse; } } void PanelDockWidget::setContentWidget( QWidget* child ) { if( widget() ) { disconnect( widget(), SIGNAL( destroyed( QObject* )), this, SLOT( onChildDestroyed( QObject* ))); } setWidget( child ); if( child ) { connect( child, SIGNAL( destroyed( QObject* )), this, SLOT( onChildDestroyed( QObject* ))); } } void PanelDockWidget::closeEvent ( QCloseEvent * event ) { Q_EMIT closed(); } void PanelDockWidget::onChildDestroyed( QObject* ) { deleteLater(); } void PanelDockWidget::save( Config config ) { config.mapSetValue( "collapsed", collapsed_ ); } void PanelDockWidget::load( Config config ) { config.mapGetBool( "collapsed", &collapsed_ ); } } // end namespace rviz rviz-1.12.4/src/rviz/panel_dock_widget.h000066400000000000000000000051761300447110700201730ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_PANEL_DOCK_WIDGET_H #define RVIZ_PANEL_DOCK_WIDGET_H #include "rviz/config.h" #include #include namespace rviz { /** @brief Dock widget class for docking widgets into VisualizationFrame. * * Use setContentWidget() instead of QDockWidget::setWidget() if you * want the PanelDockWidget to be destroyed when the content widget is * destroyed. */ class PanelDockWidget: public QDockWidget { Q_OBJECT public: PanelDockWidget( const QString& name ); void setContentWidget( QWidget* child ); void setCollapsed( bool collapsed ); void setIcon( QIcon icon ); virtual void save( Config config ); virtual void load( Config config ); protected: virtual void closeEvent ( QCloseEvent * event ); public Q_SLOTS: void setWindowTitle( QString title ); private Q_SLOTS: void onChildDestroyed( QObject* ); Q_SIGNALS: void closed(); private: // set to true if this panel was collapsed bool collapsed_; QLabel *icon_label_; QLabel *title_label_; }; } // end namespace rviz #endif // RVIZ_PANEL_DOCK_WIDGET_H rviz-1.12.4/src/rviz/panel_factory.cpp000066400000000000000000000056041300447110700177060ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/displays_panel.h" #include "rviz/help_panel.h" #include "rviz/selection_panel.h" #include "rviz/time_panel.h" #include "rviz/tool_properties_panel.h" #include "rviz/views_panel.h" #include "rviz/panel_factory.h" namespace rviz { static Panel* newDisplaysPanel() { return new DisplaysPanel(); } static Panel* newHelpPanel() { return new HelpPanel(); } static Panel* newSelectionPanel() { return new SelectionPanel(); } static Panel* newTimePanel() { return new TimePanel(); } static Panel* newToolPropertiesPanel() { return new ToolPropertiesPanel(); } static Panel* newViewsPanel() { return new ViewsPanel(); } PanelFactory::PanelFactory() : PluginlibFactory( "rviz", "rviz::Panel" ) { addBuiltInClass( "rviz", "Displays", "Show and edit the list of Displays", &newDisplaysPanel ); addBuiltInClass( "rviz", "Help", "Show the key and mouse bindings", &newHelpPanel ); addBuiltInClass( "rviz", "Selection", "Show properties of selected objects", &newSelectionPanel ); addBuiltInClass( "rviz", "Time", "Show the current time", &newTimePanel ); addBuiltInClass( "rviz", "Tool Properties", "Show and edit properties of tools", &newToolPropertiesPanel ); addBuiltInClass( "rviz", "Views", "Show and edit viewpoints", &newViewsPanel ); } } // end namespace rviz rviz-1.12.4/src/rviz/panel_factory.h000066400000000000000000000035211300447110700173470ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PANEL_FACTORY_H #define PANEL_FACTORY_H #include "rviz/panel.h" #include "rviz/pluginlib_factory.h" namespace rviz { class PanelFactory: public PluginlibFactory { public: PanelFactory(); }; } // end namespace rviz #endif // PANEL_FACTORY_H rviz-1.12.4/src/rviz/pluginlib_factory.h000066400000000000000000000157671300447110700202540ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PLUGINLIB_FACTORY_H #define PLUGINLIB_FACTORY_H #include #include #include #include #include #ifndef Q_MOC_RUN #include #endif #include "rviz/class_id_recording_factory.h" #include "rviz/load_resource.h" namespace rviz { template class PluginlibFactory: public ClassIdRecordingFactory { private: struct BuiltInClassRecord { QString class_id_; QString package_; QString name_; QString description_; Type*(*factory_function_)(); }; public: PluginlibFactory( const QString& package, const QString& base_class_type ) { class_loader_ = new pluginlib::ClassLoader( package.toStdString(), base_class_type.toStdString() ); } virtual ~PluginlibFactory() { delete class_loader_; } virtual QStringList getDeclaredClassIds() { QStringList ids; std::vector std_ids = class_loader_->getDeclaredClasses(); for( size_t i = 0; i < std_ids.size(); i++ ) { ids.push_back( QString::fromStdString( std_ids[ i ])); } typename QHash::const_iterator iter; for( iter = built_ins_.begin(); iter != built_ins_.end(); iter++ ) { ids.push_back( iter.key() ); } return ids; } virtual QString getClassDescription( const QString& class_id ) const { typename QHash::const_iterator iter = built_ins_.find( class_id ); if( iter != built_ins_.end() ) { return iter->description_; } return QString::fromStdString( class_loader_->getClassDescription( class_id.toStdString() )); } virtual QString getClassName( const QString& class_id ) const { typename QHash::const_iterator iter = built_ins_.find( class_id ); if( iter != built_ins_.end() ) { return iter->name_; } return QString::fromStdString( class_loader_->getName( class_id.toStdString() )); } virtual QString getClassPackage( const QString& class_id ) const { typename QHash::const_iterator iter = built_ins_.find( class_id ); if( iter != built_ins_.end() ) { return iter->package_; } return QString::fromStdString( class_loader_->getClassPackage( class_id.toStdString() )); } virtual QString getPluginManifestPath( const QString& class_id ) const { typename QHash::const_iterator iter = built_ins_.find( class_id ); if( iter != built_ins_.end() ) { return ""; } return QString::fromStdString( class_loader_->getPluginManifestPath( class_id.toStdString() )); } virtual QIcon getIcon( const QString& class_id ) const { QString package = getClassPackage( class_id ); QString class_name = getClassName( class_id ); QIcon icon = loadPixmap( "package://"+package+"/icons/classes/"+class_name+".svg" ); if ( icon.isNull() ) { icon = loadPixmap( "package://"+package+"/icons/classes/"+class_name+".png" ); if ( icon.isNull() ) { icon = loadPixmap( "package://rviz/icons/default_class_icon.png"); } } return icon; } virtual void addBuiltInClass( const QString& package, const QString& name, const QString& description, Type* (*factory_function)() ) { BuiltInClassRecord record; record.class_id_ = package + "/" + name; record.package_ = package; record.name_ = name; record.description_ = description; record.factory_function_ = factory_function; built_ins_[ record.class_id_ ] = record; } protected: /** @brief Instantiate and return a instance of a subclass of Type using our * pluginlib::ClassLoader. * @param class_id A string identifying the class uniquely among * classes of its parent class. rviz::GridDisplay might be * rviz/Grid, for example. * @param error_return If non-NULL and there is an error, *error_return is set to a description of the problem. * @return A new instance of the class identified by class_id, or NULL if there was an error. * * If makeRaw() returns NULL and error_return is not NULL, * *error_return will be set. On success, *error_return will not be * changed. */ virtual Type* makeRaw( const QString& class_id, QString* error_return = NULL ) { typename QHash::const_iterator iter = built_ins_.find( class_id ); if( iter != built_ins_.end() ) { Type* instance = iter->factory_function_(); if( instance == NULL && error_return != NULL ) { *error_return = "Factory function for built-in class '" + class_id + "' returned NULL."; } return instance; } try { return class_loader_->createUnmanagedInstance( class_id.toStdString() ); } catch( pluginlib::PluginlibException& ex ) { ROS_ERROR( "PluginlibFactory: The plugin for class '%s' failed to load. Error: %s", qPrintable( class_id ), ex.what() ); if( error_return ) { *error_return = QString::fromStdString( ex.what() ); } return NULL; } } private: pluginlib::ClassLoader* class_loader_; QHash built_ins_; }; } // end namespace rviz #endif // PLUGINLIB_FACTORY_H rviz-1.12.4/src/rviz/properties/000077500000000000000000000000001300447110700165435ustar00rootroot00000000000000rviz-1.12.4/src/rviz/properties/bool_property.cpp000066400000000000000000000051031300447110700221450ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/properties/bool_property.h" #include namespace rviz { BoolProperty::BoolProperty( const QString& name, bool default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : Property( name, default_value, description, parent, changed_slot, receiver ) , disable_children_if_false_(false) { } BoolProperty::~BoolProperty() { } bool BoolProperty::getBool() const { return getValue().toBool(); } void BoolProperty::setDisableChildrenIfFalse( bool disable ) { disable_children_if_false_ = disable; } bool BoolProperty::getDisableChildrenIfFalse() { return disable_children_if_false_; } bool BoolProperty::getDisableChildren() { if ( disable_children_if_false_ ) { return !getBool() || Property::getDisableChildren(); } return Property::getDisableChildren(); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/bool_property.h000066400000000000000000000050451300447110700216170ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef BOOL_PROPERTY_H #define BOOL_PROPERTY_H #include "rviz/properties/property.h" namespace rviz { /** @brief Property specialized to provide getter for booleans. */ class BoolProperty: public Property { Q_OBJECT public: BoolProperty( const QString& name = QString(), bool default_value = false, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual ~BoolProperty(); virtual bool getBool() const; //* If this is true, will disable it's children when it's own bool value is false */ void setDisableChildrenIfFalse( bool disable ); bool getDisableChildrenIfFalse(); //* Overridden from Property */ virtual bool getDisableChildren(); public Q_SLOTS: bool setBool( bool value ) { return setValue( value ); } private: bool disable_children_if_false_; }; } // end namespace rviz #endif // BOOL_PROPERTY_H rviz-1.12.4/src/rviz/properties/color_editor.cpp000066400000000000000000000107211300447110700217340ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "rviz/properties/color_property.h" #include "rviz/properties/parse_color.h" #include "rviz/properties/color_editor.h" namespace rviz { ColorEditor::ColorEditor( ColorProperty* property, QWidget* parent ) : LineEditWithButton( parent ) , property_( property ) { connect( this, SIGNAL( textChanged( const QString& )), this, SLOT( parseText() )); } void ColorEditor::paintEvent( QPaintEvent* event ) { LineEditWithButton::paintEvent( event ); QPainter painter( this ); painter.setPen( Qt::black ); paintColorBox( &painter, rect(), color_ ); } void ColorEditor::paintColorBox( QPainter* painter, const QRect& rect, const QColor& color ) { int padding = 3; int size = rect.height() - padding * 2 - 1; painter->save(); painter->setBrush( color ); painter->drawRoundedRect( rect.x() + padding + 3, rect.y() + padding, size, size, 0, 0, Qt::AbsoluteSize ); painter->restore(); } void ColorEditor::resizeEvent( QResizeEvent* event ) { // Do the normal line-edit-with-button thing LineEditWithButton::resizeEvent( event ); // Then add text padding on the left to make room for the color swatch QMargins marge = textMargins(); setTextMargins( height(), marge.top(), marge.right(), marge.bottom() ); } void ColorEditor::parseText() { QColor new_color = parseColor( text() ); if( new_color.isValid() ) { color_ = new_color; if( property_ ) { property_->setColor( new_color ); } } } void ColorEditor::setColor( const QColor& color ) { color_ = color; setText( printColor( color )); if( property_ ) { property_->setColor( color ); } } void ColorEditor::onButtonClick() { ColorProperty* prop = property_; QColor original_color = prop->getColor(); QColorDialog* dialog = new QColorDialog( color_, parentWidget() ); connect( dialog, SIGNAL( currentColorChanged( const QColor& )), property_, SLOT( setColor( const QColor& ))); // Without this connection the PropertyTreeWidget does not update // the color info "live" when it changes in the dialog and the 3D // view. connect( dialog, SIGNAL( currentColorChanged( const QColor& )), parentWidget(), SLOT( update() )); // On the TWM window manager under linux, and on OSX, this // ColorEditor object is destroyed when (or soon after) the dialog // opens. Therefore, here we delete this ColorEditor immediately to // force them all to act the same. deleteLater(); // dialog->exec() will call an event loop internally, so // deleteLater() will take effect and "this" will be destroyed. // Therefore, everything we do in this function after dialog->exec() // should only use variables on the stack, not member variables. if( dialog->exec() != QDialog::Accepted ) { prop->setColor( original_color ); } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/color_editor.h000066400000000000000000000047341300447110700214100ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_COLOR_EDITOR_H #define RVIZ_COLOR_EDITOR_H #include "rviz/properties/line_edit_with_button.h" namespace rviz { class ColorProperty; class ColorEditor: public LineEditWithButton { Q_OBJECT public: ColorEditor( ColorProperty* property = 0, QWidget* parent = 0 ); /** Static function to paint just the color box. Paints it in the * left end of rect, size rect.height() by rect.height(). */ static void paintColorBox( QPainter* painter, const QRect& rect, const QColor& color ); public Q_SLOTS: void setColor( const QColor& color ); void parseText(); protected: /** Call parent version then paint color swatch. */ virtual void paintEvent( QPaintEvent* event ); virtual void resizeEvent( QResizeEvent* event ); protected Q_SLOTS: virtual void onButtonClick(); private: QColor color_; ColorProperty* property_; }; } // end namespace rviz #endif // RVIZ_COLOR_EDITOR_H rviz-1.12.4/src/rviz/properties/color_property.cpp000066400000000000000000000072551300447110700223420ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/properties/parse_color.h" #include "rviz/properties/color_property.h" #include "rviz/properties/color_editor.h" namespace rviz { ColorProperty::ColorProperty( const QString& name, const QColor& default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : Property( name, QVariant(), description, parent, changed_slot, receiver ) , color_( default_value ) { updateString(); } bool ColorProperty::setColor( const QColor& new_color ) { if( new_color != color_ ) { Q_EMIT aboutToChange(); color_ = new_color; updateString(); Q_EMIT changed(); return true; } return false; } bool ColorProperty::setValue( const QVariant& new_value ) { if( new_value.type() == QVariant::Color ) { return setColor( new_value.value() ); } QColor new_color = parseColor( new_value.toString() ); if( new_color.isValid() ) { return setColor( new_color ); } return false; } void ColorProperty::updateString() { value_ = printColor( color_ ); } bool ColorProperty::paint( QPainter * painter, const QStyleOptionViewItem & option ) const { painter->save(); QColor color = color_; if ( !(getViewFlags( 0 ) & Qt::ItemIsEnabled) ) { color = QColor( 200, 200, 200 ); painter->setPen( QColor( Qt::lightGray ) ); } QString text = value_.toString(); QRect rect = option.rect; ColorEditor::paintColorBox( painter, rect, color ); rect.adjust( rect.height() + 4, 1, 0, 0 ); painter->drawText( rect, text ); painter->restore(); return true; // return true, since this function has done the painting. } QWidget *ColorProperty::createEditor( QWidget* parent, const QStyleOptionViewItem& option ) { ColorEditor* editor = new ColorEditor( this, parent ); editor->setFrame( false ); return editor; } } // end namespace rviz rviz-1.12.4/src/rviz/properties/color_property.h000066400000000000000000000052311300447110700217770ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef COLOR_PROPERTY_H #define COLOR_PROPERTY_H #include #include "rviz/properties/parse_color.h" #include "rviz/properties/property.h" namespace rviz { class ColorProperty: public Property { Q_OBJECT public: ColorProperty( const QString& name = QString(), const QColor& default_value = Qt::black, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual bool setValue( const QVariant& new_value ); virtual bool paint( QPainter* painter, const QStyleOptionViewItem& option ) const; virtual QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option ); virtual QColor getColor() const { return color_; } Ogre::ColourValue getOgreColor() const { return qtToOgre( color_ ); } public Q_SLOTS: virtual bool setColor( const QColor& color ); private: void updateString(); QColor color_; }; } // end namespace rviz #endif // VECTOR_PROPERTY_H rviz-1.12.4/src/rviz/properties/combo_box.cpp000066400000000000000000000033411300447110700212170ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/properties/combo_box.h" namespace rviz { ComboBox::ComboBox( QWidget* parent ) : QComboBox( parent ) { } } // end namespace rviz rviz-1.12.4/src/rviz/properties/combo_box.h000066400000000000000000000035411300447110700206660ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef COMBO_BOX_H #define COMBO_BOX_H #include namespace rviz { class ComboBox: public QComboBox { Q_OBJECT Q_PROPERTY(QString currentText READ currentText USER true) public: ComboBox( QWidget* parent = 0 ); }; } // end namespace rviz #endif // COMBO_BOX_H rviz-1.12.4/src/rviz/properties/display_group_visibility_property.cpp000066400000000000000000000111521300447110700263430ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * display_visibility_manager.cpp * * Created on: Aug 27, 2012 * Author: gossow */ #include "display_group_visibility_property.h" #include "rviz/properties/bool_property.h" #include "rviz/display_context.h" #include "rviz/bit_allocator.h" #include "rviz/display.h" #include "rviz/display_group.h" namespace rviz { DisplayGroupVisibilityProperty::DisplayGroupVisibilityProperty( uint32_t vis_bit, DisplayGroup* display_group, Display* parent_display, const QString& name, bool default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : DisplayVisibilityProperty( vis_bit, display_group, name, default_value, description, parent, changed_slot, receiver ) , display_group_(display_group) , parent_display_(parent_display) { connect( display_group, SIGNAL( displayAdded( rviz::Display* ) ), this, SLOT( onDisplayAdded( rviz::Display* ) )); connect( display_group, SIGNAL( displayRemoved( rviz::Display* ) ), this, SLOT( onDisplayRemoved( rviz::Display* ) )); for( int i = 0; i < display_group->numDisplays(); i++ ) { rviz::Display* display = display_group->getDisplayAt( i ); if ( display != parent_display ) { onDisplayAdded( display ); } } setDisableChildrenIfFalse(true); } void DisplayGroupVisibilityProperty::update() { DisplayVisibilityProperty::update(); std::map::iterator it = disp_vis_props_.begin(); for( ; it != disp_vis_props_.end(); it++ ) { it->second->update(); } } void DisplayGroupVisibilityProperty::sortDisplayList() { // remove and re-add everything in our property list // in the same order as it appears in the display group for( int i = 0; i < display_group_->numDisplays(); i++ ) { rviz::Display* display = display_group_->getDisplayAt( i ); std::map::iterator it = disp_vis_props_.find( display ); if ( it != disp_vis_props_.end() ) { takeChild( it->second ); addChild( it->second ); } } } void DisplayGroupVisibilityProperty::onDisplayAdded( Display* display ) { DisplayGroup* display_group = qobject_cast( display ); DisplayVisibilityProperty* vis_prop; if( display_group ) { vis_prop = new DisplayGroupVisibilityProperty( vis_bit_, display_group, parent_display_, "", true, "Uncheck to hide everything in this Display Group", this ); } else { vis_prop = new DisplayVisibilityProperty( vis_bit_, display, "", true, "Show or hide this Display", this ); } disp_vis_props_[ display ] = vis_prop; sortDisplayList(); } void DisplayGroupVisibilityProperty::onDisplayRemoved( Display* display ) { std::map::iterator it = disp_vis_props_.find( display ); if ( it != disp_vis_props_.end() ) { Property* child = takeChild( it->second ); child->setParent( NULL ); delete child; disp_vis_props_.erase( display ); } } DisplayGroupVisibilityProperty::~DisplayGroupVisibilityProperty() { } } rviz-1.12.4/src/rviz/properties/display_group_visibility_property.h000066400000000000000000000063211300447110700260120ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_DISPLAY_GROUP_VISIBILITY_PROPERTY_H_ #define RVIZ_DISPLAY_GROUP_VISIBILITY_PROPERTY_H_ #include "display_visibility_property.h" #include #include #include #include #include namespace rviz { class DisplayContext; class Property; class BoolProperty; class DisplayGroup; class BoolProperty; class DisplayVisibilityProperty; /* * Manages the visibility of all displays in a display group * by switching one bit in Ogre's visibility mask. */ class DisplayGroupVisibilityProperty: public DisplayVisibilityProperty { Q_OBJECT public: /* @param parent Parent display (will not get a visibility property) * @param context The display context * @param root_property Where to attach new properties to */ DisplayGroupVisibilityProperty( uint32_t vis_bit, DisplayGroup* display_group, Display* parent_display, const QString& name = QString(), bool default_value = false, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual ~DisplayGroupVisibilityProperty(); // @brief Update visibility masks of all objects in the Ogre scene virtual void update(); public Q_SLOTS: void onDisplayAdded( rviz::Display* display ); void onDisplayRemoved( rviz::Display* display ); private: // sort the properties in the same way as in the // root display group void sortDisplayList(); DisplayGroup* display_group_; std::map disp_vis_props_; Display* parent_display_; }; } #endif /* DISPLAY_VISIBILITY_MANAGER_H_ */ rviz-1.12.4/src/rviz/properties/display_visibility_property.cpp000066400000000000000000000062641300447110700251370ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "display_visibility_property.h" #include "rviz/properties/bool_property.h" #include "rviz/display_context.h" #include "rviz/bit_allocator.h" #include "rviz/display.h" #include "rviz/display_group.h" namespace rviz { DisplayVisibilityProperty::DisplayVisibilityProperty( uint32_t vis_bit, Display* display, const QString& name, bool default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : BoolProperty( name, default_value, description, parent, changed_slot, receiver ) , vis_bit_(vis_bit) , display_(display) { custom_name_ = (name.size() != 0); update(); } DisplayVisibilityProperty::~DisplayVisibilityProperty() { } void DisplayVisibilityProperty::update() { // update name, unless we had a custom name given in the constructor if ( !custom_name_ && getName() != display_->getName() ) { setName( display_->getName() ); } if ( getBool() && (getViewFlags( 0 ) & Qt::ItemIsEnabled ) ) { display_->setVisibilityBits( vis_bit_ ); } else { display_->unsetVisibilityBits( vis_bit_ ); } } bool DisplayVisibilityProperty::setValue( const QVariant& new_value ) { if ( Property::setValue( new_value ) ) { update(); return true; } return false; } bool DisplayVisibilityProperty::getBool() const { if ( !display_->isEnabled() ) { return false; } return BoolProperty::getBool(); } Qt::ItemFlags DisplayVisibilityProperty::getViewFlags( int column ) const { if ( !display_->isEnabled() ) { return Qt::ItemIsSelectable; } return BoolProperty::getViewFlags( column ); } } rviz-1.12.4/src/rviz/properties/display_visibility_property.h000066400000000000000000000052441300447110700246010ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_DISPLAY_VISIBILITY_PROPERTY_H_ #define RVIZ_DISPLAY_VISIBILITY_PROPERTY_H_ #include #include #include #include #include #include "bool_property.h" namespace rviz { class DisplayContext; class Property; class Display; class BoolProperty; class DisplayVisibilityProperty; /* * @brief Changes one visibility bit of a given Display */ class DisplayVisibilityProperty : public BoolProperty { Q_OBJECT public: DisplayVisibilityProperty( uint32_t vis_bit, Display* display, const QString& name = QString(), bool default_value = false, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual ~DisplayVisibilityProperty(); virtual void update(); virtual bool getBool() const; Qt::ItemFlags getViewFlags( int column ) const; public Q_SLOTS: virtual bool setValue( const QVariant& new_value ); protected: uint32_t vis_bit_; Display* display_; bool custom_name_; }; } #endif /* DISPLAY_VISIBILITY_MANAGER_H_ */ rviz-1.12.4/src/rviz/properties/editable_combo_box.cpp000066400000000000000000000071561300447110700230600ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "rviz/properties/editable_combo_box.h" namespace rviz { EditableComboBox::EditableComboBox( QWidget* parent ) : ComboBox( parent ) { setEditable( true ); completer()->setCompletionMode( QCompleter::PopupCompletion ); completer()->setCaseSensitivity( Qt::CaseInsensitive ); } QString findMaxCommonPrefix( const QStringList& strings ) { if( strings.size() == 0 ) { return ""; } if( strings.size() == 1 ) { return strings[ 0 ]; } QString common_prefix; int char_index = 0; // loop over character index while( true ) { if( char_index >= strings[ 0 ].size() ) { return common_prefix; } const QChar c = strings[ 0 ][ char_index ]; // loop over strings for( int string_index = 1; string_index < strings.size(); string_index++ ) { const QString& str = strings[ string_index ]; if( char_index >= str.size() || str[ char_index ] != c ) { return common_prefix; } } common_prefix += c; char_index++; } return ""; // just to satisfy compiler... I know it will never reach this. } bool EditableComboBox::event( QEvent* event ) { if( event->type() == QEvent::KeyPress ) { QKeyEvent* k = (QKeyEvent*) event; if( k->key() == Qt::Key_Tab && k->modifiers() == Qt::NoModifier ) { QCompleter* comp = completer(); QStringList completions; for( int i = 0; comp->setCurrentRow( i ); i++ ) { completions.push_back( comp->currentCompletion() ); } QString max_common_prefix = findMaxCommonPrefix( completions ); if( max_common_prefix.size() > currentText().size() ) { setEditText( max_common_prefix ); lineEdit()->setCursorPosition( max_common_prefix.size() ); } event->accept(); return true; } } return ComboBox::event( event ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/editable_combo_box.h000066400000000000000000000040121300447110700225110ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef EDITABLE_COMBO_BOX_H #define EDITABLE_COMBO_BOX_H #include "rviz/properties/combo_box.h" namespace rviz { class EditableComboBox: public ComboBox { Q_OBJECT public: EditableComboBox( QWidget* parent = 0 ); protected: /** @brief If event is a tab key press, set the edit text to the * longest common prefix from the completer. */ virtual bool event( QEvent* event ); }; } // end namespace rviz #endif // EDITABLE_COMBO_BOX_H rviz-1.12.4/src/rviz/properties/editable_enum_property.cpp000066400000000000000000000060551300447110700240160ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/editable_combo_box.h" #include "rviz/properties/editable_enum_property.h" namespace rviz { EditableEnumProperty::EditableEnumProperty( const QString& name, const QString& default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : StringProperty( name, default_value, description, parent, changed_slot, receiver ) { } void EditableEnumProperty::clearOptions() { strings_.clear(); } void EditableEnumProperty::addOption( const QString& option ) { strings_.push_back( option ); } QWidget* EditableEnumProperty::createEditor( QWidget* parent, const QStyleOptionViewItem& option ) { // Emit requestOptions() to give listeners a chance to change the option list. Q_EMIT requestOptions( this ); EditableComboBox* cb = new EditableComboBox( parent ); cb->addItems( strings_ ); cb->setEditText( getValue().toString() ); QObject::connect( cb, SIGNAL( currentIndexChanged( const QString& )), this, SLOT( setString( const QString& ))); // TODO: need to better handle string value which is not in list. return cb; } void EditableEnumProperty::setString( const QString& str ) { setValue( str ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/editable_enum_property.h000066400000000000000000000066051300447110700234640ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef EDITABLE_ENUM_PROPERTY_H #define EDITABLE_ENUM_PROPERTY_H #include #include "rviz/properties/string_property.h" namespace rviz { /** @brief Editable Enum property. * * An editable enum property works like a string property, but with * the addition of a drop-down list of predefined choices. */ class EditableEnumProperty: public StringProperty { Q_OBJECT public: EditableEnumProperty( const QString& name = QString(), const QString& default_value = QString(), const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual void clearOptions(); virtual void addOption( const QString& option ); void addOptionStd( const std::string& option ) { addOption( QString::fromStdString( option )); } virtual QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option ); /** @brief Sort the option strings. */ void sortOptions() { strings_.sort(); } public Q_SLOTS: virtual void setString( const QString& str ); Q_SIGNALS: /** @brief requestOptions() is emitted each time createEditor() is * called. * * A connection to this signal should never be made with a queued * connection, because then the "emit" would return before the * changes to the options in the EnumProperty were made. * * A connected slot should make calls to clearOptions() and/or * addOption() as needed. The option list in the EditableEnumProperty will * not be cleared before the signal is emitted. */ void requestOptions( EditableEnumProperty* property_in_need_of_options ); protected: QStringList strings_; }; } // end namespace rviz #endif // EDITABLE_ENUM_PROPERTY_H rviz-1.12.4/src/rviz/properties/enum_property.cpp000066400000000000000000000062621300447110700221650ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/properties/combo_box.h" #include "rviz/properties/enum_property.h" namespace rviz { EnumProperty::EnumProperty( const QString& name, const QString& default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : StringProperty( name, default_value, description, parent, changed_slot, receiver ) { } void EnumProperty::clearOptions() { strings_.clear(); ints_.clear(); } void EnumProperty::addOption( const QString& option, int value ) { strings_.push_back( option ); ints_[ option ] = value; } int EnumProperty::getOptionInt() { QString current_string = getValue().toString(); QHash::const_iterator int_iter = ints_.find( current_string ); if( int_iter != ints_.end() ) { return int_iter.value(); } return 0; } QWidget* EnumProperty::createEditor( QWidget* parent, const QStyleOptionViewItem& option ) { // Emit requestOptions() to give listeners a chance to change the option list. Q_EMIT requestOptions( this ); ComboBox* cb = new ComboBox( parent ); cb->addItems( strings_ ); cb->setCurrentIndex( strings_.indexOf( getValue().toString() )); QObject::connect( cb, SIGNAL( currentIndexChanged( const QString& )), this, SLOT( setString( const QString& ))); // TODO: need to better handle string value which is not in list. return cb; } void EnumProperty::setString( const QString& str ) { setValue( str ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/enum_property.h000066400000000000000000000103121300447110700216210ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef ENUM_PROPERTY_H #define ENUM_PROPERTY_H #include #include "rviz/properties/string_property.h" namespace rviz { /** @brief Enum property. * * An enum property works like a string property all the way through * the system property system, except when you get a changed() signal * you can call getOptionInt() to get the integer value of the current * option. The integer returned will be that passed to addOption() * for with the string that is currently selected. */ class EnumProperty: public StringProperty { Q_OBJECT public: EnumProperty( const QString& name = QString(), const QString& default_value = QString(), const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); /** @brief Clear the list of options. * * Does not change the current value of the property. */ virtual void clearOptions(); virtual void addOption( const QString& option, int value = 0 ); void addOptionStd( const std::string& option, int value = 0 ) { addOption( QString::fromStdString( option ), value ); } /** @brief Return the int value of the currently-chosen option, or 0 * if the current option string does not have an int value. */ virtual int getOptionInt(); virtual QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option ); public Q_SLOTS: /** @brief Set the value of this property to the given string. Does * not force the value to be one of the list of options. */ virtual void setString( const QString& str ); /** @brief Set the value of this property to the given std::string. Does * not force the value to be one of the list of options. */ void setStringStd( const std::string& str ) { setString( QString::fromStdString( str )); } /** @brief Sort the option strings. Does not change string/int associations. */ void sortOptions() { strings_.sort(); } Q_SIGNALS: /** @brief requestOptions() is emitted each time createEditor() is * called. * * A connection to this signal should never be made with a queued * connection, because then the "emit" would return before the * changes to the options in the EnumProperty were made. * * A connected slot should make calls to clearOptions() and/or * addOption() as needed. The option list in the EnumProperty will * not be cleared before the signal is emitted. */ void requestOptions( EnumProperty* property_in_need_of_options ); private: QStringList strings_; QHash ints_; }; } // end namespace rviz #endif // ENUM_PROPERTY_H rviz-1.12.4/src/rviz/properties/float_edit.cpp000066400000000000000000000046731300447110700213730ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/properties/float_edit.h" namespace rviz { FloatEdit::FloatEdit( QWidget* parent ) : QLineEdit( parent ) { setFrame( false ); setValidator( new QDoubleValidator( this )); connect( this, SIGNAL( textEdited( const QString& )), this, SLOT( updateValue() )); } void FloatEdit::setValue( float new_value ) { if( value_ != new_value ) { QLocale locale; value_ = new_value; bool ok = true; float existing_text_value = locale.toFloat(text(), &ok ); if( !ok || existing_text_value != new_value ) { setText( locale.toString((double) value_ )); } } } void FloatEdit::updateValue() { if( hasAcceptableInput() ) { bool ok = true; float new_value = QLocale().toFloat(text(), &ok ); if( ok ) { setValue( new_value ); } } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/float_edit.h000066400000000000000000000040071300447110700210270ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef FLOAT_EDIT_H #define FLOAT_EDIT_H #include namespace rviz { class FloatEdit: public QLineEdit { Q_OBJECT Q_PROPERTY( float value READ getValue WRITE setValue USER true) public: FloatEdit( QWidget* parent = 0 ); virtual float getValue() { return value_; } virtual void setValue( float new_value ); private Q_SLOTS: void updateValue(); private: float value_; }; } // end namespace rviz #endif // FLOAT_EDIT_H rviz-1.12.4/src/rviz/properties/float_property.cpp000066400000000000000000000047061300447110700223270ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include // for FLT_MAX #include #include "rviz/properties/float_property.h" namespace rviz { FloatProperty::FloatProperty( const QString& name, float default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : Property( name, default_value, description, parent, changed_slot, receiver ) , min_( -FLT_MAX ) , max_( FLT_MAX ) { } bool FloatProperty::setValue( const QVariant& new_value ) { return Property::setValue( qBound( min_, new_value.toFloat(), max_ )); } void FloatProperty::setMin( float min ) { min_ = min; setValue( getValue() ); } void FloatProperty::setMax( float max ) { max_ = max; setValue( getValue() ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/float_property.h000066400000000000000000000062751300447110700217770ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef FLOAT_PROPERTY_H #define FLOAT_PROPERTY_H #include "rviz/properties/property.h" namespace rviz { /** @brief Property specialized to enforce floating point max/min. */ class FloatProperty: public Property { Q_OBJECT public: FloatProperty( const QString& name = QString(), float default_value = 0, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); /** @brief Set the new value for this property. Returns true if the * new value is different from the old value, false if same. * * If the new value is different from the old value, this emits * aboutToChange() before changing the value and changed() after. * * Overridden from Property::setValue() to enforce minimum and maximum. */ virtual bool setValue( const QVariant& new_value ); virtual float getFloat() const { return getValue().toFloat(); } void setMin( float min ); float getMin() { return min_; } void setMax( float max ); float getMax() { return max_; } public Q_SLOTS: /** @brief Float-typed "SLOT" version of setValue(). */ bool setFloat( float new_value ) { return setValue( new_value ); } /** @brief Add the given @a delta to the property value. */ bool add( float delta ) { return setValue( delta + getValue().toFloat() ); } /** @brief Multiply the property value by the given @a factor. */ bool multiply( float factor ) { return setValue( factor * getValue().toFloat() ); } private: float min_; float max_; }; } // end namespace rviz #endif // FLOAT_PROPERTY_H rviz-1.12.4/src/rviz/properties/int_property.cpp000066400000000000000000000054141300447110700220110ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include // for INT_MAX and INT_MIN #include #include #include "rviz/properties/int_property.h" namespace rviz { IntProperty::IntProperty( const QString& name, int default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : Property( name, default_value, description, parent, changed_slot, receiver ) , min_( INT_MIN ) , max_( INT_MAX ) { } bool IntProperty::setValue( const QVariant& new_value ) { return Property::setValue( qBound( min_, new_value.toInt(), max_ )); } void IntProperty::setMin( int min ) { min_ = min; setValue( getValue() ); } void IntProperty::setMax( int max ) { max_ = max; setValue( getValue() ); } QWidget* IntProperty::createEditor( QWidget* parent, const QStyleOptionViewItem& option ) { QSpinBox* editor = new QSpinBox( parent ); editor->setFrame( false ); editor->setRange( min_, max_ ); connect( editor, SIGNAL( valueChanged( int )), this, SLOT( setInt( int ))); return editor; } } // end namespace rviz rviz-1.12.4/src/rviz/properties/int_property.h000066400000000000000000000104211300447110700214500ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef INT_PROPERTY_H #define INT_PROPERTY_H #include "rviz/properties/property.h" namespace rviz { /** @brief Property specialized to provide max/min enforcement for integers. */ class IntProperty: public Property { Q_OBJECT public: /** @brief Constructor. * @param name The name of this property. Appears in the left column of a PropertyTreeWidget. * @param default_value The initial value to store in the property. Appears in the right column of a PropertyTreeWidget. * @param description Text describing the property. Is shown in the "help" area of a PropertyTreeWithHelp widget. * @param parent The parent Property, or NULL if there is no parent at this time. * @param changed_slot This should be a Qt slot specification, * generated by Qt's @c SLOT() macro. It should be a slot on * the @a receiver object, or if @a receiver is not specified, * it should be a slot on the @a parent. * @param receiver If receiver is non-NULL, the changed() signal is * connected to the @a changed_slot on the @a receiver object. */ IntProperty( const QString& name = QString(), int default_value = 0, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); /** @brief Set the new value for this property. Returns true if the * new value is different from the old value, false if same. * * If the new value is different from the old value, this emits * aboutToChange() before changing the value and changed() after. * * Overridden from Property::setValue() to enforce minimum and maximum. */ virtual bool setValue( const QVariant& new_value ); /** @brief Return the internal property value as an integer. * * If a non-integer value was stored in this property, this will * return 0. */ virtual int getInt() const { return getValue().toInt(); } void setMin( int min ); int getMin() { return min_; } void setMax( int max ); int getMax() { return max_; } /** @brief Overridden to create a QSpinBox with the min and max set * and with a signal/slot connection to setInt(), so the Property * value updates every time the value changes, not just when * "return" is pressed. */ virtual QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option ); public Q_SLOTS: /** @brief Set the value of this property to the given integer. * * This just calls setValue(), which is where the min/max are enforced. */ void setInt( int new_value ) { setValue( new_value ); } private: int min_; int max_; }; } // end namespace rviz #endif // INT_PROPERTY_H rviz-1.12.4/src/rviz/properties/line_edit_with_button.cpp000066400000000000000000000072451300447110700236410ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/properties/line_edit_with_button.h" #include #include #include #include #include namespace rviz { LineEditWithButton::LineEditWithButton( QWidget* parent ) : QLineEdit( parent ) { button_ = new QPushButton( this ); button_->setText( "..." ); button_->setCursor( Qt::ArrowCursor ); button_->setDefault( false ); button_->setAutoDefault( false ); button_->setFocusPolicy( Qt::NoFocus ); connect( button_, SIGNAL( clicked() ), this, SLOT( onButtonClick() )); } void LineEditWithButton::resizeEvent( QResizeEvent* event ) { // This widget does not use a QLayout object, because I want the // child button to be sized and positioned a specific way. This // function lays out the child button based on the new size of the // LineEdit. int padding = 1; // Make sure the text area doesn't go under the button. setTextMargins( padding, padding, height(), padding ); // Call the original resize handler. QLineEdit::resizeEvent( event ); // Make the button square, matching the height of this widget minus // padding, and located all the way to the right. int button_width = height() - 2 * padding; int button_height = button_width; button_->setGeometry( width() - button_width - padding, padding, button_width, button_height ); } void LineEditWithButton::simulateReturnPressed() { // I couldn't find a way to directly tell the editor that I was // done with it here. "Q_EMIT returnPressed()", "Q_EMIT // editingFinished()" etc did nothing. So instead, here I // simulate the user pressing and releasing the "Return" key, // which does indeed make it act like I want: when you select a // topic from the dialog and the dialog closes, the property's // Setter is called and this editor closes. QKeyEvent* event = new QKeyEvent( QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier ); QApplication::postEvent( this, event ); event = new QKeyEvent( QEvent::KeyRelease, Qt::Key_Return, Qt::NoModifier ); QApplication::postEvent( this, event ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/line_edit_with_button.h000066400000000000000000000047671300447110700233140ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_LINE_EDIT_WITH_BUTTON_H #define RVIZ_LINE_EDIT_WITH_BUTTON_H #include class QPushButton; namespace rviz { /** * A QLineEdit with a square button on the right side that says "...". */ class LineEditWithButton: public QLineEdit { Q_OBJECT public: LineEditWithButton( QWidget* parent = 0 ); /** Returns the child button. Use this to connect() something to a * button click. */ QPushButton* button() { return button_; } protected: virtual void resizeEvent( QResizeEvent* event ); /** @brief Send key events to mimic the "return" key being pressed and * released. Useful ending an edit session and sending the data on * out. */ void simulateReturnPressed(); protected Q_SLOTS: /** @brief Override this to do something when the button is clicked. */ virtual void onButtonClick() {} private: QPushButton* button_; }; } // end namespace rviz #endif // RVIZ_LINE_EDIT_WITH_BUTTON_H rviz-1.12.4/src/rviz/properties/parse_color.cpp000066400000000000000000000056111300447110700215620ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/properties/parse_color.h" namespace rviz { static int limit( int i ) { if( i < 0 ) return 0; if( i > 255 ) return 255; return i; } QColor parseColor( const QString& color_string ) { if( color_string.indexOf( ';' ) != -1 ) { QStringList strings = color_string.split( ';' ); if( strings.size() >= 3 ) { bool r_ok = true; int r = strings[ 0 ].toInt( &r_ok ); bool g_ok = true; int g = strings[ 1 ].toInt( &g_ok ); bool b_ok = true; int b = strings[ 2 ].toInt( &b_ok ); if( r_ok && g_ok && b_ok ) { return QColor( limit( r ), limit( g ), limit( b )); } } return QColor(); } QColor new_color; if( QColor::colorNames().contains( color_string, Qt::CaseInsensitive ) || (color_string.size() > 0 && color_string[ 0 ] == '#' )) { new_color.setNamedColor( color_string.toLower() ); } return new_color; } QString printColor( const QColor& color ) { return QString( "%1; %2; %3" ) .arg( color.red() ) .arg( color.green() ) .arg( color.blue() ); } QColor ogreToQt( const Ogre::ColourValue& c ) { return QColor::fromRgbF( c.r, c.g, c.b, c.a ); } Ogre::ColourValue qtToOgre( const QColor& c ) { return Ogre::ColourValue( c.redF(), c.greenF(), c.blueF(), c.alphaF() ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/parse_color.h000066400000000000000000000037131300447110700212300ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PARSE_COLOR_H #define PARSE_COLOR_H #include #include #include namespace rviz { QColor parseColor( const QString& color_string ); QString printColor( const QColor& color ); QColor ogreToQt( const Ogre::ColourValue& ogre_color ); Ogre::ColourValue qtToOgre( const QColor& qt_color ); } // end namespace rviz #endif // PARSE_COLOR_H rviz-1.12.4/src/rviz/properties/property.cpp000066400000000000000000000316521300447110700211420ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include // for printf() #include // for INT_MIN and INT_MAX #include #include #include "rviz/properties/float_edit.h" #include "rviz/properties/property_tree_model.h" #include "rviz/properties/property.h" namespace rviz { class FailureProperty: public Property { public: virtual Property* subProp( const QString& sub_name ) { return this; } }; /** @brief The property returned by subProp() when the requested * name is not found. */ Property* Property::failprop_ = new FailureProperty; Property::Property( const QString& name, const QVariant default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : value_( default_value ) , model_( 0 ) , child_indexes_valid_( false ) , parent_( 0 ) , description_( description ) , hidden_( false ) , is_read_only_( false ) , save_( true ) { setName( name ); if( parent ) { parent->addChild( this ); } if( receiver == 0 ) { receiver = parent; } if( receiver && changed_slot ) { connect( this, SIGNAL( changed() ), receiver, changed_slot ); } } Property::~Property() { // Disconnect myself from my parent. if( getParent() ) { getParent()->takeChild( this ); } // Destroy my children. for( int i = children_.size() - 1; i >= 0; i-- ) { Property* child = children_.takeAt( i ); child->setParent( NULL ); delete child; } } void Property::removeChildren( int start_index, int count ) { if( count < 0 ) { count = children_.size() - start_index; } if( count == 0 ) return; if( model_ ) { model_->beginRemove( this, start_index, count ); } // Destroy my children. for( int i = start_index; i < start_index + count; i++ ) { Property* child = children_.at( i ); child->setParent( NULL ); // prevent child destructor from calling getParent()->takeChild(). delete child; } children_.erase( children_.begin() + start_index, children_.begin() + start_index + count ); child_indexes_valid_ = false; if( model_ ) { model_->endRemove(); } Q_EMIT childListChanged( this ); } bool Property::setValue( const QVariant& new_value ) { if( new_value != value_ ) { Q_EMIT aboutToChange(); value_ = new_value; Q_EMIT changed(); if( model_ ) { model_->emitDataChanged( this ); } return true; } return false; } QVariant Property::getValue() const { return value_; } void Property::setName( const QString& name ) { setObjectName( name ); if( model_ ) { model_->emitDataChanged( this ); } } QString Property::getName() const { return objectName(); } void Property::setDescription( const QString& description ) { description_ = description; } QString Property::getDescription() const { return description_; } Property* Property::subProp( const QString& sub_name ) { int size = numChildren(); for( int i = 0; i < size; i++ ) { Property* prop = childAtUnchecked( i ); if( prop->getName() == sub_name ) { return prop; } } // Print a useful error message showing the whole ancestry of this // property, but don't crash. QString ancestry = ""; for( Property* prop = this; prop != NULL; prop = prop->getParent() ) { ancestry = "\"" + prop->getName() + "\"->" + ancestry; } printf( "ERROR: Undefined property %s \"%s\" accessed.\n", qPrintable( ancestry ), qPrintable( sub_name )); return failprop_; } Property* Property::childAt( int index ) const { // numChildren() and childAtUnchecked() can both be overridden, so // call them instead of accessing our children_ list directly. if( 0 <= index && index < numChildren() ) { return childAtUnchecked( index ); } return NULL; } Property* Property::childAtUnchecked( int index ) const { return children_.at( index ); } bool Property::contains( Property* possible_child ) const { int num_children = numChildren(); for( int i = 0; i < num_children; i++ ) { if( childAtUnchecked( i ) == possible_child ) { return true; } } return false; } Property* Property::getParent() const { return parent_; } void Property::setParent( Property* new_parent ) { parent_ = new_parent; } QVariant Property::getViewData( int column, int role ) const { if ( role == Qt::TextColorRole && ( parent_ && parent_->getDisableChildren() ) ) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return Qt::gray; #else return QColor(Qt::gray); #endif } switch( column ) { case 0: // left column: names switch( role ) { case Qt::DisplayRole: return getName(); case Qt::DecorationRole: return icon_; default: return QVariant(); } break; case 1: // right column: values switch( role ) { case Qt::DisplayRole: case Qt::EditRole: return (value_.type() == QVariant::Bool ? QVariant() : getValue()); case Qt::CheckStateRole: if( value_.type() == QVariant::Bool ) return (value_.toBool() ? Qt::Checked : Qt::Unchecked); else return QVariant(); default: return QVariant(); } break; default: return QVariant(); } } bool Property::getDisableChildren() { // Pass down the disableChildren flag if ( parent_ ) { return parent_->getDisableChildren(); } return false; } Qt::ItemFlags Property::getViewFlags( int column ) const { // if the parent propery is a disabled bool property or // has its own enabled view flag not set, disable this property as well Qt::ItemFlags enabled_flag = ( parent_ && parent_->getDisableChildren() ) ? Qt::NoItemFlags : Qt::ItemIsEnabled; if( column == 0 ) { return enabled_flag | Qt::ItemIsSelectable; } if( value_.isValid() ) { if( value_.type() == QVariant::Bool ) { return Qt::ItemIsUserCheckable | enabled_flag | Qt::ItemIsSelectable; } return Qt::ItemIsEditable | enabled_flag | Qt::ItemIsSelectable; } return enabled_flag | Qt::ItemIsSelectable; } bool Property::isAncestorOf( Property* possible_child ) const { Property* prop = possible_child->getParent(); while( prop != NULL && prop != this ) { prop = prop->getParent(); } return prop == this; } Property* Property::takeChild( Property* child ) { for( int i = 0; i < numChildren(); i++ ) { if( childAtUnchecked( i ) == child ) { return takeChildAt( i ); } } return NULL; } Property* Property::takeChildAt( int index ) { if( index < 0 || index >= children_.size() ) { return NULL; } if( model_ ) { model_->beginRemove( this, index, 1 ); } Property* child = children_.takeAt( index ); child->setModel( NULL ); child->parent_ = NULL; child_indexes_valid_ = false; if( model_ ) { model_->endRemove(); } Q_EMIT childListChanged( this ); return child; } void Property::addChild( Property* child, int index ) { if( !child ) { return; } int num_children = children_.size(); if( index < 0 || index > num_children ) { index = num_children; } if( model_ ) { model_->beginInsert( this, index ); } children_.insert( index, child ); child_indexes_valid_ = false; child->setModel( model_ ); child->parent_ = this; if( model_ ) { model_->endInsert(); } Q_EMIT childListChanged( this ); } void Property::setModel( PropertyTreeModel* model ) { model_ = model; if( model_ && hidden_ ) { model_->emitPropertyHiddenChanged( this ); } int num_children = numChildren(); for( int i = 0; i < num_children; i++ ) { Property* child = childAtUnchecked( i ); child->setModel( model ); } } void Property::reindexChildren() { int num_children = numChildren(); for( int i = 0; i < num_children; i++ ) { Property* child = childAtUnchecked( i ); child->row_number_within_parent_ = i; } child_indexes_valid_ = true; } int Property::rowNumberInParent() const { Property* parent = getParent(); if( !parent ) { return -1; } if( !parent->child_indexes_valid_ ) { parent->reindexChildren(); } return row_number_within_parent_; } void Property::moveChild( int from_index, int to_index ) { children_.move( from_index, to_index ); child_indexes_valid_ = false; Q_EMIT childListChanged( this ); } void Property::load( const Config& config ) { if( config.getType() == Config::Value ) { loadValue( config ); } else if( config.getType() == Config::Map ) { // A special map entry named "Value" means the value of this property, not a child. // (If child "Value"does not exist, loadValue() will do nothing.) loadValue( config.mapGetChild( "Value" )); // Loop over all child Properties. int num_property_children = children_.size(); for( int i = 0; i < num_property_children; i++ ) { Property* child = children_.at( i ); // Load the child Property with the config under the child property's name. child->load( config.mapGetChild( child->getName() )); } } } void Property::loadValue( const Config& config ) { if( config.getType() == Config::Value ) { switch( int( value_.type() )) { case QVariant::Int: setValue( config.getValue().toInt() ); break; case QMetaType::Float: case QVariant::Double: setValue( config.getValue().toDouble() ); break; case QVariant::String: setValue( config.getValue().toString() ); break; case QVariant::Bool: setValue( config.getValue().toBool() ); break; default: printf( "Property::loadValue() TODO: error handling - unexpected QVariant type %d.\n", int( value_.type() )); break; } } } void Property::save( Config config ) const { // If there are child properties, save them in a map from names to children. if( children_.size() > 0 ) { // If this property has child properties *and* a value itself, // save the value in a special map entry named "Value". if( value_.isValid() ) { config.mapSetValue( "Value", value_ ); } int num_properties = children_.size(); for( int i = 0; i < num_properties; i++ ) { Property* prop = children_.at( i ); if( prop && prop->shouldBeSaved() ) { prop->save( config.mapMakeChild( prop->getName() )); } } } else // Else there are no child properties, so just save the value itself. { if( value_.isValid() ) { config.setValue( value_ ); } else { // Empty Properties get saved as empty Maps instead of null values. config.setType( Config::Map ); } } } QWidget* Property::createEditor( QWidget* parent, const QStyleOptionViewItem& option ) { switch( int( value_.type() )) { case QVariant::Int: { QSpinBox* editor = new QSpinBox( parent ); editor->setFrame( false ); editor->setRange( INT_MIN, INT_MAX ); return editor; } case QMetaType::Float: case QVariant::Double: { FloatEdit* editor = new FloatEdit( parent ); return editor; } case QVariant::String: default: { QLineEdit* editor = new QLineEdit( parent ); editor->setFrame( false ); return editor; } } } void Property::setHidden( bool hidden ) { if( hidden != hidden_ ) { hidden_ = hidden; if( model_ ) { model_->emitPropertyHiddenChanged( this ); } } } void Property::expand() { if( model_ ) { model_->expandProperty( this ); } } void Property::collapse() { if( model_ ) { model_->collapseProperty( this ); } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/property.h000066400000000000000000000475451300447110700206170ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PROPERTY_H #define PROPERTY_H #include #include #include #include #include "rviz/config.h" class QModelIndex; class QPainter; class QStyleOptionViewItem; namespace rviz { class PropertyTreeModel; /** @brief A single element of a property tree, with a name, value, * description, and possibly children. * * A Property in a property tree is a piece of data editable or at * least displayable in a PropertyTreeWidget. A Property object * @em owns the data item in question. When client code needs to be * informed about changes, it can connect to the Property's * aboutToChange() and changed() signals. A slot receiving the * changed() signal should then ask the Property itself for the new * data. Example: * @code * RangeDisplay::RangeDisplay() * { * color_property_ = new ColorProperty( "Color", Qt::white, * "Color to draw the range.", * this, SLOT( updateColorAndAlpha() )); * * alpha_property_ = new FloatProperty( "Alpha", 0.5, * "Amount of transparency to apply to the range.", * this, SLOT( updateColorAndAlpha() )); * } * * void RangeDisplay::updateColorAndAlpha() * { * Ogre::ColourValue oc = color_property_->getOgreColor(); * float alpha = alpha_property_->getFloat(); * for( size_t i = 0; i < cones_.size(); i++ ) * { * cones_[i]->setColor( oc.r, oc.g, oc.b, alpha ); * } * context_->queueRender(); * } * @endcode * Many subclasses of Property exist with specializations for storing * specific types of data. Most of these ultimately use * Property::setValue() to store the data in a QVariant. * * It is important that knowledge of subclasses not be *required* to * get and set data, so that external code can access and change * properties without needing to @c #include and link against the code * in question. For instance: * @code * prop->subProp( "Offset" )->subProp( "X" )->setValue( 3.14 ); * @endcode * Sets the X component of the VectorProperty called "Offset" which is * a child of @c prop. This works without this code needing to know * about the existence of VectorProperty. * * To show a Property tree in a PropertyTreeWidget, wrap the root * Property in a PropertyTreeModel and call * PropertyTreeWidget::setModel() with it. */ class Property: public QObject { Q_OBJECT public: /** @brief Constructor. * @param name The name of this property. Appears in the left column of a PropertyTreeWidget. * @param default_value The initial value to store in the property. Appears in the right column of a PropertyTreeWidget. * @param description Text describing the property. Is shown in the "help" area of a PropertyTreeWithHelp widget. * @param parent The parent Property, or NULL if there is no parent at this time. * @param changed_slot This should be a Qt slot specification, * generated by Qt's @c SLOT() macro. It should be a slot on * the @a receiver object, or if @a receiver is not specified, * it should be a slot on the @a parent. * @param receiver If receiver is non-NULL, the changed() signal is * connected to the @a changed_slot on the @a receiver object. * * All parameters to the constructor are optional and can all be set * after construction as well. * * If a parent is given, this constructor calls @c * parent->addChild(this) to add itself to the parent's list of * children. * * If @a changed_slot is given and either @a parent or @a receiver is * also, then the changed() signal is connected via * QObject::connect() to the slot described by @a changed_slot on the * parent or the receiver. If both parent and receiver are * specified, receiver is the one which gets connected. If receiver * is not specified, parent is used instead. */ Property( const QString& name = QString(), const QVariant default_value = QVariant(), const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); /** @brief Destructor. Removes this property from its parent's list * of children. */ virtual ~Property(); /** @brief Remove and delete some or all child Properties. Does not change * the value of this Property. * @param start_index The index of the first child to delete. * @param count The number of children to delete, or -1 to delete from start_index to the end of the list. * * Does not use numChildren() or takeChildAt(), operates directly on internal children_ list. */ virtual void removeChildren( int start_index = 0, int count = -1 ); /** @brief Set the new value for this property. Returns true if the * new value is different from the old value, false if same. * @param new_value The new value to store. * @return Returns true if @a new_value is different from current value, false if they are the same. * * If the new value is different from the old value, this emits * aboutToChange() before changing the value and emits changed() after. * * If the value set is an invalid QVariant (QVariant::isValid() * returns false), the value will not be editable in a * PropertyTreeWidget. */ virtual bool setValue( const QVariant& new_value ); /** @brief Return the value of this Property as a QVariant. If the * value has never been set, an invalid QVariant is returned. */ virtual QVariant getValue() const; /** @brief Set the name. * @param name the new name. * * Internally, the name is stored with QObject::setObjectName(). */ virtual void setName( const QString& name ); /** @brief Return the name of this Property as a QString. */ virtual QString getName() const; /** @brief Return the name of this Property as a std::string. */ std::string getNameStd() const { return getName().toStdString(); } /** @brief Set the description. * @param description the new description. */ virtual void setDescription( const QString& description ); /** @brief Return the description. */ virtual QString getDescription() const; /** @brief Set the icon to be displayed next to the property. */ virtual void setIcon( const QIcon& icon ) { icon_=icon; } virtual QIcon getIcon() const { return icon_; } /** @brief Return the first child Property with the given name, or * the FailureProperty if no child has the name. * * If no child is found with the given name, an instance of a * special Property subclass named FailureProperty is returned and * an error message is printed to stdout. * FailureProperty::subProp() always returns itself, which means you * can safely chain a bunch of subProp() calls together and not have * a crash even if one of the sub-properties does not actually * exist. For instance: * * float width = prop->subProp( "Dimenshons" )->subProp( "Width" )->getValue().toFloat(); * * If the first property @c prop has a "Dimensions" property but not * a "Dimenshons" one, @c width will end up set to 0 and an error * message will be printed, but the program will not crash here. * * This is an Order(N) operation in the number of subproperties. */ virtual Property* subProp( const QString& sub_name ); /** @brief Return the number of child objects (Property or otherwise). * * You can override this in a subclass to implement different child * storage. */ virtual int numChildren() const { return children_.size(); } /** @brief Return the child Property with the given index, or NULL * if the index is out of bounds or if the child at that index is * not a Property. * * This just checks the index against 0 and numChildren() and then * calls childAtUnchecked(), so it does not need to be overridden in * a subclass. */ Property* childAt( int index ) const; /** @brief Return the child Property with the given index, without * checking whether the index is within bounds. * * You can override this in a subclass to implement different child * storage. */ virtual Property* childAtUnchecked( int index ) const; /** @brief Return true if the list of children includes @a possible_child, false if not. */ bool contains( Property* possible_child ) const; /** @brief Return the parent Property. */ Property* getParent() const; /** @brief Set parent property, without telling the parent. * * Unlike specifying the parent property to the constructor, * setParent() does not have any immediate side effects, like adding * itself to be a child of the parent. It should only be used by * implementations of addChild() and takeChild() and such. */ void setParent( Property* new_parent ); /** @brief Return data appropriate for the given column (0 or 1) and role for this Property. * @param column 0 for left column, 1 for right column. * @param role is a Qt::ItemDataRole * * When overriding to add new data (like a color for example), check * the role for the thing you know about, and if it matches, return * your data. If it does not match, call the parent class version * of this function and return its result. * * Return values from this function or overridden versions of it are * where background and foreground colors, check-box checked-state * values, text, and fonts all come from. */ virtual QVariant getViewData( int column, int role ) const; /** @brief Return item flags appropriate for the given column (0 or * 1) for this Property. * @param column 0 for left column, 1 for right column. * @return The Qt::ItemFlags for the given column of this property, including Qt::ItemIsSelectable, Qt::ItemIsEditable, etc. */ virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Hook to provide custom painting of the value data (right-hand column) in a subclass. * @param painter The QPainter to use. * @param option A QStyleOptionViewItem with parameters of the paint job, like the rectangle, alignments, etc. * @return true if painting has been done, false if not. The default implementation always returns false. * * To implement a custom appearance of a Property value, override * this function to do the painting and return true. * * If this function returns false, a QStyledItemDelegate will do the painting. */ virtual bool paint( QPainter* painter, const QStyleOptionViewItem& option ) const { (void) painter; (void) option; return false; } /** @brief Create an editor widget to edit the value of this property. * @param parent The QWidget to set as the parent of the returned QWidget. * @param option A QStyleOptionViewItem with parameters of the editor widget, like the rectangle, alignments, etc. * * @return the newly-created editor widget. The default * implementation creates a QSpinBox for integer values, a * FloatEdit for float or double values, or a QLineEdit for * anything else. * * If this function returns NULL, a QStyledItemDelegate will make an editor widget. * * The widget returned by createEditor() must have one @c Q_PROPERTY * with @c USER set to @c true. The PropertyTreeDelegate finds it, * sets it with the results of PropertyTreeModel::data() after * creation, and after editing is finished it reads it and calls * PropertyTreeModel::setData() with the contents. */ virtual QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option ); /** @brief Returns true if @c this is an ancestor of * @a possible_child, meaning is the parent or parent of parent * etc. */ bool isAncestorOf( Property* possible_child ) const; /** @brief Remove a given child object and return a pointer to it. * @return If child is contained here, it is returned; otherwise NULL. * * This performs a linear search through all the children. * * This uses only virtual functions, numChildren(), * childAtUnchecked(), and takeChildAt(), so it does not need to be * virtual itself. */ Property* takeChild( Property* child ); /** @brief Take a child out of the child list, but don't destroy it. * @return Returns the child property at the given index, or NULL if the index is out of bounds. * * This notifies the model about the removal. */ virtual Property* takeChildAt( int index ); /** @brief Add a child property. * @param child The child property to add. * @param index [optional] The index at which to add the child. If * less than 0 or greater than the number of child properties, the * child will be added at the end. */ virtual void addChild( Property* child, int index = -1 ); /** @brief Set the model managing this Property and all its child properties, recursively. */ void setModel( PropertyTreeModel* model ); /** @brief Return the model managing this Property and its childrent. */ PropertyTreeModel* getModel() const { return model_; } /** @brief Return the row number of this property within its parent, * or -1 if it has no parent. * * This checks child_indexes_valid_ in the parent Property, and if * it is false calls reindexChildren(). Then returns * row_number_within_parent_ regardless.*/ int rowNumberInParent() const; /** @brief Move the child at from_index to to_index. */ virtual void moveChild( int from_index, int to_index ); /** @brief Load the value of this property and/or its children from * the given Config reference. */ virtual void load( const Config& config ); /** @brief Write the value of this property and/or its children into * the given Config reference. */ virtual void save( Config config ) const; /** @brief Returns true if the property is not read-only AND has data worth saving. */ bool shouldBeSaved() const { return !is_read_only_ && save_; } /** @brief If @a save is true and getReadOnly() is false, * shouldBeSaved will return true; otherwise false. Default is true. */ void setShouldBeSaved( bool save ) { save_ = save; } /** @brief If true, the children of this property should set their * ItemIsEnabled flag to false */ virtual bool getDisableChildren(); /** @brief Hide this Property in any PropertyTreeWidgets. * * This is a convenience function which calls setHidden( true ). * @sa show(), setHidden(), getHidden() */ void hide() { setHidden( true ); } /** @brief Show this Property in any PropertyTreeWidgets. * * This is a convenience function which calls setHidden( false ). * @sa show(), setHidden(), getHidden() */ void show() { setHidden( false ); } /** @brief Hide or show this property in any PropertyTreeWidget * viewing its parent. * * The hidden/shown state is not saved or loaded, it is expected to * be managed by the owner of the property. */ virtual void setHidden( bool hidden ); /** @brief Return the hidden/shown state. True means hidden, false * means visible. */ virtual bool getHidden() const { return hidden_; } /** @brief Prevent or allow users to edit this property from a PropertyTreeWidget. * * This only applies to user edits. Calling setValue() will still change the value. * * This is not inherently recursive. Parents which need this to * propagate to their children must override this to implement * that. */ virtual void setReadOnly( bool read_only ) { is_read_only_ = read_only; } /** @brief Return the read-only-ness of this property. * @sa setReadOnly() */ virtual bool getReadOnly() { return is_read_only_; } /** @brief Collapse (hide the children of) this Property. * * @note Properties start out collapsed by default. * @sa expand() */ virtual void collapse(); /** @brief Expand (show the children of) this Property. * * @note Properties start out collapsed by default. * * This function only works if the property is already owned by a * PropertyTreeModel connected to a PropertyTreeWidget. If this is * called and the model is subsequently attached to a widget, it * will not have any effect. * @sa collapse() */ virtual void expand(); Q_SIGNALS: /** @brief Emitted by setValue() just before the value has changed. */ void aboutToChange(); /** @brief Emitted by setValue() just after the value has changed. */ void changed(); /** @brief Emitted after insertions and deletions of child Properties. */ void childListChanged( Property* this_property ); protected: /** @brief Load the value of this property specifically, not including children. * * This handles value_ types of string, double/float, bool, and int. * If config is invalid, this does nothing. */ void loadValue( const Config& config ); /** @brief This is the central property value. If you set it * directly in a subclass, do so with care because many things * depend on the aboutToChange() and changed() events emitted by * setValue(). */ QVariant value_; /** @brief Pointer to the PropertyTreeModel managing this property tree. * * Any time there is a data value or structural change to the * properties in this tree, and @a model_ is non-NULL, it must be * notified of the change. Functions to notify it of changes * include PropertyTreeModel::beginInsert(), * PropertyTreeModel::endInsert(), PropertyTreeModel::beginRemove(), * PropertyTreeModel::endRemove(), and * PropertyTreeModel::emitDataChanged(). The Property class already * does this for itself, but subclasses must be aware of it if they * override functions which modify the structure or contents of the * tree. */ PropertyTreeModel* model_; /** @brief True if row_number_within_parent_ of all children is * valid, false if not. * * Subclasses should set this false when they add, remove, or * reorder children. */ bool child_indexes_valid_; QIcon icon_; private: /** @brief Set row_number_within_parent_ correctly for every child. * Sets child_indexes_valid_ to true when done. */ void reindexChildren(); Property* parent_; QList children_; QString description_; bool hidden_; /** @brief The property returned by subProp() when the requested * name is not found. */ static Property* failprop_; int row_number_within_parent_; bool is_read_only_; bool save_; }; } // end namespace rviz #endif // PROPERTY_H rviz-1.12.4/src/rviz/properties/property_tree_delegate.cpp000066400000000000000000000054321300447110700240100ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/property.h" #include "rviz/properties/line_edit_with_button.h" #include "rviz/properties/property_tree_delegate.h" namespace rviz { PropertyTreeDelegate::PropertyTreeDelegate( QObject* parent_object ) : QStyledItemDelegate( parent_object ) { } void PropertyTreeDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Property* prop = static_cast( index.internalPointer() ); if( !prop || !prop->paint( painter, option )) { QStyledItemDelegate::paint( painter, option, index ); } } QWidget *PropertyTreeDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex &index ) const { Property* prop = static_cast( index.internalPointer() ); if( !prop || prop->getReadOnly()) { return 0; } if( QWidget* editor = prop->createEditor( parent, option )) { return editor; } return QStyledItemDelegate::createEditor( parent, option, index ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/property_tree_delegate.h000066400000000000000000000043331300447110700234540ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PROPERTY_TREE_DELEGATE_H #define PROPERTY_TREE_DELEGATE_H #include namespace rviz { class PropertyTreeDelegate: public QStyledItemDelegate { Q_OBJECT public: PropertyTreeDelegate( QObject* parent_object = 0 ); virtual void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; virtual QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex &index ) const; }; } // end namespace rviz #endif // PROPERTY_TREE_DELEGATE_H rviz-1.12.4/src/rviz/properties/property_tree_model.cpp000066400000000000000000000233771300447110700233460ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/properties/property.h" #include "rviz/properties/property_tree_model.h" namespace rviz { PropertyTreeModel::PropertyTreeModel( Property* root_property, QObject* parent ) : QAbstractItemModel( parent ) , root_property_( root_property ) { root_property_->setModel( this ); } PropertyTreeModel::~PropertyTreeModel() { delete root_property_; } Property* PropertyTreeModel::getProp( const QModelIndex& index ) const { if( index.isValid() ) { Property* prop = static_cast( index.internalPointer() ); if( prop ) { return prop; } } return root_property_; } Qt::ItemFlags PropertyTreeModel::flags( const QModelIndex& index ) const { if( !index.isValid() ) { root_property_->getViewFlags( 0 ); } Property* property = getProp( index ); return property->getViewFlags( index.column() ); } QModelIndex PropertyTreeModel::index( int row, int column, const QModelIndex& parent_index ) const { if( parent_index.isValid() && parent_index.column() != 0 ) { return QModelIndex(); } Property* parent = getProp( parent_index ); Property* child = parent->childAt( row ); if( child ) { return createIndex( row, column, child ); } else { return QModelIndex(); } } QModelIndex PropertyTreeModel::parent( const QModelIndex& child_index ) const { if( !child_index.isValid() ) { return QModelIndex(); } Property* child = getProp( child_index ); return parentIndex( child ); } QModelIndex PropertyTreeModel::parentIndex( const Property* child ) const { if( !child ) { return QModelIndex(); } Property* parent = child->getParent(); if( parent == root_property_ || !parent ) { return QModelIndex(); } return indexOf( parent ); } int PropertyTreeModel::rowCount( const QModelIndex& parent_index ) const { return getProp( parent_index )->numChildren(); } QVariant PropertyTreeModel::data( const QModelIndex& index, int role ) const { if( !index.isValid() ) { return QVariant(); } return getProp( index )->getViewData( index.column(), role ); } QVariant PropertyTreeModel::headerData( int section, Qt::Orientation orientation, int role ) const { // we don't use headers. return QVariant(); } bool PropertyTreeModel::setData( const QModelIndex& index, const QVariant& value, int role ) { Property *property = getProp( index ); if( property->getValue().type() == QVariant::Bool && role == Qt::CheckStateRole ) { if( property->setValue( value.toInt() != Qt::Unchecked )) { return true; } } if( role != Qt::EditRole ) { return false; } if( property->setValue( value )) { return true; } return false; } /** @brief Override from QAbstractItemModel. Returns a * (non-standard) mime-encoded version of the given indexes. * * Returns the model indexes encoded using pointer values, which * means they will only work within the application this is compiled * into. */ QMimeData* PropertyTreeModel::mimeData( const QModelIndexList& indexes ) const { if( indexes.count() <= 0 ) { return 0; } QStringList types = mimeTypes(); if( types.isEmpty() ) { return 0; } QMimeData *data = new QMimeData(); QString format = types.at(0); QByteArray encoded; QDataStream stream( &encoded, QIODevice::WriteOnly ); QModelIndexList::ConstIterator it = indexes.begin(); for( ; it != indexes.end(); ++it ) { if( (*it).column() == 0 ) { void* pointer = (*it).internalPointer(); stream.writeRawData( (char*)&pointer, sizeof( void* )); } } data->setData( format, encoded ); return data; } /** @brief Override from QAbstractItemModel. Takes a (non-standard) * mime-encoded version of an index list and drops it at the * destination. * * The model indexes are encoded using pointer values (by * mimeData()), which means they will only work within the * application this is compiled into. */ bool PropertyTreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int dest_row, int dest_column, const QModelIndex& dest_parent ) { if( !data || action != Qt::MoveAction ) { return false; } QStringList types = mimeTypes(); if( types.isEmpty() ) { return false; } QString format = types.at(0); if( !data->hasFormat( format )) { return false; } QByteArray encoded = data->data( format ); QDataStream stream( &encoded, QIODevice::ReadOnly ); Property* dest_parent_property = getProp( dest_parent ); QList source_properties; // Decode the mime data. while( !stream.atEnd() ) { void* pointer; if( sizeof( void* ) != stream.readRawData( (char*)&pointer, sizeof( void* ))) { printf("ERROR: dropped mime data has invalid pointer data.\n"); return false; } Property* prop = static_cast( pointer ); if( prop == dest_parent_property || prop->isAncestorOf( dest_parent_property )) { // Can't drop a row into its own child. return false; } source_properties.append( prop ); } if( dest_row == -1 ) { dest_row = dest_parent_property->numChildren(); } for( int i = 0; i < source_properties.size(); i++ ) { Property* prop = source_properties.at( i ); // When moving multiple items, source indices can change. // Therefore we ask each property for its row just before we move // it. int source_row = prop->rowNumberInParent(); prop->getParent()->takeChildAt( source_row ); if( dest_parent_property == prop->getParent() && dest_row > source_row ) { dest_row--; } dest_parent_property->addChild( prop, dest_row ); dest_row++; } return true; } QStringList PropertyTreeModel::mimeTypes() const { QStringList result; result.append( "application/x-rviz-" + drag_drop_class_ ); return result; } QModelIndex PropertyTreeModel::indexOf( Property* property ) const { if( property == root_property_ || !property ) { return QModelIndex(); } return createIndex( property->rowNumberInParent(), 0, property ); } void PropertyTreeModel::emitDataChanged( Property* property ) { if( property->shouldBeSaved() ) { Q_EMIT configChanged(); } QModelIndex left_index = indexOf( property ); QModelIndex right_index = createIndex( left_index.row(), 1, left_index.internalPointer() ); Q_EMIT dataChanged( left_index, right_index ); } void PropertyTreeModel::beginInsert( Property* parent_property, int row_within_parent, int count ) { // printf( "PropertyTreeModel::beginInsert() into %s row %d, %d rows. Persistent indices:\n", // qPrintable( parent_property->getName()), row_within_parent, count ); // printPersistentIndices(); beginInsertRows( indexOf( parent_property ), row_within_parent, row_within_parent + count - 1 ); } void PropertyTreeModel::endInsert() { endInsertRows(); // printf( "PropertyTreeModel::endInsert()\n" ); } void PropertyTreeModel::beginRemove( Property* parent_property, int row_within_parent, int count ) { // printf( "PropertyTreeModel::beginRemove() from %s row %d, %d rows. Persistent indices:\n", // qPrintable( parent_property->getName()), row_within_parent, count ); // printPersistentIndices(); beginRemoveRows( indexOf( parent_property ), row_within_parent, row_within_parent + count - 1 ); } void PropertyTreeModel::endRemove() { endRemoveRows(); // printf( "PropertyTreeModel::endRemove()\n" ); } void PropertyTreeModel::expandProperty( Property* property ) { Q_EMIT expand( indexOf( property )); } void PropertyTreeModel::collapseProperty( Property* property ) { Q_EMIT collapse( indexOf( property )); } void PropertyTreeModel::printPersistentIndices() { QModelIndexList indexes = persistentIndexList(); QModelIndexList::ConstIterator it = indexes.begin(); for( ; it != indexes.end(); ++it ) { if( !(*it).isValid() ) { printf( " invalid index\n" ); } else { Property* prop = getProp( *it ); if( !prop ) { printf( " null property\n" ); } else { printf( " prop name '%s'\n", qPrintable( prop->getName() )); } } } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/property_tree_model.h000066400000000000000000000144451300447110700230070ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PROPERTY_MODEL_H #define PROPERTY_MODEL_H #include namespace rviz { class Property; class PropertyTreeModel: public QAbstractItemModel { Q_OBJECT public: /** @brief Constructor. * @param root_property The root of the property tree. * PropertyTreeModel takes ownership of root_property and * deletes it in its destructor. * @param parent A QObject to set as the parent. */ PropertyTreeModel( Property* root_property, QObject* parent = 0 ); /** @brief Destructor. Deletes the root property (and thus the * entire property tree). */ virtual ~PropertyTreeModel(); void setDragDropClass( const QString& drag_drop_class ) { drag_drop_class_ = drag_drop_class; } // Read-only model functions: virtual QVariant data( const QModelIndex &index, int role ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; virtual QModelIndex parent( const QModelIndex &index ) const; /** @brief Same as parent() but taking a Property pointer instead of * an index. */ QModelIndex parentIndex( const Property* child ) const; /** @brief Return the number of rows under the given parent index. */ virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const; /** @brief Return the number of columns under the given parent * index, which is always 2 for this model. */ virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const { return 2; } // Editable model functions: virtual Qt::ItemFlags flags( const QModelIndex &index ) const; virtual bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ); virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } /** @brief Override from QAbstractItemModel. Returns a * (non-standard) mime-encoded version of the given indexes. * * Returns the model indexes encoded using pointer values, which * means they will only work within the application this is compiled * into. */ virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; /** @brief Override from QAbstractItemModel. Takes a (non-standard) * mime-encoded version of an index list and drops it at the * destination. * * The model indexes are encoded using pointer values (by * mimeData()), which means they will only work within the * application this is compiled into. */ virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action, int destination_row, int destination_column, const QModelIndex& destination_parent ); /** @brief Returns a list with just "application/x-rviz-" plus * drag_drop_class_. */ virtual QStringList mimeTypes () const; Property* getRoot() const { return root_property_; } QModelIndex indexOf( Property* property ) const; void emitDataChanged( Property* property ); void beginInsert( Property* parent_property, int row_within_parent, int count = 1 ); void endInsert(); void beginRemove( Property* parent_property, int row_within_parent, int count = 1 ); void endRemove(); /** @brief return the Property at the given index, or the root * property if the index is invalid. */ Property* getProp( const QModelIndex& index ) const; /** @brief Emit the propertyHiddenChanged() signal for the given Property. */ void emitPropertyHiddenChanged( const Property* property ) { Q_EMIT propertyHiddenChanged( property ); } /** @brief Expand (show the children of) the given Property. */ void expandProperty( Property* property ); /** @brief Collapse (hide the children of) the given Property. */ void collapseProperty( Property* property ); /** @brief For debugging only. Uses printf() to print the property * names of current persistent indices. */ void printPersistentIndices(); Q_SIGNALS: /** @brief Emitted when a property within the model is hidden or shown. */ void propertyHiddenChanged( const Property* property ); /** @brief Emitted when a Property which should be saved changes. */ void configChanged(); /** @brief Emitted when a Property wants to expand (display its children). */ void expand( const QModelIndex& index ); /** @brief Emitted when a Property wants to collapse (hide its children). */ void collapse( const QModelIndex& index ); private: Property* root_property_; QString drag_drop_class_; ///< Identifier to add to mimeTypes() entry to keep drag/drops from crossing types. }; } // end namespace rviz #endif // PROPERTY_MODEL_H rviz-1.12.4/src/rviz/properties/property_tree_widget.cpp000066400000000000000000000160201300447110700235140ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/properties/property.h" #include "rviz/properties/property_tree_delegate.h" #include "rviz/properties/splitter_handle.h" #include "rviz/properties/status_list.h" #include "rviz/properties/property_tree_widget.h" namespace rviz { PropertyTreeWidget::PropertyTreeWidget( QWidget* parent ) : QTreeView( parent ) , model_( NULL ) , splitter_handle_( new SplitterHandle( this )) { setItemDelegateForColumn( 1, new PropertyTreeDelegate( this )); setDropIndicatorShown( true ); setUniformRowHeights( true ); setHeaderHidden( true ); setDragEnabled( true ); setAcceptDrops( true ); setAnimated( true ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setEditTriggers( QAbstractItemView::AllEditTriggers ); setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); QTimer* timer = new QTimer( this ); connect( timer, SIGNAL( timeout() ), this, SLOT( update() )); timer->start( 100 ); } void PropertyTreeWidget::currentChanged( const QModelIndex& new_current_index, const QModelIndex& previous_current_index ) { QTreeView::currentChanged( new_current_index, previous_current_index ); Q_EMIT currentPropertyChanged( static_cast( new_current_index.internalPointer() )); } void PropertyTreeWidget::selectionChanged( const QItemSelection& selected, const QItemSelection& deselected ) { QTreeView::selectionChanged( selected, deselected ); Q_EMIT selectionHasChanged(); } void PropertyTreeWidget::setModel( PropertyTreeModel* model ) { if( model_ ) { disconnect( model_, SIGNAL( propertyHiddenChanged( const Property* )), this, SLOT( propertyHiddenChanged( const Property* ))); disconnect( model_, SIGNAL( expand( const QModelIndex& )), this, SLOT( expand( const QModelIndex& ))); disconnect( model_, SIGNAL( collapse( const QModelIndex& )), this, SLOT( collapse( const QModelIndex& ))); } model_ = model; QTreeView::setModel( model_ ); if( model_ ) { connect( model_, SIGNAL( propertyHiddenChanged( const Property* )), this, SLOT( propertyHiddenChanged( const Property* )), Qt::QueuedConnection ); connect( model_, SIGNAL( expand( const QModelIndex& )), this, SLOT( expand( const QModelIndex& ))); connect( model_, SIGNAL( collapse( const QModelIndex& )), this, SLOT( collapse( const QModelIndex& ))); // this will trigger all hiddenChanged events to get re-fired model_->getRoot()->setModel( model_->getRoot()->getModel() ); } } void PropertyTreeWidget::propertyHiddenChanged( const Property* property ) { if( model_ ) { setRowHidden( property->rowNumberInParent(), model_->parentIndex( property ), property->getHidden() ); } } void PropertyTreeWidget::save( Config config ) const { saveExpandedEntries( config.mapMakeChild( "Expanded" ), QModelIndex(), "" ); config.mapSetValue( "Splitter Ratio", splitter_handle_->getRatio() ); } void PropertyTreeWidget::saveExpandedEntries( Config config, const QModelIndex& parent_index, const QString& prefix ) const { int num_children = model_->rowCount( parent_index ); if( num_children > 0 ) { QHash name_counts; for( int i = 0; i < num_children; i++ ) { QModelIndex child_index = model_->index( i, 0, parent_index ); Property* child = model_->getProp( child_index ); QString child_name = child->getName(); if( qobject_cast( child )) { // StatusList objects change their name dynamically, so // normalize to a standard string. child_name = "Status"; } int name_occurrence = ++( name_counts[ child_name ]); QString full_name = prefix + "/" + child_name + QString::number( name_occurrence ); if( isExpanded( child_index )) { config.listAppendNew().setValue( full_name ); } saveExpandedEntries( config, child_index, full_name ); } } } void PropertyTreeWidget::load( const Config& config ) { Config expanded_list_config = config.mapGetChild( "Expanded" ); QSet expanded_full_names; int num_expanded = expanded_list_config.listLength(); for( int i = 0; i < num_expanded; i++ ) { expanded_full_names.insert( expanded_list_config.listChildAt( i ).getValue().toString() ); } expandEntries( expanded_full_names, QModelIndex(), "" ); float ratio; if( config.mapGetFloat( "Splitter Ratio", &ratio )) { splitter_handle_->setRatio( ratio ); } } void PropertyTreeWidget::expandEntries( const QSet& expanded_full_names, const QModelIndex& parent_index, const QString& prefix ) { int num_children = model_->rowCount( parent_index ); if( num_children > 0 ) { QHash name_counts; for( int i = 0; i < num_children; i++ ) { QModelIndex child_index = model_->index( i, 0, parent_index ); Property* child = model_->getProp( child_index ); QString child_name = child->getName(); if( qobject_cast( child )) { child_name = "Status"; } int name_occurrence = ++( name_counts[ child_name ]); QString full_name = prefix + "/" + child_name + QString::number( name_occurrence ); if( expanded_full_names.contains( full_name )) { setExpanded( child_index, true ); } expandEntries( expanded_full_names, child_index, full_name ); } } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/property_tree_widget.h000066400000000000000000000102311300447110700231570ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PROPERTY_TREE_WIDGET_H #define PROPERTY_TREE_WIDGET_H #include #include "rviz/config.h" #include "rviz/properties/property_tree_model.h" namespace rviz { class Property; class SplitterHandle; class PropertyTreeWidget: public QTreeView { Q_OBJECT public: PropertyTreeWidget( QWidget* parent = 0 ); /** @brief Set the data model this widget should view. */ void setModel( PropertyTreeModel* model ); PropertyTreeModel* getModel() const { return model_; } /** @brief Return the list of objects of a given type which are currently selected. */ template QList getSelectedObjects() { QModelIndexList indexes = selectedIndexes(); int num_selected = indexes.size(); QList objects_out; for( int i = 0; i < num_selected; i++ ) { if( indexes[ i ].column() == 0 ) { Property* prop = model_->getProp( indexes[ i ] ); if( prop != model_->getRoot() ) { Type* obj = qobject_cast( prop ); if( obj ) { objects_out.push_back( obj ); } } } } return objects_out; } /** @brief Write state to the given Config. */ void save( Config config ) const; /** @brief Read state from the given Config. */ void load( const Config& config ); protected: /** @brief Called whenever current item changes. Calls QTreeView * implementation then emits currentPropertyChanged(). */ virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous ); /** @brief Called whenever selection changes. Calls QTreeView * implementation then emits selectionHasChanged(). */ virtual void selectionChanged( const QItemSelection& selected, const QItemSelection& deselected ); protected Q_SLOTS: virtual void propertyHiddenChanged( const Property* property ); Q_SIGNALS: void currentPropertyChanged( const Property* new_current_property ); void selectionHasChanged(); private: /** @brief Recursively write full names of properties which are expanded in this view to the given Config. */ void saveExpandedEntries( Config config, const QModelIndex& parent_index, const QString& prefix ) const; /** @brief Recursively expand entries whose full names appear in expanded_full_names. */ void expandEntries( const QSet& expanded_full_names, const QModelIndex& parent_index, const QString& prefix ); PropertyTreeModel* model_; SplitterHandle* splitter_handle_; }; } // end namespace rviz #endif // PROPERTY_TREE_WIDGET_H rviz-1.12.4/src/rviz/properties/property_tree_with_help.cpp000066400000000000000000000066441300447110700242270ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/property.h" #include "rviz/properties/property_tree_widget.h" #include "rviz/properties/property_tree_with_help.h" namespace rviz { PropertyTreeWithHelp::PropertyTreeWithHelp( QWidget* parent ) : QSplitter( parent ) { setOrientation( Qt::Vertical ); property_tree_ = new PropertyTreeWidget; help_ = new QTextBrowser; help_->setOpenExternalLinks( true ); addWidget( property_tree_ ); addWidget( help_ ); setStretchFactor( 0, 1000 ); setCollapsible( 0, false ); QList _sizes; _sizes.push_back( 1000 ); _sizes.push_back( 1 ); setSizes( _sizes ); connect( property_tree_, SIGNAL( currentPropertyChanged( const Property* )), this, SLOT( showHelpForProperty( const Property* ))); } void PropertyTreeWithHelp::showHelpForProperty( const Property* property ) { if( property ) { QString body_text = property->getDescription(); QString heading = property->getName(); QString html = "" + heading + "
" + body_text + ""; help_->setHtml( html ); } else { help_->setHtml( "" ); } } void PropertyTreeWithHelp::save( Config config ) const { property_tree_->save( config.mapMakeChild( "Property Tree Widget" )); QList _sizes = sizes(); config.mapSetValue( "Tree Height", _sizes.at( 0 )); config.mapSetValue( "Help Height", _sizes.at( 1 )); } void PropertyTreeWithHelp::load( const Config& config ) { property_tree_->load( config.mapGetChild( "Property Tree Widget" )); int tree_height; int help_height; if( config.mapGetInt( "Tree Height", &tree_height ) && config.mapGetInt( "Help Height", &help_height )) { QList _sizes; _sizes.push_back( tree_height ); _sizes.push_back( help_height ); setSizes( _sizes ); } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/property_tree_with_help.h000066400000000000000000000046111300447110700236640ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_PROPERTY_TREE_WITH_HELP_H #define RVIZ_PROPERTY_TREE_WITH_HELP_H #include #include "rviz/config.h" class QTextBrowser; namespace rviz { class Property; class PropertyTreeWidget; /** A PropertyTreeWidget with built-in help info display. */ class PropertyTreeWithHelp: public QSplitter { Q_OBJECT public: PropertyTreeWithHelp( QWidget* parent = 0 ); PropertyTreeWidget* getTree() { return property_tree_; } /** @brief Write state to the given Config. */ void save( Config config ) const; /** @brief Read state from the given Config. */ void load( const Config& config ); private Q_SLOTS: void showHelpForProperty( const Property* property ); private: PropertyTreeWidget* property_tree_; QTextBrowser* help_; }; } // end namespace rviz #endif // RVIZ_PROPERTY_TREE_WITH_HELP_H rviz-1.12.4/src/rviz/properties/quaternion_property.cpp000066400000000000000000000135021300447110700234010ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/quaternion_property.h" namespace rviz { QuaternionProperty::QuaternionProperty( const QString& name, const Ogre::Quaternion& default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : Property( name, QVariant(), description, parent, changed_slot, receiver ) , quaternion_( default_value ) , ignore_child_updates_( false ) { x_ = new Property( "X", quaternion_.x, "X coordinate", this ); y_ = new Property( "Y", quaternion_.y, "Y coordinate", this ); z_ = new Property( "Z", quaternion_.z, "Z coordinate", this ); w_ = new Property( "W", quaternion_.w, "W coordinate", this ); updateString(); connect( x_, SIGNAL( aboutToChange() ), this, SLOT( emitAboutToChange() )); connect( y_, SIGNAL( aboutToChange() ), this, SLOT( emitAboutToChange() )); connect( z_, SIGNAL( aboutToChange() ), this, SLOT( emitAboutToChange() )); connect( w_, SIGNAL( aboutToChange() ), this, SLOT( emitAboutToChange() )); connect( x_, SIGNAL( changed() ), this, SLOT( updateFromChildren() )); connect( y_, SIGNAL( changed() ), this, SLOT( updateFromChildren() )); connect( z_, SIGNAL( changed() ), this, SLOT( updateFromChildren() )); connect( w_, SIGNAL( changed() ), this, SLOT( updateFromChildren() )); } bool QuaternionProperty::setQuaternion( const Ogre::Quaternion& new_quaternion ) { if( new_quaternion != quaternion_ ) { Q_EMIT aboutToChange(); quaternion_ = new_quaternion; ignore_child_updates_ = true; x_->setValue( quaternion_.x ); y_->setValue( quaternion_.y ); z_->setValue( quaternion_.z ); w_->setValue( quaternion_.w ); ignore_child_updates_ = false; updateString(); Q_EMIT changed(); return true; } return false; } bool QuaternionProperty::setValue( const QVariant& new_value ) { QStringList strings = new_value.toString().split( ';' ); if( strings.size() >= 4 ) { bool x_ok = true; float x = strings[ 0 ].toFloat( &x_ok ); bool y_ok = true; float y = strings[ 1 ].toFloat( &y_ok ); bool z_ok = true; float z = strings[ 2 ].toFloat( &z_ok ); bool w_ok = true; float w = strings[ 3 ].toFloat( &w_ok ); if( x_ok && y_ok && z_ok && w_ok ) { return setQuaternion( Ogre::Quaternion( w, x, y, z )); } } return false; } void QuaternionProperty::updateFromChildren() { if( !ignore_child_updates_ ) { quaternion_.x = x_->getValue().toFloat(); quaternion_.y = y_->getValue().toFloat(); quaternion_.z = z_->getValue().toFloat(); quaternion_.w = w_->getValue().toFloat(); updateString(); Q_EMIT changed(); } } void QuaternionProperty::emitAboutToChange() { if( !ignore_child_updates_ ) { Q_EMIT aboutToChange(); } } void QuaternionProperty::updateString() { value_ = QString( "%1; %2; %3; %4" ) .arg( quaternion_.x, 0, 'g', 5 ) .arg( quaternion_.y, 0, 'g', 5 ) .arg( quaternion_.z, 0, 'g', 5 ) .arg( quaternion_.w, 0, 'g', 5 ); } void QuaternionProperty::load( const Config& config ) { float x, y, z, w; if( config.mapGetFloat( "X", &x ) && config.mapGetFloat( "Y", &y ) && config.mapGetFloat( "Z", &z ) && config.mapGetFloat( "W", &w )) { // Calling setQuaternion() once explicitly is better than letting // the Property class load the X, Y, Z, and W children // independently, which would result in at least 4 calls to // setQuaternion(). setQuaternion( Ogre::Quaternion( w, x, y, z )); } } void QuaternionProperty::save( Config config ) const { // Saving the child values explicitly avoids having Property::save() // save the summary string version of the property. config.mapSetValue( "X", x_->getValue() ); config.mapSetValue( "Y", y_->getValue() ); config.mapSetValue( "Z", z_->getValue() ); config.mapSetValue( "W", w_->getValue() ); } void QuaternionProperty::setReadOnly( bool read_only ) { Property::setReadOnly( read_only ); x_->setReadOnly( read_only ); y_->setReadOnly( read_only ); z_->setReadOnly( read_only ); w_->setReadOnly( read_only ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/quaternion_property.h000066400000000000000000000056231300447110700230530ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef QUATERNION_PROPERTY_H #define QUATERNION_PROPERTY_H #include #include "rviz/properties/property.h" namespace rviz { class QuaternionProperty: public Property { Q_OBJECT public: QuaternionProperty( const QString& name = QString(), const Ogre::Quaternion& default_value = Ogre::Quaternion::IDENTITY, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual bool setQuaternion( const Ogre::Quaternion& quaternion ); virtual Ogre::Quaternion getQuaternion() const { return quaternion_; } virtual bool setValue( const QVariant& new_value ); /** @brief Load the value of this property and/or its children from * the given Config node. */ virtual void load( const Config& config ); virtual void save( Config config ) const; /** @brief Overridden from Property to propagate read-only-ness to children. */ virtual void setReadOnly( bool read_only ); private Q_SLOTS: void updateFromChildren(); void emitAboutToChange(); private: void updateString(); Ogre::Quaternion quaternion_; Property* x_; Property* y_; Property* z_; Property* w_; bool ignore_child_updates_; }; } // end namespace rviz #endif // QUATERNION_PROPERTY_H rviz-1.12.4/src/rviz/properties/ros_topic_property.cpp000066400000000000000000000061361300447110700232220ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ros/master.h" #include "rviz/properties/ros_topic_property.h" #include namespace rviz { RosTopicProperty::RosTopicProperty( const QString& name, const QString& default_value, const QString& message_type, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : EditableEnumProperty( name, default_value, description, parent, changed_slot, receiver ) , message_type_( message_type ) { connect( this, SIGNAL( requestOptions( EditableEnumProperty* )), this, SLOT( fillTopicList())); } void RosTopicProperty::setMessageType( const QString& message_type ) { message_type_ = message_type; } void RosTopicProperty::fillTopicList() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); clearOptions(); std::string std_message_type = message_type_.toStdString(); ros::master::V_TopicInfo topics; ros::master::getTopics( topics ); // Loop through all published topics ros::master::V_TopicInfo::iterator it; for( it = topics.begin(); it != topics.end(); ++it ) { const ros::master::TopicInfo& topic = *it; // Only add topics whose type matches. if( topic.datatype == std_message_type ) { addOptionStd( topic.name ); } } sortOptions(); QApplication::restoreOverrideCursor(); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/ros_topic_property.h000066400000000000000000000050611300447110700226630ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef ROS_TOPIC_PROPERTY_H #define ROS_TOPIC_PROPERTY_H #include #include "rviz/properties/editable_enum_property.h" namespace rviz { class RosTopicProperty: public EditableEnumProperty { Q_OBJECT public: RosTopicProperty( const QString& name = QString(), const QString& default_value = QString(), const QString& message_type = QString(), const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); void setMessageType( const QString& message_type ); QString getMessageType() const { return message_type_; } QString getTopic() const { return getValue().toString(); } std::string getTopicStd() const { return getValue().toString().toStdString(); } protected Q_SLOTS: virtual void fillTopicList(); private: QString message_type_; }; } // end namespace rviz #endif // ROS_TOPIC_PROPERTY_H rviz-1.12.4/src/rviz/properties/splitter_handle.cpp000066400000000000000000000101711300447110700224300ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "rviz/properties/splitter_handle.h" namespace rviz { SplitterHandle::SplitterHandle( QTreeView* parent ) : QWidget( parent ) , parent_( parent ) , first_column_size_ratio_( 0.5f ) , color_( 128, 128, 128, 64 ) { setCursor( Qt::SplitHCursor ); updateGeometry(); parent_->installEventFilter( this ); } bool SplitterHandle::eventFilter( QObject* event_target, QEvent* event ) { if( event_target == parent_ && (event->type() == QEvent::Resize || event->type() == QEvent::Paint)) { updateGeometry(); } return false; // Return false regardless so resize event also does its normal job. } void SplitterHandle::updateGeometry() { int w = 7; int content_width = parent_->contentsRect().width(); int new_column_width = int( first_column_size_ratio_ * content_width ); if ( new_column_width != parent_->columnWidth(0) ) { parent_->setColumnWidth( 0, new_column_width ); parent_->setColumnWidth( 1, content_width - new_column_width ); } int new_x = new_column_width - w / 2 + parent_->columnViewportPosition(0); if ( new_x != x() || parent_->height() != height() ) setGeometry( new_x, 0, w, parent_->height() ); } void SplitterHandle::setRatio( float ratio ) { first_column_size_ratio_ = ratio; updateGeometry(); } float SplitterHandle::getRatio() { return first_column_size_ratio_; } void SplitterHandle::mousePressEvent( QMouseEvent* event ) { if( event->button() == Qt::LeftButton ) { // position of mouse press inside this QWidget x_press_offset_ = event->x(); } } void SplitterHandle::mouseMoveEvent( QMouseEvent* event ) { int padding = 55; if( event->buttons() & Qt::LeftButton ) { QPoint pos_rel_parent = parent_->mapFromGlobal( event->globalPos() ); int new_x = pos_rel_parent.x() - x_press_offset_ - parent_->columnViewportPosition(0); if( new_x > parent_->width() - width() - padding ) { new_x = parent_->width() - width() - padding; } if( new_x < padding ) { new_x = padding; } if( new_x != x() ) { int new_column_width = new_x + width() / 2 - parent_->contentsRect().x(); first_column_size_ratio_ = new_column_width / (float) parent_->contentsRect().width(); updateGeometry(); } } } void SplitterHandle::paintEvent( QPaintEvent* event ) { QPainter painter( this ); painter.setPen( color_ ); painter.drawLine( 1+width() / 2, 0, 1+width() / 2, height() ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/splitter_handle.h000066400000000000000000000061601300447110700221000ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef SPLITTER_HANDLE_H #define SPLITTER_HANDLE_H #include class QTreeView; namespace rviz { /** @brief A tall skinny invisible widget providing left-right sliding * column separator adjustment for a two-column QTreeView via mouse * drags. Shows splitter cursor when mouse hovers over it. Uses * event filtering to catch resize events for the parent. */ class SplitterHandle: public QWidget { Q_OBJECT public: SplitterHandle( QTreeView* parent = 0 ); /** @brief Set the ratio of the parent's left column to the parent widget width. */ void setRatio( float ratio ); /** @brief Get the ratio of the parent's left column to the parent widget width. */ float getRatio(); /** @brief Catch resize events sent to parent to update splitter's * geometry. Always returns false. */ bool eventFilter( QObject* event_target, QEvent* event ); void setColor( QColor color ) { color_ = color; update(); } QColor getColor() const { return color_; } protected: virtual void mousePressEvent( QMouseEvent* event ); virtual void mouseMoveEvent( QMouseEvent* event ); virtual void paintEvent( QPaintEvent* event ); private: /** @brief Update the parent's column widths and this splitter's * geometry based on first_column_size_ratio_. */ void updateGeometry(); QTreeView* parent_; int x_press_offset_; /** The ratio of the first column width to the entire widget width. * Preserved during parent widget resize. */ float first_column_size_ratio_; QColor color_; }; } // end namespace rviz #endif // SPLITTER_HANDLE_H rviz-1.12.4/src/rviz/properties/status_list.cpp000066400000000000000000000075101300447110700216300ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/property_tree_model.h" #include "rviz/properties/status_list.h" namespace rviz { StatusList::StatusList( const QString& name, Property* parent ) : StatusProperty( "", "", Ok, parent ) { setName( name ); setShouldBeSaved( false ); } void StatusList::setName( const QString& name ) { name_prefix_ = name; updateLabel(); } void StatusList::setStatus( Level level, const QString& name, const QString& text ) { QHash::iterator child_iter = status_children_.find( name ); StatusProperty* child; if( child_iter == status_children_.end() ) { child = new StatusProperty( name, text, level, this ); status_children_.insert( name, child ); } else { child = child_iter.value(); child->setLevel( level ); child->setValue( text ); } if( level > level_ ) { setLevel( level ); } else if( level < level_ ) { updateLevel(); } } void StatusList::deleteStatus( const QString& name ) { StatusProperty* child = status_children_.take( name ); if( child ) { delete child; updateLevel(); } } void StatusList::clear() { int num_rows = numChildren(); if( num_rows > 0 ) { QList to_be_deleted = status_children_.values(); status_children_.clear(); // It is important here to clear the status_children_ list before // deleting its contents. On Macs the deletion can indirectly // trigger a call to setStatus(), and status_children_ should not // contain any pointers to deleted memory at that time. for( int i = 0; i < to_be_deleted.size(); i++ ) { delete to_be_deleted[ i ]; } } setLevel( Ok ); } void StatusList::updateLevel() { Level new_level = Ok; QHash::iterator iter; for( iter = status_children_.begin(); iter != status_children_.end(); iter++ ) { Level child_level = iter.value()->getLevel(); if( child_level > new_level ) { new_level = child_level; } } setLevel( new_level ); } void StatusList::setLevel( Level new_level ) { StatusProperty::setLevel( new_level ); updateLabel(); } void StatusList::updateLabel() { StatusProperty::setName( name_prefix_ + ": " + statusWord( getLevel() )); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/status_list.h000066400000000000000000000047121300447110700212760ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef STATUSLIST_H #define STATUSLIST_H #include "rviz/properties/status_property.h" namespace rviz { class StatusList: public StatusProperty { Q_OBJECT public: StatusList( const QString& name = QString( "Status" ), Property* parent = 0 ); virtual void setLevel( Level level ); void setStatus( Level level, const QString& name, const QString& text ); void deleteStatus( const QString& name ); void clear(); void updateLevel(); /** @brief Set the prefix of the name. * * Setting the name to "Foo" will give a displayed name like "Foo: * Ok" or "Foo: Error". */ virtual void setName( const QString& name ); private: /** @brief Update the label text based on the name_prefix_ and the current status level. */ void updateLabel(); QHash status_children_; QString name_prefix_; }; } // end namespace rviz #endif // STATUSLIST_H rviz-1.12.4/src/rviz/properties/status_property.cpp000066400000000000000000000070031300447110700225360ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/property_tree_model.h" #include "rviz/properties/status_property.h" #include "rviz/load_resource.h" namespace rviz { QColor StatusProperty::status_colors_[3] = { QColor(), QColor( 192, 128, 0 ), QColor( 192, 32, 32 ) }; QString StatusProperty::status_words_[3] = { "Ok", "Warn", "Error" }; StatusProperty::StatusProperty( const QString& name, const QString& text, Level level, Property* parent ) : Property( name, text, text, parent ) , level_( level ) { setShouldBeSaved( false ); status_icons_[0] = loadPixmap( "package://rviz/icons/ok.png" ); status_icons_[1] = loadPixmap( "package://rviz/icons/warning.png" ); status_icons_[2] = loadPixmap( "package://rviz/icons/error.png" ); } bool StatusProperty::setValue( const QVariant& new_value ) { setDescription( new_value.toString() ); return Property::setValue( new_value ); } QVariant StatusProperty::getViewData( int column, int role ) const { if ( (getViewFlags(column) & Qt::ItemIsEnabled) && column == 0 && role == Qt::ForegroundRole ) { return statusColor( level_ ); } if( column == 0 && role == Qt::DecorationRole ) { return statusIcon( level_ ); } return Property::getViewData( column, role ); } Qt::ItemFlags StatusProperty::getViewFlags( int column ) const { return Property::getViewFlags( column ); } // static function QColor StatusProperty::statusColor( Level level ) { return status_colors_[ (int) level ]; } // static function QIcon StatusProperty::statusIcon( Level level ) const { return status_icons_[ level ]; } /** @brief Return the word appropriate for the given status level: * "Ok", "Warn", or "Error". */ // static function QString StatusProperty::statusWord( Level level ) { return status_words_[ (int) level ]; } void StatusProperty::setLevel( Level level ) { if( level_ != level ) { level_ = level; if( model_ ) model_->emitDataChanged( this ); } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/status_property.h000066400000000000000000000061451300447110700222110ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef STATUSPROPERTY_H #define STATUSPROPERTY_H #include "rviz/properties/property.h" #include namespace rviz { class StatusProperty: public Property { Q_OBJECT public: enum Level { Ok = 0, Warn = 1, Error = 2 }; // values index into status_colors_ array. StatusProperty( const QString& name, const QString& text, Level level, Property* parent ); /** @brief Set the status text. Overridden from Property. */ virtual bool setValue( const QVariant& new_value ); /** @brief Return data appropriate for the given column (0 or 1) and * role for this StatusProperty. */ virtual QVariant getViewData( int column, int role ) const; /** @brief Return item flags appropriate for the given column (0 or * 1) for this StatusProperty. */ virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Return the color appropriate for the given status level. * * Returns an invalid QColor for Ok status, meaning we should use * the default text color. */ static QColor statusColor( Level level ); /** @brief Return the word appropriate for the given status level: * "Ok", "Warn", or "Error". */ static QString statusWord( Level level ); QIcon statusIcon( Level level ) const; virtual void setLevel( Level level ); virtual Level getLevel() const { return level_; } protected: Level level_; private: static QColor status_colors_[3]; static QString status_words_[3]; QIcon status_icons_[3]; }; typedef StatusProperty::Level StatusLevel; } // end namespace rviz #endif // STATUSPROPERTY_H rviz-1.12.4/src/rviz/properties/string_property.cpp000066400000000000000000000041101300447110700225150ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/properties/string_property.h" namespace rviz { StringProperty::StringProperty( const QString& name, const QString& default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : Property( name, default_value, description, parent, changed_slot, receiver ) {} } // end namespace rviz rviz-1.12.4/src/rviz/properties/string_property.h000066400000000000000000000047451300447110700222000ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef STRING_PROPERTY_H #define STRING_PROPERTY_H #include #include "rviz/properties/property.h" namespace rviz { /** @brief Property specialized for string values. */ class StringProperty: public Property { Q_OBJECT public: StringProperty( const QString& name = QString(), const QString& default_value = QString(), const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); std::string getStdString() { return getValue().toString().toStdString(); } QString getString() { return getValue().toString(); } public Q_SLOTS: bool setString( const QString& str ) { return setValue( str ); } bool setStdString( const std::string& std_str ) { return setValue( QString::fromStdString( std_str )); } }; } // end namespace rviz #endif // STRING_PROPERTY_H rviz-1.12.4/src/rviz/properties/tf_frame_property.cpp000066400000000000000000000104021300447110700227730ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include // for std::sort #include "rviz/frame_manager.h" #include "rviz/properties/tf_frame_property.h" namespace rviz { const QString TfFrameProperty::FIXED_FRAME_STRING = ""; TfFrameProperty::TfFrameProperty( const QString& name, const QString& default_value, const QString& description, Property* parent, FrameManager* frame_manager, bool include_fixed_frame_string, const char *changed_slot, QObject* receiver ) : EditableEnumProperty( name, default_value, description, parent, changed_slot, receiver ) , frame_manager_( NULL ) , include_fixed_frame_string_( include_fixed_frame_string ) { // Parent class EditableEnumProperty has requestOptions() signal. connect( this, SIGNAL( requestOptions( EditableEnumProperty* )), this, SLOT( fillFrameList() )); setFrameManager( frame_manager ); } bool TfFrameProperty::setValue( const QVariant& new_value ) { QString new_string = new_value.toString(); if( new_string.size() > 0 && new_string[ 0 ] == '/' ) { new_string = new_string.right( new_string.size() - 1 ); } bool result = EditableEnumProperty::setValue( new_string ); return result; } void TfFrameProperty::setFrameManager( FrameManager* frame_manager ) { if( frame_manager_ && include_fixed_frame_string_ ) { disconnect( frame_manager_, SIGNAL( fixedFrameChanged() ), this, SLOT( handleFixedFrameChange() )); } frame_manager_ = frame_manager; if( frame_manager_ && include_fixed_frame_string_ ) { connect( frame_manager_, SIGNAL( fixedFrameChanged() ), this, SLOT( handleFixedFrameChange() )); } } void TfFrameProperty::fillFrameList() { std::vector std_frames; frame_manager_->getTFClient()->getFrameStrings( std_frames ); std::sort( std_frames.begin(), std_frames.end() ); clearOptions(); if( include_fixed_frame_string_ ) { addOption( FIXED_FRAME_STRING ); } for( size_t i = 0; i < std_frames.size(); i++ ) { addOptionStd( std_frames[ i ]); } } QString TfFrameProperty::getFrame() const { QString frame = getValue().toString(); if( frame == FIXED_FRAME_STRING && frame_manager_ ) { return QString::fromStdString( frame_manager_->getFixedFrame() ); } return frame; } std::string TfFrameProperty::getFrameStd() const { return getFrame().toStdString(); } void TfFrameProperty::handleFixedFrameChange() { if( getValue().toString() == FIXED_FRAME_STRING ) { Q_EMIT changed(); } } } // end namespace rviz rviz-1.12.4/src/rviz/properties/tf_frame_property.h000066400000000000000000000057271300447110700224560ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef TF_FRAME_PROPERTY_H #define TF_FRAME_PROPERTY_H #include #include "rviz/properties/editable_enum_property.h" namespace rviz { class FrameManager; class TfFrameProperty: public EditableEnumProperty { Q_OBJECT public: TfFrameProperty( const QString& name = QString(), const QString& default_value = QString(), const QString& description = QString(), Property* parent = 0, FrameManager* frame_manager = 0, bool include_fixed_frame_string = false, const char *changed_slot = 0, QObject* receiver = 0 ); /** @brief Override from Property to resolve the frame name on the way in. */ virtual bool setValue( const QVariant& new_value ); QString getFrame() const; std::string getFrameStd() const; void setFrameManager( FrameManager* frame_manager ); FrameManager* getFrameManager() const { return frame_manager_; } static const QString FIXED_FRAME_STRING; private Q_SLOTS: void fillFrameList(); /** @brief If this property is currently set to FIXED_FRAME_STRING, * this emits changed() to let users know that a call to getFrame() * will now return something different. */ void handleFixedFrameChange(); private: FrameManager* frame_manager_; bool include_fixed_frame_string_; }; } // end namespace rviz #endif // TF_FRAME_PROPERTY_H rviz-1.12.4/src/rviz/properties/vector_property.cpp000066400000000000000000000121411300447110700225140ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/vector_property.h" namespace rviz { VectorProperty::VectorProperty( const QString& name, const Ogre::Vector3& default_value, const QString& description, Property* parent, const char *changed_slot, QObject* receiver ) : Property( name, QVariant(), description, parent, changed_slot, receiver ) , vector_( default_value ) , ignore_child_updates_( false ) { x_ = new Property( "X", vector_.x, "X coordinate", this ); y_ = new Property( "Y", vector_.y, "Y coordinate", this ); z_ = new Property( "Z", vector_.z, "Z coordinate", this ); updateString(); connect( x_, SIGNAL( aboutToChange() ), this, SLOT( emitAboutToChange() )); connect( y_, SIGNAL( aboutToChange() ), this, SLOT( emitAboutToChange() )); connect( z_, SIGNAL( aboutToChange() ), this, SLOT( emitAboutToChange() )); connect( x_, SIGNAL( changed() ), this, SLOT( updateFromChildren() )); connect( y_, SIGNAL( changed() ), this, SLOT( updateFromChildren() )); connect( z_, SIGNAL( changed() ), this, SLOT( updateFromChildren() )); } bool VectorProperty::setVector( const Ogre::Vector3& new_vector ) { if( new_vector != vector_ ) { Q_EMIT aboutToChange(); vector_ = new_vector; ignore_child_updates_ = true; x_->setValue( vector_.x ); y_->setValue( vector_.y ); z_->setValue( vector_.z ); ignore_child_updates_ = false; updateString(); Q_EMIT changed(); return true; } return false; } bool VectorProperty::setValue( const QVariant& new_value ) { QStringList strings = new_value.toString().split( ';' ); if( strings.size() >= 3 ) { bool x_ok = true; float x = strings[ 0 ].toFloat( &x_ok ); bool y_ok = true; float y = strings[ 1 ].toFloat( &y_ok ); bool z_ok = true; float z = strings[ 2 ].toFloat( &z_ok ); if( x_ok && y_ok && z_ok ) { return setVector( Ogre::Vector3( x, y, z )); } } return false; } void VectorProperty::updateFromChildren() { if( !ignore_child_updates_ ) { vector_.x = x_->getValue().toFloat(); vector_.y = y_->getValue().toFloat(); vector_.z = z_->getValue().toFloat(); updateString(); Q_EMIT changed(); } } void VectorProperty::emitAboutToChange() { if( !ignore_child_updates_ ) { Q_EMIT aboutToChange(); } } void VectorProperty::updateString() { value_ = QString( "%1; %2; %3" ) .arg( vector_.x, 0, 'g', 5 ) .arg( vector_.y, 0, 'g', 5 ) .arg( vector_.z, 0, 'g', 5 ); } void VectorProperty::load( const Config& config ) { float x, y, z; if( config.mapGetFloat( "X", &x ) && config.mapGetFloat( "Y", &y ) && config.mapGetFloat( "Z", &z )) { // Calling setVector() once explicitly is better than letting the // Property class load the X, Y, and Z children independently, // which would result in at least 3 calls to setVector(). setVector( Ogre::Vector3( x, y, z )); } } void VectorProperty::save( Config config ) const { // Saving the child values explicitly avoids having Property::save() // save the summary string version of the property. config.mapSetValue( "X", x_->getValue() ); config.mapSetValue( "Y", y_->getValue() ); config.mapSetValue( "Z", z_->getValue() ); } void VectorProperty::setReadOnly( bool read_only ) { Property::setReadOnly( read_only ); x_->setReadOnly( read_only ); y_->setReadOnly( read_only ); z_->setReadOnly( read_only ); } } // end namespace rviz rviz-1.12.4/src/rviz/properties/vector_property.h000066400000000000000000000054701300447110700221700ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef VECTOR_PROPERTY_H #define VECTOR_PROPERTY_H #include #include "rviz/properties/property.h" namespace rviz { class VectorProperty: public Property { Q_OBJECT public: VectorProperty( const QString& name = QString(), const Ogre::Vector3& default_value = Ogre::Vector3::ZERO, const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ); virtual bool setVector( const Ogre::Vector3& vector ); virtual Ogre::Vector3 getVector() const { return vector_; } bool add( const Ogre::Vector3& offset ) { return setVector( getVector() + offset ); } virtual bool setValue( const QVariant& new_value ); virtual void load( const Config& config ); virtual void save( Config config ) const; /** @brief Overridden from Property to propagate read-only-ness to children. */ virtual void setReadOnly( bool read_only ); private Q_SLOTS: void updateFromChildren(); void emitAboutToChange(); private: void updateString(); Ogre::Vector3 vector_; Property* x_; Property* y_; Property* z_; bool ignore_child_updates_; }; } // end namespace rviz #endif // VECTOR_PROPERTY_H rviz-1.12.4/src/rviz/render_panel.cpp000066400000000000000000000141771300447110700175230ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "rviz/display.h" #include "rviz/view_controller.h" #include "rviz/viewport_mouse_event.h" #include "rviz/visualization_manager.h" #include "rviz/window_manager_interface.h" #include "rviz/render_panel.h" namespace rviz { RenderPanel::RenderPanel( QWidget* parent ) : QtOgreRenderWindow( parent ) , mouse_x_( 0 ) , mouse_y_( 0 ) , context_( 0 ) , scene_manager_( 0 ) , view_controller_( 0 ) , fake_mouse_move_event_timer_( new QTimer() ) , default_camera_(0) , context_menu_visible_(false) { setFocus( Qt::OtherFocusReason ); } RenderPanel::~RenderPanel() { delete fake_mouse_move_event_timer_; if( scene_manager_ && default_camera_ ) { scene_manager_->destroyCamera( default_camera_ ); } if( scene_manager_ ) { scene_manager_->removeListener( this ); } } void RenderPanel::initialize(Ogre::SceneManager* scene_manager, DisplayContext* context) { context_ = context; scene_manager_ = scene_manager; scene_manager_->addListener( this ); std::stringstream ss; static int count = 0; ss << "RenderPanelCamera" << count++; default_camera_ = scene_manager_->createCamera(ss.str()); default_camera_->setNearClipDistance(0.01f); default_camera_->setPosition(0, 10, 15); default_camera_->lookAt(0, 0, 0); setCamera( default_camera_ ); connect( fake_mouse_move_event_timer_, SIGNAL( timeout() ), this, SLOT( sendMouseMoveEvent() )); fake_mouse_move_event_timer_->start( 33 /*milliseconds*/ ); } void RenderPanel::sendMouseMoveEvent() { QPoint cursor_pos = QCursor::pos(); QPoint mouse_rel_widget = mapFromGlobal( cursor_pos ); if( rect().contains( mouse_rel_widget )) { bool mouse_over_this = false; QWidget *w = QApplication::widgetAt( cursor_pos ); while( w ) { if( w == this ) { mouse_over_this = true; break; } w = w->parentWidget(); } if( !mouse_over_this ) { return; } QMouseEvent fake_event( QEvent::MouseMove, mouse_rel_widget, Qt::NoButton, QApplication::mouseButtons(), QApplication::keyboardModifiers() ); onRenderWindowMouseEvents( &fake_event ); } } void RenderPanel::leaveEvent ( QEvent * event ) { setCursor( Qt::ArrowCursor ); if ( context_ ) { context_->setStatus(""); } } void RenderPanel::onRenderWindowMouseEvents( QMouseEvent* event ) { int last_x = mouse_x_; int last_y = mouse_y_; mouse_x_ = event->x(); mouse_y_ = event->y(); if (context_) { setFocus( Qt::MouseFocusReason ); ViewportMouseEvent vme(this, getViewport(), event, last_x, last_y); context_->handleMouseEvent(vme); event->accept(); } } void RenderPanel::wheelEvent( QWheelEvent* event ) { int last_x = mouse_x_; int last_y = mouse_y_; mouse_x_ = event->x(); mouse_y_ = event->y(); if (context_) { setFocus( Qt::MouseFocusReason ); ViewportMouseEvent vme(this, getViewport(), event, last_x, last_y); context_->handleMouseEvent(vme); event->accept(); } } void RenderPanel::keyPressEvent( QKeyEvent* event ) { if( context_ ) { context_->handleChar( event, this ); } } void RenderPanel::setViewController( ViewController* controller ) { view_controller_ = controller; if( view_controller_ ) { setCamera( view_controller_->getCamera() ); view_controller_->activate(); } else { setCamera( NULL ); } } void RenderPanel::showContextMenu( boost::shared_ptr menu ) { boost::mutex::scoped_lock lock(context_menu_mutex_); context_menu_ = menu; context_menu_visible_ = true; QApplication::postEvent( this, new QContextMenuEvent( QContextMenuEvent::Mouse, QPoint() )); } void RenderPanel::onContextMenuHide() { context_menu_visible_ = false; } bool RenderPanel::contextMenuVisible() { return context_menu_visible_; } void RenderPanel::contextMenuEvent( QContextMenuEvent* event ) { boost::shared_ptr context_menu; { boost::mutex::scoped_lock lock(context_menu_mutex_); context_menu.swap(context_menu_); } if ( context_menu ) { connect( context_menu.get(), SIGNAL( aboutToHide() ), this, SLOT( onContextMenuHide() ) ); context_menu->exec( QCursor::pos() ); } } void RenderPanel::sceneManagerDestroyed( Ogre::SceneManager* destroyed_scene_manager ) { if( destroyed_scene_manager == scene_manager_ ) { scene_manager_ = NULL; default_camera_ = NULL; setCamera( NULL ); } } } // namespace rviz rviz-1.12.4/src/rviz/render_panel.h000066400000000000000000000116661300447110700171700ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_RENDER_PANEL_H #define RVIZ_RENDER_PANEL_H #include "ogre_helpers/qt_ogre_render_window.h" #ifndef Q_MOC_RUN #include #include #endif #include #include namespace Ogre { class Root; class Camera; class RaySceneQuery; class ParticleSystem; } namespace ros { class Node; } class QMenu; class QKeyEvent; class PropertyTreeWidget; namespace rviz { class Display; class DisplayContext; class ViewController; /** * A widget which shows an OGRE-rendered scene in RViz. * * RenderPanel displays a scene and forwards mouse and key events to * the DisplayContext (which further forwards them to the active * Tool, etc.) */ class RenderPanel: public QtOgreRenderWindow, public Ogre::SceneManager::Listener { Q_OBJECT public: /** Constructor. Ogre::Root::createRenderWindow() is called within. */ RenderPanel( QWidget* parent = 0 ); virtual ~RenderPanel(); /** This sets up the Ogre::Camera for this widget. */ void initialize(Ogre::SceneManager* scene_manager, DisplayContext* manager); DisplayContext* getManager() { return context_; } ViewController* getViewController() { return view_controller_; } /** @brief Set the ViewController which should control the camera * position for this view. */ void setViewController( ViewController* controller ); /** Show the given menu as a context menu, positioned based on the * current mouse position. This can be called from any thread. */ void showContextMenu( boost::shared_ptr menu ); /** Return true if the context menu for this panel is visible */ bool contextMenuVisible(); virtual void sceneManagerDestroyed( Ogre::SceneManager* source ); protected: // Override from QWidget void contextMenuEvent( QContextMenuEvent* event ); /// Called when any mouse event happens inside the render window void onRenderWindowMouseEvents( QMouseEvent* event ); // QWidget mouse events all get sent to onRenderWindowMouseEvents(). // QMouseEvent.type() distinguishes them later. virtual void mouseMoveEvent( QMouseEvent* event ) { onRenderWindowMouseEvents( event ); } virtual void mousePressEvent( QMouseEvent* event ) { onRenderWindowMouseEvents( event ); } virtual void mouseReleaseEvent( QMouseEvent* event ) { onRenderWindowMouseEvents( event ); } virtual void mouseDoubleClickEvent( QMouseEvent* event ) { onRenderWindowMouseEvents( event ); } virtual void leaveEvent ( QEvent * event ); /// Called when there is a mouse-wheel event. virtual void wheelEvent( QWheelEvent* event ); virtual void keyPressEvent( QKeyEvent* event ); // Mouse handling int mouse_x_; ///< X position of the last mouse event int mouse_y_; ///< Y position of the last mouse event DisplayContext* context_; Ogre::SceneManager* scene_manager_; ViewController* view_controller_; boost::shared_ptr context_menu_; boost::mutex context_menu_mutex_; bool context_menu_visible_; // Pointer to the Display which is using this render panel, or NULL // if this does not belong to a Display. Display* display_; private Q_SLOTS: void sendMouseMoveEvent(); void onContextMenuHide(); private: QTimer* fake_mouse_move_event_timer_; Ogre::Camera* default_camera_; ///< A default camera created in initialize(). }; } // namespace rviz #endif rviz-1.12.4/src/rviz/robot/000077500000000000000000000000001300447110700154745ustar00rootroot00000000000000rviz-1.12.4/src/rviz/robot/link_updater.h000066400000000000000000000043371300447110700203350ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ROBOT_LINK_UPDATER_H #define RVIZ_ROBOT_LINK_UPDATER_H #include #include "rviz/properties/status_property.h" namespace Ogre { class Vector3; class Quaternion; } namespace rviz { class LinkUpdater { public: virtual bool getLinkTransforms(const std::string& link_name, Ogre::Vector3& visual_position, Ogre::Quaternion& visual_orientation, Ogre::Vector3& collision_position, Ogre::Quaternion& collision_orientation) const = 0; virtual void setLinkStatus(StatusLevel level, const std::string& link_name, const std::string& text) const {} }; } // namespace rviz #endif // RVIZ_ROBOT_LINK_UPDATER_H rviz-1.12.4/src/rviz/robot/robot.cpp000066400000000000000000000572601300447110700173370ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "robot.h" #include "robot_link.h" #include "robot_joint.h" #include "properties/property.h" #include "properties/enum_property.h" #include "properties/bool_property.h" #include "display_context.h" #include "ogre_helpers/object.h" #include "ogre_helpers/shape.h" #include "ogre_helpers/axes.h" #include #include #include #include #include #include #include #include #include namespace rviz { Robot::Robot( Ogre::SceneNode* root_node, DisplayContext* context, const std::string& name, Property* parent_property ) : scene_manager_( context->getSceneManager() ) , visible_( true ) , visual_visible_( true ) , collision_visible_( false ) , context_( context ) , name_( name ) , doing_set_checkbox_( false ) , robot_loaded_( false ) , inChangedEnableAllLinks( false ) { root_visual_node_ = root_node->createChildSceneNode(); root_collision_node_ = root_node->createChildSceneNode(); root_other_node_ = root_node->createChildSceneNode(); link_factory_ = new LinkFactory(); setVisualVisible( visual_visible_ ); setCollisionVisible( collision_visible_ ); setAlpha(1.0f); link_tree_ = new Property( "Links", QVariant(), "", parent_property ); link_tree_->hide(); // hide until loaded link_tree_style_ = new EnumProperty( "Link Tree Style", "", "How the list of links is displayed", link_tree_, SLOT( changedLinkTreeStyle() ), this ); initLinkTreeStyle(); expand_tree_= new BoolProperty( "Expand Tree", false, "Expand or collapse link tree", link_tree_, SLOT( changedExpandTree() ), this ); expand_link_details_ = new BoolProperty( "Expand Link Details", false, "Expand link details (sub properties) to see all info for all links.", link_tree_, SLOT( changedExpandLinkDetails() ), this ); expand_joint_details_ = new BoolProperty( "Expand Joint Details", false, "Expand joint details (sub properties) to see all info for all joints.", link_tree_, SLOT( changedExpandJointDetails() ), this ); enable_all_links_ = new BoolProperty( "All Links Enabled", true, "Turn all links on or off.", link_tree_, SLOT( changedEnableAllLinks() ), this ); } Robot::~Robot() { clear(); scene_manager_->destroySceneNode( root_visual_node_->getName() ); scene_manager_->destroySceneNode( root_collision_node_->getName() ); scene_manager_->destroySceneNode( root_other_node_->getName() ); delete link_factory_; } void Robot::setLinkFactory(LinkFactory *link_factory) { if (link_factory) { delete link_factory_; link_factory_ = link_factory; } } void Robot::setVisible( bool visible ) { visible_ = visible; if ( visible ) { root_visual_node_->setVisible( visual_visible_ ); root_collision_node_->setVisible( collision_visible_ ); updateLinkVisibilities(); } else { root_visual_node_->setVisible( false ); root_collision_node_->setVisible( false ); updateLinkVisibilities(); } } void Robot::setVisualVisible( bool visible ) { visual_visible_ = visible; updateLinkVisibilities(); } void Robot::setCollisionVisible( bool visible ) { collision_visible_ = visible; updateLinkVisibilities(); } void Robot::updateLinkVisibilities() { M_NameToLink::iterator it = links_.begin(); M_NameToLink::iterator end = links_.end(); for ( ; it != end; ++it ) { RobotLink* link = it->second; link->updateVisibility(); } } bool Robot::isVisible() { return visible_; } bool Robot::isVisualVisible() { return visual_visible_; } bool Robot::isCollisionVisible() { return collision_visible_; } void Robot::setAlpha(float a) { alpha_ = a; M_NameToLink::iterator it = links_.begin(); M_NameToLink::iterator end = links_.end(); for ( ; it != end; ++it ) { RobotLink* link = it->second; link->setRobotAlpha(alpha_); } } void Robot::clear() { // unparent all link and joint properties so they can be deleted in arbitrary // order without being delete by their parent propeties (which vary based on // style) unparentLinkProperties(); M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end; ++link_it ) { RobotLink* link = link_it->second; delete link; } M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end; ++joint_it ) { RobotJoint* joint = joint_it->second; delete joint; } links_.clear(); joints_.clear(); root_visual_node_->removeAndDestroyAllChildren(); root_collision_node_->removeAndDestroyAllChildren(); root_other_node_->removeAndDestroyAllChildren(); } RobotLink* Robot::LinkFactory::createLink( Robot* robot, const urdf::LinkConstSharedPtr& link, const std::string& parent_joint_name, bool visual, bool collision) { return new RobotLink(robot, link, parent_joint_name, visual, collision); } RobotJoint* Robot::LinkFactory::createJoint( Robot* robot, const urdf::JointConstSharedPtr& joint) { return new RobotJoint(robot, joint); } void Robot::load( const urdf::ModelInterface &urdf, bool visual, bool collision ) { link_tree_->hide(); // hide until loaded robot_loaded_ = false; // clear out any data (properties, shapes, etc) from a previously loaded robot. clear(); // the root link is discovered below. Set to NULL until found. root_link_ = NULL; // Create properties for each link. // Properties are not added to display until changedLinkTreeStyle() is called (below). { typedef std::map M_NameToUrdfLink; M_NameToUrdfLink::const_iterator link_it = urdf.links_.begin(); M_NameToUrdfLink::const_iterator link_end = urdf.links_.end(); for( ; link_it != link_end; ++link_it ) { const urdf::LinkConstSharedPtr& urdf_link = link_it->second; std::string parent_joint_name; if (urdf_link != urdf.getRoot() && urdf_link->parent_joint) { parent_joint_name = urdf_link->parent_joint->name; } RobotLink* link = link_factory_->createLink( this, urdf_link, parent_joint_name, visual, collision ); if (urdf_link == urdf.getRoot()) { root_link_ = link; } links_[urdf_link->name] = link; link->setRobotAlpha( alpha_ ); } } // Create properties for each joint. // Properties are not added to display until changedLinkTreeStyle() is called (below). { typedef std::map M_NameToUrdfJoint; M_NameToUrdfJoint::const_iterator joint_it = urdf.joints_.begin(); M_NameToUrdfJoint::const_iterator joint_end = urdf.joints_.end(); for( ; joint_it != joint_end; ++joint_it ) { const urdf::JointConstSharedPtr& urdf_joint = joint_it->second; RobotJoint* joint = link_factory_->createJoint( this, urdf_joint ); joints_[urdf_joint->name] = joint; joint->setRobotAlpha( alpha_ ); } } // robot is now loaded robot_loaded_ = true; link_tree_->show(); // set the link tree style and add link/joint properties to rviz pane. setLinkTreeStyle(LinkTreeStyle(link_tree_style_->getOptionInt())); changedLinkTreeStyle(); // at startup the link tree is collapsed since it is large and not often needed. link_tree_->collapse(); setVisualVisible( isVisualVisible() ); setCollisionVisible( isCollisionVisible() ); } void Robot::unparentLinkProperties() { // remove link properties from their parents M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end ; ++link_it ) { link_it->second->setParentProperty(NULL); } // remove joint properties from their parents M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end ; ++joint_it ) { joint_it->second->setParentProperty(NULL); } } void Robot::useDetailProperty(bool use_detail) { // remove sub properties and add them to detail M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end ; ++link_it ) { link_it->second->useDetailProperty(use_detail); } // remove joint properties from their parents M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end ; ++joint_it ) { joint_it->second->useDetailProperty(use_detail); } } void Robot::changedExpandTree() { bool expand = expand_tree_->getBool(); M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end ; ++link_it ) { if (expand) link_it->second->getLinkProperty()->expand(); else link_it->second->getLinkProperty()->collapse(); } M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end ; ++joint_it ) { if (expand) joint_it->second->getJointProperty()->expand(); else joint_it->second->getJointProperty()->collapse(); } } void Robot::changedHideSubProperties() { bool hide = /* !show_details_->getBool(); */ false; M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end ; ++link_it ) { link_it->second->hideSubProperties(hide); } M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end ; ++joint_it ) { joint_it->second->hideSubProperties(hide); } } void Robot::changedExpandLinkDetails() { bool expand = expand_link_details_->getBool(); M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end ; ++link_it ) { link_it->second->expandDetails(expand); } } void Robot::changedExpandJointDetails() { bool expand = expand_joint_details_->getBool(); M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end ; ++joint_it ) { joint_it->second->expandDetails(expand); } } void Robot::changedEnableAllLinks() { if (doing_set_checkbox_) return; bool enable = enable_all_links_->getBool(); inChangedEnableAllLinks = true; M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end ; ++link_it ) { if (link_it->second->hasGeometry()) { link_it->second->getLinkProperty()->setValue(enable); } } M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end ; ++joint_it ) { if (joint_it->second->hasDescendentLinksWithGeometry()) { joint_it->second->getJointProperty()->setValue(enable); } } inChangedEnableAllLinks = false; } void Robot::setEnableAllLinksCheckbox(QVariant val) { // doing_set_checkbox_ prevents changedEnableAllLinks from turning all // links off when we modify the enable_all_links_ property. doing_set_checkbox_ = true; enable_all_links_->setValue(val); doing_set_checkbox_ = false; } void Robot::initLinkTreeStyle() { style_name_map_.clear(); style_name_map_[STYLE_LINK_LIST] = "Links in Alphabetic Order"; style_name_map_[STYLE_JOINT_LIST] = "Joints in Alphabetic Order"; style_name_map_[STYLE_LINK_TREE] = "Tree of links"; style_name_map_[STYLE_JOINT_LINK_TREE] = "Tree of links and joints"; link_tree_style_->clearOptions(); std::map::const_iterator style_it = style_name_map_.begin(); std::map::const_iterator style_end = style_name_map_.end(); for ( ; style_it != style_end ; ++style_it ) { link_tree_style_->addOptionStd( style_it->second, style_it->first ); } } bool Robot::styleShowLink(LinkTreeStyle style) { return style == STYLE_LINK_LIST || style == STYLE_LINK_TREE || style == STYLE_JOINT_LINK_TREE; } bool Robot::styleShowJoint(LinkTreeStyle style) { return style == STYLE_JOINT_LIST || style == STYLE_JOINT_LINK_TREE; } bool Robot::styleIsTree(LinkTreeStyle style) { return style == STYLE_LINK_TREE || style == STYLE_JOINT_LINK_TREE; } void Robot::setLinkTreeStyle(LinkTreeStyle style) { std::map::const_iterator style_it = style_name_map_.find(style); if (style_it == style_name_map_.end()) link_tree_style_->setValue(style_name_map_[STYLE_DEFAULT].c_str()); else link_tree_style_->setValue(style_it->second.c_str()); } // insert properties into link_tree_ according to style void Robot::changedLinkTreeStyle() { if (!robot_loaded_) return; LinkTreeStyle style = LinkTreeStyle(link_tree_style_->getOptionInt()); unparentLinkProperties(); //expand_tree_->setValue(false); switch (style) { case STYLE_LINK_TREE: case STYLE_JOINT_LINK_TREE: useDetailProperty(true); if (root_link_) { addLinkToLinkTree(style, link_tree_, root_link_); } break; case STYLE_JOINT_LIST: { useDetailProperty(false); M_NameToJoint::iterator joint_it = joints_.begin(); M_NameToJoint::iterator joint_end = joints_.end(); for ( ; joint_it != joint_end ; ++joint_it ) { joint_it->second->setParentProperty(link_tree_); joint_it->second->setJointPropertyDescription(); } break; } case STYLE_LINK_LIST: default: useDetailProperty(false); M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end ; ++link_it ) { link_it->second->setParentProperty(link_tree_); } break; } switch (style) { case STYLE_LINK_TREE: link_tree_->setName("Link Tree"); link_tree_->setDescription("A tree of all links in the robot. Uncheck a link to hide its geometry."); expand_tree_->show(); expand_link_details_->show(); expand_joint_details_->hide(); break; case STYLE_JOINT_LINK_TREE: link_tree_->setName("Link/Joint Tree"); link_tree_->setDescription("A tree of all joints and links in the robot. Uncheck a link to hide its geometry."); expand_tree_->show(); expand_link_details_->show(); expand_joint_details_->show(); break; case STYLE_JOINT_LIST: link_tree_->setName("Joints"); link_tree_->setDescription("All joints in the robot in alphabetic order."); expand_tree_->hide(); expand_link_details_->hide(); expand_joint_details_->show(); break; case STYLE_LINK_LIST: default: link_tree_->setName("Links"); link_tree_->setDescription("All links in the robot in alphabetic order. Uncheck a link to hide its geometry."); expand_tree_->hide(); expand_link_details_->show(); expand_joint_details_->hide(); break; } expand_link_details_->setValue(false); expand_joint_details_->setValue(false); expand_tree_->setValue(false); calculateJointCheckboxes(); } // recursive helper for setLinkTreeStyle() when style is *_TREE void Robot::addLinkToLinkTree(LinkTreeStyle style, Property *parent, RobotLink *link) { if (styleShowLink(style)) { link->setParentProperty(parent); parent = link->getLinkProperty(); } std::vector::const_iterator child_joint_it = link->getChildJointNames().begin(); std::vector::const_iterator child_joint_end = link->getChildJointNames().end(); for ( ; child_joint_it != child_joint_end ; ++child_joint_it ) { RobotJoint* child_joint = getJoint( *child_joint_it ); if (child_joint) { addJointToLinkTree(style, parent, child_joint); } } } // recursive helper for setLinkTreeStyle() when style is *_TREE void Robot::addJointToLinkTree(LinkTreeStyle style, Property *parent, RobotJoint *joint) { if (styleShowJoint(style)) { joint->setParentProperty(parent); parent = joint->getJointProperty(); joint->setJointPropertyDescription(); } RobotLink *link = getLink( joint->getChildLinkName() ); if (link) { addLinkToLinkTree(style, parent, link); } } RobotLink* Robot::getLink( const std::string& name ) { M_NameToLink::iterator it = links_.find( name ); if ( it == links_.end() ) { ROS_WARN( "Link [%s] does not exist", name.c_str() ); return NULL; } return it->second; } RobotJoint* Robot::getJoint( const std::string& name ) { M_NameToJoint::iterator it = joints_.find( name ); if ( it == joints_.end() ) { ROS_WARN( "Joint [%s] does not exist", name.c_str() ); return NULL; } return it->second; } void Robot::calculateJointCheckboxes() { if (inChangedEnableAllLinks || !robot_loaded_) return; int links_with_geom_checked = 0; int links_with_geom_unchecked = 0; // check root link RobotLink *link = root_link_; if(!link) { setEnableAllLinksCheckbox(QVariant()); return; } if (link->hasGeometry()) { bool checked = link->getLinkProperty()->getValue().toBool(); links_with_geom_checked += checked ? 1 : 0; links_with_geom_unchecked += checked ? 0 : 1; } int links_with_geom = links_with_geom_checked + links_with_geom_unchecked; // check all child links and joints recursively std::vector::const_iterator child_joint_it = link->getChildJointNames().begin(); std::vector::const_iterator child_joint_end = link->getChildJointNames().end(); for ( ; child_joint_it != child_joint_end ; ++child_joint_it ) { RobotJoint* child_joint = getJoint( *child_joint_it ); if (child_joint) { int child_links_with_geom; int child_links_with_geom_checked; int child_links_with_geom_unchecked; child_joint->calculateJointCheckboxesRecursive(child_links_with_geom, child_links_with_geom_checked, child_links_with_geom_unchecked); links_with_geom_checked += child_links_with_geom_checked; links_with_geom_unchecked += child_links_with_geom_unchecked; } } links_with_geom = links_with_geom_checked + links_with_geom_unchecked; if (!links_with_geom) { setEnableAllLinksCheckbox(QVariant()); } else { setEnableAllLinksCheckbox(links_with_geom_unchecked == 0); } } void Robot::update(const LinkUpdater& updater) { M_NameToLink::iterator link_it = links_.begin(); M_NameToLink::iterator link_end = links_.end(); for ( ; link_it != link_end; ++link_it ) { RobotLink* link = link_it->second; link->setToNormalMaterial(); Ogre::Vector3 visual_position, collision_position; Ogre::Quaternion visual_orientation, collision_orientation; if( updater.getLinkTransforms( link->getName(), visual_position, visual_orientation, collision_position, collision_orientation )) { // Check if visual_orientation, visual_position, collision_orientation, and collision_position are NaN. if (visual_orientation.isNaN()) { ROS_ERROR_THROTTLE( 1.0, "visual orientation of %s contains NaNs. Skipping render as long as the orientation is invalid.", link->getName().c_str() ); continue; } if (visual_position.isNaN()) { ROS_ERROR_THROTTLE( 1.0, "visual position of %s contains NaNs. Skipping render as long as the position is invalid.", link->getName().c_str() ); continue; } if (collision_orientation.isNaN()) { ROS_ERROR_THROTTLE( 1.0, "collision orientation of %s contains NaNs. Skipping render as long as the orientation is invalid.", link->getName().c_str() ); continue; } if (collision_position.isNaN()) { ROS_ERROR_THROTTLE( 1.0, "collision position of %s contains NaNs. Skipping render as long as the position is invalid.", link->getName().c_str() ); continue; } link->setTransforms( visual_position, visual_orientation, collision_position, collision_orientation ); std::vector::const_iterator joint_it = link->getChildJointNames().begin(); std::vector::const_iterator joint_end = link->getChildJointNames().end(); for ( ; joint_it != joint_end ; ++joint_it ) { RobotJoint *joint = getJoint(*joint_it); if (joint) { joint->setTransforms(visual_position, visual_orientation); } } } else { link->setToErrorMaterial(); } } } void Robot::setPosition( const Ogre::Vector3& position ) { root_visual_node_->setPosition( position ); root_collision_node_->setPosition( position ); } void Robot::setOrientation( const Ogre::Quaternion& orientation ) { root_visual_node_->setOrientation( orientation ); root_collision_node_->setOrientation( orientation ); } void Robot::setScale( const Ogre::Vector3& scale ) { root_visual_node_->setScale( scale ); root_collision_node_->setScale( scale ); } const Ogre::Vector3& Robot::getPosition() { return root_visual_node_->getPosition(); } const Ogre::Quaternion& Robot::getOrientation() { return root_visual_node_->getOrientation(); } } // namespace rviz rviz-1.12.4/src/rviz/robot/robot.h000066400000000000000000000227771300447110700170110ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ROBOT_H_ #define RVIZ_ROBOT_H_ #include "link_updater.h" #include #include #include #include #include #include // can be replaced later by urdf_model/types.h namespace Ogre { class SceneManager; class Entity; class SceneNode; class Vector3; class Quaternion; class Any; class RibbonTrail; class SceneNode; } namespace rviz { class Object; class Axes; } namespace tf { class TransformListener; } namespace rviz { class Property; class EnumProperty; class BoolProperty; class Robot; class RobotLink; class RobotJoint; class DisplayContext; /** * \class Robot * * A helper class to draw a representation of a robot, as specified by a URDF. Can display either the visual models of the robot, * or the collision models. */ class Robot : public QObject { Q_OBJECT public: Robot( Ogre::SceneNode* root_node, DisplayContext* context, const std::string& name, Property* parent_property ); virtual ~Robot(); /** * \brief Loads meshes/primitives from a robot description. Calls clear() before loading. * * @param urdf The robot description to read from * @param visual Whether or not to load the visual representation * @param collision Whether or not to load the collision representation */ virtual void load( const urdf::ModelInterface &urdf, bool visual = true, bool collision = true ); /** * \brief Clears all data loaded from a URDF */ virtual void clear(); virtual void update(const LinkUpdater& updater); /** * \brief Set the robot as a whole to be visible or not * @param visible Should we be visible? */ virtual void setVisible( bool visible ); /** * \brief Set whether the visual meshes of the robot should be visible * @param visible Whether the visual meshes of the robot should be visible */ void setVisualVisible( bool visible ); /** * \brief Set whether the collision meshes/primitives of the robot should be visible * @param visible Whether the collision meshes/primitives should be visible */ void setCollisionVisible( bool visible ); /** * \brief Returns whether anything is visible */ bool isVisible(); /** * \brief Returns whether or not the visual representation is set to be visible * To be visible this and isVisible() must both be true. */ bool isVisualVisible(); /** * \brief Returns whether or not the collision representation is set to be visible * To be visible this and isVisible() must both be true. */ bool isCollisionVisible(); void setAlpha(float a); float getAlpha() { return alpha_; } RobotLink* getRootLink() { return root_link_; } RobotLink* getLink( const std::string& name ); RobotJoint* getJoint( const std::string& name ); typedef std::map< std::string, RobotLink* > M_NameToLink; typedef std::map< std::string, RobotJoint* > M_NameToJoint; const M_NameToLink& getLinks() const { return links_; } const M_NameToJoint& getJoints() const { return joints_; } const std::string& getName() { return name_; } Ogre::SceneNode* getVisualNode() { return root_visual_node_; } Ogre::SceneNode* getCollisionNode() { return root_collision_node_; } Ogre::SceneNode* getOtherNode() { return root_other_node_; } Ogre::SceneManager* getSceneManager() { return scene_manager_; } DisplayContext* getDisplayContext() { return context_; } virtual void setPosition( const Ogre::Vector3& position ); virtual void setOrientation( const Ogre::Quaternion& orientation ); virtual void setScale( const Ogre::Vector3& scale ); virtual const Ogre::Vector3& getPosition(); virtual const Ogre::Quaternion& getOrientation(); /** subclass LinkFactory and call setLinkFactory() to use a subclass of RobotLink and/or RobotJoint. */ class LinkFactory { public: virtual RobotLink* createLink( Robot* robot, const urdf::LinkConstSharedPtr& link, const std::string& parent_joint_name, bool visual, bool collision); virtual RobotJoint* createJoint( Robot* robot, const urdf::JointConstSharedPtr& joint); }; /** Call this before load() to subclass the RobotLink or RobotJoint class used in the link property. * Example: * class MyLinkFactory : public LinkFactory * { * ... // overload createLink() and/or createJoint() * } * ... * robot->setLinkFactory(new MyLinkFactory()); */ void setLinkFactory(LinkFactory *link_factory); enum LinkTreeStyle { STYLE_LINK_LIST, // list of all links sorted by link name STYLE_DEFAULT = STYLE_LINK_LIST, STYLE_JOINT_LIST, // list of joints sorted by joint name STYLE_LINK_TREE, // tree of links STYLE_JOINT_LINK_TREE // tree of joints with links }; /** Set the style of the link property. */ void setLinkTreeStyle(LinkTreeStyle style); /** can be used to change the name, reparent, or add extra properties to the list of links */ Property *getLinkTreeProperty() { return link_tree_; } // set joint checkboxes and All Links Enabled checkbox based on current link enables. void calculateJointCheckboxes(); private Q_SLOTS: void changedLinkTreeStyle(); void changedExpandTree(); void changedHideSubProperties(); void changedEnableAllLinks(); void changedExpandLinkDetails(); void changedExpandJointDetails(); protected: /** @brief Call RobotLink::updateVisibility() on each link. */ void updateLinkVisibilities(); /** remove all link and joint properties from their parents. * Needed before deletion and before rearranging link tree. */ void unparentLinkProperties(); // place sub properties under detail (or not) void useDetailProperty(bool use_detail); /** used by setLinkTreeStyle() to recursively build link & joint tree. */ void addLinkToLinkTree(LinkTreeStyle style, Property *parent, RobotLink *link); void addJointToLinkTree(LinkTreeStyle style, Property *parent, RobotJoint *joint); // set the value of the EnableAllLinks property without affecting child links/joints. void setEnableAllLinksCheckbox(QVariant val); /** initialize style_name_map_ and link_tree_style_ options */ void initLinkTreeStyle(); static bool styleShowLink(LinkTreeStyle style); static bool styleShowJoint(LinkTreeStyle style); static bool styleIsTree(LinkTreeStyle style); Ogre::SceneManager* scene_manager_; M_NameToLink links_; ///< Map of name to link info, stores all loaded links. M_NameToJoint joints_; ///< Map of name to joint info, stores all loaded joints. RobotLink *root_link_; LinkFactory *link_factory_; ///< factory for generating links and joints Ogre::SceneNode* root_visual_node_; ///< Node all our visual nodes are children of Ogre::SceneNode* root_collision_node_; ///< Node all our collision nodes are children of Ogre::SceneNode* root_other_node_; bool visible_; ///< Should we show anything at all? (affects visual, collision, axes, and trails) bool visual_visible_; ///< Should we show the visual representation? bool collision_visible_; ///< Should we show the collision representation? DisplayContext* context_; Property* link_tree_; EnumProperty* link_tree_style_; BoolProperty* expand_tree_; BoolProperty* expand_link_details_; BoolProperty* expand_joint_details_; BoolProperty* enable_all_links_; std::map style_name_map_; bool doing_set_checkbox_; // used only inside setEnableAllLinksCheckbox() bool robot_loaded_; // true after robot model is loaded. // true inside changedEnableAllLinks(). Prevents calculateJointCheckboxes() // from recalculating over and over. bool inChangedEnableAllLinks; std::string name_; float alpha_; }; } // namespace rviz #endif /* RVIZ_ROBOT_H_ */ rviz-1.12.4/src/rviz/robot/robot_joint.cpp000066400000000000000000000404241300447110700205340ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/robot/robot_joint.h" #include "rviz/robot/robot_link.h" #include "rviz/robot/robot.h" #include #include "rviz/properties/float_property.h" #include "rviz/properties/vector_property.h" #include "rviz/properties/quaternion_property.h" #include "rviz/properties/string_property.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/load_resource.h" namespace rviz { RobotJoint::RobotJoint( Robot* robot, const urdf::JointConstSharedPtr& joint ) : robot_( robot ) , name_( joint->name ) , child_link_name_( joint->child_link_name ) , parent_link_name_( joint->parent_link_name ) , axes_( NULL ) , axis_( NULL ) , has_decendent_links_with_geometry_( true ) , doing_set_checkbox_( false ) { joint_property_ = new Property( name_.c_str(), true, "", NULL, SLOT( updateChildVisibility() ), this); joint_property_->setIcon( rviz::loadPixmap( "package://rviz/icons/classes/RobotJoint.png" ) ); details_ = new Property( "Details", QVariant(), "", NULL); axes_property_ = new Property( "Show Axes", false, "Enable/disable showing the axes of this joint.", joint_property_, SLOT( updateAxes() ), this ); position_property_ = new VectorProperty( "Position", Ogre::Vector3::ZERO, "Position of this joint, in the current Fixed Frame. (Not editable)", joint_property_ ); position_property_->setReadOnly( true ); orientation_property_ = new QuaternionProperty( "Orientation", Ogre::Quaternion::IDENTITY, "Orientation of this joint, in the current Fixed Frame. (Not editable)", joint_property_ ); orientation_property_->setReadOnly( true ); std::string type = ""; if (joint->type == urdf::Joint::UNKNOWN) type = "unknown"; else if (joint->type == urdf::Joint::REVOLUTE) type = "revolute"; else if (joint->type == urdf::Joint::CONTINUOUS) type = "continuous"; else if (joint->type == urdf::Joint::PRISMATIC) type = "prismatic"; else if (joint->type == urdf::Joint::FLOATING) type = "floating"; else if (joint->type == urdf::Joint::PLANAR) type = "planar"; else if (joint->type == urdf::Joint::FIXED) type = "fixed"; type_property_ = new StringProperty( "Type", QString::fromStdString(type), "Type of this joint. (Not editable)", joint_property_ ); type_property_->setReadOnly( true ); if (joint->limits) { // continuous joints have lower limit and upper limits of zero, // which means this isn't very useful but show it anyhow. lower_limit_property_ = new FloatProperty( "Lower Limit", joint->limits->lower, "Lower limit of this joint. (Not editable)", joint_property_ ); lower_limit_property_->setReadOnly( true ); upper_limit_property_ = new FloatProperty( "Upper Limit", joint->limits->upper, "Upper limit of this joint. (Not editable)", joint_property_ ); upper_limit_property_->setReadOnly( true ); } if ((type == "continuous") || (type == "revolute") || (type == "prismatic") || (type == "planar")) { show_axis_property_ = new Property( "Show Joint Axis", false, "Enable/disable showing the axis of this joint.", joint_property_, SLOT( updateAxis() ), this ); axis_property_ = new VectorProperty( "Joint Axis", Ogre::Vector3(joint->axis.x, joint->axis.y, joint->axis.z), "Axis of this joint. (Not editable)", joint_property_ ); axis_property_->setReadOnly( true ); } joint_property_->collapse(); const urdf::Vector3& pos = joint->parent_to_joint_origin_transform.position; const urdf::Rotation& rot = joint->parent_to_joint_origin_transform.rotation; joint_origin_pos_ = Ogre::Vector3(pos.x, pos.y, pos.z); joint_origin_rot_ = Ogre::Quaternion(rot.w, rot.x, rot.y, rot.z); } RobotJoint::~RobotJoint() { delete axes_; if (axis_) delete axis_; delete details_; delete joint_property_; } void RobotJoint::setJointPropertyDescription() { int links_with_geom; int links_with_geom_checked; int links_with_geom_unchecked; getChildLinkState(links_with_geom, links_with_geom_checked, links_with_geom_unchecked, true); std::stringstream desc; desc << "Joint " << name_ << " with parent link " << parent_link_name_ << " and child link " << child_link_name_ << "."; if (links_with_geom == 0) { desc << " This joint's descendents have NO geometry."; setJointCheckbox(QVariant()); has_decendent_links_with_geometry_ = false; } else if (styleIsTree()) { desc << " Check/uncheck to show/hide all links descended from this joint."; setJointCheckbox(links_with_geom_unchecked == 0); has_decendent_links_with_geometry_ = true; } else { getChildLinkState(links_with_geom, links_with_geom_checked, links_with_geom_unchecked, false); if (links_with_geom == 0) { desc << " This joint's child link has NO geometry."; setJointCheckbox(QVariant()); has_decendent_links_with_geometry_ = false; } else { desc << " Check/uncheck to show/hide this joint's child link."; setJointCheckbox(links_with_geom_unchecked == 0); has_decendent_links_with_geometry_ = true; } } joint_property_->setDescription(desc.str().c_str()); } void RobotJoint::setJointCheckbox(QVariant val) { // setting doing_set_checkbox_ to true prevents updateChildVisibility() from // updating child link enables. doing_set_checkbox_ = true; joint_property_->setValue(val); doing_set_checkbox_ = false; } RobotJoint* RobotJoint::getParentJoint() { RobotLink* parent_link = robot_->getLink(parent_link_name_); if (!parent_link) return NULL; const std::string& parent_joint_name = parent_link->getParentJointName(); if (parent_joint_name.empty()) return NULL; return robot_->getJoint(parent_joint_name); } void RobotJoint::calculateJointCheckboxesRecursive( int& links_with_geom, int& links_with_geom_checked, int& links_with_geom_unchecked) { links_with_geom_checked = 0; links_with_geom_unchecked = 0; RobotLink *link = robot_->getLink(child_link_name_); if (link && link->hasGeometry()) { bool checked = link->getLinkProperty()->getValue().toBool(); links_with_geom_checked += checked ? 1 : 0; links_with_geom_unchecked += checked ? 0 : 1; } links_with_geom = links_with_geom_checked + links_with_geom_unchecked; if (!styleIsTree()) { if (!links_with_geom) { setJointCheckbox(QVariant()); } else { setJointCheckbox(links_with_geom_unchecked == 0); } } std::vector::const_iterator child_joint_it = link->getChildJointNames().begin(); std::vector::const_iterator child_joint_end = link->getChildJointNames().end(); for ( ; child_joint_it != child_joint_end ; ++child_joint_it ) { RobotJoint* child_joint = robot_->getJoint( *child_joint_it ); if (child_joint) { int child_links_with_geom; int child_links_with_geom_checked; int child_links_with_geom_unchecked; child_joint->calculateJointCheckboxesRecursive(child_links_with_geom, child_links_with_geom_checked, child_links_with_geom_unchecked); links_with_geom_checked += child_links_with_geom_checked; links_with_geom_unchecked += child_links_with_geom_unchecked; } } links_with_geom = links_with_geom_checked + links_with_geom_unchecked; if (styleIsTree()) { if (!links_with_geom) { setJointCheckbox(QVariant()); } else { setJointCheckbox(links_with_geom_unchecked == 0); } } } void RobotJoint::getChildLinkState( int& links_with_geom, int& links_with_geom_checked, int& links_with_geom_unchecked, bool recursive) const { links_with_geom_checked = 0; links_with_geom_unchecked = 0; RobotLink *link = robot_->getLink(child_link_name_); if (link && link->hasGeometry()) { bool checked = link->getLinkProperty()->getValue().toBool(); links_with_geom_checked += checked ? 1 : 0; links_with_geom_unchecked += checked ? 0 : 1; } if (recursive) { std::vector::const_iterator child_joint_it = link->getChildJointNames().begin(); std::vector::const_iterator child_joint_end = link->getChildJointNames().end(); for ( ; child_joint_it != child_joint_end ; ++child_joint_it ) { RobotJoint* child_joint = robot_->getJoint( *child_joint_it ); if (child_joint) { int child_links_with_geom; int child_links_with_geom_checked; int child_links_with_geom_unchecked; child_joint->getChildLinkState(child_links_with_geom, child_links_with_geom_checked, child_links_with_geom_unchecked, recursive); links_with_geom_checked += child_links_with_geom_checked; links_with_geom_unchecked += child_links_with_geom_unchecked; } } } links_with_geom = links_with_geom_checked + links_with_geom_unchecked; } bool RobotJoint::getEnabled() const { if (!hasDescendentLinksWithGeometry()) return true; return joint_property_->getValue().toBool(); } bool RobotJoint::styleIsTree() const { return details_->getParent() != NULL; } void RobotJoint::updateChildVisibility() { if (doing_set_checkbox_) return; if (!hasDescendentLinksWithGeometry()) return; bool visible = getEnabled(); RobotLink *link = robot_->getLink(child_link_name_); if (link) { if (link->hasGeometry()) { link->getLinkProperty()->setValue(visible); } if (styleIsTree()) { std::vector::const_iterator child_joint_it = link->getChildJointNames().begin(); std::vector::const_iterator child_joint_end = link->getChildJointNames().end(); for ( ; child_joint_it != child_joint_end ; ++child_joint_it ) { RobotJoint* child_joint = robot_->getJoint( *child_joint_it ); if (child_joint) { child_joint->getJointProperty()->setValue(visible); } } } } } void RobotJoint::updateAxes() { if( axes_property_->getValue().toBool() ) { if( !axes_ ) { static int count = 0; std::stringstream ss; ss << "Axes for joint " << name_ << count++; axes_ = new Axes( robot_->getSceneManager(), robot_->getOtherNode(), 0.1, 0.01 ); axes_->getSceneNode()->setVisible( getEnabled() ); axes_->setPosition( position_property_->getVector() ); axes_->setOrientation( orientation_property_->getQuaternion() ); } } else { if( axes_ ) { delete axes_; axes_ = NULL; } } } void RobotJoint::updateAxis() { if( show_axis_property_->getValue().toBool() ) { if( !axis_ ) { static int count = 0; std::stringstream ss; ss << "Axis for joint " << name_ << count++; axis_ = new Arrow( robot_->getSceneManager(), robot_->getOtherNode(), 0.15, 0.05, 0.05, 0.08 ); axis_->getSceneNode()->setVisible( getEnabled() ); axis_->setPosition( position_property_->getVector() ); axis_->setOrientation( orientation_property_->getQuaternion() ); // TODO(lucasw) store an Ogre::ColorValue and set it according to // joint type. axis_->setColor(0.0, 0.8, 0.0, 1.0); } } else { if( axis_ ) { delete axis_; axis_ = NULL; } } } void RobotJoint::setTransforms( const Ogre::Vector3& parent_link_position, const Ogre::Quaternion& parent_link_orientation ) { Ogre::Vector3 position = parent_link_position + parent_link_orientation * joint_origin_pos_; Ogre::Quaternion orientation = parent_link_orientation * joint_origin_rot_; position_property_->setVector( position ); orientation_property_->setQuaternion( orientation ); if ( axes_ ) { axes_->setPosition( position ); axes_->setOrientation( orientation ); } if ( axis_ ) { axis_->setPosition( position ); axis_->setOrientation( orientation ); axis_->setDirection( parent_link_orientation * axis_property_->getVector() ); } } void RobotJoint::hideSubProperties(bool hide) { position_property_->setHidden(hide); orientation_property_->setHidden(hide); axes_property_->setHidden(hide); show_axis_property_->setHidden(hide); axis_property_->setHidden(hide); } Ogre::Vector3 RobotJoint::getPosition() { return position_property_->getVector(); } Ogre::Quaternion RobotJoint::getOrientation() { return orientation_property_->getQuaternion(); } void RobotJoint::setParentProperty(Property* new_parent) { Property* old_parent = joint_property_->getParent(); if (old_parent) old_parent->takeChild(joint_property_); if (new_parent) new_parent->addChild(joint_property_); } // if use_detail: // - all sub properties become children of details_ property. // - details_ property becomes a child of joint_property_ // else (!use_detail) // - all sub properties become children of joint_property_. // details_ property does not have a parent. void RobotJoint::useDetailProperty(bool use_detail) { Property* old_parent = details_->getParent(); if (old_parent) old_parent->takeChild(details_); if (use_detail) { while (joint_property_->numChildren() > 0) { Property* child = joint_property_->childAt(0); joint_property_->takeChild(child); details_->addChild(child); } joint_property_->addChild(details_); } else { while (details_->numChildren() > 0) { Property* child = details_->childAt(0); details_->takeChild(child); joint_property_->addChild(child); } } } void RobotJoint::expandDetails(bool expand) { Property *parent = details_->getParent() ? details_ : joint_property_; if (expand) { parent->expand(); } else { parent->collapse(); } } } // namespace rviz rviz-1.12.4/src/rviz/robot/robot_joint.h000066400000000000000000000136121300447110700202000ustar00rootroot00000000000000/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ROBOT_JOINT_H #define RVIZ_ROBOT_JOINT_H #include #include #include #ifndef Q_MOC_RUN #include #include #include #include #endif #include #include #include "rviz/ogre_helpers/object.h" #include "rviz/selection/forwards.h" namespace Ogre { class SceneManager; class Entity; class SubEntity; class SceneNode; class Vector3; class Quaternion; class Any; class RibbonTrail; } namespace rviz { class Shape; class Arrow; class Axes; class DisplayContext; class FloatProperty; class Property; class BoolProperty; class QuaternionProperty; class Robot; class RobotLinkSelectionHandler; class VectorProperty; class RobotJoint; class StringProperty; /** * \struct RobotJoint * \brief Contains any data we need from a joint in the robot. */ class RobotJoint: public QObject { Q_OBJECT public: RobotJoint( Robot* robot, const urdf::JointConstSharedPtr& joint ); virtual ~RobotJoint(); void setTransforms(const Ogre::Vector3& parent_link_position, const Ogre::Quaternion& parent_link_orientation); const std::string& getName() const { return name_; } const std::string& getParentLinkName() const { return parent_link_name_; } const std::string& getChildLinkName() const { return child_link_name_; } const Property* getJointProperty() const { return joint_property_; } Property* getJointProperty() { return joint_property_; } RobotJoint* getParentJoint(); void hideSubProperties(bool hide); // Remove joint_property_ from its old parent and add to new_parent. If new_parent==NULL then leav unparented. void setParentProperty(Property* new_parent); Ogre::Vector3 getPosition(); Ogre::Quaternion getOrientation(); void setRobotAlpha(float a) {} bool hasDescendentLinksWithGeometry() const { return has_decendent_links_with_geometry_; } // place subproperties as children of details_ or joint_property_ void useDetailProperty(bool use_detail); // expand all sub properties void expandDetails(bool expand); // Set the description for the joint. // Also sets the checkbox. // Also sets has_decendent_links_with_geometry_. // Called when the link_tree style changes. void setJointPropertyDescription(); // set checkboxes based on state of descendent link enables // Should only be called by Robot::calculateJointCheckboxes() void calculateJointCheckboxesRecursive( int& links_with_geom, // returns # of children with geometry int& links_with_geom_checked, // returns # of enabled children with geometry int& links_with_geom_unchecked); // returns # of disabled children with geometry private Q_SLOTS: void updateAxes(); void updateAxis(); void updateChildVisibility(); private: bool getEnabled() const; // true if displaying in a tree style. False if list style. bool styleIsTree() const; // determine the state of child link(s) void getChildLinkState( int& links_with_geom, // returns # of children with geometry int& links_with_geom_checked, // returns # of enabled children with geometry int& links_with_geom_unchecked, // returns # of disabled children with geometry bool recursive) const; // True: all descendant links. False: just single child link. // set the value of the enable checkbox without touching child joints/links void setJointCheckbox(QVariant val); protected: Robot* robot_; std::string name_; ///< Name of this joint std::string parent_link_name_; std::string child_link_name_; // properties Property* joint_property_; Property* details_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; Property* axes_property_; // The joint axis if any, as opposed to the frame in which the joint exists above VectorProperty* axis_property_; Property* show_axis_property_; StringProperty* type_property_; FloatProperty* lower_limit_property_; FloatProperty* upper_limit_property_; private: Ogre::Vector3 joint_origin_pos_; Ogre::Quaternion joint_origin_rot_; bool has_decendent_links_with_geometry_; bool doing_set_checkbox_; // prevents updateChildVisibility() from touching children Axes* axes_; Arrow* axis_; }; } // namespace rviz #endif // RVIZ_ROBOT_LINK_H rviz-1.12.4/src/rviz/robot/robot_link.cpp000066400000000000000000000706141300447110700203520ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rviz/mesh_loader.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/ogre_helpers/object.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/float_property.h" #include "rviz/properties/bool_property.h" #include "rviz/properties/property.h" #include "rviz/properties/quaternion_property.h" #include "rviz/properties/vector_property.h" #include "rviz/robot/robot.h" #include "rviz/selection/selection_manager.h" #include "rviz/visualization_manager.h" #include "rviz/load_resource.h" #include "rviz/robot/robot_link.h" #include "rviz/robot/robot_joint.h" namespace fs=boost::filesystem; #ifndef ROS_PACKAGE_NAME # define ROS_PACKAGE_NAME "rviz" #endif namespace rviz { class RobotLinkSelectionHandler : public SelectionHandler { public: RobotLinkSelectionHandler( RobotLink* link, DisplayContext* context ); virtual ~RobotLinkSelectionHandler(); virtual void createProperties( const Picked& obj, Property* parent_property ); virtual void updateProperties(); virtual void preRenderPass(uint32_t pass); virtual void postRenderPass(uint32_t pass); private: RobotLink* link_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; }; RobotLinkSelectionHandler::RobotLinkSelectionHandler( RobotLink* link, DisplayContext* context ) : SelectionHandler( context ) , link_( link ) { } RobotLinkSelectionHandler::~RobotLinkSelectionHandler() { } void RobotLinkSelectionHandler::createProperties( const Picked& obj, Property* parent_property ) { Property* group = new Property( "Link " + QString::fromStdString( link_->getName() ), QVariant(), "", parent_property ); properties_.push_back( group ); position_property_ = new VectorProperty( "Position", Ogre::Vector3::ZERO, "", group ); position_property_->setReadOnly( true ); orientation_property_ = new QuaternionProperty( "Orientation", Ogre::Quaternion::IDENTITY, "", group ); orientation_property_->setReadOnly( true ); group->expand(); } void RobotLinkSelectionHandler::updateProperties() { position_property_->setVector( link_->getPosition() ); orientation_property_->setQuaternion( link_->getOrientation() ); } void RobotLinkSelectionHandler::preRenderPass(uint32_t pass) { if (!link_->is_selectable_) { if( link_->visual_node_ ) { link_->visual_node_->setVisible( false ); } if( link_->collision_node_ ) { link_->collision_node_->setVisible( false ); } if( link_->trail_ ) { link_->trail_->setVisible( false ); } if( link_->axes_ ) { link_->axes_->getSceneNode()->setVisible( false ); } } } void RobotLinkSelectionHandler::postRenderPass(uint32_t pass) { if (!link_->is_selectable_) { link_->updateVisibility(); } } RobotLink::RobotLink( Robot* robot, const urdf::LinkConstSharedPtr& link, const std::string& parent_joint_name, bool visual, bool collision) : robot_( robot ) , scene_manager_( robot->getDisplayContext()->getSceneManager() ) , context_( robot->getDisplayContext() ) , name_( link->name ) , parent_joint_name_( parent_joint_name ) , visual_node_( NULL ) , collision_node_( NULL ) , trail_( NULL ) , axes_( NULL ) , material_alpha_( 1.0 ) , robot_alpha_(1.0) , only_render_depth_(false) , using_color_( false ) , is_selectable_( true ) { link_property_ = new Property( link->name.c_str(), true, "", NULL, SLOT( updateVisibility() ), this ); link_property_->setIcon( rviz::loadPixmap( "package://rviz/icons/classes/RobotLink.png" ) ); details_ = new Property( "Details", QVariant(), "", NULL); alpha_property_ = new FloatProperty( "Alpha", 1, "Amount of transparency to apply to this link.", link_property_, SLOT( updateAlpha() ), this ); trail_property_ = new Property( "Show Trail", false, "Enable/disable a 2 meter \"ribbon\" which follows this link.", link_property_, SLOT( updateTrail() ), this ); axes_property_ = new Property( "Show Axes", false, "Enable/disable showing the axes of this link.", link_property_, SLOT( updateAxes() ), this ); position_property_ = new VectorProperty( "Position", Ogre::Vector3::ZERO, "Position of this link, in the current Fixed Frame. (Not editable)", link_property_ ); position_property_->setReadOnly( true ); orientation_property_ = new QuaternionProperty( "Orientation", Ogre::Quaternion::IDENTITY, "Orientation of this link, in the current Fixed Frame. (Not editable)", link_property_ ); orientation_property_->setReadOnly( true ); link_property_->collapse(); visual_node_ = robot_->getVisualNode()->createChildSceneNode(); collision_node_ = robot_->getCollisionNode()->createChildSceneNode(); // create material for coloring links std::stringstream ss; static int count = 1; ss << "robot link color material " << count; color_material_ = Ogre::MaterialManager::getSingleton().create( ss.str(), ROS_PACKAGE_NAME ); color_material_->setReceiveShadows(false); color_material_->getTechnique(0)->setLightingEnabled(true); // create the ogre objects to display if ( visual ) { createVisual( link ); } if ( collision ) { createCollision( link ); } if (collision || visual) { createSelection(); } // create description and fill in child_joint_names_ vector std::stringstream desc; if (parent_joint_name_.empty()) { desc << "Root Link " << name_ << ""; } else { desc << "Link " << name_ << ""; desc << " with parent joint " << parent_joint_name_ << ""; } if (link->child_joints.empty()) { desc << " has no children."; } else { desc << " has " << link->child_joints.size(); if (link->child_joints.size() > 1) { desc << " child joints: "; } else { desc << " child joint: "; } std::vector::const_iterator child_it = link->child_joints.begin(); std::vector::const_iterator child_end = link->child_joints.end(); for ( ; child_it != child_end ; ++child_it ) { urdf::Joint *child_joint = child_it->get(); if (child_joint && !child_joint->name.empty()) { child_joint_names_.push_back(child_joint->name); desc << "" << child_joint->name << "" << ((child_it+1 == child_end) ? "." : ", "); } } } if (hasGeometry()) { desc << " Check/uncheck to show/hide this link in the display."; if (visual_meshes_.empty()) { desc << " This link has collision geometry but no visible geometry."; } else if (collision_meshes_.empty()) { desc << " This link has visible geometry but no collision geometry."; } } else { desc << " This link has NO geometry."; } link_property_->setDescription(desc.str().c_str()); if (!hasGeometry()) { link_property_->setIcon( rviz::loadPixmap( "package://rviz/icons/classes/RobotLinkNoGeom.png" ) ); alpha_property_->hide(); link_property_->setValue(QVariant()); } } RobotLink::~RobotLink() { for( size_t i = 0; i < visual_meshes_.size(); i++ ) { scene_manager_->destroyEntity( visual_meshes_[ i ]); } for( size_t i = 0; i < collision_meshes_.size(); i++ ) { scene_manager_->destroyEntity( collision_meshes_[ i ]); } scene_manager_->destroySceneNode( visual_node_ ); scene_manager_->destroySceneNode( collision_node_ ); if ( trail_ ) { scene_manager_->destroyRibbonTrail( trail_ ); } delete axes_; delete details_; delete link_property_; } bool RobotLink::hasGeometry() const { return visual_meshes_.size() + collision_meshes_.size() > 0; } bool RobotLink::getEnabled() const { if (!hasGeometry()) return true; return link_property_->getValue().toBool(); } void RobotLink::setRobotAlpha( float a ) { robot_alpha_ = a; updateAlpha(); } void RobotLink::setRenderQueueGroup( Ogre::uint8 group ) { Ogre::SceneNode::ChildNodeIterator child_it = visual_node_->getChildIterator(); while( child_it.hasMoreElements() ) { Ogre::SceneNode* child = dynamic_cast( child_it.getNext() ); if( child ) { Ogre::SceneNode::ObjectIterator object_it = child->getAttachedObjectIterator(); while( object_it.hasMoreElements() ) { Ogre::MovableObject* obj = object_it.getNext(); obj->setRenderQueueGroup(group); } } } } void RobotLink::setOnlyRenderDepth(bool onlyRenderDepth) { setRenderQueueGroup( onlyRenderDepth ? Ogre::RENDER_QUEUE_BACKGROUND : Ogre::RENDER_QUEUE_MAIN ); only_render_depth_ = onlyRenderDepth; updateAlpha(); } void RobotLink::updateAlpha() { float link_alpha = alpha_property_->getFloat(); M_SubEntityToMaterial::iterator it = materials_.begin(); M_SubEntityToMaterial::iterator end = materials_.end(); for (; it != end; ++it) { const Ogre::MaterialPtr& material = it->second; if ( only_render_depth_ ) { material->setColourWriteEnabled( false ); material->setDepthWriteEnabled( true ); } else { Ogre::ColourValue color = material->getTechnique(0)->getPass(0)->getDiffuse(); color.a = robot_alpha_ * material_alpha_ * link_alpha; material->setDiffuse( color ); if ( color.a < 0.9998 ) { material->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); material->setDepthWriteEnabled( false ); } else { material->setSceneBlending( Ogre::SBT_REPLACE ); material->setDepthWriteEnabled( true ); } } } Ogre::ColourValue color = color_material_->getTechnique(0)->getPass(0)->getDiffuse(); color.a = robot_alpha_ * link_alpha; color_material_->setDiffuse( color ); if ( color.a < 0.9998 ) { color_material_->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); color_material_->setDepthWriteEnabled( false ); } else { color_material_->setSceneBlending( Ogre::SBT_REPLACE ); color_material_->setDepthWriteEnabled( true ); } } void RobotLink::updateVisibility() { bool enabled = getEnabled(); robot_->calculateJointCheckboxes(); if( visual_node_ ) { visual_node_->setVisible( enabled && robot_->isVisible() && robot_->isVisualVisible() ); } if( collision_node_ ) { collision_node_->setVisible( enabled && robot_->isVisible() && robot_->isCollisionVisible() ); } if( trail_ ) { trail_->setVisible( enabled && robot_->isVisible() ); } if( axes_ ) { axes_->getSceneNode()->setVisible( enabled && robot_->isVisible() ); } } Ogre::MaterialPtr RobotLink::getMaterialForLink( const urdf::LinkConstSharedPtr& link) { if (!link->visual || !link->visual->material) { return Ogre::MaterialManager::getSingleton().getByName("RVIZ/ShadedRed"); } static int count = 0; std::stringstream ss; ss << "Robot Link Material" << count; Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(ss.str(), ROS_PACKAGE_NAME); mat->getTechnique(0)->setLightingEnabled(true); if (link->visual->material->texture_filename.empty()) { const urdf::Color& col = link->visual->material->color; mat->getTechnique(0)->setAmbient(col.r * 0.5, col.g * 0.5, col.b * 0.5); mat->getTechnique(0)->setDiffuse(col.r, col.g, col.b, col.a); material_alpha_ = col.a; } else { std::string filename = link->visual->material->texture_filename; if (!Ogre::TextureManager::getSingleton().resourceExists(filename)) { resource_retriever::Retriever retriever; resource_retriever::MemoryResource res; try { res = retriever.get(filename); } catch (resource_retriever::Exception& e) { ROS_ERROR("%s", e.what()); } if (res.size != 0) { Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size)); Ogre::Image image; std::string extension = fs::extension(fs::path(filename)); if (extension[0] == '.') { extension = extension.substr(1, extension.size() - 1); } try { image.load(stream, extension); Ogre::TextureManager::getSingleton().loadImage(filename, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image); } catch (Ogre::Exception& e) { ROS_ERROR("Could not load texture [%s]: %s", filename.c_str(), e.what()); } } } Ogre::Pass* pass = mat->getTechnique(0)->getPass(0); Ogre::TextureUnitState* tex_unit = pass->createTextureUnitState();; tex_unit->setTextureName(filename); } return mat; } void RobotLink::createEntityForGeometryElement(const urdf::LinkConstSharedPtr& link, const urdf::Geometry& geom, const urdf::Pose& origin, Ogre::SceneNode* scene_node, Ogre::Entity*& entity) { entity = NULL; // default in case nothing works. Ogre::SceneNode* offset_node = scene_node->createChildSceneNode(); static int count = 0; std::stringstream ss; ss << "Robot Link" << count++; std::string entity_name = ss.str(); Ogre::Vector3 scale(Ogre::Vector3::UNIT_SCALE); Ogre::Vector3 offset_position(Ogre::Vector3::ZERO); Ogre::Quaternion offset_orientation(Ogre::Quaternion::IDENTITY); { Ogre::Vector3 position( origin.position.x, origin.position.y, origin.position.z ); Ogre::Quaternion orientation( Ogre::Quaternion::IDENTITY ); orientation = orientation * Ogre::Quaternion( origin.rotation.w, origin.rotation.x, origin.rotation.y, origin.rotation.z ); offset_position = position; offset_orientation = orientation; } switch (geom.type) { case urdf::Geometry::SPHERE: { const urdf::Sphere& sphere = static_cast(geom); entity = Shape::createEntity(entity_name, Shape::Sphere, scene_manager_); scale = Ogre::Vector3( sphere.radius*2, sphere.radius*2, sphere.radius*2 ); break; } case urdf::Geometry::BOX: { const urdf::Box& box = static_cast(geom); entity = Shape::createEntity(entity_name, Shape::Cube, scene_manager_); scale = Ogre::Vector3( box.dim.x, box.dim.y, box.dim.z ); break; } case urdf::Geometry::CYLINDER: { const urdf::Cylinder& cylinder = static_cast(geom); Ogre::Quaternion rotX; rotX.FromAngleAxis( Ogre::Degree(90), Ogre::Vector3::UNIT_X ); offset_orientation = offset_orientation * rotX; entity = Shape::createEntity(entity_name, Shape::Cylinder, scene_manager_); scale = Ogre::Vector3( cylinder.radius*2, cylinder.length, cylinder.radius*2 ); break; } case urdf::Geometry::MESH: { const urdf::Mesh& mesh = static_cast(geom); if ( mesh.filename.empty() ) return; scale = Ogre::Vector3(mesh.scale.x, mesh.scale.y, mesh.scale.z); std::string model_name = mesh.filename; try { loadMeshFromResource(model_name); entity = scene_manager_->createEntity( ss.str(), model_name ); } catch( Ogre::InvalidParametersException& e ) { ROS_ERROR( "Could not convert mesh resource '%s' for link '%s'. It might be an empty mesh: %s", model_name.c_str(), link->name.c_str(), e.what() ); } catch( Ogre::Exception& e ) { ROS_ERROR( "Could not load model '%s' for link '%s': %s", model_name.c_str(), link->name.c_str(), e.what() ); } break; } default: ROS_WARN("Unsupported geometry type for element: %d", geom.type); break; } if ( entity ) { offset_node->attachObject(entity); offset_node->setScale(scale); offset_node->setPosition(offset_position); offset_node->setOrientation(offset_orientation); if (default_material_name_.empty()) { default_material_ = getMaterialForLink(link); static int count = 0; std::stringstream ss; ss << default_material_->getName() << count++ << "Robot"; std::string cloned_name = ss.str(); default_material_ = default_material_->clone(cloned_name); default_material_name_ = default_material_->getName(); } for (uint32_t i = 0; i < entity->getNumSubEntities(); ++i) { // Assign materials only if the submesh does not have one already Ogre::SubEntity* sub = entity->getSubEntity(i); const std::string& material_name = sub->getMaterialName(); if (material_name == "BaseWhite" || material_name == "BaseWhiteNoLighting") { sub->setMaterialName(default_material_name_); } else { // Need to clone here due to how selection works. Once selection id is done per object and not per material, // this can go away static int count = 0; std::stringstream ss; ss << material_name << count++ << "Robot"; std::string cloned_name = ss.str(); sub->getMaterial()->clone(cloned_name); sub->setMaterialName(cloned_name); } materials_[sub] = sub->getMaterial(); } } } void RobotLink::createCollision(const urdf::LinkConstSharedPtr& link) { bool valid_collision_found = false; #if URDF_MAJOR_VERSION == 0 && URDF_MINOR_VERSION == 2 std::map > >::const_iterator mi; for( mi = link->collision_groups.begin(); mi != link->collision_groups.end(); mi++ ) { if( mi->second ) { std::vector::const_iterator vi; for( vi = mi->second->begin(); vi != mi->second->end(); vi++ ) { urdf::CollisionSharedPtr collision = *vi; if( collision && collision->geometry ) { Ogre::Entity* collision_mesh = NULL; createEntityForGeometryElement( link, *collision->geometry, collision->origin, collision_node_, collision_mesh ); if( collision_mesh ) { collision_meshes_.push_back( collision_mesh ); valid_collision_found = true; } } } } } #else std::vector::const_iterator vi; for( vi = link->collision_array.begin(); vi != link->collision_array.end(); vi++ ) { urdf::CollisionSharedPtr collision = *vi; if( collision && collision->geometry ) { Ogre::Entity* collision_mesh = NULL; createEntityForGeometryElement( link, *collision->geometry, collision->origin, collision_node_, collision_mesh ); if( collision_mesh ) { collision_meshes_.push_back( collision_mesh ); valid_collision_found = true; } } } #endif if( !valid_collision_found && link->collision && link->collision->geometry ) { Ogre::Entity* collision_mesh = NULL; createEntityForGeometryElement( link, *link->collision->geometry, link->collision->origin, collision_node_, collision_mesh ); if( collision_mesh ) { collision_meshes_.push_back( collision_mesh ); } } collision_node_->setVisible( getEnabled() ); } void RobotLink::createVisual(const urdf::LinkConstSharedPtr& link ) { bool valid_visual_found = false; #if URDF_MAJOR_VERSION == 0 && URDF_MINOR_VERSION == 2 std::map > >::const_iterator mi; for( mi = link->visual_groups.begin(); mi != link->visual_groups.end(); mi++ ) { if( mi->second ) { std::vector::const_iterator vi; for( vi = mi->second->begin(); vi != mi->second->end(); vi++ ) { urdf::VisualSharedPtr visual = *vi; if( visual && visual->geometry ) { Ogre::Entity* visual_mesh = NULL; createEntityForGeometryElement( link, *visual->geometry, visual->origin, visual_node_, visual_mesh ); if( visual_mesh ) { visual_meshes_.push_back( visual_mesh ); valid_visual_found = true; } } } } } #else std::vector::const_iterator vi; for( vi = link->visual_array.begin(); vi != link->visual_array.end(); vi++ ) { urdf::VisualSharedPtr visual = *vi; if( visual && visual->geometry ) { Ogre::Entity* visual_mesh = NULL; createEntityForGeometryElement( link, *visual->geometry, visual->origin, visual_node_, visual_mesh ); if( visual_mesh ) { visual_meshes_.push_back( visual_mesh ); valid_visual_found = true; } } } #endif if( !valid_visual_found && link->visual && link->visual->geometry ) { Ogre::Entity* visual_mesh = NULL; createEntityForGeometryElement( link, *link->visual->geometry, link->visual->origin, visual_node_, visual_mesh ); if( visual_mesh ) { visual_meshes_.push_back( visual_mesh ); } } visual_node_->setVisible( getEnabled() ); } void RobotLink::createSelection() { selection_handler_.reset( new RobotLinkSelectionHandler( this, context_ )); for( size_t i = 0; i < visual_meshes_.size(); i++ ) { selection_handler_->addTrackedObject( visual_meshes_[ i ]); } for( size_t i = 0; i < collision_meshes_.size(); i++ ) { selection_handler_->addTrackedObject( collision_meshes_[ i ]); } } void RobotLink::updateTrail() { if( trail_property_->getValue().toBool() ) { if( !trail_ ) { if( visual_node_ ) { static int count = 0; std::stringstream ss; ss << "Trail for link " << name_ << count++; trail_ = scene_manager_->createRibbonTrail( ss.str() ); trail_->setMaxChainElements( 100 ); trail_->setInitialWidth( 0, 0.01f ); trail_->setInitialColour( 0, 0.0f, 0.5f, 0.5f ); trail_->addNode( visual_node_ ); trail_->setTrailLength( 2.0f ); trail_->setVisible( getEnabled() ); robot_->getOtherNode()->attachObject( trail_ ); } else { ROS_WARN( "No visual node for link %s, cannot create a trail", name_.c_str() ); } } } else { if( trail_ ) { scene_manager_->destroyRibbonTrail( trail_ ); trail_ = NULL; } } } void RobotLink::updateAxes() { if( axes_property_->getValue().toBool() ) { if( !axes_ ) { static int count = 0; std::stringstream ss; ss << "Axes for link " << name_ << count++; axes_ = new Axes( scene_manager_, robot_->getOtherNode(), 0.1, 0.01 ); axes_->getSceneNode()->setVisible( getEnabled() ); axes_->setPosition( position_property_->getVector() ); axes_->setOrientation( orientation_property_->getQuaternion() ); } } else { if( axes_ ) { delete axes_; axes_ = NULL; } } } void RobotLink::setTransforms( const Ogre::Vector3& visual_position, const Ogre::Quaternion& visual_orientation, const Ogre::Vector3& collision_position, const Ogre::Quaternion& collision_orientation ) { if ( visual_node_ ) { visual_node_->setPosition( visual_position ); visual_node_->setOrientation( visual_orientation ); } if ( collision_node_ ) { collision_node_->setPosition( collision_position ); collision_node_->setOrientation( collision_orientation ); } position_property_->setVector( visual_position ); orientation_property_->setQuaternion( visual_orientation ); if ( axes_ ) { axes_->setPosition( visual_position ); axes_->setOrientation( visual_orientation ); } } void RobotLink::setToErrorMaterial() { for( size_t i = 0; i < visual_meshes_.size(); i++ ) { visual_meshes_[ i ]->setMaterialName("BaseWhiteNoLighting"); } for( size_t i = 0; i < collision_meshes_.size(); i++ ) { collision_meshes_[ i ]->setMaterialName("BaseWhiteNoLighting"); } } void RobotLink::setToNormalMaterial() { if( using_color_ ) { for( size_t i = 0; i < visual_meshes_.size(); i++ ) { visual_meshes_[ i ]->setMaterial( color_material_ ); } for( size_t i = 0; i < collision_meshes_.size(); i++ ) { collision_meshes_[ i ]->setMaterial( color_material_ ); } } else { M_SubEntityToMaterial::iterator it = materials_.begin(); M_SubEntityToMaterial::iterator end = materials_.end(); for (; it != end; ++it) { it->first->setMaterial(it->second); } } } void RobotLink::setColor( float red, float green, float blue ) { Ogre::ColourValue color = color_material_->getTechnique(0)->getPass(0)->getDiffuse(); color.r = red; color.g = green; color.b = blue; color_material_->getTechnique(0)->setAmbient( 0.5 * color ); color_material_->getTechnique(0)->setDiffuse( color ); using_color_ = true; setToNormalMaterial(); } void RobotLink::unsetColor() { using_color_ = false; setToNormalMaterial(); } bool RobotLink::setSelectable( bool selectable ) { bool old = is_selectable_; is_selectable_ = selectable; return old; } bool RobotLink::getSelectable() { return is_selectable_; } void RobotLink::hideSubProperties(bool hide) { position_property_->setHidden(hide); orientation_property_->setHidden(hide); trail_property_->setHidden(hide); axes_property_->setHidden(hide); alpha_property_->setHidden(hide); } Ogre::Vector3 RobotLink::getPosition() { return position_property_->getVector(); } Ogre::Quaternion RobotLink::getOrientation() { return orientation_property_->getQuaternion(); } void RobotLink::setParentProperty(Property* new_parent) { Property* old_parent = link_property_->getParent(); if (old_parent) old_parent->takeChild(link_property_); if (new_parent) new_parent->addChild(link_property_); } // if use_detail: // - all sub properties become children of details_ property. // - details_ property becomes a child of link_property_ // else (!use_detail) // - all sub properties become children of link_property_. // details_ property does not have a parent. void RobotLink::useDetailProperty(bool use_detail) { Property* old_parent = details_->getParent(); if (old_parent) old_parent->takeChild(details_); if (use_detail) { while (link_property_->numChildren() > 0) { Property* child = link_property_->childAt(0); link_property_->takeChild(child); details_->addChild(child); } link_property_->addChild(details_); } else { while (details_->numChildren() > 0) { Property* child = details_->childAt(0); details_->takeChild(child); link_property_->addChild(child); } } } void RobotLink::expandDetails(bool expand) { Property *parent = details_->getParent() ? details_ : link_property_; if (expand) { parent->expand(); } else { parent->collapse(); } } } // namespace rviz rviz-1.12.4/src/rviz/robot/robot_link.h000066400000000000000000000163671300447110700200240ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ROBOT_LINK_H #define RVIZ_ROBOT_LINK_H #include #include #include #ifndef Q_MOC_RUN #include #include #include #include #include #endif #include // can be replaced later by urdf_model/types.h #include #include "rviz/ogre_helpers/object.h" #include "rviz/selection/forwards.h" namespace Ogre { class SceneManager; class Entity; class SubEntity; class SceneNode; class Vector3; class Quaternion; class Any; class RibbonTrail; } namespace rviz { class Shape; class Axes; class DisplayContext; class FloatProperty; class Property; class BoolProperty; class QuaternionProperty; class Robot; class RobotLinkSelectionHandler; class VectorProperty; class RobotJoint; typedef boost::shared_ptr RobotLinkSelectionHandlerPtr; /** * \struct RobotLink * \brief Contains any data we need from a link in the robot. */ class RobotLink: public QObject { Q_OBJECT public: RobotLink( Robot* robot, const urdf::LinkConstSharedPtr& link, const std::string& parent_joint_name, bool visual, bool collision); virtual ~RobotLink(); virtual void setRobotAlpha(float a); virtual void setTransforms(const Ogre::Vector3& visual_position, const Ogre::Quaternion& visual_orientation, const Ogre::Vector3& collision_position, const Ogre::Quaternion& collision_orientation); // access const std::string& getName() const { return name_; } const std::string& getParentJointName() const { return parent_joint_name_; } const std::vector& getChildJointNames() const { return child_joint_names_; } Property* getLinkProperty() const { return link_property_; } Ogre::SceneNode* getVisualNode() const { return visual_node_; } Ogre::SceneNode* getCollisionNode() const { return collision_node_; } Robot* getRobot() const { return robot_; } // Remove link_property_ from its old parent and add to new_parent. If new_parent==NULL then leav unparented. void setParentProperty(Property* new_parent); // hide or show all sub properties (hide to make tree easier to see) virtual void hideSubProperties(bool hide); void setToErrorMaterial(); void setToNormalMaterial(); void setColor( float red, float green, float blue ); void unsetColor(); /// set whether the link is selectable. If false objects behind/inside the link can be selected/manipulated. Returns old value. bool setSelectable( bool selectable ); bool getSelectable(); Ogre::Vector3 getPosition(); Ogre::Quaternion getOrientation(); bool hasGeometry() const; /* If set to true, the link will only render to the depth channel * and be in render group 0, so it is rendered before anything else. * Thus, it will occlude other objects without being visible. */ void setOnlyRenderDepth( bool onlyRenderDepth ); bool getOnlyRenderDepth() const { return only_render_depth_; } // place subproperties as children of details_ or joint_property_ void useDetailProperty(bool use_detail); // expand all sub properties void expandDetails(bool expand); public Q_SLOTS: /** @brief Update the visibility of the link elements: visual mesh, collision mesh, trail, and axes. * * Called by Robot when changing visual and collision visibilities, * since each link may be enabled or disabled. */ void updateVisibility(); private Q_SLOTS: void updateAlpha(); void updateTrail(); void updateAxes(); private: void setRenderQueueGroup( Ogre::uint8 group ); bool getEnabled() const; void createEntityForGeometryElement( const urdf::LinkConstSharedPtr& link, const urdf::Geometry& geom, const urdf::Pose& origin, Ogre::SceneNode* scene_node, Ogre::Entity*& entity ); void createVisual( const urdf::LinkConstSharedPtr& link); void createCollision( const urdf::LinkConstSharedPtr& link); void createSelection(); Ogre::MaterialPtr getMaterialForLink( const urdf::LinkConstSharedPtr& link ); protected: Robot* robot_; Ogre::SceneManager* scene_manager_; DisplayContext* context_; std::string name_; ///< Name of this link std::string parent_joint_name_; std::vector child_joint_names_; // properties Property* link_property_; Property* details_; VectorProperty* position_property_; QuaternionProperty* orientation_property_; Property* trail_property_; Property* axes_property_; FloatProperty* alpha_property_; private: typedef std::map M_SubEntityToMaterial; M_SubEntityToMaterial materials_; Ogre::MaterialPtr default_material_; std::string default_material_name_; std::vector visual_meshes_; ///< The entities representing the visual mesh of this link (if they exist) std::vector collision_meshes_; ///< The entities representing the collision mesh of this link (if they exist) Ogre::SceneNode* visual_node_; ///< The scene node the visual meshes are attached to Ogre::SceneNode* collision_node_; ///< The scene node the collision meshes are attached to Ogre::RibbonTrail* trail_; Axes* axes_; float material_alpha_; ///< If material is not a texture, this saves the alpha value set in the URDF, otherwise is 1.0. float robot_alpha_; ///< Alpha value from top-level robot alpha Property (set via setRobotAlpha()). bool only_render_depth_; bool is_selectable_; // joint stuff std::string joint_name_; RobotLinkSelectionHandlerPtr selection_handler_; Ogre::MaterialPtr color_material_; bool using_color_; friend class RobotLinkSelectionHandler; }; } // namespace rviz #endif // RVIZ_ROBOT_LINK_H rviz-1.12.4/src/rviz/robot/tf_link_updater.cpp000066400000000000000000000061761300447110700213640ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "tf_link_updater.h" #include "frame_manager.h" #include #include #include namespace rviz { TFLinkUpdater::TFLinkUpdater(FrameManager* frame_manager, const StatusCallback& status_cb, const std::string& tf_prefix) : frame_manager_(frame_manager) , status_callback_(status_cb) , tf_prefix_(tf_prefix) { } bool TFLinkUpdater::getLinkTransforms(const std::string& _link_name, Ogre::Vector3& visual_position, Ogre::Quaternion& visual_orientation, Ogre::Vector3& collision_position, Ogre::Quaternion& collision_orientation) const { std::string link_name = _link_name; if (!tf_prefix_.empty()) { link_name = tf::resolve(tf_prefix_, link_name); } Ogre::Vector3 position; Ogre::Quaternion orientation; if (!frame_manager_->getTransform(link_name, ros::Time(), position, orientation)) { std::stringstream ss; ss << "No transform from [" << link_name << "] to [" << frame_manager_->getFixedFrame() << "]"; setLinkStatus(StatusProperty::Error, link_name, ss.str()); return false; } setLinkStatus(StatusProperty::Ok, link_name, "Transform OK"); // Collision/visual transforms are the same in this case visual_position = position; visual_orientation = orientation; collision_position = position; collision_orientation = orientation; return true; } void TFLinkUpdater::setLinkStatus(StatusLevel level, const std::string& link_name, const std::string& text) const { if (status_callback_) { status_callback_(level, link_name, text); } } } rviz-1.12.4/src/rviz/robot/tf_link_updater.h000066400000000000000000000051501300447110700210200ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_ROBOT_TF_LINK_UPDATER_H #define RVIZ_ROBOT_TF_LINK_UPDATER_H #include "link_updater.h" #include #include namespace tf { class Transformer; } namespace rviz { class FrameManager; class TFLinkUpdater : public LinkUpdater { public: typedef boost::function StatusCallback; TFLinkUpdater(FrameManager* frame_manager, const StatusCallback& status_cb = StatusCallback(), const std::string& tf_prefix = std::string()); virtual bool getLinkTransforms(const std::string& link_name, Ogre::Vector3& visual_position, Ogre::Quaternion& visual_orientation, Ogre::Vector3& collision_position, Ogre::Quaternion& collision_orientation) const; virtual void setLinkStatus(StatusLevel level, const std::string& link_name, const std::string& text) const; private: FrameManager* frame_manager_; StatusCallback status_callback_; std::string tf_prefix_; }; } // namespace rviz #endif // RVIZ_ROBOT_TF_LINK_UPDATER_H rviz-1.12.4/src/rviz/scaled_image_widget.cpp000066400000000000000000000046611300447110700210220ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "scaled_image_widget.h" namespace rviz { ScaledImageWidget::ScaledImageWidget( float scale, QWidget* parent ) : QWidget( parent ) , scale_( scale ) { } void ScaledImageWidget::setImage( QPixmap image ) { image_ = image; update(); } QSize ScaledImageWidget::sizeHint() const { return image_.size() * scale_; } void ScaledImageWidget::paintEvent( QPaintEvent* event ) { if( !image_.isNull() ) { QSize dest_size = image_.size(); dest_size.scale( width(), height(), Qt::KeepAspectRatio ); QRect dest_rect( width() / 2 - dest_size.width() / 2, height() / 2 - dest_size.height() / 2, dest_size.width(), dest_size.height() ); QPainter painter( this ); painter.drawPixmap( dest_rect, image_ ); } } } // end namespace rviz rviz-1.12.4/src/rviz/scaled_image_widget.h000066400000000000000000000046721300447110700204710ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SCALED_IMAGE_WIDGET_H #define RVIZ_SCALED_IMAGE_WIDGET_H #include namespace rviz { /** * \brief A widget for showing a scaled version of an image (QPixmap). * * The scale is just a suggestion, given to Qt by calls to sizeHint(), * which returns the image size multiplied by the scale. The actual * rendered size is the largest that fits the image into the current * widget size without changing the aspect ratio. It is always * rendered in the center. */ class ScaledImageWidget: public QWidget { Q_OBJECT public: ScaledImageWidget( float scale, QWidget* parent = 0 ); virtual ~ScaledImageWidget() {} void setImage( QPixmap image ); virtual QSize sizeHint() const; protected: virtual void paintEvent( QPaintEvent* event ); private: QPixmap image_; float scale_; }; } // namespace rviz #endif // RVIZ_SCALED_IMAGE_WIDGET_H rviz-1.12.4/src/rviz/screenshot_dialog.cpp000066400000000000000000000142301300447110700205470ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include // Included so we know that QPushButton inherits QAbstractButton #include #include #include #include "scaled_image_widget.h" #include "screenshot_dialog.h" namespace rviz { ScreenshotDialog::ScreenshotDialog( QWidget* main_window, QWidget* render_window, const QString& default_save_dir ) : QWidget( NULL ) // This should be a top-level window to act like a dialog. , main_window_( main_window ) , render_window_( render_window ) , save_full_window_( false ) , delay_timer_( new QTimer( this )) , first_time_( true ) , default_save_dir_( default_save_dir ) { image_widget_ = new ScaledImageWidget( .5 ); takeScreenshotNow(); QCheckBox* full_window_checkbox = new QCheckBox( "Save entire rviz window" ); button_box_ = new QDialogButtonBox( QDialogButtonBox::Save | QDialogButtonBox::Retry | QDialogButtonBox::Cancel ); QVBoxLayout* main_layout = new QVBoxLayout; main_layout->addWidget( image_widget_, 100 ); main_layout->addWidget( new QLabel( "Image will be saved at the original resolution." )); main_layout->addWidget( full_window_checkbox ); main_layout->addWidget( button_box_ ); setLayout( main_layout ); connect( button_box_, SIGNAL( clicked( QAbstractButton* )), this, SLOT( onButtonClicked( QAbstractButton* ))); connect( full_window_checkbox, SIGNAL( toggled( bool )), this, SLOT( setSaveFullWindow( bool ))); connect( delay_timer_, SIGNAL( timeout() ), this, SLOT( onTimeout() )); } void ScreenshotDialog::showEvent( QShowEvent* event ) { if( first_time_ ) { QPoint center = main_window_->rect().center(); move( center.x() - width() / 2, center.y() - height() / 2 ); first_time_ = false; } QWidget::showEvent( event ); } void ScreenshotDialog::setSaveFullWindow( bool save_full_window ) { save_full_window_ = save_full_window; takeScreenshot(); } void ScreenshotDialog::takeScreenshot() { main_window_->raise(); delay_timer_->start(100); } void ScreenshotDialog::onTimeout() { delay_timer_->stop(); takeScreenshotNow(); raise(); activateWindow(); } void ScreenshotDialog::takeScreenshotNow() { if( save_full_window_ ) { screenshot_ = QPixmap::grabWindow( main_window_->winId() ); } else { screenshot_ = QPixmap::grabWindow( render_window_->winId() ); } image_widget_->setImage( screenshot_ ); } void ScreenshotDialog::onButtonClicked( QAbstractButton* clicked ) { if( clicked == button_box_->button( QDialogButtonBox::Save )) { save(); } else if( clicked == button_box_->button( QDialogButtonBox::Retry )) { takeScreenshot(); } else if( clicked == button_box_->button( QDialogButtonBox::Cancel )) { close(); } } void ScreenshotDialog::save() { QString default_save_file = default_save_dir_ + "/rviz_screenshot_" + QDateTime::currentDateTime().toString( "yyyy_MM_dd-hh_mm_ss" ) + ".png"; QString filename = QFileDialog::getSaveFileName( this, "Save image", default_save_file ); if( filename != "" ) { QString with_slashes = QDir::fromNativeSeparators( filename ); QString file_part = with_slashes.section( '/', -1 ); default_save_dir_ = QDir::toNativeSeparators( with_slashes.section( '/', 0, -2 )); Q_EMIT savedInDirectory( default_save_dir_ ); // If filename has no dot, like "image" or has a dot in the zeroth // position, like ".image", add ".png" to give a default file // format. if( file_part.lastIndexOf( "." ) <= 0 ) { filename += ".png"; } QImageWriter writer( filename ); if( writer.write( screenshot_.toImage() )) { close(); } else { QString error_message; if( writer.error() == QImageWriter::UnsupportedFormatError ) { QString suffix = filename.section( '.', -1 ); QString formats_string; QList formats = QImageWriter::supportedImageFormats(); formats_string = formats[0]; for( int i = 1; i < formats.size(); i++ ) { formats_string += ", " + formats[ i ]; } error_message = "File type '" + suffix + "' is not supported.\n" + "Supported image formats are: " + formats_string + "\n"; } else { error_message = "Failed to write image to file " + filename; } QMessageBox::critical( this, "Error", error_message ); } } } } // end namespace rviz rviz-1.12.4/src/rviz/screenshot_dialog.h000066400000000000000000000056401300447110700202210ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SCREENSHOT_DIALOG_H #define RVIZ_SCREENSHOT_DIALOG_H #include class QPixmap; class QAbstractButton; class QDialogButtonBox; class QTimer; class QCheckBox; namespace rviz { class ScaledImageWidget; /** * \brief A dialog for grabbing a screen shot. * * Takes the screenshot while in the constructor, then shows a * half-size view of the screenshot in the dialog with buttons for * save/try-again/cancel. */ class ScreenshotDialog: public QWidget { Q_OBJECT public: ScreenshotDialog( QWidget* main_window, QWidget* render_window, const QString& default_save_dir = QString() ); virtual ~ScreenshotDialog() {} Q_SIGNALS: /** @brief Emitted when the user saves a file. */ void savedInDirectory( const QString& directory ); protected Q_SLOTS: void takeScreenshot(); void onTimeout(); void takeScreenshotNow(); void save(); void onButtonClicked( QAbstractButton* clicked ); void setSaveFullWindow( bool save_full_window ); protected: virtual void showEvent( QShowEvent* event ); private: ScaledImageWidget* image_widget_; QWidget* main_window_; QWidget* render_window_; QPixmap screenshot_; QDialogButtonBox* button_box_; bool save_full_window_; QTimer* delay_timer_; QSize saved_size_; bool first_time_; QString default_save_dir_; }; } // namespace rviz #endif // RVIZ_SCREENSHOT_DIALOG_H rviz-1.12.4/src/rviz/selection/000077500000000000000000000000001300447110700163345ustar00rootroot00000000000000rviz-1.12.4/src/rviz/selection/forwards.h000066400000000000000000000055241300447110700203420ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SELECTION_FORWARDS_H #define RVIZ_SELECTION_FORWARDS_H #include #include #include #include #include #include #include namespace rviz { typedef uint32_t CollObjectHandle; typedef std::vector V_CollObject; typedef std::vector VV_CollObject; typedef std::set S_CollObject; typedef std::set S_uint64; typedef std::vector V_uint64; struct Picked { Picked(CollObjectHandle _handle = 0 ) : handle(_handle), pixel_count(1) { } CollObjectHandle handle; int pixel_count; S_uint64 extra_handles; }; typedef boost::unordered_map M_Picked; inline uint32_t colorToHandle(Ogre::PixelFormat fmt, uint32_t col) { uint32_t handle = 0; if (fmt == Ogre::PF_A8R8G8B8 || fmt == Ogre::PF_X8R8G8B8) { handle = col & 0x00ffffff; } else if (fmt == Ogre::PF_R8G8B8A8) { handle = col >> 8; } else { ROS_DEBUG("Incompatible pixel format [%d]", fmt); } return handle; } inline CollObjectHandle colorToHandle( const Ogre::ColourValue & color ) { return (int(color.r * 255) << 16) | (int(color.g * 255) << 8) | int(color.b * 255); } } #endif rviz-1.12.4/src/rviz/selection/selection_handler.cpp000066400000000000000000000162101300447110700225220ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "selection_handler.h" #include "properties/property.h" #include "visualization_manager.h" #include #include #include #include #include #include #include #include "rviz/selection/selection_manager.h" namespace rviz { SelectionHandler::SelectionHandler( DisplayContext* context ) : context_( context ) , listener_( new Listener( this )) { pick_handle_ = context_->getSelectionManager()->createHandle(); context_->getSelectionManager()->addObject( pick_handle_, this ); } SelectionHandler::~SelectionHandler() { S_Movable::iterator it = tracked_objects_.begin(); S_Movable::iterator end = tracked_objects_.end(); for (; it != end; ++it) { Ogre::MovableObject* m = *it; m->setListener(0); } while (!boxes_.empty()) { destroyBox(boxes_.begin()->first); } context_->getSelectionManager()->removeObject( pick_handle_ ); } void SelectionHandler::preRenderPass(uint32_t pass) { M_HandleToBox::iterator it = boxes_.begin(); M_HandleToBox::iterator end = boxes_.end(); for (; it != end; ++it) { Ogre::WireBoundingBox* box = it->second.second; box->setVisible(false); } } void SelectionHandler::postRenderPass(uint32_t pass) { M_HandleToBox::iterator it = boxes_.begin(); M_HandleToBox::iterator end = boxes_.end(); for (; it != end; ++it) { Ogre::WireBoundingBox* box = it->second.second; box->setVisible(true); } } void SelectionHandler::addTrackedObjects( Ogre::SceneNode* node ) { if (!node) { return; } // Loop over all objects attached to this node. Ogre::SceneNode::ObjectIterator obj_it = node->getAttachedObjectIterator(); while( obj_it.hasMoreElements() ) { Ogre::MovableObject* obj = obj_it.getNext(); addTrackedObject( obj ); } // Loop over and recurse into all child nodes. Ogre::SceneNode::ChildNodeIterator child_it = node->getChildIterator(); while( child_it.hasMoreElements() ) { Ogre::SceneNode* child = dynamic_cast( child_it.getNext() ); addTrackedObjects( child ); } } void SelectionHandler::addTrackedObject(Ogre::MovableObject* object) { tracked_objects_.insert(object); object->setListener(listener_.get()); SelectionManager::setPickHandle( pick_handle_, object ); } void SelectionHandler::removeTrackedObject(Ogre::MovableObject* object) { tracked_objects_.erase(object); object->setListener(0); updateTrackedBoxes(); } void SelectionHandler::updateTrackedBoxes() { M_HandleToBox::iterator it = boxes_.begin(); M_HandleToBox::iterator end = boxes_.end(); for (; it != end; ++it) { V_AABB aabbs; Picked p(it->first.first); p.extra_handles.insert(it->first.second); getAABBs(Picked(it->first.first), aabbs); if (!aabbs.empty()) { Ogre::AxisAlignedBox combined; V_AABB::iterator aabb_it = aabbs.begin(); V_AABB::iterator aabb_end = aabbs.end(); for (; aabb_it != aabb_end; ++aabb_it) { combined.merge(*aabb_it); } createBox(std::make_pair(p.handle, it->first.second), combined, "RVIZ/Cyan"); } } } void SelectionHandler::getAABBs(const Picked& obj, V_AABB& aabbs) { S_Movable::iterator it = tracked_objects_.begin(); S_Movable::iterator end = tracked_objects_.end(); for (; it != end; ++it) { aabbs.push_back((*it)->getWorldBoundingBox()); } } void SelectionHandler::destroyProperties( const Picked& obj, Property* parent_property ) { for( int i = 0; i < properties_.size(); i++ ) { delete properties_.at( i ); } properties_.clear(); } void SelectionHandler::createBox(const std::pair& handles, const Ogre::AxisAlignedBox& aabb, const std::string& material_name) { Ogre::WireBoundingBox* box = 0; Ogre::SceneNode* node = 0; M_HandleToBox::iterator it = boxes_.find(handles); if (it == boxes_.end()) { Ogre::SceneManager* scene_manager = context_->getSceneManager(); node = scene_manager->getRootSceneNode()->createChildSceneNode(); box = new Ogre::WireBoundingBox; bool inserted = boxes_.insert(std::make_pair(handles, std::make_pair(node, box))).second; ROS_ASSERT(inserted); } else { node = it->second.first; box = it->second.second; } box->setMaterial(material_name); box->setupBoundingBox(aabb); node->detachAllObjects(); node->attachObject(box); } void SelectionHandler::destroyBox(const std::pair& handles) { M_HandleToBox::iterator it = boxes_.find(handles); if (it != boxes_.end()) { Ogre::SceneNode* node = it->second.first; Ogre::WireBoundingBox* box = it->second.second; node->detachAllObjects(); node->getParentSceneNode()->removeAndDestroyChild(node->getName()); delete box; boxes_.erase(it); } } void SelectionHandler::onSelect(const Picked& obj) { ROS_DEBUG("Selected 0x%08x", obj.handle); V_AABB aabbs; getAABBs(obj, aabbs); if (!aabbs.empty()) { Ogre::AxisAlignedBox combined; V_AABB::iterator it = aabbs.begin(); V_AABB::iterator end = aabbs.end(); for (; it != end; ++it) { combined.merge(*it); } createBox(std::make_pair(obj.handle, 0ULL), combined, "RVIZ/Cyan"); } } void SelectionHandler::onDeselect(const Picked& obj) { ROS_DEBUG("Deselected 0x%08x", obj.handle); destroyBox(std::make_pair(obj.handle, 0ULL)); } void SelectionHandler::setInteractiveObject( InteractiveObjectWPtr object ) { interactive_object_ = object; } InteractiveObjectWPtr SelectionHandler::getInteractiveObject() { return interactive_object_; } } rviz-1.12.4/src/rviz/selection/selection_handler.h000066400000000000000000000143721300447110700221760ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SELECTION_HANDLER_H #define RVIZ_SELECTION_HANDLER_H #include #include #ifndef Q_MOC_RUN #include #include #include #endif #include "rviz/selection/forwards.h" #include "rviz/selection/selection_handler.h" #include "rviz/viewport_mouse_event.h" #include "rviz/interactive_object.h" namespace Ogre { class WireBoundingBox; class SceneNode; class MovableObject; } namespace rviz { class DisplayContext; class Property; class ViewportMouseEvent; typedef std::vector V_AABB; class SelectionHandler { public: SelectionHandler( DisplayContext* context ); virtual ~SelectionHandler(); void addTrackedObjects( Ogre::SceneNode* node ); void addTrackedObject(Ogre::MovableObject* object); void removeTrackedObject(Ogre::MovableObject* object); virtual void updateTrackedBoxes(); /** @brief Override to create properties of the given picked object(s). * * Top-level properties created here should be added to * #properties_ so they will be automatically deleted by * deleteProperties(). * * This base implementation does nothing. */ virtual void createProperties( const Picked& obj, Property* parent_property ) {} /** @brief Destroy all properties for the given picked object(s). * * This base implementation destroys all the properties in #properties_. * * If createProperties() adds all the top-level properties to * #properties_, there is no need to override this in a * subclass. */ virtual void destroyProperties( const Picked& obj, Property* parent_property ); /** @brief Override to update property values. * * updateProperties() is called on a timer to give selection * handlers a chance to update displayed property values. * Subclasses with properties that can change should implement this * to update the property values based on new information from the * selected object(s). * * This base implementation does nothing. */ virtual void updateProperties() {} virtual bool needsAdditionalRenderPass(uint32_t pass) { return false; } virtual void preRenderPass(uint32_t pass); virtual void postRenderPass(uint32_t pass); virtual void getAABBs(const Picked& obj, V_AABB& aabbs); virtual void onSelect(const Picked& obj); virtual void onDeselect(const Picked& obj); /** @brief Set an object to listen to mouse events and other * interaction calls during use of the 'interact' tool. */ virtual void setInteractiveObject( InteractiveObjectWPtr object ); /** @brief Get the object to listen to mouse events and other * interaction calls during use of the 'interact' tool. * * Returns a boost::weak_ptr to the object, which may or may not * point to something. Do not lock() the result and hold it for * long periods because it may cause something visual to stick * around after it was meant to be destroyed. */ virtual InteractiveObjectWPtr getInteractiveObject(); CollObjectHandle getHandle() const { return pick_handle_; } protected: /** @brief Create or update a box for the given handle-int pair, with the box specified by @a aabb. */ void createBox(const std::pair& handles, const Ogre::AxisAlignedBox& aabb, const std::string& material_name); /** @brief Destroy the box associated with the given handle-int pair, if there is one. */ void destroyBox(const std::pair& handles); QList properties_; typedef std::map, std::pair > M_HandleToBox; M_HandleToBox boxes_; DisplayContext* context_; typedef std::set S_Movable; S_Movable tracked_objects_; class Listener : public Ogre::MovableObject::Listener { public: Listener(SelectionHandler* handler) : handler_(handler) {} virtual void objectMoved(Ogre::MovableObject* object) { handler_->updateTrackedBoxes(); } virtual void objectDestroyed(Ogre::MovableObject* object) { handler_->removeTrackedObject(object); } SelectionHandler* handler_; }; typedef boost::shared_ptr ListenerPtr; ListenerPtr listener_; InteractiveObjectWPtr interactive_object_; private: // pick_handle_ must never be changed, otherwise the destructor will // call removeObject() with the wrong handle. Use getHandle() to // access the value. CollObjectHandle pick_handle_; friend class SelectionManager; }; typedef boost::shared_ptr SelectionHandlerPtr; typedef std::vector V_SelectionHandler; typedef std::set S_SelectionHandler; } #endif rviz-1.12.4/src/rviz/selection/selection_manager.cpp000066400000000000000000001145551300447110700225320ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/ogre_helpers/custom_parameter_indices.h" #include "rviz/ogre_helpers/qt_ogre_render_window.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/properties/property.h" #include "rviz/properties/property_tree_model.h" #include "rviz/render_panel.h" #include "rviz/view_controller.h" #include "rviz/view_manager.h" #include "rviz/visualization_manager.h" #include "rviz/selection/selection_manager.h" #include namespace rviz { SelectionManager::SelectionManager(VisualizationManager* manager) : vis_manager_(manager) , highlight_enabled_(false) , uid_counter_(0) , interaction_enabled_(false) , debug_mode_( false ) , property_model_( new PropertyTreeModel( new Property( "root" ))) { for (uint32_t i = 0; i < s_num_render_textures_; ++i) { pixel_boxes_[i].data = 0; } depth_pixel_box_.data = 0; QTimer* timer = new QTimer( this ); connect( timer, SIGNAL( timeout() ), this, SLOT( updateProperties() )); timer->start( 200 ); } SelectionManager::~SelectionManager() { boost::recursive_mutex::scoped_lock lock(global_mutex_); setSelection(M_Picked()); highlight_node_->getParentSceneNode()->removeAndDestroyChild(highlight_node_->getName()); delete highlight_rectangle_; for (uint32_t i = 0; i < s_num_render_textures_; ++i) { delete [] (uint8_t*)pixel_boxes_[i].data; } delete [] (uint8_t*)depth_pixel_box_.data; vis_manager_->getSceneManager()->destroyCamera( camera_ ); delete property_model_; } void SelectionManager::setDebugMode( bool debug ) { debug_mode_ = debug; } void SelectionManager::initialize() { // Create our render textures setTextureSize(1); // Create our highlight rectangle Ogre::SceneManager* scene_manager = vis_manager_->getSceneManager(); highlight_node_ = scene_manager->getRootSceneNode()->createChildSceneNode(); std::stringstream ss; static int count = 0; ss << "SelectionRect" << count++; highlight_rectangle_ = new Ogre::Rectangle2D(true); const static uint32_t texture_data[1] = { 0xffff0080 }; Ogre::DataStreamPtr pixel_stream; pixel_stream.bind(new Ogre::MemoryDataStream( (void*)&texture_data[0], 4 )); Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().loadRawData(ss.str() + "Texture", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, pixel_stream, 1, 1, Ogre::PF_R8G8B8A8, Ogre::TEX_TYPE_2D, 0); Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); material->setLightingEnabled(false); //material->getTechnique(0)->getPass(0)->setPolygonMode(Ogre::PM_WIREFRAME); highlight_rectangle_->setMaterial(material->getName()); Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); highlight_rectangle_->setBoundingBox(aabInf); highlight_rectangle_->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - 1); material->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); material->setCullingMode(Ogre::CULL_NONE); Ogre::TextureUnitState* tex_unit = material->getTechnique(0)->getPass(0)->createTextureUnitState(); tex_unit->setTextureName(tex->getName()); tex_unit->setTextureFiltering( Ogre::TFO_NONE ); highlight_node_->attachObject(highlight_rectangle_); // create picking camera camera_= scene_manager->createCamera( ss.str()+"_camera" ); // create fallback picking material fallback_pick_material_ = Ogre::MaterialManager::getSingleton().getByName( "rviz/DefaultPickAndDepth" ); fallback_pick_material_->load(); fallback_pick_cull_technique_ = fallback_pick_material_->getTechnique( "PickCull" ); fallback_black_cull_technique_ = fallback_pick_material_->getTechnique( "BlackCull" ); fallback_depth_cull_technique_ = fallback_pick_material_->getTechnique( "DepthCull" ); fallback_pick_technique_ = fallback_pick_material_->getTechnique( "Pick" ); fallback_black_technique_ = fallback_pick_material_->getTechnique( "Black" ); fallback_depth_technique_ = fallback_pick_material_->getTechnique( "Depth" ); } bool SelectionManager::get3DPoint( Ogre::Viewport* viewport, int x, int y, Ogre::Vector3& result_point ) { ROS_DEBUG("SelectionManager.get3DPoint()"); std::vector result_points_temp; bool success = get3DPatch( viewport, x, y, 1, 1, true, result_points_temp); if (result_points_temp.size() == 0) { // return result_point unmodified if get point fails. return false; } result_point = result_points_temp[0]; return success; } bool SelectionManager::getPatchDepthImage( Ogre::Viewport* viewport, int x, int y, unsigned width, unsigned height, std::vector & depth_vector ) { unsigned int num_pixels = width*height; depth_vector.reserve(num_pixels); setDepthTextureSize( width, height ); M_CollisionObjectToSelectionHandler::iterator handler_it = objects_.begin(); M_CollisionObjectToSelectionHandler::iterator handler_end = objects_.end(); for (; handler_it != handler_end; ++handler_it) { handler_it->second->preRenderPass(0); } bool success = false; if( render( viewport, depth_render_texture_, x, y, x + width, y + height, depth_pixel_box_, "Depth", depth_texture_width_, depth_texture_height_ ) ) { uint8_t* data_ptr = (uint8_t*) depth_pixel_box_.data; for(uint32_t pixel = 0; pixel < num_pixels; ++pixel) { uint8_t a = data_ptr[4*pixel]; uint8_t b = data_ptr[4*pixel + 1]; uint8_t c = data_ptr[4*pixel + 2]; int int_depth = (c << 16) | (b << 8) | a; float normalized_depth = ((float) int_depth) / (float) 0xffffff; depth_vector.push_back(normalized_depth * camera_->getFarClipDistance()); } } else { ROS_WARN("Failed to render depth patch\n"); return false; } handler_it = objects_.begin(); handler_end = objects_.end(); for (; handler_it != handler_end; ++handler_it) { handler_it->second->postRenderPass(0); } return true; } bool SelectionManager::get3DPatch( Ogre::Viewport* viewport, int x, int y, unsigned width, unsigned height, bool skip_missing, std::vector &result_points ) { boost::recursive_mutex::scoped_lock lock(global_mutex_); ROS_DEBUG("SelectionManager.get3DPatch()"); std::vector depth_vector; if ( !getPatchDepthImage( viewport, x, y, width, height, depth_vector ) ) return false; unsigned int pixel_counter = 0; Ogre::Matrix4 projection = camera_->getProjectionMatrix(); float depth; for(int y_iter = 0; y_iter < height; ++y_iter) for(int x_iter = 0 ; x_iter < width; ++x_iter) { depth = depth_vector[pixel_counter]; //Deal with missing or invalid points if( ( depth > camera_->getFarClipDistance() ) || ( depth == 0 ) ) { ++pixel_counter; if (!skip_missing) { result_points.push_back(Ogre::Vector3(NAN,NAN,NAN)); } continue; } Ogre::Vector3 result_point; // We want to shoot rays through the center of pixels, not the corners, // so add .5 pixels to the x and y coordinate to get to the center // instead of the top left of the pixel. Ogre::Real screenx = float(x_iter + .5)/float(width); Ogre::Real screeny = float(y_iter + .5)/float(height); if( projection[3][3] == 0.0 ) // If this is a perspective projection { // get world-space ray from camera & mouse coord Ogre::Ray vp_ray = camera_->getCameraToViewportRay(screenx, screeny ); // transform ray direction back into camera coords Ogre::Vector3 dir_cam = camera_->getDerivedOrientation().Inverse() * vp_ray.getDirection(); // normalize, so dir_cam.z == -depth dir_cam = dir_cam / dir_cam.z * depth * -1; // compute 3d point from camera origin and direction*/ result_point = camera_->getDerivedPosition() + camera_->getDerivedOrientation() * dir_cam; } else // else this must be an orthographic projection. { // For orthographic projection, getCameraToViewportRay() does // the right thing for us, and the above math does not work. Ogre::Ray ray; camera_->getCameraToViewportRay(screenx, screeny, &ray); result_point = ray.getPoint(depth); } result_points.push_back(result_point); ++pixel_counter; } return result_points.size() > 0; } void SelectionManager::setDepthTextureSize(unsigned width, unsigned height) { // Cap and store requested texture size // It's probably an error if an invalid size is requested. if ( width > 1024 ) { width = 1024; ROS_ERROR_STREAM("SelectionManager::setDepthTextureSize invalid width requested. Max Width: 1024 -- Width requested: " << width << ". Capping Width at 1024."); } if ( depth_texture_width_ != width ) depth_texture_width_ = width; if ( height > 1024 ) { height = 1024; ROS_ERROR_STREAM("SelectionManager::setDepthTextureSize invalid height requested. Max Height: 1024 -- Height requested: " << width << ". Capping Height at 1024."); } if ( depth_texture_height_ != height ) depth_texture_height_ = height; if ( !depth_render_texture_.get() || depth_render_texture_->getWidth() != width || depth_render_texture_->getHeight() != height) { std::string tex_name = "DepthTexture"; if ( depth_render_texture_.get() ) { tex_name = depth_render_texture_->getName(); // destroy old Ogre::TextureManager::getSingleton().remove( tex_name ); } depth_render_texture_ = Ogre::TextureManager::getSingleton().createManual( tex_name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, depth_texture_width_, depth_texture_height_, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET ); Ogre::RenderTexture* render_texture = depth_render_texture_->getBuffer()->getRenderTarget(); render_texture->setAutoUpdated(false); } } void SelectionManager::setTextureSize( unsigned size ) { if ( size > 1024 ) { size = 1024; } texture_size_ = size; for (uint32_t pass = 0; pass < s_num_render_textures_; ++pass) { // check if we need to change the texture size if ( !render_textures_[pass].get() || render_textures_[pass]->getWidth() != size ) { std::string tex_name; if ( render_textures_[pass].get() ) { tex_name = render_textures_[pass]->getName(); // destroy old Ogre::TextureManager::getSingleton().remove( tex_name ); } else { std::stringstream ss; static int count = 0; ss << "SelectionTexture" << count++; tex_name = ss.str(); } // create new texture render_textures_[pass] = Ogre::TextureManager::getSingleton().createManual( tex_name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, size, size, 0, Ogre::PF_R8G8B8, Ogre::TU_STATIC | Ogre::TU_RENDERTARGET); Ogre::RenderTexture* render_texture = render_textures_[pass]->getBuffer()->getRenderTarget(); render_texture->setAutoUpdated(false); } } } void SelectionManager::clearHandlers() { boost::recursive_mutex::scoped_lock lock(global_mutex_); objects_.clear(); } void SelectionManager::enableInteraction( bool enable ) { interaction_enabled_ = enable; M_CollisionObjectToSelectionHandler::iterator handler_it = objects_.begin(); M_CollisionObjectToSelectionHandler::iterator handler_end = objects_.end(); for (; handler_it != handler_end; ++handler_it) { if( InteractiveObjectPtr object = handler_it->second->getInteractiveObject().lock() ) { object->enableInteraction( enable ); } } } CollObjectHandle SelectionManager::createHandle() { uid_counter_++; if (uid_counter_ > 0x00ffffff) { uid_counter_ = 0; } uint32_t handle = 0; // shuffle around the bits so we get lots of colors // when we're displaying the selection buffer for ( unsigned int i=0; i<24; i++ ) { uint32_t shift = (((23-i)%3)*8) + (23-i)/3; uint32_t bit = ( (uint32_t)(uid_counter_ >> i) & (uint32_t)1 ) << shift; handle |= bit; } return handle; } void SelectionManager::addObject(CollObjectHandle obj, SelectionHandler* handler) { if (!obj) { // ROS_BREAK(); return; } boost::recursive_mutex::scoped_lock lock(global_mutex_); InteractiveObjectPtr object = handler->getInteractiveObject().lock(); if( object ) { object->enableInteraction( interaction_enabled_ ); } bool inserted = objects_.insert( std::make_pair( obj, handler )).second; ROS_ASSERT(inserted); } void SelectionManager::removeObject(CollObjectHandle obj) { if (!obj) { return; } boost::recursive_mutex::scoped_lock lock(global_mutex_); M_Picked::iterator it = selection_.find(obj); if (it != selection_.end()) { M_Picked objs; objs.insert(std::make_pair(it->first, it->second)); removeSelection(objs); } objects_.erase(obj); } void SelectionManager::update() { boost::recursive_mutex::scoped_lock lock(global_mutex_); highlight_node_->setVisible(highlight_enabled_); if (highlight_enabled_) { setHighlightRect(highlight_.viewport, highlight_.x1, highlight_.y1, highlight_.x2, highlight_.y2); #if 0 M_Picked results; highlight_node_->setVisible(false); pick(highlight_.viewport, highlight_.x1, highlight_.y1, highlight_.x2, highlight_.y2, results); highlight_node_->setVisible(true); #endif } } void SelectionManager::highlight(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2) { boost::recursive_mutex::scoped_lock lock(global_mutex_); highlight_enabled_ = true; highlight_.viewport = viewport; highlight_.x1 = x1; highlight_.y1 = y1; highlight_.x2 = x2; highlight_.y2 = y2; } void SelectionManager::removeHighlight() { boost::recursive_mutex::scoped_lock lock(global_mutex_); highlight_enabled_ = false; } void SelectionManager::select(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2, SelectType type) { boost::recursive_mutex::scoped_lock lock(global_mutex_); highlight_enabled_ = false; highlight_node_->setVisible(false); M_Picked results; pick(viewport, x1, y1, x2, y2, results); if (type == Add) { addSelection(results); } else if (type == Remove) { removeSelection(results); } else if (type == Replace) { setSelection(results); } } void SelectionManager::setHighlightRect(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2) { float nx1 = ((float)x1 / viewport->getActualWidth()) * 2 - 1; float nx2 = ((float)x2 / viewport->getActualWidth()) * 2 - 1; float ny1 = -(((float)y1 / viewport->getActualHeight()) * 2 - 1); float ny2 = -(((float)y2 / viewport->getActualHeight()) * 2 - 1); nx1 = nx1 < -1 ? -1 : (nx1 > 1 ? 1 : nx1); ny1 = ny1 < -1 ? -1 : (ny1 > 1 ? 1 : ny1); nx2 = nx2 < -1 ? -1 : (nx2 > 1 ? 1 : nx2); ny2 = ny2 < -1 ? -1 : (ny2 > 1 ? 1 : ny2); highlight_rectangle_->setCorners(nx1, ny1, nx2, ny2); } void SelectionManager::unpackColors( const Ogre::PixelBox& box, V_CollObject& pixels) { int w = box.getWidth(); int h = box.getHeight(); pixels.clear(); pixels.reserve( w*h ); for (int y = 0; y < h; y ++) { for (int x = 0; x < w; x ++) { uint32_t pos = (x + y*w) * 4; uint32_t pix_val = *(uint32_t*)((uint8_t*)box.data + pos); uint32_t handle = colorToHandle(box.format, pix_val); pixels.push_back(handle); } } } void SelectionManager::renderAndUnpack(Ogre::Viewport* viewport, uint32_t pass, int x1, int y1, int x2, int y2, V_CollObject& pixels) { ROS_ASSERT(pass < s_num_render_textures_); std::stringstream scheme; scheme << "Pick"; if (pass > 0) { scheme << pass; } if( render( viewport, render_textures_[pass], x1, y1, x2, y2, pixel_boxes_[pass], scheme.str(), texture_size_, texture_size_ )) { unpackColors(pixel_boxes_[pass], pixels); } } bool SelectionManager::render(Ogre::Viewport* viewport, Ogre::TexturePtr tex, int x1, int y1, int x2, int y2, Ogre::PixelBox& dst_box, std::string material_scheme, unsigned texture_width, unsigned texture_height) { vis_manager_->lockRender(); if ( x1 > x2 ) std::swap( x1, x2 ); if ( y1 > y2 ) std::swap( y1, y2 ); if ( x1 < 0 ) x1 = 0; if ( y1 < 0 ) y1 = 0; if ( x1 > viewport->getActualWidth()-2 ) x1 = viewport->getActualWidth()-2; if ( y1 > viewport->getActualHeight()-2 ) y1 = viewport->getActualHeight()-2; if ( x2 < 0 ) x2 = 0; if ( y2 < 0 ) y2 = 0; if ( x2 > viewport->getActualWidth()-2 ) x2 = viewport->getActualWidth()-2; if ( y2 > viewport->getActualHeight()-2 ) y2 = viewport->getActualHeight()-2; if ( x2==x1 ) x2++; if ( y2==y1 ) y2++; if ( x2==x1 || y2==y1 ) { ROS_WARN("SelectionManager::render(): not rendering 0 size area."); vis_manager_->unlockRender(); return false; } unsigned w = x2-x1; unsigned h = y2-y1; Ogre::HardwarePixelBufferSharedPtr pixel_buffer = tex->getBuffer(); Ogre::RenderTexture* render_texture = pixel_buffer->getRenderTarget(); Ogre::Matrix4 proj_matrix = viewport->getCamera()->getProjectionMatrix(); Ogre::Matrix4 scale_matrix = Ogre::Matrix4::IDENTITY; Ogre::Matrix4 trans_matrix = Ogre::Matrix4::IDENTITY; float x1_rel = static_cast(x1) / static_cast(viewport->getActualWidth() - 1) - 0.5f; float y1_rel = static_cast(y1) / static_cast(viewport->getActualHeight() - 1) - 0.5f; float x2_rel = static_cast(x2) / static_cast(viewport->getActualWidth() - 1) - 0.5f; float y2_rel = static_cast(y2) / static_cast(viewport->getActualHeight() - 1) - 0.5f; scale_matrix[0][0] = 1.0 / (x2_rel-x1_rel); scale_matrix[1][1] = 1.0 / (y2_rel-y1_rel); trans_matrix[0][3] -= x1_rel+x2_rel; trans_matrix[1][3] += y1_rel+y2_rel; camera_->setCustomProjectionMatrix( true, scale_matrix * trans_matrix * proj_matrix ); camera_->setPosition( viewport->getCamera()->getDerivedPosition() ); camera_->setOrientation( viewport->getCamera()->getDerivedOrientation() ); // create a viewport if there is none if (render_texture->getNumViewports() == 0) { render_texture->removeAllViewports(); render_texture->addViewport( camera_ ); Ogre::Viewport* render_viewport = render_texture->getViewport(0); render_viewport->setClearEveryFrame(true); render_viewport->setBackgroundColour( Ogre::ColourValue::Black ); render_viewport->setOverlaysEnabled(false); render_viewport->setMaterialScheme(material_scheme); } unsigned render_w = w; unsigned render_h = h; if ( w>h ) { if ( render_w > texture_width ) { render_w = texture_width; render_h = round( float(h) * (float)texture_width / (float)w ); } } else { if ( render_h > texture_height ) { render_h = texture_height; render_w = round( float(w) * (float)texture_height / (float)h ); } } // safety clamping in case of rounding errors if ( render_w > texture_width ) render_w = texture_width; if ( render_h > texture_height ) render_h = texture_height; // set viewport to render to a subwindow of the texture Ogre::Viewport* render_viewport = render_texture->getViewport(0); render_viewport->setDimensions( 0, 0, (float)render_w / (float)texture_width, (float)render_h / (float)texture_height ); // make sure the same objects are visible as in the original viewport render_viewport->setVisibilityMask( viewport->getVisibilityMask() ); ros::WallTime start = ros::WallTime::now(); // update & force ogre to render the scene Ogre::MaterialManager::getSingleton().addListener(this); render_texture->update(); // For some reason we need to pretend to render the main window in // order to get the picking render to show up in the pixelbox below. // If we don't do this, it will show up there the *next* time we // pick something, but not this time. This object as a // render queue listener tells the scene manager to skip every // render step, so nothing actually gets drawn. // // TODO: find out what part of _renderScene() actually makes this work. Ogre::Viewport* main_view = vis_manager_->getRenderPanel()->getViewport(); vis_manager_->getSceneManager()->addRenderQueueListener(this); vis_manager_->getSceneManager()->_renderScene(main_view->getCamera(), main_view, false); vis_manager_->getSceneManager()->removeRenderQueueListener(this); ros::WallTime end = ros::WallTime::now(); ros::WallDuration d = end - start; // ROS_DEBUG("Render took [%f] msec", d.toSec() * 1000.0f); Ogre::MaterialManager::getSingleton().removeListener(this); render_w = render_viewport->getActualWidth(); render_h = render_viewport->getActualHeight(); Ogre::PixelFormat format = pixel_buffer->getFormat(); int size = Ogre::PixelUtil::getMemorySize(render_w, render_h, 1, format); uint8_t* data = new uint8_t[size]; delete [] (uint8_t*)dst_box.data; dst_box = Ogre::PixelBox(render_w, render_h, 1, format, data); pixel_buffer->blitToMemory(dst_box,dst_box); vis_manager_->unlockRender(); if( debug_mode_ ) { publishDebugImage( dst_box, material_scheme ); } return true; } void SelectionManager::publishDebugImage( const Ogre::PixelBox& pixel_box, const std::string& label ) { ros::Publisher pub; ros::NodeHandle nh; PublisherMap::const_iterator iter = debug_publishers_.find( label ); if( iter == debug_publishers_.end() ) { pub = nh.advertise( "/rviz_debug/" + label, 2 ); debug_publishers_[ label ] = pub; } else { pub = iter->second; } sensor_msgs::Image msg; msg.header.stamp = ros::Time::now(); msg.width = pixel_box.getWidth(); msg.height = pixel_box.getHeight(); msg.encoding = sensor_msgs::image_encodings::RGB8; msg.is_bigendian = false; msg.step = msg.width * 3; int dest_byte_count = msg.width * msg.height * 3; msg.data.resize( dest_byte_count ); int dest_index = 0; uint8_t* source_ptr = (uint8_t*)pixel_box.data; int pre_pixel_padding = 0; int post_pixel_padding = 0; switch( pixel_box.format ) { case Ogre::PF_A8R8G8B8: case Ogre::PF_X8R8G8B8: post_pixel_padding = 1; break; case Ogre::PF_R8G8B8A8: pre_pixel_padding = 1; break; default: ROS_ERROR( "SelectionManager::publishDebugImage(): Incompatible pixel format [%d]", pixel_box.format ); return; } uint8_t r, g, b; while( dest_index < dest_byte_count ) { source_ptr += pre_pixel_padding; b = *source_ptr++; g = *source_ptr++; r = *source_ptr++; source_ptr += post_pixel_padding; msg.data[ dest_index++ ] = r; msg.data[ dest_index++ ] = g; msg.data[ dest_index++ ] = b; } pub.publish( msg ); } void SelectionManager::renderQueueStarted( uint8_t queueGroupId, const std::string& invocation, bool& skipThisInvocation ) { // This render queue listener function tells the scene manager to // skip every render step, so nothing actually gets drawn. // ROS_DEBUG("SelectionManager renderQueueStarted(%d, '%s') returning skip = true.", (int)queueGroupId, invocation.c_str()); skipThisInvocation = true; } void SelectionManager::pick(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2, M_Picked& results, bool single_render_pass) { boost::recursive_mutex::scoped_lock lock(global_mutex_); bool need_additional_render = false; V_CollObject handles_by_pixel; S_CollObject need_additional; V_CollObject& pixels = pixel_buffer_; // First render is special... does the initial object picking, determines which objects have been selected // After that, individual handlers can specify that they need additional renders (max # defined in s_num_render_textures_) { M_CollisionObjectToSelectionHandler::iterator handler_it = objects_.begin(); M_CollisionObjectToSelectionHandler::iterator handler_end = objects_.end(); for (; handler_it != handler_end; ++handler_it) { handler_it->second->preRenderPass( 0 ); } renderAndUnpack(viewport, 0, x1, y1, x2, y2, pixels); handler_it = objects_.begin(); handler_end = objects_.end(); for (; handler_it != handler_end; ++handler_it) { handler_it->second->postRenderPass(0); } handles_by_pixel.reserve(pixels.size()); V_CollObject::iterator it = pixels.begin(); V_CollObject::iterator end = pixels.end(); for (; it != end; ++it) { const CollObjectHandle& p = *it; CollObjectHandle handle = p; handles_by_pixel.push_back(handle); if (handle == 0) { continue; } SelectionHandler* handler = getHandler( handle ); if( handler ) { std::pair insert_result = results.insert(std::make_pair(handle, Picked(handle))); if (insert_result.second) { if (handler->needsAdditionalRenderPass(1) && !single_render_pass) { need_additional.insert(handle); need_additional_render = true; } } else { insert_result.first->second.pixel_count++; } } } } uint32_t pass = 1; V_uint64 extra_by_pixel; extra_by_pixel.resize(handles_by_pixel.size()); while (need_additional_render && pass < s_num_render_textures_) { { S_CollObject::iterator need_it = need_additional.begin(); S_CollObject::iterator need_end = need_additional.end(); for (; need_it != need_end; ++need_it) { SelectionHandler* handler = getHandler( *need_it ); ROS_ASSERT(handler); handler->preRenderPass(pass); } } renderAndUnpack(viewport, pass, x1, y1, x2, y2, pixels); { S_CollObject::iterator need_it = need_additional.begin(); S_CollObject::iterator need_end = need_additional.end(); for (; need_it != need_end; ++need_it) { SelectionHandler* handler = getHandler( *need_it ); ROS_ASSERT(handler); handler->postRenderPass(pass); } } int i = 0; V_CollObject::iterator pix_it = pixels.begin(); V_CollObject::iterator pix_end = pixels.end(); for (; pix_it != pix_end; ++pix_it, ++i) { const CollObjectHandle& p = *pix_it; CollObjectHandle handle = handles_by_pixel[i]; if (pass == 1) { extra_by_pixel[i] = 0; } if (need_additional.find(handle) != need_additional.end()) { CollObjectHandle extra_handle = p; extra_by_pixel[i] |= extra_handle << (32 * (pass-1)); } else { extra_by_pixel[i] = 0; } } need_additional_render = false; need_additional.clear(); M_Picked::iterator handle_it = results.begin(); M_Picked::iterator handle_end = results.end(); for (; handle_it != handle_end; ++handle_it) { CollObjectHandle handle = handle_it->first; if (getHandler(handle)->needsAdditionalRenderPass(pass + 1)) { need_additional_render = true; need_additional.insert(handle); } } } int i = 0; V_uint64::iterator pix_2_it = extra_by_pixel.begin(); V_uint64::iterator pix_2_end = extra_by_pixel.end(); for (; pix_2_it != pix_2_end; ++pix_2_it, ++i) { CollObjectHandle handle = handles_by_pixel[i]; if (handle == 0) { continue; } M_Picked::iterator picked_it = results.find(handle); if (picked_it == results.end()) { continue; } Picked& picked = picked_it->second; if (*pix_2_it) { picked.extra_handles.insert(*pix_2_it); } } } Ogre::Technique *SelectionManager::handleSchemeNotFound(unsigned short scheme_index, const Ogre::String& scheme_name, Ogre::Material* original_material, unsigned short lod_index, const Ogre::Renderable* rend ) { // Find the original culling mode Ogre::CullingMode culling_mode = Ogre::CULL_CLOCKWISE; Ogre::Technique* orig_tech = original_material->getTechnique( 0 ); if( orig_tech && orig_tech->getNumPasses() > 0 ) { culling_mode = orig_tech->getPass( 0 )->getCullingMode(); } // find out if the renderable has the picking param set bool has_pick_param = ! rend->getUserObjectBindings().getUserAny( "pick_handle" ).isEmpty(); // NOTE: it is important to avoid changing the culling mode of the // fallback techniques here, because that change then propagates to // other uses of these fallback techniques in unpredictable ways. // If you want to change the technique programmatically (like with // Pass::setCullingMode()), make sure you do it on a cloned material // which doesn't get shared with other objects. // Use the technique with the right name and culling mode. if( culling_mode == Ogre::CULL_CLOCKWISE ) { if( scheme_name == "Pick" ) { return has_pick_param ? fallback_pick_cull_technique_ : fallback_black_cull_technique_; } else if( scheme_name == "Depth" ) { return fallback_depth_cull_technique_; } if( scheme_name == "Pick1" ) { return fallback_black_cull_technique_; } else { return NULL; } } else // Must be CULL_NONE because we never use CULL_ANTICLOCKWISE { if( scheme_name == "Pick" ) { return has_pick_param ? fallback_pick_technique_ : fallback_black_technique_; } else if( scheme_name == "Depth" ) { return fallback_depth_technique_; } if( scheme_name == "Pick1" ) { return fallback_black_technique_; } else { return NULL; } } } Ogre::ColourValue SelectionManager::handleToColor( CollObjectHandle handle ) { float r = ((handle >> 16) & 0xff) / 255.0f; float g = ((handle >> 8) & 0xff) / 255.0f; float b = (handle & 0xff) / 255.0f; return Ogre::ColourValue( r, g, b, 1.0f ); } void SelectionManager::setPickData( CollObjectHandle handle, const Ogre::ColourValue& color, Ogre::SceneNode* node ) { if (!node) { return; } // Loop over all objects attached to this node. Ogre::SceneNode::ObjectIterator obj_it = node->getAttachedObjectIterator(); while( obj_it.hasMoreElements() ) { Ogre::MovableObject* obj = obj_it.getNext(); setPickData( handle, color, obj ); } // Loop over and recurse into all child nodes. Ogre::SceneNode::ChildNodeIterator child_it = node->getChildIterator(); while( child_it.hasMoreElements() ) { Ogre::SceneNode* child = dynamic_cast( child_it.getNext() ); setPickData( handle, color, child ); } } class PickColorSetter: public Ogre::Renderable::Visitor { public: PickColorSetter( CollObjectHandle handle, const Ogre::ColourValue& color ) : color_vector_( color.r, color.g, color.b, 1.0 ), handle_(handle) {} virtual void visit( Ogre::Renderable* rend, ushort lodIndex, bool isDebug, Ogre::Any* pAny = 0 ) { rend->setCustomParameter( PICK_COLOR_PARAMETER, color_vector_ ); rend->getUserObjectBindings().setUserAny( "pick_handle", Ogre::Any( handle_ )); } Ogre::Vector4 color_vector_; CollObjectHandle handle_; }; void SelectionManager::setPickData( CollObjectHandle handle, const Ogre::ColourValue& color, Ogre::MovableObject* object ) { PickColorSetter visitor( handle, color ); object->visitRenderables( &visitor ); object->getUserObjectBindings().setUserAny( "pick_handle", Ogre::Any( handle )); } SelectionHandler* SelectionManager::getHandler( CollObjectHandle obj ) { boost::recursive_mutex::scoped_lock lock(global_mutex_); M_CollisionObjectToSelectionHandler::iterator it = objects_.find(obj); if (it != objects_.end()) { return it->second; } return NULL; } void SelectionManager::removeSelection(const M_Picked& objs) { boost::recursive_mutex::scoped_lock lock(global_mutex_); M_Picked::const_iterator it = objs.begin(); M_Picked::const_iterator end = objs.end(); for (; it != end; ++it) { removeSelectedObject(it->second); } selectionRemoved( objs ); } void SelectionManager::addSelection(const M_Picked& objs) { boost::recursive_mutex::scoped_lock lock(global_mutex_); M_Picked added; M_Picked::const_iterator it = objs.begin(); M_Picked::const_iterator end = objs.end(); for (; it != end; ++it) { std::pair ppb = addSelectedObject(it->second); if (ppb.second) { added.insert(std::make_pair(it->first, ppb.first)); } } selectionAdded( added ); } void SelectionManager::setSelection(const M_Picked& objs) { boost::recursive_mutex::scoped_lock lock(global_mutex_); M_Picked original(selection_.begin(), selection_.end()); removeSelection(original); addSelection(objs); } std::pair SelectionManager::addSelectedObject(const Picked& obj) { boost::recursive_mutex::scoped_lock lock(global_mutex_); std::pair pib = selection_.insert(std::make_pair(obj.handle, obj)); SelectionHandler* handler = getHandler( obj.handle ); if (pib.second) { handler->onSelect(obj); return std::make_pair(obj, true); } else { Picked& cur = pib.first->second; Picked added(cur.handle); S_uint64::iterator it = obj.extra_handles.begin(); S_uint64::iterator end = obj.extra_handles.end(); for (; it != end; ++it) { if (cur.extra_handles.insert(*it).second) { added.extra_handles.insert(*it); } } if (!added.extra_handles.empty()) { handler->onSelect(added); return std::make_pair(added, true); } } return std::make_pair(Picked(0), false); } void SelectionManager::removeSelectedObject(const Picked& obj) { boost::recursive_mutex::scoped_lock lock(global_mutex_); M_Picked::iterator sel_it = selection_.find(obj.handle); if (sel_it != selection_.end()) { S_uint64::iterator extra_it = obj.extra_handles.begin(); S_uint64::iterator extra_end = obj.extra_handles.end(); for (; extra_it != extra_end; ++extra_it) { sel_it->second.extra_handles.erase(*extra_it); } if (sel_it->second.extra_handles.empty()) { selection_.erase(sel_it); } } SelectionHandler* handler = getHandler( obj.handle ); handler->onDeselect(obj); } void SelectionManager::focusOnSelection() { boost::recursive_mutex::scoped_lock lock(global_mutex_); if (selection_.empty()) { return; } Ogre::AxisAlignedBox combined; M_Picked::iterator it = selection_.begin(); M_Picked::iterator end = selection_.end(); for (; it != end; ++it) { const Picked& p = it->second; SelectionHandler* handler = getHandler( p.handle ); V_AABB aabbs; handler->getAABBs(p, aabbs); V_AABB::iterator aabb_it = aabbs.begin(); V_AABB::iterator aabb_end = aabbs.end(); for (; aabb_it != aabb_end; ++aabb_it) { combined.merge(*aabb_it); } } if (!combined.isInfinite() && !combined.isNull()) { Ogre::Vector3 center = combined.getCenter(); ViewController* controller = vis_manager_->getViewManager()->getCurrent(); if( controller ) { controller->lookAt(center); } } } void SelectionManager::selectionRemoved( const M_Picked& removed ) { M_Picked::const_iterator it = removed.begin(); M_Picked::const_iterator end = removed.end(); for (; it != end; ++it) { const Picked& picked = it->second; SelectionHandler* handler = getHandler( picked.handle ); ROS_ASSERT(handler); handler->destroyProperties( picked, property_model_->getRoot() ); } } void SelectionManager::selectionAdded( const M_Picked& added ) { M_Picked::const_iterator it = added.begin(); M_Picked::const_iterator end = added.end(); for (; it != end; ++it) { const Picked& picked = it->second; SelectionHandler* handler = getHandler( picked.handle ); ROS_ASSERT(handler); handler->createProperties( picked, property_model_->getRoot() ); } property_model_->sort( 0, Qt::AscendingOrder ); } void SelectionManager::updateProperties() { M_Picked::const_iterator it = selection_.begin(); M_Picked::const_iterator end = selection_.end(); for (; it != end; ++it) { CollObjectHandle handle = it->first; SelectionHandler* handler = getHandler( handle ); handler->updateProperties(); } } } // namespace rviz rviz-1.12.4/src/rviz/selection/selection_manager.h000066400000000000000000000256511300447110700221750ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SELECTION_MANAGER_H #define RVIZ_SELECTION_MANAGER_H #include #include #include "forwards.h" #include "selection_handler.h" #ifndef Q_MOC_RUN #include #include #include #include #include #include #include #include #include #endif #include #include namespace ros { class Publisher; } namespace Ogre { class SceneManager; class Viewport; class WireBoundingBox; class SceneNode; class Material; class PixelBox; class Rectangle2D; class MovableObject; } namespace rviz { class Object; class PropertyTreeModel; class ViewportMouseEvent; class VisualizationManager; class SelectionManager: public QObject, public Ogre::MaterialManager::Listener, public Ogre::RenderQueueListener { Q_OBJECT public: enum SelectType { Add, Remove, Replace }; SelectionManager(VisualizationManager* manager); ~SelectionManager(); void initialize(); /** @brief Enables or disables publishing of picking and depth rendering images. */ void setDebugMode( bool debug ); void clearHandlers(); void addObject( CollObjectHandle obj, SelectionHandler* handler ); void removeObject(CollObjectHandle obj); // control the highlight box being displayed while selecting void highlight(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2); void removeHighlight(); // select all objects in bounding box void select(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2, SelectType type); // @return handles of all objects in the given bounding box // @param single_render_pass only perform one rendering pass (point cloud selecting won't work) void pick(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2, M_Picked& results, bool single_render_pass=false ); void update(); // modify the list of currently selected objects void setSelection(const M_Picked& objs); void addSelection(const M_Picked& objs); void removeSelection(const M_Picked& objs); const M_Picked& getSelection() { return selection_; } SelectionHandler* getHandler( CollObjectHandle obj ); static Ogre::ColourValue handleToColor( CollObjectHandle handle ); //static CollObjectHandle colourToHandle( const Ogre::ColourValue & color ); static void setPickColor( const Ogre::ColourValue& color, Ogre::SceneNode* node ) { setPickData( colorToHandle( color ), color, node ); } static void setPickColor( const Ogre::ColourValue& color, Ogre::MovableObject* object ) { setPickData( colorToHandle( color ), color, object ); } static void setPickHandle( CollObjectHandle handle, Ogre::SceneNode* node ) { setPickData( handle, handleToColor( handle ), node ); } static void setPickHandle( CollObjectHandle handle, Ogre::MovableObject* object ) { setPickData( handle, handleToColor( handle ), object ); } static void setPickData( CollObjectHandle handle, const Ogre::ColourValue& color, Ogre::SceneNode* node ); static void setPickData( CollObjectHandle handle, const Ogre::ColourValue& color, Ogre::MovableObject* object ); // if a material does not support the picking scheme, paint it black virtual Ogre::Technique* handleSchemeNotFound(unsigned short scheme_index, const Ogre::String& scheme_name, Ogre::Material* original_material, unsigned short lod_index, const Ogre::Renderable* rend); // create a new unique handle CollObjectHandle createHandle(); // tell all handlers that interactive mode is active/inactive void enableInteraction( bool enable ); bool getInteractionEnabled() { return interaction_enabled_; } // tell the view controller to look at the selection void focusOnSelection(); // change the size of the off-screen selection buffer texture void setTextureSize( unsigned size ); /** Return true if the point at x, y in the viewport is showing an * object, false otherwise. If it is showing an object, result will * be changed to contain the 3D point corresponding to it. */ bool get3DPoint( Ogre::Viewport* viewport, const int x, const int y, Ogre::Vector3& result_point ); /** @brief Gets the 3D points in a box around a point in a view port @param[in] viewport Rendering area clicked on. @param[in] x x coordinate of upper-left corner of box. @param[in] y y coordinate of upper-left corner of box. @param[in] width The width of the rendered box in pixels. @param[in] height The height of the rendered box in pixels. @param[in] skip_missing Whether to skip non-existing points or insert NaNs for them @param[out] result_points The vector of output points. @returns True if any valid point is rendered in the box. NaN points count, so if skip_missing is false, this will always return true if width and height are > 0. */ bool get3DPatch( Ogre::Viewport* viewport, const int x, const int y, const unsigned width, const unsigned height, const bool skip_missing, std::vector &result_points ); /** @brief Renders a depth image in a box around a point in a view port @param[in] viewport Rendering area clicked on. @param[in] x x coordinate of upper-left corner of box. @param[in] y y coordinate of upper-left corner of box. @param[in] width The width of the rendered box in pixels. @param[in] height The height of the rendered box in pixels. @param[out] depth_vector The vector of depth values. @returns True if rendering operation to render depth data to the depth texture buffer succeeds. Failure likely indicates a pretty serious problem. */ bool getPatchDepthImage( Ogre::Viewport* viewport, const int x, const int y, const unsigned width, const unsigned height, std::vector & depth_vector); // Implementation for Ogre::RenderQueueListener. void renderQueueStarted( uint8_t queueGroupId, const std::string& invocation, bool& skipThisInvocation ); PropertyTreeModel* getPropertyModel() { return property_model_; } private Q_SLOTS: /** @brief Call updateProperties() on all SelectionHandlers in the * current selection. */ void updateProperties(); private: void selectionAdded( const M_Picked& added ); void selectionRemoved( const M_Picked& removed ); std::pair addSelectedObject(const Picked& obj); void removeSelectedObject(const Picked& obj); void setHighlightRect(Ogre::Viewport* viewport, int x1, int y1, int x2, int y2); /** Render to a texture for one of the picking passes and unpack the resulting pixels. */ void renderAndUnpack(Ogre::Viewport* viewport, uint32_t pass, int x1, int y1, int x2, int y2, V_CollObject& pixels); /** Internal render function to render to a texture and read the pixels back out. */ bool render( Ogre::Viewport* viewport, Ogre::TexturePtr tex, int x1, int y1, int x2, int y2, Ogre::PixelBox& dst_box, std::string material_scheme, unsigned texture_width, unsigned textured_height ); void unpackColors(const Ogre::PixelBox& box, V_CollObject& pixels); void setDepthTextureSize(unsigned width, unsigned height); void publishDebugImage( const Ogre::PixelBox& pixel_box, const std::string& label ); VisualizationManager* vis_manager_; boost::recursive_mutex global_mutex_; typedef boost::unordered_map M_CollisionObjectToSelectionHandler; M_CollisionObjectToSelectionHandler objects_; bool highlight_enabled_; struct Highlight { int x1; int y1; int x2; int y2; Ogre::Viewport* viewport; }; Highlight highlight_; M_Picked selection_; const static uint32_t s_num_render_textures_ = 2; // If you want to change this number to something > 3 you must provide more width for extra handles in the Picked structure (currently a u64) Ogre::TexturePtr render_textures_[s_num_render_textures_]; Ogre::PixelBox pixel_boxes_[s_num_render_textures_]; // Graphics card -based depth finding of clicked points. Ogre::TexturePtr depth_render_texture_; uint32_t depth_texture_width_, depth_texture_height_; Ogre::PixelBox depth_pixel_box_; uint32_t uid_counter_; Ogre::Rectangle2D* highlight_rectangle_; Ogre::SceneNode* highlight_node_; Ogre::Camera *camera_; V_CollObject pixel_buffer_; bool interaction_enabled_; bool debug_mode_; Ogre::MaterialPtr fallback_pick_material_; Ogre::Technique *fallback_pick_technique_; Ogre::Technique *fallback_black_technique_; Ogre::Technique *fallback_depth_technique_; Ogre::Technique *fallback_pick_cull_technique_; Ogre::Technique *fallback_black_cull_technique_; Ogre::Technique *fallback_depth_cull_technique_; uint32_t texture_size_; PropertyTreeModel* property_model_; typedef std::map PublisherMap; PublisherMap debug_publishers_; }; } // namespace rviz #endif // RVIZ_SELECTION_MANAGER_H rviz-1.12.4/src/rviz/selection_panel.cpp000066400000000000000000000042751300447110700202270ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/property_tree_widget.h" #include "rviz/selection/selection_manager.h" #include "rviz/visualization_manager.h" #include "rviz/selection_panel.h" namespace rviz { SelectionPanel::SelectionPanel( QWidget* parent ) : Panel( parent ) { QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins( 0, 0, 0, 0 ); tree_widget_ = new PropertyTreeWidget(); layout->addWidget( tree_widget_ ); setLayout( layout ); } void SelectionPanel::onInitialize() { tree_widget_->setModel( vis_manager_->getSelectionManager()->getPropertyModel() ); } } // namespace rviz rviz-1.12.4/src/rviz/selection_panel.h000066400000000000000000000036371300447110700176750ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SELECTION_PANEL_H #define RVIZ_SELECTION_PANEL_H #include "rviz/panel.h" namespace rviz { class PropertyTreeWidget; class SelectionPanel: public Panel { Q_OBJECT public: SelectionPanel( QWidget* parent = 0 ); virtual void onInitialize(); private: PropertyTreeWidget* tree_widget_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/splash_screen.cpp000066400000000000000000000054301300447110700177060ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/splash_screen.h" #include "rviz/load_resource.h" #include "env_config.h" #include #include #include #include namespace rviz { SplashScreen::SplashScreen( const QPixmap& pixmap ) : QSplashScreen() { const int bottom_border = 27; QPixmap splash( pixmap.width(), pixmap.height()+bottom_border ); splash.fill( QColor(0,0,0) ); QPainter painter( &splash ); painter.drawPixmap( QPoint(0,0), pixmap ); QPixmap overlay = loadPixmap( "package://rviz/images/splash_overlay.png" ); painter.drawTiledPixmap( QRect( 0,pixmap.height()-overlay.height(), pixmap.width(),pixmap.height() ), overlay ); // draw version info QString version_info = "r"+QString(get_version().c_str()); version_info += " (" + QString(get_distro().c_str()) + ")"; painter.setPen( QColor(160,160,160) ); QRect r = splash.rect(); r .setRect(r.x() + 5, r.y() + 5, r.width() - 10, r.height() - 10); painter.drawText( r, Qt::AlignRight | Qt::AlignBottom, version_info ); setPixmap( splash ); } void SplashScreen::showMessage( const QString& message ) { QSplashScreen::showMessage( message, Qt::AlignLeft | Qt::AlignBottom, Qt::white ); } } // end namespace rviz rviz-1.12.4/src/rviz/splash_screen.h000066400000000000000000000036451300447110700173610ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_SPLASH_SCREEN_H #define RVIZ_SPLASH_SCREEN_H #include class QPainter; namespace rviz { class SplashScreen: public QSplashScreen { Q_OBJECT public: SplashScreen( const QPixmap& pixmap ); public Q_SLOTS: void showMessage( const QString& message ); }; } // end namespace rviz #endif // RVIZ_SPLASH_SCREEN_H rviz-1.12.4/src/rviz/time_panel.cpp000066400000000000000000000217731300447110700172020ustar00rootroot00000000000000 /* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "visualization_manager.h" #include "frame_manager.h" #include "display_group.h" #include "time_panel.h" namespace rviz { TimePanel::TimePanel( QWidget* parent ) : Panel( parent ) { wall_time_label_ = makeTimeLabel(); wall_elapsed_label_ = makeTimeLabel(); ros_time_label_ = makeTimeLabel(); ros_elapsed_label_ = makeTimeLabel(); experimental_cb_ = new QCheckBox("Experimental"); experimental_cb_->setSizePolicy( QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum) ); pause_button_ = new QPushButton( "Pause" ); pause_button_->setToolTip("Freeze ROS time."); pause_button_->setCheckable(true); sync_mode_selector_ = new QComboBox(this); sync_mode_selector_->addItem( "Off" ); sync_mode_selector_->addItem( "Exact" ); sync_mode_selector_->addItem( "Approximate" ); sync_mode_selector_->setSizeAdjustPolicy(QComboBox::AdjustToContents); sync_mode_selector_->setToolTip("Allows you to synchronize the ROS time and Tf transforms to a given source."); // choose time sync signal sync_source_selector_ = new QComboBox(this); sync_source_selector_->setSizeAdjustPolicy(QComboBox::AdjustToContents); sync_source_selector_->setToolTip("Time source to use for synchronization."); experimental_widget_ = new QWidget(this); QHBoxLayout* experimental_layout = new QHBoxLayout(this); experimental_layout->addWidget( pause_button_ ); experimental_layout->addWidget( new QLabel( "Synchronization:" )); experimental_layout->addWidget( sync_mode_selector_ ); experimental_layout->addWidget( new QLabel( "Source:" )); experimental_layout->addWidget( sync_source_selector_ ); experimental_layout->addSpacing(20); experimental_layout->setContentsMargins( 0, 0, 20, 0 ); experimental_widget_->setLayout(experimental_layout); old_widget_ = new QWidget(this); QHBoxLayout* old_layout = new QHBoxLayout(this); old_layout->addWidget( new QLabel( "ROS Elapsed:" )); old_layout->addWidget( ros_elapsed_label_ ); old_layout->addWidget( new QLabel( "Wall Time:" )); old_layout->addWidget( wall_time_label_ ); old_layout->addWidget( new QLabel( "Wall Elapsed:" )); old_layout->addWidget( wall_elapsed_label_ ); old_layout->setContentsMargins( 0, 0, 20, 0 ); old_widget_->setLayout(old_layout); QHBoxLayout* layout = new QHBoxLayout(this); layout->addWidget(experimental_widget_); layout->addWidget( new QLabel( "ROS Time:" )); layout->addWidget( ros_time_label_ ); layout->addWidget(old_widget_); layout->addStretch(100); layout->addWidget( experimental_cb_ ); layout->addStretch(); layout->setContentsMargins( 11, 5, 11, 5 ); connect( experimental_cb_, SIGNAL( toggled( bool )), this, SLOT( experimentalToggled( bool ) )); connect( pause_button_, SIGNAL( toggled( bool )), this, SLOT( pauseToggled( bool ) )); connect( sync_mode_selector_, SIGNAL( activated( int )), this, SLOT( syncModeSelected( int ) )); connect( sync_source_selector_, SIGNAL( activated( int )), this, SLOT( syncSourceSelected( int ) )); } void TimePanel::onInitialize() { connect( vis_manager_, SIGNAL( preUpdate() ), this, SLOT( update() )); DisplayGroup *display_group = vis_manager_->getRootDisplayGroup(); onDisplayAdded(display_group); syncModeSelected(0); pauseToggled(false); } void TimePanel::load( const Config& config ) { Panel::load(config); int sync_mode; if( config.mapGetInt( "SyncMode", &sync_mode )) { sync_mode_selector_->setCurrentIndex(sync_mode); syncModeSelected(sync_mode); } config.mapGetString( "SyncSource", &config_sync_source_ ); bool experimental = false; config.mapGetBool( "Experimental", &experimental ); experimental_cb_->setChecked(experimental); experimentalToggled(experimental); } void TimePanel::save( Config config ) const { Panel::save(config); config.mapSetValue( "SyncMode", sync_mode_selector_->currentIndex() ); config.mapSetValue( "SyncSource", sync_source_selector_->currentText() ); config.mapSetValue( "Experimental", experimental_cb_->checkState() == Qt::Checked ); } void TimePanel::onDisplayAdded( Display* display ) { DisplayGroup* display_group = qobject_cast( display ); if( display_group ) { connect( display_group, SIGNAL( displayAdded( rviz::Display* ) ), this, SLOT( onDisplayAdded( rviz::Display* ) )); connect( display_group, SIGNAL( displayRemoved( rviz::Display* ) ), this, SLOT( onDisplayRemoved( rviz::Display* ) )); for( int i = 0; i < display_group->numDisplays(); i++ ) { rviz::Display* display = display_group->getDisplayAt( i ); onDisplayAdded( display ); } } else { connect( display, SIGNAL( timeSignal( rviz::Display*, ros::Time ) ), this, SLOT( onTimeSignal( rviz::Display*, ros::Time ) )); } } void TimePanel::onDisplayRemoved( Display* display ) { QString name = display->getName(); int index = sync_source_selector_->findData( QVariant( (qulonglong)display ) ); if ( index >= 0 ) { sync_source_selector_->removeItem( index ); } } void TimePanel::onTimeSignal( Display* display, ros::Time time ) { QString name = display->getName(); int index = sync_source_selector_->findData( QVariant( (qulonglong)display ) ); // if we loaded the sync source name from the config, we need to // switch to it as soon as we get a signal if ( index < 0 && name == config_sync_source_ ) { sync_source_selector_->addItem( name, QVariant( (qulonglong)display ) ); index = sync_source_selector_->findData( QVariant( (qulonglong)display ) ); sync_source_selector_->setCurrentIndex(index); config_sync_source_.clear(); } if ( index < 0 ) { sync_source_selector_->addItem( name, QVariant( (qulonglong)display ) ); } else { sync_source_selector_->setItemText( index, name ); if ( sync_source_selector_->currentIndex() == index ) { vis_manager_->getFrameManager()->syncTime( time ); } } } QLineEdit* TimePanel::makeTimeLabel() { QLineEdit* label = new QLineEdit; label->setReadOnly( true ); return label; } void TimePanel::fillTimeLabel( QLineEdit* label, double time ) { label->setText( QString::number( time, 'f', 2 )); } void TimePanel::update() { fillTimeLabel( ros_time_label_, vis_manager_->getROSTime() ); fillTimeLabel( ros_elapsed_label_, vis_manager_->getROSTimeElapsed() ); fillTimeLabel( wall_time_label_, vis_manager_->getWallClock() ); fillTimeLabel( wall_elapsed_label_, vis_manager_->getWallClockElapsed() ); } void TimePanel::pauseToggled( bool checked ) { vis_manager_->getFrameManager()->setPause( checked ); } void TimePanel::experimentalToggled( bool checked ) { old_widget_->setVisible(!checked); experimental_widget_->setVisible(checked); if ( vis_manager_ && vis_manager_->getFrameManager() ) { if ( !checked ) { pauseToggled(false); syncModeSelected(0); } else { pauseToggled(pause_button_->isChecked()); syncModeSelected(sync_mode_selector_->currentIndex()); } } } void TimePanel::syncSourceSelected( int index ) { // clear whatever was loaded from the config config_sync_source_.clear(); vis_manager_->notifyConfigChanged(); } void TimePanel::syncModeSelected( int mode ) { vis_manager_->getFrameManager()->setSyncMode( (FrameManager::SyncMode)mode ); sync_source_selector_->setEnabled( mode != FrameManager::SyncOff ); vis_manager_->notifyConfigChanged(); } } // namespace rviz rviz-1.12.4/src/rviz/time_panel.h000066400000000000000000000061701300447110700166410ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TIME_PANEL_H #define RVIZ_TIME_PANEL_H #include "rviz/panel.h" #include "ros/time.h" class QLineEdit; class QComboBox; class QCheckBox; class QPushButton; class QHBoxLayout; class QWidget; namespace rviz { class VisualizationManager; class Display; /** * \class TimePanel * */ class TimePanel: public Panel { Q_OBJECT public: TimePanel( QWidget* parent = 0 ); virtual void onInitialize(); protected Q_SLOTS: void pauseToggled( bool checked ); void syncModeSelected( int index ); void syncSourceSelected( int index ); void experimentalToggled( bool checked ); /** Read time values from VisualizationManager and update displays. */ void update(); void onDisplayAdded( rviz::Display* display ); void onDisplayRemoved( rviz::Display* display ); void onTimeSignal( rviz::Display* display, ros::Time time ); virtual void load( const Config& config ); virtual void save( Config config ) const; protected: /** Create, configure, and return a single label for showing a time value. */ QLineEdit* makeTimeLabel(); /** Fill a single time label with the given time value (in seconds). */ void fillTimeLabel( QLineEdit* label, double time ); QWidget* old_widget_; QWidget* experimental_widget_; QString config_sync_source_; QCheckBox* experimental_cb_; QPushButton* pause_button_; QComboBox* sync_source_selector_; QComboBox* sync_mode_selector_; QLineEdit* ros_time_label_; QLineEdit* ros_elapsed_label_; QLineEdit* wall_time_label_; QLineEdit* wall_elapsed_label_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/tool.cpp000066400000000000000000000056511300447110700160370ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/display_context.h" #include "rviz/properties/property.h" #include "rviz/load_resource.h" #include "rviz/window_manager_interface.h" #include "rviz/tool.h" namespace rviz { Tool::Tool() : property_container_( new Property() ) { access_all_keys_ = false; shortcut_key_ = '\0'; } Tool::~Tool() { delete property_container_; } void Tool::initialize( DisplayContext* context ) { context_ = context; scene_manager_ = context_->getSceneManager(); // Let subclasses do initialization if they want. onInitialize(); } void Tool::setIcon( const QIcon& icon ) { icon_=icon; cursor_=makeIconCursor( icon.pixmap(16), "tool_cursor:"+name_ ); } void Tool::setCursor( const QCursor& cursor ) { cursor_=cursor; } void Tool::setName( const QString& name ) { name_ = name; property_container_->setName( name_ ); } void Tool::setDescription( const QString& description ) { description_ = description; property_container_->setDescription( description_ ); } void Tool::load( const Config& config ) { property_container_->load( config ); } void Tool::save( Config config ) const { property_container_->save( config ); config.mapSetValue( "Class", getClassId() ); } void Tool::setStatus( const QString & message ) { if ( context_ ) { context_->setStatus( message ); } } } // end namespace rviz rviz-1.12.4/src/rviz/tool.h000066400000000000000000000135211300447110700154770ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TOOL_H #define RVIZ_TOOL_H #include #include #include #include #include "rviz/config.h" class QMouseEvent; class QKeyEvent; namespace Ogre { class SceneManager; } namespace rviz { class DisplayContext; class Property; class RenderPanel; class ViewportMouseEvent; class Tool : public QObject { Q_OBJECT public: /** Default constructor. Pluginlib only instantiates classes via * default constructors. Subclasses of Tool should shortcut_key_ * field in their constructors. * * Properties to appear in the Tool Properties panel are typically * created in the constructor, as children of the property from * getPropertyContainer(), which is set up in this Tool * constructor. */ Tool(); virtual ~Tool(); /** Initialize the tool. Sets the DisplayContext and calls * onInitialize(). */ void initialize( DisplayContext* context ); /** @brief Return the container for properties of this Tool. */ virtual Property* getPropertyContainer() const { return property_container_; } char getShortcutKey() { return shortcut_key_; } bool accessAllKeys() { return access_all_keys_; } virtual void activate() = 0; virtual void deactivate() = 0; virtual void update(float wall_dt, float ros_dt) { (void) wall_dt; (void) ros_dt; } enum { Render = 1, Finished = 2 }; /** Process a mouse event. This is the central function of all the * tools, as it defines how the mouse is used. */ virtual int processMouseEvent( ViewportMouseEvent& event ) { (void) event; return 0; } /** Process a key event. Override if your tool should handle any other keypresses than the tool shortcuts, which are handled separately. */ virtual int processKeyEvent( QKeyEvent* event, RenderPanel* panel ) { (void) event; (void) panel; return 0; } QString getName() const { return name_; } /** @brief Set the name of the tool. * * This is called by ToolManager during tool initialization. If you * want a different name than it gives you, call this from * onInitialize() (or thereafter). */ void setName( const QString& name ); /** @brief Set the description of the tool. This is called by * ToolManager during tool initialization. */ QString getDescription() const { return description_; } void setDescription( const QString& description ); /** @brief Return the class identifier which was used to create this * instance. This version just returns whatever was set with * setClassId(). */ virtual QString getClassId() const { return class_id_; } /** @brief Set the class identifier used to create this instance. * Typically this will be set by the factory object which created it. */ virtual void setClassId( const QString& class_id ) { class_id_ = class_id; } /** @brief Load properties from the given Config. * * Most tools won't need to override this, because any child * Properties of property_container_ are automatically loaded by * this function. */ virtual void load( const Config& config ); /** @brief Save this entire tool into the given Config node. * * Most tools won't need to override this, because any child * Properties of property_container_ are automatically saved by * this function. */ virtual void save( Config config ) const; /** @brief Set the toolbar icon for this tool (will also set its cursor). */ void setIcon( const QIcon& icon ); /** @brief Get the icon of this tool. */ const QIcon& getIcon() { return icon_; } /** @brief Set the cursor for this tool. */ void setCursor( const QCursor& cursor ); /** @brief Get current cursor of this tool. */ const QCursor& getCursor() { return cursor_; } void setStatus( const QString & message ); Q_SIGNALS: void close(); protected: /** Override onInitialize to do any setup needed after the DisplayContext has been set. This is called by Tool::initialize(). The base implementation here does nothing. */ virtual void onInitialize() {} Ogre::SceneManager* scene_manager_; DisplayContext* context_; char shortcut_key_; bool access_all_keys_; QIcon icon_; QCursor cursor_; private: QString class_id_; Property* property_container_; QString name_; QString description_; }; } #endif rviz-1.12.4/src/rviz/tool_manager.cpp000066400000000000000000000171251300447110700175300ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/failed_tool.h" #include "rviz/properties/property.h" #include "rviz/properties/property_tree_model.h" #include "rviz/tool_manager.h" namespace rviz { QString addSpaceToCamelCase( QString input ) { QRegExp re = QRegExp( "([A-Z])([a-z]*)" ); input.replace( re, " \\1\\2" ); return input.trimmed(); } ToolManager::ToolManager( DisplayContext* context ) : factory_( new PluginlibFactory( "rviz", "rviz::Tool" )) , property_tree_model_( new PropertyTreeModel( new Property() )) , context_( context ) , current_tool_( NULL ) , default_tool_( NULL ) { connect( property_tree_model_, SIGNAL( configChanged() ), this, SIGNAL( configChanged() )); } ToolManager::~ToolManager() { removeAll(); delete factory_; delete property_tree_model_; } void ToolManager::initialize() { // Possibly this should be done with a loop over // factory_->getDeclaredClassIds(), but then I couldn't control the // order. addTool( "rviz/MoveCamera" ); addTool( "rviz/Interact" ); addTool( "rviz/Select" ); addTool( "rviz/SetInitialPose" ); addTool( "rviz/SetGoal" ); } void ToolManager::removeAll() { for( int i = tools_.size() - 1; i >= 0; i-- ) { removeTool( i ); } } void ToolManager::load( const Config& config ) { removeAll(); int num_tools = config.listLength(); for( int i = 0; i < num_tools; i++ ) { Config tool_config = config.listChildAt( i ); QString class_id; if( tool_config.mapGetString( "Class", &class_id )) { Tool* tool = addTool( class_id ); tool->load( tool_config ); } } } void ToolManager::save( Config config ) const { for( int i = 0; i < tools_.size(); i++ ) { tools_[ i ]->save( config.listAppendNew() ); } } bool ToolManager::toKey( QString const& str, uint& key ) { QKeySequence seq( str ); // We should only working with a single key here if( seq.count() == 1 ) { key = seq[ 0 ]; return true; } else { return false; } } void ToolManager::handleChar( QKeyEvent* event, RenderPanel* panel ) { // if the incoming key is ESC fallback to the default tool if( event->key() == Qt::Key_Escape ) { setCurrentTool( getDefaultTool() ); return; } // check if the incoming key triggers the activation of another tool Tool* tool = NULL; if( shortkey_to_tool_map_.find(event->key()) != shortkey_to_tool_map_.end() ) { tool = shortkey_to_tool_map_[ event->key() ]; } if( tool ) { // if there is a incoming tool check if it matches the current tool if( current_tool_ == tool) { // if yes, deactivate the current tool and fallback to default setCurrentTool( getDefaultTool() ); } else { // if no, check if the current tool accesses all key events if( current_tool_->accessAllKeys() ) { // if yes, pass the key current_tool_->processKeyEvent( event, panel ); } else { // if no, switch the tool setCurrentTool( tool ); } } } else { // if the incoming key triggers no other tool, // just hand down the key event current_tool_->processKeyEvent( event, panel ); } } void ToolManager::setCurrentTool( Tool* tool ) { if( current_tool_ ) { current_tool_->deactivate(); } current_tool_ = tool; if( current_tool_ ) { current_tool_->activate(); } Q_EMIT toolChanged( current_tool_ ); } void ToolManager::setDefaultTool( Tool* tool ) { default_tool_ = tool; } Tool* ToolManager::getTool( int index ) { ROS_ASSERT( index >= 0 ); ROS_ASSERT( index < (int)tools_.size() ); return tools_[ index ]; } void ToolManager::updatePropertyVisibility( Property* container ) { if( container->numChildren() > 0 ) { if( !property_tree_model_->getRoot()->contains( container )) { property_tree_model_->getRoot()->addChild( container ); container->expand(); } } else { property_tree_model_->getRoot()->takeChild( container ); } } void rviz::ToolManager::closeTool() { setCurrentTool( getDefaultTool() ); } Tool* ToolManager::addTool( const QString& class_id ) { QString error; bool failed = false; Tool* tool = factory_->make( class_id, &error ); if( !tool ) { tool = new FailedTool( class_id, error ); failed = true; } tools_.append( tool ); tool->setName( addSpaceToCamelCase( factory_->getClassName( class_id ))); tool->setIcon( factory_->getIcon( class_id ) ); tool->initialize( context_ ); if( tool->getShortcutKey() != '\0' ) { uint key; QString str = QString( tool->getShortcutKey() ); if( toKey( str, key ) ) { shortkey_to_tool_map_[ key ] = tool; } } Property* container = tool->getPropertyContainer(); connect( container, SIGNAL( childListChanged( Property* )), this, SLOT( updatePropertyVisibility( Property* ))); updatePropertyVisibility( container ); Q_EMIT toolAdded( tool ); // If the default tool is unset and this tool loaded correctly, set // it as the default and current. if( default_tool_ == NULL && !failed ) { setDefaultTool( tool ); setCurrentTool( tool ); } QObject::connect(tool, SIGNAL(close()), this, SLOT(closeTool())); Q_EMIT configChanged(); return tool; } void ToolManager::removeTool( int index ) { Tool* tool = tools_.takeAt( index ); Tool* fallback = NULL; if( tools_.size() > 0 ) { fallback = tools_[ 0 ]; } if( tool == current_tool_ ) { setCurrentTool( fallback ); } if( tool == default_tool_ ) { setDefaultTool( fallback ); } Q_EMIT toolRemoved( tool ); uint key; if( toKey( QString( tool->getShortcutKey() ), key ) ) { shortkey_to_tool_map_.erase( key ); } delete tool; Q_EMIT configChanged(); } void ToolManager::refreshTool( Tool* tool ) { Q_EMIT toolRefreshed( tool ); } QStringList ToolManager::getToolClasses() { QStringList class_names; for( int i = 0; i < tools_.size(); i++ ) { class_names.append( tools_[ i ]->getClassId() ); } return class_names; } } // end namespace rviz rviz-1.12.4/src/rviz/tool_manager.h000066400000000000000000000117751300447110700172020ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef TOOL_MANAGER_H #define TOOL_MANAGER_H #include #include #include #include "rviz/pluginlib_factory.h" #include "rviz/tool.h" class QKeyEvent; namespace rviz { class DisplayContext; class PropertyTreeModel; class RenderPanel; class ToolManager: public QObject { Q_OBJECT public: ToolManager( DisplayContext* context ); virtual ~ToolManager(); /** @brief Initialization for after the DisplayContext is created. * Loads standard RViz tools. */ void initialize(); void load( const Config& config ); void save( Config config ) const; PropertyTreeModel* getPropertyModel() const { return property_tree_model_; } /** @brief Create a tool by class lookup name, add it to the list, and return it. */ Tool* addTool( const QString& tool_class_lookup_name ); /** * \brief Return the tool currently in use. * \sa setCurrentTool() */ Tool* getCurrentTool() { return current_tool_; } /** * \brief Return the tool at a given index in the Tool list. * If index is less than 0 or greater than the number of tools, this * will fail an assertion. */ Tool* getTool( int index ); int numTools() { return tools_.size(); } void removeTool( int index ); void removeAll(); /** @brief Triggers redrawing the tool's icon/text in the toolbar. */ void refreshTool( Tool* tool ); /** * \brief Set the current tool. * The current tool is given all mouse and keyboard events which * VisualizationManager receives via handleMouseEvent() and * handleChar(). * \sa getCurrentTool() */ void setCurrentTool( Tool* tool ); /** * \brief Set the default tool. * * The default tool is selected directly by pressing the Escape key. * The default tool is indirectly selected when a Tool returns * Finished in the bit field result of Tool::processMouseEvent(). * This is how control moves from the InitialPoseTool back to * MoveCamera when InitialPoseTool receives a left mouse button * release event. * \sa getDefaultTool() */ void setDefaultTool( Tool* tool ); /** * \brief Get the default tool. * \sa setDefaultTool() */ Tool* getDefaultTool() { return default_tool_; } QStringList getToolClasses(); void handleChar( QKeyEvent* event, RenderPanel* panel ); PluginlibFactory* getFactory() { return factory_; } Q_SIGNALS: /** @brief Emitted when anything changes which will change the saved config file contents. */ void configChanged(); /** @brief Emitted by addTool() after the tool is added to the list of tools. */ void toolAdded( Tool* ); /** @brief Emitted by setCurrentTool() after the newly chosen tool * is activated. */ void toolChanged( Tool* ); void toolRemoved( Tool* ); /** @brief Emitted by refreshTool() to gedraw the tool's icon in the toolbar'. */ void toolRefreshed( Tool* ); private Q_SLOTS: /** @brief If @a property has children, it is added to the tool * property tree, and if it does not, it is removed. */ void updatePropertyVisibility( Property* property ); /** @brief Deactivates the current tool and sets the default tool. */ void closeTool(); private: bool toKey( QString const& str, uint& key_out ); PluginlibFactory* factory_; PropertyTreeModel* property_tree_model_; QList tools_; DisplayContext* context_; Tool* current_tool_; Tool* default_tool_; std::map shortkey_to_tool_map_; }; } // end namespace rviz #endif // TOOL_MANAGER_H rviz-1.12.4/src/rviz/tool_properties_panel.cpp000066400000000000000000000046471300447110700214760ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/property_tree_widget.h" #include "rviz/tool_manager.h" #include "rviz/visualization_manager.h" #include "rviz/tool_properties_panel.h" namespace rviz { ToolPropertiesPanel::ToolPropertiesPanel( QWidget* parent ) : Panel( parent ) { QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins( 0, 0, 0, 0 ); tree_widget_ = new PropertyTreeWidget(); layout->addWidget( tree_widget_ ); setLayout( layout ); } void ToolPropertiesPanel::onInitialize() { tree_widget_->setModel( vis_manager_->getToolManager()->getPropertyModel() ); } void ToolPropertiesPanel::save( Config config ) const { Panel::save( config ); tree_widget_->save( config ); } void ToolPropertiesPanel::load( const Config& config ) { Panel::load( config ); tree_widget_->load( config ); } } // namespace rviz rviz-1.12.4/src/rviz/tool_properties_panel.h000066400000000000000000000044721300447110700211370ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TOOL_PROPERTIES_PANEL_H #define RVIZ_TOOL_PROPERTIES_PANEL_H #include "rviz/panel.h" namespace rviz { class DisplayContext; class PropertyTreeWidget; /** A place to edit properties of all of the Tools. */ class ToolPropertiesPanel: public Panel { Q_OBJECT public: ToolPropertiesPanel( QWidget* parent = 0 ); virtual ~ToolPropertiesPanel() {} virtual void onInitialize(); /** @brief Load configuration data, specifically the PropertyTreeWidget view settings. */ virtual void load( const Config& config ); /** @brief Save configuration data, specifically the PropertyTreeWidget view settings. */ virtual void save( Config config ) const; private: PropertyTreeWidget* tree_widget_; }; } // namespace rviz #endif rviz-1.12.4/src/rviz/uniform_string_stream.cpp000066400000000000000000000044151300447110700214770ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/uniform_string_stream.h" namespace rviz { UniformStringStream::UniformStringStream() { imbue( std::locale( "C" )); } UniformStringStream::UniformStringStream( const std::string& str ) : std::stringstream( str ) { imbue( std::locale( "C" )); } void UniformStringStream::parseFloat( float& f ) { std::string float_string; *this >> float_string; size_t comma_index = float_string.find( ',' ); if( comma_index != std::string::npos ) { float_string[ comma_index ] = '.'; } UniformStringStream float_reader( float_string ); float_reader >> f; if( float_reader.fail() ) { this->setstate( std::ios::failbit ); } } } // end namespace rviz rviz-1.12.4/src/rviz/uniform_string_stream.h000066400000000000000000000047771300447110700211570ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef UNIFORM_STRING_STREAM_H #define UNIFORM_STRING_STREAM_H #include namespace rviz { /** @brief std::stringstream subclass which defaults to the "C" locale, * so serialization of numbers is uniform across locales. * * For reading floats in, use parseFloat() instead of operator>>, * because operator>> is the one from std::stringstream which only * handles "C" style floats. parseFloat() handles "C" and also * European-style floats which use the ",", like "1,2" parses to * 1.2f */ class UniformStringStream: public std::stringstream { public: UniformStringStream(); UniformStringStream( const std::string& str ); /** @brief Parse a float, supporting both period- and comma- style * floats (1,2 and 1.2). * * Uses operator>>(std::string&) internally, so consumes up to next * whitespace from the stream. */ void parseFloat( float& f ); }; } // end namespace rviz #endif // UNIFORM_STRING_STREAM_H rviz-1.12.4/src/rviz/validate_floats.h000066400000000000000000000122201300447110700176560ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_VALIDATE_FLOAT_H #define RVIZ_VALIDATE_FLOAT_H #include #include #include #include #include #include #include #include #include #include namespace rviz { inline bool validateFloats(float val) { return !(std::isnan(val) || std::isinf(val)); } inline bool validateFloats(double val) { return !(std::isnan(val) || std::isinf(val)); } inline bool validateFloats(const Ogre::Vector3& vec) { bool valid = true; valid = valid && validateFloats(vec.x); valid = valid && validateFloats(vec.y); valid = valid && validateFloats(vec.z); return valid; } inline bool validateFloats(const Ogre::Quaternion& quat) { bool valid = true; valid = valid && validateFloats(quat.x); valid = valid && validateFloats(quat.y); valid = valid && validateFloats(quat.z); valid = valid && validateFloats(quat.w); return valid; } inline bool validateFloats(const geometry_msgs::Point& msg) { bool valid = true; valid = valid && validateFloats(msg.x); valid = valid && validateFloats(msg.y); valid = valid && validateFloats(msg.z); return valid; } inline bool validateFloats(const geometry_msgs::Point32& msg) { bool valid = true; valid = valid && validateFloats(msg.x); valid = valid && validateFloats(msg.y); valid = valid && validateFloats(msg.z); return valid; } inline bool validateFloats(const geometry_msgs::Vector3& msg) { bool valid = true; valid = valid && validateFloats(msg.x); valid = valid && validateFloats(msg.y); valid = valid && validateFloats(msg.z); return valid; } inline bool validateFloats(const geometry_msgs::Twist& twist) { bool valid = true; valid = valid && validateFloats(twist.linear); valid = valid && validateFloats(twist.angular); return valid; } inline bool validateFloats(const geometry_msgs::Quaternion& msg) { bool valid = true; valid = valid && validateFloats(msg.x); valid = valid && validateFloats(msg.y); valid = valid && validateFloats(msg.z); valid = valid && validateFloats(msg.w); return valid; } inline bool validateFloats(const std_msgs::ColorRGBA& msg) { bool valid = true; valid = valid && validateFloats(msg.r); valid = valid && validateFloats(msg.g); valid = valid && validateFloats(msg.b); valid = valid && validateFloats(msg.a); return valid; } inline bool validateFloats(const geometry_msgs::PointStamped& msg) { return validateFloats(msg.point); } inline bool validateFloats(const geometry_msgs::Pose& msg) { bool valid = true; valid = valid && validateFloats(msg.position); valid = valid && validateFloats(msg.orientation); return valid; } inline bool validateFloats(const geometry_msgs::PoseStamped& msg) { return validateFloats(msg.pose); } template inline bool validateFloats(const std::vector& vec) { typedef std::vector VecType; typename VecType::const_iterator it = vec.begin(); typename VecType::const_iterator end = vec.end(); for (; it != end; ++it) { if (!validateFloats(*it)) { return false; } } return true; } template inline bool validateFloats(const boost::array& arr) { typedef boost::array ArrType; typename ArrType::const_iterator it = arr.begin(); typename ArrType::const_iterator end = arr.end(); for (; it != end; ++it) { if (!validateFloats(*it)) { return false; } } return true; } } // namespace rviz #endif // RVIZ_VALIDATE_FLOAT_H rviz-1.12.4/src/rviz/view_controller.cpp000066400000000000000000000210721300447110700202720ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "rviz/display_context.h" #include "rviz/frame_manager.h" #include "rviz/load_resource.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/float_property.h" #include "rviz/properties/bool_property.h" #include "rviz/render_panel.h" #include "rviz/selection/selection_manager.h" #include "rviz/view_manager.h" #include "rviz/viewport_mouse_event.h" #include "rviz/window_manager_interface.h" #include "rviz/ogre_helpers/render_system.h" #include "rviz/view_controller.h" namespace rviz { ViewController::ViewController() : context_( NULL ) , camera_( NULL ) , is_active_( false ) , type_property_( NULL ) { near_clip_property_ = new FloatProperty( "Near Clip Distance", 0.01f, "Anything closer to the camera than this threshold will not get rendered.", this, SLOT( updateNearClipDistance() ) ); near_clip_property_->setMin( 0.001 ); near_clip_property_->setMax( 10000 ); stereo_enable_ = new BoolProperty( "Enable Stereo Rendering", true, "Render the main view in stereo if supported." " On Linux this requires a recent version of Ogre and" " an NVIDIA Quadro card with 3DVision glasses.", this, SLOT( updateStereoProperties() ) ); stereo_eye_swap_ = new BoolProperty( "Swap Stereo Eyes", false, "Swap eyes if the monitor shows the left eye on the right.", stereo_enable_, SLOT( updateStereoProperties() ), this ); stereo_eye_separation_ = new FloatProperty( "Stereo Eye Separation", 0.06f, "Distance between eyes for stereo rendering.", stereo_enable_, SLOT( updateStereoProperties() ), this ); stereo_focal_distance_ = new FloatProperty( "Stereo Focal Distance", 1.0f, "Distance from eyes to screen. For stereo rendering.", stereo_enable_, SLOT( updateStereoProperties() ), this ); } void ViewController::initialize( DisplayContext* context ) { context_ = context; std::stringstream ss; static int count = 0; ss << "ViewControllerCamera" << count++; camera_ = context_->getSceneManager()->createCamera( ss.str() ); context_->getSceneManager()->getRootSceneNode()->attachObject( camera_ ); setValue( formatClassId( getClassId() )); setReadOnly( true ); // Do subclass initialization. onInitialize(); cursor_ = getDefaultCursor(); standard_cursors_[Default] = getDefaultCursor(); standard_cursors_[Rotate2D] = makeIconCursor( "package://rviz/icons/rotate.svg" ); standard_cursors_[Rotate3D] = makeIconCursor( "package://rviz/icons/rotate_cam.svg" ); standard_cursors_[MoveXY] = makeIconCursor( "package://rviz/icons/move2d.svg" ); standard_cursors_[MoveZ] = makeIconCursor( "package://rviz/icons/move_z.svg" ); standard_cursors_[Zoom] = makeIconCursor( "package://rviz/icons/zoom.svg" ); standard_cursors_[Crosshair] = makeIconCursor( "package://rviz/icons/crosshair.svg" ); updateNearClipDistance(); updateStereoProperties(); if (!RenderSystem::get()->isStereoSupported()) { stereo_enable_->setBool(false); stereo_enable_->hide(); } } ViewController::~ViewController() { context_->getSceneManager()->destroyCamera( camera_ ); } QString ViewController::formatClassId( const QString& class_id ) { QStringList id_parts = class_id.split( "/" ); if( id_parts.size() != 2 ) { // Should never happen with pluginlib class ids, which are // formatted like "package_name/class_name". Not worth crashing // over though. return class_id; } else { return id_parts[ 1 ] + " (" + id_parts[ 0 ] + ")"; } } QVariant ViewController::getViewData( int column, int role ) const { if ( role == Qt::TextColorRole ) { return QVariant(); } if( is_active_ ) { switch( role ) { case Qt::BackgroundRole: { return QColor( 0xba, 0xad, 0xa4 ); } case Qt::FontRole: { QFont font; font.setBold( true ); return font; } } } return Property::getViewData( column, role ); } Qt::ItemFlags ViewController::getViewFlags( int column ) const { if( is_active_ ) { return Property::getViewFlags( column ); } else { return Property::getViewFlags( column ) | Qt::ItemIsDragEnabled; } } void ViewController::activate() { is_active_ = true; onActivate(); } void ViewController::emitConfigChanged() { Q_EMIT configChanged(); } void ViewController::load( const Config& config ) { // Load the name by hand. QString name; if( config.mapGetString( "Name", &name )) { setName( name ); } // Load all sub-properties the same way the base class does. Property::load( config ); } void ViewController::save( Config config ) const { config.mapSetValue( "Class", getClassId() ); config.mapSetValue( "Name", getName() ); Property::save( config ); } void ViewController::handleKeyEvent( QKeyEvent* event, RenderPanel* panel ) { if( event->key() == Qt::Key_F && panel->getViewport() && context_->getSelectionManager() ) { QPoint mouse_rel_panel = panel->mapFromGlobal( QCursor::pos() ); Ogre::Vector3 point_rel_world; // output of get3DPoint(). if( context_->getSelectionManager()->get3DPoint( panel->getViewport(), mouse_rel_panel.x(), mouse_rel_panel.y(), point_rel_world )) { lookAt( point_rel_world ); } } if( event->key() == Qt::Key_Z ) { reset(); } } void ViewController::setCursor( CursorType cursor_type ) { cursor_=standard_cursors_[cursor_type]; } void ViewController::lookAt( float x, float y, float z ) { Ogre::Vector3 point( x, y, z ); lookAt( point ); } void ViewController::setStatus( const QString & message ) { if ( context_ ) { context_->setStatus( message ); } } void ViewController::updateNearClipDistance() { float n = near_clip_property_->getFloat(); camera_->setNearClipDistance( n ); } void ViewController::updateStereoProperties() { if (stereo_enable_->getBool()) { float focal_dist = stereo_focal_distance_->getFloat(); float eye_sep = stereo_eye_swap_->getBool() ? -stereo_eye_separation_->getFloat() : stereo_eye_separation_->getFloat(); camera_->setFrustumOffset(0.5f * eye_sep, 0.0f); camera_->setFocalLength(focal_dist); stereo_eye_swap_->show(); stereo_eye_separation_->show(); stereo_focal_distance_->show(); } else { camera_->setFrustumOffset(0.0f,0.0f); camera_->setFocalLength(1.0f); stereo_eye_swap_->hide(); stereo_eye_separation_->hide(); stereo_focal_distance_->hide(); } } } // end namespace rviz rviz-1.12.4/src/rviz/view_controller.h000066400000000000000000000161011300447110700177340ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_VIEW_CONTROLLER_H #define RVIZ_VIEW_CONTROLLER_H #include #include #include "rviz/properties/property.h" class QKeyEvent; namespace Ogre { class Camera; class SceneNode; class Vector3; class Quaternion; } namespace rviz { class DisplayContext; class EnumProperty; class RenderPanel; class ViewportMouseEvent; class FloatProperty; class BoolProperty; class ViewController: public Property { Q_OBJECT public: ViewController(); virtual ~ViewController(); /** @brief Do all setup that can't be done in the constructor. * * Creates camera_ and attaches it to the root scene node. * * Calls onInitialize() just before returning. */ void initialize( DisplayContext* context ); static QString formatClassId( const QString& class_id ); /** @brief Overridden from Property to give a different background * color and bold font if this view is active. */ virtual QVariant getViewData( int column, int role ) const; /** @brief Overridden from Property to make this draggable if it is not active. */ virtual Qt::ItemFlags getViewFlags( int column ) const; /** @brief Called by RenderPanel when this view controller is about to be used. * * There is no deactivate() because ViewControllers leaving * "current" are destroyed. Put any cleanup in the destructor. */ void activate(); /** @brief Called at 30Hz by ViewManager::update() while this view * is active. Override with code that needs to run repeatedly. */ virtual void update(float dt, float ros_dt) { (void) dt; (void) ros_dt; } virtual void handleMouseEvent(ViewportMouseEvent& evt) { (void) evt; } /** @brief Called by MoveTool and InteractionTool when keyboard events are passed to them. * * The default implementation here handles the "F" (focus on object) * and "Z" (zero - reset) keys. */ virtual void handleKeyEvent( QKeyEvent* event, RenderPanel* panel ); /** @brief Convenience function which calls lookAt(Ogre::Vector3). */ void lookAt( float x, float y, float z ); /** @brief This should be implemented in each subclass to aim the * camera at the given point in space (relative to the fixed * frame). */ virtual void lookAt( const Ogre::Vector3& point ) { (void) point; } /** Reset the view controller to some sane initial state, like * looking at 0,0,0 from a few meters away. */ virtual void reset() = 0; /** @brief Configure the settings of this view controller to give, * as much as possible, a similar view as that given by the * @a source_view. * * @a source_view must return a valid @c Ogre::Camera* from getCamera(). * * This base class implementation does nothing. */ virtual void mimic( ViewController* source_view ) { (void) source_view; } /** @brief Called by ViewManager when this ViewController is being made current. * @param previous_view is the previous "current" view, and will not be NULL. * * This gives ViewController subclasses an opportunity to implement * a smooth transition from a previous viewpoint to the new * viewpoint. * * This base class implementation does nothing. */ virtual void transitionFrom( ViewController* previous_view ) { (void) previous_view; } /** @brief Subclasses should call this whenever a change is made which would change the results of toString(). */ void emitConfigChanged(); Ogre::Camera* getCamera() const { return camera_; } /** @brief Return the class identifier which was used to create this * instance. This version just returns whatever was set with * setClassId(). */ virtual QString getClassId() const { return class_id_; } /** @brief Set the class identifier used to create this instance. * Typically this will be set by the factory object which created it. */ virtual void setClassId( const QString& class_id ) { class_id_ = class_id; } virtual void load( const Config& config ); virtual void save( Config config ) const; bool isActive() const { return is_active_; } /** @return A mouse cursor representing the current state */ virtual QCursor getCursor() { return cursor_; } Q_SIGNALS: void configChanged(); private Q_SLOTS: void updateNearClipDistance(); void updateStereoProperties(); protected: /** @brief Do subclass-specific initialization. Called by * ViewController::initialize after context_ and camera_ are set. * Default implementation does nothing. */ virtual void onInitialize() {} /** @brief called by activate(). * * Override to implement view-specific activation. This base * implementation does nothing. */ virtual void onActivate() {} // choose a cursor from the standard set enum CursorType{ Default, Rotate2D, Rotate3D, MoveXY, MoveZ, Zoom, Crosshair }; void setCursor( CursorType cursor_type ); // set a custom cursor void setCursor( QCursor cursor ) { cursor_=cursor; } DisplayContext* context_; Ogre::Camera* camera_; bool is_active_; // this cursor will be displayed when the mouse is within the // window controlled by this view controller // use SetCursor to modify. QCursor cursor_; FloatProperty* near_clip_property_; BoolProperty* stereo_enable_; BoolProperty* stereo_eye_swap_; FloatProperty* stereo_eye_separation_; FloatProperty* stereo_focal_distance_; void setStatus( const QString & message ); private: EnumProperty* type_property_; QString class_id_; // Default cursors for the most common actions QMap standard_cursors_; }; } // end namespace rviz #endif // RVIZ_VIEW_CONTROLLER_H rviz-1.12.4/src/rviz/view_manager.cpp000066400000000000000000000166411300447110700175270ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/display_context.h" #include "rviz/failed_view_controller.h" #include "rviz/properties/enum_property.h" #include "rviz/properties/property_tree_model.h" #include "rviz/render_panel.h" #include "rviz/view_controller.h" #include "rviz/view_manager.h" namespace rviz { ViewManager::ViewManager( DisplayContext* context ) : context_( context ) , root_property_( new ViewControllerContainer ) , property_model_( new PropertyTreeModel( root_property_ )) , factory_( new PluginlibFactory( "rviz", "rviz::ViewController" )) , current_( NULL ) , render_panel_( NULL ) { property_model_->setDragDropClass( "view-controller" ); connect( property_model_, SIGNAL( configChanged() ), this, SIGNAL( configChanged() )); } ViewManager::~ViewManager() { delete property_model_; delete factory_; } void ViewManager::initialize() { setCurrent( create( "rviz/Orbit" ), false ); } void ViewManager::update( float wall_dt, float ros_dt ) { if( getCurrent() ) { getCurrent()->update( wall_dt, ros_dt ); } } ViewController* ViewManager::create( const QString& class_id ) { QString error; ViewController* view = factory_->make( class_id, &error ); if( !view ) { view = new FailedViewController( class_id, error ); } view->initialize( context_ ); return view; } ViewController* ViewManager::getCurrent() const { return current_; } void ViewManager::setCurrentFrom( ViewController* source_view ) { if( source_view == NULL ) { return; } ViewController* previous = getCurrent(); if( source_view != previous ) { ViewController* new_current = copy( source_view ); setCurrent( new_current, false ); Q_EMIT configChanged(); } } void ViewManager::onCurrentDestroyed( QObject* obj ) { if( obj == current_ ) { current_ = NULL; } } void ViewManager::setCurrent( ViewController* new_current, bool mimic_view ) { ViewController* previous = getCurrent(); if( previous ) { if( mimic_view ) { new_current->mimic( previous ); } else { new_current->transitionFrom( previous ); } disconnect( previous, SIGNAL( destroyed( QObject* )), this, SLOT( onCurrentDestroyed( QObject* ))); } new_current->setName( "Current View" ); connect( new_current, SIGNAL( destroyed( QObject* )), this, SLOT( onCurrentDestroyed( QObject* ))); current_ = new_current; root_property_->addChildToFront( new_current ); delete previous; if( render_panel_ ) { // This setViewController() can indirectly call // ViewManager::update(), so make sure getCurrent() will return the // new one by this point. render_panel_->setViewController( new_current ); } Q_EMIT currentChanged(); } void ViewManager::setCurrentViewControllerType( const QString& new_class_id ) { setCurrent( create( new_class_id ), true ); } void ViewManager::copyCurrentToList() { ViewController* current = getCurrent(); if( current ) { ViewController* new_copy = copy( current ); new_copy->setName( factory_->getClassName( new_copy->getClassId() )); root_property_->addChild( new_copy ); } } ViewController* ViewManager::getViewAt( int index ) const { if( index < 0 ) { index = 0; } return qobject_cast( root_property_->childAt( index + 1 )); } int ViewManager::getNumViews() const { int count = root_property_->numChildren(); if( count <= 0 ) { return 0; } else { return count-1; } } void ViewManager::add( ViewController* view, int index ) { if( index < 0 ) { index = root_property_->numChildren(); } else { index++; } property_model_->getRoot()->addChild( view, index ); } ViewController* ViewManager::take( ViewController* view ) { for( int i = 0; i < getNumViews(); i++ ) { if( getViewAt( i ) == view ) { return qobject_cast( root_property_->takeChildAt( i + 1 )); } } return NULL; } ViewController* ViewManager::takeAt( int index ) { if( index < 0 ) { return NULL; } return qobject_cast( root_property_->takeChildAt( index + 1 )); } void ViewManager::load( const Config& config ) { Config current_config = config.mapGetChild( "Current" ); QString class_id; if( current_config.mapGetString( "Class", &class_id )) { ViewController* new_current = create( class_id ); new_current->load( current_config ); setCurrent( new_current, false ); } Config saved_views_config = config.mapGetChild( "Saved" ); root_property_->removeChildren( 1 ); int num_saved = saved_views_config.listLength(); for( int i = 0; i < num_saved; i++ ) { Config view_config = saved_views_config.listChildAt( i ); if( view_config.mapGetString( "Class", &class_id )) { ViewController* view = create( class_id ); view->load( view_config ); add( view ); } } } void ViewManager::save( Config config ) const { getCurrent()->save( config.mapMakeChild( "Current" )); Config saved_views_config = config.mapMakeChild( "Saved" ); for( int i = 0; i < getNumViews(); i++ ) { getViewAt( i )->save( saved_views_config.listAppendNew() ); } } ViewController* ViewManager::copy( ViewController* source ) { Config config; source->save( config ); ViewController* copy_of_source = create( source->getClassId() ); copy_of_source->load( config ); return copy_of_source; } void ViewManager::setRenderPanel( RenderPanel* render_panel ) { render_panel_ = render_panel; } Qt::ItemFlags ViewControllerContainer::getViewFlags( int column ) const { return Property::getViewFlags( column ) | Qt::ItemIsDropEnabled; } void ViewControllerContainer::addChild( Property* child, int index ) { if( index == 0 ) { index = 1; } Property::addChild( child, index ); } void ViewControllerContainer::addChildToFront( Property* child ) { Property::addChild( child, 0 ); } } // end namespace rviz rviz-1.12.4/src/rviz/view_manager.h000066400000000000000000000132561300447110700171730ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef VIEW_MANAGER_H #define VIEW_MANAGER_H #include #include #include #include "rviz/pluginlib_factory.h" #include "rviz/view_controller.h" namespace Ogre { class SceneNode; } namespace rviz { class DisplayContext; class Property; class PropertyTreeModel; class ViewController; class ViewControllerContainer; class ViewManager: public QObject { Q_OBJECT public: ViewManager( DisplayContext* context ); ~ViewManager(); void initialize(); void update( float wall_dt, float ros_dt ); /** @brief Return the current ViewController in use for the main * RenderWindow. */ ViewController* getCurrent() const; ViewController* create( const QString& type ); int getNumViews() const; ViewController* getViewAt( int index ) const; void add( ViewController* view, int index = -1 ); /** @brief Remove the given ViewController from the list and return * it. If it is not in the list, NULL is returned and nothing * changes. */ ViewController* take( ViewController* view ); /** @brief Remove the ViewController at the given index from the * list and return it. If the index is not valid, NULL is returned * and nothing changes. */ ViewController* takeAt( int index ); PropertyTreeModel* getPropertyModel() { return property_model_; } void load( const Config& config ); void save( Config config ) const; /** @brief Make a copy of @a view_to_copy and install that as the new current ViewController. */ void setCurrentFrom( ViewController* view_to_copy ); /** @brief Return a copy of source, made by saving source to * a Config and instantiating and loading a new one from that. */ ViewController* copy( ViewController* source ); PluginlibFactory* getFactory() const { return factory_; } /** @brief Set the 3D view widget whose view will be controlled by * ViewController instances from by this ViewManager. */ void setRenderPanel( RenderPanel* render_panel ); /** @brief Return the 3D view widget managed by this ViewManager. */ RenderPanel* getRenderPanel() const { return render_panel_; } public Q_SLOTS: /** @brief Make a copy of the current ViewController and add it to the end of the list of saved views. */ void copyCurrentToList(); /** @brief Create a new view controller of the given type and set it * up to mimic and replace the previous current view. */ void setCurrentViewControllerType( const QString& new_class_id ); Q_SIGNALS: void configChanged(); /** @brief Emitted just after the current view controller changes. */ void currentChanged(); private Q_SLOTS: void onCurrentDestroyed( QObject* obj ); private: /** @brief Set @a new_current as current. * @param mimic_view If true, call new_current->mimic( previous ), if false call new_current->transitionFrom( previous ). * * This calls mimic() or transitionFrom() on the new controller, * deletes the previous controller (if one existed), and tells the * RenderPanel about the new controller. */ void setCurrent( ViewController* new_current, bool mimic_view ); DisplayContext* context_; ViewControllerContainer* root_property_; PropertyTreeModel* property_model_; PluginlibFactory* factory_; ViewController* current_; RenderPanel* render_panel_; }; /** @brief Container property for ViewControllers which gets the * drag/drop right for the funky way Current-View is always the first * entry. */ class ViewControllerContainer: public Property { Q_OBJECT public: Qt::ItemFlags getViewFlags( int column ) const; /** @brief Add a child ViewController. * @param child The child to add. * @param index [optional] The index at which to add the child. If * less than 0 or greater than the number of child properties, the * child will be added at the end. * * This notifies the model about the addition. * * This is overridden from Property to keep saved ViewControllers from being added * at index 0, where the Current view belongs. */ virtual void addChild( Property* child, int index = -1 ); void addChildToFront( Property* child ); }; } // end namespace rviz #endif // VIEW_MANAGER_H rviz-1.12.4/src/rviz/viewport_mouse_event.h000066400000000000000000000104631300447110700210140ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef VIEWPORT_MOUSE_EVENT_H #define VIEWPORT_MOUSE_EVENT_H #include #include namespace Ogre { class Viewport; } namespace rviz { class RenderPanel; class ViewportMouseEvent { public: ViewportMouseEvent() {} /** Constructor for use with a QMouseEvent. */ ViewportMouseEvent(RenderPanel* p, Ogre::Viewport* vp, QMouseEvent* e, int lx, int ly) : panel( p ) , viewport( vp ) , type( e->type() ) , x( e->x() ) , y( e->y() ) , wheel_delta( 0 ) , acting_button( e->button() ) , buttons_down( e->buttons() ) , modifiers( e->modifiers() ) , last_x( lx ) , last_y( ly ) { } // Qt has a separate QWheelEvent for mousewheel events which is not // a subclass of QMouseEvent, but has a lot of overlap with it. /** Constructor for use with a QWheelEvent. */ ViewportMouseEvent(RenderPanel* p, Ogre::Viewport* vp, QWheelEvent* e, int lx, int ly) : panel( p ) , viewport( vp ) , type( e->type() ) , x( e->x() ) , y( e->y() ) , wheel_delta( e->delta() ) , acting_button( Qt::NoButton ) , buttons_down( e->buttons() ) , modifiers( e->modifiers() ) , last_x( lx ) , last_y( ly ) { } // Convenience functions for getting the state of the buttons and // modifiers at the time of the event. For the button which caused // a press or release event, use acting_button. bool left() { return buttons_down & Qt::LeftButton; } bool middle() { return buttons_down & Qt::MidButton; } bool right() { return buttons_down & Qt::RightButton; } bool shift() { return modifiers & Qt::ShiftModifier; } bool control() { return modifiers & Qt::ControlModifier; } bool alt() { return modifiers & Qt::AltModifier; } // Convenience functions to tell if the event is a mouse-down or // mouse-up event and which button caused it. bool leftUp() { return type == QEvent::MouseButtonRelease && acting_button == Qt::LeftButton; } bool middleUp() { return type == QEvent::MouseButtonRelease && acting_button == Qt::MidButton; } bool rightUp() { return type == QEvent::MouseButtonRelease && acting_button == Qt::RightButton; } bool leftDown() { return type == QEvent::MouseButtonPress && acting_button == Qt::LeftButton; } bool middleDown() { return type == QEvent::MouseButtonPress && acting_button == Qt::MidButton; } bool rightDown() { return type == QEvent::MouseButtonPress && acting_button == Qt::RightButton; } RenderPanel* panel; Ogre::Viewport* viewport; QEvent::Type type; int x; int y; int wheel_delta; Qt::MouseButton acting_button; // The button which caused the event. Can be Qt::NoButton (move or wheel events). Qt::MouseButtons buttons_down; Qt::KeyboardModifiers modifiers; int last_x; int last_y; }; } // namespace rviz #endif // VIEWPORT_MOUSE_EVENT_H rviz-1.12.4/src/rviz/views_panel.cpp000066400000000000000000000166051300447110700173770ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "rviz/properties/property_tree_widget.h" #include "rviz/view_controller.h" #include "rviz/view_manager.h" #include "rviz/visualization_manager.h" #include "views_panel.h" namespace rviz { ViewsPanel::ViewsPanel( QWidget* parent ) : Panel( parent ) , view_man_( NULL ) { camera_type_selector_ = new QComboBox; properties_view_ = new PropertyTreeWidget(); save_button_ = new QPushButton( "Save" ); QPushButton* remove_button = new QPushButton( "Remove" ); QPushButton* rename_button = new QPushButton( "Rename" ); QPushButton* zero_button = new QPushButton( "Zero" ); zero_button->setToolTip( "Jump to 0,0,0 with the current view controller. Shortcut: Z" ); QHBoxLayout* top_layout = new QHBoxLayout; top_layout->addWidget( new QLabel( "Type:" )); top_layout->addWidget( camera_type_selector_ ); top_layout->addStretch(); top_layout->addWidget( zero_button ); top_layout->setContentsMargins( 2, 6, 2, 2 ); QHBoxLayout* button_layout = new QHBoxLayout; button_layout->addWidget( save_button_ ); button_layout->addWidget( remove_button ); button_layout->addWidget( rename_button ); button_layout->setContentsMargins( 2, 0, 2, 2 ); QVBoxLayout* main_layout = new QVBoxLayout; main_layout->setContentsMargins( 0,0,0,0 ); main_layout->addLayout( top_layout ); main_layout->addWidget( properties_view_ ); main_layout->addLayout( button_layout ); setLayout( main_layout ); connect( remove_button, SIGNAL( clicked() ), this, SLOT( onDeleteClicked() )); connect( rename_button, SIGNAL( clicked() ), this, SLOT( renameSelected() )); connect( zero_button, SIGNAL( clicked() ), this, SLOT( onZeroClicked() )); connect( properties_view_, SIGNAL( clicked( const QModelIndex& )), this, SLOT( setCurrentViewFromIndex( const QModelIndex& ))); connect( properties_view_, SIGNAL( activated( const QModelIndex& )), this, SLOT( setCurrentViewFromIndex( const QModelIndex& ))); } void ViewsPanel::onInitialize() { setViewManager( vis_manager_->getViewManager() ); } void ViewsPanel::setViewManager( ViewManager* view_man ) { if( view_man_ ) { disconnect( save_button_, SIGNAL( clicked() ), view_man_, SLOT( copyCurrentToList() )); disconnect( camera_type_selector_, SIGNAL( activated( int )), this, SLOT( onTypeSelectorChanged( int ))); disconnect( view_man_, SIGNAL( currentChanged() ), this, SLOT( onCurrentChanged() )); } view_man_ = view_man; camera_type_selector_->clear(); if( view_man_ ) { properties_view_->setModel( view_man_->getPropertyModel() ); QStringList ids = view_man_->getFactory()->getDeclaredClassIds(); for( int i = 0; i < ids.size(); i++ ) { const QString& id = ids[ i ]; camera_type_selector_->addItem( ViewController::formatClassId( id ), id ); // send the regular-formatted id as userData. } connect( save_button_, SIGNAL( clicked() ), view_man_, SLOT( copyCurrentToList() )); connect( camera_type_selector_, SIGNAL( activated( int )), this, SLOT( onTypeSelectorChanged( int ))); connect( view_man_, SIGNAL( currentChanged() ), this, SLOT( onCurrentChanged() )); } else { properties_view_->setModel( NULL ); } onCurrentChanged(); } void ViewsPanel::onTypeSelectorChanged( int selected_index ) { QString class_id = camera_type_selector_->itemData( selected_index ).toString(); view_man_->setCurrentViewControllerType( class_id ); } void ViewsPanel::onZeroClicked() { if( view_man_->getCurrent() ) { view_man_->getCurrent()->reset(); } } void ViewsPanel::setCurrentViewFromIndex( const QModelIndex& index ) { Property* prop = view_man_->getPropertyModel()->getProp( index ); if( ViewController* view = qobject_cast( prop )) { view_man_->setCurrentFrom( view ); } } void ViewsPanel::onDeleteClicked() { QList views_to_delete = properties_view_->getSelectedObjects(); for( int i = 0; i < views_to_delete.size(); i++ ) { // TODO: should eventually move to a scheme where the CURRENT view // is not in the same list as the saved views, at which point this // check can go away. if( views_to_delete[ i ] != view_man_->getCurrent() ) { delete views_to_delete[ i ]; } } } void ViewsPanel::renameSelected() { QList views_to_rename = properties_view_->getSelectedObjects(); if( views_to_rename.size() == 1 ) { ViewController* view = views_to_rename[ 0 ]; // TODO: should eventually move to a scheme where the CURRENT view // is not in the same list as the saved views, at which point this // check can go away. if( view == view_man_->getCurrent() ) { return; } QString old_name = view->getName(); QString new_name = QInputDialog::getText( this, "Rename View", "New Name?", QLineEdit::Normal, old_name ); if( new_name.isEmpty() || new_name == old_name ) { return; } view->setName( new_name ); } } void ViewsPanel::onCurrentChanged() { QString formatted_class_id = ViewController::formatClassId( view_man_->getCurrent()->getClassId() ); // Make sure the type selector shows the type of the current view. // This is only here in case the type is changed programmatically, // instead of via the camera_type_selector_ being used. camera_type_selector_->setCurrentIndex( camera_type_selector_->findText( formatted_class_id )); properties_view_->setAnimated( false ); view_man_->getCurrent()->expand(); properties_view_->setAnimated( true ); } void ViewsPanel::save( Config config ) const { Panel::save( config ); properties_view_->save( config ); } void ViewsPanel::load( const Config& config ) { Panel::load( config ); properties_view_->load( config ); } } // namespace rviz rviz-1.12.4/src/rviz/views_panel.h000066400000000000000000000064561300447110700170470ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_VIEWS_PANEL_H #define RVIZ_VIEWS_PANEL_H #include "rviz/panel.h" class QComboBox; class QModelIndex; class QPushButton; namespace rviz { class ViewManager; class PropertyTreeWidget; /** * @brief Panel for choosing the view controller and saving and restoring * viewpoints. */ class ViewsPanel: public Panel { Q_OBJECT public: ViewsPanel( QWidget* parent = 0 ); virtual ~ViewsPanel() {} /** @brief Overridden from Panel. Just calls setViewManager() with vis_manager_->getViewManager(). */ virtual void onInitialize(); /** @brief Set the ViewManager which this panel should display and edit. * * If this ViewsPanel is to be used with a ViewManager other than * the one in the VisualizationManager sent in through * Panel::initialize(), either Panel::initialize() must not be * called or setViewManager() must be called after * Panel::initialize(). */ void setViewManager( ViewManager* view_man ); /** @brief Returns the current ViewManager. */ ViewManager* getViewManager() const { return view_man_; } /** @brief Load configuration data, specifically the PropertyTreeWidget view settings. */ virtual void load( const Config& config ); /** @brief Save configuration data, specifically the PropertyTreeWidget view settings. */ virtual void save( Config config ) const; private Q_SLOTS: void onTypeSelectorChanged( int selected_index ); void onDeleteClicked(); void renameSelected(); void onZeroClicked(); void onCurrentChanged(); void setCurrentViewFromIndex( const QModelIndex& index ); private: ViewManager* view_man_; PropertyTreeWidget* properties_view_; QPushButton* save_button_; QComboBox* camera_type_selector_; }; } // namespace rviz #endif // RVIZ_VIEWS_PANEL_H rviz-1.12.4/src/rviz/visualization_frame.cpp000066400000000000000000001122501300447110700211270ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rviz/displays_panel.h" #include "rviz/env_config.h" #include "rviz/failed_panel.h" #include "rviz/help_panel.h" #include "rviz/loading_dialog.h" #include "rviz/new_object_dialog.h" #include "rviz/panel_dock_widget.h" #include "rviz/panel_factory.h" #include "rviz/render_panel.h" #include "rviz/screenshot_dialog.h" #include "rviz/selection/selection_manager.h" #include "rviz/selection_panel.h" #include "rviz/splash_screen.h" #include "rviz/time_panel.h" #include "rviz/tool.h" #include "rviz/tool_manager.h" #include "rviz/tool_properties_panel.h" #include "rviz/views_panel.h" #include "rviz/visualization_manager.h" #include "rviz/widget_geometry_change_detector.h" #include "rviz/load_resource.h" #include "rviz/yaml_config_reader.h" #include "rviz/yaml_config_writer.h" #include "rviz/visualization_frame.h" namespace fs = boost::filesystem; #define CONFIG_EXTENSION "rviz" #define CONFIG_EXTENSION_WILDCARD "*." CONFIG_EXTENSION #define RECENT_CONFIG_COUNT 10 #if BOOST_FILESYSTEM_VERSION == 3 #define BOOST_FILENAME_STRING filename().string #define BOOST_FILE_STRING string #else #define BOOST_FILENAME_STRING filename #define BOOST_FILE_STRING file_string #endif namespace rviz { VisualizationFrame::VisualizationFrame( QWidget* parent ) : QMainWindow( parent ) , app_(NULL) , render_panel_(NULL) , show_help_action_(NULL) , file_menu_(NULL) , recent_configs_menu_(NULL) , toolbar_(NULL) , manager_(NULL) , splash_( NULL ) , toolbar_actions_( NULL ) , show_choose_new_master_option_( false ) , add_tool_action_( NULL ) , remove_tool_menu_( NULL ) , initialized_( false ) , geom_change_detector_( new WidgetGeometryChangeDetector( this )) , loading_( false ) , post_load_timer_( new QTimer( this )) , frame_count_(0) { panel_factory_ = new PanelFactory(); installEventFilter( geom_change_detector_ ); connect( geom_change_detector_, SIGNAL( changed() ), this, SLOT( setDisplayConfigModified() )); post_load_timer_->setSingleShot( true ); connect( post_load_timer_, SIGNAL( timeout() ), this, SLOT( markLoadingDone() )); package_path_ = ros::package::getPath("rviz"); help_path_ = QString::fromStdString( (fs::path(package_path_) / "help/help.html").BOOST_FILE_STRING() ); splash_path_ = QString::fromStdString( (fs::path(package_path_) / "images/splash.png").BOOST_FILE_STRING() ); QToolButton* reset_button = new QToolButton( ); reset_button->setText( "Reset" ); reset_button->setContentsMargins(0,0,0,0); statusBar()->addPermanentWidget( reset_button, 0 ); connect( reset_button, SIGNAL( clicked( bool )), this, SLOT( reset() )); status_label_ = new QLabel(""); statusBar()->addPermanentWidget( status_label_, 1 ); connect( this, SIGNAL( statusUpdate( const QString& )), status_label_, SLOT( setText( const QString& ))); fps_label_ = new QLabel(""); fps_label_->setMinimumWidth(40); fps_label_->setAlignment(Qt::AlignRight); statusBar()->addPermanentWidget( fps_label_, 0 ); original_status_bar_ = statusBar(); setWindowTitle( "RViz[*]" ); } VisualizationFrame::~VisualizationFrame() { delete render_panel_; delete manager_; for( int i = 0; i < custom_panels_.size(); i++ ) { delete custom_panels_[ i ].dock; } delete panel_factory_; } void VisualizationFrame::setApp( QApplication * app ) { app_ = app; } void VisualizationFrame::setStatus( const QString & message ) { Q_EMIT statusUpdate( message ); } void VisualizationFrame::updateFps() { frame_count_ ++; ros::WallDuration wall_diff = ros::WallTime::now() - last_fps_calc_time_; if ( wall_diff.toSec() > 1.0 ) { float fps = frame_count_ / wall_diff.toSec(); frame_count_ = 0; last_fps_calc_time_ = ros::WallTime::now(); if ( original_status_bar_ == statusBar() ) { fps_label_->setText( QString::number(int(fps)) + QString(" fps") ); } } } void VisualizationFrame::closeEvent( QCloseEvent* event ) { if( prepareToExit() ) { event->accept(); } else { event->ignore(); } } void VisualizationFrame::leaveEvent ( QEvent * event ) { setStatus(""); } void VisualizationFrame::reset() { Ogre::MeshManager::getSingleton().removeAll(); manager_->resetTime(); } void VisualizationFrame::changeMaster() { if( prepareToExit() ) { QApplication::exit( 255 ); } } void VisualizationFrame::setShowChooseNewMaster( bool show ) { show_choose_new_master_option_ = show; } void VisualizationFrame::setHelpPath( const QString& help_path ) { help_path_ = help_path; manager_->setHelpPath( help_path_ ); } void VisualizationFrame::setSplashPath( const QString& splash_path ) { splash_path_ = splash_path; } void VisualizationFrame::initialize(const QString& display_config_file ) { initConfigs(); loadPersistentSettings(); QIcon app_icon( QString::fromStdString( (fs::path(package_path_) / "icons/package.png").BOOST_FILE_STRING() ) ); setWindowIcon( app_icon ); if( splash_path_ != "" ) { QPixmap splash_image( splash_path_ ); splash_ = new SplashScreen( splash_image ); splash_->show(); connect( this, SIGNAL( statusUpdate( const QString& )), splash_, SLOT( showMessage( const QString& ))); } Q_EMIT statusUpdate( "Initializing" ); // Periodically process events for the splash screen. // See: http://doc.qt.io/qt-5/qsplashscreen.html#details if (app_) app_->processEvents(); if( !ros::isInitialized() ) { int argc = 0; ros::init( argc, 0, "rviz", ros::init_options::AnonymousName ); } // Periodically process events for the splash screen. if (app_) app_->processEvents(); QWidget* central_widget = new QWidget(this); QHBoxLayout* central_layout = new QHBoxLayout; central_layout->setSpacing(0); central_layout->setMargin(0); render_panel_ = new RenderPanel( central_widget ); hide_left_dock_button_ = new QToolButton(); hide_left_dock_button_->setContentsMargins(0,0,0,0); hide_left_dock_button_->setArrowType( Qt::LeftArrow ); hide_left_dock_button_->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) ); hide_left_dock_button_->setFixedWidth(16); hide_left_dock_button_->setAutoRaise(true); hide_left_dock_button_->setCheckable(true); connect(hide_left_dock_button_, SIGNAL(toggled(bool)), this, SLOT(hideLeftDock(bool))); hide_right_dock_button_ = new QToolButton(); hide_right_dock_button_->setContentsMargins(0,0,0,0); hide_right_dock_button_->setArrowType( Qt::RightArrow ); hide_right_dock_button_->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) ); hide_right_dock_button_->setFixedWidth(16); hide_right_dock_button_->setAutoRaise(true); hide_right_dock_button_->setCheckable(true); connect(hide_right_dock_button_, SIGNAL(toggled(bool)), this, SLOT(hideRightDock(bool))); central_layout->addWidget( hide_left_dock_button_, 0 ); central_layout->addWidget( render_panel_, 1 ); central_layout->addWidget( hide_right_dock_button_, 0 ); central_widget->setLayout( central_layout ); // Periodically process events for the splash screen. if (app_) app_->processEvents(); initMenus(); // Periodically process events for the splash screen. if (app_) app_->processEvents(); initToolbars(); // Periodically process events for the splash screen. if (app_) app_->processEvents(); setCentralWidget( central_widget ); // Periodically process events for the splash screen. if (app_) app_->processEvents(); manager_ = new VisualizationManager( render_panel_, this ); manager_->setHelpPath( help_path_ ); // Periodically process events for the splash screen. if (app_) app_->processEvents(); render_panel_->initialize( manager_->getSceneManager(), manager_ ); // Periodically process events for the splash screen. if (app_) app_->processEvents(); ToolManager* tool_man = manager_->getToolManager(); connect( manager_, SIGNAL( configChanged() ), this, SLOT( setDisplayConfigModified() )); connect( tool_man, SIGNAL( toolAdded( Tool* )), this, SLOT( addTool( Tool* ))); connect( tool_man, SIGNAL( toolRemoved( Tool* )), this, SLOT( removeTool( Tool* ))); connect( tool_man, SIGNAL( toolRefreshed( Tool* )), this, SLOT( refreshTool( Tool* ))); connect( tool_man, SIGNAL( toolChanged( Tool* )), this, SLOT( indicateToolIsCurrent( Tool* ))); manager_->initialize(); // Periodically process events for the splash screen. if (app_) app_->processEvents(); if( display_config_file != "" ) { loadDisplayConfig( display_config_file ); } else { loadDisplayConfig( QString::fromStdString( default_display_config_file_ )); } // Periodically process events for the splash screen. if (app_) app_->processEvents(); delete splash_; splash_ = 0; manager_->startUpdate(); initialized_ = true; Q_EMIT statusUpdate( "RViz is ready." ); connect( manager_, SIGNAL( preUpdate() ), this, SLOT( updateFps() ) ); connect( manager_, SIGNAL( statusUpdate( const QString& )), this, SIGNAL( statusUpdate( const QString& ))); } void VisualizationFrame::initConfigs() { home_dir_ = QDir::toNativeSeparators( QDir::homePath() ).toStdString(); config_dir_ = (fs::path(home_dir_) / ".rviz").BOOST_FILE_STRING(); persistent_settings_file_ = (fs::path(config_dir_) / "persistent_settings").BOOST_FILE_STRING(); default_display_config_file_ = (fs::path(config_dir_) / "default." CONFIG_EXTENSION).BOOST_FILE_STRING(); if( fs::is_regular_file( config_dir_ )) { ROS_ERROR("Moving file [%s] out of the way to recreate it as a directory.", config_dir_.c_str()); std::string backup_file = config_dir_ + ".bak"; fs::rename(config_dir_, backup_file); fs::create_directory(config_dir_); } else if (!fs::exists(config_dir_)) { fs::create_directory(config_dir_); } } void VisualizationFrame::loadPersistentSettings() { YamlConfigReader reader; Config config; reader.readFile( config, QString::fromStdString( persistent_settings_file_ )); if( !reader.error() ) { QString last_config_dir, last_image_dir; if( config.mapGetString( "Last Config Dir", &last_config_dir ) && config.mapGetString( "Last Image Dir", &last_image_dir )) { last_config_dir_ = last_config_dir.toStdString(); last_image_dir_ = last_image_dir.toStdString(); } Config recent_configs_list = config.mapGetChild( "Recent Configs" ); recent_configs_.clear(); int num_recent = recent_configs_list.listLength(); for( int i = 0; i < num_recent; i++ ) { recent_configs_.push_back( recent_configs_list.listChildAt( i ).getValue().toString().toStdString() ); } } else { ROS_ERROR( "%s", qPrintable( reader.errorMessage() )); } } void VisualizationFrame::savePersistentSettings() { Config config; config.mapSetValue( "Last Config Dir", QString::fromStdString( last_config_dir_ )); config.mapSetValue( "Last Image Dir", QString::fromStdString( last_image_dir_ )); Config recent_configs_list = config.mapMakeChild( "Recent Configs" ); for( D_string::iterator it = recent_configs_.begin(); it != recent_configs_.end(); ++it ) { recent_configs_list.listAppendNew().setValue( QString::fromStdString( *it )); } YamlConfigWriter writer; writer.writeFile( config, QString::fromStdString( persistent_settings_file_ )); if( writer.error() ) { ROS_ERROR( "%s", qPrintable( writer.errorMessage() )); } } void VisualizationFrame::initMenus() { file_menu_ = menuBar()->addMenu( "&File" ); file_menu_->addAction( "&Open Config", this, SLOT( onOpen() ), QKeySequence( "Ctrl+O" )); file_menu_->addAction( "&Save Config", this, SLOT( onSave() ), QKeySequence( "Ctrl+S" )); file_menu_->addAction( "Save Config &As", this, SLOT( onSaveAs() )); recent_configs_menu_ = file_menu_->addMenu( "&Recent Configs" ); file_menu_->addAction( "Save &Image", this, SLOT( onSaveImage() )); if( show_choose_new_master_option_ ) { file_menu_->addSeparator(); file_menu_->addAction( "Change &Master", this, SLOT( changeMaster() )); } file_menu_->addSeparator(); file_menu_->addAction( "&Quit", this, SLOT( close() ), QKeySequence( "Ctrl+Q" )); view_menu_ = menuBar()->addMenu( "&Panels" ); view_menu_->addAction( "Add &New Panel", this, SLOT( openNewPanelDialog() )); delete_view_menu_ = view_menu_->addMenu( "&Delete Panel" ); delete_view_menu_->setEnabled( false ); view_menu_->addSeparator(); QMenu* help_menu = menuBar()->addMenu( "&Help" ); help_menu->addAction( "Show &Help panel", this, SLOT( showHelpPanel() )); help_menu->addAction( "Open rviz wiki in browser", this, SLOT( onHelpWiki() )); help_menu->addSeparator(); help_menu->addAction( "&About", this, SLOT( onHelpAbout() )); } void VisualizationFrame::initToolbars() { QFont font; font.setPointSize( font.pointSizeF()*0.9 ); // make toolbar with plugin tools toolbar_ = addToolBar( "Tools" ); toolbar_->setFont( font ); toolbar_->setContentsMargins(0,0,0,0); toolbar_->setObjectName( "Tools" ); toolbar_->setToolButtonStyle( Qt::ToolButtonTextBesideIcon ); toolbar_actions_ = new QActionGroup( this ); connect( toolbar_actions_, SIGNAL( triggered( QAction* )), this, SLOT( onToolbarActionTriggered( QAction* ))); view_menu_->addAction( toolbar_->toggleViewAction() ); add_tool_action_ = new QAction( "", toolbar_actions_ ); add_tool_action_->setToolTip( "Add a new tool" ); add_tool_action_->setIcon( loadPixmap( "package://rviz/icons/plus.png" ) ); toolbar_->addAction( add_tool_action_ ); connect( add_tool_action_, SIGNAL( triggered() ), this, SLOT( openNewToolDialog() )); remove_tool_menu_ = new QMenu(); QToolButton* remove_tool_button = new QToolButton(); remove_tool_button->setMenu( remove_tool_menu_ ); remove_tool_button->setPopupMode( QToolButton::InstantPopup ); remove_tool_button->setToolTip( "Remove a tool from the toolbar" ); remove_tool_button->setIcon( loadPixmap( "package://rviz/icons/minus.png" ) ); toolbar_->addWidget( remove_tool_button ); connect( remove_tool_menu_, SIGNAL( triggered( QAction* )), this, SLOT( onToolbarRemoveTool( QAction* ))); } void VisualizationFrame::hideDockImpl( Qt::DockWidgetArea area, bool hide ) { QList dock_widgets = findChildren(); for ( QList::iterator it=dock_widgets.begin(); it!=dock_widgets.end(); it++ ) { Qt::DockWidgetArea curr_area = dockWidgetArea ( *it ); if ( area == curr_area ) { (*it)->setCollapsed(hide); } // allow/disallow docking to this area for all widgets if ( hide ) { (*it)->setAllowedAreas( (*it)->allowedAreas() & ~area ); } else { (*it)->setAllowedAreas( (*it)->allowedAreas() | area ); } } } void VisualizationFrame::setHideButtonVisibility( bool visible ) { hide_left_dock_button_->setVisible( visible ); hide_right_dock_button_->setVisible( visible ); } void VisualizationFrame::hideLeftDock( bool hide ) { hideDockImpl( Qt::LeftDockWidgetArea, hide ); hide_left_dock_button_->setArrowType( hide ? Qt::RightArrow : Qt::LeftArrow ); } void VisualizationFrame::hideRightDock( bool hide ) { hideDockImpl( Qt::RightDockWidgetArea, hide ); hide_right_dock_button_->setArrowType( hide ? Qt::LeftArrow : Qt::RightArrow ); } void VisualizationFrame::onDockPanelVisibilityChange( bool visible ) { // if a dock widget becomes visible and is resting inside the // left or right dock area, we want to unhide the whole area if ( visible ) { QDockWidget* dock_widget = dynamic_cast( sender() ); if ( dock_widget ) { Qt::DockWidgetArea area = dockWidgetArea( dock_widget ); if ( area == Qt::LeftDockWidgetArea ) { hide_left_dock_button_->setChecked( false ); } if ( area == Qt::RightDockWidgetArea ) { hide_right_dock_button_->setChecked( false ); } } } } void VisualizationFrame::openNewPanelDialog() { QString class_id; QString display_name; QStringList empty; NewObjectDialog* dialog = new NewObjectDialog( panel_factory_, "Panel", empty, empty, &class_id, &display_name, this ); manager_->stopUpdate(); if( dialog->exec() == QDialog::Accepted ) { addPanelByName( display_name, class_id ); } manager_->startUpdate(); } void VisualizationFrame::openNewToolDialog() { QString class_id; QStringList empty; ToolManager* tool_man = manager_->getToolManager(); NewObjectDialog* dialog = new NewObjectDialog( tool_man->getFactory(), "Tool", empty, tool_man->getToolClasses(), &class_id ); manager_->stopUpdate(); if( dialog->exec() == QDialog::Accepted ) { tool_man->addTool( class_id ); } manager_->startUpdate(); activateWindow(); // Force keyboard focus back on main window. } void VisualizationFrame::updateRecentConfigMenu() { recent_configs_menu_->clear(); D_string::iterator it = recent_configs_.begin(); D_string::iterator end = recent_configs_.end(); for (; it != end; ++it) { if( *it != "" ) { std::string display_name = *it; if( display_name == default_display_config_file_ ) { display_name += " (default)"; } if( display_name.find( home_dir_ ) == 0 ) { display_name = ("~" / fs::path( display_name.substr( home_dir_.size() ))).BOOST_FILE_STRING(); } QString qdisplay_name = QString::fromStdString( display_name ); QAction* action = new QAction( qdisplay_name, this ); action->setData( QString::fromStdString( *it )); connect( action, SIGNAL( triggered() ), this, SLOT( onRecentConfigSelected() )); recent_configs_menu_->addAction( action ); } } } void VisualizationFrame::markRecentConfig( const std::string& path ) { D_string::iterator it = std::find( recent_configs_.begin(), recent_configs_.end(), path ); if( it != recent_configs_.end() ) { recent_configs_.erase( it ); } recent_configs_.push_front( path ); if( recent_configs_.size() > RECENT_CONFIG_COUNT ) { recent_configs_.pop_back(); } updateRecentConfigMenu(); } void VisualizationFrame::loadDisplayConfig( const QString& qpath ) { std::string path = qpath.toStdString(); std::string actual_load_path = path; if( !fs::exists( path ) || fs::is_directory( path ) || fs::is_empty( path )) { actual_load_path = (fs::path(package_path_) / "default.rviz").BOOST_FILE_STRING(); if( !fs::exists( actual_load_path )) { ROS_ERROR( "Default display config '%s' not found. RViz will be very empty at first.", actual_load_path.c_str() ); return; } } // Check if we have unsaved changes to the current config the same // as we do during exit, with the same option to cancel. if( !prepareToExit() ) { return; } setWindowModified( false ); loading_ = true; LoadingDialog* dialog = NULL; if( initialized_ ) { dialog = new LoadingDialog( this ); dialog->show(); connect( this, SIGNAL( statusUpdate( const QString& )), dialog, SLOT( showMessage( const QString& ))); } YamlConfigReader reader; Config config; reader.readFile( config, QString::fromStdString( actual_load_path )); if( !reader.error() ) { load( config ); } markRecentConfig( path ); setDisplayConfigFile( path ); last_config_dir_ = fs::path( path ).parent_path().BOOST_FILE_STRING(); delete dialog; post_load_timer_->start( 1000 ); } void VisualizationFrame::markLoadingDone() { loading_ = false; } void VisualizationFrame::setImageSaveDirectory( const QString& directory ) { last_image_dir_ = directory.toStdString(); } void VisualizationFrame::setDisplayConfigModified() { if( !loading_ ) { setWindowModified( true ); } } void VisualizationFrame::setDisplayConfigFile( const std::string& path ) { display_config_file_ = path; std::string title; if( path == default_display_config_file_ ) { title = "RViz[*]"; } else { title = fs::path( path ).BOOST_FILENAME_STRING() + "[*] - RViz"; } setWindowTitle( QString::fromStdString( title )); } bool VisualizationFrame::saveDisplayConfig( const QString& path ) { Config config; save( config ); YamlConfigWriter writer; writer.writeFile( config, path ); if( writer.error() ) { ROS_ERROR( "%s", qPrintable( writer.errorMessage() )); error_message_ = writer.errorMessage(); return false; } else { setWindowModified( false ); error_message_ = ""; return true; } } void VisualizationFrame::save( Config config ) { manager_->save( config.mapMakeChild( "Visualization Manager" )); savePanels( config.mapMakeChild( "Panels" )); saveWindowGeometry( config.mapMakeChild( "Window Geometry" )); } void VisualizationFrame::load( const Config& config ) { manager_->load( config.mapGetChild( "Visualization Manager" )); loadPanels( config.mapGetChild( "Panels" )); loadWindowGeometry( config.mapGetChild( "Window Geometry" )); } void VisualizationFrame::loadWindowGeometry( const Config& config ) { int x, y; if( config.mapGetInt( "X", &x ) && config.mapGetInt( "Y", &y )) { move( x, y ); } int width, height; if( config.mapGetInt( "Width", &width ) && config.mapGetInt( "Height", &height )) { resize( width, height ); } QString main_window_config; if( config.mapGetString( "QMainWindow State", &main_window_config )) { restoreState( QByteArray::fromHex( qPrintable( main_window_config ))); } // load panel dock widget states (collapsed or not) QList dock_widgets = findChildren(); for ( QList::iterator it=dock_widgets.begin(); it!=dock_widgets.end(); it++ ) { Config itConfig = config.mapGetChild((*it)->windowTitle()); if (itConfig.isValid()) { (*it)->load(itConfig); } } bool b; config.mapGetBool( "Hide Left Dock", &b ); hide_left_dock_button_->setChecked( b ); hideLeftDock(b); config.mapGetBool( "Hide Right Dock", &b ); hideRightDock(b); hide_right_dock_button_->setChecked( b ); } void VisualizationFrame::saveWindowGeometry( Config config ) { config.mapSetValue( "X", x() ); config.mapSetValue( "Y", y() ); config.mapSetValue( "Width", width() ); config.mapSetValue( "Height", height() ); QByteArray window_state = saveState().toHex(); config.mapSetValue( "QMainWindow State", window_state.constData() ); config.mapSetValue( "Hide Left Dock", hide_left_dock_button_->isChecked() ); config.mapSetValue( "Hide Right Dock", hide_right_dock_button_->isChecked() ); // save panel dock widget states (collapsed or not) QList dock_widgets = findChildren(); for ( QList::iterator it=dock_widgets.begin(); it!=dock_widgets.end(); it++ ) { (*it)->save(config.mapMakeChild( (*it)->windowTitle() )); } } void VisualizationFrame::loadPanels( const Config& config ) { // First destroy any existing custom panels. for( int i = 0; i < custom_panels_.size(); i++ ) { delete custom_panels_[ i ].dock; delete custom_panels_[ i ].delete_action; } custom_panels_.clear(); // Then load the ones in the config. int num_custom_panels = config.listLength(); for( int i = 0; i < num_custom_panels; i++ ) { Config panel_config = config.listChildAt( i ); QString class_id, name; if( panel_config.mapGetString( "Class", &class_id ) && panel_config.mapGetString( "Name", &name )) { QDockWidget* dock = addPanelByName( name, class_id ); // This is kind of ridiculous - should just be something like // createPanel() and addPanel() so I can do load() without this // qobject_cast. if( dock ) { Panel* panel = qobject_cast( dock->widget() ); if( panel ) { panel->load( panel_config ); } } } } } void VisualizationFrame::savePanels( Config config ) { config.setType( Config::List ); // Not really necessary, but gives an empty list if there are no entries, instead of an Empty config node. for( int i = 0; i < custom_panels_.size(); i++ ) { custom_panels_[ i ].panel->save( config.listAppendNew() ); } } bool VisualizationFrame::prepareToExit() { if( !initialized_ ) { return true; } savePersistentSettings(); if( isWindowModified() ) { QMessageBox box( this ); box.setText( "There are unsaved changes." ); box.setInformativeText( QString::fromStdString( "Save changes to " + display_config_file_ + "?" )); box.setStandardButtons( QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel ); box.setDefaultButton( QMessageBox::Save ); manager_->stopUpdate(); int result = box.exec(); manager_->startUpdate(); switch( result ) { case QMessageBox::Save: if( saveDisplayConfig( QString::fromStdString( display_config_file_ ))) { return true; } else { QMessageBox box( this ); box.setWindowTitle( "Failed to save." ); box.setText( getErrorMessage() ); box.setInformativeText( QString::fromStdString( "Save copy of " + display_config_file_ + " to another file?" )); box.setStandardButtons( QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel ); box.setDefaultButton( QMessageBox::Save ); int result = box.exec(); switch( result ) { case QMessageBox::Save: onSaveAs(); return true; case QMessageBox::Discard: return true; default: return false; } } case QMessageBox::Discard: return true; default: return false; } } else { return true; } } void VisualizationFrame::onOpen() { manager_->stopUpdate(); QString filename = QFileDialog::getOpenFileName( this, "Choose a file to open", QString::fromStdString( last_config_dir_ ), "RViz config files (" CONFIG_EXTENSION_WILDCARD ")" ); manager_->startUpdate(); if( !filename.isEmpty() ) { std::string path = filename.toStdString(); if( !fs::exists( path )) { QString message = filename + " does not exist!"; QMessageBox::critical( this, "Config file does not exist", message ); return; } loadDisplayConfig( filename ); } } void VisualizationFrame::onSave() { if( !initialized_ ) { return; } savePersistentSettings(); if( !saveDisplayConfig( QString::fromStdString( display_config_file_ ))) { manager_->stopUpdate(); QMessageBox box( this ); box.setWindowTitle( "Failed to save." ); box.setText( getErrorMessage() ); box.setInformativeText( QString::fromStdString( "Save copy of " + display_config_file_ + " to another file?" )); box.setStandardButtons( QMessageBox::Save | QMessageBox::Cancel ); box.setDefaultButton( QMessageBox::Save ); if( box.exec() == QMessageBox::Save ) { onSaveAs(); } manager_->startUpdate(); } } void VisualizationFrame::onSaveAs() { manager_->stopUpdate(); QString q_filename = QFileDialog::getSaveFileName( this, "Choose a file to save to", QString::fromStdString( last_config_dir_ ), "RViz config files (" CONFIG_EXTENSION_WILDCARD ")" ); manager_->startUpdate(); if( !q_filename.isEmpty() ) { std::string filename = q_filename.toStdString(); fs::path path( filename ); if( path.extension() != "." CONFIG_EXTENSION ) { filename += "." CONFIG_EXTENSION; } if( !saveDisplayConfig( QString::fromStdString( filename ))) { QMessageBox::critical( this, "Failed to save.", getErrorMessage() ); } markRecentConfig( filename ); last_config_dir_ = fs::path( filename ).parent_path().BOOST_FILE_STRING(); setDisplayConfigFile( filename ); } } void VisualizationFrame::onSaveImage() { ScreenshotDialog* dialog = new ScreenshotDialog( this, render_panel_, QString::fromStdString( last_image_dir_ )); connect( dialog, SIGNAL( savedInDirectory( const QString& )), this, SLOT( setImageSaveDirectory( const QString& ))); dialog->show(); } void VisualizationFrame::onRecentConfigSelected() { QAction* action = dynamic_cast( sender() ); if( action ) { std::string path = action->data().toString().toStdString(); if( !path.empty() ) { if( !fs::exists( path )) { QString message = QString::fromStdString( path ) + " does not exist!"; QMessageBox::critical( this, "Config file does not exist", message ); return; } loadDisplayConfig( QString::fromStdString( path )); } } } void VisualizationFrame::addTool( Tool* tool ) { QAction* action = new QAction( tool->getName(), toolbar_actions_ ); action->setIcon( tool->getIcon() ); action->setIconText( tool->getName() ); action->setCheckable( true ); toolbar_->insertAction( add_tool_action_, action ); action_to_tool_map_[ action ] = tool; tool_to_action_map_[ tool ] = action; remove_tool_menu_->addAction( tool->getName() ); } void VisualizationFrame::onToolbarActionTriggered( QAction* action ) { Tool* tool = action_to_tool_map_[ action ]; if( tool ) { manager_->getToolManager()->setCurrentTool( tool ); } } void VisualizationFrame::onToolbarRemoveTool( QAction* remove_tool_menu_action ) { QString name = remove_tool_menu_action->text(); for( int i = 0; i < manager_->getToolManager()->numTools(); i++ ) { Tool* tool = manager_->getToolManager()->getTool( i ); if( tool->getName() == name ) { manager_->getToolManager()->removeTool( i ); return; } } } void VisualizationFrame::removeTool( Tool* tool ) { QAction* action = tool_to_action_map_[ tool ]; if( action ) { toolbar_actions_->removeAction( action ); toolbar_->removeAction( action ); tool_to_action_map_.erase( tool ); action_to_tool_map_.erase( action ); } QString tool_name = tool->getName(); QList remove_tool_actions = remove_tool_menu_->actions(); for( int i = 0; i < remove_tool_actions.size(); i++ ) { QAction* removal_action = remove_tool_actions.at( i ); if( removal_action->text() == tool_name ) { remove_tool_menu_->removeAction( removal_action ); break; } } } void VisualizationFrame::refreshTool( Tool* tool ) { QAction* action = tool_to_action_map_[ tool ]; action->setIcon( tool->getIcon() ); action->setIconText( tool->getName() ); } void VisualizationFrame::indicateToolIsCurrent( Tool* tool ) { QAction* action = tool_to_action_map_[ tool ]; if( action ) { action->setChecked( true ); } } void VisualizationFrame::showHelpPanel() { if( !show_help_action_ ) { QDockWidget* dock = addPanelByName( "Help", "rviz/Help" ); show_help_action_ = dock->toggleViewAction(); connect( dock, SIGNAL( destroyed( QObject* )), this, SLOT( onHelpDestroyed() )); } else { // show_help_action_ is a toggle action, so trigger() changes its // state. Therefore we must force it to the opposite state from // what we want before we call trigger(). (I think.) show_help_action_->setChecked( false ); show_help_action_->trigger(); } } void VisualizationFrame::onHelpDestroyed() { show_help_action_ = NULL; } void VisualizationFrame::onHelpWiki() { QDesktopServices::openUrl( QUrl( "http://www.ros.org/wiki/rviz" )); } void VisualizationFrame::onHelpAbout() { QString about_text = QString( "This is RViz version %1 (%2).\n" "\n" "Compiled against Qt version %3." "\n" "Compiled against OGRE version %4.%5.%6%7 (%8)." ) .arg(get_version().c_str()) .arg(get_distro().c_str()) .arg(QT_VERSION_STR) .arg(OGRE_VERSION_MAJOR) .arg(OGRE_VERSION_MINOR) .arg(OGRE_VERSION_PATCH) .arg(OGRE_VERSION_SUFFIX) .arg(OGRE_VERSION_NAME); QMessageBox::about(QApplication::activeWindow(), "About", about_text); } QWidget* VisualizationFrame::getParentWindow() { return this; } void VisualizationFrame::onDeletePanel() { // This should only be called as a SLOT from a QAction in the // "delete panel" submenu, so the sender will be one of the QActions // stored as "delete_action" in a PanelRecord. This code looks for // a delete_action in custom_panels_ matching sender() and removes // the panel associated with it. if( QAction* action = qobject_cast( sender() )) { for( int i = 0; i < custom_panels_.size(); i++ ) { if( custom_panels_[ i ].delete_action == action ) { delete custom_panels_[ i ].dock; custom_panels_.removeAt( i ); setDisplayConfigModified(); action->deleteLater(); if( delete_view_menu_->actions().size() == 1 && delete_view_menu_->actions().first() == action ) { delete_view_menu_->setEnabled( false ); } return; } } } } QDockWidget* VisualizationFrame::addPanelByName( const QString& name, const QString& class_id, Qt::DockWidgetArea area, bool floating ) { QString error; Panel* panel = panel_factory_->make( class_id, &error ); if( !panel ) { panel = new FailedPanel( class_id, error ); } panel->setName( name ); connect( panel, SIGNAL( configChanged() ), this, SLOT( setDisplayConfigModified() )); PanelRecord record; record.dock = addPane( name, panel, area, floating ); record.panel = panel; record.name = name; record.delete_action = delete_view_menu_->addAction( name, this, SLOT( onDeletePanel() )); custom_panels_.append( record ); delete_view_menu_->setEnabled( true ); record.panel->initialize( manager_ ); record.dock->setIcon( panel_factory_->getIcon( class_id ) ); return record.dock; } PanelDockWidget* VisualizationFrame::addPane( const QString& name, QWidget* panel, Qt::DockWidgetArea area, bool floating ) { PanelDockWidget *dock; dock = new PanelDockWidget( name ); dock->setContentWidget( panel ); dock->setFloating( floating ); dock->setObjectName( name ); // QMainWindow::saveState() needs objectName to be set. addDockWidget( area, dock ); // we want to know when that panel becomes visible connect( dock, SIGNAL( visibilityChanged( bool )), this, SLOT( onDockPanelVisibilityChange( bool ) )); QAction* toggle_action = dock->toggleViewAction(); view_menu_->addAction( toggle_action ); connect( toggle_action, SIGNAL( triggered( bool )), this, SLOT( setDisplayConfigModified() )); connect( dock, SIGNAL( closed()), this, SLOT( setDisplayConfigModified() )); dock->installEventFilter( geom_change_detector_ ); // repair/update visibility status hideLeftDock( area == Qt::LeftDockWidgetArea ? false : hide_left_dock_button_->isChecked() ); hideRightDock( area == Qt::RightDockWidgetArea ? false : hide_right_dock_button_->isChecked() ); return dock; } } // end namespace rviz rviz-1.12.4/src/rviz/visualization_frame.h000066400000000000000000000265721300447110700206070ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_VISUALIZATION_FRAME_H #define RVIZ_VISUALIZATION_FRAME_H #include #include #include #include #include "rviz/config.h" #include "rviz/window_manager_interface.h" #include "rviz/panel.h" #include class QSplashScreen; class QAction; class QActionGroup; class QTimer; class QDockWidget; class QLabel; class QToolButton; namespace rviz { class PanelFactory; class RenderPanel; class VisualizationManager; class Tool; class WidgetGeometryChangeDetector; /** @brief The main rviz window. * * VisualizationFrame is a QMainWindow, which means it has a center * area and a bunch of dock areas around it. The central widget here * is a RenderPanel, and around it (by default) are a DisplaysPanel, * ViewsPanel, TimePanel, SelectionPanel, and ToolPropertiesPanel. At * the top is a toolbar with "Move Camera", "Select", etc. There is * also a menu bar with file/open, etc. */ class VisualizationFrame : public QMainWindow, public WindowManagerInterface { Q_OBJECT public: VisualizationFrame( QWidget* parent = 0 ); ~VisualizationFrame(); void setApp( QApplication * app ); /** @brief Call this @e before initialize() to have it take effect. */ void setShowChooseNewMaster( bool show ); /** @brief Set the path to the help file. Should contain HTML. * Default is a file in the RViz package. */ void setHelpPath( const QString& help_path ); /** @brief Set the path to the "splash" image file. This image is * shown during initialization and loading of the first config file. * Default is a file in the RViz package. To prevent splash image * from showing, set this to an empty string. */ void setSplashPath( const QString& splash_path ); /** @brief Initialize the visualizer. Creates the VisualizationManager. * * This function must be called before load(), save(), getManager(), * or addPanelByName(), since it creates the VisualizationManager * instance which those calls depend on. * * This function also calls VisualizationManager::initialize(), * which means it will start the update timer and generally get * things rolling. */ void initialize( const QString& display_config_file = "" ); VisualizationManager* getManager() { return manager_; } // overrides from WindowManagerInterface virtual QWidget* getParentWindow(); virtual PanelDockWidget* addPane( const QString& name, QWidget* panel, Qt::DockWidgetArea area = Qt::LeftDockWidgetArea, bool floating = true ); /** @brief Load the "general" config file, which has just the few * things which should not be saved with a display config. * * Loads from the file named in persistent_settings_file_. */ void loadPersistentSettings(); /** @brief Save the "general" config file, which has just the few * things which should not be saved with a display config. * * Saves to the file named in persistent_settings_file_. */ void savePersistentSettings(); /** @brief Load display and other settings from the given file. * @param path The full path of the config file to load from. */ void loadDisplayConfig( const QString& path ); /** @brief Save display and other settings to the given file. * @param path The full path of the config file to save into. * @return True on success, False on failure. * * On failure, also sets error_message_ with information about the * problem. Can be retrieved with getErrorMessage(). */ bool saveDisplayConfig( const QString& path ); QString getErrorMessage() const { return error_message_; } /** @brief Load the properties of all subsystems from the given Config. * * This is called by loadDisplayConfig(). * * @param config Must have type Config::Map. * @sa save() */ virtual void load( const Config& config ); /** @brief Save the properties of each subsystem and most editable rviz * data. * * This is called by saveDisplayConfig(). * * @param config The Config node to write into. * @sa load() */ virtual void save( Config config ); /** @brief Hide or show the hide-dock buttons. */ void setHideButtonVisibility( bool visible ); public Q_SLOTS: /** @brief Call this to let the frame know that something that would * get saved in the display config has changed. */ void setDisplayConfigModified(); /** Set the message displayed in the status bar */ virtual void setStatus( const QString & message ); Q_SIGNALS: /** @brief Emitted during file-loading and initialization to indicate progress. */ void statusUpdate( const QString& message ); protected Q_SLOTS: void onOpen(); void onSave(); void onSaveAs(); void onSaveImage(); void onRecentConfigSelected(); void onHelpWiki(); void onHelpAbout(); void openNewPanelDialog(); void openNewToolDialog(); void showHelpPanel(); /** @brief Remove a the tool whose name is given by remove_tool_menu_action->text(). */ void onToolbarRemoveTool( QAction* remove_tool_menu_action ); /** @brief Looks up the Tool for this action and calls * VisualizationManager::setCurrentTool(). */ void onToolbarActionTriggered( QAction* action ); /** @brief Add the given tool to this frame's toolbar. * * This creates a QAction internally which listens for the Tool's * shortcut key. When the action is triggered by the toolbar or by * the shortcut key, onToolbarActionTriggered() is called. */ void addTool( Tool* tool ); /** @brief Remove the given tool from the frame's toolbar. */ void removeTool( Tool* tool ); /** @brief Refresh the given tool in this frame's' toolbar. * * This will update the icon and the text of the corresponding QAction. */ void refreshTool( Tool* tool ); /** @brief Mark the given tool as the current one. * * This is purely a visual change in the GUI, it does not call any * tool functions. */ void indicateToolIsCurrent(Tool* tool); /** @brief Save the current state and quit with exit code 255 to * signal the wrapper that we would like to restart with a different * ROS master URI. */ void changeMaster(); /** @brief Delete a panel widget. * * The sender() of the signal should be a QAction whose text() is * the name of the panel. */ void onDeletePanel(); protected Q_SLOTS: /** @brief Set loading_ to false. */ void markLoadingDone(); /** @brief Set the default directory in which to save screenshot images. */ void setImageSaveDirectory( const QString& directory ); void reset(); void onHelpDestroyed(); void hideLeftDock( bool hide ); void hideRightDock( bool hide ); virtual void onDockPanelVisibilityChange( bool visible ); void updateFps(); protected: /** @brief Initialize the default config directory (~/.rviz) and set * up the persistent_settings_file_ and display_config_file_ * variables. */ void initConfigs(); void initMenus(); void initToolbars(); /** @brief Check for unsaved changes, prompt to save config, etc. * @return true if it is OK to exit, false if not. */ bool prepareToExit(); virtual void closeEvent( QCloseEvent* event ); virtual void leaveEvent ( QEvent * event ); void markRecentConfig(const std::string& path); void updateRecentConfigMenu(); QDockWidget* addPanelByName( const QString& name, const QString& class_lookup_name, Qt::DockWidgetArea area = Qt::LeftDockWidgetArea, bool floating = true ); /** @brief Loads custom panels from the given config node. */ void loadPanels( const Config& config ); /** @brief Saves custom panels to the given config node. */ void savePanels( Config config ); void loadWindowGeometry( const Config& config ); void saveWindowGeometry( Config config ); /** @brief Set the display config file path. * * This does not load the given file, it just sets the member * variable and updates the window title. */ void setDisplayConfigFile( const std::string& path ); void hideDockImpl( Qt::DockWidgetArea area, bool hide ); QApplication* app_; RenderPanel* render_panel_; QAction* show_help_action_; std::string config_dir_; std::string persistent_settings_file_; std::string display_config_file_; std::string default_display_config_file_; std::string last_config_dir_; std::string last_image_dir_; std::string home_dir_; QMenu* file_menu_; QMenu* recent_configs_menu_; QMenu* view_menu_; QMenu* delete_view_menu_; QMenu* plugins_menu_; QList view_menu_actions_; QToolBar* toolbar_; VisualizationManager* manager_; std::string package_path_; QString help_path_; QString splash_path_; QSplashScreen* splash_; typedef std::deque D_string; D_string recent_configs_; QActionGroup* toolbar_actions_; std::map action_to_tool_map_; std::map tool_to_action_map_; bool show_choose_new_master_option_; QToolButton* hide_left_dock_button_; QToolButton* hide_right_dock_button_; PanelFactory* panel_factory_; struct PanelRecord { Panel* panel; PanelDockWidget* dock; QString name; QString class_id; QAction* delete_action; }; QList custom_panels_; QAction* add_tool_action_; QMenu* remove_tool_menu_; bool initialized_; WidgetGeometryChangeDetector* geom_change_detector_; bool loading_; ///< True just when loading a display config file, false all other times. QTimer* post_load_timer_; ///< Single-shot timer for calling postLoad() a short time after loadDisplayConfig() finishes. QLabel* status_label_; QLabel* fps_label_; QStatusBar* original_status_bar_; int frame_count_; ros::WallTime last_fps_calc_time_; QString error_message_; ///< Error message (if any) from most recent saveDisplayConfig() call. }; } #endif // RVIZ_VISUALIZATION_FRAME_H rviz-1.12.4/src/rviz/visualization_manager.cpp000066400000000000000000000414571300447110700214610ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rviz/display.h" #include "rviz/display_factory.h" #include "rviz/display_group.h" #include "rviz/displays_panel.h" #include "rviz/frame_manager.h" #include "rviz/ogre_helpers/qt_ogre_render_window.h" #include "rviz/properties/color_property.h" #include "rviz/properties/parse_color.h" #include "rviz/properties/property.h" #include "rviz/properties/property_tree_model.h" #include "rviz/properties/status_list.h" #include "rviz/properties/tf_frame_property.h" #include "rviz/properties/int_property.h" #include "rviz/render_panel.h" #include "rviz/selection/selection_manager.h" #include "rviz/tool.h" #include "rviz/tool_manager.h" #include "rviz/viewport_mouse_event.h" #include "rviz/view_controller.h" #include "rviz/view_manager.h" #include "rviz/load_resource.h" #include "rviz/ogre_helpers/ogre_render_queue_clearer.h" #include "rviz/ogre_helpers/render_system.h" #include "rviz/visualization_manager.h" #include "rviz/window_manager_interface.h" namespace rviz { //helper class needed to display an icon besides "Global Options" class IconizedProperty: public Property { public: IconizedProperty( const QString& name = QString(), const QVariant default_value = QVariant(), const QString& description = QString(), Property* parent = 0, const char *changed_slot = 0, QObject* receiver = 0 ) :Property( name, default_value, description, parent, changed_slot, receiver ) {}; virtual QVariant getViewData( int column, int role ) const { return (column == 0 && role == Qt::DecorationRole) ? icon_ : Property::getViewData(column,role); } void setIcon( QIcon icon ) { icon_=icon; } private: QIcon icon_; }; class VisualizationManagerPrivate { public: ros::CallbackQueue threaded_queue_; boost::thread_group threaded_queue_threads_; ros::NodeHandle update_nh_; ros::NodeHandle threaded_nh_; boost::mutex render_mutex_; }; VisualizationManager::VisualizationManager( RenderPanel* render_panel, WindowManagerInterface* wm, boost::shared_ptr tf ) : ogre_root_( Ogre::Root::getSingletonPtr() ) , update_timer_(0) , shutting_down_(false) , render_panel_( render_panel ) , time_update_timer_(0.0f) , frame_update_timer_(0.0f) , render_requested_(1) , frame_count_(0) , window_manager_(wm) , private_( new VisualizationManagerPrivate ) { // visibility_bit_allocator_ is listed after default_visibility_bit_ (and thus initialized later be default): default_visibility_bit_ = visibility_bit_allocator_.allocBit(); frame_manager_ = new FrameManager(tf); render_panel->setAutoRender(false); private_->threaded_nh_.setCallbackQueue(&private_->threaded_queue_); scene_manager_ = ogre_root_->createSceneManager( Ogre::ST_GENERIC ); rviz::RenderSystem::RenderSystem::get()->prepareOverlays(scene_manager_); directional_light_ = scene_manager_->createLight( "MainDirectional" ); directional_light_->setType( Ogre::Light::LT_DIRECTIONAL ); directional_light_->setDirection( Ogre::Vector3( -1, 0, -1 ) ); directional_light_->setDiffuseColour( Ogre::ColourValue( 1.0f, 1.0f, 1.0f ) ); root_display_group_ = new DisplayGroup(); root_display_group_->setName( "root" ); display_property_tree_model_ = new PropertyTreeModel( root_display_group_ ); display_property_tree_model_->setDragDropClass( "display" ); connect( display_property_tree_model_, SIGNAL( configChanged() ), this, SIGNAL( configChanged() )); tool_manager_ = new ToolManager( this ); connect( tool_manager_, SIGNAL( configChanged() ), this, SIGNAL( configChanged() )); connect( tool_manager_, SIGNAL( toolChanged( Tool* ) ), this, SLOT( onToolChanged( Tool* ) )); view_manager_ = new ViewManager( this ); view_manager_->setRenderPanel( render_panel_ ); connect( view_manager_, SIGNAL( configChanged() ), this, SIGNAL( configChanged() )); IconizedProperty* ip = new IconizedProperty( "Global Options", QVariant(), "", root_display_group_ ); ip->setIcon( loadPixmap("package://rviz/icons/options.png") ); global_options_ = ip; fixed_frame_property_ = new TfFrameProperty( "Fixed Frame", "/map", "Frame into which all data is transformed before being displayed.", global_options_, frame_manager_, false, SLOT( updateFixedFrame() ), this ); background_color_property_ = new ColorProperty( "Background Color", QColor(48,48,48), "Background color for the 3D view.", global_options_, SLOT( updateBackgroundColor() ), this ); fps_property_ = new IntProperty( "Frame Rate", 30, "RViz will try to render this many frames per second.", global_options_, SLOT( updateFps() ), this ); root_display_group_->initialize( this ); // only initialize() a Display after its sub-properties are created. root_display_group_->setEnabled( true ); updateFixedFrame(); updateBackgroundColor(); global_status_ = new StatusList( "Global Status", root_display_group_ ); createColorMaterials(); selection_manager_ = new SelectionManager(this); private_->threaded_queue_threads_.create_thread(boost::bind(&VisualizationManager::threadedQueueThreadFunc, this)); display_factory_ = new DisplayFactory(); ogre_render_queue_clearer_ = new OgreRenderQueueClearer(); Ogre::Root::getSingletonPtr()->addFrameListener( ogre_render_queue_clearer_ ); update_timer_ = new QTimer; connect( update_timer_, SIGNAL( timeout() ), this, SLOT( onUpdate() )); } VisualizationManager::~VisualizationManager() { delete update_timer_; shutting_down_ = true; private_->threaded_queue_threads_.join_all(); if(selection_manager_) { selection_manager_->setSelection(M_Picked()); } delete display_property_tree_model_; delete tool_manager_; delete display_factory_; delete selection_manager_; if(ogre_root_) { ogre_root_->destroySceneManager( scene_manager_ ); } delete frame_manager_; delete private_; Ogre::Root::getSingletonPtr()->removeFrameListener( ogre_render_queue_clearer_ ); delete ogre_render_queue_clearer_; } void VisualizationManager::initialize() { emitStatusUpdate( "Initializing managers." ); view_manager_->initialize(); selection_manager_->initialize(); tool_manager_->initialize(); last_update_ros_time_ = ros::Time::now(); last_update_wall_time_ = ros::WallTime::now(); } ros::CallbackQueueInterface* VisualizationManager::getThreadedQueue() { return &private_->threaded_queue_; } void VisualizationManager::lockRender() { private_->render_mutex_.lock(); } void VisualizationManager::unlockRender() { private_->render_mutex_.unlock(); } ros::CallbackQueueInterface* VisualizationManager::getUpdateQueue() { return ros::getGlobalCallbackQueue(); } void VisualizationManager::startUpdate() { float interval = 1000.0 / float(fps_property_->getInt()); update_timer_->start( interval ); } void VisualizationManager::stopUpdate() { update_timer_->stop(); } void createColorMaterial(const std::string& name, const Ogre::ColourValue& color, bool use_self_illumination) { Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create( name, ROS_PACKAGE_NAME ); mat->setAmbient(color * 0.5f); mat->setDiffuse(color); if( use_self_illumination ) { mat->setSelfIllumination(color); } mat->setLightingEnabled(true); mat->setReceiveShadows(false); } void VisualizationManager::createColorMaterials() { createColorMaterial("RVIZ/Red", Ogre::ColourValue(1.0f, 0.0f, 0.0f, 1.0f), true); createColorMaterial("RVIZ/Green", Ogre::ColourValue(0.0f, 1.0f, 0.0f, 1.0f), true); createColorMaterial("RVIZ/Blue", Ogre::ColourValue(0.0f, 0.0f, 1.0f, 1.0f), true); createColorMaterial("RVIZ/Cyan", Ogre::ColourValue(0.0f, 1.0f, 1.0f, 1.0f), true); createColorMaterial("RVIZ/ShadedRed", Ogre::ColourValue(1.0f, 0.0f, 0.0f, 1.0f), false); createColorMaterial("RVIZ/ShadedGreen", Ogre::ColourValue(0.0f, 1.0f, 0.0f, 1.0f), false); createColorMaterial("RVIZ/ShadedBlue", Ogre::ColourValue(0.0f, 0.0f, 1.0f, 1.0f), false); createColorMaterial("RVIZ/ShadedCyan", Ogre::ColourValue(0.0f, 1.0f, 1.0f, 1.0f), false); } void VisualizationManager::queueRender() { render_requested_ = 1; } void VisualizationManager::onUpdate() { ros::WallDuration wall_diff = ros::WallTime::now() - last_update_wall_time_; ros::Duration ros_diff = ros::Time::now() - last_update_ros_time_; float wall_dt = wall_diff.toSec(); float ros_dt = ros_diff.toSec(); last_update_ros_time_ = ros::Time::now(); last_update_wall_time_ = ros::WallTime::now(); if(ros_dt < 0.0) { resetTime(); } ros::spinOnce(); Q_EMIT preUpdate(); frame_manager_->update(); root_display_group_->update( wall_dt, ros_dt ); view_manager_->update(wall_dt, ros_dt); time_update_timer_ += wall_dt; if( time_update_timer_ > 0.1f ) { time_update_timer_ = 0.0f; updateTime(); } frame_update_timer_ += wall_dt; if(frame_update_timer_ > 1.0f) { frame_update_timer_ = 0.0f; updateFrames(); } selection_manager_->update(); if( tool_manager_->getCurrentTool() ) { tool_manager_->getCurrentTool()->update(wall_dt, ros_dt); } if ( view_manager_ && view_manager_->getCurrent() && view_manager_->getCurrent()->getCamera() ) { directional_light_->setDirection(view_manager_->getCurrent()->getCamera()->getDerivedDirection()); } frame_count_++; if ( render_requested_ || wall_dt > 0.01 ) { render_requested_ = 0; boost::mutex::scoped_lock lock(private_->render_mutex_); ogre_root_->renderOneFrame(); } } void VisualizationManager::updateTime() { if( ros_time_begin_.isZero() ) { ros_time_begin_ = ros::Time::now(); } ros_time_elapsed_ = ros::Time::now() - ros_time_begin_; if( wall_clock_begin_.isZero() ) { wall_clock_begin_ = ros::WallTime::now(); } wall_clock_elapsed_ = ros::WallTime::now() - wall_clock_begin_; } void VisualizationManager::updateFrames() { typedef std::vector V_string; V_string frames; frame_manager_->getTFClient()->getFrameStrings( frames ); // Check the fixed frame to see if it's ok std::string error; if( frame_manager_->frameHasProblems( getFixedFrame().toStdString(), ros::Time(), error )) { if( frames.empty() ) { // fixed_prop->setToWarn(); std::stringstream ss; ss << "No tf data. Actual error: " << error; global_status_->setStatus( StatusProperty::Warn, "Fixed Frame", QString::fromStdString( ss.str() )); } else { // fixed_prop->setToError(); global_status_->setStatus( StatusProperty::Error, "Fixed Frame", QString::fromStdString( error )); } } else { // fixed_prop->setToOK(); global_status_->setStatus( StatusProperty::Ok, "Fixed Frame", "OK" ); } } tf::TransformListener* VisualizationManager::getTFClient() const { return frame_manager_->getTFClient(); } void VisualizationManager::resetTime() { root_display_group_->reset(); frame_manager_->getTFClient()->clear(); ros_time_begin_ = ros::Time(); wall_clock_begin_ = ros::WallTime(); queueRender(); } void VisualizationManager::addDisplay( Display* display, bool enabled ) { root_display_group_->addDisplay( display ); display->initialize( this ); display->setEnabled( enabled ); } void VisualizationManager::removeAllDisplays() { root_display_group_->removeAllDisplays(); } void VisualizationManager::emitStatusUpdate( const QString& message ) { Q_EMIT statusUpdate( message ); } void VisualizationManager::load( const Config& config ) { stopUpdate(); emitStatusUpdate( "Creating displays" ); root_display_group_->load( config ); emitStatusUpdate( "Creating tools" ); tool_manager_->load( config.mapGetChild( "Tools" )); emitStatusUpdate( "Creating views" ); view_manager_->load( config.mapGetChild( "Views" )); startUpdate(); } void VisualizationManager::save( Config config ) const { root_display_group_->save( config ); tool_manager_->save( config.mapMakeChild( "Tools" )); view_manager_->save( config.mapMakeChild( "Views" )); } Display* VisualizationManager::createDisplay( const QString& class_lookup_name, const QString& name, bool enabled ) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); Display* new_display = root_display_group_->createDisplay( class_lookup_name ); addDisplay( new_display, enabled ); new_display->setName( name ); QApplication::restoreOverrideCursor(); return new_display; } double VisualizationManager::getWallClock() { return ros::WallTime::now().toSec(); } double VisualizationManager::getROSTime() { return frame_manager_->getTime().toSec(); } double VisualizationManager::getWallClockElapsed() { return wall_clock_elapsed_.toSec(); } double VisualizationManager::getROSTimeElapsed() { return (frame_manager_->getTime() - ros_time_begin_).toSec(); } void VisualizationManager::updateBackgroundColor() { render_panel_->setBackgroundColor( qtToOgre( background_color_property_->getColor() )); queueRender(); } void VisualizationManager::updateFps() { if ( update_timer_->isActive() ) { startUpdate(); } } void VisualizationManager::handleMouseEvent( const ViewportMouseEvent& vme ) { //process pending mouse events Tool* current_tool = tool_manager_->getCurrentTool(); int flags = 0; if( current_tool ) { ViewportMouseEvent _vme = vme; flags = current_tool->processMouseEvent( _vme ); vme.panel->setCursor( current_tool->getCursor() ); } else { vme.panel->setCursor( QCursor( Qt::ArrowCursor ) ); } if( flags & Tool::Render ) { queueRender(); } if( flags & Tool::Finished ) { tool_manager_->setCurrentTool( tool_manager_->getDefaultTool() ); } } void VisualizationManager::handleChar( QKeyEvent* event, RenderPanel* panel ) { tool_manager_->handleChar( event, panel ); } void VisualizationManager::threadedQueueThreadFunc() { while (!shutting_down_) { private_->threaded_queue_.callOne(ros::WallDuration(0.1)); } } void VisualizationManager::notifyConfigChanged() { Q_EMIT configChanged(); } void VisualizationManager::onToolChanged( Tool* tool ) { } void VisualizationManager::updateFixedFrame() { QString frame = fixed_frame_property_->getFrame(); frame_manager_->setFixedFrame( frame.toStdString() ); root_display_group_->setFixedFrame( frame ); } QString VisualizationManager::getFixedFrame() const { return fixed_frame_property_->getFrame(); } void VisualizationManager::setFixedFrame( const QString& frame ) { fixed_frame_property_->setValue( frame ); } void VisualizationManager::setStatus( const QString & message ) { emitStatusUpdate( message ); } } // namespace rviz rviz-1.12.4/src/rviz/visualization_manager.h000066400000000000000000000310171300447110700211150ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_VISUALIZATION_MANAGER_H_ #define RVIZ_VISUALIZATION_MANAGER_H_ #include #include #include "rviz/bit_allocator.h" #include "rviz/config.h" #include "rviz/display_context.h" class QKeyEvent; class QTimer; namespace Ogre { class Root; class SceneManager; class SceneNode; class Light; } namespace ros { class CallbackQueueInterface; } namespace tf { class TransformListener; } namespace rviz { class ColorProperty; class Display; class DisplayFactory; class DisplayGroup; class FrameManager; class Property; class IntProperty; class PropertyTreeModel; class RenderPanel; class SelectionManager; class StatusList; class TfFrameProperty; class ViewportMouseEvent; class WindowManagerInterface; class Tool; class OgreRenderQueueClearer; class VisualizationManagerPrivate; /** * \brief The VisualizationManager class is the central manager class * of rviz, holding all the Displays, Tools, ViewControllers, * and other managers. * * It keeps the current view controller for the main render window. * It has a timer which calls update() on all the displays. It * creates and holds pointers to the other manager objects: * SelectionManager, FrameManager, the PropertyManager s, and * Ogre::SceneManager. * * The "protected" members should probably all be "private", as * VisualizationManager is not intended to be subclassed. */ class VisualizationManager: public DisplayContext { Q_OBJECT public: /** * \brief Constructor * Creates managers and sets up global properties. * @param render_panel a pointer to the main render panel widget of the app. * @param wm a pointer to the window manager (which is really just a * VisualizationFrame, the top-level container widget of rviz). * @param tf a pointer to tf::TransformListener which will be internally used by FrameManager. */ VisualizationManager( RenderPanel* render_panel, WindowManagerInterface* wm = 0, boost::shared_ptr tf = boost::shared_ptr() ); /** * \brief Destructor * Stops update timers and destroys all displays, tools, and managers. */ virtual ~VisualizationManager(); /** * \brief Do initialization that wasn't done in constructor. * Initializes tool manager, view manager, selection manager. */ void initialize(); /** * \brief Start timers. * Creates and starts the update and idle timers, both set to 30Hz (33ms). */ void startUpdate(); /* * \brief Stop the update timers. No Displays will be updated and no ROS * callbacks will be called during this period. */ void stopUpdate(); /** * \brief Create and add a display to this panel, by class lookup name * @param class_lookup_name "lookup name" of the Display subclass, for pluginlib. * Should be of the form "packagename/displaynameofclass", like "rviz/Image". * @param name The name of this display instance shown on the GUI, like "Left arm camera". * @param enabled Whether to start enabled * @return A pointer to the new display. */ Display* createDisplay( const QString& class_lookup_name, const QString& name, bool enabled ); /** * \brief Add a display to be managed by this panel * @param display The display to be added */ void addDisplay( Display* display, bool enabled ); /** * \brief Remove and delete all displays */ void removeAllDisplays(); /** @brief Load the properties of each Display and most editable rviz data. * * This is what is called when loading a "*.rviz" file. * * @param config The Config object to read from. Expected to be a Config::Map type. * @sa save() */ void load( const Config& config ); /** * \brief Save the properties of each Display and most editable rviz * data. * * This is what is called when saving a "*.vcg" file. * \param config The object to write to. * \sa loadDisplayConfig() */ void save( Config config ) const; /** @brief Return the fixed frame name. * @sa setFixedFrame() */ QString getFixedFrame() const; /** @brief Set the coordinate frame we should be transforming all fixed data into. * @param frame The name of the frame -- must match the frame name broadcast to libTF * @sa getFixedFrame() */ void setFixedFrame( const QString& frame ); /** * @brief Convenience function: returns getFrameManager()->getTFClient(). */ tf::TransformListener* getTFClient() const; /** * @brief Returns the Ogre::SceneManager used for the main RenderPanel. */ Ogre::SceneManager* getSceneManager() const { return scene_manager_; } /** * @brief Return the main RenderPanel. */ RenderPanel* getRenderPanel() const { return render_panel_; } /** * @brief Return the wall clock time, in seconds since 1970. */ double getWallClock(); /** * @brief Return the ROS time, in seconds. */ double getROSTime(); /** * @brief Return the wall clock time in seconds since the last reset. */ double getWallClockElapsed(); /** * @brief Return the ROS time in seconds since the last reset. */ double getROSTimeElapsed(); /** * @brief Handle a single key event for a given RenderPanel. * * If the key is Escape, switches to the default Tool (via * getDefaultTool()). All other key events are passed to the * current Tool (via getCurrentTool()). */ void handleChar( QKeyEvent* event, RenderPanel* panel ); /** * @brief Handle a mouse event. * * This just copies the given event into an event queue. The events * in the queue are processed by onUpdate() which is called from the * main thread by a timer every 33ms. */ void handleMouseEvent( const ViewportMouseEvent& event ); /** * @brief Resets the wall and ROS elapsed time to zero and calls resetDisplays(). */ void resetTime(); /** * @brief Return a pointer to the SelectionManager. */ SelectionManager* getSelectionManager() const { return selection_manager_; } /** @brief Return a pointer to the ToolManager. */ virtual ToolManager* getToolManager() const { return tool_manager_; } /** @brief Return a pointer to the ViewManager. */ virtual ViewManager* getViewManager() const { return view_manager_; } /** * @brief Lock a mutex to delay calls to Ogre::Root::renderOneFrame(). */ void lockRender(); /** * @brief Unlock a mutex, allowing calls to Ogre::Root::renderOneFrame(). */ void unlockRender(); /** * \brief Queues a render. Multiple calls before a render happens will only cause a single render. * \note This function can be called from any thread. */ void queueRender(); /** * @brief Return the window manager, if any. */ WindowManagerInterface* getWindowManager() const { return window_manager_; } /** * @brief Return the CallbackQueue using the main GUI thread. */ ros::CallbackQueueInterface* getUpdateQueue(); /** * @brief Return a CallbackQueue using a different thread than the main GUI one. */ ros::CallbackQueueInterface* getThreadedQueue(); /** @brief Return the FrameManager instance. */ FrameManager* getFrameManager() const { return frame_manager_; } /** @brief Return the current value of the frame count. * * The frame count is just a number which increments each time a * frame is rendered. This lets clients check if a new frame has * been rendered since the last time they did something. */ uint64_t getFrameCount() const { return frame_count_; } /** @brief Notify this VisualizationManager that something about its * display configuration has changed. */ void notifyConfigChanged(); /** @brief Return a factory for creating Display subclasses based on a class id string. */ virtual DisplayFactory* getDisplayFactory() const { return display_factory_; } PropertyTreeModel* getDisplayTreeModel() const { return display_property_tree_model_; } /** @brief Emits statusUpdate() signal with the given @a message. */ void emitStatusUpdate( const QString& message ); virtual DisplayGroup* getRootDisplayGroup() const { return root_display_group_; } virtual uint32_t getDefaultVisibilityBit() const { return default_visibility_bit_; } virtual BitAllocator* visibilityBits() { return &visibility_bit_allocator_; } virtual void setStatus( const QString & message ); virtual void setHelpPath( const QString& help_path ) { help_path_ = help_path; } virtual QString getHelpPath() const { return help_path_; } Q_SIGNALS: /** @brief Emitted before updating all Displays */ void preUpdate(); /** @brief Emitted whenever the display configuration changes. */ void configChanged(); /** @brief Emitted during file-loading and initialization to indicate progress. */ void statusUpdate( const QString& message ); protected Q_SLOTS: /** @brief Call update() on all managed objects. * * This is the central place where update() is called on most rviz * objects. Display objects, the FrameManager, the current * ViewController, the SelectionManager, PropertyManager. Also * calls ros::spinOnce(), so any callbacks on the global * CallbackQueue get called from here as well. * * It is called at 30Hz from the update timer. */ void onUpdate(); void onToolChanged( Tool* ); protected: void updateTime(); void updateFrames(); void createColorMaterials(); void threadedQueueThreadFunc(); Ogre::Root* ogre_root_; ///< Ogre Root Ogre::SceneManager* scene_manager_; ///< Ogre scene manager associated with this panel QTimer* update_timer_; ///< Update timer. Display::update is called on each display whenever this timer fires ros::Time last_update_ros_time_; ///< Update stopwatch. Stores how long it's been since the last update ros::WallTime last_update_wall_time_; volatile bool shutting_down_; PropertyTreeModel* display_property_tree_model_; DisplayGroup* root_display_group_; ToolManager* tool_manager_; ViewManager* view_manager_; Property* global_options_; TfFrameProperty* fixed_frame_property_; ///< Frame to transform fixed data to StatusList* global_status_; IntProperty* fps_property_; RenderPanel* render_panel_; ros::WallTime wall_clock_begin_; ros::Time ros_time_begin_; ros::WallDuration wall_clock_elapsed_; ros::Duration ros_time_elapsed_; ColorProperty* background_color_property_; float time_update_timer_; float frame_update_timer_; SelectionManager* selection_manager_; uint32_t render_requested_; uint64_t frame_count_; WindowManagerInterface* window_manager_; FrameManager* frame_manager_; OgreRenderQueueClearer* ogre_render_queue_clearer_; private Q_SLOTS: void updateFixedFrame(); void updateBackgroundColor(); void updateFps(); private: DisplayFactory* display_factory_; VisualizationManagerPrivate* private_; uint32_t default_visibility_bit_; BitAllocator visibility_bit_allocator_; QString help_path_; Ogre::Light* directional_light_; }; } #endif /* RVIZ_VISUALIZATION_MANAGER_H_ */ rviz-1.12.4/src/rviz/visualizer_app.cpp000066400000000000000000000230061300447110700201110ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #ifdef Q_OS_MAC #include // Apparently OSX #defines 'check' to be an empty string somewhere. // That was fun to figure out. #undef check #endif #include #include #include "rviz/selection/selection_manager.h" #include "rviz/env_config.h" #include "rviz/ogre_helpers/ogre_logging.h" #include "rviz/visualization_frame.h" #include "rviz/visualization_manager.h" #include "rviz/wait_for_master_dialog.h" #include "rviz/ogre_helpers/render_system.h" #include "rviz/visualizer_app.h" #define CATCH_EXCEPTIONS 0 namespace po = boost::program_options; namespace rviz { bool reloadShaders(std_srvs::Empty::Request&, std_srvs::Empty::Response&) { ROS_INFO("Reloading materials."); { Ogre::ResourceManager::ResourceMapIterator it = Ogre::MaterialManager::getSingleton().getResourceIterator(); while (it.hasMoreElements()) { Ogre::ResourcePtr resource = it.getNext(); resource->reload(); } } ROS_INFO("Reloading high-level gpu shaders."); { Ogre::ResourceManager::ResourceMapIterator it = Ogre::HighLevelGpuProgramManager::getSingleton().getResourceIterator(); while (it.hasMoreElements()) { Ogre::ResourcePtr resource = it.getNext(); resource->reload(); } } ROS_INFO("Reloading gpu shaders."); { Ogre::ResourceManager::ResourceMapIterator it = Ogre::GpuProgramManager::getSingleton().getResourceIterator(); while (it.hasMoreElements()) { Ogre::ResourcePtr resource = it.getNext(); resource->reload(); } } return true; } VisualizerApp::VisualizerApp() : app_( 0 ) , continue_timer_( 0 ) , frame_( 0 ) { } void VisualizerApp::setApp( QApplication * app ) { app_ = app; } bool VisualizerApp::init( int argc, char** argv ) { ROS_INFO( "rviz version %s", get_version().c_str() ); ROS_INFO( "compiled against Qt version " QT_VERSION_STR ); ROS_INFO( "compiled against OGRE version %d.%d.%d%s (%s)", OGRE_VERSION_MAJOR, OGRE_VERSION_MINOR, OGRE_VERSION_PATCH, OGRE_VERSION_SUFFIX, OGRE_VERSION_NAME ); #ifdef Q_OS_MAC ProcessSerialNumber PSN; GetCurrentProcess(&PSN); TransformProcessType(&PSN,kProcessTransformToForegroundApplication); SetFrontProcess(&PSN); #endif #if CATCH_EXCEPTIONS try { #endif ros::init( argc, argv, "rviz", ros::init_options::AnonymousName ); startContinueChecker(); po::options_description options; options.add_options() ("help,h", "Produce this help message") ("splash-screen,s", po::value(), "A custom splash-screen image to display") ("help-file", po::value(), "A custom html file to show as the help screen") ("display-config,d", po::value(), "A display config file (.rviz) to load") ("fixed-frame,f", po::value(), "Set the fixed frame") ("ogre-log,l", "Enable the Ogre.log file (output in cwd) and console output.") ("in-mc-wrapper", "Signal that this is running inside a master-chooser wrapper") ("opengl", po::value(), "Force OpenGL version (use '--opengl 210' for OpenGL 2.1 compatibility mode)") ("disable-anti-aliasing", "Prevent rviz from trying to use anti-aliasing when rendering.") ("no-stereo", "Disable the use of stereo rendering.") ("verbose,v", "Enable debug visualizations") ("log-level-debug", "Sets the ROS logger level to debug."); po::variables_map vm; std::string display_config, fixed_frame, splash_path, help_path; bool enable_ogre_log = false; bool in_mc_wrapper = false; bool verbose = false; int force_gl_version = 0; bool disable_anti_aliasing = false; bool disable_stereo = false; try { po::store( po::parse_command_line( argc, argv, options ), vm ); po::notify( vm ); if( vm.count( "help" )) { std::cout << "rviz command line options:\n" << options; return false; } if( vm.count( "in-mc-wrapper" )) { in_mc_wrapper = true; } if (vm.count("display-config")) { display_config = vm["display-config"].as(); if( display_config.substr( display_config.size() - 4, 4 ) == ".vcg" ) { std::cerr << "ERROR: the config file '" << display_config << "' is a .vcg file, which is the old rviz config format." << std::endl; std::cerr << " New config files have a .rviz extension and use YAML formatting. The format changed" << std::endl; std::cerr << " between Fuerte and Groovy. There is not (yet) an automated conversion program." << std::endl; return false; } } if (vm.count("splash-screen")) { splash_path = vm["splash-screen"].as(); } if (vm.count("help-file")) { help_path = vm["help-file"].as(); } if (vm.count("fixed-frame")) { fixed_frame = vm["fixed-frame"].as(); } if (vm.count("ogre-log")) { enable_ogre_log = true; } if (vm.count("no-stereo")) { disable_stereo = true; } if (vm.count("opengl")) { //std::cout << vm["opengl"].as() << std::endl; force_gl_version = vm["opengl"].as(); } if (vm.count("disable-anti-aliasing")) { disable_anti_aliasing = true; } if (vm.count("verbose")) { verbose = true; } if (vm.count("log-level-debug")) { if( ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug) ) { ros::console::notifyLoggerLevelsChanged(); } } } catch (std::exception& e) { ROS_ERROR("Error parsing command line: %s", e.what()); return false; } if( !ros::master::check() ) { WaitForMasterDialog* dialog = new WaitForMasterDialog; if( dialog->exec() != QDialog::Accepted ) { return false; } } nh_.reset( new ros::NodeHandle ); if( enable_ogre_log ) { OgreLogging::useRosLog(); } if ( force_gl_version ) { RenderSystem::forceGlVersion( force_gl_version ); } if (disable_anti_aliasing) { RenderSystem::disableAntiAliasing(); } if ( disable_stereo ) { RenderSystem::forceNoStereo(); } frame_ = new VisualizationFrame(); frame_->setApp( this->app_ ); if( help_path != "" ) { frame_->setHelpPath( QString::fromStdString( help_path )); } frame_->setShowChooseNewMaster( in_mc_wrapper ); if( vm.count("splash-screen") ) { frame_->setSplashPath( QString::fromStdString( splash_path )); } frame_->initialize( QString::fromStdString( display_config )); if( !fixed_frame.empty() ) { frame_->getManager()->setFixedFrame( QString::fromStdString( fixed_frame )); } frame_->getManager()->getSelectionManager()->setDebugMode( verbose ); frame_->show(); ros::NodeHandle private_nh("~"); reload_shaders_service_ = private_nh.advertiseService("reload_shaders", reloadShaders); #if CATCH_EXCEPTIONS } catch (std::exception& e) { ROS_ERROR("Caught exception while loading: %s", e.what()); return false; } #endif return true; } VisualizerApp::~VisualizerApp() { delete continue_timer_; delete frame_; } void VisualizerApp::startContinueChecker() { continue_timer_ = new QTimer( this ); connect( continue_timer_, SIGNAL( timeout() ), this, SLOT( checkContinue() )); continue_timer_->start( 100 ); } void VisualizerApp::checkContinue() { if( !ros::ok() ) { if( frame_ ) { // Make sure the window doesn't ask if we want to save first. frame_->setWindowModified( false ); } QApplication::closeAllWindows(); } } } // namespace rviz rviz-1.12.4/src/rviz/visualizer_app.h000066400000000000000000000047301300447110700175610ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_VISUALIZER_APP_H #define RVIZ_VISUALIZER_APP_H #include #include #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include #endif class QTimer; namespace rviz { class VisualizationFrame; class VisualizerApp: public QObject { Q_OBJECT public: VisualizerApp(); virtual ~VisualizerApp(); void setApp( QApplication * app ); /** Start everything. Pass in command line arguments. * @return false on failure, true on success. */ bool init( int argc, char** argv ); private Q_SLOTS: /** If ros::ok() is false, close all windows. */ void checkContinue(); private: void startContinueChecker(); QApplication* app_; QTimer* continue_timer_; VisualizationFrame* frame_; ros::NodeHandlePtr nh_; ros::ServiceServer reload_shaders_service_; }; } // end namespace rviz #endif // RVIZ_VISUALIZER_APP_H rviz-1.12.4/src/rviz/wait_for_master_dialog.cpp000066400000000000000000000047321300447110700215650ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ // Apparently OSX #defines 'check' to be an empty string somewhere. // That was fun to figure out. #ifdef check #undef check #endif #include #include #include "rviz/wait_for_master_dialog.h" namespace rviz { WaitForMasterDialog::WaitForMasterDialog( QWidget* parent ) : QMessageBox( parent ) { setIcon( QMessageBox::Critical ); const std::string& master_uri = ros::master::getURI(); std::stringstream ss; ss << "Could not contact ROS master at [" << master_uri << "], retrying..."; setText( QString::fromStdString( ss.str() )); setWindowTitle( "RViz: waiting for master" ); setStandardButtons( QMessageBox::Cancel ); QTimer* timer = new QTimer( this ); connect( timer, SIGNAL( timeout() ), this, SLOT( onTimer() )); timer->start( 1000 ); } void WaitForMasterDialog::onTimer() { if( ros::master::check() ) { accept(); } } } // end namespace rviz rviz-1.12.4/src/rviz/wait_for_master_dialog.h000066400000000000000000000036321300447110700212300ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_WAIT_FOR_MASTER_DIALOG_H #define RVIZ_WAIT_FOR_MASTER_DIALOG_H #include namespace rviz { class WaitForMasterDialog: public QMessageBox { Q_OBJECT public: WaitForMasterDialog( QWidget* parent = 0 ); private Q_SLOTS: void onTimer(); }; } // end namespace rviz #endif // RVIZ_WAIT_FOR_MASTER_DIALOG_H rviz-1.12.4/src/rviz/widget_geometry_change_detector.cpp000066400000000000000000000040301300447110700234440ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/widget_geometry_change_detector.h" namespace rviz { WidgetGeometryChangeDetector::WidgetGeometryChangeDetector( QObject* parent ) : QObject( parent ) {} bool WidgetGeometryChangeDetector::eventFilter( QObject* watched, QEvent* event ) { if( event->type() == QEvent::Move || event->type() == QEvent::Resize ) { Q_EMIT changed(); } return QObject::eventFilter( watched, event ); } } // end namespace rviz rviz-1.12.4/src/rviz/widget_geometry_change_detector.h000066400000000000000000000042441300447110700231200ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef WIDGET_GEOMETRY_CHANGE_DETECTOR_H #define WIDGET_GEOMETRY_CHANGE_DETECTOR_H #include namespace rviz { /** @brief Utility class for watching for events which indicate that widget geometry has changed. */ class WidgetGeometryChangeDetector: public QObject { Q_OBJECT public: WidgetGeometryChangeDetector( QObject* parent = NULL ); virtual bool eventFilter( QObject* watched, QEvent* event ); Q_SIGNALS: /** @brief This signal is emitted whenever any filtered events are detected. */ void changed(); }; } // end namespace rviz #endif // WIDGET_GEOMETRY_CHANGE_DETECTOR_H rviz-1.12.4/src/rviz/window_manager_interface.h000066400000000000000000000046371300447110700215530ustar00rootroot00000000000000/* * Copyright (c) 2009, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef WINDOW_MANAGER_INTERFACE_H #define WINDOW_MANAGER_INTERFACE_H class QWidget; class QString; namespace rviz { class PanelDockWidget; class WindowManagerInterface { public: virtual QWidget* getParentWindow() = 0; /** Add a pane to the visualizer. To remove a pane, just delete it. * For example: "delete my_panel_dock_widget;". Other operations * can also be done directly to the PanelDockWidget: show(), hide(), * close(), etc. */ virtual PanelDockWidget* addPane( const QString& name, QWidget* pane, Qt::DockWidgetArea area = Qt::LeftDockWidgetArea, bool floating = true ) = 0; /** Set the message displayed in the status bar */ virtual void setStatus( const QString & message ) = 0; }; } // end namespace rviz #endif rviz-1.12.4/src/rviz/yaml_config_reader.cpp000066400000000000000000000101101300447110700206550ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #ifdef RVIZ_HAVE_YAMLCPP_05 #include #else #include #include #endif #include "rviz/yaml_config_reader.h" namespace rviz { YamlConfigReader::YamlConfigReader() : error_( false ) {} void YamlConfigReader::readFile( Config& config, const QString& filename ) { std::ifstream in( qPrintable( filename )); readStream( config, in, filename ); } void YamlConfigReader::readString( Config& config, const QString& data, const QString& filename ) { std::stringstream ss( data.toStdString() ); readStream( config, ss, filename ); } void YamlConfigReader::readStream( Config& config, std::istream& in, const QString& filename ) { try { YAML::Node yaml_node; #ifdef RVIZ_HAVE_YAMLCPP_05 yaml_node = YAML::Load(in); #else YAML::Parser parser( in ); parser.GetNextDocument( yaml_node ); #endif error_ = false; message_ = ""; readYamlNode( config, yaml_node ); } catch( YAML::ParserException& ex ) { message_ = ex.what(); error_ = true; } } void YamlConfigReader::readYamlNode( Config& config, const YAML::Node& yaml_node ) { switch( yaml_node.Type() ) { case YAML::NodeType::Map: { #ifdef RVIZ_HAVE_YAMLCPP_05 for( YAML::const_iterator it = yaml_node.begin(); it != yaml_node.end(); ++it ) #else for( YAML::Iterator it = yaml_node.begin(); it != yaml_node.end(); ++it ) #endif { std::string key; #ifdef RVIZ_HAVE_YAMLCPP_05 key = it->first.as(); #else it.first() >> key; #endif Config child = config.mapMakeChild( QString::fromStdString( key )); #ifdef RVIZ_HAVE_YAMLCPP_05 readYamlNode( child, it->second ); #else readYamlNode( child, it.second() ); #endif } break; } case YAML::NodeType::Sequence: { #ifdef RVIZ_HAVE_YAMLCPP_05 for( YAML::const_iterator it = yaml_node.begin(); it != yaml_node.end(); ++it ) #else for( YAML::Iterator it = yaml_node.begin(); it != yaml_node.end(); ++it ) #endif { Config child = config.listAppendNew(); readYamlNode( child, *it ); } break; } case YAML::NodeType::Scalar: { std::string s; #ifdef RVIZ_HAVE_YAMLCPP_05 s = yaml_node.as(); #else yaml_node >> s; #endif config.setValue( QString::fromStdString( s )); break; } case YAML::NodeType::Null: default: break; } } bool YamlConfigReader::error() { return error_; } QString YamlConfigReader::errorMessage() { return message_; } } // end namespace rviz rviz-1.12.4/src/rviz/yaml_config_reader.h000066400000000000000000000056321300447110700203370ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef YAML_CONFIG_READER_H #define YAML_CONFIG_READER_H #include #include "rviz/config.h" namespace YAML { class Node; } namespace rviz { class YamlConfigReader { public: /** @brief Constructor. Object begins in a no-error state. */ YamlConfigReader(); /** @brief Read config data from a file. This potentially changes the return value sof error(), statusMessage(), and config(). */ void readFile( Config& config, const QString& filename ); /** @brief Read config data from a string. This potentially changes the return value sof error(), statusMessage(), and config(). */ void readString( Config& config, const QString& data, const QString& filename = "data string" ); /** @brief Read config data from a std::istream. This potentially changes the return value sof error(), statusMessage(), and config(). */ void readStream( Config& config, std::istream& in, const QString& filename = "data stream" ); /** @brief Return true if the latest readFile() or readString() call had an error. */ bool error(); /** @brief Return an error message if the latest read call had an * error, or the empty string if not. */ QString errorMessage(); private: void readYamlNode( Config& config, const YAML::Node& yaml_node ); QString message_; bool error_; }; } // end namespace rviz #endif // YAML_CONFIG_READER_H rviz-1.12.4/src/rviz/yaml_config_writer.cpp000066400000000000000000000105671300447110700207470ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rviz/yaml_config_writer.h" namespace rviz { /** @brief Constructor. Writer starts in a non-error state with no status message. */ YamlConfigWriter::YamlConfigWriter() : error_( false ) {} /** @brief Write config data to a file. This potentially changes * the return values of error() and statusMessage(). */ void YamlConfigWriter::writeFile( const Config& config, const QString& filename ) { try { std::ofstream out( qPrintable( filename )); if( out ) { writeStream( config, out, filename ); } else { error_ = true; message_ = "Failed to open " + filename + " for writing."; } } catch( std::exception ex ) { error_ = true; message_ = ex.what(); } } /** @brief Write config data to a string, and return it. This * potentially changes the return values of error() and * statusMessage(). */ QString YamlConfigWriter::writeString( const Config& config, const QString& filename ) { std::stringstream out; writeStream( config, out, filename ); if( !error_ ) { return QString::fromStdString( out.str() ); } else { return ""; } } /** @brief Write config data to a std::ostream. This potentially * changes the return values of error() and statusMessage(). */ void YamlConfigWriter::writeStream( const Config& config, std::ostream& out, const QString& filename ) { error_ = false; message_ = ""; YAML::Emitter emitter; writeConfigNode( config, emitter ); if( !error_ ) { out << emitter.c_str() << std::endl; } } /** @brief Return true if the latest write operation had an error. */ bool YamlConfigWriter::error() { return error_; } QString YamlConfigWriter::errorMessage() { return message_; } void YamlConfigWriter::writeConfigNode( const Config& config, YAML::Emitter& emitter ) { switch( config.getType() ) { case Config::List: { emitter << YAML::BeginSeq; for( int i = 0; i < config.listLength(); i++ ) { writeConfigNode( config.listChildAt( i ), emitter ); } emitter << YAML::EndSeq; break; } case Config::Map: { emitter << YAML::BeginMap; Config::MapIterator map_iter = config.mapIterator(); while( map_iter.isValid() ) { Config child = map_iter.currentChild(); emitter << YAML::Key; emitter << map_iter.currentKey().toStdString(); emitter << YAML::Value; writeConfigNode( child, emitter ); map_iter.advance(); } emitter << YAML::EndMap; break; } case Config::Value: { QString value = config.getValue().toString(); if( value.size() == 0 ) { emitter << YAML::DoubleQuoted << ""; } else { emitter << value.toStdString(); } break; } default: emitter << YAML::Null; break; } } } // end namespace rviz rviz-1.12.4/src/rviz/yaml_config_writer.h000066400000000000000000000056451300447110700204150ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef YAML_CONFIG_WRITER_H #define YAML_CONFIG_WRITER_H #include #include "rviz/config.h" namespace YAML { class Emitter; } namespace rviz { class YamlConfigWriter { public: /** @brief Constructor. Writer starts in a non-error state. */ YamlConfigWriter(); /** @brief Write config data to a file. This potentially changes * the return values of error() and statusMessage(). */ void writeFile( const Config& config, const QString& filename ); /** @brief Write config data to a string, and return it. This * potentially changes the return values of error() and * statusMessage(). */ QString writeString( const Config& config, const QString& filename = "data string" ); /** @brief Write config data to a std::ostream. This potentially * changes the return values of error() and statusMessage(). */ void writeStream( const Config& config, std::ostream& out, const QString& filename = "data stream" ); /** @brief Return true if the latest write operation had an error. */ bool error(); /** @brief Return an error message if the latest write call had an * error, or the empty string if there was no error. */ QString errorMessage(); private: void writeConfigNode( const Config& config, YAML::Emitter& emitter ); QString message_; bool error_; }; } // end namespace rviz #endif // YAML_CONFIG_WRITER_H rviz-1.12.4/src/test/000077500000000000000000000000001300447110700143345ustar00rootroot00000000000000rviz-1.12.4/src/test/CMakeLists.txt000066400000000000000000000171451300447110700171040ustar00rootroot00000000000000# rviz's automated tests find_package(rostest REQUIRED) # This is a test utility which publishes images of different types. add_executable(send_images EXCLUDE_FROM_ALL send_images.cpp) if(NOT WIN32) set_target_properties(send_images PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(send_images ${catkin_LIBRARIES}) add_dependencies(tests send_images) # This is a test utility which can publish different kinds of markers. add_executable(marker_test EXCLUDE_FROM_ALL marker_test.cpp) if(NOT WIN32) set_target_properties(marker_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(marker_test ${catkin_LIBRARIES}) add_dependencies(tests marker_test) # This is a test utility which can publish different kinds of mesh markers. add_executable(mesh_marker_test EXCLUDE_FROM_ALL mesh_marker_test.cpp) if(NOT WIN32) set_target_properties(mesh_marker_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(mesh_marker_test ${catkin_LIBRARIES}) add_dependencies(tests mesh_marker_test) # This is a GTest which tests the different types of primitive display properties. catkin_add_gtest(property_test property_test.cpp mock_property_change_receiver.cpp ${MOC_MOCK_PROPERTY_CHANGE_RECEIVER} ) target_link_libraries(property_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) # TODO(wjwwood): Fix this test, it used to use a set of Mock classes, but # has since undergone a lot of changes and it no longer works. # This is a GTest which tests the display system. # qt4_wrap_cpp(MOC_MOCK_DISPLAY mock_display.h) # add_rostest_gtest(display_test display_test.test # display_test.cpp # mock_context.cpp # mock_display.cpp # mock_display_factory.cpp # mock_property_change_receiver.cpp # ${MOC_MOCK_DISPLAY} # ${MOC_MOCK_PROPERTY_CHANGE_RECEIVER} # ) # target_link_libraries(display_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) # This is a GTest which tests the uniform_string_stream. catkin_add_gtest(uniform_string_stream_test uniform_string_stream_test.cpp ../rviz/uniform_string_stream.cpp ) # This is an example node which serves an rviz logo as an interactive marker. add_executable(rviz_logo_marker EXCLUDE_FROM_ALL rviz_logo_marker.cpp) if(NOT WIN32) set_target_properties(rviz_logo_marker PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(rviz_logo_marker ${catkin_LIBRARIES}) add_dependencies(tests rviz_logo_marker) # This is an example node which publishes different kinds of point clouds. add_executable(cloud_test EXCLUDE_FROM_ALL cloud_test.cpp) if(NOT WIN32) set_target_properties(cloud_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(cloud_test ${catkin_LIBRARIES}) add_dependencies(tests cloud_test) # This is an example node which serves an interactive marker. add_executable(interactive_marker_test interactive_marker_test.cpp) if(NOT WIN32) set_target_properties(interactive_marker_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(interactive_marker_test ${catkin_LIBRARIES}) add_dependencies(tests interactive_marker_test) # This is another example node that publishes images. add_executable(image_test EXCLUDE_FROM_ALL image_test.cpp) if(NOT WIN32) set_target_properties(image_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(image_test ${catkin_LIBRARIES}) add_dependencies(tests image_test) # This is a node that sends lots of point clouds. add_executable(send_lots_of_points EXCLUDE_FROM_ALL send_lots_of_points_node.cpp) if(NOT WIN32) set_target_properties(send_lots_of_points PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(send_lots_of_points ${catkin_LIBRARIES}) add_dependencies(tests send_lots_of_points) # Yet another example which sends point clouds. add_executable(send_point_cloud_2 EXCLUDE_FROM_ALL send_point_cloud_2.cpp) if(NOT WIN32) set_target_properties(send_point_cloud_2 PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(send_point_cloud_2 ${catkin_LIBRARIES}) add_dependencies(tests send_point_cloud_2) # This is a node which sends grid cells. add_executable(send_grid_cells EXCLUDE_FROM_ALL send_grid_cells_node.cpp) if(NOT WIN32) set_target_properties(send_grid_cells PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(send_grid_cells ${catkin_LIBRARIES}) add_dependencies(tests send_grid_cells) # This is a test program that uses the rviz panel interface. add_executable(render_panel_test render_panel_test.cpp) if(NOT WIN32) set_target_properties(render_panel_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(render_panel_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(tests render_panel_test) # This is an executable which uses the rviz new display diaglog interface. add_executable(new_display_dialog_test new_display_dialog_test.cpp) if(NOT WIN32) set_target_properties(new_display_dialog_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(new_display_dialog_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(tests new_display_dialog_test) # This is an executable which uses the rviz color editor test. add_executable(color_editor_test color_editor_test.cpp) if(NOT WIN32) set_target_properties(color_editor_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(color_editor_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(tests color_editor_test) # This is a modified version of the property test. catkin_add_gtest(property_with_ros_spinner_test property_test.cpp ros_spinner.cpp mock_property_change_receiver.cpp ${MOC_MOCK_PROPERTY_CHANGE_RECEIVER} ) target_link_libraries(property_with_ros_spinner_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(tests property_with_ros_spinner_test) # This is an executable that uses the line_edit_with_button property interface. add_executable(line_edit_with_button_test line_edit_with_button_test.cpp) if(NOT WIN32) set_target_properties(line_edit_with_button_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(line_edit_with_button_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(tests line_edit_with_button_test) # This is an executable which tests the connect/disconnect behavior of signals and slots in Qt. add_executable(connect_test connect_test.cpp) if(NOT WIN32) set_target_properties(connect_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(connect_test ${QT_LIBRARIES}) add_dependencies(tests connect_test) # This is a GTest which tests the display configuration. catkin_add_gtest(config_test config_test.cpp ../rviz/uniform_string_stream.cpp ../rviz/config.cpp) target_link_libraries(config_test ${QT_LIBRARIES}) # This is an acceptance test executable which renders points. add_executable(render_points_test render_points_test.cpp ../rviz/ogre_helpers/orbit_camera.cpp ) if(NOT WIN32) set_target_properties(render_points_test PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(render_points_test rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(tests render_points_test) # This is an example application which creates two ogre render windows. add_executable(two_render_widgets two_render_widgets.cpp) if(NOT WIN32) set_target_properties(two_render_widgets PROPERTIES COMPILE_FLAGS "-std=c++11") endif() target_link_libraries(two_render_widgets rviz ${catkin_LIBRARIES} ${QT_LIBRARIES}) add_dependencies(tests two_render_widgets) # This is a GTest which tests the STL loader catkin_add_gtest(stl_loader_test stl_loader_test.cpp ../rviz/ogre_helpers/stl_loader.cpp) target_link_libraries(stl_loader_test ${catkin_LIBRARIES} ${OGRE_OV_LIBRARIES_ABS}) rviz-1.12.4/src/test/arrow_marker_test.py000077500000000000000000000046071300447110700204520ustar00rootroot00000000000000#!/usr/bin/env python PACKAGE_NAME = 'rviz' import roslib; roslib.load_manifest(PACKAGE_NAME) #import sys, os.path, time #import numpy as np #from scipy import linalg #from matplotlib import pyplot as plt import rospy from visualization_msgs.msg import Marker, MarkerArray from geometry_msgs.msg import Pose, Point, Vector3, Quaternion from std_msgs.msg import ColorRGBA rospy.init_node('marker_test') marker_pub = rospy.Publisher('marker_test', Marker) def make_marker(marker_type, scale, r, g, b, a): # make a visualization marker array for the occupancy grid m = Marker() m.action = Marker.ADD m.header.frame_id = '/base_link' m.header.stamp = rospy.Time.now() m.ns = 'marker_test_%d' % marker_type m.id = 0 m.type = marker_type m.pose.orientation.y = 0 m.pose.orientation.w = 1 m.scale = scale m.color.r = 1.0; m.color.g = 0.5; m.color.b = 0.2; m.color.a = 0.3; m.color.r = r; m.color.g = g; m.color.b = b; m.color.a = a; return m def make_arrow_points_marker(scale, tail, tip, idnum): # make a visualization marker array for the occupancy grid m = Marker() m.action = Marker.ADD m.header.frame_id = '/base_link' m.header.stamp = rospy.Time.now() m.ns = 'points_arrows' m.id = idnum m.type = Marker.ARROW m.pose.orientation.y = 0 m.pose.orientation.w = 1 m.scale = scale m.color.r = 0.2 m.color.g = 0.5 m.color.b = 1.0 m.color.a = 0.3 m.points = [ tail, tip ] return m while not rospy.is_shutdown(): rospy.loginfo('Publishing arrow marker') #marker_pub.publish(make_arrow_points_marker(Point(0,0,0), Point(2,2,0), 0)) #marker_pub.publish(make_arrow_points_marker(Point(0,0,0), Point(1,-1,1), 1)) #marker_pub.publish(make_arrow_points_marker(Point(-1,-1,-1), Point(1,-1,-1), 2)) #this arrow should look exactly like the other one, except that is #is twice a wide in the z direction. scale = Vector3(2,4,0.69) marker_pub.publish(make_arrow_points_marker(scale,Point(0,0,0), Point(3,0,0), 3)) scale = Vector3(3,2,1) marker_pub.publish(make_marker(Marker.SPHERE, scale, 1, .5, .2, .3)) marker_pub.publish(make_marker(Marker.CYLINDER, scale, .5, .2, 1, .3)) marker_pub.publish(make_marker(Marker.CUBE, scale, .2, 1, .5, .3)) marker_pub.publish(make_marker(Marker.ARROW, scale, 1, 1, 1, .5)) rospy.sleep(1.0) rviz-1.12.4/src/test/big-font.style000066400000000000000000000000241300447110700171170ustar00rootroot00000000000000* { font: 30px; } rviz-1.12.4/src/test/big-menus.style000066400000000000000000000001421300447110700173010ustar00rootroot00000000000000QMenu::item { padding: 20px; color: white; } QMenu::item:selected { background: #6a5b54; } rviz-1.12.4/src/test/cloud_test.cpp000066400000000000000000000133171300447110700172120ustar00rootroot00000000000000#include "ros/ros.h" #include #include "sensor_msgs/PointCloud.h" #include int main( int argc, char** argv ) { ros::init( argc, argv, "cloud_test" ); ros::NodeHandle n; ros::Publisher rgb_pub = n.advertise( "rgb_cloud_test", 0 ); ros::Publisher rgb2_pub = n.advertise( "rgb_cloud_test2", 0 ); ros::Publisher intensity_pub = n.advertise( "intensity_cloud_test", 0 ); ros::Publisher million_pub = n.advertise( "million_points_cloud_test", 0 ); ros::Publisher changing_channels_pub = n.advertise( "changing_channels_test", 0 ); tf::TransformBroadcaster tf_broadcaster; ros::Duration(0.1).sleep(); int i = 0; while (n.ok()) { ros::Time tm(ros::Time::now()); tf::Transform t; t.setIdentity(); // tf_broadcaster.sendTransform(tf::Stamped(t, tm, "base", "map")); ROS_INFO("Publishing"); sensor_msgs::PointCloud changing_cloud; { static sensor_msgs::PointCloud cloud; if (cloud.channels.empty()) { cloud.header.stamp = tm; cloud.header.frame_id = "/base_link"; cloud.channels.resize(1); int32_t xcount = 100; int32_t ycount = 100; int32_t zcount = 100; int32_t total = xcount * ycount * zcount; cloud.points.resize(total); cloud.channels[0].values.resize(total); cloud.channels[0].name = "intensities"; float factor = 0.1f; for (int32_t x = 0; x < xcount; ++x) { for (int32_t y = 0; y < ycount; ++y) { for (int32_t z = 0; z < zcount; ++z) { int32_t index = (ycount*zcount*x) + zcount*y + z; geometry_msgs::Point32& point = cloud.points[index]; point.x = x * factor; point.y = y * factor; point.z = z * factor; cloud.channels[0].values[index] = (index % 4096); } } } } million_pub.publish( cloud ); } { sensor_msgs::PointCloud cloud; cloud.header.stamp = tm; cloud.header.frame_id = "/base_link"; cloud.points.resize(5); cloud.channels.resize(2); for ( int j = 0; j < 5; ++j ) { cloud.points[j].x = (float)j; cloud.points[j].y = 0.0f; cloud.points[j].z = i % 10; if (j == 2) { cloud.points[j].z = std::numeric_limits::quiet_NaN(); } } cloud.channels[0].name = "rgb"; cloud.channels[0].values.resize(5); int rgb = (0xff << 16); cloud.channels[0].values[0] = *reinterpret_cast(&rgb); rgb = (0xff << 8); cloud.channels[0].values[1] = *reinterpret_cast(&rgb); rgb = 0xff; cloud.channels[0].values[2] = *reinterpret_cast(&rgb); rgb = (0xff << 16) | (0xff << 8); cloud.channels[0].values[3] = *reinterpret_cast(&rgb); rgb = (0xff << 8) | 0xff; cloud.channels[0].values[4] = *reinterpret_cast(&rgb); cloud.channels[1].name = "intensity"; cloud.channels[1].values.resize(5); cloud.channels[1].values[0] = 0; cloud.channels[1].values[1] = 100; cloud.channels[1].values[2] = 200; cloud.channels[1].values[3] = 300; cloud.channels[1].values[4] = 400; rgb_pub.publish(cloud); } { sensor_msgs::PointCloud cloud; cloud.header.stamp = tm; cloud.header.frame_id = "/base_link"; cloud.points.resize(5); cloud.channels.resize(3); for ( int j = 0; j < 5; ++j ) { cloud.points[j].x = (float)j; cloud.points[j].y = 1.0f; cloud.points[j].z = i % 10; } cloud.channels[0].name = "r"; cloud.channels[0].values.resize(5); cloud.channels[1].name = "g"; cloud.channels[1].values.resize(5); cloud.channels[2].name = "b"; cloud.channels[2].values.resize(5); cloud.channels[0].values[0] = 1.0f; cloud.channels[1].values[0] = 0.0f; cloud.channels[2].values[0] = 0.0f; cloud.channels[0].values[1] = 0.0f; cloud.channels[1].values[1] = 1.0f; cloud.channels[2].values[1] = 0.0f; cloud.channels[0].values[2] = 0.0f; cloud.channels[1].values[2] = 0.0f; cloud.channels[2].values[2] = 1.0f; cloud.channels[0].values[3] = 1.0f; cloud.channels[1].values[3] = 1.0f; cloud.channels[2].values[3] = 0.0f; cloud.channels[0].values[4] = 0.0f; cloud.channels[1].values[4] = 1.0f; cloud.channels[2].values[4] = 1.0f; rgb2_pub.publish(cloud); if ((i % 10) - 5 < 0) { changing_cloud = cloud; } } { sensor_msgs::PointCloud cloud; cloud.header.stamp = tm; cloud.header.frame_id = "/base_link"; int num_rows = 1; int num_cols = 200; int total_pts = num_rows * num_cols; cloud.points.resize(total_pts); cloud.channels.resize(1); cloud.channels[0].values.resize(total_pts); cloud.channels[0].name = "intensities"; int j = 0; for (int z = 0; z < num_rows; ++z) { for (int x = 0; x < num_cols; ++x, ++j) { cloud.points[j].x = x; cloud.points[j].y = 0; if (num_rows == 1) { cloud.points[j].z = i % 10; } else { cloud.points[j].z = z; } cloud.channels[0].values[j] = j; } } intensity_pub.publish(cloud); if ((i % 10) - 5 >= 0) { changing_cloud = cloud; } } changing_channels_pub.publish(changing_cloud); ++i; ros::Duration(1.0).sleep(); } } rviz-1.12.4/src/test/color_editor_test.cpp000066400000000000000000000035501300447110700205660ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/color_editor.h" using namespace rviz; int main(int argc, char **argv) { QApplication app(argc, argv); ColorEditor ce; ce.setText( "laskdjf laskjd fla jsdfl ja" ); ce.resize( 200, 40 ); ce.show(); return app.exec(); } rviz-1.12.4/src/test/config_sample.py000077500000000000000000000054531300447110700175260ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') import sys #setattr(sys, 'SELECT_QT_BINDING', 'pyside') # Shiboken setattr(sys, 'SELECT_QT_BINDING', 'pyqt') # SIP import python_qt_binding.QtBindingHelper # @UnusedImport from QtGui import * from QtCore import * import rviz c = rviz.Config() c.mapSetValue( "foo", 17 ) c.mapSetValue( "bar", "seventeen" ) c.mapMakeChild( "biff" ).mapMakeChild( "boff" ).setValue( 3.14159 ) print c.mapGetChild( "foo" ).getValue() print c.mapGetChild( "bar" ).getValue() print c.mapGetChild( "baz" ).getValue() print c.mapGetChild( "biff" ).mapGetChild( "boff" ).getValue() # print c.mapGetChild( "goo" ).mapGetChild( "biff" ).getValue() # crashes because "goo" does not exist, so getChild("biff") can't be called. mi = c.mapIterator() while mi.isValid(): print "key:", mi.currentKey(), " value:", mi.currentChild().getValue() mi2 = mi.currentChild().mapIterator() while mi2.isValid(): print " key:", mi2.currentKey(), " value:", mi2.currentChild().getValue() mi2.advance() mi.advance() c.listAppendNew().setValue( "ay" ) c.listAppendNew().setValue( "bee" ) if c.getType() == rviz.Config.List: for i in range( 0, c.listLength() ): print c.listChildAt( i ).getValue() c.mapMakeChild( "chunk" ) print "config has", c.listLength(), "list entries. (should be 0 because it is a map now.)" r = rviz.YamlConfigReader() c = rviz.Config() r.readFile( c, roslib.packages.get_pkg_dir('rviz') + "/default.rviz" ) if r.error(): print "Error:", r.errorMessage() else: print "default.rviz first two levels of maps:" mi = c.mapIterator() while mi.isValid(): print "key:", mi.currentKey(), " value:", mi.currentChild().getValue() mi2 = mi.currentChild().mapIterator() while mi2.isValid(): print " key:", mi2.currentKey(), " value:", mi2.currentChild().getValue() mi2.advance() mi.advance() print "tools:" tools = c.mapGetChild( "Visualization Manager" ).mapGetChild( "Tools" ) for i in range( 0, tools.listLength() ): print " class:", tools.listChildAt( i ).mapGetChild( "Class" ).getValue() w = rviz.YamlConfigWriter() first_string = w.writeString( c ) print "Entire default.rviz written to a string:" print first_string r2 = rviz.YamlConfigReader() c2 = rviz.Config() r2.readString( c2, first_string ) second_string = w.writeString( c2 ) if first_string == second_string: print "reading and re-writing first string gave matching result!" else: print "reading and re-writing first string gave different result:" print second_string w.writeFile( c2, "config-sample-output.yaml" ) if not w.error(): print "wrote file successfully." else: print "error writing file:", w.errorMessage() rviz-1.12.4/src/test/config_test.cpp000066400000000000000000000050651300447110700173520ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include // For ros::package::getPath() TEST( Config, set_then_get ) { rviz::Config c; c.mapSetValue( "a", "1" ); int a; EXPECT_TRUE( c.mapGetInt( "a", &a )); EXPECT_EQ( a, 1 ); float aa; EXPECT_TRUE( c.mapGetFloat( "a", &aa )); EXPECT_EQ( aa, 1.0 ); QString aaa; EXPECT_TRUE( c.mapGetString( "a", &aaa)); EXPECT_EQ( aaa, "1" ); } TEST( Config, parse_floats ) { rviz::Config c; c.mapSetValue( "f", "1.1" ); float f; EXPECT_TRUE( c.mapGetFloat( "f", &f )); EXPECT_EQ( f, 1.1f ); // In Europe they use "," for a decimal point. c.mapSetValue( "f", "1,2" ); EXPECT_TRUE( c.mapGetFloat( "f", &f )); EXPECT_EQ( f, 1.2f ); } TEST( Config, set_get_empty_value ) { rviz::Config c; c.mapSetValue( "key", "" ); QString s; EXPECT_TRUE( c.mapGetString( "key", &s )); EXPECT_EQ( "", s ); } int main(int argc, char **argv){ testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } rviz-1.12.4/src/test/connect_test.cpp000066400000000000000000000056651300447110700175440ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include // This is a simple speed test to compare suppressing a signal/slot // emission by one of two methods: // // 1) disconnect and reconnect the signal/slot. // // 2) define a bool suppress_ member which makes the slot do nothing. // // Results for Qt 4.6 are that disconnect/reconnect takes about 11 // times as long as boolean suppressor. #include "connect_test.h" double now() { struct timeval tv; gettimeofday( &tv, NULL ); return double(tv.tv_sec) + double(tv.tv_usec) / 1000000.0; } int main( int argc, char **argv ) { MyObject* obj = new MyObject; obj->enableChanges(); QObject::connect( obj, SIGNAL( changed() ), obj, SLOT( onChanged() )); obj->emitChanged(); double start, end; int count = 1000000; start = now(); for( int i = 0; i < count; i++ ) { QObject::disconnect( obj, SIGNAL( changed() ), obj, SLOT( onChanged() )); obj->emitChanged(); QObject::connect( obj, SIGNAL( changed() ), obj, SLOT( onChanged() )); } end = now(); printf("disconnect/emit/connect %d times took %lf seconds.\n", count, end - start ); obj->emitChanged(); start = now(); for( int i = 0; i < count; i++ ) { obj->suppressChanges(); obj->emitChanged(); obj->enableChanges(); } end = now(); printf("suppress/emit/enable %d times took %lf seconds.\n", count, end - start ); return 0; } rviz-1.12.4/src/test/connect_test.h000066400000000000000000000040571300447110700172030ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef CONNECT_TEST_H #define CONNECT_TEST_H #include #include // See description in connect_test.cpp. class MyObject: public QObject { Q_OBJECT public: void suppressChanges() { suppress_ = true; } void enableChanges() { suppress_ = false; } void emitChanged() { Q_EMIT changed(); } Q_SIGNALS: void changed(); public Q_SLOTS: void onChanged() { if( ! suppress_ ) { printf("changed.\n"); }} private: bool suppress_; }; #endif // CONNECT_TEST_H rviz-1.12.4/src/test/cube-and-cube-list-marker.yaml000066400000000000000000000045311300447110700220450ustar00rootroot00000000000000markers: - header: seq: 1 stamp: secs: 0 nsecs: 0 frame_id: base_link ns: cube id: 0 type: 1 action: 0 pose: position: x: 0.0 y: 0.0 z: 0.0 orientation: x: 0.0 y: 0.0 z: 0.0 w: 1.0 scale: x: 1.0 y: 1.0 z: 1.0 color: r: .5 g: .5 b: .5 a: 1 lifetime: secs: 0 nsecs: 0 frame_locked: False text: '' mesh_resource: '' mesh_use_embedded_materials: False - header: seq: 1 stamp: secs: 0 nsecs: 0 frame_id: base_link ns: cube id: 1 type: 6 action: 0 pose: position: x: 0.0 y: 0.0 z: 0.0 orientation: x: 0.0 y: 0.0 z: 0.0 w: 1.0 scale: x: 1.0 y: 1.0 z: 1.0 color: r: .5 g: .5 b: .5 a: 1 lifetime: secs: 0 nsecs: 0 frame_locked: False text: '' points: - x: 2 y: 0 z: 0 - x: 2 y: 5 z: 0 - x: 1 y: 5 z: 0 - x: 0 y: 5 z: 0 - x: 2 y: 6 z: 0 - x: 1 y: 6 z: 0 - x: 0 y: 6 z: 0 - x: 2 y: 7 z: 0 - x: 1 y: 7 z: 0 - x: 0 y: 7 z: 0 - x: 2 y: 8 z: 0 - x: 1 y: 8 z: 0 - x: 0 y: 8 z: 0 - x: 2 y: 8 z: 1 - x: 1 y: 8 z: 1 - x: 0 y: 8 z: 1 - x: 2 y: 8 z: 2 - x: 1 y: 8 z: 2 - x: 0 y: 8 z: 2 - x: -1 y: 8 z: 2 - x: -1 y: 8 z: 1 - x: -1 y: 8 z: 0 - x: -1 y: 7 z: 0 - x: -1 y: 6 z: 0 - x: -1 y: 5 z: 0 - x: 1 y: 7 z: 1 mesh_resource: '' mesh_use_embedded_materials: False --- rviz-1.12.4/src/test/display_test.cpp000066400000000000000000000200531300447110700175440ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "mock_display.h" #include "mock_context.h" using namespace rviz; TEST( Display, load_properties ) { std::stringstream input( "Name: sample\n" "Enabled: true\n" "Count: 7\n" "Pi: 3.2\n" "Offset: {X: -1, Y: 1.1, Z: 1.1e3}\n" "Color: white\n" "Style: loosey goosey\n" ); rviz::YamlConfigReader reader; rviz::Config config; reader.readStream(config, input); MockDisplay d; d.load( config ); EXPECT_EQ( 7, d.count_->getValue().toInt() ); EXPECT_EQ( "loosey goosey", d.style_->getValue().toString().toStdString() ); EXPECT_EQ( 3.2f, d.pi_->getValue().toFloat() ); Ogre::Vector3 offset = d.offset_->getVector(); EXPECT_EQ( -1.f, offset.x ); EXPECT_EQ( 1.1f, offset.y ); EXPECT_EQ( 1100.f, offset.z ); EXPECT_EQ( "255; 255; 255", d.color_->getValue().toString().toStdString() ); EXPECT_EQ( true, d.getValue().toBool() ); } TEST( DisplayGroup, load_properties ) { std::stringstream input( "Name: root\n" "Enabled: true\n" "Displays:\n" " -\n" " Class: MockDisplay\n" " Name: Steven\n" " Enabled: false\n" " Count: 17\n" " -\n" " Name: sub group\n" " Class: DisplayGroup\n" " Enabled: true\n" " Displays:\n" " -\n" " Class: MockDisplay\n" " Name: Curly\n" " Enabled: false\n" " Count: 900\n" " -\n" " Class: BrokenDisplay\n" " Name: Joe\n" " Enabled: true\n" " Count: 33\n" ); rviz::YamlConfigReader reader; rviz::Config config; reader.readStream(config, input); DisplayGroup g; g.load( config ); EXPECT_EQ( true, g.getValue().toBool() ); EXPECT_EQ( false, g.subProp("Steven")->getValue().toBool() ); EXPECT_EQ( 17, g.subProp("Steven")->subProp("Count")->getValue().toInt() ); EXPECT_EQ( 900, g.subProp("sub group")->subProp("Curly")->subProp("Count")->getValue().toInt() ); EXPECT_EQ( "The class required for this display, 'BrokenDisplay', could not be loaded.", g.subProp("Joe")->getDescription().left( 74 ).toStdString()); } TEST( Display, save_properties) { MockDisplay d; d.setName( "Steven" ); d.subProp( "Count" )->setValue( 37 ); rviz::YamlConfigWriter writer; rviz::Config config; d.save( config ); QString out = writer.writeString(config); // Since we instantiated the display directly instead of using the // DisplayFactory, it won't know its class name. EXPECT_EQ( std::string( "Class: \"\"\n" "Name: Steven\n" "Enabled: false\n" "Count: 37\n" "Style: chunky\n" "Pi: 3.14159\n" "Offset: {X: 1, Y: 2, Z: 3}\n" "Color: 10; 20; 30" ) , out.toStdString().c_str() ); } TEST( DisplayGroup, save_properties) { DisplayGroup g; g.setName( "Charles" ); MockDisplay *d = new MockDisplay; d->setName( "Steven" ); d->subProp( "Count" )->setValue( 101 ); g.addChild( d ); d = new MockDisplay; d->setName( "Katherine" ); d->subProp( "Pi" )->setValue( 1.1 ); g.addChild( d ); rviz::YamlConfigWriter writer; rviz::Config config; g.save( config ); QString out = writer.writeString(config); // Since we instantiated the display directly instead of using the // DisplayFactory, it won't know its class name. EXPECT_EQ( std::string( "Class: \"\"\n" "Name: Charles\n" "Enabled: false\n" "Displays:\n" " - Class: \"\"\n" " Name: Steven\n" " Enabled: false\n" " Count: 101\n" " Style: chunky\n" " Pi: 3.14159\n" " Offset: {X: 1, Y: 2, Z: 3}\n" " Color: 10; 20; 30\n" " - Class: \"\"\n" " Name: Katherine\n" " Enabled: false\n" " Count: 10\n" " Style: chunky\n" " Pi: 1.1\n" " Offset: {X: 1, Y: 2, Z: 3}\n" " Color: 10; 20; 30" ) , out.toStdString().c_str() ); } TEST( DisplayFactory, class_name ) { std::stringstream input( "Displays:\n" " -\n" " Class: MockDisplay\n" ); rviz::YamlConfigReader reader; rviz::Config config; reader.readStream(config, input); DisplayGroup g; g.load( config ); EXPECT_EQ( 1, g.numChildren() ); EXPECT_EQ( "MockDisplay", g.getDisplayAt( 0 )->getClassId().toStdString() ); } TEST( DisplayFactory, failed_display ) { std::stringstream input( "Displays:\n" " - Class: MissingDisplay\n" " Name: Chubbers\n" " NumLemurs: 77\n" " LemurStyle: chunky\n" " SubYaml:\n" " - 1\n" " - foo: bar\n" " food: bard\n" ); rviz::YamlConfigReader reader; rviz::Config config; reader.readStream(config, input); DisplayGroup g; g.load( config ); EXPECT_EQ( 1, g.numChildren() ); EXPECT_EQ( "MissingDisplay", g.getDisplayAt( 0 )->getClassId().toStdString() ); EXPECT_EQ( 0, g.getDisplayAt( 0 )->numChildren() ); // FailedDisplay does not have any children. // When a FailedDisplay is saved, it should write out its contents // that it was loaded with, so data is not lost. rviz::YamlConfigWriter writer; rviz::Config config2; g.save( config2 ); QString out = writer.writeString(config); EXPECT_EQ( std::string( "Class: \"\"\n" "Name: \"\"\n" "Enabled: false\n" "Displays:\n" " - Class: MissingDisplay\n" " LemurStyle: chunky\n" " Name: Chubbers\n" " NumLemurs: 77\n" " SubYaml:\n" " - 1\n" " - foo: bar\n" " food: bard" ) , out.toStdString().c_str() ); } int main( int argc, char **argv ) { ros::init( argc, argv, "display_test", ros::init_options::AnonymousName ); QApplication app(argc, argv); testing::InitGoogleTest( &argc, argv ); return RUN_ALL_TESTS(); } rviz-1.12.4/src/test/display_test.test000066400000000000000000000001731300447110700177420ustar00rootroot00000000000000 rviz-1.12.4/src/test/embedded_materials_with_stl.yaml000066400000000000000000000032531300447110700227320ustar00rootroot00000000000000markers: - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 0 type: 10 action: 0 pose: position: { x: 0, y: 0, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/ax12_box.stl' mesh_use_embedded_materials: True - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 1 type: 10 action: 0 pose: position: { x: 1, y: 0, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/ax12_box.stl' mesh_use_embedded_materials: False - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 2 type: 10 action: 0 pose: position: { x: 0, y: 1, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: 1, y: 1, z: 1 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/pr2-base.dae' mesh_use_embedded_materials: True - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 3 type: 10 action: 0 pose: position: { x: 1, y: 1, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: 1, y: 1, z: 1 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/pr2-base.dae' mesh_use_embedded_materials: False --- rviz-1.12.4/src/test/image_test.cpp000066400000000000000000000016201300447110700171600ustar00rootroot00000000000000#include "ros/ros.h" #include "sensor_msgs/Image.h" int main( int argc, char** argv ) { ros::init( argc, argv, "image_test" ); ros::NodeHandle n; ros::Publisher rgb_pub = n.advertise( "red_image", 0 ); ros::Duration(0.1).sleep(); sensor_msgs::Image red_image; red_image.header.frame_id = "/base_link"; red_image.header.stamp = ros::Time::now(); red_image.height = 100; red_image.width = 100; red_image.encoding = "rgb8"; red_image.step = 3 * red_image.height; red_image.data.resize(3 * red_image.height * red_image.width); for (uint32_t i = 0; i < 3 * red_image.height * red_image.width; ++i) { if (i % 3 == 0) { red_image.data[i] = 255; } else { red_image.data[i] = 0; } } int i = 0; while (n.ok()) { ROS_INFO("Publishing"); rgb_pub.publish(red_image); ++i; ros::Duration(1.0).sleep(); } } rviz-1.12.4/src/test/interactive_marker_test.cpp000066400000000000000000000175251300447110700217670ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ // %Tag(fullSource)% #include #include // create an interactive marker server on the topic namespace simple_marker interactive_markers::InteractiveMarkerServer* server; visualization_msgs::InteractiveMarker makeMarker( float r, float g, float b ) { // create an interactive marker for our server visualization_msgs::InteractiveMarker int_marker; int_marker.header.frame_id = "/base_link"; int_marker.name = "my_marker"; int_marker.description = "Simple 1-DOF Control"; // create a box marker visualization_msgs::Marker box_marker; box_marker.type = visualization_msgs::Marker::CUBE; box_marker.scale.x = 0.45; box_marker.scale.y = 0.45; box_marker.scale.z = 0.45; box_marker.color.r = r; box_marker.color.g = g; box_marker.color.b = b; box_marker.color.a = 1.0; // create a non-interactive control which contains the box visualization_msgs::InteractiveMarkerControl box_control; box_control.always_visible = true; box_control.markers.push_back( box_marker ); // add the control to the interactive marker int_marker.controls.push_back( box_control ); // create a control which will move the box // this control does not contain any markers, // which will cause RViz to insert two arrows visualization_msgs::InteractiveMarkerControl linear_control; linear_control.name = "move_x"; linear_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::MOVE_AXIS; // add the control to the interactive marker int_marker.controls.push_back(linear_control); return int_marker; } bool is_red = false; void processFeedback( const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback ) { ROS_INFO_STREAM( feedback->marker_name << " is now at " << feedback->pose.position.x << ", " << feedback->pose.position.y << ", " << feedback->pose.position.z ); bool changed = false; visualization_msgs::InteractiveMarker int_marker; // red when x < 0, green otherwise. Update marker color when x // crosses boundary. if( feedback->pose.position.x < 0 && !is_red ) { printf( "turning red.\n" ); is_red = true; int_marker = makeMarker( 1, 0, 0 ); changed = true; } if( feedback->pose.position.x >= 0 && is_red ) { printf( "turning green.\n" ); is_red = false; int_marker = makeMarker( 0, 1, 0 ); changed = true; } if( changed ) { printf( "changed.\n" ); int_marker.pose = feedback->pose; server->insert( int_marker ); server->applyChanges(); } } visualization_msgs::InteractiveMarker makeCrazyMarker( bool linear ) { // create an interactive marker for our server visualization_msgs::InteractiveMarker int_marker; int_marker.header.frame_id = "/base_link"; int_marker.name = "crazy_marker"; int_marker.description = "Unusual 1-DOF Control"; // create a box marker visualization_msgs::Marker box_marker; box_marker.type = visualization_msgs::Marker::CUBE; box_marker.scale.x = 1; box_marker.scale.y = .3; box_marker.scale.z = .3; box_marker.color.r = .3; box_marker.color.g = .1; box_marker.color.b = 1; box_marker.color.a = 1.0; box_marker.pose.position.y = -1.0; // create a non-interactive control which contains the box visualization_msgs::InteractiveMarkerControl box_control; box_control.always_visible = true; box_control.markers.push_back( box_marker ); box_control.name = "crazy"; if( linear ) { box_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::MOVE_AXIS; } else { box_control.orientation.w = 1; box_control.orientation.x = 0; box_control.orientation.y = 1; box_control.orientation.z = 0; box_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS; } // add the control to the interactive marker int_marker.controls.push_back( box_control ); int_marker.pose.position.y = 3; return int_marker; } bool is_linear = true; void processCrazyFeedback( const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback ) { ROS_INFO_STREAM( feedback->marker_name << " is now at pos " << feedback->pose.position.x << ", " << feedback->pose.position.y << ", " << feedback->pose.position.z << "; quat " << feedback->pose.orientation.x << ", " << feedback->pose.orientation.y << ", " << feedback->pose.orientation.z << ", " << feedback->pose.orientation.w ); bool changed = false; visualization_msgs::InteractiveMarker int_marker; // linear when x < 0, rotary otherwise. Update when x // crosses boundary. if( feedback->pose.orientation.z < 0 && !is_linear ) { printf( "turning linear.\n" ); is_linear = true; int_marker = makeCrazyMarker( true ); changed = true; } if( feedback->pose.position.x > 0 && is_linear ) { printf( "turning rotary.\n" ); is_linear = false; int_marker = makeCrazyMarker( false ); changed = true; } if( changed ) { printf( "changed.\n" ); int_marker.pose.position.x = 0; int_marker.pose.orientation.x = 0; int_marker.pose.orientation.y = 0; int_marker.pose.orientation.z = 0; int_marker.pose.orientation.w = 1; server->insert( int_marker ); server->applyChanges(); } } int main(int argc, char** argv) { ros::init(argc, argv, "interactive_marker_test"); // create an interactive marker server on the topic namespace simple_marker server = new interactive_markers::InteractiveMarkerServer("simple_marker"); // create an interactive marker for our server visualization_msgs::InteractiveMarker int_marker = makeMarker(0, 1, 0); // add the interactive marker to our collection & // tell the server to call processFeedback() when feedback arrives for it server->insert(int_marker, &processFeedback); // create an interactive marker for our server visualization_msgs::InteractiveMarker crazy_marker = makeCrazyMarker( true ); // add the interactive marker to our collection & // tell the server to call processCrazyFeedback() when feedback arrives for it server->insert(crazy_marker, &processCrazyFeedback); // 'commit' changes and send to all clients server->applyChanges(); // start the ROS main loop ros::spin(); } // %Tag(fullSource)% rviz-1.12.4/src/test/kitchen-mesh-marker.yaml000066400000000000000000000005671300447110700210660ustar00rootroot00000000000000header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 0 type: 10 action: 0 pose: position: { x: 0, y: 0, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 1 } color: { r: 1, g: 1, b: 1, a: 1 } scale: { x: 1, y: 1, z: 1 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/kitchen/models/dada.dae' mesh_use_embedded_materials: True rviz-1.12.4/src/test/line_edit_with_button_test.cpp000066400000000000000000000035171300447110700224670ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "rviz/properties/line_edit_with_button.h" using namespace rviz; int main(int argc, char **argv) { QApplication app(argc, argv); LineEditWithButton lewb; lewb.resize( 200, 50 ); lewb.show(); return app.exec(); } rviz-1.12.4/src/test/map_test.py000066400000000000000000000014231300447110700165220ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from nav_msgs.msg import OccupancyGrid import rospy import math topic = 'moving_map' publisher = rospy.Publisher(topic, OccupancyGrid) rospy.init_node('map_test') grid = OccupancyGrid() t = 0 while not rospy.is_shutdown(): grid.header.frame_id = "/map" grid.header.stamp = rospy.Time.now() grid.info.map_load_time = rospy.Time.now() grid.info.resolution = 1.0 grid.info.width = 3 grid.info.height = 3 grid.info.origin.position.x = math.cos( t ) grid.info.origin.position.y = math.sin( t ) grid.info.origin.orientation.w = 1.0 grid.data = [0, 20, 40, 60, 80, 100, 120, -10, -100] # Publish the MarkerArray publisher.publish( grid ) rospy.sleep(.05) t += .1 rviz-1.12.4/src/test/marker_array_test.py000077500000000000000000000024231300447110700204300ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('visualization_marker_tutorials') from visualization_msgs.msg import Marker from visualization_msgs.msg import MarkerArray import rospy import math topic = 'visualization_marker_array' publisher = rospy.Publisher(topic, MarkerArray) rospy.init_node('register') markerArray = MarkerArray() count = 0 MARKERS_MAX = 100 while not rospy.is_shutdown(): marker = Marker() marker.header.frame_id = "/base_link" marker.type = marker.SPHERE marker.action = marker.ADD marker.scale.x = 0.2 marker.scale.y = 0.2 marker.scale.z = 0.2 marker.color.a = 1.0 marker.color.r = 1.0 marker.color.g = 1.0 marker.color.b = 0.0 marker.pose.orientation.w = 1.0 marker.pose.position.x = math.cos(count / 50.0) marker.pose.position.y = math.cos(count / 40.0) marker.pose.position.z = math.cos(count / 30.0) # We add the new marker to the MarkerArray, removing the oldest marker from it when necessary if(count > MARKERS_MAX): markerArray.markers.pop(0) markerArray.markers.append(marker) # Renumber the marker IDs id = 0 for m in markerArray.markers: m.id = id id += 1 # Publish the MarkerArray publisher.publish(markerArray) count += 1 rospy.sleep(0.01) rviz-1.12.4/src/test/marker_test.cpp000066400000000000000000000473221300447110700173700ustar00rootroot00000000000000#include "ros/ros.h" #include "visualization_msgs/Marker.h" #include "visualization_msgs/MarkerArray.h" #include #include ros::Publisher g_marker_pub; void emitRow(const std::string type_name, uint32_t type, int32_t x_pos, float r, float g, float b, ros::Duration lifetime, ros::Publisher& pub, bool frame_locked = true, std::string frame_id = std::string("/base_link"), float sx = 1.0, float sy = 1.0, float sz = 1.0) { static uint32_t count = 0; for (int i = -5; i < 5; ++i) { visualization_msgs::Marker marker; marker.header.frame_id = frame_id; ros::Time ros_time = ros::Time::now(); // ros_time.sec -=1; marker.header.stamp = ros_time; marker.ns = "marker_test_" + type_name; marker.id = i; marker.type = type; marker.action = visualization_msgs::Marker::ADD; marker.pose.position.x = x_pos; marker.pose.position.y = (i * 2); marker.pose.position.z = 0; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.scale.x = sx; marker.scale.y = sy; marker.scale.z = sz; marker.color.r = r; marker.color.g = g; marker.color.b = b; marker.color.a = float(i+5) / 10.0; marker.lifetime = lifetime; marker.frame_locked = frame_locked; marker.text = "This is some text\nthis is a new line\nthis is another line\nand another adfoije owijeoiwej\na really really really really really really really really really really long one"; marker.mesh_resource = "package://pr2_description/meshes/base_v0/base.dae"; marker.mesh_use_embedded_materials = (i > int((count / 12) % 5)); pub.publish(marker); } ++count; } void publishCallback(const ros::TimerEvent&) { static uint32_t counter = 0; ROS_INFO("Publishing"); int32_t x_pos = -15; emitRow("arrows", visualization_msgs::Marker::ARROW, x_pos, 1.0, 0.0, 0.0, ros::Duration(), g_marker_pub); x_pos += 3; emitRow("cubes", visualization_msgs::Marker::CUBE, x_pos, 0.0, 1.0, 0.0, ros::Duration(), g_marker_pub); x_pos += 3; emitRow("cubes_frame_locked", visualization_msgs::Marker::CUBE, x_pos, 1.0, 1.0, 0.0, ros::Duration(), g_marker_pub, true, "/my_link"); x_pos += 3; emitRow("spheres", visualization_msgs::Marker::SPHERE, x_pos, 0.0, 0.0, 1.0, ros::Duration(), g_marker_pub); x_pos += 3; emitRow("cylinder", visualization_msgs::Marker::CYLINDER, x_pos, 1.0, 0.0, 0.0, ros::Duration(), g_marker_pub); x_pos += 3; emitRow("arrows_with_lifetime", visualization_msgs::Marker::ARROW, x_pos, 0.0, 1.0, 0.0, ros::Duration(0.6), g_marker_pub); x_pos += 3; emitRow("cubes_with_lifetime", visualization_msgs::Marker::CUBE, x_pos, 0.0, 0.0, 1.0, ros::Duration(0.7), g_marker_pub); x_pos += 3; emitRow("spheres_with_lifetime", visualization_msgs::Marker::SPHERE, x_pos, 1.0, 0.0, 0.0, ros::Duration(0.8), g_marker_pub); x_pos += 3; emitRow("cylinder_with_lifetime", visualization_msgs::Marker::CYLINDER, x_pos, 0.0, 1.0, 0.0, ros::Duration(0.9), g_marker_pub); x_pos += 3; emitRow("text_view_facing", visualization_msgs::Marker::TEXT_VIEW_FACING, x_pos, 1.0, 1.0, 1.0, ros::Duration(), g_marker_pub, false, "/base_link", 1.0, 1.0, 0.2); x_pos += 3; emitRow("mesh_resource", visualization_msgs::Marker::MESH_RESOURCE, x_pos, 0.0, 1.0, 1.0, ros::Duration(), g_marker_pub); x_pos += 3; emitRow("invalid_scales", visualization_msgs::Marker::CUBE, x_pos, 0.0, 1.0, 1.0, ros::Duration(), g_marker_pub, false, "/base_link", 0.0, 1.0, 1.0); x_pos += 3; { for (int i = -5; i < 5; ++i) { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_arrow_by_points"; marker.id = i; marker.type = visualization_msgs::Marker::ARROW; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.pose.position.y = i * 2; marker.scale.x = 0.25; marker.scale.y = 0.5; marker.color.r = 0.0; marker.color.g = 1.0; marker.color.b = 1.0; marker.color.a = 1.0; marker.frame_locked = true; if (counter % 2 == 0) { marker.points.resize(1); marker.points[0].x = 0.0f; marker.points[0].y = 0.0f; marker.points[0].z = 0.0f; } else { marker.points.resize(2); marker.points[0].x = 0.0f; marker.points[0].y = 0.0f; marker.points[0].z = 0.0f; marker.points[1].x = 1.0f; marker.points[1].y = 0.0f; marker.points[1].z = 0.0f; } g_marker_pub.publish(marker); } } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_cube_list"; marker.id = 0; marker.type = visualization_msgs::Marker::CUBE_LIST; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.05; marker.scale.y = 0.05; marker.scale.z = 0.05; marker.color.r = 1.0; marker.color.g = 1.0; marker.color.b = 0.0; marker.color.a = 1.0; marker.frame_locked = true; for (int x = 0; x < 10; ++x) { for (int y = 0; y < 10; ++y) { for (int z = 0; z < 10; ++z) { geometry_msgs::Point p; p.x = x * 0.1f; p.y = y * 0.1f; p.z = z * 0.1f; marker.points.push_back(p); } } } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_cube_list_color_per"; marker.id = 0; marker.type = visualization_msgs::Marker::CUBE_LIST; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.05; marker.scale.y = 0.05; marker.scale.z = 0.05; marker.color.r = 1.0; marker.color.g = 1.0; marker.color.b = 0.0; marker.color.a = 1.0; marker.frame_locked = true; for (int x = 0; x < 10; ++x) { for (int y = 0; y < 10; ++y) { for (int z = 0; z < 10; ++z) { geometry_msgs::Point p; p.x = x * 0.1f; p.y = y * 0.1f; p.z = z * 0.1f; marker.points.push_back(p); std_msgs::ColorRGBA c; c.r = x * 0.1; c.g = y * 0.1; c.b = z * 0.1; c.a = 1.0; marker.colors.push_back(c); } } } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_point_list_alpha_per"; marker.id = 0; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.05; marker.scale.y = 0.05; marker.scale.z = 0.05; marker.color.r = 1.0; marker.color.g = 1.0; marker.color.b = 0.0; marker.color.a = 1.0; marker.frame_locked = true; for( int type = visualization_msgs::Marker::CUBE_LIST; type <= visualization_msgs::Marker::POINTS; type++ ) { marker.id = type; marker.pose.position.x += 0.5; marker.type = type; for (int y = 0; y < 10; ++y) { geometry_msgs::Point p; p.x = 0; p.y = y * 0.1f; p.z = 0; marker.points.push_back(p); std_msgs::ColorRGBA c; c.r = 1; c.g = 1; c.b = 1; c.a = (float)y * 0.1 + 0.1; marker.colors.push_back(c); } g_marker_pub.publish(marker); } } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_sphere_list"; marker.id = 0; marker.type = visualization_msgs::Marker::SPHERE_LIST; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.05; marker.scale.y = 0.05; marker.scale.z = 0.05; marker.color.r = 1.0; marker.color.g = 1.0; marker.color.b = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int x = 0; x < 10; ++x) { for (int y = 0; y < 10; ++y) { for (int z = 0; z < 1; ++z) { geometry_msgs::Point p; p.x = x * 0.1f; p.y = y * 0.1f; p.z = z * 0.1f; marker.points.push_back(p); std_msgs::ColorRGBA c; c.r = x * 0.1; c.g = y * 0.1; c.b = 0.5; c.a = 1.0; marker.colors.push_back(c); } } } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_points"; marker.id = 0; marker.type = visualization_msgs::Marker::POINTS; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.02; marker.scale.y = 0.02; marker.scale.z = 0.02; marker.color.r = 1.0; marker.color.g = 0.0; marker.color.b = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int x = 0; x < 10; ++x) { for (int y = 0; y < 10; ++y) { for (int z = 0; z < 10; ++z) { geometry_msgs::Point p; p.x = x * 0.1f; p.y = y * 0.1f; p.z = z * 0.1f; marker.points.push_back(p); } } } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_points_color_per"; marker.id = 0; marker.type = visualization_msgs::Marker::POINTS; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.02; marker.scale.y = 0.02; marker.scale.z = 0.02; marker.color.r = 1.0; marker.color.g = 0.0; marker.color.b = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int x = 0; x < 10; ++x) { for (int y = 0; y < 10; ++y) { for (int z = 0; z < 10; ++z) { geometry_msgs::Point p; p.x = x * 0.1f; p.y = y * 0.1f; p.z = z * 0.1f; marker.points.push_back(p); std_msgs::ColorRGBA c; c.r = x * 0.1; c.g = y * 0.1; c.b = z * 0.1; c.a = 1.0; marker.colors.push_back(c); } } } g_marker_pub.publish(marker); } x_pos += 3; { int count = 10; visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_line_list"; marker.id = 0; marker.type = visualization_msgs::Marker::LINE_LIST; marker.action = visualization_msgs::Marker::ADD; marker.pose.position.x = 0.0; marker.pose.position.y = 0.0; marker.pose.position.z = 0.0; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.1; marker.color.r = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int i = 0; i < count; ++i) { geometry_msgs::Point p1, p2; p1.x = 0; p1.y = (i - count / 2) * 2; p1.z = 0; p2.x = 0; p2.y = (i - count / 2) * 2; p2.z = 1; marker.points.push_back(p1); marker.points.push_back(p2); } g_marker_pub.publish(marker); } x_pos += 3; { int count = 10; visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_line_list_color_per"; marker.id = 0; marker.type = visualization_msgs::Marker::LINE_LIST; marker.action = visualization_msgs::Marker::ADD; marker.pose.position.x = 0.0; marker.pose.position.y = 0.0; marker.pose.position.z = 0.0; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.1; marker.color.r = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int i = 0; i < count; ++i) { geometry_msgs::Point p1, p2; p1.x = 0; p1.y = (i - count / 2) * 2; p1.z = 0; p2.x = 0; p2.y = (i - count / 2) * 2; p2.z = 1; marker.points.push_back(p1); marker.points.push_back(p2); std_msgs::ColorRGBA c; float pct = (float)i / (float)count; c.r = pct * 1.0 + (1 - pct) * 0.0; c.g = pct * 0.0 + (1 - pct) * 0.0; c.b = pct * 0.0 + (1 - pct) * 1.0; c.a = 1.0; marker.colors.push_back(c); marker.colors.push_back(c); } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_line_strip"; marker.id = 0; marker.type = visualization_msgs::Marker::LINE_STRIP; marker.action = visualization_msgs::Marker::ADD; marker.pose.position.x = 0.0; marker.pose.position.y = 0.0; marker.pose.position.z = 0.0; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.1; marker.color.g = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int i = -5; i < 5; ++i) { geometry_msgs::Point p; p.x = 1 + (i % 2); p.y = (i * 2); p.z = 0; marker.points.push_back(p); } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_line_strip_color_per"; marker.id = 0; marker.type = visualization_msgs::Marker::LINE_STRIP; marker.action = visualization_msgs::Marker::ADD; marker.pose.position.x = 0.0; marker.pose.position.y = 0.0; marker.pose.position.z = 0.0; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 0.1; marker.color.g = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int i = -5; i < 5; ++i) { geometry_msgs::Point p; p.x = 1 + (i % 2); p.y = (i * 2); p.z = 0; marker.points.push_back(p); std_msgs::ColorRGBA c; float pct = (i + 5) / 10.0; c.r = pct * 0.0 + (1 - pct) * 0.0; c.g = pct * 1.0 + (1 - pct) * 0.0; c.b = pct * 0.0 + (1 - pct) * 1.0; c.a = 1.0; marker.colors.push_back(c); } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_triangle_list"; marker.id = 0; marker.type = visualization_msgs::Marker::TRIANGLE_LIST; marker.action = visualization_msgs::Marker::ADD; marker.pose.position.x = 0.0; marker.pose.position.y = 0.0; marker.pose.position.z = 0.0; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 1.0; marker.scale.y = 1.0; marker.scale.z = 1.0; marker.color.g = 1.0; marker.color.a = 1.0; marker.frame_locked = true; for (int x = 0; x < 10; ++x) { for (int y = 0; y < 10; ++y) { for (int z = 0; z < 10; ++z) { geometry_msgs::Point p; p.x = x * 0.1f; p.y = y * 0.1f; p.z = z * 0.1f; geometry_msgs::Point p2 = p; p2.x = p.x + 0.05; geometry_msgs::Point p3 = p; p3.x = p2.x; p3.z = p.z + 0.05; marker.points.push_back(p); marker.points.push_back(p2); marker.points.push_back(p3); std_msgs::ColorRGBA c; c.r = x * 0.1; c.g = y * 0.1; c.b = z * 0.1; c.a = 1.0; marker.colors.push_back(c); marker.colors.push_back(c); marker.colors.push_back(c); } } } g_marker_pub.publish(marker); } x_pos += 3; { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "marker_test_mesh_color_change"; marker.id = 0; marker.type = visualization_msgs::Marker::MESH_RESOURCE; marker.action = visualization_msgs::Marker::ADD; marker.pose.position.x = 0.0; marker.pose.position.y = 0.0; marker.pose.position.z = 0.0; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.pose.position.x = x_pos; marker.scale.x = 1.0; marker.scale.y = 1.0; marker.scale.z = 1.0; marker.color.r = float(counter % 255) / 255; marker.color.g = float((counter*3) % 255) / 255; marker.color.b = float((counter*10) % 255) / 255; marker.color.a = 1.0; marker.frame_locked = true; marker.mesh_resource = "package://pr2_description/meshes/base_v0/base.dae"; marker.mesh_use_embedded_materials = false; g_marker_pub.publish(marker); } ++counter; } void frameCallback(const ros::TimerEvent&) { static uint32_t counter = 0; static tf::TransformBroadcaster br; tf::Transform t; t.setOrigin(tf::Vector3(0.0, 0.0, (counter % 1000) * 0.01)); t.setRotation(tf::Quaternion(0.0, 0.0, 0.0, 1.0)); br.sendTransform(tf::StampedTransform(t, ros::Time::now(), "base_link", "my_link")); t.setOrigin(tf::Vector3(0.0, 0.0, 0.0)); t.setRotation(tf::createQuaternionFromRPY(M_PI*0.25, M_PI*0.25, 0.0)); br.sendTransform(tf::StampedTransform(t, ros::Time::now(), "rotate_base_link", "base_link")); ++counter; } int main(int argc, char** argv) { ros::init(argc, argv, "marker_test"); ros::NodeHandle n; g_marker_pub = n.advertise ("visualization_marker", 0); ros::Timer publish_timer = n.createTimer(ros::Duration(1), publishCallback); ros::Timer frame_timer = n.createTimer(ros::Duration(0.01), frameCallback); tf::TransformBroadcaster tf_broadcaster; ros::Duration(0.1).sleep(); ros::spin(); } rviz-1.12.4/src/test/mesh_marker_test.cpp000066400000000000000000000067121300447110700204020ustar00rootroot00000000000000#include "ros/ros.h" #include "visualization_msgs/Marker.h" #include "visualization_msgs/MarkerArray.h" #include #include ros::Publisher g_marker_pub; void publishMesh( int id, float x, float y, float r, float g, float b, float a, bool use_embedded_materials, bool mesh ) { visualization_msgs::Marker marker; marker.header.frame_id = "/base_link"; marker.header.stamp = ros::Time::now(); marker.ns = "mesh"; marker.type = mesh ? (int) visualization_msgs::Marker::MESH_RESOURCE : (int) visualization_msgs::Marker::SPHERE; marker.action = visualization_msgs::Marker::ADD; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.1; marker.pose.orientation.w = 1.0; marker.scale.x = 1; marker.scale.y = 1; marker.scale.z = 1; marker.color.r = r; marker.color.g = g; marker.color.b = b; marker.color.a = a; marker.frame_locked = true; marker.mesh_resource = "package://rviz/src/test/meshes/pr2-base.dae"; marker.mesh_use_embedded_materials = use_embedded_materials; marker.id = id; marker.pose.position.x = x; marker.pose.position.y = y; g_marker_pub.publish(marker); } void publishCallback(const ros::TimerEvent&) { static uint32_t counter = 0; ROS_INFO("Publishing"); int id = 0; float x = 0; float y = 0; publishMesh( id, x, y, 1, 1, 1, 1, true, true); id++; x++; publishMesh( id, x, y, 1, 1, 1, .5, true, true); id++; x++; publishMesh( id, x, y, 1, 1, 1, 0, true, true); id++; x++; publishMesh( id, x, y, 1, 0, 0, 1, true, true); id++; x++; publishMesh( id, x, y, 1, 0, 0, .5, true, true); id++; x++; publishMesh( id, x, y, 1, 0, 0, 0, true, true); id++; x++; publishMesh( id, x, y, 1, .5, .5, 1, true, true); id++; x++; publishMesh( id, x, y, 1, .5, .5, .5, true, true); id++; x++; publishMesh( id, x, y, 1, .5, .5, 0, true, true); id++; x++; y++; x = 0; publishMesh( id, x, y, 1, 1, 1, 1, false, true); id++; x++; publishMesh( id, x, y, 1, 1, 1, .5, false, true); id++; x++; publishMesh( id, x, y, 1, 1, 1, 0, false, true); id++; x++; publishMesh( id, x, y, 1, 0, 0, 1, false, true); id++; x++; publishMesh( id, x, y, 1, 0, 0, .5, false, true); id++; x++; publishMesh( id, x, y, 1, 0, 0, 0, false, true); id++; x++; publishMesh( id, x, y, 1, .5, .5, 1, false, true); id++; x++; publishMesh( id, x, y, 1, .5, .5, .5, false, true); id++; x++; publishMesh( id, x, y, 1, .5, .5, 0, false, true); id++; x++; y++; x = 0; publishMesh( id, x, y, 1, 1, 1, 1, true, false); id++; x++; publishMesh( id, x, y, 1, 1, 1, .5, true, false); id++; x++; publishMesh( id, x, y, 1, 1, 1, 0, true, false); id++; x++; publishMesh( id, x, y, 1, 0, 0, 1, true, false); id++; x++; publishMesh( id, x, y, 1, 0, 0, .5, true, false); id++; x++; publishMesh( id, x, y, 1, 0, 0, 0, true, false); id++; x++; publishMesh( id, x, y, 1, .5, .5, 1, true, false); id++; x++; publishMesh( id, x, y, 1, .5, .5, .5, true, false); id++; x++; publishMesh( id, x, y, 1, .5, .5, 0, true, false); id++; x++; y++; x = 0; publishMesh( id, x, y, 0, 0, 0, 0, true, true); id++; x++; ++counter; } int main(int argc, char** argv) { ros::init(argc, argv, "mesh_marker_test"); ros::NodeHandle n; g_marker_pub = n.advertise ("mesh_markers", 0); ros::Timer publish_timer = n.createTimer(ros::Duration(1), publishCallback); ros::Duration(0.1).sleep(); ros::spin(); } rviz-1.12.4/src/test/meshes/000077500000000000000000000000001300447110700156205ustar00rootroot00000000000000rviz-1.12.4/src/test/meshes/16bit_vs_32bit_should_fail.stl000066400000000000000000000002701300447110700233540ustar00rootroot00000000000000Binary STL fileff=L>>>??333?L?fff??̌??̌??ff?33????ff?33?@ff@ @rviz-1.12.4/src/test/meshes/ascii.stl000066400000000000000000000010371300447110700174350ustar00rootroot00000000000000solid ascii.stl facet normal 0.648000e-001 0.648000e-002 0.648000e-003 outer loop vertex 1.648000e-001 2.648000e-002 3.648000e-003 vertex 4.648000e-001 5.648000e-002 6.648000e-003 vertex 7.648000e-001 8.648000e-002 9.648000e-003 end loop end facet facet normal 4.648000e-001 4.648000e-002 4.648000e-003 outer loop vertex 10.648000e-001 11.648000e-002 12.648000e-003 vertex 13.648000e-001 14.648000e-002 15.648000e-003 vertex 16.648000e-001 17.648000e-002 18.648000e-003 end loop end facet endsolid ascii.stl rviz-1.12.4/src/test/meshes/invalid.stl000066400000000000000000000002571300447110700177760ustar00rootroot00000000000000Binary STL file=L>>>??333?L?fff??̌??̌??ff?33????ff?33?@ff rviz-1.12.4/src/test/meshes/invalid_short.stl000066400000000000000000000001061300447110700212060ustar00rootroot00000000000000Binary STL filerviz-1.12.4/src/test/meshes/valid.stl000066400000000000000000000002701300447110700174420ustar00rootroot00000000000000Binary STL file=L>>>??333?L?fff??̌??̌??ff?33????ff?33?@ff@ @rviz-1.12.4/src/test/meshes/valid_extra.stl000066400000000000000000000003221300447110700206430ustar00rootroot00000000000000Binary STL file=L>>>??333?L?fff??̌??̌??ff?33????ff?33?@ff@ @Extra data to be ignored. rviz-1.12.4/src/test/mock_context.cpp000066400000000000000000000034031300447110700175350ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "mock_display_factory.h" #include "mock_context.h" namespace rviz { MockContext::MockContext() : display_factory_( new MockDisplayFactory ) { } } // end namespace rviz rviz-1.12.4/src/test/mock_context.h000066400000000000000000000060161300447110700172050ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef MOCK_CONTEXT_H #define MOCK_CONTEXT_H #include namespace rviz { class MockContext: public DisplayContext { public: MockContext(); virtual Ogre::SceneManager* getSceneManager() const { return 0; } virtual WindowManagerInterface* getWindowManager() const { return 0; } virtual SelectionManager* getSelectionManager() const { return 0; } virtual FrameManager* getFrameManager() const { return 0; } virtual tf::TransformListener* getTFClient() const { return 0; } virtual QString getFixedFrame() const { return ""; } virtual uint64_t getFrameCount() const { return 0; } virtual DisplayFactory* getDisplayFactory() const { return display_factory_; } virtual ros::CallbackQueueInterface* getUpdateQueue() { return 0; } virtual ros::CallbackQueueInterface* getThreadedQueue() { return 0; } virtual void handleChar( QKeyEvent* event, RenderPanel* panel ) {} virtual void handleMouseEvent( const ViewportMouseEvent& event ) {} virtual ToolManager* getToolManager() const { return 0; } virtual ViewManager* getViewManager() const { return 0; } virtual DisplayGroup* getRootDisplayGroup() const { return 0; } virtual uint32_t getDefaultVisibilityBit() const { return 0; } virtual BitAllocator* visibilityBits() { return 0; } virtual void setStatus( const QString & message ) {} virtual void queueRender() {} private: DisplayFactory* display_factory_; }; } // end namespace rviz #endif // MOCK_CONTEXT_H rviz-1.12.4/src/test/mock_display.cpp000066400000000000000000000042211300447110700175150ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "mock_display.h" namespace rviz { MockDisplay::MockDisplay() { count_ = new Property( "Count", 10, "How many?", this ); style_ = new Property( "Style", "chunky", "What style?", this ); pi_ = new Property( "Pi", 3.14159, "Circumference over diameter", this ); offset_ = new VectorProperty( "Offset", Ogre::Vector3( 1, 2, 3 ), "Translation", this ); color_ = new ColorProperty( "Color", QColor( 10, 20, 30 ), "Color", this ); } } // end namespace rviz rviz-1.12.4/src/test/mock_display.h000066400000000000000000000036751300447110700171760ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef MOCK_DISPLAY_H #define MOCK_DISPLAY_H #include "rviz/display.h" namespace rviz { class VectorProperty; class ColorProperty; class MockDisplay: public Display { Q_OBJECT public: MockDisplay(); Property* count_; Property* style_; Property* pi_; VectorProperty* offset_; ColorProperty* color_; }; } // end namespace rviz #endif // MOCK_DISPLAY_H rviz-1.12.4/src/test/mock_display_factory.cpp000066400000000000000000000041151300447110700212460ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "mock_display.h" #include "mock_display_factory.h" namespace rviz { Display* MockDisplayFactory::makeRaw( const QString& class_id, QString* error_return ) { if( class_id == "MockDisplay" ) { return new MockDisplay(); } else if( class_id == "DisplayGroup" ) { return new DisplayGroup(); } else { if( error_return ) { *error_return = "MockDisplayFactory cannot make a " + class_id; } return 0; } } } // end namespace rviz rviz-1.12.4/src/test/mock_display_factory.h000066400000000000000000000036171300447110700207210ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef MOCK_DISPLAY_FACTORY_H #define MOCK_DISPLAY_FACTORY_H #include namespace rviz { class MockDisplayFactory: public DisplayFactory { protected: virtual Display* makeRaw( const QString& class_id, QString* error_return = NULL ); }; } // end namespace rviz #endif // MOCK_DISPLAY_FACTORY_H rviz-1.12.4/src/test/mock_property_change_receiver.cpp000066400000000000000000000040401300447110700231240ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "mock_property_change_receiver.h" namespace rviz { MockPropertyChangeReceiver::MockPropertyChangeReceiver( Property* property ) : property_( property ) {} void MockPropertyChangeReceiver::aboutToChange() { result_ += " aboutToChange, v=" + property_->getValue().toString(); } void MockPropertyChangeReceiver::changed() { result_ += " changed, v=" + property_->getValue().toString(); } } // end namespace rviz rviz-1.12.4/src/test/mock_property_change_receiver.h000066400000000000000000000041051300447110700225730ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef MOCK_PROPERTY_CHANGE_RECEIVER_H #define MOCK_PROPERTY_CHANGE_RECEIVER_H #include namespace rviz { class Property; class MockPropertyChangeReceiver: public QObject { Q_OBJECT public: MockPropertyChangeReceiver( Property* prop ); void reset() { result_ = ""; } QString result() { return result_; } public Q_SLOTS: void aboutToChange(); void changed(); private: QString result_; Property* property_; }; } // end namespace rviz #endif // MOCK_PROPERTY_CHANGE_RECEIVER_H rviz-1.12.4/src/test/new_display_dialog_test.cpp000066400000000000000000000050261300447110700217370ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "rviz/display.h" #include "rviz/pluginlib_factory.h" #include "rviz/new_object_dialog.h" int main( int argc, char **argv ) { QApplication app( argc, argv ); QString lookup_name; QString display_name; rviz::PluginlibFactory * factory = new rviz::PluginlibFactory( "rviz", "rviz::Display" ); typedef std::set > S_string; QStringList current_names; current_names << "Chub" << "Town"; QStringList empty; rviz::NewObjectDialog* dialog = new rviz::NewObjectDialog( factory, QString("Display"), current_names, empty, &lookup_name, &display_name, 0 ); if( dialog->exec() == QDialog::Accepted ) { printf( "lookup_name='%s', display_name='%s'\n", lookup_name.toStdString().c_str(), display_name.toStdString().c_str() ); } else { printf( "cancelled\n" ); } } rviz-1.12.4/src/test/posearray.py000077500000000000000000000015571300447110700167260ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from geometry_msgs.msg import Pose from geometry_msgs.msg import PoseArray import rospy topic = 'test_poses' publisher = rospy.Publisher(topic, PoseArray) rospy.init_node('posearray') while not rospy.is_shutdown(): ps = PoseArray() ps.header.frame_id = "/base_link" ps.header.stamp = rospy.Time.now() pose = Pose() pose.position.x = 2 pose.position.y = 2 pose.position.z = 0 pose.orientation.x = 0 pose.orientation.y = 0 pose.orientation.z = .7071 pose.orientation.w = .7071 ps.poses.append( pose ) pose = Pose() pose.position.x = 1 pose.position.y = 1 pose.position.z = 0 pose.orientation.x = 0 pose.orientation.y = 0 pose.orientation.z = 0 pose.orientation.w = 1 ps.poses.append( pose ) publisher.publish( ps ) rospy.sleep(0.1) rviz-1.12.4/src/test/property_test.cpp000066400000000000000000000240141300447110700177640ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "mock_property_change_receiver.h" using namespace rviz; TEST( Property, name ) { Property p; p.setName( "chub" ); EXPECT_EQ( "chub", p.getName().toStdString() ); } TEST( Property, description ) { Property p; p.setDescription( "chub" ); EXPECT_EQ( "chub", p.getDescription().toStdString() ); } TEST( Property, value ) { Property p; p.setValue( 199 ); EXPECT_EQ( 199, p.getValue().toInt() ); } TEST( Property, set_value_events ) { Property p; p.setValue( 0 ); MockPropertyChangeReceiver r( &p ); p.connect( &p, SIGNAL( aboutToChange() ), &r, SLOT( aboutToChange() )); p.connect( &p, SIGNAL( changed() ), &r, SLOT( changed() )); p.setValue( 17 ); EXPECT_EQ( " aboutToChange, v=0 changed, v=17", r.result().toStdString() ); } TEST( Property, children ) { Property* display = new Property( "Test" ); new Property( "Alpha", 0.5, "The amount of transparency to apply to the grid lines.", display ); Property* beta = new Property( "Beta Band", 10, "The number of betas to apply to the grid lines.", display ); new Property( "Gamma Topic", "chubby", "The topic on which to listen for Gamma messages.", display ); Property* position = new Property( "Position", QVariant(), "Position of the chub.", display ); new Property( "X", 1.1f, "X component of the position of the chub.", position ); new Property( "Y", 0.717f, "Y component of the position of the chub.", position ); // Sample usage inside the Display which owns the property. int b = beta->getValue().toInt(); EXPECT_EQ( 10, b ); // Sample usage outside the Display beta->setValue( 12 ); EXPECT_EQ( 12, display->subProp( "Beta Band" )->getValue().toInt() ); // Compound property float y = display->subProp( "Position" )->subProp( "Y" )->getValue().toFloat(); EXPECT_EQ( 0.717f, y ); // Accessing a missing property should not crash. printf( "Next line should say 'ERROR' but not crash.\n" ); display->subProp( "Position" )->subProp( "Z" )->getValue().toFloat(); } TEST( VectorProperty, default_value ) { VectorProperty* vp = new VectorProperty(); Ogre::Vector3 vec = vp->getVector(); EXPECT_EQ( 0, vec.x ); EXPECT_EQ( 0, vec.y ); EXPECT_EQ( 0, vec.z ); } TEST( VectorProperty, set_and_get ) { VectorProperty* vp = new VectorProperty(); Ogre::Vector3 vec( 1, 2, 3 ); vp->setVector( vec ); Ogre::Vector3 vec2 = vp->getVector(); EXPECT_EQ( 1, vec2.x ); EXPECT_EQ( 2, vec2.y ); EXPECT_EQ( 3, vec2.z ); } TEST( VectorProperty, set_string ) { VectorProperty* vp = new VectorProperty(); vp->setValue( QString( "1;2;3" )); Ogre::Vector3 vec = vp->getVector(); EXPECT_EQ( 1, vec.x ); EXPECT_EQ( 2, vec.y ); EXPECT_EQ( 3, vec.z ); vp->setValue( QString( "chubby!" )); vec = vp->getVector(); EXPECT_EQ( 1, vec.x ); EXPECT_EQ( 2, vec.y ); EXPECT_EQ( 3, vec.z ); } TEST( VectorProperty, set_child ) { VectorProperty* vp = new VectorProperty(); vp->subProp( "X" )->setValue( 0.9 ); vp->subProp( "Y" )->setValue( 1.1 ); vp->subProp( "Z" )->setValue( 1.3 ); Ogre::Vector3 vec = vp->getVector(); EXPECT_EQ( 0.9f, vec.x ); EXPECT_EQ( 1.1f, vec.y ); EXPECT_EQ( 1.3f, vec.z ); } TEST( VectorProperty, get_child ) { VectorProperty* vp = new VectorProperty( "v", Ogre::Vector3( 1, 2, 3 )); EXPECT_EQ( 1, vp->subProp( "X" )->getValue().toFloat() ); EXPECT_EQ( 2, vp->subProp( "Y" )->getValue().toFloat() ); EXPECT_EQ( 3, vp->subProp( "Z" )->getValue().toFloat() ); } TEST( VectorProperty, set_value_events ) { VectorProperty p; MockPropertyChangeReceiver r( &p ); p.connect( &p, SIGNAL( aboutToChange() ), &r, SLOT( aboutToChange() )); p.connect( &p, SIGNAL( changed() ), &r, SLOT( changed() )); p.setVector( Ogre::Vector3( .1, .0001, 1000 )); EXPECT_EQ( " aboutToChange, v=0; 0; 0 changed, v=0.1; 0.0001; 1000", r.result().toStdString() ); r.reset(); p.subProp( "Z" )->setValue( 2.1 ); EXPECT_EQ( " aboutToChange, v=0.1; 0.0001; 1000 changed, v=0.1; 0.0001; 2.1", r.result().toStdString() ); } TEST( QuaternionProperty, default_value ) { QuaternionProperty* qp = new QuaternionProperty(); Ogre::Quaternion quat = qp->getQuaternion(); EXPECT_EQ( 0, quat.x ); EXPECT_EQ( 0, quat.y ); EXPECT_EQ( 0, quat.z ); EXPECT_EQ( 1, quat.w ); } TEST( QuaternionProperty, set_and_get ) { QuaternionProperty* qp = new QuaternionProperty(); Ogre::Quaternion quat( 4, 1, 2, 3 ); qp->setQuaternion( quat ); Ogre::Quaternion quat2 = qp->getQuaternion(); EXPECT_EQ( 1, quat2.x ); EXPECT_EQ( 2, quat2.y ); EXPECT_EQ( 3, quat2.z ); EXPECT_EQ( 4, quat2.w ); } TEST( QuaternionProperty, set_string ) { QuaternionProperty* qp = new QuaternionProperty(); qp->setValue( QString( "1;2;3;4" )); Ogre::Quaternion quat = qp->getQuaternion(); EXPECT_EQ( 1, quat.x ); EXPECT_EQ( 2, quat.y ); EXPECT_EQ( 3, quat.z ); EXPECT_EQ( 4, quat.w ); qp->setValue( QString( "chubby!" )); quat = qp->getQuaternion(); EXPECT_EQ( 1, quat.x ); EXPECT_EQ( 2, quat.y ); EXPECT_EQ( 3, quat.z ); EXPECT_EQ( 4, quat.w ); } TEST( QuaternionProperty, set_child ) { QuaternionProperty* qp = new QuaternionProperty(); qp->subProp( "X" )->setValue( 0.9 ); qp->subProp( "Y" )->setValue( 1.1 ); qp->subProp( "Z" )->setValue( 1.3 ); qp->subProp( "W" )->setValue( 1.5 ); Ogre::Quaternion quat = qp->getQuaternion(); EXPECT_EQ( 0.9f, quat.x ); EXPECT_EQ( 1.1f, quat.y ); EXPECT_EQ( 1.3f, quat.z ); EXPECT_EQ( 1.5f, quat.w ); } TEST( QuaternionProperty, get_child ) { QuaternionProperty* qp = new QuaternionProperty( "v", Ogre::Quaternion( 4, 1, 2, 3 )); EXPECT_EQ( 1, qp->subProp( "X" )->getValue().toFloat() ); EXPECT_EQ( 2, qp->subProp( "Y" )->getValue().toFloat() ); EXPECT_EQ( 3, qp->subProp( "Z" )->getValue().toFloat() ); EXPECT_EQ( 4, qp->subProp( "W" )->getValue().toFloat() ); } TEST( QuaternionProperty, set_value_events ) { QuaternionProperty p; MockPropertyChangeReceiver r( &p ); p.connect( &p, SIGNAL( aboutToChange() ), &r, SLOT( aboutToChange() )); p.connect( &p, SIGNAL( changed() ), &r, SLOT( changed() )); p.setQuaternion( Ogre::Quaternion( 1, .1, .0001, 1000 )); EXPECT_EQ( " aboutToChange, v=0; 0; 0; 1 changed, v=0.1; 0.0001; 1000; 1", r.result().toStdString() ); r.reset(); p.subProp( "Z" )->setValue( 2.1 ); EXPECT_EQ( " aboutToChange, v=0.1; 0.0001; 1000; 1 changed, v=0.1; 0.0001; 2.1; 1", r.result().toStdString() ); } TEST( ColorProperty, default_value ) { ColorProperty* qp = new ColorProperty(); QColor color = qp->getColor(); EXPECT_EQ( 0, color.red() ); EXPECT_EQ( 0, color.green() ); EXPECT_EQ( 0, color.blue() ); } TEST( ColorProperty, set_and_get ) { ColorProperty* qp = new ColorProperty(); QColor color( 1, 2, 3 ); qp->setColor( color ); QColor color2 = qp->getColor(); EXPECT_EQ( 1, color2.red() ); EXPECT_EQ( 2, color2.green() ); EXPECT_EQ( 3, color2.blue() ); } TEST( ColorProperty, set_string ) { ColorProperty* qp = new ColorProperty(); qp->setValue( QString( "1;2;3" )); QColor color = qp->getColor(); EXPECT_EQ( 1, color.red() ); EXPECT_EQ( 2, color.green() ); EXPECT_EQ( 3, color.blue() ); qp->setValue( QString( "chubby!" )); color = qp->getColor(); EXPECT_EQ( 1, color.red() ); EXPECT_EQ( 2, color.green() ); EXPECT_EQ( 3, color.blue() ); } TEST( ColorProperty, set_string_limits ) { ColorProperty* qp = new ColorProperty(); qp->setValue( QString( "-1;2000;3" )); QColor color = qp->getColor(); EXPECT_EQ( 0, color.red() ); EXPECT_EQ( 255, color.green() ); EXPECT_EQ( 3, color.blue() ); } TEST( ColorProperty, set_value_events ) { ColorProperty p; MockPropertyChangeReceiver r( &p ); p.connect( &p, SIGNAL( aboutToChange() ), &r, SLOT( aboutToChange() )); p.connect( &p, SIGNAL( changed() ), &r, SLOT( changed() )); p.setColor( QColor( 1, 2, 3 )); EXPECT_EQ( " aboutToChange, v=0; 0; 0 changed, v=1; 2; 3", r.result().toStdString() ); } TEST( EnumProperty, basic ) { EnumProperty p; EXPECT_EQ( 0, p.getOptionInt() ); p.addOption( "chub", 10 ); EXPECT_EQ( 0, p.getOptionInt() ); p.addOption( "foo", 3 ); p.addOption( "bar", 999 ); p.setValue( "chub" ); EXPECT_EQ( 10, p.getOptionInt() ); p.clearOptions(); EXPECT_EQ( 0, p.getOptionInt() ); } int main( int argc, char **argv ) { testing::InitGoogleTest( &argc, argv ); return RUN_ALL_TESTS(); } rviz-1.12.4/src/test/publish_test_map.py000066400000000000000000000007161300447110700202540ustar00rootroot00000000000000#!/usr/bin/env python import rospy import numpy from nav_msgs.msg import OccupancyGrid pub = rospy.Publisher('test_map', OccupancyGrid, latch = True) rospy.init_node('test_map') _map = OccupancyGrid() _map.header.stamp = rospy.get_rostime() _map.header.frame_id = '/map' _map.info.resolution = .1 _map.info.width = 16 _map.info.height = 16 _map.info.origin.orientation.w = 1 _map.data = [numpy.int8(x) for x in range(256)] pub.publish( _map ) rospy.spin() rviz-1.12.4/src/test/python_sample.py000077500000000000000000000153011300447110700175730ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') import sys # This setattr() call is useful only to force the use of a particular # binding scheme. It's useful for testing rviz, but can be left out # for most other users. #setattr(sys, 'SELECT_QT_BINDING', 'pyside') # Shiboken setattr(sys, 'SELECT_QT_BINDING', 'pyqt') # SIP from python_qt_binding import QT_BINDING from python_qt_binding.QtGui import * from python_qt_binding.QtCore import * import rviz if QT_BINDING == 'pyside': print "Using PySide and shiboken for rviz python bindings." elif QT_BINDING == 'pyqt': print "Using PyQt and sip for rviz python bindings." class SampleWidget( QWidget ): def __init__(self): QWidget.__init__(self) self.grid_display = None self.props = [] layout = QVBoxLayout() frame_button = QPushButton("Set Fixed Frame") frame_button.clicked.connect( self.onFrameButtonClick ) layout.addWidget( frame_button ) enable_button = QPushButton("Toggle Grid Enable") enable_button.clicked.connect( self.onEnableButtonClick ) layout.addWidget( enable_button ) thickness_slider = QSlider( Qt.Horizontal ) thickness_slider.setTracking( True ) thickness_slider.setMinimum( 1 ) thickness_slider.setMaximum( 1000 ) thickness_slider.valueChanged.connect( self.onThicknessSliderChanged ) layout.addWidget( thickness_slider ) fps_button = QPushButton("Switch to FPS") fps_button.clicked.connect( self.onFpsButtonClick ) layout.addWidget( fps_button ) h_layout = QHBoxLayout() top_button = QPushButton( "Top View" ) top_button.clicked.connect( self.onTopButtonClick ) h_layout.addWidget( top_button ) side_button = QPushButton( "Side View" ) side_button.clicked.connect( self.onSideButtonClick ) h_layout.addWidget( side_button ) look_button = QPushButton( "Look Away" ) look_button.clicked.connect( self.onLookButtonClick ) h_layout.addWidget( look_button ) layout.addLayout( h_layout ) distance_slider = QSlider( Qt.Horizontal ) distance_slider.setTracking( True ) distance_slider.setMinimum( 1 ) distance_slider.setMaximum( 1000 ) distance_slider.valueChanged.connect( self.onDistanceSliderChanged ) layout.addWidget( distance_slider ) tool_button = QPushButton( "Select" ) tool_button.clicked.connect( self.onSelectClick ) layout.addWidget( tool_button ) coolify_button = QPushButton( "Coolify Displays" ) coolify_button.clicked.connect( self.onCoolifyClick ) layout.addWidget( coolify_button ) self.setLayout( layout ) def destruct( self ): """ Disconnect internal object connections. Without something like this, it is easy to have a crash when the object goes out of scope. """ self.frame = None if self.grid_display != None: self.grid_display.getParent().takeChild( self.grid_display ) self.grid_display = None for p in self.props: p.getParent().takeChild( p ) self.props = [] def setFrame( self, vis_frame ): self.frame = vis_frame def onFrameButtonClick(self): self.frame.getManager().setFixedFrame("Python") def onEnableButtonClick(self): if self.grid_display == None: self.grid_display = self.frame.getManager().createDisplay( "rviz/Grid", "Awesome grid", True ) self.grid_display.subProp( "Line Style" ).setValue( "Billboards" ) else: self.grid_display.setEnabled( not self.grid_display.isEnabled() ) def onThicknessSliderChanged( self, new_value ): if self.grid_display != None: self.grid_display.subProp( "Line Style" ).subProp( "Line Width" ).setValue( new_value / 1000.0 ) prop = rviz.Property( "Prop " + str(new_value), new_value / 1000.0, "Bad idea property generation" ) self.grid_display.addChild( prop ) self.props.append( prop ) def onDistanceSliderChanged( self, new_value ): controller = self.frame.getManager().getViewManager().getCurrent() if controller != None: controller.subProp( "Distance" ).setValue( new_value / 10.0 ) def onFpsButtonClick( self ): self.frame.getManager().getViewManager().setCurrentViewControllerType( "rviz/FPS" ) def onTopButtonClick( self ): self.switchToView( "Top View" ); def onSideButtonClick( self ): self.switchToView( "Side View" ); def onLookButtonClick( self ): controller = self.frame.getManager().getViewManager().getCurrent() if controller != None: controller.lookAt( 5, 5, 0 ) def switchToView( self, view_name ): view_man = self.frame.getManager().getViewManager() for i in range( view_man.getNumViews() ): if view_man.getViewAt( i ).getName() == view_name: view_man.setCurrentFrom( view_man.getViewAt( i )) return print( "Did not find view named %s." % view_name ) def onSelectClick( self ): tool_man = self.frame.getManager().getToolManager() for i in range( tool_man.numTools() ): if tool_man.getTool( i ).getName() == "Select": tool_man.setCurrentTool( tool_man.getTool( i )) return def onCoolifyClick( self ): self.coolify( self.frame.getManager().getRootDisplayGroup() ) def coolify( self, group ): for i in range( group.numDisplays() ): display = group.getDisplayAt( i ) display.setName( "Cool " + display.getName() ) subgroup = group.getGroupAt( i ) if subgroup != None: self.coolify( subgroup ) def fun(): # rviz.OgreLogging.noLog() # (no log is the default) # rviz.OgreLogging.useStandardOut() # rviz.OgreLogging.useLogFile( "frame_test.ogre-log" ) app = QApplication( sys.argv ) frame = rviz.VisualizationFrame() frame.initialize() frame.show() sw = SampleWidget() sw.setFrame( frame ) sw.show() frame.addPane( "Button", sw ) app.exec_() # Without this destruct() call, this program crashes just after # the "after exec_()" printout, when "sw" goes out of scope and is # destroyed. sw.destruct() print "after exec_()" if __name__ == '__main__': # This fun() function call is just here to demonstrate rviz # objects going out of scope and being cleaned up correctly. fun() print "after fun()" rviz-1.12.4/src/test/render_panel_test.cpp000066400000000000000000000044631300447110700205440ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "ros/ros.h" #include "rviz/visualization_manager.h" #include "rviz/render_panel.h" #include "rviz/displays_panel.h" using namespace rviz; int main(int argc, char **argv) { QApplication app( argc, argv ); ros::init( argc, argv, "render_panel_test" ); DisplaysPanel* displays_panel = new DisplaysPanel; RenderPanel* render_panel = new RenderPanel(); VisualizationManager* vman = new VisualizationManager( render_panel ); render_panel->initialize( vman->getSceneManager(), vman ); displays_panel->initialize( vman ); vman->initialize(); vman->startUpdate(); render_panel->show(); displays_panel->show(); vman->createDisplay( "rviz/Grid", "My Grid", true ); return app.exec(); } rviz-1.12.4/src/test/render_points_test.cpp000066400000000000000000000204171300447110700207560ustar00rootroot00000000000000/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "test/render_points_test.h" #include #include #include #include using namespace rviz; MyFrame::MyFrame( QWidget* parent ) : QWidget(parent) , left_mouse_down_( false ) , middle_mouse_down_( false ) , right_mouse_down_( false ) , mouse_x_( 0 ) , mouse_y_( 0 ) { render_system_ = RenderSystem::get(); root_ = render_system_->root(); try { scene_manager_ = root_->createSceneManager( Ogre::ST_GENERIC, "TestSceneManager" ); render_panel_ = new QtOgreRenderWindow(); render_panel_->resize( this->size() ); render_panel_->setAutoRender(false); QVBoxLayout* layout = new QVBoxLayout; layout->setContentsMargins( 0, 0, 0, 0 ); layout->addWidget( render_panel_ ); setLayout( layout ); camera_ = new OrbitCamera( scene_manager_ ); camera_->setPosition( 0, 0, 15 ); camera_->getOgreCamera()->setNearClipDistance( 0.1 ); render_panel_->setCamera( camera_->getOgreCamera() ); render_panel_->setBackgroundColor( Ogre::ColourValue( 0.8,0.8,1 ) ); Ogre::Light* directional_light = scene_manager_->createLight( "MainDirectional" ); directional_light->setType( Ogre::Light::LT_DIRECTIONAL ); directional_light->setDirection( Ogre::Vector3( 0, -1, 1 ) ); directional_light->setDiffuseColour( Ogre::ColourValue( 1.0f, 1.0f, 1.0f ) ); #if 0 Grid* grid = new Grid( scene_manager_, NULL, Grid::Lines, 10, 1.0f, 0.02, Ogre::ColourValue(1.0f, 1.0f, 1.0f, 0.5f)); grid->setHeight(4); BillboardLine* line = new BillboardLine( scene_manager_, NULL ); line->setMaxPointsPerLine(105); for ( int i = -50; i < 50; ++i ) { line->addPoint( Ogre::Vector3( i*2, 0.0f, -1.0f ) ); } for ( int i = 0; i < 5; ++i ) { line->addPoint( Ogre::Vector3( 4.0f, 0.0f, i ) ); } line->setLineWidth( 0.05 ); line->setColor( 0.0f, 1.0f, 0.0f, 0.5f ); Shape* sphere = new Shape(Shape::Sphere, scene_manager_); sphere->setPosition(Ogre::Vector3(0.0f, 0.0f, 2.0f)); sphere->setColor(0.0f, 1.0f, 2.0f, 1.0f); Shape* cube = new Shape(Shape::Cube, scene_manager_); cube->setPosition(Ogre::Vector3(0.0f, 1.0f, 2.0f)); cube->setColor(1.0f, 0.0f, 0.0f, 1.0f); Shape* cylinder = new Shape(Shape::Cylinder, scene_manager_); cylinder->setPosition(Ogre::Vector3(0.0f, 2.0f, 2.0f)); cylinder->setColor(1.0f, 1.0f, 0.0f, 1.0f); Shape* cone = new Shape(Shape::Cone, scene_manager_); cone->setPosition(Ogre::Vector3(0.0f, 3.0f, 2.0f)); cone->setColor(0.0f, 0.0f, 1.0f, 1.0f); Axes* axes = new Axes( scene_manager_ ); //axes->setScale( Ogre::Vector3( 2.0f, 2.0f, 2.0f ) ); /*Cone* cone = new Cone( scene_manager_, NULL ); cone->setScale( Ogre::Vector3( 0.3f, 2.0f, 0.3f ) );*/ Arrow* arrow = new Arrow( scene_manager_ ); arrow->setHeadColor( 1.0f, 0.0f, 0.0f ); arrow->setShaftColor( 0.0f, 0.0f, 1.0f ); arrow->setOrientation( Ogre::Quaternion::IDENTITY ); //arrow->setOrientation( Ogre::Quaternion( Ogre::Degree( 45 ), Ogre::Vector3::UNIT_X ) ); //arrow->setScale( Ogre::Vector3( 1.0f, 1.0f, 3.0f ) ); #endif #if 01 Ogre::SceneNode* scene_node = scene_manager_->getRootSceneNode()->createChildSceneNode(); PointCloud* pointCloud = new PointCloud(); pointCloud->setDimensions(0.05f, 0.05f, 0.05f); //pointCloud->setColorByIndex(true); pointCloud->setRenderMode(PointCloud::RM_SQUARES); pointCloud->setCommonDirection(Ogre::Vector3(0.0, 1.0, 0.0)); pointCloud->setCommonUpVector(Ogre::Vector3(0.0, 0.0, -1.0)); pointCloud->setAlpha(1.0); std::vector points; int32_t xcount = 200; int32_t ycount = 100; int32_t zcount = 100; // points.resize(xcount * ycount * zcount); float factor = 0.1f; for (int32_t x = 0; x < xcount; ++x) { for (int32_t y = 0; y < ycount; ++y) { for (int32_t z = 0; z < zcount; ++z) { // int32_t index = (ycount*zcount*x) + zcount*y + z; PointCloud::Point point;// = points[index]; point.position.x = x * factor; point.position.y = y * factor; point.position.z = z * factor; point.setColor(x * 0.1, y * 0.1, z * 0.1); points.push_back(point); } } } printf("size: %d\n", (int)points.size()); pointCloud->addPoints( &points.front(), points.size() ); scene_node->attachObject(pointCloud); #endif } catch ( Ogre::Exception& e ) { printf( "Fatal error: %s\n", e.what() ); exit(1); } connect( &render_timer_, SIGNAL( timeout() ), this, SLOT( doRender() )); render_timer_.start(33); } MyFrame::~MyFrame() { } void MyFrame::doRender() { ros::WallTime start = ros::WallTime::now(); root_->renderOneFrame(); ros::WallTime end = ros::WallTime::now(); printf("Render took [%f] msec\n", (end - start).toSec() * 1000.0f); } void MyFrame::mousePressEvent( QMouseEvent* event ) { left_mouse_down_ = false; middle_mouse_down_ = false; right_mouse_down_ = false; switch( event->button() ) { case Qt::LeftButton: left_mouse_down_ = true; break; case Qt::MidButton: middle_mouse_down_ = true; break; case Qt::RightButton: right_mouse_down_ = true; break; default: break; } } void MyFrame::mouseReleaseEvent( QMouseEvent* event ) { switch( event->button() ) { case Qt::LeftButton: left_mouse_down_ = false; break; case Qt::MidButton: middle_mouse_down_ = false; break; case Qt::RightButton: right_mouse_down_ = false; break; default: break; } } void MyFrame::mouseMoveEvent( QMouseEvent* event ) { int32_t diff_x = event->x() - mouse_x_; int32_t diff_y = event->y() - mouse_y_; mouse_x_ = event->x(); mouse_y_ = event->y(); bool cmd = event->modifiers() & Qt::ControlModifier; bool shift = event->modifiers() & Qt::ShiftModifier; bool alt = event->modifiers() & Qt::AltModifier; if ( left_mouse_down_ ) { camera_->mouseLeftDrag( diff_x, diff_y, cmd, alt, shift ); } else if ( middle_mouse_down_ ) { camera_->mouseMiddleDrag( diff_x, diff_y, cmd, alt, shift ); } else if ( right_mouse_down_ ) { camera_->mouseRightDrag( diff_x, diff_y, cmd, alt, shift ); } } void MyFrame::wheelEvent( QWheelEvent* event ) { if( event->delta() != 0 ) { bool cmd = event->modifiers() & Qt::ControlModifier; bool shift = event->modifiers() & Qt::ShiftModifier; bool alt = event->modifiers() & Qt::AltModifier; camera_->scrollWheel( event->delta(), cmd, alt, shift ); } } int main( int argc, char** argv ) { QApplication app( argc, argv ); MyFrame frame; frame.resize( 800, 600 ); frame.setWindowTitle( "I hope this is not all black." ); frame.show(); return app.exec(); } rviz-1.12.4/src/test/render_points_test.h000066400000000000000000000057461300447110700204330ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RENDER_POINTS_TEST_H #define RENDER_POINTS_TEST_H #include #include #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 #include "rviz/ogre_helpers/qt_ogre_render_window.h" #include "rviz/ogre_helpers/grid.h" #include "rviz/ogre_helpers/orbit_camera.h" #include "rviz/ogre_helpers/axes.h" #include "rviz/ogre_helpers/shape.h" #include "rviz/ogre_helpers/arrow.h" #include "rviz/ogre_helpers/point_cloud.h" #include "rviz/ogre_helpers/billboard_line.h" #include "rviz/ogre_helpers/render_system.h" #include #include #include #include #include #endif using namespace rviz; class MyFrame : public QWidget { Q_OBJECT public: MyFrame(QWidget* parent = 0); virtual ~MyFrame(); private Q_SLOTS: void doRender(); private: virtual void mousePressEvent( QMouseEvent* event ); virtual void mouseReleaseEvent( QMouseEvent* event ); virtual void mouseMoveEvent( QMouseEvent* event ); virtual void wheelEvent( QWheelEvent* event ); Ogre::Root* root_; RenderSystem* render_system_; Ogre::SceneManager* scene_manager_; QtOgreRenderWindow* render_panel_; Grid* grid_; CameraBase* camera_; // Mouse handling bool left_mouse_down_; bool middle_mouse_down_; bool right_mouse_down_; int mouse_x_; int mouse_y_; QTimer render_timer_; }; #endif // RENDER_POINTS_TEST_H rviz-1.12.4/src/test/ros_spinner.cpp000066400000000000000000000035421300447110700174050ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "ros_spinner.h" RosSpinner::RosSpinner() { QTimer* timer = new QTimer( this ); connect( timer, SIGNAL( timeout() ), this, SLOT( onTimer() )); timer->start( 10 ); } void RosSpinner::onTimer() { if( ros::ok() ) { ros::spinOnce(); } } rviz-1.12.4/src/test/ros_spinner.h000066400000000000000000000036351300447110700170550ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RVIZ_TEST_ROS_SPINNER_H #define RVIZ_TEST_ROS_SPINNER_H #include #ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 # include #endif class RosSpinner: public QObject { Q_OBJECT public: RosSpinner(); private Q_SLOTS: void onTimer(); }; #endif // RVIZ_TEST_ROS_SPINNER_H rviz-1.12.4/src/test/rviz_logo.rviz000066400000000000000000000232441300447110700172670ustar00rootroot00000000000000Visualization Manager: Class: "" Name: root Enabled: true Global Options: Fixed Frame: /rviz_logo Background Color: 64; 64; 64 Displays: - Class: rviz/Grid Name: Grid Enabled: true Reference Frame: Plane Cell Count: 10 Normal Cell Count: 0 Cell Size: 1 Line Style: Value: Lines Line Width: 0.0299999993294477 Color: 255; 255; 255 Alpha: 0.5 Plane: XY Offset: {X: 0, Y: 0, Z: 0} - Class: rviz/RobotModel Name: RobotModel Enabled: true Visual Enabled: true Collision Enabled: false Update Interval: 0 Alpha: 1 Robot Description: robot_description TF Prefix: "" Links: base_bellow_link: Value: true Alpha: 1 Show Trail: false Show Axes: false base_footprint: Value: true Alpha: 1 Show Trail: false Show Axes: false base_link: Value: true Alpha: 1 Show Trail: false Show Axes: false bl_caster_l_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false bl_caster_r_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false bl_caster_rotation_link: Value: true Alpha: 1 Show Trail: false Show Axes: false br_caster_l_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false br_caster_r_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false br_caster_rotation_link: Value: true Alpha: 1 Show Trail: false Show Axes: false double_stereo_link: Value: true Alpha: 1 Show Trail: false Show Axes: false fl_caster_l_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false fl_caster_r_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false fl_caster_rotation_link: Value: true Alpha: 1 Show Trail: false Show Axes: false fr_caster_l_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false fr_caster_r_wheel_link: Value: true Alpha: 1 Show Trail: false Show Axes: false fr_caster_rotation_link: Value: true Alpha: 1 Show Trail: false Show Axes: false head_mount_kinect_ir_link: Value: true Alpha: 1 Show Trail: false Show Axes: false head_mount_kinect_rgb_link: Value: true Alpha: 1 Show Trail: false Show Axes: false head_mount_link: Value: true Alpha: 1 Show Trail: false Show Axes: false head_mount_prosilica_link: Value: true Alpha: 1 Show Trail: false Show Axes: false head_pan_link: Value: true Alpha: 1 Show Trail: false Show Axes: false head_plate_frame: Value: true Alpha: 1 Show Trail: false Show Axes: false head_tilt_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_elbow_flex_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_forearm_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_forearm_roll_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_gripper_l_finger_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_gripper_l_finger_tip_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_gripper_motor_accelerometer_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_gripper_palm_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_gripper_r_finger_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_gripper_r_finger_tip_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_shoulder_lift_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_shoulder_pan_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_upper_arm_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_upper_arm_roll_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_wrist_flex_link: Value: true Alpha: 1 Show Trail: false Show Axes: false l_wrist_roll_link: Value: true Alpha: 1 Show Trail: false Show Axes: false laser_tilt_mount_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_elbow_flex_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_forearm_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_forearm_roll_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_gripper_l_finger_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_gripper_l_finger_tip_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_gripper_motor_accelerometer_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_gripper_palm_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_gripper_r_finger_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_gripper_r_finger_tip_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_shoulder_lift_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_shoulder_pan_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_upper_arm_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_upper_arm_roll_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_wrist_flex_link: Value: true Alpha: 1 Show Trail: false Show Axes: false r_wrist_roll_link: Value: true Alpha: 1 Show Trail: false Show Axes: false sensor_mount_link: Value: true Alpha: 1 Show Trail: false Show Axes: false torso_lift_link: Value: true Alpha: 1 Show Trail: false Show Axes: false - Class: rviz/Marker Name: Marker Enabled: false Marker Topic: visualization_marker Queue Size: 100 Namespaces: {} - Class: rviz/TF Name: TF Enabled: false Show Names: true Show Axes: true Show Arrows: true Marker Scale: 1 Update Interval: 0 Frame Timeout: 15 Frames: All Enabled: false Tree: {} - Class: rviz/InteractiveMarkers Name: InteractiveMarkers Enabled: true Update Topic: /rviz_logo/update Show Descriptions: true Show Axes: false Tools: - Class: rviz/MoveCamera - Class: rviz/Interact - Class: rviz/Select - Class: rviz/SetInitialPose Topic: initialpose - Class: rviz/SetGoal Topic: /move_base_simple/goal Views: Current: Class: rviz/Orbit Name: Current View Target Frame: Distance: 30.7631340026855 Yaw: 5.73317718505859 Pitch: 0.235000416636467 Focal Point: {X: -17.6926803588867, Y: 10.8476543426514, Z: -3.56247138977051} Saved: [] Panels: Displays: Property Tree Widget: Expanded: - /Global Options1 - /Status1 - /InteractiveMarkers1 Splitter Ratio: 0.5 Tree Height: 606 Help Height: 144 Custom Panels: [] Window Geometry: X: 2286 Y: 155 Width: 1094 Height: 649 QMainWindow State: 000000ff00000000fd0000000300000000000002150000042cfc0200000001fb000000100044006900730070006c006100790073030000050b000000f50000021500000348000000010000011d0000038ffc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730000000028000000c90000006700fffffffb0000000a0056006900650077007303000004c20000034d0000012500000113fb0000001200530065006c0065006300740069006f006e0000000028000002b60000006700ffffff000000030000053c0000003efc0100000001fb0000000800540069006d006500000000000000053c000002bf00ffffff000004360000023c00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 rviz-1.12.4/src/test/rviz_logo_marker.cpp000066400000000000000000000061521300447110700204170ustar00rootroot00000000000000#include "ros/ros.h" #include "visualization_msgs/Marker.h" #include "visualization_msgs/MarkerArray.h" #include "interactive_markers/interactive_marker_server.h" #include #include interactive_markers::InteractiveMarkerServer* server; void makeMarker( ) { // create an interactive marker for our server visualization_msgs::InteractiveMarker int_marker; int_marker.header.frame_id = "/rviz_logo"; int_marker.name = "R"; int_marker.pose.orientation.x = 0.0; int_marker.pose.orientation.y = 0.0; int_marker.pose.orientation.z = 1.0; int_marker.pose.orientation.w = 1.0; int_marker.pose.position.y = - 2.0; int_marker.scale = 2.3; visualization_msgs::Marker marker; marker.type = visualization_msgs::Marker::MESH_RESOURCE; tf::quaternionTFToMsg( tf::Quaternion( tf::Vector3(0, 0, 1), 0.2 ), marker.pose.orientation ); marker.pose.position.x = 0; marker.pose.position.y = -0.22; marker.pose.position.z = 0; marker.scale.x = marker.scale.y = marker.scale.z = 4; marker.color.r = 0; marker.color.g = 0; marker.color.b = 0; marker.color.a = 0; marker.mesh_resource = "package://rviz/image_src/R.stl"; marker.mesh_use_embedded_materials = true; marker.id = 0; // create a non-interactive control which contains the box visualization_msgs::InteractiveMarkerControl control; control.always_visible = true; control.markers.push_back( marker ); // add the control to the interactive marker int_marker.controls.push_back( control ); visualization_msgs::InteractiveMarkerControl linear_control; linear_control.name = "rotate_z"; linear_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS; linear_control.orientation.y = 1; linear_control.orientation.w = 1; // add the control to the interactive marker int_marker.controls.push_back(linear_control); server->insert(int_marker); int_marker.name = "Viz"; marker.mesh_resource = "package://rviz/image_src/Viz.stl"; marker.pose.position.x = 3.3; marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; control.markers.clear(); control.markers.push_back( marker ); // add the control to the interactive marker int_marker.controls.clear(); int_marker.controls.push_back( control ); server->insert(int_marker); server->applyChanges(); } void publishCallback(tf::TransformBroadcaster& tf_broadcaster, const ros::TimerEvent&) { static tf::TransformBroadcaster br; tf::Transform transform; transform.setOrigin( tf::Vector3(3, 1, 0) ); transform.setRotation( tf::createQuaternionFromRPY(0, 0, M_PI * 0.9) ); br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "base_link", "rviz_logo")); } int main(int argc, char** argv) { ros::init(argc, argv, "rviz_logo_marker"); ros::NodeHandle n; tf::TransformBroadcaster tf_broadcaster; ros::Timer publish_timer = n.createTimer(ros::Duration(0.1), boost::bind(&publishCallback,tf_broadcaster,_1)); server = new interactive_markers::InteractiveMarkerServer("rviz_logo"); makeMarker( ); ros::spin(); } rviz-1.12.4/src/test/sample_file.yaml000066400000000000000000000016261300447110700175050ustar00rootroot00000000000000Enabled: true Displays: - Class: MockDisplay Name: Steven Enabled: false Count: 17 Style: a b c d e !@#$%^:& Offset: X: 1 Y: 2 Z: 1000.1 Color: orange - Name: sub group Class: DisplayGroup Enabled: true Displays: - Name: sub group Class: DisplayGroup Enabled: true Displays: - Name: sub group Class: DisplayGroup Enabled: true Displays: - Name: sub group Class: DisplayGroup Enabled: true Displays: - Class: MockDisplay Name: Curly Enabled: false Count: 9000 - Class: BrokenDisplay Name: Joe Enabled: true Count: 33 - Class: BrokenDisplay Name: Joe Enabled: true Count: 33 - Class: BrokenDisplay Name: Joe Enabled: true Count: 33 rviz-1.12.4/src/test/send_bad_pc2.py000077500000000000000000000021371300447110700172170ustar00rootroot00000000000000#!/usr/bin/env python # This program publishes a pointcloud2 which has much shorter data # than what is described by width, height, and point_step. RViz # should catch this and show an error instead of crashing. import rospy from sensor_msgs.msg import PointCloud2 from sensor_msgs.msg import PointField rospy.init_node( 'bad_pointcloud_publisher' ) pfx = PointField() pfx.name = 'x' pfx.offset = 0 pfx.datatype = 7 pfx.count = 1 pfy = PointField() pfy.name = 'y' pfy.offset = 4 pfy.datatype = 7 pfy.count = 1 pfz = PointField() pfz.name = 'z' pfz.offset = 8 pfz.datatype = 7 pfz.count = 1 pc = PointCloud2() pc.header.frame_id = "/map" pc.header.stamp = rospy.Time.now() pc.fields = [ pfx, pfy, pfz ] pc.data = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] pc.width = 10 pc.height = 10 pc.point_step = 12 pc.row_step = 120 pc.is_dense = False pub = rospy.Publisher( 'bad_pointcloud', PointCloud2 ) while not rospy.is_shutdown(): print( "publishing bad PointCloud2." ) pub.publish( pc ) rospy.sleep( 1.0 ) rviz-1.12.4/src/test/send_grid_cells_node.cpp000066400000000000000000000051141300447110700211660ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ros/ros.h" #include "nav_msgs/GridCells.h" #include "math.h" int main( int argc, char **argv ) { ros::init( argc, argv, "send_grid_cells" ); ros::NodeHandle nh; ros::Publisher pub = nh.advertise("grid_cells", 100); ros::Rate loop_rate( 100 ); nav_msgs::GridCells msg; int width = 500; int length = 500; msg.cells.resize( width * length ); msg.header.frame_id = "base_link"; msg.cell_width = .01; msg.cell_height = .01; int count = 0; while( ros::ok() ) { for( int x = 0; x < width; x++ ) { for( int y = 0; y < length; y++ ) { geometry_msgs::Point & point = msg.cells[ x + y * width ]; point.x = x / 100.0; point.y = y / 100.0; point.z = sin( x / 100.0 + y / 100.0 + count / 100.0 ); // point.z = ((x + y + count) % 100) / 100.0; } } msg.header.seq = count; msg.header.stamp = ros::Time::now(); pub.publish( msg ); ros::spinOnce(); loop_rate.sleep(); ++count; } } rviz-1.12.4/src/test/send_images.cpp000066400000000000000000000113301300447110700173140ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "stdlib.h" #include "ros/ros.h" #include "sensor_msgs/Image.h" #include "sensor_msgs/image_encodings.h" #include "math.h" #include "image_transport/image_transport.h" int main( int argc, char **argv ) { ros::init( argc, argv, "send_images" ); if( argc != 2 ) { printf( "USAGE: %s \n" " Where is rgb8, 32FC1, or 16UC1.", argv[ 0 ] ); exit( 1 ); } const std::string image_format( argv[ 1 ]); ros::NodeHandle nh; image_transport::ImageTransport it( nh ); image_transport::Publisher pub = it.advertise("images", 100); ros::Rate loop_rate( 100 ); if( image_format == "rgb8" ) { sensor_msgs::Image msg; int width = 100; int height = 1000; msg.data.resize( width * height * 3 ); msg.header.frame_id = "base_link"; msg.height = height; msg.width = width; msg.encoding = image_format; msg.step = width * 3; int count = 0; while( ros::ok() ) { for( int x = 0; x < width; x++ ) { for( int y = 0; y < height; y++ ) { int index = (x + y * width) * 3; long int rand = random(); msg.data[ index ] = rand & 0xff; index++; msg.data[ index ] = (rand >> 8) & 0xff; index++; msg.data[ index ] = (rand >> 16) & 0xff; } } msg.header.seq = count; msg.header.stamp = ros::Time::now(); pub.publish( msg ); ros::spinOnce(); loop_rate.sleep(); ++count; } } else if( image_format == "32FC1" ) { sensor_msgs::Image msg; int width = 400; int height = 400; msg.data.resize( width * height * sizeof( float )); msg.header.frame_id = "base_link"; msg.height = height; msg.width = width; msg.encoding = image_format; msg.step = width; int count = 0; while( ros::ok() ) { for( int x = 0; x < width; x++ ) { for( int y = 0; y < height; y++ ) { int index = x + y * width; float* ptr = ((float*) &msg.data[ 0 ]) + index; *ptr = sinf( (x + count) / 10.0f ) * sinf( y / 10.0f ) * 20.0f - 10.0f; } } msg.header.seq = count; msg.header.stamp = ros::Time::now(); pub.publish( msg ); ros::spinOnce(); loop_rate.sleep(); ++count; } } else if( image_format == "16UC1" ) { sensor_msgs::Image msg; int width = 400; int height = 400; msg.data.resize( width * height * sizeof( short )); msg.header.frame_id = "base_link"; msg.height = height; msg.width = width; msg.encoding = image_format; msg.step = width; int count = 0; while( ros::ok() ) { for( int x = 0; x < width; x++ ) { for( int y = 0; y < height; y++ ) { int index = x + y * width; short* ptr = ((short*) &msg.data[ 0 ]) + index; *ptr = (count + abs( x % 100 - 50 ) + abs( y % 100 - 50 )) % 50 * 65535 / 50; } } msg.header.seq = count; msg.header.stamp = ros::Time::now(); pub.publish( msg ); ros::spinOnce(); loop_rate.sleep(); ++count; } } } rviz-1.12.4/src/test/send_lots_of_points_node.cpp000066400000000000000000000062671300447110700221320ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ros/ros.h" #include "sensor_msgs/PointCloud.h" #include "math.h" int main( int argc, char **argv ) { ros::init( argc, argv, "send_lots_of_points" ); int rate = 1; bool moving = true; int size = 100; if( argc > 1 ) { rate = atoi( argv[1] ); } if( argc > 2 ) { moving = bool( atoi( argv[2] )); } if( argc > 3 ) { size = atoi( argv[3] ); } ros::NodeHandle nh; ros::Publisher pub = nh.advertise("lots_of_points", 100); ros::Rate loop_rate( rate ); sensor_msgs::PointCloud msg; int width = size; int length = 2*size; msg.points.resize( width * length ); msg.header.frame_id = "base_link"; int count = 0; while( ros::ok() ) { width++; msg.points.resize( width * length + (count % 2) ); for( int x = 0; x < width; x++ ) { for( int y = 0; y < length; y++ ) { geometry_msgs::Point32 & point = msg.points[ x + y * width ]; point.x = float(x / 100.0); point.y = float(y / 100.0); // point.z = sinf( x / 100.0 + y / 100.0 + count / 100.0 ); point.z = ((x + y + count) % 100) / 100.0; } } if( count % 2 ) { msg.points[ width * length + 1 ].x = -.1; msg.points[ width * length + 1 ].y = -.1; msg.points[ width * length + 1 ].z = 1.1; } msg.header.seq = count; msg.header.stamp = ros::Time::now(); printf( "publishing at %d hz, %s, %d x %d points.\n", rate, (moving?"moving":"static"), width, length ); pub.publish( msg ); ros::spinOnce(); loop_rate.sleep(); if( moving ) { ++count; } } } rviz-1.12.4/src/test/send_lots_of_tf.py000077500000000000000000000050421300447110700200610ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2008, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of the Willow Garage nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #!/usr/bin/env python import roslib roslib.load_manifest('rviz') import rospy import math import tf if __name__ == '__main__': rospy.init_node('send_tf') br = tf.TransformBroadcaster() r = rospy.Rate(10) t = 0 while not rospy.is_shutdown(): for m in range(1,20): br.sendTransform((0, 0, 0), tf.transformations.quaternion_from_euler(0, .8*m, 0), rospy.Time.now(), "frame0_{0}".format(m), "base_link") for n in range(1,20): br.sendTransform((.2*math.sin(t*10+n), 0, .2), tf.transformations.quaternion_from_euler(0, .6 * math.sin(t), .2), rospy.Time.now(), "frame{0}_{1}".format(n, m), "frame{0}_{1}".format(n-1, m)) t += .01 r.sleep() rviz-1.12.4/src/test/send_odometry.py000077500000000000000000000012561300447110700175700ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from nav_msgs.msg import Odometry import rospy topic = 'test_odometry' publisher = rospy.Publisher(topic, Odometry) rospy.init_node('send_odometry') y = 0 while not rospy.is_shutdown(): odo = Odometry() odo.header.frame_id = "/base_link" odo.header.stamp = rospy.Time.now() odo.pose.pose.position.x = 0 odo.pose.pose.position.y = y odo.pose.pose.position.z = 0 odo.pose.pose.orientation.x = 0 odo.pose.pose.orientation.y = 0 odo.pose.pose.orientation.z = 0 odo.pose.pose.orientation.w = 1 publisher.publish( odo ) y = y + .2 if y > 5: y = -5 rospy.sleep(0.1) rviz-1.12.4/src/test/send_path.py000077500000000000000000000016221300447110700166570ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from nav_msgs.msg import Path from geometry_msgs.msg import PoseStamped import math import rospy topic = 'test_path' publisher = rospy.Publisher(topic, Path) rospy.init_node('send_path') t = 0 while not rospy.is_shutdown(): p = Path() p.header.frame_id = "/base_link" p.header.stamp = rospy.Time.now() num_points = 100 for i in range( 0, num_points ): ps = PoseStamped() ps.header.stamp = p.header.stamp ps.header.frame_id = p.header.frame_id ps.pose.position.x = 10.0 * i / num_points - 5 ps.pose.position.y = math.sin( 10.0 * i / num_points + t ) ps.pose.position.z = 0 ps.pose.orientation.x = 0 ps.pose.orientation.y = 0 ps.pose.orientation.z = 0 ps.pose.orientation.w = 1 p.poses.append( ps ) publisher.publish( p ) t += .1 rospy.sleep(0.03) rviz-1.12.4/src/test/send_point.py000077500000000000000000000010221300447110700170460ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from geometry_msgs.msg import PointStamped import math import rospy topic = 'test_point' publisher = rospy.Publisher(topic, PointStamped) rospy.init_node('send_point') t = 0 while not rospy.is_shutdown(): p = PointStamped() p.header.frame_id = "/base_link" p.header.stamp = rospy.Time.now() r = 5.0 p.point.x = r * math.cos( t ) p.point.y = r * math.sin( t ) p.point.z = 0 publisher.publish( p ) t += .1 rospy.sleep(0.03) rviz-1.12.4/src/test/send_point_cloud_2.cpp000066400000000000000000000102251300447110700206110ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ros/ros.h" #include "sensor_msgs/PointCloud2.h" #include "math.h" int main( int argc, char **argv ) { ros::init( argc, argv, "send_points2" ); int rate = 1; bool moving = true; int size = 100; if( argc > 1 ) { rate = atoi( argv[1] ); } if( argc > 2 ) { moving = bool( atoi( argv[2] )); } if( argc > 3 ) { size = atoi( argv[3] ); } ros::NodeHandle nh; ros::Publisher pub = nh.advertise("points2", 10); ros::Rate loop_rate( rate ); sensor_msgs::PointCloud2 msg; int width = size; int height = 2*size; msg.header.frame_id = "base_link"; msg.is_dense = false; msg.is_bigendian = false; msg.fields.resize( 5 ); msg.fields[0].name = "x"; msg.fields[0].offset = 0; msg.fields[0].datatype = sensor_msgs::PointField::FLOAT32; msg.fields[0].count = 1; msg.fields[1].name = "y"; msg.fields[1].offset = 4; msg.fields[1].datatype = sensor_msgs::PointField::FLOAT32; msg.fields[1].count = 1; msg.fields[2].name = "z"; msg.fields[2].offset = 8; msg.fields[2].datatype = sensor_msgs::PointField::FLOAT32; msg.fields[2].count = 1; msg.fields[3].name = "rgb"; msg.fields[3].offset = 12; msg.fields[3].datatype = sensor_msgs::PointField::INT32; msg.fields[3].count = 1; msg.fields[4].name = "joy"; msg.fields[4].offset = 16; msg.fields[4].datatype = sensor_msgs::PointField::FLOAT32; msg.fields[4].count = 1; msg.point_step = 20; int count = 0; while( ros::ok() ) { width++; int num_points = width * height; msg.row_step = width * msg.point_step; msg.height = height; msg.width = width; msg.data.resize( num_points * msg.point_step ); for( int x = 0; x < width; x++ ) { for( int y = 0; y < height; y++ ) { uint8_t* ptr = &msg.data[0] + (x + y * width) * msg.point_step; *(float*)ptr = x / 100.0f; ptr += 4; *(float*)ptr = y / 100.0f; ptr += 4; *(float*)ptr = 0.1 * sinf( x / 10.0f ) * sinf( y / 10.0f ); ptr += 4; *ptr = (x+count) & 0xff; ptr++; *ptr = y & 0xff; ptr++; *ptr = (x+y) & 0xff; ptr++; ptr++; *(float*)ptr = 127.0f + 127.0f * sinf( (x - count)/ 10.0f ) * sinf( y / 10.0f ); // ptr += 4; } } msg.header.seq = count; msg.header.stamp = ros::Time::now(); printf( "publishing at %d hz, %s, %d x %d points.\n", rate, (moving?"moving":"static"), width, height ); pub.publish( msg ); ros::spinOnce(); loop_rate.sleep(); if( moving ) { ++count; } } } rviz-1.12.4/src/test/send_polygon.py000077500000000000000000000016131300447110700174120ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from geometry_msgs.msg import PolygonStamped from geometry_msgs.msg import Point32 import math import rospy topic = 'test_polygon' publisher = rospy.Publisher(topic, PolygonStamped) rospy.init_node('send_polygon') t = 0 while not rospy.is_shutdown(): p = PolygonStamped() p.header.frame_id = "/base_link" p.header.stamp = rospy.Time.now() dr = 0.5 * math.cos( t ) radii = [ 1-dr, 1+dr ] radius_index = 0 num_points = 10 for i in range( 0, num_points ): point = Point32() radius = radii[ radius_index ] radius_index = (radius_index + 1) % 2 point.x = radius * math.cos( i * 2 * math.pi / num_points ) point.y = radius * math.sin( i * 2 * math.pi / num_points ) point.z = 0 p.polygon.points.append( point ) publisher.publish( p ) t += .1 rospy.sleep(0.03) rviz-1.12.4/src/test/send_pose.py000077500000000000000000000012671300447110700166760ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from geometry_msgs.msg import PoseStamped import math import rospy topic = 'test_pose' publisher = rospy.Publisher(topic, PoseStamped) rospy.init_node('send_pose') t = 0 while not rospy.is_shutdown(): p = PoseStamped() p.header.frame_id = "/base_link" p.header.stamp = rospy.Time.now() r = 5.0 p.pose.position.x = r * math.cos( t ) p.pose.position.y = r * math.sin( t ) p.pose.position.z = 0 p.pose.orientation.x = 0 p.pose.orientation.y = 0 p.pose.orientation.z = math.sin( .5 * t ) p.pose.orientation.w = math.cos( .5 * t ) publisher.publish( p ) t += .1 rospy.sleep(0.03) rviz-1.12.4/src/test/send_range.py000077500000000000000000000010421300447110700170130ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from sensor_msgs.msg import Range import rospy topic = 'test_range' publisher = rospy.Publisher(topic, Range) rospy.init_node('range_test') dist = 3 while not rospy.is_shutdown(): r = Range() r.header.frame_id = "/moon" r.header.stamp = rospy.Time.now() r.radiation_type = 0 r.field_of_view = 2.0/dist r.min_range = .4 r.max_range = 10 r.range = dist publisher.publish( r ) rospy.sleep(0.1) dist += .3 if dist > 10: dist = 3 rviz-1.12.4/src/test/send_tf.py000077500000000000000000000043561300447110700163430ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2008, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of the Willow Garage nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #!/usr/bin/env python import roslib roslib.load_manifest('rviz') import rospy import math import tf if __name__ == '__main__': rospy.init_node('send_tf') br = tf.TransformBroadcaster() rate = rospy.Rate(10) radius = 5 t = 0 while not rospy.is_shutdown(): print "sending..." for m in range(1,10): br.sendTransform((radius * math.cos(t), radius * math.sin(t), 0), tf.transformations.quaternion_from_euler(0, 0, t), rospy.Time.now(), "base_link", "map") t += .01 rate.sleep() rviz-1.12.4/src/test/send_two_clouds.py000077500000000000000000000045511300447110700201110ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2012, Willow Garage, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of the Willow Garage nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #!/usr/bin/env python import roslib roslib.load_manifest('rviz') import rospy from sensor_msgs.msg import PointCloud from geometry_msgs.msg import Point32 pub1 = rospy.Publisher("cloud1", PointCloud) pub2 = rospy.Publisher("cloud2", PointCloud) rospy.init_node('send_two_clouds') cloud = PointCloud() while not rospy.is_shutdown(): cloud.header.frame_id = "/base_link" cloud.header.stamp = rospy.Time.now() cloud.points = [ Point32( 0, 0, 0 ), Point32( .1, 0, 0 ), Point32( 0, .1, 0 ), Point32( .1, .1, 0 ) ] pub1.publish( cloud ) cloud.points = [ Point32( .5, 0, 0 ), Point32( .6, 0, 0 ), Point32( .5, .1, 0 ), Point32( .6, .1, 0 ) ] pub2.publish( cloud ) rospy.sleep(.5) rviz-1.12.4/src/test/send_wrench.py000077500000000000000000000012771300447110700172170ustar00rootroot00000000000000#!/usr/bin/env python import roslib; roslib.load_manifest('rviz') from geometry_msgs.msg import WrenchStamped import math import rospy topic = 'test_wrench' publisher = rospy.Publisher(topic, WrenchStamped) rospy.init_node('send_wrench') t = 0 while not rospy.is_shutdown(): p = WrenchStamped() p.header.frame_id = "/base_link" p.header.stamp = rospy.Time.now() f = 0.5 * math.sin(t); p.wrench.force.x = 0 p.wrench.force.y = 0 p.wrench.force.z = f * math.sin( t ) q = 0.5 + 0.5 * math.sin( t / 3.14 ) p.wrench.torque.x = q * math.sin( t ) p.wrench.torque.y = q * math.cos( t ) p.wrench.torque.z = 0 publisher.publish( p ) t += .1 rospy.sleep(0.03) rviz-1.12.4/src/test/stl_loader_test.cpp000066400000000000000000000031141300447110700202260ustar00rootroot00000000000000#include #include #include #include TEST( STLLoader, load ) { // Get the path to the directory where the meshes are located. boost::filesystem::path meshDir = ros::package::getPath("rviz"); meshDir /= "src/test/meshes"; // Load an ascii STL file. Note that only binary STL files are supported. ogre_tools::STLLoader loader; boost::filesystem::path meshFilePath = meshDir / "ascii.stl"; EXPECT_FALSE(loader.load(meshFilePath.string())); // Load an invalid STL binary file (size < 84 bytes). meshFilePath = meshDir / "invalid_short.stl"; EXPECT_FALSE(loader.load(meshFilePath.string())); // Load an invalid STL binary file (size does not match the expected size). meshFilePath = meshDir / "invalid.stl"; EXPECT_FALSE(loader.load(meshFilePath.string())); // Load an invalid STL binary file (size does not match the expected size, // but does if incorrectly read as an 16-bit uint) meshFilePath = meshDir / "16bit_vs_32bit_should_fail.stl"; EXPECT_FALSE(loader.load(meshFilePath.string())); // Load a valid STL binary file. meshFilePath = meshDir / "valid.stl"; EXPECT_TRUE(loader.load(meshFilePath.string())); // Load a "potentially" valid STL binary file with bigger size than the // expected. The extra "unexpected" data at the end of the file should be // ignored. meshFilePath = meshDir / "valid_extra.stl"; EXPECT_TRUE(loader.load(meshFilePath.string())); } int main( int argc, char **argv ) { testing::InitGoogleTest( &argc, argv ); return RUN_ALL_TESTS(); } rviz-1.12.4/src/test/test_in.vcg000066400000000000000000000452771300447110700165210ustar00rootroot00000000000000Background\ ColorR=0 Background\ ColorG=0 Background\ ColorB=0 Fixed\ Frame=/map Target\ Frame=/map 2D\ Pose\:\ Localized.Angle\ Tolerance=0.1 2D\ Pose\:\ Localized.ColorR=0 2D\ Pose\:\ Localized.ColorG=0.1 2D\ Pose\:\ Localized.ColorB=0.8 2D\ Pose\:\ Localized.Enabled=0 2D\ Pose\:\ Localized.Keep=100 2D\ Pose\:\ Localized.Position\ Tolerance=0.1 2D\ Pose\:\ Localized.Topic=localizedpose 2D\ Pose\:\ Odom.Angle\ Tolerance=0.1 2D\ Pose\:\ Odom.ColorR=1 2D\ Pose\:\ Odom.ColorG=0.1 2D\ Pose\:\ Odom.ColorB=0 2D\ Pose\:\ Odom.Enabled=0 2D\ Pose\:\ Odom.Keep=100 2D\ Pose\:\ Odom.Position\ Tolerance=0.1 2D\ Pose\:\ Odom.Topic=odom AMCL\ Cloud.ColorR=1 AMCL\ Cloud.ColorG=0.1 AMCL\ Cloud.ColorB=0 AMCL\ Cloud.Enabled=1 AMCL\ Cloud.Topic=/particlecloud Current\ Goal.Alpha=1 Current\ Goal.ColorR=1 Current\ Goal.ColorG=0.1 Current\ Goal.ColorB=0 Current\ Goal.Enabled=1 Current\ Goal.Head\ Length=0.3 Current\ Goal.Head\ Radius=0.2 Current\ Goal.Shaft\ Length=1 Current\ Goal.Shaft\ Radius=0.1 Current\ Goal.Shape=0 Current\ Goal.Topic=/move_base_node/current_goal FilteredTiltCloud.Alpha=0.2 FilteredTiltCloud.Billboard\ Size=0.02 FilteredTiltCloud.Color\ Transformer= FilteredTiltCloud.Decay\ Time=4 FilteredTiltCloud.Enabled=0 FilteredTiltCloud.Position\ Transformer= FilteredTiltCloud.Selectable=1 FilteredTiltCloud.Style=1 FilteredTiltCloud.Topic=/tilt_scan_filtered FilteredTiltCloud..AxisAutocompute\ Value\ Bounds=1 FilteredTiltCloud..AxisAxis=2 FilteredTiltCloud..AxisMax\ Value=10 FilteredTiltCloud..AxisMin\ Value=-10 FilteredTiltCloud..AxisUse\ Fixed\ Frame=1 FilteredTiltCloud..Flat\ ColorColorR=1 FilteredTiltCloud..Flat\ ColorColorG=1 FilteredTiltCloud..Flat\ ColorColorB=1 FilteredTiltCloud..IntensityAutocompute\ Intensity\ Bounds=1 FilteredTiltCloud..IntensityMax\ ColorR=1 FilteredTiltCloud..IntensityMax\ ColorG=1 FilteredTiltCloud..IntensityMax\ ColorB=1 FilteredTiltCloud..IntensityMax\ Intensity=4096 FilteredTiltCloud..IntensityMin\ ColorR=0 FilteredTiltCloud..IntensityMin\ ColorG=0 FilteredTiltCloud..IntensityMin\ ColorB=0 FilteredTiltCloud..IntensityMin\ Intensity=0 Floor\ Scan.Alpha=1 Floor\ Scan.Billboard\ Size=0.05 Floor\ Scan.Color\ Transformer=Axis Floor\ Scan.Decay\ Time=0 Floor\ Scan.Enabled=1 Floor\ Scan.Position\ Transformer=XYZ Floor\ Scan.Selectable=1 Floor\ Scan.Style=1 Floor\ Scan.Topic=/base_scan_throttled Floor\ Scan..AxisAutocompute\ Value\ Bounds=1 Floor\ Scan..AxisAxis=2 Floor\ Scan..AxisMax\ Value=0.328082 Floor\ Scan..AxisMin\ Value=0.209754 Floor\ Scan..AxisUse\ Fixed\ Frame=1 Floor\ Scan..Flat\ ColorColorR=1 Floor\ Scan..Flat\ ColorColorG=1 Floor\ Scan..Flat\ ColorColorB=1 Floor\ Scan..IntensityAutocompute\ Intensity\ Bounds=1 Floor\ Scan..IntensityMax\ ColorR=1 Floor\ Scan..IntensityMax\ ColorG=1 Floor\ Scan..IntensityMax\ ColorB=1 Floor\ Scan..IntensityMax\ Intensity=4096 Floor\ Scan..IntensityMin\ ColorR=0 Floor\ Scan..IntensityMin\ ColorG=0 Floor\ Scan..IntensityMin\ ColorB=0 Floor\ Scan..IntensityMin\ Intensity=0 Global\ Plan.Alpha=1 Global\ Plan.ColorR=0 Global\ Plan.ColorG=1 Global\ Plan.ColorB=0 Global\ Plan.Enabled=1 Global\ Plan.Topic=/move_base_node/DWAPlannerROS/global_plan Grid.Alpha=0.5 Grid.Cell\ Size=1 Grid.ColorR=0.5 Grid.ColorG=0.5 Grid.ColorB=0.5 Grid.Enabled=1 Grid.Line\ Style=0 Grid.Line\ Width=0.03 Grid.Normal\ Cell\ Count=0 Grid.OffsetX=0 Grid.OffsetY=0 Grid.OffsetZ=0 Grid.Plane=0 Grid.Plane\ Cell\ Count=50 Grid.Reference\ Frame= Head\ Scan.Alpha=1 Head\ Scan.Billboard\ Size=0.01 Head\ Scan.Color\ Transformer= Head\ Scan.Decay\ Time=2 Head\ Scan.Enabled=0 Head\ Scan.Position\ Transformer= Head\ Scan.Selectable=1 Head\ Scan.Style=1 Head\ Scan.Topic=/tilt_scan Head\ Scan..AxisAutocompute\ Value\ Bounds=1 Head\ Scan..AxisAxis=2 Head\ Scan..AxisMax\ Value=10 Head\ Scan..AxisMin\ Value=-10 Head\ Scan..AxisUse\ Fixed\ Frame=1 Head\ Scan..Flat\ ColorColorR=1 Head\ Scan..Flat\ ColorColorG=1 Head\ Scan..Flat\ ColorColorB=1 Head\ Scan..IntensityAutocompute\ Intensity\ Bounds=1 Head\ Scan..IntensityMax\ ColorR=1 Head\ Scan..IntensityMax\ ColorG=1 Head\ Scan..IntensityMax\ ColorB=1 Head\ Scan..IntensityMax\ Intensity=4096 Head\ Scan..IntensityMin\ ColorR=0 Head\ Scan..IntensityMin\ ColorG=0 Head\ Scan..IntensityMin\ ColorB=0 Head\ Scan..IntensityMin\ Intensity=0 Inflated\ Obstacles.Alpha=1 Inflated\ Obstacles.ColorR=0 Inflated\ Obstacles.ColorG=0 Inflated\ Obstacles.ColorB=1 Inflated\ Obstacles.Enabled=1 Inflated\ Obstacles.Topic=/move_base_node/local_costmap/inflated_obstacles Local\ Plan.Alpha=1 Local\ Plan.ColorR=0 Local\ Plan.ColorG=0 Local\ Plan.ColorB=1 Local\ Plan.Enabled=1 Local\ Plan.Topic=/move_base_node/DWAPlannerROS/local_plan Map.Alpha=0.7 Map.Draw\ Behind=0 Map.Enabled=1 Map.Topic=map New\ Ground\ Plane\ Cloud.Alpha=1 New\ Ground\ Plane\ Cloud.Billboard\ Size=0.05 New\ Ground\ Plane\ Cloud.Color\ Transformer= New\ Ground\ Plane\ Cloud.Decay\ Time=3 New\ Ground\ Plane\ Cloud.Enabled=0 New\ Ground\ Plane\ Cloud.Position\ Transformer= New\ Ground\ Plane\ Cloud.Selectable=1 New\ Ground\ Plane\ Cloud.Style=1 New\ Ground\ Plane\ Cloud.Topic=/ground_object_cloud New\ Ground\ Plane\ Cloud..AxisAutocompute\ Value\ Bounds=1 New\ Ground\ Plane\ Cloud..AxisAxis=2 New\ Ground\ Plane\ Cloud..AxisMax\ Value=10 New\ Ground\ Plane\ Cloud..AxisMin\ Value=-10 New\ Ground\ Plane\ Cloud..AxisUse\ Fixed\ Frame=1 New\ Ground\ Plane\ Cloud..Flat\ ColorColorR=1 New\ Ground\ Plane\ Cloud..Flat\ ColorColorG=1 New\ Ground\ Plane\ Cloud..Flat\ ColorColorB=1 New\ Ground\ Plane\ Cloud..IntensityAutocompute\ Intensity\ Bounds=1 New\ Ground\ Plane\ Cloud..IntensityMax\ ColorR=1 New\ Ground\ Plane\ Cloud..IntensityMax\ ColorG=1 New\ Ground\ Plane\ Cloud..IntensityMax\ ColorB=1 New\ Ground\ Plane\ Cloud..IntensityMax\ Intensity=4096 New\ Ground\ Plane\ Cloud..IntensityMin\ ColorR=0 New\ Ground\ Plane\ Cloud..IntensityMin\ ColorG=0 New\ Ground\ Plane\ Cloud..IntensityMin\ ColorB=0 New\ Ground\ Plane\ Cloud..IntensityMin\ Intensity=0 Obstacles.Alpha=1 Obstacles.ColorR=1 Obstacles.ColorG=0 Obstacles.ColorB=0 Obstacles.Enabled=1 Obstacles.Topic=/move_base_node/local_costmap/obstacles Origin\ Axes.Enabled=0 Origin\ Axes.Length=1 Origin\ Axes.Radius=0.1 Origin\ Axes.Reference\ Frame= Planner\ Plan.Alpha=1 Planner\ Plan.ColorR=0 Planner\ Plan.ColorG=1 Planner\ Plan.ColorB=0 Planner\ Plan.Enabled=1 Planner\ Plan.Topic=/move_base_node/NavfnROS/plan Robot\ Footprint.Alpha=1 Robot\ Footprint.ColorR=1 Robot\ Footprint.ColorG=0 Robot\ Footprint.ColorB=0 Robot\ Footprint.Enabled=1 Robot\ Footprint.Topic=/move_base_node/local_costmap/robot_footprint Robot\ Model.Alpha=0.5 Robot\ Model.Collision\ Enabled=0 Robot\ Model.Enabled=1 Robot\ Model.Robot\ Description=robot_description Robot\ Model.TF\ Prefix= Robot\ Model.Update\ Interval=0.1 Robot\ Model.Visual\ Enabled=1 Robot\:\ Robot\ Model\ Link\ base_bellow_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ base_bellow_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ base_footprintShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ base_footprintShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ base_laser_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ base_laser_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ base_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ base_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ bl_caster_l_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ bl_caster_l_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ bl_caster_r_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ bl_caster_r_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ bl_caster_rotation_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ bl_caster_rotation_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ br_caster_l_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ br_caster_l_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ br_caster_r_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ br_caster_r_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ br_caster_rotation_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ br_caster_rotation_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ double_stereo_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ double_stereo_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ fl_caster_l_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ fl_caster_l_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ fl_caster_r_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ fl_caster_r_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ fl_caster_rotation_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ fl_caster_rotation_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ fr_caster_l_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ fr_caster_l_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ fr_caster_r_wheel_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ fr_caster_r_wheel_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ fr_caster_rotation_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ fr_caster_rotation_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ head_pan_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ head_pan_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ head_plate_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ head_plate_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ head_tilt_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ head_tilt_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ high_def_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ high_def_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ high_def_optical_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ high_def_optical_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ imu_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ imu_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_elbow_flex_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_elbow_flex_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_forearm_cam_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_forearm_cam_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_forearm_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_forearm_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_forearm_roll_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_forearm_roll_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_gripper_l_finger_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_gripper_l_finger_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_gripper_l_finger_tip_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_gripper_l_finger_tip_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_gripper_motor_accelerometer_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_gripper_motor_accelerometer_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_gripper_palm_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_gripper_palm_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_gripper_r_finger_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_gripper_r_finger_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_gripper_r_finger_tip_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_gripper_r_finger_tip_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_shoulder_lift_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_shoulder_lift_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_shoulder_pan_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_shoulder_pan_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_upper_arm_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_upper_arm_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_upper_arm_roll_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_upper_arm_roll_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_wrist_flex_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_wrist_flex_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ l_wrist_roll_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ l_wrist_roll_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ laser_tilt_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ laser_tilt_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ laser_tilt_mount_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ laser_tilt_mount_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ narrow_stereo_gazebo_l_stereo_camera_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ narrow_stereo_gazebo_l_stereo_camera_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ narrow_stereo_gazebo_r_stereo_camera_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ narrow_stereo_gazebo_r_stereo_camera_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ narrow_stereo_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ narrow_stereo_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ projector_wg6802418_child_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ projector_wg6802418_child_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ projector_wg6802418_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ projector_wg6802418_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_elbow_flex_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_elbow_flex_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_forearm_cam_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_forearm_cam_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_forearm_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_forearm_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_forearm_roll_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_forearm_roll_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_gripper_l_finger_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_gripper_l_finger_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_gripper_l_finger_tip_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_gripper_l_finger_tip_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_gripper_motor_accelerometer_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_gripper_motor_accelerometer_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_gripper_palm_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_gripper_palm_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_gripper_r_finger_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_gripper_r_finger_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_gripper_r_finger_tip_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_gripper_r_finger_tip_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_shoulder_lift_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_shoulder_lift_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_shoulder_pan_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_shoulder_pan_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_upper_arm_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_upper_arm_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_upper_arm_roll_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_upper_arm_roll_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_wrist_flex_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_wrist_flex_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ r_wrist_roll_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ r_wrist_roll_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ sensor_mount_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ sensor_mount_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ torso_lift_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ torso_lift_linkShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ wide_stereo_gazebo_l_stereo_camera_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ wide_stereo_gazebo_l_stereo_camera_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ wide_stereo_gazebo_r_stereo_camera_frameShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ wide_stereo_gazebo_r_stereo_camera_frameShow\ Trail=0 Robot\:\ Robot\ Model\ Link\ wide_stereo_linkShow\ Axes=0 Robot\:\ Robot\ Model\ Link\ wide_stereo_linkShow\ Trail=0 Stereo\ Cloud.Alpha=1 Stereo\ Cloud.Billboard\ Size=0.01 Stereo\ Cloud.Color\ Transformer= Stereo\ Cloud.Decay\ Time=0 Stereo\ Cloud.Enabled=0 Stereo\ Cloud.Position\ Transformer= Stereo\ Cloud.Selectable=1 Stereo\ Cloud.Style=1 Stereo\ Cloud.Topic=/dcam/cloud Stereo\ Cloud..AxisAutocompute\ Value\ Bounds=1 Stereo\ Cloud..AxisAxis=2 Stereo\ Cloud..AxisMax\ Value=10 Stereo\ Cloud..AxisMin\ Value=-10 Stereo\ Cloud..AxisUse\ Fixed\ Frame=1 Stereo\ Cloud..Flat\ ColorColorR=1 Stereo\ Cloud..Flat\ ColorColorG=1 Stereo\ Cloud..Flat\ ColorColorB=1 Stereo\ Cloud..IntensityAutocompute\ Intensity\ Bounds=1 Stereo\ Cloud..IntensityMax\ ColorR=1 Stereo\ Cloud..IntensityMax\ ColorG=1 Stereo\ Cloud..IntensityMax\ ColorB=1 Stereo\ Cloud..IntensityMax\ Intensity=4096 Stereo\ Cloud..IntensityMin\ ColorR=0 Stereo\ Cloud..IntensityMin\ ColorG=0 Stereo\ Cloud..IntensityMin\ ColorB=0 Stereo\ Cloud..IntensityMin\ Intensity=0 Transforms.All\ Enabled=1 Transforms.Enabled=0 Transforms.Frame\ Timeout=15 Transforms.Show\ Arrows=0 Transforms.Show\ Axes=1 Transforms.Show\ Names=1 Transforms.Update\ Interval=1 Visualization\ Markers.Enabled=1 Visualization\ Markers.Marker\ Topic=visualization_marker Tool\ 2D\ Nav\ GoalTopic=move_base_simple/goal Tool\ 2D\ Pose\ EstimateTopic=initialpose Camera\ Type=rviz::OrbitViewController Camera\ Config=0.641005 0.225801 37.6566 -8.59894 -8.94399 -2.83087 Property\ Grid\ State=selection=Global Plan.Enabled.Global Plan.Topic;expanded=.Global Options,Origin Axes.Enabled.Origin Axes.StatusTopStatus,Visualization Markers.Enabled.Visualization Markers.Namespaces,Head Scan.Enabled.Head Scan.StatusTopStatus,Transforms.Enabled.Transforms.StatusTopStatus,Transforms.Enabled.Transforms.Tree,Stereo Cloud.Enabled.Stereo Cloud.StatusTopStatus,FilteredTiltCloud.Enabled.FilteredTiltCloud.StatusTopStatus,New Ground Plane Cloud.Enabled.New Ground Plane Cloud.StatusTopStatus,AMCL Cloud.Enabled,Obstacles.Enabled,Inflated Obstacles.Enabled,Robot Footprint.Enabled,Global Plan.Enabled,Local Plan.Enabled,Planner Plan.Enabled,Current Goal.Enabled;scrollpos=0,18;splitterpos=188,361;ispageselected=1 [Display0] Name=Grid Package=rviz ClassName=rviz::GridDisplay [Display1] Name=Origin Axes Package=rviz ClassName=rviz::AxesDisplay [Display2] Name=Visualization Markers Package=rviz ClassName=rviz::MarkerDisplay [Display3] Name=Robot Model Package=rviz ClassName=rviz::RobotModelDisplay [Display4] Name=2D Pose: Odom Package=rviz ClassName=rviz::OdometryDisplay [Display5] Name=2D Pose: Localized Package=rviz ClassName=rviz::OdometryDisplay [Display6] Name=Map Package=rviz ClassName=rviz::MapDisplay [Display7] Name=Head Scan Package=rviz ClassName=rviz::LaserScanDisplay [Display8] Name=Floor Scan Package=rviz ClassName=rviz::LaserScanDisplay [Display9] Name=Transforms Package=rviz ClassName=rviz::TFDisplay [Display10] Name=Stereo Cloud Package=rviz ClassName=rviz::PointCloudDisplay [Display11] Name=FilteredTiltCloud Package=rviz ClassName=rviz::PointCloudDisplay [Display12] Name=New Ground Plane Cloud Package=rviz ClassName=rviz::PointCloudDisplay [Display13] Name=AMCL Cloud Package=rviz ClassName=rviz::PoseArrayDisplay [Display14] Name=Obstacles Package=rviz ClassName=rviz::GridCellsDisplay [Display15] Name=Inflated Obstacles Package=rviz ClassName=rviz::GridCellsDisplay [Display16] Name=Robot Footprint Package=rviz ClassName=rviz::PolygonDisplay [Display17] Name=Global Plan Package=rviz ClassName=rviz::PathDisplay [Display18] Name=Local Plan Package=rviz ClassName=rviz::PathDisplay [Display19] Name=Planner Plan Package=rviz ClassName=rviz::PathDisplay [Display20] Name=Current Goal Package=rviz ClassName=rviz::PoseDisplay [Visualization\ Markers.] [Visualization\ Markers./move_base_node] [Visualization\ Markers./move_base_node/local_costmap] voxel_grid_throttled=1 rviz-1.12.4/src/test/triangle_list_marker.yaml000066400000000000000000000013051300447110700214200ustar00rootroot00000000000000header: seq: 1 stamp: secs: 0 nsecs: 0 frame_id: base_link ns: cube id: 1 type: 11 action: 0 pose: position: x: 0.0 y: 0.0 z: 0.0 orientation: x: 0.0 y: 0.0 z: 0.0 w: 1.0 scale: x: 1.0 y: 1.0 z: 1.0 color: r: .5 g: .5 b: 1 a: 1 lifetime: secs: 0 nsecs: 0 frame_locked: False text: '' points: - x: 0 y: 0 z: 0 - x: 1 y: 0 z: 0 - x: 1 y: 1 z: 0 - x: 0 y: 0 z: 0 - x: 1 y: 0 z: 0 - x: 1 y: 0 z: 1 - x: 0 y: 0 z: 0 - x: 0 y: 0 z: 0 - x: 0 y: 0 z: 0 mesh_resource: '' mesh_use_embedded_materials: False --- rviz-1.12.4/src/test/turtlebot-arm-mesh-marker-array.yaml000066400000000000000000000056341300447110700233560ustar00rootroot00000000000000markers: - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 0 type: 10 action: 0 pose: position: { x: 0, y: 0, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/ax12_box.stl' mesh_use_embedded_materials: False - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 1 type: 10 action: 0 pose: position: { x: 1, y: 0, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/F10.stl' mesh_use_embedded_materials: False - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 2 type: 10 action: 0 pose: position: { x: 2, y: 0, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/F2.stl' mesh_use_embedded_materials: False - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 3 type: 10 action: 0 pose: position: { x: 0, y: 1, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/F3.stl' mesh_use_embedded_materials: False - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 4 type: 10 action: 0 pose: position: { x: 1, y: 1, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/F4.stl' mesh_use_embedded_materials: False - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 5 type: 10 action: 0 pose: position: { x: 2, y: 1, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: 1, g: 1, b: 0, a: 1 } scale: { x: .01, y: .01, z: .01 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/finger.stl' mesh_use_embedded_materials: False - header: { seq: 0, stamp: { secs: 0, nsecs: 0 }, frame_id: base_link } ns: chunk id: 6 type: 10 action: 0 pose: position: { x: 0, y: 2, z: 0 } orientation: { x: 0, y: 0, z: 0, w: 0 } color: { r: .5, g: 1, b: 0, a: 1 } scale: { x: 1, y: 1, z: 1 } frame_locked: False mesh_resource: 'package://rviz/src/test/meshes/pr2-base.dae' mesh_use_embedded_materials: False --- rviz-1.12.4/src/test/two_render_widgets.cpp000066400000000000000000000111101300447110700207300ustar00rootroot00000000000000/* * Copyright (c) 2011, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "rviz/ogre_helpers/render_system.h" #include "rviz/ogre_helpers/render_widget.h" #include #include #include #include #include #include using namespace rviz; int main( int argc, char** argv ) { // initialize the entire render system RenderSystem* render_system = RenderSystem::get(); QApplication app( argc, argv ); // make the render window RenderWidget* window = new RenderWidget( render_system ); window->setWindowTitle( "I hope this is not all black." ); QVBoxLayout* layout = new QVBoxLayout; layout->addWidget( window ); QPushButton* hide_button = new QPushButton( "hide" ); layout->addWidget( hide_button ); QPushButton* show_button = new QPushButton( "show" ); layout->addWidget( show_button ); QWidget container; container.setLayout( layout ); container.resize( 900, 600 ); container.show(); // Make a scene and show it in the window. Ogre::SceneManager* scene_manager = render_system->root()->createSceneManager( Ogre::ST_GENERIC ); Ogre::Entity* thing = scene_manager->createEntity( "thing", "rviz_cone.mesh" ); Ogre::SceneNode* node = scene_manager->getRootSceneNode()->createChildSceneNode(); node->attachObject( thing ); scene_manager->setAmbientLight( Ogre::ColourValue( .5, .5, .5 )); Ogre::Light* light = scene_manager->createLight( "light" ); light->setPosition( 20, 80, 50 ); Ogre::Camera* camera = scene_manager->createCamera( "SampleCam" ); camera->setPosition( Ogre::Vector3( 0, 0, 10 )); camera->lookAt( Ogre::Vector3( 0, 0, -300 )); camera->setNearClipDistance( 5 ); Ogre::Viewport* viewport = window->getRenderWindow()->addViewport( camera ); viewport->setBackgroundColour( Ogre::ColourValue( 0, 0, 1.0 )); camera->setAspectRatio( Ogre::Real( viewport->getActualWidth() ) / Ogre::Real( viewport->getActualHeight() )); // redraw every 33ms. QTimer timer; QObject::connect( &timer, SIGNAL(timeout()), window, SLOT(update()) ); timer.start( 33 ); RenderWidget window2( render_system ); window2.resize( 400, 400 ); window2.setWindowTitle( "I hope this is also not all black." ); window2.show(); hide_button->connect( hide_button, SIGNAL( clicked() ), &window2, SLOT( hide() )); show_button->connect( show_button, SIGNAL( clicked() ), &window2, SLOT( show() )); Ogre::Camera* camera2 = scene_manager->createCamera( "SampleCam2" ); camera2->setPosition( Ogre::Vector3( 0, 10, 0 )); camera2->setFixedYawAxis( false ); camera2->lookAt( Ogre::Vector3( 0, 0, 0 )); camera2->setNearClipDistance( 5 ); Ogre::Viewport* viewport2 = window2.getRenderWindow()->addViewport( camera2 ); viewport2->setBackgroundColour( Ogre::ColourValue( 0, 1.0, 0 )); camera2->setAspectRatio( Ogre::Real( viewport2->getActualWidth() ) / Ogre::Real( viewport2->getActualHeight() )); // redraw every 33ms. QTimer timer2; QObject::connect( &timer2, SIGNAL(timeout()), &window2, SLOT(update()) ); timer2.start( 33 ); // main loop return app.exec(); } rviz-1.12.4/src/test/uniform_string_stream_test.cpp000066400000000000000000000062011300447110700225160ustar00rootroot00000000000000/* * Copyright (c) 2012, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include using namespace rviz; TEST( UniformStringStream, parse_floats ) { UniformStringStream uss( "1,2 3.4 5,6e2" ); float a, b, c; uss.parseFloat( a ); uss.parseFloat( b ); uss.parseFloat( c ); EXPECT_TRUE( !!uss ); EXPECT_EQ( a, 1.2f ); EXPECT_EQ( b, 3.4f ); EXPECT_EQ( c, 560.0f ); uss.parseFloat( a ); EXPECT_FALSE( !!uss ); } TEST( UniformStringStream, parse_ints ) { UniformStringStream uss( "1 2 -3" ); int a, b, c; uss >> a; uss >> b; uss >> c; EXPECT_TRUE( !!uss ); EXPECT_EQ( a, 1 ); EXPECT_EQ( b, 2 ); EXPECT_EQ( c, -3 ); uss >> a; EXPECT_FALSE( !!uss ); } class CommaFloat: public std::numpunct { protected: virtual char do_decimal_point() const { return 'p'; } }; TEST( UniformStringStream, print_floats ) { UniformStringStream uss; uss << 1.2f; EXPECT_EQ( uss.str(), "1.2" ); CommaFloat* comma_float_facet = new CommaFloat; std::locale new_locale( std::locale::classic(), comma_float_facet ); std::locale old_locale = std::locale::global( new_locale ); // Make sure the comma_float_facet is working. std::stringstream ss; ss << 3.4f; EXPECT_EQ( ss.str(), "3p4" ); // Make sure the float facet gets clobbered within UniformStringStream. UniformStringStream uss2; uss2 << 3.4f; EXPECT_EQ( uss2.str(), "3.4" ); // Put things back to normal so other tests don't break. std::locale::global( old_locale ); } int main(int argc, char **argv){ testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }