monitoring v1.0.0
Loading...
Searching...
No Matches
geofence_display.cpp
Go to the documentation of this file.
1// Copyright Institute for Automotive Engineering (ika), RWTH Aachen University
2// SPDX-License-Identifier: Apache-2.0
3
4/*
5 * Geofence display - renders polygon edges as thin 3D quads with vertical fade.
6 */
7
9
10#include <OgreManualObject.h>
11#include <OgreMaterialManager.h>
12#include <OgreSceneManager.h>
13#include <OgreSceneNode.h>
14#include <OgreTechnique.h>
15
16#include <string>
17#include <vector>
18
19#include "rviz_common/display_context.hpp"
20#include "rviz_common/frame_manager_iface.hpp"
21#include "rviz_common/logging.hpp"
22#include "rviz_common/properties/color_property.hpp"
23#include "rviz_common/properties/float_property.hpp"
24#include "rviz_common/validate_floats.hpp"
25#include "rviz_rendering/material_manager.hpp"
26
27namespace rviz_plugins {
28namespace displays {
29
30namespace {
31bool validateFloats(const geometry_msgs::msg::PolygonStamped::ConstSharedPtr& msg) {
32 return rviz_common::validateFloats(msg->polygon.points);
33}
34} // namespace
35
37 color_property_ = new rviz_common::properties::ColorProperty("Color", QColor(25, 255, 0), "Base color for geofence edges.",
38 this, SLOT(queueRender()));
39
40 bottom_alpha_property_ = new rviz_common::properties::FloatProperty(
41 "Bottom Alpha", 0.8f, "Alpha at the bottom of the edge (0..1).", this, SLOT(queueRender()));
42 bottom_alpha_property_->setMin(0.0);
43 bottom_alpha_property_->setMax(1.0);
44
45 top_alpha_property_ = new rviz_common::properties::FloatProperty("Top Alpha", 0.05f, "Alpha at the top of the edge (0..1).",
46 this, SLOT(queueRender()));
47 top_alpha_property_->setMin(0.0);
48 top_alpha_property_->setMax(1.0);
49
50 height_property_ = new rviz_common::properties::FloatProperty("Height", 2.0f, "Extrusion height of the edges (meters).", this,
51 SLOT(queueRender()));
52 height_property_->setMin(0.0);
53
54 thickness_property_ = new rviz_common::properties::FloatProperty(
55 "Thickness", 0.05f, "Visual thickness of the edge band (meters).", this, SLOT(queueRender()));
56 thickness_property_->setMin(0.0);
57
58 static int geofence_count = 0;
59 std::string material_name = "GeofenceMaterial" + std::to_string(geofence_count++);
60 material_ = rviz_rendering::MaterialManager::createMaterialWithNoLighting(material_name);
61 material_->setCullingMode(Ogre::CULL_NONE);
62}
63
65 if (initialized()) {
66 scene_manager_->destroyManualObject(manual_object_);
67 }
68}
69
71 MFDClass::onInitialize();
72 manual_object_ = scene_manager_->createManualObject();
73 manual_object_->setDynamic(true);
74 scene_node_->attachObject(manual_object_);
75}
76
78 MFDClass::reset();
79 manual_object_->clear();
80}
81
82void GeofenceDisplay::processMessage(geometry_msgs::msg::PolygonStamped::ConstSharedPtr msg) {
83 if (!validateFloats(msg)) {
84 setStatus(rviz_common::properties::StatusProperty::Error, "Topic",
85 "Message contained invalid floating point values (nans or infs)");
86 return;
87 }
88
89 rclcpp::Time msg_time(msg->header.stamp, RCL_ROS_TIME);
90 if (!updateFrame(msg->header.frame_id, msg_time)) {
91 setMissingTransformToFixedFrame(msg->header.frame_id);
92 return;
93 }
94 setTransformOk();
95
96 manual_object_->clear();
97
98 const auto base_color_qt = color_property_->getColor();
99 Ogre::ColourValue base_color(static_cast<float>(base_color_qt.redF()), static_cast<float>(base_color_qt.greenF()),
100 static_cast<float>(base_color_qt.blueF()), 1.0f);
101
102 const float alpha_bottom = std::max(0.0f, std::min(1.0f, bottom_alpha_property_->getFloat()));
103 const float alpha_top = std::max(0.0f, std::min(1.0f, top_alpha_property_->getFloat()));
104 const float height = std::max(0.0f, height_property_->getFloat());
105 const float thickness = std::max(0.0f, thickness_property_->getFloat());
106
107 // If any alpha < 1, enable alpha blending
108 rviz_rendering::MaterialManager::enableAlphaBlending(material_, std::min(alpha_bottom, alpha_top));
109
110 const size_t n = msg->polygon.points.size();
111 if (n < 2 || height <= 0.0f) {
112 return;
113 }
114
115 // Two quads per edge if thickness > 0, otherwise one quad centered on the edge normal.
116 // We'll use OT_TRIANGLE_LIST and per-vertex colors for vertical fade.
117 manual_object_->begin(material_->getName(), Ogre::RenderOperation::OT_TRIANGLE_LIST, "rviz_rendering");
118
119 // Helper lambda to push a quad as two triangles with vertical fade.
120 unsigned int vertex_index = 0;
121 auto add_quad = [&](const Ogre::Vector3& b0, const Ogre::Vector3& b1, const Ogre::Vector3& t1, const Ogre::Vector3& t0) {
122 // Vertex order: b0, b1, t1, t0
123 const unsigned int start_index = vertex_index;
124
125 Ogre::ColourValue bottom_color = base_color;
126 bottom_color.a = alpha_bottom;
127 Ogre::ColourValue top_color = base_color;
128 top_color.a = alpha_top;
129
130 manual_object_->position(b0);
131 manual_object_->colour(bottom_color);
132 manual_object_->position(b1);
133 manual_object_->colour(bottom_color);
134 manual_object_->position(t1);
135 manual_object_->colour(top_color);
136 manual_object_->position(t0);
137 manual_object_->colour(top_color);
138
139 // Two triangles: (0,1,2) and (0,2,3)
140 manual_object_->triangle(start_index + 0, start_index + 1, start_index + 2);
141 manual_object_->triangle(start_index + 0, start_index + 2, start_index + 3);
142 vertex_index += 4;
143 };
144
145 const Ogre::Vector3 z_up(0.0f, 0.0f, 1.0f);
146
147 for (size_t i = 0; i < n; ++i) {
148 const auto& p0 = msg->polygon.points[i];
149 const auto& p1 = msg->polygon.points[(i + 1) % n];
150
151 Ogre::Vector3 P0(p0.x, p0.y, p0.z);
152 Ogre::Vector3 P1(p1.x, p1.y, p1.z);
153
154 Ogre::Vector3 edge = P1 - P0;
155 Ogre::Vector3 edge_xy(edge.x, edge.y, 0.0f);
156 if (edge_xy.squaredLength() < 1e-10f) {
157 continue; // skip degenerate edge
158 }
159 edge_xy.normalise();
160 Ogre::Vector3 normal(-edge_xy.y, edge_xy.x, 0.0f); // perpendicular in XY
161
162 const float hw = thickness * 0.5f;
163
164 // Base and top points for this edge
165 Ogre::Vector3 B0 = P0;
166 Ogre::Vector3 B1 = P1;
167 Ogre::Vector3 T0 = P0 + height * z_up;
168 Ogre::Vector3 T1 = P1 + height * z_up;
169
170 if (thickness > 1e-6f) {
171 // Left face (offset -normal)
172 Ogre::Vector3 off = -normal * hw;
173 add_quad(B0 + off, B1 + off, T1 + off, T0 + off);
174 // Right face (offset +normal)
175 off = normal * hw;
176 add_quad(B0 + off, B1 + off, T1 + off, T0 + off);
177 } else {
178 // Single centered face: create a very thin band by offsetting half-width on each side
179 Ogre::Vector3 off = normal * 1e-3f; // virtually zero thickness
180 add_quad(B0 - off, B1 - off, T1 - off, T0 - off);
181 add_quad(B0 + off, B1 + off, T1 + off, T0 + off);
182 }
183 }
184
185 manual_object_->end();
186}
187
188} // namespace displays
189} // namespace rviz_plugins
190
191#include <pluginlib/class_list_macros.hpp> // NOLINT
192PLUGINLIB_EXPORT_CLASS(rviz_plugins::displays::GeofenceDisplay, rviz_common::Display)
rviz_common::properties::FloatProperty * height_property_
GeofenceDisplay()
Construct a new GeofenceDisplay.
void reset() override
Reset the display and clear all rendered data.
rviz_common::properties::FloatProperty * thickness_property_
void processMessage(geometry_msgs::msg::PolygonStamped::ConstSharedPtr msg) override
Process an incoming geofence polygon message.
rviz_common::properties::ColorProperty * color_property_
void onInitialize() override
Initialize display resources and properties.
rviz_common::properties::FloatProperty * bottom_alpha_property_
~GeofenceDisplay() override
Destroy the GeofenceDisplay.
rviz_common::properties::FloatProperty * top_alpha_property_