diff --git a/Applications/DataExplorer/DataView/ElementTreeModel.cpp b/Applications/DataExplorer/DataView/ElementTreeModel.cpp index 5288786efbe718f2592f8dc14d503fedd35f8df4..9b639ebc5de8441cae84d453910f9fac5cf08a59 100644 --- a/Applications/DataExplorer/DataView/ElementTreeModel.cpp +++ b/Applications/DataExplorer/DataView/ElementTreeModel.cpp @@ -25,6 +25,22 @@ #include "TreeItem.h" +namespace +{ +template <typename PropertyType> +QList<QVariant> propertyBounds(PropertyType const& property) +{ + auto const bounds = MeshLib::MeshInformation::getValueBounds(property); + if (bounds.has_value()) + { + return {"[" + QString::number(bounds->first) + ",", + QString::number(bounds->second) + "]"}; + } + // Makeup the same structure of output as in the valid case above. + return {"[empty,", "empty]"}; +} +} // namespace + /** * Constructor. */ @@ -168,39 +184,55 @@ void ElementTreeModel::setMesh(MeshLib::Mesh const& mesh) auto* edge_item = new TreeItem(edges, _rootItem); _rootItem->appendChild(edge_item); - std::vector<std::string> const& vec_names (mesh.getProperties().getPropertyVectorNames()); - for (const auto& vec_name : vec_names) + for (auto [name, property] : mesh.getProperties()) { - QList<QVariant> array_info; - array_info << QString::fromStdString(vec_name) + ": "; - if (auto const vec_bounds = // test if boost::optional is empty - MeshLib::MeshInformation::getValueBounds<int>(mesh, vec_name)) + QList<QVariant> array_info{QString::fromStdString(name) + ": "}; + + if (auto p = dynamic_cast<MeshLib::PropertyVector<double>*>(property)) { - array_info << "[" + QString::number(vec_bounds->first) + "," - << QString::number(vec_bounds->second) + "]"; + array_info.append(propertyBounds(*p)); } - else if (auto const vec_bounds = // test if boost::optional is empty - MeshLib::MeshInformation::getValueBounds<double>(mesh, - vec_name)) + else if (auto p = + dynamic_cast<MeshLib::PropertyVector<float>*>(property)) { - array_info << "[" + QString::number(vec_bounds->first) + "," - << QString::number(vec_bounds->second) + "]"; + array_info.append(propertyBounds(*p)); } - else + else if (auto p = dynamic_cast<MeshLib::PropertyVector<int>*>(property)) { - // Makeup the same structure of output as in the valid cases above. - array_info << "[error," - << "error]"; + array_info.append(propertyBounds(*p)); } - - if (array_info.size() == 1) + else if (auto p = + dynamic_cast<MeshLib::PropertyVector<unsigned>*>(property)) { + array_info.append(propertyBounds(*p)); + } + else if (auto p = + dynamic_cast<MeshLib::PropertyVector<long>*>(property)) + { + array_info.append(propertyBounds(*p)); + } + else if (auto p = dynamic_cast<MeshLib::PropertyVector<unsigned long>*>( + property)) + { + array_info.append(propertyBounds(*p)); + } + else if (auto p = dynamic_cast<MeshLib::PropertyVector<std::size_t>*>( + property)) + { + array_info.append(propertyBounds(*p)); + } + else if (auto p = + dynamic_cast<MeshLib::PropertyVector<char>*>(property)) + { + array_info.append(propertyBounds(*p)); + } + else + { // Unhandled property vector type. array_info << "[ ?" << "? ]" << ""; } - auto* vec_item = new TreeItem(array_info, _rootItem); - _rootItem->appendChild(vec_item); + _rootItem->appendChild(new TreeItem(array_info, _rootItem)); } endResetModel(); diff --git a/Applications/DataExplorer/DataView/MeshElementRemovalDialog.cpp b/Applications/DataExplorer/DataView/MeshElementRemovalDialog.cpp index 51f798466c1d8c1b04b0814eb5874ee027264780..f59e16b6e42900fcb932b6f2898b6453a36e3a0c 100644 --- a/Applications/DataExplorer/DataView/MeshElementRemovalDialog.cpp +++ b/Applications/DataExplorer/DataView/MeshElementRemovalDialog.cpp @@ -178,28 +178,14 @@ void MeshElementRemovalDialog::reject() std::size_t MeshElementRemovalDialog::addScalarArrays(MeshLib::Mesh const& mesh) const { - MeshLib::Properties const& properties = mesh.getProperties(); - std::vector<std::string> const& names = properties.getPropertyVectorNames(); - for (auto const& name : names) + for (auto [name, property] : mesh.getProperties()) { - if (properties.existsPropertyVector<int>(name)) + if (property->getMeshItemType() != MeshLib::MeshItemType::Cell) { - auto const& p = properties.getPropertyVector<int>(name); - if (p->getMeshItemType() == MeshLib::MeshItemType::Cell) - { - this->scalarArrayComboBox->addItem(QString::fromStdString(name)); - enableScalarArrayWidgets(true); - } - } - if (properties.existsPropertyVector<double>(name)) - { - auto const& p = properties.getPropertyVector<double>(name); - if (p->getMeshItemType() == MeshLib::MeshItemType::Cell) - { - this->scalarArrayComboBox->addItem(QString::fromStdString(name)); - enableScalarArrayWidgets(true); - } + continue; } + this->scalarArrayComboBox->addItem(QString::fromStdString(name)); + enableScalarArrayWidgets(true); } return this->scalarArrayComboBox->count(); } diff --git a/Applications/Utils/MeshEdit/UnityPreprocessing.cpp b/Applications/Utils/MeshEdit/UnityPreprocessing.cpp index a19ed789bf6045f3503322fd8b32f776803a1606..9700ffeb354d8ab42936e34f12b40bc8860c5aa2 100644 --- a/Applications/Utils/MeshEdit/UnityPreprocessing.cpp +++ b/Applications/Utils/MeshEdit/UnityPreprocessing.cpp @@ -28,9 +28,11 @@ bool containsCellVecs(MeshLib::Mesh const& mesh) { - MeshLib::Properties const& props (mesh.getProperties()); - std::vector<std::string> const& vec_names(props.getPropertyVectorNames(MeshLib::MeshItemType::Cell)); - return !vec_names.empty(); + auto is_cell_property = [](auto const p) { + return p.second->getMeshItemType() == MeshLib::MeshItemType::Cell; + }; + return std::any_of(mesh.getProperties().begin(), mesh.getProperties().end(), + is_cell_property); } template <class T> @@ -50,81 +52,108 @@ MeshLib::Element* createElement(MeshLib::Element const& e, } template <class T> -bool fillPropVec(MeshLib::Properties const& props, - std::string const& name, - MeshLib::Properties &new_props, - std::vector<MeshLib::Element*> const& elems, - std::vector<std::vector<std::size_t>> const& node_map, - std::size_t total_nodes) +void fillPropVec(MeshLib::PropertyVector<T> const& property, + MeshLib::Properties& new_props, + std::vector<MeshLib::Element*> const& elems, + std::vector<std::vector<std::size_t>> const& node_map, + std::size_t const total_nodes) { - if (!props.existsPropertyVector<T>(name)) - { - return false; - } - - MeshLib::PropertyVector<T> const*const vec = props.getPropertyVector<T>(name); - if (vec->getNumberOfComponents() != 1) - { - INFO("Ignoring array '{:s}' (more than one component).", name); - return false; - } - - MeshLib::PropertyVector<T>* new_vec = - new_props.createNewPropertyVector<T>(vec->getPropertyName(), MeshLib::MeshItemType::Node, 1); - new_vec->resize(total_nodes); - if (vec->getMeshItemType() == MeshLib::MeshItemType::Node) + assert(property.getNumberOfComponents() == 1); + MeshLib::PropertyVector<T>* new_property = + new_props.createNewPropertyVector<T>(property.getPropertyName(), + MeshLib::MeshItemType::Node, 1); + new_property->resize(total_nodes); + if (property.getMeshItemType() == MeshLib::MeshItemType::Node) { - INFO("Migrating node array '{:s}' to new mesh structure...", name); + INFO("Migrating node array '{:s}' to new mesh structure...", + property.getPropertyName()); std::size_t const n_nodes (node_map.size()); for (std::size_t i = 0; i<n_nodes; ++i) { std::size_t const n_nodes_i = node_map[i].size(); for (std::size_t j = 0; j < n_nodes_i; ++j) { - (*new_vec)[node_map[i][j]] = (*vec)[i]; + (*new_property)[node_map[i][j]] = property[i]; } } } - else if (vec->getMeshItemType() == MeshLib::MeshItemType::Cell) + else if (property.getMeshItemType() == MeshLib::MeshItemType::Cell) { - INFO("Transforming cell array '{:s}' into node array...", name); - std::size_t const n_elems (vec->size()); + INFO("Transforming cell array '{:s}' into node array...", + property.getPropertyName()); + std::size_t const n_elems(property.size()); for (std::size_t i = 0; i<n_elems; ++i) { std::size_t const n_nodes = elems[i]->getNumberOfNodes(); for (std::size_t j = 0; j < n_nodes; ++j) { - (*new_vec)[elems[i]->getNodeIndex(j)] = (*vec)[i]; + (*new_property)[elems[i]->getNodeIndex(j)] = property[i]; } } } - return true; } -MeshLib::Properties constructProperties(MeshLib::Properties const& props, +MeshLib::Properties constructProperties( + MeshLib::Properties const& properties, std::vector<MeshLib::Element*> const& elems, std::vector<std::vector<std::size_t>> const& node_map, - std::size_t n_nodes) + std::size_t const n_nodes) { - std::vector<std::string> const& names = props.getPropertyVectorNames(); - MeshLib::Properties new_props; - for (std::string const& name : names) + using namespace MeshLib; + Properties new_properties; + for (auto [name, property] : properties) { - if (fillPropVec<int>(props, name, new_props, elems, node_map, n_nodes)) + if (property->getNumberOfComponents() != 1) + { + INFO("Ignoring array '{:s}' (more than one component).", name); + continue; + } + + if (auto const p = dynamic_cast<PropertyVector<double>*>(property)) + { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); + continue; + } + else if (auto const p = dynamic_cast<PropertyVector<float>*>(property)) + { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); + continue; + } + else if (auto const p = dynamic_cast<PropertyVector<int>*>(property)) + { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); + continue; + } + else if (auto const p = + dynamic_cast<PropertyVector<unsigned>*>(property)) + { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); + continue; + } + else if (auto const p = dynamic_cast<PropertyVector<long>*>(property)) + { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); + continue; + } + else if (auto const p = + dynamic_cast<PropertyVector<unsigned long>*>(property)) { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); continue; } - if (fillPropVec<double>(props, name, new_props, elems, node_map, - n_nodes)) + else if (auto const p = + dynamic_cast<PropertyVector<std::size_t>*>(property)) { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); continue; } - if (fillPropVec<long>(props, name, new_props, elems, node_map, n_nodes)) + else if (auto const p = dynamic_cast<PropertyVector<char>*>(property)) { + fillPropVec(*p, new_properties, elems, node_map, n_nodes); continue; } } - return new_props; + return new_properties; } MeshLib::Mesh* constructMesh(MeshLib::Mesh const& mesh) diff --git a/MeshLib/MeshInformation.cpp b/MeshLib/MeshInformation.cpp index c0dfa29e8b4de6a9f4ba30ba1af4c3479d9473c6..2af260e242eeedb109dd30600029629cbb1f6368 100644 --- a/MeshLib/MeshInformation.cpp +++ b/MeshLib/MeshInformation.cpp @@ -17,6 +17,23 @@ #include "Elements/Element.h" #include "MeshLib/MeshQuality/MeshValidation.h" +namespace +{ +template <typename T> +void printBounds(MeshLib::PropertyVector<T> const& property) +{ + auto const bounds = MeshLib::MeshInformation::getValueBounds(property); + if (!bounds.has_value()) + { + INFO("\t{:s}: Could not get value bounds for property vector.", + property.getPropertyName()); + return; + } + INFO("\t{:s}: ({:d} values) [{}, {}]", property.getPropertyName(), + property.size(), bounds->first, bounds->second); +} +} // namespace + namespace MeshLib { GeoLib::AABB MeshInformation::getBoundingBox(const MeshLib::Mesh& mesh) @@ -55,28 +72,50 @@ void MeshInformation::writeAllNumbersOfElementTypes(const MeshLib::Mesh& mesh) void MeshInformation::writePropertyVectorInformation(const MeshLib::Mesh& mesh) { - std::vector<std::string> const& vec_names( - mesh.getProperties().getPropertyVectorNames()); - INFO("There are {:d} properties in the mesh:", vec_names.size()); - for (const auto& vec_name : vec_names) + auto const& properties = mesh.getProperties(); + INFO("There are {:d} properties in the mesh:", properties.size()); + + for (auto [name, property] : properties) { - if (auto const vec_bounds = - MeshLib::MeshInformation::getValueBounds<int>(mesh, vec_name)) + if (auto p = dynamic_cast<PropertyVector<double>*>(property)) + { + printBounds(*p); + } + else if (auto p = dynamic_cast<PropertyVector<float>*>(property)) + { + printBounds(*p); + } + else if (auto p = dynamic_cast<PropertyVector<int>*>(property)) + { + printBounds(*p); + } + else if (auto p = dynamic_cast<PropertyVector<unsigned>*>(property)) + { + printBounds(*p); + } + else if (auto p = dynamic_cast<PropertyVector<long>*>(property)) + { + printBounds(*p); + } + else if (auto p = + dynamic_cast<PropertyVector<unsigned long>*>(property)) + { + printBounds(*p); + } + else if (auto p = dynamic_cast<PropertyVector<std::size_t>*>(property)) { - INFO("\t{:s}: [{:d}, {:d}]", vec_name, vec_bounds->first, - vec_bounds->second); + printBounds(*p); } - else if (auto const vec_bounds = - MeshLib::MeshInformation::getValueBounds<double>(mesh, - vec_name)) + else if (auto p = dynamic_cast<PropertyVector<char>*>(property)) { - INFO("\t{:s}: [{:g}, {:g}]", vec_name, vec_bounds->first, - vec_bounds->second); + printBounds(*p); } else { - INFO("\t{:s}: Could not get value bounds for property vector.", - vec_name); + INFO( + "\t{:s}: Could not get value bounds for property vector of " + "type '{:s}'.", + name, typeid(*p).name()); } } } diff --git a/MeshLib/MeshInformation.h b/MeshLib/MeshInformation.h index b68968597c51663289daa63c7e1d6ba025771227..88e674ab0da0cfe91d5d5608b7e14e9f75c6fbd3 100644 --- a/MeshLib/MeshInformation.h +++ b/MeshLib/MeshInformation.h @@ -17,6 +17,7 @@ #include <array> #include <limits> #include <map> +#include <optional> #include <string> #include "GeoLib/AABB.h" @@ -35,24 +36,18 @@ public: /// Returns the smallest and largest value of a scalar array with the given /// name. template <typename T> - static boost::optional<std::pair<T, T>> const getValueBounds( - MeshLib::Mesh const& mesh, std::string const& name) + static std::optional<std::pair<T, T>> const getValueBounds( + PropertyVector<T> const& property) { - if (!mesh.getProperties().existsPropertyVector<T>(name)) + if (property.empty()) { - return {}; - } - - auto const* const data_vec = - mesh.getProperties().getPropertyVector<T>(name); - if (data_vec->empty()) - { - INFO("Mesh does not contain values for the property '{:s}'.", name); - return {}; + INFO("Mesh property vector '{:s}' is empty.", + property.getPropertyName()); + return std::nullopt; } auto const [min, max] = - std::minmax_element(begin(*data_vec), end(*data_vec)); + std::minmax_element(begin(property), end(property)); return {{*min, *max}}; } diff --git a/MeshLib/convertMeshToGeo.cpp b/MeshLib/convertMeshToGeo.cpp index 6e9ee80d8bcfcd7af95cce06a83359295a542a82..0c69489f1478377c4e814cac562f855bdd90c05c 100644 --- a/MeshLib/convertMeshToGeo.cpp +++ b/MeshLib/convertMeshToGeo.cpp @@ -97,8 +97,7 @@ bool convertMeshToGeo(const MeshLib::Mesh& mesh, return std::make_tuple(nullptr, std::make_pair(0, 0)); } - auto const bounds = - MeshInformation::getValueBounds<int>(mesh, "MaterialIDs"); + auto const bounds = MeshInformation::getValueBounds(*materialIds); if (!bounds) { OGS_FATAL( diff --git a/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp b/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp index 48b16643e5da236d173075e0d251197786a7c92f..75f2dac295c6eecd9d20c58244184572807c437a 100644 --- a/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp +++ b/ProcessLib/LIE/HydroMechanics/HydroMechanicsProcess.cpp @@ -102,7 +102,7 @@ HydroMechanicsProcess<GlobalDim>::HydroMechanicsProcess( else { auto const range = - MeshLib::MeshInformation::getValueBounds<int>(mesh, "MaterialIDs"); + MeshLib::MeshInformation::getValueBounds(*materialIDs(mesh)); if (!range) { OGS_FATAL( diff --git a/Tests/FileIO/TestGmsInterface.cpp b/Tests/FileIO/TestGmsInterface.cpp index 0a8553838fb915f2a06f9d2964ba7f164a2287a2..ea8bd2a44b399b5315fe09e26f9849e0b5f65c0b 100644 --- a/Tests/FileIO/TestGmsInterface.cpp +++ b/Tests/FileIO/TestGmsInterface.cpp @@ -31,8 +31,8 @@ TEST(FileIO, TestGmsInterface) ASSERT_EQ(1355, types.at(MeshLib::MeshElemType::PYRAMID)); // pyramids ASSERT_EQ(17074, types.at(MeshLib::MeshElemType::PRISM)); // prism auto const& bounds = - MeshLib::MeshInformation::getValueBounds<int>(*mesh, "MaterialIDs"); - ASSERT_TRUE(boost::none != bounds); + MeshLib::MeshInformation::getValueBounds(*materialIDs(*mesh)); + ASSERT_TRUE(bounds.has_value()); ASSERT_EQ(1, bounds->first); ASSERT_EQ(63, bounds->second); } diff --git a/Tests/FileIO/TestTetGenInterface.cpp b/Tests/FileIO/TestTetGenInterface.cpp index ca06839b0714a6cc6e24f208153962cfb21253b8..772bf2d2dc2e2dfac3c22b8317c3574732c0bbad 100644 --- a/Tests/FileIO/TestTetGenInterface.cpp +++ b/Tests/FileIO/TestTetGenInterface.cpp @@ -101,9 +101,10 @@ TEST(FileIO, TetGenMeshReaderWithMaterials) ASSERT_EQ(1378, mesh->getNumberOfNodes()); ASSERT_EQ(5114, mesh->getNumberOfElements()); + ASSERT_NE(nullptr, materialIDs(*mesh)); auto const& bounds = - MeshLib::MeshInformation::getValueBounds<int>(*mesh, "MaterialIDs"); - ASSERT_TRUE(boost::none != bounds); + MeshLib::MeshInformation::getValueBounds(*materialIDs(*mesh)); + ASSERT_TRUE(bounds.has_value()); ASSERT_EQ(-20, bounds->first); ASSERT_EQ(-10, bounds->second); } @@ -119,7 +120,5 @@ TEST(FileIO, TetGenMeshReaderWithoutMaterials) ASSERT_EQ(202, mesh->getNumberOfNodes()); ASSERT_EQ(650, mesh->getNumberOfElements()); - auto const& bounds = - MeshLib::MeshInformation::getValueBounds<int>(*mesh, "MaterialIDs"); - ASSERT_TRUE(boost::none == bounds); + ASSERT_EQ(nullptr, materialIDs(*mesh)); } diff --git a/Tests/FileIO_SWMM/TestSwmmInterface.cpp b/Tests/FileIO_SWMM/TestSwmmInterface.cpp index bfb92f234ed8f839c07367a0fa83da980e8de045..1a5f7200d461b904596a4ae463594af370f9b38f 100644 --- a/Tests/FileIO_SWMM/TestSwmmInterface.cpp +++ b/Tests/FileIO_SWMM/TestSwmmInterface.cpp @@ -70,8 +70,8 @@ TEST(FileIO, TestSwmmInterface) ASSERT_EQ(n_elems, types.at(MeshLib::MeshElemType::LINE)); // all elems are lines auto const bounds = - MeshLib::MeshInformation::getValueBounds<int>(mesh, "MaterialIDs"); - ASSERT_TRUE(boost::none != bounds); + MeshLib::MeshInformation::getValueBounds(*materialIDs(mesh)); + ASSERT_TRUE(bounds.has_value()); ASSERT_EQ(0, bounds->first); ASSERT_EQ(0, bounds->second); diff --git a/Tests/MeshLib/TestRasterToMesh.cpp b/Tests/MeshLib/TestRasterToMesh.cpp index cc5ec97156d04d42a95f53b472c569276a338833..a5308f27e300d0b92a133a9c22b45e2b25be2c0c 100644 --- a/Tests/MeshLib/TestRasterToMesh.cpp +++ b/Tests/MeshLib/TestRasterToMesh.cpp @@ -121,9 +121,8 @@ TEST_F(RasterToMeshTest, convertRasterToTriMeshValue) ASSERT_TRUE(prop != nullptr); ASSERT_EQ(2 * _n_pix, prop->size()); - auto const& bounds = - MeshLib::MeshInformation::getValueBounds<double>(*mesh, "test"); - ASSERT_TRUE(boost::none != bounds); + auto const& bounds = MeshLib::MeshInformation::getValueBounds(*prop); + ASSERT_TRUE(bounds.has_value()); ASSERT_NEAR(0, bounds->first, std::numeric_limits<double>::epsilon()); ASSERT_NEAR(0.07, bounds->second, std::numeric_limits<double>::epsilon()); @@ -153,9 +152,8 @@ TEST_F(RasterToMeshTest, convertRasterToQuadMeshValue) ASSERT_TRUE(prop != nullptr); ASSERT_EQ(_n_pix, prop->size()); - auto const& bounds = - MeshLib::MeshInformation::getValueBounds<double>(*mesh, "test"); - ASSERT_TRUE(boost::none != bounds); + auto const& bounds = MeshLib::MeshInformation::getValueBounds(*prop); + ASSERT_TRUE(bounds.has_value()); ASSERT_NEAR(0, bounds->first, std::numeric_limits<double>::epsilon()); ASSERT_NEAR(0.07, bounds->second, std::numeric_limits<double>::epsilon()); @@ -185,9 +183,8 @@ TEST_F(RasterToMeshTest, convertRasterToPrismMeshValue) ASSERT_TRUE(prop != nullptr); ASSERT_EQ(2 * _n_pix, prop->size()); - auto const& bounds = - MeshLib::MeshInformation::getValueBounds<double>(*mesh, "test"); - ASSERT_TRUE(boost::none != bounds); + auto const& bounds = MeshLib::MeshInformation::getValueBounds(*prop); + ASSERT_TRUE(bounds.has_value()); ASSERT_NEAR(0, bounds->first, std::numeric_limits<double>::epsilon()); ASSERT_NEAR(0.07, bounds->second, std::numeric_limits<double>::epsilon()); @@ -217,9 +214,8 @@ TEST_F(RasterToMeshTest, convertRasterToHexMeshValue) ASSERT_TRUE(prop != nullptr); ASSERT_EQ(_n_pix, prop->size()); - auto const& bounds = - MeshLib::MeshInformation::getValueBounds<int>(*mesh, "MaterialIDs"); - ASSERT_TRUE(boost::none != bounds); + auto const& bounds = MeshLib::MeshInformation::getValueBounds(*prop); + ASSERT_TRUE(bounds.has_value()); ASSERT_NEAR(0, bounds->first, std::numeric_limits<double>::epsilon()); ASSERT_NEAR(0, bounds->second, std::numeric_limits<double>::epsilon()); @@ -276,9 +272,8 @@ TEST_F(RasterToMeshTest, vtkImage) ASSERT_TRUE(prop != nullptr); ASSERT_EQ(2 * _n_pix, prop->size()); - auto const& bounds = - MeshLib::MeshInformation::getValueBounds<double>(*mesh, "test"); - ASSERT_TRUE(boost::none != bounds); + auto const& bounds = MeshLib::MeshInformation::getValueBounds(*prop); + ASSERT_TRUE(bounds.has_value()); ASSERT_NEAR(0, bounds->first, std::numeric_limits<double>::epsilon()); ASSERT_NEAR(0.07, bounds->second, std::numeric_limits<float>::epsilon());