47#include <armarx/navigation/components/navigation_memory/ComponentInterface.h>
54 const std::string Component::defaultName =
"room_editor";
68 def->optional(properties.providerSegmentName,
69 "p.providerSegmentName",
70 "If set, only the rooms of this provider segment (i.e. navigation graph) "
71 "are edited. If empty, all rooms are edited.");
74 properties.updateRate,
"p.updateRate",
"Rate of the ArViz interaction loop [Hz].");
76 def->optional(properties.layerPrefix,
78 "Prefix of the ArViz layers created by this component.");
80 def->optional(properties.vertexHandleRadius,
81 "p.visu.vertexHandleRadius",
82 "Radius of the draggable polygon vertex handles [mm].");
84 def->optional(properties.edgeHandleSize,
85 "p.visu.edgeHandleSize",
86 "Edge length of the draggable edge handles [mm].");
88 def->optional(properties.exportPackageName,
89 "p.export.packageName",
90 "ArmarX package the rooms are exported to.");
92 def->optional(properties.exportDirectory,
94 "Directory relative to the package's data directory the rooms are "
95 "exported to. The `rooms.json` files are written to "
96 "`<directory>/<navigation graph>/rooms.json`, so this usually has to "
97 "include the dataset, e.g. `navigation-graphs/50_19`.");
111 editorParameters.
layerPrefix = properties.layerPrefix;
115 editor = std::make_unique<RoomEditor>(
arviz, editorParameters);
116 editor->setRoomChangedCallback([
this](
const EditableRoom& room) { storeRoom(room); });
130 const bool join =
true;
146 return Component::defaultName;
152 return Component::defaultName;
163 editor->redrawAll(stage);
169 ARMARX_IMPORTANT <<
"Room editor is ready. Drag the handles in ArViz to reshape a room. "
170 "If the handles cannot be grabbed, disable the 3D viewer's viewing "
171 "mode (the toolbar toggle above the 3D view, shortcut `V`).";
173 const float rate = std::max(properties.updateRate, 1.F);
177 while (not task->isStopped())
185 editor->update(result, stage);
188 if (not editor->isInteracting() and reloadRequested.exchange(
false))
191 editor->redrawAll(stage);
194 metronome.waitForNextTick();
203 memory::client::rooms::Reader::Query query;
205 if (not properties.providerSegmentName.empty())
207 query.providerName = properties.providerSegmentName;
210 const auto result = roomsReaderPlugin->get().query(query);
214 ARMARX_WARNING <<
"Could not read the rooms from the navigation memory: "
215 << result.errorMessage;
216 editor->setRooms({});
221 std::vector<EditableRoom> rooms;
222 rooms.reserve(result.entries.size());
224 for (
const auto& entry : result.entries)
226 EditableRoom editable{.providerSegmentName = entry.instanceID.providerSegmentName,
229 if (editable.room.name.empty())
232 editable.room.name = entry.instanceID.entityName;
235 rooms.push_back(std::move(editable));
239 std::sort(rooms.begin(),
241 [](
const EditableRoom& lhs,
const EditableRoom& rhs)
243 return std::tie(lhs.providerSegmentName, lhs.room.name) <
244 std::tie(rhs.providerSegmentName, rhs.room.name);
247 ARMARX_INFO <<
"Read " << rooms.size() <<
" room(s) from the navigation memory.";
249 numRooms =
static_cast<int>(rooms.size());
250 editor->setRooms(rooms);
258 if (editable.providerSegmentName.empty())
260 ARMARX_ERROR <<
"Cannot write room `" << editable.room.name
261 <<
"` back into the memory: the provider segment is unknown.";
265 if (not roomsWriterPlugin->get().store(
268 ARMARX_ERROR <<
"Failed to write room `" << editable.room.name
269 <<
"` back into the navigation memory.";
273 ARMARX_INFO <<
"Updated room `" << editable.room.name <<
"` in the navigation memory.";
277 Component::exportRooms()
279 std::string packageName;
280 std::string directory;
282 std::scoped_lock lock(exportPathMutex);
283 packageName = properties.exportPackageName;
284 directory = properties.exportDirectory;
287 const auto navigationMemoryPrx = memory::NavigationMemoryInterfacePrx::uncheckedCast(
288 roomsReaderPlugin->get().readingPrx());
290 if (not navigationMemoryPrx)
292 ARMARX_ERROR <<
"Export failed: not connected to a navigation memory.";
296 const armarx::PackagePath packagePath(packageName, directory);
300 if (not navigationMemoryPrx->storeRooms(packagePath.serialize()))
302 ARMARX_ERROR <<
"Export failed: the navigation memory could not store the rooms.";
306 catch (
const Ice::Exception& e)
312 ARMARX_IMPORTANT <<
"Exported the rooms to package `" << packageName <<
"`, directory `"
313 << directory <<
"`.";
320 reloadRequested =
true;
326 return exportRooms();
334 tab.statusLabel.setText(
"Editing " + std::to_string(numRooms.load()) +
" room(s).");
336 tab.reloadButton.setLabel(
"Reload from memory");
338 tab.exportPackageName.setValue(properties.exportPackageName);
339 tab.exportDirectory.setValue(properties.exportDirectory);
340 tab.exportButton.setLabel(
"Export rooms to JSON");
341 tab.exportLabel.setText(
"");
346 exportGrid.
add(
Label(
"Package:"), {row, 0}).add(tab.exportPackageName, {row, 1});
349 exportGrid.
add(
Label(
"Data path:"), {row, 0}).add(tab.exportDirectory, {row, 1});
352 exportGrid.
add(tab.exportButton, {row, 0}).
add(tab.exportLabel, {row, 1});
367 tab.statusLabel.setText(
"Editing " + std::to_string(numRooms.load()) +
" room(s).");
369 if (tab.reloadButton.wasClicked())
371 reloadRequested =
true;
374 if (tab.exportButton.wasClicked())
377 std::scoped_lock lock(exportPathMutex);
378 properties.exportPackageName = tab.exportPackageName.getValue();
379 properties.exportDirectory = tab.exportDirectory.getValue();
382 tab.exportLabel.setText(exportRooms() ?
"Exported the rooms."
383 :
"Export failed. See the log for details.");
int Label(int n[], int size, int *curLabel, MiscLib::Vector< std::pair< int, size_t > > *labels)
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
armarx::viz::Client arviz
static DateTime Now()
Current time on the virtual clock.
Default component property definition container.
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
Simple rate limiter for use in loops to maintain a certain frequency given a clock.
Interactive ArViz-based editor for room polygons.
void onInitComponent() override
void onDisconnectComponent() override
void RemoteGui_update() override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onConnectComponent() override
static std::string GetDefaultName()
Get the component's default name.
void onExitComponent() override
void createRemoteGuiTab()
std::string getDefaultName() const override
CommitResult commit(StagedCommit const &commit)
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
void reloadFromMemory()
Re-reads the rooms from the navigation memory.
bool exportToJson()
Dumps the rooms of the navigation memory to disk (rooms.json), using the package and directory config...
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
void RemoteGui_startRunningTask()
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
GridLayout & add(Widget const &child, Pos pos, Span span=Span{1, 1})
void setLabel(std::string const &text)
A room together with the provider segment (i.e. the navigation graph) it belongs to.
float edgeHandleSize
Edge length of the (cubic) edge handles [mm].
float vertexHandleRadius
Radius of the (spherical) vertex handles [mm].
std::string layerPrefix
Prefix of the ArViz layers created by the editor.
A staged commit prepares multiple layers to be committed.
void reset()
Reset all staged layers and interaction requests.