1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3 
4 // Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_GEOMETRY_TEST_DISTANCE_HPP
10 #define BOOST_GEOMETRY_TEST_DISTANCE_HPP
11 
12 #include <geometry_test_common.hpp>
13 
14 #include <boost/geometry/algorithms/distance.hpp>
15 #include <boost/geometry/io/wkt/read.hpp>
16 #include <boost/geometry/strategies/strategies.hpp>
17 
18 // Define a custom distance strategy
19 // For this one, the "taxicab" distance,
20 // see http://en.wikipedia.org/wiki/Taxicab_geometry
21 
22 // For a point-point-distance operation, one typename Point is enough.
23 // For a point-segment-distance operation, there is some magic inside
24 // using another point type and casting if necessary. Therefore,
25 // two point-types are necessary.
26 struct taxicab_distance
27 {
28     template <typename P1, typename P2>
applytaxicab_distance29     static inline typename bg::coordinate_type<P1>::type apply(
30                     P1 const& p1, P2 const& p2)
31     {
32         using bg::get;
33         using bg::math::abs;
34         return abs(get<0>(p1) - get<1>(p2))
35             + abs(get<1>(p1) - get<1>(p2));
36     }
37 };
38 
39 
40 
41 namespace boost { namespace geometry { namespace strategy { namespace distance { namespace services
42 {
43 
44 template <>
45 struct tag<taxicab_distance>
46 {
47     typedef strategy_tag_distance_point_point type;
48 };
49 
50 
51 template <typename P1, typename P2>
52 struct return_type<taxicab_distance, P1, P2>
53 {
54     typedef typename coordinate_type<P1>::type type;
55 };
56 
57 
58 template <>
59 struct comparable_type<taxicab_distance>
60 {
61     typedef taxicab_distance type;
62 };
63 
64 template <>
65 struct get_comparable<taxicab_distance>
66 {
applyboost::geometry::strategy::distance::services::get_comparable67     static inline taxicab_distance apply(taxicab_distance const& input)
68     {
69         return input;
70     }
71 };
72 
73 template <typename P1, typename P2>
74 struct result_from_distance<taxicab_distance, P1, P2>
75 {
76     template <typename T>
applyboost::geometry::strategy::distance::services::result_from_distance77     static inline typename coordinate_type<P1>::type apply(taxicab_distance const& , T const& value)
78     {
79         return value;
80     }
81 };
82 
83 
84 }}}}} // namespace bg::strategy::distance::services
85 
86 
87 
88 
89 
90 template <typename Geometry1, typename Geometry2>
test_distance(Geometry1 const & geometry1,Geometry2 const & geometry2,long double expected_distance)91 void test_distance(Geometry1 const& geometry1,
92             Geometry2 const& geometry2,
93             long double expected_distance)
94 {
95     typename bg::default_distance_result<Geometry1>::type distance = bg::distance(geometry1, geometry2);
96 
97 #ifdef BOOST_GEOMETRY_TEST_DEBUG
98     std::ostringstream out;
99     out << typeid(typename bg::coordinate_type<Geometry1>::type).name()
100         << std::endl
101         << typeid(typename bg::default_distance_result<Geometry1>::type).name()
102         << std::endl
103         << "distance : " << bg::distance(geometry1, geometry2)
104         << std::endl;
105     std::cout << out.str();
106 #endif
107 
108     BOOST_CHECK_CLOSE(distance, expected_distance, 0.0001);
109 }
110 
111 
112 template <typename Geometry1, typename Geometry2>
test_geometry(std::string const & wkt1,std::string const & wkt2,double expected_distance)113 void test_geometry(std::string const& wkt1, std::string const& wkt2, double expected_distance)
114 {
115     Geometry1 geometry1;
116     bg::read_wkt(wkt1, geometry1);
117     Geometry2 geometry2;
118     bg::read_wkt(wkt2, geometry2);
119 
120     test_distance(geometry1, geometry2, expected_distance);
121 }
122 
123 template <typename Geometry1, typename Geometry2>
test_empty_input(Geometry1 const & geometry1,Geometry2 const & geometry2)124 void test_empty_input(Geometry1 const& geometry1, Geometry2 const& geometry2)
125 {
126     try
127     {
128         bg::distance(geometry1, geometry2);
129     }
130     catch(bg::empty_input_exception const& )
131     {
132         return;
133     }
134     BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
135 }
136 
137 
138 #endif
139