Program Listing for File RegularSampling2D.cpp

Return to documentation for file (SPlisHSPlasH/Utilities/RegularSampling2D.cpp)

#include "RegularSampling2D.h"

#include <vector>

using namespace SPH;

RegularSampling2D::RegularSampling2D()
{
}

void RegularSampling2D::sampleMesh(const Matrix3r& rotation, const Vector3r & translation, const unsigned numVertices, const Vector3r * vertices, const unsigned int numFaces, const unsigned int * faces, const Real maxDistance, std::vector<Vector3r>& samples)
{
    using Vector3ui = Eigen::Matrix<unsigned int, 3, 1>;
    using Vector3b = Eigen::Matrix<bool, 3, 1>;

    // transform vertices
    std::vector<Vector3r> x(numVertices);
    #pragma omp parallel
    {
        #pragma omp for schedule(static)
        for (int i = 0; i < static_cast<int>(numVertices); i++)
        {
            x[i] = rotation * vertices[i] + translation;
        }
        #pragma omp barrier
        #pragma omp for schedule(static)
        for (int i = 0; i < (int) numFaces; i++)
        {
            // get face indices
            const Vector3ui & face = Eigen::Map<const Vector3ui>(faces + 3 * i);
            // find edges that cut the z=0 plane
            Vector3b cutsZ;
            for (unsigned int c = 0; c < 3; c++)
            {
                const Real z1 = x[face[c]].z();
                const Real z2 = x[face[(c + 1) % 3]].z();
                const bool bothGreaterOrEqual = z1 >= 0 && z2 >= 0;
                const bool bothLess = z1 < 0 && z2 < 0;
                cutsZ[c] = !(bothGreaterOrEqual || bothLess);
            }
            // ignore faces that do not cut the z=0 plane
            if (!cutsZ.any())
                continue;

            // compute cuts of edges with the plane
            std::vector<Vector3r> cuts;
            cuts.reserve(2);
            for (unsigned int c = 0; c < 3; c++)
            {
                if (!cutsZ[c])
                    continue;
                const Vector3r & a = x[face[c]];
                const Vector3r & b = x[face[(c + 1) % 3]];
                const Vector3r d = b - a;
                const Real alpha = a.z() / d.z();
                cuts.emplace_back(a.x() - alpha * d.x(), a.y() - alpha * d.y(), 0);
            }

            // sample line between cuts
            const Vector3r & v0 = cuts[0];
            const Vector3r dir = cuts[1] - v0;
            const Real l = dir.norm();
            // ceil for oversampling, +1 to get from end to end
            const auto numSamples = static_cast<unsigned int>(std::ceil(l / maxDistance)) + 1u;
            #pragma omp critical
            {
                for (unsigned sample = 0; sample < numSamples; sample++)
                {
                    if(numSamples > 1)
                        samples.emplace_back(v0 + static_cast<Real>(sample) / (numSamples - 1) * dir);

                }
            }
        }
    }

    // remove duplicate points
    const auto less = [](const Vector3r & a, const Vector3r & b) -> bool { return (a[0] < b[0]) || (a[0] == b[0] && a[1] < b[1] || (a[0] == b[0] && a[1] == b[1] && a[2] < b[2])); };
    std::sort(samples.begin(), samples.end(), less);

    const Real squaredMinDist = 1e-12f;
    const auto equals = [squaredMinDist](const Vector3r & a, const Vector3r & b) -> bool { return (a - b).squaredNorm() < squaredMinDist; };
    samples.erase(std::unique(samples.begin(), samples.end(), equals), samples.end());
}