libcruft-util/geom/sample/subregion.hpp

63 lines
1.8 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 2020, Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include <algorithm>
#include "../../extent.hpp"
#include "../../region.hpp"
#include "../../random.hpp"
namespace cruft::geom::sample {
/// Given a desired subregion shape, and a possible field of locations,
/// select a random location for surface placement.
///
/// Valid placements allow for rotations, but are exclusive of far edges
/// for integer types.
///
/// The largest axis of the shape must not be larger than the smallest
/// axis of the placement field otherwise the chosen region may fall
/// outside the field.
class subregion {
public:
subregion (cruft::extent2i _shape, cruft::extent2i _field)
: m_shape (_shape)
, m_field (_field)
{
CHECK (all (m_shape <= m_field));
}
// Choose placements by looking at each axis in turn.
//
// We support rotations by randomising the axis ordering for the shape
// but not the field.
template <typename GeneratorT>
cruft::region2i
operator() (GeneratorT &&gen)
{
int axes[] = { 0, 1 };
std::shuffle (std::begin (axes), std::end (axes), gen);
cruft::region2i res;
for (int i = 0; i < std::ssize (axes); ++i) {
res.e[i] = m_shape[axes[i]];
res.p[i] = cruft::random::uniform (m_field[i] - res.e[i]);
}
return res;
}
private:
cruft::extent2i m_shape;
cruft::extent2i m_field;
};
}