From 0704d7e660f9faa57f4c68eb1bd95cebb921b704 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Tue, 13 Aug 2019 00:16:16 +0200 Subject: [PATCH 01/12] Add uniform_point_distribution. --- extensions/example/Jamfile.v2 | 1 + extensions/example/random/Jamfile.v2 | 16 + extensions/example/random/random_example.cpp | 78 +++ extensions/test/Jamfile.v2 | 2 +- extensions/test/random/Jamfile.v2 | 11 + extensions/test/random/random.cpp | 141 ++++ .../detail/uniform_point_distribution.hpp | 659 ++++++++++++++++++ .../dispatch/uniform_point_distribution.hpp | 71 ++ .../random/uniform_point_distribution.hpp | 67 ++ 9 files changed, 1045 insertions(+), 1 deletion(-) create mode 100644 extensions/example/random/Jamfile.v2 create mode 100644 extensions/example/random/random_example.cpp create mode 100644 extensions/test/random/Jamfile.v2 create mode 100644 extensions/test/random/random.cpp create mode 100644 include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp create mode 100644 include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp create mode 100644 include/boost/geometry/extensions/random/uniform_point_distribution.hpp diff --git a/extensions/example/Jamfile.v2 b/extensions/example/Jamfile.v2 index 8110621689..3c28f5e4fa 100644 --- a/extensions/example/Jamfile.v2 +++ b/extensions/example/Jamfile.v2 @@ -13,3 +13,4 @@ project boost-geometry-examples-extensions ; build-project gis ; +build-project random ; diff --git a/extensions/example/random/Jamfile.v2 b/extensions/example/random/Jamfile.v2 new file mode 100644 index 0000000000..6347a8eca0 --- /dev/null +++ b/extensions/example/random/Jamfile.v2 @@ -0,0 +1,16 @@ +# Boost.Geometry (aka GGL, Generic Geometry Library) +# +# Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +# Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +# Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + +project boost-geometry-example-extensions-random + : # requirements + ; + +exe random_example : random_example.cpp ; diff --git a/extensions/example/random/random_example.cpp b/extensions/example/random/random_example.cpp new file mode 100644 index 0000000000..d42f1b6102 --- /dev/null +++ b/extensions/example/random/random_example.cpp @@ -0,0 +1,78 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Random Example - showing random sampling in various geometries + +#include +#include +#include + +#include +#include + +const int samples = 100; + +template +void draw_samples(Distribution& d, Generator& g, Mapper& m) { + for (int i = 0 ; i < samples ; ++i) { + m.map(d(g), "fill-opacity:1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:1", 1); + } +} + +int main() +{ + namespace bg = boost::geometry; + typedef bg::model::point point; + typedef bg::model::segment segment; + typedef bg::model::box box; + typedef bg::model::multi_point multi_point; + typedef bg::model::polygon polygon; + + std::default_random_engine generator(1); + polygon poly; + boost::geometry::read_wkt("POLYGON((16 21,17.1226 17.5451,20.7553 17.5451,17.8164 15.4098,18.9389 11.9549,16 14.0902,13.0611 11.9549,14.1836 15.4098,11.2447 17.5451,14.8774 17.5451,16 21))", poly); + box b(point(0, 0), point(10, 10)); + segment s(point(11, 0), point(21, 10)); + multi_point mp; + for (double y = 11.0 ; y <= 21.0 ; y += 0.5) { + for(double x = 0.0 ; x <= 10.0 ; x += 0.5) { + bg::append(mp, point(x, y)); + } + } + auto box_dist = bg::random::uniform_point_distribution(b); + auto mp_dist = bg::random::uniform_point_distribution(mp); + auto seg_dist = bg::random::uniform_point_distribution(s); + auto poly_dist = bg::random::uniform_point_distribution(poly); + std::ofstream svg("random.svg"); + bg::svg_mapper mapper(svg, 720, 720); + mapper.add(poly); + mapper.add(b); + mapper.add(mp); + mapper.add(s); + mapper.add(box(point(0, 22), point(22, 35))); + mapper.map(b, "fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2"); + mapper.map(s, "fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2"); + mapper.map(mp, "fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2", 2); + mapper.map(poly, "fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2"); + draw_samples(box_dist, generator, mapper); + draw_samples(mp_dist, generator, mapper); + draw_samples(seg_dist, generator, mapper); + draw_samples(poly_dist, generator, mapper); + + typedef bg::model::point> point_spherical; + typedef bg::model::box box_spherical; + box_spherical sb(point_spherical(0, 0), point_spherical(90, 90)); + auto sb_dist = bg::random::uniform_point_distribution(sb); + for (int i = 0 ; i < 10*samples ; ++i) { + point_spherical p = sb_dist(generator); + double x = bg::get<0>(p) / 90 * 22; + double y = 32 - bg::get<1>(p) / 90 * 10; + mapper.map(point(x,y), "fill-opacity:1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:1", 1); + } + return 0; +} diff --git a/extensions/test/Jamfile.v2 b/extensions/test/Jamfile.v2 index f35b9a1f95..31a228cba8 100644 --- a/extensions/test/Jamfile.v2 +++ b/extensions/test/Jamfile.v2 @@ -27,4 +27,4 @@ build-project algorithms ; build-project gis ; build-project iterators ; build-project nsphere ; - +build-project random ; diff --git a/extensions/test/random/Jamfile.v2 b/extensions/test/random/Jamfile.v2 new file mode 100644 index 0000000000..fcd3e40938 --- /dev/null +++ b/extensions/test/random/Jamfile.v2 @@ -0,0 +1,11 @@ +# Boost.Geometry (aka GGL, Generic Geometry Library) +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +test-suite boost-geometry-extensions-random + : + [ run random.cpp ] + ; + diff --git a/extensions/test/random/random.cpp b/extensions/test/random/random.cpp new file mode 100644 index 0000000000..19d580efa0 --- /dev/null +++ b/extensions/test/random/random.cpp @@ -0,0 +1,141 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include + +#include +#include + +namespace bg = boost::geometry; + +using point2d_cart = bg::model::point; +using point3d_cart = bg::model::point; +using point2d_geog = + bg::model::point>; + +void test_geographic() +{ + //We check whether the generated points lie roughly along + //the great circle segment (<2 km distance on a sphere with + //the radius of earth) and are distributed uniformly with respect + //to great circle arc length. + using linestring = bg::model::linestring; + linestring ls {{ 0.0, 0.0 }, { 45.0, 45.0 }, { 60.0, 60.0 }}; + auto l_dist = bg::random::uniform_point_distribution(ls); + std::mt19937 generator(0); + int sample_count = 2000; + int count_below_45 = 0; + for(int i = 0 ; i < sample_count ; ++i) { + point2d_geog sample = l_dist(generator); + BOOST_CHECK( bg::distance(sample, ls) < 2000 ); + if(bg::get<0>(sample) < 45.0) count_below_45++; + } + double length_ratio = bg::distance(ls[0], ls[1]) / + ( bg::distance(ls[0], ls[1]) + bg::distance(ls[1], ls[2]) ); + double sample_ratio = ((double) count_below_45) / sample_count; + bool in_range = sample_ratio * 0.95 < length_ratio + && sample_ratio * 1.05 > length_ratio; + BOOST_CHECK( in_range ); + + //We check whether the generated points lie in the spherical box + //(which is actually a triangle in this case) and whether the latitude + //is distributed as expected for uniform spherical distribution, using + //known area ratios of spherical caps. + using box = bg::model::box; + box b {{ 0.0, 0.0 }, { 90.0, 90.0 }}; + auto b_dist = bg::random::uniform_point_distribution(b); + int under_60 = 0; + for(int i = 0 ; i < sample_count; ++i) { + point2d_geog sample = b_dist(generator); + BOOST_CHECK( bg::within(sample, b) ); + if(bg::get<1>(sample) < 60.0) ++under_60; + } + BOOST_CHECK_GT(under_60, 0.5 * 0.95 * sample_count); + BOOST_CHECK_LT(under_60, 0.5 * 1.05 * sample_count); +} + +void test_polygon() +{ + //This test will test uniform sampling in polygon, which also checks + //uniform sampling in boxes. We check whether two equal distributions + //(copied using operator<< and operator>>) generate the same sequence + //of points and whether those points are uniformly distributed with + //respect to cartesian area. + using polygon = bg::model::polygon; + polygon poly; + bg::read_wkt( + "POLYGON((16 21,17.1226 17.5451,20.7553 17.5451, 17.8164 15.4098,18.9389 11.9549,16 14.0902,13.0611 11.9549, 14.1836 15.4098,11.2447 17.5451,14.8774 17.5451,16 21))", + poly); + auto poly_dist = bg::random::uniform_point_distribution(poly); + decltype(poly_dist) poly_dist2; + BOOST_CHECK( !(poly_dist == poly_dist2) ); + std::stringstream ss; + ss << poly_dist; + ss >> poly_dist2; + BOOST_CHECK( poly_dist == poly_dist2 ); + std::mt19937 generator(0), generator2(0); + for(int i = 0; i < 100 ; ++i) { + point2d_cart sample1 = poly_dist(generator); + BOOST_CHECK( bg::equals(sample1, poly_dist2(generator2)) ); + BOOST_CHECK( bg::within(sample1, poly) ); + } + std::vector randoms; + const int uniformity_test_samples = 2000; + for(int i = 0; i < uniformity_test_samples ; ++i) { + randoms.push_back(poly_dist(generator)); + } + using box = bg::model::box; + box env, lhalf; + bg::envelope(poly, env); + bg::set(lhalf, bg::get(env)); + bg::set(lhalf, bg::get(env)); + bg::set(lhalf, bg::get(env)); + bg::set(lhalf, + (bg::get(env) + bg::get(env)) / 2); + std::vector lower; + bg::intersection(lhalf, poly, lower); + double area_ratio = bg::area(lower[0])/bg::area(poly); + int in_lower = 0; + for(int i = 0 ; i < uniformity_test_samples ; ++i) { + if(bg::within(randoms[i], lhalf)) + ++in_lower; + } + double sample_ratio = ((double) in_lower ) / uniformity_test_samples; + BOOST_CHECK_GT( sample_ratio * 1.05, area_ratio ); + BOOST_CHECK_LT( sample_ratio * 0.95, area_ratio ); +} + +void test_multipoint() +{ + using multipoint = bg::model::multi_point; + multipoint mp {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}}; + int first = 0; + auto mp_dist = bg::random::uniform_point_distribution(mp); + std::mt19937 generator(0); + int sample_count = 1000; + for(int i = 0 ; i < sample_count ; ++i) { + point3d_cart sample = mp_dist(generator); + BOOST_CHECK( bg::within(sample, mp) ); + if(bg::equals(sample, mp[0])) ++first; + } + BOOST_CHECK_GT(first * 1.05, sample_count / 3); + BOOST_CHECK_LT(first * 0.95, sample_count / 3); +} + +int test_main(int, char* []) +{ + test_polygon(); + test_geographic(); + test_multipoint(); + return 0; +} diff --git a/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp new file mode 100644 index 0000000000..174212f579 --- /dev/null +++ b/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp @@ -0,0 +1,659 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_DETAIL_UNIFORM_POINT_DISTRIBUTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_DETAIL_UNIFORM_POINT_DISTRIBUTION_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { namespace geometry { namespace random { namespace detail +{ + +template +class uniform_point_distribution_base +{ +public: + typedef Point result_type; + class param_type { + public: + param_type(DomainGeometry const& domain):_domain(domain) {} + param_type(param_type const& p):_domain(p._domain) {} + DomainGeometry const& domain() const {return _domain;} + bool operator==(param_type const& rhs) const + { + return equals(_domain,rhs._domain); + } + private: + DomainGeometry _domain; + }; + uniform_point_distribution_base():_param(DomainGeometry()) {} + uniform_point_distribution_base(param_type const& param):_param(param) {} + uniform_point_distribution_base(DomainGeometry const& domain) : + _param(param_type(domain)) {} + void reset() {} + param_type param() const {return _param;} + DomainGeometry const& domain() const {return _param.domain();} + bool operator==(uniform_point_distribution_base const& rhs) const + { + return _param==rhs._param; + } + void param(param_type const& p) {_param = p;} +protected: + param_type _param; +}; + +template +< + typename Point, + typename DomainGeometry, + typename DomainTag, + typename SingleOrMulti, + typename CSTag, + std::size_t dimension +> +class uniform_point_distribution {}; + +template +< + typename Point, + typename DomainGeometry, + typename CSTag, + std::size_t dimension +> +class uniform_point_distribution +< + Point, + DomainGeometry, + pointlike_tag, + single_tag, + CSTag, + dimension +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; +public: + using base::base; + template + Point operator()(Generator& gen, typename base::param_type const& p) + { return this->domain(); } + template + Point operator()(Generator& gen) {return (*this)(gen, this->_param);} +}; + +template +< + typename Point, + typename DomainGeometry, + typename CSTag, + std::size_t dimension +> +class uniform_point_distribution +< + Point, + DomainGeometry, + pointlike_tag, + multi_tag, + CSTag, + dimension +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; +public: + using base::base; + template + Point operator()(Generator& gen, typename base::param_type const& p) + { + std::size_t count = num_points(p.domain()); + std::uniform_int_distribution dis(0, count-1); + return *(boost::begin(p.domain())+dis(gen)); + } + template + Point operator()(Generator& gen) {return (*this)(gen, this->_param);} + bool operator==( + uniform_point_distribution + < + Point, + DomainGeometry, + pointlike_tag, + multi_tag, + CSTag, + dimension + >& rhs) + { + DomainGeometry const& lhs_domain = this->domain(); + DomainGeometry const& rhs_domain = rhs.domain(); + if(num_points(lhs_domain) != num_points(rhs_domain)) return false; + typedef typename range_iterator::type cit; + cit lhs_it = boost::begin(lhs_domain), + lhs_end = boost::end(lhs_domain), + rhs_it = boost::begin(rhs_domain); + while(lhs_it != lhs_end) { + if(!equals(*lhs_it++, *rhs_it++)) return false; + } + return true; + } +}; + +template +< + typename Point, + typename Box, + typename Generator, + bool isIntegral = + boost::is_integral::type>::type::value +> +struct interval_sample {}; + +template +struct interval_sample +{ + Box const& b; + Generator& gen; + inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} + template + inline void apply(PointDst& point_dst) const + { + std::uniform_int_distribution::type> + dist(get(b),get(b)); + set(point_dst,dist(gen)); + } +}; + +template +struct interval_sample +{ + Box const& b; + Generator& gen; + inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} + + template + inline void apply(PointDst& point_dst) const + { + std::uniform_real_distribution::type> + dist(get(b),get(b)); + set(point_dst,dist(gen)); + } +}; + +template +inline Point sample_spherical_box_2d(DomainGeometry const& b, Generator& gen) +{ + typedef typename coordinate_type::type coordinate_type; + typedef typename select_most_precise + < + coordinate_type, + double + >::type computation_type; + + Point out; + std::uniform_real_distribution lon_dist( + get_as_radian<0, 0>(b), + get_as_radian<1, 0>(b)); + set_from_radian<0>(out, lon_dist(gen)); + + coordinate_type lat1 = get_as_radian<0, 1>(b); + coordinate_type lat2 = get_as_radian<1, 1>(b); + coordinate_type x1 = (1.0 - std::cos(lat1))/2, + x2 = (1.0 - std::cos(lat2))/2; + std::uniform_real_distribution x_dist( + std::min(x1, x2), + std::max(x1, x2)); + coordinate_type x = x_dist(gen); + set_from_radian<1>(out, std::acos(1.0 - 2.0 * x)); + return out; +} + +template +class uniform_point_distribution +< + Point, + DomainGeometry, + box_tag, + single_tag, + spherical_tag, + 2 +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; +public: + using base::base; + template + Point operator()(Generator& gen, typename base::param_type const& p) + { + return sample_spherical_box_2d(p.domain(), gen); + } + template + Point operator()(Generator& gen) + { + return (*this)(gen, this->_param); + } +}; + +template +class uniform_point_distribution +< + Point, + DomainGeometry, + box_tag, + single_tag, + spherical_tag, + 3 +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; +public: + using base::base; + template + Point operator()(Generator& gen, typename base::param_type const& p) + { + typedef typename coordinate_type::type coordinate_type; + typedef typename select_most_precise + < + coordinate_type, + double + >::type computation_type; + + Point out = sample_spherical_box_2d(p.domain(), gen); + coordinate_type r1 = get<0, 2>(p.domain()); + coordinate_type r2 = get<1, 2>(p.domain()); + std::uniform_real_distribution + r_dist( r1 * r1 * r1 , r2 * r2 * r2 ); + set<2>(out, std::cbrt(r_dist(gen))); + return out; + } + template + Point operator()(Generator& gen) + { + return (*this)(gen, this->_param); + } +}; + +template +class uniform_point_distribution +< + Point, + DomainGeometry, + box_tag, + single_tag, + cartesian_tag, + dimension +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; +public: + using base::base; + template + Point operator()(Generator& gen, typename base::param_type const& p) + { + model::box cached_box; + assign(cached_box, p.domain()); + Point out; + for_each_coordinate(out, + interval_sample(p.domain(), gen)); + return out; + } + template + Point operator()(Generator& gen) + { + return (*this)(gen, this->_param); + } +}; + +template +< + typename Point, + typename CSTag, + std::size_t dimension, + typename PointIn, + typename LengthType +> +struct sample_segment; + +template +< + typename Point, + std::size_t dimension, + typename PointIn, + typename LengthType +> +struct sample_segment +< + Point, + cartesian_tag, + dimension, + PointIn, + LengthType +> +{ + static Point apply(PointIn const& p1, PointIn const& p2, + LengthType const& r) + { + Point out; + assign(out,p2); + subtract_point(out, p1); + multiply_value(out, r); + add_point(out, p1); + return out; + } +}; + +template +inline Point sample_segment_spherical_2d(PointIn const& p1, PointIn const& p2, + LengthType const& f) +{ + Point out; + const auto lat1 = get_as_radian<1>(p1); + const auto lon1 = get_as_radian<0>(p1); + const auto lat2 = get_as_radian<1>(p2); + const auto lon2 = get_as_radian<0>(p2); + LengthType const d = std::acos( + std::sin(lat1) * std::sin(lat2) + + std::cos(lat1) * std::cos(lat2) * std::cos(lon1 - lon2)); + LengthType const A = std::sin( ( 1 - f ) * d ) / std::sin(d); + LengthType const B = std::sin( f * d ) / std::sin( d ); + LengthType const x = A * std::cos(lat1) * std::cos(lon1) + + B * std::cos(lat2) * std::cos(lon2); + LengthType const y = A * std::cos(lat1) * std::sin(lon1) + + B * std::cos(lat2) * std::sin(lon2); + LengthType const z = A * std::sin(lat1) + B * std::sin(lat2); + LengthType const lat = std::atan2(z, std::sqrt(x * x + y * y)); + LengthType const lon = std::atan2(y, x); + set_from_radian<1>(out, lat); + set_from_radian<0>(out, lon); + return out; +} + +template +struct sample_segment { + static Point apply(PointIn const& p1, PointIn const& p2, + LengthType const& f) + { + return sample_segment_spherical_2d(p1, p2, f); + } +}; + +template +< + typename Point, + typename PointVec, + typename IndexVec, + typename LengthVec, + typename LengthType +> +inline Point sample_multi_line(PointVec const& point_cache, + IndexVec const& skip_list, LengthVec const& accumulated_lengths, + LengthType const& r) +{ + std::size_t i = std::distance( + accumulated_lengths.begin(), + std::lower_bound( + accumulated_lengths.begin(), accumulated_lengths.end(), r)); + std::size_t offset = std::distance(skip_list.begin(), + std::lower_bound(skip_list.begin(), skip_list.end(), i)); + return sample_segment + < + Point, + typename tag_cast + < + typename cs_tag::type, + spherical_tag + >::type, + dimension::type::value, + typename PointVec::value_type, + LengthType + >::apply(point_cache[ i + offset - 1 ], point_cache[ i + offset ], + ( r - accumulated_lengths[ i - 1 ]) / + ( accumulated_lengths[ i ] - accumulated_lengths[ i - 1 ] )); +} + +template +< + typename Point, + typename DomainGeometry, + typename SingleOrMulti, + typename CSTag, + std::size_t dimension +> +class uniform_point_distribution +< + Point, + DomainGeometry, + areal_tag, + SingleOrMulti, + CSTag, + dimension +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; +public: + typedef typename uniform_point_distribution_base + ::param_type param_type; + using base::base; + using base::param; + uniform_point_distribution() {} + uniform_point_distribution(DomainGeometry const& g) : base(g) + { + envelope(g,_cached_box); + } + void param(param_type const& p) + { + this->_param = p; + envelope(p.domain(), _cached_box); + } + template + Point operator()(Generator& gen, typename base::param_type const& p) + { + model::box _cached_box; + envelope(p.domain(), _cached_box); + uniform_point_distribution + < + Point, + model::box, + box_tag, + single_tag, + CSTag, + dimension + > box_dist(_cached_box); + Point out = box_dist(gen); + while(!within(out, p.domain())) + out = box_dist(gen); + return out; + } + template + Point operator()(Generator& gen) + { + uniform_point_distribution + < + Point, + model::box, + box_tag, + single_tag, + CSTag, + dimension + > box_dist(_cached_box); + Point out = box_dist(gen); + while(!within(out, this->_param.domain())) + out = box_dist(gen); + return out; + } +private: + model::box _cached_box; +}; + +template +< + typename Point, + typename DomainGeometry, + typename SingleOrMulti, + typename CSTag, + std::size_t dimension +> +class uniform_point_distribution +< + Point, + DomainGeometry, + linear_tag, + SingleOrMulti, + CSTag, + dimension +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; + typedef typename default_length_result::type length_type; + typedef typename point_type::type domain_point_type; +public: + using base::base; + using base::param; + bool operator==(uniform_point_distribution const& rhs) const + { + if(rhs.skip_list.size() != skip_list.size() + || rhs.point_cache.size() != point_cache.size()) + return false; + for(std::size_t i = 0; i < skip_list.size(); ++i) + if(skip_list[i] != rhs.skip_list[i]) return false; + for(std::size_t i = 0; i < point_cache.size(); ++i) + if(!equals(point_cache[i], rhs.point_cache[i])) return false; + return true; + } + uniform_point_distribution(DomainGeometry const& g) : base(g) + { + init(skip_list, point_cache, accumulated_lengths, this->_param); + } + void init(std::vector& skip_list, + std::vector& point_cache, + std::vector& accumulated_lengths, + typename base::param_type const& p) + { + std::size_t i = 0; + point_cache.push_back(*segments_begin(p.domain())->first); + accumulated_lengths.push_back(0); + for(auto it = segments_begin(p.domain()); it!=segments_end(p.domain()); + ++it) { + accumulated_lengths.push_back( + accumulated_lengths.back() + length(*it)); + if(!equals(point_cache.back(),*it->first)) { + point_cache.push_back(*it->first); + skip_list.push_back(i); + } + point_cache.push_back(*it->second); + ++i; + } + } + void param(typename base::param_type const& p) + { + this->_param = p; + skip_list.clear(); + point_cache.clear(); + accumulated_lengths.clear(); + init(skip_list, point_cache, accumulated_lengths, p); + } + template + Point operator()(Generator& gen, typename base::param_type const& p) + { + std::vector skip_list; + std::vector point_cache; + std::vector accumulated_lengths; + init(skip_list, point_cache, accumulated_lengths, p); + typedef typename select_most_precise + < + double, + typename coordinate_type::type + >::type sample_type; + std::uniform_real_distribution dist(0, 1); + return sample_multi_line( + point_cache, + skip_list, + accumulated_lengths, + dist(gen)*accumulated_lengths.back()); + } + template + Point operator()(Generator& gen) + { + typedef typename select_most_precise + < + double, + typename coordinate_type::type + >::type sample_type; + std::uniform_real_distribution dist(0, 1); + return sample_multi_line( + point_cache, + skip_list, + accumulated_lengths, + dist(gen)*accumulated_lengths.back()); + } +private: + std::vector skip_list; + std::vector point_cache; + std::vector accumulated_lengths; +}; + +template +< + typename Point, + typename DomainGeometry, + typename SingleOrMulti, + typename CSTag, + std::size_t dimension +> +class uniform_point_distribution +< + Point, + DomainGeometry, + segment_tag, + SingleOrMulti, + CSTag, + dimension +> : public uniform_point_distribution_base +{ + typedef uniform_point_distribution_base base; + typedef uniform_point_distribution, + linear_tag, SingleOrMulti, CSTag, dimension> delegate_dist; +public: + using base::base; + using base::param; + uniform_point_distribution(DomainGeometry const& g) : + base(g), + d(segment_view(g)) {} + void param(typename base::param_type const& p) { + d = delegate_dist(segment_view(p.domain())); + } + template + Point operator()(Generator& gen, typename base::param_type const& p) + { + delegate_dist d(segment_view(p.domain())); + return d(gen); + } + template + Point operator()(Generator& gen) + { + return d(gen); + } + private: + delegate_dist d; + }; + +}}}} // namespace boost::geometry::random::detail + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_DETAIL_UNIFORM_POINT_DISTRIBUTION_HPP diff --git a/include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp new file mode 100644 index 0000000000..13eeb01974 --- /dev/null +++ b/include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp @@ -0,0 +1,71 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_DISPATCH_UNIFORM_POINT_DISTRIBUTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_DISPATCH_UNIFORM_POINT_DISTRIBUTION_HPP + +#include +#include +#include +#include + +#include + +namespace boost { namespace geometry { namespace random { namespace dispatch +{ + +template +< + typename DomainGeometry, + typename Point, + typename DomainTag = typename tag_cast + < + typename tag::type, + segment_tag, + box_tag, + linear_tag, + areal_tag, + pointlike_tag + >::type, + typename MultiOrSingle = typename tag_cast + < + typename tag::type, + single_tag, + multi_tag + >::type, + typename CSTag = typename tag_cast + < + typename cs_tag::type, + spherical_tag + >::type, + std::size_t dimension = dimension::type::value +> +class uniform_point_distribution : public detail::uniform_point_distribution + < + Point, DomainGeometry, DomainTag, + MultiOrSingle, + CSTag, + dimension + > +{ +public: + typedef detail::uniform_point_distribution + < + Point, + DomainGeometry, + DomainTag, + MultiOrSingle, + CSTag, + dimension + > base; + using base::base; +}; + +}}}} // namespace boost::geometry::random::dispatch + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_DISPATCH_UNIFORM_POINT_DISTRIBUTION_HPP diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp new file mode 100644 index 0000000000..192b86f5ec --- /dev/null +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_UNIFORM_POINT_DISTRIBUTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_UNIFORM_POINT_DISTRIBUTION_HPP + +#include + +namespace boost { namespace geometry { namespace random +{ + +template +< + typename DomainGeometry, + typename Point = typename geometry::point_type::type +> +inline dispatch::uniform_point_distribution + uniform_point_distribution(DomainGeometry const& domain) +{ + return dispatch::uniform_point_distribution(domain); +} + +}}} // namespace boost::geometry::random + +template +< + typename Char, + typename Traits, + typename Point, + typename DomainGeometry +> +inline std::basic_ostream& operator<< + ( + std::basic_ostream &os, + boost::geometry::random::dispatch::uniform_point_distribution< + DomainGeometry, Point> const& dist + ) +{ + os << boost::geometry::wkt(dist.domain()); + return os; +} + +template +inline std::basic_istream& operator>> + ( + std::basic_istream &is, + boost::geometry::random::dispatch::uniform_point_distribution< + DomainGeometry, Point> & dist + ) +{ + std::basic_string line; + std::getline(is, line); + DomainGeometry g; + namespace bg = boost::geometry; + typedef typename bg::random::dispatch::uniform_point_distribution< + DomainGeometry, Point>::param_type param_type; + bg::read_wkt(line, g); + dist.param( param_type(g) ); + return is; +} + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_UNIFORM_POINT_DISTRIBUTION_HPP From 0c4615575f9b10a4f522cb1096814f20f7a5a8b8 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Tue, 13 Aug 2019 00:46:57 +0200 Subject: [PATCH 02/12] Formatting. --- extensions/example/random/random_example.cpp | 12 ++++++--- extensions/test/random/random.cpp | 18 ++++++++----- .../detail/uniform_point_distribution.hpp | 26 ++++++++++++------- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/extensions/example/random/random_example.cpp b/extensions/example/random/random_example.cpp index d42f1b6102..c15258634e 100644 --- a/extensions/example/random/random_example.cpp +++ b/extensions/example/random/random_example.cpp @@ -19,7 +19,8 @@ const int samples = 100; template void draw_samples(Distribution& d, Generator& g, Mapper& m) { - for (int i = 0 ; i < samples ; ++i) { + for (int i = 0 ; i < samples ; ++i) + { m.map(d(g), "fill-opacity:1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:1", 1); } } @@ -39,8 +40,10 @@ int main() box b(point(0, 0), point(10, 10)); segment s(point(11, 0), point(21, 10)); multi_point mp; - for (double y = 11.0 ; y <= 21.0 ; y += 0.5) { - for(double x = 0.0 ; x <= 10.0 ; x += 0.5) { + for (double y = 11.0 ; y <= 21.0 ; y += 0.5) + { + for(double x = 0.0 ; x <= 10.0 ; x += 0.5) + { bg::append(mp, point(x, y)); } } @@ -68,7 +71,8 @@ int main() typedef bg::model::box box_spherical; box_spherical sb(point_spherical(0, 0), point_spherical(90, 90)); auto sb_dist = bg::random::uniform_point_distribution(sb); - for (int i = 0 ; i < 10*samples ; ++i) { + for (int i = 0 ; i < 10*samples ; ++i) + { point_spherical p = sb_dist(generator); double x = bg::get<0>(p) / 90 * 22; double y = 32 - bg::get<1>(p) / 90 * 10; diff --git a/extensions/test/random/random.cpp b/extensions/test/random/random.cpp index 19d580efa0..381e4e7c2c 100644 --- a/extensions/test/random/random.cpp +++ b/extensions/test/random/random.cpp @@ -35,7 +35,8 @@ void test_geographic() std::mt19937 generator(0); int sample_count = 2000; int count_below_45 = 0; - for(int i = 0 ; i < sample_count ; ++i) { + for (int i = 0 ; i < sample_count ; ++i) + { point2d_geog sample = l_dist(generator); BOOST_CHECK( bg::distance(sample, ls) < 2000 ); if(bg::get<0>(sample) < 45.0) count_below_45++; @@ -55,7 +56,8 @@ void test_geographic() box b {{ 0.0, 0.0 }, { 90.0, 90.0 }}; auto b_dist = bg::random::uniform_point_distribution(b); int under_60 = 0; - for(int i = 0 ; i < sample_count; ++i) { + for (int i = 0 ; i < sample_count ; ++i) + { point2d_geog sample = b_dist(generator); BOOST_CHECK( bg::within(sample, b) ); if(bg::get<1>(sample) < 60.0) ++under_60; @@ -84,14 +86,16 @@ void test_polygon() ss >> poly_dist2; BOOST_CHECK( poly_dist == poly_dist2 ); std::mt19937 generator(0), generator2(0); - for(int i = 0; i < 100 ; ++i) { + for (int i = 0 ; i < 100 ; ++i) + { point2d_cart sample1 = poly_dist(generator); BOOST_CHECK( bg::equals(sample1, poly_dist2(generator2)) ); BOOST_CHECK( bg::within(sample1, poly) ); } std::vector randoms; const int uniformity_test_samples = 2000; - for(int i = 0; i < uniformity_test_samples ; ++i) { + for (int i = 0 ; i < uniformity_test_samples ; ++i) + { randoms.push_back(poly_dist(generator)); } using box = bg::model::box; @@ -106,7 +110,8 @@ void test_polygon() bg::intersection(lhalf, poly, lower); double area_ratio = bg::area(lower[0])/bg::area(poly); int in_lower = 0; - for(int i = 0 ; i < uniformity_test_samples ; ++i) { + for (int i = 0 ; i < uniformity_test_samples ; ++i) + { if(bg::within(randoms[i], lhalf)) ++in_lower; } @@ -123,7 +128,8 @@ void test_multipoint() auto mp_dist = bg::random::uniform_point_distribution(mp); std::mt19937 generator(0); int sample_count = 1000; - for(int i = 0 ; i < sample_count ; ++i) { + for (int i = 0 ; i < sample_count ; ++i) + { point3d_cart sample = mp_dist(generator); BOOST_CHECK( bg::within(sample, mp) ); if(bg::equals(sample, mp[0])) ++first; diff --git a/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp index 174212f579..78631edda0 100644 --- a/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp @@ -149,7 +149,8 @@ class uniform_point_distribution cit lhs_it = boost::begin(lhs_domain), lhs_end = boost::end(lhs_domain), rhs_it = boost::begin(rhs_domain); - while(lhs_it != lhs_end) { + while(lhs_it != lhs_end) + { if(!equals(*lhs_it++, *rhs_it++)) return false; } return true; @@ -531,10 +532,14 @@ class uniform_point_distribution if(rhs.skip_list.size() != skip_list.size() || rhs.point_cache.size() != point_cache.size()) return false; - for(std::size_t i = 0; i < skip_list.size(); ++i) - if(skip_list[i] != rhs.skip_list[i]) return false; - for(std::size_t i = 0; i < point_cache.size(); ++i) - if(!equals(point_cache[i], rhs.point_cache[i])) return false; + for (std::size_t i = 0; i < skip_list.size(); ++i) + { + if (skip_list[i] != rhs.skip_list[i]) return false; + } + for (std::size_t i = 0; i < point_cache.size(); ++i) + { + if (!equals(point_cache[i], rhs.point_cache[i])) return false; + } return true; } uniform_point_distribution(DomainGeometry const& g) : base(g) @@ -549,11 +554,13 @@ class uniform_point_distribution std::size_t i = 0; point_cache.push_back(*segments_begin(p.domain())->first); accumulated_lengths.push_back(0); - for(auto it = segments_begin(p.domain()); it!=segments_end(p.domain()); - ++it) { + for (auto it = segments_begin(p.domain()) ; it!=segments_end(p.domain()) ; + ++it) + { accumulated_lengths.push_back( accumulated_lengths.back() + length(*it)); - if(!equals(point_cache.back(),*it->first)) { + if (!equals(point_cache.back(), *it->first)) + { point_cache.push_back(*it->first); skip_list.push_back(i); } @@ -636,7 +643,8 @@ class uniform_point_distribution uniform_point_distribution(DomainGeometry const& g) : base(g), d(segment_view(g)) {} - void param(typename base::param_type const& p) { + void param(typename base::param_type const& p) + { d = delegate_dist(segment_view(p.domain())); } template From 57632e189555f1089fc577d78492dae8ccc9c5d4 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Tue, 13 Aug 2019 01:09:59 +0200 Subject: [PATCH 03/12] Use typedefs for consistenc --- extensions/test/random/random.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/extensions/test/random/random.cpp b/extensions/test/random/random.cpp index 381e4e7c2c..1535ac6306 100644 --- a/extensions/test/random/random.cpp +++ b/extensions/test/random/random.cpp @@ -16,12 +16,9 @@ #include #include -namespace bg = boost::geometry; - -using point2d_cart = bg::model::point; -using point3d_cart = bg::model::point; -using point2d_geog = - bg::model::point>; +typedef bg::model::point point2d_cart; +typedef bg::model::point point3d_cart; +typedef bg::model::point> point2d_geog; void test_geographic() { @@ -29,7 +26,7 @@ void test_geographic() //the great circle segment (<2 km distance on a sphere with //the radius of earth) and are distributed uniformly with respect //to great circle arc length. - using linestring = bg::model::linestring; + typedef bg::model::linestring linestring; linestring ls {{ 0.0, 0.0 }, { 45.0, 45.0 }, { 60.0, 60.0 }}; auto l_dist = bg::random::uniform_point_distribution(ls); std::mt19937 generator(0); @@ -52,7 +49,7 @@ void test_geographic() //(which is actually a triangle in this case) and whether the latitude //is distributed as expected for uniform spherical distribution, using //known area ratios of spherical caps. - using box = bg::model::box; + typedef bg::model::box box; box b {{ 0.0, 0.0 }, { 90.0, 90.0 }}; auto b_dist = bg::random::uniform_point_distribution(b); int under_60 = 0; @@ -73,7 +70,7 @@ void test_polygon() //(copied using operator<< and operator>>) generate the same sequence //of points and whether those points are uniformly distributed with //respect to cartesian area. - using polygon = bg::model::polygon; + typedef bg::model::polygon polygon; polygon poly; bg::read_wkt( "POLYGON((16 21,17.1226 17.5451,20.7553 17.5451, 17.8164 15.4098,18.9389 11.9549,16 14.0902,13.0611 11.9549, 14.1836 15.4098,11.2447 17.5451,14.8774 17.5451,16 21))", @@ -98,7 +95,7 @@ void test_polygon() { randoms.push_back(poly_dist(generator)); } - using box = bg::model::box; + typedef bg::model::box box; box env, lhalf; bg::envelope(poly, env); bg::set(lhalf, bg::get(env)); @@ -122,7 +119,7 @@ void test_polygon() void test_multipoint() { - using multipoint = bg::model::multi_point; + typedef bg::model::multi_point multipoint; multipoint mp {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}}; int first = 0; auto mp_dist = bg::random::uniform_point_distribution(mp); From a6bfe950c9e9ce4718abe1543316f91c80e1fe07 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Tue, 13 Aug 2019 08:27:47 +0200 Subject: [PATCH 04/12] Formatting. --- .../random/uniform_point_distribution.hpp | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp index 192b86f5ec..918a08fe24 100644 --- a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -37,28 +37,40 @@ template inline std::basic_ostream& operator<< ( std::basic_ostream &os, - boost::geometry::random::dispatch::uniform_point_distribution< - DomainGeometry, Point> const& dist + boost::geometry::random::dispatch::uniform_point_distribution + < + DomainGeometry, Point + > const& dist ) { os << boost::geometry::wkt(dist.domain()); return os; } -template +template +< + typename Char, + typename Traits, + typename Point, + typename DomainGeometry +> inline std::basic_istream& operator>> ( std::basic_istream &is, - boost::geometry::random::dispatch::uniform_point_distribution< - DomainGeometry, Point> & dist + boost::geometry::random::dispatch::uniform_point_distribution + < + DomainGeometry, Point + > & dist ) { std::basic_string line; std::getline(is, line); DomainGeometry g; namespace bg = boost::geometry; - typedef typename bg::random::dispatch::uniform_point_distribution< - DomainGeometry, Point>::param_type param_type; + typedef typename bg::random::dispatch::uniform_point_distribution + < + DomainGeometry, Point + >::param_type param_type; bg::read_wkt(line, g); dist.param( param_type(g) ); return is; From d906785184d48c84af6625f6960ecfdfc11abacf Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Sun, 18 Aug 2019 23:05:31 +0200 Subject: [PATCH 05/12] Remove auto usage in tests, create public name for uniform_point_distribution --- extensions/example/random/random_example.cpp | 10 +++---- extensions/test/random/random.cpp | 10 +++---- .../random/uniform_point_distribution.hpp | 26 ++++++++++++++----- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/extensions/example/random/random_example.cpp b/extensions/example/random/random_example.cpp index c15258634e..fd46a85c99 100644 --- a/extensions/example/random/random_example.cpp +++ b/extensions/example/random/random_example.cpp @@ -47,10 +47,10 @@ int main() bg::append(mp, point(x, y)); } } - auto box_dist = bg::random::uniform_point_distribution(b); - auto mp_dist = bg::random::uniform_point_distribution(mp); - auto seg_dist = bg::random::uniform_point_distribution(s); - auto poly_dist = bg::random::uniform_point_distribution(poly); + bg::random::uniform_point_distribution box_dist(b); + bg::random::uniform_point_distribution mp_dist(mp); + bg::random::uniform_point_distribution seg_dist(s); + bg::random::uniform_point_distribution poly_dist(poly); std::ofstream svg("random.svg"); bg::svg_mapper mapper(svg, 720, 720); mapper.add(poly); @@ -70,7 +70,7 @@ int main() typedef bg::model::point> point_spherical; typedef bg::model::box box_spherical; box_spherical sb(point_spherical(0, 0), point_spherical(90, 90)); - auto sb_dist = bg::random::uniform_point_distribution(sb); + bg::random::uniform_point_distribution sb_dist(sb); for (int i = 0 ; i < 10*samples ; ++i) { point_spherical p = sb_dist(generator); diff --git a/extensions/test/random/random.cpp b/extensions/test/random/random.cpp index 1535ac6306..89b8da75aa 100644 --- a/extensions/test/random/random.cpp +++ b/extensions/test/random/random.cpp @@ -28,7 +28,7 @@ void test_geographic() //to great circle arc length. typedef bg::model::linestring linestring; linestring ls {{ 0.0, 0.0 }, { 45.0, 45.0 }, { 60.0, 60.0 }}; - auto l_dist = bg::random::uniform_point_distribution(ls); + bg::random::uniform_point_distribution l_dist(ls); std::mt19937 generator(0); int sample_count = 2000; int count_below_45 = 0; @@ -51,7 +51,7 @@ void test_geographic() //known area ratios of spherical caps. typedef bg::model::box box; box b {{ 0.0, 0.0 }, { 90.0, 90.0 }}; - auto b_dist = bg::random::uniform_point_distribution(b); + bg::random::uniform_point_distribution b_dist(b); int under_60 = 0; for (int i = 0 ; i < sample_count ; ++i) { @@ -75,8 +75,8 @@ void test_polygon() bg::read_wkt( "POLYGON((16 21,17.1226 17.5451,20.7553 17.5451, 17.8164 15.4098,18.9389 11.9549,16 14.0902,13.0611 11.9549, 14.1836 15.4098,11.2447 17.5451,14.8774 17.5451,16 21))", poly); - auto poly_dist = bg::random::uniform_point_distribution(poly); - decltype(poly_dist) poly_dist2; + bg::random::uniform_point_distribution poly_dist(poly); + bg::random::uniform_point_distribution poly_dist2; BOOST_CHECK( !(poly_dist == poly_dist2) ); std::stringstream ss; ss << poly_dist; @@ -122,7 +122,7 @@ void test_multipoint() typedef bg::model::multi_point multipoint; multipoint mp {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}}; int first = 0; - auto mp_dist = bg::random::uniform_point_distribution(mp); + bg::random::uniform_point_distribution mp_dist(mp); std::mt19937 generator(0); int sample_count = 1000; for (int i = 0 ; i < sample_count ; ++i) diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp index 918a08fe24..8669fccf18 100644 --- a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -19,10 +19,24 @@ template typename DomainGeometry, typename Point = typename geometry::point_type::type > -inline dispatch::uniform_point_distribution - uniform_point_distribution(DomainGeometry const& domain) +class uniform_point_distribution : + public dispatch::uniform_point_distribution { - return dispatch::uniform_point_distribution(domain); +public: + typedef dispatch::uniform_point_distribution base; + using base::base; + uniform_point_distribution(DomainGeometry const& domain) : base(domain) {} +}; + +template +< + typename DomainGeometry, + typename Point = typename geometry::point_type::type +> +inline uniform_point_distribution + return_uniform_point_distribution(DomainGeometry const& domain) +{ + return uniform_point_distribution(domain); } }}} // namespace boost::geometry::random @@ -37,7 +51,7 @@ template inline std::basic_ostream& operator<< ( std::basic_ostream &os, - boost::geometry::random::dispatch::uniform_point_distribution + boost::geometry::random::uniform_point_distribution < DomainGeometry, Point > const& dist @@ -57,7 +71,7 @@ template inline std::basic_istream& operator>> ( std::basic_istream &is, - boost::geometry::random::dispatch::uniform_point_distribution + boost::geometry::random::uniform_point_distribution < DomainGeometry, Point > & dist @@ -67,7 +81,7 @@ inline std::basic_istream& operator>> std::getline(is, line); DomainGeometry g; namespace bg = boost::geometry; - typedef typename bg::random::dispatch::uniform_point_distribution + typedef typename bg::random::uniform_point_distribution < DomainGeometry, Point >::param_type param_type; From b9a3660f47e8ddf818b28add26695a5b84102e12 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Fri, 23 Aug 2019 13:14:16 +0200 Subject: [PATCH 06/12] Move implementations into strategies. --- .../detail/uniform_point_distribution.hpp | 667 ------------------ .../dispatch/uniform_point_distribution.hpp | 71 -- .../agnostic/uniform_envelope_rejection.hpp | 119 ++++ .../strategies/agnostic/uniform_linear.hpp | 144 ++++ .../uniform_point_distribution_discrete.hpp | 132 ++++ .../uniform_point_distribution_box.hpp | 124 ++++ .../uniform_point_distribution_segment.hpp | 100 +++ .../edwilliams_avform_intermediate.hpp | 111 +++ .../uniform_inverse_transform_sampling.hpp | 156 ++++ .../strategies/uniform_point_distribution.hpp | 57 ++ .../random/uniform_point_distribution.hpp | 73 +- 11 files changed, 1009 insertions(+), 745 deletions(-) delete mode 100644 include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp delete mode 100644 include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp diff --git a/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp deleted file mode 100644 index 78631edda0..0000000000 --- a/include/boost/geometry/extensions/random/detail/uniform_point_distribution.hpp +++ /dev/null @@ -1,667 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_DETAIL_UNIFORM_POINT_DISTRIBUTION_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_DETAIL_UNIFORM_POINT_DISTRIBUTION_HPP - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace boost { namespace geometry { namespace random { namespace detail -{ - -template -class uniform_point_distribution_base -{ -public: - typedef Point result_type; - class param_type { - public: - param_type(DomainGeometry const& domain):_domain(domain) {} - param_type(param_type const& p):_domain(p._domain) {} - DomainGeometry const& domain() const {return _domain;} - bool operator==(param_type const& rhs) const - { - return equals(_domain,rhs._domain); - } - private: - DomainGeometry _domain; - }; - uniform_point_distribution_base():_param(DomainGeometry()) {} - uniform_point_distribution_base(param_type const& param):_param(param) {} - uniform_point_distribution_base(DomainGeometry const& domain) : - _param(param_type(domain)) {} - void reset() {} - param_type param() const {return _param;} - DomainGeometry const& domain() const {return _param.domain();} - bool operator==(uniform_point_distribution_base const& rhs) const - { - return _param==rhs._param; - } - void param(param_type const& p) {_param = p;} -protected: - param_type _param; -}; - -template -< - typename Point, - typename DomainGeometry, - typename DomainTag, - typename SingleOrMulti, - typename CSTag, - std::size_t dimension -> -class uniform_point_distribution {}; - -template -< - typename Point, - typename DomainGeometry, - typename CSTag, - std::size_t dimension -> -class uniform_point_distribution -< - Point, - DomainGeometry, - pointlike_tag, - single_tag, - CSTag, - dimension -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; -public: - using base::base; - template - Point operator()(Generator& gen, typename base::param_type const& p) - { return this->domain(); } - template - Point operator()(Generator& gen) {return (*this)(gen, this->_param);} -}; - -template -< - typename Point, - typename DomainGeometry, - typename CSTag, - std::size_t dimension -> -class uniform_point_distribution -< - Point, - DomainGeometry, - pointlike_tag, - multi_tag, - CSTag, - dimension -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; -public: - using base::base; - template - Point operator()(Generator& gen, typename base::param_type const& p) - { - std::size_t count = num_points(p.domain()); - std::uniform_int_distribution dis(0, count-1); - return *(boost::begin(p.domain())+dis(gen)); - } - template - Point operator()(Generator& gen) {return (*this)(gen, this->_param);} - bool operator==( - uniform_point_distribution - < - Point, - DomainGeometry, - pointlike_tag, - multi_tag, - CSTag, - dimension - >& rhs) - { - DomainGeometry const& lhs_domain = this->domain(); - DomainGeometry const& rhs_domain = rhs.domain(); - if(num_points(lhs_domain) != num_points(rhs_domain)) return false; - typedef typename range_iterator::type cit; - cit lhs_it = boost::begin(lhs_domain), - lhs_end = boost::end(lhs_domain), - rhs_it = boost::begin(rhs_domain); - while(lhs_it != lhs_end) - { - if(!equals(*lhs_it++, *rhs_it++)) return false; - } - return true; - } -}; - -template -< - typename Point, - typename Box, - typename Generator, - bool isIntegral = - boost::is_integral::type>::type::value -> -struct interval_sample {}; - -template -struct interval_sample -{ - Box const& b; - Generator& gen; - inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} - template - inline void apply(PointDst& point_dst) const - { - std::uniform_int_distribution::type> - dist(get(b),get(b)); - set(point_dst,dist(gen)); - } -}; - -template -struct interval_sample -{ - Box const& b; - Generator& gen; - inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} - - template - inline void apply(PointDst& point_dst) const - { - std::uniform_real_distribution::type> - dist(get(b),get(b)); - set(point_dst,dist(gen)); - } -}; - -template -inline Point sample_spherical_box_2d(DomainGeometry const& b, Generator& gen) -{ - typedef typename coordinate_type::type coordinate_type; - typedef typename select_most_precise - < - coordinate_type, - double - >::type computation_type; - - Point out; - std::uniform_real_distribution lon_dist( - get_as_radian<0, 0>(b), - get_as_radian<1, 0>(b)); - set_from_radian<0>(out, lon_dist(gen)); - - coordinate_type lat1 = get_as_radian<0, 1>(b); - coordinate_type lat2 = get_as_radian<1, 1>(b); - coordinate_type x1 = (1.0 - std::cos(lat1))/2, - x2 = (1.0 - std::cos(lat2))/2; - std::uniform_real_distribution x_dist( - std::min(x1, x2), - std::max(x1, x2)); - coordinate_type x = x_dist(gen); - set_from_radian<1>(out, std::acos(1.0 - 2.0 * x)); - return out; -} - -template -class uniform_point_distribution -< - Point, - DomainGeometry, - box_tag, - single_tag, - spherical_tag, - 2 -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; -public: - using base::base; - template - Point operator()(Generator& gen, typename base::param_type const& p) - { - return sample_spherical_box_2d(p.domain(), gen); - } - template - Point operator()(Generator& gen) - { - return (*this)(gen, this->_param); - } -}; - -template -class uniform_point_distribution -< - Point, - DomainGeometry, - box_tag, - single_tag, - spherical_tag, - 3 -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; -public: - using base::base; - template - Point operator()(Generator& gen, typename base::param_type const& p) - { - typedef typename coordinate_type::type coordinate_type; - typedef typename select_most_precise - < - coordinate_type, - double - >::type computation_type; - - Point out = sample_spherical_box_2d(p.domain(), gen); - coordinate_type r1 = get<0, 2>(p.domain()); - coordinate_type r2 = get<1, 2>(p.domain()); - std::uniform_real_distribution - r_dist( r1 * r1 * r1 , r2 * r2 * r2 ); - set<2>(out, std::cbrt(r_dist(gen))); - return out; - } - template - Point operator()(Generator& gen) - { - return (*this)(gen, this->_param); - } -}; - -template -class uniform_point_distribution -< - Point, - DomainGeometry, - box_tag, - single_tag, - cartesian_tag, - dimension -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; -public: - using base::base; - template - Point operator()(Generator& gen, typename base::param_type const& p) - { - model::box cached_box; - assign(cached_box, p.domain()); - Point out; - for_each_coordinate(out, - interval_sample(p.domain(), gen)); - return out; - } - template - Point operator()(Generator& gen) - { - return (*this)(gen, this->_param); - } -}; - -template -< - typename Point, - typename CSTag, - std::size_t dimension, - typename PointIn, - typename LengthType -> -struct sample_segment; - -template -< - typename Point, - std::size_t dimension, - typename PointIn, - typename LengthType -> -struct sample_segment -< - Point, - cartesian_tag, - dimension, - PointIn, - LengthType -> -{ - static Point apply(PointIn const& p1, PointIn const& p2, - LengthType const& r) - { - Point out; - assign(out,p2); - subtract_point(out, p1); - multiply_value(out, r); - add_point(out, p1); - return out; - } -}; - -template -inline Point sample_segment_spherical_2d(PointIn const& p1, PointIn const& p2, - LengthType const& f) -{ - Point out; - const auto lat1 = get_as_radian<1>(p1); - const auto lon1 = get_as_radian<0>(p1); - const auto lat2 = get_as_radian<1>(p2); - const auto lon2 = get_as_radian<0>(p2); - LengthType const d = std::acos( - std::sin(lat1) * std::sin(lat2) - + std::cos(lat1) * std::cos(lat2) * std::cos(lon1 - lon2)); - LengthType const A = std::sin( ( 1 - f ) * d ) / std::sin(d); - LengthType const B = std::sin( f * d ) / std::sin( d ); - LengthType const x = A * std::cos(lat1) * std::cos(lon1) - + B * std::cos(lat2) * std::cos(lon2); - LengthType const y = A * std::cos(lat1) * std::sin(lon1) - + B * std::cos(lat2) * std::sin(lon2); - LengthType const z = A * std::sin(lat1) + B * std::sin(lat2); - LengthType const lat = std::atan2(z, std::sqrt(x * x + y * y)); - LengthType const lon = std::atan2(y, x); - set_from_radian<1>(out, lat); - set_from_radian<0>(out, lon); - return out; -} - -template -struct sample_segment { - static Point apply(PointIn const& p1, PointIn const& p2, - LengthType const& f) - { - return sample_segment_spherical_2d(p1, p2, f); - } -}; - -template -< - typename Point, - typename PointVec, - typename IndexVec, - typename LengthVec, - typename LengthType -> -inline Point sample_multi_line(PointVec const& point_cache, - IndexVec const& skip_list, LengthVec const& accumulated_lengths, - LengthType const& r) -{ - std::size_t i = std::distance( - accumulated_lengths.begin(), - std::lower_bound( - accumulated_lengths.begin(), accumulated_lengths.end(), r)); - std::size_t offset = std::distance(skip_list.begin(), - std::lower_bound(skip_list.begin(), skip_list.end(), i)); - return sample_segment - < - Point, - typename tag_cast - < - typename cs_tag::type, - spherical_tag - >::type, - dimension::type::value, - typename PointVec::value_type, - LengthType - >::apply(point_cache[ i + offset - 1 ], point_cache[ i + offset ], - ( r - accumulated_lengths[ i - 1 ]) / - ( accumulated_lengths[ i ] - accumulated_lengths[ i - 1 ] )); -} - -template -< - typename Point, - typename DomainGeometry, - typename SingleOrMulti, - typename CSTag, - std::size_t dimension -> -class uniform_point_distribution -< - Point, - DomainGeometry, - areal_tag, - SingleOrMulti, - CSTag, - dimension -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; -public: - typedef typename uniform_point_distribution_base - ::param_type param_type; - using base::base; - using base::param; - uniform_point_distribution() {} - uniform_point_distribution(DomainGeometry const& g) : base(g) - { - envelope(g,_cached_box); - } - void param(param_type const& p) - { - this->_param = p; - envelope(p.domain(), _cached_box); - } - template - Point operator()(Generator& gen, typename base::param_type const& p) - { - model::box _cached_box; - envelope(p.domain(), _cached_box); - uniform_point_distribution - < - Point, - model::box, - box_tag, - single_tag, - CSTag, - dimension - > box_dist(_cached_box); - Point out = box_dist(gen); - while(!within(out, p.domain())) - out = box_dist(gen); - return out; - } - template - Point operator()(Generator& gen) - { - uniform_point_distribution - < - Point, - model::box, - box_tag, - single_tag, - CSTag, - dimension - > box_dist(_cached_box); - Point out = box_dist(gen); - while(!within(out, this->_param.domain())) - out = box_dist(gen); - return out; - } -private: - model::box _cached_box; -}; - -template -< - typename Point, - typename DomainGeometry, - typename SingleOrMulti, - typename CSTag, - std::size_t dimension -> -class uniform_point_distribution -< - Point, - DomainGeometry, - linear_tag, - SingleOrMulti, - CSTag, - dimension -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; - typedef typename default_length_result::type length_type; - typedef typename point_type::type domain_point_type; -public: - using base::base; - using base::param; - bool operator==(uniform_point_distribution const& rhs) const - { - if(rhs.skip_list.size() != skip_list.size() - || rhs.point_cache.size() != point_cache.size()) - return false; - for (std::size_t i = 0; i < skip_list.size(); ++i) - { - if (skip_list[i] != rhs.skip_list[i]) return false; - } - for (std::size_t i = 0; i < point_cache.size(); ++i) - { - if (!equals(point_cache[i], rhs.point_cache[i])) return false; - } - return true; - } - uniform_point_distribution(DomainGeometry const& g) : base(g) - { - init(skip_list, point_cache, accumulated_lengths, this->_param); - } - void init(std::vector& skip_list, - std::vector& point_cache, - std::vector& accumulated_lengths, - typename base::param_type const& p) - { - std::size_t i = 0; - point_cache.push_back(*segments_begin(p.domain())->first); - accumulated_lengths.push_back(0); - for (auto it = segments_begin(p.domain()) ; it!=segments_end(p.domain()) ; - ++it) - { - accumulated_lengths.push_back( - accumulated_lengths.back() + length(*it)); - if (!equals(point_cache.back(), *it->first)) - { - point_cache.push_back(*it->first); - skip_list.push_back(i); - } - point_cache.push_back(*it->second); - ++i; - } - } - void param(typename base::param_type const& p) - { - this->_param = p; - skip_list.clear(); - point_cache.clear(); - accumulated_lengths.clear(); - init(skip_list, point_cache, accumulated_lengths, p); - } - template - Point operator()(Generator& gen, typename base::param_type const& p) - { - std::vector skip_list; - std::vector point_cache; - std::vector accumulated_lengths; - init(skip_list, point_cache, accumulated_lengths, p); - typedef typename select_most_precise - < - double, - typename coordinate_type::type - >::type sample_type; - std::uniform_real_distribution dist(0, 1); - return sample_multi_line( - point_cache, - skip_list, - accumulated_lengths, - dist(gen)*accumulated_lengths.back()); - } - template - Point operator()(Generator& gen) - { - typedef typename select_most_precise - < - double, - typename coordinate_type::type - >::type sample_type; - std::uniform_real_distribution dist(0, 1); - return sample_multi_line( - point_cache, - skip_list, - accumulated_lengths, - dist(gen)*accumulated_lengths.back()); - } -private: - std::vector skip_list; - std::vector point_cache; - std::vector accumulated_lengths; -}; - -template -< - typename Point, - typename DomainGeometry, - typename SingleOrMulti, - typename CSTag, - std::size_t dimension -> -class uniform_point_distribution -< - Point, - DomainGeometry, - segment_tag, - SingleOrMulti, - CSTag, - dimension -> : public uniform_point_distribution_base -{ - typedef uniform_point_distribution_base base; - typedef uniform_point_distribution, - linear_tag, SingleOrMulti, CSTag, dimension> delegate_dist; -public: - using base::base; - using base::param; - uniform_point_distribution(DomainGeometry const& g) : - base(g), - d(segment_view(g)) {} - void param(typename base::param_type const& p) - { - d = delegate_dist(segment_view(p.domain())); - } - template - Point operator()(Generator& gen, typename base::param_type const& p) - { - delegate_dist d(segment_view(p.domain())); - return d(gen); - } - template - Point operator()(Generator& gen) - { - return d(gen); - } - private: - delegate_dist d; - }; - -}}}} // namespace boost::geometry::random::detail - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_DETAIL_UNIFORM_POINT_DISTRIBUTION_HPP diff --git a/include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp deleted file mode 100644 index 13eeb01974..0000000000 --- a/include/boost/geometry/extensions/random/dispatch/uniform_point_distribution.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_DISPATCH_UNIFORM_POINT_DISTRIBUTION_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_DISPATCH_UNIFORM_POINT_DISTRIBUTION_HPP - -#include -#include -#include -#include - -#include - -namespace boost { namespace geometry { namespace random { namespace dispatch -{ - -template -< - typename DomainGeometry, - typename Point, - typename DomainTag = typename tag_cast - < - typename tag::type, - segment_tag, - box_tag, - linear_tag, - areal_tag, - pointlike_tag - >::type, - typename MultiOrSingle = typename tag_cast - < - typename tag::type, - single_tag, - multi_tag - >::type, - typename CSTag = typename tag_cast - < - typename cs_tag::type, - spherical_tag - >::type, - std::size_t dimension = dimension::type::value -> -class uniform_point_distribution : public detail::uniform_point_distribution - < - Point, DomainGeometry, DomainTag, - MultiOrSingle, - CSTag, - dimension - > -{ -public: - typedef detail::uniform_point_distribution - < - Point, - DomainGeometry, - DomainTag, - MultiOrSingle, - CSTag, - dimension - > base; - using base::base; -}; - -}}}} // namespace boost::geometry::random::dispatch - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_DISPATCH_UNIFORM_POINT_DISTRIBUTION_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp new file mode 100644 index 0000000000..606318aeea --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp @@ -0,0 +1,119 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_ENVELOPE_REJECTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_ENVELOPE_REJECTION_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +template +< + typename Point, + typename DomainGeometry, + typename BoxStrategy = services::default_strategy + < + typename point_type::type, + model::box::type> + > +> +struct uniform_envelope_rejection +{ +private: + typedef model::box::type> envelope_type; + envelope_type m_env; + BoxStrategy m_env_strat; +public: + uniform_envelope_rejection(DomainGeometry const& g) : + m_env(return_envelope(g)), + m_env_strat(m_env) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_envelope_rejection const& r_strategy) const + { + return boost::geometry::equals(l_domain, r_domain); + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + typedef typename point_type::type domain_point; + domain_point p; + do { + p = m_env_strat.apply(g, m_env); + }while( !::boost::geometry::within(p, d) ); + Point r; + boost::geometry::transform(p, r); + return r; + } + void reset(DomainGeometry const&) {}; +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry, + typename MultiOrSingle, + typename CsTag +> +struct default_strategy +< + Point, + DomainGeometry, + areal_tag, + MultiOrSingle, + 2, + CsTag +> : public uniform_envelope_rejection { + typedef uniform_envelope_rejection base; + using base::base; +}; + +template +< + typename Point, + typename DomainGeometry, + typename MultiOrSingle, + typename CsTag +> +struct default_strategy +< + Point, + DomainGeometry, + volumetric_tag, + MultiOrSingle, + 3, + CsTag +> : public uniform_envelope_rejection { + typedef uniform_envelope_rejection base; + using base::base; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_ENVELOPE_REJECTION_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp new file mode 100644 index 0000000000..c869a685b9 --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp @@ -0,0 +1,144 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_LINEAR_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_LINEAR_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +template +< + typename Point, + typename DomainGeometry, + typename SegmentStrategy = services::default_strategy + < + typename point_type::type, + model::segment::type> + > +> +class uniform_linear +{ +private: + typedef typename default_length_result::type length_type; + typedef typename point_type::type domain_point_type; + std::vector skip_list; + std::vector point_cache; + std::vector accumulated_lengths; +public: + uniform_linear(DomainGeometry const& g) + { + std::size_t i = 0; + point_cache.push_back(*segments_begin(g)->first); + accumulated_lengths.push_back(0); + for (auto it = segments_begin(g) ; it != segments_end(g) ; ++it) + { + accumulated_lengths.push_back( + accumulated_lengths.back() + length(*it)); + if (!boost::geometry::equals(point_cache.back(), *it->first)) + { + point_cache.push_back(*it->first); + skip_list.push_back(i); + } + point_cache.push_back(*it->second); + ++i; + } + } + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_linear const& r_strategy) const + { + if(r_strategy.skip_list.size() != skip_list.size() + || r_strategy.point_cache.size() != point_cache.size()) + return false; + for (std::size_t i = 0; i < skip_list.size(); ++i) + { + if (skip_list[i] != r_strategy.skip_list[i]) return false; + } + for (std::size_t i = 0; i < point_cache.size(); ++i) + { + if (!boost::geometry::equals(point_cache[i], r_strategy.point_cache[i])) return false; + } + return true; + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + typedef typename select_most_precise + < + double, + typename coordinate_type::type + >::type sample_type; + std::uniform_real_distribution dist(0, accumulated_lengths.back()); + sample_type r = dist(g); + std::size_t i = std::distance( + accumulated_lengths.begin(), + std::lower_bound(accumulated_lengths.begin(), + accumulated_lengths.end(), + r)); + std::size_t offset = std::distance( + skip_list.begin(), + std::lower_bound(skip_list.begin(), skip_list.end(), i)); + + return SegmentStrategy::template map + < + sample_type, + domain_point_type + >(point_cache[ i + offset - 1 ], point_cache[ i + offset ], + ( r - accumulated_lengths[ i - 1 ]) / + ( accumulated_lengths[ i ] - accumulated_lengths[ i - 1 ] )); + } + void reset(DomainGeometry const&) {}; +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry, + typename MultiOrSingle, + int Dim, + typename CsTag +> +struct default_strategy +< + Point, + DomainGeometry, + linear_tag, + MultiOrSingle, + Dim, + CsTag +> : public uniform_linear { + typedef uniform_linear base; + using base::base; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_LINEAR_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp new file mode 100644 index 0000000000..97ed5c953d --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp @@ -0,0 +1,132 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_POINT_DISTRIBUTION_DISCRETE_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_POINT_DISTRIBUTION_DISCRETE_HPP + +#include +#include + +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +template +< + typename Point, + typename DomainGeometry +> +struct single_point_distribution +{ + single_point_distribution(DomainGeometry const& g) {} + template + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + Strategy const& r_strategy) const + { + return boost::geometry::equals(l_domain.domain(), r_domain.domain()); + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + Point r; + boost::geometry::transform(d, r); + return r; + } + void reset(DomainGeometry const&) {}; +}; + +template +< + typename Point, + typename DomainGeometry +> +struct multi_point_distribution +{ + multi_point_distribution(DomainGeometry const& p) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + multi_point_distribution const& r_strategy) const + { + if(boost::size(l_domain) != boost::size(r_domain)) return false; + for (std::size_t i = 0; i < boost::size(l_domain); ++i) + if( !boost::geometry::equals( *(std::begin(l_domain) + i), + *(std::begin(r_domain) + i)) ) + { + return false; + } + return true; + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + Point r; + if(boost::size(d) == 0) return r; + std::uniform_int_distribution + int_dist(0, boost::size(d) - 1); + boost::geometry::transform(*(std::begin(d) + int_dist(g)), r); + return r; + } + void reset(DomainGeometry const&) {} +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry, + int Dim, + typename CsTag +> +struct default_strategy +< + Point, + DomainGeometry, + pointlike_tag, + single_tag, + Dim, + CsTag +> : public single_point_distribution { + typedef single_point_distribution base; + using base::base; +}; + +template +< + typename Point, + typename DomainGeometry, + int Dim, + typename CsTag +> +struct default_strategy +< + Point, + DomainGeometry, + pointlike_tag, + multi_tag, + Dim, + CsTag +> : public multi_point_distribution { + typedef multi_point_distribution base; + using base::base; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_POINT_DISTRIBUTION_DISCRETE_HPP diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp new file mode 100644 index 0000000000..6a37158ad7 --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp @@ -0,0 +1,124 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_BOX_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_BOX_HPP + +#include +#include + +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +namespace detail +{ + +template +< + typename Point, + typename Box, + typename Generator, + bool isIntegral = + boost::is_integral::type>::type::value +> +struct interval_sample {}; + +template +struct interval_sample +{ + Box const& b; + Generator& gen; + inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} + template + inline void apply(PointDst& point_dst) const + { + std::uniform_int_distribution::type> + dist(get(b),get(b)); + set(point_dst,dist(gen)); + } +}; + +template +struct interval_sample +{ + Box const& b; + Generator& gen; + inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} + + template + inline void apply(PointDst& point_dst) const + { + std::uniform_real_distribution::type> + dist(get(b),get(b)); + set(point_dst,dist(gen)); + } +}; + +} + +template +< + typename Point, + typename DomainGeometry, + int Dim +> +struct interval_product_distribution +{ + interval_product_distribution(DomainGeometry const& g) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + interval_product_distribution const& r_strategy) const + { + return boost::geometry::equals(l_domain.domain(), r_domain.domain()); + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + Point r; + for_each_coordinate(r, + detail::interval_sample(d, g)); + return r; + } + void reset(DomainGeometry const&) {}; +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry, + int Dim +> +struct default_strategy +< + Point, + DomainGeometry, + box_tag, + single_tag, //There are no MultiBoxes right now + Dim, + cartesian_tag +> : public interval_product_distribution { + typedef interval_product_distribution base; + using base::base; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_BOX_HPP diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp new file mode 100644 index 0000000000..3c09b366f4 --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp @@ -0,0 +1,100 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_SEGMENT_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_SEGMENT_HPP + +#include +#include + +#include +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +template +< + typename Point, + typename DomainGeometry +> +struct segment_linear_mapping_distribution +{ + segment_linear_mapping_distribution(DomainGeometry const& g) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + segment_linear_mapping_distribution const& r_strategy) const + { + return boost::geometry::equals(l_domain.domain(), r_domain.domain()); + } + + template + < + typename LengthType, + typename PointIn + > + static Point map(PointIn const& p1, PointIn const& p2, LengthType const& l) + { + Point r; + assign(r, p2); + subtract_point(r, p1); + multiply_value(r, l); + add_point(r, p1); + return r; + } + + template + Point apply(Gen& g, DomainGeometry const& d) + { + typedef typename select_most_precise + < + typename coordinate_type::type, + double + >::type sample_type; + std::uniform_real_distribution real_dist(0, 1); + typedef typename default_length_result::type + length_type; + boost::geometry::segment_view view(d); + return map(*view.begin(), *(view.begin() + 1), real_dist(g)); + } + void reset(DomainGeometry const&) {}; +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry, + int Dim +> +struct default_strategy +< + Point, + DomainGeometry, + segment_tag, + single_tag, + Dim, + cartesian_tag +> : public segment_linear_mapping_distribution { + typedef segment_linear_mapping_distribution base; + using base::base; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_SEGMENT_HPP diff --git a/include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp b/include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp new file mode 100644 index 0000000000..28df18f08f --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp @@ -0,0 +1,111 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_EDWILLIAMS_AVFORM_INTERMEDIATE_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_EDWILLIAMS_AVFORM_INTERMEDIATE_HPP + +#include +#include + +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +template +< + typename Point, + typename DomainGeometry +> +struct edwilliams_avform_intermediate +{ + edwilliams_avform_intermediate(DomainGeometry const& g) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + edwilliams_avform_intermediate const& r_strategy) const + { + return boost::geometry::equals(l_domain.domain(), r_domain.domain()); + } + + // The following implementation is adapted from + // https://www.edwilliams.org/avform.htm#Intermediate + template + < + typename LengthType, + typename PointIn + > + static Point map(PointIn const& p1, PointIn const& p2, LengthType const& f) + { + Point out; + const auto lat1 = get_as_radian<1>(p1); + const auto lon1 = get_as_radian<0>(p1); + const auto lat2 = get_as_radian<1>(p2); + const auto lon2 = get_as_radian<0>(p2); + LengthType const d = std::acos( + std::sin(lat1) * std::sin(lat2) + + std::cos(lat1) * std::cos(lat2) * std::cos(lon1 - lon2)); + LengthType const A = std::sin( ( 1 - f ) * d ) / std::sin(d); + LengthType const B = std::sin( f * d ) / std::sin( d ); + LengthType const x = A * std::cos(lat1) * std::cos(lon1) + + B * std::cos(lat2) * std::cos(lon2); + LengthType const y = A * std::cos(lat1) * std::sin(lon1) + + B * std::cos(lat2) * std::sin(lon2); + LengthType const z = A * std::sin(lat1) + B * std::sin(lat2); + LengthType const lat = std::atan2(z, std::sqrt(x * x + y * y)); + LengthType const lon = std::atan2(y, x); + set_from_radian<1>(out, lat); + set_from_radian<0>(out, lon); + return out; + } + + template + Point apply(Gen& g, DomainGeometry const& d) + { + typedef typename select_most_precise + < + typename coordinate_type::type, + double + >::type sample_type; + std::uniform_real_distribution real_dist(0, 1); + return map(d, real_dist(g)); + } + void reset(DomainGeometry const&) {}; +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry +> +struct default_strategy +< + Point, + DomainGeometry, + segment_tag, + single_tag, + 2, + spherical_tag +> : public edwilliams_avform_intermediate { + typedef edwilliams_avform_intermediate base; + using base::base; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_EDWILLIAMS_AVFORM_INTERMEDIATE_HPP diff --git a/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp b/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp new file mode 100644 index 0000000000..95389f2f6f --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp @@ -0,0 +1,156 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_INVERSE_TRANSFORM_SAMPLING_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_INVERSE_TRANSFORM_SAMPLING_HPP + +#include +#include + +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution +{ + +template +< + typename Point, + typename DomainGeometry, + int Dim +> +struct uniform_inverse_transform_sampling +{}; + +template +< + typename Point, + typename DomainGeometry +> +struct uniform_inverse_transform_sampling +{ + uniform_inverse_transform_sampling(DomainGeometry const& g) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_inverse_transform_sampling const& r_strategy) const + { + return boost::geometry::equals(l_domain.domain(), r_domain.domain()); + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + Point out; + typedef typename coordinate_type::type coordinate_type; + typedef typename select_most_precise + < + coordinate_type, + double + >::type computation_type; + std::uniform_real_distribution lon_dist( + get_as_radian<0, 0>(d), + get_as_radian<1, 0>(d)); + set_from_radian<0>(out, lon_dist(g)); + + coordinate_type lat1 = get_as_radian<0, 1>(d); + coordinate_type lat2 = get_as_radian<1, 1>(d); + coordinate_type x1 = (1.0 - std::cos(lat1)) / 2, + x2 = (1.0 - std::cos(lat2)) / 2; + std::uniform_real_distribution x_dist( + std::min(x1, x2), + std::max(x1, x2)); + coordinate_type x = x_dist(g); + set_from_radian<1>(out, std::acos(1.0 - 2.0 * x)); + return out; + } + void reset(DomainGeometry const&) {}; +}; + +template +< + typename Point, + typename DomainGeometry +> +struct uniform_inverse_transform_sampling +{ + uniform_inverse_transform_sampling(DomainGeometry const& g) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_inverse_transform_sampling const& r_strategy) const + { + return boost::geometry::equals(l_domain.domain(), r_domain.domain()); + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + uniform_inverse_transform_sampling helper(d); + Point out = helper.apply(g, d); + typedef typename coordinate_type::type coordinate_type; + typedef typename select_most_precise + < + coordinate_type, + double + >::type computation_type; + coordinate_type r1 = get<0, 2>(d); + coordinate_type r2 = get<1, 2>(d); + std::uniform_real_distribution + r_dist( r1 * r1 * r1 , r2 * r2 * r2 ); + set<2>(out, std::cbrt(r_dist(g))); + return out; + } + void reset(DomainGeometry const&) {}; +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry +> +struct default_strategy +< + Point, + DomainGeometry, + box_tag, + single_tag, //There are no MultiBoxes right now + 2, + spherical_tag +> : public uniform_inverse_transform_sampling { + typedef uniform_inverse_transform_sampling base; + using base::base; +}; + +template +< + typename Point, + typename DomainGeometry +> +struct default_strategy +< + Point, + DomainGeometry, + box_tag, + single_tag, //There are no MultiBoxes right now + 3, + spherical_tag +> : public uniform_inverse_transform_sampling { + typedef uniform_inverse_transform_sampling base; + using base::base; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_INVERSE_TRANSFORM_SAMPLING_HPP diff --git a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp new file mode 100644 index 0000000000..70670d94e3 --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp @@ -0,0 +1,57 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP + +#include +#include +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { namespace services +{ + +template +< + typename Point, + typename DomainGeometry, + typename Tag = typename tag_cast + < + typename tag::type, + segment_tag, + box_tag, + linear_tag, + areal_tag, + pointlike_tag + >::type, + typename MultiOrSingle = typename tag_cast + < + typename tag::type, + single_tag, + multi_tag + >::type, + int Dim = dimension::value, + typename CsTag = typename tag_cast + < + typename cs_tag::type, + spherical_tag + >::type +> +struct default_strategy +{}; + +}}} // namespace strategy::uniform_point_distribution::services + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp index 8669fccf18..83d35a68a1 100644 --- a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -9,7 +9,13 @@ #ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_UNIFORM_POINT_DISTRIBUTION_HPP #define BOOST_GEOMETRY_EXTENSIONS_RANDOM_UNIFORM_POINT_DISTRIBUTION_HPP -#include +#include +#include +#include +#include +#include +#include +#include namespace boost { namespace geometry { namespace random { @@ -17,15 +23,68 @@ namespace boost { namespace geometry { namespace random template < typename DomainGeometry, - typename Point = typename geometry::point_type::type + typename Point = typename geometry::point_type::type, + typename Strategy = + typename strategy::uniform_point_distribution::services::default_strategy + < + Point, + DomainGeometry + > > -class uniform_point_distribution : - public dispatch::uniform_point_distribution +class uniform_point_distribution { public: - typedef dispatch::uniform_point_distribution base; - using base::base; - uniform_point_distribution(DomainGeometry const& domain) : base(domain) {} + typedef Point result_type; + typedef DomainGeometry domain_type; + class param_type { + public: + param_type(DomainGeometry const& domain) : m_domain(domain) {} + param_type(param_type const& p) : m_domain(p.m_domain) {} + DomainGeometry const& domain() const { return m_domain; } + bool operator==(param_type const& rhs) const + { + return equals(m_domain, rhs.m_domain); + } + private: + DomainGeometry m_domain; + }; + uniform_point_distribution(DomainGeometry const& domain) + : m_strategy(domain), + m_param(domain) {} + uniform_point_distribution() + : m_strategy(DomainGeometry()), + m_param(DomainGeometry()) {} + uniform_point_distribution(param_type const& param) + : m_strategy(param.domain()), + m_param(param) {} + void reset() { m_strategy.reset(); } + param_type param() const { return m_param; } + void param(param_type const& p) + { + m_param = p; + m_strategy = Strategy(p.domain()); + } + bool operator==(uniform_point_distribution const& rhs) const + { + return m_strategy.equals(m_param.domain(), + rhs.domain(), + rhs.m_strategy); + } + domain_type const& domain() const { return m_param.domain(); } + template< typename Gen > + result_type operator()(Gen& g) + { + return m_strategy.apply(g, m_param.domain()); + } + template< typename Gen > + result_type operator()(Gen& g, param_type const& p) + { + Strategy strat(p.domain()); + return strat.apply(g, p.domain()); + } +private: + Strategy m_strategy; + param_type m_param; }; template From 1156767e5a8d1243a682270da17b4fae8784dbae Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Sat, 24 Aug 2019 18:22:44 +0200 Subject: [PATCH 07/12] provide not implemented message in default_strategy --- .../random/strategies/uniform_point_distribution.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp index 70670d94e3..89834b392a 100644 --- a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp @@ -9,6 +9,9 @@ #ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP #define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP +#include +#include + #include #include #include @@ -48,7 +51,13 @@ template >::type > struct default_strategy -{}; +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types>) + ); +}; }}} // namespace strategy::uniform_point_distribution::services From e981c4656edeb446f09bfb863e87d29499da67f9 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Sun, 25 Aug 2019 23:35:16 +0200 Subject: [PATCH 08/12] Add missing Strategy parameter. --- .../extensions/random/uniform_point_distribution.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp index 83d35a68a1..1a8d70632a 100644 --- a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -105,14 +105,15 @@ template typename Char, typename Traits, typename Point, - typename DomainGeometry + typename DomainGeometry, + typename Strategy > inline std::basic_ostream& operator<< ( std::basic_ostream &os, boost::geometry::random::uniform_point_distribution < - DomainGeometry, Point + DomainGeometry, Point, Strategy > const& dist ) { @@ -125,14 +126,15 @@ template typename Char, typename Traits, typename Point, - typename DomainGeometry + typename DomainGeometry, + typename Strategy > inline std::basic_istream& operator>> ( std::basic_istream &is, boost::geometry::random::uniform_point_distribution < - DomainGeometry, Point + DomainGeometry, Point, Strategy > & dist ) { @@ -142,7 +144,7 @@ inline std::basic_istream& operator>> namespace bg = boost::geometry; typedef typename bg::random::uniform_point_distribution < - DomainGeometry, Point + DomainGeometry, Point, Strategy >::param_type param_type; bg::read_wkt(line, g); dist.param( param_type(g) ); From 361861ca9fb37e37aad36f81bfbee84b686bd3e1 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Sun, 25 Aug 2019 23:37:00 +0200 Subject: [PATCH 09/12] Add some specialized distributions for rings that are triangles (cartesian 2d only at this time) or convex and a general rejection sampling strategy based on convex hull. --- .../agnostic/uniform_convex_fan.hpp | 95 +++++++++++++++++++ .../uniform_convex_hull_rejection.hpp | 82 ++++++++++++++++ .../uniform_point_distribution_triangle.hpp | 82 ++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_fan.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_fan.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_fan.hpp new file mode 100644 index 0000000000..cecdfda3b6 --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_fan.hpp @@ -0,0 +1,95 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_FAN_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_FAN_HPP + +#include +#include +#include +#include + +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +// The following strategy is suitable for convex rings and polygons with +// non-empty interior. +template +< + typename Point, + typename DomainGeometry, + typename TriangleStrategy, + typename SideStrategy //Actually, we need a triangle area strategy here. +> +struct uniform_convex_fan +{ +private: + std::vector accumulated_areas; + // It is hard to see a reason not to use double here. If a triangles + // relative size is smaller than doubles epsilon, it is too unlikely to + // realistically occur in a random sample anyway. +public: + uniform_convex_fan(DomainGeometry const& g) + { + accumulated_areas.push_back(0); + for (int i = 2 ; i < g.size() ; ++i) { + accumulated_areas.push_back( + accumulated_areas.back() + + std::abs(SideStrategy::template side_value( + *g.begin(), + *(g.begin() + i - 1), + *(g.begin() + i)))); + } + } + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_convex_fan const& r_strategy) const + { + if( l_domain.size() != r_domain.size() ) return false; + for (int i = 0; i < l_domain.size(); ++i) { + if( !boost::geometry::equals(*(l_domain.begin() + i), + *(r_domain.begin() + i))) + return false; + } + return true; + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + std::uniform_real_distribution dist(0, 1); + double r = dist(g) * accumulated_areas.back(), + s = dist(g); + std::size_t i = std::distance( + accumulated_areas.begin(), + std::lower_bound(accumulated_areas.begin(), + accumulated_areas.end(), + r)); + return TriangleStrategy::template map + < + double + >(* d.begin(), + *(d.begin() + i), + *(d.begin() + i + 1), + ( r - accumulated_areas[ i - 1 ]) / + ( accumulated_areas[ i ] - accumulated_areas[ i - 1 ] ), + s); + } + void reset(DomainGeometry const&) {}; +}; + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_FAN_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp new file mode 100644 index 0000000000..844c53733a --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp @@ -0,0 +1,82 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_HULL_REJECTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_HULL_REJECTION_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +// The following strategy is suitable for geometries for which +// a Triangle sampling strategy can be provided +// a SideStrategy that compues the triangle area can be provided. +template +< + typename Point, + typename DomainGeometry, + typename TriangleStrategy, + typename SideStrategy //Actually, we need a triangle area strategy here. +> +struct uniform_convex_hull_rejection +{ +private: + typedef typename point_type::type domain_point_type; + typedef boost::geometry::model::ring ring; + ring hull; + uniform_convex_fan + m_strategy; +public: + uniform_convex_hull_rejection(DomainGeometry const& g) : m_strategy(hull) + { + boost::geometry::convex_hull(g, hull); + m_strategy = + uniform_convex_fan + < + Point, + ring, + TriangleStrategy, + SideStrategy + >(hull); + } + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_convex_hull_rejection const& r_strategy) const + { + return boost::geometry::equals(l_domain, r_domain) + && m_strategy.equals(l_domain, r_domain, r_strategy.m_strategy); + } + template + Point apply(Gen& g, DomainGeometry const& d) + { + Point p; + do{ + p = m_strategy.apply(g, hull); + }while( !boost::geometry::within(p, d) ); + return p; + } + void reset(DomainGeometry const&) {}; +}; + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_HULL_REJECTION_HPP diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp new file mode 100644 index 0000000000..4daf0114ac --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp @@ -0,0 +1,82 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_TRIANGLE_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_TRIANGLE_HPP + +#include +#include + +#include +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { + +//The following strategy is suitable for rings or polygons of three points. +template +< + typename Point, + typename DomainGeometry +> +struct uniform_2d_cartesian_triangle +{ +private: + typedef typename point_type::type domain_point_type; +public: + uniform_2d_cartesian_triangle(DomainGeometry const& g) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_2d_cartesian_triangle const& r_strategy) const + { + return boost::geometry::equals(l_domain.domain(), r_domain.domain()); + } + + template + static Point map(domain_point_type const& p1, + domain_point_type const& p2, + domain_point_type const& p3, + sample_type const& s1, + sample_type const& s2) + { + Point out; + sample_type r1 = std::sqrt(s1); + set<0>(out, (1 - r1) * get<0>(p1) + + ( r1 * (1 - s2) ) * get<0>(p2) + + ( s2 * r1 * get<0>(p3))); + set<1>(out, (1 - r1) * get<1>(p1) + + ( r1 * (1 - s2) ) * get<1>(p2) + + ( s2 * r1 * get<1>(p3))); + return out; + } + + template + Point apply(Gen& g, DomainGeometry const& d) + { + typedef typename select_most_precise + < + typename coordinate_type::type, + double + >::type sample_type; + std::uniform_real_distribution real_dist(0, 1); + sample_type s1 = real_dist(g), + s2 = real_dist(g); + return map(*d.begin(), *(d.begin() + 1), *(d.begin() + 2), s1, s2); + } + void reset(DomainGeometry const&) {}; +}; + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_TRIANGLE_HPP From f24780335ea9b74c64f1c149f77451f46e80badf Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Thu, 5 Sep 2019 09:16:01 +0200 Subject: [PATCH 10/12] Replace cs-specific segment strategies with line_interpolate. --- .../strategies/agnostic/uniform_linear.hpp | 103 ++++++++++++---- .../uniform_point_distribution_segment.hpp | 100 ---------------- .../edwilliams_avform_intermediate.hpp | 111 ------------------ .../random/uniform_point_distribution.hpp | 2 - 4 files changed, 80 insertions(+), 236 deletions(-) delete mode 100644 include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp delete mode 100644 include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp index c869a685b9..37e6d9f1f6 100644 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp @@ -14,14 +14,15 @@ #include #include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include -#include -#include namespace boost { namespace geometry { @@ -32,13 +33,50 @@ template < typename Point, typename DomainGeometry, - typename SegmentStrategy = services::default_strategy - < - typename point_type::type, - model::segment::type> - > + typename InterpolationStrategy = + typename strategy::line_interpolate::services::default_strategy + < + typename cs_tag::type + >::type > -class uniform_linear +struct uniform_linear_single +{ + uniform_linear_single(DomainGeometry const& g) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + uniform_linear_single const& r_strategy) const + { + return boost::geometry::equals(l_domain, r_domain); + } + + template + Point apply(Gen& g, DomainGeometry const& d) + { + typedef typename select_most_precise + < + double, + typename coordinate_type::type + >::type sample_type; + std::uniform_real_distribution dist(0, length(d)); + sample_type r = dist(g); + Point p; + boost::geometry::line_interpolate(d, r, p); + return p; + } + void reset(DomainGeometry const&) {}; +}; + +template +< + typename Point, + typename DomainGeometry, + typename InterpolationStrategy = + typename strategy::line_interpolate::services::default_strategy + < + typename cs_tag::type + >::type +> +class uniform_linear_multi { private: typedef typename default_length_result::type length_type; @@ -47,7 +85,7 @@ class uniform_linear std::vector point_cache; std::vector accumulated_lengths; public: - uniform_linear(DomainGeometry const& g) + uniform_linear_multi(DomainGeometry const& g) { std::size_t i = 0; point_cache.push_back(*segments_begin(g)->first); @@ -67,7 +105,7 @@ class uniform_linear } bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, - uniform_linear const& r_strategy) const + uniform_linear_multi const& r_strategy) const { if(r_strategy.skip_list.size() != skip_list.size() || r_strategy.point_cache.size() != point_cache.size()) @@ -90,6 +128,7 @@ class uniform_linear double, typename coordinate_type::type >::type sample_type; + typedef model::segment segment; std::uniform_real_distribution dist(0, accumulated_lengths.back()); sample_type r = dist(g); std::size_t i = std::distance( @@ -100,20 +139,38 @@ class uniform_linear std::size_t offset = std::distance( skip_list.begin(), std::lower_bound(skip_list.begin(), skip_list.end(), i)); - - return SegmentStrategy::template map - < - sample_type, - domain_point_type - >(point_cache[ i + offset - 1 ], point_cache[ i + offset ], - ( r - accumulated_lengths[ i - 1 ]) / - ( accumulated_lengths[ i ] - accumulated_lengths[ i - 1 ] )); + Point p; + boost::geometry::line_interpolate( + segment(point_cache[ i + offset - 1], point_cache[ i + offset ]), + r - accumulated_lengths[ i - 1 ], + p); + return p; } void reset(DomainGeometry const&) {}; }; namespace services { +template +< + typename Point, + typename DomainGeometry, + int Dim, + typename CsTag +> +struct default_strategy +< + Point, + DomainGeometry, + segment_tag, + single_tag, + Dim, + CsTag +> : public uniform_linear_single { + typedef uniform_linear_single base; + using base::base; +}; + template < typename Point, @@ -130,8 +187,8 @@ struct default_strategy MultiOrSingle, Dim, CsTag -> : public uniform_linear { - typedef uniform_linear base; +> : public uniform_linear_multi { + typedef uniform_linear_multi base; using base::base; }; diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp deleted file mode 100644 index 3c09b366f4..0000000000 --- a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_segment.hpp +++ /dev/null @@ -1,100 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_SEGMENT_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_SEGMENT_HPP - -#include -#include - -#include -#include -#include - -#include - -namespace boost { namespace geometry -{ - -namespace strategy { namespace uniform_point_distribution { - -template -< - typename Point, - typename DomainGeometry -> -struct segment_linear_mapping_distribution -{ - segment_linear_mapping_distribution(DomainGeometry const& g) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - segment_linear_mapping_distribution const& r_strategy) const - { - return boost::geometry::equals(l_domain.domain(), r_domain.domain()); - } - - template - < - typename LengthType, - typename PointIn - > - static Point map(PointIn const& p1, PointIn const& p2, LengthType const& l) - { - Point r; - assign(r, p2); - subtract_point(r, p1); - multiply_value(r, l); - add_point(r, p1); - return r; - } - - template - Point apply(Gen& g, DomainGeometry const& d) - { - typedef typename select_most_precise - < - typename coordinate_type::type, - double - >::type sample_type; - std::uniform_real_distribution real_dist(0, 1); - typedef typename default_length_result::type - length_type; - boost::geometry::segment_view view(d); - return map(*view.begin(), *(view.begin() + 1), real_dist(g)); - } - void reset(DomainGeometry const&) {}; -}; - -namespace services { - -template -< - typename Point, - typename DomainGeometry, - int Dim -> -struct default_strategy -< - Point, - DomainGeometry, - segment_tag, - single_tag, - Dim, - cartesian_tag -> : public segment_linear_mapping_distribution { - typedef segment_linear_mapping_distribution base; - using base::base; -}; - -} // namespace services - -}} // namespace strategy::uniform_point_distribution - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_CARTESIAN_UNIFORM_POINT_DISTRIBUTION_SEGMENT_HPP diff --git a/include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp b/include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp deleted file mode 100644 index 28df18f08f..0000000000 --- a/include/boost/geometry/extensions/random/strategies/spherical/edwilliams_avform_intermediate.hpp +++ /dev/null @@ -1,111 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_EDWILLIAMS_AVFORM_INTERMEDIATE_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_EDWILLIAMS_AVFORM_INTERMEDIATE_HPP - -#include -#include - -#include -#include - -#include - -namespace boost { namespace geometry -{ - -namespace strategy { namespace uniform_point_distribution { - -template -< - typename Point, - typename DomainGeometry -> -struct edwilliams_avform_intermediate -{ - edwilliams_avform_intermediate(DomainGeometry const& g) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - edwilliams_avform_intermediate const& r_strategy) const - { - return boost::geometry::equals(l_domain.domain(), r_domain.domain()); - } - - // The following implementation is adapted from - // https://www.edwilliams.org/avform.htm#Intermediate - template - < - typename LengthType, - typename PointIn - > - static Point map(PointIn const& p1, PointIn const& p2, LengthType const& f) - { - Point out; - const auto lat1 = get_as_radian<1>(p1); - const auto lon1 = get_as_radian<0>(p1); - const auto lat2 = get_as_radian<1>(p2); - const auto lon2 = get_as_radian<0>(p2); - LengthType const d = std::acos( - std::sin(lat1) * std::sin(lat2) - + std::cos(lat1) * std::cos(lat2) * std::cos(lon1 - lon2)); - LengthType const A = std::sin( ( 1 - f ) * d ) / std::sin(d); - LengthType const B = std::sin( f * d ) / std::sin( d ); - LengthType const x = A * std::cos(lat1) * std::cos(lon1) - + B * std::cos(lat2) * std::cos(lon2); - LengthType const y = A * std::cos(lat1) * std::sin(lon1) - + B * std::cos(lat2) * std::sin(lon2); - LengthType const z = A * std::sin(lat1) + B * std::sin(lat2); - LengthType const lat = std::atan2(z, std::sqrt(x * x + y * y)); - LengthType const lon = std::atan2(y, x); - set_from_radian<1>(out, lat); - set_from_radian<0>(out, lon); - return out; - } - - template - Point apply(Gen& g, DomainGeometry const& d) - { - typedef typename select_most_precise - < - typename coordinate_type::type, - double - >::type sample_type; - std::uniform_real_distribution real_dist(0, 1); - return map(d, real_dist(g)); - } - void reset(DomainGeometry const&) {}; -}; - -namespace services { - -template -< - typename Point, - typename DomainGeometry -> -struct default_strategy -< - Point, - DomainGeometry, - segment_tag, - single_tag, - 2, - spherical_tag -> : public edwilliams_avform_intermediate { - typedef edwilliams_avform_intermediate base; - using base::base; -}; - -} // namespace services - -}} // namespace strategy::uniform_point_distribution - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_EDWILLIAMS_AVFORM_INTERMEDIATE_HPP diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp index 1a8d70632a..1b28906427 100644 --- a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include namespace boost { namespace geometry { namespace random From c899eb64bf905ef6713eeb5cb41fdad2eae46332 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Sun, 20 Oct 2019 16:43:59 +0200 Subject: [PATCH 11/12] [extensions][random] Naming and formatting fixes. GSoC acknowledgement --- extensions/example/random/random_example.cpp | 8 +++- extensions/test/random/random.cpp | 7 +++- .../uniform_convex_hull_rejection.hpp | 23 +++++----- ...hpp => uniform_convex_polygon_sampler.hpp} | 42 ++++++++++++------- .../agnostic/uniform_envelope_rejection.hpp | 13 +++--- .../strategies/agnostic/uniform_linear.hpp | 19 +++++---- .../uniform_point_distribution_discrete.hpp | 13 +++--- .../uniform_point_distribution_box.hpp | 11 +++-- .../uniform_point_distribution_triangle.hpp | 9 ++-- .../uniform_inverse_transform_sampling.hpp | 15 ++++--- .../strategies/uniform_point_distribution.hpp | 3 ++ .../random/uniform_point_distribution.hpp | 11 +++-- 12 files changed, 111 insertions(+), 63 deletions(-) rename include/boost/geometry/extensions/random/strategies/agnostic/{uniform_convex_fan.hpp => uniform_convex_polygon_sampler.hpp} (72%) diff --git a/extensions/example/random/random_example.cpp b/extensions/example/random/random_example.cpp index fd46a85c99..d3ecd8cdbb 100644 --- a/extensions/example/random/random_example.cpp +++ b/extensions/example/random/random_example.cpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -36,7 +39,10 @@ int main() std::default_random_engine generator(1); polygon poly; - boost::geometry::read_wkt("POLYGON((16 21,17.1226 17.5451,20.7553 17.5451,17.8164 15.4098,18.9389 11.9549,16 14.0902,13.0611 11.9549,14.1836 15.4098,11.2447 17.5451,14.8774 17.5451,16 21))", poly); + boost::geometry::read_wkt("POLYGON((16 21,17.1226 17.5451,20.7553 17.5451," + "17.8164 15.4098,18.9389 11.9549,16 14.0902,13.0611 11.9549," + "14.1836 15.4098,11.2447 17.5451,14.8774 17.5451,16 21))", + poly); box b(point(0, 0), point(10, 10)); segment s(point(11, 0), point(21, 10)); multi_point mp; diff --git a/extensions/test/random/random.cpp b/extensions/test/random/random.cpp index 89b8da75aa..29bcca49b9 100644 --- a/extensions/test/random/random.cpp +++ b/extensions/test/random/random.cpp @@ -3,6 +3,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -73,7 +76,9 @@ void test_polygon() typedef bg::model::polygon polygon; polygon poly; bg::read_wkt( - "POLYGON((16 21,17.1226 17.5451,20.7553 17.5451, 17.8164 15.4098,18.9389 11.9549,16 14.0902,13.0611 11.9549, 14.1836 15.4098,11.2447 17.5451,14.8774 17.5451,16 21))", + "POLYGON((16 21,17.1226 17.5451,20.7553 17.5451, 17.8164 15.4098," + "18.9389 11.9549,16 14.0902,13.0611 11.9549, 14.1836 15.4098," + "11.2447 17.5451,14.8774 17.5451,16 21))", poly); bg::random::uniform_point_distribution poly_dist(poly); bg::random::uniform_point_distribution poly_dist2; diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp index 844c53733a..b0505046e0 100644 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -18,7 +21,7 @@ #include #include -#include +#include namespace boost { namespace geometry { @@ -40,21 +43,21 @@ struct uniform_convex_hull_rejection private: typedef typename point_type::type domain_point_type; typedef boost::geometry::model::ring ring; - ring hull; - uniform_convex_fan + ring m_hull; + uniform_convex_polygon_sampler m_strategy; public: - uniform_convex_hull_rejection(DomainGeometry const& g) : m_strategy(hull) + uniform_convex_hull_rejection(DomainGeometry const& d) : m_strategy(m_hull) { - boost::geometry::convex_hull(g, hull); + boost::geometry::convex_hull(d, m_hull); m_strategy = - uniform_convex_fan + uniform_convex_polygon_sampler < Point, ring, TriangleStrategy, SideStrategy - >(hull); + >(m_hull); } bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, @@ -63,12 +66,12 @@ struct uniform_convex_hull_rejection return boost::geometry::equals(l_domain, r_domain) && m_strategy.equals(l_domain, r_domain, r_strategy.m_strategy); } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { Point p; do{ - p = m_strategy.apply(g, hull); + p = m_strategy.apply(g, m_hull); }while( !boost::geometry::within(p, d) ); return p; } diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_fan.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_polygon_sampler.hpp similarity index 72% rename from include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_fan.hpp rename to include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_polygon_sampler.hpp index cecdfda3b6..433929a9a8 100644 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_fan.hpp +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_polygon_sampler.hpp @@ -2,18 +2,22 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_FAN_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_FAN_HPP +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_POLYGON_SAMPLER_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_POLYGON_SAMPLER_HPP #include #include #include #include +#include #include #include #include @@ -32,7 +36,7 @@ template typename TriangleStrategy, typename SideStrategy //Actually, we need a triangle area strategy here. > -struct uniform_convex_fan +struct uniform_convex_polygon_sampler { private: std::vector accumulated_areas; @@ -40,36 +44,42 @@ struct uniform_convex_fan // relative size is smaller than doubles epsilon, it is too unlikely to // realistically occur in a random sample anyway. public: - uniform_convex_fan(DomainGeometry const& g) + uniform_convex_polygon_sampler(DomainGeometry const& d) { accumulated_areas.push_back(0); - for (int i = 2 ; i < g.size() ; ++i) { + for (std::size_t i = 2 ; i < boost::size(d) ; ++i) { accumulated_areas.push_back( accumulated_areas.back() + std::abs(SideStrategy::template side_value( - *g.begin(), - *(g.begin() + i - 1), - *(g.begin() + i)))); + *d.begin(), + *(d.begin() + i - 1), + *(d.begin() + i)))); } } bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, - uniform_convex_fan const& r_strategy) const + uniform_convex_polygon_sampler const& r_strategy) const { - if( l_domain.size() != r_domain.size() ) return false; - for (int i = 0; i < l_domain.size(); ++i) { + if( boost::size(l_domain) != boost::size(r_domain) ) + { + return false; + } + for (std::size_t i = 0; i < boost::size(l_domain); ++i) + { if( !boost::geometry::equals(*(l_domain.begin() + i), *(r_domain.begin() + i))) + { return false; + } } return true; } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { std::uniform_real_distribution dist(0, 1); - double r = dist(g) * accumulated_areas.back(), - s = dist(g); + double r = dist(g) * accumulated_areas.back(); + double s = dist(g); std::size_t i = std::distance( accumulated_areas.begin(), std::lower_bound(accumulated_areas.begin(), @@ -92,4 +102,4 @@ struct uniform_convex_fan }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_FAN_HPP +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_POLYGON_SAMPLER_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp index 606318aeea..830af9ce12 100644 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -44,8 +47,8 @@ struct uniform_envelope_rejection envelope_type m_env; BoxStrategy m_env_strat; public: - uniform_envelope_rejection(DomainGeometry const& g) : - m_env(return_envelope(g)), + uniform_envelope_rejection(DomainGeometry const& d) : + m_env(return_envelope(d)), m_env_strat(m_env) {} bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, @@ -53,14 +56,14 @@ struct uniform_envelope_rejection { return boost::geometry::equals(l_domain, r_domain); } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { typedef typename point_type::type domain_point; domain_point p; do { p = m_env_strat.apply(g, m_env); - }while( !::boost::geometry::within(p, d) ); + } while( !::boost::geometry::within(p, d) ); Point r; boost::geometry::transform(p, r); return r; diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp index 37e6d9f1f6..39255a3050 100644 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -41,7 +44,7 @@ template > struct uniform_linear_single { - uniform_linear_single(DomainGeometry const& g) {} + uniform_linear_single(DomainGeometry const& d) {} bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, uniform_linear_single const& r_strategy) const @@ -49,8 +52,8 @@ struct uniform_linear_single return boost::geometry::equals(l_domain, r_domain); } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { typedef typename select_most_precise < @@ -85,12 +88,12 @@ class uniform_linear_multi std::vector point_cache; std::vector accumulated_lengths; public: - uniform_linear_multi(DomainGeometry const& g) + uniform_linear_multi(DomainGeometry const& d) { std::size_t i = 0; - point_cache.push_back(*segments_begin(g)->first); + point_cache.push_back(*segments_begin(d)->first); accumulated_lengths.push_back(0); - for (auto it = segments_begin(g) ; it != segments_end(g) ; ++it) + for (auto it = segments_begin(d) ; it != segments_end(d) ; ++it) { accumulated_lengths.push_back( accumulated_lengths.back() + length(*it)); @@ -120,8 +123,8 @@ class uniform_linear_multi } return true; } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { typedef typename select_most_precise < diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp index 97ed5c953d..ccdf51cef0 100644 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp +++ b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -29,7 +32,7 @@ template > struct single_point_distribution { - single_point_distribution(DomainGeometry const& g) {} + single_point_distribution(DomainGeometry const& d) {} template bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, @@ -37,8 +40,8 @@ struct single_point_distribution { return boost::geometry::equals(l_domain.domain(), r_domain.domain()); } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { Point r; boost::geometry::transform(d, r); @@ -68,8 +71,8 @@ struct multi_point_distribution } return true; } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { Point r; if(boost::size(d) == 0) return r; diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp index 6a37158ad7..8efd372c44 100644 --- a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp +++ b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -76,19 +79,19 @@ template > struct interval_product_distribution { - interval_product_distribution(DomainGeometry const& g) {} + interval_product_distribution(DomainGeometry const& d) {} bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, interval_product_distribution const& r_strategy) const { return boost::geometry::equals(l_domain.domain(), r_domain.domain()); } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { Point r; for_each_coordinate(r, - detail::interval_sample(d, g)); + detail::interval_sample(d, g)); return r; } void reset(DomainGeometry const&) {}; diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp index 4daf0114ac..0702a42025 100644 --- a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp +++ b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -33,7 +36,7 @@ struct uniform_2d_cartesian_triangle private: typedef typename point_type::type domain_point_type; public: - uniform_2d_cartesian_triangle(DomainGeometry const& g) {} + uniform_2d_cartesian_triangle(DomainGeometry const& d) {} bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, uniform_2d_cartesian_triangle const& r_strategy) const @@ -59,8 +62,8 @@ struct uniform_2d_cartesian_triangle return out; } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { typedef typename select_most_precise < diff --git a/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp b/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp index 95389f2f6f..414284c79c 100644 --- a/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp +++ b/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -38,15 +41,15 @@ template > struct uniform_inverse_transform_sampling { - uniform_inverse_transform_sampling(DomainGeometry const& g) {} + uniform_inverse_transform_sampling(DomainGeometry const& d) {} bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, uniform_inverse_transform_sampling const& r_strategy) const { return boost::geometry::equals(l_domain.domain(), r_domain.domain()); } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { Point out; typedef typename coordinate_type::type coordinate_type; @@ -81,15 +84,15 @@ template > struct uniform_inverse_transform_sampling { - uniform_inverse_transform_sampling(DomainGeometry const& g) {} + uniform_inverse_transform_sampling(DomainGeometry const& d) {} bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, uniform_inverse_transform_sampling const& r_strategy) const { return boost::geometry::equals(l_domain.domain(), r_domain.domain()); } - template - Point apply(Gen& g, DomainGeometry const& d) + template + Point apply(Generator& g, DomainGeometry const& d) { uniform_inverse_transform_sampling helper(d); Point out = helper.apply(g, d); diff --git a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp index 89834b392a..1c2cd7f33d 100644 --- a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp index 1b28906427..6e8548d6c7 100644 --- a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -2,6 +2,9 @@ // Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -69,13 +72,13 @@ class uniform_point_distribution rhs.m_strategy); } domain_type const& domain() const { return m_param.domain(); } - template< typename Gen > - result_type operator()(Gen& g) + template< typename Generator > + result_type operator()(Generator& g) { return m_strategy.apply(g, m_param.domain()); } - template< typename Gen > - result_type operator()(Gen& g, param_type const& p) + template< typename Generator > + result_type operator()(Generator& g, param_type const& p) { Strategy strat(p.domain()); return strat.apply(g, p.domain()); From ec6adac13d6fa289a79af5f027775646859a5677 Mon Sep 17 00:00:00 2001 From: Tinko Bartels Date: Mon, 6 Apr 2020 14:37:25 +0200 Subject: [PATCH 12/12] Refactored code such that non-cs-specific code is moved to policies --- .../random/policies/uniform_box.hpp | 121 +++++++++ .../uniform_convex_hull_rejection.hpp | 129 +++++++++ .../policies/uniform_convex_polygon.hpp | 155 +++++++++++ .../policies/uniform_default_policy.hpp | 68 +++++ .../policies/uniform_envelope_rejection.hpp | 175 ++++++++++++ .../random/policies/uniform_linear.hpp | 249 ++++++++++++++++++ .../uniform_point_discrete.hpp} | 44 ++-- .../uniform_convex_hull_rejection.hpp | 85 ------ .../uniform_convex_polygon_sampler.hpp | 105 -------- .../agnostic/uniform_envelope_rejection.hpp | 122 --------- .../strategies/agnostic/uniform_linear.hpp | 204 -------------- .../uniform_point_distribution_box.hpp | 76 ++---- .../uniform_point_distribution_triangle.hpp | 66 +++-- .../uniform_inverse_transform_sampling.hpp | 159 ----------- .../uniform_point_distribution_box.hpp | 130 +++++++++ ...hpp => uniform_point_distribution_box.hpp} | 33 +-- .../uniform_point_distribution_triangle.hpp | 52 ++++ .../random/uniform_point_distribution.hpp | 55 ++-- 18 files changed, 1194 insertions(+), 834 deletions(-) create mode 100644 include/boost/geometry/extensions/random/policies/uniform_box.hpp create mode 100644 include/boost/geometry/extensions/random/policies/uniform_convex_hull_rejection.hpp create mode 100644 include/boost/geometry/extensions/random/policies/uniform_convex_polygon.hpp create mode 100644 include/boost/geometry/extensions/random/policies/uniform_default_policy.hpp create mode 100644 include/boost/geometry/extensions/random/policies/uniform_envelope_rejection.hpp create mode 100644 include/boost/geometry/extensions/random/policies/uniform_linear.hpp rename include/boost/geometry/extensions/random/{strategies/agnostic/uniform_point_distribution_discrete.hpp => policies/uniform_point_discrete.hpp} (65%) delete mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp delete mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_polygon_sampler.hpp delete mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp delete mode 100644 include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp delete mode 100644 include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp create mode 100644 include/boost/geometry/extensions/random/strategies/spherical/uniform_point_distribution_box.hpp rename include/boost/geometry/extensions/random/strategies/{uniform_point_distribution.hpp => uniform_point_distribution_box.hpp} (64%) create mode 100644 include/boost/geometry/extensions/random/strategies/uniform_point_distribution_triangle.hpp diff --git a/include/boost/geometry/extensions/random/policies/uniform_box.hpp b/include/boost/geometry/extensions/random/policies/uniform_box.hpp new file mode 100644 index 0000000000..5e390abf06 --- /dev/null +++ b/include/boost/geometry/extensions/random/policies/uniform_box.hpp @@ -0,0 +1,121 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2020 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_BOX_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_BOX_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +namespace boost { namespace geometry +{ + +namespace policy { namespace uniform_point_distribution +{ + +template +< + typename Point, + typename DomainGeometry, + typename BoxStrategy = void, + typename CalculationType = void +> +struct box +{ +private: + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::uniform_point_distribution::services:: + default_box_strategy + < + Point, + DomainGeometry + >::type, + BoxStrategy + >::type box_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename select_most_precise + < + typename coordinate_type::type, + double + >::type, + CalculationType + >::type ct; + box_strategy m_box_strategy; +public: + box(DomainGeometry const& d, box_strategy const& b = box_strategy()) : m_box_strategy(b) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + box const& r_policy) const + { + return boost::geometry::equals(l_domain, r_domain); + } + template + Point apply(Generator& g, DomainGeometry const& d) + { + typedef typename point_type::type domain_point; + domain_point p; + std::array::value> fractions; + std::uniform_real_distribution dist(0, 1); + std::generate(fractions.begin(), fractions.end(), std::bind(dist, std::ref(g))); + p = m_box_strategy.template apply<>(d, fractions); + Point r; + boost::geometry::transform(p, r); + return r; + } + void reset(DomainGeometry const&) {}; +}; + +namespace services +{ + +template +< + typename Point, + typename DomainGeometry, + int Dim, + typename CsTag +> +struct default_policy +< + Point, + DomainGeometry, + box_tag, + single_tag, + Dim, + CsTag +> +{ + typedef box type; +}; + +} // namespace services + +}} // namespace policy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_BOX_HPP diff --git a/include/boost/geometry/extensions/random/policies/uniform_convex_hull_rejection.hpp b/include/boost/geometry/extensions/random/policies/uniform_convex_hull_rejection.hpp new file mode 100644 index 0000000000..1ba3510c10 --- /dev/null +++ b/include/boost/geometry/extensions/random/policies/uniform_convex_hull_rejection.hpp @@ -0,0 +1,129 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2020 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_CONVEX_HULL_REJECTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_CONVEX_HULL_REJECTION_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace boost { namespace geometry +{ + +namespace policy { namespace uniform_point_distribution +{ + +// The following strategy is suitable for geometries for which +// a Triangle sampling strategy can be provided +// a SideStrategy that computes the triangle area can be provided. +template +< + typename Point, + typename DomainGeometry, + typename TriangleStrategy = void, + typename AreaStrategy = void, +// typename ConvexHullStrategy + typename WithinStrategy = void +> +struct convex_hull_rejection +{ +private: + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::uniform_point_distribution::services + ::default_triangle_strategy + < + Point, typename point_type::type + >::type, + TriangleStrategy + >::type triangle_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::area::services::default_strategy + < + typename cs_tag::type + >::type, + AreaStrategy + >::type area_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::within::services::default_strategy + < + Point, + DomainGeometry + >::type, + WithinStrategy + >::type within_strategy; + typedef typename point_type::type domain_point_type; + typedef boost::geometry::model::ring ring; + ring m_hull; + convex_polygon m_policy; + within_strategy m_within_strategy; +public: + convex_hull_rejection(DomainGeometry const& d, + triangle_strategy const& t = triangle_strategy(), + area_strategy const& a = area_strategy(), + within_strategy const& w = within_strategy()) : m_within_strategy(w) + + { + boost::geometry::convex_hull(d, m_hull); + m_policy = convex_polygon + < + Point, + ring, + triangle_strategy, + area_strategy + >(m_hull, t, a); + } + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + convex_hull_rejection const& r_policy) const + { + return boost::geometry::equals(l_domain, r_domain) + && m_policy.equals(l_domain, r_domain, r_policy.m_policy); + } + template + Point apply(Generator& g, DomainGeometry const& d) + { + Point p; + do { + p = m_policy.apply(g, m_hull); + } while( !boost::geometry::within(p, d, m_within_strategy) ); + return p; + } + void reset(DomainGeometry const&) {}; +}; + +}} // namespace policy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_HULL_REJECTION_HPP diff --git a/include/boost/geometry/extensions/random/policies/uniform_convex_polygon.hpp b/include/boost/geometry/extensions/random/policies/uniform_convex_polygon.hpp new file mode 100644 index 0000000000..05d6220b0e --- /dev/null +++ b/include/boost/geometry/extensions/random/policies/uniform_convex_polygon.hpp @@ -0,0 +1,155 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2020 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_CONVEX_POLYGON_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_CONVEX_POLYGON_HPP + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace policy { namespace uniform_point_distribution +{ + +// The following policy is suitable for convex rings and polygons with +// non-empty interior. +template +< + typename Point, + typename DomainGeometry, + typename TriangleStrategy = void, + typename AreaStrategy = void, + typename CalculationType = void +> +struct convex_polygon +{ +private: + typedef typename boost::mpl::if_ + < + boost::is_void, + typename select_most_precise + < + typename coordinate_type::type, + double + >::type, + CalculationType + >::type ct; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::area::services::default_strategy + < + typename cs_tag::type + >::type, + AreaStrategy + >::type area_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::uniform_point_distribution::services + ::default_triangle_strategy + < + Point, typename point_type::type + >::type, + TriangleStrategy + >::type triangle_strategy; + typedef typename area_strategy::template state area_state; + typedef typename area_strategy::template result_type area_result; + std::vector m_accumulated_areas; + triangle_strategy m_triangle; + // It is hard to see a reason not to use double here. If a triangle's + // relative size is smaller than doubles epsilon, it is too unlikely to + // realistically occur in a random sample. +public: + convex_polygon() {} + convex_polygon(DomainGeometry const& d, + triangle_strategy const& t = triangle_strategy(), + area_strategy const& a = area_strategy()) : + m_triangle(t) + { + m_accumulated_areas.reserve(boost::size(d) - 1); + m_accumulated_areas.push_back(0); + for (std::size_t i = 2 ; i < boost::size(d) ; ++i) { + area_state state; + a.apply(*d.begin(), *(d.begin() + i - 1), state); + a.apply(*(d.begin() + i - 1), *(d.begin() + i), state); + a.apply(*(d.begin() + i), *d.begin(), state); + ct s; + if(boost::geometry::point_order::value == boost::geometry::clockwise) + { + s = area_strategy::result(state); + } else { + s = -area_strategy::result(state); + } + m_accumulated_areas.push_back(m_accumulated_areas.back() + s); + } + } + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + convex_polygon const& r_strategy) const + { + if( boost::size(l_domain) != boost::size(r_domain) ) + { + return false; + } + for (std::size_t i = 0; i < boost::size(l_domain); ++i) + { + if( !boost::geometry::equals(*(l_domain.begin() + i), + *(r_domain.begin() + i))) + { + return false; + } + } + return true; + } + template + Point apply(Generator& g, DomainGeometry const& d) + { + std::uniform_real_distribution dist(0, 1); + ct r = dist(g) * m_accumulated_areas.back(); + ct s = dist(g); + std::size_t i = std::distance( + m_accumulated_areas.begin(), + std::lower_bound(m_accumulated_areas.begin(), + m_accumulated_areas.end(), + r)); + return m_triangle.template apply + < + ct + >(* d.begin(), + *(d.begin() + i), + *(d.begin() + i + 1), + ( r - m_accumulated_areas[ i - 1 ]) / + ( m_accumulated_areas[ i ] - m_accumulated_areas[ i - 1 ] ), + s); + } + void reset(DomainGeometry const&) {}; +}; + +}} // namespace policy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_CONVEX_POLYGON_HPP diff --git a/include/boost/geometry/extensions/random/policies/uniform_default_policy.hpp b/include/boost/geometry/extensions/random/policies/uniform_default_policy.hpp new file mode 100644 index 0000000000..d5a1fd0acd --- /dev/null +++ b/include/boost/geometry/extensions/random/policies/uniform_default_policy.hpp @@ -0,0 +1,68 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2020 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_DEFAULT_POLICY_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_DEFAULT_POLICY_HPP + +#include +#include +#include +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace policy { namespace uniform_point_distribution { namespace services +{ + +template +< + typename Point, + typename DomainGeometry, + typename Tag = typename tag_cast + < + typename tag::type, + segment_tag, + box_tag, + linear_tag, + areal_tag, + pointlike_tag + >::type, + typename SingleOrMulti = typename tag_cast + < + typename tag::type, + single_tag, + multi_tag + >::type, + int Dim = dimension::value, + typename CsTag = typename tag_cast + < + typename cs_tag::type, + spherical_tag + >::type +> +struct default_policy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types, CsTag>) + ); +}; + +}}} // namespace policy::uniform_point_distribution::services + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_DEFAULT_POLICY_HPP diff --git a/include/boost/geometry/extensions/random/policies/uniform_envelope_rejection.hpp b/include/boost/geometry/extensions/random/policies/uniform_envelope_rejection.hpp new file mode 100644 index 0000000000..3e4e9d3809 --- /dev/null +++ b/include/boost/geometry/extensions/random/policies/uniform_envelope_rejection.hpp @@ -0,0 +1,175 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2020 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_ENVELOPE_REJECTION_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_ENVELOPE_REJECTION_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace boost { namespace geometry +{ + +namespace policy { namespace uniform_point_distribution +{ + +template +< + typename Point, + typename DomainGeometry, + typename BoxStrategy = void, + typename EnvelopeStrategy = void, + typename WithinStrategy = void, + typename CalculationType = void +> +struct envelope_rejection +{ +private: + typedef model::box::type> envelope_type; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::uniform_point_distribution::services:: + default_box_strategy + < + Point, + envelope_type + >::type, + BoxStrategy + >::type box_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::envelope::services::default_strategy + < + typename tag::type, + typename cs_tag::type + >::type, + EnvelopeStrategy + >::type envelope_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename boost::geometry::strategy::within::services::default_strategy + < + Point, + DomainGeometry + >::type, + WithinStrategy + >::type within_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename select_most_precise + < + typename coordinate_type::type, + double + >::type, + CalculationType + >::type ct; + box_strategy m_box_strategy; + within_strategy m_within_strategy; + envelope_type m_env; +public: + envelope_rejection(DomainGeometry const& d, + box_strategy const& b = box_strategy(), + envelope_strategy const& e = envelope_strategy(), + within_strategy const& w = within_strategy()) : + m_box_strategy(b), + m_within_strategy(w), + m_env(return_envelope(d, e)) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + envelope_rejection const&) const + { + return boost::geometry::equals(l_domain, r_domain); + } + template + Point apply(Generator& g, DomainGeometry const& d) + { + typedef typename point_type::type domain_point; + domain_point p; + do { + std::array::value> fractions; + std::uniform_real_distribution dist(0, 1); + std::generate(fractions.begin(), fractions.end(), std::bind(dist, std::ref(g))); + p = m_box_strategy.template apply(m_env, fractions); + } while( ! ::boost::geometry::within(p, d, m_within_strategy) ); + Point r; + boost::geometry::transform(p, r); + return r; + } + void reset(DomainGeometry const&) {}; +}; + +namespace services +{ + +template +< + typename Point, + typename DomainGeometry, + typename MultiOrSingle, + typename CsTag +> +struct default_policy +< + Point, + DomainGeometry, + areal_tag, + MultiOrSingle, + 2, + CsTag +> +{ + typedef envelope_rejection type; +}; + +template +< + typename Point, + typename DomainGeometry, + typename MultiOrSingle, + typename CsTag +> +struct default_policy +< + Point, + DomainGeometry, + volumetric_tag, + MultiOrSingle, + 3, + CsTag +> +{ + typedef envelope_rejection type; +}; + +} // namespace services + +}} // namespace policy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_ENVELOPE_REJECTION_HPP diff --git a/include/boost/geometry/extensions/random/policies/uniform_linear.hpp b/include/boost/geometry/extensions/random/policies/uniform_linear.hpp new file mode 100644 index 0000000000..4caf052538 --- /dev/null +++ b/include/boost/geometry/extensions/random/policies/uniform_linear.hpp @@ -0,0 +1,249 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2020 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_LINEAR_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_LINEAR_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { namespace geometry +{ + +namespace policy { namespace uniform_point_distribution { + +template +< + typename Point, + typename DomainGeometry, + typename InterpolationStrategy = void, + typename DistanceStrategy = void +> +struct linear_single +{ +private: + typedef typename boost::mpl::if_ + < + boost::is_void, + typename strategy::line_interpolate::services::default_strategy + < + typename cs_tag::type + >::type, + InterpolationStrategy + >::type interpolation_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename strategy::distance::services::default_strategy + < + point_tag, point_tag, Point + >::type, + DistanceStrategy + >::type distance_strategy; + interpolation_strategy m_interpolation_strategy; + distance_strategy m_distance_strategy; +public: + linear_single(DomainGeometry const& d, + interpolation_strategy const& s = interpolation_strategy(), + distance_strategy const& l = distance_strategy()) : + m_interpolation_strategy(s), + m_distance_strategy(l) {} + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + linear_single const&) const + { + return boost::geometry::equals(l_domain, r_domain); + } + template + Point apply(Generator& g, DomainGeometry const& d) + { + typedef typename select_most_precise + < + double, + typename coordinate_type::type + >::type sample_type; + std::uniform_real_distribution dist(0, length(d, m_distance_strategy)); + sample_type r = dist(g); + Point p; + boost::geometry::line_interpolate(d, r, p, m_interpolation_strategy); + return p; + } + void reset(DomainGeometry const&) {}; +}; + +template +< + typename Point, + typename DomainGeometry, + typename InterpolationStrategy = void, + typename DistanceStrategy = void +> +class linear_multi +{ +private: + typedef typename default_length_result::type length_type; + typedef typename point_type::type domain_point_type; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename strategy::line_interpolate::services::default_strategy + < + typename cs_tag::type + >::type, + InterpolationStrategy + >::type interpolation_strategy; + typedef typename boost::mpl::if_ + < + boost::is_void, + typename strategy::distance::services::default_strategy + < + point_tag, point_tag, Point + >::type, + DistanceStrategy + >::type distance_strategy; + std::vector skip_list; + std::vector point_cache; + std::vector m_accumulated_lengths; + interpolation_strategy m_interpolation_strategy; +public: + linear_multi(DomainGeometry const& d, + interpolation_strategy const& in = interpolation_strategy(), + distance_strategy const& l = distance_strategy()) : + m_interpolation_strategy(in) + { + std::size_t i = 0; + point_cache.push_back(*segments_begin(d)->first); + m_accumulated_lengths.push_back(0); + for (auto it = segments_begin(d) ; it != segments_end(d) ; ++it) + { + m_accumulated_lengths.push_back( + m_accumulated_lengths.back() + length(*it, l)); + if (!boost::geometry::equals(point_cache.back(), *it->first)) + { + point_cache.push_back(*it->first); + skip_list.push_back(i); + } + point_cache.push_back(*it->second); + ++i; + } + } + bool equals(DomainGeometry const& l_domain, + DomainGeometry const& r_domain, + linear_multi const& r_policy) const + { + if(r_policy.skip_list.size() != skip_list.size() + || r_policy.point_cache.size() != point_cache.size()) + return false; + for (std::size_t i = 0; i < skip_list.size(); ++i) + { + if (skip_list[i] != r_policy.skip_list[i]) return false; + } + for (std::size_t i = 0; i < point_cache.size(); ++i) + { + if (!boost::geometry::equals(point_cache[i], r_policy.point_cache[i])) return false; + } + return true; + } + template + Point apply(Generator& g, DomainGeometry const& d) + { + typedef typename select_most_precise + < + double, + typename coordinate_type::type + >::type sample_type; + typedef model::segment segment; + std::uniform_real_distribution dist(0, m_accumulated_lengths.back()); + sample_type r = dist(g); + std::size_t i = std::distance( + m_accumulated_lengths.begin(), + std::lower_bound(m_accumulated_lengths.begin(), + m_accumulated_lengths.end(), + r)); + std::size_t offset = std::distance( + skip_list.begin(), + std::lower_bound(skip_list.begin(), skip_list.end(), i)); + Point p; + boost::geometry::line_interpolate( + segment(point_cache[ i + offset - 1], point_cache[ i + offset ]), + r - m_accumulated_lengths[ i - 1 ], + p, + m_interpolation_strategy); + return p; + } + void reset(DomainGeometry const&) {}; +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry, + int Dim, + typename CsTag +> +struct default_policy +< + Point, + DomainGeometry, + segment_tag, + single_tag, + Dim, + CsTag +> +{ + typedef linear_single type; +}; + +template +< + typename Point, + typename DomainGeometry, + typename MultiOrSingle, + int Dim, + typename CsTag +> +struct default_policy +< + Point, + DomainGeometry, + linear_tag, + MultiOrSingle, + Dim, + CsTag +> +{ + typedef linear_multi type; +}; + +} // namespace services + +}} // namespace policy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_LINEAR_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp b/include/boost/geometry/extensions/random/policies/uniform_point_discrete.hpp similarity index 65% rename from include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp rename to include/boost/geometry/extensions/random/policies/uniform_point_discrete.hpp index ccdf51cef0..9bde4e90c6 100644 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_point_distribution_discrete.hpp +++ b/include/boost/geometry/extensions/random/policies/uniform_point_discrete.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. +// Copyright (c) 2020 Tinko Bartels, Berlin, Germany. // Contributed and/or modified by Tinko Bartels, // as part of Google Summer of Code 2019 program. @@ -9,8 +9,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_POINT_DISTRIBUTION_DISCRETE_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_POINT_DISTRIBUTION_DISCRETE_HPP +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_POINT_DISCRETE_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_POINT_DISCRETE_HPP #include #include @@ -18,25 +18,25 @@ #include #include -#include +#include namespace boost { namespace geometry { -namespace strategy { namespace uniform_point_distribution { +namespace policy { namespace uniform_point_distribution { template < typename Point, typename DomainGeometry > -struct single_point_distribution +struct single_point { - single_point_distribution(DomainGeometry const& d) {} - template + single_point(DomainGeometry const& d) {} + template bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, - Strategy const& r_strategy) const + Policy const&) const { return boost::geometry::equals(l_domain.domain(), r_domain.domain()); } @@ -55,12 +55,12 @@ template typename Point, typename DomainGeometry > -struct multi_point_distribution +struct multi_point { - multi_point_distribution(DomainGeometry const& p) {} + multi_point(DomainGeometry const& p) {} bool equals(DomainGeometry const& l_domain, DomainGeometry const& r_domain, - multi_point_distribution const& r_strategy) const + multi_point const&) const { if(boost::size(l_domain) != boost::size(r_domain)) return false; for (std::size_t i = 0; i < boost::size(l_domain); ++i) @@ -93,7 +93,7 @@ template int Dim, typename CsTag > -struct default_strategy +struct default_policy < Point, DomainGeometry, @@ -101,9 +101,9 @@ struct default_strategy single_tag, Dim, CsTag -> : public single_point_distribution { - typedef single_point_distribution base; - using base::base; +> +{ + typedef single_point type; }; template @@ -113,7 +113,7 @@ template int Dim, typename CsTag > -struct default_strategy +struct default_policy < Point, DomainGeometry, @@ -121,15 +121,15 @@ struct default_strategy multi_tag, Dim, CsTag -> : public multi_point_distribution { - typedef multi_point_distribution base; - using base::base; +> +{ + typedef multi_point type; }; } // namespace services -}} // namespace strategy::uniform_point_distribution +}} // namespace policy::uniform_point_distribution }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_POINT_DISTRIBUTION_DISCRETE_HPP +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_POLICIES_UNIFORM_POINT_DISCRETE_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp deleted file mode 100644 index b0505046e0..0000000000 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_hull_rejection.hpp +++ /dev/null @@ -1,85 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Contributed and/or modified by Tinko Bartels, -// as part of Google Summer of Code 2019 program. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_HULL_REJECTION_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_HULL_REJECTION_HPP - -#include -#include - -#include -#include -#include -#include -#include - -#include - -namespace boost { namespace geometry -{ - -namespace strategy { namespace uniform_point_distribution { - -// The following strategy is suitable for geometries for which -// a Triangle sampling strategy can be provided -// a SideStrategy that compues the triangle area can be provided. -template -< - typename Point, - typename DomainGeometry, - typename TriangleStrategy, - typename SideStrategy //Actually, we need a triangle area strategy here. -> -struct uniform_convex_hull_rejection -{ -private: - typedef typename point_type::type domain_point_type; - typedef boost::geometry::model::ring ring; - ring m_hull; - uniform_convex_polygon_sampler - m_strategy; -public: - uniform_convex_hull_rejection(DomainGeometry const& d) : m_strategy(m_hull) - { - boost::geometry::convex_hull(d, m_hull); - m_strategy = - uniform_convex_polygon_sampler - < - Point, - ring, - TriangleStrategy, - SideStrategy - >(m_hull); - } - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_convex_hull_rejection const& r_strategy) const - { - return boost::geometry::equals(l_domain, r_domain) - && m_strategy.equals(l_domain, r_domain, r_strategy.m_strategy); - } - template - Point apply(Generator& g, DomainGeometry const& d) - { - Point p; - do{ - p = m_strategy.apply(g, m_hull); - }while( !boost::geometry::within(p, d) ); - return p; - } - void reset(DomainGeometry const&) {}; -}; - -}} // namespace strategy::uniform_point_distribution - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_HULL_REJECTION_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_polygon_sampler.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_polygon_sampler.hpp deleted file mode 100644 index 433929a9a8..0000000000 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_convex_polygon_sampler.hpp +++ /dev/null @@ -1,105 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Contributed and/or modified by Tinko Bartels, -// as part of Google Summer of Code 2019 program. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_POLYGON_SAMPLER_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_POLYGON_SAMPLER_HPP - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace boost { namespace geometry -{ - -namespace strategy { namespace uniform_point_distribution { - -// The following strategy is suitable for convex rings and polygons with -// non-empty interior. -template -< - typename Point, - typename DomainGeometry, - typename TriangleStrategy, - typename SideStrategy //Actually, we need a triangle area strategy here. -> -struct uniform_convex_polygon_sampler -{ -private: - std::vector accumulated_areas; - // It is hard to see a reason not to use double here. If a triangles - // relative size is smaller than doubles epsilon, it is too unlikely to - // realistically occur in a random sample anyway. -public: - uniform_convex_polygon_sampler(DomainGeometry const& d) - { - accumulated_areas.push_back(0); - for (std::size_t i = 2 ; i < boost::size(d) ; ++i) { - accumulated_areas.push_back( - accumulated_areas.back() + - std::abs(SideStrategy::template side_value( - *d.begin(), - *(d.begin() + i - 1), - *(d.begin() + i)))); - } - } - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_convex_polygon_sampler const& r_strategy) const - { - if( boost::size(l_domain) != boost::size(r_domain) ) - { - return false; - } - for (std::size_t i = 0; i < boost::size(l_domain); ++i) - { - if( !boost::geometry::equals(*(l_domain.begin() + i), - *(r_domain.begin() + i))) - { - return false; - } - } - return true; - } - template - Point apply(Generator& g, DomainGeometry const& d) - { - std::uniform_real_distribution dist(0, 1); - double r = dist(g) * accumulated_areas.back(); - double s = dist(g); - std::size_t i = std::distance( - accumulated_areas.begin(), - std::lower_bound(accumulated_areas.begin(), - accumulated_areas.end(), - r)); - return TriangleStrategy::template map - < - double - >(* d.begin(), - *(d.begin() + i), - *(d.begin() + i + 1), - ( r - accumulated_areas[ i - 1 ]) / - ( accumulated_areas[ i ] - accumulated_areas[ i - 1 ] ), - s); - } - void reset(DomainGeometry const&) {}; -}; - -}} // namespace strategy::uniform_point_distribution - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_CONVEX_POLYGON_SAMPLER_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp deleted file mode 100644 index 830af9ce12..0000000000 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_envelope_rejection.hpp +++ /dev/null @@ -1,122 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Contributed and/or modified by Tinko Bartels, -// as part of Google Summer of Code 2019 program. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_ENVELOPE_REJECTION_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_ENVELOPE_REJECTION_HPP - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace boost { namespace geometry -{ - -namespace strategy { namespace uniform_point_distribution { - -template -< - typename Point, - typename DomainGeometry, - typename BoxStrategy = services::default_strategy - < - typename point_type::type, - model::box::type> - > -> -struct uniform_envelope_rejection -{ -private: - typedef model::box::type> envelope_type; - envelope_type m_env; - BoxStrategy m_env_strat; -public: - uniform_envelope_rejection(DomainGeometry const& d) : - m_env(return_envelope(d)), - m_env_strat(m_env) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_envelope_rejection const& r_strategy) const - { - return boost::geometry::equals(l_domain, r_domain); - } - template - Point apply(Generator& g, DomainGeometry const& d) - { - typedef typename point_type::type domain_point; - domain_point p; - do { - p = m_env_strat.apply(g, m_env); - } while( !::boost::geometry::within(p, d) ); - Point r; - boost::geometry::transform(p, r); - return r; - } - void reset(DomainGeometry const&) {}; -}; - -namespace services { - -template -< - typename Point, - typename DomainGeometry, - typename MultiOrSingle, - typename CsTag -> -struct default_strategy -< - Point, - DomainGeometry, - areal_tag, - MultiOrSingle, - 2, - CsTag -> : public uniform_envelope_rejection { - typedef uniform_envelope_rejection base; - using base::base; -}; - -template -< - typename Point, - typename DomainGeometry, - typename MultiOrSingle, - typename CsTag -> -struct default_strategy -< - Point, - DomainGeometry, - volumetric_tag, - MultiOrSingle, - 3, - CsTag -> : public uniform_envelope_rejection { - typedef uniform_envelope_rejection base; - using base::base; -}; - -} // namespace services - -}} // namespace strategy::uniform_point_distribution - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_ENVELOPE_REJECTION_HPP diff --git a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp b/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp deleted file mode 100644 index 39255a3050..0000000000 --- a/include/boost/geometry/extensions/random/strategies/agnostic/uniform_linear.hpp +++ /dev/null @@ -1,204 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Contributed and/or modified by Tinko Bartels, -// as part of Google Summer of Code 2019 program. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_LINEAR_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_LINEAR_HPP - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace boost { namespace geometry -{ - -namespace strategy { namespace uniform_point_distribution { - -template -< - typename Point, - typename DomainGeometry, - typename InterpolationStrategy = - typename strategy::line_interpolate::services::default_strategy - < - typename cs_tag::type - >::type -> -struct uniform_linear_single -{ - uniform_linear_single(DomainGeometry const& d) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_linear_single const& r_strategy) const - { - return boost::geometry::equals(l_domain, r_domain); - } - - template - Point apply(Generator& g, DomainGeometry const& d) - { - typedef typename select_most_precise - < - double, - typename coordinate_type::type - >::type sample_type; - std::uniform_real_distribution dist(0, length(d)); - sample_type r = dist(g); - Point p; - boost::geometry::line_interpolate(d, r, p); - return p; - } - void reset(DomainGeometry const&) {}; -}; - -template -< - typename Point, - typename DomainGeometry, - typename InterpolationStrategy = - typename strategy::line_interpolate::services::default_strategy - < - typename cs_tag::type - >::type -> -class uniform_linear_multi -{ -private: - typedef typename default_length_result::type length_type; - typedef typename point_type::type domain_point_type; - std::vector skip_list; - std::vector point_cache; - std::vector accumulated_lengths; -public: - uniform_linear_multi(DomainGeometry const& d) - { - std::size_t i = 0; - point_cache.push_back(*segments_begin(d)->first); - accumulated_lengths.push_back(0); - for (auto it = segments_begin(d) ; it != segments_end(d) ; ++it) - { - accumulated_lengths.push_back( - accumulated_lengths.back() + length(*it)); - if (!boost::geometry::equals(point_cache.back(), *it->first)) - { - point_cache.push_back(*it->first); - skip_list.push_back(i); - } - point_cache.push_back(*it->second); - ++i; - } - } - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_linear_multi const& r_strategy) const - { - if(r_strategy.skip_list.size() != skip_list.size() - || r_strategy.point_cache.size() != point_cache.size()) - return false; - for (std::size_t i = 0; i < skip_list.size(); ++i) - { - if (skip_list[i] != r_strategy.skip_list[i]) return false; - } - for (std::size_t i = 0; i < point_cache.size(); ++i) - { - if (!boost::geometry::equals(point_cache[i], r_strategy.point_cache[i])) return false; - } - return true; - } - template - Point apply(Generator& g, DomainGeometry const& d) - { - typedef typename select_most_precise - < - double, - typename coordinate_type::type - >::type sample_type; - typedef model::segment segment; - std::uniform_real_distribution dist(0, accumulated_lengths.back()); - sample_type r = dist(g); - std::size_t i = std::distance( - accumulated_lengths.begin(), - std::lower_bound(accumulated_lengths.begin(), - accumulated_lengths.end(), - r)); - std::size_t offset = std::distance( - skip_list.begin(), - std::lower_bound(skip_list.begin(), skip_list.end(), i)); - Point p; - boost::geometry::line_interpolate( - segment(point_cache[ i + offset - 1], point_cache[ i + offset ]), - r - accumulated_lengths[ i - 1 ], - p); - return p; - } - void reset(DomainGeometry const&) {}; -}; - -namespace services { - -template -< - typename Point, - typename DomainGeometry, - int Dim, - typename CsTag -> -struct default_strategy -< - Point, - DomainGeometry, - segment_tag, - single_tag, - Dim, - CsTag -> : public uniform_linear_single { - typedef uniform_linear_single base; - using base::base; -}; - -template -< - typename Point, - typename DomainGeometry, - typename MultiOrSingle, - int Dim, - typename CsTag -> -struct default_strategy -< - Point, - DomainGeometry, - linear_tag, - MultiOrSingle, - Dim, - CsTag -> : public uniform_linear_multi { - typedef uniform_linear_multi base; - using base::base; -}; - -} // namespace services - -}} // namespace strategy::uniform_point_distribution - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_AGNOSTIC_UNIFORM_LINEAR_HPP diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp index 8efd372c44..4ea835797f 100644 --- a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp +++ b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_box.hpp @@ -18,58 +18,36 @@ #include #include -#include +#include namespace boost { namespace geometry { -namespace strategy { namespace uniform_point_distribution { +namespace strategy { namespace uniform_point_distribution +{ namespace detail { -template -< - typename Point, - typename Box, - typename Generator, - bool isIntegral = - boost::is_integral::type>::type::value -> -struct interval_sample {}; - -template -struct interval_sample +template +struct interval_product { - Box const& b; - Generator& gen; - inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} - template - inline void apply(PointDst& point_dst) const - { - std::uniform_int_distribution::type> - dist(get(b),get(b)); - set(point_dst,dist(gen)); - } -}; - -template -struct interval_sample -{ - Box const& b; - Generator& gen; - inline interval_sample(Box const& b, Generator& gen):b(b),gen(gen) {} + Box const& m_b; + std::array const& m_fractions; + inline interval_product(Box const& b, std::array const& f) : + m_b(b), m_fractions(f) {} template inline void apply(PointDst& point_dst) const { - std::uniform_real_distribution::type> - dist(get(b),get(b)); - set(point_dst,dist(gen)); + set(point_dst, + get(m_b) + + m_fractions[Index] + * (get(m_b) - get(m_b)) ); } }; -} +} // namespace detail template < @@ -77,24 +55,16 @@ template typename DomainGeometry, int Dim > -struct interval_product_distribution +struct cartesian_box { - interval_product_distribution(DomainGeometry const& d) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - interval_product_distribution const& r_strategy) const - { - return boost::geometry::equals(l_domain.domain(), r_domain.domain()); - } - template - Point apply(Generator& g, DomainGeometry const& d) + template + static Point apply(DomainGeometry const& d, std::array const& f) { Point r; for_each_coordinate(r, - detail::interval_sample(d, g)); + detail::interval_product(d, f)); return r; } - void reset(DomainGeometry const&) {}; }; namespace services { @@ -105,17 +75,15 @@ template typename DomainGeometry, int Dim > -struct default_strategy +struct default_box_strategy < Point, DomainGeometry, - box_tag, - single_tag, //There are no MultiBoxes right now Dim, cartesian_tag -> : public interval_product_distribution { - typedef interval_product_distribution base; - using base::base; +> +{ + typedef cartesian_box type; }; } // namespace services diff --git a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp index 0702a42025..d425a3ed90 100644 --- a/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp +++ b/include/boost/geometry/extensions/random/strategies/cartesian/uniform_point_distribution_triangle.hpp @@ -20,39 +20,32 @@ #include #include +#include + namespace boost { namespace geometry { -namespace strategy { namespace uniform_point_distribution { +namespace strategy { namespace uniform_point_distribution +{ -//The following strategy is suitable for rings or polygons of three points. template < typename Point, - typename DomainGeometry + typename DomainPoint > -struct uniform_2d_cartesian_triangle +struct cartesian_triangle { private: - typedef typename point_type::type domain_point_type; public: - uniform_2d_cartesian_triangle(DomainGeometry const& d) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_2d_cartesian_triangle const& r_strategy) const - { - return boost::geometry::equals(l_domain.domain(), r_domain.domain()); - } - - template - static Point map(domain_point_type const& p1, - domain_point_type const& p2, - domain_point_type const& p3, - sample_type const& s1, - sample_type const& s2) + template + static Point apply(DomainPoint const& p1, + DomainPoint const& p2, + DomainPoint const& p3, + CalculationType const& s1, + CalculationType const& s2) { Point out; - sample_type r1 = std::sqrt(s1); + CalculationType r1 = std::sqrt(s1); set<0>(out, (1 - r1) * get<0>(p1) + ( r1 * (1 - s2) ) * get<0>(p2) + ( s2 * r1 * get<0>(p3))); @@ -61,23 +54,28 @@ struct uniform_2d_cartesian_triangle + ( s2 * r1 * get<1>(p3))); return out; } +}; - template - Point apply(Generator& g, DomainGeometry const& d) - { - typedef typename select_most_precise - < - typename coordinate_type::type, - double - >::type sample_type; - std::uniform_real_distribution real_dist(0, 1); - sample_type s1 = real_dist(g), - s2 = real_dist(g); - return map(*d.begin(), *(d.begin() + 1), *(d.begin() + 2), s1, s2); - } - void reset(DomainGeometry const&) {}; +namespace services +{ + +template +< + typename Point, + typename DomainPoint +> +struct default_triangle_strategy +< + Point, + DomainPoint, + cartesian_tag +> +{ + typedef cartesian_triangle type; }; +} // namespace services + }} // namespace strategy::uniform_point_distribution }} // namespace boost::geometry diff --git a/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp b/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp deleted file mode 100644 index 414284c79c..0000000000 --- a/include/boost/geometry/extensions/random/strategies/spherical/uniform_inverse_transform_sampling.hpp +++ /dev/null @@ -1,159 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. - -// Contributed and/or modified by Tinko Bartels, -// as part of Google Summer of Code 2019 program. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_INVERSE_TRANSFORM_SAMPLING_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_INVERSE_TRANSFORM_SAMPLING_HPP - -#include -#include - -#include - -#include - -namespace boost { namespace geometry -{ - -namespace strategy { namespace uniform_point_distribution -{ - -template -< - typename Point, - typename DomainGeometry, - int Dim -> -struct uniform_inverse_transform_sampling -{}; - -template -< - typename Point, - typename DomainGeometry -> -struct uniform_inverse_transform_sampling -{ - uniform_inverse_transform_sampling(DomainGeometry const& d) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_inverse_transform_sampling const& r_strategy) const - { - return boost::geometry::equals(l_domain.domain(), r_domain.domain()); - } - template - Point apply(Generator& g, DomainGeometry const& d) - { - Point out; - typedef typename coordinate_type::type coordinate_type; - typedef typename select_most_precise - < - coordinate_type, - double - >::type computation_type; - std::uniform_real_distribution lon_dist( - get_as_radian<0, 0>(d), - get_as_radian<1, 0>(d)); - set_from_radian<0>(out, lon_dist(g)); - - coordinate_type lat1 = get_as_radian<0, 1>(d); - coordinate_type lat2 = get_as_radian<1, 1>(d); - coordinate_type x1 = (1.0 - std::cos(lat1)) / 2, - x2 = (1.0 - std::cos(lat2)) / 2; - std::uniform_real_distribution x_dist( - std::min(x1, x2), - std::max(x1, x2)); - coordinate_type x = x_dist(g); - set_from_radian<1>(out, std::acos(1.0 - 2.0 * x)); - return out; - } - void reset(DomainGeometry const&) {}; -}; - -template -< - typename Point, - typename DomainGeometry -> -struct uniform_inverse_transform_sampling -{ - uniform_inverse_transform_sampling(DomainGeometry const& d) {} - bool equals(DomainGeometry const& l_domain, - DomainGeometry const& r_domain, - uniform_inverse_transform_sampling const& r_strategy) const - { - return boost::geometry::equals(l_domain.domain(), r_domain.domain()); - } - template - Point apply(Generator& g, DomainGeometry const& d) - { - uniform_inverse_transform_sampling helper(d); - Point out = helper.apply(g, d); - typedef typename coordinate_type::type coordinate_type; - typedef typename select_most_precise - < - coordinate_type, - double - >::type computation_type; - coordinate_type r1 = get<0, 2>(d); - coordinate_type r2 = get<1, 2>(d); - std::uniform_real_distribution - r_dist( r1 * r1 * r1 , r2 * r2 * r2 ); - set<2>(out, std::cbrt(r_dist(g))); - return out; - } - void reset(DomainGeometry const&) {}; -}; - -namespace services { - -template -< - typename Point, - typename DomainGeometry -> -struct default_strategy -< - Point, - DomainGeometry, - box_tag, - single_tag, //There are no MultiBoxes right now - 2, - spherical_tag -> : public uniform_inverse_transform_sampling { - typedef uniform_inverse_transform_sampling base; - using base::base; -}; - -template -< - typename Point, - typename DomainGeometry -> -struct default_strategy -< - Point, - DomainGeometry, - box_tag, - single_tag, //There are no MultiBoxes right now - 3, - spherical_tag -> : public uniform_inverse_transform_sampling { - typedef uniform_inverse_transform_sampling base; - using base::base; -}; - -} // namespace services - -}} // namespace strategy::uniform_point_distribution - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_INVERSE_TRANSFORM_SAMPLING_HPP diff --git a/include/boost/geometry/extensions/random/strategies/spherical/uniform_point_distribution_box.hpp b/include/boost/geometry/extensions/random/strategies/spherical/uniform_point_distribution_box.hpp new file mode 100644 index 0000000000..f64f0bdb60 --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/spherical/uniform_point_distribution_box.hpp @@ -0,0 +1,130 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_POINT_DISTRIBUTION_BOX_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_POINT_DISTRIBUTION_BOX_HPP + +#include + +#include +#include + +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution +{ + +template +< + typename Point, + typename DomainGeometry, + std::size_t Dim +> +struct spherical_box +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types>) + ); +}; + +template +< + typename Point, + typename DomainGeometry +> +struct spherical_box +{ + template + static Point apply(DomainGeometry const& d, std::array const& f) + { + Point out; + set_from_radian<0>(out, get_as_radian<0, 0>(d) + + f[0] * ( get_as_radian<1, 0>(d) - get_as_radian<0, 0>(d) )); + CalculationType lat1 = get_as_radian<0, 1>(d); + CalculationType lat2 = get_as_radian<1, 1>(d); + CalculationType x1 = (1.0 - std::cos(lat1)) / 2; + CalculationType x2 = (1.0 - std::cos(lat2)) / 2; + CalculationType lo = std::min(x1, x2); + CalculationType hi = std::max(x1, x2); + CalculationType x = lo + f[1] * (hi - lo); + set_from_radian<1>(out, std::acos(1.0 - 2.0 * x)); + return out; + } +}; + +template +< + typename Point, + typename DomainGeometry +> +struct spherical_box +{ + template + static Point apply(DomainGeometry const& d, std::array const& f) + { + Point out = spherical_box::apply(d, {{f[0], f[1]}}); + CalculationType r1 = get<0, 2>(d); + CalculationType r2 = get<1, 2>(d); + CalculationType lo = r1 * r1 * r1; + CalculationType hi = r2 * r2 * r2; + set<2>(out, std::cbrt( lo + f[2] * ( hi - lo ) )); + return out; + } +}; + +namespace services { + +template +< + typename Point, + typename DomainGeometry +> +struct default_box_strategy +< + Point, + DomainGeometry, + 2, + spherical_tag +> +{ + typedef spherical_box type; +}; + +template +< + typename Point, + typename DomainGeometry +> +struct default_box_strategy +< + Point, + DomainGeometry, + 3, + spherical_tag +> +{ + typedef spherical_box type; +}; + +} // namespace services + +}} // namespace strategy::uniform_point_distribution + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_SPHERICAL_UNIFORM_POINT_DISTRIBUTION_BOX_HPP diff --git a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution_box.hpp similarity index 64% rename from include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp rename to include/boost/geometry/extensions/random/strategies/uniform_point_distribution_box.hpp index 1c2cd7f33d..280cc52253 100644 --- a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution_box.hpp @@ -9,8 +9,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP -#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_BOX_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_BOX_HPP #include #include @@ -31,34 +31,19 @@ template < typename Point, typename DomainGeometry, - typename Tag = typename tag_cast - < - typename tag::type, - segment_tag, - box_tag, - linear_tag, - areal_tag, - pointlike_tag - >::type, - typename MultiOrSingle = typename tag_cast - < - typename tag::type, - single_tag, - multi_tag - >::type, int Dim = dimension::value, typename CsTag = typename tag_cast - < - typename cs_tag::type, - spherical_tag - >::type + < + typename cs_tag::type, + spherical_tag + >::type > -struct default_strategy +struct default_box_strategy { BOOST_MPL_ASSERT_MSG ( false, NOT_IMPLEMENTED_FOR_THIS_TYPE - , (types>) + , (types>) ); }; @@ -66,4 +51,4 @@ struct default_strategy }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_HPP +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_BOX_HPP diff --git a/include/boost/geometry/extensions/random/strategies/uniform_point_distribution_triangle.hpp b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution_triangle.hpp new file mode 100644 index 0000000000..fa4607d33c --- /dev/null +++ b/include/boost/geometry/extensions/random/strategies/uniform_point_distribution_triangle.hpp @@ -0,0 +1,52 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019 Tinko Bartels, Berlin, Germany. + +// Contributed and/or modified by Tinko Bartels, +// as part of Google Summer of Code 2019 program. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_TRIANGLE_HPP +#define BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_TRIANGLE_HPP + +#include + +#include +#include +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace uniform_point_distribution { namespace services +{ + +template +< + typename Point, + typename DomainPoint, + typename CsTag = typename tag_cast + < + typename cs_tag::type, + spherical_tag + >::type +> +struct default_triangle_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPE + , (types) + ); +}; + +}}} // namespace strategy::uniform_point_distribution::services + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_EXTENSIONS_RANDOM_STRATEGIES_UNIFORM_POINT_DISTRIBUTION_TRIANGLE_HPP diff --git a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp index 6e8548d6c7..32527f83d9 100644 --- a/include/boost/geometry/extensions/random/uniform_point_distribution.hpp +++ b/include/boost/geometry/extensions/random/uniform_point_distribution.hpp @@ -12,11 +12,12 @@ #ifndef BOOST_GEOMETRY_EXTENSIONS_RANDOM_UNIFORM_POINT_DISTRIBUTION_HPP #define BOOST_GEOMETRY_EXTENSIONS_RANDOM_UNIFORM_POINT_DISTRIBUTION_HPP -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace boost { namespace geometry { namespace random { @@ -25,12 +26,12 @@ template < typename DomainGeometry, typename Point = typename geometry::point_type::type, - typename Strategy = - typename strategy::uniform_point_distribution::services::default_strategy + typename Policy = + typename policy::uniform_point_distribution::services::default_policy < Point, DomainGeometry - > + >::type > class uniform_point_distribution { @@ -49,42 +50,46 @@ class uniform_point_distribution private: DomainGeometry m_domain; }; + uniform_point_distribution(DomainGeometry const& domain, + Policy const& policy) + : m_policy(policy), + m_param(domain) {} uniform_point_distribution(DomainGeometry const& domain) - : m_strategy(domain), + : m_policy(domain), m_param(domain) {} uniform_point_distribution() - : m_strategy(DomainGeometry()), + : m_policy(DomainGeometry()), m_param(DomainGeometry()) {} uniform_point_distribution(param_type const& param) - : m_strategy(param.domain()), + : m_policy(param.domain()), m_param(param) {} - void reset() { m_strategy.reset(); } + void reset() { m_policy.reset(); } param_type param() const { return m_param; } void param(param_type const& p) { m_param = p; - m_strategy = Strategy(p.domain()); + m_policy = Policy(p.domain()); } bool operator==(uniform_point_distribution const& rhs) const { - return m_strategy.equals(m_param.domain(), - rhs.domain(), - rhs.m_strategy); + return m_policy.equals(m_param.domain(), + rhs.domain(), + rhs.m_policy); } domain_type const& domain() const { return m_param.domain(); } template< typename Generator > result_type operator()(Generator& g) { - return m_strategy.apply(g, m_param.domain()); + return m_policy.apply(g, m_param.domain()); } template< typename Generator > result_type operator()(Generator& g, param_type const& p) { - Strategy strat(p.domain()); - return strat.apply(g, p.domain()); + Policy pol(p.domain()); + return pol.apply(g, p.domain()); } private: - Strategy m_strategy; + Policy m_policy; param_type m_param; }; @@ -107,14 +112,14 @@ template typename Traits, typename Point, typename DomainGeometry, - typename Strategy + typename Policy > inline std::basic_ostream& operator<< ( std::basic_ostream &os, boost::geometry::random::uniform_point_distribution < - DomainGeometry, Point, Strategy + DomainGeometry, Point, Policy > const& dist ) { @@ -128,14 +133,14 @@ template typename Traits, typename Point, typename DomainGeometry, - typename Strategy + typename Policy > inline std::basic_istream& operator>> ( std::basic_istream &is, boost::geometry::random::uniform_point_distribution < - DomainGeometry, Point, Strategy + DomainGeometry, Point, Policy > & dist ) { @@ -145,7 +150,7 @@ inline std::basic_istream& operator>> namespace bg = boost::geometry; typedef typename bg::random::uniform_point_distribution < - DomainGeometry, Point, Strategy + DomainGeometry, Point, Policy >::param_type param_type; bg::read_wkt(line, g); dist.param( param_type(g) );