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

91 lines
2.6 KiB
C++
Raw Normal View History

/*
* 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 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "fwd.hpp"
#include "../../extent.hpp"
#include "../../region.hpp"
namespace cruft::geom::sample {
template <typename T>
struct edge<cruft::extent2<T>> {
using shape_type = cruft::extent2<T>;
edge (shape_type _shape)
: m_shape (_shape)
{ ; }
template <typename GeneratorT>
point2<T>
eval (GeneratorT &&gen)
{
// Generate a point at some point along the perimeter.
//
// Unwind half the perimeter with length `w + h - 1`.
// This gives us the full length of the width, and subtract one of
// the extreme axis on the height side that is covered by the full
// width case.
//
// If we're in the first portion of the perimeter then choose if
// we're on the top/bottom randomly. And use the position as the x
// coordinate.
//
// Otherwise bump the coordinate above the baseline which was
// already covered and choose the left/right side randomly.
//
// TODO: avoid repeated calls into uniform. We can do this by
// doubling the extent we're testing and using the extra bit for
// the side test. But I'm lacking time right now.
auto const [w, h] = m_shape;
auto const len = w + h - 1;
auto pos = cruft::random::uniform (T{0}, len, gen);
if (pos <= w) {
auto const _w = pos;
auto const _h = cruft::random::uniform (1, gen) ? h : 0;
return { _w, _h };
}
pos -= w;
auto const _w = cruft::random::uniform (1, gen) ? w : 0;
auto const _h = pos;
return { _w, _h };
}
private:
shape_type m_shape;
};
template <typename T>
struct edge<cruft::region2<T>> {
using shape_type = cruft::region2<T>;
edge (shape_type _shape)
: m_shape (_shape)
{ ; }
template <typename GeneratorT>
decltype(auto)
eval (GeneratorT &&gen)
{
return edge<cruft::extent2i> (m_shape.e).eval (
std::forward<GeneratorT> (gen)
) + m_shape.p.template as<vector> ();
}
private:
shape_type m_shape;
};
}