#pragma once #include #include namespace meshless { template struct Pi { static constexpr T value = T(3.14159265358979323846264338327950L); ///< Value of @f$\pi@f$. }; static const double PI = Pi::value; ///< Mathematical constant pi in double precision. static const double INF = 1.0 / 0.0; ///< Infinite floating point value. static const double NaN = 0.0 / 0.0; ///< Not-a-number floating point value. template struct SphereDiscretization { /** * Construct a randomized discretization. * @param radius Radius of the sphere. * @param num_samples Number of points on the equator, implies nodal spacing `dp = 2*pi*r/n`. * @param generator A random number generator. * @return A vector of discretization points. */ template static std::vector, Eigen::aligned_allocator>> construct( scalar_t radius, int num_samples, generator_t& generator) { scalar_t dphi = 2 * Pi::value / num_samples; std::uniform_real_distribution distribution(0, Pi::value); scalar_t offset = distribution(generator); std::vector, Eigen::aligned_allocator>> result; for(int i = 0; i < num_samples / 2; ++i) { scalar_t phi = i * dphi + offset; if(phi > Pi::value) phi -= Pi::value; int slice_n = static_cast(std::ceil(num_samples * std::sin(phi))); if(slice_n == 0) continue; auto slice = SphereDiscretization::construct( radius * std::sin(phi), slice_n, generator); Eigen::Matrix v; for(const auto& p : slice) { v[0] = radius * std::cos(phi); v.template tail() = p; result.push_back(v); } } return result; } /// Construct the discretization. static std::vector, Eigen::aligned_allocator>> construct( scalar_t radius, int num_samples) { scalar_t dphi = 2 * Pi::value / num_samples; std::vector, Eigen::aligned_allocator>> result; for(int i = 0; i < num_samples / 2; ++i) { scalar_t phi = i * dphi; if(phi > Pi::value) phi -= Pi::value; int slice_n = static_cast(std::ceil(num_samples * std::sin(phi))); if(slice_n == 0) continue; auto slice = SphereDiscretization::construct( radius * std::sin(phi), slice_n); Eigen::Matrix v; for(const auto& p : slice) { v[0] = radius * std::cos(phi); v.template tail() = p; result.push_back(v); } } return result; } }; /// Two-dimensional base case of the discretization. template struct SphereDiscretization { /// Construct a randomized discretization. template static std::vector, Eigen::aligned_allocator>> construct( scalar_t radius, int num_samples, generator_t& generator) { scalar_t dphi = 2 * Pi::value / num_samples; std::uniform_real_distribution distribution(0, 2 * Pi::value); scalar_t offset = distribution(generator); std::vector, Eigen::aligned_allocator>> result; for(int i = 0; i < num_samples; ++i) { scalar_t phi = i * dphi + offset; result.emplace_back(radius * std::cos(phi), radius * std::sin(phi)); } return result; } /// Construct the discretization. static std::vector, Eigen::aligned_allocator>> construct( scalar_t radius, int num_samples) { scalar_t dphi = 2 * Pi::value / num_samples; std::vector, Eigen::aligned_allocator>> result; for(int i = 0; i < num_samples; ++i) { scalar_t phi = i * dphi; result.emplace_back(radius * std::cos(phi), radius * std::sin(phi)); } return result; } }; /// One-dimensional base case of the discretization. template struct SphereDiscretization { template /// Construct a randomized discretization. static std::vector, Eigen::aligned_allocator>> construct( scalar_t radius, int, generator_t&) { return { Eigen::Matrix(-radius), Eigen::Matrix(radius) }; } /// Construct the discretization. static std::vector, Eigen::aligned_allocator>> construct( scalar_t radius, int) { return { Eigen::Matrix(-radius), Eigen::Matrix(radius) }; } }; };