diff --git a/VirtualRobot/Visualization/TriMeshModel.cpp b/VirtualRobot/Visualization/TriMeshModel.cpp index c692a396d62a68a48982c440e012dab3ec20e08e..1c788b6036d492dcd811a08a08b8d488eb1948b1 100644 --- a/VirtualRobot/Visualization/TriMeshModel.cpp +++ b/VirtualRobot/Visualization/TriMeshModel.cpp @@ -620,6 +620,16 @@ namespace VirtualRobot return areas; } + float TriMeshModel::getVolume() const + { + float volume = 0.0f; + for (const auto& face : faces) + { + volume += vertices.at(face.id1).dot(vertices.at(face.id2).cross(vertices.at(face.id3))); + } + return std::abs(volume); + } + void TriMeshModel::rotate(const Eigen::Matrix3f& mx) { for (auto& vec3f : normals) diff --git a/VirtualRobot/Visualization/TriMeshModel.h b/VirtualRobot/Visualization/TriMeshModel.h index 01fa13ceb6cf75ee00e44c1ee72c3f51bc4b60a4..15ae900062fc6a049c631475dda7b23db890ae7f 100644 --- a/VirtualRobot/Visualization/TriMeshModel.h +++ b/VirtualRobot/Visualization/TriMeshModel.h @@ -168,6 +168,9 @@ namespace VirtualRobot /// Get the areas of all faces. std::vector<float> getFaceAreas() const; + //! Computes the volume of the mesh. Works only for closed meshes + float getVolume() const; + void rotate(const Eigen::Matrix3f& mx); // Overwrite all colors diff --git a/VirtualRobot/Visualization/TriMeshUtils.cpp b/VirtualRobot/Visualization/TriMeshUtils.cpp index 35a66a9c4c6e5a251346928c49f272421b942f55..6bc0262c31588d48d63efa800f9cd98094004b1f 100644 --- a/VirtualRobot/Visualization/TriMeshUtils.cpp +++ b/VirtualRobot/Visualization/TriMeshUtils.cpp @@ -22,6 +22,9 @@ * GNU General Public License */ #include "TriMeshUtils.h" +#include "../VirtualRobotException.h" +#include <Eigen/Geometry> +#include <numeric> namespace VirtualRobot { @@ -148,4 +151,61 @@ TriMeshModelPtr TriMeshUtils::CreateSparseBoxGrid(const Eigen::Matrix4f &globalP return mesh; } + +inline double +uniformDeviate(int seed) +{ + double ran = seed * (1.0 / (RAND_MAX + 1.0)); + return ran; +} + +Eigen::Vector3f TriMeshUtils::sampleSurfacePoint(std::vector<float> *cumulativeAreas, double totalArea, const TriMeshModel& tri) +{ + if (tri.faces.empty()) + { + return Eigen::Vector3f::Zero(); + } + + float r = static_cast<float>(uniformDeviate(rand()) * totalArea); + std::vector<float>::iterator low = std::lower_bound(cumulativeAreas->begin(), cumulativeAreas->end(), r); + auto f = tri.faces[low - cumulativeAreas->begin()]; + + float r1 = static_cast<float>(uniformDeviate(rand())); + float r2 = static_cast<float>(uniformDeviate(rand())); + + float r1sqr = std::sqrt (r1); + float OneMinR1Sqr = (1 - r1sqr); + float OneMinR2 = (1 - r2); + Eigen::Vector3f a = tri.vertices.at(f.id1) * OneMinR1Sqr; + Eigen::Vector3f b = tri.vertices.at(f.id2) * OneMinR2; + Eigen::Vector3f c = r1sqr * (r2 * tri.vertices.at(f.id3) + b) + a; + return c; +} + +std::vector<Eigen::Vector3f> TriMeshUtils::uniformSampling(const TriMeshModel& tri, unsigned int n) { + std::vector<Eigen::Vector3f> samples(n); + + std::vector<float> faceAreas = tri.getFaceAreas(); + std::vector<float> cumulativeAreas(faceAreas.size(), 0.0); + float totalArea = 0; + for (size_t i = 0; i < faceAreas.size(); i++) { + totalArea += faceAreas[i]; + cumulativeAreas[i] = totalArea; + } + + unsigned int i = 0; + unsigned int counter = 0; + while (i < n) { + Eigen::Vector3f sampledPoint = sampleSurfacePoint(&cumulativeAreas, totalArea, tri); + if (!sampledPoint.isZero()) { + samples[i] = sampledPoint; + i++; + counter = 0; + } + if (counter > 10) + throw VirtualRobotException("Sampling surface points gone wrong!"); + } + return samples; +} + } // namespace VirtualRobot diff --git a/VirtualRobot/Visualization/TriMeshUtils.h b/VirtualRobot/Visualization/TriMeshUtils.h index cc28fe82661508a66fdba651832a07ec120a8089..8dfbb89095d6b30bc40158bb6631fdb85795634c 100644 --- a/VirtualRobot/Visualization/TriMeshUtils.h +++ b/VirtualRobot/Visualization/TriMeshUtils.h @@ -39,6 +39,9 @@ public: const VisualizationFactory::Color &color = VisualizationFactory::Color::Gray(), const std::vector<VisualizationFactory::Color>& colors = {}); + static Eigen::Vector3f sampleSurfacePoint(std::vector<float> *cumulativeAreas, double totalArea, const VirtualRobot::TriMeshModel& tri); + //! Uniformly samples points on the surface of a trimesh model and can be used to create a point cloud of the model + static std::vector<Eigen::Vector3f> uniformSampling(const VirtualRobot::TriMeshModel& tri, unsigned int n = 1000); }; } // namespace VirtualRobot