summaryrefslogtreecommitdiff
path: root/libs/geometry/example/c11_custom_cs_transform_example.cpp
blob: 38a3f012a05a161e1f022a10e73ee65c86181009 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// 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)
//
// Example: Custom coordinate system example, using transform

#include <iostream>

#include <boost/geometry/geometry.hpp>

// See also c10_custom_cs_example

// 1: declare, for example two cartesian coordinate systems
struct cart {};
struct cart_shifted5 {};

// 2: register to which coordinate system family they belong
namespace boost { namespace geometry { namespace traits
{

template<> struct cs_tag<cart> { typedef cartesian_tag type; };
template<> struct cs_tag<cart_shifted5> { typedef cartesian_tag type; };

}}} // namespaces


// 3: sample implementation of a shift 
//    to convert coordinate system "cart" to "cart_shirted5"
template <typename P1, typename P2>
struct shift
{
    inline bool apply(P1 const& p1, P2& p2) const
    {
        namespace bg = boost::geometry;
        bg::set<0>(p2, bg::get<0>(p1) + 5);
        bg::set<1>(p2, bg::get<1>(p1));
        return true;
    }
};


// 4: register the default strategy to transform any cart point to any cart_shifted5 point
namespace boost { namespace geometry  { namespace strategy { namespace transform { namespace services 
{

template <typename P1, typename P2>
struct default_strategy<cartesian_tag, cartesian_tag, cart, cart_shifted5, 2, 2, P1, P2>
{
    typedef shift<P1, P2> type;
};

}}}}} // namespaces


// 5: implement a distance strategy between the two different ones
template <typename P1, typename P2>
struct shift_and_calc_distance
{
    inline double apply(P1 const& p1, P2 const& p2) const
    {
        P2 p1_shifted;
        boost::geometry::transform(p1, p1_shifted);
        return boost::geometry::distance(p1_shifted, p2);
    }
};

// 6: Define point types using this explicitly
typedef boost::geometry::model::point<double, 2, cart> point1;
typedef boost::geometry::model::point<double, 2, cart_shifted5> point2;

// 7: register the distance strategy
namespace boost { namespace geometry { namespace strategy { namespace distance { namespace services 
{
    template <typename Point1, typename Point2>
    struct tag<shift_and_calc_distance<Point1, Point2> >
    {
        typedef strategy_tag_distance_point_point type;
    };
    
    template <typename Point1, typename Point2>
    struct return_type<shift_and_calc_distance<Point1, Point2> >
    {
        typedef double type;
    };

    template <>
    struct default_strategy<point_tag, point1, point2, cartesian_tag, cartesian_tag>
    {
        typedef shift_and_calc_distance<point1, point2> type;
    };


}}}}}



int main()
{
    point1 p1_a(0, 0), p1_b(5, 5);
    point2 p2_a(2, 2), p2_b(6, 6); 

    // Distances run for points on the same coordinate system.
    // This is possible by default because they are cartesian coordinate systems.
    double d1 = boost::geometry::distance(p1_a, p1_b); 
    double d2 = boost::geometry::distance(p2_a, p2_b); 

    std::cout << d1 << " " << d2 << std::endl;

    // Transform from a to b:
    boost::geometry::model::point<double, 2, cart_shifted5> p1_shifted;
    boost::geometry::transform(p1_a, p1_shifted); 


    // Of course this can be calculated now, same CS
    double d3 = boost::geometry::distance(p1_shifted, p2_a); 


    // Calculate distance between them. Note that inside distance the 
    // transformation is called.
    double d4 = boost::geometry::distance(p1_a, p2_a); 

    // The result should be the same.
    std::cout << d3 << " " << d4 << std::endl;

    return 0;
}