91 lines
2.6 KiB
C++
91 lines
2.6 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 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) ? h : 0;
|
||
|
return { _w, _h };
|
||
|
}
|
||
|
|
||
|
pos -= w;
|
||
|
|
||
|
auto const _w = cruft::random::uniform (1) ? 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;
|
||
|
};
|
||
|
}
|