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
|
* 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/.
|
* 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>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef CRUFT_UTIL_GEOM_AABB_HPP
|
|
||||||
#define CRUFT_UTIL_GEOM_AABB_HPP
|
|
||||||
|
|
||||||
#include "../debug.hpp"
|
#include "../debug.hpp"
|
||||||
#include "../extent.hpp"
|
#include "../extent.hpp"
|
||||||
@ -16,6 +14,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::geom {
|
namespace cruft::geom {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// represents an axis-aligned bounding-box through two opposing corners.
|
/// represents an axis-aligned bounding-box through two opposing corners.
|
||||||
@ -144,19 +143,18 @@ namespace cruft::geom {
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
namespace cruft::geom {
|
namespace cruft::geom {
|
||||||
template <size_t S, typename T, typename G>
|
template <size_t S, typename T>
|
||||||
struct sampler<S,T,aabb,G> {
|
struct sampler<aabb<S,T>> {
|
||||||
static point<S,T>
|
template <typename GeneratorT>
|
||||||
fn (aabb<S,T> b, G &g)
|
static auto
|
||||||
|
eval (aabb<S,T> shape, GeneratorT &g)
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<T> d;
|
point<S,T> res;
|
||||||
|
|
||||||
point<S,T> p;
|
for (size_t i = 0; i < S; ++i)
|
||||||
std::generate (p.begin (), p.end (), [&] (void) { return d (g); });
|
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>
|
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UTIL_GEOM_ELLIPSE_HPP
|
#pragma once
|
||||||
#define __UTIL_GEOM_ELLIPSE_HPP
|
|
||||||
|
|
||||||
#include "fwd.hpp"
|
#include "fwd.hpp"
|
||||||
|
|
||||||
@ -145,22 +144,54 @@ namespace cruft::geom {
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
namespace cruft::geom {
|
namespace cruft::geom {
|
||||||
template <typename T, template <size_t,typename> class K, typename G>
|
/// Specialisation for uniform sampling of ellipses
|
||||||
struct sampler<2,T,K,G>
|
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>;
|
// TODO: We assume floating point for the time being because it
|
||||||
float rho = std::sqrt (dist (g));
|
// 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::cos (phi),
|
||||||
std::sin (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
|
#endif
|
||||||
|
}
|
||||||
|
@ -6,17 +6,18 @@
|
|||||||
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UTIL_GEOM_SAMPLE_HPP
|
#pragma once
|
||||||
#define __UTIL_GEOM_SAMPLE_HPP
|
|
||||||
|
|
||||||
#include "../coord/fwd.hpp"
|
#include "../coord/fwd.hpp"
|
||||||
#include "../extent.hpp"
|
#include "../extent.hpp"
|
||||||
|
#include "../random.hpp"
|
||||||
|
|
||||||
#include "ops.hpp"
|
#include "ops.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
namespace cruft::geom {
|
namespace cruft::geom {
|
||||||
/// a function object that selects a uniformly random point inside a shape
|
/// 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
|
/// may be specialised for arbitrary shapes but uses rejection sampling
|
||||||
/// as a safe default. this implies that execution may not take a constant
|
/// as a safe default. this implies that execution may not take a constant
|
||||||
/// time.
|
/// time.
|
||||||
///
|
template <typename ShapeT>
|
||||||
/// \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
|
|
||||||
>
|
|
||||||
struct sampler {
|
struct sampler {
|
||||||
static point<S,T>
|
/// Returns a point which lies within the supplied shape, inclusive
|
||||||
fn (K<S,T> k, G &g)
|
/// of borders.
|
||||||
|
template <typename GeneratorT>
|
||||||
|
static auto
|
||||||
|
eval (ShapeT const &shape, GeneratorT &&g)
|
||||||
{
|
{
|
||||||
auto b = bounds (k);
|
auto b = bounds (shape);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto p = sample (b, g);
|
auto p = sample (b, g);
|
||||||
if (intersects (k, p))
|
if (intersects (shape, p))
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,15 +50,13 @@ namespace cruft::geom {
|
|||||||
/// a convenience function that calls sample::fn to select a random point
|
/// a convenience function that calls sample::fn to select a random point
|
||||||
/// in a provided shape.
|
/// in a provided shape.
|
||||||
template <
|
template <
|
||||||
size_t S,
|
typename ShapeT,
|
||||||
typename T,
|
typename GeneratorT // random generator
|
||||||
template <size_t,typename> class K,
|
|
||||||
typename G // random generator
|
|
||||||
>
|
>
|
||||||
point<S,T>
|
auto
|
||||||
sample (K<S,T> k, G &g)
|
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;
|
cruft::point<S,T> p;
|
||||||
|
|
||||||
for (size_t i = 0; i < S; ++i) {
|
for (size_t i = 0; i < S; ++i)
|
||||||
if constexpr (std::is_floating_point_v<T>) {
|
p[i] = random::uniform (T{0}, target[i], gen);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
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
|
* 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/.
|
* 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
|
#pragma once
|
||||||
#define CRUFT_UTIL_RANDOM_HPP
|
|
||||||
|
|
||||||
#include "coord/traits.hpp"
|
#include "coord/traits.hpp"
|
||||||
|
|
||||||
@ -19,9 +18,16 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace cruft::random {
|
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;
|
struct state_size;
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
template <
|
template <
|
||||||
class UIntType,
|
class UIntType,
|
||||||
size_t w, size_t n, size_t m, size_t r,
|
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);
|
static constexpr auto value = n * sizeof (UIntType);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
template <typename UIntType, UIntType a, UIntType c, UIntType m>
|
template <typename UIntType, UIntType a, UIntType c, UIntType m>
|
||||||
struct state_size<std::linear_congruential_engine<UIntType,a,c,m>> {
|
struct state_size<std::linear_congruential_engine<UIntType,a,c,m>> {
|
||||||
static constexpr auto value = sizeof (UIntType);
|
static constexpr auto value = sizeof (UIntType);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr auto state_size_v = state_size<T>::value;
|
constexpr auto state_size_v = state_size<T>::value;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// return correctly initialised thread-local generator of an unspecified,
|
/// Returns a correctly pre-initialised reference to a thread-local
|
||||||
/// but not entirely useless, type. ie, not LCG.
|
/// generator of an unspecified (but not entirely useless) type.
|
||||||
|
///
|
||||||
|
/// ie, not LCG.
|
||||||
inline auto&
|
inline auto&
|
||||||
generator (void)
|
generator (void)
|
||||||
{
|
{
|
||||||
@ -61,72 +74,91 @@ namespace cruft::random {
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// select a value uniformly from the range [lo, hi)
|
/// A convenience typedef that selects between
|
||||||
template <typename T>
|
/// std::uniform_real_distribution and std::uniform_int_distribution
|
||||||
std::enable_if_t<std::is_floating_point_v<T>,T>
|
/// depending on the supplied value type.
|
||||||
uniform (T lo, T hi)
|
template <typename ValueT>
|
||||||
{
|
using uniform_distribution = std::conditional_t<
|
||||||
return std::uniform_real_distribution<T> { lo, hi } (generator ());
|
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>
|
/// Returns a value chosen uniformly at random the supplied range.
|
||||||
uniform (void)
|
///
|
||||||
|
/// 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
|
/// Return a value uniformly random chosen value between lo and hi.
|
||||||
/// generator
|
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 <
|
template <
|
||||||
typename T,
|
typename ValueT,
|
||||||
typename GeneratorT,
|
typename GeneratorT,
|
||||||
typename = std::enable_if_t<std::is_integral_v<T>>
|
typename = std::enable_if_t<std::is_floating_point_v<ValueT>>
|
||||||
>
|
>
|
||||||
T
|
auto uniform (GeneratorT &&gen)
|
||||||
uniform (T lo, T hi, 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)
|
/// Return a uniformly random chosen value on the interval [0.f, 1.f)
|
||||||
template <typename T>
|
template <
|
||||||
std::enable_if_t<std::is_integral_v<T>,T>
|
typename ValueT,
|
||||||
uniform (T lo, T hi)
|
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>
|
template <typename T>
|
||||||
std::enable_if_t<std::is_integral_v<T>,T>
|
std::enable_if_t<std::is_integral_v<T>,T>
|
||||||
uniform (void)
|
uniform (void)
|
||||||
{
|
{
|
||||||
return uniform (
|
return uniform<T> (
|
||||||
std::numeric_limits<T>::min (),
|
std::numeric_limits<T>::min (),
|
||||||
std::numeric_limits<T>::max ()
|
std::numeric_limits<T>::max ()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
///------------------------------------------------------------------------
|
||||||
|
/// Returns a uniformly random initialised coordinate type by value.
|
||||||
template <
|
template <
|
||||||
typename T,
|
typename ValueT,
|
||||||
typename = std::enable_if_t<
|
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)
|
uniform (void)
|
||||||
{
|
{
|
||||||
T res {};
|
ValueT res {};
|
||||||
std::fill (res.begin (), res.end (), uniform<typename T::value_type> ());
|
std::fill (res.begin (), res.end (), uniform<typename ValueT::value_type> ());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,5 +173,3 @@ namespace cruft::random {
|
|||||||
return t[dist (generator ())];
|
return t[dist (generator ())];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Loading…
Reference in New Issue
Block a user