-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MaliputViewerPlugin: Provides ray-cast support #388
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
#include "maliput_viewer_plugin.hh" | ||
|
||
#include <ignition/common/Console.hh> | ||
#include <ignition/gui/Conversions.hh> | ||
#include <ignition/plugin/Register.hh> | ||
#include <ignition/rendering/RenderEngine.hh> | ||
#include <ignition/rendering/RenderingIface.hh> | ||
|
@@ -125,7 +126,7 @@ void MaliputViewerPlugin::timerEvent(QTimerEvent* _event) { | |
return; | ||
} | ||
timer.stop(); | ||
ConfigurateScene(); | ||
Initialize(); | ||
RenderMeshes(); | ||
} | ||
|
||
|
@@ -316,16 +317,22 @@ void MaliputViewerPlugin::LoadConfig(const tinyxml2::XMLElement* _pluginElem) { | |
timer.start(kTimerPeriodInMs, this); | ||
return; | ||
} | ||
ConfigurateScene(); | ||
Initialize(); | ||
RenderMeshes(); | ||
} | ||
|
||
void MaliputViewerPlugin::ConfigurateScene() { | ||
void MaliputViewerPlugin::Initialize() { | ||
rayQuery = scene->CreateRayQuery(); | ||
rootVisual = scene->RootVisual(); | ||
if (!rootVisual) { | ||
ignerr << "Failed to find the root visual" << std::endl; | ||
return; | ||
} | ||
camera = std::dynamic_pointer_cast<ignition::rendering::Camera>(rootVisual->ChildByIndex(0)); | ||
if (!camera) { | ||
ignerr << "Failed to find the camera" << std::endl; | ||
return; | ||
} | ||
// Lights. | ||
const double lightRed = 0.88; | ||
const double lightGreen = 0.88; | ||
|
@@ -340,6 +347,58 @@ void MaliputViewerPlugin::ConfigurateScene() { | |
directionalLight->SetDiffuseColor(lightRed, lightGreen, lightBlue); | ||
directionalLight->SetSpecularColor(lightRed, lightGreen, lightBlue); | ||
rootVisual->AddChild(directionalLight); | ||
|
||
// Install event filter to get mouse event from the main scene. | ||
QList<Plugin*> plugins = parent()->findChildren<Plugin*>(); | ||
Plugin* scene3D{nullptr}; | ||
for (auto& plugin : plugins) { | ||
if (plugin->Title() == kMainScene3dPlugin) { | ||
scene3D = plugin; | ||
break; | ||
} | ||
} | ||
if (!scene3D) { | ||
ignerr << "Scene3D plugin titled '" << kMainScene3dPlugin << "' wasn't found. MouseEvents won't be filtered." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't it be a definitive error? I recommend returning and flagging and error or raising an exception. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
<< std::endl; | ||
} else { | ||
auto renderWindowItem = scene3D->PluginItem()->findChild<QQuickItem*>(); | ||
renderWindowItem->installEventFilter(this); | ||
} | ||
} | ||
|
||
bool MaliputViewerPlugin::eventFilter(QObject* _obj, QEvent* _event) { | ||
if (_event->type() == QEvent::Type::MouseButtonPress) { | ||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(_event); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can it be const? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
if (mouseEvent && mouseEvent->button() == Qt::LeftButton) { | ||
MouseClickHandler(mouseEvent); | ||
} | ||
} | ||
// Standard event processing | ||
return QObject::eventFilter(_obj, _event); | ||
} | ||
|
||
void MaliputViewerPlugin::MouseClickHandler(QMouseEvent* _mouseEvent) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
const auto rayQueryResult = ScreenToScene(_mouseEvent->x(), _mouseEvent->y()); | ||
if (rayQueryResult.distance > -1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume that distance being less than zero is an error (i.e. no collision)? Can we test for non-negative values? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! My bad. Done |
||
const maliput::api::Lane* lane = model->GetLaneFromWorldPosition(rayQueryResult.point); | ||
if (lane) { | ||
const std::string& lane_id = lane->id().string(); | ||
ignmsg << "Clicked lane ID: " << lane_id << std::endl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't you do: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Done. |
||
} | ||
} | ||
} | ||
|
||
ignition::rendering::RayQueryResult MaliputViewerPlugin::ScreenToScene(int screenX, int screenY) const { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you missed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
// Normalize point on the image | ||
const double width = camera->ImageWidth(); | ||
const double height = camera->ImageHeight(); | ||
|
||
const double nx = 2.0 * screenX / width - 1.0; | ||
const double ny = 1.0 - 2.0 * screenY / height; | ||
|
||
// Make a ray query | ||
rayQuery->SetFromCamera(camera, {nx, ny}); | ||
return rayQuery->ClosestPoint(); | ||
} | ||
|
||
} // namespace gui | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,9 @@ | |
|
||
#include <maliput/api/road_geometry.h> | ||
|
||
#include <ignition/common/MouseEvent.hh> | ||
#include <ignition/gui/Plugin.hh> | ||
#include <ignition/rendering/RayQuery.hh> | ||
#include <ignition/rendering/RenderTypes.hh> | ||
#include <ignition/rendering/Scene.hh> | ||
|
||
|
@@ -52,10 +54,16 @@ class MaliputViewerPlugin : public ignition::gui::Plugin { | |
void LabelCheckboxesChanged(); | ||
|
||
protected: | ||
/// @brief Timer event callback which handles the logic to load the meshes when | ||
/// \brief Timer event callback which handles the logic to load the meshes when | ||
/// the scene is not ready yet. | ||
void timerEvent(QTimerEvent* _event) override; | ||
|
||
/// \brief Intercepts an @p _event delivered to other object @p _obj. | ||
/// \details We are particularly interested in QMouseEvents happening within the main scene. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rephrase this to say:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
/// This method is called automatically by the QT Event System iff the event filter was installed | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: QT -> Qt There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
/// in the target object. \see QObject::installEventFilter method. | ||
bool eventFilter(QObject* _obj, QEvent* _event) override; | ||
|
||
protected slots: | ||
/// \brief Clears the visualizer, loads a RoadNetwork and update the GUI with meshes and labels. | ||
/// \param[in] _mapFile The path to the map file to load and visualize. | ||
|
@@ -82,6 +90,9 @@ class MaliputViewerPlugin : public ignition::gui::Plugin { | |
/// @brief The scene name. | ||
static constexpr char const* kSceneName = "scene"; | ||
|
||
/// @brief The Scene3D instance holding the main scene. | ||
static constexpr char const* kMainScene3dPlugin = "Main3DScene"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's make this a plugin argument. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And change occurrences of kMainScene3dPlugin to refer the xml argument. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should also update the plugin documentation to state what it is expected as configuration. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. Done. |
||
|
||
/// @brief The rendering engine name. | ||
static constexpr char const* kEngineName = "ogre"; | ||
|
||
|
@@ -104,6 +115,16 @@ class MaliputViewerPlugin : public ignition::gui::Plugin { | |
/// \brief Renders meshes for the road and the labels. | ||
void RenderMeshes(); | ||
|
||
/// \brief Handles the left click mouse event. | ||
/// @param[in] _mouseEvent QMouseEvent pointer. | ||
void MouseClickHandler(QMouseEvent* _mouseEvent); | ||
|
||
/// \brief Performs a raycast on the screen. | ||
/// \param[in] screenX X screen's coordinate. | ||
/// \param[in] screenY Y screen's coordinate. | ||
/// \return A ignition::rendering::RayQueryResult. | ||
ignition::rendering::RayQueryResult ScreenToScene(int screenX, int screenY) const; | ||
|
||
/// \brief Builds visuals for each mesh inside @p _maliputMeshes that is | ||
/// enabled. | ||
/// \param[in] _maliputMeshes A map of meshes to render. | ||
|
@@ -116,8 +137,10 @@ class MaliputViewerPlugin : public ignition::gui::Plugin { | |
/// \brief Clears all the references to text labels, meshes and the scene. | ||
void Clear(); | ||
|
||
/// \brief Configurate scene. | ||
void ConfigurateScene(); | ||
/// \brief Configurate scene and install event filter for filtering QMouseEvents. | ||
/// \details To install the event filter the Scene3D plugin hosting the scene | ||
/// is expected to be titled as #kMainScene3dPlugin. | ||
void Initialize(); | ||
|
||
/// \brief Holds the map file path. | ||
std::string mapFile{""}; | ||
|
@@ -146,6 +169,12 @@ class MaliputViewerPlugin : public ignition::gui::Plugin { | |
/// \brief Holds a pointer to the scene. | ||
ignition::rendering::ScenePtr scene{nullptr}; | ||
|
||
/// \brief Holds a pointer to a ray query. | ||
ignition::rendering::RayQueryPtr rayQuery{nullptr}; | ||
|
||
/// \brief Holds a pointer to the camera. | ||
ignition::rendering::CameraPtr camera{}; | ||
|
||
/// \brief Model that holds the meshes and the visualization status. | ||
std::unique_ptr<MaliputViewerModel> model{}; | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we convert this block in a function that filters plugins by title?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.