geom: remove template templates from geom::sampler
This commit is contained in:
parent
e26165cea9
commit
210c963d9f
@ -3,12 +3,10 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRUFT_UTIL_GEOM_AABB_HPP
|
||||
#define CRUFT_UTIL_GEOM_AABB_HPP
|
||||
#pragma once
|
||||
|
||||
#include "../debug.hpp"
|
||||
#include "../extent.hpp"
|
||||
@ -16,6 +14,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace cruft::geom {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// represents an axis-aligned bounding-box through two opposing corners.
|
||||
@ -144,19 +143,18 @@ namespace cruft::geom {
|
||||
#include <random>
|
||||
|
||||
namespace cruft::geom {
|
||||
template <size_t S, typename T, typename G>
|
||||
struct sampler<S,T,aabb,G> {
|
||||
static point<S,T>
|
||||
fn (aabb<S,T> b, G &g)
|
||||
template <size_t S, typename T>
|
||||
struct sampler<aabb<S,T>> {
|
||||
template <typename GeneratorT>
|
||||
static auto
|
||||
eval (aabb<S,T> shape, GeneratorT &g)
|
||||
{
|
||||
std::uniform_real_distribution<T> d;
|
||||
point<S,T> res;
|
||||
|
||||
point<S,T> p;
|
||||
std::generate (p.begin (), p.end (), [&] (void) { return d (g); });
|
||||
for (size_t i = 0; i < S; ++i)
|
||||
res[i] = cruft::random::uniform (shape.lo[i], shape.hi[i], g);
|
||||
|
||||
return p * (b.hi - b.lo) + b.lo.template as<cruft::vector> ();
|
||||
return res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,8 +6,7 @@
|
||||
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_GEOM_ELLIPSE_HPP
|
||||
#define __UTIL_GEOM_ELLIPSE_HPP
|
||||
#pragma once
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
@ -145,22 +144,54 @@ namespace cruft::geom {
|
||||
#include <random>
|
||||
|
||||
namespace cruft::geom {
|
||||
template <typename T, template <size_t,typename> class K, typename G>
|
||||
struct sampler<2,T,K,G>
|
||||
/// Specialisation for uniform sampling of ellipses
|
||||
template <typename T>
|
||||
struct sampler<ellipse<2,T>>
|
||||
{
|
||||
static cruft::point<2,T> fn (K<2,T> k, G &g)
|
||||
/// Generate a random point within the ellipse.
|
||||
template <typename GeneratorT>
|
||||
static auto
|
||||
eval (ellipse<2,T> shape, GeneratorT &&g)
|
||||
{
|
||||
std::uniform_real_distribution<T> dist;
|
||||
// We use a two step process:
|
||||
// * Generate a point within a unit sphere
|
||||
// * Transform the point to an ellipse.
|
||||
|
||||
float phi = dist (g) * 2 * pi<T>;
|
||||
float rho = std::sqrt (dist (g));
|
||||
// TODO: We assume floating point for the time being because it
|
||||
// simplifies interaction with trig routines. There's no
|
||||
// intrinsic reason for this limitation though.
|
||||
static_assert (
|
||||
std::is_floating_point_v<T>,
|
||||
"The current implementation assumes floating point."
|
||||
);
|
||||
|
||||
return cruft::point<2,T> {
|
||||
// Choose a direction and a distance within the unit circle.
|
||||
//
|
||||
// `sqrt` of the distance is used to ensure a uniform
|
||||
// distribution.
|
||||
T phi = random::uniform<T> (g) * 2 * pi<T>;
|
||||
T rho = std::sqrt (random::uniform<T> (g));
|
||||
|
||||
cruft::point2<T> const circle_pos {
|
||||
std::cos (phi),
|
||||
std::sin (phi)
|
||||
} * rho * k.radius + k.origin.template as<cruft::vector> ();
|
||||
};
|
||||
|
||||
auto const offset = circle_pos * rho * shape.radius;
|
||||
return shape.origin + offset.template as<cruft::vector> ();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// TODO: We should implement a higher dimensional ellipsoid sampler for
|
||||
// efficiency gains over rejection sampling that we currently use.
|
||||
template <typename T>
|
||||
struct sampler<ellipse<3,T>>
|
||||
{
|
||||
template <typename GeneratorT>
|
||||
static cruft::point<3,T>
|
||||
eval (ellipse<3,T>, GeneratorT&&);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
@ -6,17 +6,18 @@
|
||||
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_GEOM_SAMPLE_HPP
|
||||
#define __UTIL_GEOM_SAMPLE_HPP
|
||||
#pragma once
|
||||
|
||||
#include "../coord/fwd.hpp"
|
||||
#include "../extent.hpp"
|
||||
#include "../random.hpp"
|
||||
|
||||
#include "ops.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <random>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace cruft::geom {
|
||||
/// a function object that selects a uniformly random point inside a shape
|
||||
@ -26,26 +27,19 @@ namespace cruft::geom {
|
||||
/// may be specialised for arbitrary shapes but uses rejection sampling
|
||||
/// as a safe default. this implies that execution may not take a constant
|
||||
/// time.
|
||||
///
|
||||
/// \tparam S coordinate type dimension
|
||||
/// \tparam T value type for the shape/coordinate
|
||||
/// \tparam K the shape type to test
|
||||
/// \tparam G a UniformRandomBitGenerator, eg std::min19937
|
||||
template <
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class K,
|
||||
typename G
|
||||
>
|
||||
template <typename ShapeT>
|
||||
struct sampler {
|
||||
static point<S,T>
|
||||
fn (K<S,T> k, G &g)
|
||||
/// Returns a point which lies within the supplied shape, inclusive
|
||||
/// of borders.
|
||||
template <typename GeneratorT>
|
||||
static auto
|
||||
eval (ShapeT const &shape, GeneratorT &&g)
|
||||
{
|
||||
auto b = bounds (k);
|
||||
auto b = bounds (shape);
|
||||
|
||||
while (true) {
|
||||
auto p = sample (b, g);
|
||||
if (intersects (k, p))
|
||||
if (intersects (shape, p))
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@ -56,15 +50,13 @@ namespace cruft::geom {
|
||||
/// a convenience function that calls sample::fn to select a random point
|
||||
/// in a provided shape.
|
||||
template <
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class K,
|
||||
typename G // random generator
|
||||
typename ShapeT,
|
||||
typename GeneratorT // random generator
|
||||
>
|
||||
point<S,T>
|
||||
sample (K<S,T> k, G &g)
|
||||
auto
|
||||
sample (ShapeT const &shape, GeneratorT &&gen)
|
||||
{
|
||||
return sampler<S,T,K,G>::fn (k, g);
|
||||
return sampler<ShapeT>::eval (shape, std::forward<GeneratorT> (gen));
|
||||
}
|
||||
|
||||
|
||||
@ -95,14 +87,8 @@ namespace cruft::geom {
|
||||
{
|
||||
cruft::point<S,T> p;
|
||||
|
||||
for (size_t i = 0; i < S; ++i) {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
p[i] = std::uniform_real_distribution<T> (0, target[i]) (gen);
|
||||
} else {
|
||||
CHECK_GE (target[i], T{1});
|
||||
p[i] = std::uniform_int_distribution<T> (0, target[i] - 1) (gen);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < S; ++i)
|
||||
p[i] = random::uniform (T{0}, target[i], gen);
|
||||
|
||||
return p;
|
||||
}
|
||||
@ -182,5 +168,3 @@ namespace cruft::geom {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
108
random.hpp
108
random.hpp
@ -3,11 +3,10 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2016-2017 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2016-2018 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef CRUFT_UTIL_RANDOM_HPP
|
||||
#define CRUFT_UTIL_RANDOM_HPP
|
||||
#pragma once
|
||||
|
||||
#include "coord/traits.hpp"
|
||||
|
||||
@ -19,9 +18,16 @@
|
||||
|
||||
|
||||
namespace cruft::random {
|
||||
template <typename T>
|
||||
/// A trait describing the internal state size of a given Generator.
|
||||
///
|
||||
/// The structure must be specialised.
|
||||
///
|
||||
/// \tparam GeneratorT The generator to query
|
||||
template <typename GeneratorT>
|
||||
struct state_size;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <
|
||||
class UIntType,
|
||||
size_t w, size_t n, size_t m, size_t r,
|
||||
@ -32,17 +38,24 @@ namespace cruft::random {
|
||||
static constexpr auto value = n * sizeof (UIntType);
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename UIntType, UIntType a, UIntType c, UIntType m>
|
||||
struct state_size<std::linear_congruential_engine<UIntType,a,c,m>> {
|
||||
static constexpr auto value = sizeof (UIntType);
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
constexpr auto state_size_v = state_size<T>::value;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// return correctly initialised thread-local generator of an unspecified,
|
||||
/// but not entirely useless, type. ie, not LCG.
|
||||
/// Returns a correctly pre-initialised reference to a thread-local
|
||||
/// generator of an unspecified (but not entirely useless) type.
|
||||
///
|
||||
/// ie, not LCG.
|
||||
inline auto&
|
||||
generator (void)
|
||||
{
|
||||
@ -61,72 +74,91 @@ namespace cruft::random {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// select a value uniformly from the range [lo, hi)
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_floating_point_v<T>,T>
|
||||
uniform (T lo, T hi)
|
||||
{
|
||||
return std::uniform_real_distribution<T> { lo, hi } (generator ());
|
||||
}
|
||||
/// A convenience typedef that selects between
|
||||
/// std::uniform_real_distribution and std::uniform_int_distribution
|
||||
/// depending on the supplied value type.
|
||||
template <typename ValueT>
|
||||
using uniform_distribution = std::conditional_t<
|
||||
std::is_floating_point<ValueT>::value,
|
||||
std::uniform_real_distribution<ValueT>,
|
||||
std::uniform_int_distribution<ValueT>
|
||||
>;
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_floating_point_v<T>,T>
|
||||
uniform (void)
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Returns a value chosen uniformly at random the supplied range.
|
||||
///
|
||||
/// This is primarily a convenience helper around the uniform_distribution
|
||||
/// type.
|
||||
template <typename ValueT, typename GeneratorT>
|
||||
auto
|
||||
uniform (ValueT lo, ValueT hi, GeneratorT &&gen)
|
||||
{
|
||||
return uniform<T> (0, 1);
|
||||
return uniform_distribution<ValueT> { lo, hi } (gen);
|
||||
}
|
||||
|
||||
|
||||
///------------------------------------------------------------------------
|
||||
/// select a value uniformly from the range [lo, hi) using a supplied
|
||||
/// generator
|
||||
/// Return a value uniformly random chosen value between lo and hi.
|
||||
template <typename T>
|
||||
auto
|
||||
uniform (T lo, T hi)
|
||||
{
|
||||
return uniform<T> (lo, hi, generator ());
|
||||
}
|
||||
|
||||
|
||||
///------------------------------------------------------------------------
|
||||
/// Return a uniformly random value chosen on the interval [0,1)
|
||||
template <
|
||||
typename T,
|
||||
typename ValueT,
|
||||
typename GeneratorT,
|
||||
typename = std::enable_if_t<std::is_integral_v<T>>
|
||||
typename = std::enable_if_t<std::is_floating_point_v<ValueT>>
|
||||
>
|
||||
T
|
||||
uniform (T lo, T hi, GeneratorT &&gen)
|
||||
auto uniform (GeneratorT &&gen)
|
||||
{
|
||||
return std::uniform_int_distribution<T> { lo, hi } (gen);
|
||||
return uniform<ValueT> (ValueT{0}, ValueT{1}, std::forward<GeneratorT> (gen));
|
||||
}
|
||||
|
||||
|
||||
///------------------------------------------------------------------------
|
||||
/// select a value uniformly from the range [lo, hi)
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_integral_v<T>,T>
|
||||
uniform (T lo, T hi)
|
||||
/// Return a uniformly random chosen value on the interval [0.f, 1.f)
|
||||
template <
|
||||
typename ValueT,
|
||||
typename = std::enable_if_t<std::is_floating_point_v<ValueT>>
|
||||
>
|
||||
auto uniform (void)
|
||||
{
|
||||
return uniform (lo, hi, generator ());
|
||||
return uniform<ValueT> (ValueT{0}, ValueT{1}, generator ());
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
///------------------------------------------------------------------------
|
||||
/// Return a uniformly random chosen value on the interval [0, 1]
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_integral_v<T>,T>
|
||||
uniform (void)
|
||||
{
|
||||
return uniform (
|
||||
return uniform<T> (
|
||||
std::numeric_limits<T>::min (),
|
||||
std::numeric_limits<T>::max ()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
///------------------------------------------------------------------------
|
||||
/// Returns a uniformly random initialised coordinate type by value.
|
||||
template <
|
||||
typename T,
|
||||
typename ValueT,
|
||||
typename = std::enable_if_t<
|
||||
is_coord_v<T> && std::is_floating_point_v<typename T::value_type>
|
||||
is_coord_v<ValueT> && std::is_floating_point_v<typename ValueT::value_type>
|
||||
>
|
||||
>
|
||||
T
|
||||
ValueT
|
||||
uniform (void)
|
||||
{
|
||||
T res {};
|
||||
std::fill (res.begin (), res.end (), uniform<typename T::value_type> ());
|
||||
ValueT res {};
|
||||
std::fill (res.begin (), res.end (), uniform<typename ValueT::value_type> ());
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -141,5 +173,3 @@ namespace cruft::random {
|
||||
return t[dist (generator ())];
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user