From 4062cc3e647f9a1e955f0375625b1a4c744bc39d Mon Sep 17 00:00:00 2001 From: Levi Armstrong Date: Sat, 12 Oct 2024 09:57:50 -0500 Subject: [PATCH] Add Task Composer Widgets --- CMakeLists.txt | 1 - .../composite_instruction_standard_item.h | 5 +- .../composite_instruction_standard_item.cpp | 11 +- common/CMakeLists.txt | 1 + .../tesseract_qt/common/events/event_type.h | 9 + .../common/events/task_composer_events.h | 109 ++++++ .../common/models/standard_item_type.h | 3 +- common/src/events/task_composer_events.cpp | 82 ++++ environment/demo/CMakeLists.txt | 4 +- environment/demo/environment_demo.cpp | 10 +- joint_state_slider/demo/CMakeLists.txt | 5 +- .../demo/joint_state_slider_demo.cpp | 6 +- kinematic_groups/demo/CMakeLists.txt | 6 +- .../demo/groups_joint_states_demo.cpp | 6 +- planning/CMakeLists.txt | 65 ++- planning/demo/CMakeLists.txt | 14 + planning/demo/task_composer_demo.cpp | 65 +++ ...planning_profile_remapping_standard_item.h | 0 .../models/task_composer_context_model.h | 87 ++++ .../task_composer_context_standard_item.h | 0 .../task_composer_data_storage_model.h | 0 ...task_composer_data_storage_standard_item.h | 0 .../task_composer_keys_standard_item.h | 0 .../planning/models/task_composer_log_model.h | 87 ++++ .../models/task_composer_log_standard_item.h | 45 +++ ...ask_composer_node_info_map_standard_item.h | 0 .../task_composer_node_info_standard_item.h | 0 .../planning/widgets/task_composer_tool_bar.h | 51 +++ .../planning/widgets/task_composer_widget.h | 71 ++++ .../planning/widgets/task_composer_widget.ui | 311 +++++++++++++++ ...anning_profile_remapping_standard_item.cpp | 2 +- .../models/task_composer_context_model.cpp | 118 ++++++ .../task_composer_context_standard_item.cpp | 6 +- .../task_composer_data_storage_model.cpp | 6 +- ...sk_composer_data_storage_standard_item.cpp | 2 +- .../task_composer_keys_standard_item.cpp | 2 +- .../src/models/task_composer_log_model.cpp | 118 ++++++ .../task_composer_log_standard_item.cpp | 64 +++ ...k_composer_node_info_map_standard_item.cpp | 4 +- .../task_composer_node_info_standard_item.cpp | 6 +- .../src/widgets/task_composer_tool_bar.cpp | 164 ++++++++ planning/src/widgets/task_composer_widget.cpp | 370 ++++++++++++++++++ rendering/demo/CMakeLists.txt | 2 - .../demo/render_environment_widget_demo.cpp | 10 +- scene_graph/demo/CMakeLists.txt | 9 +- scene_graph/demo/scene_graph_demo.cpp | 6 +- studio/CMakeLists.txt | 3 + studio/config/viewer.studio | 19 +- studio/config/viewer.studio.ini | 6 +- .../studio_task_composer_dock_widget.h | 59 +++ .../src/plugins/studio_plugin_factories.cpp | 5 + .../studio_task_composer_dock_widget.cpp | 119 ++++++ workbench/CMakeLists.txt | 3 +- workbench/demo/CMakeLists.txt | 4 +- workbench/demo/workbench_demo.cpp | 10 +- .../tesseract_qt/workbench/workbench_widget.h | 4 + .../workbench/workbench_widget.ui | 31 +- workbench/src/workbench_widget.cpp | 26 +- 58 files changed, 2136 insertions(+), 96 deletions(-) create mode 100644 common/include/tesseract_qt/common/events/task_composer_events.h create mode 100644 common/src/events/task_composer_events.cpp create mode 100644 planning/demo/CMakeLists.txt create mode 100644 planning/demo/task_composer_demo.cpp rename planning/include/tesseract_qt/planning/{ => models}/planning_profile_remapping_standard_item.h (100%) create mode 100644 planning/include/tesseract_qt/planning/models/task_composer_context_model.h rename planning/include/tesseract_qt/planning/{ => models}/task_composer_context_standard_item.h (100%) rename planning/include/tesseract_qt/planning/{ => models}/task_composer_data_storage_model.h (100%) rename planning/include/tesseract_qt/planning/{ => models}/task_composer_data_storage_standard_item.h (100%) rename planning/include/tesseract_qt/planning/{ => models}/task_composer_keys_standard_item.h (100%) create mode 100644 planning/include/tesseract_qt/planning/models/task_composer_log_model.h create mode 100644 planning/include/tesseract_qt/planning/models/task_composer_log_standard_item.h rename planning/include/tesseract_qt/planning/{ => models}/task_composer_node_info_map_standard_item.h (100%) rename planning/include/tesseract_qt/planning/{ => models}/task_composer_node_info_standard_item.h (100%) create mode 100644 planning/include/tesseract_qt/planning/widgets/task_composer_tool_bar.h create mode 100644 planning/include/tesseract_qt/planning/widgets/task_composer_widget.h create mode 100644 planning/include/tesseract_qt/planning/widgets/task_composer_widget.ui rename planning/src/{ => models}/planning_profile_remapping_standard_item.cpp (96%) create mode 100644 planning/src/models/task_composer_context_model.cpp rename planning/src/{ => models}/task_composer_context_standard_item.cpp (91%) rename planning/src/{ => models}/task_composer_data_storage_model.cpp (95%) rename planning/src/{ => models}/task_composer_data_storage_standard_item.cpp (97%) rename planning/src/{ => models}/task_composer_keys_standard_item.cpp (97%) create mode 100644 planning/src/models/task_composer_log_model.cpp create mode 100644 planning/src/models/task_composer_log_standard_item.cpp rename planning/src/{ => models}/task_composer_node_info_map_standard_item.cpp (94%) rename planning/src/{ => models}/task_composer_node_info_standard_item.cpp (95%) create mode 100644 planning/src/widgets/task_composer_tool_bar.cpp create mode 100644 planning/src/widgets/task_composer_widget.cpp create mode 100644 studio/include/tesseract_qt/studio/plugins/studio_task_composer_dock_widget.h create mode 100644 studio/src/plugins/studio_task_composer_dock_widget.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3da2a361..3335be14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,6 @@ set(DEPS tesseract_environment tesseract_scene_graph tesseract_common - tesseract_support tesseract_urdf tesseract_srdf tesseract_visualization diff --git a/command_language/include/tesseract_qt/command_language/models/composite_instruction_standard_item.h b/command_language/include/tesseract_qt/command_language/models/composite_instruction_standard_item.h index 7b6e1833..1a1ba217 100644 --- a/command_language/include/tesseract_qt/command_language/models/composite_instruction_standard_item.h +++ b/command_language/include/tesseract_qt/command_language/models/composite_instruction_standard_item.h @@ -24,7 +24,7 @@ #define TESSERACT_QT_COMMAND_LANGUAGE_COMPOSITE_INSTRUCTION_STANDARD_ITEM_H #include -#include +#include namespace tesseract_gui { @@ -38,7 +38,10 @@ class CompositeInstructionStandardItem : public QStandardItem const tesseract_planning::CompositeInstruction& ci); int type() const override; + const tesseract_planning::CompositeInstruction& getCompositeInstruction() const; + private: + tesseract_planning::CompositeInstruction ci_; void ctor(const tesseract_planning::CompositeInstruction& ci); }; } // namespace tesseract_gui diff --git a/command_language/src/models/composite_instruction_standard_item.cpp b/command_language/src/models/composite_instruction_standard_item.cpp index 04090017..ea7385fb 100644 --- a/command_language/src/models/composite_instruction_standard_item.cpp +++ b/command_language/src/models/composite_instruction_standard_item.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -64,6 +63,11 @@ int CompositeInstructionStandardItem::type() const return static_cast(StandardItemType::CL_COMPOSITE_INSTRUCTION); } +const tesseract_planning::CompositeInstruction& CompositeInstructionStandardItem::getCompositeInstruction() const +{ + return ci_; +} + std::string toString(tesseract_planning::CompositeInstructionOrder order) { switch (order) @@ -81,12 +85,13 @@ std::string toString(tesseract_planning::CompositeInstructionOrder order) void CompositeInstructionStandardItem::ctor(const tesseract_planning::CompositeInstruction& ci) { + ci_ = ci; appendRow(createStandardItemString("description", ci.getDescription())); appendRow(createStandardItemString("order", toString(ci.getOrder()))); appendRow(createStandardItemString("profile", ci.getProfile())); appendRow(createStandardItemString("uuid", boost::uuids::to_string(ci.getUUID()))); appendRow(createStandardItemString("parent uuid", boost::uuids::to_string(ci.getParentUUID()))); - appendRow(new ManipulatorInfoStandardItem("manip info", ci.getManipulatorInfo())); - appendRow(new VectorInstructionStandardItem("instructions", ci.getInstructions())); + appendRow(new ManipulatorInfoStandardItem("manip info", ci.getManipulatorInfo())); // NOLINT + appendRow(new VectorInstructionStandardItem("instructions", ci.getInstructions())); // NOLINT } } // namespace tesseract_gui diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index ae4d1b78..23c3ea98 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -62,6 +62,7 @@ add_library( src/events/render_events.cpp src/events/scene_graph_events.cpp src/events/scene_graph_render_manager.cpp + src/events/task_composer_events.cpp src/events/tool_path_events.cpp src/events/tool_path_render_manager.cpp src/factories/any_poly_standard_item_factory.cpp diff --git a/common/include/tesseract_qt/common/events/event_type.h b/common/include/tesseract_qt/common/events/event_type.h index 151117e1..90e75aad 100644 --- a/common/include/tesseract_qt/common/events/event_type.h +++ b/common/include/tesseract_qt/common/events/event_type.h @@ -178,6 +178,15 @@ enum class EventType : int MANIPULATION_TYPES_START = JOINT_TRAJECTORY_TYPES_END, MANIPULATION_CHANGED = MANIPULATION_TYPES_START + 1, MANIPULATION_TYPES_END = MANIPULATION_TYPES_START + 2, + + // Task Composer + TASK_COMPOSER_TYPES_START = MANIPULATION_TYPES_END, + TASK_COMPOSER_LOAD_CONFIG = TASK_COMPOSER_TYPES_START + 1, + TASK_COMPOSER_LOAD_LOG = TASK_COMPOSER_TYPES_START + 2, + TASK_COMPOSER_SAVE_LOG = TASK_COMPOSER_TYPES_START + 3, + TASK_COMPOSER_PLOT_DOTGRAPH = TASK_COMPOSER_TYPES_START + 4, + TASK_COMPOSER_SET_PROFILES = TASK_COMPOSER_TYPES_START + 5, + TASK_COMPOSER_TYPES_END = TASK_COMPOSER_TYPES_START + 6, }; } diff --git a/common/include/tesseract_qt/common/events/task_composer_events.h b/common/include/tesseract_qt/common/events/task_composer_events.h new file mode 100644 index 00000000..c2d50fcd --- /dev/null +++ b/common/include/tesseract_qt/common/events/task_composer_events.h @@ -0,0 +1,109 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TESSERACT_QT_COMMON_TASK_COMPOSER_EVENTS_H +#define TESSERACT_QT_COMMON_TASK_COMPOSER_EVENTS_H + +#include +#include +#include +#include + +namespace tesseract_gui::events +{ +class TaskComposerLoadConfig : public ComponentEvent +{ +public: + TaskComposerLoadConfig(std::shared_ptr component_info, std::string resource_path); + ~TaskComposerLoadConfig() override; + + const std::string& getResourcePath() const; + + /** @brief Unique type for this event. */ + static const QEvent::Type kType = QEvent::Type(EventType::TASK_COMPOSER_LOAD_CONFIG); + +private: + std::string resource_path_; +}; + +class TaskComposerLoadLog : public ComponentEvent +{ +public: + TaskComposerLoadLog(std::shared_ptr component_info, + std::string resource_path, + std::string ns = ""); + ~TaskComposerLoadLog() override; + + const std::string& getResourcePath() const; + const std::string& getNamespace() const; + + /** @brief Unique type for this event. */ + static const QEvent::Type kType = QEvent::Type(EventType::TASK_COMPOSER_LOAD_LOG); + +private: + std::string resource_path_; + std::string ns_; +}; + +class TaskComposerSaveLog : public ComponentEvent +{ +public: + TaskComposerSaveLog(std::shared_ptr component_info, std::string save_path); + ~TaskComposerSaveLog() override; + + const std::string& getSavePath() const; + + /** @brief Unique type for this event. */ + static const QEvent::Type kType = QEvent::Type(EventType::TASK_COMPOSER_SAVE_LOG); + +private: + std::string save_path_; +}; + +class TaskComposerPlotDotgraph : public ComponentEvent +{ +public: + TaskComposerPlotDotgraph(std::shared_ptr component_info); + ~TaskComposerPlotDotgraph() override; + + /** @brief Unique type for this event. */ + static const QEvent::Type kType = QEvent::Type(EventType::TASK_COMPOSER_PLOT_DOTGRAPH); +}; + +class TaskComposerSetProfiles : public ComponentEvent +{ +public: + TaskComposerSetProfiles(std::shared_ptr component_info, + std::shared_ptr profiles); + ~TaskComposerSetProfiles() override; + + std::shared_ptr getProfiles() const; + + /** @brief Unique type for this event. */ + static const QEvent::Type kType = QEvent::Type(EventType::TASK_COMPOSER_SET_PROFILES); + +private: + std::shared_ptr profiles_; +}; +} // namespace tesseract_gui::events + +#endif // TESSERACT_QT_COMMON_TASK_COMPOSER_EVENTS_H diff --git a/common/include/tesseract_qt/common/models/standard_item_type.h b/common/include/tesseract_qt/common/models/standard_item_type.h index dcde94ae..b91db733 100644 --- a/common/include/tesseract_qt/common/models/standard_item_type.h +++ b/common/include/tesseract_qt/common/models/standard_item_type.h @@ -170,7 +170,8 @@ enum class StandardItemType : int MP_TASK_COMPOSER_NODE_INFO = CL_TYPES_END + 5, MP_TASK_COMPOSER_NODE_INFO_MAP = CL_TYPES_END + 6, MP_TASK_COMPOSER_DATA_STORAGE = CL_TYPES_END + 7, - MP_TYPES_END = CL_TYPES_END + 8, + MP_TASK_COMPOSER_LOG = CL_TYPES_END + 8, + MP_TYPES_END = CL_TYPES_END + 9, }; // clang-format on diff --git a/common/src/events/task_composer_events.cpp b/common/src/events/task_composer_events.cpp new file mode 100644 index 00000000..42000e4d --- /dev/null +++ b/common/src/events/task_composer_events.cpp @@ -0,0 +1,82 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +namespace tesseract_gui::events +{ +TaskComposerLoadConfig::TaskComposerLoadConfig(std::shared_ptr component_info, + std::string resource_path) + : ComponentEvent(std::move(component_info), kType), resource_path_(std::move(resource_path)) +{ +} + +TaskComposerLoadConfig::~TaskComposerLoadConfig() = default; +const std::string& TaskComposerLoadConfig::getResourcePath() const { return resource_path_; } + +////////////////////////////////////////////////////// + +TaskComposerLoadLog::TaskComposerLoadLog(std::shared_ptr component_info, + std::string resource_path, + std::string ns) + : ComponentEvent(std::move(component_info), kType), resource_path_(std::move(resource_path)), ns_(std::move(ns)) +{ +} + +TaskComposerLoadLog::~TaskComposerLoadLog() = default; +const std::string& TaskComposerLoadLog::getResourcePath() const { return resource_path_; } +const std::string& TaskComposerLoadLog::getNamespace() const { return ns_; } + +////////////////////////////////////////////////////// + +TaskComposerSaveLog::TaskComposerSaveLog(std::shared_ptr component_info, std::string save_path) + : ComponentEvent(std::move(component_info), kType), save_path_(std::move(save_path)) +{ +} + +TaskComposerSaveLog::~TaskComposerSaveLog() = default; +const std::string& TaskComposerSaveLog::getSavePath() const { return save_path_; } + +////////////////////////////////////////////////////// + +TaskComposerPlotDotgraph::TaskComposerPlotDotgraph(std::shared_ptr component_info) + : ComponentEvent(std::move(component_info), kType) +{ +} + +TaskComposerPlotDotgraph::~TaskComposerPlotDotgraph() = default; + +////////////////////////////////////////////////////// + +TaskComposerSetProfiles::TaskComposerSetProfiles(std::shared_ptr component_info, + std::shared_ptr profiles) + : ComponentEvent(std::move(component_info), kType), profiles_(std::move(profiles)) +{ +} + +TaskComposerSetProfiles::~TaskComposerSetProfiles() = default; +std::shared_ptr TaskComposerSetProfiles::getProfiles() const +{ + return profiles_; +} +} // namespace tesseract_gui::events diff --git a/environment/demo/CMakeLists.txt b/environment/demo/CMakeLists.txt index b76c2528..fcc3d71f 100644 --- a/environment/demo/CMakeLists.txt +++ b/environment/demo/CMakeLists.txt @@ -1,12 +1,10 @@ -find_package(tesseract_support REQUIRED) find_package(tesseract_urdf REQUIRED) find_package(tesseract_srdf REQUIRED) add_executable(${PROJECT_NAME}_environment_demo environment_demo.cpp) target_link_libraries( ${PROJECT_NAME}_environment_demo - PRIVATE tesseract::tesseract_support - tesseract::tesseract_urdf + PRIVATE tesseract::tesseract_urdf tesseract::tesseract_srdf ${PROJECT_NAME}_environment_widgets ${PROJECT_NAME}_common) diff --git a/environment/demo/environment_demo.cpp b/environment/demo/environment_demo.cpp index ee920fcb..bcd2ae03 100644 --- a/environment/demo/environment_demo.cpp +++ b/environment/demo/environment_demo.cpp @@ -31,7 +31,7 @@ #include #include -#include +#include int main(int argc, char** argv) { @@ -39,9 +39,11 @@ int main(int argc, char** argv) Q_INIT_RESOURCE(tesseract_qt_resources); - auto locator = std::make_shared(); - tesseract_common::fs::path urdf_path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.urdf"; - tesseract_common::fs::path srdf_path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.srdf"; + auto locator = std::make_shared(); + tesseract_common::fs::path urdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.urdf")->getFilePath()); + tesseract_common::fs::path srdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.srdf")->getFilePath()); auto env = std::make_shared(); env->init(urdf_path, srdf_path, locator); diff --git a/joint_state_slider/demo/CMakeLists.txt b/joint_state_slider/demo/CMakeLists.txt index e10cec0a..1aa3451d 100644 --- a/joint_state_slider/demo/CMakeLists.txt +++ b/joint_state_slider/demo/CMakeLists.txt @@ -1,8 +1,7 @@ -find_package(tesseract_support REQUIRED) find_package(tesseract_urdf REQUIRED) add_executable(${PROJECT_NAME}_joint_state_slider_demo joint_state_slider_demo.cpp) -target_link_libraries(${PROJECT_NAME}_joint_state_slider_demo - PRIVATE ${PROJECT_NAME}_joint_state_slider tesseract::tesseract_support tesseract::tesseract_urdf) +target_link_libraries(${PROJECT_NAME}_joint_state_slider_demo PRIVATE ${PROJECT_NAME}_joint_state_slider + tesseract::tesseract_urdf) install_targets(TARGETS ${PROJECT_NAME}_joint_state_slider_demo) diff --git a/joint_state_slider/demo/joint_state_slider_demo.cpp b/joint_state_slider/demo/joint_state_slider_demo.cpp index 1667a6fd..bbff033f 100644 --- a/joint_state_slider/demo/joint_state_slider_demo.cpp +++ b/joint_state_slider/demo/joint_state_slider_demo.cpp @@ -29,15 +29,15 @@ #include #include #include -#include +#include int main(int argc, char** argv) { QApplication app(argc, argv); // Load Scene Graph - std::string path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.urdf"; - tesseract_common::TesseractSupportResourceLocator locator; + tesseract_common::GeneralResourceLocator locator; + std::string path = locator.locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.urdf")->getFilePath(); tesseract_scene_graph::SceneGraph::UPtr sg = tesseract_urdf::parseURDFFile(path, locator); std::vector joints; for (const auto& joint : sg->getJoints()) diff --git a/kinematic_groups/demo/CMakeLists.txt b/kinematic_groups/demo/CMakeLists.txt index 621a9853..83a7e504 100644 --- a/kinematic_groups/demo/CMakeLists.txt +++ b/kinematic_groups/demo/CMakeLists.txt @@ -1,12 +1,10 @@ -find_package(tesseract_support REQUIRED) find_package(tesseract_urdf REQUIRED) add_executable(${PROJECT_NAME}_kinematic_groups_demo kinematic_group_demo.cpp) target_link_libraries(${PROJECT_NAME}_kinematic_groups_demo PRIVATE ${PROJECT_NAME}_kinematic_groups_widgets) add_executable(${PROJECT_NAME}_groups_joint_states_demo groups_joint_states_demo.cpp) -target_link_libraries( - ${PROJECT_NAME}_groups_joint_states_demo PRIVATE ${PROJECT_NAME}_kinematic_groups_widgets - tesseract::tesseract_support tesseract::tesseract_urdf) +target_link_libraries(${PROJECT_NAME}_groups_joint_states_demo PRIVATE ${PROJECT_NAME}_kinematic_groups_widgets + tesseract::tesseract_urdf) install_targets(TARGETS ${PROJECT_NAME}_kinematic_groups_demo ${PROJECT_NAME}_groups_joint_states_demo) diff --git a/kinematic_groups/demo/groups_joint_states_demo.cpp b/kinematic_groups/demo/groups_joint_states_demo.cpp index 59297e40..35948972 100644 --- a/kinematic_groups/demo/groups_joint_states_demo.cpp +++ b/kinematic_groups/demo/groups_joint_states_demo.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include int main(int argc, char** argv) { @@ -35,8 +35,8 @@ int main(int argc, char** argv) Q_INIT_RESOURCE(tesseract_qt_resources); // Load Scene Graph - std::string path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.urdf"; - tesseract_common::TesseractSupportResourceLocator locator; + tesseract_common::GeneralResourceLocator locator; + std::string path = locator.locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.urdf")->getFilePath(); /** @todo need to load environment */ diff --git a/planning/CMakeLists.txt b/planning/CMakeLists.txt index 91ee0875..dcf4150a 100644 --- a/planning/CMakeLists.txt +++ b/planning/CMakeLists.txt @@ -6,24 +6,34 @@ find_package(Qt5 COMPONENTS Core Widgets REQUIRED) tesseract_variables() set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) -set(PLANNING_headers_MOC include/tesseract_qt/planning/task_composer_data_storage_model.h) +set(CMAKE_AUTOUIC_SEARCH_PATHS include/tesseract_qt/planning/widgets) + +set(PLANNING_headers_MOC + include/tesseract_qt/planning/models/task_composer_data_storage_model.h + include/tesseract_qt/planning/models/task_composer_context_model.h + include/tesseract_qt/planning/models/task_composer_log_model.h) add_library( ${PROJECT_NAME}_planning SHARED ${PLANNING_headers_MOC} - src/planning_profile_remapping_standard_item.cpp - src/register_poly_types.cpp - src/task_composer_context_standard_item.cpp - src/task_composer_data_storage_model.cpp - src/task_composer_data_storage_standard_item.cpp - src/task_composer_keys_standard_item.cpp - src/task_composer_node_info_map_standard_item.cpp - src/task_composer_node_info_standard_item.cpp) + src/models/planning_profile_remapping_standard_item.cpp + src/models/task_composer_context_standard_item.cpp + src/models/task_composer_context_model.cpp + src/models/task_composer_data_storage_model.cpp + src/models/task_composer_data_storage_standard_item.cpp + src/models/task_composer_keys_standard_item.cpp + src/models/task_composer_log_model.cpp + src/models/task_composer_log_standard_item.cpp + src/models/task_composer_node_info_map_standard_item.cpp + src/models/task_composer_node_info_standard_item.cpp + src/register_poly_types.cpp) target_link_libraries( ${PROJECT_NAME}_planning - PUBLIC tesseract::tesseract_motion_planners_core + PUBLIC tesseract::tesseract_common + tesseract::tesseract_motion_planners_core tesseract::tesseract_task_composer tesseract::tesseract_task_composer_nodes tesseract::tesseract_task_composer_planning_nodes @@ -32,19 +42,42 @@ target_link_libraries( Qt5::Gui ${PROJECT_NAME}_common ${PROJECT_NAME}_collision_models - ${PROJECT_NAME}_scene_graph_widgets - ${PROJECT_NAME}_environment_widgets - ${PROJECT_NAME}_command_language_widgets) + ${PROJECT_NAME}_scene_graph_models + ${PROJECT_NAME}_environment_models + ${PROJECT_NAME}_command_language_models) target_include_directories( ${PROJECT_NAME}_planning PUBLIC "$" "$" "$") -# add_subdirectory(demo) +set(PLANNING_WIDGET_headers_MOC include/tesseract_qt/planning/widgets/task_composer_widget.h + include/tesseract_qt/planning/widgets/task_composer_tool_bar.h) + +add_library(${PROJECT_NAME}_planning_widgets SHARED ${PLANNING_WIDGET_headers_MOC} src/widgets/task_composer_widget.cpp + src/widgets/task_composer_tool_bar.cpp) +target_link_libraries( + ${PROJECT_NAME}_planning_widgets + PUBLIC tesseract::tesseract_environment + tesseract::tesseract_common + Qt5::Core + Qt5::Gui + Qt5::Widgets + ${PROJECT_NAME}_common + ${PROJECT_NAME}_planning) +target_include_directories( + ${PROJECT_NAME}_planning_widgets + PUBLIC "$" "$" + "$") + +add_subdirectory(demo) # Mark cpp header files for installation install(DIRECTORY include/${PROJECT_NAME} DESTINATION include) # Install -list(APPEND PROJECT_TARGETS ${PROJECT_NAME}_planning) +list( + APPEND + PROJECT_TARGETS + ${PROJECT_NAME}_planning + ${PROJECT_NAME}_planning_widgets) set(PROJECT_TARGETS ${PROJECT_TARGETS} PARENT_SCOPE) -install_targets(TARGETS ${PROJECT_NAME}_planning) +install_targets(TARGETS ${PROJECT_NAME}_planning ${PROJECT_NAME}_planning_widgets) diff --git a/planning/demo/CMakeLists.txt b/planning/demo/CMakeLists.txt new file mode 100644 index 00000000..c7949705 --- /dev/null +++ b/planning/demo/CMakeLists.txt @@ -0,0 +1,14 @@ +find_package(tesseract_urdf REQUIRED) +find_package(tesseract_srdf REQUIRED) + +add_executable(${PROJECT_NAME}_planning_task_composer_demo task_composer_demo.cpp) +target_link_libraries( + ${PROJECT_NAME}_planning_task_composer_demo + PRIVATE tesseract::tesseract_urdf + tesseract::tesseract_srdf + tesseract::tesseract_environment + tesseract::tesseract_common + ${PROJECT_NAME}_planning_widgets + ${PROJECT_NAME}_common) + +install_targets(TARGETS ${PROJECT_NAME}_planning_task_composer_demo) diff --git a/planning/demo/task_composer_demo.cpp b/planning/demo/task_composer_demo.cpp new file mode 100644 index 00000000..2142c807 --- /dev/null +++ b/planning/demo/task_composer_demo.cpp @@ -0,0 +1,65 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + + Q_INIT_RESOURCE(tesseract_qt_resources); + + auto locator = std::make_shared(); + tesseract_common::fs::path urdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.urdf")->getFilePath()); + tesseract_common::fs::path srdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.srdf")->getFilePath()); + + auto env = std::make_shared(); + env->init(urdf_path, srdf_path, locator); + + auto component_info = tesseract_gui::ComponentInfoManager::create("tesseract_scene"); + tesseract_gui::EnvironmentManager::set( + std::make_shared(component_info, env)); + + tesseract_gui::TaskComposerToolBar toolbar(component_info); + tesseract_gui::TaskComposerWidget widget(component_info); + static_cast(widget.layout())->insertWidget(0, &toolbar); + widget.show(); + + return QApplication::exec(); +} diff --git a/planning/include/tesseract_qt/planning/planning_profile_remapping_standard_item.h b/planning/include/tesseract_qt/planning/models/planning_profile_remapping_standard_item.h similarity index 100% rename from planning/include/tesseract_qt/planning/planning_profile_remapping_standard_item.h rename to planning/include/tesseract_qt/planning/models/planning_profile_remapping_standard_item.h diff --git a/planning/include/tesseract_qt/planning/models/task_composer_context_model.h b/planning/include/tesseract_qt/planning/models/task_composer_context_model.h new file mode 100644 index 00000000..6d24bbdb --- /dev/null +++ b/planning/include/tesseract_qt/planning/models/task_composer_context_model.h @@ -0,0 +1,87 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TESSERACT_QT_PLANNING_TASK_COMPOSER_CONTEXT_MODEL_H +#define TESSERACT_QT_PLANNING_TASK_COMPOSER_CONTEXT_MODEL_H + +#ifndef Q_MOC_RUN +#include +#include +#include +#endif + +namespace tesseract_gui +{ +class TaskComposerContextModel : public QStandardItemModel +{ + Q_OBJECT + +public: + explicit TaskComposerContextModel(QObject* parent = nullptr); + ~TaskComposerContextModel() override; + + /** + * @brief Add context + * @param context The context associated with the namespace + * @param ns The namespace to store the context under + * @return The key associated with added context for removal + */ + QString add(std::shared_ptr context, std::string ns = "general"); + + /** + * @brief Remove the context + * @param key The key associated with the context to be removed + */ + void remove(const QString& key); + + /** + * @brief Check if a context with the provided key exists + * @param key The key associated with the context to find + * @return True if a context exists under the provided key, otherwise false + */ + bool has(const QString& key); + + /** + * @brief Get the context associated with the row + * @param row The row to get associated context + * @return The context + */ + const tesseract_planning::TaskComposerContext& get(const QModelIndex& row) const; + + /** + * @brief Get the context namespace associated with the row + * @param row The row to get associated context + * @return The namespace + */ + const QString& getNamespace(const QModelIndex& row) const; + + /** @brief Clear the model */ + void clear(); + +private: + struct Implementation; + std::unique_ptr data_; +}; + +} // namespace tesseract_gui + +#endif // TESSERACT_QT_PLANNING_TASK_COMPOSER_CONTEXT_MODEL_H diff --git a/planning/include/tesseract_qt/planning/task_composer_context_standard_item.h b/planning/include/tesseract_qt/planning/models/task_composer_context_standard_item.h similarity index 100% rename from planning/include/tesseract_qt/planning/task_composer_context_standard_item.h rename to planning/include/tesseract_qt/planning/models/task_composer_context_standard_item.h diff --git a/planning/include/tesseract_qt/planning/task_composer_data_storage_model.h b/planning/include/tesseract_qt/planning/models/task_composer_data_storage_model.h similarity index 100% rename from planning/include/tesseract_qt/planning/task_composer_data_storage_model.h rename to planning/include/tesseract_qt/planning/models/task_composer_data_storage_model.h diff --git a/planning/include/tesseract_qt/planning/task_composer_data_storage_standard_item.h b/planning/include/tesseract_qt/planning/models/task_composer_data_storage_standard_item.h similarity index 100% rename from planning/include/tesseract_qt/planning/task_composer_data_storage_standard_item.h rename to planning/include/tesseract_qt/planning/models/task_composer_data_storage_standard_item.h diff --git a/planning/include/tesseract_qt/planning/task_composer_keys_standard_item.h b/planning/include/tesseract_qt/planning/models/task_composer_keys_standard_item.h similarity index 100% rename from planning/include/tesseract_qt/planning/task_composer_keys_standard_item.h rename to planning/include/tesseract_qt/planning/models/task_composer_keys_standard_item.h diff --git a/planning/include/tesseract_qt/planning/models/task_composer_log_model.h b/planning/include/tesseract_qt/planning/models/task_composer_log_model.h new file mode 100644 index 00000000..f7eed000 --- /dev/null +++ b/planning/include/tesseract_qt/planning/models/task_composer_log_model.h @@ -0,0 +1,87 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TESSERACT_QT_PLANNING_TASK_COMPOSER_LOG_MODEL_H +#define TESSERACT_QT_PLANNING_TASK_COMPOSER_LOG_MODEL_H + +#ifndef Q_MOC_RUN +#include +#include +#include +#endif + +namespace tesseract_gui +{ +class TaskComposerLogModel : public QStandardItemModel +{ + Q_OBJECT + +public: + explicit TaskComposerLogModel(QObject* parent = nullptr); + ~TaskComposerLogModel() override; + + /** + * @brief Add log + * @param log The log associated with the namespace + * @param ns The namespace to store the log under + * @return The key associated with added log for removal + */ + QString add(tesseract_planning::TaskComposerLog log, std::string ns = "general"); + + /** + * @brief Remove the log + * @param key The key associated with the log to be removed + */ + void remove(const QString& key); + + /** + * @brief Check if a log with the provided key exists + * @param key The key associated with the log to find + * @return True if a log exists under the provided key, otherwise false + */ + bool has(const QString& key); + + /** + * @brief Get the log associated with the row + * @param row The row to get associated log + * @return The log + */ + const tesseract_planning::TaskComposerLog& get(const QModelIndex& row) const; + + /** + * @brief Get the log namespace associated with the row + * @param row The row to get associated log + * @return The namespace + */ + const QString& getNamespace(const QModelIndex& row) const; + + /** @brief Clear the model */ + void clear(); + +private: + struct Implementation; + std::unique_ptr data_; +}; + +} // namespace tesseract_gui + +#endif // TESSERACT_QT_PLANNING_TASK_COMPOSER_LOG_MODEL_H diff --git a/planning/include/tesseract_qt/planning/models/task_composer_log_standard_item.h b/planning/include/tesseract_qt/planning/models/task_composer_log_standard_item.h new file mode 100644 index 00000000..942cacaa --- /dev/null +++ b/planning/include/tesseract_qt/planning/models/task_composer_log_standard_item.h @@ -0,0 +1,45 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2023 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TESSERACT_QT_PLANNING_TASK_COMPOSER_LOG_STANDARD_ITEM_H +#define TESSERACT_QT_PLANNING_TASK_COMPOSER_LOG_STANDARD_ITEM_H + +#include + +#include + +namespace tesseract_gui +{ +class TaskComposerLogStandardItem : public QStandardItem +{ +public: + explicit TaskComposerLogStandardItem(const tesseract_planning::TaskComposerLog& data); + TaskComposerLogStandardItem(const QString& text, const tesseract_planning::TaskComposerLog& data); + TaskComposerLogStandardItem(const QIcon& icon, const QString& text, const tesseract_planning::TaskComposerLog& data); + int type() const override; + +private: + void ctor(const tesseract_planning::TaskComposerLog& data); +}; +} // namespace tesseract_gui + +#endif // TESSERACT_QT_PLANNING_TASK_COMPOSER_LOG_STANDARD_ITEM_H diff --git a/planning/include/tesseract_qt/planning/task_composer_node_info_map_standard_item.h b/planning/include/tesseract_qt/planning/models/task_composer_node_info_map_standard_item.h similarity index 100% rename from planning/include/tesseract_qt/planning/task_composer_node_info_map_standard_item.h rename to planning/include/tesseract_qt/planning/models/task_composer_node_info_map_standard_item.h diff --git a/planning/include/tesseract_qt/planning/task_composer_node_info_standard_item.h b/planning/include/tesseract_qt/planning/models/task_composer_node_info_standard_item.h similarity index 100% rename from planning/include/tesseract_qt/planning/task_composer_node_info_standard_item.h rename to planning/include/tesseract_qt/planning/models/task_composer_node_info_standard_item.h diff --git a/planning/include/tesseract_qt/planning/widgets/task_composer_tool_bar.h b/planning/include/tesseract_qt/planning/widgets/task_composer_tool_bar.h new file mode 100644 index 00000000..bb333e15 --- /dev/null +++ b/planning/include/tesseract_qt/planning/widgets/task_composer_tool_bar.h @@ -0,0 +1,51 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TESSERACT_QT_TASK_COMPOSER_TOOL_BAR_H +#define TESSERACT_QT_TASK_COMPOSER_TOOL_BAR_H + +#ifndef Q_MOC_RUN +#include +#include +#endif + +namespace tesseract_gui +{ +class ComponentInfo; +class TaskComposerToolBar : public QToolBar +{ + Q_OBJECT +public: + TaskComposerToolBar(QWidget* parent = nullptr); + explicit TaskComposerToolBar(std::shared_ptr component_info, QWidget* parent = nullptr); + ~TaskComposerToolBar() final; + + void setComponentInfo(std::shared_ptr component_info); + std::shared_ptr getComponentInfo() const; + +private: + class Implementation; + std::unique_ptr data_; +}; +} // namespace tesseract_gui + +#endif // TESSERACT_QT_TASK_COMPOSER_TOOL_BAR_H diff --git a/planning/include/tesseract_qt/planning/widgets/task_composer_widget.h b/planning/include/tesseract_qt/planning/widgets/task_composer_widget.h new file mode 100644 index 00000000..7ca1230e --- /dev/null +++ b/planning/include/tesseract_qt/planning/widgets/task_composer_widget.h @@ -0,0 +1,71 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TESSERACT_QT_TASK_COMPOSER_WIDGET_H +#define TESSERACT_QT_TASK_COMPOSER_WIDGET_H + +#ifndef Q_MOC_RUN +#include +#include +#include +#endif + +namespace Ui +{ +class TaskComposerWidget; +} + +namespace tesseract_gui +{ +class ComponentInfo; + +class TaskComposerWidget : public QWidget +{ + Q_OBJECT + +public: + explicit TaskComposerWidget(QWidget* parent = nullptr); + explicit TaskComposerWidget(std::shared_ptr component_info, QWidget* parent = nullptr); + ~TaskComposerWidget() override; + + void setComponentInfo(std::shared_ptr component_info); + std::shared_ptr getComponentInfo() const; + +private Q_SLOTS: + void onRun(bool checked = false); + void onShowContextMenu(const QPoint& pos); + void onPickEnvironmentClicked(bool checked = false); + +protected: + // Documentation inherited + bool eventFilter(QObject* obj, QEvent* event) override; + void createContextMenu(QMenu& log_menu); + static void viewDotgraph(const std::string& dotgraph); + +private: + struct Implementation; + std::unique_ptr ui; + std::unique_ptr data_; +}; +} // namespace tesseract_gui + +#endif // TESSERACT_QT_TASK_COMPOSER_WIDGET_H diff --git a/planning/include/tesseract_qt/planning/widgets/task_composer_widget.ui b/planning/include/tesseract_qt/planning/widgets/task_composer_widget.ui new file mode 100644 index 00000000..d4ef4f88 --- /dev/null +++ b/planning/include/tesseract_qt/planning/widgets/task_composer_widget.ui @@ -0,0 +1,311 @@ + + + TaskComposerWidget + + + + 0 + 0 + 400 + 487 + + + + Form + + + + 10 + + + 10 + + + 10 + + + 10 + + + + + Config + + + + 3 + + + 9 + + + 3 + + + 3 + + + + + Executor: + + + + + + + + + + Task: + + + + + + + + 1 + 0 + + + + + + + + Namespace: + + + + + + + + + + Dot Graph: + + + + + + + + + + true + + + + + + + Description: + + + + + + + + + + Environment: + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Log Environment + + + + + + + + 25 + 0 + + + + + 25 + 16777215 + + + + Pick Environment + + + ... + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + run + + + + + + + + + + Status + + + + 3 + + + 9 + + + 3 + + + 3 + + + + + Message: + + + + + + + true + + + + + + + Time: + + + + + + + true + + + + + + + + + + Logs + + + + 3 + + + 9 + + + 3 + + + 3 + + + + + QAbstractItemView::NoEditTriggers + + + + + + + + + + + diff --git a/planning/src/planning_profile_remapping_standard_item.cpp b/planning/src/models/planning_profile_remapping_standard_item.cpp similarity index 96% rename from planning/src/planning_profile_remapping_standard_item.cpp rename to planning/src/models/planning_profile_remapping_standard_item.cpp index 98c9cf4d..5735b07f 100644 --- a/planning/src/planning_profile_remapping_standard_item.cpp +++ b/planning/src/models/planning_profile_remapping_standard_item.cpp @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include +#include #include #include #include diff --git a/planning/src/models/task_composer_context_model.cpp b/planning/src/models/task_composer_context_model.cpp new file mode 100644 index 00000000..457fc64a --- /dev/null +++ b/planning/src/models/task_composer_context_model.cpp @@ -0,0 +1,118 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace tesseract_gui +{ +struct TaskComposerContextModel::Implementation +{ + std::map items; + std::map> contexts; + std::map contexts_ns; + void clear() + { + items.clear(); + contexts.clear(); + contexts_ns.clear(); + } +}; + +TaskComposerContextModel::TaskComposerContextModel(QObject* parent) + : QStandardItemModel(parent), data_(std::make_unique()) +{ + clear(); +} + +TaskComposerContextModel::~TaskComposerContextModel() = default; + +void TaskComposerContextModel::clear() +{ + QStandardItemModel::clear(); + setColumnCount(2); + setHorizontalHeaderLabels({ "Name", "Values" }); + data_->clear(); +} + +QString TaskComposerContextModel::add(std::shared_ptr context, std::string ns) +{ + QString key = QUuid::createUuid().toString(); + ns = (ns.empty()) ? "general" : ns; + NamespaceStandardItem* item = createNamespaceItem(*invisibleRootItem(), ns); + + auto* context_item = new TaskComposerContextStandardItem(key, *context); + item->appendRow(context_item); + data_->items[key] = context_item; + data_->contexts[context_item] = std::move(context); + data_->contexts_ns[context_item] = ns.c_str(); + return key; +} + +void TaskComposerContextModel::remove(const QString& key) +{ + auto it = data_->items.find(key); + if (it == data_->items.end()) + throw std::runtime_error("Tried to remove context '" + key.toStdString() + "' which does not exist!"); + + data_->contexts.erase(it->second); + data_->contexts_ns.erase(it->second); + QModelIndex idx = indexFromItem(it->second); + data_->items.erase(it); + removeRow(idx.row(), idx.parent()); +} + +bool TaskComposerContextModel::has(const QString& key) { return (data_->items.find(key) != data_->items.end()); } + +TaskComposerContextStandardItem* findTaskComposerContextItem(QStandardItem* item) +{ + if (item == nullptr) + return nullptr; + + if (item->type() == static_cast(StandardItemType::MP_TASK_COMPOSER_CONTEXT)) + return dynamic_cast(item); + + return findTaskComposerContextItem(item->parent()); +} + +const tesseract_planning::TaskComposerContext& TaskComposerContextModel::get(const QModelIndex& row) const +{ + QStandardItem* item = itemFromIndex(row); + return *data_->contexts.at(findTaskComposerContextItem(item)); +} + +const QString& TaskComposerContextModel::getNamespace(const QModelIndex& row) const +{ + QStandardItem* item = itemFromIndex(row); + return data_->contexts_ns.at(findTaskComposerContextItem(item)); +} + +} // namespace tesseract_gui diff --git a/planning/src/task_composer_context_standard_item.cpp b/planning/src/models/task_composer_context_standard_item.cpp similarity index 91% rename from planning/src/task_composer_context_standard_item.cpp rename to planning/src/models/task_composer_context_standard_item.cpp index 7f59abf7..47e7ee84 100644 --- a/planning/src/task_composer_context_standard_item.cpp +++ b/planning/src/models/task_composer_context_standard_item.cpp @@ -20,9 +20,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include -#include +#include +#include +#include #include #include diff --git a/planning/src/task_composer_data_storage_model.cpp b/planning/src/models/task_composer_data_storage_model.cpp similarity index 95% rename from planning/src/task_composer_data_storage_model.cpp rename to planning/src/models/task_composer_data_storage_model.cpp index bbc67edd..7eeb2355 100644 --- a/planning/src/task_composer_data_storage_model.cpp +++ b/planning/src/models/task_composer_data_storage_model.cpp @@ -20,8 +20,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include +#include +#include #include #include #include @@ -85,7 +85,7 @@ void TaskComposerDataStorageModel::remove(const QString& key) throw std::runtime_error("Tried to remove data storage '" + key.toStdString() + "' which does not exist!"); data_->data_storages.erase(it->second); - data_->data_storages.erase(it->second); + data_->data_storages_ns.erase(it->second); QModelIndex idx = indexFromItem(it->second); data_->items.erase(it); removeRow(idx.row(), idx.parent()); diff --git a/planning/src/task_composer_data_storage_standard_item.cpp b/planning/src/models/task_composer_data_storage_standard_item.cpp similarity index 97% rename from planning/src/task_composer_data_storage_standard_item.cpp rename to planning/src/models/task_composer_data_storage_standard_item.cpp index 92635192..d288a362 100644 --- a/planning/src/task_composer_data_storage_standard_item.cpp +++ b/planning/src/models/task_composer_data_storage_standard_item.cpp @@ -21,7 +21,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include +#include #include #include #include diff --git a/planning/src/task_composer_keys_standard_item.cpp b/planning/src/models/task_composer_keys_standard_item.cpp similarity index 97% rename from planning/src/task_composer_keys_standard_item.cpp rename to planning/src/models/task_composer_keys_standard_item.cpp index 059e5168..00534c20 100644 --- a/planning/src/task_composer_keys_standard_item.cpp +++ b/planning/src/models/task_composer_keys_standard_item.cpp @@ -21,7 +21,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include +#include #include #include #include diff --git a/planning/src/models/task_composer_log_model.cpp b/planning/src/models/task_composer_log_model.cpp new file mode 100644 index 00000000..b149972a --- /dev/null +++ b/planning/src/models/task_composer_log_model.cpp @@ -0,0 +1,118 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace tesseract_gui +{ +struct TaskComposerLogModel::Implementation +{ + std::map items; + std::map logs; + std::map logs_ns; + void clear() + { + items.clear(); + logs.clear(); + logs_ns.clear(); + } +}; + +TaskComposerLogModel::TaskComposerLogModel(QObject* parent) + : QStandardItemModel(parent), data_(std::make_unique()) +{ + clear(); +} + +TaskComposerLogModel::~TaskComposerLogModel() = default; + +void TaskComposerLogModel::clear() +{ + QStandardItemModel::clear(); + setColumnCount(2); + setHorizontalHeaderLabels({ "Name", "Values" }); + data_->clear(); +} + +QString TaskComposerLogModel::add(tesseract_planning::TaskComposerLog log, std::string ns) +{ + QString key = QUuid::createUuid().toString(); + ns = (ns.empty()) ? "general" : ns; + NamespaceStandardItem* item = createNamespaceItem(*invisibleRootItem(), ns); + + auto* log_item = new TaskComposerLogStandardItem(key, log); + item->appendRow(log_item); + data_->items[key] = log_item; + data_->logs[log_item] = std::move(log); + data_->logs_ns[log_item] = ns.c_str(); + return key; +} + +void TaskComposerLogModel::remove(const QString& key) +{ + auto it = data_->items.find(key); + if (it == data_->items.end()) + throw std::runtime_error("Tried to remove log '" + key.toStdString() + "' which does not exist!"); + + data_->logs.erase(it->second); + data_->logs_ns.erase(it->second); + QModelIndex idx = indexFromItem(it->second); + data_->items.erase(it); + removeRow(idx.row(), idx.parent()); +} + +bool TaskComposerLogModel::has(const QString& key) { return (data_->items.find(key) != data_->items.end()); } + +TaskComposerLogStandardItem* findTaskComposerLogItem(QStandardItem* item) +{ + if (item == nullptr) + return nullptr; + + if (item->type() == static_cast(StandardItemType::MP_TASK_COMPOSER_LOG)) + return dynamic_cast(item); + + return findTaskComposerLogItem(item->parent()); +} + +const tesseract_planning::TaskComposerLog& TaskComposerLogModel::get(const QModelIndex& row) const +{ + QStandardItem* item = itemFromIndex(row); + return data_->logs.at(findTaskComposerLogItem(item)); +} + +const QString& TaskComposerLogModel::getNamespace(const QModelIndex& row) const +{ + QStandardItem* item = itemFromIndex(row); + return data_->logs_ns.at(findTaskComposerLogItem(item)); +} + +} // namespace tesseract_gui diff --git a/planning/src/models/task_composer_log_standard_item.cpp b/planning/src/models/task_composer_log_standard_item.cpp new file mode 100644 index 00000000..15bad457 --- /dev/null +++ b/planning/src/models/task_composer_log_standard_item.cpp @@ -0,0 +1,64 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include + +namespace tesseract_gui +{ +TaskComposerLogStandardItem::TaskComposerLogStandardItem(const tesseract_planning::TaskComposerLog& data) + : QStandardItem(icons::getLogIcon(), "Task Composer Log") +{ + ctor(data); +} + +TaskComposerLogStandardItem::TaskComposerLogStandardItem(const QString& text, + const tesseract_planning::TaskComposerLog& data) + : QStandardItem(icons::getLogIcon(), text) +{ + ctor(data); +} + +TaskComposerLogStandardItem::TaskComposerLogStandardItem(const QIcon& icon, + const QString& text, + const tesseract_planning::TaskComposerLog& data) + : QStandardItem(icon, text) +{ + ctor(data); +} + +int TaskComposerLogStandardItem::type() const { return static_cast(StandardItemType::MP_TASK_COMPOSER_LOG); } + +void TaskComposerLogStandardItem::ctor(const tesseract_planning::TaskComposerLog& data) +{ + appendRow(createStandardItemString("description", data.description)); + appendRow(new TaskComposerDataStorageStandardItem("initial_data", data.initial_data)); // NOLINT + appendRow(new TaskComposerContextStandardItem("context", *data.context)); // NOLINT +} +} // namespace tesseract_gui diff --git a/planning/src/task_composer_node_info_map_standard_item.cpp b/planning/src/models/task_composer_node_info_map_standard_item.cpp similarity index 94% rename from planning/src/task_composer_node_info_map_standard_item.cpp rename to planning/src/models/task_composer_node_info_map_standard_item.cpp index 64d0b5a9..7b8688a7 100644 --- a/planning/src/task_composer_node_info_map_standard_item.cpp +++ b/planning/src/models/task_composer_node_info_map_standard_item.cpp @@ -20,8 +20,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include +#include +#include #include #include diff --git a/planning/src/task_composer_node_info_standard_item.cpp b/planning/src/models/task_composer_node_info_standard_item.cpp similarity index 95% rename from planning/src/task_composer_node_info_standard_item.cpp rename to planning/src/models/task_composer_node_info_standard_item.cpp index 3128d887..ff1d5909 100644 --- a/planning/src/task_composer_node_info_standard_item.cpp +++ b/planning/src/models/task_composer_node_info_standard_item.cpp @@ -20,9 +20,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include -#include +#include +#include +#include #include #include diff --git a/planning/src/widgets/task_composer_tool_bar.cpp b/planning/src/widgets/task_composer_tool_bar.cpp new file mode 100644 index 00000000..7e208e8d --- /dev/null +++ b/planning/src/widgets/task_composer_tool_bar.cpp @@ -0,0 +1,164 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tesseract_gui +{ +struct TaskComposerToolBar::Implementation +{ + std::shared_ptr component_info; + + QAction* load_config_action{ nullptr }; + QAction* load_log_action{ nullptr }; + QAction* save_log_action{ nullptr }; + QAction* plot_dotgraph_action{ nullptr }; + + QString default_config_dir; + QString default_log_dir; +}; + +TaskComposerToolBar::TaskComposerToolBar(QWidget* parent) : TaskComposerToolBar(nullptr, parent) {} + +TaskComposerToolBar::TaskComposerToolBar(std::shared_ptr component_info, QWidget* parent) + : QToolBar(parent), data_(std::make_unique()) +{ + data_->component_info = std::move(component_info); + + QSettings ms; + ms.beginGroup("TaskComposerToolBar"); + data_->default_config_dir = + ms.value("default_config_dir", QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation)[0]) + .toString(); + data_->default_log_dir = + ms.value("default_log_dir", QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation)[0]).toString(); + ms.endGroup(); + + data_->load_config_action = addAction(icons::getOpenIcon(), "Load Task Composer Server Config", [this]() { + QStringList filters; + filters.append("Task Composer Config (*.yaml)"); + + QFileDialog dialog(this, "Open Task Composer Config", data_->default_config_dir); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setWindowModality(Qt::ApplicationModal); // Required, see RenderWidget::onFrameSwapped() + dialog.setModal(true); + dialog.setNameFilters(filters); + if (dialog.exec() == 1) + { + QString config_filepath = dialog.selectedFiles().first(); + if (!QFileInfo(config_filepath).exists()) + { + QMessageBox messageBox; + messageBox.critical(nullptr, "Error", "Config file does not exist"); + messageBox.setFixedSize(500, 200); + messageBox.show(); + return; + } + + data_->default_config_dir = QFileInfo(config_filepath).absoluteDir().path(); + events::TaskComposerLoadConfig event(data_->component_info, config_filepath.toStdString()); + QApplication::sendEvent(qApp, &event); + } + }); + + data_->load_log_action = addAction(icons::getLogIcon(), "Load Task Composer Log", [this]() { + QStringList filters; + filters.append("Task Composer Log (*.tclx *.tclb)"); + + QFileDialog dialog(this, "Open Task Composer Log", data_->default_log_dir); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setWindowModality(Qt::ApplicationModal); // Required, see RenderWidget::onFrameSwapped() + dialog.setModal(true); + dialog.setNameFilters(filters); + if (dialog.exec() == 1) + { + QString config_filepath = dialog.selectedFiles().first(); + if (!QFileInfo(config_filepath).exists()) + { + QMessageBox messageBox; + messageBox.critical(nullptr, "Error", "Log file does not exist"); + messageBox.setFixedSize(500, 200); + messageBox.show(); + return; + } + + data_->default_log_dir = QFileInfo(config_filepath).absoluteDir().path(); + events::TaskComposerLoadLog event(data_->component_info, config_filepath.toStdString()); + QApplication::sendEvent(qApp, &event); + } + }); + + addSeparator(); + + data_->save_log_action = addAction(icons::getSaveIcon(), "Save Task Composer Log", [this]() { + QStringList filters; + filters.append("Task Composer Log (*.tclx *.tclb)"); + + QFileDialog dialog(this, "Save Task Composer Log", data_->default_log_dir); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setWindowModality(Qt::ApplicationModal); // Required, see RenderWidget::onFrameSwapped() + dialog.setModal(true); + dialog.setNameFilters(filters); + if (dialog.exec() == 1) + { + QString config_filepath = dialog.selectedFiles().first(); + data_->default_log_dir = QFileInfo(config_filepath).absoluteDir().path(); + events::TaskComposerSaveLog event(data_->component_info, config_filepath.toStdString()); + QApplication::sendEvent(qApp, &event); + } + }); + + addSeparator(); + + data_->plot_dotgraph_action = addAction(icons::getPlotIcon(), "Plot Task Composer Dotgraph", [this]() { + events::TaskComposerPlotDotgraph event(data_->component_info); + QApplication::sendEvent(qApp, &event); + }); +} + +TaskComposerToolBar::~TaskComposerToolBar() +{ + { + QSettings ms; + ms.beginGroup("TaskComposerToolBar"); + ms.setValue("default_config_dir", data_->default_config_dir); + ms.setValue("default_log_dir", data_->default_log_dir); + ms.endGroup(); + } +} + +void TaskComposerToolBar::setComponentInfo(std::shared_ptr component_info) +{ + data_->component_info = std::move(component_info); +} +std::shared_ptr TaskComposerToolBar::getComponentInfo() const { return data_->component_info; } + +} // namespace tesseract_gui diff --git a/planning/src/widgets/task_composer_widget.cpp b/planning/src/widgets/task_composer_widget.cpp new file mode 100644 index 00000000..fa433339 --- /dev/null +++ b/planning/src/widgets/task_composer_widget.cpp @@ -0,0 +1,370 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "ui_task_composer_widget.h" + +#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 +#include + +#include +#include +#include +#include +#include + +BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::GeneralResourceLocator) + +namespace tesseract_gui +{ +struct TaskComposerWidget::Implementation +{ + std::shared_ptr component_info; + tesseract_planning::TaskComposerServer task_composer_server; + tesseract_common::GeneralResourceLocator resource_locator; + tesseract_planning::ProfileDictionary::Ptr profiles; + tesseract_gui::TaskComposerLogModel log_model; + + ComponentInfoDialog environment_picker; +}; + +TaskComposerWidget::TaskComposerWidget(QWidget* parent) : TaskComposerWidget(nullptr, parent) {} +TaskComposerWidget::TaskComposerWidget(std::shared_ptr component_info, QWidget* parent) + : QWidget(parent), ui(std::make_unique()), data_(std::make_unique()) +{ + ui->setupUi(this); + + ui->log_tree_view->setModel(&data_->log_model); + ui->log_tree_view->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); + + setComponentInfo(std::move(component_info)); + + connect(ui->task_run_push_button, SIGNAL(clicked(bool)), this, SLOT(onRun(bool))); + connect(ui->log_tree_view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onShowContextMenu(QPoint))); + connect(ui->environment_push_button, SIGNAL(clicked(bool)), this, SLOT(onPickEnvironmentClicked(bool))); + + // Register Types + registerCommonAnyPolyTypes(); + registerCommonInstructionPolyTypes(); + + // Install event filter for interactive view controller + qGuiApp->installEventFilter(this); +} + +TaskComposerWidget::~TaskComposerWidget() = default; + +void TaskComposerWidget::setComponentInfo(std::shared_ptr component_info) +{ + data_->component_info = std::move(component_info); +} + +std::shared_ptr TaskComposerWidget::getComponentInfo() const { return data_->component_info; } + +void TaskComposerWidget::createContextMenu(QMenu& log_menu) +{ + auto component_infos = ComponentInfoManager::get(); + + QMenu* vtp_menu = log_menu.addMenu(icons::getToolPathIcon(), "View Tool Path"); + for (const auto& component_info : component_infos) + { + vtp_menu->addAction( + icons::getModelIcon(), QString::fromStdString(component_info->getName()), [this, component_info]() { + QModelIndex row = ui->log_tree_view->selectionModel()->currentIndex(); + if (row.isValid()) + { + QStandardItem* item = static_cast(ui->log_tree_view->model())->itemFromIndex(row); + if (item->type() == static_cast(StandardItemType::CL_COMPOSITE_INSTRUCTION)) + { + const auto& ci = dynamic_cast(item)->getCompositeInstruction(); + const auto& log = data_->log_model.get(row); + auto env_any = log.initial_data.getData("environment"); + auto env = env_any.as>(); + // The toolpath is in world coordinate system + tesseract_common::Toolpath toolpath = tesseract_planning::toToolpath(ci, *env); + events::ToolPathAdd event(component_info, toolpath); + QApplication::sendEvent(qApp, &event); + } + } + }); + } + + QMenu* vjt_menu = log_menu.addMenu(icons::getTrajectoryIcon(), "View Joint Trajectory"); + for (const auto& component_info : component_infos) + { + vjt_menu->addAction( + icons::getModelIcon(), QString::fromStdString(component_info->getName()), [this, component_info]() { + QModelIndex row = ui->log_tree_view->selectionModel()->currentIndex(); + if (row.isValid()) + { + QStandardItem* item = static_cast(ui->log_tree_view->model())->itemFromIndex(row); + if (item->type() == static_cast(StandardItemType::CL_COMPOSITE_INSTRUCTION)) + { + const auto& ci = dynamic_cast(item)->getCompositeInstruction(); + const auto& log = data_->log_model.get(row); + auto env_any = log.initial_data.getData("environment"); + auto env = env_any.as>(); + tesseract_common::JointTrajectorySet jset(env->clone(), log.description); + jset.appendJointTrajectory(tesseract_planning::toJointTrajectory(ci)); + jset.setNamespace(ui->ns_line_edit->text().toStdString()); + events::JointTrajectoryAdd event(component_info, jset); + QApplication::sendEvent(qApp, &event); + } + } + }); + } + log_menu.setWindowModality(Qt::ApplicationModal); +} + +void TaskComposerWidget::viewDotgraph(const std::string& dotgraph) +{ + if (dotgraph.empty()) + return; + + const std::string dotgraph_location = + tesseract_common::getTempPath() + tesseract_common::getTimestampString() + ".dot"; + { // Save to temp under unique name + std::ofstream os{}; + os.open(dotgraph_location); + os << dotgraph; + os.close(); + } + + // Open Dotgraph + std::system(std::string("xdot " + dotgraph_location + " &").c_str()); +} + +void TaskComposerWidget::onShowContextMenu(const QPoint& pos) +{ + QModelIndex index = ui->log_tree_view->indexAt(pos); + if (index.isValid()) + { + QPoint global_pos = ui->log_tree_view->viewport()->mapToGlobal(pos); + QMenu menu; + createContextMenu(menu); + menu.exec(global_pos); + } +} + +void TaskComposerWidget::onRun(bool /*checked*/) +{ + tesseract_planning::TaskComposerLog nlog(ui->desc_line_edit->text().toStdString()); + + QModelIndex current_index = ui->log_tree_view->selectionModel()->currentIndex(); + if (!current_index.isValid()) + { + ui->status_line_edit->setText("No log selected!"); + return; + } + + const auto& log = data_->log_model.get(current_index); + auto data_storage = std::make_shared(log.initial_data); + data_storage->setData("profiles", data_->profiles); + + // Load environment + const QString current_environment_txt = ui->environment_line_edit->text(); + if (!current_environment_txt.isEmpty()) + { + QStringList list = current_environment_txt.split("::"); + if (list.size() == 2) + { + auto uuid = boost::lexical_cast(list[1].toStdString()); + std::shared_ptr component_info = ComponentInfoManager::get(uuid); + if (component_info != nullptr) + { + auto env = EnvironmentManager::get(component_info); + if (env != nullptr) + data_storage->setData("environment", + std::shared_ptr(env->environment().clone())); + } + } + } + + // Log initial data + nlog.initial_data = *data_storage; + + const std::string task_name = ui->task_combo_box->currentText().toStdString(); + const std::string executor_name = ui->executor_combo_box->currentText().toStdString(); + const bool dotgraph = ui->dotgraph_check_box->isChecked(); + + tesseract_common::Stopwatch stopwatch; + stopwatch.start(); + auto future = data_->task_composer_server.run(task_name, data_storage, dotgraph, executor_name); + future->wait(); + stopwatch.stop(); + + // Log Context + nlog.context = future->context; + + ui->time_line_edit->setText(QString::fromStdString(std::to_string(stopwatch.elapsedSeconds()) + "s")); + if (future->context->isSuccessful()) + ui->status_line_edit->setText("Successful"); + else + ui->status_line_edit->setText("Failed"); + + // Add llog + data_->log_model.add(nlog, ui->ns_line_edit->text().toStdString()); + + // Show Dotgraph + if (dotgraph) + TaskComposerWidget::viewDotgraph(nlog.dotgraph); +} + +void TaskComposerWidget::onPickEnvironmentClicked(bool /*checked*/) +{ + if (data_->environment_picker.exec() == 1) + { + auto component_info = data_->environment_picker.getComponentInfo(); + if (component_info != nullptr) + { + const QString text = QString("%1::%2").arg(component_info->getName().c_str(), + boost::uuids::to_string(component_info->getNamespace()).c_str()); + ui->environment_line_edit->setText(text); + return; + } + } +} + +bool TaskComposerWidget::eventFilter(QObject* obj, QEvent* event) +{ + if (event->type() == events::TaskComposerLoadConfig::kType) + { + assert(dynamic_cast(event) != nullptr); + auto* e = static_cast(event); + if (e->getComponentInfo() == data_->component_info) + { + auto resource = data_->resource_locator.locateResource(e->getResourcePath()); + if (resource != nullptr) + { + data_->task_composer_server.loadConfig(tesseract_common::fs::path(resource->getFilePath())); + + ui->executor_combo_box->clear(); + for (const auto& executor : data_->task_composer_server.getAvailableExecutors()) + ui->executor_combo_box->addItem(QString::fromStdString(executor)); + + ui->task_combo_box->clear(); + for (const auto& task : data_->task_composer_server.getAvailableTasks()) + ui->task_combo_box->addItem(QString::fromStdString(task)); + } + } + } + + if (event->type() == events::TaskComposerLoadLog::kType) + { + assert(dynamic_cast(event) != nullptr); + auto* e = static_cast(event); + if (e->getComponentInfo() == data_->component_info) + { + auto resource = data_->resource_locator.locateResource(e->getResourcePath()); + if (resource != nullptr) + { + auto log = tesseract_common::Serialization::fromArchiveFile( + resource->getFilePath()); + if (e->getNamespace().empty()) + data_->log_model.add(std::move(log)); + else + data_->log_model.add(std::move(log), e->getNamespace()); + } + } + } + + if (event->type() == events::TaskComposerSaveLog::kType) + { + assert(dynamic_cast(event) != nullptr); + auto* e = static_cast(event); + if (e->getComponentInfo() == data_->component_info) + { + QModelIndex current_index = ui->log_tree_view->selectionModel()->currentIndex(); + if (current_index.isValid()) + { + const auto& log = data_->log_model.get(current_index); + tesseract_common::Serialization::toArchiveFile(log, e->getSavePath()); + } + } + } + + if (event->type() == events::TaskComposerPlotDotgraph::kType) + { + assert(dynamic_cast(event) != nullptr); + auto* e = static_cast(event); + if (e->getComponentInfo() == data_->component_info) + { + QModelIndex current_index = ui->log_tree_view->selectionModel()->currentIndex(); + if (current_index.isValid()) + { + const auto& log = data_->log_model.get(current_index); + if (!log.dotgraph.empty()) + { + TaskComposerWidget::viewDotgraph(log.dotgraph); + } + else if (data_->task_composer_server.hasTask(log.context->name)) + { + const auto& task = data_->task_composer_server.getTask(log.context->name); + const std::string dotgraph = task.getDotgraph(log.context->task_infos.getInfoMap()); + TaskComposerWidget::viewDotgraph(dotgraph); + } + } + } + } + + if (event->type() == events::TaskComposerSetProfiles::kType) + { + assert(dynamic_cast(event) != nullptr); + auto* e = static_cast(event); + if (e->getComponentInfo() == data_->component_info) + data_->profiles = e->getProfiles(); + } + + // Standard event processing + return QObject::eventFilter(obj, event); +} +} // namespace tesseract_gui diff --git a/rendering/demo/CMakeLists.txt b/rendering/demo/CMakeLists.txt index f7ea5e98..febb9d4a 100644 --- a/rendering/demo/CMakeLists.txt +++ b/rendering/demo/CMakeLists.txt @@ -1,4 +1,3 @@ -find_package(tesseract_support REQUIRED) add_executable(${PROJECT_NAME}_render_widget_demo render_widget_demo.cpp) target_link_libraries( ${PROJECT_NAME}_render_widget_demo @@ -16,7 +15,6 @@ target_link_libraries( ${PROJECT_NAME}_manipulation_widgets ${PROJECT_NAME}_tool_path_widgets tesseract::tesseract_common - tesseract::tesseract_support Qt5::Core Qt5::Widgets) diff --git a/rendering/demo/render_environment_widget_demo.cpp b/rendering/demo/render_environment_widget_demo.cpp index ef0b44f7..45dcfd60 100644 --- a/rendering/demo/render_environment_widget_demo.cpp +++ b/rendering/demo/render_environment_widget_demo.cpp @@ -56,8 +56,8 @@ #include #include -#include #include +#include #include tesseract_gui::ToolPath getToolPath() @@ -121,9 +121,11 @@ int main(int argc, char** argv) Q_INIT_RESOURCE(tesseract_qt_resources); - auto locator = std::make_shared(); - tesseract_common::fs::path urdf_path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.urdf"; - tesseract_common::fs::path srdf_path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.srdf"; + auto locator = std::make_shared(); + tesseract_common::fs::path urdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.urdf")->getFilePath()); + tesseract_common::fs::path srdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.srdf")->getFilePath()); auto env = std::make_shared(); env->init(urdf_path, srdf_path, locator); diff --git a/scene_graph/demo/CMakeLists.txt b/scene_graph/demo/CMakeLists.txt index e1fd6b0d..ca4eb8bb 100644 --- a/scene_graph/demo/CMakeLists.txt +++ b/scene_graph/demo/CMakeLists.txt @@ -1,12 +1,7 @@ -find_package(tesseract_support REQUIRED) find_package(tesseract_urdf REQUIRED) add_executable(${PROJECT_NAME}_scene_graph_demo scene_graph_demo.cpp) -target_link_libraries( - ${PROJECT_NAME}_scene_graph_demo - PRIVATE tesseract::tesseract_support - tesseract::tesseract_urdf - ${PROJECT_NAME}_scene_graph_widgets - ${PROJECT_NAME}_common) +target_link_libraries(${PROJECT_NAME}_scene_graph_demo + PRIVATE tesseract::tesseract_urdf ${PROJECT_NAME}_scene_graph_widgets ${PROJECT_NAME}_common) install_targets(TARGETS ${PROJECT_NAME}_scene_graph_demo) diff --git a/scene_graph/demo/scene_graph_demo.cpp b/scene_graph/demo/scene_graph_demo.cpp index 9e555f3f..b6c1b7e4 100644 --- a/scene_graph/demo/scene_graph_demo.cpp +++ b/scene_graph/demo/scene_graph_demo.cpp @@ -35,7 +35,7 @@ #include #include -#include +#include int main(int argc, char** argv) { @@ -43,9 +43,9 @@ int main(int argc, char** argv) Q_INIT_RESOURCE(tesseract_qt_resources); - std::string path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.urdf"; + tesseract_common::GeneralResourceLocator locator; + std::string path = locator.locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.urdf")->getFilePath(); - tesseract_common::TesseractSupportResourceLocator locator; auto scene_graph = tesseract_urdf::parseURDFFile(path, locator); std::shared_ptr component_info = tesseract_gui::ComponentInfoManager::create("sce" diff --git a/studio/CMakeLists.txt b/studio/CMakeLists.txt index 42eb14d6..510c827e 100644 --- a/studio/CMakeLists.txt +++ b/studio/CMakeLists.txt @@ -65,6 +65,7 @@ qt5_wrap_cpp( include/tesseract_qt/studio/plugins/render/studio_render_dock_widget.h include/tesseract_qt/studio/plugins/studio_environment_dock_widget.h include/tesseract_qt/studio/plugins/studio_joint_trajectory_dock_widget.h + include/tesseract_qt/studio/plugins/studio_task_composer_dock_widget.h include/tesseract_qt/studio/plugins/studio_tool_path_dock_widget.h) qt5_wrap_ui( STUDIO_PLUGINS_headers_UI include/tesseract_qt/studio/plugins/manipulation/studio_manipulation_config_dialog.ui @@ -80,6 +81,7 @@ add_library( src/plugins/render/studio_render_dock_widget.cpp src/plugins/studio_environment_dock_widget.cpp src/plugins/studio_joint_trajectory_dock_widget.cpp + src/plugins/studio_task_composer_dock_widget.cpp src/plugins/studio_tool_path_dock_widget.cpp src/plugins/studio_plugin_factories.cpp) @@ -96,6 +98,7 @@ target_link_libraries( ${PROJECT_NAME}_environment_widgets ${PROJECT_NAME}_joint_trajectory_widgets ${PROJECT_NAME}_manipulation_widgets + ${PROJECT_NAME}_planning_widgets ${PROJECT_NAME}_tool_path_widgets) target_include_directories( ${PROJECT_NAME}_studio_plugins PUBLIC "$" diff --git a/studio/config/viewer.studio b/studio/config/viewer.studio index 6a0b7be4..c0f7e232 100644 --- a/studio/config/viewer.studio +++ b/studio/config/viewer.studio @@ -1,6 +1,7 @@ studio_config: search_paths: - /home/larmstrong/catkin_ws/tesseract_ws/devel/lib + - /home/lharmstrong/catkin_ws/tesseract_ws/devel/lib search_libraries: - tesseract_qt_studio_plugins component_infos: @@ -24,6 +25,10 @@ studio_config: class: StudioJointTrajectoryDockWidgetFactory config: component_info: bc184caf-74f7-457f-a2e2-a659f88b90f1 + Joint Trajectory Environment: + class: StudioEnvironmentDockWidgetFactory + config: + component_info: bc184caf-74f7-457f-a2e2-a659f88b90f1 Manipulation: class: StudioManipulationDockWidgetFactory config: @@ -38,7 +43,19 @@ studio_config: show_grid: true show_shadows: false central_widget: true + StudioPlugin18379996627190872657: + class: StudioTaskComposerDockWidgetFactory + config: + component_info: f203e94e-f59a-4612-88fe-358188aeed02 + StudioPlugin6600024128670871300: + class: StudioTaskComposerDockWidgetFactory + config: + component_info: f203e94e-f59a-4612-88fe-358188aeed02 + Task Composer: + class: StudioTaskComposerDockWidgetFactory + config: + component_info: f203e94e-f59a-4612-88fe-358188aeed02 Tool Path: class: StudioToolPathDockWidgetFactory config: - component_info: f203e94e-f59a-4612-88fe-358188aeed02 + component_info: f203e94e-f59a-4612-88fe-358188aeed02 \ No newline at end of file diff --git a/studio/config/viewer.studio.ini b/studio/config/viewer.studio.ini index 399a6bb4..b381e769 100644 --- a/studio/config/viewer.studio.ini +++ b/studio/config/viewer.studio.ini @@ -2,6 +2,6 @@ size=0 [TesseractStudio] -DockingState="@ByteArray(\0\0\x2\x61x\xda\x85\x92\xcdN\xc3\x30\x10\x84\xef<\xc5\xcawH\xab\x88R\xa4$U\x14\xe8\x1\x89?%-g\x93,\xc1\xe0\xac+\xc7)\x14\xf1\xf0l\xd2(\xd0\x8a\xc2\xc9\xf6\xce\xb7\x33+\xdb\xc1\xec\xbd\xd2\xb0\x46[+C\xa1\x18\x9f\x8c\x4 \xe5\xa6PT\x86\x62\x91\xcd\x8f\xa7\x62\x16\x5\xf7..\xd6\x92r,.L\xfe\xcaZ\xba\xa9\x1dV\xb0\x1c\x1a\x5,j\xb4\xc3\x99m\x12\x43N*\xe2J''H\xceJ\xfd\xa0\x8a\x12](\xd2\x1c\tE\x14\f\x14\xcc\xb5\x91\xae\x8b\x1dq=]i\xe5\x1c\x97o\xad\xe2NVZ\xdb\xcf\xd6\xb6!\xee\xf7\x99\x89-J\xc8\xe4\x63\x1f\xd0X\x8b\xadtIke\rU|`h\x1b\b7\xb2\xc2]\t\x12mj,\xda\x38/\n\xbc\xd6\xec\xa0\xe5vZ\x88\xb5\x36oX\xb4\x10\x3O\x82g\x96\x65\x87\xee\xe5\xf4\xfc?\t\xfe\x8f\x84\xcc\x18\rw\xd2=\xef[}\v\xbbv;\xd0\x95Q\xe4 \xb3\xf2\x5sg\xec\xe6/\xf6Z\x92Z5\xba\xbb\xd1\xdfGL\xd5\a\xd6\xd1\xe9x\n\xe7\xfe\x4\xfc\xb3\t\x4\xde\xb6\xc6k\xff.\xbc\x1d\x9e\x8e\xf7\a>Ht\xf4\x5\xf1H\xc8\x12)" -Geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0H\0\0\0\x1b\0\0\a\x7f\0\0\x4\xaf\0\0\0\x9b\0\0\0\x92\0\0\x3\xba\0\0\x2\xe9\0\0\0\0\x2\0\0\0\a\x80\0\0\0H\0\0\0@\0\0\a\x7f\0\0\x4\xaf) -State=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\a8\0\0\x4\x1a\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\xe\0t\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0) +DockingState="@ByteArray(\0\0\x4\xbex\xda\x95T\xdbn\xdb\x30\f}\xdfW\x10z\xef,\xd9\x89/\x80\xe3\"\xe8\xd6\x1\x3\xb6u\xb0\xbb=+\xb6\x92j\x95\xa5@\x96\xb3\x65\xd8\xc7\x97N27v\x93\x14\x5|\x13y\xc8\x43\x8aGN\xaf\xff\xd4\n6\xc2\x36\xd2\xe8\x19\x61\xef)\x1\xa1KSI\xbd\x9a\x91\xfb\xe2\xf6*&\xd7Y\xfa\xdd\xcd\xab\r\xd7\xa5\xa8>\x98\xf2\x11}\xf9\xb6q\xa2\x86\x1f} \x81\xfb\x46\xd8~\x8din\x8cv\\j\xb4\xcc\x88\x8fK\xa1\x9d\xe5\xea\xa7\xacV\xc2\xcdH^\n-H\x96\xf6(\xb8U\x86\xbb\x1d-E{\xbeV\xd2\x39\x34\x7f\xb3\x12#\xd1\xd3\xa5\xfd\xd7\xa5m5\xc6\a\x88\x99[\xc1\xa1\xe0\x8b\x3\x41k\xad\xe8\\\x1f\xf5\x46Z\xa3k\\ hO\b_y-\x86.\xb8Q\xa6\x11UG\xe7\x8d`\x9f\x8d\xd4\xe\n\xcb\x7f\x89\xd2\x19\xbb\x85\xf3q^W\xc4\xa0\x14vT\xca\xbeK\x98+e~\x8b\xaa\x3!`I\xb0W\xbe\xda\x41G\xc4\a\xfc+\f\xd3#\x86q\xa9\xe3\x8c\x5o\x1eq\xcf\xea\x35\x66\xb4\x97z\xce][Is\xa7\xda\x95\xd4,\xe\xa2$I\xc2\xd0\x8fXB\xe3\xc8\xf\xa7\xd1s,{\x11[\x18\xa3\xe0\x8e\xbb\x87\xb7l\xea%\xec\x17\xae\xe5\xbaU\xbb\xa9\x9f\xde\x8e\\\xfe\x15M6e1DxO\x93\t\xa4\xde\xde\x86\xef\x83v\xf0\xb3\x97\xd7i\xa5u\x3\xf8$L-\x9c\xdd\x66\x94\x41\x95@E\xa1\\\0\xa5@\x83\xdd\xf3\xe8\x9a\xc4\xb0\\\x1e\xaej\xf1\xdf\xce\x80.\x9f\x31\x61\x30\xc0\x8f\x32\\\xc6S\x7f\x88\x8c \xa6o\xcd\x96z}?g\xce\xd0U\x7f\x86\x18\x39/\xdc#5\x84!\xa5\xd4\x9f\x30?\xe#\x14\x3\v(%\x17\xc4s\n>\xd4\xce`\x84\xf4\xd5\xc1yg\xfe>\xd9\xbb'\xc0wo\x16)" +Geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\a\xc8\0\0\0\0\0\0\xe\xff\0\0\x4\x37\0\0\t\xad\0\0\x1\xfe\0\0\f\xcc\0\0\x4U\0\0\0\x3\x2\0\0\0\a\x80\0\0\a\xc8\0\0\0%\0\0\xe\xff\0\0\x4\x37) +State=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\a8\0\0\x3\xbd\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\xe\0t\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0) diff --git a/studio/include/tesseract_qt/studio/plugins/studio_task_composer_dock_widget.h b/studio/include/tesseract_qt/studio/plugins/studio_task_composer_dock_widget.h new file mode 100644 index 00000000..67fc6727 --- /dev/null +++ b/studio/include/tesseract_qt/studio/plugins/studio_task_composer_dock_widget.h @@ -0,0 +1,59 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef TESSERACT_QT_STUDIO_STUDIO_TASK_COMPOSER_DOCK_WIDGET_H +#define TESSERACT_QT_STUDIO_STUDIO_TASK_COMPOSER_DOCK_WIDGET_H + +#ifndef Q_MOC_RUN +#include +#include +#endif + +namespace tesseract_gui +{ +class StudioTaskComposerDockWidget : public StudioDockWidget +{ + Q_OBJECT +public: + StudioTaskComposerDockWidget(const QString& title, QWidget* parent = nullptr); + + ~StudioTaskComposerDockWidget() override; + + std::string getFactoryClassName() const override; + + void loadConfig(const YAML::Node& config) override; + + YAML::Node getConfig() const override; + +public Q_SLOTS: + void onInitialize() override; + +private: + struct Implementation; + std::unique_ptr data_; + + void setup(); +}; + +} // namespace tesseract_gui + +#endif // TESSERACT_QT_STUDIO_STUDIO_TASK_COMPOSER_DOCK_WIDGET_H diff --git a/studio/src/plugins/studio_plugin_factories.cpp b/studio/src/plugins/studio_plugin_factories.cpp index ccc2e156..ceb05695 100644 --- a/studio/src/plugins/studio_plugin_factories.cpp +++ b/studio/src/plugins/studio_plugin_factories.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace tesseract_gui @@ -34,6 +35,7 @@ using StudioRenderDockWidgetFactory = StudioDockWidgetFactoryImpl; using StudioJointTrajectoryDockWidgetFactory = StudioDockWidgetFactoryImpl; using StudioManipulationDockWidgetFactory = StudioDockWidgetFactoryImpl; +using StudioTaskComposerDockWidgetFactory = StudioDockWidgetFactoryImpl; using StudioToolPathDockWidgetFactory = StudioDockWidgetFactoryImpl; } // namespace tesseract_gui @@ -50,5 +52,8 @@ TESSERACT_ADD_STUDIO_PLUGIN(tesseract_gui::StudioJointTrajectoryDockWidgetFactor // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) TESSERACT_ADD_STUDIO_PLUGIN(tesseract_gui::StudioManipulationDockWidgetFactory, StudioManipulationDockWidgetFactory) +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +TESSERACT_ADD_STUDIO_PLUGIN(tesseract_gui::StudioTaskComposerDockWidgetFactory, StudioTaskComposerDockWidgetFactory) + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) TESSERACT_ADD_STUDIO_PLUGIN(tesseract_gui::StudioToolPathDockWidgetFactory, StudioToolPathDockWidgetFactory) diff --git a/studio/src/plugins/studio_task_composer_dock_widget.cpp b/studio/src/plugins/studio_task_composer_dock_widget.cpp new file mode 100644 index 00000000..777aa1d2 --- /dev/null +++ b/studio/src/plugins/studio_task_composer_dock_widget.cpp @@ -0,0 +1,119 @@ +/** + * @author Levi Armstrong + * + * @copyright Copyright (C) 2024 Levi Armstrong + * + * @par License + * GNU Lesser General Public License Version 3, 29 June 2007 + * @par + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * @par + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::GeneralResourceLocator) +BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_environment::Environment) + +namespace tesseract_gui +{ +struct StudioTaskComposerDockWidget::Implementation +{ + std::shared_ptr component_info; + TaskComposerWidget* widget{ nullptr }; + TaskComposerToolBar* tool_bar{ nullptr }; +}; + +StudioTaskComposerDockWidget::StudioTaskComposerDockWidget(const QString& title, QWidget* parent) + : StudioDockWidget(title, parent), data_(std::make_unique()) +{ +} + +StudioTaskComposerDockWidget::~StudioTaskComposerDockWidget() = default; + +std::string StudioTaskComposerDockWidget::getFactoryClassName() const { return "StudioTaskComposerDockWidgetFactory"; } + +void StudioTaskComposerDockWidget::loadConfig(const YAML::Node& config) +{ + if (const YAML::Node& n = config["component_info"]) // NOLINT + { + auto uuid = boost::lexical_cast(n.as()); + if (uuid.is_nil()) + throw std::runtime_error("StudioTaskComposerDockWidget, config component info is nil."); + + data_->component_info = ComponentInfoManager::get(uuid); + if (data_->component_info == nullptr) + throw std::runtime_error("StudioTaskComposerDockWidget, config component info was not found."); + } + else + { + throw std::runtime_error("StudioTaskComposerDockWidget, config is missing component info."); + } + + setup(); +} + +YAML::Node StudioTaskComposerDockWidget::getConfig() const +{ + // Config + YAML::Node config_node; + config_node["component_info"] = boost::uuids::to_string(data_->component_info->getNamespace()); + return config_node; +} + +void StudioTaskComposerDockWidget::onInitialize() +{ + if (isInitialized()) + return; + + ComponentInfoDialog dialog(this); + if (dialog.exec()) + { + data_->component_info = dialog.getComponentInfo(); + if (data_->component_info == nullptr) + return; + + setup(); + } +} + +void StudioTaskComposerDockWidget::setup() +{ + data_->widget = new TaskComposerWidget(data_->component_info); + data_->tool_bar = new TaskComposerToolBar(data_->component_info); + + setWidget(data_->widget); + setToolBar(data_->tool_bar); + toolBar()->setIconSize(QSize(25, 25)); + setFeature(ads::CDockWidget::DockWidgetFocusable, true); +} +} // namespace tesseract_gui diff --git a/workbench/CMakeLists.txt b/workbench/CMakeLists.txt index cd95c7c2..8dd10f8d 100644 --- a/workbench/CMakeLists.txt +++ b/workbench/CMakeLists.txt @@ -17,7 +17,8 @@ target_link_libraries( Qt5::Widgets ${PROJECT_NAME}_environment_widgets ${PROJECT_NAME}_joint_trajectory_widgets - ${PROJECT_NAME}_manipulation_widgets) + ${PROJECT_NAME}_manipulation_widgets + ${PROJECT_NAME}_planning_widgets) target_include_directories( ${PROJECT_NAME}_workbench_widgets PUBLIC "$" "$" diff --git a/workbench/demo/CMakeLists.txt b/workbench/demo/CMakeLists.txt index ff1f1240..45b19b5a 100644 --- a/workbench/demo/CMakeLists.txt +++ b/workbench/demo/CMakeLists.txt @@ -1,12 +1,10 @@ -find_package(tesseract_support REQUIRED) find_package(tesseract_urdf REQUIRED) find_package(tesseract_srdf REQUIRED) add_executable(${PROJECT_NAME}_workbench_demo workbench_demo.cpp) target_link_libraries( ${PROJECT_NAME}_workbench_demo - PRIVATE tesseract::tesseract_support - tesseract::tesseract_urdf + PRIVATE tesseract::tesseract_urdf tesseract::tesseract_srdf ${PROJECT_NAME}_workbench_widgets ${PROJECT_NAME}_environment_widgets diff --git a/workbench/demo/workbench_demo.cpp b/workbench/demo/workbench_demo.cpp index b33b3221..9f59614b 100644 --- a/workbench/demo/workbench_demo.cpp +++ b/workbench/demo/workbench_demo.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include int main(int argc, char** argv) { @@ -38,9 +38,11 @@ int main(int argc, char** argv) Q_INIT_RESOURCE(tesseract_qt_resources); - auto locator = std::make_shared(); - tesseract_common::fs::path urdf_path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.urdf"; - tesseract_common::fs::path srdf_path = std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.srdf"; + auto locator = std::make_shared(); + tesseract_common::fs::path urdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.urdf")->getFilePath()); + tesseract_common::fs::path srdf_path( + locator->locateResource("package://tesseract_support/urdf/lbr_iiwa_14_r820.srdf")->getFilePath()); auto env = std::make_shared(); env->init(urdf_path, srdf_path, locator); diff --git a/workbench/include/tesseract_qt/workbench/workbench_widget.h b/workbench/include/tesseract_qt/workbench/workbench_widget.h index 3a46dbb1..fe2f19fe 100644 --- a/workbench/include/tesseract_qt/workbench/workbench_widget.h +++ b/workbench/include/tesseract_qt/workbench/workbench_widget.h @@ -38,6 +38,7 @@ namespace tesseract_gui class EnvironmentWidget; class JointTrajectoryWidget; class ManipulationWidget; +class TaskComposerWidget; class ComponentInfo; class WorkbenchWidget : public QWidget @@ -61,6 +62,9 @@ class WorkbenchWidget : public QWidget ManipulationWidget& getManipulationWidget(); const ManipulationWidget& getManipulationWidget() const; + TaskComposerWidget& getTaskComposerWidget(); + const TaskComposerWidget& getTaskComposerWidget() const; + private: struct Implementation; std::unique_ptr ui; diff --git a/workbench/include/tesseract_qt/workbench/workbench_widget.ui b/workbench/include/tesseract_qt/workbench/workbench_widget.ui index 1bbd13ab..e9f3bd37 100644 --- a/workbench/include/tesseract_qt/workbench/workbench_widget.ui +++ b/workbench/include/tesseract_qt/workbench/workbench_widget.ui @@ -6,7 +6,7 @@ 0 0 - 369 + 420 347 @@ -38,7 +38,7 @@ - 0 + 3 @@ -134,7 +134,7 @@ - + 0 @@ -142,8 +142,25 @@ - Planning + Task Composer + + + 3 + + + 3 + + + 3 + + + 3 + + + + + @@ -168,6 +185,12 @@
tesseract_qt/manipulation/manipulation_widget.h
1 + + tesseract_gui::TaskComposerWidget + QWidget +
tesseract_qt/planning/widgets/task_composer_widget.h
+ 1 +
diff --git a/workbench/src/workbench_widget.cpp b/workbench/src/workbench_widget.cpp index 7a88e7b5..e23e0ed9 100644 --- a/workbench/src/workbench_widget.cpp +++ b/workbench/src/workbench_widget.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -38,10 +39,11 @@ struct WorkbenchWidget::Implementation std::shared_ptr component_info; std::shared_ptr jt_component_info; - SceneGraphToolBar* env_toolbar; - SceneGraphToolBar* jt_env_toolbar; - JointTrajectoryToolBar* jt_toolbar; - ManipulationToolBar* manip_toolbar; + SceneGraphToolBar* env_toolbar{ nullptr }; + SceneGraphToolBar* jt_env_toolbar{ nullptr }; + JointTrajectoryToolBar* jt_toolbar{ nullptr }; + ManipulationToolBar* manip_toolbar{ nullptr }; + TaskComposerToolBar* task_composer_toolbar{ nullptr }; }; WorkbenchWidget::WorkbenchWidget(QWidget* parent) : WorkbenchWidget(nullptr, parent) {} @@ -52,18 +54,21 @@ WorkbenchWidget::WorkbenchWidget(std::shared_ptr component_ ui->setupUi(this); ui->tabWidget->setCurrentIndex(0); - data_->env_toolbar = new SceneGraphToolBar(); + data_->env_toolbar = new SceneGraphToolBar(); // NOLINT static_cast(ui->environment_widget->layout())->insertWidget(0, data_->env_toolbar); - data_->jt_env_toolbar = new SceneGraphToolBar(); + data_->jt_env_toolbar = new SceneGraphToolBar(); // NOLINT static_cast(ui->jt_environment_widget->layout())->insertWidget(0, data_->jt_env_toolbar); - data_->jt_toolbar = new JointTrajectoryToolBar(); + data_->jt_toolbar = new JointTrajectoryToolBar(); // NOLINT static_cast(ui->joint_trajectory_widget->layout())->insertWidget(0, data_->jt_toolbar); - data_->manip_toolbar = new ManipulationToolBar(); + data_->manip_toolbar = new ManipulationToolBar(); // NOLINT static_cast(ui->manipulation_widget->layout())->insertWidget(0, data_->manip_toolbar); + data_->task_composer_toolbar = new TaskComposerToolBar(); // NOLINT + static_cast(ui->task_composer_widget->layout())->insertWidget(0, data_->task_composer_toolbar); + setComponentInfo(std::move(component_info)); } @@ -82,6 +87,8 @@ void WorkbenchWidget::setComponentInfo(std::shared_ptr comp data_->jt_toolbar->setComponentInfo(data_->jt_component_info); ui->jt_environment_widget->setComponentInfo(data_->jt_component_info); data_->jt_env_toolbar->setComponentInfo(data_->jt_component_info); + ui->task_composer_widget->setComponentInfo(data_->component_info); + data_->task_composer_toolbar->setComponentInfo(data_->component_info); } std::shared_ptr WorkbenchWidget::getComponentInfo() const { return data_->component_info; } @@ -95,4 +102,7 @@ const JointTrajectoryWidget& WorkbenchWidget::getJointTrajectoryWidget() const { ManipulationWidget& WorkbenchWidget::getManipulationWidget() { return *ui->manipulation_widget; } const ManipulationWidget& WorkbenchWidget::getManipulationWidget() const { return *ui->manipulation_widget; } +TaskComposerWidget& WorkbenchWidget::getTaskComposerWidget() { return *ui->task_composer_widget; } +const TaskComposerWidget& WorkbenchWidget::getTaskComposerWidget() const { return *ui->task_composer_widget; } + } // namespace tesseract_gui