SimoxObjectWrapper.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package MemoryX::Helpers
17* @author ALexey Kozlov ( kozlov at kit dot edu)
18* @date 2012
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "SimoxObjectWrapper.h"
24
25// ArmarXCore
29
30// MemoryX
31#include <Inventor/nodes/SoMaterial.h>
34
35// Simox-VirtualRobot
36#include <SimoxUtility/algorithm/string/string_tools.h>
37#include <VirtualRobot/CollisionDetection/CollisionModel.h>
38#include <VirtualRobot/Visualization/CoinVisualization/CoinVisualizationNode.h>
39#include <VirtualRobot/XML/ObjectIO.h>
40
41// Coin3D headers
42#include <Inventor/VRMLnodes/SoVRMLImageTexture.h>
43#include <Inventor/actions/SoSearchAction.h>
44#include <Inventor/nodes/SoFile.h>
45#include <Inventor/nodes/SoGroup.h>
46#include <Inventor/nodes/SoImage.h>
47#include <Inventor/nodes/SoNode.h>
48#include <Inventor/nodes/SoSeparator.h>
49#include <Inventor/nodes/SoTexture2.h>
50#include <Inventor/nodes/SoTexture3.h>
51
52// Eigen
53#include <cfloat>
54#include <filesystem>
55
56#include <Eigen/Eigenvalues>
57
59
61{
62 namespace fs = std::filesystem;
63
64 const std::string ATTR_TEXTURE_FILES = "texFiles";
65 const std::string ATTR_IV_FILE = "IvFile";
66 const std::string ATTR_IV_COLLISION_FILE = "IvFileCollision";
67 const std::string ATTR_MANIPULATION_FILE = "ManipulationFile";
68 const std::string ATTR_UNCERTAINTY_COLOR_MAP = "UncertaintyColorMap";
69 const std::string ATTR_UNCERTAINTY_TRANSPARENCY = "UncertaintyTransparency";
70 const std::string ATTR_PUTDOWN_ORIENTATION_RPY = "PutdownOrientationRPY";
71
72 const std::string MO_TEMP_FILE_NAME = "___tmpManipulationObject___.xml";
73
74 // default uncertainty visu params
75 const float ELLIPSE_RADIUS_IN_SIGMAS = 3.;
76 const float HEATMAP_MIN_VARIANCE = 1.; // mm
77 const float HEATMAP_DENSITY_THRESHOLD = expf(-15.);
78 const int HEATMAP_GRID_SIZE = 100;
79
81 VirtualRobot::RobotIO::RobotDescription loadMode) :
82 AbstractFileEntityWrapper(gfm), uncertaintyVisuType(eEllipse)
83 {
84 coinVisFactory.reset(new VirtualRobot::CoinVisualizationFactory());
85
86 cachePath = fileManager->getFileCachePath();
87 moTempFile = (cachePath / MO_TEMP_FILE_NAME).string();
88
89 ellipseRadiusInSigmas = ELLIPSE_RADIUS_IN_SIGMAS;
90 heatmapMinVariance = HEATMAP_MIN_VARIANCE; // mm
91 heatmapDensityThreshold = HEATMAP_DENSITY_THRESHOLD;
92 heatmapGridSize = HEATMAP_GRID_SIZE;
93 if (loadMode != VirtualRobot::RobotIO::eFull &&
94 loadMode != VirtualRobot::RobotIO::eCollisionModel)
95 {
96 throw armarx::LocalException("Loadmode must either be eFull oder eCollisionModel");
97 }
98 this->loadMode = loadMode;
99 }
100
104
105 Ice::ObjectPtr
107 {
108 return new SimoxObjectWrapper(*this);
109 }
110
111 VirtualRobot::VisualizationNodePtr
113 {
114 if (simoxObject)
115 {
116 return simoxObject->getVisualization();
117 }
118 else
119 {
120 cacheAttributeFiles(ATTR_TEXTURE_FILES, true);
121 const std::string ivFName = cacheAttributeFile(ATTR_IV_FILE, true);
122 return coinVisFactory->getVisualizationFromFile(ivFName);
123 }
124 }
125
126 VirtualRobot::CollisionModelPtr
128 {
129 if (simoxObject)
130 {
131 return simoxObject->getCollisionModel();
132 }
133 else
134 {
135 cacheAttributeFiles(ATTR_TEXTURE_FILES, true);
136 const std::string ivFName = cacheAttributeFile(ATTR_IV_COLLISION_FILE, true);
137 return VirtualRobot::CollisionModelPtr(new VirtualRobot::CollisionModel(
138 coinVisFactory->getVisualizationFromFile(ivFName)));
139 }
140 }
141
142 VirtualRobot::ManipulationObjectPtr
144 {
146 if (!simoxObject)
147 {
149 loadSimoxObject();
150 }
151
152 return simoxObject;
153 }
154
155 std::string
157 {
158 cacheAttributeFiles(ATTR_TEXTURE_FILES, true);
159 const std::string ivFName = cacheAttributeFile(ATTR_IV_FILE, true);
160 const std::string ivFNameCollision = cacheAttributeFile(ATTR_IV_COLLISION_FILE, true);
161
162 const std::string moFName = cacheAttributeFile(ATTR_MANIPULATION_FILE, true);
163
164 return moFName;
165 }
166
167 std::string
168 SimoxObjectWrapper::setAndStoreManipulationObject(const VirtualRobot::ManipulationObjectPtr mo,
169 const std::string& filesDBName)
170 {
172 return storeManipulationObject(mo, filesDBName);
173 }
174
175 void
176 SimoxObjectWrapper::setManipulationObject(const VirtualRobot::ManipulationObjectPtr mo)
177 {
178 // clear(false);
179 simoxObject = mo;
180 }
181
182 void
184 const std::string& filesDBName)
185 {
186 if (!xmlFName.empty())
187 {
188 VirtualRobot::ManipulationObjectPtr mo = loadManipulationObjectFile(xmlFName);
189 const std::string fileId = setAndStoreManipulationObject(mo, filesDBName);
190 ARMARX_INFO_S << " Saved manipulation object file: " << xmlFName << " (Id: " << fileId
191 << ")";
192 }
193 else
194 {
195 ARMARX_WARNING_S << "xmlFName empty";
196 }
197 }
198
199 void
200 SimoxObjectWrapper::setManipulationFile(const std::string& xmlFName)
201 {
202 if (!xmlFName.empty())
203 {
204 ARMARX_INFO_S << " Setting manipulation object file: " << xmlFName << armarx::flush;
205 VirtualRobot::ManipulationObjectPtr mo = loadManipulationObjectFile(xmlFName);
207 }
208 }
209
210 void
211 SimoxObjectWrapper::setAndStoreModelIVFiles(const std::string& ivFNameVis,
212 const std::string& ivFNameCollision,
213 const std::string& filesDBName)
214 {
215 VirtualRobot::ManipulationObjectPtr mo = createManipulationObjectFromIvFiles(
216 getEntity()->getName(), ivFNameVis, ivFNameCollision);
217 const std::string ivFileId = setAndStoreManipulationObject(mo, filesDBName);
218 ARMARX_INFO_S << " Saved IV model file: " << ivFNameVis << " (Id: " << ivFileId << ")";
219 }
220
221 void
222 SimoxObjectWrapper::setModelIVFiles(const std::string& ivFNameVis,
223 const std::string& ivFNameCollision)
224 {
225 VirtualRobot::ManipulationObjectPtr mo = createManipulationObjectFromIvFiles(
226 getEntity()->getName(), ivFNameVis, ivFNameCollision);
228 }
229
230 void
232 {
233 this->uncertaintyVisuType = visuType;
234 }
235
236 void
238 float heatmapMinVariance,
239 float heatmapDensityThreshold,
240 int heatmapGridSize)
241 {
242 this->ellipseRadiusInSigmas = ellipseRadiusInSigmas;
243 this->heatmapMinVariance = heatmapMinVariance;
244 this->heatmapDensityThreshold = heatmapDensityThreshold;
245 this->heatmapGridSize = heatmapGridSize;
246 }
247
248 VirtualRobot::ColorMap
249 SimoxObjectWrapper::getUncertaintyColorMap()
250 {
251 if (getEntity()->hasAttribute(ATTR_UNCERTAINTY_COLOR_MAP))
252 {
253 const std::string mapName =
254 getEntity()->getAttribute(ATTR_UNCERTAINTY_COLOR_MAP)->getValue()->getString();
255
256 if (mapName == "eHot")
257 {
258 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHot);
259 }
260 else if (mapName == "eIntensity")
261 {
262 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eIntensity);
263 }
264 else if (mapName == "eRed")
265 {
266 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eRed);
267 }
268 else if (mapName == "eGreen")
269 {
270 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eGreen);
271 }
272 else if (mapName == "eBlue")
273 {
274 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eBlue);
275 }
276 else if (mapName == "eHotAlpha")
277 {
278 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHotAlpha);
279 }
280 else if (mapName == "eRedAlpha")
281 {
282 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eRedAlpha);
283 }
284 else if (mapName == "eGreenAlpha")
285 {
286 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eGreenAlpha);
287 }
288 else if (mapName == "eBlueAlpha")
289 {
290 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eBlueAlpha);
291 }
292 else
293 {
294 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHot);
295 }
296 }
297 else
298 {
299 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHot);
300 }
301 }
302
303 float
304 SimoxObjectWrapper::getUncertaintyEllipseTransparency()
305 {
306 if (getEntity()->hasAttribute(ATTR_UNCERTAINTY_TRANSPARENCY))
307 {
308 return getEntity()->getAttribute(ATTR_UNCERTAINTY_TRANSPARENCY)->getValue()->getFloat();
309 }
310 else
311 {
312 return 0.3f;
313 }
314 }
315
316 void
317 SimoxObjectWrapper::updateFromEntity(const EntityBasePtr& entity)
318 {
319 setEntity(entity);
320
322 }
323
324 void
326 {
327 // std::cout << "Refreshing visu pose... " << std::endl;
328
329 // only object instances are supported so far
330 ObjectInstancePtr obj = ObjectInstancePtr::dynamicCast(getEntity());
331
332 if (!obj)
333 {
334 return;
335 }
336
337 Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
338
339 // Position
340 armarx::FramedPositionPtr objPos = obj->getPosition();
341 if (objPos)
342 {
343 m.block(0, 3, 3, 1) = objPos->toEigen();
344 }
345
346 // Orientation
347 armarx::FramedOrientationPtr objOrient = obj->getOrientation();
348
349 if (objOrient)
350 {
351 m.block(0, 0, 3, 3) = objOrient->toEigen();
352 }
353
354 VirtualRobot::ManipulationObjectPtr mo = getManipulationObject();
355
356 if (!mo)
357 {
358 //ARMARX_WARNING_S << "Manipulation object is null";
359 }
360 else
361 {
362 mo->setGlobalPose(m);
363 }
364
365
366 // Position uncertainty
367 EntityAttributeBasePtr posAttr = obj->getPositionAttribute();
368 ProbabilityMeasureBasePtr posDist = posAttr->getUncertainty();
369
370 if (posDist)
371 {
372 static const std::string UNCERTAINTY_VISU_NAME = "positionUncertainty";
373 VirtualRobot::VisualizationNodePtr moVis;
374
375 if (mo)
376 {
377 moVis = mo->getVisualization();
378
379 if (moVis)
380 {
381 moVis->detachVisualization(UNCERTAINTY_VISU_NAME);
382 }
383 else
384 {
385 //ARMARX_WARNING_S << "Manipulation object's visu is null";
386 }
387 }
388
389
390 GaussianMixtureDistributionBasePtr posGM =
392
393 if (posGM)
394 {
395
396 VirtualRobot::VisualizationNodePtr posDistVisu;
397
398 posGM->normalize();
399
400 const VirtualRobot::ColorMap cmap = getUncertaintyColorMap();
401
402 switch (uncertaintyVisuType)
403 {
404 case eEllipse:
405 posDistVisu = getUncertaintyEllipsesVisu(
406 posGM, objPos->toEigen(), cmap, getUncertaintyEllipseTransparency());
407 break;
408
409 case eHeatMap:
410 posDistVisu = getUncertaintyHeatVisu(posGM, objPos->toEigen(), false, cmap);
411 break;
412
413 case eHeatSurface:
414 posDistVisu = getUncertaintyHeatVisu(posGM, objPos->toEigen(), true, cmap);
415 break;
416
417 default:
418 ARMARX_ERROR_S << "Uncertainty visualization type not supported!"
419 << armarx::flush;
420 }
421
422 if (posDistVisu)
423 {
424 // Object orientation shouldn't affect uncertainty, but it does,
425 // since technically attached visu's are child nodes of main object.
426 // Thus apply inverse transformation to compensate for this
427 Eigen::Matrix3f objOrientInv = objOrient->toEigen().inverse();
428 Eigen::Matrix4f dm = Eigen::Matrix4f::Identity();
429 dm.block(0, 0, 3, 3) = objOrientInv;
430 posDistVisu->setGlobalPose(dm);
431
432 if (moVis)
433 {
434 moVis->attachVisualization(UNCERTAINTY_VISU_NAME, posDistVisu);
435 }
436 else
437 {
438 //ARMARX_WARNING_S << "Manipulation object's visu is null";
439 }
440 }
441 }
442 }
443 }
444
445 VirtualRobot::VisualizationNodePtr
446 SimoxObjectWrapper::getUncertaintyEllipsesVisu(GaussianMixtureDistributionBasePtr posGM,
447 const Eigen::Vector3f& objPos,
448 const VirtualRobot::ColorMap& cmap,
449 float transparency)
450 {
451 static float COV_SCALE_FACTOR = 1.f; // make cov more realistic
452
453 std::vector<VirtualRobot::VisualizationNodePtr> compVisuList;
454
455 for (int i = 0; i < posGM->size(); ++i)
456 {
457 GaussianMixtureComponent comp = posGM->getComponent(i);
458 NormalDistributionPtr gaussian = NormalDistributionPtr::dynamicCast(comp.gaussian);
459
460 Eigen::Matrix3f cov = gaussian->toEigenCovariance() * COV_SCALE_FACTOR;
461
462 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> es(cov);
463 Eigen::Vector3f eval = es.eigenvalues();
464 Eigen::Matrix3f evec = es.eigenvectors();
465 // std::cout << "evalues: " << eval << ", evectors: " << evec << std::endl << std::endl;
466
467 VirtualRobot::VisualizationFactory::Color color = cmap.getColor(comp.weight);
468
469 SoMaterial* matBody = new SoMaterial;
470 matBody->diffuseColor.setValue(color.r, color.b, color.g);
471 matBody->ambientColor.setValue(color.r, color.b, color.g);
472 matBody->transparency.setValue(transparency);
473
474 VirtualRobot::VisualizationNodePtr compVisu(
475 new VirtualRobot::CoinVisualizationNode(coinVisFactory->CreateEllipse(
476 ellipseRadiusInSigmas * sqrt(eval(0)) / 1000., // mm -> m
477 ellipseRadiusInSigmas * sqrt(eval(1)) / 1000.,
478 ellipseRadiusInSigmas * sqrt(eval(2)) / 1000.,
479 matBody, // default material
480 false // hide axis
481 )));
482
483 Eigen::Matrix4f dm = Eigen::Matrix4f::Identity();
484 dm.block(0, 0, 3, 3) = evec;
485 dm.block(0, 3, 3, 1) = gaussian->toEigenMean() - objPos;
486 compVisu->setGlobalPose(dm);
487
488 compVisuList.push_back(compVisu);
489 }
490
491 return coinVisFactory->createUnitedVisualization(compVisuList);
492 }
493
494 VirtualRobot::VisualizationNodePtr
495 SimoxObjectWrapper::getUncertaintyHeatVisu(GaussianMixtureDistributionBasePtr posGM,
496 const Eigen::Vector3f& objPos,
497 bool heatSurface,
498 const VirtualRobot::ColorMap& cmap)
499 {
500 const float SCALE_FACTOR = sqrt(
501 2 * M_PI *
502 heatmapMinVariance); // scale axes in a way that the height of distribution with sigmaX=sigmaY=1mm is 1.0
503 const float COV_SCALE_FACTOR = 1.f; // make cov more realistic
504 const float LOG_PROB_CUTOFF = -logf(heatmapDensityThreshold);
505 const float MAX_CLUSTER_VARIANCE = 100; // AABB side size in mm
506
507 std::vector<VirtualRobot::VisualizationNodePtr> clusterVisuList;
508
509 WestGMMReducer reducer;
510 GaussianMixtureDistributionBasePtr reducedGMM =
511 reducer.reduceByMaxAABB(posGM, MAX_CLUSTER_VARIANCE);
512
513 // iterate over clusters
514 for (int k = 0; k < reducedGMM->size(); ++k)
515 {
516
517 // calculate common mean
518 /* float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;
519 for (int i = 0; i < posGM->size(); ++i)
520 {
521 GaussianMixtureComponent comp = posGM->getComponent(i);
522 NormalDistributionPtr gaussian = NormalDistributionPtr::dynamicCast(comp.gaussian);
523
524 Eigen::Vector3f mean = gaussian->toEigenMean();
525 float varX = 6. * sqrt(gaussian->getCovariance(0, 0) * COV_SCALE_FACTOR);
526 float varY = 6. * sqrt(gaussian->getCovariance(1, 1) * COV_SCALE_FACTOR);
527 minX = std::min(minX, mean(0) - varX);
528 minY = std::min(minY, mean(1) - varY);
529 maxX = std::max(maxX, mean(0) + varX);
530 maxY = std::max(maxY, mean(1) + varY);
531 }
532 float sx = maxX - minX;
533 float sy = maxY - minY;*/
534
535 NormalDistributionPtr compGaussian =
536 NormalDistributionPtr::dynamicCast(reducedGMM->getComponent(k).gaussian);
537 Eigen::Vector3f clusterCenter = compGaussian->toEigenMean();
538 // clusterCenter << minX + sx / 2., minY + sy / 2., objPos(2);
539 std::cout << "Cluster mean: " << clusterCenter << std::endl;
540 // std::cout << "MinX: " << minX << ", MaxX: " << maxX << ", minY: " << minY << ", MaxY: " << maxY << std::endl;
541
542 clusterCenter /= SCALE_FACTOR; // scale mean
543
544 float sx = 6. * sqrtf(compGaussian->getCovariance(0, 0));
545 float sy = 6. * sqrtf(compGaussian->getCovariance(1, 1));
546 int GRID_SIZE_X = (int)round(sqrt(sx / sy) * (float)heatmapGridSize);
547 int GRID_SIZE_Y = (int)round(sqrt(sy / sx) * (float)heatmapGridSize);
548 float CELL_SIZE_X = sx / (float)GRID_SIZE_X / SCALE_FACTOR; //
549 float CELL_SIZE_Y = sy / (float)GRID_SIZE_Y / SCALE_FACTOR; //
550
551 Eigen::MatrixXf grid = Eigen::MatrixXf::Zero(GRID_SIZE_X, GRID_SIZE_Y);
552
553 for (int i = 0; i < posGM->size(); ++i)
554 {
555 GaussianMixtureComponent comp = posGM->getComponent(i);
556 NormalDistributionPtr gaussian = NormalDistributionPtr::dynamicCast(comp.gaussian);
557
558 FloatVector meanVec = comp.gaussian->getMean();
559 Eigen::Vector2f mean;
560 mean << meanVec[0], meanVec[1];
561 mean /= SCALE_FACTOR; // scale mean
562
563 Eigen::Matrix3f cov3D = gaussian->toEigenCovariance();
564 Eigen::Matrix2f cov =
565 cov3D.block(0, 0, 2, 2) * COV_SCALE_FACTOR / (SCALE_FACTOR * SCALE_FACTOR);
566 Eigen::Matrix2f covInv = cov.inverse();
567 float covDet = cov.determinant();
568 float covDetSqrtInv = powf(covDet, -0.5f);
569
570 Eigen::Vector2f pos;
571 pos(0) = clusterCenter(0) - (float)(GRID_SIZE_X * CELL_SIZE_X) / 2.;
572
573 for (int xc = 0; xc < GRID_SIZE_X; ++xc)
574 {
575 pos(1) = clusterCenter(1) - (float)(GRID_SIZE_Y * CELL_SIZE_Y) / 2.;
576
577 for (int yc = 0; yc < GRID_SIZE_Y; ++yc)
578 {
579 float pdfValue =
580 (LOG_PROB_CUTOFF +
581 log(evaluate2DGaussian(pos, mean, covInv, covDetSqrtInv))) /
582 LOG_PROB_CUTOFF * comp.weight;
583
584 // normalize value to [0, 1]
585 if (pdfValue < 0.)
586 {
587 // probablity density too low -> set it to 0, since we can ignore such small differences for visu
588 // std::cout << "Cutting off value: " << pdfValue << ", new value: 0.0" << std::endl;
589 pdfValue = 0.f;
590 }
591 else if (pdfValue > 1.)
592 {
593 // probablity density too high (i.e. stddev < 1 mm) -> cut off at 1
594 pdfValue = 1.f;
595 }
596
597 grid(xc, yc) += pdfValue;
598
599 // std::cout << "Pos: " << pos << ", mean: " << mean << ", value: " << grid(xc, yc) << std::endl;
600 pos(1) += CELL_SIZE_Y; // step y
601 }
602
603 pos(0) += CELL_SIZE_X; // step x
604 }
605 }
606
607 VirtualRobot::VisualizationNodePtr clusterVisu;
608
609 if (heatSurface)
610 {
611 clusterVisu.reset(
612 new VirtualRobot::CoinVisualizationNode(coinVisFactory->Create2DHeightMap(
613 grid, // prob map
614 CELL_SIZE_X * SCALE_FACTOR, // x cell size in mm
615 CELL_SIZE_Y * SCALE_FACTOR, // y cell size in mm
616 100., // height in mm
617 cmap, // color map
618 false, // draw zero cells
619 false // draw lines between cells
620 )));
621 }
622 else
623 {
624 clusterVisu.reset(new VirtualRobot::CoinVisualizationNode(
625 coinVisFactory->Create2DMap(grid, // prob map
626 CELL_SIZE_X * SCALE_FACTOR, // x cell size in mm
627 CELL_SIZE_Y * SCALE_FACTOR, // y cell size in mm
628 cmap, // color map
629 false, // draw zero cells
630 false // draw lines between cells
631 )));
632 }
633
634 Eigen::Matrix4f dm = Eigen::Matrix4f::Identity();
635 dm.block(0, 3, 3, 1) = clusterCenter * SCALE_FACTOR - objPos;
636 clusterVisu->setGlobalPose(dm);
637
638 clusterVisuList.push_back(clusterVisu);
639 } // end clusters loop
640
641 return coinVisFactory->createUnitedVisualization(clusterVisuList);
642 ;
643 }
644
645 float
646 SimoxObjectWrapper::evaluate2DGaussian(const Eigen::Vector2f& point,
647 const Eigen::Vector2f& mean,
648 const Eigen::Matrix2f& covInv,
649 float covDetSqrtInv)
650 {
651 Eigen::Matrix<float, 1, 1> inner =
652 -0.5 * (point - mean).transpose() * covInv * (point - mean);
653 float e = exp(inner(0, 0));
654
655 static const float c = 1. / 2 * M_PI;
656
657 return c * covDetSqrtInv * e;
658 }
659
660 float
661 SimoxObjectWrapper::evaluate3DGaussian(const Eigen::Vector3f& point,
662 const Eigen::Vector3f& mean,
663 const Eigen::Matrix3f& covInv,
664 float covDet)
665 {
666 Eigen::Matrix<float, 1, 1> inner =
667 -0.5 * (point - mean).transpose() * covInv * (point - mean);
668 float e = exp(inner(0, 0));
669
670 return pow(2 * M_PI, -3.0f / 2.0f) * pow(covDet, -0.5) * e;
671 }
672
673 void
674 SimoxObjectWrapper::clear(bool removeFiles /* = true */)
675 {
676 if (getEntity() && removeFiles)
677 {
678 fileManager->removeAttrFiles(getEntity()->getAttribute(ATTR_MANIPULATION_FILE));
679 fileManager->removeAttrFiles(getEntity()->getAttribute(ATTR_IV_COLLISION_FILE));
680 fileManager->removeAttrFiles(getEntity()->getAttribute(ATTR_IV_FILE));
681 fileManager->removeAttrFiles(getEntity()->getAttribute(ATTR_TEXTURE_FILES));
682 }
683
684 simoxObject.reset();
685 }
686
687 /*
688 * private methods
689 */
690 void
691 SimoxObjectWrapper::loadSimoxObject() const
692 {
694 if (loadMode != VirtualRobot::RobotIO::eStructure)
695 {
697 cacheAttributeFiles(ATTR_TEXTURE_FILES, true);
698 }
699
700 const std::string ivFName = (loadMode == VirtualRobot::RobotIO::eFull ||
701 (loadMode == VirtualRobot::RobotIO::eCollisionModel &&
702 !getEntity()->hasAttribute(ATTR_IV_COLLISION_FILE)))
703 ? cacheAttributeFile(ATTR_IV_FILE, true)
704 : "";
706 const std::string ivFNameCollision = (loadMode == VirtualRobot::RobotIO::eFull ||
707 loadMode == VirtualRobot::RobotIO::eCollisionModel)
708 ? cacheAttributeFile(ATTR_IV_COLLISION_FILE, true)
709 : "";
711 const std::string moFName = cacheAttributeFile(ATTR_MANIPULATION_FILE, true);
712
714 if (moFName.empty() && ivFName.empty() && ivFNameCollision.empty())
715 {
716 ARMARX_WARNING_S << "SimoxWrapper was not able to find ManipulationObjectFile or an "
717 "ivFile an ivCollision of ObjectInstance "
718 << getEntity()->getName() << std::endl;
719 }
720 else if (ivFName.empty() && loadMode == VirtualRobot::RobotIO::eFull)
721 {
723 << "SimoxWrapper was not able to find IvFile Attribute of ObjectInstance "
724 << getEntity()->getName() << std::endl;
725 }
726 else if (ivFNameCollision.empty() && loadMode == VirtualRobot::RobotIO::eCollisionModel)
727 {
729 << "SimoxWrapper was not able to find ivFNameCollision Attribute of ObjectInstance "
730 << getEntity()->getName() << std::endl;
731 }
732
733 if (!moFName.empty())
734 {
736 ARMARX_DEBUG_S << "Loading simox object " << moFName;
737 simoxObject = loadManipulationObjectFile(moFName);
738 }
739 else
740 {
742 simoxObject = createManipulationObjectFromIvFiles(
743 getEntity()->getName(), ivFName, ivFNameCollision);
744 }
745 }
746
747 std::string
748 SimoxObjectWrapper::cacheAttributeFile(const std::string& attrName,
749 bool preserveOriginalFName /* = false */) const
750 {
752 std::string result = "";
753
754 if (getEntity()->hasAttribute(attrName))
755 {
757 ARMARX_DEBUG_S << "Caching file(s) from attribute \"" << attrName << "\"";
758
759 fileManager->ensureFileInCache(
760 getEntity()->getAttribute(attrName), result, preserveOriginalFName);
761 }
762 else
763 {
764 ARMARX_DEBUG_S << "Attribute \"" << attrName << "\" not available";
765 }
766
767 return result;
768 }
769
770 bool
771 SimoxObjectWrapper::cacheAttributeFiles(const std::string& attrName,
772 bool preserveOriginalFName /* = false */) const
773 {
774 if (getEntity()->hasAttribute(attrName))
775 {
776 // ARMARX_INFO_S << "Caching file(s) from attribute \"" << attrName << "\"" << armarx::flush;
777
778 return fileManager->ensureFilesInCache(getEntity()->getAttribute(attrName),
779 preserveOriginalFName);
780 }
781 else
782 {
783 return false;
784 }
785 }
786
787 VirtualRobot::ManipulationObjectPtr
788 SimoxObjectWrapper::loadManipulationObjectFile(const std::string& xmlFName) const
789 {
790 return VirtualRobot::ObjectIO::loadManipulationObject(xmlFName);
791 }
792
793 VirtualRobot::ManipulationObjectPtr
794 SimoxObjectWrapper::createManipulationObjectFromIvFiles(
795 const std::string& objName,
796 const std::string& ivFNameVis,
797 const std::string& ivFNameCollision) const
798 {
799 VirtualRobot::ManipulationObjectPtr mo(new VirtualRobot::ManipulationObject(objName));
800
801 mo->setFilename(objName + ".xml");
802
803 VirtualRobot::VisualizationNodePtr visFull =
804 (!ivFNameVis.empty()) ? coinVisFactory->getVisualizationFromFile(ivFNameVis)
805 : VirtualRobot::VisualizationNodePtr();
806
807 if (visFull)
808 {
809 mo->setVisualization(visFull);
810 }
811
812 VirtualRobot::VisualizationNodePtr visCollision =
813 ivFNameCollision.empty() ? VirtualRobot::VisualizationNodePtr()
814 : coinVisFactory->getVisualizationFromFile(ivFNameCollision);
815
816 if (visCollision)
817 {
818 VirtualRobot::CollisionModelPtr collisionModel(
819 new VirtualRobot::CollisionModel(visCollision));
820 mo->setCollisionModel(collisionModel);
821 }
822
823 return mo;
824 }
825
826 std::string
827 SimoxObjectWrapper::storeManipulationObject(const VirtualRobot::ManipulationObjectPtr mo,
828 const std::string& filesDBName)
829 {
830 if (!mo)
831 {
832 return "";
833 }
834
835 EntityAttributeBasePtr oldMOFileAttr = getEntity()->getAttribute(ATTR_MANIPULATION_FILE);
836
837
838 // store .iv files and their textures first
839 fs::path visuFName = mo->getVisualization()->getFilename();
840 fs::path collisionFName = mo->getCollisionModel()->getVisualization()->getFilename();
841 storeEntityIVFiles(visuFName.string(), collisionFName.string(), filesDBName);
842
843 // we don't want relative filepaths for IVs in MO XML file, since they would become invalid after caching on local system
844 // so create a new XML with IVs truncated to filenames only
845 const std::string onlyFilenameVisu = visuFName.filename().string();
846 mo->getVisualization()->setFilename(onlyFilenameVisu,
847 mo->getVisualization()->usedBoundingBoxVisu());
848
849 const std::string onlyFilenameCol = collisionFName.filename().string();
850 mo->getCollisionModel()->getVisualization()->setFilename(
851 onlyFilenameCol, mo->getCollisionModel()->getVisualization()->usedBoundingBoxVisu());
852
853 VirtualRobot::ObjectIO::saveManipulationObject(mo, moTempFile);
854
855 EntityAttributeBasePtr moAttr = new EntityAttribute(ATTR_MANIPULATION_FILE);
856
857
858 std::string fileId = fileManager->storeFileToAttr(
859 filesDBName, moTempFile, moAttr, fs::path(mo->getFilename()).filename().string());
860
861 cleanUpAttributeFiles(oldMOFileAttr, moAttr);
862 getEntity()->putAttribute(moAttr);
863
864 fs::remove(moTempFile);
865 return fileId;
866 }
867
868 void
869 SimoxObjectWrapper::storeEntityIVFiles(const std::string& visuFName,
870 const std::string& collisionFName,
871 const std::string& filesDBName,
872 bool processTextures)
873 {
874 NameList textures;
875 NameList::const_iterator itTex;
876
877 EntityAttributeBasePtr oldIVColFileAttr = getEntity()->getAttribute(ATTR_IV_COLLISION_FILE);
878 EntityAttributeBasePtr oldIVFileAttr = getEntity()->getAttribute(ATTR_IV_FILE);
879 EntityAttributeBasePtr oldTextureFileAttr = getEntity()->getAttribute(ATTR_TEXTURE_FILES);
880
881 EntityAttributeBasePtr visuAttr = new EntityAttribute(ATTR_IV_FILE);
882
883 std::string visu_filename = visuFName;
884 if (!visu_filename.empty())
885 {
886 // Make filename an absolute path if needed
887 if (std::filesystem::path(visu_filename).is_relative())
888 {
889 visu_filename = (cachePath / visu_filename).string();
890 }
891
892 ARMARX_INFO << " Saving visualization iv file: " << visu_filename;
893 fileManager->storeFileToAttr(filesDBName, visu_filename, visuAttr);
894 cleanUpAttributeFiles(oldIVFileAttr, visuAttr);
895 getEntity()->putAttribute(visuAttr);
896
897 if (processTextures)
898 {
899 SimoxObjectWrapper::FindIvTextures(visu_filename, textures);
900 }
901 }
902
903 std::string col_filename = collisionFName;
904 if (!col_filename.empty())
905 {
906 // Make filename an absolute path if needed
907 if (std::filesystem::path(col_filename).is_relative())
908 {
909 col_filename = (cachePath / col_filename).string();
910 }
911
912 ARMARX_INFO_S << " Saving collision iv file: " << col_filename << armarx::flush;
913 EntityAttributeBasePtr collisionAttr = new EntityAttribute(ATTR_IV_COLLISION_FILE);
914
915 // if the same .iv-file is used as both visu and collision model, we don't need to store it again,
916 // just copy a reference instead
917 if (col_filename == visu_filename)
918 {
919 collisionAttr->addValue(visuAttr->getValue());
920 }
921 else
922 {
923 fileManager->storeFileToAttr(filesDBName, col_filename, collisionAttr);
924
925 if (processTextures)
926 {
927 SimoxObjectWrapper::FindIvTextures(col_filename, textures);
928 }
929 }
930
931 cleanUpAttributeFiles(oldIVColFileAttr, collisionAttr);
932 getEntity()->putAttribute(collisionAttr);
933 }
934
935
936 if (!textures.empty())
937 {
938 EntityAttributeBasePtr texAttr = new EntityAttribute(ATTR_TEXTURE_FILES);
939
940 //fileManager->storeFilesToAttr(filesDBName,localBaseDir,textures,texAttr);
941 for (itTex = textures.begin(); itTex != textures.end(); ++itTex)
942 {
943 ARMARX_INFO_S << " Saving texture file: " << *itTex << armarx::flush;
944 fileManager->storeFileToAttr(filesDBName, *itTex, texAttr);
945 }
946
947 cleanUpAttributeFiles(oldTextureFileAttr, texAttr);
948 getEntity()->putAttribute(texAttr);
949 }
950 else if (
951 oldTextureFileAttr) // new object has no texture, remove old texture attributes and files
952 {
953 removeAttributeFiles(oldTextureFileAttr);
954 getEntity()->removeAttribute(oldTextureFileAttr->getName());
955 }
956 }
957
958 void
959 SimoxObjectWrapper::FindIvTextures(const std::string& ivFName, NameList& textures)
960 {
961 // TODO replace with CoinVisualizationFactory call ???
962 SoInput in;
963
964 if (!in.openFile(ivFName.c_str()))
965 {
966 ARMARX_WARNING_S << "Could not open iv file:" << ivFName << std::endl;
967 return;
968 }
969
970 SoNode* n = SoDB::readAll(&in);
971 n->ref();
972 SimoxObjectWrapper::GetAllFilenames(n, textures, ivFName);
973 n->unref();
974 }
975
976 Eigen::Vector3f
978 {
979 Eigen::Vector3f result = {0, 0, 0};
980
981 if (getEntity()->hasAttribute(ATTR_PUTDOWN_ORIENTATION_RPY))
982 {
983 EntityPtr p = EntityPtr::dynamicCast(getEntity());
984 EntityAttributeBasePtr attr = p->getAttribute(ATTR_PUTDOWN_ORIENTATION_RPY);
985
986 if (attr->size() > 0)
987 {
988 armarx::Vector3BasePtr vecBase =
989 armarx::VariantPtr::dynamicCast(attr->getValueAt(0))
990 ->getClass<armarx::Vector3Base>();
991 result(0) = vecBase->x;
992 result(1) = vecBase->y;
993 result(2) = vecBase->z;
994 }
995 }
996
997 return result;
998 }
999
1000 void
1002 {
1003 EntityAttributeBasePtr attr = new EntityAttribute(ATTR_PUTDOWN_ORIENTATION_RPY);
1004 armarx::Vector3 vec(rpy);
1005 attr->addValue(new armarx::Variant(vec));
1006 getEntity()->putAttribute(attr);
1007 }
1008
1009 void
1011 std::vector<std::string>& storeFilenames,
1012 const std::string& origFile)
1013 {
1014 if (!node)
1015 {
1016 return;
1017 }
1018
1019 if (node->getTypeId() == SoFile::getClassTypeId())
1020 {
1021 // get filename
1022 SoFile* fileNode = (SoFile*)node;
1023 SbString fileNodeName = fileNode->getFullName();
1024
1025 if (!fileNodeName)
1026 {
1027 ARMARX_INFO_S << "Empty file?!";
1028 SbString s2 = fileNode->name.getValue();
1029
1030 if (!s2)
1031 {
1032 ARMARX_INFO_S << "Empty relative name";
1033 }
1034 else
1035 {
1036 storeFilenames.push_back(s2.getString());
1037 }
1038 }
1039 else
1040 {
1041 storeFilenames.push_back(fileNodeName.getString());
1042 }
1043
1044 // process file data
1045 SoGroup* fileChildren = fileNode->copyChildren();
1047 fileChildren, storeFilenames, fileNodeName.getString());
1048 }
1049 else if (node->getTypeId().isDerivedFrom(SoGroup::getClassTypeId()))
1050 {
1051 SoGroup* groupNode = (SoGroup*)node;
1052
1053 // process group node
1054 for (int i = 0; i < groupNode->getNumChildren(); i++)
1055 {
1057 groupNode->getChild(i), storeFilenames, origFile);
1058 }
1059 }
1060 else if (node->getTypeId() == SoImage::getClassTypeId())
1061 {
1062 // get image filename
1063 SbString imageFilename = ((SoImage*)node)->filename.getValue();
1064 storeFilenames.push_back(SimoxObjectWrapper::GetAbsolutePath(imageFilename, origFile));
1065 }
1066 else if (node->getTypeId() == SoTexture2::getClassTypeId())
1067 {
1068 // get filename
1069 SbString texture2Filename = ((SoTexture2*)node)->filename.getValue();
1070 storeFilenames.push_back(
1071 SimoxObjectWrapper::GetAbsolutePath(texture2Filename, origFile));
1072 }
1073 else if (node->getTypeId() == SoTexture3::getClassTypeId())
1074 {
1075 ARMARX_WARNING_S << "Texture3 nyi..." << std::endl;
1076 }
1077 else //if (node->getTypeId() == SoVRMLImageTexture::getClassTypeId())
1078 {
1079 SoSearchAction sa;
1080 sa.setType(SoVRMLImageTexture::getClassTypeId());
1081 sa.setInterest(SoSearchAction::ALL);
1082 sa.setSearchingAll(TRUE);
1083 sa.apply(node);
1084
1085 SoPathList& pathList = sa.getPaths();
1086 if (pathList.getLength() <= 0)
1087 {
1088 return;
1089 }
1090 SoFullPath* p = (SoFullPath*)pathList[0];
1091 if (!p->getTail()->isOfType(SoVRMLImageTexture::getClassTypeId()))
1092 {
1093 return;
1094 }
1095 SoVRMLImageTexture* texture = (SoVRMLImageTexture*)p->getTail();
1096 if (texture->url.getNum() <= 0)
1097 {
1098 return;
1099 }
1100 for (int i = 0; i < texture->url.getNum(); ++i)
1101 {
1102 auto path = SimoxObjectWrapper::GetAbsolutePath(texture->url[i], origFile);
1103 if (!path.empty() && fs::exists(path))
1104 {
1105 storeFilenames.push_back(path);
1106 break;
1107 }
1108 if (i == texture->url.getNum() - 1)
1109 {
1110 Ice::StringSeq textures;
1111 for (int j = 0; j < texture->url.getNum(); ++j)
1112 {
1113 textures.push_back(texture->url[j].getString());
1114 }
1115 ARMARX_ERROR << "Could not make any of the texture paths absolute: "
1116 << simox::alg::join(textures, ", ");
1117 }
1118 }
1119
1120 // ARMARX_IMPORTANT_S << "VRML ImageTexture of node: " << node->getName().getString() << " : " << texture->url[0].getString() << VAROUT(origFile) << VAROUT(storeFilenames);
1121 }
1122 }
1123
1124 std::string
1125 SimoxObjectWrapper::GetAbsolutePath(SbString filename, const std::string& origFile)
1126 {
1127 if (!filename)
1128 {
1129 //ARMARX_INFO_S << "Empty relative name"; // skip
1130 return std::string();
1131 }
1132 else
1133 {
1134 fs::path filepath(armarx::ArmarXDataPath::cleanPath(filename.getString()));
1135 fs::path absOrigFileDirPath;
1136 std::string resultPathStr;
1137 if (!origFile.empty())
1138 {
1139 absOrigFileDirPath =
1140 fs::path(armarx::ArmarXDataPath::cleanPath(origFile)).parent_path();
1141 }
1142 if (filepath.is_absolute())
1143 {
1144 try
1145 {
1146 return armarx::ArmarXDataPath::relativeTo(absOrigFileDirPath.string(),
1147 filepath.string());
1148 }
1149 catch (...)
1150 {
1151 return std::string();
1152 }
1153 }
1154 else if (!filepath.has_parent_path())
1155 {
1156 return (absOrigFileDirPath / filepath).string();
1157 }
1159 absOrigFileDirPath.string(), filepath.string(), resultPathStr))
1160 {
1161 return resultPathStr;
1162 }
1163
1164 // completeFile = relativePath / fs::path(filename.getString());
1165 }
1166 return std::string();
1167 }
1168} // namespace memoryx::EntityWrappers
#define float
Definition 16_Level.h:22
#define M_PI
Definition MathTools.h:17
const std::string ATTR_IV_FILE
constexpr T c
static std::string cleanPath(const std::string &filepathStr)
static bool mergePaths(std::string path, std::string subPath, std::string &result)
static std::string relativeTo(const std::string &from, const std::string &to)
Transform an absolute filepath into a relative path of the other absolute filepath.
The Variant class is described here: Variants.
Definition Variant.h:224
The Vector3 class.
Definition Pose.h:113
Attribute of MemoryX entities.
EntityBasePtr getEntity() const
Get the stored name of the stored entity.
std::string getName() const
Get the name of the stored entity.
void setEntity(const EntityBasePtr &entity)
Replace the stored entity with a new one.
void cleanUpAttributeFiles(EntityAttributeBasePtr oldAttr, EntityAttributeBasePtr newAttr)
cleanUpAttributeFiles compares the files attached to the two given attributes and removes the files o...
void removeAttributeFiles(const memoryx::EntityAttributeBasePtr &attr)
removes all files of an attribute from the gridfs
static void GetAllFilenames(SoNode *node, std::vector< std::string > &storeFilenames, const std::string &origFile="")
GetAllFilenames walks node and appends absolute paths of all found SoFile, SoImage,...
std::string setAndStoreManipulationObject(const VirtualRobot::ManipulationObjectPtr mo, const std::string &filesDBName)
Store Simox ManipulationObject in the wrapped entity.
void setPutdownOrientationRPY(Eigen::Vector3f &rpy)
Sets the orientation of the object that it should have when it is being put down e....
SimoxObjectWrapper(const GridFileManagerPtr &gfm, VirtualRobot::RobotIO::RobotDescription loadMode=VirtualRobot::RobotIO::eFull)
Constructs new SimoxObjectWrapper.
void updateFromEntity(const EntityBasePtr &entity)
Update the Simox object using attribute values (position, orientation etc) from the entity,...
void setAndStoreModelIVFiles(const std::string &ivFNameVis, const std::string &ivFNameCollision, const std::string &filesDBName)
Create Simox ManipulationObject from separate .iv models and store it in the wrapped entity.
void setManipulationFile(const std::string &xmlFName)
Create Simox ManipulationObject from an XML file, but do not store it in the wrapped entity.
void setUncertaintyVisuParams(float ellipseRadiusInSigmas, float heatmapMinVariance, float heatmapDensityThreshold, int heatmapGridSize)
Set parameters for uncertainty visualization.
void setUncertaintyVisuType(UncertaintyVisuType visuType)
Set visualization type for position uncertainty.
VirtualRobot::VisualizationNodePtr getVisualization() const
Retrieve visualization model.
VirtualRobot::ManipulationObjectPtr getManipulationObject() const
Retrieve the complete Simox ManipulationObject.
VirtualRobot::CollisionModelPtr getCollisionModel() const
Retrieve collision model.
static void FindIvTextures(const std::string &ivFName, NameList &textures)
FindIvTextures scans the given ivFName for texture files and returns them in the textures string list...
void setModelIVFiles(const std::string &ivFNameVis, const std::string &ivFNameCollision)
Create Simox ManipulationObject from separate .iv models, but do not store it in the wrapped entity.
std::string getManipulationObjectFileName() const
Retrieve the Simox MainpulationObjects file name in local cache.
Eigen::Vector3f getPutdownOrientationRPY()
Returns the orientation of the object that it should have when it is being put down e....
void clear(bool removeFiles=true)
Clears the Simox ManipulationObject and optionally removes the corresponding files from GridFS.
void refreshVisuPose()
Update object visualization using the current values of pose and position uncertainty from the wrappe...
void setAndStoreManipulationFile(const std::string &xmlFName, const std::string &filesDBName)
Create Simox ManipulationObject from an XML file and store it in the wrapped entity.
static std::string GetAbsolutePath(SbString filename, const std::string &origFile)
GetAbsolutePath prepend filename with origFile and append it to storeFilenames (does nothing if filen...
void setManipulationObject(const VirtualRobot::ManipulationObjectPtr mo)
Set Simox ManipulationObject in the wrapped entity.
static GaussianMixtureDistributionPtr FromProbabilityMeasure(const ProbabilityMeasureBasePtr &probMeasure)
Convert or approximate given ProbabilityMeasure to a gaussian mixture.
#define ARMARX_DEBUG_S
The logging level for output that is only interesting while debugging.
Definition Logging.h:205
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR_S
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:216
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
std::optional< float > mean(const boost::circular_buffer< NameValueMap > &buffer, const std::string &key)
std::vector< std::vector< T > > transpose(const std::vector< std::vector< T > > &src, Thrower thrower)
IceInternal::Handle< FramedPosition > FramedPositionPtr
Definition FramedPose.h:149
IceInternal::Handle< FramedOrientation > FramedOrientationPtr
Definition FramedPose.h:207
const LogSender::manipulator flush
Definition LogSender.h:251
const std::string ATTR_TEXTURE_FILES
const std::string ATTR_MANIPULATION_FILE
const std::string ATTR_PUTDOWN_ORIENTATION_RPY
const std::string ATTR_UNCERTAINTY_COLOR_MAP
const std::string MO_TEMP_FILE_NAME
const std::string ATTR_IV_COLLISION_FILE
const std::string ATTR_UNCERTAINTY_TRANSPARENCY
IceInternal::Handle< NormalDistribution > NormalDistributionPtr
IceInternal::Handle< ObjectInstance > ObjectInstancePtr
IceInternal::Handle< Entity > EntityPtr
Typedef of EntityPtr as IceInternal::Handle<Entity> for convenience.
Definition Entity.h:45
std::shared_ptr< GridFileManager > GridFileManagerPtr
#define ARMARX_TRACE
Definition trace.h:77