31 #include <Inventor/nodes/SoMaterial.h>
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>
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>
56 #include <Eigen/Eigenvalues>
62 namespace fs = std::filesystem;
81 VirtualRobot::RobotIO::RobotDescription loadMode) :
84 coinVisFactory.reset(
new VirtualRobot::CoinVisualizationFactory());
94 loadMode != VirtualRobot::RobotIO::eCollisionModel)
96 throw armarx::LocalException(
"Loadmode must either be eFull oder eCollisionModel");
98 this->loadMode = loadMode;
111 VirtualRobot::VisualizationNodePtr
116 return simoxObject->getVisualization();
121 const std::string ivFName = cacheAttributeFile(
ATTR_IV_FILE,
true);
122 return coinVisFactory->getVisualizationFromFile(ivFName);
126 VirtualRobot::CollisionModelPtr
131 return simoxObject->getCollisionModel();
137 return VirtualRobot::CollisionModelPtr(
new VirtualRobot::CollisionModel(
138 coinVisFactory->getVisualizationFromFile(ivFName)));
142 VirtualRobot::ManipulationObjectPtr
159 const std::string ivFName = cacheAttributeFile(
ATTR_IV_FILE,
true);
169 const std::string& filesDBName)
172 return storeManipulationObject(mo, filesDBName);
184 const std::string& filesDBName)
186 if (!xmlFName.empty())
188 VirtualRobot::ManipulationObjectPtr mo = loadManipulationObjectFile(xmlFName);
190 ARMARX_INFO_S <<
" Saved manipulation object file: " << xmlFName <<
" (Id: " << fileId
202 if (!xmlFName.empty())
205 VirtualRobot::ManipulationObjectPtr mo = loadManipulationObjectFile(xmlFName);
212 const std::string& ivFNameCollision,
213 const std::string& filesDBName)
215 VirtualRobot::ManipulationObjectPtr mo = createManipulationObjectFromIvFiles(
218 ARMARX_INFO_S <<
" Saved IV model file: " << ivFNameVis <<
" (Id: " << ivFileId <<
")";
223 const std::string& ivFNameCollision)
225 VirtualRobot::ManipulationObjectPtr mo = createManipulationObjectFromIvFiles(
233 this->uncertaintyVisuType = visuType;
238 float heatmapMinVariance,
239 float heatmapDensityThreshold,
242 this->ellipseRadiusInSigmas = ellipseRadiusInSigmas;
243 this->heatmapMinVariance = heatmapMinVariance;
244 this->heatmapDensityThreshold = heatmapDensityThreshold;
245 this->heatmapGridSize = heatmapGridSize;
248 VirtualRobot::ColorMap
249 SimoxObjectWrapper::getUncertaintyColorMap()
253 const std::string mapName =
256 if (mapName ==
"eHot")
258 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHot);
260 else if (mapName ==
"eIntensity")
262 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eIntensity);
264 else if (mapName ==
"eRed")
266 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eRed);
268 else if (mapName ==
"eGreen")
270 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eGreen);
272 else if (mapName ==
"eBlue")
274 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eBlue);
276 else if (mapName ==
"eHotAlpha")
278 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHotAlpha);
280 else if (mapName ==
"eRedAlpha")
282 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eRedAlpha);
284 else if (mapName ==
"eGreenAlpha")
286 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eGreenAlpha);
288 else if (mapName ==
"eBlueAlpha")
290 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eBlueAlpha);
294 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHot);
299 return VirtualRobot::ColorMap(VirtualRobot::ColorMap::eHot);
304 SimoxObjectWrapper::getUncertaintyEllipseTransparency()
343 m.block(0, 3, 3, 1) = objPos->toEigen();
351 m.block(0, 0, 3, 3) = objOrient->toEigen();
362 mo->setGlobalPose(m);
367 EntityAttributeBasePtr posAttr = obj->getPositionAttribute();
368 ProbabilityMeasureBasePtr posDist = posAttr->getUncertainty();
372 static const std::string UNCERTAINTY_VISU_NAME =
"positionUncertainty";
373 VirtualRobot::VisualizationNodePtr moVis;
377 moVis = mo->getVisualization();
381 moVis->detachVisualization(UNCERTAINTY_VISU_NAME);
390 GaussianMixtureDistributionBasePtr posGM =
396 VirtualRobot::VisualizationNodePtr posDistVisu;
400 const VirtualRobot::ColorMap cmap = getUncertaintyColorMap();
402 switch (uncertaintyVisuType)
405 posDistVisu = getUncertaintyEllipsesVisu(
406 posGM, objPos->toEigen(), cmap, getUncertaintyEllipseTransparency());
410 posDistVisu = getUncertaintyHeatVisu(posGM, objPos->toEigen(),
false, cmap);
414 posDistVisu = getUncertaintyHeatVisu(posGM, objPos->toEigen(),
true, cmap);
429 dm.block(0, 0, 3, 3) = objOrientInv;
430 posDistVisu->setGlobalPose(dm);
434 moVis->attachVisualization(UNCERTAINTY_VISU_NAME, posDistVisu);
445 VirtualRobot::VisualizationNodePtr
446 SimoxObjectWrapper::getUncertaintyEllipsesVisu(GaussianMixtureDistributionBasePtr posGM,
447 const Eigen::Vector3f& objPos,
448 const VirtualRobot::ColorMap& cmap,
451 static float COV_SCALE_FACTOR = 1.f;
453 std::vector<VirtualRobot::VisualizationNodePtr> compVisuList;
455 for (
int i = 0; i < posGM->size(); ++i)
457 GaussianMixtureComponent comp = posGM->getComponent(i);
460 Eigen::Matrix3f cov = gaussian->toEigenCovariance() * COV_SCALE_FACTOR;
462 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> es(cov);
463 Eigen::Vector3f eval = es.eigenvalues();
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);
474 VirtualRobot::VisualizationNodePtr compVisu(
475 new VirtualRobot::CoinVisualizationNode(coinVisFactory->CreateEllipse(
476 ellipseRadiusInSigmas *
sqrt(eval(0)) / 1000.,
477 ellipseRadiusInSigmas *
sqrt(eval(1)) / 1000.,
478 ellipseRadiusInSigmas *
sqrt(eval(2)) / 1000.,
484 dm.block(0, 0, 3, 3) = evec;
485 dm.block(0, 3, 3, 1) = gaussian->toEigenMean() - objPos;
486 compVisu->setGlobalPose(dm);
488 compVisuList.push_back(compVisu);
491 return coinVisFactory->createUnitedVisualization(compVisuList);
494 VirtualRobot::VisualizationNodePtr
495 SimoxObjectWrapper::getUncertaintyHeatVisu(GaussianMixtureDistributionBasePtr posGM,
496 const Eigen::Vector3f& objPos,
498 const VirtualRobot::ColorMap& cmap)
500 const float SCALE_FACTOR =
sqrt(
503 const float COV_SCALE_FACTOR = 1.f;
504 const float LOG_PROB_CUTOFF = -logf(heatmapDensityThreshold);
505 const float MAX_CLUSTER_VARIANCE = 100;
507 std::vector<VirtualRobot::VisualizationNodePtr> clusterVisuList;
509 WestGMMReducer reducer;
510 GaussianMixtureDistributionBasePtr reducedGMM =
511 reducer.reduceByMaxAABB(posGM, MAX_CLUSTER_VARIANCE);
514 for (
int k = 0; k < reducedGMM->size(); ++k)
536 NormalDistributionPtr::dynamicCast(reducedGMM->getComponent(k).gaussian);
537 Eigen::Vector3f clusterCenter = compGaussian->toEigenMean();
539 std::cout <<
"Cluster mean: " << clusterCenter << std::endl;
542 clusterCenter /= SCALE_FACTOR;
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;
551 Eigen::MatrixXf grid = Eigen::MatrixXf::Zero(GRID_SIZE_X, GRID_SIZE_Y);
553 for (
int i = 0; i < posGM->size(); ++i)
555 GaussianMixtureComponent comp = posGM->getComponent(i);
559 Eigen::Vector2f
mean;
560 mean << meanVec[0], meanVec[1];
561 mean /= SCALE_FACTOR;
565 cov3D.block(0, 0, 2, 2) * COV_SCALE_FACTOR / (SCALE_FACTOR * SCALE_FACTOR);
567 float covDet = cov.determinant();
568 float covDetSqrtInv = powf(covDet, -0.5f);
571 pos(0) = clusterCenter(0) - (
float)(GRID_SIZE_X * CELL_SIZE_X) / 2.;
573 for (
int xc = 0;
xc < GRID_SIZE_X; ++
xc)
575 pos(1) = clusterCenter(1) - (
float)(GRID_SIZE_Y * CELL_SIZE_Y) / 2.;
577 for (
int yc = 0; yc < GRID_SIZE_Y; ++yc)
581 log(evaluate2DGaussian(pos,
mean, covInv, covDetSqrtInv))) /
582 LOG_PROB_CUTOFF * comp.weight;
591 else if (pdfValue > 1.)
597 grid(
xc, yc) += pdfValue;
600 pos(1) += CELL_SIZE_Y;
603 pos(0) += CELL_SIZE_X;
607 VirtualRobot::VisualizationNodePtr clusterVisu;
612 new VirtualRobot::CoinVisualizationNode(coinVisFactory->Create2DHeightMap(
614 CELL_SIZE_X * SCALE_FACTOR,
615 CELL_SIZE_Y * SCALE_FACTOR,
624 clusterVisu.reset(
new VirtualRobot::CoinVisualizationNode(
625 coinVisFactory->Create2DMap(grid,
626 CELL_SIZE_X * SCALE_FACTOR,
627 CELL_SIZE_Y * SCALE_FACTOR,
635 dm.block(0, 3, 3, 1) = clusterCenter * SCALE_FACTOR - objPos;
636 clusterVisu->setGlobalPose(dm);
638 clusterVisuList.push_back(clusterVisu);
641 return coinVisFactory->createUnitedVisualization(clusterVisuList);
646 SimoxObjectWrapper::evaluate2DGaussian(
const Eigen::Vector2f& point,
647 const Eigen::Vector2f&
mean,
653 float e = exp(inner(0, 0));
655 static const float c = 1. / 2 *
M_PI;
657 return c * covDetSqrtInv * e;
661 SimoxObjectWrapper::evaluate3DGaussian(
const Eigen::Vector3f& point,
662 const Eigen::Vector3f&
mean,
668 float e = exp(inner(0, 0));
670 return pow(2 *
M_PI, -3.0f / 2.0f) * pow(covDet, -0.5) * e;
691 SimoxObjectWrapper::loadSimoxObject()
const
694 if (loadMode != VirtualRobot::RobotIO::eStructure)
701 (loadMode == VirtualRobot::RobotIO::eCollisionModel &&
707 loadMode == VirtualRobot::RobotIO::eCollisionModel)
714 if (moFName.empty() && ivFName.empty() && ivFNameCollision.empty())
716 ARMARX_WARNING_S <<
"SimoxWrapper was not able to find ManipulationObjectFile or an "
717 "ivFile an ivCollision of ObjectInstance "
723 <<
"SimoxWrapper was not able to find IvFile Attribute of ObjectInstance "
726 else if (ivFNameCollision.empty() && loadMode == VirtualRobot::RobotIO::eCollisionModel)
729 <<
"SimoxWrapper was not able to find ivFNameCollision Attribute of ObjectInstance "
733 if (!moFName.empty())
737 simoxObject = loadManipulationObjectFile(moFName);
742 simoxObject = createManipulationObjectFromIvFiles(
748 SimoxObjectWrapper::cacheAttributeFile(
const std::string& attrName,
749 bool preserveOriginalFName )
const
752 std::string result =
"";
757 ARMARX_DEBUG_S <<
"Caching file(s) from attribute \"" << attrName <<
"\"";
760 getEntity()->getAttribute(attrName), result, preserveOriginalFName);
764 ARMARX_DEBUG_S <<
"Attribute \"" << attrName <<
"\" not available";
771 SimoxObjectWrapper::cacheAttributeFiles(
const std::string& attrName,
772 bool preserveOriginalFName )
const
779 preserveOriginalFName);
787 VirtualRobot::ManipulationObjectPtr
788 SimoxObjectWrapper::loadManipulationObjectFile(
const std::string& xmlFName)
const
790 return VirtualRobot::ObjectIO::loadManipulationObject(xmlFName);
793 VirtualRobot::ManipulationObjectPtr
794 SimoxObjectWrapper::createManipulationObjectFromIvFiles(
795 const std::string& objName,
796 const std::string& ivFNameVis,
797 const std::string& ivFNameCollision)
const
799 VirtualRobot::ManipulationObjectPtr mo(
new VirtualRobot::ManipulationObject(objName));
801 mo->setFilename(objName +
".xml");
803 VirtualRobot::VisualizationNodePtr visFull =
804 (!ivFNameVis.empty()) ? coinVisFactory->getVisualizationFromFile(ivFNameVis)
805 : VirtualRobot::VisualizationNodePtr();
809 mo->setVisualization(visFull);
812 VirtualRobot::VisualizationNodePtr visCollision =
813 ivFNameCollision.empty() ? VirtualRobot::VisualizationNodePtr()
814 : coinVisFactory->getVisualizationFromFile(ivFNameCollision);
818 VirtualRobot::CollisionModelPtr collisionModel(
819 new VirtualRobot::CollisionModel(visCollision));
820 mo->setCollisionModel(collisionModel);
827 SimoxObjectWrapper::storeManipulationObject(
const VirtualRobot::ManipulationObjectPtr mo,
828 const std::string& filesDBName)
839 fs::path visuFName = mo->getVisualization()->getFilename();
840 fs::path collisionFName = mo->getCollisionModel()->getVisualization()->getFilename();
841 storeEntityIVFiles(visuFName.string(), collisionFName.string(), filesDBName);
845 const std::string onlyFilenameVisu = visuFName.filename().string();
846 mo->getVisualization()->setFilename(onlyFilenameVisu,
847 mo->getVisualization()->usedBoundingBoxVisu());
849 const std::string onlyFilenameCol = collisionFName.filename().string();
850 mo->getCollisionModel()->getVisualization()->setFilename(
851 onlyFilenameCol, mo->getCollisionModel()->getVisualization()->usedBoundingBoxVisu());
853 VirtualRobot::ObjectIO::saveManipulationObject(mo, moTempFile);
859 filesDBName, moTempFile, moAttr, fs::path(mo->getFilename()).filename().string());
864 fs::remove(moTempFile);
869 SimoxObjectWrapper::storeEntityIVFiles(
const std::string& visuFName,
870 const std::string& collisionFName,
871 const std::string& filesDBName,
872 bool processTextures)
875 NameList::const_iterator itTex;
881 EntityAttributeBasePtr visuAttr =
new EntityAttribute(
ATTR_IV_FILE);
883 std::string visu_filename = visuFName;
884 if (!visu_filename.empty())
887 if (std::filesystem::path(visu_filename).is_relative())
889 visu_filename = (cachePath / visu_filename).
string();
892 ARMARX_INFO <<
" Saving visualization iv file: " << visu_filename;
893 fileManager->storeFileToAttr(filesDBName, visu_filename, visuAttr);
903 std::string col_filename = collisionFName;
904 if (!col_filename.empty())
907 if (std::filesystem::path(col_filename).is_relative())
909 col_filename = (cachePath / col_filename).
string();
917 if (col_filename == visu_filename)
919 collisionAttr->addValue(visuAttr->getValue());
923 fileManager->storeFileToAttr(filesDBName, col_filename, collisionAttr);
932 getEntity()->putAttribute(collisionAttr);
936 if (!textures.empty())
941 for (itTex = textures.begin(); itTex != textures.end(); ++itTex)
944 fileManager->storeFileToAttr(filesDBName, *itTex, texAttr);
954 getEntity()->removeAttribute(oldTextureFileAttr->getName());
964 if (!in.openFile(ivFName.c_str()))
970 SoNode*
n = SoDB::readAll(&in);
979 Eigen::Vector3f result = {0, 0, 0};
986 if (attr->size() > 0)
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;
1011 std::vector<std::string>& storeFilenames,
1012 const std::string& origFile)
1019 if (node->getTypeId() == SoFile::getClassTypeId())
1022 SoFile* fileNode = (SoFile*)node;
1023 SbString fileNodeName = fileNode->getFullName();
1028 SbString s2 = fileNode->name.getValue();
1036 storeFilenames.push_back(s2.getString());
1041 storeFilenames.push_back(fileNodeName.getString());
1045 SoGroup* fileChildren = fileNode->copyChildren();
1047 fileChildren, storeFilenames, fileNodeName.getString());
1049 else if (node->getTypeId().isDerivedFrom(SoGroup::getClassTypeId()))
1051 SoGroup* groupNode = (SoGroup*)node;
1054 for (
int i = 0; i < groupNode->getNumChildren(); i++)
1057 groupNode->getChild(i), storeFilenames, origFile);
1060 else if (node->getTypeId() == SoImage::getClassTypeId())
1063 SbString imageFilename = ((SoImage*)node)->filename.getValue();
1066 else if (node->getTypeId() == SoTexture2::getClassTypeId())
1069 SbString texture2Filename = ((SoTexture2*)node)->filename.getValue();
1070 storeFilenames.push_back(
1073 else if (node->getTypeId() == SoTexture3::getClassTypeId())
1080 sa.setType(SoVRMLImageTexture::getClassTypeId());
1082 sa.setSearchingAll(TRUE);
1085 SoPathList& pathList = sa.getPaths();
1086 if (pathList.getLength() <= 0)
1090 SoFullPath* p = (SoFullPath*)pathList[0];
1091 if (!p->getTail()->isOfType(SoVRMLImageTexture::getClassTypeId()))
1095 SoVRMLImageTexture* texture = (SoVRMLImageTexture*)p->getTail();
1096 if (texture->url.getNum() <= 0)
1100 for (
int i = 0; i < texture->url.getNum(); ++i)
1103 if (!path.empty() && fs::exists(path))
1105 storeFilenames.push_back(path);
1108 if (i == texture->url.getNum() - 1)
1110 Ice::StringSeq textures;
1111 for (
int j = 0; j < texture->url.getNum(); ++j)
1113 textures.push_back(texture->url[j].getString());
1115 ARMARX_ERROR <<
"Could not make any of the texture paths absolute: "
1116 << simox::alg::join(textures,
", ");
1130 return std::string();
1135 fs::path absOrigFileDirPath;
1136 std::string resultPathStr;
1137 if (!origFile.empty())
1139 absOrigFileDirPath =
1142 if (filepath.is_absolute())
1151 return std::string();
1154 else if (!filepath.has_parent_path())
1156 return (absOrigFileDirPath / filepath).string();
1159 absOrigFileDirPath.string(), filepath.string(), resultPathStr))
1161 return resultPathStr;
1166 return std::string();