4 #include <QApplication>
10 #include <QTreeWidget>
12 #include <SimoxUtility/color/cmaps.h>
13 #include <SimoxUtility/math/SoftMinMax.h>
16 #include <RobotAPI/libraries/armem/aron/MemoryID.aron.generated.h>
35 QLayout* layout =
new QVBoxLayout();
36 this->setLayout(layout);
38 layout->setContentsMargins(margin, margin, margin, margin);
48 tree->setColumnCount(columns.size());
49 tree->setHeaderLabels(columns);
57 tree->setContextMenuPolicy(Qt::CustomContextMenu);
59 &QTreeWidget::customContextMenuRequested,
86 child->addWidget(dataView);
108 QTreeWidgetItem* item =
new QTreeWidgetItem({
"(No data.)"});
141 std::optional<aron::Path>
144 QStringList qpath = item->data(
int(
Columns::KEY), Qt::UserRole).toStringList();
156 std::optional<MemoryID>
169 element =
data->navigateAbsolute(elementPath);
177 catch (
const armarx::LocalException& e)
183 std::stringstream couldNotParseMsg;
184 couldNotParseMsg <<
"Element " << elementPath.
toString()
185 <<
" could not be parsed as MemoryID.";
187 auto dictElement = std::dynamic_pointer_cast<aron::data::Dict>(element);
190 showErrorMessage(couldNotParseMsg.str() +
" (Failed to cast to DictNavigator.)");
197 dto.fromAron(dictElement);
211 DataView::makeActionResolveMemoryID(
const MemoryID&
id)
213 auto* action =
new QAction(
"Resolve memory ID");
215 if (not(
id.hasEntityName() and
id.isWellDefined()))
217 action->setDisabled(
true);
218 action->setText(action->text() +
" (incomplete Memory ID)");
234 QAction* action =
new QAction(
"Copy memory ID to clipboard");
240 const QString idStr = QString::fromStdString(
id.
str());
243 QClipboard* clipboard = QApplication::clipboard();
244 clipboard->setText(idStr);
245 QApplication::processEvents();
251 std::vector<QAction*>
252 DataView::makeActionsCopyDataToClipboard()
262 std::vector<QAction*>
263 DataView::makeActionsCopyDataToClipboard(
const aron::Path& path)
282 catch (
const aron::error::AronException& e)
287 return makeCopyActions(element, elementType);
289 catch (
const aron::error::AronException& e)
291 ARMARX_WARNING <<
"Could not convert Aron data to JSON: " << e.getReason();
296 std::vector<QAction*>
300 auto* easyJsonAction =
new QAction(
"Copy data to clipboard as easy JSON");
301 connect(easyJsonAction,
303 [
this, element, elementType]()
307 TreeTypedJSONConverter conv;
309 QClipboard* clipboard = QApplication::clipboard();
310 clipboard->setText(QString::fromStdString(conv.getJSON().dump(2)));
311 QApplication::processEvents();
313 catch (
const aron::error::AronException& e)
315 ARMARX_WARNING <<
"Could not convert Aron data to JSON: " << e.getReason();
319 auto* aronJsonAction =
new QAction(
"Copy data to clipboard as aron JSON");
320 connect(aronJsonAction,
326 nlohmann::json json =
329 QClipboard* clipboard = QApplication::clipboard();
330 clipboard->setText(QString::fromStdString(json.dump(2)));
331 QApplication::processEvents();
333 catch (
const aron::error::AronException& e)
335 ARMARX_WARNING <<
"Could not convert Aron data to JSON: " << e.getReason();
339 return {easyJsonAction, aronJsonAction};
345 QMenu* menu =
new QMenu(
this);
347 const QTreeWidgetItem* item =
tree->itemAt(pos);
355 auto actions = makeActionsCopyDataToClipboard();
356 for (
const auto& action : actions)
360 menu->addAction(action);
373 QAction* viewAction =
new QAction(
"Show image");
374 menu->addAction(viewAction);
386 const std::vector<int> shape = imageData->getShape();
387 if (std::find(shape.begin(), shape.end(), 0) != shape.end())
389 viewAction->setText(viewAction->text() +
" (image is empty)");
390 viewAction->setEnabled(
false);
397 catch (
const armarx::LocalException&)
408 const std::string typeName = item->text(
int(
Columns::TYPE)).toStdString();
417 menu->addAction(action);
419 if (QAction* action = makeActionResolveMemoryID(
id.
value()))
421 menu->addAction(action);
427 const std::optional<aron::Path> elementPath =
getElementPath(item);
430 auto actions = makeActionsCopyDataToClipboard(elementPath.value());
431 for (
const auto& action : actions)
435 menu->addAction(action);
447 if (menu->actions().isEmpty())
491 const std::vector<int> shape = aron.
getShape();
493 ARMARX_CHECK_EQUAL(shape.at(2), 4) <<
"Expected Depth32 image to have 4 bytes per pixel.";
495 const int rows = shape.at(0);
496 const int cols = shape.at(1);
500 QImage image(cols, rows, QImage::Format::Format_RGB32);
501 const float*
data =
reinterpret_cast<float*
>(aron.
getData());
503 auto updateLimits = [](
float value,
Limits& limits)
516 const float* sourceRow =
data;
517 for (
int row = 0; row < rows; ++row)
519 for (
int col = 0; col < cols; ++col)
521 float value = sourceRow[col];
522 updateLimits(
value, limits);
540 cmap.set_vlimits(softMin.getSoftMin(), softMax.getSoftMax());
545 const float* sourceRow =
data;
547 const int bytesPerLine = image.bytesPerLine();
548 uchar* targetRow = image.bits();
550 for (
int row = 0; row < rows; ++row)
552 for (
int col = 0; col < cols; ++col)
554 float value = sourceRow[col];
556 targetRow[col * 4 + 0] = color.b;
557 targetRow[col * 4 + 1] = color.g;
558 targetRow[col * 4 + 2] = color.r;
559 targetRow[col * 4 + 3] = color.a;
561 updateLimits(
value, limits);
564 targetRow += bytesPerLine;
603 catch (
const armarx::LocalException&)
610 NDArray::PointerType imageData = NDArray::DynamicCast(element);
614 simox::meta::get_type_name(element));
618 const std::vector<int> shape = imageData->getShape();
619 if (shape.size() != 3)
622 NDArray::DimensionsToString(shape));
625 const int rows = shape.at(0);
626 const int cols = shape.at(1);
628 using aron::type::image::PixelType;
629 std::optional<PixelType> pixelType;
636 pixelType = (imageData->getType() ==
"5" ? PixelType::DEPTH32 : PixelType::RGB24);
642 bool clearLimitsHistory =
true;
643 std::optional<QImage> image;
646 switch (pixelType.value())
648 case PixelType::RGB24:
650 <<
"Expected Rgb24 image to have 3 bytes per pixel.";
651 image = QImage(imageData->getData(), cols, rows, QImage::Format::Format_RGB888);
654 case PixelType::DEPTH32:
656 clearLimitsHistory =
false;
666 format = QImage::Format::Format_Grayscale8;
670 format = QImage::Format::Format_RGB888;
674 showErrorMessage(
"Expected 1 or 3 elements in last dimension, but got shape: " +
675 NDArray::DimensionsToString(shape));
678 image = QImage(imageData->getData(), cols, rows, format);
683 std::stringstream title;
686 imageView->setTitle(QString::fromStdString(title.str()));
689 if (clearLimitsHistory)
696 cmap(
simox::color::cmaps::plasma().reversed()), limitsHistoryMaxSize(32)
698 setLayout(
new QHBoxLayout());
700 layout()->setContentsMargins(margin, margin, margin, margin);
703 QFont font = this->font();
704 font.setPointSizeF(font.pointSize() * 0.75);
709 layout()->addWidget(
view);