From 7afaa597ab27313273d5297479abda0f49ab5750 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 12 May 2013 21:16:35 +0000 Subject: [PATCH 01/12] [geometry] updated doc/releaes notes for 1.54 [SVN r84258] --- doc/release_notes.qbk | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 879ca5fde..c803f8187 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -20,9 +20,18 @@ [*Additional functionality] * added Spatial Index, developed for Boost.Geometry by Adam Wulkiewicz. The spatial index was originally started by Federico J. Fernandez during the Google Summer of Code 2008 program, mentored by Hartmut Kaiser. +* added SVG-output, this was already in extensions for several years + +[*Documentation] + +* small fixes of missing words [*Bugfixes] + * collinear opposite segments did sometimes (in circles) have a robustness issue, fixed +* fixed insertion of false intersection point (found by buffer) +* applied patch of Vladimir Petrovic for debugging traversals + [*Solved tickets] @@ -34,6 +43,10 @@ * [@https://svn.boost.org/trac/boost/ticket/8403 8403] silenced compiler warning C4127: conditional expression is constant * [@https://svn.boost.org/trac/boost/ticket/8405 8405] silenced compiler warning C4189: '...' : local variable is initialized but not referenced +[*Internal changes] + +* Made several algorithms variant-aware (append, area, clear, convert, equals, length, num_points) + [/=================] [heading Boost 1.53] From f36f347857d7465b9e458f3decb5c0d6f19ff75d Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sun, 12 May 2013 23:48:54 +0000 Subject: [PATCH 02/12] geometry.index docs: index general introduction modified, not included yet [SVN r84259] --- doc/index/introduction.qbk | 66 +++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/doc/index/introduction.qbk b/doc/index/introduction.qbk index 0c7e0b7a8..32e98ecb9 100644 --- a/doc/index/introduction.qbk +++ b/doc/index/introduction.qbk @@ -1,7 +1,7 @@ [/============================================================================ Boost.Geometry Index - Copyright (c) 2011-2012 Adam Wulkiewicz. + Copyright (c) 2011-2013 Adam Wulkiewicz. Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -10,10 +10,68 @@ [section Introduction] -The __boost_geometry_index__ is intetended to gather containers (spatial indexes) which may be used to accelerate spatial searching. -It is a part of the __boost_geometry__ library. In general, spatial indexes stores geometric objects' representations and -allows searching for objects occupying some space or close to some point in space. +The __boost_geometry_index__ is intetended to gather data structures called spatial +indexes which may be used to accelerate searching for objects in space. In general, +spatial indexes stores geometric objects' representations and allows searching for +objects occupying some space or close to some point in space. Currently, only one spatial index is implemented - __rtree__. +[section __rtree__] + +__rtree__ is a tree data structure used for spatial searching. It was proposed by +Antonin Guttman in 1984 [footnote Guttman, A. (1984). /R-Trees: A Dynamic Index Structure for Spatial Searching/] +as an expansion of B-tree for multi-dimensional data. It may be used to store points or volumetric data in order to +perform a spatial query. This query may for example return objects that are inside some area or are close to some point in space +[footnote Cheung, K.; Fu, A. (1998). /Enhanced Nearest Neighbour Search on the R-tree/]. It's possible to insert new objects or +to remove the ones already stored. + +The __rtree__ structure is presented on the image below. Each __rtree__'s node store a box descring the space occupied by +its children nodes. At the bottom of the structure, there are leaf-nodes which contains values +(geometric objects representations). + +[$img/index/rtree/rstar.png] + +The __rtree__ is a self-balanced data structure. The key part of balancing algorithm is node splitting algorithm +[footnote Greene, D. (1989). /An implementation and performance analysis of spatial data access methods/] +[footnote Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). /The R*-tree: an efficient and robust access method for points and rectangles/]. +Each algorithm produces different splits so the internal structure of a tree may be different for each one of them. +In general more complex algorithms analyses elements better and produces less overlapping nodes. In the searching process less nodes must be traversed +in order to find desired obejcts. On the other hand more complex analysis takes more time. In general faster inserting will result in slower searching +and vice versa. The performance of the R-tree depends on balancing algorithm, parameters and data inserted into the container. +Example structures of trees created by use of three different algorithms and operations time are presented below. Data used in benchmark was random, +non-overlapping boxes. + +[table +[[] [linear algorithm] [quadratic algorithm] [R*-tree]] +[[*Example structure*] [[$img/index/rtree/linear.png]] [[$img/index/rtree/quadratic.png]] [[$img/index/rtree/rstar.png]]] +[[*1M Values inserts*] [1.65s] [2.51s] [4.96s]] +[[*100k spatial queries*] [0.87s] [0.25s] [0.09s]] +[[*100k knn queries*] [3.25s] [1.41s] [0.51s]] +] + +[heading Implementation details] + +Key features of this implementation of the __rtree__ are: + +* capable to store arbitrary __value__ type, +* three different creation algorithms - linear, quadratic or rstar, +* parameters (including maximal and minimal number of elements) may be passed as compile- or run-time parameters, +* advanced queries - e.g. search for 5 nearest values to some point and intersecting some region but not within the other one, +* C++11 conformant: move semantics, stateful allocators, +* capable to store __value__ type with no default constructor. + +[heading Dependencies] + +R-tree depends on *Boost.Move*, *Boost.Container*, *Boost.Tuple*, *Boost.Utility*, *Boost.MPL*. + +[heading Contributors] + +The spatial index was originally started by Federico J. Fernandez during the Google Summer of Code 2008 program, mentored by Hartmut Kaiser. + +[heading Spatial thanks] + +I'd like to thank Barend Gehrels, Bruno Lalande, Mateusz Łoskot, Lucanus J. Simonson for their support and ideas. + [endsect] + From 4b2c00e6ccc7bc91453fc95f9e748504cf831933 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 13 May 2013 00:39:43 +0000 Subject: [PATCH 03/12] geometry docs: sections rearranged, titles unified. [SVN r84260] --- doc/about_documentation.qbk | 2 +- doc/geometry.qbk | 12 ++-- doc/html/index.html | 29 ++++++---- doc/index/index.qbk | 9 ++- doc/index/introduction.qbk | 2 +- doc/index/rtree/creation.qbk | 28 ++++------ doc/index/rtree/experimental.qbk | 2 +- doc/index/rtree/query.qbk | 4 +- doc/matrix.qbk | 2 +- doc/quickref.xml | 94 ++++++++++++++++---------------- doc/reference.qbk | 6 +- 11 files changed, 100 insertions(+), 90 deletions(-) diff --git a/doc/about_documentation.qbk b/doc/about_documentation.qbk index 33219df5a..e2b277851 100644 --- a/doc/about_documentation.qbk +++ b/doc/about_documentation.qbk @@ -10,7 +10,7 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================/] -[section:aboutdoc About this documentation] +[section:aboutdoc About this Documentation] Within the Boost community there are several styles of documenting. Most libraries nowadays are using QuickBook, the WikiWiki style documentation. diff --git a/doc/geometry.qbk b/doc/geometry.qbk index d0c40eb16..1ba285e36 100644 --- a/doc/geometry.qbk +++ b/doc/geometry.qbk @@ -115,15 +115,17 @@ Boost.Geometry contains contributions by: [include imports.qbk] [include introduction.qbk] -[include quickstart.qbk] - -[include design_rationale.qbk] [include compiling.qbk] -[section Spatial indexes] +[include design_rationale.qbk] +[include quickstart.qbk] + +[section Spatial Indexes] [include index/index.qbk] [endsect] +[include reference.qbk] + [section Indexes] [include matrix.qbk] [section Alphabetical Index] @@ -131,8 +133,6 @@ Boost.Geometry contains contributions by: [endsect] [endsect] -[include reference.qbk] - [include release_notes.qbk] [include about_documentation.qbk] diff --git a/doc/html/index.html b/doc/html/index.html index 044613b92..21783e346 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -46,15 +46,19 @@

Table of Contents

Introduction
-
Quick Start
-
Design Rationale
Compilation
-
Spatial indexes
-
R-tree
-
Indexes
+
Design Rationale
+
Quick Start
+
Spatial Indexes
-
Reference matrix
-
Alphabetical Index
+
Introduction
+
Quick Start
+
Creation + and Modification
+
Queries
+
Examples
+
Experimental + Features
Reference
@@ -70,12 +74,17 @@
Exceptions
Iterators
Models
-
Spatial indexes
+
Spatial Indexes
Strategies
Views
+
Indexes
+
+
Reference Matrix
+
Alphabetical Index
+
Release Notes
-
About this documentation
+
About this Documentation
Acknowledgments
@@ -102,7 +111,7 @@ - +

Last revised: April 03, 2013 at 01:36:35 GMT

Last revised: May 13, 2013 at 00:36:10 GMT


diff --git a/doc/index/index.qbk b/doc/index/index.qbk index 5766162af..0a95c3077 100644 --- a/doc/index/index.qbk +++ b/doc/index/index.qbk @@ -33,6 +33,11 @@ [include imports.qbk] -[/include introduction.qbk/] +[include introduction.qbk] -[include rtree.qbk] +[/include rtree.qbk] +[include rtree/quickstart.qbk] +[include rtree/creation.qbk] +[include rtree/query.qbk] +[include rtree/examples.qbk] +[include rtree/experimental.qbk] diff --git a/doc/index/introduction.qbk b/doc/index/introduction.qbk index 32e98ecb9..2d15a39f4 100644 --- a/doc/index/introduction.qbk +++ b/doc/index/introduction.qbk @@ -17,7 +17,7 @@ objects occupying some space or close to some point in space. Currently, only one spatial index is implemented - __rtree__. -[section __rtree__] +[heading __rtree__] __rtree__ is a tree data structure used for spatial searching. It was proposed by Antonin Guttman in 1984 [footnote Guttman, A. (1984). /R-Trees: A Dynamic Index Structure for Spatial Searching/] diff --git a/doc/index/rtree/creation.qbk b/doc/index/rtree/creation.qbk index 04aa9734b..0b6e87748 100644 --- a/doc/index/rtree/creation.qbk +++ b/doc/index/rtree/creation.qbk @@ -8,11 +8,13 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================/] -[section Creation and modification] +[section Creation and Modification] -[section Template parameters] +[section Construction] -__rtree__ has 5 parameters: +[h4 Template parameters] + +__rtree__ has 5 parameters but only 2 are required: rtree`: * for `tuple<...>` - compares all components of the `__value__`. If the component is a `Geometry`, `geometry::equals()` function is used. For other types it uses `operator==()`. -[endsect] - -[section Balancing algorithms] - -[heading Compile-time] +[h4 Balancing algorithms compile-time parameters] `__value__`s may be inserted to the __rtree__ in many various ways. Final internal structure of the __rtree__ depends on algorithms used in the insertion process and parameters. The most important is @@ -85,7 +81,7 @@ R*-tree - balancing algorithm minimizing nodes' overlap with forced reinsertions index::rtree< __value__, index::rstar<16> > rt; -[heading Run-time] +[h4 Balancing algorithms run-time parameters] Balancing algorithm parameters may be passed to the __rtree__ in run-time. To use run-time versions of the __rtree__ one may pass parameters which @@ -102,7 +98,7 @@ names start with `dynamic_`. The obvious drawback is a slightly slower __rtree__. -[heading Non-default parameters] +[h4 Non-default parameters] Non-default R-tree parameters are described in the reference. @@ -163,7 +159,7 @@ Typically you will perform those operations in a loop in order to e.g. insert some number of `__value__`s corresponding to geometrical objects (e.g. `Polygons`) stored in another container. -[heading Additional interface] +[h4 Additional interface] The __rtree__ allows creation, inserting and removing of Values from a range. The range may be passed as [first, last) Iterators pair or as a Range. @@ -204,7 +200,7 @@ The __rtree__ allows creation, inserting and removing of Values from a range. Th // remove values with remove(Range) rt3.remove(values); -[heading Insert iterator] +[h4 Insert iterator] There are functions like `std::copy()`, or __rtree__'s queries that copy values to an output iterator. In order to insert values to a container in this kind of function insert iterators may be used. @@ -228,4 +224,4 @@ Geometry.Index provide its own `bgi::insert_iterator` which is genera [endsect] -[endsect] [/ Creation and modification /] +[endsect] [/ Creation and Modification /] diff --git a/doc/index/rtree/experimental.qbk b/doc/index/rtree/experimental.qbk index 71aae4f28..cfa87a911 100644 --- a/doc/index/rtree/experimental.qbk +++ b/doc/index/rtree/experimental.qbk @@ -8,7 +8,7 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================/] -[section Experimental features] +[section Experimental Features] This section describes experimental features which are implemented but unavailable by default. Be aware that they may not be released in the future or functionalities may be released but diff --git a/doc/index/rtree/query.qbk b/doc/index/rtree/query.qbk index 328dc6437..5246a14b9 100644 --- a/doc/index/rtree/query.qbk +++ b/doc/index/rtree/query.qbk @@ -81,7 +81,7 @@ All spatial predicates may be negated, e.g.: [section Distance predicates] -[heading Nearest neighbours queries] +[h4 Nearest neighbours queries] Nearest neighbours queries returns `__value__`s which are closest to some point in space. Additionally it is possible to define how the distance to the `Value` should be calculated. @@ -89,7 +89,7 @@ The example of knn query is presented below. 5 `__value__`s nearest to some poin [$img/index/rtree/knn.png] -[heading k nearest neighbours] +[h4 k nearest neighbours] There are three ways of performing knn queries. Following queries returns `k` `__value__`s closest to some point in space. For `__box__`es diff --git a/doc/matrix.qbk b/doc/matrix.qbk index 2b6bdb538..4e03a9b85 100644 --- a/doc/matrix.qbk +++ b/doc/matrix.qbk @@ -10,6 +10,6 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================/] -[section:matrix Reference matrix] +[section:matrix Reference Matrix] [xinclude quickref.xml] [endsect] diff --git a/doc/quickref.xml b/doc/quickref.xml index 98c9ef203..87952f4d7 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -643,69 +643,69 @@ R-tree - boost::geometry::index::rtree + boost::geometry::index::rtree R-tree parameters - boost::geometry::index::linear - boost::geometry::index::quadratic - boost::geometry::index::rstar - boost::geometry::index::dynamic_linear - boost::geometry::index::dynamic_quadratic - boost::geometry::index::dynamic_rstar + boost::geometry::index::linear + boost::geometry::index::quadratic + boost::geometry::index::rstar + boost::geometry::index::dynamic_linear + boost::geometry::index::dynamic_quadratic + boost::geometry::index::dynamic_rstar R-tree constructors and destructor - rtree() - rtree(parameters_type const &, indexable_getter const &, value_equal const &, allocator_type const &) - rtree(Iterator, Iterator) - rtree(Range const &) - rtree(rtree const &) - rtree(rtree const &, allocator_type const &) - rtree(rtree &&) - rtree(rtree &&, allocator_type const &) - ~rtree() + rtree() + rtree(parameters_type const &, indexable_getter const &, value_equal const &, allocator_type const &) + rtree(Iterator, Iterator) + rtree(Range const &) + rtree(rtree const &) + rtree(rtree const &, allocator_type const &) + rtree(rtree &&) + rtree(rtree &&, allocator_type const &) + ~rtree() R-tree member functions - operator=(const rtree &) - operator=(rtree &&) - swap(rtree &) - insert(value_type const &) - insert(Iterator, Iterator) - insert(Range const &) - remove(value_type const &) - remove(Iterator, Iterator) - remove(Range const &) - query(Predicates const &, OutIter) - size() - empty() - clear() - bounds() - count(ValueOrIndexable const &) - parameters() - indexable_get() - value_eq() - get_allocator() + operator=(const rtree &) + operator=(rtree &&) + swap(rtree &) + insert(value_type const &) + insert(Iterator, Iterator) + insert(Range const &) + remove(value_type const &) + remove(Iterator, Iterator) + remove(Range const &) + query(Predicates const &, OutIter) + size() + empty() + clear() + bounds() + count(ValueOrIndexable const &) + parameters() + indexable_get() + value_eq() + get_allocator() R-tree free functions (boost::geometry::index::) - insert(rtree<...> &, Value const &) - insert(rtree<...> &, Iterator, Iterator) - insert(rtree<...> &, Range const &) - remove(rtree<...> &, Value const &) - remove(rtree<...> &, Iterator, Iterator) - remove(rtree<...> &, Range const &) - query(rtree<...> const &, Predicates const &, OutIter) - clear(rtree<...> &) - size(rtree<...> const &) - empty(rtree<...> const &) - bounds(rtree<...> const &) - swap(rtree<...> &, rtree<...> &) + insert(rtree<...> &, Value const &) + insert(rtree<...> &, Iterator, Iterator) + insert(rtree<...> &, Range const &) + remove(rtree<...> &, Value const &) + remove(rtree<...> &, Iterator, Iterator) + remove(rtree<...> &, Range const &) + query(rtree<...> const &, Predicates const &, OutIter) + clear(rtree<...> &) + size(rtree<...> const &) + empty(rtree<...> const &) + bounds(rtree<...> const &) + swap(rtree<...> &, rtree<...> &) diff --git a/doc/reference.qbk b/doc/reference.qbk index 563f589ef..6aae5db01 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -242,9 +242,9 @@ [endsect] -[section:spatial_indexes Spatial indexes] +[section:spatial_indexes Spatial Indexes] -[section:rtree R-tree] +[/section:rtree R-tree] [include index/generated/rtree.qbk] [include index/generated/rtree_functions.qbk] [section:parameters R-tree parameters (boost::geometry::index::)] @@ -255,7 +255,7 @@ [include index/generated/rtree_dynamic_quadratic.qbk] [include index/generated/rtree_dynamic_rstar.qbk] [endsect] -[endsect] +[/endsect] [section:observers Observers (boost::geometry::index::)] [include index/generated/indexable.qbk] From ed2f1fd3876db61a8533857d0b2c61807e62b552 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 13 May 2013 00:46:45 +0000 Subject: [PATCH 04/12] geometry.index docs: section title changed. [SVN r84261] --- doc/index/rtree/creation.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index/rtree/creation.qbk b/doc/index/rtree/creation.qbk index 0b6e87748..b4f912e27 100644 --- a/doc/index/rtree/creation.qbk +++ b/doc/index/rtree/creation.qbk @@ -10,7 +10,7 @@ [section Creation and Modification] -[section Construction] +[section Creation] [h4 Template parameters] From 3ebe782140b3ef6a4b5fb2e237c252b6e6be95e1 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 13 May 2013 00:54:31 +0000 Subject: [PATCH 05/12] geometry.index docs: sections in section 'Creation and Modification' replaced by headings. [SVN r84262] --- doc/index/rtree/creation.qbk | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/doc/index/rtree/creation.qbk b/doc/index/rtree/creation.qbk index b4f912e27..0f5055e86 100644 --- a/doc/index/rtree/creation.qbk +++ b/doc/index/rtree/creation.qbk @@ -10,8 +10,6 @@ [section Creation and Modification] -[section Creation] - [h4 Template parameters] __rtree__ has 5 parameters but only 2 are required: @@ -102,9 +100,7 @@ The obvious drawback is a slightly slower __rtree__. Non-default R-tree parameters are described in the reference. -[endsect] - -[section Copying, moving and swapping] +[h4 Copying, moving and swapping] The __rtree__ is copyable and movable container. Move semantics is implemented using Boost.Move library so it's possible to move the container on a compilers without rvalue references support. @@ -127,9 +123,7 @@ so it's possible to move the container on a compilers without rvalue references // swap rt3.swap(rt2); -[endsect] - -[section Inserting and removing Values] +[h4 Inserting and removing Values] The following code creates an __rtree__ using quadratic balancing algorithm. @@ -222,6 +216,4 @@ Geometry.Index provide its own `bgi::insert_iterator` which is genera RTree rt2; rt1.spatial_query(Box(/*...*/), bgi::inserter(rt2)); -[endsect] - [endsect] [/ Creation and Modification /] From 6d63401f0828864c6c0cc1dd8eff4db51aca4cf6 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 13 May 2013 23:26:07 +0000 Subject: [PATCH 06/12] geometry.index docs: typo fixed. [SVN r84278] --- doc/index/introduction.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index/introduction.qbk b/doc/index/introduction.qbk index 2d15a39f4..d8c82e25f 100644 --- a/doc/index/introduction.qbk +++ b/doc/index/introduction.qbk @@ -10,7 +10,7 @@ [section Introduction] -The __boost_geometry_index__ is intetended to gather data structures called spatial +The __boost_geometry_index__ is intended to gather data structures called spatial indexes which may be used to accelerate searching for objects in space. In general, spatial indexes stores geometric objects' representations and allows searching for objects occupying some space or close to some point in space. From a5695c831120ce1f5e18e9c3f451abbe04da51b1 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Wed, 15 May 2013 23:24:56 +0000 Subject: [PATCH 07/12] geometry.index: added handling of Segments to path queries. [SVN r84292] --- .../detail/algorithms/path_intersection.hpp | 56 ++++++++++++------- .../index/detail/distance_predicates.hpp | 10 ++-- .../geometry/index/detail/predicates.hpp | 8 +-- include/boost/geometry/index/predicates.hpp | 18 +++--- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/include/boost/geometry/index/detail/algorithms/path_intersection.hpp b/include/boost/geometry/index/detail/algorithms/path_intersection.hpp index 5e5d91830..0bdb6552f 100644 --- a/include/boost/geometry/index/detail/algorithms/path_intersection.hpp +++ b/include/boost/geometry/index/detail/algorithms/path_intersection.hpp @@ -17,24 +17,33 @@ namespace boost { namespace geometry { namespace index { namespace detail { namespace dispatch { -template +template struct path_intersection { - BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (path_intersection)); + BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_OR_INDEXABLE, (path_intersection)); +}; + +template +struct path_intersection +{ + typedef typename default_distance_result::type>::type comparable_distance_type; + + static inline bool apply(Indexable const& b, Segment const& segment, comparable_distance_type & comparable_distance) + { + typedef typename ::boost::geometry::traits::point_type::type point_type; + point_type p1, p2; + geometry::detail::assign_point_from_index<0>(segment, p1); + geometry::detail::assign_point_from_index<1>(segment, p2); + return index::detail::segment_intersection(b, p1, p2, comparable_distance); + } }; template -struct path_intersection +struct path_intersection { - BOOST_MPL_ASSERT_MSG((false), SEGMENT_POINT_INTERSECTION_UNAVAILABLE, (path_intersection)); -}; + typedef typename default_length_result::type comparable_distance_type; -template -struct path_intersection -{ - typedef typename default_length_result::type length_type; - - static inline bool apply(Indexable const& b, Linestring const& path, length_type & comparable_distance) + static inline bool apply(Indexable const& b, Linestring const& path, comparable_distance_type & comparable_distance) { typedef typename ::boost::range_value::type point_type; typedef typename ::boost::range_const_iterator::type const_iterator; @@ -59,7 +68,7 @@ struct path_intersection typename default_distance_result::type dist = geometry::distance(*it0, *it1); - length_type rel_dist; + comparable_distance_type rel_dist; if ( index::detail::segment_intersection(b, *it0, *it1, rel_dist) ) { comparable_distance += dist * rel_dist; @@ -76,19 +85,28 @@ struct path_intersection } // namespace dispatch -// TODO - change the name e.g. to path_intersection_distance -// and segment_intersection e.g. to segment_intersection_relative_distance +template +struct default_path_intersection_distance_type +{ + typedef typename dispatch::path_intersection< + Indexable, SegmentOrLinestring, + typename detail::traits::tag::type, + typename detail::traits::tag::type + >::comparable_distance_type type; +}; -template inline +template inline bool path_intersection(Indexable const& b, - Linestring const& path, - typename default_length_result::type & distance) + SegmentOrLinestring const& path, + typename default_path_intersection_distance_type::type & comparable_distance) { // TODO check Indexable and Linestring concepts return dispatch::path_intersection< - Indexable, Linestring, typename detail::traits::tag::type - >::apply(b, path, distance); + Indexable, SegmentOrLinestring, + typename detail::traits::tag::type, + typename detail::traits::tag::type + >::apply(b, path, comparable_distance); } }}}} // namespace boost::geometry::index::detail diff --git a/include/boost/geometry/index/detail/distance_predicates.hpp b/include/boost/geometry/index/detail/distance_predicates.hpp index 5ab66ca1a..bf1a86021 100644 --- a/include/boost/geometry/index/detail/distance_predicates.hpp +++ b/include/boost/geometry/index/detail/distance_predicates.hpp @@ -143,14 +143,14 @@ struct calculate_distance< nearest< to_furthest >, Indexable, value_tag> } }; -template -struct calculate_distance< path, Indexable, Tag> +template +struct calculate_distance< path, Indexable, Tag> { - typedef typename geometry::default_length_result::type result_type; + typedef typename geometry::default_length_result::type result_type; - static inline bool apply(path const& p, Indexable const& i, result_type & result) + static inline bool apply(path const& p, Indexable const& i, result_type & result) { - return index::detail::path_intersection(i, p.linestring, result); + return index::detail::path_intersection(i, p.geometry, result); } }; diff --git a/include/boost/geometry/index/detail/predicates.hpp b/include/boost/geometry/index/detail/predicates.hpp index 0149d7cd4..dbd98cf1c 100644 --- a/include/boost/geometry/index/detail/predicates.hpp +++ b/include/boost/geometry/index/detail/predicates.hpp @@ -151,14 +151,14 @@ struct nearest unsigned count; }; -template +template struct path { - path(Linestring const& ls, unsigned k) - : linestring(ls) + path(SegmentOrLinestring const& g, unsigned k) + : geometry(g) , count(k) {} - Linestring linestring; + SegmentOrLinestring geometry; unsigned count; }; diff --git a/include/boost/geometry/index/predicates.hpp b/include/boost/geometry/index/predicates.hpp index a42e8665b..67690b1f2 100644 --- a/include/boost/geometry/index/predicates.hpp +++ b/include/boost/geometry/index/predicates.hpp @@ -240,14 +240,14 @@ nearest(Point const& point, unsigned k) /*! \brief Generate path() predicate. -When path predicate is passed to the query, the returned values are k values on the path closest to -its begin. \c path() predicate takes a \c Linestring defining the path and the maximum +When path predicate is passed to the query, the returned values are k values along the path closest to +its begin. \c path() predicate takes a \c Segment or a \c Linestring defining the path and the maximum number of \c Values that should be returned. \par Example \verbatim -bgi::query(spatial_index, bgi::path(pt, 5), std::back_inserter(result)); -bgi::query(spatial_index, bgi::path(pt, 5) && bgi::intersects(box), std::back_inserter(result)); +bgi::query(spatial_index, bgi::path(segment, 5), std::back_inserter(result)); +bgi::query(spatial_index, bgi::path(linestring, 5) && bgi::intersects(box), std::back_inserter(result)); \endverbatim \warning @@ -255,14 +255,14 @@ Only one distance predicate (\c nearest() or \c path()) may be used in a query. \ingroup predicates -\param point The point from which distance is calculated. +\param linestring The path along which distance is calculated. \param k The maximum number of values to return. */ -template inline -detail::path -path(Linestring const& linestring, unsigned k) +template inline +detail::path +path(SegmentOrLinestring const& linestring, unsigned k) { - return detail::path(linestring, k); + return detail::path(linestring, k); } #endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL From 82b4c794417f4eb40f544e3c290bff03a844bebb Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Wed, 15 May 2013 23:26:55 +0000 Subject: [PATCH 08/12] geometry.index test,example: added benchmark and test for segment path queries. [SVN r84293] --- index/example/benchmark_experimental.cpp | 22 +++++++++++++++-- index/test/algorithms/path_intersection.cpp | 26 ++++++++++++++++----- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/index/example/benchmark_experimental.cpp b/index/example/benchmark_experimental.cpp index 67c7dc348..e84637d0c 100644 --- a/index/example/benchmark_experimental.cpp +++ b/index/example/benchmark_experimental.cpp @@ -18,6 +18,7 @@ #include #include +#include namespace bg = boost::geometry; namespace bgi = bg::index; @@ -25,6 +26,7 @@ namespace bgi = bg::index; typedef bg::model::point P; typedef bg::model::box

B; typedef bg::model::linestring

LS; +typedef bg::model::segment

S; template void mycopy(I1 first, I2 last, O o) @@ -283,7 +285,7 @@ int main() temp += result.size(); } dur_t time = clock_t::now() - start; - std::cout << time << " - query(path(LS, " << path_values_count << ")) " << path_queries_count << " found " << temp << '\n'; + std::cout << time << " - query(path(LS6, " << path_values_count << ")) " << path_queries_count << " found " << temp << '\n'; } { @@ -303,7 +305,23 @@ int main() temp += result.size(); } dur_t time = clock_t::now() - start; - std::cout << time << " - query(path(LS, " << path_values_count << ")) " << path_queries_count2 << " found " << temp << '\n'; + std::cout << time << " - query(path(LS2, " << path_values_count << ")) " << path_queries_count2 << " found " << temp << '\n'; + } + + { + clock_t::time_point start = clock_t::now(); + size_t temp = 0; + for (size_t i = 0 ; i < path_queries_count2 ; ++i ) + { + float x = coords[i].first; + float y = coords[i].second; + S seg(P(x, y), P(x+max_val/100, y+max_val/100)); + result.clear(); + t.query(bgi::path(seg, path_values_count), std::back_inserter(result)); + temp += result.size(); + } + dur_t time = clock_t::now() - start; + std::cout << time << " - query(path(S, " << path_values_count << ")) " << path_queries_count2 << " found " << temp << '\n'; } #endif { diff --git a/index/test/algorithms/path_intersection.cpp b/index/test/algorithms/path_intersection.cpp index ff7c75759..2670d0775 100644 --- a/index/test/algorithms/path_intersection.cpp +++ b/index/test/algorithms/path_intersection.cpp @@ -11,6 +11,12 @@ #include +#include +#include +#include +#include +#include + //#include template @@ -18,11 +24,24 @@ void test_path_intersection(Box const& box, Linestring const& path, bool expected_result, typename bg::default_length_result::type expected_dist) { - typename bg::default_length_result::type dist; + typename bgi::detail::default_path_intersection_distance_type::type dist; + bool value = bgi::detail::path_intersection(box, path, dist); BOOST_CHECK(value == expected_result); if ( value && expected_result ) BOOST_CHECK_CLOSE(dist, expected_dist, 0.0001); + + if ( ::boost::size(path) == 2 ) + { + typedef typename ::boost::range_value::type P; + typedef bg::model::segment

Seg; + typename bgi::detail::default_path_intersection_distance_type::type dist; + Seg seg(*::boost::begin(path), *(::boost::begin(path)+1)); + bool value = bgi::detail::path_intersection(box, seg, dist); + BOOST_CHECK(value == expected_result); + if ( value && expected_result ) + BOOST_CHECK_CLOSE(dist, expected_dist, 0.0001); + } } template @@ -37,11 +56,6 @@ void test_geometry(std::string const& wkt_g, std::string const& wkt_path, test_path_intersection(box, path, expected_result, expected_dist); } -#include -#include -#include -#include - void test_large_integers() { typedef bg::model::point int_point_type; From 4a59810947328c842c0a590ee011d761030624ff Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 16 May 2013 10:17:25 +0000 Subject: [PATCH 09/12] geometry.index docs: experimental features commented, sections replaced by headings in queries description [SVN r84296] --- doc/html/index.html | 4 +--- doc/index/index.qbk | 2 +- doc/index/rtree/experimental.qbk | 5 +++-- doc/index/rtree/query.qbk | 28 ++++++++-------------------- 4 files changed, 13 insertions(+), 26 deletions(-) diff --git a/doc/html/index.html b/doc/html/index.html index 21783e346..fd6a30faf 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -57,8 +57,6 @@ and Modification

Queries
Examples
-
Experimental - Features
Reference
@@ -111,7 +109,7 @@ - +

Last revised: May 13, 2013 at 00:36:10 GMT

Last revised: May 16, 2013 at 10:14:50 GMT


diff --git a/doc/index/index.qbk b/doc/index/index.qbk index 0a95c3077..e8021c3e7 100644 --- a/doc/index/index.qbk +++ b/doc/index/index.qbk @@ -40,4 +40,4 @@ [include rtree/creation.qbk] [include rtree/query.qbk] [include rtree/examples.qbk] -[include rtree/experimental.qbk] +[/include rtree/experimental.qbk] diff --git a/doc/index/rtree/experimental.qbk b/doc/index/rtree/experimental.qbk index cfa87a911..afce597f0 100644 --- a/doc/index/rtree/experimental.qbk +++ b/doc/index/rtree/experimental.qbk @@ -33,14 +33,15 @@ a relation object instead of a Point to the nearest predicate, as follows: [heading Path query] -Path query returns `k` first `__value__`s intersecting a path defined by a `Linestring`. The result of a query returning first 5 +Path query returns `k` first `__value__`s intersecting a path defined by a `Segment` or a`Linestring`. The result of a query returning first 5 values intersecting a path is presented below. Path's flow is denoted by blue arrows, returned values are orange. [$img/index/rtree/path.png] -To perform this query one may pass a `path()` predicate taking a `Linestring` and maximum number of `__value__`s which +To perform this query one may pass a `path()` predicate taking a `Segment` or a `Linestring` and maximum number of `__value__`s which should be returned: + rtree.query(index::path(segment, k), std::back_inserter(returned_values)); rtree.query(index::path(linestring, k), std::back_inserter(returned_values)); [warning Only one distance predicate may be used in a query. This means that there can be only one `nearest()` or `path()` predicate passed. Passing more of them will result in compile-time error.] diff --git a/doc/index/rtree/query.qbk b/doc/index/rtree/query.qbk index 5246a14b9..e171c7f50 100644 --- a/doc/index/rtree/query.qbk +++ b/doc/index/rtree/query.qbk @@ -22,7 +22,7 @@ For example queries may be used to retrieve Values: * are nearest to some point, * overlapping a box and has user-defined property. -[section Performing a query] +[h4 Performing a query] There are three ways to perform a query presented below. All of them returns `__value__`s intersecting some region defined as a `__box__`. @@ -45,9 +45,7 @@ Use of pipe operator generating a range BOOST_FOREACH(__value__ & v, rt | index::adaptors::queried(bgi::intersects(box_region))) ; // do something with v -[endsect] - -[section Spatial predicates] +[h4 Spatial predicates] Queries using spatial predicates returns `__value__`s which are related somehow to some Geometry - box, polygon, etc. Names of spatial predicates correspond to names of __boost_geometry__ algorithms. Examples of some @@ -77,11 +75,9 @@ All spatial predicates may be negated, e.g.: // the same as rt.query(index::disjoint(box), std::back_inserter(result)); -[endsect] +[h4 Distance predicates] -[section Distance predicates] - -[h4 Nearest neighbours queries] +[h5 Nearest neighbours queries] Nearest neighbours queries returns `__value__`s which are closest to some point in space. Additionally it is possible to define how the distance to the `Value` should be calculated. @@ -89,7 +85,7 @@ The example of knn query is presented below. 5 `__value__`s nearest to some poin [$img/index/rtree/knn.png] -[h4 k nearest neighbours] +[h5 k nearest neighbours] There are three ways of performing knn queries. Following queries returns `k` `__value__`s closest to some point in space. For `__box__`es @@ -113,9 +109,7 @@ Use of `operator |` BOOST_FOREACH(__value__ & v, rt | index::adaptors::queried(index::nearest(pt, k))) ; // do something with v -[endsect] - -[section User-defined unary predicate] +[h4 User-defined unary predicate] The user may pass a `UnaryPredicate` - function, function object or lambda expression taking const reference to Value and returning bool. This object may be passed to the query in order to check if `__value__` should be returned by the query. To do it one @@ -161,9 +155,7 @@ may use `index::satisfies()` function like on the example below: rt.query(index::intersects(box) && !index::satisfies(is_not_red), std::back_inserter(result)); -[endsect] - -[section Passing a set of predicates] +[h4 Passing a set of predicates] It's possible to use some number of predicates in one query by connecting them with `operator&&` e.g. `Pred1 && Pred2 && Pred3 && ...`. @@ -185,9 +177,7 @@ Of course it's possible to connect different types of predicates together. BOOST_FOREACH(Value & v, rt | index::adaptors::queried(index::nearest(pt, k) && index::covered_by(b))) ; // do something with v -[endsect] - -[section Inserting query results into the other R-tree] +[h4 Inserting query results into the other R-tree] There are several ways of inserting Values returned by a query to the other R-tree container. The most basic way is creating a temporary container for Values and insert them later. @@ -214,6 +204,4 @@ constructor. RTree rt4(rt1 | bgi::adaptors::queried(bgi::intersects(Box(/*...*/))))); -[endsect] - [endsect] [/ Queries /] From a8c6c4bad6116433539501137f477f7a8fcf5d5a Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 18 May 2013 10:59:21 +0000 Subject: [PATCH 10/12] geometry::index: wrong result_type in calculate_distance for path predicate fixed [SVN r84344] --- include/boost/geometry/index/detail/distance_predicates.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/geometry/index/detail/distance_predicates.hpp b/include/boost/geometry/index/detail/distance_predicates.hpp index bf1a86021..c5c2c4c51 100644 --- a/include/boost/geometry/index/detail/distance_predicates.hpp +++ b/include/boost/geometry/index/detail/distance_predicates.hpp @@ -146,7 +146,9 @@ struct calculate_distance< nearest< to_furthest >, Indexable, value_tag> template struct calculate_distance< path, Indexable, Tag> { - typedef typename geometry::default_length_result::type result_type; + typedef typename index::detail::default_path_intersection_distance_type< + Indexable, SegmentOrLinestring + >::type result_type; static inline bool apply(path const& p, Indexable const& i, result_type & result) { From 881fb2d33dc5133c718b61f7da12e2a89fdf754f Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Mon, 20 May 2013 17:42:36 +0000 Subject: [PATCH 11/12] [geometry] added Mats' example of adapting a legacy hierarchy, added SVG samples [SVN r84393] --- doc/doxy/Doxyfile | 2 + ...dapting_a_legacy_geometry_object_model.qbk | 587 ++++++++++++++++++ doc/geometry.qbk | 4 + doc/html/img/io/svg_mapper.png | Bin 0 -> 12582 bytes doc/imports.qbk | 2 + doc/make_qbk.py | 5 +- doc/reference.qbk | 11 + doc/reference/io/svg.qbk | 16 + doc/src/examples/io/svg.cpp | 65 ++ 9 files changed, 691 insertions(+), 1 deletion(-) create mode 100644 doc/example_adapting_a_legacy_geometry_object_model.qbk create mode 100644 doc/html/img/io/svg_mapper.png create mode 100644 doc/reference/io/svg.qbk create mode 100644 doc/src/examples/io/svg.cpp diff --git a/doc/doxy/Doxyfile b/doc/doxy/Doxyfile index e75f5a84c..880e69b0c 100644 --- a/doc/doxy/Doxyfile +++ b/doc/doxy/Doxyfile @@ -184,6 +184,8 @@ INPUT = . .. ../../../../boost/geometry/core \ ../../../../boost/geometry/geometries/adapted \ ../../../../boost/geometry/geometries/register \ ../../../../boost/geometry/iterators \ + ../../../../boost/geometry/io/wkt \ + ../../../../boost/geometry/io/svg \ ../../../../boost/geometry/multi/algorithms \ ../../../../boost/geometry/multi/algorithms/detail \ ../../../../boost/geometry/multi/core \ diff --git a/doc/example_adapting_a_legacy_geometry_object_model.qbk b/doc/example_adapting_a_legacy_geometry_object_model.qbk new file mode 100644 index 000000000..8c3b9b3a2 --- /dev/null +++ b/doc/example_adapting_a_legacy_geometry_object_model.qbk @@ -0,0 +1,587 @@ +[section Example: Adapting a legacy geometry object model] + +One of the primary benefits of __boost_geometry__, and the reason for its fairly complex template-based implementation, is that it allows for integration with legacy classes/objects. + +By defining the relationship between the __boost_geometry__ concepts and an existing, legacy object model, the legacy objects can be used in place of __boost_geometry__'s own geometry classes. + +__boost_geometry__ will then happliy read and write directly from and to the legacy object, treating it as a native __boost_geometry__ object. + +This means that one can adapt algorithms and methods from __boost_geometry__ to any existing legacy geometry object model at a very small runtime cost, which is simply not possible with most geometry libraries, where one has to make an intermediate object specific to the geometry library one is using. + +The following example will demonstrate the adaption process of a legacy geometry object model for use with __boost_geometry__. + +[h2 Adapting a shared geometry legacy object model] + +[h3 Example code: object hierarcy] + + class QPoint + { + public: + double x; + double y; + QPoint(double x, double y) : x(x), y(y) {} + }; + + class QLineString + { + public: + bool cw; + std::vector points; + }; + + class QRing + { + public: + std::vector lines; + }; + + class QPolygon + { + public: + QRing* exterior; + std::vector interiors; + }; + +The legacy object hierarcy is based on topology (e.g. two QRings might share one QLineString) instead of points directly (i.e. each object does not point directly to it's QPoints), and it also uses pointers for access. + +This is the other common way to approach geometries, to enable e.g. shared boundaries between surfaces. __boost_geometry__'s approach use simple features, and does not have shared geometries. + +The mismatch in representation is fixed by creating a custom iterator, that exposes a __boost_range__ of Points for every object. This way, __boost_geometry__'s functions will operate on the QRing as if it was a collection of Points, which is a requirement. + +[h2 Adapting QPoint] + +The [link adaption_of_qpoint_source_code adaption of the QPoint] is fairly straightforward, one just needs to implement the requirements. + +Even though the geometries in our legacy object model use pointers of QPoints, __boost_geometry__ automatically handles the conversion from pointers-to-Points to references-to-Points internally, so we do not have to convert them manually. + +Alternatively, we can use the [link geometry.reference.adapted.register.boost_geometry_register_point_2d BOOST_GEOMETRY_REGISTER_POINT_2D(QPoint, double, cs::cartesian, x, y)] helper macro, which does exactly the same as our manual adaption. + +The sample code adapts QPoint to the [link geometry.reference.concepts.concept_point Point Concept] using specialization of the traits class. + +[h2 Adapting QLineString] + +The [link adaption_of_qlinestring_source_code adaption of the QLineString] is very simple on the surface, as it is just "a specialization of traits::tag defining linestring_tag as type". Alternatively, we can use the [link geometry.reference.adapted.register.boost_geometry_register_linestring BOOST_GEOMETRY_REGISTER_LINESTRING(QLineString)] helper macro, which does exactly the same as our manual adaption. + +However, the [link geometry.reference.concepts.concept_linestring LineString concept] also requires that the collection of Points "must behave like a __boost_range__ Random Access Range" and "the type defined by the metafunction range_value<...>::type must fulfill the Point Concept". + +This means that we have to do two things: + +* Make QLineString behave like a __boost_range__, with Random Access requirements +* Make sure that the __boost_range__ iterates over QPoints, which we already have adapted + +This might look like a lot of work, but we are in luck: a std::vector is nearly a __boost_range__, and already iterate over pointers-to-QPoints, that are handled by __boost_geometry__. The [link adaption_of_qlinestring_range_source_code code for making QLineString a __boost_range__] is therefore fairly straightforward. + +[h2 Adapting QRing] + +The [link adaption_of_qring_source_code adaption of the QRing] is mostly equal to the QLineString in that there is a tag and a collection to iterate through. Alternatively, we can use the [link geometry.reference.adapted.register.boost_geometry_register_ring BOOST_GEOMETRY_REGISTER_RING(QRing)] helper macro, which does exactly the same as our manual adaption. + +However, the QRing expose pointers-to-QLineStrings, and not QPoints directly, which is [link geometry.reference.concepts.concept_ring required in the Ring concept], so it is not enough to trivially make the std::vector into a __boost_range__. We need to create a Boost.Iterator that expose QPoints, and because we are dealing with a legacy object model, we are not allowed to change the class definition. + +The [link adaption_of_qring_iterator_source_code custom iterator that does this] uses Boost.Iterator Facade, and is not very different from the [@http://www.boost.org/doc/libs/1_53_0/libs/iterator/doc/iterator_facade.html example provided in Boost.Iterator's own documentation](link), except that our __boost_range__ need to be random access. + +Now, with the custom iterator made, we can [link adaption_of_qring_range_source_code define the __boost_range__] that traverses through QPoints. + +[h2 Adapting QPolygon] + +[link adaption_of_qpolygon_source_code Adapting the QPolygon] to the [link geometry.reference.concepts.concept_polygon Polygon Concept] is a little more involved than the other geometry types. + +The only requirement that is not straightforward to adapt is the interior_rings' get method. + +A __boost_geometry__ Polygon operates on Ring objects, and unfortunately, __boost_geometry__ does not automatically handle the conversion from pointers to references for Rings internally (only Points, as mentioned). + +Therefore, we need to expose QRings instead of pointers-to-QRings for the interior Rings, which means a little more work than the pointers-to-QPoints for QLineString and QRing. + +First, we [link adaption_of_qpolygon_iterator_source_code create a Boost.Iterator Facade] that returns QRing instead of pointer-to-QRing: + +Now we have an iterator that can "convert" our pointer-to-QRing into QRing. However, the get method of the interior Rings must return a __boost_range__ compatible object, which a plain PolygonRingIterator is not. + +We need to [link adaption_of_qpolygon_range_source_code define another __boost_range__], that can be constructed with PolygonRingIterators as arguments, and returned from the get method. + +[h2 Conclusion] + +That's it! The methods of __boost_geometry__ can now be used directly on instances of our legacy object model. + +[endsect] + +[section Example source code: Adapting a legacy geometry object model] + +[h2 Adaption of QPoint] +[#adaption_of_qpoint_source_code] + + #include + + namespace boost + { + namespace geometry + { + namespace traits + { + // Adapt QPoint to Boost.Geometry + + template<> struct tag + { typedef point_tag type; }; + + template<> struct coordinate_type + { typedef QPoint::double type; }; + + template<> struct coordinate_system + { typedef cs::cartesian type; }; + + template<> struct dimension : boost::mpl::int_<2> {}; + + template<> + struct access + { + static QPoint::double get(QPoint const& p) + { + return p.x; + } + + static void set(QPoint& p, QPoint::double const& value) + { + p.x = value; + } + }; + + template<> + struct access + { + static QPoint::double get(QPoint const& p) + { + return p.y; + } + + static void set(QPoint& p, QPoint::double const& value) + { + p.y = value; + } + }; + } + } + } // namespace boost::geometry::traits + + + + +[h2 Adaption of QLineString] +[#adaption_of_qlinestring_source_code] + + namespace boost + { + namespace geometry + { + namespace traits + { + template<> + struct tag + { + typedef linestring_tag type; + }; + } + } + } // namespace boost::geometry::traits + +[h3 Boost.Range for QLineString] +[#adaption_of_qlinestring_range_source_code] + + #include + + namespace boost + { + template <> + struct range_iterator + { typedef std::vector::iterator type; }; + + template<> + struct range_const_iterator + { typedef std::vector::const_iterator type; }; + } + + inline std::vector::iterator + range_begin(QLineString& qls) {return qls.points.begin();} + + inline std::vector::iterator + range_end(QLineString& qls) {return qls.points.end();} + + inline std::vector::const_iterator + range_begin(const QLineString& qls) {return qls.points.begin();} + + inline std::vector::const_iterator + range_end(const QLineString& qls) {return qls.points.end();} + +[h2 Adaption of QRing] +[#adaption_of_qring_source_code] + + namespace boost + { + namespace geometry + { + namespace traits + { + template<> + struct tag + { + typedef ring_tag type; + }; + } + } + } // namespace boost::geometry::traits + +[h3 Boost.Iterator for QRing] +[#adaption_of_qring_iterator_source_code] + + #include + + /* Custom iterator type that flattens a 2D array into a 1D array */ + template + class RingIteratorImpl : public boost::iterator_facade< + RingIteratorImpl, R, std::random_access_iterator_tag, R> //new traversal tag boost::random_access_traversal_tag + { + public: + RingIteratorImpl() : pointIndex_(0) + { + } + + explicit RingIteratorImpl(I lineStringIterCurrent) + : lineStringIterCurrent_(lineStringIterCurrent), pointIndex_(0) + { + } + + template + RingIteratorImpl(RingIteratorImpl const& other) : + lineStringIterCurrent_(other.getLineStrIt()), pointIndex_(other.getPointIdx()) + { + } + + I getLineStrIt() const {return lineStringIterCurrent_;} + + bool isEmpty() const {return isEmpty;} + size_t getPointIdx() const {return pointIndex_;} + + typedef typename boost::iterator_facade, R, std::random_access_iterator_tag, R>::difference_type difference_type; + + private: + friend class boost::iterator_core_access; + + void increment() + { + ++pointIndex_; + if (pointIndex_ >= (*lineStringIterCurrent_)->points.size()) + { + ++lineStringIterCurrent_; + pointIndex_ = 0; + } + } + + void decrement() + { + if(pointIndex_>0) + { + --pointIndex_; + } + else + { + --lineStringIterCurrent_; + pointIndex_ = (*lineStringIterCurrent_)->points.size(); + } + } + + void advance(difference_type n) + { + difference_type counter = n; + + difference_type maxPointIndex, remainderPointIndex; + + while(counter>0) + { + maxPointIndex = (*lineStringIterCurrent_)->points.size(), + remainderPointIndex = maxPointIndex - pointIndex_; + + if(counter>remainderPointIndex) + { + counter -= remainderPointIndex; + ++lineStringIterCurrent_; + } + else // (counter<=remainderPointIndex) + { + counter = 0; + pointIndex_ = remainderPointIndex; + } + } + + } + + difference_type distance_to(const RingIteratorImpl& other) const + { + I currentLineStringIter = getLineStrIt(); + I otherLineStringIter = other.getLineStrIt(); + + difference_type count = 0; + difference_type distance_to_other = std::distance(currentLineStringIter, otherLineStringIter); + + if(distance_to_other < 0) + { + count += pointIndex_; + + while(distance_to_other < 0) + { + QLineString const* ls = *otherLineStringIter; + count -= ls->points.size(); + + ++otherLineStringIter; + ++distance_to_other; + } + + assert(otherLineStringIter==currentLineStringIter); + } + else if(distance_to_other > 0) + { + count -= pointIndex_; + + while(distance_to_other < 0) + { + QLineString const* ls = *currentLineStringIter; + count += ls->points.size(); + + ++currentLineStringIter; + --distance_to_other; + } + + assert(otherLineStringIter==currentLineStringIter); + } + else + { + count = pointIndex_ - other.getPointIdx(); + } + + return count; + } + + bool equal(const RingIteratorImpl& other) const + { + return (lineStringIterCurrent_ == other.getLineStrIt()) && + (pointIndex_ == other.getPointIdx()); + } + + R dereference() const {return *(*lineStringIterCurrent_)->points[pointIndex_];} + + + I lineStringIterCurrent_; + + bool empty; + size_t pointIndex_; + }; + + +[h3 Boost.Range for QRing] +[#adaption_of_qring_range_source_code] + + typedef RingIteratorImpl::iterator, QPoint> RingIterator; + typedef RingIteratorImpl::const_iterator, const QPoint> ConstRingIterator; + + namespace boost + { + // Specialize metafunctions. We must include the range.hpp header. + // We must open the 'boost' namespace. + + template <> + struct range_iterator + { typedef RingIterator type; }; + + template<> + struct range_const_iterator + { typedef ConstRingIterator type; }; + + } // namespace 'boost' + + + // The required Range functions. These should be defined in the same namespace + // as Ring. + + inline RingIterator range_begin(QRing& r) + {return RingIterator(r.lines.begin());} + + inline ConstRingIterator range_begin(const QRing& r) + {return ConstRingIterator(r.lines.begin());} + + inline RingIterator range_end(QRing& r) + {return RingIterator(r.lines.end());} + + inline ConstRingIterator range_end(const QRing& r) + {return ConstRingIterator(r.lines.end());} + +[h2 Adaption of QPolygon] +[#adaption_of_qpolygon_source_code] + + namespace boost { + namespace geometry { + namespace traits { + template<> struct tag { typedef polygon_tag type; }; + template<> struct ring_const_type { typedef const QRing& type; }; + template<> struct ring_mutable_type { typedef QRing& type; }; + template<> struct interior_const_type { typedef const CustomPolygonRingRange type; }; + template<> struct interior_mutable_type { typedef CustomPolygonRingRange type; }; + + template<> struct exterior_ring + { + static QRing& get(QPolygon& p) + { + return (*p.exterior); + } + static QRing const& get(QPolygon const& p) + { + return (*p.exterior); + } + }; + + template<> struct interior_rings + { + static CustomPolygonRingRange get(QPolygon& p) + { + return CustomPolygonRingRange(PolygonRingIterator(p.interiors.begin()), PolygonRingIterator(p.interiors.end())); + } + static const CustomPolygonRingRange get(QPolygon const& p) + { + return CustomPolygonRingRange(ConstPolygonRingIterator(p.interiors.begin()), ConstPolygonRingIterator(p.interiors.end())); + } + }; + } + } + } // namespace boost::geometry::traits + + +[h3 Boost.Iterator for QRings in QPolygon] +[#adaption_of_qpolygon_iterator_source_code] + + template + class PolyRingIterator : public boost::iterator_facade< + PolyRingIterator, R, std::random_access_iterator_tag, R> //new traversal tag + { + public: + PolyRingIterator() {} + + explicit PolyRingIterator(I ringIter) : _ringIter(ringIter) {} + + template + PolyRingIterator(PolyRingIterator const& other) : + _ringIter(other.getRingIter()) {} + + I getRingIter() const {return _ringIter;} + + typedef typename boost::iterator_facade, R, std::random_access_iterator_tag, R>::difference_type difference_type; + + private: + friend class boost::iterator_core_access; + + void increment() + { + ++_ringIter; + } + + void decrement() + { + --_ringIter; + } + + void advance(difference_type n) + { + std::advance(_ringIter,n); + } + + difference_type distance_to(const PolyRingIterator& other) const + { + return std::distance(_ringIter, other.getRingIter()); + } + + bool equal(const PolyRingIterator& other) const + { + return _ringIter == other.getRingIter(); + } + + R dereference() const {return *(*_ringIter);} + + I _ringIter; + }; + +[h3 Boost.Range for PolygonRingIterator] +[#adaption_of_qpolygon_range_source_code] + + typedef PolyRingIterator::iterator, QRing> PolygonRingIterator; + typedef PolyRingIterator::const_iterator, const QRing> ConstPolygonRingIterator; + + class CustomPolygonRingRange + { + PolygonRingIterator _begin; + PolygonRingIterator _end; + + bool isIterSet; + + ConstPolygonRingIterator _cbegin; + ConstPolygonRingIterator _cend; + + bool isCIterSet; + + public: + + CustomPolygonRingRange(PolygonRingIterator begin, PolygonRingIterator end) : _begin(begin), _end(end), isIterSet(true) {} + CustomPolygonRingRange(ConstPolygonRingIterator begin, ConstPolygonRingIterator end) : _cbegin(begin), _cend(end), isCIterSet(true) {} + + PolygonRingIterator begin() + { + assert(isIterSet); + return _begin; + } + + ConstPolygonRingIterator cbegin() const + { + assert(isCIterSet); + return _cbegin; + } + + PolygonRingIterator end() + { + assert(isIterSet); + return _end; + } + + ConstPolygonRingIterator cend() const + { + assert(isCIterSet); + return _cend; + } + }; + + namespace boost + { + // Specialize metafunctions. We must include the range.hpp header. + // We must open the 'boost' namespace. + + template <> + struct range_iterator { typedef PolygonRingIterator type; }; + + template<> + struct range_const_iterator { typedef ConstPolygonRingIterator type; }; + + } // namespace 'boost' + + + // The required Range functions. These should be defined in the same namespace + // as Ring. + + inline PolygonRingIterator range_begin(CustomPolygonRingRange& r) + {return r.begin();} + + inline ConstPolygonRingIterator range_begin(const CustomPolygonRingRange& r) + {return r.cbegin();} + + inline PolygonRingIterator range_end(CustomPolygonRingRange& r) + {return r.end();} + + inline ConstPolygonRingIterator range_end(const CustomPolygonRingRange& r) + {return r.cend();} + +[endsect] diff --git a/doc/geometry.qbk b/doc/geometry.qbk index 1ba285e36..f472ae1ef 100644 --- a/doc/geometry.qbk +++ b/doc/geometry.qbk @@ -133,6 +133,10 @@ Boost.Geometry contains contributions by: [endsect] [endsect] +[section Examples] +[include example_adapting_a_legacy_geometry_object_model.qbk] +[endsect] + [include release_notes.qbk] [include about_documentation.qbk] diff --git a/doc/html/img/io/svg_mapper.png b/doc/html/img/io/svg_mapper.png new file mode 100644 index 0000000000000000000000000000000000000000..8330692aafb535c3d278d8e278ca29bdbd49fc35 GIT binary patch literal 12582 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 +#include + +#include +#include +#include + +int main() +{ + // Specify the basic type + typedef boost::geometry::model::d2::point_xy point_type; + + // Declare some geometries and set their values + point_type a; + boost::geometry::assign_values(a, 3, 6); + + boost::geometry::model::polygon b; + boost::geometry::read_wkt("POLYGON((0 0,0 7,4 2,2 0,0 0))", b); + + boost::geometry::model::linestring c; + c.push_back(point_type(3, 4)); + c.push_back(point_type(4, 5)); + + // Declare a stream and an SVG mapper + std::ofstream svg("my_map.svg"); + boost::geometry::svg_mapper mapper(svg, 400, 400); + + // Add geometries such that all these geometries fit on the map + mapper.add(a); + mapper.add(b); + mapper.add(c); + + // Draw the geometries on the SVG map, using a specific SVG style + mapper.map(a, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2", 5); + mapper.map(b, "fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2"); + mapper.map(c, "opacity:0.4;fill:none;stroke:rgb(212,0,0);stroke-width:5"); + + // Destructor of map will be called - adding + // Destructor of stream will be called, closing the file + + return 0; +} + +//] + + +//[svg_mapper_output +/*` +Output: + +[$img/io/svg_mapper.png] +*/ +//] From 4efb54c25debf3fc270c29b107768b46b2672b3b Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Mon, 20 May 2013 18:04:29 +0000 Subject: [PATCH 12/12] [geometry] SVG (mainly svg_mapper) documentation [SVN r84394] --- include/boost/geometry/io/svg/svg_mapper.hpp | 53 ++++++++++++++++++-- include/boost/geometry/io/svg/write_svg.hpp | 13 +++-- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/include/boost/geometry/io/svg/svg_mapper.hpp b/include/boost/geometry/io/svg/svg_mapper.hpp index 40aa6561b..1252cc806 100644 --- a/include/boost/geometry/io/svg/svg_mapper.hpp +++ b/include/boost/geometry/io/svg/svg_mapper.hpp @@ -214,6 +214,15 @@ inline void svg_map(std::ostream& stream, } +/*! +\brief Helper class to create SVG maps +\tparam Point Point type, for input geometries. +\tparam SameScale Boolean flag indicating if horizontal and vertical scale should + be the same. The default value is true +\ingroup svg + +\qbk{[include reference/io/svg.qbk]} +*/ template class svg_mapper : boost::noncopyable { @@ -252,21 +261,39 @@ class svg_mapper : boost::noncopyable } public : - svg_mapper(std::ostream& s, int w, int h + + /*! + \brief Constructor, initializing the SVG map. Opens and initializes the SVG. + Should be called explicitly. + \param stream Output stream, should be a stream already open + \param width Width of the SVG map (in SVG pixels) + \param height Height of the SVG map (in SVG pixels) + \param width_height Optional information to increase width and/or height + */ + explicit svg_mapper(std::ostream& stream, int width, int height , std::string const& width_height = "width=\"100%\" height=\"100%\"") - : m_stream(s) - , m_width(w) - , m_height(h) + : m_stream(stream) + , m_width(width) + , m_height(height) , m_width_height(width_height) { assign_inverse(m_bounding_box); } + /*! + \brief Destructor, called automatically. Closes the SVG by streaming <\/svg> + */ virtual ~svg_mapper() { m_stream << "" << std::endl; } + /*! + \brief Adds a geometry to the transformation matrix. After doing this, + the specified geometry can be mapped fully into the SVG map + \tparam Geometry \tparam_geometry + \param geometry \param_geometry + */ template void add(Geometry const& geometry) { @@ -280,6 +307,14 @@ public : } } + /*! + \brief Maps a geometry into the SVG map using the specified style + \tparam Geometry \tparam_geometry + \param geometry \param_geometry + \param style String containing verbatim SVG style information + \param size Optional size (used for SVG points) in SVG pixels. For linestrings, + specify linewidth in the SVG style information + */ template void map(Geometry const& geometry, std::string const& style, int size = -1) @@ -300,6 +335,16 @@ public : svg_map(m_stream, style, size, geometry, *m_matrix); } + /*! + \brief Adds a text to the SVG map + \tparam TextPoint \tparam_point + \param point Location of the text (in map units) + \param s The text itself + \param style String containing verbatim SVG style information, of the text + \param offset_x Offset in SVG pixels, defaults to 0 + \param offset_y Offset in SVG pixels, defaults to 0 + \param lineheight Line height in SVG pixels, in case the text contains \n + */ template void text(TextPoint const& point, std::string const& s, std::string const& style, diff --git a/include/boost/geometry/io/svg/write_svg.hpp b/include/boost/geometry/io/svg/write_svg.hpp index 078521268..15fa9c11c 100644 --- a/include/boost/geometry/io/svg/write_svg.hpp +++ b/include/boost/geometry/io/svg/write_svg.hpp @@ -224,7 +224,7 @@ struct svg /*! \brief Generic geometry template manipulator class, takes corresponding output class from traits class \ingroup svg -\details Stream manipulator, streams geometry classes as Virtual Earth shape +\details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics) */ template class svg_manipulator @@ -256,15 +256,20 @@ private: }; /*! -\brief Main svg function to stream geometries as SVG +\brief Manipulator to stream geometries as SVG +\tparam Geometry \tparam_geometry +\param geometry \param_geometry +\param style String containing verbatim SVG style information +\param size Optional size (used for SVG points) in SVG pixels. For linestrings, + specify linewidth in the SVG style information \ingroup svg */ template -inline svg_manipulator svg(Geometry const& t, std::string const& style, int size = -1) +inline svg_manipulator svg(Geometry const& geometry, std::string const& style, int size = -1) { concept::check(); - return svg_manipulator(t, style, size); + return svg_manipulator(geometry, style, size); } }} // namespace boost::geometry