/* * 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 */ #pragma once #include "fwd.hpp" #include "../../extent.hpp" #include "../../region.hpp" namespace cruft::geom::sample { template struct edge> { using shape_type = cruft::extent2; edge (shape_type _shape) : m_shape (_shape) { ; } template point2 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 struct edge> { using shape_type = cruft::region2; edge (shape_type _shape) : m_shape (_shape) { ; } template decltype(auto) eval (GeneratorT &&gen) { return edge (m_shape.e).eval ( std::forward (gen) ) + m_shape.p.template as (); } private: shape_type m_shape; }; }