diff --git a/geom/sample/surface.hpp b/geom/sample/surface.hpp index 8ffc3927..63c367b1 100644 --- a/geom/sample/surface.hpp +++ b/geom/sample/surface.hpp @@ -30,16 +30,29 @@ namespace cruft::geom::sample { /// best of a set of candidates. The 'best' is the point that is /// furthest from all selected points. /// + /// \tparam SamplerT A surface sampler + /// \tparam DistanceT The type of point-to-point distances + /// \tparam GeneratorT The random generator passed to the sampler + /// \tparam AcceptT A unary bool function that returns true if a sampled + /// point is permissible. The point is counted in the candidate set + /// regardless. + /// /// \return A vector of the computed points - template + template < + typename SamplerT, + typename DistanceT, + typename GeneratorT, + typename AcceptT + > auto - poisson (SamplerT const &target, - GeneratorT &&gen, - DistanceT &&minimum_distance, - size_t candidates_count) - - { - using point_type = decltype (target.eval (gen)); + poisson ( + SamplerT const &sampler, + GeneratorT &&gen, + AcceptT &&accept, + DistanceT &&minimum_distance, + std::size_t candidates_count + ) { + using point_type = decltype (sampler.eval (gen)); using value_type = typename point_type::value_type; std::vector selected; @@ -47,7 +60,7 @@ namespace cruft::geom::sample { // prime the found elements list with an initial point we can // perform distance calculations on - selected.push_back (target.eval (gen)); + selected.push_back (sampler.eval (gen)); // keep trying to add one more new point while (1) { @@ -57,10 +70,16 @@ namespace cruft::geom::sample { std::back_inserter (candidates), candidates_count, [&] (void) { - return target.eval (gen); + return sampler.eval (gen); } ); + // Remove points that aren't acceptable + std::erase_if ( + candidates, + [&] (auto const &p) { return !accept (p); } + ); + // find the point whose minimum distance to the existing // points is the greatest (while also being greater than the // required minimum distance); @@ -95,6 +114,30 @@ namespace cruft::geom::sample { } + /// A convenience function that forwards to poisson with unconditional + /// point acceptance. + template < + typename SamplerT, + typename DistanceT, + typename GeneratorT + > + auto + poisson ( + SamplerT &&sampler, + GeneratorT &&gen, + DistanceT &&minimum_distance, + std::size_t candidates_count + ) { + return poisson ( + std::forward (sampler), + std::forward (gen), + [] (auto&&...) { return true; }, + std::forward (minimum_distance), + candidates_count + ); + } + + /// A surface sampler specialisation for 2d extents. /// /// The actual work is handed off to the volume sampler, as it's