diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 711c33189..511c51402 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -14,8 +14,10 @@ project geometry/doc ; # Auto-index, experimental. Commented otherwise does not build without. #using auto-index ; -import boostbook ; -import quickbook ; +using quickbook ; + +path-constant here : . ; +path-constant images_location : html ; boostbook geometry @@ -23,18 +25,19 @@ boostbook geometry : Jamfile.v2 quickref.xml generated/point.qbk - : chunk.section.depth=4 + chunk.section.depth=4 # off # on # off # index.on.type=1 - html - chunk.first.sections=1 - toc.section.depth=3 - toc.max.depth=2 - generate.section.toc.level=4 - boost.root=../../../.. - enable_index - ; - +# html + chunk.first.sections=1 + toc.section.depth=3 + toc.max.depth=2 + generate.section.toc.level=4 + boost.root=../../../.. + enable_index + $(here) + pdf:img.src.path=$(images_location)/ +; diff --git a/doc/introduction.qbk b/doc/introduction.qbk index 266997946..0ccd76ddc 100644 --- a/doc/introduction.qbk +++ b/doc/introduction.qbk @@ -39,10 +39,17 @@ The library follows existing conventions: * conventions from the std library * conventions and names from one of the __ogc__ standards on geometry -The library can be downloaded from [@http://svn.boost.org/svn/boost/trunk Boost.Trunk], -from [@http://svn.boost.org/svn/boost/branches/release Boost.Release], or will come -to you by the normal Boost distribution process. Note that [*extensions] are -only distributed in Boost.Trunk, and that they are subject to change. +The library was released with Boost 1.47.0 and from that point on it is oficially part of the Boost C++ Libraries. + +Latest stable version of the source code is included in the [@http://www.boost.org/users/download/ Boost packaged releases]. +It can also be downloaded from the current [@http://svn.boost.org/svn/boost/branches/release Boost release branch] +in the Boost Subversion repository. + +The library development upstream is available from the [@http://svn.boost.org/svn/boost/trunk Boost trunk] in the Boost Subversion repository. + +Note that the library [*extensions] are not distributed in the official Boost releases, but only available +in the [@http://svn.boost.org/svn/boost/trunk/boost/geometry/extensions/ Boost trunk] +and that they are subject to change. __boost_geometry__ was accepted by Boost at November 28, 2009 ([@http://permalink.gmane.org/gmane.comp.lib.boost.announce/246 review report]). diff --git a/doc/reference/algorithms/convex_hull.qbk b/doc/reference/algorithms/convex_hull.qbk index 2a1de1892..6916d4066 100644 --- a/doc/reference/algorithms/convex_hull.qbk +++ b/doc/reference/algorithms/convex_hull.qbk @@ -11,7 +11,7 @@ =============================================================================/] [heading Complexity] -Linear +Logarithmic [heading Example] [convex_hull] diff --git a/doc/src/examples/algorithms/create_svg_overlay.hpp b/doc/src/examples/algorithms/create_svg_overlay.hpp index a8ed47bcf..add3bb3f6 100644 --- a/doc/src/examples/algorithms/create_svg_overlay.hpp +++ b/doc/src/examples/algorithms/create_svg_overlay.hpp @@ -12,6 +12,8 @@ #define CREATE_SVG_OVERLAY_HPP #include + +#include #include #if defined(HAVE_SVG) diff --git a/doc/src/examples/geometries/adapted/boost_fusion.cpp b/doc/src/examples/geometries/adapted/boost_fusion.cpp index f13c6bad6..405e5a970 100644 --- a/doc/src/examples/geometries/adapted/boost_fusion.cpp +++ b/doc/src/examples/geometries/adapted/boost_fusion.cpp @@ -24,7 +24,7 @@ struct sample_point }; BOOST_FUSION_ADAPT_STRUCT(sample_point, (double, x) (double, y) (double, z)) -BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(sample_point) +BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(cs::cartesian) int main() { diff --git a/example/ml01_multipolygon_simplify.cpp b/example/ml01_multipolygon_simplify.cpp new file mode 100644 index 000000000..d423c6983 --- /dev/null +++ b/example/ml01_multipolygon_simplify.cpp @@ -0,0 +1,67 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2009-2011 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) +// +// Multipolygon DP simplification example from the mailing list discussion +// about the DP algorithm issue: +// http://lists.osgeo.org/pipermail/ggl/2011-September/001533.html + +#include +#include +#include +#include +#include +#include + +int main() +{ + typedef boost::geometry::model::d2::point_xy point_xy; + typedef boost::geometry::model::polygon polygon; + typedef boost::geometry::model::ring ring; + typedef boost::geometry::model::multi_polygon multi_polygon; + + multi_polygon original_1; + multi_polygon simplified_1; + + // Values between 0..1 and simplified with 1/2048 + boost::geometry::read_wkt("MULTIPOLYGON(((0.561648 1,1 1,1 0,0.468083 0,0.52758 0.00800554,0.599683 0.0280924,0.601611 0.265374,0.622693 0.316765,0.69507 0.357497,0.695623 0.429711,0.655111 0.502298,0.696467 0.543147,0.840712 0.593546,0.882583 0.66546,0.852357 0.748213,0.84264 0.789567,0.832667 0.841202,0.832667 0.841202,0.740538 0.873004,0.617349 0.905045,0.566576 0.977697,0.561648 1)),((0 0.801979,0.0308575 0.786234,0.0705513 0.631135,0.141616 0.527248,0.233985 0.505872,0.264777 0.526263,0.336631 0.505009,0.356603 0.422321,0.355803 0.350038,0.375252 0.205364,0.415206 0.0709182,0.45479 0,0 0,0 0,0 0.801979)))", original_1); + + std::cout << "Original: \n" << boost::geometry::num_points(original_1) << " points.\n\n"; + + boost::geometry::simplify(original_1, simplified_1, 1.0 / 2048.0); + + std::cout << "Polygon with values 0..1 and simplified with 1.0 / 2048.0 \n" + << "Result: \n" << boost::geometry::wkt(simplified_1) << "\n" << boost::geometry::num_points(simplified_1) << " points.\n\n"; + + // Multiply every points from original_1 by 2047 + multi_polygon original_2(original_1); + BOOST_FOREACH(polygon& p, original_2) + { + BOOST_FOREACH(point_xy& pt, p.outer()) + { + pt.x(pt.x() * 2047.0); + pt.y(pt.y() * 2047.0); + } + + BOOST_FOREACH(ring& r, p.inners()) + { + BOOST_FOREACH(point_xy& pt, r) + { + pt.x(pt.x() * 2047.0); + pt.y(pt.y() * 2047.0); + } + } + } + + multi_polygon simplified_2; + boost::geometry::simplify(original_2, simplified_2, 1.0); + std::cout << "Same values but multiplied by 2047.0 and simplified with 1.0\n" + << "Result: \n" << boost::geometry::wkt(simplified_2) << "\n" << boost::geometry::num_points(simplified_2) << " points.\n"; + + return 0; +} + diff --git a/example/ml01_multipolygon_simplify.vcproj b/example/ml01_multipolygon_simplify.vcproj new file mode 100644 index 000000000..fe5492da9 --- /dev/null +++ b/example/ml01_multipolygon_simplify.vcproj @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ml02_distance_strategy.cpp b/example/ml02_distance_strategy.cpp new file mode 100644 index 000000000..3b887d5e4 --- /dev/null +++ b/example/ml02_distance_strategy.cpp @@ -0,0 +1,36 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2009-2011 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) +// +// Multipolygon DP simplification example from the mailing list discussion +// about the DP algorithm issue: +// http://lists.osgeo.org/pipermail/ggl/2011-September/001533.html + +#include +#include +#include +using namespace boost::geometry; + +int main() +{ + typedef model::d2::point_xy point_xy; + + point_xy p1(0.0, 0.0); + point_xy p2(5.0, 0.0); + + // 1) This is direct call to Pythagoras algo + typedef strategy::distance::pythagoras strategy1_type; + strategy1_type strategy1; + strategy1_type ::calculation_type d1 = strategy1.apply(p1, p2); + + // 2) This is what is effectively called by simplify + typedef strategy::distance::comparable::pythagoras strategy2_type; + strategy2_type strategy2; + strategy2_type::calculation_type d2 = strategy2.apply(p1, p2); + + return 0; +} diff --git a/example/ml02_distance_strategy.vcproj b/example/ml02_distance_strategy.vcproj new file mode 100644 index 000000000..0b04ecfac --- /dev/null +++ b/example/ml02_distance_strategy.vcproj @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/boost/geometry/algorithms/assign.hpp b/include/boost/geometry/algorithms/assign.hpp index df5cd663d..74089f95b 100644 --- a/include/boost/geometry/algorithms/assign.hpp +++ b/include/boost/geometry/algorithms/assign.hpp @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include @@ -122,124 +124,6 @@ inline void assign_zero(Geometry& geometry) >::apply(geometry); } - -#ifndef DOXYGEN_NO_DETAIL -namespace detail -{ -// Note: this is moved to namespace detail because the names and parameter orders -// are not yet 100% clear. - -/*! -\brief Assign the four points of a 2D box -\ingroup assign -\note The order is crucial. Most logical is LOWER, UPPER and sub-order LEFT, RIGHT - so this is how it is implemented. -\tparam Box \tparam_box -\tparam Point \tparam_point -\param box \param_box -\param lower_left point being assigned to lower left coordinates of the box -\param lower_right point being assigned to lower right coordinates of the box -\param upper_left point being assigned to upper left coordinates of the box -\param upper_right point being assigned to upper right coordinates of the box - -\qbk{ -[heading Example] -[assign_box_corners] [assign_box_corners_output] -} -*/ -template -inline void assign_box_corners(Box const& box, - Point& lower_left, Point& lower_right, - Point& upper_left, Point& upper_right) -{ - concept::check(); - concept::check(); - - detail::assign::assign_box_2d_corner - (box, lower_left); - detail::assign::assign_box_2d_corner - (box, lower_right); - detail::assign::assign_box_2d_corner - (box, upper_left); - detail::assign::assign_box_2d_corner - (box, upper_right); -} - -template -inline void assign_box_corners_oriented(Box const& box, Range& corners) -{ - if (Reverse) - { - // make counterclockwise ll,lr,ur,ul - assign_box_corners(box, corners[0], corners[1], corners[3], corners[2]); - } - else - { - // make clockwise ll,ul,ur,lr - assign_box_corners(box, corners[0], corners[3], corners[1], corners[2]); - } -} - - -/*! -\brief Assign a box or segment with the value of a point -\ingroup assign -\tparam Index indicates which box-corner, min_corner (0) or max_corner (1) - or which point of segment (0/1) -\tparam Point \tparam_point -\tparam Geometry \tparam_box_or_segment -\param point \param_point -\param geometry \param_box_or_segment - -\qbk{ -[heading Example] -[assign_point_to_index] [assign_point_to_index_output] -} -*/ -template -inline void assign_point_to_index(Point const& point, Geometry& geometry) -{ - concept::check(); - concept::check(); - - detail::assign::assign_point_to_index - < - Geometry, Point, Index, 0, dimension::type::value - >::apply(point, geometry); -} - - -/*! -\brief Assign a point with a point of a box or segment -\ingroup assign -\tparam Index indicates which box-corner, min_corner (0) or max_corner (1) - or which point of segment (0/1) -\tparam Geometry \tparam_box_or_segment -\tparam Point \tparam_point -\param geometry \param_box_or_segment -\param point \param_point - -\qbk{ -[heading Example] -[assign_point_from_index] [assign_point_from_index_output] -} -*/ -template -inline void assign_point_from_index(Geometry const& geometry, Point& point) -{ - concept::check(); - concept::check(); - - detail::assign::assign_point_from_index - < - Geometry, Point, Index, 0, dimension::type::value - >::apply(geometry, point); -} - -} // namespace detail -#endif // DOXYGEN_NO_DETAIL - - /*! \brief Assigns one geometry to another geometry \details The assign algorithm assigns one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only @@ -263,8 +147,25 @@ inline void assign(Geometry1& geometry1, Geometry2 const& geometry2) { concept::check_concepts_and_equal_dimensions(); + bool const same_point_order = + point_order::value == point_order::value; + bool const same_closure = + closure::value == closure::value; + + BOOST_MPL_ASSERT_MSG + ( + same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER + , (types) + ); + BOOST_MPL_ASSERT_MSG + ( + same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE + , (types) + ); + dispatch::convert < + false, typename tag::type, typename tag::type, dimension::type::value, diff --git a/include/boost/geometry/algorithms/convert.hpp b/include/boost/geometry/algorithms/convert.hpp index b90e008c1..e6f16a77f 100644 --- a/include/boost/geometry/algorithms/convert.hpp +++ b/include/boost/geometry/algorithms/convert.hpp @@ -11,23 +11,31 @@ // 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_CONVERT_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_HPP +#ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP #include #include #include +#include #include #include #include #include #include +#include +#include #include +#include +#include + #include +#include +#include #include @@ -76,6 +84,123 @@ struct point_to_box {} }; +template +struct box_to_range +{ + static inline void apply(Box const& box, Range& range) + { + traits::resize::apply(range, Close ? 5 : 4); + assign_box_corners_oriented(box, range); + if (Close) + { + range[4] = range[0]; + } + } +}; + +template +struct segment_to_range +{ + static inline void apply(Segment const& segment, Range& range) + { + traits::resize::apply(range, 2); + + typename boost::range_iterator::type it = boost::begin(range); + + assign_point_from_index<0>(segment, *it); + ++it; + assign_point_from_index<1>(segment, *it); + } +}; + +template +< + typename Range1, + typename Range2, + bool Reverse = false +> +struct range_to_range +{ + typedef typename reversible_view + < + Range1 const, + Reverse ? iterate_reverse : iterate_forward + >::type rview_type; + typedef typename closeable_view + < + rview_type const, + geometry::closure::value + >::type view_type; + + static inline void apply(Range1 const& source, Range2& destination) + { + geometry::clear(destination); + + rview_type rview(source); + + // We consider input always as closed, and skip last + // point for open output. + view_type view(rview); + + int n = boost::size(view); + if (geometry::closure::value == geometry::open) + { + n--; + } + + int i = 0; + for (typename boost::range_iterator::type it + = boost::begin(view); + it != boost::end(view) && i < n; + ++it, ++i) + { + geometry::append(destination, *it); + } + } +}; + +template +struct polygon_to_polygon +{ + typedef range_to_range + < + typename geometry::ring_type::type, + typename geometry::ring_type::type, + geometry::point_order::value + != geometry::point_order::value + > per_ring; + + static inline void apply(Polygon1 const& source, Polygon2& destination) + { + // Clearing managed per ring, and in the resizing of interior rings + + per_ring::apply(geometry::exterior_ring(source), + geometry::exterior_ring(destination)); + + // Container should be resizeable + traits::resize + < + typename boost::remove_reference + < + typename traits::interior_mutable_type::type + >::type + >::apply(interior_rings(destination), num_interior_rings(source)); + + typename interior_return_type::type rings_source + = interior_rings(source); + typename interior_return_type::type rings_dest + = interior_rings(destination); + + BOOST_AUTO_TPL(it_source, boost::begin(rings_source)); + BOOST_AUTO_TPL(it_dest, boost::begin(rings_dest)); + + for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest) + { + per_ring::apply(*it_source, *it_dest); + } + } +}; + }} // namespace detail::conversion #endif // DOXYGEN_NO_DETAIL @@ -87,12 +212,18 @@ namespace dispatch template < + bool UseAssignment, typename Tag1, typename Tag2, std::size_t DimensionCount, typename Geometry1, typename Geometry2 > struct convert { + BOOST_MPL_ASSERT_MSG + ( + false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES + , (types) + ); }; @@ -102,10 +233,9 @@ template std::size_t DimensionCount, typename Geometry1, typename Geometry2 > -struct convert +struct convert { - // Same geometry type -> copy coordinates from G1 to G2 - // Actually: we try now to just copy it + // Same geometry type -> copy whole geometry static inline void apply(Geometry1 const& source, Geometry2& destination) { destination = source; @@ -118,57 +248,51 @@ template std::size_t DimensionCount, typename Geometry1, typename Geometry2 > -struct convert +struct convert : detail::conversion::point_to_point {}; +template +struct convert + : detail::conversion::segment_to_range +{}; + template -struct convert -{ - static inline void apply(Ring1 const& source, Ring2& destination) - { - geometry::clear(destination); - for (typename boost::range_iterator::type it - = boost::begin(source); - it != boost::end(source); - ++it) - { - geometry::append(destination, *it); - } - } -}; +struct convert + : detail::conversion::range_to_range + < + Ring1, + Ring2, + geometry::point_order::value + != geometry::point_order::value + > +{}; +template +struct convert + : detail::conversion::range_to_range +{}; + +template +struct convert + : detail::conversion::polygon_to_polygon +{}; template -struct convert -{ - static inline void apply(Box const& box, Ring& ring) - { - // go from box to ring -> add coordinates in correct order - geometry::clear(ring); - typename point_type::type point; - - geometry::assign_values(point, get(box), get(box)); - geometry::append(ring, point); - - geometry::assign_values(point, get(box), get(box)); - geometry::append(ring, point); - - geometry::assign_values(point, get(box), get(box)); - geometry::append(ring, point); - - geometry::assign_values(point, get(box), get(box)); - geometry::append(ring, point); - - geometry::assign_values(point, get(box), get(box)); - geometry::append(ring, point); - } -}; +struct convert + : detail::conversion::box_to_range + < + Box, + Ring, + geometry::closure::value == closed, + geometry::point_order::value == counterclockwise + > +{}; template -struct convert +struct convert { static inline void apply(Box const& box, Polygon& polygon) { @@ -176,7 +300,7 @@ struct convert convert < - box_tag, ring_tag, + false, box_tag, ring_tag, 2, Box, ring_type >::apply(box, exterior_ring(polygon)); } @@ -184,7 +308,7 @@ struct convert template -struct convert +struct convert { static inline void apply(Point const& point, Box& box) { @@ -201,14 +325,14 @@ struct convert template -struct convert +struct convert { static inline void apply(Ring const& ring, Polygon& polygon) { typedef typename ring_type::type ring_type; convert < - ring_tag, ring_tag, DimensionCount, + false, ring_tag, ring_tag, DimensionCount, Ring, ring_type >::apply(ring, exterior_ring(polygon)); } @@ -216,7 +340,7 @@ struct convert template -struct convert +struct convert { static inline void apply(Polygon const& polygon, Ring& ring) { @@ -224,6 +348,7 @@ struct convert convert < + false, ring_tag, ring_tag, DimensionCount, ring_type, Ring >::apply(exterior_ring(polygon), ring); @@ -237,8 +362,11 @@ struct convert /*! \brief Converts one geometry to another geometry -\details The convert algorithm converts one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only -if it is possible and applicable. +\details The convert algorithm converts one geometry, e.g. a BOX, to another +geometry, e.g. a RING. This only if it is possible and applicable. +If the point-order is different, or the closure is different between two +geometry types, it will be converted correctly by explicitly reversing the +points or closing or opening the polygon rings. \ingroup convert \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry @@ -254,8 +382,11 @@ inline void convert(Geometry1 const& geometry1, Geometry2& geometry2) dispatch::convert < - typename tag::type, - typename tag::type, + boost::is_same::value + // && boost::has_assign::value, -- type traits extensions + && ! boost::is_array::value, + typename tag_cast::type, multi_tag>::type, + typename tag_cast::type, multi_tag>::type, dimension::type::value, Geometry1, Geometry2 @@ -266,4 +397,4 @@ inline void convert(Geometry1 const& geometry1, Geometry2& geometry2) }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_HPP +#endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP diff --git a/include/boost/geometry/algorithms/covered_by.hpp b/include/boost/geometry/algorithms/covered_by.hpp new file mode 100644 index 000000000..3e099126a --- /dev/null +++ b/include/boost/geometry/algorithms/covered_by.hpp @@ -0,0 +1,206 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_ALGORITHMS_COVERED_BY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP + + +#include + + +#include + + +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Tag1, + typename Tag2, + typename Geometry1, + typename Geometry2, + typename Strategy +> +struct covered_by +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE + , (types) + ); +}; + + +template +struct covered_by +{ + static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) + { + return strategy.apply(point, box); + } +}; + +template +struct covered_by +{ + static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) + { + assert_dimension_equal(); + return strategy.apply(box1, box2); + } +}; + + + +template +struct covered_by +{ + static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy) + { + return detail::within::point_in_ring + < + Point, + Ring, + order_as_direction::value>::value, + geometry::closure::value, + Strategy + >::apply(point, ring) >= 0; + } +}; + +template +struct covered_by +{ + static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy) + { + return detail::within::point_in_polygon + < + Point, + Polygon, + order_as_direction::value>::value, + geometry::closure::value, + Strategy + >::apply(point, polygon, strategy) >= 0; + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +/*! +\brief \brief_check12{is inside or on border} +\ingroup covered_by +\details \details_check12{covered_by, is inside or on border}. +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param geometry1 geometry which might be covered_by the second geometry +\param geometry2 geometry which might contain the first geometry +\return true if geometry1 is completely contained covered_by geometry2, + else false +\note The default strategy is used for covered_by detection + + */ +template +inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + concept::check(); + concept::check(); + assert_dimension_equal(); + + typedef typename point_type::type point_type1; + typedef typename point_type::type point_type2; + + typedef typename strategy::covered_by::services::default_strategy + < + typename tag::type, + typename tag::type, + typename tag::type, + typename tag_cast::type, areal_tag>::type, + typename tag_cast + < + typename cs_tag::type, spherical_tag + >::type, + typename tag_cast + < + typename cs_tag::type, spherical_tag + >::type, + Geometry1, + Geometry2 + >::type strategy_type; + + return dispatch::covered_by + < + typename tag::type, + typename tag::type, + Geometry1, + Geometry2, + strategy_type + >::apply(geometry1, geometry2, strategy_type()); +} + +/*! +\brief \brief_check12{is inside or on border} \brief_strategy +\ingroup covered_by +\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons +\tparam Geometry1 \tparam_geometry +\tparam Geometry2 \tparam_geometry +\param geometry1 \param_geometry +\param geometry2 \param_geometry +\param geometry1 \param_geometry geometry which might be covered_by the second geometry +\param geometry2 \param_geometry which might contain the first geometry +\param strategy strategy to be used +\return true if geometry1 is completely contained covered_by geometry2, + else false + +\qbk{distinguish,with strategy} + +*/ +template +inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) +{ + concept::within::check + < + typename tag::type, + typename tag::type, + typename tag_cast::type, areal_tag>::type, + Strategy + >(); + concept::check(); + concept::check(); + assert_dimension_equal(); + + return dispatch::covered_by + < + typename tag::type, + typename tag::type, + Geometry1, + Geometry2, + Strategy + >::apply(geometry1, geometry2, strategy); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP diff --git a/include/boost/geometry/algorithms/detail/assign_box_corners.hpp b/include/boost/geometry/algorithms/detail/assign_box_corners.hpp new file mode 100644 index 000000000..1262dd6ed --- /dev/null +++ b/include/boost/geometry/algorithms/detail/assign_box_corners.hpp @@ -0,0 +1,93 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP + + +#include + +#include +#include + + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ +// Note: this is moved to namespace detail because the names and parameter orders +// are not yet 100% clear. + +/*! +\brief Assign the four points of a 2D box +\ingroup assign +\note The order is crucial. Most logical is LOWER, UPPER and sub-order LEFT, RIGHT + so this is how it is implemented. +\tparam Box \tparam_box +\tparam Point \tparam_point +\param box \param_box +\param lower_left point being assigned to lower left coordinates of the box +\param lower_right point being assigned to lower right coordinates of the box +\param upper_left point being assigned to upper left coordinates of the box +\param upper_right point being assigned to upper right coordinates of the box + +\qbk{ +[heading Example] +[assign_box_corners] [assign_box_corners_output] +} +*/ +template +inline void assign_box_corners(Box const& box, + Point& lower_left, Point& lower_right, + Point& upper_left, Point& upper_right) +{ + concept::check(); + concept::check(); + + detail::assign::assign_box_2d_corner + (box, lower_left); + detail::assign::assign_box_2d_corner + (box, lower_right); + detail::assign::assign_box_2d_corner + (box, upper_left); + detail::assign::assign_box_2d_corner + (box, upper_right); +} + +template +inline void assign_box_corners_oriented(Box const& box, Range& corners) +{ + if (Reverse) + { + // make counterclockwise ll,lr,ur,ul + assign_box_corners(box, corners[0], corners[1], corners[3], corners[2]); + } + else + { + // make clockwise ll,ul,ur,lr + assign_box_corners(box, corners[0], corners[3], corners[1], corners[2]); + } +} + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP diff --git a/include/boost/geometry/algorithms/detail/assign_indexed_point.hpp b/include/boost/geometry/algorithms/detail/assign_indexed_point.hpp new file mode 100644 index 000000000..3be239018 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/assign_indexed_point.hpp @@ -0,0 +1,94 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP + + +#include + +#include +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +/*! +\brief Assign a box or segment with the value of a point +\ingroup assign +\tparam Index indicates which box-corner, min_corner (0) or max_corner (1) + or which point of segment (0/1) +\tparam Point \tparam_point +\tparam Geometry \tparam_box_or_segment +\param point \param_point +\param geometry \param_box_or_segment + +\qbk{ +[heading Example] +[assign_point_to_index] [assign_point_to_index_output] +} +*/ +template +inline void assign_point_to_index(Point const& point, Geometry& geometry) +{ + concept::check(); + concept::check(); + + detail::assign::assign_point_to_index + < + Geometry, Point, Index, 0, dimension::type::value + >::apply(point, geometry); +} + + +/*! +\brief Assign a point with a point of a box or segment +\ingroup assign +\tparam Index indicates which box-corner, min_corner (0) or max_corner (1) + or which point of segment (0/1) +\tparam Geometry \tparam_box_or_segment +\tparam Point \tparam_point +\param geometry \param_box_or_segment +\param point \param_point + +\qbk{ +[heading Example] +[assign_point_from_index] [assign_point_from_index_output] +} +*/ +template +inline void assign_point_from_index(Geometry const& geometry, Point& point) +{ + concept::check(); + concept::check(); + + detail::assign::assign_point_from_index + < + Geometry, Point, Index, 0, dimension::type::value + >::apply(geometry, point); +} + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP diff --git a/include/boost/geometry/algorithms/detail/assign_values.hpp b/include/boost/geometry/algorithms/detail/assign_values.hpp index d9c6fc49d..17f1ac794 100644 --- a/include/boost/geometry/algorithms/detail/assign_values.hpp +++ b/include/boost/geometry/algorithms/detail/assign_values.hpp @@ -90,14 +90,7 @@ struct assign_inverse_box_or_segment static inline void apply(BoxOrSegment& geometry) { - typedef typename coordinate_type::type coordinate_type; - - typedef typename boost::mpl::if_ - < - typename boost::is_arithmetic::type, - coordinate_type, - double - >::type bound_type; + typedef typename coordinate_type::type bound_type; initialize < @@ -207,7 +200,7 @@ struct assign_point_from_index { geometry::set( point, boost::numeric_cast < - typename coordinate_type::type + typename coordinate_type::type >(geometry::get(geometry))); assign_point_from_index diff --git a/include/boost/geometry/algorithms/detail/has_self_intersections.hpp b/include/boost/geometry/algorithms/detail/has_self_intersections.hpp index 38493878c..e466b26f8 100644 --- a/include/boost/geometry/algorithms/detail/has_self_intersections.hpp +++ b/include/boost/geometry/algorithms/detail/has_self_intersections.hpp @@ -59,11 +59,10 @@ namespace detail { namespace overlay template inline bool has_self_intersections(Geometry const& geometry) { - using namespace boost::geometry; typedef typename point_type::type point_type; typedef detail::overlay::turn_info turn_info; std::deque turns; - detail::get_turns::no_interrupt_policy policy; + detail::disjoint::disjoint_interrupt_policy policy; geometry::self_turns(geometry, turns, policy); #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS diff --git a/include/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/include/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp new file mode 100644 index 000000000..b9b50b238 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp @@ -0,0 +1,53 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. + +// 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_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP + + +#include + +#include +#include + + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +template +inline void append_no_duplicates(Range& range, Point const& point, bool force = false) +{ + if (boost::size(range) == 0 + || force + || ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point)) + { +#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION + std::cout << " add: (" + << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" + << std::endl; +#endif + geometry::append(range, point); + } +} + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index 423e051f9..be992ac86 100644 --- a/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include @@ -42,23 +42,22 @@ static inline bool within_selected_input(Item const& item2, ring_identifier cons typedef typename geometry::tag::type tag1; typedef typename geometry::tag::type tag2; - int code = -1; switch (ring_id.source_index) { case 0 : - code = point_in_ring(item2.point, + return geometry::within(item2.point, get_ring::apply(ring_id, geometry1)); break; case 1 : - code = point_in_ring(item2.point, + return geometry::within(item2.point, get_ring::apply(ring_id, geometry2)); break; case 2 : - code = point_in_ring(item2.point, + return geometry::within(item2.point, get_ring::apply(ring_id, collection)); break; } - return code == 1; + return false; } @@ -77,7 +76,7 @@ struct ring_info_helper {} inline ring_info_helper(ring_identifier i, area_type a) - : id(i), real_area(a), abs_area(abs(a)) + : id(i), real_area(a), abs_area(geometry::math::abs(a)) {} }; diff --git a/include/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/include/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp new file mode 100644 index 000000000..ad0b304d3 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp @@ -0,0 +1,181 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. + +// 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_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP + + +#include + +#include + +#include + +#include +#include + +# include + + +#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) +# include +# include +#endif + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +inline void clear_visit_info(Turns& turns) +{ + typedef typename boost::range_value::type tp_type; + + for (typename boost::range_iterator::type + it = boost::begin(turns); + it != boost::end(turns); + ++it) + { + for (typename boost::range_iterator + < + typename tp_type::container_type + >::type op_it = boost::begin(it->operations); + op_it != boost::end(it->operations); + ++op_it) + { + op_it->visited.clear(); + } + it->discarded = false; + } +} + +struct backtrack_state +{ + bool m_good; + + inline backtrack_state() : m_good(true) {} + inline void reset() { m_good = true; } + inline bool good() const { return m_good; } +}; + + +template +< + typename Geometry1, + typename Geometry2 +> +class backtrack_check_self_intersections +{ + struct state : public backtrack_state + { + bool m_checked; + inline state() + : m_checked() + {} + }; +public : + typedef state state_type; + + template + static inline void apply(std::size_t size_at_start, + Rings& rings, typename boost::range_value::type& ring, + Turns& turns, Operation& operation, + std::string const& , + Geometry1 const& geometry1, + Geometry2 const& geometry2, + state_type& state + ) + { + state.m_good = false; + + // Check self-intersections and throw exception if appropriate + if (! state.m_checked) + { + state.m_checked = true; + has_self_intersections(geometry1); + has_self_intersections(geometry2); + } + + // Make bad output clean + rings.resize(size_at_start); + ring.clear(); + + // Reject this as a starting point + operation.visited.set_rejected(); + + // And clear all visit info + clear_visit_info(turns); + } +}; + +#ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT +template +< + typename Geometry1, + typename Geometry2 +> +class backtrack_debug +{ +public : + typedef backtrack_state state_type; + + template + static inline void apply(std::size_t size_at_start, + Rings& rings, typename boost::range_value::type& ring, + Turns& turns, Operation& operation, + std::string const& reason, + Geometry1 const& geometry1, + Geometry2 const& geometry2, + state_type& state + ) + { + std::cout << " REJECT " << reason << std::endl; + + state.m_good = false; + + rings.resize(size_at_start); + ring.clear(); + operation.visited.set_rejected(); + clear_visit_info(turns); + + int c = 0; + for (int i = 0; i < turns.size(); i++) + { + for (int j = 0; j < 2; j++) + { + if (turns[i].operations[j].visited.rejected()) + { + c++; + } + } + } + std::cout << "BACKTRACK (" << reason << " )" + << " " << c << " of " << turns.size() << " rejected" + << std::endl; + std::cout + << geometry::wkt(geometry1) << std::endl + << geometry::wkt(geometry2) << std::endl; + } +}; +#endif // BOOST_GEOMETRY_OVERLAY_REPORT_WKT + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/include/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp index a88060efb..5b0c38467 100644 --- a/include/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp @@ -10,7 +10,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP -#include +#include namespace boost { namespace geometry @@ -34,9 +34,9 @@ struct calculate_distance_policy static inline void apply(Info& info, Point1 const& p1, Point2 const& p2) { info.operations[0].enriched.distance - = geometry::distance(info.point, p1); + = geometry::comparable_distance(info.point, p1); info.operations[1].enriched.distance - = geometry::distance(info.point, p2); + = geometry::comparable_distance(info.point, p2); } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp b/include/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp index 6e8a7f6c3..801890a32 100644 --- a/include/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp @@ -11,10 +11,11 @@ #include -#include #include #include +#include + #include #include @@ -215,9 +216,9 @@ OutputIterator clip_range_with_box(Box const& b, Range const& range, // b. Add p1 only if it is the first point, then add p2 if (boost::empty(line_out)) { - geometry::append(line_out, p1); + detail::overlay::append_no_duplicates(line_out, p1, true); } - geometry::append(line_out, p2); + detail::overlay::append_no_duplicates(line_out, p2); // c. If c2 is clipped, finish the line if (c2) diff --git a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index 36cc9f5fb..c03f77e9f 100644 --- a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -27,6 +27,7 @@ #include #include +#include namespace boost { namespace geometry { @@ -92,12 +93,7 @@ struct copy_segments_ring for (size_type i = 0; i < count; ++i, ++it) { -#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION - std::cout << " add: (" - << geometry::get<0>(*it) << ", " << geometry::get<1>(*it) << ")" - << std::endl; -#endif - geometry::append(current_output, *it); + detail::overlay::append_no_duplicates(current_output, *it); } } }; @@ -164,7 +160,8 @@ struct copy_segments_box // (see comments in ring-version) for (int i = 0; i < count; i++, index++) { - geometry::append(current_output, bp[index % 5]); + detail::overlay::append_no_duplicates(current_output, bp[index % 5]); + } } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp index 132b2dbf1..9d838fb49 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp @@ -10,7 +10,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP -#include +#include namespace boost { namespace geometry @@ -23,15 +23,25 @@ namespace detail { namespace overlay /*! - \brief Keeps info to enrich intersection info (per source) - \details Class to keep information necessary for traversal phase (a phase - of the overlay process). The information is gathered during the - enrichment phase +\brief Keeps info to enrich intersection info (per source) +\details Class to keep information necessary for traversal phase (a phase + of the overlay process). The information is gathered during the + enrichment phase */ template struct enrichment_info { - typedef typename default_distance_result::type distance_type; + typedef typename strategy::distance::services::return_type + < + typename strategy::distance::services::comparable_type + < + typename strategy::distance::services::default_strategy + < + point_tag, + P + >::type + >::type + >::type distance_type; inline enrichment_info() : travels_to_vertex_index(-1) diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 6b7fbe19d..e79bf4ed9 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -127,6 +127,31 @@ class get_turns_in_sections >::type range2_iterator; + template + static inline bool neighbouring(Section const& section, + int index1, int index2) + { + // About n-2: + // (square: range_count=5, indices 0,1,2,3 + // -> 0-3 are adjacent, don't check on intersections) + // Also tested for open polygons, and/or duplicates + // About first condition: will be optimized by compiler (static) + // It checks if it is areal (box,ring,(multi)polygon + int const n = int(section.range_count); + return boost::is_same + < + typename tag_cast + < + typename geometry::point_type::type, + areal_tag + >::type, + areal_tag + >::value + && index1 == 0 + && index2 >= n - 2 + ; + } + public : // Returns true if terminated, false if interrupted @@ -196,7 +221,7 @@ public : if (skip) { // If sources are the same (possibly self-intersecting): - // skip if it is a neighbouring sement. + // skip if it is a neighbouring segment. // (including first-last segment // and two segments with one or more degenerate/duplicate // (zero-length) segments in between) @@ -204,12 +229,9 @@ public : // Also skip if index1 < index2 to avoid getting all // intersections twice (only do this on same source!) - // About n-2: - // (square: range_count=5, indices 0,1,2,3 - // -> 0-3 are adjacent) - skip = index2 >= index1 - || ndi1 == ndi2 + 1 - || (index2 == 0 && index1 >= int(sec1.range_count) - 2) + skip = index1 >= index2 + || ndi2 == ndi1 + 1 + || neighbouring(sec1, index1, index2) ; } @@ -492,9 +514,9 @@ struct get_turns_cs next++; next++; - bool first = true; + //bool first = true; - char previous_side[2] = {0, 0}; + //char previous_side[2] = {0, 0}; int index = 0; @@ -505,7 +527,7 @@ struct get_turns_cs segment_identifier seg_id(source_id1, multi_index, ring_index, index); - if (first) + /*if (first) { previous_side[0] = get_side<0>(box, *prev); previous_side[1] = get_side<1>(box, *prev); @@ -519,7 +541,7 @@ struct get_turns_cs // 1) EITHER the two points are lying on one side of the box (! 0 && the same) // 2) OR same in Y-direction // 3) OR all points are inside the box (0) - /*if (! ( + if (! ( (current_side[0] != 0 && current_side[0] == previous_side[0]) || (current_side[1] != 0 && current_side[1] == previous_side[1]) || (current_side[0] == 0 diff --git a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index be5efb371..5ae8f772c 100644 --- a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -295,6 +295,49 @@ struct intersection_insert } }; +template +< + typename Tag1, typename Tag2, + bool Areal1, bool Areal2, + typename Geometry1, typename Geometry2, + bool Reverse1, bool Reverse2, bool ReverseOut, + typename OutputIterator, typename PointOut, + overlay_type OverlayType, + typename Strategy +> +struct intersection_insert + < + Tag1, Tag2, point_tag, + Areal1, Areal2, false, + Geometry1, Geometry2, + Reverse1, Reverse2, ReverseOut, + OutputIterator, PointOut, + OverlayType, + Strategy + > +{ + static inline OutputIterator apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, OutputIterator out, Strategy const& strategy) + { + + typedef detail::overlay::turn_info turn_info; + std::vector turns; + + detail::get_turns::no_interrupt_policy policy; + geometry::get_turns + < + false, false, detail::overlay::assign_null_policy + >(geometry1, geometry2, turns, policy); + for (typename std::vector::const_iterator it + = turns.begin(); it != turns.end(); ++it) + { + *out++ = it->point; + } + + return out; + } +}; + template < diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index e9233f764..2b71e54b0 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -9,6 +9,7 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP + #include #include @@ -25,8 +26,6 @@ #include #include -#include - #include #include @@ -124,7 +123,7 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1, std::map empty; std::map all_of_one_of_them; - select_rings(geometry1, geometry2, empty, all_of_one_of_them); + select_rings(geometry1, geometry2, empty, all_of_one_of_them, false); ring_container_type rings; assign_parents(geometry1, geometry2, rings, all_of_one_of_them); return add_rings(all_of_one_of_them, geometry1, geometry2, rings, out); @@ -169,9 +168,6 @@ struct overlay >(geometry1, geometry2, out); } - has_self_intersections(geometry1); - has_self_intersections(geometry2); - container_type turn_points; #ifdef BOOST_GEOMETRY_TIME_OVERLAY @@ -215,11 +211,14 @@ std::cout << "traverse" << std::endl; // Note that these rings are always in clockwise order, even in CCW polygons, // and are marked as "to be reversed" below ring_container_type rings; - geometry::traverse(geometry1, geometry2, - Direction == overlay_union - ? geometry::detail::overlay::operation_union - : geometry::detail::overlay::operation_intersection, - turn_points, rings); + traverse::apply + ( + geometry1, geometry2, + Direction == overlay_union + ? geometry::detail::overlay::operation_union + : geometry::detail::overlay::operation_intersection, + turn_points, rings + ); #ifdef BOOST_GEOMETRY_TIME_OVERLAY std::cout << "traverse: " << timer.elapsed() << std::endl; @@ -236,7 +235,7 @@ std::cout << "traverse" << std::endl; typedef ring_properties::type> properties; std::map selected; - select_rings(geometry1, geometry2, map, selected); + select_rings(geometry1, geometry2, map, selected, ! turn_points.empty()); #ifdef BOOST_GEOMETRY_TIME_OVERLAY std::cout << "select_rings: " << timer.elapsed() << std::endl; @@ -251,7 +250,7 @@ std::cout << "traverse" << std::endl; it != boost::end(rings); ++it) { - selected[id] = properties(*it); + selected[id] = properties(*it, true); selected[id].reversed = ReverseOut; id.multi_index++; } diff --git a/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp index c6bcaf10b..d112b71dc 100644 --- a/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp @@ -52,17 +52,17 @@ struct ring_properties {} template - inline ring_properties(RingOrBox const& ring_or_box) + inline ring_properties(RingOrBox const& ring_or_box, bool midpoint) : within_code(-1) , reversed(false) , discarded(false) , parent_area(-1) { this->area = geometry::area(ring_or_box); - geometry::point_on_border(this->point, ring_or_box, true); + geometry::point_on_border(this->point, ring_or_box, midpoint); } - area_type get_area() const + inline area_type get_area() const { return reversed ? -area : area; } diff --git a/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp index 60ec4c88a..21dec45ca 100644 --- a/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -40,15 +40,17 @@ namespace dispatch struct select_rings { template - static inline void apply(Box const& box, Geometry const& geometry, ring_identifier const& id, Map& map) + static inline void apply(Box const& box, Geometry const& geometry, + ring_identifier const& id, Map& map, bool midpoint) { - map[id] = typename Map::mapped_type(box); + map[id] = typename Map::mapped_type(box, midpoint); } template - static inline void apply(Box const& box, ring_identifier const& id, Map& map) + static inline void apply(Box const& box, + ring_identifier const& id, Map& map, bool midpoint) { - map[id] = typename Map::mapped_type(box); + map[id] = typename Map::mapped_type(box, midpoint); } }; @@ -56,20 +58,22 @@ namespace dispatch struct select_rings { template - static inline void apply(Ring const& ring, Geometry const& geometry, ring_identifier const& id, Map& map) + static inline void apply(Ring const& ring, Geometry const& geometry, + ring_identifier const& id, Map& map, bool midpoint) { if (boost::size(ring) > 0) { - map[id] = typename Map::mapped_type(ring); + map[id] = typename Map::mapped_type(ring, midpoint); } } template - static inline void apply(Ring const& ring, ring_identifier const& id, Map& map) + static inline void apply(Ring const& ring, + ring_identifier const& id, Map& map, bool midpoint) { if (boost::size(ring) > 0) { - map[id] = typename Map::mapped_type(ring); + map[id] = typename Map::mapped_type(ring, midpoint); } } }; @@ -79,36 +83,38 @@ namespace dispatch struct select_rings { template - static inline void apply(Polygon const& polygon, Geometry const& geometry, ring_identifier id, Map& map) + static inline void apply(Polygon const& polygon, Geometry const& geometry, + ring_identifier id, Map& map, bool midpoint) { typedef typename geometry::ring_type::type ring_type; typedef select_rings per_ring; - per_ring::apply(exterior_ring(polygon), geometry, id, map); + per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint); typename interior_return_type::type rings = interior_rings(polygon); for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) { id.ring_index++; - per_ring::apply(*it, geometry, id, map); + per_ring::apply(*it, geometry, id, map, midpoint); } } template - static inline void apply(Polygon const& polygon, ring_identifier id, Map& map) + static inline void apply(Polygon const& polygon, + ring_identifier id, Map& map, bool midpoint) { typedef typename geometry::ring_type::type ring_type; typedef select_rings per_ring; - per_ring::apply(exterior_ring(polygon), id, map); + per_ring::apply(exterior_ring(polygon), id, map, midpoint); typename interior_return_type::type rings = interior_rings(polygon); for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) { id.ring_index++; - per_ring::apply(*it, id, map); + per_ring::apply(*it, id, map, midpoint); } } }; @@ -203,7 +209,7 @@ inline void update_selection_map(Geometry1 const& geometry1, bool found = intersection_map.find(it->first) != intersection_map.end(); if (! found) { - ring_identifier id = it->first; + ring_identifier const id = it->first; typename SelectionMap::mapped_type properties = it->second; // Copy by value // Calculate the "within code" (previously this was done earlier but is @@ -242,16 +248,20 @@ template typename IntersectionMap, typename SelectionMap > inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2, - IntersectionMap const& intersection_map, SelectionMap& selection_map) + IntersectionMap const& intersection_map, + SelectionMap& selection_map, bool midpoint) { typedef typename geometry::tag::type tag1; typedef typename geometry::tag::type tag2; SelectionMap map_with_all; - dispatch::select_rings::apply(geometry1, geometry2, ring_identifier(0, -1, -1), map_with_all); - dispatch::select_rings::apply(geometry2, geometry1, ring_identifier(1, -1, -1), map_with_all); + dispatch::select_rings::apply(geometry1, geometry2, + ring_identifier(0, -1, -1), map_with_all, midpoint); + dispatch::select_rings::apply(geometry2, geometry1, + ring_identifier(1, -1, -1), map_with_all, midpoint); - update_selection_map(geometry1, geometry2, intersection_map, map_with_all, selection_map); + update_selection_map(geometry1, geometry2, intersection_map, + map_with_all, selection_map); } template @@ -261,14 +271,17 @@ template typename IntersectionMap, typename SelectionMap > inline void select_rings(Geometry const& geometry, - IntersectionMap const& intersection_map, SelectionMap& selection_map) + IntersectionMap const& intersection_map, + SelectionMap& selection_map, bool midpoint) { typedef typename geometry::tag::type tag; SelectionMap map_with_all; - dispatch::select_rings::apply(geometry, ring_identifier(0, -1, -1), map_with_all); + dispatch::select_rings::apply(geometry, + ring_identifier(0, -1, -1), map_with_all, midpoint); - update_selection_map(intersection_map, map_with_all, selection_map); + update_selection_map(geometry, geometry, intersection_map, + map_with_all, selection_map); } diff --git a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index 62b8ef484..d4147eac5 100644 --- a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -31,6 +32,60 @@ namespace boost { namespace geometry namespace detail { namespace self_get_turn_points { +class self_ip_exception : public geometry::exception {}; + +template +< + typename Geometry, + typename Turns, + typename TurnPolicy, + typename InterruptPolicy +> +struct self_section_visitor +{ + Geometry const& m_geometry; + Turns& m_turns; + InterruptPolicy& m_interrupt_policy; + + inline self_section_visitor(Geometry const& g, + Turns& turns, InterruptPolicy& ip) + : m_geometry(g) + , m_turns(turns) + , m_interrupt_policy(ip) + {} + + template + inline bool apply(Section const& sec1, Section const& sec2) + { + if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box) + && ! sec1.duplicate + && ! sec2.duplicate) + { + detail::get_turns::get_turns_in_sections + < + Geometry, Geometry, + false, false, + Section, Section, + Turns, TurnPolicy, + InterruptPolicy + >::apply( + 0, m_geometry, sec1, + 0, m_geometry, sec2, + m_turns, m_interrupt_policy); + } + if (m_interrupt_policy.has_intersections) + { + // TODO: we should give partition an interrupt policy. + // Now we throw, and catch below, to stop the partition loop. + throw self_ip_exception(); + } + return true; + } + +}; + + + template < typename Geometry, @@ -45,49 +100,38 @@ struct get_turns Turns& turns, InterruptPolicy& interrupt_policy) { + typedef model::box + < + typename geometry::point_type::type + > box_type; typedef typename geometry::sections < - model::box ::type>, - 1 + box_type, 1 > sections_type; sections_type sec; geometry::sectionalize(geometry, sec); - for (typename boost::range_iterator::type - it1 = sec.begin(); - it1 != sec.end(); - ++it1) + self_section_visitor + < + Geometry, + Turns, TurnPolicy, InterruptPolicy + > visitor(geometry, turns, interrupt_policy); + + try { - for (typename boost::range_iterator::type - it2 = sec.begin(); - it2 != sec.end(); - ++it2) - { - if (! geometry::detail::disjoint::disjoint_box_box( - it1->bounding_box, it2->bounding_box) - && ! it1->duplicate - && ! it2->duplicate - ) - { - if (! geometry::detail::get_turns::get_turns_in_sections - < - Geometry, Geometry, - false, false, - typename boost::range_value::type, - typename boost::range_value::type, - Turns, TurnPolicy, - InterruptPolicy - >::apply( - 0, geometry, *it1, - 0, geometry, *it2, - turns, interrupt_policy)) - { - return false; - } - } - } + geometry::partition + < + box_type, + detail::get_turns::get_section_box, + detail::get_turns::ovelaps_section_box + >::apply(sec, visitor); } + catch(self_ip_exception const& ) + { + return false; + } + return true; } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index d91efa71c..8edae0f2b 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -14,8 +14,10 @@ #include -#include +#include +#include #include +#include #include #include #include @@ -38,7 +40,8 @@ namespace detail { namespace overlay { template -inline void debug_traverse(Turn const& turn, Operation op, std::string const& header) +inline void debug_traverse(Turn const& turn, Operation op, + std::string const& header) { #ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE std::cout << header @@ -57,30 +60,6 @@ inline void debug_traverse(Turn const& turn, Operation op, std::string const& he } -template -inline void clear_visit_info(Turns& turns) -{ - typedef typename boost::range_value::type tp_type; - - for (typename boost::range_iterator::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) - { - for (typename boost::range_iterator - < - typename tp_type::container_type - >::type op_it = boost::begin(it->operations); - op_it != boost::end(it->operations); - ++op_it) - { - op_it->visited.clear(); - } - it->discarded = false; - } -} - - template inline void set_visited_for_continue(Info& info, Turn const& turn) { @@ -125,7 +104,11 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2, // If there is no next IP on this segment if (info.enriched.next_ip_index < 0) { - if (info.enriched.travels_to_vertex_index < 0 || info.enriched.travels_to_ip_index < 0) return false; + if (info.enriched.travels_to_vertex_index < 0 + || info.enriched.travels_to_ip_index < 0) + { + return false; + } BOOST_ASSERT(info.enriched.travels_to_vertex_index >= 0); BOOST_ASSERT(info.enriched.travels_to_ip_index >= 0); @@ -151,7 +134,7 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2, seg_id = info.seg_id; } - geometry::append(current_output, ip->point); + detail::overlay::append_no_duplicates(current_output, ip->point); return true; } @@ -227,76 +210,6 @@ inline bool select_next_ip(operation_type operation, -template -< - typename Rings, - typename Turns, - typename Operation, - typename Geometry1, - typename Geometry2 -> -inline void backtrack(std::size_t size_at_start, bool& fail, - Rings& rings, typename boost::range_value::type& ring, - Turns& turns, Operation& operation, - -#ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT - std::string const& reason, - Geometry1 const& geometry1, - Geometry2 const& geometry2 -#else - std::string const& reason, - Geometry1 const& , - Geometry2 const& -#endif - ) -{ -#ifdef BOOST_GEOMETRY_DEBUG_ENRICH - std::cout << " REJECT " << reason << std::endl; -#endif - fail = true; - - // Make bad output clean - rings.resize(size_at_start); - ring.clear(); - - // Reject this as a starting point - operation.visited.set_rejected(); - - // And clear all visit info - clear_visit_info(turns); - - /*** - int c = 0; - for (int i = 0; i < turns.size(); i++) - { - for (int j = 0; j < 2; j++) - { - if (turns[i].operations[j].visited.rejected()) - { - c++; - } - } - } - std::cout << "BACKTRACK (" << reason << " )" - << " " << c << " of " << turns.size() << " rejected" - << std::endl; - ***/ - - - -#ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT - std::cout << " BT (" << reason << " )"; - std::cout - << geometry::wkt(geometry1) << std::endl - << geometry::wkt(geometry2) << std::endl; -#endif - -} - -}} // namespace detail::overlay -#endif // DOXYGEN_NO_DETAIL - - /*! \brief Traverses through intersection points / geometries \ingroup overlay @@ -306,164 +219,173 @@ template bool Reverse1, bool Reverse2, typename Geometry1, typename Geometry2, - typename Turns, - typename Rings + typename Backtrack = backtrack_check_self_intersections > -inline void traverse(Geometry1 const& geometry1, - Geometry2 const& geometry2, - detail::overlay::operation_type operation, - Turns& turns, Rings& rings) +class traverse { - typedef typename boost::range_iterator::type turn_iterator; - typedef typename boost::range_value::type turn_type; - typedef typename boost::range_iterator - < - typename turn_type::container_type - >::type turn_operation_iterator_type; - - std::size_t size_at_start = boost::size(rings); - - bool fail = false; - do +public : + template + static inline void apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + detail::overlay::operation_type operation, + Turns& turns, Rings& rings) { - fail = false; - // Iterate through all unvisited points - for (turn_iterator it = boost::begin(turns); - ! fail && it != boost::end(turns); - ++it) + typedef typename boost::range_iterator::type turn_iterator; + typedef typename boost::range_value::type turn_type; + typedef typename boost::range_iterator + < + typename turn_type::container_type + >::type turn_operation_iterator_type; + + std::size_t size_at_start = boost::size(rings); + + typename Backtrack::state_type state; + do { - // Skip discarded ones - if (! (it->is_discarded() || it->blocked())) + state.reset(); + + // Iterate through all unvisited points + for (turn_iterator it = boost::begin(turns); + state.good() && it != boost::end(turns); + ++it) { - for (turn_operation_iterator_type iit = boost::begin(it->operations); - ! fail && iit != boost::end(it->operations); - ++iit) + // Skip discarded ones + if (! (it->is_discarded() || it->blocked())) { - if (iit->visited.none() - && ! iit->visited.rejected() - && (iit->operation == operation - || iit->operation == detail::overlay::operation_continue) - ) + for (turn_operation_iterator_type iit = boost::begin(it->operations); + state.good() && iit != boost::end(it->operations); + ++iit) { - set_visited_for_continue(*it, *iit); - - typename boost::range_value::type current_output; - geometry::append(current_output, it->point); - - turn_iterator current = it; - turn_operation_iterator_type current_iit = iit; - segment_identifier current_seg_id; - - if (! detail::overlay::assign_next_ip( - geometry1, geometry2, - turns, - current, current_output, - *iit, current_seg_id)) + if (iit->visited.none() + && ! iit->visited.rejected() + && (iit->operation == operation + || iit->operation == detail::overlay::operation_continue) + ) { - detail::overlay::backtrack( - size_at_start, fail, - rings, current_output, turns, *current_iit, - "No next IP", - geometry1, geometry2); - } + set_visited_for_continue(*it, *iit); - if (! detail::overlay::select_next_ip( - operation, - *current, - current_seg_id, - current_iit)) - { - detail::overlay::backtrack( - size_at_start, fail, - rings, current_output, turns, *iit, - "Dead end at start", - geometry1, geometry2); - } - else - { + typename boost::range_value::type current_output; + detail::overlay::append_no_duplicates(current_output, + it->point, true); - iit->visited.set_started(); - detail::overlay::debug_traverse(*it, *iit, "-> Started"); - detail::overlay::debug_traverse(*current, *current_iit, "Selected "); + turn_iterator current = it; + turn_operation_iterator_type current_iit = iit; + segment_identifier current_seg_id; - - unsigned int i = 0; - - while (current_iit != iit && ! fail) - { - if (current_iit->visited.visited()) - { - // It visits a visited node again, without passing the start node. - // This makes it suspicious for endless loops - detail::overlay::backtrack( - size_at_start, fail, - rings, current_output, turns, *iit, - "Visit again", - geometry1, geometry2); - } - else - { - - - // We assume clockwise polygons only, non self-intersecting, closed. - // However, the input might be different, and checking validity - // is up to the library user. - - // Therefore we make here some sanity checks. If the input - // violates the assumptions, the output polygon will not be correct - // but the routine will stop and output the current polygon, and - // will continue with the next one. - - // Below three reasons to stop. - detail::overlay::assign_next_ip( + if (! detail::overlay::assign_next_ip( geometry1, geometry2, - turns, current, current_output, - *current_iit, current_seg_id); - - if (! detail::overlay::select_next_ip( - operation, - *current, - current_seg_id, - current_iit)) - { - // Should not occur in valid (non-self-intersecting) polygons - // Should not occur in self-intersecting polygons without spikes - // Might occur in polygons with spikes - detail::overlay::backtrack( - size_at_start, fail, - rings, current_output, turns, *iit, - "Dead end", - geometry1, geometry2); - } - detail::overlay::debug_traverse(*current, *current_iit, "Selected "); - - if (i++ > 2 + 2 * turns.size()) - { - // Sanity check: there may be never more loops - // than turn points. - // Turn points marked as "ii" can be visited twice. - detail::overlay::backtrack( - size_at_start, fail, - rings, current_output, turns, *iit, - "Endless loop", - geometry1, geometry2); - } - } + turns, + current, current_output, + *iit, current_seg_id)) + { + Backtrack::apply( + size_at_start, + rings, current_output, turns, *current_iit, + "No next IP", + geometry1, geometry2, state); } - if (! fail) + if (! detail::overlay::select_next_ip( + operation, + *current, + current_seg_id, + current_iit)) { - iit->visited.set_finished(); - detail::overlay::debug_traverse(*current, *iit, "->Finished"); - rings.push_back(current_output); + Backtrack::apply( + size_at_start, + rings, current_output, turns, *iit, + "Dead end at start", + geometry1, geometry2, state); + } + else + { + + iit->visited.set_started(); + detail::overlay::debug_traverse(*it, *iit, "-> Started"); + detail::overlay::debug_traverse(*current, *current_iit, "Selected "); + + + unsigned int i = 0; + + while (current_iit != iit && state.good()) + { + if (current_iit->visited.visited()) + { + // It visits a visited node again, without passing the start node. + // This makes it suspicious for endless loops + Backtrack::apply( + size_at_start, + rings, current_output, turns, *iit, + "Visit again", + geometry1, geometry2, state); + } + else + { + + + // We assume clockwise polygons only, non self-intersecting, closed. + // However, the input might be different, and checking validity + // is up to the library user. + + // Therefore we make here some sanity checks. If the input + // violates the assumptions, the output polygon will not be correct + // but the routine will stop and output the current polygon, and + // will continue with the next one. + + // Below three reasons to stop. + detail::overlay::assign_next_ip( + geometry1, geometry2, + turns, current, current_output, + *current_iit, current_seg_id); + + if (! detail::overlay::select_next_ip( + operation, + *current, + current_seg_id, + current_iit)) + { + // Should not occur in valid (non-self-intersecting) polygons + // Should not occur in self-intersecting polygons without spikes + // Might occur in polygons with spikes + Backtrack::apply( + size_at_start, + rings, current_output, turns, *iit, + "Dead end", + geometry1, geometry2, state); + } + detail::overlay::debug_traverse(*current, *current_iit, "Selected "); + + if (i++ > 2 + 2 * turns.size()) + { + // Sanity check: there may be never more loops + // than turn points. + // Turn points marked as "ii" can be visited twice. + Backtrack::apply( + size_at_start, + rings, current_output, turns, *iit, + "Endless loop", + geometry1, geometry2, state); + } + } + } + + if (state.good()) + { + iit->visited.set_finished(); + detail::overlay::debug_traverse(*current, *iit, "->Finished"); + rings.push_back(current_output); + } } } } } } - } - } while (fail); -} + } while (! state.good()); + } +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/overlay/within_util.hpp b/include/boost/geometry/algorithms/detail/overlay/within_util.hpp deleted file mode 100644 index 8618b81fe..000000000 --- a/include/boost/geometry/algorithms/detail/overlay/within_util.hpp +++ /dev/null @@ -1,98 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. - -// 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_ALGORITHMS_DETAIL_OVERLAY_WITHIN_UTIL_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_WITHIN_UTIL_HPP - - - -#include -#include - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace overlay -{ - - -template -struct within_code -{}; - -template -struct within_code -{ - static inline int apply(Point const& point, Box const& box) - { - // 1. Check outside - if (get<0>(point) < get(box) - || get<0>(point) > get(box) - || get<1>(point) < get(box) - || get<1>(point) > get(box)) - { - return -1; - } - // 2. Check border - if (geometry::math::equals(get<0>(point), get(box)) - || geometry::math::equals(get<0>(point), get(box)) - || geometry::math::equals(get<1>(point), get(box)) - || geometry::math::equals(get<1>(point), get(box))) - { - return 0; - } - return 1; - } -}; -template -struct within_code -{ - static inline int apply(Point const& point, Ring const& ring) - { - // Same as point_in_ring but here ALWAYS with winding. - typedef strategy::within::winding strategy_type; - - return detail::within::point_in_ring - < - Point, - Ring, - order_as_direction::value>::value, - geometry::closure::value, - strategy_type - >::apply(point, ring, strategy_type()); - } -}; - - -template -inline int point_in_ring(Point const& point, Geometry const& geometry) -{ - return within_code::type, Point, Geometry> - ::apply(point, geometry); -} - -template -inline bool within_or_touch(Point const& point, Geometry const& geometry) -{ - return within_code::type, Point, Geometry> - ::apply(point, geometry) >= 0; -} - - - -}} // namespace detail::overlay -#endif // DOXYGEN_NO_DETAIL - - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_WITHIN_UTIL_HPP diff --git a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp index 52cf15866..aea7d17ce 100644 --- a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -189,11 +189,12 @@ struct check_duplicate_loop static inline bool apply(Segment const& seg) { - coordinate_type const diff = - geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg); - - coordinate_type const zero = 0; - if (! geometry::math::equals(diff, zero)) + if (! geometry::math::equals + ( + geometry::get<0, Dimension>(seg), + geometry::get<1, Dimension>(seg) + ) + ) { return false; } diff --git a/include/boost/geometry/algorithms/within.hpp b/include/boost/geometry/algorithms/within.hpp index 912ba4bab..987c6101b 100644 --- a/include/boost/geometry/algorithms/within.hpp +++ b/include/boost/geometry/algorithms/within.hpp @@ -31,10 +31,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -48,105 +50,6 @@ namespace detail { namespace within { -/*! - \brief Implementation for boxes - \ingroup boolean_relations - \note Should have strategy for e.g. Wrangel - */ -template -< - typename Point, - typename Box, - typename Strategy, - std::size_t Dimension, - std::size_t DimensionCount -> -struct point_in_box -{ - static inline int apply(Point const& p, Box const& b, Strategy const& s) - { - assert_dimension_equal(); - - if (get(p) <= get(b) - || get(p) >= get(b)) - { - return -1; - } - - return point_in_box - < - Point, - Box, - Strategy, - Dimension + 1, - DimensionCount - >::apply(p, b, s); - } -}; - -template -< - typename Point, - typename Box, - typename Strategy, - std::size_t DimensionCount -> -struct point_in_box -{ - static inline int apply(Point const& , Box const& , Strategy const& ) - { - return 1; - } -}; - - -template -< - typename Box1, - typename Box2, - typename Strategy, - std::size_t Dimension, - std::size_t DimensionCount -> -struct box_in_box -{ - static inline int apply(Box1 const& b1, Box2 const& b2, Strategy const& s) - { - assert_dimension_equal(); - - if (get(b1) <= get(b2) - || get(b1) >= get(b2)) - { - return -1; - } - - return box_in_box - < - Box1, - Box2, - Strategy, - Dimension + 1, - DimensionCount - >::apply(b1, b2, s); - } -}; - -template -< - typename Box1, - typename Box2, - typename Strategy, - std::size_t DimensionCount -> -struct box_in_box -{ - static inline int apply(Box1 const& , Box2 const& , Strategy const&) - { - return 1; - } -}; - - template < typename Point, @@ -157,7 +60,7 @@ template > struct point_in_ring { - BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategy) ); + BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal) ); static inline int apply(Point const& point, Ring const& ring, Strategy const& strategy) @@ -181,13 +84,14 @@ struct point_in_ring iterator_type it = boost::begin(view); iterator_type end = boost::end(view); + bool stop = false; for (iterator_type previous = it++; - it != end; + it != end && ! stop; ++previous, ++it) { if (! strategy.apply(point, *previous, *it, state)) { - return false; + stop = true; } } @@ -196,7 +100,6 @@ struct point_in_ring }; - // Polygon: in exterior ring, and if so, not within interior ring(s) template < @@ -208,7 +111,7 @@ template > struct point_in_polygon { - BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategy) ); + BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal) ); static inline int apply(Point const& point, Polygon const& poly, Strategy const& strategy) @@ -280,85 +183,61 @@ struct within template struct within - : detail::within::point_in_box - < - Point, - Box, - Strategy, - 0, - dimension::type::value - > -{}; +{ + static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) + { + return strategy.apply(point, box); + } +}; template struct within - : detail::within::box_in_box - < - Box1, - Box2, - Strategy, - 0, - dimension::type::value - > -{}; +{ + static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) + { + assert_dimension_equal(); + return strategy.apply(box1, box2); + } +}; template struct within - : detail::within::point_in_ring - < - Point, - Ring, - order_as_direction::value>::value, - geometry::closure::value, - Strategy - > -{}; +{ + static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy) + { + return detail::within::point_in_ring + < + Point, + Ring, + order_as_direction::value>::value, + geometry::closure::value, + Strategy + >::apply(point, ring, strategy) == 1; + } +}; template struct within - : detail::within::point_in_polygon - < - Point, - Polygon, - order_as_direction::value>::value, - geometry::closure::value, - Strategy - > -{}; +{ + static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy) + { + return detail::within::point_in_polygon + < + Point, + Polygon, + order_as_direction::value>::value, + geometry::closure::value, + Strategy + >::apply(point, polygon, strategy) == 1; + } +}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS -namespace strategy { namespace within -{ - -/// Strategy for box-in-box (not used but has to be present for default strategy) -struct unused_strategy {}; - -namespace services -{ - -// Specialize for box-in-areal (box-in-box). This is meant to do box-in-box -// but will be catched by box-in-any-areal, which has to change later -// (we might introduce another tag which is not "areal", derived by poly/ring/ -// multi_poly, but NOT by box, and use that here. E.g. "polygonal") -// Using cartesian prevents spherical yet from compiling, which is good. -template -struct default_strategy -{ - typedef unused_strategy type; -}; - -} // namespace services - -}} // namespace strategy::within - -#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - /*! \brief \brief_check12{is completely inside} \ingroup within @@ -387,18 +266,27 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2) { concept::check(); concept::check(); + assert_dimension_equal(); typedef typename point_type::type point_type1; typedef typename point_type::type point_type2; typedef typename strategy::within::services::default_strategy < + typename tag::type, + typename tag::type, typename tag::type, typename tag_cast::type, areal_tag>::type, - typename cs_tag::type, - typename cs_tag::type, - point_type1, - point_type2 + typename tag_cast + < + typename cs_tag::type, spherical_tag + >::type, + typename tag_cast + < + typename cs_tag::type, spherical_tag + >::type, + Geometry1, + Geometry2 >::type strategy_type; return dispatch::within @@ -408,7 +296,7 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2) Geometry1, Geometry2, strategy_type - >::apply(geometry1, geometry2, strategy_type()) == 1; + >::apply(geometry1, geometry2, strategy_type()); } /*! @@ -443,12 +331,16 @@ template inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - // Always assume a point-in-polygon strategy here. - // Because for point-in-box, it makes no sense to specify one. - BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategy) ); - + concept::within::check + < + typename tag::type, + typename tag::type, + typename tag_cast::type, areal_tag>::type, + Strategy + >(); concept::check(); concept::check(); + assert_dimension_equal(); return dispatch::within < @@ -457,7 +349,7 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2, Geometry1, Geometry2, Strategy - >::apply(geometry1, geometry2, strategy) == 1; + >::apply(geometry1, geometry2, strategy); } }} // namespace boost::geometry diff --git a/include/boost/geometry/core/tags.hpp b/include/boost/geometry/core/tags.hpp index f110a079a..8b9739861 100644 --- a/include/boost/geometry/core/tags.hpp +++ b/include/boost/geometry/core/tags.hpp @@ -20,18 +20,21 @@ namespace boost { namespace geometry // Tags defining strategies linked to coordinate systems +/// Tag used for casting spherical/geographic coordinate systems +struct spherical_tag {}; + /// Tag indicating Cartesian coordinate system family (cartesian,epsg) struct cartesian_tag {}; /// Tag indicating Spherical polar coordinate system family -struct spherical_polar_tag {}; +struct spherical_polar_tag : spherical_tag {}; /// Tag indicating Spherical equatorial coordinate system family -struct spherical_equatorial_tag {}; +struct spherical_equatorial_tag : spherical_tag {}; /// Tag indicating Geographic coordinate system family (geographic) -struct geographic_tag {}; +struct geographic_tag : spherical_tag {}; @@ -53,6 +56,9 @@ struct linear_tag {}; /// For areal types (polygon, multi_polygon, box, ring) struct areal_tag {}; +// Subset of areal types (polygon, multi_polygon, ring) +struct polygonal_tag : areal_tag {}; + /// For volume types (also box (?), polyhedron) struct volumetric_tag {}; @@ -70,10 +76,10 @@ struct point_tag : single_tag, pointlike_tag {}; struct linestring_tag : single_tag, linear_tag {}; /// OGC Polygon identifying tag -struct polygon_tag : single_tag, areal_tag {}; +struct polygon_tag : single_tag, polygonal_tag {}; /// Convenience (linear) ring identifying tag -struct ring_tag : single_tag, areal_tag {}; +struct ring_tag : single_tag, polygonal_tag {}; /// Convenience 2D or 3D box (mbr / aabb) identifying tag struct box_tag : single_tag, areal_tag {}; diff --git a/include/boost/geometry/geometries/adapted/boost_fusion.hpp b/include/boost/geometry/geometries/adapted/boost_fusion.hpp index 3c81672f8..4e6c850db 100644 --- a/include/boost/geometry/geometries/adapted/boost_fusion.hpp +++ b/include/boost/geometry/geometries/adapted/boost_fusion.hpp @@ -165,7 +165,7 @@ struct tag fusion_adapt_detail::is_fusion_sequence \ >::type \ > \ - { typedef cs::cartesian type; }; \ + { typedef CoordinateSystem type; }; \ }}} diff --git a/include/boost/geometry/geometries/concepts/check.hpp b/include/boost/geometry/geometries/concepts/check.hpp index cd913e48b..e858a6662 100644 --- a/include/boost/geometry/geometries/concepts/check.hpp +++ b/include/boost/geometry/geometries/concepts/check.hpp @@ -44,7 +44,7 @@ class check BOOST_CONCEPT_ASSERT((Concept )); }; -}} // namespace detail::check +}} // namespace detail::concept_check #endif // DOXYGEN_NO_DETAIL diff --git a/include/boost/geometry/multi/algorithms/convert.hpp b/include/boost/geometry/multi/algorithms/convert.hpp new file mode 100644 index 000000000..9d27badec --- /dev/null +++ b/include/boost/geometry/multi/algorithms/convert.hpp @@ -0,0 +1,133 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_ALGORITHMS_CONVERT_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP + + +#include + +#include + +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace conversion +{ + +template +struct single_to_multi +{ + static inline void apply(Single const& single, Multi& multi) + { + traits::resize::apply(multi, 1); + Policy::apply(single, *boost::begin(multi)); + } +}; + + + +template +struct multi_to_multi +{ + static inline void apply(Multi1 const& multi1, Multi2& multi2) + { + traits::resize::apply(multi2, boost::size(multi1)); + + typename boost::range_iterator::type it1 + = boost::begin(multi1); + typename boost::range_iterator::type it2 + = boost::begin(multi2); + + for (; it1 != boost::end(multi1); ++it1, ++it2) + { + Policy::apply(*it1, *it2); + } + } +}; + + +}} // namespace detail::convert +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// Dispatch for multi <-> multi, specifying their single-version as policy. +// Note that, even if the multi-types are mutually different, their single +// version types might be the same and therefore we call boost::is_same again + +template +struct convert + : detail::conversion::multi_to_multi + < + Multi1, + Multi2, + convert + < + boost::is_same + < + typename boost::range_value::type, + typename boost::range_value::type + >::value, + typename single_tag_of + < + typename tag::type + >::type, + typename single_tag_of + < + typename tag::type + >::type, + DimensionCount, + typename boost::range_value::type, + typename boost::range_value::type + > + > +{}; + +template +struct convert + : detail::conversion::single_to_multi + < + Single, + Multi, + convert + < + false, + typename tag::type, + typename single_tag_of + < + typename tag::type + >::type, + DimensionCount, + Single, + typename boost::range_value::type + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP diff --git a/include/boost/geometry/multi/algorithms/covered_by.hpp b/include/boost/geometry/multi/algorithms/covered_by.hpp new file mode 100644 index 000000000..b5eeb782a --- /dev/null +++ b/include/boost/geometry/multi/algorithms/covered_by.hpp @@ -0,0 +1,68 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_ALGORITHMS_COVERED_BY_HPP +#define BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP + + +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +struct covered_by +{ + static inline bool apply(Point const& point, + MultiPolygon const& multi_polygon, Strategy const& strategy) + { + return detail::within::geometry_multi_within_code + < + Point, + MultiPolygon, + Strategy, + detail::within::point_in_polygon + < + Point, + typename boost::range_value::type, + order_as_direction + < + geometry::point_order::value + >::value, + geometry::closure::value, + Strategy + > + >::apply(point, multi_polygon, strategy) >= 0; + } +}; + + +} // namespace dispatch + + +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP diff --git a/include/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp b/include/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp index 6e150cf58..ffe86a36b 100644 --- a/include/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp +++ b/include/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp @@ -30,7 +30,8 @@ namespace dispatch struct select_rings { template - static inline void apply(Multi const& multi, Geometry const& geometry, ring_identifier id, Map& map) + static inline void apply(Multi const& multi, Geometry const& geometry, + ring_identifier id, Map& map, bool midpoint) { typedef typename boost::range_iterator < @@ -43,7 +44,7 @@ namespace dispatch for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) { id.ring_index = -1; - per_polygon::apply(*it, geometry, id, map); + per_polygon::apply(*it, geometry, id, map, midpoint); id.multi_index++; } } diff --git a/include/boost/geometry/multi/algorithms/within.hpp b/include/boost/geometry/multi/algorithms/within.hpp index e9fcbb65a..50ec1c1e8 100644 --- a/include/boost/geometry/multi/algorithms/within.hpp +++ b/include/boost/geometry/multi/algorithms/within.hpp @@ -37,7 +37,7 @@ template typename Strategy, typename Policy > -struct geometry_in_multi +struct geometry_multi_within_code { static inline int apply(Geometry const& geometry, MultiGeometry const& multi, @@ -48,7 +48,8 @@ struct geometry_in_multi it != boost::end(multi); ++it) { - // Geometry within a multi: true if within one of them + // Geometry coding on multi: 1 (within) if within one of them; + // 0 (touch) if on border of one of them int const code = Policy::apply(geometry, *it, strategy); if (code != -1) { @@ -70,21 +71,29 @@ namespace dispatch template struct within - : detail::within::geometry_in_multi - < - Point, - MultiPolygon, - Strategy, - detail::within::point_in_polygon - < - Point, - typename boost::range_value::type, - order_as_direction::value>::value, - geometry::closure::value, - Strategy - > - > -{}; +{ + static inline bool apply(Point const& point, + MultiPolygon const& multi_polygon, Strategy const& strategy) + { + return detail::within::geometry_multi_within_code + < + Point, + MultiPolygon, + Strategy, + detail::within::point_in_polygon + < + Point, + typename boost::range_value::type, + order_as_direction + < + geometry::point_order::value + >::value, + geometry::closure::value, + Strategy + > + >::apply(point, multi_polygon, strategy) == 1; + } +}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/multi/core/tags.hpp b/include/boost/geometry/multi/core/tags.hpp index 69398f791..c168cfc16 100644 --- a/include/boost/geometry/multi/core/tags.hpp +++ b/include/boost/geometry/multi/core/tags.hpp @@ -27,7 +27,7 @@ struct multi_point_tag : multi_tag, pointlike_tag {}; struct multi_linestring_tag : multi_tag, linear_tag {}; /// OGC Multi polygon identifying tag -struct multi_polygon_tag : multi_tag, areal_tag {}; +struct multi_polygon_tag : multi_tag, polygonal_tag {}; /// OGC Geometry Collection identifying tag struct geometry_collection_tag : multi_tag {}; diff --git a/include/boost/geometry/policies/relate/intersection_points.hpp b/include/boost/geometry/policies/relate/intersection_points.hpp index cb47dedc9..ac5e96680 100644 --- a/include/boost/geometry/policies/relate/intersection_points.hpp +++ b/include/boost/geometry/policies/relate/intersection_points.hpp @@ -70,7 +70,16 @@ struct segments_intersection_points promoted_type const da = (promoted_type(dx2) * wy) - (promoted_type(dy2) * wx); // r: ratio 0-1 where intersection divides A/B - promoted_type const r = da / d; + promoted_type r = da / d; + // Handle robustness issues + if (r < 0) + { + r = 0; + } + else if (r > 1) + { + r = 1; + } result.count = 1; set<0>(result.intersections[0], diff --git a/include/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp b/include/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp new file mode 100644 index 000000000..2cda53862 --- /dev/null +++ b/include/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp @@ -0,0 +1,151 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP +#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP + +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry { namespace strategy +{ + +namespace within +{ + +struct decide_within +{ + static inline bool apply(int side, bool& result) + { + if (side != 1) + { + result = false; + return false; + } + return true; // continue + } +}; + +struct decide_covered_by +{ + static inline bool apply(int side, bool& result) + { + if (side != 1) + { + result = side >= 0; + return false; + } + return true; // continue + } +}; + + +template +struct point_in_box_by_side +{ + typedef typename strategy::side::services::default_strategy + < + typename cs_tag::type + >::type side_strategy_type; + + static inline bool apply(Point const& point, Box const& box) + { + // Create (counterclockwise) array of points, the fifth one closes it + // Every point should be on the LEFT side (=1), or ON the border (=0), + // So >= 1 or >= 0 + boost::array::type, 5> bp; + geometry::detail::assign_box_corners_oriented(box, bp); + bp[4] = bp[0]; + + bool result = true; + side_strategy_type strategy; + boost::ignore_unused_variable_warning(strategy); + + for (int i = 1; i < 5; i++) + { + int const side = strategy.apply(point, bp[i - 1], bp[i]); + if (! Decide::apply(side, result)) + { + return result; + } + } + + return result; + } +}; + + +} // namespace within + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace within { namespace services +{ + +template +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + spherical_tag, spherical_tag, + Point, Box + > +{ + typedef within::point_in_box_by_side + < + Point, Box, within::decide_within + > type; +}; + + + +}} // namespace within::services + + +namespace covered_by { namespace services +{ + + +template +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + spherical_tag, spherical_tag, + Point, Box + > +{ + typedef within::point_in_box_by_side + < + Point, Box, within::decide_covered_by + > type; +}; + + +}} // namespace covered_by::services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}}} // namespace boost::geometry::strategy + + +#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP diff --git a/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp index c98de8ab3..fda35cc2a 100644 --- a/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp +++ b/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -181,23 +182,18 @@ namespace services { // Register using "areal_tag" for ring, polygon, multi-polygon -template -struct default_strategy +template +struct default_strategy { - typedef winding type; + typedef winding::type> type; }; -template -struct default_strategy +template +struct default_strategy { - typedef winding type; + typedef winding::type> type; }; -template -struct default_strategy -{ - typedef winding type; -}; } // namespace services @@ -207,6 +203,29 @@ struct default_strategy +struct default_strategy +{ + typedef strategy::within::winding::type> type; +}; + +template +struct default_strategy +{ + typedef strategy::within::winding::type> type; +}; + + +}}} // namespace strategy::covered_by::services +#endif + + }} // namespace boost::geometry diff --git a/include/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp b/include/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp index b4e95b8a4..4ce74e946 100644 --- a/include/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp +++ b/include/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp @@ -94,7 +94,12 @@ class douglas_peucker { public : - typedef typename strategy::distance::services::comparable_type::type distance_strategy_type; + // See also ticket 5954 https://svn.boost.org/trac/boost/ticket/5954 + // Comparable is currently not possible here because it has to be compared to the squared of max_distance, and more. + // For now we have to take the real distance. + typedef PointDistanceStrategy distance_strategy_type; + // typedef typename strategy::distance::services::comparable_type::type distance_strategy_type; + typedef typename strategy::distance::services::return_type::type return_type; private : @@ -145,7 +150,7 @@ private : #ifdef GL_DEBUG_DOUGLAS_PEUCKER std::cout << "consider " << dsv(it->p) << " at " << double(dist) - << ((dist > max_dist) ? " maybe" : " no") + << ((dist > max_dist) ? " maybe" : " no") << std::endl; #endif diff --git a/include/boost/geometry/strategies/cartesian/area_surveyor.hpp b/include/boost/geometry/strategies/cartesian/area_surveyor.hpp index 033c4a433..2759466e5 100644 --- a/include/boost/geometry/strategies/cartesian/area_surveyor.hpp +++ b/include/boost/geometry/strategies/cartesian/area_surveyor.hpp @@ -82,7 +82,7 @@ private : inline return_type area() const { return_type result = sum; - result *= 0.5; + result /= 2; return result; } }; diff --git a/include/boost/geometry/strategies/cartesian/box_in_box.hpp b/include/boost/geometry/strategies/cartesian/box_in_box.hpp new file mode 100644 index 000000000..85a1caafb --- /dev/null +++ b/include/boost/geometry/strategies/cartesian/box_in_box.hpp @@ -0,0 +1,176 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_CARTESIAN_BOX_IN_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP + + +#include +#include +#include +#include + + +namespace boost { namespace geometry { namespace strategy +{ + + +namespace within +{ + +struct box_within_range +{ + template + static inline bool apply(BoxContainedValue const& bed_min + , BoxContainedValue const& bed_max + , BoxContainingValue const& bing_min + , BoxContainingValue const& bing_max) + { + return bed_min > bing_min && bed_max < bing_max; + } +}; + + +struct box_covered_by_range +{ + template + static inline bool apply(BoxContainedValue const& bed_min + , BoxContainedValue const& bed_max + , BoxContainingValue const& bing_min + , BoxContainingValue const& bing_max) + { + return bed_min >= bing_min && bed_max <= bing_max; + } +}; + + +template +< + typename SubStrategy, + typename Box1, + typename Box2, + std::size_t Dimension, + std::size_t DimensionCount +> +struct relate_box_box_loop +{ + static inline bool apply(Box1 const& b_contained, Box2 const& b_containing) + { + assert_dimension_equal(); + + if (! SubStrategy::apply( + get(b_contained), + get(b_contained), + get(b_containing), + get(b_containing) + ) + ) + { + return false; + } + + return relate_box_box_loop + < + SubStrategy, + Box1, Box2, + Dimension + 1, DimensionCount + >::apply(b_contained, b_containing); + } +}; + +template +< + typename SubStrategy, + typename Box1, + typename Box2, + std::size_t DimensionCount +> +struct relate_box_box_loop +{ + static inline bool apply(Box1 const& , Box2 const& ) + { + return true; + } +}; + +template +< + typename Box1, + typename Box2, + typename SubStrategy = box_within_range +> +struct box_in_box +{ + static inline bool apply(Box1 const& box1, Box2 const& box2) + { + return relate_box_box_loop + < + SubStrategy, + Box1, Box2, 0, dimension::type::value + >::apply(box1, box2); + } +}; + + +} // namespace within + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace within { namespace services +{ + +template +struct default_strategy + < + box_tag, box_tag, + box_tag, areal_tag, + cartesian_tag, cartesian_tag, + BoxContained, BoxContaining + > +{ + typedef within::box_in_box type; +}; + + +}} // namespace within::services + +namespace covered_by { namespace services +{ + +template +struct default_strategy + < + box_tag, box_tag, + box_tag, areal_tag, + cartesian_tag, cartesian_tag, + BoxContained, BoxContaining + > +{ + typedef within::box_in_box + < + BoxContained, BoxContaining, + within::box_covered_by_range + > type; +}; + +}} // namespace covered_by::services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}}} // namespace boost::geometry::strategy + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP diff --git a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp index 4df6a478e..b081e1937 100644 --- a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -16,6 +16,8 @@ #include #include +#include + #include #include @@ -54,6 +56,19 @@ struct segment_arrange } }; +template +inline typename geometry::point_type::type get_from_index( + Segment const& segment) +{ + typedef typename geometry::point_type::type point_type; + point_type point; + geometry::detail::assign::assign_point_from_index + < + Segment, point_type, Index, 0, dimension::type::value + >::apply(segment, point); + return point; +} + } #endif @@ -91,10 +106,10 @@ struct relate_cartesian_segments /// Relate segments a and b static inline return_type apply(segment_type1 const& a, segment_type2 const& b) { - coordinate_type dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir - coordinate_type dx_b = get<1, 0>(b) - get<0, 0>(b); - coordinate_type dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir - coordinate_type dy_b = get<1, 1>(b) - get<0, 1>(b); + coordinate_type const dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir + coordinate_type const dx_b = get<1, 0>(b) - get<0, 0>(b); + coordinate_type const dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir + coordinate_type const dy_b = get<1, 1>(b) - get<0, 1>(b); return apply(a, b, dx_a, dy_a, dx_b, dy_b); } @@ -133,8 +148,15 @@ struct relate_cartesian_segments // Note: Do NOT yet calculate the determinant here, but use the SIDE strategy. // Determinant calculation is not robust; side (orient) can be made robust // (and is much robuster even without measures) - sides.set<1>(side::apply(a.first, a.second, b.first), - side::apply(a.first, a.second, b.second)); + sides.set<1> + ( + side::apply(detail::get_from_index<0>(a) + , detail::get_from_index<1>(a) + , detail::get_from_index<0>(b)), + side::apply(detail::get_from_index<0>(a) + , detail::get_from_index<1>(a) + , detail::get_from_index<1>(b)) + ); if (sides.same<1>()) { @@ -143,8 +165,15 @@ struct relate_cartesian_segments } // 2b) For other segment - sides.set<0>(side::apply(b.first, b.second, a.first), - side::apply(b.first, b.second, a.second)); + sides.set<0> + ( + side::apply(detail::get_from_index<0>(b) + , detail::get_from_index<1>(b) + , detail::get_from_index<0>(a)), + side::apply(detail::get_from_index<0>(b) + , detail::get_from_index<1>(b) + , detail::get_from_index<1>(a)) + ); if (sides.same<0>()) { @@ -164,7 +193,7 @@ struct relate_cartesian_segments bool collinear = sides.collinear(); - // Get the same type, but at least a double (also used for divisions + // Get the same type, but at least a double (also used for divisions) typedef typename select_most_precise < coordinate_type, double @@ -347,8 +376,8 @@ private : // In robustness it can occur that a point of A is inside B AND a point of B is inside A, // still while has_common_points is true (so one point equals the other). // If that is the case we select on length. - coordinate_type const length_a = abs(a_1 - a_2); - coordinate_type const length_b = abs(b_1 - b_2); + coordinate_type const length_a = geometry::math::abs(a_1 - a_2); + coordinate_type const length_b = geometry::math::abs(b_1 - b_2); if (length_a > length_b) { a_in_b = false; diff --git a/include/boost/geometry/strategies/cartesian/point_in_box.hpp b/include/boost/geometry/strategies/cartesian/point_in_box.hpp new file mode 100644 index 000000000..a9450b6c0 --- /dev/null +++ b/include/boost/geometry/strategies/cartesian/point_in_box.hpp @@ -0,0 +1,172 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_CARTESIAN_POINT_IN_BOX_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP + + +#include +#include +#include +#include + + +namespace boost { namespace geometry { namespace strategy +{ + +namespace within +{ + + +struct within_range +{ + template + static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value) + { + return value > min_value && value < max_value; + } +}; + + +struct covered_by_range +{ + template + static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value) + { + return value >= min_value && value <= max_value; + } +}; + + +template +< + typename SubStrategy, + typename Point, + typename Box, + std::size_t Dimension, + std::size_t DimensionCount +> +struct relate_point_box_loop +{ + static inline bool apply(Point const& point, Box const& box) + { + if (! SubStrategy::apply(get(point), + get(box), + get(box)) + ) + { + return false; + } + + return relate_point_box_loop + < + SubStrategy, + Point, Box, + Dimension + 1, DimensionCount + >::apply(point, box); + } +}; + + +template +< + typename SubStrategy, + typename Point, + typename Box, + std::size_t DimensionCount +> +struct relate_point_box_loop +{ + static inline bool apply(Point const& , Box const& ) + { + return true; + } +}; + + +template +< + typename Point, + typename Box, + typename SubStrategy = within_range +> +struct point_in_box +{ + static inline bool apply(Point const& point, Box const& box) + { + return relate_point_box_loop + < + SubStrategy, + Point, Box, + 0, dimension::type::value + >::apply(point, box); + } +}; + + +} // namespace within + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +namespace within { namespace services +{ + +template +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + cartesian_tag, cartesian_tag, + Point, Box + > +{ + typedef within::point_in_box type; +}; + + +}} // namespace within::services + + +namespace covered_by { namespace services +{ + + +template +struct default_strategy + < + point_tag, box_tag, + point_tag, areal_tag, + cartesian_tag, cartesian_tag, + Point, Box + > +{ + typedef within::point_in_box + < + Point, Box, + within::covered_by_range + > type; +}; + + +}} // namespace covered_by::services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}}} // namespace boost::geometry::strategy + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP diff --git a/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp b/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp index b4255c8a1..d3d8b1ff3 100644 --- a/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp +++ b/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp @@ -89,7 +89,7 @@ public : promoted_type const s = dx * dpy - dy * dpx; - promoted_type zero = promoted_type(); + promoted_type const zero = promoted_type(); return math::equals(s, zero) ? 0 : s > zero ? 1 : -1; diff --git a/include/boost/geometry/strategies/concepts/distance_concept.hpp b/include/boost/geometry/strategies/concepts/distance_concept.hpp index a29ad6358..5ec23df79 100644 --- a/include/boost/geometry/strategies/concepts/distance_concept.hpp +++ b/include/boost/geometry/strategies/concepts/distance_concept.hpp @@ -19,13 +19,7 @@ #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include @@ -50,40 +44,15 @@ private : template static void apply(ApplyMethod const&) { - namespace ft = boost::function_types; - typedef typename ft::parameter_types - < - ApplyMethod - >::type parameter_types; - - typedef typename boost::mpl::if_ - < - ft::is_member_function_pointer, - boost::mpl::int_<1>, - boost::mpl::int_<0> - >::type base_index; - // 1: inspect and define both arguments of apply - typedef typename boost::remove_reference + typedef typename parameter_type_of < - typename boost::mpl::at - < - parameter_types, - base_index - >::type + ApplyMethod, 0 >::type ptype1; - typedef typename boost::remove_reference + typedef typename parameter_type_of < - typename boost::mpl::at - < - parameter_types, - typename boost::mpl::plus - < - base_index, - boost::mpl::int_<1> - >::type - >::type + ApplyMethod, 1 >::type ptype2; // 2) check if apply-arguments fulfill point concept @@ -177,40 +146,14 @@ private : template static void apply(ApplyMethod const&) { - namespace ft = boost::function_types; - typedef typename ft::parameter_types + typedef typename parameter_type_of < - ApplyMethod - >::type parameter_types; - - typedef typename boost::mpl::if_ - < - ft::is_member_function_pointer, - boost::mpl::int_<1>, - boost::mpl::int_<0> - >::type base_index; - - // 1: inspect and define both arguments of apply - typedef typename boost::remove_reference - < - typename boost::mpl::at - < - parameter_types, - base_index - >::type + ApplyMethod, 0 >::type ptype; - typedef typename boost::remove_reference + typedef typename parameter_type_of < - typename boost::mpl::at - < - parameter_types, - typename boost::mpl::plus - < - base_index, - boost::mpl::int_<1> - >::type - >::type + ApplyMethod, 1 >::type sptype; // 2) check if apply-arguments fulfill point concept diff --git a/include/boost/geometry/strategies/concepts/within_concept.hpp b/include/boost/geometry/strategies/concepts/within_concept.hpp index c1f07bc71..19c617416 100644 --- a/include/boost/geometry/strategies/concepts/within_concept.hpp +++ b/include/boost/geometry/strategies/concepts/within_concept.hpp @@ -17,6 +17,9 @@ #include +#include + +#include namespace boost { namespace geometry { namespace concept @@ -24,57 +27,265 @@ namespace boost { namespace geometry { namespace concept /*! - \brief Checks strategy for within (point-in-polygon) - \ingroup within +\brief Checks strategy for within (point-in-polygon) +\ingroup within */ template -class WithinStrategy +class WithinStrategyPolygonal { #ifndef DOXYGEN_NO_CONCEPT_MEMBERS - // 1) must define state_type, + // 1) must define state_type typedef typename Strategy::state_type state_type; - // 2) must define point_type (of "point" in poly) - typedef typename Strategy::point_type point_type; - - // 3) must define point_type, of polygon (segments) - typedef typename Strategy::segment_point_type spoint_type; - - - struct check_methods + struct checker { - static void apply() + template + static void apply(ApplyMethod const&, ResultMethod const& ) { - Strategy const* str; + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type point_type; + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type segment_point_type; + // CHECK: apply-arguments should both fulfill point concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint) + ); + + // CHECK: return types (result: int, apply: bool) + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + bool, typename boost::function_types::result_type::type + >::type::value), + WRONG_RETURN_TYPE_OF_APPLY + , (bool) + ); + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + int, typename boost::function_types::result_type::type + >::type::value), + WRONG_RETURN_TYPE_OF_RESULT + , (int) + ); + + + // CHECK: calling method apply and result + Strategy const* str; state_type* st; point_type const* p; - spoint_type const* sp; + segment_point_type const* sp; - // 4) must implement a method apply - // having a point, two segment-points, and state - str->apply(*p, *sp, *sp, *st); - - // 5) must implement a method result returning int + bool b = str->apply(*p, *sp, *sp, *st); int r = str->result(*st); boost::ignore_unused_variable_warning(r); + boost::ignore_unused_variable_warning(b); boost::ignore_unused_variable_warning(str); } }; public : - BOOST_CONCEPT_USAGE(WithinStrategy) + BOOST_CONCEPT_USAGE(WithinStrategyPolygonal) { - check_methods::apply(); + checker::apply(&Strategy::apply, &Strategy::result); } #endif }; +template +class WithinStrategyPointBox +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + struct checker + { + template + static void apply(ApplyMethod const&) + { + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type point_type; + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type box_type; + + // CHECK: apply-arguments should fulfill point/box concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstPoint) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstBox) + ); + + // CHECK: return types (apply: bool) + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + bool, + typename boost::function_types::result_type::type + >::type::value), + WRONG_RETURN_TYPE + , (bool) + ); -}}} // namespace boost::geometry::concept + // CHECK: calling method apply + Strategy const* str; + point_type const* p; + box_type const* bx; + + bool b = str->apply(*p, *bx); + + boost::ignore_unused_variable_warning(b); + boost::ignore_unused_variable_warning(str); + } + }; + + +public : + BOOST_CONCEPT_USAGE(WithinStrategyPointBox) + { + checker::apply(&Strategy::apply); + } +#endif +}; + +template +class WithinStrategyBoxBox +{ +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + struct checker + { + template + static void apply(ApplyMethod const&) + { + typedef typename parameter_type_of + < + ApplyMethod, 0 + >::type box_type1; + typedef typename parameter_type_of + < + ApplyMethod, 1 + >::type box_type2; + + // CHECK: apply-arguments should both fulfill box concept + BOOST_CONCEPT_ASSERT + ( + (concept::ConstBox) + ); + + BOOST_CONCEPT_ASSERT + ( + (concept::ConstBox) + ); + + // CHECK: return types (apply: bool) + BOOST_MPL_ASSERT_MSG + ( + (boost::is_same + < + bool, + typename boost::function_types::result_type::type + >::type::value), + WRONG_RETURN_TYPE + , (bool) + ); + + + // CHECK: calling method apply + Strategy const* str; + box_type1 const* b1; + box_type2 const* b2; + + bool b = str->apply(*b1, *b2); + + boost::ignore_unused_variable_warning(b); + boost::ignore_unused_variable_warning(str); + } + }; + + +public : + BOOST_CONCEPT_USAGE(WithinStrategyBoxBox) + { + checker::apply(&Strategy::apply); + } +#endif +}; + +// So now: boost::geometry::concept::within +namespace within +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +struct check_within +{}; + + +template +struct check_within +{ + BOOST_CONCEPT_ASSERT( (WithinStrategyPolygonal) ); +}; + + +template +struct check_within +{ + BOOST_CONCEPT_ASSERT( (WithinStrategyPointBox) ); +}; + +template +struct check_within +{ + BOOST_CONCEPT_ASSERT( (WithinStrategyBoxBox) ); +}; + + +} // namespace dispatch +#endif + + +/*! +\brief Checks, in compile-time, the concept of any within-strategy +\ingroup concepts +*/ +template +inline void check() +{ + dispatch::check_within c; + boost::ignore_unused_variable_warning(c); +} + + +}}}} // namespace boost::geometry::concept::within + #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/covered_by.hpp b/include/boost/geometry/strategies/covered_by.hpp new file mode 100644 index 000000000..59704eac4 --- /dev/null +++ b/include/boost/geometry/strategies/covered_by.hpp @@ -0,0 +1,72 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_COVERED_BY_HPP +#define BOOST_GEOMETRY_STRATEGIES_COVERED_BY_HPP + +#include + + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace covered_by +{ + + +namespace services +{ + +/*! +\brief Traits class binding a covered_by determination strategy to a coordinate system +\ingroup covered_by +\tparam TagContained tag (possibly casted) of point-type +\tparam TagContained tag (possibly casted) of (possibly) containing type +\tparam CsTagContained tag of coordinate system of point-type +\tparam CsTagContaining tag of coordinate system of (possibly) containing type +\tparam Geometry geometry-type of input (often point, or box) +\tparam GeometryContaining geometry-type of input (possibly) containing type +*/ +template +< + typename TagContained, + typename TagContaining, + typename CastedTagContained, + typename CastedTagContaining, + typename CsTagContained, + typename CsTagContaining, + typename GeometryContained, + typename GeometryContaining +> +struct default_strategy +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPES + , (types) + ); +}; + + +} // namespace services + + +}} // namespace strategy::covered_by + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_COVERED_BY_HPP + diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index 25369a7bf..7242b3db0 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -28,10 +28,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -43,6 +45,7 @@ #include #include +#include #include #include diff --git a/include/boost/geometry/strategies/strategy_transform.hpp b/include/boost/geometry/strategies/strategy_transform.hpp index 34e19fc77..0410833ca 100644 --- a/include/boost/geometry/strategies/strategy_transform.hpp +++ b/include/boost/geometry/strategies/strategy_transform.hpp @@ -222,6 +222,17 @@ namespace detail set_from_radian<1>(p, acos(z)); return true; } + + template + inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p) + { + assert_dimension(); + + set_from_radian<0>(p, atan2(y, x)); + set_from_radian<1>(p, asin(z)); + return true; + } + template inline bool cartesian_to_spherical3(T x, T y, T z, P& p) @@ -323,6 +334,16 @@ struct from_cartesian_3_to_spherical_polar_2 } }; +template +struct from_cartesian_3_to_spherical_equatorial_2 +{ + inline bool apply(P1 const& p1, P2& p2) const + { + assert_dimension(); + return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2); + } +}; + /*! \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r) @@ -421,6 +442,12 @@ struct default_strategy type; }; +template +struct default_strategy +{ + typedef from_cartesian_3_to_spherical_equatorial_2 type; +}; + /// Specialization to transform from XYZ to sphere(phi,theta,r) template struct default_strategy diff --git a/include/boost/geometry/strategies/within.hpp b/include/boost/geometry/strategies/within.hpp index ca61156b8..717fe5f15 100644 --- a/include/boost/geometry/strategies/within.hpp +++ b/include/boost/geometry/strategies/within.hpp @@ -16,7 +16,6 @@ #include -#include namespace boost { namespace geometry { @@ -29,28 +28,32 @@ namespace services { /*! - \brief Traits class binding a within determination strategy to a coordinate system - \ingroup within - \tparam CsTagContained tag of coordinate system of point-type - \tparam CsTagContained tag of coordinate system of segment-type - \tparam Point point-type of input points - \tparam PointContaining point-type of input segment-points +\brief Traits class binding a within determination strategy to a coordinate system +\ingroup within +\tparam TagContained tag (possibly casted) of point-type +\tparam TagContained tag (possibly casted) of (possibly) containing type +\tparam CsTagContained tag of coordinate system of point-type +\tparam CsTagContaining tag of coordinate system of (possibly) containing type +\tparam Geometry geometry-type of input (often point, or box) +\tparam GeometryContaining geometry-type of input (possibly) containing type */ template < typename TagContained, typename TagContaining, + typename CastedTagContained, + typename CastedTagContaining, typename CsTagContained, typename CsTagContaining, - typename Point, - typename PointContaining + typename GeometryContained, + typename GeometryContaining > struct default_strategy { BOOST_MPL_ASSERT_MSG ( false, NOT_IMPLEMENTED_FOR_THIS_TYPES - , (types) + , (types) ); }; diff --git a/include/boost/geometry/util/parameter_type_of.hpp b/include/boost/geometry/util/parameter_type_of.hpp new file mode 100644 index 000000000..2e8294164 --- /dev/null +++ b/include/boost/geometry/util/parameter_type_of.hpp @@ -0,0 +1,75 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_UTIL_PARAMETER_TYPE_OF_HPP +#define BOOST_GEOMETRY_UTIL_PARAMETER_TYPE_OF_HPP + + +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + + +/*! +\brief Meta-function selecting a parameter type of a (member) function, by index +\ingroup utility + */ +template +struct parameter_type_of +{ + typedef typename boost::function_types::parameter_types + < + Method + >::type parameter_types; + + typedef typename boost::mpl::if_ + < + boost::function_types::is_member_function_pointer, + boost::mpl::int_<1>, + boost::mpl::int_<0> + >::type base_index_type; + + typedef typename boost::mpl::if_c + < + Index == 0, + base_index_type, + typename boost::mpl::plus + < + base_index_type, + boost::mpl::int_ + >::type + >::type indexed_type; + + typedef typename boost::remove_reference + < + typename boost::mpl::at + < + parameter_types, + indexed_type + >::type + >::type type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_PARAMETER_TYPE_OF_HPP diff --git a/include/boost/geometry/util/rational.hpp b/include/boost/geometry/util/rational.hpp new file mode 100644 index 000000000..d450a8497 --- /dev/null +++ b/include/boost/geometry/util/rational.hpp @@ -0,0 +1,179 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2011-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2011-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_UTIL_RATIONAL_HPP +#define BOOST_GEOMETRY_UTIL_RATIONAL_HPP + +#include +#include + +#include +#include + + +namespace boost{ namespace geometry +{ + + +// Specialize for Boost.Geometry's coordinate cast +// (from string to coordinate type) +namespace detail +{ + +template +struct coordinate_cast > +{ + static inline void split_parts(std::string const& source, std::string::size_type p, + T& before, T& after, bool& negate, std::string::size_type& len) + { + std::string before_part = source.substr(0, p); + std::string const after_part = source.substr(p + 1); + + negate = false; + + if (before_part.size() > 0 && before_part[0] == '-') + { + negate = true; + before_part.erase(0, 1); + } + before = atol(before_part.c_str()); + after = atol(after_part.c_str()); + len = after_part.length(); + } + + + static inline rational apply(std::string const& source) + { + T before, after; + bool negate; + std::string::size_type len; + + // Note: decimal comma is not (yet) supported, it does (and should) not + // occur in a WKT, where points are comma separated. + std::string::size_type p = source.find("."); + if (p == std::string::npos) + { + p = source.find("/"); + if (p == std::string::npos) + { + return rational(atol(source.c_str())); + } + split_parts(source, p, before, after, negate, len); + + return negate + ? -rational(before, after) + : rational(before, after) + ; + + } + + split_parts(source, p, before, after, negate, len); + + T den = 1; + for (std::string::size_type i = 0; i < len; i++) + { + den *= 10; + } + + return negate + ? -rational(before) - rational(after, den) + : rational(before) + rational(after, den) + ; + } +}; + +} // namespace detail + +// Specialize for Boost.Geometry's select_most_precise +template +struct select_most_precise, boost::rational > +{ + typedef typename boost::rational + < + typename select_most_precise::type + > type; +}; + +template +struct select_most_precise, double> +{ + typedef typename boost::rational type; +}; + + +}} // namespace boost::geometry + + +// Specializes boost::rational to boost::numeric::bounds +namespace boost { namespace numeric +{ + +template +struct bounds > +{ + static inline rational lowest() + { + return rational(bounds::lowest(), 1); + } + static inline rational highest() + { + return rational(bounds::highest(), 1); + } +}; + +}} // namespace boost::numeric + + +// Support for boost::numeric_cast to int and to double (necessary for SVG-mapper) +namespace boost { namespace numeric +{ + +template +< + typename T, + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker> +{ + static inline int convert(rational const& arg) + { + return int(rational_cast(arg)); + } +}; + +template +< + typename T, + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker> +{ + static inline double convert(rational const& arg) + { + return rational_cast(arg); + } +}; + + +}} + + +#endif // BOOST_GEOMETRY_UTIL_RATIONAL_HPP diff --git a/test/algorithms/Jamfile.v2 b/test/algorithms/Jamfile.v2 index 7058f6753..3e37dcaf0 100644 --- a/test/algorithms/Jamfile.v2 +++ b/test/algorithms/Jamfile.v2 @@ -19,6 +19,7 @@ test-suite boost-geometry-algorithms [ run convex_hull.cpp ] [ run correct.cpp ] [ run convert.cpp ] + [ run covered_by.cpp ] [ run difference.cpp ] [ run disjoint.cpp ] [ run distance.cpp ] diff --git a/test/algorithms/algorithms_tests.sln b/test/algorithms/algorithms_tests.sln index 6880312aa..124ad8af0 100644 --- a/test/algorithms/algorithms_tests.sln +++ b/test/algorithms/algorithms_tests.sln @@ -56,6 +56,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "comparable_distance", "comp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "convert", "convert.vcproj", "{FABF1AA7-F695-49F8-92F6-AB6C4B0C088A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "covered_by", "covered_by.vcproj", "{5ABF0B56-F9F1-4D93-B15A-E3972F45D97B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -174,6 +176,10 @@ Global {FABF1AA7-F695-49F8-92F6-AB6C4B0C088A}.Debug|Win32.Build.0 = Debug|Win32 {FABF1AA7-F695-49F8-92F6-AB6C4B0C088A}.Release|Win32.ActiveCfg = Release|Win32 {FABF1AA7-F695-49F8-92F6-AB6C4B0C088A}.Release|Win32.Build.0 = Release|Win32 + {5ABF0B56-F9F1-4D93-B15A-E3972F45D97B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5ABF0B56-F9F1-4D93-B15A-E3972F45D97B}.Debug|Win32.Build.0 = Debug|Win32 + {5ABF0B56-F9F1-4D93-B15A-E3972F45D97B}.Release|Win32.ActiveCfg = Release|Win32 + {5ABF0B56-F9F1-4D93-B15A-E3972F45D97B}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/algorithms/assign.cpp b/test/algorithms/assign.cpp index ad3bef97b..f99e11a55 100644 --- a/test/algorithms/assign.cpp +++ b/test/algorithms/assign.cpp @@ -162,6 +162,14 @@ void test_assign_conversion() ring_type ring; bg::assign(ring, b); + { + typedef bg::model::ring ring_type_ccw; + ring_type_ccw ring_ccw; + // Should NOT compile (currently): bg::assign(ring_ccw, ring); + + } + + //std::cout << bg::wkt(b) << std::endl; //std::cout << bg::wkt(ring) << std::endl; diff --git a/test/algorithms/convert.cpp b/test/algorithms/convert.cpp index 039922b3b..8b230f8bb 100644 --- a/test/algorithms/convert.cpp +++ b/test/algorithms/convert.cpp @@ -12,97 +12,237 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include + +#include -#include -#include -#include -#include -#include -#include -#include -#include - -BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian) -BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) - - -template -void test_all() +template +void test_mixed_point_types() { - typedef bg::model::box

box_type; + // Point + test_mixed_identical_result("POINT(1 2)"); - P p; - bg::assign_values(p, 1, 2); + // Linestring + test_mixed_identical_result + < + bg::model::linestring, + bg::model::linestring + > + ("LINESTRING(1 1,2 2)"); - box_type b; - bg::convert(p, b); + // Ring + test_mixed_identical_result + < + bg::model::ring, + bg::model::ring + > + ("POLYGON((1 1,2 2,3 0,1 1))"); + test_mixed_reversible_result + < + bg::model::ring, + bg::model::ring + > + ( + "POLYGON((1 1,2 2,3 0,1 1))", + "POLYGON((1 1,3 0,2 2,1 1))" + ); + test_mixed + < + bg::model::ring, + bg::model::ring + > + ( + "POLYGON((1 1,2 2,3 0,1 1))", + "POLYGON((1 1,2 2,3 0))" + ); + test_mixed + < + bg::model::ring, + bg::model::ring + > + ( + "POLYGON((1 1,2 2,3 0))", + "POLYGON((1 1,2 2,3 0,1 1))" + ); - BOOST_CHECK_CLOSE((bg::get<0, 0>(b)), 1.0, 0.001); - BOOST_CHECK_CLOSE((bg::get<0, 1>(b)), 2.0, 0.001); - BOOST_CHECK_CLOSE((bg::get<1, 0>(b)), 1.0, 0.001); - BOOST_CHECK_CLOSE((bg::get<1, 1>(b)), 2.0, 0.001); + // Polygon + test_mixed_reversible_result + < + bg::model::polygon, + bg::model::polygon + > + ( + "POLYGON((0 0,0 5,5 5,5 0,0 0),(1 1,3 2,2 4,1 1))", + "POLYGON((0 0,5 0,5 5,0 5,0 0),(1 1,2 4,3 2,1 1))" + ); + test_mixed + < + bg::model::polygon, + bg::model::polygon + > + ( + "POLYGON((0 0,0 5,5 5,5 0,0 0),(1 1,3 2,2 4,1 1))", + "POLYGON((0 0,5 0,5 5,0 5),(1 1,2 4,3 2))" + ); + // (polygon uses ring, so other tests omitted here) + + // Combinations: + // ring <-> polygon + test_mixed_identical_result + < + bg::model::polygon, + bg::model::ring + > + ("POLYGON((1 1,2 2,3 0,1 1))"); + test_mixed_reversible_result + < + bg::model::polygon, + bg::model::ring + > + ( + "POLYGON((1 1,2 2,3 0,1 1))", + "POLYGON((1 1,3 0,2 2,1 1))" + ); + // Any hole will be omitted going from polygon to ring + test_mixed + < + bg::model::polygon, + bg::model::ring + > + ( + "POLYGON((0 0,0 5,5 5,5 0,0 0),(1 1,3 2,2 4,1 1))", + "POLYGON((0 0,0 5,5 5,5 0,0 0))" + ); + + // point -> box + test_mixed + < + Point1, + bg::model::box + > + ( + "POINT(0 0)", + "POLYGON((0 0,0 0,0 0,0 0,0 0))" + ); + + // segment -> line + test_mixed + < + bg::model::segment, + bg::model::linestring + > + ( + "LINESTRING(0 0,1 1)", + "LINESTRING(0 0,1 1)" + ); + + // box -> ring ( <- is NYI) + test_mixed + < + bg::model::box, + bg::model::ring + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,0 2,2 2,2 0,0 0))" + ); + test_mixed + < + bg::model::box, + bg::model::ring + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,2 0,2 2,0 2,0 0))" + ); + test_mixed + < + bg::model::box, + bg::model::ring + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,0 2,2 2,2 0))" + ); + test_mixed + < + bg::model::box, + bg::model::ring + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,2 0,2 2,0 2))" + ); + + // box -> polygon ( <- is NYI) + test_mixed + < + bg::model::box, + bg::model::polygon + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,0 2,2 2,2 0,0 0))" + ); + test_mixed + < + bg::model::box, + bg::model::polygon + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,2 0,2 2,0 2,0 0))" + ); + test_mixed + < + bg::model::box, + bg::model::polygon + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,0 2,2 2,2 0))" + ); + test_mixed + < + bg::model::box, + bg::model::polygon + > + ( + "BOX(0 0,2 2)", + "POLYGON((0 0,2 0,2 2,0 2))" + ); } -template -void test_std() +template +void test_mixed_types() { - test_all

(); + test_mixed_point_types(); + test_mixed_point_types(); +} - typedef bg::model::box

box_type; - typedef bg::model::ring

ring_type; - typedef bg::model::polygon

polygon_type; - - box_type b; - bg::set(b, 1); - bg::set(b, 2); - bg::set(b, 3); - bg::set(b, 4); - - ring_type ring; - bg::convert(b, ring); - - //std::cout << bg::wkt(b) << std::endl; - //std::cout << bg::wkt(ring) << std::endl; - - typename boost::range_const_iterator::type it = ring.begin(); - BOOST_CHECK_CLOSE(bg::get<0>(*it), 1.0, 0.001); - BOOST_CHECK_CLOSE(bg::get<1>(*it), 2.0, 0.001); - it++; - BOOST_CHECK_CLOSE(bg::get<0>(*it), 1.0, 0.001); - BOOST_CHECK_CLOSE(bg::get<1>(*it), 4.0, 0.001); - it++; - BOOST_CHECK_CLOSE(bg::get<0>(*it), 3.0, 0.001); - BOOST_CHECK_CLOSE(bg::get<1>(*it), 4.0, 0.001); - it++; - BOOST_CHECK_CLOSE(bg::get<0>(*it), 3.0, 0.001); - BOOST_CHECK_CLOSE(bg::get<1>(*it), 2.0, 0.001); - it++; - BOOST_CHECK_CLOSE(bg::get<0>(*it), 1.0, 0.001); - BOOST_CHECK_CLOSE(bg::get<1>(*it), 2.0, 0.001); - - BOOST_CHECK_EQUAL(ring.size(), 5u); - - - polygon_type polygon; - - bg::convert(ring, polygon); - BOOST_CHECK_EQUAL(bg::num_points(polygon), 5u); - - bg::convert(polygon, ring); - BOOST_CHECK_EQUAL(bg::num_points(ring), 5u); +void test_array() +{ + int a[2] = {1, 2}; + int b[2]; + bg::convert(a, b); + BOOST_CHECK_EQUAL(b[0], 1); + BOOST_CHECK_EQUAL(b[1], 2); } int test_main(int, char* []) { - test_std >(); - test_std >(); - test_std >(); + test_mixed_types + < + bg::model::point, + bg::model::point + >(); + test_mixed_types + < + boost::tuple, + bg::model::point + >(); -#ifdef HAVE_TTMATH - test_std >(); -#endif + test_array(); return 0; } diff --git a/test/algorithms/covered_by.cpp b/test/algorithms/covered_by.cpp new file mode 100644 index 000000000..a6cb7aef1 --- /dev/null +++ b/test/algorithms/covered_by.cpp @@ -0,0 +1,149 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// 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) + +#include + + +#include +#include + + +template +void test_all() +{ + /* + // trivial case + test_ring

("POINT(1 1)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", true, false); + + // on border/corner + test_ring

("POINT(0 0)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", false, true); + test_ring

("POINT(0 1)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", false, true); + + // aligned to segment/vertex + test_ring

("POINT(1 1)", "POLYGON((0 0,0 3,3 3,3 1,2 1,2 0,0 0))", true, false); + test_ring

("POINT(1 1)", "POLYGON((0 0,0 3,4 3,3 1,2 2,2 0,0 0))", true, false); + + // same polygon, but point on border + test_ring

("POINT(3 3)", "POLYGON((0 0,0 3,3 3,3 1,2 1,2 0,0 0))", false, true); + test_ring

("POINT(3 3)", "POLYGON((0 0,0 3,4 3,3 1,2 2,2 0,0 0))", false, true); + + // holes + test_geometry >("POINT(2 2)", + "POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,3 1,3 3,1 3,1 1))", false); + + */ + + typedef bg::model::box

box_type; + + test_geometry("POINT(1 1)", "BOX(0 0,2 2)", true); + test_geometry("POINT(0 0)", "BOX(0 0,2 2)", true); + test_geometry("POINT(2 2)", "BOX(0 0,2 2)", true); + test_geometry("POINT(0 1)", "BOX(0 0,2 2)", true); + test_geometry("POINT(1 0)", "BOX(0 0,2 2)", true); + test_geometry("POINT(3 3)", "BOX(0 0,2 2)", false); + + test_geometry("BOX(1 1,2 2)", "BOX(0 0,3 3)", true); + test_geometry("BOX(0 0,3 3)", "BOX(1 1,2 2)", false); + test_geometry("BOX(0 0,2 2)", "BOX(0 0,3 3)", true); + test_geometry("BOX(1 1,3 3)", "BOX(0 0,3 3)", true); + test_geometry("BOX(1 2,3 3)", "BOX(0 0,3 3)", true); + test_geometry("BOX(1 1,4 3)", "BOX(0 0,3 3)", false); + + + /* + test_within_code("POINT(1 1)", "BOX(0 0,2 2)", 1); + test_within_code("POINT(1 0)", "BOX(0 0,2 2)", 0); + test_within_code("POINT(0 1)", "BOX(0 0,2 2)", 0); + test_within_code("POINT(0 3)", "BOX(0 0,2 2)", -1); + test_within_code("POINT(3 3)", "BOX(0 0,2 2)", -1); + + test_within_code("BOX(1 1,2 2)", "BOX(0 0,3 3)", 1); + test_within_code("BOX(0 1,2 2)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 0,2 2)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 1,2 3)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 1,3 2)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 1,3 4)", "BOX(0 0,3 3)", -1); + */ +} + + +void test_3d() +{ + typedef boost::geometry::model::point point_type; + typedef boost::geometry::model::box box_type; + box_type box(point_type(0, 0, 0), point_type(4, 4, 4)); + BOOST_CHECK_EQUAL(bg::covered_by(point_type(2, 2, 2), box), true); + BOOST_CHECK_EQUAL(bg::covered_by(point_type(2, 4, 2), box), true); + BOOST_CHECK_EQUAL(bg::covered_by(point_type(2, 2, 4), box), true); + BOOST_CHECK_EQUAL(bg::covered_by(point_type(2, 2, 5), box), false); +} + +template +void test_mixed_of() +{ + typedef boost::geometry::model::polygon polygon_type1; + typedef boost::geometry::model::polygon polygon_type2; + typedef boost::geometry::model::box box_type1; + typedef boost::geometry::model::box box_type2; + + polygon_type1 poly1, poly2; + boost::geometry::read_wkt("POLYGON((0 0,0 5,5 5,5 0,0 0))", poly1); + boost::geometry::read_wkt("POLYGON((0 0,0 5,5 5,5 0,0 0))", poly2); + + box_type1 box1(P1(1, 1), P1(4, 4)); + box_type2 box2(P2(0, 0), P2(5, 5)); + P1 p1(3, 3); + P2 p2(3, 3); + + BOOST_CHECK_EQUAL(bg::covered_by(p1, poly2), true); + BOOST_CHECK_EQUAL(bg::covered_by(p2, poly1), true); + BOOST_CHECK_EQUAL(bg::covered_by(p2, box1), true); + BOOST_CHECK_EQUAL(bg::covered_by(p1, box2), true); + BOOST_CHECK_EQUAL(bg::covered_by(box1, box2), true); + BOOST_CHECK_EQUAL(bg::covered_by(box2, box1), false); +} + + +void test_mixed() +{ + // Mixing point types and coordinate types + test_mixed_of + < + boost::geometry::model::d2::point_xy, + boost::geometry::model::point + >(); + test_mixed_of + < + boost::geometry::model::d2::point_xy, + boost::geometry::model::point + >(); + test_mixed_of + < + boost::geometry::model::d2::point_xy, + boost::geometry::model::d2::point_xy + >(); +} + + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + + //test_spherical > >(); + + test_mixed(); + test_3d(); + + +#if defined(HAVE_TTMATH) + test_all >(); + //test_spherical > >(); +#endif + + return 0; +} diff --git a/test/algorithms/covered_by.vcproj b/test/algorithms/covered_by.vcproj new file mode 100644 index 000000000..13f41e930 --- /dev/null +++ b/test/algorithms/covered_by.vcproj @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/algorithms/difference.cpp b/test/algorithms/difference.cpp index 7787dea3d..1cd2bb8ae 100644 --- a/test/algorithms/difference.cpp +++ b/test/algorithms/difference.cpp @@ -46,8 +46,7 @@ void test_all() typedef bg::model::polygon

polygon; typedef bg::model::ring

ring; - bool const is_float = - boost::is_same::type, float>::value; + typedef typename bg::coordinate_type

::type ct; test_one("simplex_normal", simplex_normal[0], simplex_normal[1], @@ -93,7 +92,7 @@ void test_all() test_one("distance_zero", distance_zero[0], distance_zero[1], 2, 0, 8.7048386, - is_float ? 1 : 2, // The too small one is discarded for floating point + if_typed(1, 2), // The too small one is discarded for floating point 0, 0.0098387); @@ -200,17 +199,54 @@ void test_all() ***/ #ifdef _MSC_VER - { - // Isovist (submitted by Brandon during Formal Review) - std::string tn = string_from_type::type>::name(); - test_one("isovist", - isovist1[0], isovist1[1], - 4, 0, 0.279121891701124, - 4, 0, 224.889211358929, - 0.01); - } -#endif + // Isovist (submitted by Brandon during Formal Review) + test_one("isovist", + isovist1[0], isovist1[1], + 4, 0, 0.279121891701124, + 4, 0, 224.889211358929, + 0.01); + test_one("ggl_list_20110306_javier", + ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], + 1, 0, 71495.3331, + 2, 0, 8960.49049); +#endif + + test_one("ggl_list_20110307_javier", + ggl_list_20110307_javier[0], ggl_list_20110307_javier[1], + 1, 0, 16815.6, + 1, 0, 3200.4, + 0.01); + + test_one("ggl_list_20110716_enrico", + ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1], + 3, 0, 35723.8506317139, + 1, 0, 58456.4964294434 + ); + + test_one("ggl_list_20110820_christophe", + ggl_list_20110820_christophe[0], ggl_list_20110820_christophe[1], + 1, 0, 2.8570121719168924, + 1, 0, 64.498061986388564); + + + +#ifdef _MSC_VER + // 2011-07-02 + // Interesting FP-precision case. + // sql server gives: 6.62295817619452E-05 + // PostGIS gives: 0.0 (no output) + // Boost.Geometry gives results depending on FP-type, and compiler, and operating system. + // For double, it is zero (skipped). On gcc/Linux, for float either. + // Because we cannot predict this, we only test for MSVC + test_one("ggl_list_20110627_phillip", + ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1], + if_typed(0, 1), 0, + if_typed_tt(0.0000000000001105367, 0.0), + 1, 0, 3577.40960816756, + 0.01 + ); +#endif // Other combi's { diff --git a/test/algorithms/intersection.cpp b/test/algorithms/intersection.cpp index c4d9ec5c3..c85ebb877 100644 --- a/test/algorithms/intersection.cpp +++ b/test/algorithms/intersection.cpp @@ -20,11 +20,15 @@ //#define BOOST_GEOMETRY_DEBUG_IDENTIFIER +#include +#include + +#include + #include #include -#include -#include +#include #include #include @@ -155,17 +159,40 @@ void test_areal() crossed[0], crossed[1], 3, 0, 1.5); + typedef typename bg::coordinate_type::type ct; + #ifdef _MSC_VER - { - // Isovist (submitted by Brandon during Formal Review) - std::string tn = string_from_type::type>::name(); - test_one("isovist", - isovist1[0], isovist1[1], - 1, - tn == std::string("f") ? 19 : tn == std::string("d") ? 22 : 20, - 88.19203, - tn == std::string("f") ? 0.5 : tn == std::string("d") ? 0.1 : 0.01); - } + // Isovist (submitted by Brandon during Formal Review) + test_one("isovist", + isovist1[0], isovist1[1], + 1, + if_typed(19, if_typed(20, 20)), + 88.19203, + if_typed(0.5, if_typed(0.1, 0.01))); +#endif + + //std::cout << typeid(ct).name() << std::endl; + + test_one("ggl_list_20110306_javier", + ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], + 1, if_typed_tt(5, 4), + 0.6649875, + if_typed(1.0, 0.01)); + + test_one("ggl_list_20110307_javier", + ggl_list_20110307_javier[0], ggl_list_20110307_javier[1], + 1, 4, 0.4, 0.01); + + test_one("ggl_list_20110627_phillip", + ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1], + 1, if_typed_tt(6, 5), 11151.6618); + +#ifdef _MSC_VER // gcc/linux behaves differently + test_one("ggl_list_20110716_enrico", + ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1], + 3, + if_typed(19, if_typed(22, 21)), + 35723.8506317139); #endif return; @@ -237,6 +264,23 @@ void test_boxes(std::string const& wkt1, std::string const& wkt2, double expecte } +template +void test_point_output() +{ + typedef bg::model::linestring

linestring; + typedef bg::model::polygon

polygon; + typedef bg::model::box

box; + typedef bg::model::segment

segment; + + test_point_output(simplex_normal[0], simplex_normal[1], 6); + test_point_output("box(1 1,6 4)", simplex_normal[0], 4); + test_point_output("linestring(0 2,6 2)", simplex_normal[0], 2); + // NYI because of sectionize: + // test_point_output("linestring(0 2,6 2)", simplex_normal[0], 2); + // NYI because needs special treatment: + // test_point_output("box(0 0,4 4)", "box(2 2,6 6)", 2); +} + template void test_all() { @@ -311,6 +355,8 @@ void test_all() test_boxes("box(2 2,8 7)", "box(14 4,20 10)", 0, false); test_boxes("box(2 2,4 4)", "box(4 4,8 8)", 0, true); + test_point_output

(); + /* test_one(99, "box(115041.10 471900.10, 118334.60 474523.40)", @@ -375,10 +421,18 @@ void test_exception() BOOST_CHECK_MESSAGE(false, "No exception thrown"); } +template +void test_rational() +{ + typedef bg::model::polygon polygon; + test_one("simplex_normal", + simplex_normal[0], simplex_normal[1], + 1, 7, 5.47363293); +} + + int test_main(int, char* []) { - test_exception >(); - test_all >(); #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) @@ -388,9 +442,12 @@ int test_main(int, char* []) test_all >(); #endif - //test_pointer_version(); #endif + test_exception >(); + test_pointer_version(); + test_rational > >(); + return 0; } diff --git a/test/algorithms/intersects.cpp b/test/algorithms/intersects.cpp index 4e71452f2..51e7b8cac 100644 --- a/test/algorithms/intersects.cpp +++ b/test/algorithms/intersects.cpp @@ -58,6 +58,57 @@ void test_all() // Hole: two intersecting holes test_self_intersects( "POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 3,3 3,3 1,1 1),(2 2,2 3.5,3.5 3.5,3.5 2,2 2))", true); + + // Mail Akira T on [Boost-users] at 27-7-2011 3:17 + test_self_intersects >( + "LINESTRING(0 0,0 4,4 4,2 2,2 5)", true); + + test_self_intersects >( + "LINESTRING(0 4,4 4,2 2,2 5)", true); + + // Test self-intersections at last segment in close/open rings: + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,0 0))", false); + + test_self_intersects >( + "POLYGON((0 0,3 3,4 1))", false); + + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,0 1,0 0))", true); + + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,0 1))", true); + + // Duplicates in first or last + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,0 1,0 1,0 0))", true); + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,0 1,0 0,0 0))", true); + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,0 1,0 1))", true); + test_self_intersects >( + "POLYGON((0 0,0 0,3 3,4 1,0 1,0 1,0 0))", true); + test_self_intersects >( + "POLYGON((0 0,0 0,3 3,4 1,0 1,0 1))", true); + test_self_intersects >( + "POLYGON((0 0,3 3,3 3,4 1,0 1,0 1,0 0))", true); + test_self_intersects >( + "POLYGON((0 0,3 3,3 3,4 1,0 1,0 1))", true); + + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,0 0,0 0))", false); + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,4 1,0 0))", false); + test_self_intersects >( + "POLYGON((0 0,3 3,4 1,4 1))", false); + test_self_intersects >( + "POLYGON((0 0,0 0,3 3,4 1,0 0))", false); + test_self_intersects >( + "POLYGON((0 0,0 0,3 3,4 1))", false); + test_self_intersects >( + "POLYGON((0 0,3 3,3 3,4 1,0 0))", false); + test_self_intersects >( + "POLYGON((0 0,3 3,3 3,4 1))", false); } diff --git a/test/algorithms/overlay/ccw_traverse.cpp b/test/algorithms/overlay/ccw_traverse.cpp index 463ecdbde..edf9dcb5a 100644 --- a/test/algorithms/overlay/ccw_traverse.cpp +++ b/test/algorithms/overlay/ccw_traverse.cpp @@ -62,7 +62,11 @@ inline typename bg::coordinate_type::type intersect(Geometry1 const& typedef std::deque out_vector; out_vector v; - bg::traverse::value, rev::value>(g1, g2, op, turns, v); + bg::detail::overlay::traverse + < + rev::value, rev::value, + Geometry1, Geometry2 + >::apply(g1, g2, op, turns, v); typename bg::coordinate_type::type result = 0.0; BOOST_FOREACH(ring_type& ring, v) diff --git a/test/algorithms/overlay/get_turns.cpp b/test/algorithms/overlay/get_turns.cpp index 2ee3a050c..6ebac44e4 100644 --- a/test/algorithms/overlay/get_turns.cpp +++ b/test/algorithms/overlay/get_turns.cpp @@ -303,6 +303,11 @@ void test_all() 4, ggl_list_20110306_javier[0], ggl_list_20110306_javier[1]); +#ifdef _MSC_VER // gcc returns 14 for float + test_get_turns::apply("ggl_list_20110716_enrico", + 13, + ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1]); +#endif // pies test_get_turns::apply("pie_23_16_16", 3, pie_23_16_16[0], pie_23_16_16[1]); diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 650a49123..64e5f865a 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -490,6 +490,33 @@ static std::string ggl_list_20110306_javier[2] = "POLYGON((-2 2,2002 2,2002 -2002,-2 -2002,-2 2),(0 -147.00000000000003,0 -2000,2000 -2000,2000 0,104 0,440 -240,400 -280,0 -147.00000000000003))", "POLYGON((359.99000000000001 -280,0 -182,0 -147,400.00999999999999 -280,359.99000000000001 -280))" }; + +static std::string ggl_list_20110307_javier[2] = + { + "POLYGON((-2 2, 1842 2, 1842 -2362, -2 -2362, -2 2), (0 0, 0 -2360, 1840 -2360, 1840 0, 0 0))", + // "POLYGON((-0.01 -1960, 0 -1960, 0 -1880, 0.01 -1960, -0.01 -1960))" + "POLYGON ((-0.01 -1960, 80.01 -1960, 0 -1880, -0.01 -1960))" + }; + + +static std::string ggl_list_20110627_phillip[2] = + { + "POLYGON((537.99678544791459 124.30517362077681,437.36539413622404 142.02728895075373,456.33031803043468 249.50296671450121,556.96217263181723 231.78347688272990,537.99678544791459 124.30517362077681))", + "POLYGON((437.35 142.03,461.94 281.32,564.5 263.26,539.9 123.97,437.35 142.03))" + }; + +static std::string ggl_list_20110716_enrico[2] = + { + "POLYGON((1.83691e-014 -300,-259.808 -150,-259.808 150,-5.51073e-014 300,259.808 150,259.808 -150,9.18455e-014 -300,1.83691e-014 -300),(7.65379e-014 -250,216.506 -125,216.506 125,-4.59227e-014 250,-216.506 125,-216.506 -125,1.53076e-014 -250,7.65379e-014 -250))", + "POLYGON((1.83691e-014 -300,-259.808 -150,-216.506 -125,-216.506 125,-259.808 150,-5.51073e-014 300,-4.59227e-014 250,216.506 125,259.808 150,259.808 -150,216.506 -125,7.65379e-014 -250,9.18455e-014 -300,1.83691e-014 -300),(6.12303e-014 -200,173.205 -100,173.205 100,-3.67382e-014 200,-173.205 100,-173.205 -100,1.22461e-014 -200,6.12303e-014 -200))" + }; + + +static std::string ggl_list_20110820_christophe[2] = +{ + "POLYGON((17.763942722600319 32.23605727739968,19.192448808558737 30.807551191441263,16.000000000000000 30.000000000000000,17.763942722600319 32.236057277399681))", + "POLYGON((0.24806946917841693 26.015444246572663,31.751930530821582 33.984555753427337,32.248069469178418 30.015444246572663,0.24806946917841693 26.015444246572663))" +}; // GEOS "TestOverlay" test. diff --git a/test/algorithms/overlay/robustness/intersects.cpp b/test/algorithms/overlay/robustness/intersects.cpp new file mode 100644 index 000000000..8d60f1321 --- /dev/null +++ b/test/algorithms/overlay/robustness/intersects.cpp @@ -0,0 +1,181 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2011 Barend Gehrels, Amsterdam, the Netherlands. + +// 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) + +#include +#include +#include +#include +#include + +#define BOOST_GEOMETRY_REPORT_OVERLAY_ERROR +#define BOOST_GEOMETRY_NO_BOOST_TEST +//#define BOOST_GEOMETRY_TIME_OVERLAY + + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + + +template +inline void make_polygon(MultiPolygon& mp, int count_x, int count_y, int index, int width_x) +{ + typedef typename bg::point_type::type point_type; + + for(int j = 0; j < count_x; ++j) + { + for(int k = 0; k < count_y; ++k) + { + mp.push_back(MultiPolygon::value_type()); + mp.back().outer().push_back(point_type(width_x + j * 10 + 1, k * 10 + 1)); + mp.back().outer().push_back(point_type(width_x + j * 10 + width_x, k * 10 + 5 + index)); + mp.back().outer().push_back(point_type(width_x + j * 10 + 5 + index, k * 10 + 7)); + mp.back().outer().push_back(point_type(width_x + j * 10 + 1, k * 10 + 1)); + } + } +} + + + +template +void test_intersects(int count_x, int count_y, int width_x, p_q_settings const& settings) +{ + MultiPolygon mp; + + make_polygon(mp, count_x, count_y, 0, width_x); + + bool const b = bg::intersects(mp); + if (b) + { + std::cout << " YES"; + } + + if(settings.svg) + { + typedef typename bg::coordinate_type::type coordinate_type; + typedef typename bg::point_type::type point_type; + std::ostringstream filename; + filename << "intersects_" + << string_from_type::name() + << ".svg"; + + std::ofstream svg(filename.str().c_str()); + bg::svg_mapper mapper(svg, 500, 500); + mapper.add(mp); + mapper.map(mp, "fill-opacity:0.5;fill:rgb(153,204,0);" + "stroke:rgb(153,204,0);stroke-width:3"); + } +} + + +template +void test_all(int count, int count_x, int count_y, int width_x, p_q_settings const& settings) +{ + boost::timer t; + + typedef bg::model::polygon + < + bg::model::d2::point_xy, Clockwise, Closed + > polygon; + typedef bg::model::multi_polygon + < + polygon + > multi_polygon; + + + int index = 0; + for(int i = 0; i < count; i++) + { + test_intersects(count_x, count_y, width_x, settings); + } + std::cout + << " type: " << string_from_type::name() + << " time: " << t.elapsed() << std::endl; +} + +int main(int argc, char** argv) +{ + try + { + namespace po = boost::program_options; + po::options_description description("=== intersects ===\nAllowed options"); + + int width_x = 7; + int count = 1; + int count_x = 10; + int count_y = 10; + bool ccw = false; + bool open = false; + p_q_settings settings; + + description.add_options() + ("help", "Help message") + ("count", po::value(&count)->default_value(1), "Number of tests") + ("count_x", po::value(&count_x)->default_value(10), "Triangle count in x-direction") + ("count_y", po::value(&count_y)->default_value(10), "Triangle count in y-direction") + ("width_x", po::value(&width_x)->default_value(7), "Width of triangle in x-direction") + ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") + ("open", po::value(&open)->default_value(false), "Open polygons") + ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") + ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") + ; + + po::variables_map varmap; + po::store(po::parse_command_line(argc, argv, description), varmap); + po::notify(varmap); + + if (varmap.count("help")) + { + std::cout << description << std::endl; + return 1; + } + + if (ccw && open) + { + test_all(count, count_x, count_y, width_x, settings); + } + else if (ccw) + { + test_all(count, count_x, count_y, width_x, settings); + } + else if (open) + { + test_all(count, count_x, count_y, width_x, settings); + } + else + { + test_all(count, count_x, count_y, width_x, settings); + } + +#if defined(HAVE_TTMATH) + // test_all(seed, count, max, svg, level); +#endif + } + catch(std::exception const& e) + { + std::cout << "Exception " << e.what() << std::endl; + } + catch(...) + { + std::cout << "Other exception" << std::endl; + } + + return 0; +} diff --git a/test/algorithms/overlay/robustness/intersects.vcproj b/test/algorithms/overlay/robustness/intersects.vcproj new file mode 100644 index 000000000..8331792e5 --- /dev/null +++ b/test/algorithms/overlay/robustness/intersects.vcproj @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/algorithms/overlay/robustness/robustness.sln b/test/algorithms/overlay/robustness/robustness.sln index ccb43ed93..dd6ff8821 100644 --- a/test/algorithms/overlay/robustness/robustness.sln +++ b/test/algorithms/overlay/robustness/robustness.sln @@ -12,6 +12,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "star_comb", "star_comb.vcpr EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "interior_triangles", "interior_triangles.vcproj", "{7583C2E3-AD74-4C34-8E94-9162F641B215}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intersects", "intersects.vcproj", "{1AC9B120-3ED0-4444-86E5-1916108943C7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -42,6 +44,10 @@ Global {7583C2E3-AD74-4C34-8E94-9162F641B215}.Debug|Win32.Build.0 = Debug|Win32 {7583C2E3-AD74-4C34-8E94-9162F641B215}.Release|Win32.ActiveCfg = Release|Win32 {7583C2E3-AD74-4C34-8E94-9162F641B215}.Release|Win32.Build.0 = Release|Win32 + {1AC9B120-3ED0-4444-86E5-1916108943C7}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AC9B120-3ED0-4444-86E5-1916108943C7}.Debug|Win32.Build.0 = Debug|Win32 + {1AC9B120-3ED0-4444-86E5-1916108943C7}.Release|Win32.ActiveCfg = Release|Win32 + {1AC9B120-3ED0-4444-86E5-1916108943C7}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/algorithms/overlay/select_rings.cpp b/test/algorithms/overlay/select_rings.cpp index e9dcad5e7..af2f18761 100644 --- a/test/algorithms/overlay/select_rings.cpp +++ b/test/algorithms/overlay/select_rings.cpp @@ -50,7 +50,7 @@ void test_geometry(std::string const& wkt1, std::string const& wkt2, map_type selected; std::map empty; - bg::detail::overlay::select_rings(geometry1, geometry2, empty, selected); + bg::detail::overlay::select_rings(geometry1, geometry2, empty, selected, true); BOOST_CHECK_EQUAL(selected.size(), expected_ids.size()); BOOST_CHECK_EQUAL(selected.size(), expected_withins.size()); diff --git a/test/algorithms/overlay/self_intersection_points.vcproj b/test/algorithms/overlay/self_intersection_points.vcproj index 450ea2270..a4cdb8049 100644 --- a/test/algorithms/overlay/self_intersection_points.vcproj +++ b/test/algorithms/overlay/self_intersection_points.vcproj @@ -46,6 +46,7 @@ ExceptionHandling="2" RuntimeLibrary="1" UsePrecompiledHeader="0" + DebugInformationFormat="1" /> (g1, g2, Direction, turns, v); + bg::detail::overlay::traverse + < + Reverse1, Reverse2, + G1, G2 + >::apply(g1, g2, Direction, turns, v); // Check number of resulting rings BOOST_CHECK_MESSAGE(expected_count == boost::size(v), diff --git a/test/algorithms/test_convert.hpp b/test/algorithms/test_convert.hpp new file mode 100644 index 000000000..65e5a73eb --- /dev/null +++ b/test/algorithms/test_convert.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// 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_TEST_CONVERT_HPP +#define BOOST_GEOMETRY_TEST_CONVERT_HPP + + +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#include + +#include + +BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian) +BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) + + + +template +void test_mixed(std::string const& wkt, std::string const& expected) +{ + Geometry1 geometry1; + bg::read_wkt(wkt, geometry1); + + Geometry2 geometry2; + bg::convert(geometry1, geometry2); + + std::ostringstream out; + out << bg::wkt(geometry2); + BOOST_CHECK_EQUAL(out.str(), expected); + + // std::cout << bg::area(geometry1) << " " << bg::area(geometry2) << std::endl; +} + +template +void test_mixed_identical_result(std::string const& wkt) +{ + test_mixed(wkt, wkt); + test_mixed(wkt, wkt); +} + +template +void test_mixed_reversible_result(std::string const& wkt1, std::string const& wkt2) +{ + test_mixed(wkt1, wkt2); + test_mixed(wkt2, wkt1); +} + +#endif diff --git a/test/algorithms/test_covered_by.hpp b/test/algorithms/test_covered_by.hpp new file mode 100644 index 000000000..b99257bbc --- /dev/null +++ b/test/algorithms/test_covered_by.hpp @@ -0,0 +1,123 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// 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_TEST_COVERED_BY_HPP +#define BOOST_GEOMETRY_TEST_COVERED_BY_HPP + + +#include + +#include +#include +#include +#include +#include + +#include + + +template +void test_geometry(std::string const& wkt1, + std::string const& wkt2, bool expected) +{ + Geometry1 geometry1; + Geometry2 geometry2; + + bg::read_wkt(wkt1, geometry1); + bg::read_wkt(wkt2, geometry2); + + bool detected = bg::covered_by(geometry1, geometry2); + + BOOST_CHECK_MESSAGE(detected == expected, + "covered_by: " << wkt1 + << " in " << wkt2 + << " -> Expected: " << expected + << " detected: " << detected); +} + +/* + +template +void test_ordered_ring(std::string const& wkt_point, + std::string const& wkt_geometry, bool expected) +{ + typedef bg::model::ring ring_type; + ring_type ring; + Point point; + + bg::read_wkt(wkt_geometry, ring); + if (! Clockwise) + { + std::reverse(boost::begin(ring), boost::end(ring)); + } + if (! Closed) + { + ring.resize(ring.size() - 1); + } + + bg::read_wkt(wkt_point, point); + + bool detected = bg::covered_by(point, ring); + + BOOST_CHECK_MESSAGE(detected == expected, + "covered_by: " << wkt_point + << " in " << wkt_geometry + << " -> Expected: " << expected + << " detected: " << detected + << " clockwise: " << int(Clockwise) + << " closed: " << int(Closed) + ); + + // other strategy (note that this one cannot detect OnBorder + // (without modifications) + + bg::strategy::covered_by::franklin franklin; + detected = bg::covered_by(point, ring, franklin); + if (! on_border) + { + BOOST_CHECK_MESSAGE(detected == expected, + "covered_by: " << wkt_point + << " in " << wkt_geometry + << " -> Expected: " << expected + << " detected: " << detected + << " clockwise: " << int(Clockwise) + << " closed: " << int(Closed) + ); + } + + + bg::strategy::covered_by::crossings_multiply cm; + detected = bg::covered_by(point, ring, cm); + if (! on_border) + { + BOOST_CHECK_MESSAGE(detected == expected, + "covered_by: " << wkt_point + << " in " << wkt_geometry + << " -> Expected: " << expected + << " detected: " << detected + << " clockwise: " << int(Clockwise) + << " closed: " << int(Closed) + ); + } +} + +template +void test_ring(std::string const& wkt_point, + std::string const& wkt_geometry, + bool expected) +{ + test_ordered_ring(wkt_point, wkt_geometry, expected); + test_ordered_ring(wkt_point, wkt_geometry, expected); + test_ordered_ring(wkt_point, wkt_geometry, expected); + test_ordered_ring(wkt_point, wkt_geometry, expected); + test_geometry >(wkt_point, wkt_geometry, expected); +} +*/ + +#endif diff --git a/test/algorithms/test_difference.hpp b/test/algorithms/test_difference.hpp index 30b97bbb2..948b90334 100644 --- a/test/algorithms/test_difference.hpp +++ b/test/algorithms/test_difference.hpp @@ -23,7 +23,6 @@ #include #include -#include #include @@ -73,9 +72,6 @@ void test_difference(std::string const& caseid, G1 const& g1, G2 const& g2, { if (expected_point_count > 0) { - // Get a correct point-count without duplicate points - // (note that overlay might be adapted to avoid duplicates) - bg::unique(*it); n += bg::num_points(*it); } diff --git a/test/algorithms/test_intersection.hpp b/test/algorithms/test_intersection.hpp index 4dcda0e8e..2b606a11a 100644 --- a/test/algorithms/test_intersection.hpp +++ b/test/algorithms/test_intersection.hpp @@ -13,14 +13,12 @@ #include #include -#include #include #include #include #include #include -#include #include @@ -33,7 +31,7 @@ # include #endif - +#include template @@ -41,8 +39,7 @@ typename bg::default_area_result::type test_intersection(std::string const& G1 const& g1, G2 const& g2, std::size_t expected_count = 0, std::size_t expected_point_count = 0, double expected_length_or_area = 0, - double percentage = 0.0001, - bool make_unique = true) + double percentage = 0.0001) { static const bool is_line = bg::geometry_id::type::value == 2; @@ -78,21 +75,11 @@ typename bg::default_area_result::type test_intersection(std::string const& { if (expected_point_count > 0) { - if (make_unique) - { - // Get a correct point-count without duplicate points - // (note that overlay might be adapted to avoid duplicates) - bg::unique(*it); - n += bg::num_points(*it, true); - } - else - { - n += bg::num_points(*it, true); - } + n += bg::num_points(*it, true); } // instead of specialization we check it run-time here - length_or_area += is_line + length_or_area += is_line ? bg::length(*it) : bg::area(*it); @@ -126,7 +113,8 @@ typename bg::default_area_result::type test_intersection(std::string const& ); } - BOOST_CHECK_CLOSE(length_or_area, expected_length_or_area, percentage); + double const detected_length_or_area = boost::numeric_cast(length_or_area); + BOOST_CHECK_CLOSE(detected_length_or_area, expected_length_or_area, percentage); #endif @@ -179,8 +167,7 @@ typename bg::default_area_result::type test_one(std::string const& caseid, std::string const& wkt1, std::string const& wkt2, std::size_t expected_count = 0, std::size_t expected_point_count = 0, double expected_length_or_area = 0, - double percentage = 0.0001, - bool make_unique = true) + double percentage = 0.0001) { G1 g1; bg::read_wkt(wkt1, g1); @@ -194,9 +181,24 @@ typename bg::default_area_result::type test_one(std::string const& caseid, return test_intersection(caseid, g1, g2, expected_count, expected_point_count, - expected_length_or_area, percentage, make_unique); + expected_length_or_area, percentage); +} + +template +void test_point_output(std::string const& wkt1, std::string const& wkt2, int expected_count) +{ + Geometry1 g1; + bg::read_wkt(wkt1, g1); + bg::correct(g1); + + Geometry2 g2; + bg::read_wkt(wkt2, g2); + bg::correct(g2); + + std::vector::type> points; + bg::intersection(g1, g2, points); + BOOST_CHECK_EQUAL(points.size(), expected_count); } - #endif diff --git a/test/algorithms/test_overlay.hpp b/test/algorithms/test_overlay.hpp index acae98ce2..bece5e1e9 100644 --- a/test/algorithms/test_overlay.hpp +++ b/test/algorithms/test_overlay.hpp @@ -144,7 +144,7 @@ static std::string two_bends[2] = // within each other, having no intersections but many holes within each other static std::string winded[2] = - {"POLYGON((0 0,0 11,11 11,11 0,0 0),(3 3,4 3,4 4,3 4,3 3),(5 3,6 3,6 4,5 4,5 3),(2 6,7 6,7 6,7 9,2 9,2 6),(9 2,10 2,10 5,9 5,9 2))", + {"POLYGON((0 0,0 11,11 11,11 0,0 0),(3 3,4 3,4 4,3 4,3 3),(5 3,6 3,6 4,5 4,5 3),(2 6,7 6,7 9,2 9,2 6),(9 2,10 2,10 5,9 5,9 2))", "POLYGON((1 1,1 10,10 10,10 6,8 6,8 1,1 1),(2 2,7 2,7 5,2 5,2 2),(3 7,4 7,4 8,3 8,3 7),(5 7,6 7,6 8,5 8,5 7),(8 7,9 7,9 8,8 8,8 7))"}; static std::string within_holes_disjoint[2] = diff --git a/test/algorithms/test_union.hpp b/test/algorithms/test_union.hpp index dc316d349..47a567eb8 100644 --- a/test/algorithms/test_union.hpp +++ b/test/algorithms/test_union.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include @@ -55,10 +54,6 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2, area += bg::area(*it); holes += bg::num_interior_rings(*it); - // Get a correct point-count without duplicate points - // (note that overlay might be adapted to avoid duplicates) - OutputType simplified; - bg::unique(*it); n += bg::num_points(*it, true); } diff --git a/test/algorithms/test_within.hpp b/test/algorithms/test_within.hpp index c15b0f3e4..d2c517009 100644 --- a/test/algorithms/test_within.hpp +++ b/test/algorithms/test_within.hpp @@ -21,6 +21,10 @@ #include +#include +#include +#include + template void test_geometry(std::string const& wkt1, @@ -42,6 +46,7 @@ void test_geometry(std::string const& wkt1, } + template void test_ordered_ring(std::string const& wkt_point, std::string const& wkt_geometry, bool expected, bool on_border) diff --git a/test/algorithms/union.cpp b/test/algorithms/union.cpp index 95d079f1b..f1b05ca22 100644 --- a/test/algorithms/union.cpp +++ b/test/algorithms/union.cpp @@ -25,26 +25,12 @@ #include #include -static std::string javier4[2] = - { - "POLYGON((-2 2, 1842 2, 1842 -2362, -2 -2362, -2 2), (0 0, 0 -2360, 1840 -2360, 1840 0, 0 0))", - // "POLYGON((-0.01 -1960, 0 -1960, 0 -1880, 0.01 -1960, -0.01 -1960))" - "POLYGON ((-0.01 -1960, 80.01 -1960, 0 -1880, -0.01 -1960))" - }; - - - - - - template void test_areal() { - test_one("javier4", - javier4[0], javier4[1], - 1, 1, 13, 20016.4); + typedef typename bg::coordinate_type::type ct; test_one("simplex_normal", simplex_normal[0], simplex_normal[1], @@ -63,12 +49,7 @@ void test_areal() // This sample was selected because of the border case, and ttmath generates one point more. test_one("star_poly", example_star, example_polygon, 1, 1, -#if defined(HAVE_TTMATH) - boost::is_same::type, ttmath_big>::value ? 28 : 27, -#else - 27, -#endif - 5.647949); + if_typed_tt(28, 27), 5.647949); // Pseudo-box as Polygon // (note, internally, the intersection points is different, so yes, @@ -237,20 +218,34 @@ void test_areal() test_one("ggl_list_20110306_javier", ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], 1, 1, 16, 80456.4904910401); + + test_one("ggl_list_20110307_javier", + ggl_list_20110307_javier[0], ggl_list_20110307_javier[1], + 1, 1, 13, 20016.4); + + test_one("ggl_list_20110627_phillip", + ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1], + 1, 0, + if_typed(5, if_typed_tt(8, 7)), + 14729.07145); + +#ifdef TEST_ENRICO + test_one("ggl_list_20110716_enrico", + ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1], + 1, 1, + if_typed(18, 17), + 129904.197692871); +#endif #ifdef _MSC_VER - { - // Isovist (submitted by Brandon during Formal Review) - std::string tn = string_from_type::type>::name(); - test_one("isovist", - isovist1[0], isovist1[1], - 1, - 0, - tn == std::string("f") ? 71 - : tn == std::string("d") ? 72 - : 73, - 313.36036462); - } + // Isovist (submitted by Brandon during Formal Review) + test_one("isovist", + isovist1[0], isovist1[1], + 1, + 0, + if_typed(71, + if_typed(70, 73)), + 313.36036462); #endif } diff --git a/test/algorithms/within.cpp b/test/algorithms/within.cpp index b8820f99b..85c6f13b6 100644 --- a/test/algorithms/within.cpp +++ b/test/algorithms/within.cpp @@ -37,18 +37,28 @@ void test_all() typedef bg::model::box

box_type; test_geometry("POINT(1 1)", "BOX(0 0,2 2)", true); + test_geometry("POINT(0 0)", "BOX(0 0,2 2)", false); + test_geometry("POINT(2 2)", "BOX(0 0,2 2)", false); + test_geometry("POINT(0 1)", "BOX(0 0,2 2)", false); + test_geometry("POINT(1 0)", "BOX(0 0,2 2)", false); test_geometry("BOX(1 1,2 2)", "BOX(0 0,3 3)", true); test_geometry("BOX(0 0,3 3)", "BOX(1 1,2 2)", false); + /* + test_within_code("POINT(1 1)", "BOX(0 0,2 2)", 1); + test_within_code("POINT(1 0)", "BOX(0 0,2 2)", 0); + test_within_code("POINT(0 1)", "BOX(0 0,2 2)", 0); + test_within_code("POINT(0 3)", "BOX(0 0,2 2)", -1); + test_within_code("POINT(3 3)", "BOX(0 0,2 2)", -1); - // Mixed point types - test_geometry - < - bg::model::d2::point_xy, - bg::model::polygon

- >("POINT(1 1)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", true); - + test_within_code("BOX(1 1,2 2)", "BOX(0 0,3 3)", 1); + test_within_code("BOX(0 1,2 2)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 0,2 2)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 1,2 3)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 1,3 2)", "BOX(0 0,3 3)", 0); + test_within_code("BOX(1 1,3 4)", "BOX(0 0,3 3)", -1); + */ // Real-life problem (solved now), point is in the middle, 409623 is also a coordinate // on the border, has been wrong in the past (2009) @@ -106,6 +116,105 @@ void test_spherical() BOOST_CHECK_EQUAL(bg::within(Point(7, 52.5), triangle), true); BOOST_CHECK_EQUAL(bg::within(Point(8.0, 51.5), triangle), false); BOOST_CHECK_EQUAL(bg::within(Point(6.0, 51.0), triangle), false); + + // Test spherical boxes + // See also http://www.gcmap.com/mapui?P=1E45N-19E45N-19E55N-1E55N-1E45N,10E55.1N,10E45.1N + bg::model::box box; + bg::read_wkt("POLYGON((1 45,19 55))", box); + BOOST_CHECK_EQUAL(bg::within(Point(10, 55.1), box), true); + BOOST_CHECK_EQUAL(bg::within(Point(10, 55.2), box), true); + BOOST_CHECK_EQUAL(bg::within(Point(10, 55.3), box), true); + BOOST_CHECK_EQUAL(bg::within(Point(10, 55.4), box), false); + + BOOST_CHECK_EQUAL(bg::within(Point(10, 45.1), box), false); + BOOST_CHECK_EQUAL(bg::within(Point(10, 45.2), box), false); + BOOST_CHECK_EQUAL(bg::within(Point(10, 45.3), box), false); + BOOST_CHECK_EQUAL(bg::within(Point(10, 45.4), box), true); + + // Crossing the dateline (Near Tuvalu) + // http://www.gcmap.com/mapui?P=178E10S-178W10S-178W6S-178E6S-178E10S,180W5.999S,180E9.999S + // http://en.wikipedia.org/wiki/Tuvalu + + bg::model::box tuvalu(Point(178, -10), Point(-178, -6)); + BOOST_CHECK_EQUAL(bg::within(Point(180, -8), tuvalu), true); + BOOST_CHECK_EQUAL(bg::within(Point(-180, -8), tuvalu), true); + BOOST_CHECK_EQUAL(bg::within(Point(180, -5.999), tuvalu), false); + BOOST_CHECK_EQUAL(bg::within(Point(180, -10.001), tuvalu), true); +} + +void test_3d() +{ + typedef boost::geometry::model::point point_type; + typedef boost::geometry::model::box box_type; + box_type box(point_type(0, 0, 0), point_type(4, 4, 4)); + BOOST_CHECK_EQUAL(bg::within(point_type(2, 2, 2), box), true); + BOOST_CHECK_EQUAL(bg::within(point_type(2, 4, 2), box), false); + BOOST_CHECK_EQUAL(bg::within(point_type(2, 2, 4), box), false); + BOOST_CHECK_EQUAL(bg::within(point_type(2, 2, 5), box), false); +} + +template +void test_mixed_of() +{ + typedef boost::geometry::model::polygon polygon_type1; + typedef boost::geometry::model::polygon polygon_type2; + typedef boost::geometry::model::box box_type1; + typedef boost::geometry::model::box box_type2; + + polygon_type1 poly1, poly2; + boost::geometry::read_wkt("POLYGON((0 0,0 5,5 5,5 0,0 0))", poly1); + boost::geometry::read_wkt("POLYGON((0 0,0 5,5 5,5 0,0 0))", poly2); + + box_type1 box1(P1(1, 1), P1(4, 4)); + box_type2 box2(P2(0, 0), P2(5, 5)); + P1 p1(3, 3); + P2 p2(3, 3); + + BOOST_CHECK_EQUAL(bg::within(p1, poly2), true); + BOOST_CHECK_EQUAL(bg::within(p2, poly1), true); + BOOST_CHECK_EQUAL(bg::within(p2, box1), true); + BOOST_CHECK_EQUAL(bg::within(p1, box2), true); + BOOST_CHECK_EQUAL(bg::within(box1, box2), true); + BOOST_CHECK_EQUAL(bg::within(box2, box1), false); +} + + +void test_mixed() +{ + // Mixing point types and coordinate types + test_mixed_of + < + boost::geometry::model::d2::point_xy, + boost::geometry::model::point + >(); + test_mixed_of + < + boost::geometry::model::d2::point_xy, + boost::geometry::model::point + >(); + test_mixed_of + < + boost::geometry::model::d2::point_xy, + boost::geometry::model::d2::point_xy + >(); +} + +void test_strategy() +{ + // Test by explicitly specifying a strategy + typedef bg::model::d2::point_xy point_type; + typedef bg::model::box box_type; + point_type p(3, 3); + box_type b(point_type(0, 0), point_type(5, 5)); + + bool r = bg::within(p, b, + bg::strategy::within::point_in_box()); + + r = bg::within(b, b, + bg::strategy::within::box_in_box()); + + r = bg::within(p, b, + bg::strategy::within::point_in_box_by_side()); } @@ -116,6 +225,10 @@ int test_main( int , char* [] ) test_spherical > >(); + test_mixed(); + test_3d(); + test_strategy(); + #if defined(HAVE_TTMATH) test_all >(); diff --git a/test/geometry_test_common.hpp b/test/geometry_test_common.hpp index 0af0a8340..2e4a645be 100644 --- a/test/geometry_test_common.hpp +++ b/test/geometry_test_common.hpp @@ -32,16 +32,28 @@ #endif - #include // Include some always-included-for-testing files #if ! defined(BOOST_GEOMETRY_NO_BOOST_TEST) -# include -# include + +// Until Boost fixes it, silence warning issued by clang: +// warning: unused variable 'check_is_close' [-Wunused-variable] +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-variable" +#endif + +# include +# include //# include -# include +# include + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + #endif @@ -82,6 +94,11 @@ template <> struct string_from_type { static std::string name() { return "t"; } }; #endif +#if defined(BOOST_RATIONAL_HPP) +template struct string_from_type > +{ static std::string name() { return "r"; } }; +#endif + #if defined(HAVE_GMP) template <> struct string_from_type @@ -94,6 +111,24 @@ template <> struct string_from_type #endif +template +inline T if_typed_tt(T value_tt, T value) +{ +#if defined(HAVE_TTMATH) + return boost::is_same::value ? value_tt : value; +#else + return value; +#endif +} + +template +inline T if_typed(T value_typed, T value) +{ + return boost::is_same::value ? value_typed : value; +} + + + struct geographic_policy { diff --git a/test/multi/algorithms/Jamfile.v2 b/test/multi/algorithms/Jamfile.v2 index 9087b7ac3..1076835aa 100644 --- a/test/multi/algorithms/Jamfile.v2 +++ b/test/multi/algorithms/Jamfile.v2 @@ -12,8 +12,10 @@ test-suite boost-geometry-multi-algorithms : [ run multi_area.cpp ] [ run multi_centroid.cpp ] + [ run multi_convert.cpp ] [ run multi_convex_hull.cpp ] [ run multi_correct.cpp ] + [ run multi_covered_by.cpp ] [ run multi_difference.cpp ] [ run multi_envelope.cpp ] [ run multi_equals.cpp ] diff --git a/test/multi/algorithms/multi_convert.cpp b/test/multi/algorithms/multi_convert.cpp new file mode 100644 index 000000000..68023aaf9 --- /dev/null +++ b/test/multi/algorithms/multi_convert.cpp @@ -0,0 +1,99 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// 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) + +#include + +#include + +#include +#include +#include + + +template +void test_mixed_point_types() +{ + test_mixed_identical_result + < + bg::model::multi_point, + bg::model::multi_point + > + ("MULTIPOINT((1 1),(2 2),(3 3))"); + + test_mixed_identical_result + < + bg::model::multi_linestring >, + bg::model::multi_linestring > + > + ("MULTILINESTRING((1 1,2 2),(3 3,4 4))"); + + // Single -> multi (always possible) + test_mixed + < + Point1, bg::model::multi_point + > + ( + "POINT(1 1)", + "MULTIPOINT((1 1))" + ); + test_mixed + < + bg::model::linestring, + bg::model::multi_linestring > + > + ( + "LINESTRING(1 1,2 2)", + "MULTILINESTRING((1 1,2 2))" + ); + test_mixed + < + bg::model::segment, + bg::model::multi_linestring > + > + ( + "LINESTRING(1 1,2 2)", + "MULTILINESTRING((1 1,2 2))" + ); + test_mixed + < + bg::model::box, + bg::model::multi_polygon > + > + ( + "BOX(0 0,1 1)", + "MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)))" + ); + test_mixed + < + bg::model::ring, + bg::model::multi_polygon > + > + ( + "POLYGON((0 0,0 1,1 1,1 0,0 0))", + "MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)))" + ); + + // Multi -> single: should not compile (because multi often have 0 or >1 elements) +} + +template +void test_mixed_types() +{ + test_mixed_point_types(); + test_mixed_point_types(); +} + +int test_main( int , char* [] ) +{ + test_mixed_types + < + bg::model::point, + bg::model::point + >(); + + return 0; +} diff --git a/test/multi/algorithms/multi_convert.vcproj b/test/multi/algorithms/multi_convert.vcproj new file mode 100644 index 000000000..4829412be --- /dev/null +++ b/test/multi/algorithms/multi_convert.vcproj @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/multi/algorithms/multi_covered_by.cpp b/test/multi/algorithms/multi_covered_by.cpp new file mode 100644 index 000000000..5d937f4eb --- /dev/null +++ b/test/multi/algorithms/multi_covered_by.cpp @@ -0,0 +1,58 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// 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) + +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + + +template +void test_all() +{ + typedef bg::model::multi_polygon > mp; + + // test multi-with-one-polygon (trivial case) + test_geometry("POINT(1 1)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", true); + test_geometry("POINT(3 3)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", false); + test_geometry("POINT(0 1)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", true); + test_geometry("POINT(4 4)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", false); + + // test if it is in one of them + std::string multi("MULTIPOLYGON(" + "((0 0,0 2,2 2,2 0,0 0))" + "((3 3,3 6,6 6,6 3,3 3))" + ")"); + test_geometry("POINT(4 4)", multi, true); + test_geometry("POINT(1 1)", multi, true); + test_geometry("POINT(0 1)", multi, true); +} + +int test_main( int , char* [] ) +{ + //test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/multi/algorithms/multi_covered_by.vcproj b/test/multi/algorithms/multi_covered_by.vcproj new file mode 100644 index 000000000..87a62a938 --- /dev/null +++ b/test/multi/algorithms/multi_covered_by.vcproj @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/multi/algorithms/multi_difference.cpp b/test/multi/algorithms/multi_difference.cpp index fe6a8fcd7..f99b566a5 100644 --- a/test/multi/algorithms/multi_difference.cpp +++ b/test/multi/algorithms/multi_difference.cpp @@ -11,7 +11,7 @@ #include // #define BOOST_GEOMETRY_DEBUG_ASSEMBLE -#define BOOST_GEOMETRY_CHECK_WITH_SQLSERVER +//#define BOOST_GEOMETRY_CHECK_WITH_SQLSERVER #include #include diff --git a/test/multi/algorithms/multi_intersection.cpp b/test/multi/algorithms/multi_intersection.cpp index be8821cd5..473c1f5a6 100644 --- a/test/multi/algorithms/multi_intersection.cpp +++ b/test/multi/algorithms/multi_intersection.cpp @@ -138,6 +138,19 @@ void test_linear() 2, 4, 2 * std::sqrt(2.0)); } +template +void test_point_output() +{ + typedef bg::model::box

box; + typedef bg::model::linestring

linestring; + typedef bg::model::polygon

polygon; + typedef bg::model::multi_polygon multi_polygon; + + test_point_output(case_multi_simplex[0], case_multi_simplex[1], 10); + test_point_output("linestring(4 0,0 4)", case_multi_simplex[0], 4); + test_point_output("box(3 0,4 6)", case_multi_simplex[0], 8); +} + template void test_all() @@ -174,6 +187,7 @@ void test_all() test_linear(); #endif + test_point_output

(); // linear } diff --git a/test/multi/algorithms/multi_simplify.cpp b/test/multi/algorithms/multi_simplify.cpp index 09a836178..68424985d 100644 --- a/test/multi/algorithms/multi_simplify.cpp +++ b/test/multi/algorithms/multi_simplify.cpp @@ -44,6 +44,15 @@ void test_all() test_geometry( "MULTIPOLYGON(((4 0,8 2,8 7,4 9,0 7,0 2,2 1,4 0),(7 3,7 6,1 6,1 3,4 3,7 3)))", "MULTIPOLYGON(((4 0,8 2,8 7,4 9,0 7,0 2,4 0),(7 3,7 6,1 6,1 3,7 3)))", 1.0); + + // Ticket 5954 https://svn.boost.org/trac/boost/ticket/5954 + test_geometry( + "MULTIPOLYGON(((0.561648 1,1 1,1 0,0.468083 0,0.52758 0.00800554,0.599683 0.0280924,0.601611 0.265374,0.622693 0.316765,0.69507 0.357497,0.695623 0.429711,0.655111 0.502298,0.696467 0.543147,0.840712 0.593546,0.882583 0.66546,0.852357 0.748213,0.84264 0.789567,0.832667 0.841202,0.832667 0.841202,0.740538 0.873004,0.617349 0.905045,0.566576 0.977697,0.561648 1)),((0 0.801979,0.0308575 0.786234,0.0705513 0.631135,0.141616 0.527248,0.233985 0.505872,0.264777 0.526263,0.336631 0.505009,0.356603 0.422321,0.355803 0.350038,0.375252 0.205364,0.415206 0.0709182,0.45479 0,0 0,0 0,0 0.801979)))", + "MULTIPOLYGON(((0.561648 1,1 1,1 0,0.468083 0,0.52758 0.00800554,0.599683 0.0280924,0.601611 0.265374,0.622693 0.316765,0.69507 0.357497,0.695623 0.429711,0.655111 0.502298,0.696467 0.543147,0.840712 0.593546,0.882583 0.66546,0.852357 0.748213,0.84264 0.789567,0.832667 0.841202,0.740538 0.873004,0.617349 0.905045,0.566576 0.977697,0.561648 1)),((0 0.801979,0.0308575 0.786234,0.0705513 0.631135,0.141616 0.527248,0.233985 0.505872,0.264777 0.526263,0.336631 0.505009,0.356603 0.422321,0.355803 0.350038,0.375252 0.205364,0.415206 0.0709182,0.45479 0,0 0,0 0.801979)))", 1.0 / 2048.0); + test_geometry( + "MULTIPOLYGON(((1149.69 2047,2047 2047,2047 0,958.166 0,1079.96 16.3873,1227.55 57.5051,1231.5 543.221,1274.65 648.418,1422.81 731.796,1423.94 879.618,1341.01 1028.2,1425.67 1111.82,1720.94 1214.99,1806.65 1362.2,1744.77 1531.59,1724.88 1616.24,1704.47 1721.94,1704.47 1721.94,1515.88 1787.04,1263.71 1852.63,1159.78 2001.35,1149.69 2047)),((0 1641.65,63.1653 1609.42,144.419 1291.93,289.888 1079.28,478.967 1035.52,541.999 1077.26,689.084 1033.75,729.966 864.491,728.329 716.528,768.141 420.38,849.927 145.17,930.955 0,0 0,0 0,0 1641.65)))", + "MULTIPOLYGON(((1149.69 2047,2047 2047,2047 0,958.166 0,1079.96 16.3873,1227.55 57.5051,1231.5 543.221,1274.65 648.418,1422.81 731.796,1423.94 879.618,1341.01 1028.2,1425.67 1111.82,1720.94 1214.99,1806.65 1362.2,1744.77 1531.59,1724.88 1616.24,1704.47 1721.94,1515.88 1787.04,1263.71 1852.63,1159.78 2001.35,1149.69 2047)),((0 1641.65,63.1653 1609.42,144.419 1291.93,289.888 1079.28,478.967 1035.52,541.999 1077.26,689.084 1033.75,729.966 864.491,728.329 716.528,768.141 420.38,849.927 145.17,930.955 0,0 0,0 1641.65)))", 1.0); + // End ticket 5954 } int test_main( int , char* [] ) diff --git a/test/multi/algorithms/multi_within.cpp b/test/multi/algorithms/multi_within.cpp index a3815b686..9c4f64ef6 100644 --- a/test/multi/algorithms/multi_within.cpp +++ b/test/multi/algorithms/multi_within.cpp @@ -29,16 +29,20 @@ void test_all() { typedef bg::model::multi_polygon > mp; - // trivial cases + // test multi-with-one-polygon (trivial case) test_geometry("POINT(1 1)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", true); test_geometry("POINT(3 3)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", false); + test_geometry("POINT(0 1)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", false); + test_geometry("POINT(4 4)", "MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)))", false); // test if it is in one of them - test_geometry("POINT(4 4)", "MULTIPOLYGON(" + std::string multi("MULTIPOLYGON(" "((0 0,0 2,2 2,2 0,0 0))" "((3 3,3 6,6 6,6 3,3 3))" - ")", - true); + ")"); + test_geometry("POINT(4 4)", multi, true); + test_geometry("POINT(1 1)", multi, true); + test_geometry("POINT(0 1)", multi, false); } int test_main( int , char* [] ) diff --git a/test/multi/multi_tests.sln b/test/multi/multi_tests.sln index bc6b4ca80..57d180722 100644 --- a/test/multi/multi_tests.sln +++ b/test/multi/multi_tests.sln @@ -42,6 +42,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_difference", "algorit EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_transform", "algorithms\multi_transform.vcproj", "{64985954-0A74-46F5-908F-865E905C3414}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_covered_by", "algorithms\multi_covered_by.vcproj", "{680E56F0-229C-4377-BDC0-80EB9B59314B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_convert", "algorithms\multi_convert.vcproj", "{21B7EF55-23C3-4FD2-9F2F-FD8F0F3FE167}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -132,6 +136,14 @@ Global {64985954-0A74-46F5-908F-865E905C3414}.Debug|Win32.Build.0 = Debug|Win32 {64985954-0A74-46F5-908F-865E905C3414}.Release|Win32.ActiveCfg = Release|Win32 {64985954-0A74-46F5-908F-865E905C3414}.Release|Win32.Build.0 = Release|Win32 + {680E56F0-229C-4377-BDC0-80EB9B59314B}.Debug|Win32.ActiveCfg = Debug|Win32 + {680E56F0-229C-4377-BDC0-80EB9B59314B}.Debug|Win32.Build.0 = Debug|Win32 + {680E56F0-229C-4377-BDC0-80EB9B59314B}.Release|Win32.ActiveCfg = Release|Win32 + {680E56F0-229C-4377-BDC0-80EB9B59314B}.Release|Win32.Build.0 = Release|Win32 + {21B7EF55-23C3-4FD2-9F2F-FD8F0F3FE167}.Debug|Win32.ActiveCfg = Debug|Win32 + {21B7EF55-23C3-4FD2-9F2F-FD8F0F3FE167}.Debug|Win32.Build.0 = Debug|Win32 + {21B7EF55-23C3-4FD2-9F2F-FD8F0F3FE167}.Release|Win32.ActiveCfg = Release|Win32 + {21B7EF55-23C3-4FD2-9F2F-FD8F0F3FE167}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/strategies/within.cpp b/test/strategies/within.cpp index ef6b9179c..6e0cbe955 100644 --- a/test/strategies/within.cpp +++ b/test/strategies/within.cpp @@ -11,16 +11,21 @@ #include +#include #include #include #include #include +#include +#include +#include #include #include +#include #include #include @@ -36,7 +41,7 @@ void test_point_in_polygon(std::string const& case_id, Strategy const& strategy, std::string const& strategy_id, bool expected) { - BOOST_CONCEPT_ASSERT( (bg::concept::WithinStrategy) ); + BOOST_CONCEPT_ASSERT( (bg::concept::WithinStrategyPolygonal) ); bool detected = bg::within(point, polygon, strategy); BOOST_CHECK_MESSAGE(detected == expected, @@ -68,11 +73,63 @@ void test_geometry(std::string const& case_id, std::string const& wkt_point "cross.mult", boost::contains(deviations, "c") ? !expected : expected); } +template +void test_box_of(std::string const& wkt_point, std::string const& wkt_box, + bool expected_within, bool expected_covered_by) +{ + typedef bg::model::box box_type; + + Point point; + box_type box; + bg::read_wkt(wkt_point, point); + bg::read_wkt(wkt_box, box); + + bool detected_within = bg::within(point, box); + bool detected_covered_by = bg::covered_by(point, box); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); + + // Also test with the non-default agnostic side version + namespace wi = bg::strategy::within; + wi::point_in_box_by_side within_strategy; + wi::point_in_box_by_side covered_by_strategy; + + detected_within = bg::within(point, box, within_strategy); + detected_covered_by = bg::covered_by(point, box, covered_by_strategy); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); + + // We might exchange strategies between within/covered by. + // So the lines below might seem confusing, but are as intended + detected_within = bg::covered_by(point, box, within_strategy); + detected_covered_by = bg::within(point, box, covered_by_strategy); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); + + // Finally we call the strategies directly + detected_within = within_strategy.apply(point, box); + detected_covered_by = covered_by_strategy.apply(point, box); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); +} + +template +void test_box() +{ + test_box_of("POINT(1 1)", "BOX(0 0,2 2)", true, true); + test_box_of("POINT(0 0)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(2 2)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(0 1)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(1 0)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(3 3)", "BOX(0 0,2 2)", false, false); +} template void test_all() { + test_box(); + typedef bg::model::polygon polygon; std::string const box = "POLYGON((0 0,0 2,2 2,2 0,0 0))"; diff --git a/test/util/Jamfile.v2 b/test/util/Jamfile.v2 index 0ec3e7543..2b620c50a 100644 --- a/test/util/Jamfile.v2 +++ b/test/util/Jamfile.v2 @@ -11,6 +11,7 @@ test-suite boost-geometry-util : [ run for_each_coordinate.cpp ] + [ run rational.cpp ] [ run select_most_precise.cpp ] [ run write_dsv.cpp ] ; diff --git a/test/util/rational.cpp b/test/util/rational.cpp new file mode 100644 index 000000000..20f876caf --- /dev/null +++ b/test/util/rational.cpp @@ -0,0 +1,61 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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) + + +#include + +#include +#include +#include + +void test_coordinate_cast(std::string const& s, int expected_nom, int expected_denom) +{ + boost::rational a = bg::detail::coordinate_cast >::apply(s); + BOOST_CHECK_EQUAL(a.numerator(), expected_nom); + BOOST_CHECK_EQUAL(a.denominator(), expected_denom); +} + + +void test_wkt(std::string const& wkt, std::string const expected_wkt) +{ + bg::model::point, 2, bg::cs::cartesian> p; + bg::read_wkt(wkt, p); + std::ostringstream out; + out << bg::wkt(p); + + BOOST_CHECK_EQUAL(out.str(), expected_wkt); +} + +int test_main(int, char* []) +{ + test_coordinate_cast("0", 0, 1); + test_coordinate_cast("1", 1, 1); + test_coordinate_cast("-1", -1, 1); + test_coordinate_cast("-0.5", -1, 2); + test_coordinate_cast("-1.5", -3, 2); + test_coordinate_cast("0.5", 1, 2); + test_coordinate_cast("1.5", 3, 2); + test_coordinate_cast("2.12345", 42469, 20000); + test_coordinate_cast("1.", 1, 1); + + test_coordinate_cast("3/2", 3, 2); + test_coordinate_cast("-3/2", -3, 2); + + test_wkt("POINT(1.5 2.75)", "POINT(3/2 11/4)"); + test_wkt("POINT(3/2 11/4)", "POINT(3/2 11/4)"); + test_wkt("POINT(-1.5 2.75)", "POINT(-3/2 11/4)"); + test_wkt("POINT(-3/2 11/4)", "POINT(-3/2 11/4)"); + + return 0; +} diff --git a/test/util/rational.vcproj b/test/util/rational.vcproj new file mode 100644 index 000000000..28ad0a237 --- /dev/null +++ b/test/util/rational.vcproj @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/util/util_tests.sln b/test/util/util_tests.sln index a4aa5c146..fbbb18042 100644 --- a/test/util/util_tests.sln +++ b/test/util/util_tests.sln @@ -8,6 +8,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "write_dsv", "write_dsv.vcpr EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "as_range", "as_range.vcproj", "{A36D8426-67EB-405C-B6E8-3FBB3374A59B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rational", "rational.vcproj", "{6ABF6324-C1DC-4687-9895-B4CE2B27446F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -30,6 +32,10 @@ Global {A36D8426-67EB-405C-B6E8-3FBB3374A59B}.Debug|Win32.Build.0 = Debug|Win32 {A36D8426-67EB-405C-B6E8-3FBB3374A59B}.Release|Win32.ActiveCfg = Release|Win32 {A36D8426-67EB-405C-B6E8-3FBB3374A59B}.Release|Win32.Build.0 = Release|Win32 + {6ABF6324-C1DC-4687-9895-B4CE2B27446F}.Debug|Win32.ActiveCfg = Debug|Win32 + {6ABF6324-C1DC-4687-9895-B4CE2B27446F}.Debug|Win32.Build.0 = Debug|Win32 + {6ABF6324-C1DC-4687-9895-B4CE2B27446F}.Release|Win32.ActiveCfg = Release|Win32 + {6ABF6324-C1DC-4687-9895-B4CE2B27446F}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE