109 lines
2.9 KiB
C++
109 lines
2.9 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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-2018 Danny Robson <danny@nerdcruft.net>
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "../../coord/fwd.hpp"
|
|
#include "../../extent.hpp"
|
|
#include "../../random.hpp"
|
|
|
|
#include "../ops.hpp"
|
|
|
|
#include <cstddef>
|
|
#include <random>
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
namespace cruft::geom::sample {
|
|
///////////////////////////////////////////////////////////////////////
|
|
/// A convenience function that calls sample::fn to select a random
|
|
/// point in a provided shape.
|
|
///
|
|
/// This function is useful because we can perform use partial
|
|
/// specialisation if we pass the functionality off to a well known
|
|
/// class.
|
|
template <
|
|
typename ShapeT,
|
|
typename GeneratorT // random generator
|
|
>
|
|
auto
|
|
eval (ShapeT const &shape, GeneratorT &&gen)
|
|
{
|
|
volume query (shape);
|
|
return query.eval (std::forward<GeneratorT> (gen));
|
|
}
|
|
|
|
|
|
/// A function object that selects a uniformly random point inside a
|
|
/// shape using a provided random generator. The point will lie
|
|
/// within the shape, inclusive of boundaries.
|
|
///
|
|
/// This should be specialised for anything complex, but will work
|
|
/// (with a varying performance hit) for anything that provides
|
|
/// bounds` and `intersects`.
|
|
template <typename ShapeT>
|
|
class volume {
|
|
public:
|
|
using shape_type = ShapeT;
|
|
|
|
explicit volume (shape_type&&) = delete;
|
|
explicit volume (shape_type const &target):
|
|
m_target (target)
|
|
{ ; }
|
|
|
|
|
|
/// Returns a point which lies within the supplied shape, inclusive
|
|
/// of borders.
|
|
///
|
|
template <typename GeneratorT>
|
|
auto
|
|
eval (GeneratorT &&g) const
|
|
{
|
|
auto b = bounds (m_target);
|
|
|
|
while (true) {
|
|
auto p = ::cruft::geom::sample::eval (b, g);
|
|
if (intersects (m_target, p))
|
|
return p;
|
|
}
|
|
}
|
|
|
|
private:
|
|
ShapeT const &m_target;
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
/// A specialisation of the volume sampler for extents.
|
|
template <size_t S, typename T>
|
|
class volume<cruft::extent<S,T>> {
|
|
public:
|
|
using shape_type = extent<S,T>;
|
|
|
|
explicit volume (shape_type&&) = delete;
|
|
explicit volume (shape_type const &target):
|
|
m_target (target)
|
|
{ ; }
|
|
|
|
|
|
template <typename GeneratorT>
|
|
auto
|
|
eval (GeneratorT &&gen) const noexcept
|
|
{
|
|
cruft::point<S,T> p;
|
|
|
|
for (size_t i = 0; i < S; ++i)
|
|
p[i] = random::uniform (T{0}, m_target[i], gen);
|
|
|
|
return p;
|
|
}
|
|
|
|
private:
|
|
shape_type const &m_target;
|
|
};
|
|
} |