libcruft-util/cruft/util/geom/sample/volume.hpp

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;
};
}