mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-09 15:14:02 +00:00
[util] move bounds to geometry::util
This commit is contained in:
parent
993b36515c
commit
d9eface3e8
@ -26,7 +26,6 @@
|
||||
|
||||
#include <boost/concept/requires.hpp>
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/append.hpp>
|
||||
#include <boost/geometry/algorithms/clear.hpp>
|
||||
@ -38,7 +37,7 @@
|
||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||
|
||||
#include <boost/geometry/util/algorithm.hpp>
|
||||
#include <boost/geometry/util/is_inverse_spheroidal_coordinates.hpp>
|
||||
#include <boost/geometry/util/bounds.hpp>
|
||||
#include <boost/geometry/util/numeric_cast.hpp>
|
||||
|
||||
|
||||
@ -74,8 +73,8 @@ struct assign_inverse_box_or_segment
|
||||
{
|
||||
typedef typename coordinate_type<BoxOrSegment>::type coordinate_type;
|
||||
|
||||
coordinate_type const highest = geometry::bounds<coordinate_type>::highest();
|
||||
coordinate_type const lowest = geometry::bounds<coordinate_type>::lowest();
|
||||
coordinate_type const highest = util::bounds<coordinate_type>::highest();
|
||||
coordinate_type const lowest = util::bounds<coordinate_type>::lowest();
|
||||
detail::for_each_dimension<BoxOrSegment>([&](auto dimension)
|
||||
{
|
||||
set<0, dimension>(geometry, highest);
|
||||
|
@ -13,11 +13,10 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
|
||||
#include <boost/geometry/core/access.hpp>
|
||||
#include <boost/geometry/core/coordinate_dimension.hpp>
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/util/bounds.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
@ -67,9 +66,9 @@ struct initialize
|
||||
|
||||
static inline void apply(Box& box,
|
||||
coordinate_type min_value
|
||||
= boost::numeric::bounds<coordinate_type>::highest(),
|
||||
= util::bounds<coordinate_type>::highest(),
|
||||
coordinate_type max_value
|
||||
= boost::numeric::bounds<coordinate_type>::lowest())
|
||||
= util::bounds<coordinate_type>::lowest())
|
||||
{
|
||||
initialize_loop
|
||||
<
|
||||
|
28
include/boost/geometry/util/bounds.hpp
Normal file
28
include/boost/geometry/util/bounds.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Boost.Geometry
|
||||
|
||||
// Copyright (c) 2024 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// 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_UTIL_BOUNDS_HPP
|
||||
#define BOOST_GEOMETRY_UTIL_BOUNDS_HPP
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace util
|
||||
{
|
||||
|
||||
// Define a boost::geometry::util::bounds
|
||||
// It might be specialized for other numeric types, for example Boost.Rational
|
||||
template<class CT>
|
||||
struct bounds
|
||||
{
|
||||
static CT lowest () { return boost::numeric::bounds<CT>::lowest(); }
|
||||
static CT highest () { return boost::numeric::bounds<CT>::highest(); }
|
||||
};
|
||||
|
||||
}}} // namespace boost::geometry::util
|
||||
|
||||
#endif // BOOST_GEOMETRY_UTIL_BOUNDS_HPP
|
@ -16,26 +16,20 @@
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
|
||||
#include <boost/geometry/util/bounds.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
template<class CT>
|
||||
struct bounds
|
||||
{
|
||||
static CT lowest () { return boost::numeric::bounds<CT>::lowest(); }
|
||||
static CT highest () { return boost::numeric::bounds<CT>::highest(); }
|
||||
};
|
||||
|
||||
template <typename Box>
|
||||
bool is_inverse_spheroidal_coordinates(Box const& box)
|
||||
{
|
||||
typedef typename point_type<Box>::type point_type;
|
||||
typedef typename coordinate_type<point_type>::type bound_type;
|
||||
|
||||
bound_type high = bounds<bound_type>::highest();
|
||||
bound_type low = bounds<bound_type>::lowest();
|
||||
bound_type const high = util::bounds<bound_type>::highest();
|
||||
bound_type const low = util::bounds<bound_type>::lowest();
|
||||
|
||||
return (geometry::get<0, 0>(box) == high) &&
|
||||
(geometry::get<0, 1>(box) == high) &&
|
||||
|
@ -10,7 +10,6 @@
|
||||
#define BOOST_GEOMETRY_UTIL_NUMERIC_CAST_HPP
|
||||
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace util
|
||||
|
||||
@ -30,21 +29,11 @@ struct numeric_caster
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for Boost.Rational
|
||||
template <typename Target, typename T>
|
||||
struct numeric_caster<Target, rational<T>>
|
||||
{
|
||||
static inline Target apply(rational<T> const& source)
|
||||
{
|
||||
return boost::rational_cast<Target>(source);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
#endif
|
||||
|
||||
// Calls either boost::numeric_cast, or functionality specific for Boost.Geometry
|
||||
// such as rational_cast for Boost.Rational
|
||||
// (such as rational_cast for Boost.Rational)
|
||||
template <typename Target, typename Source>
|
||||
inline Target numeric_cast(Source const& source)
|
||||
{
|
||||
|
@ -14,9 +14,11 @@
|
||||
#ifndef BOOST_GEOMETRY_UTIL_RATIONAL_HPP
|
||||
#define BOOST_GEOMETRY_UTIL_RATIONAL_HPP
|
||||
|
||||
#include <boost/rational.hpp>
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
// Contains specializations for Boost.Rational
|
||||
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
#include <boost/geometry/util/bounds.hpp>
|
||||
#include <boost/geometry/util/coordinate_cast.hpp>
|
||||
#include <boost/geometry/util/numeric_cast.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
@ -111,14 +113,30 @@ struct select_most_precise<boost::rational<T>, double>
|
||||
typedef typename boost::rational<T> type;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
// Specializes boost::rational to boost::numeric::bounds
|
||||
namespace boost { namespace numeric
|
||||
namespace util
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// Specialize numeric_caster, needed for geomery::util::numeric_cast, for Boost.Rational
|
||||
// Without it, code using Boost.Rational does not compile
|
||||
template <typename Target, typename T>
|
||||
struct numeric_caster<Target, rational<T>>
|
||||
{
|
||||
static inline Target apply(rational<T> const& source)
|
||||
{
|
||||
return boost::rational_cast<Target>(source);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
#endif
|
||||
|
||||
|
||||
// Specializes geometry::util::bounds for Boost.Rational
|
||||
// Without it, bounds contains (0,1) by default for Boost.Rational
|
||||
template<class T>
|
||||
struct bounds<rational<T> >
|
||||
{
|
||||
@ -132,7 +150,9 @@ struct bounds<rational<T> >
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::numeric
|
||||
} // namespace util
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_UTIL_RATIONAL_HPP
|
||||
|
@ -48,3 +48,4 @@ if (NOT TARGET tests)
|
||||
endif()
|
||||
|
||||
add_subdirectory(algorithms)
|
||||
add_subdirectory(util)
|
||||
|
@ -8,6 +8,7 @@ add_subdirectory(area)
|
||||
add_subdirectory(buffer)
|
||||
add_subdirectory(convex_hull)
|
||||
add_subdirectory(detail)
|
||||
add_subdirectory(envelope_expand)
|
||||
add_subdirectory(overlay)
|
||||
add_subdirectory(relate)
|
||||
add_subdirectory(set_operations)
|
||||
|
23
test/algorithms/envelope_expand/CMakeLists.txt
Normal file
23
test/algorithms/envelope_expand/CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
||||
# Boost.Geometry
|
||||
# Copyright (c) 2024 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
# 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)
|
||||
|
||||
foreach(item IN ITEMS
|
||||
envelope
|
||||
envelope_multi
|
||||
expand
|
||||
expand_on_spheroid
|
||||
)
|
||||
boost_geometry_add_unit_test("algorithms" ${item})
|
||||
endforeach()
|
||||
|
||||
if (NOT APPLE)
|
||||
# The results of these tests vary considerably on Apple/Darwin/arm64 using clang
|
||||
foreach(item IN ITEMS
|
||||
envelope_on_spheroid
|
||||
)
|
||||
boost_geometry_add_unit_test("algorithms" ${item})
|
||||
endforeach()
|
||||
endif()
|
@ -18,8 +18,6 @@
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
|
||||
#include "test_envelope.hpp"
|
||||
|
||||
#include <boost/geometry/geometries/geometries.hpp>
|
||||
@ -27,6 +25,7 @@
|
||||
#include <boost/geometry/geometries/adapted/c_array.hpp>
|
||||
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
|
||||
#include <boost/geometry/geometries/adapted/std_pair_as_segment.hpp>
|
||||
#include <boost/geometry/util/bounds.hpp>
|
||||
#include <test_common/test_point.hpp>
|
||||
|
||||
BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian)
|
||||
@ -68,8 +67,8 @@ template <typename Geometry>
|
||||
void test_empty_geometry(std::string const& wkt)
|
||||
{
|
||||
typedef typename bg::coordinate_type<Geometry>::type ct;
|
||||
ct high_val = boost::numeric::bounds<ct>::highest();
|
||||
ct low_val = boost::numeric::bounds<ct>::lowest();
|
||||
ct const high_val = bg::util::bounds<ct>::highest();
|
||||
ct const low_val = bg::util::bounds<ct>::lowest();
|
||||
|
||||
test_envelope<Geometry>(wkt, high_val, low_val, high_val, low_val);
|
||||
}
|
||||
|
@ -22,8 +22,6 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
|
||||
#include <from_wkt.hpp>
|
||||
#include <geometry_test_common.hpp>
|
||||
#include "test_envelope_expand_on_spheroid.hpp"
|
||||
@ -38,6 +36,7 @@
|
||||
#include <boost/geometry/index/detail/algorithms/is_valid.hpp>
|
||||
#include <boost/geometry/io/dsv/write.hpp>
|
||||
#include <boost/geometry/io/wkt/wkt.hpp>
|
||||
#include <boost/geometry/util/bounds.hpp>
|
||||
#include <boost/geometry/util/condition.hpp>
|
||||
#include <boost/geometry/util/type_traits.hpp>
|
||||
|
||||
@ -492,8 +491,8 @@ void test_empty_geometry(std::string const& case_id, std::string const& wkt)
|
||||
typedef test_envelope_on_sphere_or_spheroid<Geometry, B> tester;
|
||||
|
||||
typedef typename bg::coordinate_type<Geometry>::type ct;
|
||||
ct high_val = boost::numeric::bounds<ct>::highest();
|
||||
ct low_val = boost::numeric::bounds<ct>::lowest();
|
||||
ct const high_val = bg::util::bounds<ct>::highest();
|
||||
ct const low_val = bg::util::bounds<ct>::lowest();
|
||||
|
||||
if (BOOST_GEOMETRY_CONDITION(dim == 2))
|
||||
{
|
||||
|
@ -69,12 +69,12 @@ void test_construction()
|
||||
check_box(b2, 1,2,5,3,4,6);
|
||||
|
||||
bg::model::box<P> b3 = bg::make_inverse<bg::model::box<P> >();
|
||||
check_box(b3, boost::numeric::bounds<T>::highest(),
|
||||
boost::numeric::bounds<T>::highest(),
|
||||
boost::numeric::bounds<T>::highest(),
|
||||
boost::numeric::bounds<T>::lowest(),
|
||||
boost::numeric::bounds<T>::lowest(),
|
||||
boost::numeric::bounds<T>::lowest());
|
||||
check_box(b3, bg::util::bounds<T>::highest(),
|
||||
bg::util::bounds<T>::highest(),
|
||||
bg::util::bounds<T>::highest(),
|
||||
bg::util::bounds<T>::lowest(),
|
||||
bg::util::bounds<T>::lowest(),
|
||||
bg::util::bounds<T>::lowest());
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
|
24
test/util/CMakeLists.txt
Normal file
24
test/util/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
# Boost.Geometry
|
||||
# Copyright (c) 2024 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
# 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)
|
||||
|
||||
foreach(item IN ITEMS
|
||||
algorithm
|
||||
calculation_type
|
||||
for_each_coordinate
|
||||
math_abs
|
||||
math_divide
|
||||
math_equals
|
||||
math_sqrt
|
||||
math_normalize_spheroidal
|
||||
promote_integral
|
||||
range
|
||||
rational
|
||||
select_most_precise
|
||||
tuples
|
||||
write_dsv
|
||||
)
|
||||
boost_geometry_add_unit_test("util" ${item})
|
||||
endforeach()
|
@ -1,7 +1,7 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
// Unit Test
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
// Copyright (c) 2007-2024 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
||||
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
||||
|
||||
@ -15,6 +15,11 @@
|
||||
|
||||
#include <geometry_test_common.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/area.hpp>
|
||||
#include <boost/geometry/algorithms/assign.hpp>
|
||||
#include <boost/geometry/algorithms/make.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
#include <boost/geometry/algorithms/within.hpp>
|
||||
#include <boost/geometry/geometries/geometries.hpp>
|
||||
#include <boost/geometry/io/wkt/wkt.hpp>
|
||||
#include <boost/geometry/util/numeric_cast.hpp>
|
||||
@ -22,21 +27,93 @@
|
||||
|
||||
void test_coordinate_cast(std::string const& s, int expected_nom, int expected_denom)
|
||||
{
|
||||
boost::rational<int> a = bg::detail::coordinate_cast<boost::rational<int> >::apply(s);
|
||||
boost::rational<int> const a = bg::detail::coordinate_cast<boost::rational<int> >::apply(s);
|
||||
BOOST_CHECK_EQUAL(a.numerator(), expected_nom);
|
||||
BOOST_CHECK_EQUAL(a.denominator(), expected_denom);
|
||||
}
|
||||
|
||||
void test_numeric_cast()
|
||||
{
|
||||
const boost::rational<int> r1(3, 4);
|
||||
boost::rational<int> const r1(3, 4);
|
||||
BOOST_CHECK_CLOSE(bg::util::numeric_cast<double>(r1), 0.75, 0.00001);
|
||||
|
||||
const boost::rational<int> r2(10, 4);
|
||||
boost::rational<int> const r2(10, 4);
|
||||
BOOST_CHECK_CLOSE(bg::util::numeric_cast<double>(r2), 2.5, 0.00001);
|
||||
BOOST_CHECK_EQUAL(bg::util::numeric_cast<int>(r2), 2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void test_bounds()
|
||||
{
|
||||
using coordinate_t = boost::rational<T>;
|
||||
using point_t = bg::model::point<coordinate_t, 2, bg::cs::cartesian>;
|
||||
|
||||
auto const lowest = bg::util::bounds<coordinate_t>::lowest();
|
||||
auto const highest = bg::util::bounds<coordinate_t>::highest();
|
||||
|
||||
BOOST_CHECK_MESSAGE(lowest < highest,
|
||||
"Lowest should be smaller than highest, lowest: " << lowest << " highest: " << highest);
|
||||
}
|
||||
|
||||
// Tests box-related functionality, which depends on geometry::util::bounds
|
||||
// specialization for Boost.Rational
|
||||
template <typename T>
|
||||
void test_box()
|
||||
{
|
||||
using coordinate_t = boost::rational<T>;
|
||||
using point_t = bg::model::point<coordinate_t, 2, bg::cs::cartesian>;
|
||||
using box_t = bg::model::box<point_t>;
|
||||
|
||||
box_t box;
|
||||
bg::assign_inverse(box);
|
||||
|
||||
point_t south_west, north_east;
|
||||
bg::detail::assign_point_from_index<0>(box, south_west);
|
||||
bg::detail::assign_point_from_index<1>(box, north_east);
|
||||
|
||||
BOOST_CHECK_MESSAGE(bg::get<0>(south_west) > bg::get<0>(north_east),
|
||||
"Bounding box should be inversed. Now x-min: " << bg::get<0>(south_west)
|
||||
<< " x-max: " << bg::get<0>(north_east)
|
||||
<< " " << bg::wkt(box));
|
||||
|
||||
BOOST_CHECK_MESSAGE(bg::get<1>(south_west) > bg::get<1>(north_east),
|
||||
"Bounding box should be inversed. Now y-min: " << bg::get<1>(south_west)
|
||||
<< " y-max: " << bg::get<1>(north_east)
|
||||
<< " " << bg::wkt(box));
|
||||
|
||||
// Test specifically for points larger than 0, because without specialization Boost.Rational
|
||||
// will return (0,1) (== 0) by default and code will compile but give wrong results.
|
||||
bg::expand(box, bg::make<point_t>(4, 4));
|
||||
bg::expand(box, bg::make<point_t>(8, 8));
|
||||
|
||||
// Test within (without specialization, both points are within the box)
|
||||
auto const point1 = bg::make<point_t>(6, 6);
|
||||
auto const point2 = bg::make<point_t>(2, 2);
|
||||
BOOST_CHECK_MESSAGE(bg::within(point1, box),
|
||||
"Point " << bg::wkt(point1) << " is not within the box " << bg::wkt(box));
|
||||
BOOST_CHECK_MESSAGE(! bg::within(point2, box),
|
||||
"Point " << bg::wkt(point2) << " is within the box " << bg::wkt(box));
|
||||
|
||||
// Test area (without specialization, it will be 64)
|
||||
auto const area = bg::util::numeric_cast<T>(bg::area(box));
|
||||
T const expected_area = 16;
|
||||
BOOST_CHECK_EQUAL(expected_area, area);
|
||||
}
|
||||
|
||||
void test_select_most_precise()
|
||||
{
|
||||
using rational1_t = boost::rational<std::int32_t>;
|
||||
using rational2_t = boost::rational<std::int64_t>;
|
||||
|
||||
using t1 = bg::select_most_precise<double, rational1_t>::type;
|
||||
using t2 = bg::select_most_precise<double, rational2_t>::type;
|
||||
using t12 = bg::select_most_precise<rational1_t, rational2_t>::type;
|
||||
|
||||
BOOST_CHECK((std::is_same<t1, rational1_t>::value));
|
||||
BOOST_CHECK((std::is_same<t2, rational2_t>::value));
|
||||
BOOST_CHECK((std::is_same<t12, rational2_t>::value));
|
||||
}
|
||||
|
||||
void test_wkt(std::string const& wkt, std::string const expected_wkt)
|
||||
{
|
||||
bg::model::point<boost::rational<int>, 2, bg::cs::cartesian> p;
|
||||
@ -64,6 +141,14 @@ int test_main(int, char* [])
|
||||
|
||||
test_numeric_cast();
|
||||
|
||||
test_bounds<std::int16_t>();
|
||||
test_bounds<std::int32_t>();
|
||||
test_bounds<std::int64_t>();
|
||||
|
||||
test_box<std::int64_t>();
|
||||
|
||||
test_select_most_precise();
|
||||
|
||||
test_wkt("POINT(1.5 2.75)", "POINT(3/2 11/4)");
|
||||
test_wkt("POINT(3/2 11/4)", "POINT(3/2 11/4)");
|
||||
test_wkt("POINT(-1.5 2.75)", "POINT(-3/2 11/4)");
|
||||
|
Loading…
x
Reference in New Issue
Block a user