Merge branch 'develop' into feature/disjoint_geo_new

This commit is contained in:
Adam Wulkiewicz
2017-03-05 23:43:45 +01:00
committed by GitHub
115 changed files with 8089 additions and 1502 deletions

View File

@@ -211,6 +211,7 @@ INPUT = . .. ../../../../boost/geometry/core \
../../../../boost/geometry/strategies/agnostic \
../../../../boost/geometry/strategies/cartesian \
../../../../boost/geometry/strategies/spherical \
../../../../boost/geometry/strategies/geographic \
../../../../boost/geometry/strategies/transform \
../../../../boost/geometry/util \
../../../../boost/geometry/views \

View File

@@ -1,9 +1,10 @@
[/============================================================================
Boost.Geometry (aka GGL, Generic Geometry Library)
Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands.
Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
Copyright (c) 2009-2015 Bruno Lalande, Paris, France.
Copyright (c) 2009-2017 Barend Gehrels, Amsterdam, the Netherlands.
Copyright (c) 2009-2017 Mateusz Loskot, London, UK.
Copyright (c) 2009-2017 Bruno Lalande, Paris, France.
Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
Use, modification and distribution is subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -12,8 +13,8 @@
[library Geometry
[quickbook 1.5]
[authors [Gehrels, Barend], [Lalande, Bruno], [Loskot, Mateusz], [Wulkiewicz, Adam], [Karavelas, Menelaos]]
[copyright 2009-2015 Barend Gehrels, Bruno Lalande, Mateusz Loskot, Adam Wulkiewicz, Oracle and/or its affiliates]
[authors [Gehrels, Barend], [Lalande, Bruno], [Loskot, Mateusz], [Wulkiewicz, Adam], [Karavelas, Menelaos], [Fisikopoulos, Vissarion]]
[copyright 2009-2017 Barend Gehrels, Bruno Lalande, Mateusz Loskot, Adam Wulkiewicz, Oracle and/or its affiliates]
[purpose Documentation of Boost.Geometry library]
[license
Distributed under the Boost Software License, Version 1.0.

View File

@@ -37,8 +37,12 @@
<div><div class="author"><h3 class="author">
<span class="firstname">Menelaos</span> <span class="surname">Karavelas</span>
</h3></div></div>
<div><p class="copyright">Copyright &#169; 2009-2014 Barend Gehrels, Bruno Lalande, Mateusz Loskot, Adam
Wulkiewicz, Oracle and/or its affiliates</p></div>
<div><div class="author"><h3 class="author">
<span class="firstname">Vissarion</span> <span class="surname">Fisikopoulos</span>
</h3></div></div>
<div><p class="copyright">Copyright &#169; 2009-2017 Barend
Gehrels, Bruno Lalande, Mateusz Loskot, Adam Wulkiewicz, Oracle and/or its
affiliates</p></div>
<div><div class="legalnotice">
<a name="geometry.legal"></a><p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -72,6 +76,7 @@
<dt><span class="section"><a href="geometry/reference/constants.html">Constants</a></span></dt>
<dt><span class="section"><a href="geometry/reference/cs.html">Coordinate Systems</a></span></dt>
<dt><span class="section"><a href="geometry/reference/core.html">Core Metafunctions</a></span></dt>
<dt><span class="section"><a href="geometry/reference/de9im.html">DE-9IM</a></span></dt>
<dt><span class="section"><a href="geometry/reference/enumerations.html">Enumerations</a></span></dt>
<dt><span class="section"><a href="geometry/reference/exceptions.html">Exceptions</a></span></dt>
<dt><span class="section"><a href="geometry/reference/io.html">IO (input/output)</a></span></dt>
@@ -81,11 +86,9 @@
<dt><span class="section"><a href="geometry/reference/strategies.html">Strategies</a></span></dt>
<dt><span class="section"><a href="geometry/reference/views.html">Views</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="geometry/indexes.html">Indexes</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="geometry/indexes/matrix.html">Reference Matrix</a></span></dt>
<dt><span class="section"><a href="geometry/indexes/alphabetical_index.html">Alphabetical Index</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="geometry/matrix.html">Reference Matrix</a></span></dt>
<dt><span class="section"><a href="geometry/reference_alphabetical_index.html">Reference Alphabetical
Index</a></span></dt>
<dt><span class="section"><a href="geometry/examples.html">Examples</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="geometry/examples/example__adapting_a_legacy_geometry_object_model.html">Example:
@@ -124,6 +127,9 @@
<li class="listitem">
Mats Taraldsvik (documentation: adapting a legacy model)
</li>
<li class="listitem">
Matt Amos (fixes for point_on_surface)
</li>
<li class="listitem">
Samuel Debionne (variant support for distance, assign, crosses, intersection,
...)
@@ -131,7 +137,7 @@
</ul></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: July 17, 2014 at 20:45:09 GMT</small></p></td>
<td align="left"><p><small>Last revised: February 26, 2017 at 00:30:21 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>

View File

@@ -1,7 +1,7 @@
[/============================================================================
Boost.Geometry Index
Copyright (c) 2011-2013 Adam Wulkiewicz.
Copyright (c) 2011-2017 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
@@ -57,7 +57,7 @@ Query iterators returned by free functions
__box__ box_region(...);
std::copy(bgi::qbegin(rt, bgi::intersects(box_region)), bgi::qend(rt), std::back_inserter(returned_values));
[h4 Spatial predicates]
[h4 Spatial queries]
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 (boolean operations).
@@ -129,6 +129,9 @@ The same way different query Geometries can be used:
Segment seg(/*...*/);
rt.query(bgi::nearest(seg, k), std::back_inserter(returned_values));
[note In case of k-NN queries performed with `query()` function it's not guaranteed that the returned values will be sorted according to the distance.
It's different in case of k-NN queries performed with query iterator returned by `qbegin()` function which guarantees the iteration over the closest `__value__`s first. ]
[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.
@@ -175,7 +178,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));
[h4 Passing a set of predicates]
[h4 Passing 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 && ...`.
@@ -190,7 +193,7 @@ left-to-right so placing most restrictive predicates first should accelerate the
rt.query(index::intersects(box1) && !index::within(box2) && index::overlaps(box3),
std::back_inserter(result));
Of course it's possible to connect different types of predicates together.
It's possible to connect different types of predicates together.
index::query(rt, index::nearest(pt, k) && index::within(b), std::back_inserter(returned_values));
@@ -211,13 +214,11 @@ or may be stopped at some point, when all interesting values were gathered. The
break;
}
[note In the case of iterative k-NN queries it's guaranteed to iterate over the closest `__value__`s first. ]
[warning The modification of the `rtree`, e.g. insertion or removal of `__value__`s may invalidate the iterators. ]
[h4 Inserting query results into the other R-tree]
[h4 Inserting query results into another R-tree]
There are several ways of inserting Values returned by a query to the other R-tree container.
There are several ways of inserting Values returned by a query into another R-tree container.
The most basic way is creating a temporary container for Values and insert them later.
namespace bgi = boost::geometry::index;
@@ -231,14 +232,13 @@ The most basic way is creating a temporary container for Values and insert them
rt1.query(bgi::intersects(Box(/*...*/)), std::back_inserter(result));
RTree rt2(result.begin(), result.end());
However there are better ways. One of these methods is mentioned in the "Creation and modification" section.
However there are other ways. One of these methods is mentioned in the "Creation and modification" section.
The insert iterator may be passed directly into the query.
RTree rt3;
rt1.query(bgi::intersects(Box(/*...*/))), bgi::inserter(rt3));
If you're a user of Boost.Range you'll appreciate the third option. You may pass the result Range directly into the
constructor or `insert()` member function.
You may also pass the resulting Range directly into the constructor or `insert()` member function using Boost.Range adaptor syntax.
RTree rt4(rt1 | bgi::adaptors::queried(bgi::intersects(Box(/*...*/)))));

View File

@@ -4,6 +4,7 @@
# Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
# Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
# Copyright (c) 2009-2012 Mateusz Loskot (mateusz@loskot.net), London, UK
# Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland
#
# Use, modification and distribution is subject to the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -123,7 +124,8 @@ strategies = ["distance::pythagoras", "distance::pythagoras_box_box"
, "distance::cross_track", "distance::cross_track_point_box"
, "distance::projected_point"
, "within::winding", "within::franklin", "within::crossings_multiply"
, "area::surveyor", "area::huiller"
, "area::surveyor", "area::spherical"
#, "area::geographic"
, "buffer::point_circle", "buffer::point_square"
, "buffer::join_round", "buffer::join_miter"
, "buffer::end_round", "buffer::end_flat"

View File

@@ -10,10 +10,10 @@
Copyright (c) 2009-2015 Bruno Lalande, Paris, France.
Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
This file was modified by Oracle on 2014, 2015.
Modifications copyright (c) 2014-2015, Oracle and/or its affiliates.
This file was modified by Oracle on 2014, 2015, 2017.
Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
Use, modification and distribution is subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -521,7 +521,8 @@
<bridgehead renderas="sect3">Area</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="geometry.reference.strategies.strategy_area_surveyor">strategy::area::surveyor</link></member>
<member><link linkend="geometry.reference.strategies.strategy_area_huiller">strategy::area::huiller</link></member>
<member><link linkend="geometry.reference.strategies.strategy_area_spherical">strategy::area::spherical</link></member>
<!--member><link linkend="geometry.reference.strategies.strategy_area_geographic">strategy::area::geographic</link></member-->
</simplelist>
</entry>
<entry valign="top">

View File

@@ -1,15 +1,16 @@
[/============================================================================
Boost.Geometry (aka GGL, Generic Geometry Library)
Copyright (c) 2009-2014 Barend Gehrels, Amsterdam, the Netherlands.
Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
Copyright (c) 2009-2014 Bruno Lalande, Paris, France.
Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
Copyright (c) 2009-2017 Barend Gehrels, Amsterdam, the Netherlands.
Copyright (c) 2009-2017 Mateusz Loskot, London, UK.
Copyright (c) 2009-2017 Bruno Lalande, Paris, France.
Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland.
This file was modified by Oracle on 2014.
Modifications copyright (c) 2014, Oracle and/or its affiliates.
This file was modified by Oracle on 2014, 2017.
Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
Use, modification and distribution is subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -94,10 +95,17 @@
[include generated/covered_by.qbk]
[endsect]
[section:crosses crosses]
[include generated/crosses.qbk]
[endsect]
[section:difference difference]
[include generated/difference.qbk]
[endsect]
[section:disjoint disjoint]
[include generated/disjoint.qbk]
[endsect]
[section:distance distance]
[include generated/distance.qbk]
@@ -107,16 +115,21 @@
[include generated/envelope.qbk]
[endsect]
[section:equals equals]
[include generated/equals.qbk]
[endsect]
[section:expand expand]
[include generated/expand.qbk]
[endsect]
[section:for_each for_each]
[include generated/for_each.qbk]
[endsect]
[/section:intersection intersection]
[section:intersection intersection]
[include generated/intersection.qbk]
[/endsect]
[endsect]
[section:intersects intersects]
[include generated/intersects.qbk]
@@ -124,7 +137,9 @@
[include generated/is_empty.qbk]
[section:is_simple is_simple]
[include generated/is_simple.qbk]
[endsect]
[section:is_valid is_valid]
[include generated/is_valid.qbk]
@@ -143,16 +158,21 @@
[include generated/num_points.qbk]
[include generated/num_segments.qbk]
[section:overlaps overlaps]
[include generated/overlaps.qbk]
[endsect]
[section:perimeter perimeter]
[include generated/perimeter.qbk]
[endsect]
[section:relate relate]
[include generated/relate.qbk]
[endsect]
[section:relation relation]
[include generated/relation.qbk]
[endsect]
[include generated/reverse.qbk]
@@ -160,9 +180,9 @@
[include generated/simplify.qbk]
[endsect]
[/section:sym_difference sym_difference]
[section:sym_difference sym_difference]
[include generated/sym_difference.qbk]
[/endsect]
[endsect]
[section:touches touches]
[include generated/touches.qbk]
@@ -172,9 +192,9 @@
[include generated/transform.qbk]
[endsect]
[/section:union union]
[section:union_ union_]
[include generated/union.qbk]
[/endsect]
[endsect]
[include generated/unique.qbk]
@@ -317,7 +337,8 @@
[include generated/distance_cross_track.qbk]
[include generated/distance_cross_track_point_box.qbk]
[include generated/area_surveyor.qbk]
[include generated/area_huiller.qbk]
[include generated/area_spherical.qbk]
[/include generated/area_geographic.qbk]
[include generated/buffer_join_round.qbk]
[include generated/buffer_join_miter.qbk]
[include generated/buffer_end_round.qbk]

View File

@@ -1,13 +1,13 @@
[/============================================================================
Boost.Geometry (aka GGL, Generic Geometry Library)
Copyright (c) 2009-2016 Barend Gehrels, Geodan, Amsterdam, the Netherlands.
Copyright (c) 2009-2016 Bruno Lalande, Paris, France.
Copyright (c) 2009-2016 Mateusz Loskot <mateusz@loskot.net>, London, UK.
Copyright (c) 2011-2016 Adam Wulkiewicz, Lodz, Poland.
Copyright (c) 2009-2017 Barend Gehrels, Geodan, Amsterdam, the Netherlands.
Copyright (c) 2009-2017 Bruno Lalande, Paris, France.
Copyright (c) 2009-2017 Mateusz Loskot <mateusz@loskot.net>, London, UK.
Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
This file was modified by Oracle on 2015, 2016.
Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
This file was modified by Oracle on 2015, 2017.
Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -29,6 +29,8 @@
[*Breaking changes]
* ublas_transformer is renamed to matrix_transformer
* explicit modifier is added to constructors of rtree index::dynamic_* parameters
* strategy::area::huiller replaced by strategy::area::spherical
[*Solved issues]
@@ -38,6 +40,7 @@
[*Solved tickets]
* [@https://svn.boost.org/trac/boost/ticket/12566 12566] Ambiguous template instantiation in equal_to<> when pair value contains raw pointer
* [@https://svn.boost.org/trac/boost/ticket/12861 12566] Segmentation fault in stdlibc++ (gcc 4.8.2) affecting rtree
[/=================]
[heading Boost 1.63]

View File

@@ -12,12 +12,12 @@
#include <iostream>
#include <boost/assign.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <boost/assign.hpp> /*< At the end to avoid conflicts with Boost.QVM >*/
BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
int main()

View File

@@ -12,13 +12,13 @@
#include <iostream>
#include <boost/assign.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <boost/assign.hpp> /*< At the end to avoid conflicts with Boost.QVM >*/
BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
template <typename Tag> struct dispatch {};

View File

@@ -12,13 +12,13 @@
#include <iostream>
#include <boost/assign.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/adapted/boost_range/sliced.hpp>
#include <boost/assign.hpp> /*< At the end to avoid conflicts with Boost.QVM >*/
int main()
{

View File

@@ -12,13 +12,13 @@
#include <iostream>
#include <boost/assign.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/geometries/adapted/boost_range/strided.hpp>
#include <boost/assign.hpp> /*< At the end to avoid conflicts with Boost.QVM >*/
int main()
{

View File

@@ -19,6 +19,8 @@
//#pragma warning( disable : 4244 )
#endif // defined(_MSC_VER)
#include <iostream>
//[quickstart_include
#include <boost/geometry.hpp>

View File

@@ -27,6 +27,12 @@
#include <boost/geometry/io/wkt/write.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/geometry/multi/algorithms/equals.hpp>
#include <boost/geometry/multi/geometries/multi_geometries.hpp>
#include <boost/geometry/multi/io/wkt/wkt.hpp>
#include <boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp>
namespace bg = boost::geometry;
namespace { // anonymous
@@ -42,6 +48,15 @@ void test_geometry_wrong_wkb(std::string const& wkbhex, std::string const& wkt)
BOOST_MESSAGE("read_wkb: " << bg::read_wkb(wkb.begin(), wkb.end(), g_wkb));
}
template <typename Geometry>
void test_geometry_parse_failure(std::string const& wkbhex, std::string const& wkt)
{
byte_vector wkb;
BOOST_CHECK( bg::hex2wkb(wkbhex, std::back_inserter(wkb)) );
Geometry g_wkb;
BOOST_CHECK( bg::read_wkb(wkb.begin(), wkb.end(), g_wkb) == false );
}
template <typename Geometry, bool IsEqual>
void test_geometry_equals_old(std::string const& wkbhex, std::string const& wkt)
{
@@ -130,16 +145,17 @@ int test_main(int, char* [])
// "POINT (1.234 5.678)");
}
typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
typedef bg::model::point<double, 3, bg::cs::cartesian> point3d_type;
typedef bg::model::linestring<point_type> linestring_type;
//typedef bg::model::linestring<point3d_type> linestring3d_type;
typedef bg::model::polygon<point_type> polygon_type;
//typedef bg::model::polygon<point3d_type> polygon3d_type;
{
typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
typedef bg::model::point<double, 3, bg::cs::cartesian> point3d_type;
typedef bg::model::linestring<point_type> linestring_type;
//typedef bg::model::linestring<point3d_type> linestring3d_type;
typedef bg::model::polygon<point_type> polygon_type;
//typedef bg::model::polygon<point3d_type> polygon3d_type;
//
// POINT
@@ -165,6 +181,16 @@ int test_main(int, char* [])
);
}
{
point3d_type point(1.234, 5.678, 99.0);
test_geometry_equals<point3d_type, true>
(
point,
"01e90300005839b4c876bef33f83c0caa145b616400000000000c05840"
);
}
//
// LINESTRING
//
@@ -185,6 +211,30 @@ int test_main(int, char* [])
"010200000003000000000000000000F03F00000000000000400000000000000040000000000000084000000000000010400000000000001440"
);
}
{
linestring_type linestring;
bg::append(linestring,
boost::assign::list_of
(point_type(1.234, 5.678))
(point_type(9.1011, 10.1112))
(point_type(13.1415, 16.1718))
);
test_geometry_equals<linestring_type, true>
(
linestring,
"0102000000030000005839B4C876BEF33F83C0CAA145B616404F401361C333224062A1D634EF3824409CC420B072482A40EB73B515FB2B3040"
);
test_geometry_equals<linestring_type, false>
(
linestring,
"0102000080030000005839B4C876BEF33F83C0CAA145B616400000000000C058404F401361C333224062A1D634EF3824400000000000C058409CC420B072482A40EB73B515FB2B30400000000000C05840"
);
}
// {
// linestring3d_type linestring;
@@ -225,7 +275,26 @@ int test_main(int, char* [])
"010300000001000000050000000000000000004940000000000000494000000000000049400000000000005940000000000000594000000000000059400000000000005940000000000000494000000000000049400000000000004940"
);
}
{
polygon_type polygon;
bg::append(polygon,
boost::assign::list_of
(point_type(100.0, 200.0))
(point_type(200.0, 200.0))
(point_type(200.0, 400.0))
(point_type(100.0, 400.0))
(point_type(100.0, 200.0))
);
test_geometry_equals<polygon_type, true>
(
polygon,
"010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940"
);
}
// {
// polygon3d_type polygon;
//
@@ -251,7 +320,7 @@ int test_main(int, char* [])
);
// Create an interior ring (append does not do this automatically)
boost::geometry::interior_rings(polygon).resize(1);
polygon.inners().resize(1);
bg::append(polygon,
boost::assign::list_of
@@ -269,6 +338,158 @@ int test_main(int, char* [])
}
}
//
// Multi Geometries
//
typedef bg::model::multi_point<point_type> multipoint_type;
typedef bg::model::multi_linestring<linestring_type> multilinestring_type;
typedef bg::model::multi_polygon<polygon_type> multipolygon_type;
//
// MultiPoint
//
{
multipoint_type multipoint;
bg::append(multipoint,
boost::assign::list_of
(point_type(1.234, 5.678))
);
test_geometry_equals<multipoint_type, true>
(
multipoint,
"01040000000100000001010000005839b4c876bef33f83c0caa145b61640"
);
}
{
multipoint_type multipoint;
bg::append(multipoint,
boost::assign::list_of
(point_type(1.234, 5.678))
(point_type(10.1112, 13.1415))
);
test_geometry_equals<multipoint_type, true>
(
multipoint,
"01040000000200000001010000005839b4c876bef33f83c0caa145b61640010100000062a1d634ef3824409cc420b072482a40"
);
}
//
// MultiLineString
//
{
multilinestring_type multilinestring;
// Create linestrings (append does not do this automatically)
multilinestring.resize(1);
bg::append(multilinestring[0],
boost::assign::list_of
(point_type(1.234, 5.678))
(point_type(9.1011, 10.1112))
(point_type(13.1415, 16.1718))
);
test_geometry_equals<multilinestring_type, true>
(
multilinestring,
"0105000000010000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b3040"
);
}
{
multilinestring_type multilinestring;
// Create linestrings (append does not do this automatically)
multilinestring.resize(2);
bg::append(multilinestring[0],
boost::assign::list_of
(point_type(1.234, 5.678))
(point_type(9.1011, 10.1112))
(point_type(13.1415, 16.1718))
);
bg::append(multilinestring[1],
boost::assign::list_of
(point_type(19.2, 21.22))
(point_type(23.24, 25.26))
);
test_geometry_equals<multilinestring_type, true>
(
multilinestring,
"0105000000020000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b30400102000000020000003333333333333340b81e85eb513835403d0ad7a3703d3740c3f5285c8f423940"
);
}
//
// MultiPolygon
//
{
multipolygon_type multipolygon;
// Create polygons (append does not do this automatically)
multipolygon.resize(1);
bg::append(multipolygon[0],
boost::assign::list_of
(point_type(100, 200))
(point_type(200, 200))
(point_type(200, 400))
(point_type(100, 400))
(point_type(100, 200))
);
test_geometry_equals<multipolygon_type, true>
(
multipolygon,
"010600000001000000010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940"
);
}
{
multipolygon_type multipolygon;
// Create polygons (append does not do this automatically)
multipolygon.resize(1);
// Create an interior ring (append does not do this automatically)
multipolygon[0].inners().resize(1);
bg::append(multipolygon[0],
boost::assign::list_of
(point_type(35, 10))
(point_type(10, 20))
(point_type(15, 40))
(point_type(45, 45))
(point_type(35, 10))
);
bg::append(multipolygon[0],
boost::assign::list_of
(point_type(20, 30))
(point_type(35, 35))
(point_type(30, 20))
(point_type(20, 30)),
0
);
test_geometry_equals<multipolygon_type, true>
(
multipolygon,
"0106000000010000000103000000020000000500000000000000008041400000000000002440000000000000244000000000000034400000000000002e40000000000000444000000000008046400000000000804640000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40"
);
}
return 0;
}

View File

@@ -27,9 +27,17 @@
#include <boost/geometry/io/wkt/wkt.hpp>
#include <boost/geometry/multi/algorithms/equals.hpp>
#include <boost/geometry/multi/geometries/multi_geometries.hpp>
#include <boost/geometry/multi/io/wkt/wkt.hpp>
#include <boost/geometry/extensions/multi/gis/io/wkb/write_wkb.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/algorithm/string.hpp>
namespace bg = boost::geometry;
namespace { // anonymous
@@ -42,10 +50,11 @@ void test_geometry_equals(Geometry const& geometry, std::string const& wkbhex)
std::string hex_out;
BOOST_CHECK( bg::wkb2hex(wkb_out.begin(), wkb_out.end(), hex_out) );
boost::algorithm::to_lower(hex_out);
BOOST_CHECK_EQUAL( wkbhex, hex_out);
}
} // namespace anonymous
int test_main(int, char* [])
@@ -67,7 +76,7 @@ int test_main(int, char* [])
test_geometry_equals<point_type, true>
(
point,
"0101000000000000000000F03F0000000000000040"
"0101000000000000000000f03f0000000000000040"
);
}
@@ -77,7 +86,7 @@ int test_main(int, char* [])
test_geometry_equals<point3d_type, true>
(
point,
"01E9030000000000000000F03F00000000000000400000000000000840"
"01e9030000000000000000f03f00000000000000400000000000000840"
);
}
@@ -98,7 +107,7 @@ int test_main(int, char* [])
test_geometry_equals<linestring_type, true>
(
linestring,
"010200000003000000000000000000F03F00000000000000400000000000000040000000000000084000000000000010400000000000001440"
"010200000003000000000000000000f03f00000000000000400000000000000040000000000000084000000000000010400000000000001440"
);
}
@@ -115,7 +124,7 @@ int test_main(int, char* [])
test_geometry_equals<linestring3d_type, true>
(
linestring,
"01EA03000003000000000000000000F03F00000000000000400000000000000840000000000000004000000000000008400000000000001040000000000000104000000000000014400000000000001840"
"01ea03000003000000000000000000f03f00000000000000400000000000000840000000000000004000000000000008400000000000001040000000000000104000000000000014400000000000001840"
);
}
@@ -157,7 +166,7 @@ int test_main(int, char* [])
test_geometry_equals<polygon3d_type, true>
(
polygon,
"01EB0300000100000005000000000000000000494000000000000049400000000000001440000000000000494000000000000059400000000000002440000000000000594000000000000059400000000000001440000000000000594000000000000049400000000000002440000000000000494000000000000049400000000000001440"
"01eb0300000100000005000000000000000000494000000000000049400000000000001440000000000000494000000000000059400000000000002440000000000000594000000000000059400000000000001440000000000000594000000000000049400000000000002440000000000000494000000000000049400000000000001440"
);
}
@@ -187,9 +196,161 @@ int test_main(int, char* [])
test_geometry_equals<polygon_type, true>
(
polygon,
"0103000000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002E40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003E40000000000080414000000000008041400000000000003E40000000000000344000000000000034400000000000003E40"
"0103000000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002e40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40"
);
}
//
// Multi Geometries
//
typedef bg::model::multi_point<point_type> multipoint_type;
typedef bg::model::multi_linestring<linestring_type> multilinestring_type;
typedef bg::model::multi_polygon<polygon_type> multipolygon_type;
//
// MultiPoint
//
{
multipoint_type multipoint;
bg::append(multipoint,
boost::assign::list_of
(point_type(1.234, 5.678))
);
test_geometry_equals<multipoint_type, true>
(
multipoint,
"01040000000100000001010000005839b4c876bef33f83c0caa145b61640"
);
}
{
multipoint_type multipoint;
bg::append(multipoint,
boost::assign::list_of
(point_type(1.234, 5.678))
(point_type(10.1112, 13.1415))
);
test_geometry_equals<multipoint_type, true>
(
multipoint,
"01040000000200000001010000005839b4c876bef33f83c0caa145b61640010100000062a1d634ef3824409cc420b072482a40"
);
}
//
// MultiLineString
//
{
multilinestring_type multilinestring;
// Create linestrings (append does not do this automatically)
multilinestring.resize(1);
bg::append(multilinestring[0],
boost::assign::list_of
(point_type(1.234, 5.678))
(point_type(9.1011, 10.1112))
(point_type(13.1415, 16.1718))
);
test_geometry_equals<multilinestring_type, true>
(
multilinestring,
"0105000000010000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b3040"
);
}
{
multilinestring_type multilinestring;
// Create linestrings (append does not do this automatically)
multilinestring.resize(2);
bg::append(multilinestring[0],
boost::assign::list_of
(point_type(1.234, 5.678))
(point_type(9.1011, 10.1112))
(point_type(13.1415, 16.1718))
);
bg::append(multilinestring[1],
boost::assign::list_of
(point_type(19.2, 21.22))
(point_type(23.24, 25.26))
);
test_geometry_equals<multilinestring_type, true>
(
multilinestring,
"0105000000020000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b30400102000000020000003333333333333340b81e85eb513835403d0ad7a3703d3740c3f5285c8f423940"
);
}
//
// MultiPolygon
//
{
multipolygon_type multipolygon;
// Create polygons (append does not do this automatically)
multipolygon.resize(1);
bg::append(multipolygon[0],
boost::assign::list_of
(point_type(100, 200))
(point_type(200, 200))
(point_type(200, 400))
(point_type(100, 400))
(point_type(100, 200))
);
test_geometry_equals<multipolygon_type, true>
(
multipolygon,
"010600000001000000010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940"
);
}
{
multipolygon_type multipolygon;
// Create polygons (append does not do this automatically)
multipolygon.resize(1);
// Create an interior ring (append does not do this automatically)
multipolygon[0].inners().resize(1);
bg::append(multipolygon[0],
boost::assign::list_of
(point_type(35, 10))
(point_type(10, 20))
(point_type(15, 40))
(point_type(45, 45))
(point_type(35, 10))
);
bg::append(multipolygon[0],
boost::assign::list_of
(point_type(20, 30))
(point_type(35, 35))
(point_type(30, 20))
(point_type(20, 30)),
0
);
test_geometry_equals<multipolygon_type, true>
(
multipolygon,
"0106000000010000000103000000020000000500000000000000008041400000000000002440000000000000244000000000000034400000000000002e40000000000000444000000000008046400000000000804640000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40"
);
}
return 0;
}

View File

@@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -303,7 +307,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_area_surveyor Surveyor (cartesian)]
\* [link geometry.reference.strategies.strategy_area_huiller Huiller (spherical)]
\* [link geometry.reference.strategies.strategy_area_spherical Spherical]
[/link geometry.reference.strategies.strategy_area_geographic Geographic]
}
*/
template <typename Geometry, typename Strategy>

View File

@@ -228,6 +228,7 @@ namespace resolve_variant
\param strategy \param_strategy{crosses}
\return \return_check2{crosses}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/crosses.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>

View File

@@ -203,6 +203,7 @@ struct disjoint
\param strategy \param_strategy{disjoint}
\return \return_check2{are disjoint}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/disjoint.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>

View File

@@ -135,6 +135,7 @@ struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
\param mbr \param_box \param_set{envelope}
\param strategy \param_strategy{envelope}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/envelope.qbk]}
\qbk{
[heading Example]
@@ -142,7 +143,7 @@ struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
}
*/
template<typename Geometry, typename Box, typename Strategy>
inline void envelope(Geometry const& geometry, Box& mbr, Strategy& strategy)
inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strategy)
{
resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy);
}
@@ -169,6 +170,32 @@ inline void envelope(Geometry const& geometry, Box& mbr)
}
/*!
\brief \brief_calc{envelope}
\ingroup envelope
\details \details_calc{return_envelope,\det_envelope}. \details_return{envelope}
\tparam Box \tparam_box
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Envelope}
\param geometry \param_geometry
\param strategy \param_strategy{envelope}
\return \return_calc{envelope}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/envelope.qbk]}
\qbk{
[heading Example]
[return_envelope] [return_envelope_output]
}
*/
template<typename Box, typename Geometry, typename Strategy>
inline Box return_envelope(Geometry const& geometry, Strategy const& strategy)
{
Box mbr;
resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy);
return mbr;
}
/*!
\brief \brief_calc{envelope}
\ingroup envelope

View File

@@ -160,10 +160,13 @@ inline void expand(Box& box, Geometry const& geometry,
\ingroup expand
\tparam Box type of the box
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{expand}
\param box box to be expanded using another geometry, mutable
\param geometry \param_geometry geometry which envelope (bounding box)
\param strategy \param_strategy{expand}
will be added to the box
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/expand.qbk]}
*/
template <typename Box, typename Geometry, typename Strategy>

View File

@@ -15,12 +15,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP
// TODO: those headers probably may be removed
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -98,33 +100,46 @@ struct intersection
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2>
namespace resolve_strategy {
struct intersection
{
template <typename GeometryOut>
static inline bool
apply(
const Geometry1& geometry1,
const Geometry2& geometry2,
GeometryOut& geometry_out)
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename GeometryOut,
typename Strategy
>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
GeometryOut & geometry_out,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
typedef typename geometry::rescale_overlay_policy_type
return dispatch::intersection
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1,
geometry2);
>::apply(geometry1, geometry2, robust_policy, geometry_out,
strategy);
}
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename GeometryOut
>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
GeometryOut & geometry_out,
default_strategy)
{
typedef typename strategy::relate::services::default_strategy
<
Geometry1, Geometry2
@@ -139,44 +154,83 @@ struct intersection
}
};
} // resolve_strategy
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2>
struct intersection
{
template <typename GeometryOut, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
GeometryOut& geometry_out,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1,
geometry2);
return resolve_strategy::intersection::apply(geometry1,
geometry2,
robust_policy,
geometry_out,
strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
template <typename GeometryOut>
template <typename GeometryOut, typename Strategy>
struct visitor: static_visitor<bool>
{
Geometry2 const& m_geometry2;
GeometryOut& m_geometry_out;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2,
GeometryOut& geometry_out)
GeometryOut& geometry_out,
Strategy const& strategy)
: m_geometry2(geometry2)
, m_geometry_out(geometry_out)
, m_strategy(strategy)
{}
template <typename Geometry1>
result_type operator()(Geometry1 const& geometry1) const
bool operator()(Geometry1 const& geometry1) const
{
return intersection
<
Geometry1,
Geometry2
>::template apply
<
GeometryOut
>
(geometry1, m_geometry2, m_geometry_out);
<
Geometry1,
Geometry2
>::apply(geometry1, m_geometry2, m_geometry_out, m_strategy);
}
};
template <typename GeometryOut>
template <typename GeometryOut, typename Strategy>
static inline bool
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
GeometryOut& geometry_out)
GeometryOut& geometry_out,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<GeometryOut>(geometry2, geometry_out), geometry1);
return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry2,
geometry_out,
strategy),
geometry1);
}
};
@@ -184,40 +238,43 @@ struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename GeometryOut>
template <typename GeometryOut, typename Strategy>
struct visitor: static_visitor<bool>
{
Geometry1 const& m_geometry1;
GeometryOut& m_geometry_out;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1,
GeometryOut& geometry_out)
GeometryOut& geometry_out,
Strategy const& strategy)
: m_geometry1(geometry1)
, m_geometry_out(geometry_out)
, m_strategy(strategy)
{}
template <typename Geometry2>
result_type operator()(Geometry2 const& geometry2) const
bool operator()(Geometry2 const& geometry2) const
{
return intersection
<
Geometry1,
Geometry2
>::template apply
<
GeometryOut
>
(m_geometry1, geometry2, m_geometry_out);
<
Geometry1,
Geometry2
>::apply(m_geometry1, geometry2, m_geometry_out, m_strategy);
}
};
template <typename GeometryOut>
template <typename GeometryOut, typename Strategy>
static inline bool
apply(Geometry1 const& geometry1,
const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2,
GeometryOut& geometry_out)
variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
GeometryOut& geometry_out,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<GeometryOut>(geometry1, geometry_out), geometry2);
return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry1,
geometry_out,
strategy),
geometry2);
}
};
@@ -225,44 +282,83 @@ struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
{
template <typename GeometryOut>
template <typename GeometryOut, typename Strategy>
struct visitor: static_visitor<bool>
{
GeometryOut& m_geometry_out;
Strategy const& m_strategy;
visitor(GeometryOut& geometry_out)
visitor(GeometryOut& geometry_out, Strategy const& strategy)
: m_geometry_out(geometry_out)
, m_strategy(strategy)
{}
template <typename Geometry1, typename Geometry2>
result_type operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
bool operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
{
return intersection
<
Geometry1,
Geometry2
>::template apply
<
GeometryOut
>
(geometry1, geometry2, m_geometry_out);
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, m_geometry_out, m_strategy);
}
};
template <typename GeometryOut>
template <typename GeometryOut, typename Strategy>
static inline bool
apply(const variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1,
const variant<BOOST_VARIANT_ENUM_PARAMS(T2)>& geometry2,
GeometryOut& geometry_out)
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
GeometryOut& geometry_out,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<GeometryOut>(geometry_out), geometry1, geometry2);
return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry_out,
strategy),
geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief \brief_calc2{intersection}
\ingroup intersection
\details \details_calc2{intersection, spatial set theoretic intersection}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which
the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box)
\tparam Strategy \tparam_strategy{Intersection}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param geometry_out The output geometry, either a multi_point, multi_polygon,
multi_linestring, or a box (for intersection of two boxes)
\param strategy \param_strategy{intersection}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/intersection.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename GeometryOut,
typename Strategy
>
inline bool intersection(Geometry1 const& geometry1,
Geometry2 const& geometry2,
GeometryOut& geometry_out,
Strategy const& strategy)
{
return resolve_variant::intersection
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, geometry_out, strategy);
}
/*!
\brief \brief_calc2{intersection}
\ingroup intersection
@@ -285,18 +381,14 @@ template
typename GeometryOut
>
inline bool intersection(Geometry1 const& geometry1,
Geometry2 const& geometry2,
GeometryOut& geometry_out)
Geometry2 const& geometry2,
GeometryOut& geometry_out)
{
return resolve_variant::intersection
<
Geometry1,
Geometry2
>::template apply
<
GeometryOut
>
(geometry1, geometry2, geometry_out);
Geometry1,
Geometry2
>::apply(geometry1, geometry2, geometry_out, default_strategy());
}

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -27,7 +28,8 @@ namespace detail { namespace is_simple
template <typename Geometry>
struct always_simple
{
static inline bool apply(Geometry const&)
template <typename Strategy>
static inline bool apply(Geometry const&, Strategy const&)
{
return true;
}

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -37,6 +38,12 @@ namespace detail { namespace is_simple
template <typename Ring>
struct is_simple_ring
{
template <typename Strategy>
static inline bool apply(Ring const& ring, Strategy const&)
{
return apply(ring);
}
static inline bool apply(Ring const& ring)
{
simplicity_failure_policy policy;
@@ -69,6 +76,12 @@ private:
}
public:
template <typename Strategy>
static inline bool apply(Polygon const& polygon, Strategy const&)
{
return apply(polygon);
}
static inline bool apply(Polygon const& polygon)
{
return
@@ -119,7 +132,8 @@ struct is_simple<Polygon, polygon_tag>
template <typename MultiPolygon>
struct is_simple<MultiPolygon, multi_polygon_tag>
{
static inline bool apply(MultiPolygon const& multipolygon)
template <typename Strategy>
static inline bool apply(MultiPolygon const& multipolygon, Strategy const&)
{
return
detail::check_iterator_range

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -17,46 +18,106 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/intersection.hpp>
namespace boost { namespace geometry
{
namespace resolve_strategy
{
namespace resolve_variant {
struct is_simple
{
template <typename Geometry, typename Strategy>
static inline bool apply(Geometry const& geometry,
Strategy const& strategy)
{
return dispatch::is_simple<Geometry>::apply(geometry, strategy);
}
template <typename Geometry>
static inline bool apply(Geometry const& geometry,
default_strategy)
{
// NOTE: Currently the strategy is only used for Linear geometries
typedef typename strategy::intersection::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
return dispatch::is_simple<Geometry>::apply(geometry, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry>
struct is_simple
{
static inline bool apply(Geometry const& geometry)
template <typename Strategy>
static inline bool apply(Geometry const& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();
return dispatch::is_simple<Geometry>::apply(geometry);
return resolve_strategy::is_simple::apply(geometry, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor : boost::static_visitor<bool>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Geometry>
bool operator()(Geometry const& geometry) const
{
return is_simple<Geometry>::apply(geometry);
return is_simple<Geometry>::apply(geometry, m_strategy);
}
};
template <typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
Strategy const& strategy)
{
return boost::apply_visitor(visitor(), geometry);
return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
} // namespace resolve_variant
/*!
\brief \brief_check{is simple}
\ingroup is_simple
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Is_simple}
\param geometry \param_geometry
\param strategy \param_strategy{is_simple}
\return \return_check{is simple}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/is_simple.qbk]}
*/
template <typename Geometry, typename Strategy>
inline bool is_simple(Geometry const& geometry, Strategy const& strategy)
{
return resolve_variant::is_simple<Geometry>::apply(geometry, strategy);
}
/*!
\brief \brief_check{is simple}
@@ -70,7 +131,7 @@ struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline bool is_simple(Geometry const& geometry)
{
return resolve_variant::is_simple<Geometry>::apply(geometry);
return resolve_variant::is_simple<Geometry>::apply(geometry, default_strategy());
}

View File

@@ -189,8 +189,8 @@ private:
};
template <typename Linear>
inline bool has_self_intersections(Linear const& linear)
template <typename Linear, typename Strategy>
inline bool has_self_intersections(Linear const& linear, Strategy const& strategy)
{
typedef typename point_type<Linear>::type point_type;
@@ -217,16 +217,11 @@ inline bool has_self_intersections(Linear const& linear)
is_acceptable_turn<Linear>
> interrupt_policy(predicate);
typedef typename strategy::intersection::services::default_strategy
<
typename cs_tag<Linear>::type
>::type strategy_type;
detail::self_get_turn_points::get_turns
<
turn_policy
>::apply(linear,
strategy_type(),
strategy,
detail::no_rescale_policy(),
turns,
interrupt_policy);
@@ -252,8 +247,19 @@ struct is_simple_linestring
&& ! detail::is_valid::has_spikes
<
Linestring, closed
>::apply(linestring, policy)
&& ! (CheckSelfIntersections && has_self_intersections(linestring));
>::apply(linestring, policy);
}
};
template <typename Linestring>
struct is_simple_linestring<Linestring, true>
{
template <typename Strategy>
static inline bool apply(Linestring const& linestring,
Strategy const& strategy)
{
return is_simple_linestring<Linestring, false>::apply(linestring)
&& ! has_self_intersections(linestring, strategy);
}
};
@@ -261,7 +267,9 @@ struct is_simple_linestring
template <typename MultiLinestring>
struct is_simple_multilinestring
{
static inline bool apply(MultiLinestring const& multilinestring)
template <typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
Strategy const& strategy)
{
// check each of the linestrings for simplicity
// but do not compute self-intersections yet; these will be
@@ -281,7 +289,7 @@ struct is_simple_multilinestring
return false;
}
return ! has_self_intersections(multilinestring);
return ! has_self_intersections(multilinestring, strategy);
}
};

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -38,7 +39,8 @@ namespace detail { namespace is_simple
template <typename MultiPoint>
struct is_simple_multipoint
{
static inline bool apply(MultiPoint const& multipoint)
template <typename Strategy>
static inline bool apply(MultiPoint const& multipoint, Strategy const&)
{
if (boost::empty(multipoint))
{

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -71,8 +71,8 @@ struct has_valid_corners<Box, 0>
template <typename Box>
struct is_valid_box
{
template <typename VisitPolicy>
static inline bool apply(Box const& box, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Box const& box, VisitPolicy& visitor, Strategy const&)
{
return
! has_invalid_coordinate<Box>::apply(box, visitor)

View File

@@ -48,11 +48,6 @@ class has_valid_self_turns
private:
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::intersection::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type intersection_strategy_type;
typedef typename geometry::rescale_policy_type
<
point_type
@@ -75,15 +70,14 @@ public:
> turn_type;
// returns true if all turns are valid
template <typename Turns, typename VisitPolicy>
template <typename Turns, typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry,
Turns& turns,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
intersection_strategy_type intersection_strategy;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry);
@@ -93,7 +87,7 @@ public:
> interrupt_policy;
geometry::self_turns<turn_policy>(geometry,
intersection_strategy,
strategy,
robust_policy,
turns,
interrupt_policy);
@@ -110,11 +104,11 @@ public:
}
// returns true if all turns are valid
template <typename VisitPolicy>
static inline bool apply(Geometry const& geometry, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy)
{
std::vector<turn_type> turns;
return apply(geometry, turns, visitor);
return apply(geometry, turns, visitor, strategy);
}
};

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -23,48 +24,88 @@
#include <boost/geometry/policies/is_valid/default_policy.hpp>
#include <boost/geometry/policies/is_valid/failing_reason_policy.hpp>
#include <boost/geometry/policies/is_valid/failure_type_policy.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/intersection.hpp>
namespace boost { namespace geometry
{
namespace resolve_strategy
{
struct is_valid
{
template <typename Geometry, typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry,
VisitPolicy& visitor,
Strategy const& strategy)
{
return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
namespace resolve_variant {
template <typename Geometry, typename VisitPolicy>
static inline bool apply(Geometry const& geometry,
VisitPolicy& visitor,
default_strategy)
{
// NOTE: Currently the strategy is only used for Areal geometries
typedef typename strategy::intersection::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry>
struct is_valid
{
template <typename VisitPolicy>
static inline bool apply(Geometry const& geometry, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry,
VisitPolicy& visitor,
Strategy const& strategy)
{
concepts::check<Geometry const>();
return dispatch::is_valid<Geometry>::apply(geometry, visitor);
return resolve_strategy::is_valid::apply(geometry, visitor, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
struct visitor : boost::static_visitor<bool>
{
visitor(VisitPolicy& policy) : m_policy(policy) {}
visitor(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Geometry>
bool operator()(Geometry const& geometry) const
{
return is_valid<Geometry>::apply(geometry, m_policy);
return is_valid<Geometry>::apply(geometry, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
VisitPolicy& policy_visitor)
VisitPolicy& policy_visitor,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<VisitPolicy>(policy_visitor),
return boost::apply_visitor(visitor<VisitPolicy, Strategy>(policy_visitor, strategy),
geometry);
}
};
@@ -73,13 +114,38 @@ struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
// Undocumented for now
template <typename Geometry, typename VisitPolicy>
inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor)
template <typename Geometry, typename VisitPolicy, typename Strategy>
inline bool is_valid(Geometry const& geometry,
VisitPolicy& visitor,
Strategy const& strategy)
{
return resolve_variant::is_valid<Geometry>::apply(geometry, visitor);
return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Is_valid}
\param geometry \param_geometry
\param strategy \param_strategy{is_valid}
\return \return_check{is valid (in the OGC sense);
furthermore, the following geometries are considered valid:
multi-geometries with no elements,
linear geometries containing spikes,
areal geometries with duplicate (consecutive) points}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/is_valid.qbk]}
*/
template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, Strategy const& strategy)
{
is_valid_default_policy<> visitor;
return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
@@ -96,11 +162,37 @@ inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor)
template <typename Geometry>
inline bool is_valid(Geometry const& geometry)
{
is_valid_default_policy<> policy_visitor;
return geometry::is_valid(geometry, policy_visitor);
return is_valid(geometry, default_strategy());
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Is_valid}
\param geometry \param_geometry
\param failure An enumeration value indicating that the geometry is
valid or not, and if not valid indicating the reason why
\param strategy \param_strategy{is_valid}
\return \return_check{is valid (in the OGC sense);
furthermore, the following geometries are considered valid:
multi-geometries with no elements,
linear geometries containing spikes,
areal geometries with duplicate (consecutive) points}
\qbk{distinguish,with failure value and strategy}
\qbk{[include reference/algorithms/is_valid_with_failure.qbk]}
*/
template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, validity_failure_type& failure, Strategy const& strategy)
{
failure_type_policy<> visitor;
bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
failure = visitor.failure();
return result;
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
@@ -120,13 +212,38 @@ inline bool is_valid(Geometry const& geometry)
template <typename Geometry>
inline bool is_valid(Geometry const& geometry, validity_failure_type& failure)
{
failure_type_policy<> policy_visitor;
bool result = geometry::is_valid(geometry, policy_visitor);
failure = policy_visitor.failure();
return result;
return is_valid(geometry, failure, default_strategy());
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Is_valid}
\param geometry \param_geometry
\param message A string containing a message stating if the geometry
is valid or not, and if not valid a reason why
\param strategy \param_strategy{is_valid}
\return \return_check{is valid (in the OGC sense);
furthermore, the following geometries are considered valid:
multi-geometries with no elements,
linear geometries containing spikes,
areal geometries with duplicate (consecutive) points}
\qbk{distinguish,with message and strategy}
\qbk{[include reference/algorithms/is_valid_with_message.qbk]}
*/
template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, std::string& message, Strategy const& strategy)
{
std::ostringstream stream;
failing_reason_policy<> visitor(stream);
bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
message = stream.str();
return result;
}
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
@@ -146,11 +263,7 @@ inline bool is_valid(Geometry const& geometry, validity_failure_type& failure)
template <typename Geometry>
inline bool is_valid(Geometry const& geometry, std::string& message)
{
std::ostringstream stream;
failing_reason_policy<> policy_visitor(stream);
bool result = geometry::is_valid(geometry, policy_visitor);
message = stream.str();
return result;
return is_valid(geometry, message, default_strategy());
}

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -77,6 +77,14 @@ struct is_valid_linestring
}
return ! has_spikes<Linestring, closed>::apply(linestring, visitor);
}
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
VisitPolicy& visitor,
Strategy const&)
{
return apply(linestring, visitor);
}
};
@@ -142,9 +150,10 @@ private:
};
public:
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const&)
{
if (BOOST_GEOMETRY_CONDITION(
AllowEmptyMultiGeometries && boost::empty(multilinestring)))

View File

@@ -237,23 +237,28 @@ private:
}
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
struct per_polygon
{
per_polygon(VisitPolicy& policy) : m_policy(policy) {}
per_polygon(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Polygon>
inline bool apply(Polygon const& polygon) const
{
return base::apply(polygon, m_policy);
return base::apply(polygon, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
public:
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiPolygon const& multipolygon,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
typedef debug_validity_phase<MultiPolygon> debug_phase;
@@ -268,11 +273,11 @@ public:
if (! detail::check_iterator_range
<
per_polygon<VisitPolicy>,
per_polygon<VisitPolicy, Strategy>,
false // do not check for empty multipolygon (done above)
>::apply(boost::begin(multipolygon),
boost::end(multipolygon),
per_polygon<VisitPolicy>(visitor)))
per_polygon<VisitPolicy, Strategy>(visitor, strategy)))
{
return false;
}
@@ -285,7 +290,7 @@ public:
std::deque<typename has_valid_turns::turn_type> turns;
bool has_invalid_turns =
! has_valid_turns::apply(multipolygon, turns, visitor);
! has_valid_turns::apply(multipolygon, turns, visitor, strategy);
debug_print_turns(turns.begin(), turns.end());
if (has_invalid_turns)

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -36,8 +36,8 @@ namespace dispatch
template <typename Point>
struct is_valid<Point, point_tag>
{
template <typename VisitPolicy>
static inline bool apply(Point const& point, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Point const& point, VisitPolicy& visitor, Strategy const&)
{
boost::ignore_unused(visitor);
return ! detail::is_valid::has_invalid_coordinate
@@ -56,9 +56,10 @@ struct is_valid<Point, point_tag>
template <typename MultiPoint, bool AllowEmptyMultiGeometries>
struct is_valid<MultiPoint, multi_point_tag, AllowEmptyMultiGeometries>
{
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiPoint const& multipoint,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const&)
{
boost::ignore_unused(multipoint, visitor);

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -74,10 +75,13 @@ class is_valid_polygon
protected:
typedef debug_validity_phase<Polygon> debug_phase;
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
struct per_ring
{
per_ring(VisitPolicy& policy) : m_policy(policy) {}
per_ring(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Ring>
inline bool apply(Ring const& ring) const
@@ -85,30 +89,34 @@ protected:
return detail::is_valid::is_valid_ring
<
Ring, false, true
>::apply(ring, m_policy);
>::apply(ring, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
template <typename InteriorRings, typename VisitPolicy>
template <typename InteriorRings, typename VisitPolicy, typename Strategy>
static bool has_valid_interior_rings(InteriorRings const& interior_rings,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
return
detail::check_iterator_range
<
per_ring<VisitPolicy>,
per_ring<VisitPolicy, Strategy>,
true // allow for empty interior ring range
>::apply(boost::begin(interior_rings),
boost::end(interior_rings),
per_ring<VisitPolicy>(visitor));
per_ring<VisitPolicy, Strategy>(visitor, strategy));
}
struct has_valid_rings
{
template <typename VisitPolicy>
static inline bool apply(Polygon const& polygon, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
VisitPolicy& visitor,
Strategy const& strategy)
{
typedef typename ring_type<Polygon>::type ring_type;
@@ -119,7 +127,7 @@ protected:
<
ring_type,
false // do not check self intersections
>::apply(exterior_ring(polygon), visitor))
>::apply(exterior_ring(polygon), visitor, strategy))
{
return false;
}
@@ -128,7 +136,8 @@ protected:
debug_phase::apply(2);
return has_valid_interior_rings(geometry::interior_rings(polygon),
visitor);
visitor,
strategy);
}
};
@@ -344,10 +353,12 @@ protected:
};
public:
template <typename VisitPolicy>
static inline bool apply(Polygon const& polygon, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
VisitPolicy& visitor,
Strategy const& strategy)
{
if (! has_valid_rings::apply(polygon, visitor))
if (! has_valid_rings::apply(polygon, visitor, strategy))
{
return false;
}
@@ -364,7 +375,7 @@ public:
std::deque<typename has_valid_turns::turn_type> turns;
bool has_invalid_turns
= ! has_valid_turns::apply(polygon, turns, visitor);
= ! has_valid_turns::apply(polygon, turns, visitor, strategy);
debug_print_turns(turns.begin(), turns.end());
if (has_invalid_turns)

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -101,35 +101,33 @@ struct ring_area_predicate<ResultType, true>
template <typename Ring, bool IsInteriorRing>
struct is_properly_oriented
{
typedef typename point_type<Ring>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value
> ring_area_type;
typedef typename default_area_result<Ring>::type area_result_type;
template <typename VisitPolicy>
static inline bool apply(Ring const& ring, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Ring const& ring, VisitPolicy& visitor,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
typedef typename point_type<Ring>::type point_type;
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value
> ring_area_type;
typedef typename default_area_result<Ring>::type area_result_type;
typename ring_area_predicate
<
area_result_type, IsInteriorRing
>::type predicate;
// Check area
area_result_type const zero = area_result_type();
if (predicate(ring_area_type::apply(ring, strategy_type()), zero))
area_result_type const zero = 0;
area_result_type const area
= ring_area_type::apply(ring,
strategy.template get_area_strategy<point_type>());
if (predicate(area, zero))
{
return visitor.template apply<no_failure>();
}
@@ -150,8 +148,9 @@ template
>
struct is_valid_ring
{
template <typename VisitPolicy>
static inline bool apply(Ring const& ring, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Ring const& ring, VisitPolicy& visitor,
Strategy const& strategy)
{
// return invalid if any of the following condition holds:
// (a) the ring's point coordinates are not invalid (e.g., NaN)
@@ -198,8 +197,8 @@ struct is_valid_ring
&& ! has_duplicates<Ring, closure>::apply(ring, visitor)
&& ! has_spikes<Ring, closure>::apply(ring, visitor)
&& (! CheckSelfIntersections
|| has_valid_self_turns<Ring>::apply(ring, visitor))
&& is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor);
|| has_valid_self_turns<Ring>::apply(ring, visitor, strategy))
&& is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy);
}
};

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -44,8 +44,8 @@ namespace dispatch
template <typename Segment>
struct is_valid<Segment, segment_tag>
{
template <typename VisitPolicy>
static inline bool apply(Segment const& segment, VisitPolicy& visitor)
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Segment const& segment, VisitPolicy& visitor, Strategy const&)
{
boost::ignore_unused(visitor);

View File

@@ -272,6 +272,7 @@ struct self_get_turn_points
\tparam Turns type of intersection container
(e.g. vector of "intersection/turn point"'s)
\param geometry geometry
\param strategy strategy to be used
\param robust_policy policy to handle robustness issues
\param turns container which will contain intersection points
\param interrupt_policy policy determining if process is stopped

View File

@@ -375,6 +375,7 @@ struct relate<
\param strategy \param_strategy{relate}
\return true if the relation is compatible with the mask, false otherwise.
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/relate.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Mask, typename Strategy>

View File

@@ -175,6 +175,7 @@ struct relation
\param strategy \param_strategy{relation}
\return The DE-9IM matrix expressing the relation between geometries.
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/relation.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>

View File

@@ -4,6 +4,7 @@
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@@ -13,10 +14,16 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP
#include <algorithm>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
@@ -101,18 +108,14 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1,
RobustPolicy const& robust_policy,
OutputIterator out)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
concepts::check<GeometryOut>();
typename strategy::relate::services::default_strategy
typedef typename strategy::relate::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy;
>::type strategy_type;
return difference_insert<GeometryOut>(geometry1, geometry2,
robust_policy, out, strategy);
robust_policy, out, strategy_type());
}
@@ -120,6 +123,251 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1,
#endif // DOXYGEN_NO_DETAIL
namespace resolve_strategy {
struct difference
{
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename Collection,
typename Strategy
>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Collection & output_collection,
Strategy const& strategy)
{
typedef typename boost::range_value<Collection>::type geometry_out;
detail::difference::difference_insert<geometry_out>(
geometry1, geometry2, robust_policy,
range::back_inserter(output_collection),
strategy);
}
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename Collection
>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Collection & output_collection,
default_strategy)
{
typedef typename boost::range_value<Collection>::type geometry_out;
detail::difference::difference_insert<geometry_out>(
geometry1, geometry2, robust_policy,
range::back_inserter(output_collection));
}
};
} // resolve_strategy
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2>
struct difference
{
template <typename Collection, typename Strategy>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1,
geometry2);
resolve_strategy::difference::apply(geometry1, geometry2,
robust_policy,
output_collection,
strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Geometry2 const& m_geometry2;
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
: m_geometry2(geometry2)
, m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry1>
void operator()(Geometry1 const& geometry1) const
{
difference
<
Geometry1,
Geometry2
>::apply(geometry1, m_geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(geometry2,
output_collection,
strategy),
geometry1);
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Geometry1 const& m_geometry1;
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1,
Collection& output_collection,
Strategy const& strategy)
: m_geometry1(geometry1)
, m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry2>
void operator()(Geometry2 const& geometry2) const
{
difference
<
Geometry1,
Geometry2
>::apply(m_geometry1, geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(Geometry1 const& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(geometry1,
output_collection,
strategy),
geometry2);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Collection& output_collection, Strategy const& strategy)
: m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry1, typename Geometry2>
void operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
{
difference
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(output_collection,
strategy),
geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief_calc2{difference}
\ingroup difference
\details \details_calc2{difference, spatial set theoretic difference}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Collection \tparam_output_collection
\tparam Strategy \tparam_strategy{Difference}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param output_collection the output collection
\param strategy \param_strategy{difference}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/difference.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename Collection,
typename Strategy
>
inline void difference(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
resolve_variant::difference
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, output_collection, strategy);
}
/*!
\brief_calc2{difference}
@@ -144,25 +392,11 @@ inline void difference(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
typedef typename boost::range_value<Collection>::type geometry_out;
concepts::check<geometry_out>();
typedef typename geometry::rescale_overlay_policy_type
resolve_variant::difference
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1,
geometry2);
detail::difference::difference_insert<geometry_out>(
geometry1, geometry2, robust_policy,
range::back_inserter(output_collection));
>::apply(geometry1, geometry2, output_collection, default_strategy());
}

View File

@@ -138,24 +138,32 @@ struct segment_segment
struct area_check
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return geometry::math::equals(
geometry::area(geometry1),
geometry::area(geometry2));
geometry::area(geometry1,
strategy.template get_area_strategy<Geometry1>()),
geometry::area(geometry2,
strategy.template get_area_strategy<Geometry2>()));
}
};
struct length_check
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return geometry::math::equals(
geometry::length(geometry1),
geometry::length(geometry2));
geometry::length(geometry1,
strategy.template get_distance_strategy<Geometry1>()),
geometry::length(geometry2,
strategy.template get_distance_strategy<Geometry2>()));
}
};
@@ -184,9 +192,11 @@ template <typename TrivialCheck>
struct equals_by_collection
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const&)
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
if (! TrivialCheck::apply(geometry1, geometry2))
if (! TrivialCheck::apply(geometry1, geometry2, strategy))
{
return false;
}
@@ -321,6 +331,20 @@ struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
: detail::equals::point_point<0, DimensionCount>
{};
template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse>
struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, DimensionCount, Reverse>
: detail::equals::equals_by_relate<MultiPoint1, MultiPoint2>
{};
template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
struct equals<MultiPoint, Point, multi_point_tag, point_tag, DimensionCount, Reverse>
: detail::equals::equals_by_relate<MultiPoint, Point>
{};
template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
struct equals<Point, MultiPoint, point_tag, multi_point_tag, DimensionCount, Reverse>
: detail::equals::equals_by_relate<Point, MultiPoint>
{};
template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse>
@@ -601,8 +625,8 @@ struct equals<
\param strategy \param_strategy{equals}
\return \return_check2{are spatially equal}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/equals.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool equals(Geometry1 const& geometry1,
@@ -631,7 +655,6 @@ inline bool equals(Geometry1 const& geometry1,
\return \return_check2{are spatially equal}
\qbk{[include reference/algorithms/equals.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)

View File

@@ -97,7 +97,7 @@ inline bool intersects(Geometry const& geometry)
\param strategy \param_strategy{intersects}
\return \return_check2{intersect each other}
\qbk{distinguish,two geometries}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/intersects.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>

View File

@@ -180,6 +180,7 @@ struct overlaps<Box1, Box2, box_tag, box_tag>
\param strategy \param_strategy{overlaps}
\return \return_check2{overlap}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/overlaps.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>

View File

@@ -15,13 +15,21 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP
#include <algorithm>
#include <iterator>
#include <vector>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/algorithms/union.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -289,6 +297,253 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
#endif // DOXYGEN_NO_DETAIL
namespace resolve_strategy {
struct sym_difference
{
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename Collection,
typename Strategy
>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Collection & output_collection,
Strategy const& strategy)
{
typedef typename boost::range_value<Collection>::type geometry_out;
detail::sym_difference::sym_difference_insert<geometry_out>(
geometry1, geometry2, robust_policy,
range::back_inserter(output_collection),
strategy);
}
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename Collection
>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Collection & output_collection,
default_strategy)
{
typedef typename boost::range_value<Collection>::type geometry_out;
detail::sym_difference::sym_difference_insert<geometry_out>(
geometry1, geometry2, robust_policy,
range::back_inserter(output_collection));
}
};
} // resolve_strategy
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2>
struct sym_difference
{
template <typename Collection, typename Strategy>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1,
geometry2);
resolve_strategy::sym_difference::apply(geometry1, geometry2,
robust_policy,
output_collection,
strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Geometry2 const& m_geometry2;
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
: m_geometry2(geometry2)
, m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry1>
void operator()(Geometry1 const& geometry1) const
{
sym_difference
<
Geometry1,
Geometry2
>::apply(geometry1, m_geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(geometry2,
output_collection,
strategy),
geometry1);
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct sym_difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Geometry1 const& m_geometry1;
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1,
Collection& output_collection,
Strategy const& strategy)
: m_geometry1(geometry1)
, m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry2>
void operator()(Geometry2 const& geometry2) const
{
sym_difference
<
Geometry1,
Geometry2
>::apply(m_geometry1, geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(Geometry1 const& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(geometry1,
output_collection,
strategy),
geometry2);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Collection& output_collection, Strategy const& strategy)
: m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry1, typename Geometry2>
void operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
{
sym_difference
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(output_collection,
strategy),
geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief \brief_calc2{symmetric difference}
\ingroup sym_difference
\details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Collection output collection, either a multi-geometry,
or a std::vector<Geometry> / std::deque<Geometry> etc
\tparam Strategy \tparam_strategy{Sym_difference}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param output_collection the output collection
\param strategy \param_strategy{sym_difference}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/sym_difference.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename Collection,
typename Strategy
>
inline void sym_difference(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
resolve_variant::sym_difference
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, output_collection, strategy);
}
/*!
\brief \brief_calc2{symmetric difference}
\ingroup sym_difference
@@ -310,26 +565,14 @@ template
typename Collection
>
inline void sym_difference(Geometry1 const& geometry1,
Geometry2 const& geometry2, Collection& output_collection)
Geometry2 const& geometry2,
Collection& output_collection)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
typedef typename boost::range_value<Collection>::type geometry_out;
concepts::check<geometry_out>();
typedef typename geometry::rescale_overlay_policy_type
resolve_variant::sym_difference
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
detail::sym_difference::sym_difference_insert<geometry_out>(
geometry1, geometry2, robust_policy,
range::back_inserter(output_collection));
>::apply(geometry1, geometry2, output_collection, default_strategy());
}

View File

@@ -687,7 +687,7 @@ inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
\param strategy \param_strategy{touches}
\return \return_check2{touch each other}
\qbk{distinguish,two geometries}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/touches.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>

View File

@@ -25,6 +25,8 @@
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
@@ -234,6 +236,266 @@ inline OutputIterator union_insert(Geometry1 const& geometry1,
#endif // DOXYGEN_NO_DETAIL
namespace resolve_strategy {
struct union_
{
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename Collection,
typename Strategy
>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Collection & output_collection,
Strategy const& strategy)
{
typedef typename boost::range_value<Collection>::type geometry_out;
dispatch::union_insert
<
Geometry1, Geometry2, geometry_out
>::apply(geometry1, geometry2, robust_policy,
range::back_inserter(output_collection),
strategy);
}
template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename Collection
>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Collection & output_collection,
default_strategy)
{
typedef typename boost::range_value<Collection>::type geometry_out;
typedef typename strategy::intersection::services::default_strategy
<
typename cs_tag<geometry_out>::type
>::type strategy_type;
dispatch::union_insert
<
Geometry1, Geometry2, geometry_out
>::apply(geometry1, geometry2, robust_policy,
range::back_inserter(output_collection),
strategy_type());
}
};
} // resolve_strategy
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2>
struct union_
{
template <typename Collection, typename Strategy>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
concepts::check<typename boost::range_value<Collection>::type>();
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1,
geometry2);
resolve_strategy::union_::apply(geometry1, geometry2,
robust_policy,
output_collection,
strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct union_<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Geometry2 const& m_geometry2;
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
: m_geometry2(geometry2)
, m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry1>
void operator()(Geometry1 const& geometry1) const
{
union_
<
Geometry1,
Geometry2
>::apply(geometry1, m_geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(geometry2,
output_collection,
strategy),
geometry1);
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct union_<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Geometry1 const& m_geometry1;
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1,
Collection& output_collection,
Strategy const& strategy)
: m_geometry1(geometry1)
, m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry2>
void operator()(Geometry2 const& geometry2) const
{
union_
<
Geometry1,
Geometry2
>::apply(m_geometry1, geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(Geometry1 const& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(geometry1,
output_collection,
strategy),
geometry2);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
struct union_<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
{
template <typename Collection, typename Strategy>
struct visitor: static_visitor<>
{
Collection& m_output_collection;
Strategy const& m_strategy;
visitor(Collection& output_collection, Strategy const& strategy)
: m_output_collection(output_collection)
, m_strategy(strategy)
{}
template <typename Geometry1, typename Geometry2>
void operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
{
union_
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, m_output_collection, m_strategy);
}
};
template <typename Collection, typename Strategy>
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Collection, Strategy>(output_collection,
strategy),
geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief Combines two geometries which each other
\ingroup union
\details \details_calc2{union, spatial set theoretic union}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Collection output collection, either a multi-geometry,
or a std::vector<Geometry> / std::deque<Geometry> etc
\tparam Strategy \tparam_strategy{Union_}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param output_collection the output collection
\param strategy \param_strategy{union_}
\note Called union_ because union is a reserved word.
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/union.qbk]}
*/
template
<
typename Geometry1,
typename Geometry2,
typename Collection,
typename Strategy
>
inline void union_(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection,
Strategy const& strategy)
{
resolve_variant::union_
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, output_collection, strategy);
}
/*!
@@ -258,17 +520,14 @@ template
typename Collection
>
inline void union_(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection)
Geometry2 const& geometry2,
Collection& output_collection)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
typedef typename boost::range_value<Collection>::type geometry_out;
concepts::check<geometry_out>();
detail::union_::union_insert<geometry_out>(geometry1, geometry2,
range::back_inserter(output_collection));
resolve_variant::union_
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, output_collection, default_strategy());
}

View File

@@ -0,0 +1,71 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ARITHMETIC_NORMALIZE_HPP
#define BOOST_GEOMETRY_ARITHMETIC_NORMALIZE_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename Point>
inline typename coordinate_type<Point>::type vec_length_sqr(Point const& pt)
{
return dot_product(pt, pt);
}
template <typename Point>
inline typename coordinate_type<Point>::type vec_length(Point const& pt)
{
// NOTE: hypot() could be used instead of sqrt()
return math::sqrt(dot_product(pt, pt));
}
template <typename Point>
inline bool vec_normalize(Point & pt, typename coordinate_type<Point>::type & len)
{
typedef typename coordinate_type<Point>::type coord_t;
coord_t const c0 = 0;
len = vec_length(pt);
if (math::equals(len, c0))
{
return false;
}
divide_value(pt, len);
return true;
}
template <typename Point>
inline bool vec_normalize(Point & pt)
{
typedef typename coordinate_type<Point>::type coord_t;
coord_t len;
return vec_normalize(pt, len);
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ARITHMETIC_NORMALIZE_HPP

View File

@@ -4,8 +4,8 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -51,7 +51,7 @@ public:
spheroid()
: m_a(RadiusType(6378137.0))
, m_b(RadiusType(6356752.314245))
, m_b(RadiusType(6356752.3142451793))
{}
template <std::size_t I>

View File

@@ -68,12 +68,10 @@ struct geometry_type_ogc
{
point = 1,
linestring = 2,
polygon = 3
// TODO: Not implemented
//multipoint = 4,
//multilinestring = 5,
//multipolygon = 6,
polygon = 3,
multipoint = 4,
multilinestring = 5,
multipolygon = 6,
//collection = 7
};
};
@@ -169,6 +167,21 @@ struct geometry_type<Geometry, CheckPolicy, polygon_tag>
: geometry_type_impl<Geometry, geometry_type_ogc::polygon>
{};
template <typename Geometry, typename CheckPolicy>
struct geometry_type<Geometry, CheckPolicy, multi_point_tag>
: geometry_type_impl<Geometry, geometry_type_ogc::multipoint>
{};
template <typename Geometry, typename CheckPolicy>
struct geometry_type<Geometry, CheckPolicy, multi_linestring_tag>
: geometry_type_impl<Geometry, geometry_type_ogc::multilinestring>
{};
template <typename Geometry, typename CheckPolicy>
struct geometry_type<Geometry, CheckPolicy, multi_polygon_tag>
: geometry_type_impl<Geometry, geometry_type_ogc::multipolygon>
{};
}} // namespace detail::wkb
#endif // DOXYGEN_NO_IMPL

View File

@@ -15,6 +15,8 @@
#include <iterator>
#include <limits>
#include <boost/geometry/core/exception.hpp>
#include <boost/concept_check.hpp>
#include <boost/cstdint.hpp>
#include <boost/type_traits/is_integral.hpp>
@@ -33,6 +35,23 @@
namespace boost { namespace geometry
{
/*!
\brief Read WKB Exception
\ingroup core
\details The read_wkb_exception is thrown when there is an error in wkb parsing
*/
class read_wkb_exception : public geometry::exception
{
public:
inline read_wkb_exception() {}
virtual char const* what() const throw()
{
return "Boost.Geometry Read WKB exception";
}
};
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace wkb
{
@@ -191,9 +210,12 @@ struct point_container_parser
{
return false;
}
typedef typename std::iterator_traits<Iterator>::difference_type size_type;
BOOST_GEOMETRY_ASSERT(num_points <= boost::uint32_t( (std::numeric_limits<size_type>::max)() ) );
if(num_points > (std::numeric_limits<boost::uint32_t>::max)() )
{
throw boost::geometry::read_wkb_exception();
}
size_type const container_size = static_cast<size_type>(num_points);
size_type const point_size = dimension<point_type>::value * sizeof(double);
@@ -237,7 +259,11 @@ struct linestring_parser
return false;
}
BOOST_GEOMETRY_ASSERT(it != end);
if(it == end)
{
throw boost::geometry::read_wkb_exception();
}
return point_container_parser<L>::parse(it, end, linestring, order);
}
};
@@ -259,15 +285,15 @@ struct polygon_parser
{
return false;
}
typedef typename ring_type<Polygon>::type ring_type;
typedef typename boost::geometry::ring_return_type<Polygon>::type ring_type;
std::size_t rings_parsed = 0;
while (rings_parsed < num_rings && it != end)
{
if (0 == rings_parsed)
{
ring_type& ring0 = exterior_ring(polygon);
ring_type ring0 = exterior_ring(polygon);
if (!point_container_parser<ring_type>::parse(it, end, ring0, order))
{
return false;
@@ -275,19 +301,16 @@ struct polygon_parser
}
else
{
interior_rings(polygon).resize(rings_parsed);
ring_type& ringN = interior_rings(polygon).back();
boost::geometry::range::resize(interior_rings(polygon), rings_parsed);
ring_type ringN = boost::geometry::range::back(interior_rings(polygon));
if (!point_container_parser<ring_type>::parse(it, end, ringN, order))
{
return false;
}
}
++rings_parsed;
}
if (num_rings != rings_parsed)
{
return false;
++rings_parsed;
}
return true;

View File

@@ -27,38 +27,38 @@ namespace dispatch
template <typename Tag, typename G>
struct read_wkb {};
template <typename G>
struct read_wkb<point_tag, G>
template <typename Geometry>
struct read_wkb<point_tag, Geometry>
{
template <typename Iterator>
static inline bool parse(Iterator& it, Iterator end, G& geometry,
static inline bool parse(Iterator& it, Iterator end, Geometry& geometry,
detail::wkb::byte_order_type::enum_t order)
{
return detail::wkb::point_parser<G>::parse(it, end, geometry, order);
return detail::wkb::point_parser<Geometry>::parse(it, end, geometry, order);
}
};
template <typename G>
struct read_wkb<linestring_tag, G>
template <typename Geometry>
struct read_wkb<linestring_tag, Geometry>
{
template <typename Iterator>
static inline bool parse(Iterator& it, Iterator end, G& geometry,
static inline bool parse(Iterator& it, Iterator end, Geometry& geometry,
detail::wkb::byte_order_type::enum_t order)
{
geometry::clear(geometry);
return detail::wkb::linestring_parser<G>::parse(it, end, geometry, order);
return detail::wkb::linestring_parser<Geometry>::parse(it, end, geometry, order);
}
};
template <typename G>
struct read_wkb<polygon_tag, G>
template <typename Geometry>
struct read_wkb<polygon_tag, Geometry>
{
template <typename Iterator>
static inline bool parse(Iterator& it, Iterator end, G& geometry,
static inline bool parse(Iterator& it, Iterator end, Geometry& geometry,
detail::wkb::byte_order_type::enum_t order)
{
geometry::clear(geometry);
return detail::wkb::polygon_parser<G>::parse(it, end, geometry, order);
return detail::wkb::polygon_parser<Geometry>::parse(it, end, geometry, order);
}
};
@@ -66,8 +66,8 @@ struct read_wkb<polygon_tag, G>
#endif // DOXYGEN_NO_DISPATCH
template <typename Iterator, typename G>
inline bool read_wkb(Iterator begin, Iterator end, G& geometry)
template <typename Iterator, typename Geometry>
inline bool read_wkb(Iterator begin, Iterator end, Geometry& geometry)
{
// Stream of bytes can only be parsed using random access iterator.
BOOST_STATIC_ASSERT((
@@ -82,16 +82,16 @@ inline bool read_wkb(Iterator begin, Iterator end, G& geometry)
{
return dispatch::read_wkb
<
typename tag<G>::type,
G
typename tag<Geometry>::type,
Geometry
>::parse(begin, end, geometry, byte_order);
}
return false;
}
template <typename ByteType, typename G>
inline bool read_wkb(ByteType const* bytes, std::size_t length, G& geometry)
template <typename ByteType, typename Geometry>
inline bool read_wkb(ByteType const* bytes, std::size_t length, Geometry& geometry)
{
BOOST_STATIC_ASSERT((boost::is_integral<ByteType>::value));
BOOST_STATIC_ASSERT((sizeof(boost::uint8_t) == sizeof(ByteType)));

View File

@@ -0,0 +1,248 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_PARSER_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_PARSER_HPP
#include <cstddef>
#include <iterator>
#include <limits>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/extensions/gis/io/wkb/detail/endian.hpp>
#include <boost/geometry/extensions/gis/io/wkb/detail/parser.hpp>
#include <boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp>
#include <boost/geometry/multi/core/point_type.hpp>
#include <boost/geometry/multi/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/multi/core/interior_rings.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace wkb
{
template <typename MultiPoint>
struct multipoint_parser
{
template <typename Iterator>
static bool parse(Iterator& it, Iterator end, MultiPoint& multipoint, byte_order_type::enum_t order)
{
if (!geometry_type_parser<MultiPoint>::parse(it, end, order))
{
return false;
}
boost::uint32_t num_points(0);
if (!value_parser<boost::uint32_t>::parse(it, end, num_points, order))
{
return false;
}
// Check that the number of double values in the stream is equal
// or greater than the number of expected values in the multipoint
typedef typename std::iterator_traits<Iterator>::difference_type size_type;
typedef typename point_type<MultiPoint>::type point_type;
size_type const container_byte_size = dimension<point_type>::value * num_points * sizeof(double)
+ num_points * sizeof(boost::uint8_t)
+ num_points * sizeof(boost::uint32_t);
size_type const stream_byte_size = std::distance(it,end);
if(stream_byte_size < container_byte_size)
{
throw boost::geometry::read_wkb_exception();
}
point_type point_buffer;
std::back_insert_iterator<MultiPoint> output(std::back_inserter(multipoint));
typedef typename std::iterator_traits<Iterator>::difference_type size_type;
if(num_points > (std::numeric_limits<boost::uint32_t>::max)() )
{
throw boost::geometry::read_wkb_exception();
}
size_type points_parsed = 0;
while (points_parsed < num_points && it != end)
{
detail::wkb::byte_order_type::enum_t point_byte_order;
if (!detail::wkb::byte_order_parser::parse(it, end, point_byte_order))
{
return false;
}
if (!geometry_type_parser<point_type>::parse(it, end, point_byte_order))
{
return false;
}
parsing_assigner<point_type, 0, dimension<point_type>::value>::run(it, end, point_buffer, point_byte_order);
output = point_buffer;
++output;
++points_parsed;
}
return true;
}
};
template <typename MultiLinestring>
struct multilinestring_parser
{
template <typename Iterator>
static bool parse(Iterator& it, Iterator end, MultiLinestring& multilinestring, byte_order_type::enum_t order)
{
typedef typename MultiLinestring::value_type linestring_type;
typedef typename point_type<MultiLinestring>::type point_type;
if (!geometry_type_parser<MultiLinestring>::parse(it, end, order))
{
return false;
}
boost::uint32_t num_linestrings(0);
if (!value_parser<boost::uint32_t>::parse(it, end, num_linestrings, order))
{
return false;
}
std::back_insert_iterator<MultiLinestring> output(std::back_inserter(multilinestring));
typedef typename std::iterator_traits<Iterator>::difference_type size_type;
if(num_linestrings > (std::numeric_limits<boost::uint32_t>::max)() )
{
throw boost::geometry::read_wkb_exception();
}
size_type linestrings_parsed = 0;
while (linestrings_parsed < num_linestrings && it != end)
{
linestring_type linestring_buffer;
detail::wkb::byte_order_type::enum_t linestring_byte_order;
if (!detail::wkb::byte_order_parser::parse(it, end, linestring_byte_order))
{
return false;
}
if (!geometry_type_parser<linestring_type>::parse(it, end, order))
{
return false;
}
if(!point_container_parser<linestring_type>::parse(it, end, linestring_buffer, linestring_byte_order))
{
return false;
}
output = linestring_buffer;
++output;
++linestrings_parsed;
}
return true;
}
};
template <typename MultiPolygon>
struct multipolygon_parser
{
template <typename Iterator>
static bool parse(Iterator& it, Iterator end, MultiPolygon& multipolygon, byte_order_type::enum_t order)
{
typedef typename boost::range_value<MultiPolygon>::type polygon_type;
if (!geometry_type_parser<MultiPolygon>::parse(it, end, order))
{
return false;
}
boost::uint32_t num_polygons(0);
if (!value_parser<boost::uint32_t>::parse(it, end, num_polygons, order))
{
return false;
}
std::back_insert_iterator<MultiPolygon> output(std::back_inserter(multipolygon));
std::size_t polygons_parsed = 0;
while(polygons_parsed < num_polygons && it != end)
{
polygon_type polygon_buffer;
detail::wkb::byte_order_type::enum_t polygon_byte_order;
if (!detail::wkb::byte_order_parser::parse(it, end, polygon_byte_order))
{
return false;
}
if (!geometry_type_parser<polygon_type>::parse(it, end, order))
{
return false;
}
boost::uint32_t num_rings(0);
if (!value_parser<boost::uint32_t>::parse(it, end, num_rings, polygon_byte_order))
{
return false;
}
std::size_t rings_parsed = 0;
while (rings_parsed < num_rings && it != end)
{
typedef typename boost::geometry::ring_return_type<polygon_type>::type ring_type;
if (0 == rings_parsed)
{
ring_type ring0 = exterior_ring(polygon_buffer);
if (!point_container_parser<ring_type>::parse(it, end, ring0, polygon_byte_order))
{
return false;
}
}
else
{
boost::geometry::range::resize(interior_rings(polygon_buffer), rings_parsed);
ring_type ringN = boost::geometry::range::back(interior_rings(polygon_buffer));
if (!point_container_parser<ring_type>::parse(it, end, ringN, polygon_byte_order))
{
return false;
}
}
++rings_parsed;
}
output = polygon_buffer;
++output;
}
return true;
}
};
}} // namespace detail::wkb
#endif // DOXYGEN_NO_IMPL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_PARSER_HPP

View File

@@ -0,0 +1,145 @@
// Boost.Geometry
//
// Copyright (c) 2015 Mats Taraldsvik.
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_WRITER_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_WRITER_HPP
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <limits>
#include <boost/concept_check.hpp>
#include <boost/cstdint.hpp>
#include <boost/range.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/extensions/gis/io/wkb/detail/writer.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/extensions/gis/io/wkb/detail/endian.hpp>
#include <boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp>
#include <iostream>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace wkb
{
template <typename MultiPoint>
struct multipoint_writer
{
template <typename OutputIterator>
static bool write(MultiPoint const& multipoint,
OutputIterator& iter,
byte_order_type::enum_t byte_order)
{
// write endian type
value_writer<uint8_t>::write(byte_order, iter, byte_order);
// write geometry type
uint32_t type = geometry_type<MultiPoint>::get();
value_writer<uint32_t>::write(type, iter, byte_order);
// write num points
uint32_t num_points = boost::size(multipoint);
value_writer<uint32_t>::write(num_points, iter, byte_order);
typedef typename point_type<MultiPoint>::type point_type;
for(typename boost::range_iterator<MultiPoint const>::type
point_iter = boost::begin(multipoint);
point_iter != boost::end(multipoint);
++point_iter)
{
detail::wkb::point_writer<point_type>::write(*point_iter, iter, byte_order);
}
return true;
}
};
template <typename MultiLinestring>
struct multilinestring_writer
{
template <typename OutputIterator>
static bool write(MultiLinestring const& multilinestring,
OutputIterator& iter,
byte_order_type::enum_t byte_order)
{
// write endian type
value_writer<uint8_t>::write(byte_order, iter, byte_order);
// write geometry type
uint32_t type = geometry_type<MultiLinestring>::get();
value_writer<uint32_t>::write(type, iter, byte_order);
// write num linestrings
uint32_t num_linestrings = boost::size(multilinestring);
value_writer<uint32_t>::write(num_linestrings, iter, byte_order);
typedef typename boost::range_value<MultiLinestring>::type linestring_type;
for(typename boost::range_iterator<MultiLinestring const>::type
linestring_iter = boost::begin(multilinestring);
linestring_iter != boost::end(multilinestring);
++linestring_iter)
{
detail::wkb::linestring_writer<linestring_type>::write(*linestring_iter, iter, byte_order);
}
return true;
}
};
template <typename MultiPolygon>
struct multipolygon_writer
{
template <typename OutputIterator>
static bool write(MultiPolygon const& multipolygon,
OutputIterator& iter,
byte_order_type::enum_t byte_order)
{
// write endian type
value_writer<uint8_t>::write(byte_order, iter, byte_order);
// write geometry type
uint32_t type = geometry_type<MultiPolygon>::get();
value_writer<uint32_t>::write(type, iter, byte_order);
// write num polygons
uint32_t num_polygons = boost::size(multipolygon);
value_writer<uint32_t>::write(num_polygons, iter, byte_order);
typedef typename boost::range_value<MultiPolygon>::type polygon_type;
for(typename boost::range_iterator<MultiPolygon const>::type
polygon_iter = boost::begin(multipolygon);
polygon_iter != boost::end(multipolygon);
++polygon_iter)
{
detail::wkb::polygon_writer<polygon_type>::write(*polygon_iter, iter, byte_order);
}
return true;
}
};
}} // namespace detail::wkb
#endif // DOXYGEN_NO_IMPL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_WRITER_HPP

View File

@@ -0,0 +1,62 @@
// Boost.Geometry
// Copyright (c) 2015 Mats Taraldsvik
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_MULTI_IO_WKB_READ_WKB_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKB_READ_WKB_HPP
#include <iterator>
#include <boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp>
#include <boost/geometry/extensions/gis/io/wkb/read_wkb.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry>
struct read_wkb<multi_point_tag, Geometry>
{
template <typename Iterator>
static inline bool parse(Iterator& it, Iterator end, Geometry& geometry,
detail::wkb::byte_order_type::enum_t order)
{
return detail::wkb::multipoint_parser<Geometry>::parse(it, end, geometry, order);
}
};
template <typename Geometry>
struct read_wkb<multi_linestring_tag, Geometry>
{
template <typename Iterator>
static inline bool parse(Iterator& it, Iterator end, Geometry& geometry,
detail::wkb::byte_order_type::enum_t order)
{
return detail::wkb::multilinestring_parser<Geometry>::parse(it, end, geometry, order);
}
};
template <typename Geometry>
struct read_wkb<multi_polygon_tag, Geometry>
{
template <typename Iterator>
static inline bool parse(Iterator& it, Iterator end, Geometry& geometry,
detail::wkb::byte_order_type::enum_t order)
{
return detail::wkb::multipolygon_parser<Geometry>::parse(it, end, geometry, order);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_WKB_READ_WKB_HPP

View File

@@ -0,0 +1,66 @@
// Boost.Geometry
//
// Copyright (c) 2015 Mats Taraldsvik.
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_MULTI_IO_WKB_WRITE_WKB_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKB_WRITE_WKB_HPP
#include <iterator>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/static_assert.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/extensions/multi/gis/io/wkb/detail/writer.hpp>
#include <boost/geometry/extensions/gis/io/wkb/write_wkb.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry>
struct write_wkb<multi_point_tag, Geometry>
{
template <typename OutputIterator>
static inline bool write(const Geometry& geometry, OutputIterator iter,
detail::wkb::byte_order_type::enum_t byte_order)
{
return detail::wkb::multipoint_writer<Geometry>::write(geometry, iter, byte_order);
}
};
template <typename Geometry>
struct write_wkb<multi_linestring_tag, Geometry>
{
template <typename OutputIterator>
static inline bool write(const Geometry& geometry, OutputIterator iter,
detail::wkb::byte_order_type::enum_t byte_order)
{
return detail::wkb::multilinestring_writer<Geometry>::write(geometry, iter, byte_order);
}
};
template <typename Geometry>
struct write_wkb<multi_polygon_tag, Geometry>
{
template <typename OutputIterator>
static inline bool write(const Geometry& geometry, OutputIterator iter,
detail::wkb::byte_order_type::enum_t byte_order)
{
return detail::wkb::multipolygon_writer<Geometry>::write(geometry, iter, byte_order);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_WKB_WRITE_WKB_HPP

View File

@@ -1,6 +1,6 @@
// Boost.Geometry
// Copyright (c) 2015-2016 Oracle and/or its affiliates.
// Copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -20,9 +20,8 @@
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/formulas/differential_quantities.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/result_inverse.hpp>
@@ -75,7 +74,7 @@ public:
CT const c0 = CT(0);
CT const c1 = CT(1);
CT const pi = math::pi<CT>();
CT const f = detail::flattening<CT>(spheroid);
CT const f = formula::flattening<CT>(spheroid);
CT const dlon = lon2 - lon1;
CT const sin_dlon = sin(dlon);
@@ -138,7 +137,14 @@ public:
CT A = c0;
CT U = c0;
if ( ! math::equals(cos_lat2, c0) )
if (math::equals(cos_lat2, c0))
{
if (sin_lat2 < c0)
{
A = pi;
}
}
else
{
CT const tan_lat2 = sin_lat2/cos_lat2;
CT const M = cos_lat1*tan_lat2-sin_lat1*cos_dlon;
@@ -149,7 +155,14 @@ public:
CT B = c0;
CT V = c0;
if ( ! math::equals(cos_lat1, c0) )
if (math::equals(cos_lat1, c0))
{
if (sin_lat1 < c0)
{
B = pi;
}
}
else
{
CT const tan_lat1 = sin_lat1/cos_lat1;
CT const N = cos_lat2*tan_lat1-sin_lat2*cos_dlon;

View File

@@ -11,7 +11,7 @@
#ifndef BOOST_GEOMETRY_FORMULAS_AREA_FORMULAS_HPP
#define BOOST_GEOMETRY_FORMULAS_AREA_FORMULAS_HPP
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/math/special_functions/hypot.hpp>
namespace boost { namespace geometry { namespace formula
@@ -429,7 +429,7 @@ public:
// Constants
CT const ep = spheroid_const.m_ep;
CT const f = geometry::detail::flattening<CT>(spheroid_const.m_spheroid);
CT const f = formula::flattening<CT>(spheroid_const.m_spheroid);
CT const one_minus_f = CT(1) - f;
std::size_t const series_order_plus_one = SeriesOrder + 1;
std::size_t const series_order_plus_two = SeriesOrder + 2;

View File

@@ -1,6 +1,6 @@
// Boost.Geometry
// Copyright (c) 2016 Oracle and/or its affiliates.
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -64,8 +64,8 @@ public:
CT const c1 = 1;
CT const one_minus_f = c1 - f;
CT const sin_bet1 = one_minus_f * sin_lat1;
CT const sin_bet2 = one_minus_f * sin_lat2;
CT sin_bet1 = one_minus_f * sin_lat1;
CT sin_bet2 = one_minus_f * sin_lat2;
// equator
if (math::equals(sin_bet1, c0) && math::equals(sin_bet2, c0))
@@ -89,14 +89,17 @@ public:
CT const e2 = f * (c2 - f);
CT const ep2 = e2 / math::sqr(one_minus_f);
CT const cos_bet1 = cos_lat1;
CT const cos_bet2 = cos_lat2;
CT const sin_alp1 = sin(azimuth);
CT const cos_alp1 = cos(azimuth);
//CT const sin_alp2 = sin(reverse_azimuth);
CT const cos_alp2 = cos(reverse_azimuth);
CT cos_bet1 = cos_lat1;
CT cos_bet2 = cos_lat2;
normalize(sin_bet1, cos_bet1);
normalize(sin_bet2, cos_bet2);
CT sin_sig1 = sin_bet1;
CT cos_sig1 = cos_alp1 * cos_bet1;
CT sin_sig2 = sin_bet2;
@@ -112,8 +115,8 @@ public:
J12_f(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, f) :
J12_ep_sqr(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, ep2) ;
CT const dn1 = math::sqrt(c1 + e2 * math::sqr(sin_lat1));
CT const dn2 = math::sqrt(c1 + e2 * math::sqr(sin_lat2));
CT const dn1 = math::sqrt(c1 + ep2 * math::sqr(sin_bet1));
CT const dn2 = math::sqrt(c1 + ep2 * math::sqr(sin_bet2));
if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
{

View File

@@ -0,0 +1,70 @@
// Boost.Geometry
// Copyright (c) 2016 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_HPP
#define BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_HPP
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace formula_dispatch
{
template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type>
struct eccentricity_sqr
: not_implemented<Tag>
{};
template <typename ResultType, typename Geometry>
struct eccentricity_sqr<ResultType, Geometry, srs_sphere_tag>
{
static inline ResultType apply(Geometry const& /*geometry*/)
{
return ResultType(0);
}
};
template <typename ResultType, typename Geometry>
struct eccentricity_sqr<ResultType, Geometry, srs_spheroid_tag>
{
static inline ResultType apply(Geometry const& geometry)
{
// 1 - (b / a)^2
return ResultType(1) - math::sqr(ResultType(get_radius<2>(geometry))
/ ResultType(get_radius<0>(geometry)));
}
};
} // namespace formula_dispatch
#endif // DOXYGEN_NO_DISPATCH
#ifndef DOXYGEN_NO_DETAIL
namespace formula
{
template <typename ResultType, typename Geometry>
ResultType eccentricity_sqr(Geometry const& geometry)
{
return formula_dispatch::eccentricity_sqr<ResultType, Geometry>::apply(geometry);
}
} // namespace formula
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_FORMULAS_ECCENCRICITY_SQR_HPP

View File

@@ -1,6 +1,6 @@
// Boost.Geometry
// Copyright (c) 2014 Oracle and/or its affiliates.
// Copyright (c) 2014-2016 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -8,8 +8,8 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP
#ifndef BOOST_GEOMETRY_FORMULAS_FLATTENING_HPP
#define BOOST_GEOMETRY_FORMULAS_FLATTENING_HPP
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/tag.hpp>
@@ -21,7 +21,7 @@ namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace detail_dispatch
namespace formula_dispatch
{
template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type>
@@ -43,27 +43,28 @@ struct flattening<ResultType, Geometry, srs_spheroid_tag>
{
static inline ResultType apply(Geometry const& geometry)
{
// (a - b) / a
return ResultType(get_radius<0>(geometry) - get_radius<2>(geometry))
/ ResultType(get_radius<0>(geometry));
}
};
} // namespace detail_dispatch
} // namespace formula_dispatch
#endif // DOXYGEN_NO_DISPATCH
#ifndef DOXYGEN_NO_DETAIL
namespace detail
namespace formula
{
template <typename ResultType, typename Geometry>
ResultType flattening(Geometry const& geometry)
{
return detail_dispatch::flattening<ResultType, Geometry>::apply(geometry);
return formula_dispatch::flattening<ResultType, Geometry>::apply(geometry);
}
} // namespace detail
} // namespace formula
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP
#endif // BOOST_GEOMETRY_FORMULAS_FLATTENING_HPP

View File

@@ -0,0 +1,457 @@
// Boost.Geometry
// Copyright (c) 2016, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_HPP
#define BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_HPP
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/cross_product.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/arithmetic/normalize.hpp>
#include <boost/geometry/formulas/eccentricity_sqr.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
namespace boost { namespace geometry {
namespace formula {
template <typename Point3d, typename PointGeo, typename Spheroid>
inline Point3d geo_to_cart3d(PointGeo const& point_geo, Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type calc_t;
calc_t const c1 = 1;
calc_t const e_sqr = eccentricity_sqr<calc_t>(spheroid);
calc_t const lon = get_as_radian<0>(point_geo);
calc_t const lat = get_as_radian<1>(point_geo);
Point3d res;
calc_t const sin_lat = sin(lat);
// "unit" spheroid, a = 1
calc_t const N = c1 / math::sqrt(c1 - e_sqr * math::sqr(sin_lat));
calc_t const N_cos_lat = N * cos(lat);
set<0>(res, N_cos_lat * cos(lon));
set<1>(res, N_cos_lat * sin(lon));
set<2>(res, N * (c1 - e_sqr) * sin_lat);
return res;
}
template <typename PointGeo, typename Spheroid, typename Point3d>
inline void geo_to_cart3d(PointGeo const& point_geo, Point3d & result, Point3d & north, Point3d & east, Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type calc_t;
calc_t const c1 = 1;
calc_t const e_sqr = eccentricity_sqr<calc_t>(spheroid);
calc_t const lon = get_as_radian<0>(point_geo);
calc_t const lat = get_as_radian<1>(point_geo);
calc_t const sin_lon = sin(lon);
calc_t const cos_lon = cos(lon);
calc_t const sin_lat = sin(lat);
calc_t const cos_lat = cos(lat);
// "unit" spheroid, a = 1
calc_t const N = c1 / math::sqrt(c1 - e_sqr * math::sqr(sin_lat));
calc_t const N_cos_lat = N * cos_lat;
set<0>(result, N_cos_lat * cos_lon);
set<1>(result, N_cos_lat * sin_lon);
set<2>(result, N * (c1 - e_sqr) * sin_lat);
set<0>(east, -sin_lon);
set<1>(east, cos_lon);
set<2>(east, 0);
set<0>(north, -sin_lat * cos_lon);
set<1>(north, -sin_lat * sin_lon);
set<2>(north, cos_lat);
}
template <typename PointGeo, typename Point3d, typename Spheroid>
inline PointGeo cart3d_to_geo(Point3d const& point_3d, Spheroid const& spheroid)
{
typedef typename coordinate_type<PointGeo>::type coord_t;
typedef typename coordinate_type<Point3d>::type calc_t;
calc_t const c1 = 1;
//calc_t const c2 = 2;
calc_t const e_sqr = eccentricity_sqr<calc_t>(spheroid);
calc_t const x = get<0>(point_3d);
calc_t const y = get<1>(point_3d);
calc_t const z = get<2>(point_3d);
calc_t const xy_l = math::sqrt(math::sqr(x) + math::sqr(y));
calc_t const lonr = atan2(y, x);
// NOTE: Alternative version
// http://www.iag-aig.org/attach/989c8e501d9c5b5e2736955baf2632f5/V60N2_5FT.pdf
// calc_t const lonr = c2 * atan2(y, x + xy_l);
calc_t const latr = atan2(z, (c1 - e_sqr) * xy_l);
// NOTE: If h is equal to 0 then there is no need to improve value of latitude
// because then N_i / (N_i + h_i) = 1
// http://www.navipedia.net/index.php/Ellipsoidal_and_Cartesian_Coordinates_Conversion
PointGeo res;
set_from_radian<0>(res, lonr);
set_from_radian<1>(res, latr);
coord_t lon = get<0>(res);
coord_t lat = get<1>(res);
math::normalize_spheroidal_coordinates
<
typename coordinate_system<PointGeo>::type::units,
coord_t
>(lon, lat);
set<0>(res, lon);
set<1>(res, lat);
return res;
}
template <typename Point3d, typename Spheroid>
inline Point3d projected_to_xy(Point3d const& point_3d, Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type coord_t;
// len_xy = sqrt(x^2 + y^2)
// r = len_xy - |z / tan(lat)|
// assuming h = 0
// lat = atan2(z, (1 - e^2) * len_xy);
// |z / tan(lat)| = (1 - e^2) * len_xy
// r = e^2 * len_xy
// x_res = r * cos(lon) = e^2 * len_xy * x / len_xy = e^2 * x
// y_res = r * sin(lon) = e^2 * len_xy * y / len_xy = e^2 * y
coord_t const c0 = 0;
coord_t const e_sqr = formula::eccentricity_sqr<coord_t>(spheroid);
Point3d res;
set<0>(res, e_sqr * get<0>(point_3d));
set<1>(res, e_sqr * get<1>(point_3d));
set<2>(res, c0);
return res;
}
template <typename Point3d, typename Spheroid>
inline Point3d projected_to_surface(Point3d const& direction, Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type coord_t;
//coord_t const c0 = 0;
coord_t const c2 = 2;
coord_t const c4 = 4;
// calculate the point of intersection of a ray and spheroid's surface
// the origin is the origin of the coordinate system
//(x*x+y*y)/(a*a) + z*z/(b*b) = 1
// x = d.x * t
// y = d.y * t
// z = d.z * t
coord_t const dx = get<0>(direction);
coord_t const dy = get<1>(direction);
coord_t const dz = get<2>(direction);
//coord_t const a_sqr = math::sqr(get_radius<0>(spheroid));
//coord_t const b_sqr = math::sqr(get_radius<2>(spheroid));
// "unit" spheroid, a = 1
coord_t const a_sqr = 1;
coord_t const b_sqr = math::sqr(get_radius<2>(spheroid) / get_radius<0>(spheroid));
coord_t const param_a = (dx*dx + dy*dy) / a_sqr + dz*dz / b_sqr;
coord_t const delta = c4 * param_a;
// delta >= 0
coord_t const t = math::sqrt(delta) / (c2 * param_a);
// result = direction * t
Point3d result = direction;
multiply_value(result, t);
return result;
}
template <typename Point3d, typename Spheroid>
inline bool projected_to_surface(Point3d const& origin, Point3d const& direction, Point3d & result1, Point3d & result2, Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type coord_t;
coord_t const c0 = 0;
coord_t const c1 = 1;
coord_t const c2 = 2;
coord_t const c4 = 4;
// calculate the point of intersection of a ray and spheroid's surface
//(x*x+y*y)/(a*a) + z*z/(b*b) = 1
// x = o.x + d.x * t
// y = o.y + d.y * t
// z = o.z + d.z * t
coord_t const ox = get<0>(origin);
coord_t const oy = get<1>(origin);
coord_t const oz = get<2>(origin);
coord_t const dx = get<0>(direction);
coord_t const dy = get<1>(direction);
coord_t const dz = get<2>(direction);
//coord_t const a_sqr = math::sqr(get_radius<0>(spheroid));
//coord_t const b_sqr = math::sqr(get_radius<2>(spheroid));
// "unit" spheroid, a = 1
coord_t const a_sqr = 1;
coord_t const b_sqr = math::sqr(get_radius<2>(spheroid) / get_radius<0>(spheroid));
coord_t const param_a = (dx*dx + dy*dy) / a_sqr + dz*dz / b_sqr;
coord_t const param_b = c2 * ((ox*dx + oy*dy) / a_sqr + oz*dz / b_sqr);
coord_t const param_c = (ox*ox + oy*oy) / a_sqr + oz*oz / b_sqr - c1;
coord_t const delta = math::sqr(param_b) - c4 * param_a*param_c;
// equals() ?
if (delta < c0 || param_a == 0)
{
return false;
}
// result = origin + direction * t
coord_t const sqrt_delta = math::sqrt(delta);
coord_t const two_a = c2 * param_a;
coord_t const t1 = (-param_b + sqrt_delta) / two_a;
result1 = direction;
multiply_value(result1, t1);
add_point(result1, origin);
coord_t const t2 = (-param_b - sqrt_delta) / two_a;
result2 = direction;
multiply_value(result2, t2);
add_point(result2, origin);
return true;
}
template <typename Point3d, typename Spheroid>
inline bool great_elliptic_intersection(Point3d const& a1, Point3d const& a2,
Point3d const& b1, Point3d const& b2,
Point3d & result,
Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type coord_t;
coord_t c0 = 0;
coord_t c1 = 1;
Point3d n1 = cross_product(a1, a2);
Point3d n2 = cross_product(b1, b2);
// intersection direction
Point3d id = cross_product(n1, n2);
coord_t id_len_sqr = dot_product(id, id);
if (math::equals(id_len_sqr, c0))
{
return false;
}
// no need to normalize a1 and a2 because the intersection point on
// the opposite side of the globe is at the same distance from the origin
coord_t cos_a1i = dot_product(a1, id);
coord_t cos_a2i = dot_product(a2, id);
coord_t gri = math::detail::greatest(cos_a1i, cos_a2i);
Point3d neg_id = id;
multiply_value(neg_id, -c1);
coord_t cos_a1ni = dot_product(a1, neg_id);
coord_t cos_a2ni = dot_product(a2, neg_id);
coord_t grni = math::detail::greatest(cos_a1ni, cos_a2ni);
if (gri >= grni)
{
result = projected_to_surface(id, spheroid);
}
else
{
result = projected_to_surface(neg_id, spheroid);
}
return true;
}
template <typename Point3d1, typename Point3d2>
static inline int elliptic_side_value(Point3d1 const& origin, Point3d1 const& norm, Point3d2 const& pt)
{
typedef typename coordinate_type<Point3d1>::type calc_t;
calc_t c0 = 0;
// vector oposite to pt - origin
// only for the purpose of assigning origin
Point3d1 vec = origin;
subtract_point(vec, pt);
calc_t d = dot_product(norm, vec);
// since the vector is opposite the signs are opposite
return math::equals(d, c0) ? 0
: d < c0 ? 1
: -1; // d > 0
}
template <typename Point3d, typename Spheroid>
inline bool planes_spheroid_intersection(Point3d const& o1, Point3d const& n1,
Point3d const& o2, Point3d const& n2,
Point3d & ip1, Point3d & ip2,
Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type coord_t;
coord_t c0 = 0;
coord_t c1 = 1;
// Below
// n . (p - o) = 0
// n . p - n . o = 0
// n . p + d = 0
// n . p = h
// intersection direction
Point3d id = cross_product(n1, n2);
if (math::equals(dot_product(id, id), c0))
{
return false;
}
coord_t dot_n1_n2 = dot_product(n1, n2);
coord_t dot_n1_n2_sqr = math::sqr(dot_n1_n2);
coord_t h1 = dot_product(n1, o1);
coord_t h2 = dot_product(n2, o2);
coord_t denom = c1 - dot_n1_n2_sqr;
coord_t C1 = (h1 - h2 * dot_n1_n2) / denom;
coord_t C2 = (h2 - h1 * dot_n1_n2) / denom;
// C1 * n1 + C2 * n2
Point3d C1_n1 = n1;
multiply_value(C1_n1, C1);
Point3d C2_n2 = n2;
multiply_value(C2_n2, C2);
Point3d io = C1_n1;
add_point(io, C2_n2);
if (! projected_to_surface(io, id, ip1, ip2, spheroid))
{
return false;
}
return true;
}
template <typename Point3d, typename Spheroid>
inline void experimental_elliptic_plane(Point3d const& p1, Point3d const& p2,
Point3d & v1, Point3d & v2,
Point3d & origin, Point3d & normal,
Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type coord_t;
Point3d xy1 = projected_to_xy(p1, spheroid);
Point3d xy2 = projected_to_xy(p2, spheroid);
// origin = (xy1 + xy2) / 2
origin = xy1;
add_point(origin, xy2);
multiply_value(origin, coord_t(0.5));
// v1 = p1 - origin
v1 = p1;
subtract_point(v1, origin);
// v2 = p2 - origin
v2 = p2;
subtract_point(v2, origin);
normal = cross_product(v1, v2);
}
template <typename Point3d, typename Spheroid>
inline void experimental_elliptic_plane(Point3d const& p1, Point3d const& p2,
Point3d & origin, Point3d & normal,
Spheroid const& spheroid)
{
Point3d v1, v2;
experimental_elliptic_plane(p1, p2, v1, v2, origin, normal, spheroid);
}
template <typename Point3d, typename Spheroid>
inline bool experimental_elliptic_intersection(Point3d const& a1, Point3d const& a2,
Point3d const& b1, Point3d const& b2,
Point3d & result,
Spheroid const& spheroid)
{
typedef typename coordinate_type<Point3d>::type coord_t;
coord_t c0 = 0;
coord_t c1 = 1;
Point3d a1v, a2v, o1, n1;
experimental_elliptic_plane(a1, a2, a1v, a2v, o1, n1, spheroid);
Point3d b1v, b2v, o2, n2;
experimental_elliptic_plane(b1, b2, b1v, b2v, o2, n2, spheroid);
if (! detail::vec_normalize(n1) || ! detail::vec_normalize(n2))
{
return false;
}
Point3d ip1_s, ip2_s;
if (! planes_spheroid_intersection(o1, n1, o2, n2, ip1_s, ip2_s, spheroid))
{
return false;
}
// NOTE: simplified test, may not work in all cases
coord_t dot_a1i1 = dot_product(a1, ip1_s);
coord_t dot_a2i1 = dot_product(a2, ip1_s);
coord_t gri1 = math::detail::greatest(dot_a1i1, dot_a2i1);
coord_t dot_a1i2 = dot_product(a1, ip2_s);
coord_t dot_a2i2 = dot_product(a2, ip2_s);
coord_t gri2 = math::detail::greatest(dot_a1i2, dot_a2i2);
result = gri1 >= gri2 ? ip1_s : ip2_s;
return true;
}
} // namespace formula
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_HPP

View File

@@ -14,12 +14,11 @@
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/thomas_inverse.hpp>
#include <boost/geometry/formulas/vincenty_direct.hpp>
#include <boost/geometry/formulas/vincenty_inverse.hpp>

File diff suppressed because it is too large Load Diff

View File

@@ -40,38 +40,55 @@ struct result_spherical
T reverse_azimuth;
};
template <typename T>
static inline void sph_to_cart3d(T const& lon, T const& lat, T & x, T & y, T & z)
{
T const cos_lat = cos(lat);
x = cos_lat * cos(lon);
y = cos_lat * sin(lon);
z = sin(lat);
}
template <typename Point3d, typename PointSph>
static inline Point3d sph_to_cart3d(PointSph const& point_sph)
{
typedef typename coordinate_type<Point3d>::type calc_t;
calc_t const lon = get_as_radian<0>(point_sph);
calc_t const lat = get_as_radian<1>(point_sph);
calc_t x, y, z;
sph_to_cart3d(lon, lat, x, y, z);
Point3d res;
calc_t lon = get_as_radian<0>(point_sph);
calc_t lat = get_as_radian<1>(point_sph);
calc_t const cos_lat = cos(lat);
set<0>(res, cos_lat * cos(lon));
set<1>(res, cos_lat * sin(lon));
set<2>(res, sin(lat));
set<0>(res, x);
set<1>(res, y);
set<2>(res, z);
return res;
}
template <typename T>
static inline void cart3d_to_sph(T const& x, T const& y, T const& z, T & lon, T & lat)
{
lon = atan2(y, x);
lat = asin(z);
}
template <typename PointSph, typename Point3d>
static inline PointSph cart3d_to_sph(Point3d const& point_3d)
{
typedef typename coordinate_type<PointSph>::type coord_t;
typedef typename coordinate_type<Point3d>::type calc_t;
PointSph res;
calc_t const x = get<0>(point_3d);
calc_t const y = get<1>(point_3d);
calc_t const z = get<2>(point_3d);
calc_t lonr, latr;
cart3d_to_sph(x, y, z, lonr, latr);
set_from_radian<0>(res, atan2(y, x));
set_from_radian<1>(res, asin(z));
PointSph res;
set_from_radian<0>(res, lonr);
set_from_radian<1>(res, latr);
coord_t lon = get<0>(res);
coord_t lat = get<1>(res);
@@ -104,9 +121,9 @@ static inline int sph_side_value(Point3d1 const& norm, Point3d2 const& pt)
template <typename CT, bool ReverseAzimuth, typename T1, typename T2>
static inline result_spherical<CT> spherical_azimuth(T1 const& lon1,
T1 const& lat1,
T2 const& lon2,
T2 const& lat2)
T1 const& lat1,
T2 const& lon2,
T2 const& lat2)
{
typedef result_spherical<CT> result_type;
result_type result;
@@ -114,12 +131,6 @@ static inline result_spherical<CT> spherical_azimuth(T1 const& lon1,
// http://williams.best.vwh.net/avform.htm#Crs
// https://en.wikipedia.org/wiki/Great-circle_navigation
CT dlon = lon2 - lon1;
CT cos_dlon = cos(dlon);
CT sin_dlon = sin(dlon);
CT cos_lat1 = cos(lat1);
CT cos_lat2 = cos(lat2);
CT sin_lat1 = sin(lat1);
CT sin_lat2 = sin(lat2);
// An optimization which should kick in often for Boxes
//if ( math::equals(dlon, ReturnType(0)) )
@@ -128,21 +139,84 @@ static inline result_spherical<CT> spherical_azimuth(T1 const& lon1,
// return - sin(get_as_radian<1>(p1)) * cos_p2lat);
//}
// "An alternative formula, not requiring the pre-computation of d"
// In the formula below dlon is used as "d"
result.azimuth = atan2(sin_dlon * cos_lat2,
cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon);
CT const cos_dlon = cos(dlon);
CT const sin_dlon = sin(dlon);
CT const cos_lat1 = cos(lat1);
CT const cos_lat2 = cos(lat2);
CT const sin_lat1 = sin(lat1);
CT const sin_lat2 = sin(lat2);
{
// "An alternative formula, not requiring the pre-computation of d"
// In the formula below dlon is used as "d"
CT const y = sin_dlon * cos_lat2;
CT const x = cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon;
result.azimuth = atan2(y, x);
}
if (ReverseAzimuth)
{
result.reverse_azimuth =
atan2(sin_dlon * cos_lat1,
sin_lat2 * cos_lat1 * cos_dlon - cos_lat2 * sin_lat1);
CT const y = sin_dlon * cos_lat1;
CT const x = sin_lat2 * cos_lat1 * cos_dlon - cos_lat2 * sin_lat1;
result.reverse_azimuth = atan2(y, x);
}
return result;
}
template <typename ReturnType, typename T1, typename T2>
inline ReturnType spherical_azimuth(T1 const& lon1, T1 const& lat1,
T2 const& lon2, T2 const& lat2)
{
return spherical_azimuth<ReturnType, false>(lon1, lat1, lon2, lat2).azimuth;
}
template <typename T>
inline T spherical_azimuth(T const& lon1, T const& lat1, T const& lon2, T const& lat2)
{
return spherical_azimuth<T, false>(lon1, lat1, lon2, lat2).azimuth;
}
template <typename T>
inline int azimuth_side_value(T const& azi_a1_p, T const& azi_a1_a2)
{
T const pi = math::pi<T>();
T const two_pi = math::two_pi<T>();
// instead of the formula from XTD
//calc_t a_diff = asin(sin(azi_a1_p - azi_a1_a2));
T a_diff = azi_a1_p - azi_a1_a2;
// normalize, angle in [-pi, pi]
while (a_diff > pi)
a_diff -= two_pi;
while (a_diff < -pi)
a_diff += two_pi;
// NOTE: in general it shouldn't be required to support the pi/-pi case
// because in non-cartesian systems it makes sense to check the side
// only "between" the endpoints.
// However currently the winding strategy calls the side strategy
// for vertical segments to check if the point is "between the endpoints.
// This could be avoided since the side strategy is not required for that
// because meridian is the shortest path. So a difference of
// longitudes would be sufficient (of course normalized to [-pi, pi]).
// NOTE: with the above said, the pi/-pi check is temporary
// however in case if this was required
// the geodesics on ellipsoid aren't "symmetrical"
// therefore instead of comparing a_diff to pi and -pi
// one should probably use inverse azimuths and compare
// the difference to 0 as well
// positive azimuth is on the right side
return math::equals(a_diff, 0)
|| math::equals(a_diff, pi)
|| math::equals(a_diff, -pi) ? 0
: a_diff > 0 ? -1 // right
: 1; // left
}
} // namespace formula
}} // namespace boost::geometry

View File

@@ -20,9 +20,8 @@
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/formulas/differential_quantities.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/result_direct.hpp>
@@ -82,7 +81,7 @@ public:
CT const a = CT(get_radius<0>(spheroid));
CT const b = CT(get_radius<2>(spheroid));
CT const f = detail::flattening<CT>(spheroid);
CT const f = formula::flattening<CT>(spheroid);
CT const one_minus_f = c1 - f;
CT const pi = math::pi<CT>();

View File

@@ -20,9 +20,8 @@
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/formulas/differential_quantities.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/result_inverse.hpp>
@@ -78,7 +77,7 @@ public:
CT const c4 = 4;
CT const pi_half = math::pi<CT>() / c2;
CT const f = detail::flattening<CT>(spheroid);
CT const f = formula::flattening<CT>(spheroid);
CT const one_minus_f = c1 - f;
// CT const tan_theta1 = one_minus_f * tan(lat1);

View File

@@ -12,9 +12,9 @@
#ifndef BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP
#define BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry { namespace formula
@@ -55,7 +55,7 @@ public:
T2 const& alp1,
Spheroid const& spheroid)
{
CT const f = detail::flattening<CT>(spheroid);
CT const f = formula::flattening<CT>(spheroid);
CT const e2 = f * (CT(2) - f);
CT const sin_alp1 = sin(alp1);
@@ -76,7 +76,7 @@ public:
T2 const& alp1,
Spheroid const& spheroid)
{
CT const f = detail::flattening<CT>(spheroid);
CT const f = formula::flattening<CT>(spheroid);
CT const one_minus_f = (CT(1) - f);

View File

@@ -23,9 +23,8 @@
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/formulas/differential_quantities.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/result_direct.hpp>
@@ -85,7 +84,7 @@ public:
CT const radius_a = CT(get_radius<0>(spheroid));
CT const radius_b = CT(get_radius<2>(spheroid));
CT const flattening = geometry::detail::flattening<CT>(spheroid);
CT const flattening = formula::flattening<CT>(spheroid);
CT const sin_azimuth12 = sin(azimuth12);
CT const cos_azimuth12 = cos(azimuth12);

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2016, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -23,9 +23,8 @@
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/formulas/differential_quantities.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/result_inverse.hpp>
@@ -41,7 +40,7 @@ namespace boost { namespace geometry { namespace formula
\brief The solution of the inverse problem of geodesics on latlong coordinates, after Vincenty, 1975
\author See
- http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
- http://www.icsm.gov.au/gda/gdav2.3.pdf
- http://www.icsm.gov.au/gda/gda-v_2.4.pdf
\author Adapted from various implementations to get it close to the original document
- http://www.movable-type.co.uk/scripts/LatLongVincenty.html
- http://exogen.case.edu/projects/geopy/source/geopy.distance.html
@@ -99,10 +98,10 @@ public:
CT const radius_a = CT(get_radius<0>(spheroid));
CT const radius_b = CT(get_radius<2>(spheroid));
CT const flattening = geometry::detail::flattening<CT>(spheroid);
CT const f = formula::flattening<CT>(spheroid);
// U: reduced latitude, defined by tan U = (1-f) tan phi
CT const one_min_f = c1 - flattening;
CT const one_min_f = c1 - f;
CT const tan_U1 = one_min_f * tan(lat1); // above (1)
CT const tan_U2 = one_min_f * tan(lat2); // above (1)
@@ -113,8 +112,9 @@ public:
CT const cos_U1 = c1 / temp_den_U1;
CT const cos_U2 = c1 / temp_den_U2;
// sin = tan / sqrt(1 + tan^2)
CT const sin_U1 = tan_U1 / temp_den_U1;
CT const sin_U2 = tan_U2 / temp_den_U2;
// sin = tan * cos
CT const sin_U1 = tan_U1 * cos_U1;
CT const sin_U2 = tan_U2 * cos_U2;
// calculate sin U and cos U directly
//CT const U1 = atan(tan_U1);
@@ -130,7 +130,8 @@ public:
CT sin_sigma;
CT sin_alpha;
CT cos2_alpha;
CT cos2_sigma_m;
CT cos_2sigma_m;
CT cos2_2sigma_m;
CT sigma;
int counter = 0; // robustness
@@ -144,12 +145,13 @@ public:
CT cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda; // (15)
sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma; // (17)
cos2_alpha = c1 - math::sqr(sin_alpha);
cos2_sigma_m = math::equals(cos2_alpha, 0) ? 0 : cos_sigma - c2 * sin_U1 * sin_U2 / cos2_alpha; // (18)
cos_2sigma_m = math::equals(cos2_alpha, 0) ? 0 : cos_sigma - c2 * sin_U1 * sin_U2 / cos2_alpha; // (18)
cos2_2sigma_m = math::sqr(cos_2sigma_m);
CT C = flattening/c16 * cos2_alpha * (c4 + flattening * (c4 - c3 * cos2_alpha)); // (10)
CT C = f/c16 * cos2_alpha * (c4 + f * (c4 - c3 * cos2_alpha)); // (10)
sigma = atan2(sin_sigma, cos_sigma); // (16)
lambda = L + (c1 - C) * flattening * sin_alpha *
(sigma + C * sin_sigma * ( cos2_sigma_m + C * cos_sigma * (-c1 + c2 * math::sqr(cos2_sigma_m)))); // (11)
lambda = L + (c1 - C) * f * sin_alpha *
(sigma + C * sin_sigma * (cos_2sigma_m + C * cos_sigma * (-c1 + c2 * cos2_2sigma_m))); // (11)
++counter; // robustness
@@ -182,8 +184,10 @@ public:
CT A = c1 + sqr_u/c16384 * (c4096 + sqr_u * (-c768 + sqr_u * (c320 - c175 * sqr_u))); // (3)
CT B = sqr_u/c1024 * (c256 + sqr_u * ( -c128 + sqr_u * (c74 - c47 * sqr_u))); // (4)
CT delta_sigma = B * sin_sigma * ( cos2_sigma_m + (B/c4) * (cos(sigma)* (-c1 + c2 * cos2_sigma_m)
- (B/c6) * cos2_sigma_m * (-c3 + c4 * math::sqr(sin_sigma)) * (-c3 + c4 * cos2_sigma_m))); // (6)
CT const cos_sigma = cos(sigma);
CT const sin2_sigma = math::sqr(sin_sigma);
CT delta_sigma = B * sin_sigma * (cos_2sigma_m + (B/c4) * (cos_sigma* (-c1 + c2 * cos2_2sigma_m)
- (B/c6) * cos_2sigma_m * (-c3 + c4 * sin2_sigma) * (-c3 + c4 * cos2_2sigma_m))); // (6)
result.distance = radius_b * A * (sigma - delta_sigma); // (19)
}
@@ -206,7 +210,7 @@ public:
typedef differential_quantities<CT, EnableReducedLength, EnableGeodesicScale, 2> quantities;
quantities::apply(lon1, lat1, lon2, lat2,
result.azimuth, result.reverse_azimuth,
radius_b, flattening,
radius_b, f,
result.reduced_length, result.geodesic_scale);
}

View File

@@ -0,0 +1,62 @@
// Boost.Geometry Index
//
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP
#include <algorithm>
namespace boost { namespace geometry { namespace index { namespace detail {
// See https://svn.boost.org/trac/boost/ticket/12861
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58800
// https://gcc.gnu.org/develop.html#timeline
// 20120920 4.7.2 - no bug
// 20130322 4.8.0 - no bug
// 20130411 4.7.3 - no bug
// 20130531 4.8.1 - no bug
// 20131016 4.8.2 - bug
// 20140422 4.9.0 - fixed
// 20140522 4.8.3 - fixed
// 20140612 4.7.4 - fixed
// 20140716 4.9.1 - fixed
#if defined(__GLIBCXX__) && (__GLIBCXX__ == 20131016)
#warning "std::nth_element replaced with std::sort, libstdc++ bug workaround.";
template <typename RandomIt>
void nth_element(RandomIt first, RandomIt , RandomIt last)
{
std::sort(first, last);
}
template <typename RandomIt, typename Compare>
void nth_element(RandomIt first, RandomIt , RandomIt last, Compare comp)
{
std::sort(first, last, comp);
}
#else
template <typename RandomIt>
void nth_element(RandomIt first, RandomIt nth, RandomIt last)
{
std::nth_element(first, nth, last);
}
template <typename RandomIt, typename Compare>
void nth_element(RandomIt first, RandomIt nth, RandomIt last, Compare comp)
{
std::nth_element(first, nth, last, comp);
}
#endif
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP

View File

@@ -2,7 +2,7 @@
//
// R-tree initial packing
//
// Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -13,6 +13,7 @@
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/index/detail/algorithms/bounds.hpp>
#include <boost/geometry/index/detail/algorithms/nth_element.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
@@ -67,7 +68,7 @@ struct nth_element_and_half_boxes
{
if ( I == dim_index )
{
std::nth_element(first, median, last, point_entries_comparer<I>());
index::detail::nth_element(first, median, last, point_entries_comparer<I>());
geometry::convert(box, left);
geometry::convert(box, right);

View File

@@ -2,7 +2,7 @@
//
// R-tree R*-tree next node choosing algorithm implementation
//
// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,6 +17,7 @@
#include <boost/geometry/index/detail/algorithms/content.hpp>
#include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
#include <boost/geometry/index/detail/algorithms/nth_element.hpp>
#include <boost/geometry/index/detail/algorithms/union_content.hpp>
#include <boost/geometry/index/detail/rtree/node/node.hpp>
@@ -112,7 +113,7 @@ private:
first_n_children_count = overlap_cost_threshold;
// rearrange by content_diff
// in order to calculate nearly minimum overlap cost
std::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less);
index::detail::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less);
}
// calculate minimum or nearly minimum overlap cost

View File

@@ -2,7 +2,7 @@
//
// R-tree R*-tree split algorithm implementation
//
// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -12,8 +12,9 @@
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
#include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
#include <boost/geometry/index/detail/algorithms/union_content.hpp>
#include <boost/geometry/index/detail/algorithms/margin.hpp>
#include <boost/geometry/index/detail/algorithms/nth_element.hpp>
#include <boost/geometry/index/detail/algorithms/union_content.hpp>
#include <boost/geometry/index/detail/bounded_view.hpp>
@@ -122,8 +123,9 @@ struct choose_split_axis_and_index_for_corner
// {
// typename Elements::iterator f = elements_copy.begin() + index_first;
// typename Elements::iterator l = elements_copy.begin() + index_last;
// std::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
// std::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
// // NOTE: for stdlibc++ shipped with gcc 4.8.2 std::nth_element is replaced with std::sort anyway
// index::detail::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
// index::detail::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
// std::sort(f, l, elements_less); // MAY THROW, BASIC (copy)
// }
@@ -349,7 +351,7 @@ struct nth_element
typedef typename tag<indexable_type>::type indexable_tag;
element_axis_corner_less<element_type, Translator, indexable_tag, Corner, I> less(tr);
std::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
index::detail::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
}
}
};

View File

@@ -2,7 +2,7 @@
//
// R-tree algorithms parameters
//
// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -162,8 +162,8 @@ public:
\param max_elements Maximum number of elements in nodes.
\param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
*/
dynamic_linear(size_t max_elements,
size_t min_elements = detail::default_min_elements_d())
explicit dynamic_linear(size_t max_elements,
size_t min_elements = detail::default_min_elements_d())
: m_max_elements(max_elements)
, m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
{
@@ -191,8 +191,8 @@ public:
\param max_elements Maximum number of elements in nodes.
\param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
*/
dynamic_quadratic(size_t max_elements,
size_t min_elements = detail::default_min_elements_d())
explicit dynamic_quadratic(size_t max_elements,
size_t min_elements = detail::default_min_elements_d())
: m_max_elements(max_elements)
, m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
{
@@ -228,10 +228,10 @@ public:
nearly minimum overlap cost, otherwise all leafs are analyzed
and true minimum overlap cost is calculated. Default: 32.
*/
dynamic_rstar(size_t max_elements,
size_t min_elements = detail::default_min_elements_d(),
size_t reinserted_elements = detail::default_rstar_reinserted_elements_d(),
size_t overlap_cost_threshold = 32)
explicit dynamic_rstar(size_t max_elements,
size_t min_elements = detail::default_min_elements_d(),
size_t reinserted_elements = detail::default_rstar_reinserted_elements_d(),
size_t overlap_cost_threshold = 32)
: m_max_elements(max_elements)
, m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
, m_reinserted_elements(detail::default_rstar_reinserted_elements_d_calc(max_elements, reinserted_elements))

View File

@@ -4,8 +4,8 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2016, 2017.
// Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -25,6 +25,7 @@
//#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

View File

@@ -34,6 +34,8 @@
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/intersection.hpp>
@@ -95,6 +97,39 @@ struct relate_cartesian_segments
return strategy_type();
}
template <typename Geometry>
struct area_strategy
{
typedef area::surveyor
<
typename point_type<Geometry>::type,
CalculationType
> type;
};
template <typename Geometry>
static inline typename area_strategy<Geometry>::type get_area_strategy()
{
typedef typename area_strategy<Geometry>::type strategy_type;
return strategy_type();
}
template <typename Geometry>
struct distance_strategy
{
typedef distance::pythagoras
<
CalculationType
> type;
};
template <typename Geometry>
static inline typename distance_strategy<Geometry>::type get_distance_strategy()
{
typedef typename distance_strategy<Geometry>::type strategy_type;
return strategy_type();
}
template <typename CoordinateType, typename SegmentRatio>
struct segment_intersection_info
{

View File

@@ -1,7 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016 Oracle and/or its affiliates.
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -11,6 +12,7 @@
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
#include <boost/geometry/formulas/area_formulas.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/thomas_inverse.hpp>
#include <boost/math/special_functions/atanh.hpp>
@@ -21,12 +23,26 @@ namespace strategy { namespace area
{
/*!
\brief Geographic area calculation by trapezoidal rule plus integral
approximation that gives the ellipsoidal correction
\brief Geographic area calculation
\ingroup strategies
\details Geographic area calculation by trapezoidal rule plus integral
approximation that gives the ellipsoidal correction
\tparam PointOfSegment \tparam_segment_point
\tparam Inverse Formula used to calculate azimuths
\tparam SeriesOrder The order of approximation of the geodesic integral
\tparam ExpandEpsN Switch between two kinds of approximation (series in eps and n v.s. series in k^2 and e'^2)
\tparam LongSegment Enables special handling of long segments
\tparam Spheroid The spheroid model
\tparam CalculationType \tparam_calculation
\author See
- Danielsen JS, The area under the geodesic. Surv Rev 30(232): 6166, 1989
- Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf
\qbk{
[heading See also]
[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
}
*/
template
<
typename PointOfSegment,
@@ -87,8 +103,8 @@ protected :
inline spheroid_constants(SpheroidType spheroid)
: m_spheroid(spheroid)
, m_a2(math::sqr(get_radius<0>(spheroid)))
, m_e2(detail::flattening<CT>(spheroid)
* (CT(2.0) - CT(detail::flattening<CT>(spheroid))))
, m_e2(formula::flattening<CT>(spheroid)
* (CT(2.0) - CT(formula::flattening<CT>(spheroid))))
, m_ep2(m_e2 / (CT(1.0) - m_e2))
, m_ep(math::sqrt(m_ep2))
, m_c2((m_a2 / CT(2.0)) +

View File

@@ -0,0 +1,194 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2016 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
template
<
template<typename, bool, bool, bool, bool, bool> class InverseFormula = formula::andoyer_inverse,
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class geographic
{
public :
template <typename Point1, typename Point2>
struct calculation_type
: promote_floating_point
<
typename select_calculation_type
<
Point1,
Point2,
CalculationType
>::type
>
{};
typedef Spheroid model_type;
inline geographic()
: m_spheroid()
{}
explicit inline geographic(Spheroid const& spheroid)
: m_spheroid(spheroid)
{}
template <typename Point1, typename Point2>
inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& point1, Point2 const& point2) const
{
return InverseFormula
<
typename calculation_type<Point1, Point2>::type,
true, false, false, false, false
>::apply(get_as_radian<0>(point1), get_as_radian<1>(point1),
get_as_radian<0>(point2), get_as_radian<1>(point2),
m_spheroid).distance;
}
inline Spheroid const& model() const
{
return m_spheroid;
}
private :
Spheroid m_spheroid;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template
<
template<typename, bool, bool, bool, bool, bool> class Formula,
typename Spheroid,
typename CalculationType
>
struct tag<geographic<Formula, Spheroid, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template
<
template<typename, bool, bool, bool, bool, bool> class Formula,
typename Spheroid,
typename CalculationType,
typename P1,
typename P2
>
struct return_type<geographic<Formula, Spheroid, CalculationType>, P1, P2>
: geographic<Formula, Spheroid, CalculationType>::template calculation_type<P1, P2>
{};
template
<
template<typename, bool, bool, bool, bool, bool> class Formula,
typename Spheroid,
typename CalculationType
>
struct comparable_type<geographic<Formula, Spheroid, CalculationType> >
{
typedef geographic<Formula, Spheroid, CalculationType> type;
};
template
<
template<typename, bool, bool, bool, bool, bool> class Formula,
typename Spheroid,
typename CalculationType
>
struct get_comparable<geographic<Formula, Spheroid, CalculationType> >
{
static inline geographic<Formula, Spheroid, CalculationType>
apply(geographic<Formula, Spheroid, CalculationType> const& input)
{
return input;
}
};
template
<
template<typename, bool, bool, bool, bool, bool> class Formula,
typename Spheroid,
typename CalculationType,
typename P1,
typename P2
>
struct result_from_distance<geographic<Formula, Spheroid, CalculationType>, P1, P2>
{
template <typename T>
static inline typename return_type<geographic<Formula, Spheroid, CalculationType>, P1, P2>::type
apply(geographic<Formula, Spheroid, CalculationType> const& , T const& value)
{
return value;
}
};
template <typename Point1, typename Point2>
struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, geographic_tag>
{
typedef strategy::distance::geographic
<
formula::andoyer_inverse,
srs::spheroid
<
typename select_coordinate_type<Point1, Point2>::type
>
> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2016 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -11,24 +11,13 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/algorithms/detail/flattening.hpp>
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
namespace boost { namespace geometry
@@ -61,51 +50,24 @@ template
typename CalculationType = void
>
class andoyer
: public strategy::distance::geographic
<
formula::andoyer_inverse, Spheroid, CalculationType
>
{
typedef strategy::distance::geographic
<
formula::andoyer_inverse, Spheroid, CalculationType
> base_type;
public :
template <typename Point1, typename Point2>
struct calculation_type
: promote_floating_point
<
typename select_calculation_type
<
Point1,
Point2,
CalculationType
>::type
>
{};
typedef Spheroid model_type;
inline andoyer()
: m_spheroid()
: base_type()
{}
explicit inline andoyer(Spheroid const& spheroid)
: m_spheroid(spheroid)
: base_type(spheroid)
{}
template <typename Point1, typename Point2>
inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& point1, Point2 const& point2) const
{
return geometry::formula::andoyer_inverse
<
typename calculation_type<Point1, Point2>::type,
true, false
>::apply(get_as_radian<0>(point1), get_as_radian<1>(point1),
get_as_radian<0>(point2), get_as_radian<1>(point2),
m_spheroid).distance;
}
inline Spheroid const& model() const
{
return m_spheroid;
}
private :
Spheroid m_spheroid;
};
@@ -154,19 +116,6 @@ struct result_from_distance<andoyer<Spheroid, CalculationType>, P1, P2>
};
template <typename Point1, typename Point2>
struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, geographic_tag>
{
typedef strategy::distance::andoyer
<
srs::spheroid
<
typename select_coordinate_type<Point1, Point2>::type
>
> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
@@ -177,4 +126,4 @@ struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, ge
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ANDOYER_HPP
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -15,16 +15,11 @@
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_THOMAS_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/formulas/thomas_inverse.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
namespace boost { namespace geometry
{
@@ -49,53 +44,24 @@ template
typename CalculationType = void
>
class thomas
: public strategy::distance::geographic
<
formula::thomas_inverse, Spheroid, CalculationType
>
{
typedef strategy::distance::geographic
<
formula::thomas_inverse, Spheroid, CalculationType
> base_type;
public :
template <typename Point1, typename Point2>
struct calculation_type
: promote_floating_point
<
typename select_calculation_type
<
Point1,
Point2,
CalculationType
>::type
>
{};
typedef Spheroid model_type;
inline thomas()
: m_spheroid()
: base_type()
{}
explicit inline thomas(Spheroid const& spheroid)
: m_spheroid(spheroid)
: base_type(spheroid)
{}
template <typename Point1, typename Point2>
inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& point1, Point2 const& point2) const
{
return geometry::formula::thomas_inverse
<
typename calculation_type<Point1, Point2>::type,
true, false
>::apply(get_as_radian<0>(point1),
get_as_radian<1>(point1),
get_as_radian<0>(point2),
get_as_radian<1>(point2),
m_spheroid).distance;
}
inline Spheroid const& model() const
{
return m_spheroid;
}
private :
Spheroid m_spheroid;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -15,16 +15,11 @@
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/formulas/vincenty_inverse.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
namespace boost { namespace geometry
{
@@ -51,53 +46,24 @@ template
typename CalculationType = void
>
class vincenty
: public strategy::distance::geographic
<
formula::vincenty_inverse, Spheroid, CalculationType
>
{
public :
template <typename Point1, typename Point2>
struct calculation_type
: promote_floating_point
<
typename select_calculation_type
<
Point1,
Point2,
CalculationType
>::type
>
{};
typedef Spheroid model_type;
typedef strategy::distance::geographic
<
formula::vincenty_inverse, Spheroid, CalculationType
> base_type;
public:
inline vincenty()
: m_spheroid()
: base_type()
{}
explicit inline vincenty(Spheroid const& spheroid)
: m_spheroid(spheroid)
: base_type(spheroid)
{}
template <typename Point1, typename Point2>
inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& point1, Point2 const& point2) const
{
return geometry::formula::vincenty_inverse
<
typename calculation_type<Point1, Point2>::type,
true, false
>::apply(get_as_radian<0>(point1),
get_as_radian<1>(point1),
get_as_radian<0>(point2),
get_as_radian<1>(point2),
m_spheroid).distance;
}
inline Spheroid const& model() const
{
return m_spheroid;
}
private :
Spheroid m_spheroid;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS

View File

@@ -0,0 +1,893 @@
// Boost.Geometry
// Copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_GEODESIC_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_GEODESIC_INTERSECTION_HPP
#include <algorithm>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/formulas/sjoberg_intersection.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/concepts/segment_concept.hpp>
#include <boost/geometry/policies/robustness/segment_ratio.hpp>
#include <boost/geometry/strategies/geographic/area_geographic.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
// CONSIDER: Improvement of the robustness/accuracy/repeatability by
// moving all segments to 0 longitude
// picking latitudes closer to 0
// etc.
template
<
typename Spheroid = srs::spheroid<double>,
template <typename, bool, bool, bool, bool, bool> class Inverse = formula::andoyer_inverse,
unsigned int Order = 2,
typename CalculationType = void
>
struct relate_geodesic_segments
{
typedef side::geographic
<
Inverse, Spheroid, CalculationType
> side_strategy_type;
inline side_strategy_type get_side_strategy()
{
return side_strategy_type(m_spheroid);
}
template <typename Geometry1, typename Geometry2>
struct point_in_geometry_strategy
{
typedef strategy::within::winding
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
side_strategy_type,
CalculationType
> type;
};
template <typename Geometry1, typename Geometry2>
inline typename point_in_geometry_strategy<Geometry1, Geometry2>::type
get_point_in_geometry_strategy()
{
typedef typename point_in_geometry_strategy
<
Geometry1, Geometry2
>::type strategy_type;
return strategy_type(get_side_strategy());
}
template <typename Geometry>
struct area_strategy
{
typedef area::geographic
<
typename point_type<Geometry>::type,
Inverse,
Order,
true,
false,
Spheroid,
CalculationType
> type;
};
template <typename Geometry>
inline typename area_strategy<Geometry>::type get_area_strategy()
{
typedef typename area_strategy<Geometry>::type strategy_type;
return strategy_type(m_spheroid);
}
template <typename Geometry>
struct distance_strategy
{
typedef distance::geographic<Inverse, Spheroid, CalculationType> type;
};
template <typename Geometry>
inline typename distance_strategy<Geometry>::type get_distance_strategy()
{
typedef typename distance_strategy<Geometry>::type strategy_type;
return strategy_type(m_spheroid);
}
enum intersection_point_flag { ipi_inters = 0, ipi_at_a1, ipi_at_a2, ipi_at_b1, ipi_at_b2 };
template <typename CoordinateType, typename SegmentRatio>
struct segment_intersection_info
{
typedef typename select_most_precise
<
CoordinateType, double
>::type promoted_type;
promoted_type comparable_length_a() const
{
return robust_ra.denominator();
}
promoted_type comparable_length_b() const
{
return robust_rb.denominator();
}
template <typename Point, typename Segment1, typename Segment2>
void assign_a(Point& point, Segment1 const& a, Segment2 const& b) const
{
assign(point, a, b);
}
template <typename Point, typename Segment1, typename Segment2>
void assign_b(Point& point, Segment1 const& a, Segment2 const& b) const
{
assign(point, a, b);
}
template <typename Point, typename Segment1, typename Segment2>
void assign(Point& point, Segment1 const& a, Segment2 const& b) const
{
if (ip_flag == ipi_inters)
{
// TODO: assign the rest of coordinates
set_from_radian<0>(point, lon);
set_from_radian<1>(point, lat);
}
else if (ip_flag == ipi_at_a1)
{
detail::assign_point_from_index<0>(a, point);
}
else if (ip_flag == ipi_at_a2)
{
detail::assign_point_from_index<1>(a, point);
}
else if (ip_flag == ipi_at_b1)
{
detail::assign_point_from_index<0>(b, point);
}
else // ip_flag == ipi_at_b2
{
detail::assign_point_from_index<1>(b, point);
}
}
CoordinateType lon;
CoordinateType lat;
SegmentRatio robust_ra;
SegmentRatio robust_rb;
intersection_point_flag ip_flag;
};
relate_geodesic_segments(Spheroid const& spheroid = Spheroid())
: m_spheroid(spheroid)
{}
// Relate segments a and b
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy
>
inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b,
Policy const& policy,
RobustPolicy const& robust_policy) const
{
typedef typename point_type<Segment1>::type point1_t;
typedef typename point_type<Segment2>::type point2_t;
point1_t a1, a2;
point2_t b1, b2;
detail::assign_point_from_index<0>(a, a1);
detail::assign_point_from_index<1>(a, a2);
detail::assign_point_from_index<0>(b, b1);
detail::assign_point_from_index<1>(b, b2);
return apply(a, b, policy, robust_policy, a1, a2, b1, b2);
}
// Relate segments a and b
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy,
typename Point1,
typename Point2
>
inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b,
Policy const&, RobustPolicy const&,
Point1 a1, Point1 a2, Point2 b1, Point2 b2) const
{
bool is_a_reversed = get<1>(a1) > get<1>(a2);
bool is_b_reversed = get<1>(b1) > get<1>(b2);
if (is_a_reversed)
{
std::swap(a1, a2);
}
if (is_b_reversed)
{
std::swap(b1, b2);
}
return apply<Policy>(a, b, a1, a2, b1, b2, is_a_reversed, is_b_reversed);
}
private:
// Relate segments a and b
template
<
typename Policy,
typename Segment1,
typename Segment2,
typename Point1,
typename Point2
>
inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b,
Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
bool is_a_reversed, bool is_b_reversed) const
{
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) );
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) );
typedef typename select_calculation_type
<Segment1, Segment2, CalculationType>::type calc_t;
// normalized spheroid
srs::spheroid<calc_t> spheroid = normalized_spheroid<calc_t>(m_spheroid);
// TODO: check only 2 first coordinates here?
using geometry::detail::equals::equals_point_point;
bool a_is_point = equals_point_point(a1, a2);
bool b_is_point = equals_point_point(b1, b2);
if(a_is_point && b_is_point)
{
return equals_point_point(a1, b2)
? Policy::degenerate(a, true)
: Policy::disjoint()
;
}
calc_t const a1_lon = get_as_radian<0>(a1);
calc_t const a1_lat = get_as_radian<1>(a1);
calc_t const a2_lon = get_as_radian<0>(a2);
calc_t const a2_lat = get_as_radian<1>(a2);
calc_t const b1_lon = get_as_radian<0>(b1);
calc_t const b1_lat = get_as_radian<1>(b1);
calc_t const b2_lon = get_as_radian<0>(b2);
calc_t const b2_lat = get_as_radian<1>(b2);
side_info sides;
// NOTE: potential optimization, don't calculate distance at this point
// this would require to reimplement inverse strategy to allow
// calculation of distance if needed, probably also storing intermediate
// results somehow inside an object.
typedef Inverse<calc_t, true, true, false, false, false> inverse_dist_azi;
typedef typename inverse_dist_azi::result_type inverse_result;
// TODO: no need to call inverse formula if we know that the points are equal
// distance can be set to 0 in this case and azimuth may be not calculated
bool const is_equal_a1_b1 = equals_point_point(a1, b1);
bool const is_equal_a2_b1 = equals_point_point(a2, b1);
inverse_result res_b1_b2 = inverse_dist_azi::apply(b1_lon, b1_lat, b2_lon, b2_lat, spheroid);
inverse_result res_b1_a1 = inverse_dist_azi::apply(b1_lon, b1_lat, a1_lon, a1_lat, spheroid);
inverse_result res_b1_a2 = inverse_dist_azi::apply(b1_lon, b1_lat, a2_lon, a2_lat, spheroid);
sides.set<0>(is_equal_a1_b1 ? 0 : formula::azimuth_side_value(res_b1_a1.azimuth, res_b1_b2.azimuth),
is_equal_a2_b1 ? 0 : formula::azimuth_side_value(res_b1_a2.azimuth, res_b1_b2.azimuth));
if (sides.same<0>())
{
// Both points are at the same side of other segment, we can leave
return Policy::disjoint();
}
bool const is_equal_a1_b2 = equals_point_point(a1, b2);
inverse_result res_a1_a2 = inverse_dist_azi::apply(a1_lon, a1_lat, a2_lon, a2_lat, spheroid);
inverse_result res_a1_b1 = inverse_dist_azi::apply(a1_lon, a1_lat, b1_lon, b1_lat, spheroid);
inverse_result res_a1_b2 = inverse_dist_azi::apply(a1_lon, a1_lat, b2_lon, b2_lat, spheroid);
sides.set<1>(is_equal_a1_b1 ? 0 : formula::azimuth_side_value(res_a1_b1.azimuth, res_a1_a2.azimuth),
is_equal_a1_b2 ? 0 : formula::azimuth_side_value(res_a1_b2.azimuth, res_a1_a2.azimuth));
if (sides.same<1>())
{
// Both points are at the same side of other segment, we can leave
return Policy::disjoint();
}
// NOTE: at this point the segments may still be disjoint
// NOTE: at this point one of the segments may be degenerated
bool collinear = sides.collinear();
if (! collinear)
{
// WARNING: the side strategy doesn't have the info about the other
// segment so it may return results inconsistent with this intersection
// strategy, as it checks both segments for consistency
if (sides.get<0, 0>() == 0 && sides.get<0, 1>() == 0)
{
collinear = true;
sides.set<1>(0, 0);
}
else if (sides.get<1, 0>() == 0 && sides.get<1, 1>() == 0)
{
collinear = true;
sides.set<0>(0, 0);
}
}
if (collinear)
{
if (a_is_point)
{
return collinear_one_degenerated<Policy, calc_t>(a, true, b1, b2, a1, a2, res_b1_b2, res_b1_a1, is_b_reversed);
}
else if (b_is_point)
{
return collinear_one_degenerated<Policy, calc_t>(b, false, a1, a2, b1, b2, res_a1_a2, res_a1_b1, is_a_reversed);
}
else
{
calc_t dist_a1_a2, dist_a1_b1, dist_a1_b2;
calc_t dist_b1_b2, dist_b1_a1, dist_b1_a2;
// use shorter segment
if (res_a1_a2.distance <= res_b1_b2.distance)
{
calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_b1, dist_a1_a2, dist_a1_b1);
calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_b2, dist_a1_a2, dist_a1_b2);
dist_b1_b2 = dist_a1_b2 - dist_a1_b1;
dist_b1_a1 = -dist_a1_b1;
dist_b1_a2 = dist_a1_a2 - dist_a1_b1;
}
else
{
calculate_collinear_data(b1, b2, a1, a2, res_b1_b2, res_b1_a1, dist_b1_b2, dist_b1_a1);
calculate_collinear_data(b1, b2, a1, a2, res_b1_b2, res_b1_a2, dist_b1_b2, dist_b1_a2);
dist_a1_a2 = dist_b1_a2 - dist_b1_a1;
dist_a1_b1 = -dist_b1_a1;
dist_a1_b2 = dist_b1_b2 - dist_b1_a1;
}
// NOTE: this is probably not needed
calc_t const c0 = 0;
int a1_on_b = position_value(c0, dist_a1_b1, dist_a1_b2);
int a2_on_b = position_value(dist_a1_a2, dist_a1_b1, dist_a1_b2);
int b1_on_a = position_value(c0, dist_b1_a1, dist_b1_a2);
int b2_on_a = position_value(dist_b1_b2, dist_b1_a1, dist_b1_a2);
if ((a1_on_b < 1 && a2_on_b < 1) || (a1_on_b > 3 && a2_on_b > 3))
{
return Policy::disjoint();
}
if (a1_on_b == 1)
{
dist_b1_a1 = 0;
dist_a1_b1 = 0;
}
else if (a1_on_b == 3)
{
dist_b1_a1 = dist_b1_b2;
dist_a1_b2 = 0;
}
if (a2_on_b == 1)
{
dist_b1_a2 = 0;
dist_a1_b1 = dist_a1_a2;
}
else if (a2_on_b == 3)
{
dist_b1_a2 = dist_b1_b2;
dist_a1_b2 = dist_a1_a2;
}
bool opposite = ! same_direction(res_a1_a2.azimuth, res_b1_b2.azimuth);
// NOTE: If segment was reversed opposite, positions and segment ratios has to be altered
if (is_a_reversed)
{
// opposite
opposite = ! opposite;
// positions
std::swap(a1_on_b, a2_on_b);
b1_on_a = 4 - b1_on_a;
b2_on_a = 4 - b2_on_a;
// distances for ratios
std::swap(dist_b1_a1, dist_b1_a2);
dist_a1_b1 = dist_a1_a2 - dist_a1_b1;
dist_a1_b2 = dist_a1_a2 - dist_a1_b2;
}
if (is_b_reversed)
{
// opposite
opposite = ! opposite;
// positions
a1_on_b = 4 - a1_on_b;
a2_on_b = 4 - a2_on_b;
std::swap(b1_on_a, b2_on_a);
// distances for ratios
dist_b1_a1 = dist_b1_b2 - dist_b1_a1;
dist_b1_a2 = dist_b1_b2 - dist_b1_a2;
std::swap(dist_a1_b1, dist_a1_b2);
}
segment_ratio<calc_t> ra_from(dist_b1_a1, dist_b1_b2);
segment_ratio<calc_t> ra_to(dist_b1_a2, dist_b1_b2);
segment_ratio<calc_t> rb_from(dist_a1_b1, dist_a1_a2);
segment_ratio<calc_t> rb_to(dist_a1_b2, dist_a1_a2);
return Policy::segments_collinear(a, b, opposite,
a1_on_b, a2_on_b, b1_on_a, b2_on_a,
ra_from, ra_to, rb_from, rb_to);
}
}
else // crossing or touching
{
if (a_is_point || b_is_point)
{
return Policy::disjoint();
}
calc_t lon = 0, lat = 0;
intersection_point_flag ip_flag;
calc_t dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1;
if (calculate_ip_data(a1, a2, b1, b2,
a1_lon, a1_lat, a2_lon, a2_lat,
b1_lon, b1_lat, b2_lon, b2_lat,
res_a1_a2, res_a1_b1, res_a1_b2,
res_b1_b2, res_b1_a1, res_b1_a2,
sides, spheroid,
lon, lat,
dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1,
ip_flag))
{
// NOTE: If segment was reversed sides and segment ratios has to be altered
if (is_a_reversed)
{
// sides
sides_reverse_segment<0>(sides);
// distance for ratio
dist_a1_i1 = dist_a1_a2 - dist_a1_i1;
// ip flag
ip_flag_reverse_segment(ip_flag, ipi_at_a1, ipi_at_a2);
}
if (is_b_reversed)
{
// sides
sides_reverse_segment<1>(sides);
// distance for ratio
dist_b1_i1 = dist_b1_b2 - dist_b1_i1;
// ip flag
ip_flag_reverse_segment(ip_flag, ipi_at_b1, ipi_at_b2);
}
// intersects
segment_intersection_info
<
calc_t,
segment_ratio<calc_t>
> sinfo;
sinfo.lon = lon;
sinfo.lat = lat;
sinfo.robust_ra.assign(dist_a1_i1, dist_a1_a2);
sinfo.robust_rb.assign(dist_b1_i1, dist_b1_b2);
sinfo.ip_flag = ip_flag;
return Policy::segments_crosses(sides, sinfo, a, b);
}
else
{
return Policy::disjoint();
}
}
}
template <typename Policy, typename CalcT, typename Segment, typename Point1, typename Point2, typename ResultInverse>
static inline typename Policy::return_type
collinear_one_degenerated(Segment const& segment, bool degenerated_a,
Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
ResultInverse const& res_a1_a2,
ResultInverse const& res_a1_bi,
bool is_other_reversed)
{
CalcT dist_1_2, dist_1_o;
if (! calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_bi, dist_1_2, dist_1_o))
{
return Policy::disjoint();
}
// NOTE: If segment was reversed segment ratio has to be altered
if (is_other_reversed)
{
// distance for ratio
dist_1_o = dist_1_2 - dist_1_o;
}
return Policy::one_degenerate(segment, segment_ratio<CalcT>(dist_1_o, dist_1_2), degenerated_a);
}
// TODO: instead of checks below test bi against a1 and a2 here?
// in order to make this independent from is_near()
template <typename Point1, typename Point2, typename ResultInverse, typename CalcT>
static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
ResultInverse const& res_a1_a2, // in
ResultInverse const& res_a1_bi, // in
CalcT& dist_a1_a2, CalcT& dist_a1_bi) // out
{
dist_a1_a2 = res_a1_a2.distance;
dist_a1_bi = res_a1_bi.distance;
if (! same_direction(res_a1_bi.azimuth, res_a1_a2.azimuth))
{
dist_a1_bi = -dist_a1_bi;
}
// if i1 is close to a1 and b1 or b2 is equal to a1
if (is_endpoint_equal(dist_a1_bi, a1, b1, b2))
{
dist_a1_bi = 0;
return true;
}
// or i1 is close to a2 and b1 or b2 is equal to a2
else if (is_endpoint_equal(dist_a1_a2 - dist_a1_bi, a2, b1, b2))
{
dist_a1_bi = dist_a1_a2;
return true;
}
// or i1 is on b
return segment_ratio<CalcT>(dist_a1_bi, dist_a1_a2).on_segment();
}
template <typename Point1, typename Point2, typename CalcT, typename ResultInverse, typename Spheroid_>
static inline bool calculate_ip_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
CalcT const& a1_lon, CalcT const& a1_lat, // in
CalcT const& a2_lon, CalcT const& a2_lat, // in
CalcT const& b1_lon, CalcT const& b1_lat, // in
CalcT const& b2_lon, CalcT const& b2_lat, // in
ResultInverse const& res_a1_a2, // in
ResultInverse const& res_a1_b1, // in
ResultInverse const& res_a1_b2, // in
ResultInverse const& res_b1_b2, // in
ResultInverse const& res_b1_a1, // in
ResultInverse const& res_b1_a2, // in
side_info const& sides, // in
Spheroid_ const& spheroid, // in
CalcT & lon, CalcT & lat, // out
CalcT& dist_a1_a2, CalcT& dist_a1_ip, // out
CalcT& dist_b1_b2, CalcT& dist_b1_ip, // out
intersection_point_flag& ip_flag) // out
{
dist_a1_a2 = res_a1_a2.distance;
dist_b1_b2 = res_b1_b2.distance;
// assign the IP if some endpoints overlap
using geometry::detail::equals::equals_point_point;
if (equals_point_point(a1, b1))
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
dist_b1_ip = 0;
ip_flag = ipi_at_a1;
return true;
}
else if (equals_point_point(a1, b2))
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
dist_b1_ip = dist_b1_b2;
ip_flag = ipi_at_a1;
return true;
}
else if (equals_point_point(a2, b1))
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = dist_a1_a2;
dist_b1_ip = 0;
ip_flag = ipi_at_a2;
return true;
}
else if (equals_point_point(a2, b2))
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = dist_a1_a2;
dist_b1_ip = dist_b1_b2;
ip_flag = ipi_at_a2;
return true;
}
// at this point we know that the endpoints doesn't overlap
// check cases when an endpoint lies on the other geodesic
if (sides.template get<0, 0>() == 0) // a1 wrt b
{
if (res_b1_a1.distance <= res_b1_b2.distance
&& same_direction(res_b1_a1.azimuth, res_b1_b2.azimuth))
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
dist_b1_ip = res_b1_a1.distance;
ip_flag = ipi_at_a1;
return true;
}
else
{
return false;
}
}
else if (sides.template get<0, 1>() == 0) // a2 wrt b
{
if (res_b1_a2.distance <= res_b1_b2.distance
&& same_direction(res_b1_a2.azimuth, res_b1_b2.azimuth))
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = res_a1_a2.distance;
dist_b1_ip = res_b1_a2.distance;
ip_flag = ipi_at_a2;
return true;
}
else
{
return false;
}
}
else if (sides.template get<1, 0>() == 0) // b1 wrt a
{
if (res_a1_b1.distance <= res_a1_a2.distance
&& same_direction(res_a1_b1.azimuth, res_a1_a2.azimuth))
{
lon = b1_lon;
lat = b1_lat;
dist_a1_ip = res_a1_b1.distance;
dist_b1_ip = 0;
ip_flag = ipi_at_b1;
return true;
}
else
{
return false;
}
}
else if (sides.template get<1, 1>() == 0) // b2 wrt a
{
if (res_a1_b2.distance <= res_a1_a2.distance
&& same_direction(res_a1_b2.azimuth, res_a1_a2.azimuth))
{
lon = b2_lon;
lat = b2_lat;
dist_a1_ip = res_a1_b2.distance;
dist_b1_ip = res_b1_b2.distance;
ip_flag = ipi_at_b2;
return true;
}
else
{
return false;
}
}
// At this point neither the endpoints overlaps
// nor any andpoint lies on the other geodesic
// So the endpoints should lie on the opposite sides of both geodesics
bool const ok = formula::sjoberg_intersection<CalcT, Inverse, Order>::apply(
a1_lon, a1_lat, a2_lon, a2_lat, res_a1_a2.azimuth,
b1_lon, b1_lat, b2_lon, b2_lat, res_b1_b2.azimuth,
lon, lat, spheroid);
if (! ok)
{
return false;
}
typedef Inverse<CalcT, true, true, false, false, false> inverse_dist_azi;
typedef typename inverse_dist_azi::result_type inverse_result;
inverse_result const res_a1_ip = inverse_dist_azi::apply(a1_lon, a1_lat, lon, lat, spheroid);
dist_a1_ip = res_a1_ip.distance;
if (! same_direction(res_a1_ip.azimuth, res_a1_a2.azimuth))
{
dist_a1_ip = -dist_a1_ip;
}
bool is_on_a = segment_ratio<CalcT>(dist_a1_ip, dist_a1_a2).on_segment();
// NOTE: not fully consistent with equals_point_point() since radians are always used.
bool is_on_a1 = math::equals(lon, a1_lon) && math::equals(lat, a1_lat);
bool is_on_a2 = math::equals(lon, a2_lon) && math::equals(lat, a2_lat);
if (! (is_on_a || is_on_a1 || is_on_a2))
{
return false;
}
inverse_result const res_b1_ip = inverse_dist_azi::apply(b1_lon, b1_lat, lon, lat, spheroid);
dist_b1_ip = res_b1_ip.distance;
if (! same_direction(res_b1_ip.azimuth, res_b1_b2.azimuth))
{
dist_b1_ip = -dist_b1_ip;
}
bool is_on_b = segment_ratio<CalcT>(dist_b1_ip, dist_b1_b2).on_segment();
// NOTE: not fully consistent with equals_point_point() since radians are always used.
bool is_on_b1 = math::equals(lon, b1_lon) && math::equals(lat, b1_lat);
bool is_on_b2 = math::equals(lon, b2_lon) && math::equals(lat, b2_lat);
if (! (is_on_b || is_on_b1 || is_on_b2))
{
return false;
}
ip_flag = ipi_inters;
if (is_on_b1)
{
lon = b1_lon;
lat = b1_lat;
dist_b1_ip = 0;
ip_flag = ipi_at_b1;
}
else if (is_on_b2)
{
lon = b2_lon;
lat = b2_lat;
dist_b1_ip = res_b1_b2.distance;
ip_flag = ipi_at_b2;
}
if (is_on_a1)
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
ip_flag = ipi_at_a1;
}
else if (is_on_a2)
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = res_a1_a2.distance;
ip_flag = ipi_at_a2;
}
return true;
}
template <typename CalcT, typename P1, typename P2>
static inline bool is_endpoint_equal(CalcT const& dist,
P1 const& ai, P2 const& b1, P2 const& b2)
{
using geometry::detail::equals::equals_point_point;
return is_near(dist) && (equals_point_point(ai, b1) || equals_point_point(ai, b2));
}
template <typename CalcT>
static inline bool is_near(CalcT const& dist)
{
// NOTE: This strongly depends on the Inverse method
CalcT const small_number = CalcT(boost::is_same<CalcT, float>::value ? 0.0001 : 0.00000001);
return math::abs(dist) <= small_number;
}
template <typename ProjCoord1, typename ProjCoord2>
static inline int position_value(ProjCoord1 const& ca1,
ProjCoord2 const& cb1,
ProjCoord2 const& cb2)
{
// S1x 0 1 2 3 4
// S2 |---------->
return math::equals(ca1, cb1) ? 1
: math::equals(ca1, cb2) ? 3
: cb1 < cb2 ?
( ca1 < cb1 ? 0
: ca1 > cb2 ? 4
: 2 )
: ( ca1 > cb1 ? 0
: ca1 < cb2 ? 4
: 2 );
}
template <typename CalcT>
static inline bool same_direction(CalcT const& azimuth1, CalcT const& azimuth2)
{
// distance between two angles normalized to (-180, 180]
CalcT const angle_diff = math::longitude_distance_signed<radian>(azimuth1, azimuth2);
return math::abs(angle_diff) <= math::half_pi<CalcT>();
}
template <int Which>
static inline void sides_reverse_segment(side_info & sides)
{
// names assuming segment A is reversed (Which == 0)
int a1_wrt_b = sides.template get<Which, 0>();
int a2_wrt_b = sides.template get<Which, 1>();
std::swap(a1_wrt_b, a2_wrt_b);
sides.template set<Which>(a1_wrt_b, a2_wrt_b);
int b1_wrt_a = sides.template get<1 - Which, 0>();
int b2_wrt_a = sides.template get<1 - Which, 1>();
sides.template set<1 - Which>(-b1_wrt_a, -b2_wrt_a);
}
static inline void ip_flag_reverse_segment(intersection_point_flag & ip_flag,
intersection_point_flag const& ipi_at_p1,
intersection_point_flag const& ipi_at_p2)
{
ip_flag = ip_flag == ipi_at_p1 ? ipi_at_p2 :
ip_flag == ipi_at_p2 ? ipi_at_p1 :
ip_flag;
}
template <typename CalcT, typename SpheroidT>
static inline srs::spheroid<CalcT> normalized_spheroid(SpheroidT const& spheroid)
{
return srs::spheroid<CalcT>(CalcT(1),
CalcT(get_radius<2>(spheroid)) // b/a
/ CalcT(get_radius<0>(spheroid)));
}
private:
Spheroid m_spheroid;
};
}} // namespace strategy::intersection
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_GEODESIC_INTERSECTION_HPP

View File

@@ -0,0 +1,235 @@
// Boost.Geometry
// Copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/geographic.hpp>
#include <boost/geometry/strategies/spherical/intersection.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
template <typename Spheroid>
struct relate_great_elliptic_segments_calc_policy
: relate_spherical_segments_calc_policy
{
explicit relate_great_elliptic_segments_calc_policy(Spheroid const& spheroid = Spheroid())
: m_spheroid(spheroid)
{}
template <typename Point, typename Point3d>
Point from_cart3d(Point3d const& point_3d) const
{
return formula::cart3d_to_geo<Point>(point_3d, m_spheroid);
}
template <typename Point3d, typename Point>
Point3d to_cart3d(Point const& point) const
{
return formula::geo_to_cart3d<Point3d>(point, m_spheroid);
}
// relate_xxx_calc_policy must live londer than plane because it contains
// Spheroid object and plane keeps the reference to that object.
template <typename Point3d>
struct plane
{
typedef typename coordinate_type<Point3d>::type coord_t;
// not normalized
plane(Point3d const& p1, Point3d const& p2)
: normal(cross_product(p1, p2))
{}
int side_value(Point3d const& pt) const
{
return formula::sph_side_value(normal, pt);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2) const
{
Point3d v1 = p1;
detail::vec_normalize(v1);
Point3d v2 = p2;
detail::vec_normalize(v2);
return dot_product(v1, v2);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const
{
coord_t const c0 = 0;
Point3d v1 = p1;
detail::vec_normalize(v1);
Point3d v2 = p2;
detail::vec_normalize(v2);
is_forward = dot_product(normal, cross_product(v1, v2)) >= c0;
return dot_product(v1, v2);
}
Point3d normal;
};
template <typename Point3d>
plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2) const
{
return plane<Point3d>(p1, p2);
}
template <typename Point3d>
bool intersection_points(plane<Point3d> const& plane1,
plane<Point3d> const& plane2,
Point3d & ip1, Point3d & ip2) const
{
typedef typename coordinate_type<Point3d>::type coord_t;
Point3d id = cross_product(plane1.normal, plane2.normal);
// NOTE: the length should be greater than 0 at this point
// NOTE: no need to normalize in this case
ip1 = formula::projected_to_surface(id, m_spheroid);
ip2 = ip1;
multiply_value(ip2, coord_t(-1));
return true;
}
private:
Spheroid m_spheroid;
};
template <typename Spheroid>
struct relate_experimental_elliptic_segments_calc_policy
{
explicit relate_experimental_elliptic_segments_calc_policy(Spheroid const& spheroid = Spheroid())
: m_spheroid(spheroid)
{}
template <typename Point, typename Point3d>
Point from_cart3d(Point3d const& point_3d) const
{
return formula::cart3d_to_geo<Point>(point_3d, m_spheroid);
}
template <typename Point3d, typename Point>
Point3d to_cart3d(Point const& point) const
{
return formula::geo_to_cart3d<Point3d>(point, m_spheroid);
}
// relate_xxx_calc_policy must live londer than plane because it contains
// Spheroid object and plane keeps the reference to that object.
template <typename Point3d>
struct plane
{
typedef typename coordinate_type<Point3d>::type coord_t;
// not normalized
plane(Point3d const& p1, Point3d const& p2, Spheroid const& spheroid)
: m_spheroid(spheroid)
{
formula::experimental_elliptic_plane(p1, p2, origin, normal, m_spheroid);
}
int side_value(Point3d const& pt) const
{
return formula::elliptic_side_value(origin, normal, pt);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2) const
{
Point3d const v1 = normalized_vec(p1);
Point3d const v2 = normalized_vec(p2);
return dot_product(v1, v2);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const
{
coord_t const c0 = 0;
Point3d const v1 = normalized_vec(p1);
Point3d const v2 = normalized_vec(p2);
is_forward = dot_product(normal, cross_product(v1, v2)) >= c0;
return dot_product(v1, v2);
}
Point3d origin;
Point3d normal;
private:
Point3d normalized_vec(Point3d const& p) const
{
Point3d v = p;
subtract_point(v, origin);
detail::vec_normalize(v);
return v;
}
Spheroid const& m_spheroid;
};
template <typename Point3d>
plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2) const
{
return plane<Point3d>(p1, p2, m_spheroid);
}
template <typename Point3d>
bool intersection_points(plane<Point3d> const& plane1,
plane<Point3d> const& plane2,
Point3d & ip1, Point3d & ip2) const
{
return formula::planes_spheroid_intersection(plane1.origin, plane1.normal,
plane2.origin, plane2.normal,
ip1, ip2, m_spheroid);
}
private:
Spheroid m_spheroid;
};
template <typename Spheroid = srs::spheroid<double>, typename CalculationType = void>
struct relate_great_elliptic_segments
: relate_ecef_segments
<
relate_great_elliptic_segments_calc_policy<Spheroid>,
CalculationType
>
{};
template <typename Spheroid = srs::spheroid<double>, typename CalculationType = void>
struct relate_experimental_elliptic_segments
: relate_ecef_segments
<
relate_experimental_elliptic_segments_calc_policy<Spheroid>,
CalculationType
>
{};
}} // namespace strategy::intersection
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2015, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -11,14 +11,16 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_DETAIL_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_DETAIL_HPP
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
@@ -34,9 +36,6 @@ namespace boost { namespace geometry
namespace strategy { namespace side
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/*!
\brief Check at which side of a segment a point lies
@@ -49,10 +48,13 @@ namespace detail
template <template<typename, bool, bool, bool, bool, bool> class InverseFormula,
typename Model,
typename CalculationType = void>
class by_azimuth
class geographic
{
public:
by_azimuth(Model const& model = Model())
geographic()
{}
explicit geographic(Model const& model)
: m_model(model)
{}
@@ -73,40 +75,7 @@ public:
calc_t a1p = azimuth<calc_t, inverse_formula>(p1, p, m_model);
calc_t a12 = azimuth<calc_t, inverse_formula>(p1, p2, m_model);
calc_t const pi = math::pi<calc_t>();
// instead of the formula from XTD
//calc_t a_diff = asin(sin(a1p - a12));
calc_t a_diff = a1p - a12;
// normalize, angle in [-pi, pi]
while ( a_diff > pi )
a_diff -= calc_t(2) * pi;
while ( a_diff < -pi )
a_diff += calc_t(2) * pi;
// NOTE: in general it shouldn't be required to support the pi/-pi case
// because in non-cartesian systems it makes sense to check the side
// only "between" the endpoints.
// However currently the winding strategy calls the side strategy
// for vertical segments to check if the point is "between the endpoints.
// This could be avoided since the side strategy is not required for that
// because meridian is the shortest path. So a difference of
// longitudes would be sufficient (of course normalized to [-pi, pi]).
// NOTE: with the above said, the pi/-pi check is temporary
// however in case if this was required
// the geodesics on ellipsoid aren't "symmetrical"
// therefore instead of comparing a_diff to pi and -pi
// one should probably use inverse azimuths and compare
// the difference to 0 as well
// positive azimuth is on the right side
return math::equals(a_diff, 0)
|| math::equals(a_diff, pi)
|| math::equals(a_diff, -pi) ? 0
: a_diff > 0 ? -1 // right
: 1; // left
return formula::azimuth_side_value(a1p, a12);
}
private:
@@ -127,8 +96,6 @@ private:
Model m_model;
};
} // detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace strategy::side
@@ -136,4 +103,4 @@ private:
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_DETAIL_HPP
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2015, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -17,7 +17,7 @@
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/strategies/geographic/side_detail.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
namespace boost { namespace geometry
@@ -36,12 +36,15 @@ namespace strategy { namespace side
*/
template <typename Model, typename CalculationType = void>
class andoyer
: public detail::by_azimuth<geometry::formula::andoyer_inverse, Model, CalculationType>
: public side::geographic<formula::andoyer_inverse, Model, CalculationType>
{
typedef detail::by_azimuth<geometry::formula::andoyer_inverse, Model, CalculationType> base_t;
typedef side::geographic<formula::andoyer_inverse, Model, CalculationType> base_t;
public:
andoyer(Model const& model = Model())
andoyer()
{}
explicit andoyer(Model const& model)
: base_t(model)
{}
};

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2015, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -17,7 +17,7 @@
#include <boost/geometry/formulas/thomas_inverse.hpp>
#include <boost/geometry/strategies/geographic/side_detail.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
namespace boost { namespace geometry
@@ -36,12 +36,15 @@ namespace strategy { namespace side
*/
template <typename Model, typename CalculationType = void>
class thomas
: public detail::by_azimuth<geometry::formula::thomas_inverse, Model, CalculationType>
: public side::geographic<formula::thomas_inverse, Model, CalculationType>
{
typedef detail::by_azimuth<geometry::formula::thomas_inverse, Model, CalculationType> base_t;
typedef side::geographic<formula::thomas_inverse, Model, CalculationType> base_t;
public:
thomas(Model const& model = Model())
thomas()
{}
explicit thomas(Model const& model)
: base_t(model)
{}
};

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2015, 2016.
// Modifications copyright (c) 2014-2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -17,7 +17,7 @@
#include <boost/geometry/formulas/vincenty_inverse.hpp>
#include <boost/geometry/strategies/geographic/side_detail.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
namespace boost { namespace geometry
@@ -36,12 +36,15 @@ namespace strategy { namespace side
*/
template <typename Model, typename CalculationType = void>
class vincenty
: public detail::by_azimuth<geometry::formula::vincenty_inverse, Model, CalculationType>
: public side::geographic<formula::vincenty_inverse, Model, CalculationType>
{
typedef detail::by_azimuth<geometry::formula::vincenty_inverse, Model, CalculationType> base_t;
typedef side::geographic<formula::vincenty_inverse, Model, CalculationType> base_t;
public:
vincenty(Model const& model = Model())
vincenty()
{}
explicit vincenty(Model const& model)
: base_t(model)
{}
};

View File

@@ -1,7 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016 Oracle and/or its affiliates.
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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,9 +11,12 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_SPHERICAL_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_SPHERICAL_HPP
#include <boost/geometry/formulas/area_formulas.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/strategies/area.hpp>
namespace boost { namespace geometry
{
@@ -21,10 +25,17 @@ namespace strategy { namespace area
{
/*!
\brief Spherical area calculation by trapezoidal rule
\brief Spherical area calculation
\ingroup strategies
\details Calculates area on the surface of a sphere using the trapezoidal rule
\tparam PointOfSegment \tparam_segment_point
\tparam LongSegment Enables special handling of long segments
\tparam CalculationType \tparam_calculation
\qbk{
[heading See also]
[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
}
*/
template
<
@@ -102,7 +113,7 @@ public :
inline spherical(CT radius) //backward compatibility
: m_sphere()
{
m_sphere.set_radius<0>(radius);
geometry::set_radius<0>(m_sphere, radius);
}
inline void apply(PointOfSegment const& p1,

View File

@@ -25,6 +25,7 @@
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/cross_product.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/arithmetic/normalize.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
@@ -38,6 +39,8 @@
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/strategies/spherical/area_spherical.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/strategies/within.hpp>
@@ -73,8 +76,8 @@ namespace strategy { namespace intersection
// For now, intersection points near the endpoints are checked explicitly if needed (if the IP is near the endpoint)
// to generate precise result for them. Only the crossing (i) case may suffer from lower precision.
template <typename CalculationType = void>
struct relate_spherical_segments
template <typename CalcPolicy, typename CalculationType = void>
struct relate_ecef_segments
{
typedef side::spherical_side_formula<CalculationType> side_strategy_type;
@@ -106,8 +109,44 @@ struct relate_spherical_segments
return strategy_type();
}
template <typename Geometry>
struct area_strategy
{
typedef area::spherical
<
typename point_type<Geometry>::type,
false,
CalculationType
> type;
};
template <typename Geometry>
static inline typename area_strategy<Geometry>::type get_area_strategy()
{
typedef typename area_strategy<Geometry>::type strategy_type;
return strategy_type();
}
template <typename Geometry>
struct distance_strategy
{
typedef distance::haversine
<
typename coordinate_type<Geometry>::type,
CalculationType
> type;
};
template <typename Geometry>
static inline typename distance_strategy<Geometry>::type get_distance_strategy()
{
typedef typename distance_strategy<Geometry>::type strategy_type;
return strategy_type();
}
enum intersection_point_flag { ipi_inters = 0, ipi_at_a1, ipi_at_a2, ipi_at_b1, ipi_at_b2 };
// segment_intersection_info cannot outlive relate_ecef_segments
template <typename CoordinateType, typename SegmentRatio, typename Vector3d>
struct segment_intersection_info
{
@@ -116,6 +155,10 @@ struct relate_spherical_segments
CoordinateType, double
>::type promoted_type;
segment_intersection_info(CalcPolicy const& calc)
: calc_policy(calc)
{}
promoted_type comparable_length_a() const
{
return robust_ra.denominator();
@@ -143,7 +186,7 @@ struct relate_spherical_segments
if (ip_flag == ipi_inters)
{
// TODO: assign the rest of coordinates
point = formula::cart3d_to_sph<Point>(intersection_point);
point = calc_policy.template from_cart3d<Point>(intersection_point);
}
else if (ip_flag == ipi_at_a1)
{
@@ -167,6 +210,8 @@ struct relate_spherical_segments
SegmentRatio robust_ra;
SegmentRatio robust_rb;
intersection_point_flag ip_flag;
CalcPolicy const& calc_policy;
};
// Relate segments a and b
@@ -210,6 +255,12 @@ struct relate_spherical_segments
Policy const&, RobustPolicy const&,
Point1 const& a1, Point1 const& a2, Point2 const& b1, Point2 const& b2)
{
// For now create it using default constructor. In the future it could
// be stored in strategy. However then apply() wouldn't be static and
// all relops and setops would have to take the strategy or model.
// Initialize explicitly to prevent compiler errors in case of PoD type
CalcPolicy const calc_policy = CalcPolicy();
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) );
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) );
@@ -234,25 +285,29 @@ struct relate_spherical_segments
typedef model::point<calc_t, 3, cs::cartesian> vec3d_t;
using namespace formula;
vec3d_t const a1v = sph_to_cart3d<vec3d_t>(a1);
vec3d_t const a2v = sph_to_cart3d<vec3d_t>(a2);
vec3d_t const b1v = sph_to_cart3d<vec3d_t>(b1);
vec3d_t const b2v = sph_to_cart3d<vec3d_t>(b2);
vec3d_t const a1v = calc_policy.template to_cart3d<vec3d_t>(a1);
vec3d_t const a2v = calc_policy.template to_cart3d<vec3d_t>(a2);
vec3d_t const b1v = calc_policy.template to_cart3d<vec3d_t>(b1);
vec3d_t const b2v = calc_policy.template to_cart3d<vec3d_t>(b2);
vec3d_t norm1 = cross_product(a1v, a2v);
vec3d_t norm2 = cross_product(b1v, b2v);
side_info sides;
// not normalized normals, the same as in SSF
sides.set<0>(sph_side_value(norm2, a1v), sph_side_value(norm2, a2v));
typename CalcPolicy::template plane<vec3d_t>
plane2 = calc_policy.get_plane(b1v, b2v);
// not normalized normals, the same as in side strategy
sides.set<0>(plane2.side_value(a1v), plane2.side_value(a2v));
if (sides.same<0>())
{
// Both points are at same side of other segment, we can leave
return Policy::disjoint();
}
// not normalized normals, the same as in SSF
sides.set<1>(sph_side_value(norm1, b1v), sph_side_value(norm1, b2v));
typename CalcPolicy::template plane<vec3d_t>
plane1 = calc_policy.get_plane(a1v, a2v);
// not normalized normals, the same as in side strategy
sides.set<1>(plane1.side_value(b1v), plane1.side_value(b2v));
if (sides.same<1>())
{
// Both points are at same side of other segment, we can leave
@@ -261,13 +316,10 @@ struct relate_spherical_segments
// NOTE: at this point the segments may still be disjoint
bool collinear = sides.collinear();
calc_t len1, len2;
calc_t const len1 = math::sqrt(dot_product(norm1, norm1));
calc_t const len2 = math::sqrt(dot_product(norm2, norm2));
// point or opposite sides of a sphere, assume point
if (math::equals(len1, c0))
// point or opposite sides of a sphere/spheroid, assume point
if (! detail::vec_normalize(plane1.normal, len1))
{
a_is_point = true;
if (sides.get<0, 0>() == 0 || sides.get<0, 1>() == 0)
@@ -275,13 +327,8 @@ struct relate_spherical_segments
sides.set<0>(0, 0);
}
}
else
{
// normalize
divide_value(norm1, len1);
}
if (math::equals(len2, c0))
if (! detail::vec_normalize(plane2.normal, len2))
{
b_is_point = true;
if (sides.get<1, 0>() == 0 || sides.get<1, 1>() == 0)
@@ -289,11 +336,6 @@ struct relate_spherical_segments
sides.set<1>(0, 0);
}
}
else
{
// normalize
divide_value(norm2, len2);
}
// check both degenerated once more
if (a_is_point && b_is_point)
@@ -304,16 +346,42 @@ struct relate_spherical_segments
;
}
// NOTE: at this point the segments may still be disjoint
// NOTE: at this point one of the segments may be degenerated
// and the segments may still be disjoint
calc_t dot_n1n2 = dot_product(norm1, norm2);
bool collinear = sides.collinear();
if (! collinear)
{
// NOTE: for some approximations it's possible that both points may lie
// on the same geodesic but still some of the sides may be != 0.
// This is e.g. true for long segments represented as elliptic arcs
// with origin different than the center of the coordinate system.
// So make the sides consistent
// WARNING: the side strategy doesn't have the info about the other
// segment so it may return results inconsistent with this intersection
// strategy, as it checks both segments for consistency
if (sides.get<0, 0>() == 0 && sides.get<0, 1>() == 0)
{
collinear = true;
sides.set<1>(0, 0);
}
else if (sides.get<1, 0>() == 0 && sides.get<1, 1>() == 0)
{
collinear = true;
sides.set<0>(0, 0);
}
}
calc_t dot_n1n2 = dot_product(plane1.normal, plane2.normal);
// NOTE: this is technically not needed since theoretically above sides
// are calculated, but just in case check the normals.
// Have in mind that SSF side strategy doesn't check this.
// collinear if normals are equal or opposite: cos(a) in {-1, 1}
if (!collinear && math::equals(math::abs(dot_n1n2), c1))
if (! collinear && math::equals(math::abs(dot_n1n2), c1))
{
collinear = true;
sides.set<0>(0, 0);
@@ -324,12 +392,12 @@ struct relate_spherical_segments
{
if (a_is_point)
{
return collinear_one_degenerted<Policy, calc_t>(a, true, b1, b2, a1, a2, b1v, b2v, norm2, a1v);
return collinear_one_degenerated<Policy, calc_t>(a, true, b1, b2, a1, a2, b1v, b2v, plane2, a1v);
}
else if (b_is_point)
{
// b2 used to be consistent with (degenerated) checks above (is it needed?)
return collinear_one_degenerted<Policy, calc_t>(b, false, a1, a2, b1, b2, a1v, a2v, norm1, b1v);
return collinear_one_degenerated<Policy, calc_t>(b, false, a1, a2, b1, b2, a1v, a2v, plane1, b1v);
}
else
{
@@ -338,16 +406,16 @@ struct relate_spherical_segments
// use shorter segment
if (len1 <= len2)
{
calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, norm1, b1v, dist_a1_a2, dist_a1_b1);
calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, norm1, b2v, dist_a1_a2, dist_a1_b2);
calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, plane1, b1v, dist_a1_a2, dist_a1_b1);
calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, plane1, b2v, dist_a1_a2, dist_a1_b2);
dist_b1_b2 = dist_a1_b2 - dist_a1_b1;
dist_b1_a1 = -dist_a1_b1;
dist_b1_a2 = dist_a1_a2 - dist_a1_b1;
}
else
{
calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, norm2, a1v, dist_b1_b2, dist_b1_a1);
calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, norm2, a2v, dist_b1_b2, dist_b1_a2);
calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, plane2, a1v, dist_b1_b2, dist_b1_a1);
calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, plane2, a2v, dist_b1_b2, dist_b1_a2);
dist_a1_a2 = dist_b1_a2 - dist_b1_a1;
dist_a1_b1 = -dist_b1_a1;
dist_a1_b2 = dist_b1_b2 - dist_b1_a1;
@@ -408,7 +476,8 @@ struct relate_spherical_segments
vec3d_t i1;
intersection_point_flag ip_flag;
calc_t dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1;
if (calculate_ip_data(a1, a2, b1, b2, a1v, a2v, b1v, b2v, norm1, norm2, sides,
if (calculate_ip_data(a1, a2, b1, b2, a1v, a2v, b1v, b2v,
plane1, plane2, calc_policy, sides,
i1, dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1, ip_flag))
{
// intersects
@@ -417,7 +486,7 @@ struct relate_spherical_segments
calc_t,
segment_ratio<calc_t>,
vec3d_t
> sinfo;
> sinfo(calc_policy);
sinfo.robust_ra.assign(dist_a1_i1, dist_a1_a2);
sinfo.robust_rb.assign(dist_b1_i1, dist_b1_b2);
@@ -434,31 +503,32 @@ struct relate_spherical_segments
}
private:
template <typename Policy, typename CalcT, typename Segment, typename Point1, typename Point2, typename Vec3d>
template <typename Policy, typename CalcT, typename Segment, typename Point1, typename Point2, typename Vec3d, typename Plane>
static inline typename Policy::return_type
collinear_one_degenerted(Segment const& segment, bool degenerated_a,
Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
Vec3d const& v1, Vec3d const& v2, Vec3d const& norm,
Vec3d const& vother)
collinear_one_degenerated(Segment const& segment, bool degenerated_a,
Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
Vec3d const& v1, Vec3d const& v2,
Plane const& plane,
Vec3d const& vother)
{
CalcT dist_1_2, dist_1_o;
return ! calculate_collinear_data(a1, a2, b1, b2, v1, v2, norm, vother, dist_1_2, dist_1_o)
return ! calculate_collinear_data(a1, a2, b1, b2, v1, v2, plane, vother, dist_1_2, dist_1_o)
? Policy::disjoint()
: Policy::one_degenerate(segment, segment_ratio<CalcT>(dist_1_o, dist_1_2), degenerated_a);
}
template <typename Point1, typename Point2, typename Vec3d, typename CalcT>
static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
Vec3d const& a1v, // in
Vec3d const& a2v, // in
Vec3d const& norm1, // in
Vec3d const& b1v_or_b2v, // in
template <typename Point1, typename Point2, typename Vec3d, typename Plane, typename CalcT>
static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
Vec3d const& a1v, // in
Vec3d const& a2v, // in
Plane const& plane1, // in
Vec3d const& b1v_or_b2v, // in
CalcT& dist_a1_a2, CalcT& dist_a1_i1) // out
{
// calculate dist_a1_a2 and dist_a1_i1
calculate_dists(a1v, a2v, norm1, b1v_or_b2v, dist_a1_a2, dist_a1_i1);
calculate_dists(a1v, a2v, plane1, b1v_or_b2v, dist_a1_a2, dist_a1_i1);
// if i1 is close to a1 and b1 or b2 is equal to a1
if (is_endpoint_equal(dist_a1_i1, a1, b1, b2))
@@ -477,54 +547,53 @@ private:
return segment_ratio<CalcT>(dist_a1_i1, dist_a1_a2).on_segment();
}
template <typename Point1, typename Point2, typename Vec3d, typename CalcT>
template <typename Point1, typename Point2, typename Vec3d, typename Plane, typename CalcT>
static inline bool calculate_ip_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
Vec3d const& a1v, Vec3d const& a2v, // in
Vec3d const& b1v, Vec3d const& b2v, // in
Vec3d const& norm1, Vec3d const& norm2, // in
side_info const& sides, // in
Vec3d & i1, // in-out
CalcT& dist_a1_a2, CalcT& dist_a1_i1, // out
CalcT& dist_b1_b2, CalcT& dist_b1_i1, // out
Plane const& plane1, // in
Plane const& plane2, // in
CalcPolicy const& calc_policy, // in
side_info const& sides, // in
Vec3d & ip, // out
CalcT& dist_a1_a2, CalcT& dist_a1_ip, // out
CalcT& dist_b1_b2, CalcT& dist_b1_ip, // out
intersection_point_flag& ip_flag) // out
{
// great circles intersections
i1 = cross_product(norm1, norm2);
// NOTE: the length should be greater than 0 at this point
// if the normals were not normalized and their dot product
// not checked before this function is called the length
// should be checked here (math::equals(len, c0))
CalcT const len = math::sqrt(dot_product(i1, i1));
divide_value(i1, len); // normalize i1
calculate_dists(a1v, a2v, norm1, i1, dist_a1_a2, dist_a1_i1);
Vec3d ip1, ip2;
calc_policy.intersection_points(plane1, plane2, ip1, ip2);
calculate_dists(a1v, a2v, plane1, ip1, dist_a1_a2, dist_a1_ip);
ip = ip1;
// choose the opposite side of the globe if the distance is shorter
{
CalcT const d = abs_distance(dist_a1_a2, dist_a1_i1);
CalcT const d = abs_distance(dist_a1_a2, dist_a1_ip);
if (d > CalcT(0))
{
CalcT const dist_a1_i2 = dist_of_i2(dist_a1_i1);
// TODO: this should be ok not only for sphere
// but requires more investigation
CalcT const dist_a1_i2 = dist_of_i2(dist_a1_ip);
CalcT const d2 = abs_distance(dist_a1_a2, dist_a1_i2);
if (d2 < d)
{
dist_a1_i1 = dist_a1_i2;
multiply_value(i1, CalcT(-1)); // the opposite intersection
dist_a1_ip = dist_a1_i2;
ip = ip2;
}
}
}
bool is_on_a = false, is_near_a1 = false, is_near_a2 = false;
if (! is_potentially_crossing(dist_a1_a2, dist_a1_i1, is_on_a, is_near_a1, is_near_a2))
if (! is_potentially_crossing(dist_a1_a2, dist_a1_ip, is_on_a, is_near_a1, is_near_a2))
{
return false;
}
calculate_dists(b1v, b2v, norm2, i1, dist_b1_b2, dist_b1_i1);
calculate_dists(b1v, b2v, plane2, ip, dist_b1_b2, dist_b1_ip);
bool is_on_b = false, is_near_b1 = false, is_near_b2 = false;
if (! is_potentially_crossing(dist_b1_b2, dist_b1_i1, is_on_b, is_near_b1, is_near_b2))
if (! is_potentially_crossing(dist_b1_b2, dist_b1_ip, is_on_b, is_near_b1, is_near_b2))
{
return false;
}
@@ -535,8 +604,8 @@ private:
{
if (is_near_b1 && equals_point_point(a1, b1))
{
dist_a1_i1 = 0;
dist_b1_i1 = 0;
dist_a1_ip = 0;
dist_b1_ip = 0;
//i1 = a1v;
ip_flag = ipi_at_a1;
return true;
@@ -544,8 +613,8 @@ private:
if (is_near_b2 && equals_point_point(a1, b2))
{
dist_a1_i1 = 0;
dist_b1_i1 = dist_b1_b2;
dist_a1_ip = 0;
dist_b1_ip = dist_b1_b2;
//i1 = a1v;
ip_flag = ipi_at_a1;
return true;
@@ -556,8 +625,8 @@ private:
{
if (is_near_b1 && equals_point_point(a2, b1))
{
dist_a1_i1 = dist_a1_a2;
dist_b1_i1 = 0;
dist_a1_ip = dist_a1_a2;
dist_b1_ip = 0;
//i1 = a2v;
ip_flag = ipi_at_a2;
return true;
@@ -565,8 +634,8 @@ private:
if (is_near_b2 && equals_point_point(a2, b2))
{
dist_a1_i1 = dist_a1_a2;
dist_b1_i1 = dist_b1_b2;
dist_a1_ip = dist_a1_a2;
dist_b1_ip = dist_b1_b2;
//i1 = a2v;
ip_flag = ipi_at_a2;
return true;
@@ -580,7 +649,7 @@ private:
{
if (is_near_b1 && sides.template get<1, 0>() == 0) // b1 wrt a
{
dist_b1_i1 = 0;
dist_b1_ip = 0;
//i1 = b1v;
ip_flag = ipi_at_b1;
return true;
@@ -588,7 +657,7 @@ private:
if (is_near_b2 && sides.template get<1, 1>() == 0) // b2 wrt a
{
dist_b1_i1 = dist_b1_b2;
dist_b1_ip = dist_b1_b2;
//i1 = b2v;
ip_flag = ipi_at_b2;
return true;
@@ -599,7 +668,7 @@ private:
{
if (is_near_a1 && sides.template get<0, 0>() == 0) // a1 wrt b
{
dist_a1_i1 = 0;
dist_a1_ip = 0;
//i1 = a1v;
ip_flag = ipi_at_a1;
return true;
@@ -607,7 +676,7 @@ private:
if (is_near_a2 && sides.template get<0, 1>() == 0) // a2 wrt b
{
dist_a1_i1 = dist_a1_a2;
dist_a1_ip = dist_a1_a2;
//i1 = a2v;
ip_flag = ipi_at_a2;
return true;
@@ -619,24 +688,26 @@ private:
return is_on_a && is_on_b;
}
template <typename Vec3d, typename CalcT>
static inline void calculate_dists(Vec3d const& a1v, // in
Vec3d const& a2v, // in
Vec3d const& norm1, // in
Vec3d const& i1, // in
CalcT& dist_a1_a2, CalcT& dist_a1_i1) // out
template <typename Vec3d, typename Plane, typename CalcT>
static inline void calculate_dists(Vec3d const& a1v, // in
Vec3d const& a2v, // in
Plane const& plane1, // in
Vec3d const& i1, // in
CalcT& dist_a1_a2, // out
CalcT& dist_a1_i1) // out
{
CalcT const c0 = 0;
//CalcT const c0 = 0;
CalcT const c1 = 1;
CalcT const c2 = 2;
CalcT const c4 = 4;
CalcT cos_a1_a2 = dot_product(a1v, a2v);
CalcT cos_a1_a2 = plane1.cos_angle_between(a1v, a2v);
dist_a1_a2 = -cos_a1_a2 + c1; // [1, -1] -> [0, 2] representing [0, pi]
CalcT cos_a1_i1 = dot_product(a1v, i1);
bool is_forward = true;
CalcT cos_a1_i1 = plane1.cos_angle_between(a1v, i1, is_forward);
dist_a1_i1 = -cos_a1_i1 + c1; // [0, 2] representing [0, pi]
if (dot_product(norm1, cross_product(a1v, i1)) < c0) // left or right of a1 on a
if (! is_forward) // left or right of a1 on a
{
dist_a1_i1 = -dist_a1_i1; // [0, 2] -> [0, -2] representing [0, -pi]
}
@@ -716,6 +787,88 @@ private:
}
};
struct relate_spherical_segments_calc_policy
{
template <typename Point, typename Point3d>
static Point from_cart3d(Point3d const& point_3d)
{
return formula::cart3d_to_sph<Point>(point_3d);
}
template <typename Point3d, typename Point>
static Point3d to_cart3d(Point const& point)
{
return formula::sph_to_cart3d<Point3d>(point);
}
template <typename Point3d>
struct plane
{
typedef typename coordinate_type<Point3d>::type coord_t;
// not normalized
plane(Point3d const& p1, Point3d const& p2)
: normal(cross_product(p1, p2))
{}
int side_value(Point3d const& pt) const
{
return formula::sph_side_value(normal, pt);
}
static coord_t cos_angle_between(Point3d const& p1, Point3d const& p2)
{
return dot_product(p1, p2);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const
{
coord_t const c0 = 0;
is_forward = dot_product(normal, cross_product(p1, p2)) >= c0;
return dot_product(p1, p2);
}
Point3d normal;
};
template <typename Point3d>
static plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2)
{
return plane<Point3d>(p1, p2);
}
template <typename Point3d>
static bool intersection_points(plane<Point3d> const& plane1,
plane<Point3d> const& plane2,
Point3d & ip1, Point3d & ip2)
{
typedef typename coordinate_type<Point3d>::type coord_t;
ip1 = cross_product(plane1.normal, plane2.normal);
// NOTE: the length should be greater than 0 at this point
// if the normals were not normalized and their dot product
// not checked before this function is called the length
// should be checked here (math::equals(len, c0))
coord_t const len = math::sqrt(dot_product(ip1, ip1));
divide_value(ip1, len); // normalize i1
ip2 = ip1;
multiply_value(ip2, coord_t(-1));
return true;
}
};
template <typename CalculationType = void>
struct relate_spherical_segments
: relate_ecef_segments
<
relate_spherical_segments_calc_policy,
CalculationType
>
{};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
@@ -736,6 +889,11 @@ struct default_strategy<spherical_equatorial_tag, CalculationType>
template <typename CalculationType>
struct default_strategy<geographic_tag, CalculationType>
{
// NOTE: Spherical strategy returns the same result as the geographic one
// representing segments as great elliptic arcs. If the elliptic arcs are
// not great elliptic arcs (the origin not in the center of the coordinate
// system) then there may be problems with consistency of the side and
// intersection strategies.
typedef relate_spherical_segments<CalculationType> type;
};

View File

@@ -80,10 +80,14 @@
#include <boost/geometry/strategies/geographic/area_geographic.hpp>
#include <boost/geometry/strategies/geographic/azimuth_geographic.hpp>
#include <boost/geometry/strategies/geographic/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/distance_andoyer.hpp>
#include <boost/geometry/strategies/geographic/distance_thomas.hpp>
#include <boost/geometry/strategies/geographic/distance_vincenty.hpp>
#include <boost/geometry/strategies/geographic/envelope_segment.hpp>
//#include <boost/geometry/strategies/geographic/geodesic_intersection.hpp>
//#include <boost/geometry/strategies/geographic/intersection.hpp>
//#include <boost/geometry/strategies/geographic/side.hpp>
//#include <boost/geometry/strategies/geographic/side_andoyer.hpp>
//#include <boost/geometry/strategies/geographic/side_thomas.hpp>
//#include <boost/geometry/strategies/geographic/side_vincenty.hpp>

View File

@@ -71,6 +71,19 @@ inline T const& greatest(T const& v1, T const& v2, T const& v3, T const& v4, T c
}
template <typename T>
inline T bounded(T const& v, T const& lower, T const& upper)
{
return (std::min)((std::max)(v, lower), upper);
}
template <typename T>
inline T bounded(T const& v, T const& lower)
{
return (std::max)(v, lower);
}
template <typename T,
bool IsFloatingPoint = boost::is_floating_point<T>::value>
struct abs

View File

@@ -282,6 +282,40 @@ inline CoordinateType longitude_distance_unsigned(CoordinateType const& longitud
return diff;
}
/*!
\brief The abs difference between longitudes in range [0, 180].
\tparam Units The units of the coordindate system in the spheroid
\tparam CoordinateType The type of the coordinates
\param longitude1 Longitude 1
\param longitude2 Longitude 2
\ingroup utility
*/
template <typename Units, typename CoordinateType>
inline CoordinateType longitude_difference(CoordinateType const& longitude1,
CoordinateType const& longitude2)
{
return math::abs(math::longitude_distance_signed<Units>(longitude1, longitude2));
}
template <typename Units, typename CoordinateType>
inline CoordinateType longitude_interval_distance_signed(CoordinateType const& longitude_a1,
CoordinateType const& longitude_a2,
CoordinateType const& longitude_b)
{
CoordinateType const c0 = 0;
CoordinateType dist_a12 = longitude_distance_signed<Units>(longitude_a1, longitude_a2);
CoordinateType dist_a1b = longitude_distance_signed<Units>(longitude_a1, longitude_b);
if (dist_a12 < c0)
{
dist_a12 = -dist_a12;
dist_a1b = -dist_a1b;
}
return dist_a1b < c0 ? dist_a1b
: dist_a1b > dist_a12 ? dist_a1b - dist_a12
: c0;
}
} // namespace math

View File

@@ -50,6 +50,7 @@
#include "test_envelope_expand_on_spheroid.hpp"
template <
template <typename, bool, bool, bool, bool, bool> class Inverse,
typename CS_Tag
@@ -152,11 +153,54 @@ private:
BOOST_CHECK_MESSAGE(same_boxes, stream.str());
}
template <typename Box, typename Geometry>
template
<
typename Geometry, typename Box,
typename T1, typename T2, typename T3, typename T4
>
static inline void check_message(bool same_boxes,
std::string const& case_id,
std::string const& units_str,
Geometry const& geometry,
T1 const& lon_min, T2 const& lat_min, double height_min,
T3 const& lon_max, T4 const& lat_max, double height_max,
Box const& detected)
{
std::ostringstream stream;
stream << "case ID: " << case_id << ", "
<< "MBR units: " << units_str << "; "
<< "geometry: ";
write_geometry<Geometry>::apply(stream, geometry);
stream << std::setprecision(17);
stream << "; " << "expected: ";
if (BOOST_GEOMETRY_CONDITION(bg::dimension<Box>::value == 2))
{
stream << "(" << lon_min << " " << lat_min
<< ", " << lon_max << " " << lat_max << ")";
}
else
{
stream << "(" << lon_min << " " << lat_min << " " << height_min
<< ", " << lon_max << " " << lat_max << " " << height_max << ")";
}
stream << ", " << "detected: " << bg::dsv(detected);
BOOST_CHECK_MESSAGE(same_boxes, stream.str());
}
template
<
typename Box, typename Geometry,
typename T1, typename T2, typename T3, typename T4
>
static inline void base_test(std::string const& case_id,
Geometry const& geometry,
double lon_min, double lat_min, double height_min,
double lon_max, double lat_max, double height_max,
T1 const& lon_min, T2 const& lat_min, double height_min,
T3 const& lon_max, T4 const& lat_max, double height_max,
double tolerance)
{
typedef typename bg::coordinate_system<Box>::type::units box_units_type;
@@ -168,27 +212,40 @@ private:
typename bg::cs_tag<Geometry>::type
>::apply(geometry, detected);
Box expected;
initialize_box<Box>::apply(expected,
lon_min, lat_min, height_min,
lon_max, lat_max, height_max);
#ifdef BOOST_GEOMETRY_TEST_DEBUG
std::cout << "geometry: ";
write_geometry<Geometry>::apply(std::cout, geometry);
std::cout << std::endl
<< "MBR units: " << units_str
<< std::endl
<< "expected: " << bg::dsv(expected)
<< std::endl
<< std::endl;
std::cout << "expected: ";
if (BOOST_GEOMETRY_CONDITION(bg::dimension<Box>::value == 2))
{
std::cout << "(" << lon_min << " " << lat_min
<< ", " << lon_max << " " << lat_max << ")";
}
else
{
std::cout << "(" << lon_min << " " << lat_min << " " << height_min
<< ", " << lon_max << " " << lat_max << " " << height_max << ")";
}
std::cout << std::endl
<< "detected: " << bg::dsv(detected)
<< std::endl << std::endl;
#endif
check_message(box_equals<Box>::apply(detected, expected, tolerance),
bool check = box_check_equals<Box>::apply(detected,
lon_min, lat_min, height_min,
lon_max, lat_max, height_max,
tolerance);
check_message(check,
case_id, units_str,
geometry, expected, detected);
geometry,
lon_min, lat_min, height_min,
lon_max, lat_max, height_max,
detected);
// if valid box is expected, check the validity
if (lon_min <= lon_max && lat_min <= lat_max && height_min <= height_max)
@@ -201,11 +258,15 @@ private:
}
public:
template <typename Geometry>
template
<
typename Geometry,
typename T1, typename T2, typename T3, typename T4
>
static inline void apply(std::string const& case_id,
Geometry const& geometry,
double lon_min, double lat_min, double height_min,
double lon_max, double lat_max, double height_max,
T1 const& lon_min, T2 const& lat_min, double height_min,
T3 const& lon_max, T4 const& lat_max, double height_max,
double tolerance)
{
typedef other_system_info
@@ -291,12 +352,14 @@ template
>
struct test_envelope_on_sphere_or_spheroid
{
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8>
static inline void apply(std::string const& case_id,
Geometry const& geometry,
double lon_min1, double lat_min1, double height_min1,
double lon_max1, double lat_max1, double height_max1,
double lon_min2, double lat_min2, double height_min2,
double lon_max2, double lat_max2, double height_max2,
T1 const& lon_min1, T2 const& lat_min1, double height_min1,
T3 const& lon_max1, T4 const& lat_max1, double height_max1,
T5 const& lon_min2, T6 const& lat_min2, double height_min2,
T7 const& lon_max2, T8 const& lat_max2, double height_max2,
double tolerance = std::numeric_limits<double>::epsilon())
{
envelope_on_spheroid_basic_tester
@@ -328,12 +391,14 @@ struct test_envelope_on_sphere_or_spheroid
#endif
}
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8>
static inline void apply(std::string const& case_id,
Geometry const& geometry,
double lon_min1, double lat_min1,
double lon_max1, double lat_max1,
double lon_min2, double lat_min2,
double lon_max2, double lat_max2,
T1 const& lon_min1, T2 const& lat_min1,
T3 const& lon_max1, T4 const& lat_max1,
T5 const& lon_min2, T6 const& lat_min2,
T7 const& lon_max2, T8 const& lat_max2,
double tolerance = std::numeric_limits<double>::epsilon())
{
apply(case_id, geometry,
@@ -342,10 +407,11 @@ struct test_envelope_on_sphere_or_spheroid
tolerance);
}
template <typename T1, typename T2, typename T3, typename T4>
static inline void apply(std::string const& case_id,
Geometry const& geometry,
double lon_min, double lat_min, double height_min,
double lon_max, double lat_max, double height_max,
T1 const& lon_min, T2 const& lat_min, double height_min,
T3 const& lon_max, T4 const& lat_max, double height_max,
double tolerance = std::numeric_limits<double>::epsilon())
{
apply(case_id, geometry,
@@ -356,10 +422,11 @@ struct test_envelope_on_sphere_or_spheroid
tolerance);
}
template <typename T1, typename T2, typename T3, typename T4>
static inline void apply(std::string const& case_id,
Geometry const& geometry,
double lon_min, double lat_min,
double lon_max, double lat_max,
T1 const& lon_min, T2 const& lat_min,
T3 const& lon_max, T4 const& lat_max,
double tolerance = std::numeric_limits<double>::epsilon())
{
apply(case_id, geometry,
@@ -373,13 +440,15 @@ struct test_envelope_on_sphere_or_spheroid
template <typename Geometry, typename MBR, bool TestReverse>
struct test_envelope_on_sphere_or_spheroid<Geometry, MBR, bg::ring_tag, TestReverse>
{
template <typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8>
static inline void apply(std::string const& case_id,
Geometry const& geometry,
double lon_min1, double lat_min1,
double lon_max1, double lat_max1,
double lon_min2, double lat_min2,
double lon_max2, double lat_max2,
double tolerance = std::numeric_limits<double>::epsilon())
T1 const& lon_min1, T2 const& lat_min1,
T3 const& lon_max1, T4 const& lat_max1,
T5 const& lon_min2, T6 const& lat_min2,
T7 const& lon_max2, T8 const& lat_max2,
double const& tolerance = std::numeric_limits<double>::epsilon())
{
envelope_on_spheroid_basic_tester
<
@@ -409,10 +478,11 @@ struct test_envelope_on_sphere_or_spheroid<Geometry, MBR, bg::ring_tag, TestReve
#endif
}
template <typename T1, typename T2, typename T3, typename T4>
static inline void apply(std::string const& case_id,
Geometry const& geometry,
double lon_min, double lat_min,
double lon_max, double lat_max,
T1 const& lon_min, T2 const& lat_min,
T3 const& lon_max, T4 const& lat_max,
double tolerance = std::numeric_limits<double>::epsilon())
{
apply(case_id, geometry,
@@ -822,26 +892,24 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid )
tester::apply("s09",
from_wkt<G>("SEGMENT(1 -45,179 30)"),
1, -85.392785243526134, 179, 30,
3 * eps);
1, rng(-85.392785243526134, -85.392785243525253), 179, 30);
tester::apply("s09a",
from_wkt<G>("SEGMENT(2 -45,181 30)"),
2, -87.689300911353811, 181, 30);
2, rng(-87.689300911353811, -87.689300911353371), 181, 30);
// very long segment
tester::apply("s10",
from_wkt<G>("SEGMENT(0 -45,181 30)"),
-179, -87.689300911353797, 0, 30,
2.0 * eps);
-179, rng(-87.689300911353797, -87.689300911353385), 0, 30);
tester::apply("s11",
from_wkt<G>("SEGMENT(260 30,20 45)"),
-100, 30, 20, 57.990810958016965);
-100, 30, 20, rng(57.990810958016482, 57.990810958016965));
tester::apply("s11a",
from_wkt<G>("SEGMENT(260 45,20 30)"),
-100, 30, 20, 57.990810958016965);
-100, 30, 20, rng(57.990810958016453, 57.990810958016965));
// segment degenerating to the north pole
tester::apply("s12",
@@ -859,7 +927,7 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid )
tester::apply("s15",
from_wkt<G>("SEGMENT(50 45,185 45)"),
50, 45, 185, 69.098479073903178);
50, 45, 185, rng(69.098479073902851, 69.098479073903178));
// segment that lies on the equator
tester::apply("s16",
@@ -924,7 +992,7 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid )
1-heps, 1, 1, 1);
tester::apply("s104",
G(P(2, 1), P(1, 1-heps)),
1, 1-heps, 2, 1.0000383271569036);
1, 1-heps, 2, rng(1.0000383271568751, 1.0000383271569036));
tester::apply("s105",
G(P(1, 2), P(1-heps, 1)),
1-heps, 1, 1, 2);
@@ -940,13 +1008,11 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_thomas )
typedef test_envelope_on_sphere_or_spheroid
<
G, B,
typename bg::tag<G>::type,
bg::tag<G>::type,
test_reverse_geometry<G>::value,
bg::formula::thomas_inverse
> tester;
double const eps = std::numeric_limits<double>::epsilon();
tester::apply("s01",
from_wkt<G>("SEGMENT(10 10,40 40)"),
10, 10, 40, 40);
@@ -1011,26 +1077,24 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_thomas )
tester::apply("s09",
from_wkt<G>("SEGMENT(1 -45,179 30)"),
1, -85.392785243526134, 179, 30,
3 * eps);
1, rng(-85.392785243526134, -85.392785243525253), 179, 30);
tester::apply("s09a",
from_wkt<G>("SEGMENT(2 -45,181 30)"),
2, -87.689300911353811, 181, 30);
2, rng(-87.689300911353811, -87.689300911353371), 181, 30);
// very long segment
tester::apply("s10",
from_wkt<G>("SEGMENT(0 -45,181 30)"),
-179, -87.689300911353797, 0, 30,
2.0 * eps);
-179, rng(-87.689300911353797, -87.689300911353385), 0, 30);
tester::apply("s11",
from_wkt<G>("SEGMENT(260 30,20 45)"),
-100, 30, 20, 57.990810958016965);
-100, 30, 20, rng(57.990810958016482, 57.990810958016965));
tester::apply("s11a",
from_wkt<G>("SEGMENT(260 45,20 30)"),
-100, 30, 20, 57.990810958016965);
-100, 30, 20, rng(57.990810958016453, 57.990810958016965));
// segment degenerating to the north pole
tester::apply("s12",
@@ -1048,7 +1112,7 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_thomas )
tester::apply("s15",
from_wkt<G>("SEGMENT(50 45,185 45)"),
50, 45, 185, 69.098479073903178);
50, 45, 185, rng(69.098479073902851, 69.098479073903178));
// segment that lies on the equator
tester::apply("s16",
@@ -1098,13 +1162,11 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_andoyer )
typedef test_envelope_on_sphere_or_spheroid
<
G, B,
typename bg::tag<G>::type,
bg::tag<G>::type,
test_reverse_geometry<G>::value,
bg::formula::andoyer_inverse
> tester;
double const eps = std::numeric_limits<double>::epsilon();
tester::apply("s01",
from_wkt<G>("SEGMENT(10 10,40 40)"),
10, 10, 40, 40);
@@ -1169,26 +1231,24 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_andoyer )
tester::apply("s09",
from_wkt<G>("SEGMENT(1 -45,179 30)"),
1, -85.394745211091248, 179, 30,
3 * eps);
1, rng(-85.394745211091248, -85.394745211090353), 179, 30);
tester::apply("s09a",
from_wkt<G>("SEGMENT(2 -45,181 30)"),
2, -87.690317839849726, 181, 30);
2, rng(-87.690317839849726, -87.690317839849271), 181, 30);
// very long segment
tester::apply("s10",
from_wkt<G>("SEGMENT(0 -45,181 30)"),
-179, -87.69031783984974, 0, 30,
2.0 * eps);
-179, rng(-87.69031783984974, -87.690317839849271), 0, 30);
tester::apply("s11",
from_wkt<G>("SEGMENT(260 30,20 45)"),
-100, 30, 20, 57.990742552280153);
-100, 30, 20, rng(57.990742552279649, 57.990742552280153));
tester::apply("s11a",
from_wkt<G>("SEGMENT(260 45,20 30)"),
-100, 30, 20, 57.990742552280118);
-100, 30, 20, rng(57.99074255227962, 57.990742552280118));
// segment degenerating to the north pole
tester::apply("s12",
@@ -1206,7 +1266,7 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_andoyer )
tester::apply("s15",
from_wkt<G>("SEGMENT(50 45,185 45)"),
50, 45, 185, 69.09844689340845);
50, 45, 185, rng(69.098446893408124, 69.09844689340845));
// segment that lies on the equator
tester::apply("s16",
@@ -1256,36 +1316,34 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_vincenty )
typedef test_envelope_on_sphere_or_spheroid
<
G, B,
typename bg::tag<G>::type,
bg::tag<G>::type,
test_reverse_geometry<G>::value,
bg::formula::vincenty_inverse
> tester;
double const eps = std::numeric_limits<double>::epsilon();
tester::apply("s01",
from_wkt<G>("SEGMENT(10 10,40 40)"),
10, 10, 40, 40);
tester::apply("s02",
from_wkt<G>("SEGMENT(10 10,40 10)"),
10, 10, 40, 10.347587628821941);
10, 10, 40, rng(10.347587628821937, 10.347587628821941));
tester::apply("s02a",
from_wkt<G>("SEGMENT(40 10,10 10)"),
10, 10, 40, 10.347587628821941);
10, 10, 40, rng(10.347587628821937, 10.347587628821941));
tester::apply("s03",
from_wkt<G>("SEGMENT(160 10,-170 10)"),
160, 10, 190, 10.347587628821941);
160, 10, 190, rng(10.347587628821937, 10.347587628821941));
tester::apply("s03a",
from_wkt<G>("SEGMENT(-170 10,160 10)"),
160, 10, 190, 10.347587628821941);
160, 10, 190, rng(10.347587628821937, 10.347587628821941));
tester::apply("s03b",
from_wkt<G>("SEGMENT(-170 -10,160 -10)"),
160, -10.347587628821941, 190, -10);
160, rng(-10.347587628821941, -10.347587628821937), 190, -10);
tester::apply("s04",
from_wkt<G>("SEGMENT(-40 45,140 60)"),
@@ -1327,26 +1385,24 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_vincenty )
tester::apply("s09",
from_wkt<G>("SEGMENT(1 -45,179 30)"),
1, -85.392840929577218, 179, 30,
3 * eps);
1, rng(-85.392840929577218, -85.392840929576352), 179, 30);
tester::apply("s09a",
from_wkt<G>("SEGMENT(2 -45,181 30)"),
2, -87.689330275867817, 181, 30);
2, rng(-87.689330275867817, -87.689330275867405), 181, 30);
// very long segment
tester::apply("s10",
from_wkt<G>("SEGMENT(0 -45,181 30)"),
-179, -87.689330275867832, 0, 30,
2.0 * eps);
-179, rng(-87.689330275867832, -87.689330275867405), 0, 30);
tester::apply("s11",
from_wkt<G>("SEGMENT(260 30,20 45)"),
-100, 30, 20, 57.990810647057032);
-100, 30, 20, rng(57.990810647056549, 57.990810647057032));
tester::apply("s11a",
from_wkt<G>("SEGMENT(260 45,20 30)"),
-100, 30, 20, 57.990810647057032);
-100, 30, 20, rng(57.990810647056541, 57.990810647057032));
// segment degenerating to the north pole
tester::apply("s12",
@@ -1364,7 +1420,7 @@ BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_vincenty )
tester::apply("s15",
from_wkt<G>("SEGMENT(50 45,185 45)"),
50, 45, 185, 69.098479136978497);
50, 45, 185, rng(69.098479136978156, 69.098479136978497));
// segment that lies on the equator
tester::apply("s16",
@@ -2012,8 +2068,7 @@ BOOST_AUTO_TEST_CASE( envelope_spheroid_linestring )
// linestring that circles the entire globe
tester::apply("l03",
from_wkt<G>("LINESTRING(-185 0,-170 25,-50 10,10 10,20 20,100 5,180 15)"),
-180, 0, 180, 33.702476580413318,
4.0 * std::numeric_limits<double>::epsilon());
-180, 0, 180, rng(33.702476580412359, 33.702476580413318));
// linestring that crosses the antimeridian but staying close to it
tester::apply("l04",
@@ -2261,19 +2316,19 @@ BOOST_AUTO_TEST_CASE( envelope_spheroid_multilinestring )
tester::apply("ml04",
from_wkt<G>("MULTILINESTRING((-150 40,-100 80),(10 35,100 80))"),
-150, 35, 100, 80.082544902477267);
-150, 35, 100, rng(80.07385383411011, 80.082544902477267));
tester::apply("ml04a",
from_wkt<G>("MULTILINESTRING((-150 40,-100 80),(10 35,100 80),(170 25,-160 80))"),
10, 25, 260, 80.082544902477267);
10, 25, 260, rng(80.07385383411011, 80.082544902477267));
tester::apply("ml05",
from_wkt<G>("MULTILINESTRING((-140 40,-100 80),(10 35,100 80))"),
-140, 35, 100, 80.082544902477267);
-140, 35, 100, rng(80.07385383411011, 80.082544902477267));
tester::apply("ml05a",
from_wkt<G>("MULTILINESTRING((-140 40,-100 80),(10 35,100 80),(170 25,-160 80))"),
10, 25, 260, 80.082544902477267);
10, 25, 260, rng(80.07385383411011, 80.082544902477267));
}

View File

@@ -11,9 +11,11 @@
#ifndef BOOST_GEOMETRY_TEST_ENVELOPE_EXPAND_ON_SPHEROID_HPP
#define BOOST_GEOMETRY_TEST_ENVELOPE_EXPAND_ON_SPHEROID_HPP
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <algorithm>
#include <iostream>
#include <boost/type_traits/is_same.hpp>
@@ -29,6 +31,37 @@
#include <boost/geometry/algorithms/assign.hpp>
struct rng
{
typedef double type;
rng(double l, double h)
: lo(l), hi(h)
{
BOOST_GEOMETRY_ASSERT(lo <= hi);
}
friend rng operator*(rng const& l, double v) { return rng(l.lo * v, l.hi * v); }
friend bool operator<=(rng const& l, rng const& r) { return l.lo <= r.hi; }
friend bool operator<=(double l, rng const& r) { return l <= r.hi; }
friend bool operator<=(rng const& l, double r) { return l.lo <= r; }
friend bool operator<(rng const& l, rng const& r) { return !operator<=(r, l); }
friend bool operator<(double l, rng const& r) { return !operator<=(r, l); }
friend bool operator<(rng const& l, double r) { return !operator<=(r, l); }
friend bool operator==(double l, rng const& r) { return r.lo <= l && l <= r.hi; }
friend std::ostream & operator<<(std::ostream & os, rng const& v)
{
return (os << "[" << v.lo << ", " << v.hi << "]");
}
double lo, hi;
};
template <typename Units>
char const* units2string()
{
@@ -49,10 +82,14 @@ struct other_system_info<bg::cs::spherical_equatorial<bg::radian> >
typedef bg::degree units;
typedef bg::cs::spherical_equatorial<units> type;
template <typename T>
static inline T convert(T const& value)
static inline double convert(double value)
{
return value * bg::math::r2d<T>();
return value * bg::math::r2d<double>();
}
static inline rng convert(rng const& value)
{
return value * bg::math::r2d<double>();
}
};
@@ -62,10 +99,14 @@ struct other_system_info<bg::cs::spherical_equatorial<bg::degree> >
typedef bg::radian units;
typedef bg::cs::spherical_equatorial<units> type;
template <typename T>
static inline T convert(T const& value)
static inline double convert(double value)
{
return value * bg::math::d2r<T>();
return value * bg::math::d2r<double>();
}
static inline rng convert(rng const& value)
{
return value * bg::math::d2r<double>();
}
};
@@ -75,10 +116,14 @@ struct other_system_info<bg::cs::geographic<bg::radian> >
typedef bg::degree units;
typedef bg::cs::geographic<units> type;
template <typename T>
static inline T convert(T const& value)
static inline double convert(double value)
{
return value * bg::math::r2d<T>();
return value * bg::math::r2d<double>();
}
static inline rng convert(rng const& value)
{
return value * bg::math::r2d<double>();
}
};
@@ -88,15 +133,18 @@ struct other_system_info<bg::cs::geographic<bg::degree> >
typedef bg::radian units;
typedef bg::cs::geographic<units> type;
template <typename T>
static inline T convert(T const& value)
static inline double convert(double value)
{
return value * bg::math::d2r<T>();
return value * bg::math::d2r<double>();
}
static inline rng convert(rng const& value)
{
return value * bg::math::d2r<double>();
}
};
class equals_with_tolerance
{
private:
@@ -118,11 +166,99 @@ private:
public:
equals_with_tolerance(double tolerence) : m_tolerence(tolerence) {}
template <typename T>
inline bool operator()(T const& value1, T const& value2) const
inline bool operator()(double value1, double value2) const
{
return check_close(value1, value2, m_tolerence);
}
inline bool operator()(double l, rng const& r) const
{
return (r.lo < l && l < r.hi)
|| check_close(l, r.lo, m_tolerence)
|| check_close(l, r.hi, m_tolerence);
}
};
bool equals_with_eps(double l, double r)
{
return bg::math::equals(l, r);
}
bool equals_with_eps(double l, rng r)
{
return (r.lo < l && l < r.hi)
|| bg::math::equals(l, r.lo)
|| bg::math::equals(l, r.hi);
}
template
<
typename Box,
std::size_t DimensionCount = bg::dimension<Box>::value
>
struct box_check_equals
{
template <typename T1, typename T2, typename T3, typename T4>
static inline bool apply(Box const& box,
T1 const& lon_min, T2 const& lat_min, double,
T3 const& lon_max, T4 const& lat_max, double,
double tol)
{
equals_with_tolerance equals(tol);
#ifndef BOOST_GEOMETRY_TEST_ENABLE_FAILING
// check latitude with tolerance when necessary
return equals_with_eps(bg::get<0, 0>(box), lon_min)
&& (bg::get<0, 1>(box) < 0
? equals(bg::get<0, 1>(box), lat_min)
: equals_with_eps(bg::get<0, 1>(box), lat_min))
&& equals_with_eps(bg::get<1, 0>(box), lon_max)
&& (bg::get<1, 1>(box) > 0
? equals(bg::get<1, 1>(box), lat_max)
: equals_with_eps(bg::get<1, 1>(box), lat_max));
#else
// check latitude with tolerance when necessary
return bg::get<0, 0>(box) == lon_min
&& (bg::get<0, 1>(box) < 0
? equals(bg::get<0, 1>(box), lat_min)
: bg::get<0, 1>(box) == lat_min)
&& bg::get<1, 0>(box) == lon_max
&& (bg::get<1, 1>(box) > 0
? equals(bg::get<1, 1>(box), lat_max)
: bg::get<1, 1>(box) == lat_max);
#endif
}
};
template <typename Box>
struct box_check_equals<Box, 3>
{
template <typename T1, typename T2, typename T3, typename T4>
static inline bool apply(Box const& box,
T1 const& lon_min, T2 const& lat_min, double height_min,
T3 const& lon_max, T4 const& lat_max, double height_max,
double tol)
{
#ifndef BOOST_GEOMETRY_TEST_ENABLE_FAILING
equals_with_tolerance equals(tol);
return box_check_equals<Box, 2>::apply(box,
lon_min, lat_min, height_min,
lon_max, lat_max, height_max,
tol)
&& equals(bg::get<0, 2>(box), height_min)
&& equals(bg::get<1, 2>(box), height_max);
#else
return box_equals<Box, 2>::apply(box,
lon_min, lat_min, height_min,
lon_max, lat_max, height_max,
tol)
&& bg::get<0, 2>(box) == height_min
&& bg::get<1, 2>(box) == height_max;
#endif
}
};
@@ -136,48 +272,22 @@ struct box_equals
{
static inline bool apply(Box1 const& box1, Box2 const& box2, double tol)
{
equals_with_tolerance equals(tol);
#ifndef BOOST_GEOMETRY_TEST_ENABLE_FAILING
// check latitude with tolerance when necessary
return bg::math::equals(bg::get<0, 0>(box1), bg::get<0, 0>(box2))
&& (bg::get<0, 1>(box1) < 0
? equals(bg::get<0, 1>(box1), bg::get<0, 1>(box2))
: bg::math::equals(bg::get<0, 1>(box1), bg::get<0, 1>(box2)))
&& bg::math::equals(bg::get<1, 0>(box1), bg::get<1, 0>(box2))
&& (bg::get<1, 1>(box1) > 0
? equals(bg::get<1, 1>(box1), bg::get<1, 1>(box2))
: bg::math::equals(bg::get<1, 1>(box1), bg::get<1, 1>(box2)));
#else
// check latitude with tolerance when necessary
return bg::get<0, 0>(box1) == bg::get<0, 0>(box2)
&& (bg::get<0, 1>(box1) < 0
? equals(bg::get<0, 1>(box1), bg::get<0, 1>(box2))
: bg::get<0, 1>(box1) == bg::get<0, 1>(box2))
&& bg::get<1, 0>(box1) == bg::get<1, 0>(box2)
&& (bg::get<1, 1>(box1) > 0
? equals(bg::get<1, 1>(box1), bg::get<1, 1>(box2))
: bg::get<1, 1>(box1) == bg::get<1, 1>(box2));
#endif
return box_check_equals<Box1>::apply(box1,
bg::get<0, 0>(box2), bg::get<0, 1>(box2), 0.0,
bg::get<1, 0>(box2), bg::get<1, 1>(box2), 0.0,
tol);
}
};
template <typename Box1, typename Box2>
template<typename Box1, typename Box2>
struct box_equals<Box1, Box2, 3>
{
static inline bool apply(Box1 const& box1, Box2 const& box2, double tol)
{
#ifndef BOOST_GEOMETRY_TEST_ENABLE_FAILING
equals_with_tolerance equals(tol);
return box_equals<Box1, Box2, 2>::apply(box1, box2, tol)
&& equals(bg::get<0, 2>(box1), bg::get<0, 2>(box2))
&& equals(bg::get<1, 2>(box1), bg::get<1, 2>(box2));
#else
return box_equals<Box1, Box2, 2>::apply(box1, box2, tol)
&& bg::get<0, 2>(box1) == bg::get<0, 2>(box2)
&& bg::get<1, 2>(box1) == bg::get<1, 2>(box2);
#endif
return box_check_equals<Box1>::apply(box1,
bg::get<0, 0>(box2), bg::get<0, 1>(box2), bg::get<0, 2>(box2),
bg::get<1, 0>(box2), bg::get<1, 1>(box2), bg::get<1, 2>(box2),
tol);
}
};

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -63,7 +64,7 @@ typedef bg::model::box<point_type> box_type;
//----------------------------------------------------------------------------
template <typename Geometry>
template <typename CSTag, typename Geometry>
void test_simple(Geometry const& geometry, bool expected_result,
bool check_validity = true)
{
@@ -72,12 +73,22 @@ void test_simple(Geometry const& geometry, bool expected_result,
#endif
bool simple = bg::is_simple(geometry);
BOOST_ASSERT( ! check_validity || bg::is_valid(geometry) );
BOOST_CHECK_MESSAGE( simple == expected_result,
"Expected: " << expected_result
<< " detected: " << simple
<< " wkt: " << bg::wkt(geometry) );
typedef typename bg::strategy::intersection::services::default_strategy
<
CSTag
>::type strategy_type;
bool simple_s = bg::is_simple(geometry, strategy_type());
BOOST_CHECK_EQUAL(simple, simple_s);
#ifdef BOOST_GEOMETRY_TEST_DEBUG
std::cout << "Geometry: ";
pretty_print_geometry<Geometry>::apply(std::cout, geometry);
@@ -92,6 +103,26 @@ void test_simple(Geometry const& geometry, bool expected_result,
}
template <typename Geometry>
void test_simple(Geometry const& geometry,
bool expected_result,
bool check_validity = true)
{
typedef typename bg::cs_tag<Geometry>::type cs_tag;
test_simple<cs_tag>(geometry, expected_result, check_validity);
}
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
void test_simple(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& variant_geometry,
bool expected_result,
bool check_validity = true)
{
typedef typename bg::cs_tag<T0>::type cs_tag;
test_simple<cs_tag>(variant_geometry, expected_result, check_validity);
}
//----------------------------------------------------------------------------

View File

@@ -80,7 +80,7 @@ template <typename P>
void test_vincenty()
{
typename geo_strategies<P>::vincenty_type vincenty;
test_with_strategy<P>(1116828.8624 + 1116161.625, vincenty);
test_with_strategy<P>(1116825.857 + 1116159.144, vincenty);
}
template <typename P>

View File

@@ -83,7 +83,7 @@ template <typename P>
void test_vincenty()
{
typename geo_strategies<P>::vincenty_type vincenty;
test_with_strategy<P>(1116828.8624 + 1116161.625, vincenty);
test_with_strategy<P>(1116825.857 + 1116159.144, vincenty);
}
template <typename P>

View File

@@ -3,8 +3,8 @@
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2016, 2017.
// Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@@ -131,20 +131,28 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
typedef typename bg::coordinate_type<G1>::type coordinate_type;
boost::ignore_unused<coordinate_type>();
bg::model::multi_polygon<OutputType> result;
bg::model::multi_polygon<OutputType> result, result_s;
typedef typename bg::strategy::relate::services::default_strategy
<
G1, G2
>::type strategy_type;
if (sym)
{
bg::sym_difference(g1, g2, result);
bg::sym_difference(g1, g2, result_s, strategy_type());
}
else
{
bg::difference(g1, g2, result);
bg::difference(g1, g2, result_s, strategy_type());
}
if (settings.remove_spikes)
{
bg::remove_spikes(result);
bg::remove_spikes(result_s);
}
std::ostringstream return_string;
@@ -233,6 +241,8 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
}
BOOST_CHECK_CLOSE(area, expected_area, settings.percentage);
BOOST_CHECK_EQUAL(bg::num_points(result), bg::num_points(result_s));
#endif

View File

@@ -1,11 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
#ifndef BOOST_GEOMETRY_TEST_DIFFERENCE_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_TEST_DIFFERENCE_LINEAR_LINEAR_HPP
@@ -25,6 +26,23 @@
//==================================================================
//==================================================================
template <typename Geometry1, typename Geometry2, typename MultiLineString>
inline void check_result(Geometry1 const& geometry1,
Geometry2 const& geometry2,
MultiLineString const& mls_output,
MultiLineString const& mls_diff,
std::string const& case_id,
double tolerance)
{
BOOST_CHECK_MESSAGE( equals::apply(mls_diff, mls_output, tolerance),
"case id: " << case_id
<< ", difference L/L: " << bg::wkt(geometry1)
<< " " << bg::wkt(geometry2)
<< " -> Expected: " << bg::wkt(mls_diff)
<< std::setprecision(20)
<< " computed: " << bg::wkt(mls_output) );
}
template
<
typename Geometry1, typename Geometry2,
@@ -52,6 +70,22 @@ private:
linestring_vector ls_vector_output;
linestring_deque ls_deque_output;
// Check strategy passed explicitly
typedef typename bg::strategy::relate::services::default_strategy
<
Geometry1, Geometry2
>::type strategy_type;
bg::difference(geometry1, geometry2, mls_output, strategy_type());
if (reverse_output_for_checking)
{
bg::reverse(mls_output);
}
check_result(geometry1, geometry2, mls_output, mls_diff, case_id, tolerance);
// Check normal behaviour
bg::clear(mls_output);
bg::difference(geometry1, geometry2, mls_output);
if ( reverse_output_for_checking )
@@ -59,14 +93,8 @@ private:
bg::reverse(mls_output);
}
BOOST_CHECK_MESSAGE( equals::apply(mls_diff, mls_output, tolerance),
"case id: " << case_id
<< ", difference L/L: " << bg::wkt(geometry1)
<< " " << bg::wkt(geometry2)
<< " -> Expected: " << bg::wkt(mls_diff)
<< std::setprecision(20)
<< " computed: " << bg::wkt(mls_output) );
check_result(geometry1, geometry2, mls_output, mls_diff, case_id, tolerance);
set_operation_output("difference", case_id,
geometry1, geometry2, mls_output);

View File

@@ -3,8 +3,8 @@
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2016, 2017.
// Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@@ -189,6 +189,18 @@ typename bg::default_area_result<G1>::type test_intersection(std::string const&
result_type intersection_output;
bg::intersection(g1, g2, intersection_output);
check_result<G1, G2>(intersection_output, caseid, expected_count,
expected_holes_count, expected_point_count, expected_length_or_area,
settings);
// Check strategy passed explicitly
typedef typename bg::strategy::relate::services::default_strategy
<
G1, G2
>::type strategy_type;
intersection_output.clear();
bg::intersection(g1, g2, intersection_output, strategy_type());
check_result<G1, G2>(intersection_output, caseid, expected_count,
expected_holes_count, expected_point_count, expected_length_or_area,
settings);

View File

@@ -1,11 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
#ifndef BOOST_GEOMETRY_TEST_INTERSECTION_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_TEST_INTERSECTION_LINEAR_LINEAR_HPP
@@ -26,6 +27,25 @@
//==================================================================
//==================================================================
template <typename Geometry1, typename Geometry2, typename MultiLineString>
inline void check_result(Geometry1 const& geometry1,
Geometry2 const& geometry2,
MultiLineString const& mls_output,
MultiLineString const& mls_int1,
MultiLineString const& mls_int2,
std::string const& case_id,
double tolerance)
{
BOOST_CHECK_MESSAGE( equals::apply(mls_int1, mls_output, tolerance)
|| equals::apply(mls_int2, mls_output, tolerance),
"case id: " << case_id
<< ", intersection L/L: " << bg::wkt(geometry1)
<< " " << bg::wkt(geometry2)
<< " -> Expected: " << bg::wkt(mls_int1)
<< " or: " << bg::wkt(mls_int2)
<< " computed: " << bg::wkt(mls_output) );
}
template
<
typename Geometry1, typename Geometry2,
@@ -53,16 +73,20 @@ private:
linestring_vector ls_vector_output;
linestring_deque ls_deque_output;
// Check normal behaviour
bg::intersection(geometry1, geometry2, mls_output);
BOOST_CHECK_MESSAGE( equals::apply(mls_int1, mls_output, tolerance)
|| equals::apply(mls_int2, mls_output, tolerance),
"case id: " << case_id
<< ", intersection L/L: " << bg::wkt(geometry1)
<< " " << bg::wkt(geometry2)
<< " -> Expected: " << bg::wkt(mls_int1)
<< " or: " << bg::wkt(mls_int2)
<< " computed: " << bg::wkt(mls_output) );
check_result(geometry1, geometry2, mls_output, mls_int1, mls_int2, case_id, tolerance);
// Check strategy passed explicitly
typedef typename bg::strategy::relate::services::default_strategy
<
Geometry1, Geometry2
>::type strategy_type;
bg::clear(mls_output);
bg::intersection(geometry1, geometry2, mls_output, strategy_type());
check_result(geometry1, geometry2, mls_output, mls_int1, mls_int2, case_id, tolerance);
set_operation_output("intersection", case_id,
geometry1, geometry2, mls_output);
@@ -109,14 +133,7 @@ private:
bg::clear(mls_output);
bg::intersection(geometry2, geometry1, mls_output);
BOOST_CHECK_MESSAGE( equals::apply(mls_int1, mls_output, tolerance)
|| equals::apply(mls_int2, mls_output, tolerance),
"case id: " << case_id
<< ", intersection L/L: " << bg::wkt(geometry1)
<< " " << bg::wkt(geometry2)
<< " -> Expected: " << bg::wkt(mls_int1)
<< " or: " << bg::wkt(mls_int2)
<< " computed: " << bg::wkt(mls_output) );
check_result(geometry1, geometry2, mls_output, mls_int1, mls_int2, case_id, tolerance);
#ifdef BOOST_GEOMETRY_TEST_DEBUG
std::cout << "Geometry #1: " << bg::wkt(geometry2) << std::endl;

Some files were not shown because too many files have changed in this diff Show More