Changeset 62170


Ignore:
Timestamp:
May 24, 2010, 9:07:05 AM (9 years ago)
Author:
Barend Gehrels
Message:

Added closed / closure
Updated jamfiles

Location:
sandbox/geometry
Files:
2 added
32 edited

Legend:

Unmodified
Added
Removed
  • sandbox/geometry/boost/geometry/algorithms/area.hpp

    r61701 r62170  
    1616
    1717
    18 #include <boost/geometry/core/point_order.hpp>
     18#include <boost/geometry/core/closure.hpp>
    1919#include <boost/geometry/core/exterior_ring.hpp>
    2020#include <boost/geometry/core/interior_rings.hpp>
     21#include <boost/geometry/core/point_order.hpp>
    2122#include <boost/geometry/core/ring_type.hpp>
    2223
     
    3132#include <boost/geometry/strategies/concepts/area_concept.hpp>
    3233
     34#include <boost/geometry/util/closure_as_bool.hpp>
    3335#include <boost/geometry/util/math.hpp>
    3436#include <boost/geometry/util/order_as_direction.hpp>
     37#include <boost/geometry/util/closeable_view.hpp>
    3538#include <boost/geometry/util/reversible_view.hpp>
    3639
     
    8891
    8992
    90 template<typename Ring, iterate_direction Direction, typename Strategy>
     93template
     94<
     95    typename Ring,
     96    iterate_direction Direction,
     97    closure_selector Closure,
     98    typename Strategy
     99>
    91100struct ring_area
    92101{
     
    109118        }
    110119
    111         typedef reversible_view<Ring const, Direction> view_type;
     120
     121        typedef reversible_view<Ring const, Direction> rview_type;
     122        typedef closeable_view
     123            <
     124                rview_type const,
     125                Closure == closed
     126            > view_type;
    112127        typedef typename boost::range_iterator<view_type const>::type iterator_type;
    113128
    114         view_type view(ring);
     129        rview_type rview(ring);
     130        view_type view(rview);
    115131        typename Strategy::state_type state;
    116132        iterator_type it = boost::begin(view);
     133        iterator_type end = boost::end(view);
    117134
    118135        for (iterator_type previous = it++;
    119             it != boost::end(view);
    120             previous = it++)
     136            it != end;
     137            ++previous, ++it)
    121138        {
    122139            strategy.apply(*previous, *it, state);
     
    144161    typename Geometry,
    145162    order_selector Order,
     163    closure_selector Closure,
    146164    typename Strategy
    147165>
     
    155173
    156174
    157 template <typename Geometry, order_selector Order, typename Strategy>
    158 struct area<box_tag, Geometry, Order, Strategy>
     175template <typename Geometry, order_selector Order, closure_selector Closure, typename Strategy>
     176struct area<box_tag, Geometry, Order, Closure, Strategy>
    159177    : detail::area::box_area<Geometry, Strategy>
    160178{};
    161179
    162180
    163 template <typename Geometry, order_selector Order, typename Strategy>
    164 struct area<ring_tag, Geometry, Order, Strategy>
     181template <typename Geometry, order_selector Order, closure_selector Closure, typename Strategy>
     182struct area<ring_tag, Geometry, Order, Closure, Strategy>
    165183    : detail::area::ring_area
    166184        <
    167185            Geometry,
    168186            order_as_direction<Order>::value,
     187            Closure, //closure_as_bool<Closure>::value,
    169188            Strategy
    170189        >
     
    172191
    173192
    174 template <typename Polygon, order_selector Order, typename Strategy>
    175 struct area<polygon_tag, Polygon, Order, Strategy>
     193template <typename Polygon, order_selector Order, closure_selector Closure, typename Strategy>
     194struct area<polygon_tag, Polygon, Order, Closure, Strategy>
    176195    : detail::calculate_polygon_sum
    177196        <
     
    183202                    typename ring_type<Polygon>::type,
    184203                    order_as_direction<Order>::value,
     204                    Closure, //closure_as_bool<Closure>::value,
    185205                    Strategy
    186206                >
     
    217237            Geometry,
    218238            geometry::point_order<Geometry>::value,
     239            geometry::closure<Geometry>::value,
    219240            strategy_type
    220241        >::apply(geometry, strategy_type());
     
    241262            Geometry,
    242263            geometry::point_order<Geometry>::value,
     264            geometry::closure<Geometry>::value,
    243265            Strategy
    244266        >::apply(geometry, strategy);
  • sandbox/geometry/boost/geometry/algorithms/correct.hpp

    r61710 r62170  
    104104                Ring,
    105105                order_as_direction<geometry::point_order<Ring>::value>::value,
     106                geometry::closure<Ring>::value,
    106107                strategy_type
    107108            > ring_area_type;
  • sandbox/geometry/boost/geometry/algorithms/detail/equals/collect_vectors.hpp

    r61511 r62170  
    4444        , dx(pdx)
    4545        , dy(pdy)
     46        , dx_0(T())
     47        , dy_0(T())
    4648    {}
    4749
    4850    T x, y;
    4951    T dx, dy;
     52    T dx_0, dy_0;
     53
    5054    bool collinear;
    5155
     
    115119            v.dx = get<0>(*it) - v.x;
    116120            v.dy = get<1>(*it) - v.y;
     121            v.dx_0 = v.dx;
     122            v.dy_0 = v.dy;
    117123
    118124            // Normalize the vector -> this results in points+direction
  • sandbox/geometry/boost/geometry/algorithms/length.hpp

    r61527 r62170  
    1717#include <boost/type_traits.hpp>
    1818
    19 
    2019#include <boost/geometry/core/cs.hpp>
    2120
     
    2423#include <boost/geometry/algorithms/assign.hpp>
    2524#include <boost/geometry/algorithms/detail/calculate_null.hpp>
    26 
     25#include <boost/geometry/util/closeable_view.hpp>
    2726#include <boost/geometry/strategies/distance.hpp>
    2827#include <boost/geometry/strategies/length_result.hpp>
     
    7271    range iterator
    7372*/
    74 template<typename Range, typename Strategy>
     73template<typename Range, typename Strategy, bool Close>
    7574struct range_length
    7675{
     
    8079            Range const& range, Strategy const& strategy)
    8180    {
     81        typedef closeable_view<Range const, Close> view_type;
     82        typedef typename boost::range_iterator
     83            <
     84                view_type const
     85            >::type iterator_type;
     86
    8287        return_type sum = return_type();
    83 
    84         typedef typename boost::range_iterator<Range const>::type iterator_type;
    85         iterator_type it = boost::begin(range);
    86         if (it != boost::end(range))
     88        view_type view(range);
     89        iterator_type it = boost::begin(view), end = boost::end(view);
     90        if(it != end)
    8791        {
    88             iterator_type previous = it++;
    89             while(it != boost::end(range))
     92            for(iterator_type previous = it++;
     93                    it != end;
     94                    ++previous, ++it)
    9095            {
    9196                // Add point-point distance using the return type belonging
    9297                // to strategy
    9398                sum += strategy.apply(*previous, *it);
    94                 previous = it++;
    9599            }
    96100        }
     
    100104};
    101105
     106
    102107}} // namespace detail::length
    103108#endif // DOXYGEN_NO_DETAIL
     109
    104110
    105111#ifndef DOXYGEN_NO_DISPATCH
     
    120126template <typename Geometry, typename Strategy>
    121127struct length<linestring_tag, Geometry, Strategy>
    122     : detail::length::range_length<Geometry, Strategy>
     128    : detail::length::range_length<Geometry, Strategy, false>
    123129{};
    124130
  • sandbox/geometry/boost/geometry/algorithms/perimeter.hpp

    r61527 r62170  
    1212
    1313#include <boost/geometry/core/cs.hpp>
    14 
     14#include <boost/geometry/core/closure.hpp>
    1515#include <boost/geometry/geometries/concepts/check.hpp>
    16 
    1716#include <boost/geometry/strategies/length_result.hpp>
    18 
    1917#include <boost/geometry/algorithms/length.hpp>
    2018#include <boost/geometry/algorithms/detail/calculate_null.hpp>
     
    5048template <typename Geometry, typename Strategy>
    5149struct perimeter<ring_tag, Geometry, Strategy>
    52     : detail::length::range_length<Geometry, Strategy>
     50    : detail::length::range_length<Geometry, Strategy,
     51    closure<Geometry>::value == closed>
    5352{};
    5453
     
    6362                <
    6463                    typename ring_type<Polygon>::type,
    65                     Strategy
     64                    Strategy,
     65                                        closure<Polygon>::value == closed
    6666                >
    6767        >
  • sandbox/geometry/boost/geometry/core/point_order.hpp

    r61511 r62170  
    3232    \par Geometries:
    3333        - ring
    34         - polygon
    35         - multi polygon
    36     \par Specializations should provide:
    37         - typedef P type (where P should fulfil the Point concept)
    3834    \tparam G geometry
    3935*/
     
    8278
    8379/*!
    84     \brief Meta-function which defines point type of any geometry
     80    \brief Meta-function which defines point order of any geometry
    8581    \ingroup core
    8682*/
     
    8884struct point_order
    8985{
    90     typedef typename boost::remove_const<Geometry>::type ncg;
    9186    static const order_selector value = core_dispatch::point_order
    9287        <
    9388            typename tag<Geometry>::type,
    94             ncg
     89            typename boost::remove_const<Geometry>::type
    9590        >::value;
    9691};
  • sandbox/geometry/boost/geometry/extensions/algorithms/connect.hpp

    r61511 r62170  
    2222#include <boost/geometry/geometries/concepts/check.hpp>
    2323
     24#include <boost/geometry/util/write_dsv.hpp>
     25
    2426
    2527
     
    3234{
    3335
     36
     37template <typename Point>
     38struct node
     39{
     40    Point point;
     41    int index;
     42    bool is_from;
     43
     44    node(int i, bool f, Point const& p)
     45        : index(i)
     46        , is_from(f)
     47        , point(p)
     48    {}
     49
     50    node()
     51        : index(-1)
     52        , is_from(false)
     53    {}
     54};
     55
     56template <typename Point>
     57struct map_policy
     58{
     59
     60    // Have a map<point, <index,start/end> > such that we can find
     61    // the corresponding point on each end. Note that it uses the
     62    // default "equals" for the point-type
     63    typedef std::map
     64        <
     65            Point,
     66            std::vector<node<Point> >,
     67            boost::geometry::less<Point>
     68        > map_type;
     69
     70    typedef typename map_type::const_iterator map_iterator_type;
     71    typedef typename std::vector<node<Point> >::const_iterator vector_iterator_type;
     72
     73    typedef Point point_type;
     74    typedef typename distance_result<Point>::type distance_result_type;
     75
     76
     77    map_type map;
     78
     79
     80    inline bool find_start(node<Point>& object,
     81            std::map<int, bool>& included,
     82            int expected_count = 1)
     83    {
     84        for (map_iterator_type it = map.begin();
     85            it != map.end();
     86            ++it)
     87        {
     88            if ((expected_count == 1 && boost::size(it->second) == 1)
     89                || (expected_count > 1 && boost::size(it->second) > 1))
     90            {
     91                for (vector_iterator_type vit = it->second.begin();
     92                    vit != it->second.end();
     93                    ++vit)
     94                {
     95                    if (! included[vit->index])
     96                    {
     97                        included[vit->index] = true;
     98                        object = *vit;
     99                        return true;
     100                    }
     101                }
     102            }
     103        }
     104
     105        // Not found with one point, try one with two points
     106        // to find rings
     107        if (expected_count == 1)
     108        {
     109            return find_start(object, included, 2);
     110        }
     111
     112        return false;
     113    }
     114
     115    inline void add(int index, Point const& p, bool is_from)
     116    {
     117        map[p].push_back(node<Point>(index, is_from, p));
     118    }
     119
     120
     121    template <typename LineString>
     122    inline void add(int index, LineString const& ls)
     123    {
     124        if (boost::size(ls) > 0)
     125        {
     126            add(index, *boost::begin(ls), true);
     127            add(index, *(boost::end(ls) - 1), false);
     128        }
     129    }
     130
     131    inline node<Point> find_closest(Point const& p1, std::map<int, bool>& included)
     132    {
     133        std::vector<node<Point> > const& range = map[p1];
     134
     135        node<Point> closest;
     136
     137
     138        // Alternatively, we might look for the closest points
     139        if (boost::size(range) == 0)
     140        {
     141            std::cout << "nothing found" << std::endl;
     142            return closest;
     143        }
     144
     145        // 2c: for all candidates get closest one
     146
     147        // TODO: make utility to initalize distance result with large value
     148        distance_result_type min_dist
     149            = make_distance_result<distance_result_type>(100);
     150        for (vector_iterator_type it = boost::begin(range);
     151            it != boost::end(range);
     152            ++it)
     153        {
     154            if (! included[it->index])
     155            {
     156                distance_result_type d = geometry::distance(p1, it->point);
     157                if (d < min_dist)
     158                {
     159                    closest = *it;
     160                    min_dist = d;
     161
     162                    //std::cout << "TO " << geometry::wkt(p2) << std::endl;
     163                }
     164            }
     165        }
     166        return closest;
     167    }
     168
     169};
     170
     171
     172template <typename Point>
     173struct fuzzy_policy
     174{
     175
     176    // Have a map<point, <index,start/end> > such that we can find
     177    // the corresponding point on each end. Note that it uses the
     178    // default "equals" for the point-type
     179    typedef std::vector
     180        <
     181            std::pair
     182                <
     183                    Point,
     184                    std::vector<node<Point> >
     185                >
     186        > map_type;
     187
     188    typedef typename map_type::const_iterator map_iterator_type;
     189    typedef typename std::vector<node<Point> >::const_iterator vector_iterator_type;
     190
     191    typedef Point point_type;
     192    typedef typename distance_result<Point>::type distance_result_type;
     193
     194
     195    map_type map;
     196    typename coordinate_type<Point>::type m_limit;
     197
     198
     199    fuzzy_policy(typename coordinate_type<Point>::type limit)
     200        : m_limit(limit)
     201    {}
     202
     203    inline bool find_start(node<Point>& object,
     204            std::map<int, bool>& included,
     205            int expected_count = 1)
     206    {
     207        for (map_iterator_type it = map.begin();
     208            it != map.end();
     209            ++it)
     210        {
     211            if ((expected_count == 1 && boost::size(it->second) == 1)
     212                || (expected_count > 1 && boost::size(it->second) > 1))
     213            {
     214                for (vector_iterator_type vit = it->second.begin();
     215                    vit != it->second.end();
     216                    ++vit)
     217                {
     218                    if (! included[vit->index])
     219                    {
     220                        included[vit->index] = true;
     221                        object = *vit;
     222                        return true;
     223                    }
     224                }
     225            }
     226        }
     227
     228        // Not found with one point, try one with two points
     229        // to find rings
     230        if (expected_count == 1)
     231        {
     232            return find_start(object, included, 2);
     233        }
     234
     235        return false;
     236    }
     237
     238    inline typename boost::range_iterator<map_type>::type fuzzy_closest(Point const& p)
     239    {
     240        typename boost::range_iterator<map_type>::type closest = boost::end(map);
     241
     242        for (typename boost::range_iterator<map_type>::type it = boost::begin(map);
     243            it != boost::end(map);
     244            ++it)
     245        {
     246            distance_result_type d = geometry::distance(p, it->first);
     247            if (d < m_limit)
     248            {
     249                if (closest == boost::end(map))
     250                {
     251                    closest = it;
     252                }
     253                else
     254                {
     255                    distance_result_type dc = geometry::distance(p, closest->first);
     256                    if (d < dc)
     257                    {
     258                        closest = it;
     259                    }
     260                }
     261            }
     262        }
     263        return closest;
     264    }
     265
     266
     267    inline void add(int index, Point const& p, bool is_from)
     268    {
     269        // Iterate through all points and get the closest one.
     270        typename boost::range_iterator<map_type>::type it = fuzzy_closest(p);
     271        if (it == map.end())
     272        {
     273            map.resize(map.size() + 1);
     274            map.back().first = p;
     275            it = map.end() - 1;
     276        }
     277        it->second.push_back(node<Point>(index, is_from, p));
     278    }
     279
     280
     281    template <typename LineString>
     282    inline void add(int index, LineString const& ls)
     283    {
     284        if (boost::size(ls) > 0)
     285        {
     286            add(index, *boost::begin(ls), true);
     287            add(index, *(boost::end(ls) - 1), false);
     288        }
     289    }
     290
     291    inline node<Point> find_closest(Point const& p1, std::map<int, bool>& included)
     292    {
     293        node<Point> closest;
     294
     295        typename boost::range_iterator<map_type>::type it = fuzzy_closest(p1);
     296        if (it == map.end())
     297        {
     298            return closest;
     299        }
     300
     301        std::vector<node<Point> > const& range = it->second;
     302
     303
     304
     305        // Alternatively, we might look for the closest points
     306        if (boost::size(range) == 0)
     307        {
     308            std::cout << "nothing found" << std::endl;
     309            return closest;
     310        }
     311
     312        // 2c: for all candidates get closest one
     313
     314        // TODO: make utility to initalize distance result with large value
     315        distance_result_type min_dist
     316            = make_distance_result<distance_result_type>(100);
     317        for (vector_iterator_type it = boost::begin(range);
     318            it != boost::end(range);
     319            ++it)
     320        {
     321            if (! included[it->index])
     322            {
     323                distance_result_type d = geometry::distance(p1, it->point);
     324                if (d < min_dist)
     325                {
     326                    closest = *it;
     327                    min_dist = d;
     328
     329                    //std::cout << "TO " << geometry::wkt(p2) << std::endl;
     330                }
     331            }
     332        }
     333        return closest;
     334    }
     335};
     336
     337template <typename Policy>
     338inline void debug(Policy const& policy)
     339{
     340    std::cout << "MAP" << std::endl;
     341    typedef typename Policy::map_type::const_iterator iterator;
     342    typedef typename Policy::point_type point_type;
     343
     344    for (iterator it=policy.map.begin(); it != policy.map.end(); ++it)
     345    {
     346        std::cout << geometry::dsv(it->first) << " => " ;
     347        std::vector<node<point_type> > const& range =it->second;
     348        for ( std::vector<node<point_type> >::const_iterator
     349            vit = boost::begin(range); vit != boost::end(range); ++vit)
     350        {
     351            std::cout
     352                << " (" << vit->index
     353                << ", " << (vit->is_from ? "F" : "T")
     354                << ")"
     355                ;
     356        }
     357        std::cout << std::endl;
     358    }
     359}
     360
     361
     362
     363
    34364// Dissolve on multi_linestring tries to create larger linestrings from input,
    35365// or closed rings.
    36366
    37 template <typename Multi, typename GeometryOut>
     367template <typename Multi, typename GeometryOut, typename Policy>
    38368struct connect_multi_linestring
    39369{
     
    41371    typedef typename boost::range_iterator<Multi const>::type iterator_type;
    42372    typedef typename boost::range_value<Multi>::type linestring_type;
    43     typedef typename distance_result<point_type>::type distance_result_type;
    44 
    45     struct mapped
    46     {
    47         int index;
    48         bool is_from;
    49         mapped(int i, bool f) : index(i), is_from(f)
    50         {}
    51     };
    52 
    53     // Have a map<point, <index,start/end> > such that we can find
    54     // the corresponding point on each end. Note that it uses the
    55     // default "equals" for the point-type
    56     typedef std::multimap
    57         <
    58             point_type,
    59             mapped,
    60             boost::geometry::less<point_type>
    61         > map_type;
    62 
    63     typedef typename map_type::const_iterator map_iterator_type;
     373
    64374
    65375    static inline void copy(linestring_type const& ls,
     
    79389    }
    80390
    81     static inline map_iterator_type find_start(map_type const& map,
    82             std::map<int, bool>& included, int expected_count = 1)
    83     {
    84         for (map_iterator_type it = map.begin();
    85             it != map.end();
    86             ++it)
    87         {
    88             typename map_type::size_type count = map.count(it->first);
    89             if (count == expected_count && ! included[it->second.index])
    90             {
    91                 included[it->second.index] = true;
    92                 return it;
    93             }
    94         }
    95 
    96         // Not found with one point, try one with two points
    97         // to find rings
    98         if (expected_count == 1)
    99         {
    100             return find_start(map, included, 2);
    101         }
    102 
    103         return map.end();
    104     }
    105391
    106392    template <typename OutputIterator>
    107     static inline OutputIterator apply(Multi const& multi, OutputIterator out)
     393    static inline OutputIterator apply(Multi const& multi, Policy& policy, OutputIterator out)
    108394    {
    109395        if (boost::size(multi) <= 0)
     
    111397            return out;
    112398        }
    113 
    114         map_type map;
    115399
    116400        // 1: fill the map.
     
    120404            ++it, ++index)
    121405        {
    122             linestring_type const& ls = *it;
    123             if (boost::size(ls) > 0)
    124             {
    125                 map.insert(std::make_pair(*boost::begin(ls), mapped(index, true)));
    126                 map.insert(std::make_pair(*(boost::end(ls) - 1), mapped(index, false)));
    127             }
    128         }
     406            policy.add(index, *it);
     407        }
     408
     409        debug(policy);
    129410
    130411        std::map<int, bool> included;
     
    133414
    134415        // 2a: start with one having a unique starting point
    135         map_iterator_type first = find_start(map, included);
    136         bool found = first != map.end();
    137         if (! found)
     416        node<point_type> starting_point;
     417        if (! policy.find_start(starting_point, included))
    138418        {
    139419            return out;
    140420        }
    141421
    142         int current_index = first->second.index;
    143422        GeometryOut current;
    144         copy(multi[current_index], current, first->second.is_from);
    145 
     423        copy(multi[starting_point.index], current, starting_point.is_from);
     424
     425        bool found = true;
    146426        while(found)
    147427        {
    148428            // 2b: get all candidates, by asking multi-map for range
    149             point_type const& p = *(boost::end(current) - 1);
    150             std::pair<map_iterator_type, map_iterator_type> range
    151                         = map.equal_range(p);
    152 
    153             // Alternatively, we might look for the closest points
    154             if (range.first == map.end())
    155             {
    156                 std::cout << "nothing found" << std::endl;
    157             }
    158 
    159             // 2c: for all candidates get closest one
     429            point_type const& p1 = *(boost::end(current) - 1);
     430
     431            node<point_type> closest = policy.find_closest(p1, included);
     432
    160433            found = false;
    161             int closest_index = -1;
    162             bool from_is_closest = false;
    163             // TODO: make utility to initalize distance result with large value
    164             distance_result_type min_dist
    165                 = make_distance_result<distance_result_type>(100);
    166             for (map_iterator_type it = range.first;
    167                 ! found && it != range.second;
    168                 ++it)
    169             {
    170                 if (it->second.index != current_index
    171                     && ! included[it->second.index])
    172                 {
    173                     linestring_type const& ls = multi[it->second.index];
    174                     point_type const& p = it->second.is_from
    175                         ? *boost::begin(ls)
    176                         : *(boost::end(ls) - 1);
    177 
    178                     distance_result_type d = geometry::distance(it->first, p);
    179                     if (! found || d < min_dist)
    180                     {
    181                         closest_index = it->second.index;
    182                         from_is_closest = it->second.is_from;
    183                         min_dist = d;
    184 
    185                         //std::cout << "TO " << geometry::wkt(p) << std::endl;
    186                     }
     434
     435            // 2d: if there is a closest one add it
     436            if (closest.index >= 0)
     437            {
     438                found = true;
     439                included[closest.index] = true;
     440                copy(multi[closest.index], current, closest.is_from);
     441            }
     442            else if ((included.size() != boost::size(multi)))
     443            {
     444                // Get one which is NOT found and go again
     445                node<point_type> next;
     446                if (policy.find_start(next, included))
     447                {
    187448                    found = true;
    188                 }
    189             }
    190             // 2d: if there is a closest one add it
    191             if (found && closest_index >= 0)
    192             {
    193                 current_index = closest_index;
    194                 included[current_index] = true;
    195                 copy(multi[current_index], current, from_is_closest);
    196             }
    197 
    198             if (! found && (included.size() != boost::size(multi)))
    199             {
    200                 // Get one which is NOT found and go again
    201                 map_iterator_type next = find_start(map, included);
    202                 found = next != map.end();
    203 
    204                 if (found)
    205                 {
    206                     current_index = next->second.index;
    207449
    208450                    *out++ = current;
    209451                    geometry::clear(current);
    210452
    211                     copy(multi[current_index], current, next->second.is_from);
     453                    copy(multi[next.index], current, next.is_from);
    212454                }
    213455            }
     
    236478    typename GeometryOutTag,
    237479    typename Geometry,
    238     typename GeometryOut
     480    typename GeometryOut,
     481    typename Policy
    239482>
    240483struct connect
     
    242485
    243486
    244 template<typename Multi, typename GeometryOut>
    245 struct connect<multi_linestring_tag, linestring_tag, Multi, GeometryOut>
    246     : detail::connect::connect_multi_linestring<Multi, GeometryOut>
     487template<typename Multi, typename GeometryOut, typename Policy>
     488struct connect<multi_linestring_tag, linestring_tag, Multi, GeometryOut, Policy>
     489    : detail::connect::connect_multi_linestring
     490        <
     491            Multi,
     492            GeometryOut,
     493            Policy
     494        >
    247495{};
    248496
     
    259507inline void connect(Geometry const& geometry, Collection& output_collection)
    260508{
     509    typedef typename boost::range_value<Collection>::type geometry_out;
     510
    261511    concept::check<Geometry const>();
    262 
    263     typedef typename boost::range_value<Collection>::type geometry_out;
    264 
    265512    concept::check<geometry_out>();
     513
     514    typedef detail::connect::map_policy
     515        <
     516            typename point_type<Geometry>::type
     517        > policy;
    266518
    267519    dispatch::connect
     
    270522        typename tag<geometry_out>::type,
    271523        Geometry,
    272         geometry_out
    273     >::apply(geometry, std::back_inserter(output_collection));
     524        geometry_out,
     525        policy
     526    >::apply(geometry, policy(), std::back_inserter(output_collection));
    274527}
    275528
    276529
     530
     531template
     532<
     533    typename Geometry,
     534    typename Collection
     535>
     536inline void connect(Geometry const& geometry, Collection& output_collection,
     537            typename coordinate_type<Geometry>::type const& limit)
     538{
     539    typedef typename boost::range_value<Collection>::type geometry_out;
     540
     541    concept::check<Geometry const>();
     542    concept::check<geometry_out>();
     543
     544    typedef detail::connect::fuzzy_policy
     545        <
     546            typename point_type<Geometry>::type
     547        > policy;
     548
     549
     550    dispatch::connect
     551    <
     552        typename tag<Geometry>::type,
     553        typename tag<geometry_out>::type,
     554        Geometry,
     555        geometry_out,
     556        policy
     557    >::apply(geometry, policy(limit), std::back_inserter(output_collection));
     558}
     559
     560
     561
    277562}} // namespace boost::geometry
    278563
  • sandbox/geometry/boost/geometry/geometries/linear_ring.hpp

    r59381 r62170  
    1515#include <boost/concept/assert.hpp>
    1616
     17#include <boost/geometry/core/closure.hpp>
     18#include <boost/geometry/core/point_order.hpp>
    1719#include <boost/geometry/core/tag.hpp>
    1820#include <boost/geometry/core/tags.hpp>
    19 #include <boost/geometry/core/point_order.hpp>
    2021
    2122#include <boost/geometry/geometries/concepts/point_concept.hpp>
     
    3637    typename P,
    3738    template<typename, typename> class V = std::vector,
    38     bool ClockWise = true,
     39    bool ClockWise = true, bool Closed = true,
    3940    template<typename> class A = std::allocator
    4041>
     
    5253    typename P,
    5354    template<typename, typename> class V,
    54     bool ClockWise,
     55    bool ClockWise, bool Closed,
    5556    template<typename> class A
    5657>
    57 struct tag< linear_ring<P, V, ClockWise, A> >
     58struct tag< linear_ring<P, V, ClockWise, Closed, A> >
    5859{
    5960    typedef ring_tag type;
     
    6566    typename P,
    6667    template<typename, typename> class V,
     68    bool Closed,
    6769    template<typename> class A
    6870>
    69 struct point_order< linear_ring<P, V, false, A> >
     71struct point_order< linear_ring<P, V, false, Closed, A> >
    7072{
    7173    static const order_selector value = counterclockwise;
     
    7779    typename P,
    7880    template<typename, typename> class V,
     81    bool Closed,
    7982    template<typename> class A
    8083>
    81 struct point_order< linear_ring<P, V, true, A> >
     84struct point_order< linear_ring<P, V, true, Closed, A> >
    8285{
    8386    static const order_selector value = clockwise;
  • sandbox/geometry/boost/geometry/geometries/polygon.hpp

    r59381 r62170  
    3535    \tparam ClockWise optional parameter, true for clockwise direction,
    3636                false for CounterClockWise direction
     37    \tparam Closed optional parameter, true for closed polygons (last point == first point),
     38                false open points
    3739    \tparam PointAlloc container-allocator-type
    3840    \tparam RingAlloc container-allocator-type
     
    4648    template<typename, typename> class RingList = std::vector,
    4749    bool ClockWise = true,
     50    bool Closed = true,
    4851    template<typename> class PointAlloc = std::allocator,
    4952    template<typename> class RingAlloc = std::allocator
     
    5760    // Member types
    5861    typedef Point point_type;
    59     typedef linear_ring<Point, PointList, ClockWise, PointAlloc> ring_type;
     62    typedef linear_ring<Point, PointList, ClockWise, Closed, PointAlloc> ring_type;
    6063    typedef RingList<ring_type , RingAlloc<ring_type > > inner_container_type;
    6164
     
    8992    template<typename, typename> class PointList,
    9093    template<typename, typename> class RingList,
    91     bool ClockWise,
     94    bool ClockWise, bool Closed,
    9295    template<typename> class PointAlloc,
    9396    template<typename> class RingAlloc
    9497>
    95 struct tag<polygon<Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc> >
     98struct tag<polygon<Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc> >
    9699{
    97100    typedef polygon_tag type;
     
    103106    template<typename, typename> class PointList,
    104107    template<typename, typename> class RingList,
    105     bool ClockWise,
     108    bool ClockWise, bool Closed,
    106109    template<typename> class PointAlloc,
    107110    template<typename> class RingAlloc
    108111>
    109 struct ring_type<polygon<Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc> >
     112struct ring_type<polygon<Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc> >
    110113{
    111114    typedef typename polygon
    112115        <
    113             Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc
     116            Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc
    114117        >::ring_type type;
    115118};
     
    120123    template<typename, typename> class PointList,
    121124    template<typename, typename> class RingList,
    122     bool ClockWise,
     125    bool ClockWise, bool Closed,
    123126    template<typename> class PointAlloc,
    124127    template<typename> class RingAlloc
    125128>
    126 struct interior_type< polygon<Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc> >
     129struct interior_type< polygon<Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc> >
    127130{
    128131    typedef typename polygon
    129132        <
    130             Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc
     133            Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc
    131134        >::inner_container_type type;
    132135};
     
    137140    template<typename, typename> class PointList,
    138141    template<typename, typename> class RingList,
    139     bool ClockWise,
     142    bool ClockWise, bool Closed,
    140143    template<typename> class PointAlloc,
    141144    template<typename> class RingAlloc
    142145>
    143 struct exterior_ring< polygon<Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc> >
     146struct exterior_ring< polygon<Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc> >
    144147{
    145     typedef polygon<Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc> polygon_type;
     148    typedef polygon<Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc> polygon_type;
    146149
    147150    static inline typename polygon_type::ring_type& get(polygon_type& p)
     
    161164    template<typename, typename> class PointList,
    162165    template<typename, typename> class RingList,
    163     bool ClockWise,
     166    bool ClockWise, bool Closed,
    164167    template<typename> class PointAlloc,
    165168    template<typename> class RingAlloc
    166169>
    167 struct interior_rings< polygon<Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc> >
     170struct interior_rings< polygon<Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc> >
    168171{
    169     typedef polygon<Point, PointList, RingList, ClockWise, PointAlloc, RingAlloc> polygon_type;
     172    typedef polygon<Point, PointList, RingList, ClockWise, Closed, PointAlloc, RingAlloc> polygon_type;
    170173
    171174    static inline typename polygon_type::inner_container_type& get(
  • sandbox/geometry/boost/geometry/multi/algorithms/area.hpp

    r61511 r62170  
    2525namespace dispatch
    2626{
    27 template <typename MultiGeometry, order_selector Order, typename Strategy>
    28 struct area<multi_polygon_tag, MultiGeometry, Order, Strategy>
     27template <typename MultiGeometry, order_selector Order, closure_selector Closure, typename Strategy>
     28struct area<multi_polygon_tag, MultiGeometry, Order, Closure, Strategy>
    2929    : detail::multi_sum
    3030        <
     
    3636                    polygon_tag,
    3737                    typename boost::range_value<MultiGeometry>::type,
    38                     Order,
     38                    Order, Closure,
    3939                    Strategy
    4040                >
  • sandbox/geometry/boost/geometry/multi/algorithms/length.hpp

    r61511 r62170  
    3434                <
    3535                    typename boost::range_value<MultiLinestring>::type,
    36                     Strategy
     36                    Strategy,
     37                                        false
    3738                >
    3839        >
  • sandbox/geometry/boost/geometry/util/closeable_view.hpp

    r61760 r62170  
    5151struct closeable_view<Range, true>
    5252{
    53     closeable_view(Range& r)
     53    explicit closeable_view(Range& r)
    5454        : m_range(r)
    5555    {}
  • sandbox/geometry/boost/geometry/util/reversible_view.hpp

    r62070 r62170  
    3131struct reversible_view<Range, iterate_forward>
    3232{
    33     reversible_view(Range& r)
     33    explicit reversible_view(Range& r)
    3434        : m_range(r)
    3535    {}
  • sandbox/geometry/libs/geometry/Jamroot

    r61536 r62170  
    1111project
    1212    : requirements
    13         <warnings>all
    14         <toolset>intel:<warnings>on
     13        <toolset>msvc
     14                <define>_SCL_SECURE_NO_DEPRECATE # For Ublas
    1515        <toolset>gcc:<cxxflags>"-pedantic -Wall -Wstrict-aliasing -fstrict-aliasing -Wno-long-long"
    1616        <include>../..
    17         <include>.
    18         <include>/boost//headers
     17        <dependency>/boost//headers
    1918    ;
  • sandbox/geometry/libs/geometry/example/02_linestring_example.cpp

    r59383 r62170  
    3939};
    4040
     41
     42template<typename Point>
     43struct round_coordinates
     44{
     45    typedef typename boost::geometry::coordinate_type<Point>::type coordinate_type;
     46    coordinate_type m_factor;
     47
     48    inline round_coordinates(coordinate_type const& factor)
     49        : m_factor(factor)
     50    {}
     51
     52    template <int Dimension>
     53    inline void round(Point& p)
     54    {
     55        coordinate_type c = boost::geometry::get<Dimension>(p) / m_factor;
     56        int rounded = c;
     57        boost::geometry::set<Dimension>(p, coordinate_type(rounded) * m_factor);
     58    }
     59
     60    inline void operator()(Point& p)
     61    {
     62        round<0>(p);
     63        round<1>(p);
     64    }
     65};
     66
     67
    4168int main(void)
    4269{
  • sandbox/geometry/libs/geometry/example/Jamfile.v2

    r61168 r62170  
    77# http://www.boost.org/LICENSE_1_0.txt)
    88
    9 project ggl-example
    10     :
    11     requirements
    12         <include>../../../boost
    13         <toolset>gcc:<cxxflags>-pedantic
     9
     10project boost-geometry-example
     11    : # requirements
    1412    ;
    1513
    16 #
    17 # Build core examples
    18 #
    1914exe 01_point_example : 01_point_example.cpp ;
    2015exe 02_linestring_example : 02_linestring_example.cpp ;
     
    3328exe c06_custom_polygon_example : c06_custom_polygon_example.cpp  ;
    3429exe c07_custom_ring_pointer_example : c07_custom_ring_pointer_example.cpp ;
     30# exe c08_custom_non_std_example : c08_custom_non_std_example.cpp ;
  • sandbox/geometry/libs/geometry/example/c04_b_custom_triangle_example.cpp

    r59383 r62170  
    3636
    3737// Specializations of area dispatch structure, implement algorithm
    38 template<typename P, typename S>
    39 struct area<ring_tag, triangle<P>, clockwise, S>
     38template<typename P, typename S, closure_selector Closure>
     39struct area<ring_tag, triangle<P>, clockwise, Closure, S>
    4040{
    4141    static inline double apply(triangle<P> const& t, S const&)
  • sandbox/geometry/libs/geometry/example/extensions/Jamfile.v2

    r60000 r62170  
    66# http://www.boost.org/LICENSE_1_0.txt)
    77
    8 project ggl-example-extensions
     8project boost-geometry-extensions-examples
    99    : # requirements
    1010    ;
  • sandbox/geometry/libs/geometry/example/extensions/gis/Jamfile.v2

    r60000 r62170  
    3535}
    3636
    37 project ggl-example-extensions-gis
     37project boost-geometry-extensions-gis-examples
    3838    :
    3939    requirements
  • sandbox/geometry/libs/geometry/test/Jamfile.v2

    r59773 r62170  
    99import testing ;
    1010
    11 project ggl-test
     11project boost-geometry-test
    1212    :
    1313    requirements
     
    1515        <toolset>msvc:<asynch-exceptions>on
    1616    ;
     17   
    1718
    1819build-project core ;
  • sandbox/geometry/libs/geometry/test/algorithms/Jamfile.v2

    r60550 r62170  
    77# http://www.boost.org/LICENSE_1_0.txt)
    88
    9 test-suite ggl-algorithms
     9test-suite boost-geometry-algorithms
    1010    :
    1111    [ run append.cpp ]
  • sandbox/geometry/libs/geometry/test/algorithms/area.cpp

    r61707 r62170  
    2626    test_geometry<boost::geometry::box<P> >("POLYGON((2 2,0 0))", 4.0);
    2727
     28    // Rotated square, length=sqrt(2) -> area=2
     29    test_geometry<boost::geometry::polygon<P> >("POLYGON((1 1,2 2,3 1,2 0,1 1))", 2.0);
     30
     31
    2832    // clockwise rings (second is wrongly ordered)
    2933    test_geometry<boost::geometry::linear_ring<P> >("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0);
    3034    test_geometry<boost::geometry::linear_ring<P> >("POLYGON((0 0,2 0,4 2,0 7,0 0))", -16.0);
    31 
    32     // counter clockwise rings (first is wrongly ordered)
    33     test_geometry<boost::geometry::linear_ring<P, std::vector, false> >
    34             ("POLYGON((0 0,0 7,4 2,2 0,0 0))", -16.0);
    35     test_geometry<boost::geometry::linear_ring<P, std::vector, false> >
    36             ("POLYGON((0 0,2 0,4 2,0 7,0 0))", 16.0);
    3735
    3836    test_geometry<boost::geometry::polygon<P> >("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0);
     
    7169    typedef boost::geometry::polygon<P, std::vector, std::vector, false> ccw_polygon;
    7270    // counterclockwise rings (second is wrongly ordered)
     71    test_geometry<ccw_polygon>("POLYGON((1 1,2 2,3 1,2 0,1 1))", -2.0);
     72    test_geometry<ccw_polygon>("POLYGON((1 1,2 0,3 1,2 2,1 1))", +2.0);
    7373    test_geometry<ccw_polygon>("POLYGON((0 0,0 7,4 2,2 0,0 0))", -16.0);
    74     test_geometry<ccw_polygon>("POLYGON((0 0,2 0,4 2,0 7,0 0))", 16.0);
     74    test_geometry<ccw_polygon>("POLYGON((0 0,2 0,4 2,0 7,0 0))", +16.0);
    7575}
     76
     77template <typename P>
     78void test_open()
     79{
     80    typedef boost::geometry::polygon<P, std::vector, std::vector, true, false> open_polygon;
     81    test_geometry<open_polygon>("POLYGON((1 1,2 2,3 1,2 0))", 2.0);
     82    // Note the triangular testcase used in CCW is not sensible for open/close
     83}
     84
     85template <typename P>
     86void test_open_ccw()
     87{
     88    typedef boost::geometry::polygon<P, std::vector, std::vector, false, false> open_polygon;
     89    test_geometry<open_polygon>("POLYGON((1 1,2 0,3 1,2 2))", 2.0);
     90    // Note the triangular testcase used in CCW is not sensible for open/close
     91}
     92
    7693
    7794
     
    85102
    86103    test_ccw<boost::geometry::point<double, 2, boost::geometry::cs::cartesian> >();
     104    test_open<boost::geometry::point<double, 2, boost::geometry::cs::cartesian> >();
     105    test_open_ccw<boost::geometry::point<double, 2, boost::geometry::cs::cartesian> >();
    87106
    88107#if defined(HAVE_CLN)
  • sandbox/geometry/libs/geometry/test/algorithms/perimeter.cpp

    r59773 r62170  
    2626}
    2727
     28template <typename P>
     29void test_open()
     30{
     31    typedef boost::geometry::polygon<P, std::vector, std::vector, true, false> open_polygon;
     32    test_geometry<open_polygon>("POLYGON((0 0,0 1,1 1,1 0))", 4);
     33}
     34
     35
    2836int test_main(int, char* [])
    2937{
     
    3139    test_all<boost::geometry::point_xy<float> >();
    3240    test_all<boost::geometry::point_xy<double> >();
     41
     42    test_open<boost::geometry::point_xy<double> >();
    3343
    3444#if defined(HAVE_CLN)
  • sandbox/geometry/libs/geometry/test/extensions/algorithms/connect.cpp

    r61508 r62170  
    1313#include <boost/geometry/geometries/geometries.hpp>
    1414
     15#include <boost/geometry/algorithms/buffer.hpp>
    1516#include <boost/geometry/algorithms/num_points.hpp>
    1617#include <boost/geometry/algorithms/unique.hpp>
     
    3233
    3334
     35
     36
    3437template <typename GeometryOut, typename Geometry>
    35 void test_connect(std::string const& caseid, Geometry const& geometry,
    36         std::size_t expected_point_count,
    37         double expected_length, double percentage)
     38void test_connect(std::string const& caseid, Geometry const& geometry, 
     39        std::size_t expected_count, std::size_t expected_point_count,
     40        double expected_length, double limit = -1, double percentage = 0.001)
    3841{
    3942        namespace bg = boost::geometry;
     
    4144
    4245        std::vector<GeometryOut> connected_vector;
    43         bg::connect(geometry, connected_vector);
     46    if (limit > 0)
     47    {
     48            bg::connect(geometry, connected_vector, limit);
     49    }
     50    else
     51    {
     52            bg::connect(geometry, connected_vector);
     53    }
    4454
    4555        typename bg::length_result<Geometry>::type length = 0;
    46         std::size_t count = 0;
     56    std::size_t count = boost::size(connected_vector);
     57        std::size_t point_count = 0;
    4758
    4859        BOOST_FOREACH(GeometryOut& connected, connected_vector)
     
    5061            bg::unique(connected);
    5162                length += bg::length(connected);
    52                 count += bg::num_points(connected);
     63                point_count += bg::num_points(connected);
    5364        }
    5465
    55     BOOST_CHECK_MESSAGE(count == expected_point_count,
     66    BOOST_CHECK_MESSAGE(count == expected_count,
    5667            "connect: " << caseid
    57             << " #points expected: " << expected_point_count
     68            << " #lines expected: " << expected_count
    5869            << " detected: " << count
    5970            << " type: " << string_from_type<coordinate_type>::name()
     
    6172
    6273
    63     //BOOST_CHECK_EQUAL(holes, expected_hole_count);
     74    BOOST_CHECK_EQUAL(point_count, expected_point_count);
    6475    BOOST_CHECK_CLOSE(length, expected_length, percentage);
    6576
     
    8091            > mapper(svg, 500, 500);
    8192        mapper.add(geometry);
     93
     94        bg::box<typename bg::point_type<Geometry>::type> extent;
     95        bg::envelope(geometry, extent);
     96        bg::buffer(extent, extent, 0.1);
     97        mapper.add(extent);
     98
    8299
    83100        mapper.map(geometry, "opacity:0.6;fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:1");
     
    93110template <typename Geometry, typename GeometryOut>
    94111void test_one(std::string const& caseid, std::string const& wkt,
    95         std::size_t expected_point_count,
    96         double expected_length, double percentage = 0.001)
     112        std::size_t expected_count, std::size_t expected_point_count,
     113        double expected_length, double limit = -1, double percentage = 0.001)
    97114{
    98115    Geometry geometry;
     
    100117
    101118    test_connect<GeometryOut>(caseid, geometry,
    102         expected_point_count,
    103         expected_length, percentage);
     119        expected_count, expected_point_count,
     120        expected_length, limit, percentage);
    104121
    105122#ifdef BOOST_GEOMETRY_TEST_MULTI_PERMUTATIONS
     
    145162    typedef bg::multi_linestring<linestring> multi_linestring;
    146163
     164    goto disconnected;
     165
    147166    test_one<multi_linestring, linestring>("ls_simplex",
    148167        "MULTILINESTRING((0 0,1 1),(1 1,2 2))",
    149         3, 2 * std::sqrt(2.0));
     168        1, 3, 2 * std::sqrt(2.0));
    150169   
    151170    // Opposites, forming one line
    152171    test_one<multi_linestring, linestring>("ls_simplex_opposite_to",
    153172        "MULTILINESTRING((0 0,1 1),(2 2,1 1))",
    154         3, 2 * std::sqrt(2.0));
     173        1, 3, 2 * std::sqrt(2.0));
    155174    test_one<multi_linestring, linestring>("ls_simplex_opposite_from",
    156175        "MULTILINESTRING((1 1,0 0),(1 1,2 2))",
    157         3, 2 * std::sqrt(2.0));
     176        1, 3, 2 * std::sqrt(2.0));
    158177
    159178    // Two output linestrings
    160179    test_one<multi_linestring, linestring>("ls_simplex_two",
    161180        "MULTILINESTRING((0 0,1 1),(1 1,2 2),(3 3,4 4),(4 4,5 5))",
    162         6, 4 * std::sqrt(2.0));
     181        2, 6, 4 * std::sqrt(2.0));
    163182
    164183    // Linestrings forming a ring
    165184    test_one<multi_linestring, linestring>("ls_simplex_ring",
    166185        "MULTILINESTRING((0 0,0 1),(1 1,1 0),(0 1,1 1),(1 0,0 0))",
    167         5, 4.0);
    168 
    169     // disconnected ring
    170     test_one<multi_linestring, linestring>("ls_disconnected_ring",
     186        1, 5, 4.0);
     187
     188    // disconnected rings
     189    test_one<multi_linestring, linestring>("ls_disconnected_ring1",
    171190        "MULTILINESTRING((0 0,0 1.01),(1.02 1.03,0.99 0),(0 0.98,1.001 1),(1.01 0,0 0))",
    172         5, 4.0);
     191        1, 8, 4.137147, 0.5);
     192    test_one<multi_linestring, linestring>("ls_disconnected_ring2",
     193        "MULTILINESTRING((0 0,0 1.01),(1.02 1.03,0.99 0),(0 0.98,1.001 1),(1.01 0,0 0))",
     194        1, 8, 4.137147, 0.1);
     195    test_one<multi_linestring, linestring>("ls_disconnected_ring3",
     196        "MULTILINESTRING((0 0,0 1.01),(1.02 1.03,0.99 0),(0 0.98,1.001 1),(1.01 0,0 0))",
     197        3, 7, 4.05163658, 0.01);
     198
     199disconnected:
     200    test_one<multi_linestring, linestring>("ls_disconnected_ring4",
     201        "MULTILINESTRING((0.01 0,0 1.01),(1.02 1.03,0.99 0),(0 0.98,1.001 1),(1.01 0,0.02 0))",
     202        1, 8, 4.137147, 0.1);
    173203}
    174204
  • sandbox/geometry/libs/geometry/test/geometry_test_common.hpp

    r59786 r62170  
    2727#  include <boost/test/floating_point_comparison.hpp>
    2828#  include <boost/test/included/test_exec_monitor.hpp>
     29//#  include <boost/test/included/prg_exec_monitor.hpp>
     30#  include <boost/test/impl/execution_monitor.ipp>
    2931#endif
    3032
Note: See TracChangeset for help on using the changeset viewer.