From c3c238623d2d459aaf0858905de92fcce1938d32 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Mon, 8 Nov 2010 10:18:33 +0000 Subject: [PATCH] Assemble/traverse/enrich: complete update for handling self tangencies Strategies area, within, centroid, transform adapted to new conventions using services Centroid: removed underscore Correct: support for open polygons Get turns: support for open polygons Sectionalize/segments: support for open polygons Closing iterator: complete new implementation to support open polygons better Numpoints: added boolean parameter to add one for open polygons Within: bugfix for point-on-border-of-interior ring, this needed returning three values -1,0,1 instead of boolean polygon/ring: added a copy in namespace model:: as agreed long ago, with other default template parameters [SVN r66449] --- include/boost/geometry/algorithms/area.hpp | 11 +- .../boost/geometry/algorithms/centroid.hpp | 2 +- include/boost/geometry/algorithms/correct.hpp | 20 +- .../algorithms/detail/overlay/assemble.hpp | 99 ++- .../detail/overlay/check_enrich.hpp | 171 +++++ .../detail/overlay/copy_segments.hpp | 24 +- .../overlay/enrich_intersection_points.hpp | 597 ++++++++++------- .../algorithms/detail/overlay/get_turns.hpp | 69 +- .../detail/overlay/handle_tangencies.hpp | 620 ++++++++++++++++++ .../algorithms/detail/overlay/overlay.hpp | 6 +- .../detail/overlay/ring_properties.hpp | 2 +- .../algorithms/detail/overlay/split_rings.hpp | 2 - .../algorithms/detail/overlay/traverse.hpp | 97 ++- .../algorithms/detail/overlay/turn_info.hpp | 38 +- .../algorithms/detail/ring_identifier.hpp | 3 +- .../detail/sections/get_full_section.hpp | 89 ++- .../detail/sections/get_section.hpp | 137 +--- .../detail/sections/sectionalize.hpp | 43 +- .../boost/geometry/algorithms/dissolve.hpp | 14 +- .../boost/geometry/algorithms/num_points.hpp | 37 +- .../boost/geometry/algorithms/transform.hpp | 18 +- include/boost/geometry/algorithms/within.hpp | 62 +- .../buffer/sectionalizing_buffer.hpp | 8 +- .../algorithms/buffer/traversing_buffer.hpp | 2 - .../extensions/contrib/ttmath_stub.hpp | 87 ++- .../strategies/area_huiller_earth.hpp | 21 +- .../boost/geometry/geometries/linear_ring.hpp | 98 +++ include/boost/geometry/geometries/polygon.hpp | 175 ++++- include/boost/geometry/geometry.hpp | 4 - .../geometry/iterators/closing_iterator.hpp | 119 +++- .../algorithms/detail/overlay/get_turns.hpp | 3 +- .../detail/sections/get_full_section.hpp | 24 +- .../detail/sections/get_section.hpp | 3 + .../multi/algorithms/intersection.hpp | 1 - .../geometry/multi/algorithms/num_points.hpp | 6 +- .../boost/geometry/multi/algorithms/union.hpp | 1 - .../geometry/multi/algorithms/within.hpp | 9 +- include/boost/geometry/multi/multi.hpp | 1 - .../strategies/cartesian/centroid_average.hpp | 16 +- .../geometry/multi/strategies/centroid.hpp | 10 +- .../agnostic/point_in_poly_winding.hpp | 90 ++- include/boost/geometry/strategies/area.hpp | 19 +- .../boost/geometry/strategies/area_result.hpp | 6 +- .../cartesian/area_by_triangles.hpp | 24 +- .../strategies/cartesian/cart_intersect.hpp | 9 +- .../cartesian/centroid_bashein_detmer.hpp | 26 +- .../point_in_poly_crossings_multiply.hpp | 4 +- .../cartesian/point_in_poly_franklin.hpp | 4 +- .../boost/geometry/strategies/centroid.hpp | 47 +- .../strategies/concepts/within_concept.hpp | 4 +- .../geometry/strategies/point_in_poly.hpp | 36 - .../strategies/spherical/area_huiller.hpp | 23 +- .../boost/geometry/strategies/strategies.hpp | 2 +- .../strategies/strategy_transform.hpp | 54 +- .../boost/geometry/strategies/transform.hpp | 16 +- .../strategies/transform/map_transformer.hpp | 5 +- include/boost/geometry/strategies/within.hpp | 74 +++ 57 files changed, 2412 insertions(+), 780 deletions(-) create mode 100644 include/boost/geometry/algorithms/detail/overlay/check_enrich.hpp create mode 100644 include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp delete mode 100644 include/boost/geometry/strategies/point_in_poly.hpp create mode 100644 include/boost/geometry/strategies/within.hpp diff --git a/include/boost/geometry/algorithms/area.hpp b/include/boost/geometry/algorithms/area.hpp index 69a574c4c..0063a5161 100644 --- a/include/boost/geometry/algorithms/area.hpp +++ b/include/boost/geometry/algorithms/area.hpp @@ -84,9 +84,10 @@ struct ring_area // Ignore warning (because using static method sometimes) on strategy boost::ignore_unused_variable_warning(strategy); + // An open linear_ring has at least three points, // A closed linear_ring has at least four points, // if not, there is no (zero) area - if (boost::size(ring) < 4) + if (boost::size(ring) < (Closure == open ? 3 : 4)) { return type(); } @@ -123,7 +124,6 @@ struct ring_area #endif // DOXYGEN_NO_DETAIL - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -229,7 +229,12 @@ inline typename area_result::type area(Geometry const& geometry) { concept::check(); - typedef typename area_result::strategy_type strategy_type; + typedef typename point_type::type point_type; + typedef typename strategy::area::services::default_strategy + < + typename cs_tag::type, + point_type + >::type strategy_type; return dispatch::area < diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index de8b8d4e4..8847f89a9 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -408,7 +408,7 @@ inline void centroid(Geometry const& geometry, Point& c) { concept::check_concepts_and_equal_dimensions(); - typedef typename strategy_centroid + typedef typename strategy::centroid::services::default_strategy < typename cs_tag::type, typename tag::type, diff --git a/include/boost/geometry/algorithms/correct.hpp b/include/boost/geometry/algorithms/correct.hpp index 7be0df6db..5b6568e7b 100644 --- a/include/boost/geometry/algorithms/correct.hpp +++ b/include/boost/geometry/algorithms/correct.hpp @@ -102,7 +102,7 @@ struct correct_ring { typedef typename point_type::type point_type; - typedef typename strategy_area + typedef typename strategy::area::services::default_strategy < typename cs_tag::type, point_type @@ -124,7 +124,7 @@ struct correct_ring { // check if closed, if not, close it bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1)); - closure_selector s = geometry::closure::value; + closure_selector const s = geometry::closure::value; if (disjoint && (s == closed)) { @@ -132,8 +132,8 @@ struct correct_ring } if (! disjoint && geometry::closure::value != closed) { - // Open it, TODO! - std::cout << "TODO"; + // Open it by removing last point + r.resize(boost::size(r) - 1); } } // Check area @@ -178,7 +178,7 @@ namespace dispatch { template -struct correct +struct correct { BOOST_MPL_ASSERT_MSG ( @@ -188,18 +188,18 @@ struct correct }; template -struct correct - : detail::correct::correct_nop +struct correct + : detail::correct::correct_nop {}; template -struct correct +struct correct : detail::correct::correct_nop {}; template -struct correct - : detail::correct::correct_nop +struct correct + : detail::correct::correct_nop {}; diff --git a/include/boost/geometry/algorithms/detail/overlay/assemble.hpp b/include/boost/geometry/algorithms/detail/overlay/assemble.hpp index 47ae27395..a0467cb21 100644 --- a/include/boost/geometry/algorithms/detail/overlay/assemble.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/assemble.hpp @@ -19,6 +19,7 @@ #include #include #include +#include //#include @@ -29,6 +30,8 @@ #include #include +#include + #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE # include @@ -44,6 +47,81 @@ 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; +} + + +// Skip for assemble process +template +inline bool skip(TurnInfo const& turn_info) +{ + return (turn_info.discarded || turn_info.both(operation_union)) + && ! turn_info.any_blocked() + && ! turn_info.both(operation_intersection) + ; +} + + + template inline void map_turns(Map& map, TurnPoints const& turn_points) { @@ -56,7 +134,7 @@ inline void map_turns(Map& map, TurnPoints const& turn_points) it != boost::end(turn_points); ++it, ++index) { - if (! it->ignore()) + if (! skip(*it)) { int op_index = 0; for (typename boost::range_iterator::type @@ -137,22 +215,27 @@ struct enrich_containment Geometry1 const& geometry1, Geometry2 const& geometry2, RingCollection const& collection) { + int code = -1; if (item1.ring_id.source_index == 0) { - return geometry::within(item2.point, + code = point_in_ring(item2.point, get_ring::apply(item1.ring_id, geometry1)); } else if (item1.ring_id.source_index == 1) { - return geometry::within(item2.point, + code = point_in_ring(item2.point, get_ring::apply(item1.ring_id, geometry2)); } else if (item1.ring_id.source_index == 2) { - return geometry::within(item2.point, + code = point_in_ring(item2.point, get_ring::apply(item1.ring_id, collection)); } - return false; + else + { + return false; + } + return code == 0 ? item1.area < 0 : code == 1; } template @@ -255,12 +338,16 @@ std::cout << "spatial divide n=" item_type& item1 = *it1; #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << item1.ring_id << " area: " << item1.area << std::endl; +if (item1.area < 0) +{ + std::cout << "(negative "; +} #endif iterator it2 = it1; for (it2++; it2 != boost::end(container); ++it2) { item_type& item2 = *it2; - if (geometry::within(item2.point, item1.box) + if (within_or_touch(item2.point, item1.box) && geometry::math::abs(item2.area) < geometry::math::abs(item1.area) && contains(item1, item2, geometry1, geometry2, collection) diff --git a/include/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/include/boost/geometry/algorithms/detail/overlay/check_enrich.hpp new file mode 100644 index 000000000..bb3969621 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/check_enrich.hpp @@ -0,0 +1,171 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright Barend Gehrels 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_OVERLAY_CHECK_ENRICH_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP + + +#include + + +#include +#include + + + +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +struct meta_turn +{ + int index; + Turn const* turn; + bool handled[2]; + + inline meta_turn(int i, Turn const& t) + : index(i), turn(&t) + { + handled[0] = false; + handled[1] = false; + } +}; + + +template +inline void display(MetaTurn const& meta_turn, std::string const& reason = "") +{ +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << meta_turn.index + << "\tMethods: " << method_char(meta_turn.turn->method) + << " operations: " << operation_char(meta_turn.turn->operations[0].operation) + << operation_char(meta_turn.turn->operations[1].operation) + << " travels to " << meta_turn.turn->operations[0].enriched.travels_to_ip_index + << " and " << meta_turn.turn->operations[1].enriched.travels_to_ip_index + //<< " -> " << op_index + << " " << reason + << std::endl; +#endif +} + + +template +inline void check_detailed(MetaTurns& meta_turns, MetaTurn const& meta_turn, + int op_index, int cycle, int start, operation_type for_operation, + bool& error) +{ + display(meta_turn); + int const ip_index = meta_turn.turn->operations[op_index].enriched.travels_to_ip_index; + if (ip_index >= 0) + { + bool found = false; + + if (ip_index == start) + { + display(meta_turns[ip_index], " FINISH"); + return; + } + + // check on continuing, or on same-operation-on-same-geometry + if (! meta_turns[ip_index].handled[op_index] + && (meta_turns[ip_index].turn->operations[op_index].operation == operation_continue + || meta_turns[ip_index].turn->operations[op_index].operation == for_operation) + ) + { + meta_turns[ip_index].handled[op_index] = true; + check_detailed(meta_turns, meta_turns[ip_index], op_index, cycle, start, for_operation, error); + found = true; + } + // check on other geometry + if (! found) + { + int const other_index = 1 - op_index; + if (! meta_turns[ip_index].handled[other_index] + && meta_turns[ip_index].turn->operations[other_index].operation == for_operation) + { + meta_turns[ip_index].handled[other_index] = true; + check_detailed(meta_turns, meta_turns[ip_index], other_index, cycle, start, for_operation, error); + found = true; + } + } + + if (! found) + { + display(meta_turns[ip_index], " STOP"); + error = true; +#ifndef BOOST_GEOMETRY_DEBUG_ENRICH + //std::cout << " STOP"; +#endif + } + } +} + + +template +inline bool check_graph(TurnPoints& turn_points, operation_type for_operation) +{ + typedef typename boost::range_value::type turn_point_type; + + bool error = false; + int index = 0; + + std::vector > meta_turns; + for (typename boost::range_iterator::type + it = boost::begin(turn_points); + it != boost::end(turn_points); + ++it, ++index) + { + meta_turns.push_back(meta_turn(index, *it)); + } + + int cycle = 0; + for (typename boost::range_iterator > > ::type + it = boost::begin(meta_turns); + it != boost::end(meta_turns); + ++it) + { + if (! (it->turn->blocked() || it->turn->is_discarded())) + { + for (int i = 0 ; i < 2; i++) + { + if (! it->handled[i] + && it->turn->operations[i].operation == for_operation) + { +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << "CYCLE " << cycle << std::endl; +#endif + it->handled[i] = true; + check_detailed(meta_turns, *it, i, cycle++, it->index, for_operation, error); +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout <<" END CYCLE " << it->index << std::endl; +#endif + } + } + } + } + return error; +} + + + +}} // namespace detail::overlay +#endif //DOXYGEN_NO_DETAIL + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index 1f2499144..289d325eb 100644 --- a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -42,11 +42,18 @@ namespace detail { namespace copy_segments template struct copy_segments_ring { + typedef closeable_view + < + Ring const, + closure::value == open + > view_type; + static inline void apply(Ring const& ring, SegmentIdentifier const& seg_id, int to_index, RangeOut& current_output) { - typedef typename boost::range_iterator::type iterator; + view_type view(ring); + typedef typename boost::range_iterator::type iterator; typedef geometry::ever_circling_iterator ec_iterator; @@ -59,10 +66,10 @@ struct copy_segments_ring int const from_index = seg_id.segment_index + 1; // Sanity check - BOOST_ASSERT(from_index < boost::size(ring)); + BOOST_ASSERT(from_index < boost::size(view)); - ec_iterator it(boost::begin(ring), boost::end(ring), - boost::begin(ring) + from_index); + ec_iterator it(boost::begin(view), boost::end(view), + boost::begin(view) + from_index); // [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK // [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK @@ -70,7 +77,7 @@ struct copy_segments_ring typedef typename boost::range_difference::type size_type; size_type const count = from_index <= to_index ? to_index - from_index + 1 - : boost::size(ring) - from_index + to_index + 1; + : boost::size(view) - from_index + to_index + 1; for (size_type i = 0; i < count; ++i, ++it) { @@ -158,8 +165,6 @@ struct copy_segments_box }; - - }} // namespace detail::copy_segments #endif // DOXYGEN_NO_DETAIL @@ -201,6 +206,7 @@ struct copy_segments > {}; + template < typename Polygon, @@ -236,9 +242,6 @@ struct copy_segments #endif // DOXYGEN_NO_DISPATCH - - - /*! \brief Copy segments from a geometry, starting with the specified segment (seg_id) until the specified index (to_index) @@ -270,4 +273,5 @@ inline void copy_segments(Geometry const& geometry, }} // namespace boost::geometry + #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index b94d90b74..a48bf715d 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -12,12 +12,15 @@ #include #include #include +#include #include -//#ifdef BOOST_GEOMETRY_DEBUG_OVERLAY -#include -#include -//#endif +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +# include +# include +# include +# define BOOST_GEOMETRY_DEBUG_IDENTIFIER +#endif #include #include @@ -28,6 +31,12 @@ #include #include +#include + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH +# include +#endif + namespace boost { namespace geometry { @@ -36,210 +45,146 @@ namespace boost { namespace geometry namespace detail { namespace overlay { - -template -struct indexed_operation +// Wraps "turn_operation" from turn_info.hpp, +// giving it extra information +template +struct indexed_turn_operation { - typedef Operation type; + typedef TurnOperation type; int index; int operation_index; - Operation subject; + bool discarded; + TurnOperation subject; - inline indexed_operation(int i, int oi, Operation const& s) + inline indexed_turn_operation(int i, int oi, TurnOperation const& s) : index(i) , operation_index(oi) + , discarded(false) , subject(s) {} }; - -template -< - typename Indexed, - typename Geometry1, - typename Geometry2, - typename Strategy -> -struct sort_on_distance +template +struct remove_discarded { -private : - Geometry1 const& m_geometry1; - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - typedef typename Indexed::type operation_type; - typedef typename point_type::type point_type; - - - inline bool normal_compare_distances(operation_type const& left, - operation_type const& right) const + inline bool operator()(IndexedTurnOperation const& operation) const { - return left.enriched.distance < right.enriched.distance; - } - -protected : - - - // Note that left/right do NOT correspond to m_geometry1/m_geometry2 - inline bool compare_distances(operation_type const& left, - operation_type const& right) const - { - // TODO: change this, it gives non-consequent behaviour resulting in - // an assertion within sort. - // SOLUTION: first sort on distance, then check if the sorted vector - // has distances close to zero, swap them mutually if there is a reason - // (reason by sides) - //if (fuzzy_equals(left.enriched.distance, right.enriched.distance)) - if (false) - { - - // Distances are the same, or quite close. - // We sort now using sides instead of using distance - // In most cases, this is possible. Else we fallback to distance - // (--> very rare cases, when both methods fail) - -#ifdef BOOST_GEOMETRY_DEBUG_OVERLAY - std::cout << "Equal Distance" - << " : " << left.seg_id << " / " << left.other_id - << " and " << right.seg_id << " / " << right.other_id - << std::endl; -#endif - - point_type pi, pj, ri, rj, si, sj; - if (left.seg_id == right.seg_id) - { - geometry::copy_segment_points(m_geometry1, m_geometry2, - left.seg_id, - pi, pj); - geometry::copy_segment_points(m_geometry1, m_geometry2, - left.other_id, - ri, rj); - geometry::copy_segment_points(m_geometry1, m_geometry2, - right.other_id, - si, sj); - } - else if (left.other_id == right.other_id) - { - geometry::copy_segment_points(m_geometry1, m_geometry2, - left.other_id, - pi, pj); - geometry::copy_segment_points(m_geometry1, m_geometry2, - left.seg_id, - ri, rj); - geometry::copy_segment_points(m_geometry1, m_geometry2, - right.seg_id, - si, sj); - } - else - { - return normal_compare_distances(left, right); - } - - int const order = get_relative_order::apply(pi, pj, - ri, rj, si, sj); - if (order != 0) - { - // If order == -1, r is the first segment along p - // So then return true; - return order == -1; - } - } - - return normal_compare_distances(left, right); - } - -public : - sort_on_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, - Strategy const& strategy) - : m_geometry1(geometry1) - , m_geometry2(geometry2) - , m_strategy(strategy) - {} - - inline bool operator()(Indexed const& left, Indexed const& right) const - { - return compare_distances(left.subject, right.subject); + return operation.discarded; } }; template < + typename TurnPoints, typename Indexed, typename Geometry1, typename Geometry2, typename Strategy > struct sort_on_segment_and_distance - : public sort_on_distance - < - Indexed, - Geometry1, Geometry2, Strategy - > { - sort_on_segment_and_distance(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - : sort_on_distance - < - Indexed, - Geometry1, Geometry2, Strategy - >(geometry1, geometry2, strategy) - {} + inline sort_on_segment_and_distance(TurnPoints const& turn_points + , Geometry1 const& geometry1 + , Geometry2 const& geometry2 + , Strategy const& strategy + , bool& clustered) + : m_turn_points(turn_points) + , m_geometry1(geometry1) + , m_geometry2(geometry2) + , m_strategy(strategy) + , m_clustered(clustered) + { + } +private : + + TurnPoints const& m_turn_points; + Geometry1 const& m_geometry1; + Geometry2 const& m_geometry2; + Strategy const& m_strategy; + mutable bool& m_clustered; + + inline bool consider_relative_order(Indexed const& left, + Indexed const& right) const + { + typedef typename geometry::point_type::type point_type; + point_type pi, pj, ri, rj, si, sj; + + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.seg_id, + pi, pj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.other_id, + ri, rj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + right.subject.other_id, + si, sj); + + int const order = get_relative_order + < + point_type + >::apply(pi, pj,ri, rj, si, sj); + //debug("r/o", order == -1); + return order == -1; + } + +public : + + // Note that left/right do NOT correspond to m_geometry1/m_geometry2 + // but to the "indexed_turn_operation" inline bool operator()(Indexed const& left, Indexed const& right) const { segment_identifier const& sl = left.subject.seg_id; segment_identifier const& sr = right.subject.seg_id; + if (sl == sr + && geometry::math::equals(left.subject.enriched.distance + , right.subject.enriched.distance)) + { + // Both left and right are located on the SAME segment. + + // First check "real" intersection (crosses) + // -> distance zero due to precision, solve it by sorting + if (m_turn_points[left.index].method == method_crosses + && m_turn_points[right.index].method == method_crosses) + { + return consider_relative_order(left, right); + } + + // If that is not the case, cluster it later on. + // Indicate that this is necessary. + m_clustered = true; + + return left.index < right.index; + } return sl == sr - ? this->compare_distances(left.subject, right.subject) + ? left.subject.enriched.distance < right.subject.enriched.distance : sl < sr; + } }; -template -inline bool swap_operations(Operation const& left, Operation const& right, - Geometry1 const& geometry1, Geometry2 const& geometry2) +template +inline void update_discarded(Turns& turn_points, Operations& operations) { - Point pi, pj, ri, rj, si, sj; - if (left.seg_id == right.seg_id) + // Vice-versa, set discarded to true for discarded operations; + // AND set discarded points to true + for (typename boost::range_iterator::type it = boost::begin(operations); + it != boost::end(operations); + ++it) { - geometry::copy_segment_points(geometry1, geometry2, - left.seg_id, - pi, pj); - geometry::copy_segment_points(geometry1, geometry2, - left.other_id, - ri, rj); - geometry::copy_segment_points(geometry1, geometry2, - right.other_id, - si, sj); - std::cout << "Considering seg" << std::endl; + if (turn_points[it->index].discarded) + { + it->discarded = true; + } + else if (it->discarded) + { + turn_points[it->index].discarded = true; + } } - else if (left.other_id == right.other_id) - { - geometry::copy_segment_points(geometry1, geometry2, - left.other_id, - pi, pj); - geometry::copy_segment_points(geometry1, geometry2, - left.seg_id, - ri, rj); - geometry::copy_segment_points(geometry1, geometry2, - right.seg_id, - si, sj); - std::cout << "Considering other" << std::endl; - } - else - { - return false; - } - - int const order = get_relative_order::apply(pi, pj, - ri, rj, si, sj); - std::cout << "Order: " << order << std::endl; - return order == 1; } @@ -257,96 +202,210 @@ template typename Geometry2, typename Strategy > -static inline bool enrich(Container& operations, +inline void enrich_sort(Container& operations, TurnPoints& turn_points, + operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { + typedef typename IndexType::type operations_type; + + bool clustered = false; std::sort(boost::begin(operations), boost::end(operations), sort_on_segment_and_distance < + TurnPoints, IndexType, Geometry1, Geometry2, Strategy - >(geometry1, geometry2, strategy)); + >(turn_points, geometry1, geometry2, strategy, clustered)); + // DONT'T discard xx / (for union) ix / ii / (for intersection) ux / uu here + // It would give way to "lonely" ui turn points, traveling all + // the way round. See #105 - typedef typename IndexType::type operation_type; - typedef typename boost::range_iterator::type iterator_type; - -//#ifdef BOOST_GEOMETRY_DEBUG_OVERLAY - /*** - // Check if it is really sorted. - if (operations.size() > 1) + if (clustered) { typedef typename boost::range_iterator::type nc_iterator; nc_iterator it = boost::begin(operations); + nc_iterator begin_cluster = boost::end(operations); for (nc_iterator prev = it++; it != boost::end(operations); prev = it++) { - operation_type& prev_op = turn_points[prev->index] + operations_type& prev_op = turn_points[prev->index] .operations[prev->operation_index]; - operation_type& op = turn_points[it->index] + operations_type& op = turn_points[it->index] .operations[it->operation_index]; - if ((prev_op.seg_id == op.seg_id || prev_op.other_id == op.other_id) - && geometry::math::equals(prev_op.enriched.distance, + + if (prev_op.seg_id == op.seg_id + && (turn_points[prev->index].method != method_crosses + || turn_points[it->index].method != method_crosses) + && geometry::math::equals(prev_op.enriched.distance, op.enriched.distance)) - { - std::cout << "Equal Distance on " - << " : " << prev_op.seg_id << " / " << prev_op.other_id - << " and " << op.seg_id << " / " << op.other_id - << std::endl; - std::cout << "\tType of intersections: " - << operation_char(prev_op.operation) - << " , " << operation_char(op.operation) - << std::endl; - - if (swap_operations - < - typename point_type::type - >(prev_op, op, geometry1, geometry2)) + { + if (begin_cluster == boost::end(operations)) { - std::cout << "Should be swapped" << std::endl; - - std::swap(*prev, *it); + begin_cluster = prev; } - } + } + else if (begin_cluster != boost::end(operations)) + { + handle_cluster(begin_cluster, it, turn_points, + for_operation, geometry1, geometry2, strategy); + begin_cluster = boost::end(operations); + } + } + if (begin_cluster != boost::end(operations)) + { + handle_cluster(begin_cluster, it, turn_points, + for_operation, geometry1, geometry2, strategy); } } - ***/ -//#endif + + update_discarded(turn_points, operations); +} - // Assign travel-to-vertex/ip index for each turning point. - // Because IP's are circular, PREV starts at the very last one, - // being assigned from the first one. - // For "next ip on same segment" it should not be considered circular. - bool first = true; - iterator_type it = boost::begin(operations); - for (iterator_type prev = it + (boost::size(operations) - 1); - it != boost::end(operations); - prev = it++) +template +< + typename IndexType, + typename Container, + typename TurnPoints +> +inline void enrich_discard(Container& operations, TurnPoints& turn_points) +{ + update_discarded(turn_points, operations); + + // Then delete discarded operations from vector + remove_discarded predicate; + operations.erase( + std::remove_if(boost::begin(operations), + boost::end(operations), + predicate), + boost::end(operations)); +} + +template +< + typename IndexType, + typename Container, + typename TurnPoints, + typename Geometry1, + typename Geometry2, + typename Strategy +> +inline void enrich_assign(Container& operations, + TurnPoints& turn_points, + operation_type for_operation, + Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) +{ + typedef typename IndexType::type operations_type; + typedef typename boost::range_iterator::type iterator_type; + + + if (operations.size() > 0) { - operation_type& prev_op = turn_points[prev->index] - .operations[prev->operation_index]; + // Assign travel-to-vertex/ip index for each turning point. + // Because IP's are circular, PREV starts at the very last one, + // being assigned from the first one. + // "next ip on same segment" should not be considered circular. + bool first = true; + iterator_type it = boost::begin(operations); + for (iterator_type prev = it + (boost::size(operations) - 1); + it != boost::end(operations); + prev = it++) + { + operations_type& prev_op + = turn_points[prev->index].operations[prev->operation_index]; + operations_type& op + = turn_points[it->index].operations[it->operation_index]; - prev_op.enriched.travels_to_ip_index = it->index; - prev_op.enriched.travels_to_vertex_index + prev_op.enriched.travels_to_ip_index + = it->index; + prev_op.enriched.travels_to_vertex_index = it->subject.seg_id.segment_index; - operation_type& op = turn_points[it->index] - .operations[it->operation_index]; - - if (! first && prev_op.seg_id.segment_index == op.seg_id.segment_index) - { - prev_op.enriched.next_ip_index = it->index; + if (! first + && prev_op.seg_id.segment_index == op.seg_id.segment_index) + { + prev_op.enriched.next_ip_index = it->index; + } + first = false; } - first = false; } - return true; + // DEBUG +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + { + for (iterator_type it = boost::begin(operations); + it != boost::end(operations); + ++it) + { + operations_type& op = turn_points[it->index] + .operations[it->operation_index]; + + std::cout << it->index + << " meth: " << method_char(turn_points[it->index].method) + << " seg: " << op.seg_id + << " dst: " << boost::numeric_cast(op.enriched.distance) + << " op: " << operation_char(turn_points[it->index].operations[0].operation) + << operation_char(turn_points[it->index].operations[1].operation) + << " dsc: " << (turn_points[it->index].discarded ? "T" : "F") + << " ->vtx " << op.enriched.travels_to_vertex_index + << " ->ip " << op.enriched.travels_to_ip_index + << " ->nxt ip " << op.enriched.next_ip_index + //<< " vis: " << visited_char(op.visited) + << std::endl; + ; + } + } +#endif + // END DEBUG + +} + + +template +inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vector) +{ + typedef typename boost::range_value::type turn_point_type; + typedef typename turn_point_type::container_type container_type; + + int index = 0; + for (typename boost::range_iterator::type + it = boost::begin(turn_points); + it != boost::end(turn_points); + ++it, ++index) + { + // Add operations on this ring, but skip discarded ones + if (! it->discarded) + { + int op_index = 0; + for (typename boost::range_iterator::type + op_it = boost::begin(it->operations); + op_it != boost::end(it->operations); + ++op_it, ++op_index) + { + // We should NOT skip blocked operations here + // because they can be relevant for "the other side" + // NOT if (op_it->operation != operation_blocked) + + ring_identifier ring_id + ( + op_it->seg_id.source_index, + op_it->seg_id.multi_index, + op_it->seg_id.ring_index + ); + mapped_vector[ring_id].push_back + ( + IndexedType(index, op_index, *op_it) + ); + } + } + } } @@ -354,6 +413,7 @@ static inline bool enrich(Container& operations, #endif //DOXYGEN_NO_DETAIL + /*! \brief All intersection points are enriched with successor information \ingroup overlay @@ -361,7 +421,7 @@ static inline bool enrich(Container& operations, (e.g. vector of "intersection/turn point"'s) \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry -\tparam Strategy point-point-distance strategy type +\tparam Strategy side strategy type \param turn_points container containing intersectionpoints \param geometry1 \param_geometry \param geometry2 \param_geometry @@ -375,61 +435,90 @@ template typename Strategy > inline void enrich_intersection_points(TurnPoints& turn_points, + detail::overlay::operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename boost::range_value::type turn_point_type; - typedef typename turn_point_type::container_type container_type; - typedef typename boost::range_value::type operation_type; - typedef detail::overlay::indexed_operation indexed_type; + typedef typename turn_point_type::turn_operation_type turn_operation_type; + typedef detail::overlay::indexed_turn_operation + < + turn_operation_type + > indexed_turn_operation; + typedef std::map < ring_identifier, - std::vector + std::vector > mapped_vector_type; - // Create a map of vectors of indexed operation-types to be able - // to sort per ring, later on. - mapped_vector_type mapped_vector; - - int index = 0; - for (typename boost::range_iterator::type + // DISCARD ALL UU + // #76 is the reason that this is necessary... + // With uu, at all points there is the risk that rings are being traversed twice or more. + // Without uu, all rings having only uu will be untouched and gathered by assemble + for (typename boost::range_iterator::type it = boost::begin(turn_points); it != boost::end(turn_points); - ++it, ++index) + ++it) { - if (! it->ignore()) + if (it->both(detail::overlay::operation_union)) { - int op_index = 0; - for (typename boost::range_iterator::type - op_it = boost::begin(it->operations); - op_it != boost::end(it->operations); - ++op_it, ++op_index) - { - ring_identifier ring_id - ( - op_it->seg_id.source_index, - op_it->seg_id.multi_index, - op_it->seg_id.ring_index - ); - mapped_vector[ring_id].push_back - ( - indexed_type(index, op_index, *op_it) - ); - } + it->discarded = true; } } - // Note: no const-operator because contents of mapped copy is temporary, - // and changed by enrich) + + // Create a map of vectors of indexed operation-types to be able + // to sort intersection points PER RING + mapped_vector_type mapped_vector; + + detail::overlay::create_map(turn_points, mapped_vector); + + + // No const-iterator; contents of mapped copy is temporary, + // and changed by enrich for (typename mapped_vector_type::iterator mit = mapped_vector.begin(); mit != mapped_vector.end(); ++mit) { - detail::overlay::enrich(mit->second, turn_points, +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << "ENRICH-sort Ring " + << mit->first << std::endl; +#endif + detail::overlay::enrich_sort(mit->second, turn_points, for_operation, geometry1, geometry2, strategy); } + + for (typename mapped_vector_type::iterator mit + = mapped_vector.begin(); + mit != mapped_vector.end(); + ++mit) + { +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << "ENRICH-discard Ring " + << mit->first << std::endl; +#endif + detail::overlay::enrich_discard(mit->second, turn_points); + } + + for (typename mapped_vector_type::iterator mit + = mapped_vector.begin(); + mit != mapped_vector.end(); + ++mit) + { +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << "ENRICH-assign Ring " + << mit->first << std::endl; +#endif + detail::overlay::enrich_assign(mit->second, turn_points, for_operation, + geometry1, geometry2, strategy); + } + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + //detail::overlay::check_graph(turn_points, for_operation); +#endif + } diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index ba409f628..411b6796b 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -50,7 +50,6 @@ #include #include #include -#include #include #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION @@ -90,6 +89,28 @@ template > class get_turns_in_sections { + typedef closeable_view + < + typename range_type::type const, + closure::value == open + > view_type1; + typedef closeable_view + < + typename range_type::type const, + closure::value == open + > view_type2; + + typedef typename boost::range_iterator + < + view_type1 const + >::type range1_iterator; + + typedef typename boost::range_iterator + < + view_type2 const + >::type range2_iterator; + + public : // Returns true if terminated, false if interrupted @@ -99,22 +120,14 @@ public : Turns& turns, InterruptPolicy& interrupt_policy) { + view_type1 view1 = get_full_section(geometry1, sec1); + view_type2 view2 = get_full_section(geometry2, sec2); - typedef typename boost::range_iterator - < - typename geometry::range_type::type const - >::type range1_iterator; + range1_iterator begin_range_1 = boost::begin(view1); + range1_iterator end_range_1 = boost::end(view1); - typedef typename boost::range_iterator - < - typename geometry::range_type::type const - >::type range2_iterator; - - range1_iterator begin_range_1, end_range_1; - get_full_section(geometry1, sec1, begin_range_1, end_range_1); - - range2_iterator begin_range_2, end_range_2; - get_full_section(geometry2, sec2, begin_range_2, end_range_2); + range2_iterator begin_range_2 = boost::begin(view2); + range2_iterator end_range_2 = boost::end(view2); int const dir1 = sec1.directions[0]; int const dir2 = sec2.directions[0]; @@ -128,8 +141,8 @@ public : range1_iterator prev1, it1, end1; - get_start_point_iterator(sec1, prev1, it1, end1, - index1, ndi1, geometry1, dir1, sec2.bounding_box); + get_start_point_iterator(sec1, view1, prev1, it1, end1, + index1, ndi1, dir1, sec2.bounding_box); // We need a circular iterator because it might run through the closing point. // One circle is actually enough but this one is just convenient. @@ -141,7 +154,7 @@ public : // section 1: |----|---|---|---|---| for (prev1 = it1++, next1++; it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box); - prev1 = it1++, index1++, next1++, ndi1++) + ++prev1, ++it1, ++index1, ++next1, ++ndi1) { ever_circling_iterator nd_next1( begin_range_1, end_range_1, next1, true); @@ -152,14 +165,14 @@ public : range2_iterator prev2, it2, end2; - get_start_point_iterator(sec2, prev2, it2, end2, - index2, ndi2, geometry2, dir2, sec1.bounding_box); + get_start_point_iterator(sec2, view2, prev2, it2, end2, + index2, ndi2, dir2, sec1.bounding_box); ever_circling_iterator next2(begin_range_2, end_range_2, it2, true); next2++; for (prev2 = it2++, next2++; it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box); - prev2 = it2++, index2++, next2++, ndi2++) + ++prev2, ++it2, ++index2, ++next2, ++ndi2) { bool skip = same_source; if (skip) @@ -268,14 +281,17 @@ private : // because of the logistics of "index" (the section-iterator automatically // skips to the begin-point, we loose the index or have to recalculate it) // So we mimic it here - template - static inline RangeIterator get_start_point_iterator(Section & section, - RangeIterator& it, RangeIterator& prev, RangeIterator& end, + template + static inline void get_start_point_iterator(Section & section, + Range const& range, + typename boost::range_iterator::type& it, + typename boost::range_iterator::type& prev, + typename boost::range_iterator::type& end, int& index, int& ndi, - Geometry const& geometry, int dir, Box const& other_bounding_box) { - get_section(geometry, section, it, end); + it = boost::begin(range) + section.begin_index; + end = boost::begin(range) + section.end_index + 1; // Mimic section-iterator: // Skip to point such that section interects other box @@ -285,7 +301,6 @@ private : {} // Go back one step because we want to start completely preceding it = prev; - return it; } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp new file mode 100644 index 000000000..000af78e1 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp @@ -0,0 +1,620 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright Barend Gehrels 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_OVERLAY_HANDLE_TANGENCIES_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP + +#include + + +#include +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +< + typename TurnPoints, + typename Indexed, + typename Geometry1, + typename Geometry2, + typename Strategy +> +struct sort_in_cluster +{ + inline sort_in_cluster(TurnPoints const& turn_points + , Geometry1 const& geometry1 + , Geometry2 const& geometry2 + , Strategy const& strategy) + : m_turn_points(turn_points) + , m_geometry1(geometry1) + , m_geometry2(geometry2) + , m_strategy(strategy) + {} + +private : + + TurnPoints const& m_turn_points; + Geometry1 const& m_geometry1; + Geometry2 const& m_geometry2; + Strategy const& m_strategy; + + typedef typename Indexed::type turn_operation_type; + typedef typename geometry::point_type point_type; + + + inline void debug_consider(int order, Indexed const& left, + Indexed const& right, std::string const& header, + bool skip = true, + std::string const& extra = "", bool ret = false + ) const + { + //if (skip) return; +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + typedef typename geometry::point_type::type point_type; + point_type pi, pj, ri, rj, si, sj; + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.seg_id, + pi, pj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.other_id, + ri, rj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + right.subject.other_id, + si, sj); + + std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl; + std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl; + std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl; + std::cout << " Segment s:" << geometry::wkt(si) << " .. " << geometry::wkt(sj) << std::endl; + + int const side_ri_p = m_strategy.apply(pi, pj, ri); + int const side_rj_p = m_strategy.apply(pi, pj, rj); + int const side_si_p = m_strategy.apply(pi, pj, si); + int const side_sj_p = m_strategy.apply(pi, pj, sj); + int const side_si_r = m_strategy.apply(ri, rj, si); + int const side_sj_r = m_strategy.apply(ri, rj, sj); + std::cout << " r//p: " << side_ri_p << " / " << side_rj_p << std::endl; + std::cout << " s//p: " << side_si_p << " / " << side_sj_p << std::endl; + std::cout << " s//r: " << side_si_r << " / " << side_sj_r << std::endl; + + std::cout << header << " order: " << order + << " ops: " << operation_char(left.subject.operation) + << "/" << operation_char(right.subject.operation) + << " ri//p: " << side_ri_p + << " si//p: " << side_si_p + << " si//r: " << side_si_r + << " idx: " << left.index << "/" << right.index; + + if (! extra.empty()) + { + std::cout << " " << extra << " " << (ret ? "true" : "false"); + } + std::cout << std::endl; +#endif + } + + + // ux/ux + inline bool consider_ux_ux(Indexed const& left, + Indexed const& right + , std::string const& header + ) const + { + bool ret = left.index < right.index; + + // In combination of u/x, x/u: take first union, then blocked. + // Solves #88, #61, #56, #80 + if (left.subject.operation == operation_union + && right.subject.operation == operation_blocked) + { + ret = true; + } + else if (left.subject.operation == operation_blocked + && right.subject.operation == operation_union) + { + ret = false; + } + else + { +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << "ux/ux unhandled" << std::endl; +#endif + } + + debug_consider(0, left, right, header, false, "-> return ", ret); + + return ret; + } + + inline bool consider_iu_ux(Indexed const& left, + Indexed const& right, + int order // 1: iu first, -1: ux first + , std::string const& header + ) const + { + bool ret = false; + + if (left.subject.operation == operation_union + && right.subject.operation == operation_union) + { + ret = order == 1; + } + else if (left.subject.operation == operation_union + && right.subject.operation == operation_blocked) + { + ret = true; + } + else if (right.subject.operation == operation_union + && left.subject.operation == operation_blocked) + { + ret = false; + } + else if (left.subject.operation == operation_union) + { + ret = true; + } + else if (right.subject.operation == operation_union) + { + ret = false; + } + else + { +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << " iu/ux unhandled"; +#endif + ret = order == 1; + } + + debug_consider(0, left, right, header, false, "-> return", ret); + return ret; + } + + inline bool consider_iu_ix(Indexed const& left, + Indexed const& right, + int order // 1: iu first, -1: ix first + , std::string const& header + ) const + { + debug_consider(order, left, right, header, false, "iu/ix"); + + return left.subject.operation == operation_intersection + && right.subject.operation == operation_intersection ? order == 1 + : left.subject.operation == operation_intersection ? false + : right.subject.operation == operation_intersection ? true + : order == 1; + } + + + inline bool consider_iu_iu(Indexed const& left, Indexed const& right, + std::string const& header) const + { + debug_consider(0, left, right, header); + + typedef typename geometry::point_type::type point_type; + point_type pi, pj, ri, rj, si, sj; + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.seg_id, + pi, pj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.other_id, + ri, rj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + right.subject.other_id, + si, sj); + + int const side_ri_p = m_strategy.apply(pi, pj, ri); + int const side_si_p = m_strategy.apply(pi, pj, si); + int const side_si_r = m_strategy.apply(ri, rj, si); + + // Both located right (#58) + if (side_ri_p == -1 && side_si_p == -1 && side_si_r != 0) + { + // Take the most left one + // Solves #58 + bool const ret = side_si_r != 1; + return ret; + } + + + // Coming from opposite sides (#59, #99) + if (side_ri_p * side_si_p == -1) + { + bool ret = false; + + if (left.subject.operation == operation_intersection + && right.subject.operation == operation_union) + { + // #55_iet_iet: reverse this + ret = false; + } + else if (left.subject.operation == operation_union + && right.subject.operation == operation_intersection) + { + // #55_iet_iet: also. + ret = true; + } + else if (left.subject.operation == operation_union + && right.subject.operation == operation_union) + { + ret = side_ri_p == 1; // #100 + } + else + { +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << " iu/iu coming from opposite unhandled"; +#endif + ret = left.index < right.index; + } + + debug_consider(0, left, right, header, false, "coming from opposite", ret); + return ret; + } + + + if (side_si_r != 0) + { + // One coming from right (#83,#90) + if ((side_ri_p == 0 && side_si_p == -1) + || (side_ri_p == -1 && side_si_p == 0)) + { + bool const ret = side_si_r != 1; + return ret; + } + + // One coming from left (#90, #94, #95) + if ((side_ri_p == 0 && side_si_p == 1) + || (side_ri_p == 1 && side_si_p == 0)) + { + bool const ret = side_si_r != -1; + return ret; + } + } + + // All aligned (#92, #96) + if (side_ri_p == 0 && side_si_p == 0 && side_si_r == 0) + { + // Determine how p/r and p/s are located. + // One of them is coming from opposite direction. + typedef geometry::segment segment_type; + + typedef strategy::intersection::relate_cartesian_segments + < + policies::relate::segments_intersection_points + < + segment_type, + segment_type, + segment_intersection_points + > + > policy; + + segment_type p(pi, pj); + segment_type r(ri, rj); + segment_type s(si, sj); + + // Get the intersection point (or two points) + segment_intersection_points pr = policy::apply(p, r); + segment_intersection_points ps = policy::apply(p, s); + + // Take the one NOT being collinear + if (pr.count == 2 && ps.count == 1) return true; + if (pr.count == 1 && ps.count == 2) return false; + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << "iu/iu all collinear unhandled" << std::endl; +#endif + + } + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << " iu/iu unhandled"; +#endif + return left.index < right.index; + } + + inline bool consider_ii(Indexed const& left, Indexed const& right, + std::string const& header) const + { + debug_consider(0, left, right, header); + + typedef typename geometry::point_type::type point_type; + point_type pi, pj, ri, rj, si, sj; + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.seg_id, + pi, pj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + left.subject.other_id, + ri, rj); + geometry::copy_segment_points(m_geometry1, m_geometry2, + right.subject.other_id, + si, sj); + + int const side_ri_p = m_strategy.apply(pi, pj, ri); + int const side_si_p = m_strategy.apply(pi, pj, si); + + // Two other points are (mostly) lying both right of the considered segment + // Take the most left one + int const side_si_r = m_strategy.apply(ri, rj, si); + if (side_ri_p == -1 + && side_si_p == -1 + && side_si_r != 0) + { + bool const ret = side_si_r != 1; + return ret; + } + return left.index < right.index; + } + + +public : + inline bool operator()(Indexed const& left, Indexed const& right) const + { + bool const default_order = left.index < right.index; + + if ((m_turn_points[left.index].discarded || left.discarded) + && (m_turn_points[right.index].discarded || right.discarded)) + { + return default_order; + } + else if (m_turn_points[left.index].discarded || left.discarded) + { + // Be careful to sort discarded first, then all others + return true; + } + else if (m_turn_points[right.index].discarded || right.discarded) + { + // See above so return false here such that right (discarded) + // is sorted before left (not discarded) + return false; + } + else if (m_turn_points[left.index].combination(operation_blocked, operation_union) + && m_turn_points[right.index].combination(operation_blocked, operation_union)) + { + // ux/ux + return consider_ux_ux(left, right, "ux/ux"); + } + else if (m_turn_points[left.index].both(operation_union) + && m_turn_points[right.index].both(operation_union)) + { + // uu/uu, Order is arbitrary + // Note: uu/uu is discarded now before so this point will + // not be reached. + return default_order; + } + else if (m_turn_points[left.index].combination(operation_intersection, operation_union) + && m_turn_points[right.index].combination(operation_intersection, operation_union)) + { + return consider_iu_iu(left, right, "iu/iu"); + } + else if (m_turn_points[left.index].both(operation_intersection) + && m_turn_points[right.index].both(operation_intersection)) + { + return consider_ii(left, right, "ii/ii"); + } + else if (m_turn_points[left.index].combination(operation_union, operation_blocked) + && m_turn_points[right.index].combination(operation_intersection, operation_union)) + { + return consider_iu_ux(left, right, -1, "ux/iu"); + } + else if (m_turn_points[left.index].combination(operation_intersection, operation_union) + && m_turn_points[right.index].combination(operation_union, operation_blocked)) + { + return consider_iu_ux(left, right, 1, "iu/ux"); + } + else if (m_turn_points[left.index].combination(operation_intersection, operation_blocked) + && m_turn_points[right.index].combination(operation_intersection, operation_union)) + { + return consider_iu_ix(left, right, 1, "ix/iu"); + } + else if (m_turn_points[left.index].combination(operation_intersection, operation_union) + && m_turn_points[right.index].combination(operation_intersection, operation_blocked)) + { + return consider_iu_ix(left, right, -1, "iu/ix"); + } + else if (m_turn_points[left.index].method != method_equal + && m_turn_points[right.index].method == method_equal + ) + { + // If one of them was EQUAL or CONTINUES, it should always come first + return false; + } + else if (m_turn_points[left.index].method == method_equal + && m_turn_points[right.index].method != method_equal + ) + { + return true; + } + + // Now we have no clue how to sort. + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << " Consider: " << operation_char(m_turn_points[left.index].operations[0].operation) + << operation_char(m_turn_points[left.index].operations[1].operation) + << "/" << operation_char(m_turn_points[right.index].operations[0].operation) + << operation_char(m_turn_points[right.index].operations[1].operation) + << " " << " Take " << left.index << " < " << right.index; +#endif + + return default_order; + } +}; + + + +template +< + typename IndexType, + typename Iterator, + typename TurnPoints, + typename Geometry1, + typename Geometry2, + typename Strategy +> +inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster, + TurnPoints& turn_points, + operation_type for_operation, + Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) +{ + int count = 0; + + // Make an analysis about all occuring cases here. + std::map, int> inspection; + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + operation_type first = turn_points[it->index].operations[0].operation; + operation_type second = turn_points[it->index].operations[1].operation; + if (first > second) + { + std::swap(first, second); + } + inspection[std::make_pair(first, second)]++; + count++; + } + + + bool keep_cc = false; + + // Decide about which is going to be discarded here. + if (inspection[std::make_pair(operation_union, operation_union)] == 1 + && inspection[std::make_pair(operation_continue, operation_continue)] == 1) + { + // In case of uu/cc, discard the uu, that indicates a tangency and + // inclusion would disturb the (e.g.) cc-cc-cc ordering + // NOTE: uu is now discarded anyhow. + keep_cc = true; + } + else if (count == 2 + && inspection[std::make_pair(operation_intersection, operation_intersection)] == 1 + && inspection[std::make_pair(operation_union, operation_intersection)] == 1) + { + // In case of ii/iu, discard the iu. The ii should always be visited, + // Because (in case of not discarding iu) correctly ordering of ii/iu appears impossible + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + if (turn_points[it->index].combination(operation_intersection, operation_union)) + { + it->discarded = true; + } + } + } + + // Discard any continue turn, unless it is the only thing left + // (necessary to avoid cc-only rings, all being discarded + // e.g. traversal case #75) + int nd_count= 0, cc_count = 0; + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + if (! it->discarded) + { + nd_count++; + if (turn_points[it->index].both(operation_continue)) + { + cc_count++; + } + } + } + + if (nd_count == cc_count) + { + keep_cc = true; + } + + if (! keep_cc) + { + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + if (turn_points[it->index].both(operation_continue)) + { + it->discarded = true; + } + } + } +} + + +template +< + typename IndexType, + typename Iterator, + typename TurnPoints, + typename Geometry1, + typename Geometry2, + typename Strategy +> +inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster, + TurnPoints& turn_points, + operation_type for_operation, + Geometry1 const& geometry1, Geometry2 const& geometry2, + Strategy const& strategy) +{ + // First inspect and (possibly) discard rows + inspect_cluster(begin_cluster, end_cluster, turn_points, + for_operation, geometry1, geometry2, strategy); + + + // Then sort this range (discard rows will be ordered first and will be removed in enrich_assign) + std::sort(begin_cluster, end_cluster, + sort_in_cluster + < + TurnPoints, + IndexType, + Geometry1, Geometry2, + Strategy + >(turn_points, geometry1, geometry2, strategy)); + + +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + typedef typename IndexType::type operations_type; + operations_type const& op = turn_points[begin_cluster->index].operations[begin_cluster->operation_index]; + std::cout << "Clustered points on equal distance " << op.enriched.distance << std::endl; + std::cout << "->Indexes "; + + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + std::cout << " " << it->index; + } + std::cout << std::endl << "->Methods: "; + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + std::cout << " " << method_char(turn_points[it->index].method); + } + std::cout << std::endl << "->Operations: "; + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + std::cout << " " << operation_char(turn_points[it->index].operations[0].operation) + << operation_char(turn_points[it->index].operations[1].operation); + } + std::cout << std::endl << "->Discarded: "; + for (Iterator it = begin_cluster; it != end_cluster; ++it) + { + std::cout << " " << (it->discarded ? "true" : "false"); + } + std::cout << std::endl; + //<< "\tOn segments: " << prev_op.seg_id << " / " << prev_op.other_id + //<< " and " << op.seg_id << " / " << op.other_id + //<< geometry::distance(turn_points[prev->index].point, turn_points[it->index].point) +#endif + +} + + +}} // namespace detail::overlay +#endif //DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index e62eb1c5a..3713e7b8f 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -112,7 +112,11 @@ std::cout << "get turns" << std::endl; std::cout << "enrich" << std::endl; #endif typename Strategy::side_strategy_type side_strategy; - geometry::enrich_intersection_points(turn_points, geometry1, geometry2, + geometry::enrich_intersection_points(turn_points, + Direction == -1 + ? boost::geometry::detail::overlay::operation_intersection + : boost::geometry::detail::overlay::operation_union, + geometry1, geometry2, side_strategy); #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE diff --git a/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp index 7159796cc..01c46f296 100644 --- a/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/ring_properties.hpp @@ -69,7 +69,7 @@ struct ring_properties { has_point = geometry::point_on_border(point, geometry, true); typedef typename coordinate_type::type coordinate_type; - coordinate_type zero = coordinate_type(); + coordinate_type const zero = coordinate_type(); signum = area > zero ? 1 : area < zero ? -1 : 0; parent_ring_id.source_index = -1; } diff --git a/include/boost/geometry/algorithms/detail/overlay/split_rings.hpp b/include/boost/geometry/algorithms/detail/overlay/split_rings.hpp index e0533ba70..126bc9d63 100644 --- a/include/boost/geometry/algorithms/detail/overlay/split_rings.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/split_rings.hpp @@ -24,11 +24,9 @@ #include #include - #include #include -#include #include diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index 79fff4d20..01a95b606 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -36,6 +36,25 @@ namespace boost { namespace geometry namespace detail { namespace overlay { +template +inline void debug_traverse(Turn const& turn, Operation op, std::string const& header) +{ +#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE + std::cout << header + << " at " << op.seg_id + << " op: " << operation_char(op.operation) + << " vis: " << visited_char(op.visited) + << " of: " << operation_char(turn.operations[0].operation) + << operation_char(turn.operations[1].operation) + << std::endl; + + if (boost::contains(header, "Finished")) + { + std::cout << std::endl; + } +#endif +} + template inline void clear_visit_info(Turns& turns) @@ -56,6 +75,7 @@ inline void clear_visit_info(Turns& turns) { op_it->visited.clear(); } + it->discarded = false; } } @@ -91,11 +111,11 @@ template typename Turns, typename IntersectionInfo > -inline void assign_next_ip(G1 const& g1, G2 const& g2, +inline bool assign_next_ip(G1 const& g1, G2 const& g2, Turns& turns, - typename boost::range_iterator::type & ip, + typename boost::range_iterator::type& ip, GeometryOut& current_output, - IntersectionInfo & info, + IntersectionInfo& info, segment_identifier& seg_id) { info.visited.set_visited(); @@ -104,6 +124,11 @@ inline void 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; + + BOOST_ASSERT(info.enriched.travels_to_vertex_index >= 0); + BOOST_ASSERT(info.enriched.travels_to_ip_index >= 0); + if (info.seg_id.source_index == 0) { geometry::copy_segments(g1, info.seg_id, @@ -116,8 +141,8 @@ inline void assign_next_ip(G1 const& g1, G2 const& g2, info.enriched.travels_to_vertex_index, current_output); } - ip = boost::begin(turns) + info.enriched.travels_to_ip_index; seg_id = info.seg_id; + ip = boost::begin(turns) + info.enriched.travels_to_ip_index; } else { @@ -126,12 +151,15 @@ inline void assign_next_ip(G1 const& g1, G2 const& g2, } geometry::append(current_output, ip->point); + return true; } inline bool select_source(operation_type operation, int source1, int source2) { - return operation == operation_intersection && source1 != source2; + return (operation == operation_intersection && source1 != source2) + || (operation == operation_union && source1 == source2) + ; } @@ -145,23 +173,35 @@ inline bool select_next_ip(operation_type operation, segment_identifier const& seg_id, Iterator& selected) { + if (turn.discarded) + { + return false; + } bool has_tp = false; selected = boost::end(turn.operations); for (Iterator it = boost::begin(turn.operations); it != boost::end(turn.operations); ++it) { + if (it->visited.started()) + { + selected = it; + //std::cout << " RETURN"; + return true; + } + // In some cases there are two alternatives. // For "ii", take the other one (alternate) + // UNLESS the other one is already visited // For "uu", take the same one (see above); // For "cc", take either one, but if there is a starting one, // take that one. if ( (it->operation == operation_continue - && (! has_tp - || it->visited.started() + && (! has_tp || it->visited.started() ) ) || (it->operation == operation + && ! it->visited.finished() && (! has_tp || select_source(operation, it->seg_id.source_index, seg_id.source_index) @@ -170,16 +210,17 @@ inline bool select_next_ip(operation_type operation, ) { selected = it; + debug_traverse(turn, *it, " Candidate"); has_tp = true; } - - if (it->visited.started()) - { - selected = it; - return true; - } } + if (has_tp) + { + debug_traverse(turn, *selected, " Accepted"); + } + + return has_tp; } @@ -208,6 +249,9 @@ inline void backtrack(std::size_t size_at_start, bool& fail, #endif ) { +#ifdef BOOST_GEOMETRY_DEBUG_ENRICH + std::cout << " REJECT " << reason << std::endl; +#endif fail = true; // Make bad output clean @@ -287,8 +331,8 @@ inline void traverse(Geometry1 const& geometry1, ! fail && it != boost::end(turns); ++it) { - // Skip the self-tangent ones (uu) - if (! it->ignore()) + // Skip discarded ones + if (! (it->is_discarded() || it->blocked())) { for (turn_operation_iterator_type iit = boost::begin(it->operations); ! fail && iit != boost::end(it->operations); @@ -309,16 +353,22 @@ inline void traverse(Geometry1 const& geometry1, turn_operation_iterator_type current_iit = iit; segment_identifier current_seg_id; - detail::overlay::assign_next_ip(geometry1, geometry2, + if (! detail::overlay::assign_next_ip(geometry1, geometry2, turns, current, current_output, - *iit, current_seg_id); + *iit, current_seg_id)) + { + detail::overlay::backtrack( + size_at_start, fail, + rings, current_output, turns, *current_iit, + "No next IP", + geometry1, geometry2); + } if (! detail::overlay::select_next_ip( operation, *current, current_seg_id, - current_iit)) { detail::overlay::backtrack( @@ -331,6 +381,9 @@ inline void traverse(Geometry1 const& geometry1, { iit->visited.set_started(); + detail::overlay::debug_traverse(*it, *iit, "-> Started"); + detail::overlay::debug_traverse(*current, *current_iit, "Selected "); + unsigned int i = 0; @@ -368,7 +421,6 @@ inline void traverse(Geometry1 const& geometry1, operation, *current, current_seg_id, - current_iit)) { // Should not occur in valid (non-self-intersecting) polygons @@ -380,11 +432,13 @@ inline void traverse(Geometry1 const& geometry1, "Dead end", geometry1, geometry2); } + detail::overlay::debug_traverse(*current, *current_iit, "Selected "); - if (i++ > turns.size()) + if (i++ > 2 + 2 * turns.size()) { // Sanity check: there may be never more loops - // than intersection points. + // than turn points. + // Turn points marked as "ii" can be visited twice. detail::overlay::backtrack( size_at_start, fail, rings, current_output, turns, *iit, @@ -397,6 +451,7 @@ inline void traverse(Geometry1 const& geometry1, if (! fail) { iit->visited.set_finished(); + detail::overlay::debug_traverse(*current, *iit, "->Finished"); rings.push_back(current_output); } } diff --git a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp index f0a97fc29..5a8206b5d 100644 --- a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -58,7 +58,7 @@ struct turn_operation segment_identifier seg_id; segment_identifier other_id; - turn_operation() + inline turn_operation() : operation(operation_none) {} }; @@ -82,22 +82,50 @@ template struct turn_info { typedef Point point_type; - typedef Operation operation_type; + typedef Operation turn_operation_type; typedef Container container_type; Point point; method_type method; + bool discarded; + Container operations; inline turn_info() : method(method_none) + , discarded(false) {} - inline bool ignore() const + inline bool both(operation_type type) const { - return this->operations[0].operation == operation_union - && this->operations[1].operation == operation_union; + return has12(type, type); + } + + inline bool combination(operation_type type1, operation_type type2) const + { + return has12(type1, type2) || has12(type2, type1); + } + + + inline bool is_discarded() const { return discarded; } + inline bool blocked() const + { + return both(operation_blocked); + } + inline bool any_blocked() const + { + return this->operations[0].operation == operation_blocked + || this->operations[1].operation == operation_blocked; + } + + +private : + inline bool has12(operation_type type1, operation_type type2) const + { + return this->operations[0].operation == type1 + && this->operations[1].operation == type2 + ; } }; diff --git a/include/boost/geometry/algorithms/detail/ring_identifier.hpp b/include/boost/geometry/algorithms/detail/ring_identifier.hpp index 6435591be..8de42e92e 100644 --- a/include/boost/geometry/algorithms/detail/ring_identifier.hpp +++ b/include/boost/geometry/algorithms/detail/ring_identifier.hpp @@ -27,8 +27,7 @@ struct ring_identifier : source_index(src) , multi_index(mul) , ring_index(rin) - { - } + {} inline bool operator<(ring_identifier const& other) const { diff --git a/include/boost/geometry/algorithms/detail/sections/get_full_section.hpp b/include/boost/geometry/algorithms/detail/sections/get_full_section.hpp index 2fc6b20be..3c7b61ad1 100644 --- a/include/boost/geometry/algorithms/detail/sections/get_full_section.hpp +++ b/include/boost/geometry/algorithms/detail/sections/get_full_section.hpp @@ -8,17 +8,16 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_GET_FULL_SECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_GET_FULL_SECTION_HPP +// TODO rename to "range_by_section" #include #include #include +#include #include #include - -#include - -#include +#include @@ -30,31 +29,42 @@ namespace detail { namespace section { -template + + +template struct full_section_range { - static inline void apply(Range const& range, Section const& section, - Iterator& begin, Iterator& end) + typedef closeable_view + < + Range const, + closure::value == open // close it if it is open + > view_type; + + static inline view_type apply(Range const& range, Section const& section) { - begin = boost::begin(range); - end = boost::end(range); + return view_type(range); } }; -template +template struct full_section_polygon { - static inline void apply(Polygon const& polygon, Section const& section, - Iterator& begin, Iterator& end) + typedef typename geometry::ring_type::type ring_type; + typedef closeable_view + < + ring_type const, + closure::value == open // close it if it is open + > view_type; + + static inline view_type apply(Polygon const& polygon, Section const& section) { - typedef typename geometry::ring_type::type ring_type; + ring_type const& ring = section.ring_index < 0 ? geometry::exterior_ring(polygon) : geometry::interior_rings(polygon)[section.ring_index]; - begin = boost::begin(ring); - end = boost::end(ring); + return view_type(ring); } }; @@ -72,8 +82,7 @@ template < typename Tag, typename Geometry, - typename Section, - typename Iterator + typename Section > struct get_full_section { @@ -85,21 +94,21 @@ struct get_full_section }; -template -struct get_full_section - : detail::section::full_section_range +template +struct get_full_section + : detail::section::full_section_range {}; -template -struct get_full_section - : detail::section::full_section_range +template +struct get_full_section + : detail::section::full_section_range {}; -template -struct get_full_section - : detail::section::full_section_polygon +template +struct get_full_section + : detail::section::full_section_polygon {}; @@ -108,42 +117,28 @@ struct get_full_section /*! - \brief Get iterators for a specified section + \brief Get a closeable view indicated by the specified section \ingroup sectionalize \tparam Geometry type \tparam Section type of section to get from - \param geometry geometry which might be located in the neighborhood + \param geometry geometry to take section of \param section structure with section \param begin begin-iterator (const iterator over points of section) \param end end-iterator (const iterator over points of section) \todo Create non-const version as well */ -template -inline void get_full_section(Geometry const& geometry, Section const& section, - typename boost::range_iterator - < - typename geometry::range_type::type const - >::type& begin, - typename boost::range_iterator - < - typename geometry::range_type::type const - >::type& end) +template +inline Range get_full_section(Geometry const& geometry, Section const& section) { concept::check(); - typedef typename boost::range_iterator - < - typename geometry::range_type::type const - >::type iterator_type; - - dispatch::get_full_section + return dispatch::get_full_section < typename tag::type, Geometry, - Section, - iterator_type - >::apply(geometry, section, begin, end); + Section + >::apply(geometry, section); } diff --git a/include/boost/geometry/algorithms/detail/sections/get_section.hpp b/include/boost/geometry/algorithms/detail/sections/get_section.hpp index 25ed309ab..b52952258 100644 --- a/include/boost/geometry/algorithms/detail/sections/get_section.hpp +++ b/include/boost/geometry/algorithms/detail/sections/get_section.hpp @@ -9,149 +9,50 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP +// OBSOLETE + +/*** #include -#include -#include -#include -#include -#include - namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ -// Generic case (linestring/linear ring) -template -struct get_section -{ - typedef typename add_const_if_c - < - IsConst, - Geometry - >::type geometry_type; - - typedef typename boost::range_iterator - < - typename add_const_if_c - < - IsConst, - typename geometry::range_type::type - >::type - >::type iterator_type; - - static inline void apply(geometry_type& geometry, Section const& section, - iterator_type& begin, iterator_type& end) - { - begin = boost::begin(geometry) + section.begin_index; - end = boost::begin(geometry) + section.end_index + 1; - } -}; - -template -struct get_section -{ - typedef typename add_const_if_c - < - IsConst, - Polygon - >::type polygon_type; - - typedef typename boost::range_iterator - < - typename add_const_if_c - < - IsConst, - typename geometry::range_type::type - >::type - >::type iterator_type; - - static inline void apply(polygon_type& polygon, Section const& section, - iterator_type& begin, iterator_type& end) - { - typename add_const_if_c - < - IsConst, - typename geometry::ring_type::type - >::type& ring = section.ring_index < 0 - ? geometry::exterior_ring(polygon) - : geometry::interior_rings(polygon)[section.ring_index]; - - begin = boost::begin(ring) + section.begin_index; - end = boost::begin(ring) + section.end_index + 1; - } -}; - - -} // namespace dispatch -#endif - - -/*! \brief Get iterators for a specified section \ingroup sectionalize - \tparam Geometry type + \tparam Range type \tparam Section type of section to get from - \param geometry geometry which might be located in the neighborhood + \param range range (retrieved by "range_by_section") to take section of \param section structure with section \param begin begin-iterator (const iterator over points of section) \param end end-iterator (const iterator over points of section) - */ -template -inline void get_section(Geometry const& geometry, Section const& section, - typename boost::range_iterator - < - typename geometry::range_type::type const - >::type& begin, - typename boost::range_iterator - < - typename geometry::range_type::type const - >::type& end) -{ - concept::check(); - dispatch::get_section - < - typename tag::type, - Geometry, - Section, - true - >::apply(geometry, section, begin, end); +template +inline void get_section(Range const& range, Section const& section, + typename boost::range_iterator::type& begin, + typename boost::range_iterator::type& end) +{ + begin = boost::begin(range) + section.begin_index; + end = boost::begin(range) + section.end_index + 1; } // non const version -template -inline void get_section(Geometry& geometry, Section const& section, - typename boost::range_iterator - < - typename geometry::range_type::type - >::type& begin, - typename boost::range_iterator - < - typename geometry::range_type::type - >::type& end) +template +inline void get_section(Range& range, Section const& section, + typename boost::range_iterator::type& begin, + typename boost::range_iterator::type& end) { - concept::check(); - - dispatch::get_section - < - typename tag::type, - Geometry, - Section, - false - >::apply(geometry, section, begin, end); + begin = boost::begin(range) + section.begin_index; + end = boost::begin(range) + section.end_index + 1; } - }} // namespace boost::geometry +****/ #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP diff --git a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp index 94e53ab34..29ed1b78e 100644 --- a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -19,12 +19,14 @@ #include #include +#include #include +#include #include - #include +#include #include @@ -186,7 +188,8 @@ struct check_duplicate_loop coordinate_type const diff = geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg); - if (! geometry::math::equals(diff, 0)) + coordinate_type const zero = 0; + if (! geometry::math::equals(diff, zero)) { return false; } @@ -228,7 +231,7 @@ struct assign_loop /// @brief Helper class to create sections of a part of a range, on the fly template < - typename Range, + typename Range, // Can be closeable_view typename Point, typename Sections, std::size_t DimensionCount, @@ -238,6 +241,7 @@ struct sectionalize_part { typedef geometry::segment segment_type; typedef typename boost::range_value::type section_type; + typedef typename boost::range_iterator::type iterator_type; static inline void apply(Sections& sections, section_type& section, @@ -260,7 +264,7 @@ struct sectionalize_part for(iterator_type previous = it++; it != boost::end(range); - previous = it++, index++) + ++previous, ++it, index++) { segment_type segment(*previous, *it); @@ -341,7 +345,7 @@ struct sectionalize_part template < - typename Range, + typename Range, closure_selector Closure, typename Point, typename Sections, std::size_t DimensionCount, @@ -349,12 +353,20 @@ template > struct sectionalize_range { + typedef closeable_view + < + Range const, + Closure == open // close it if it is open + > view_type; + static inline void apply(Range const& range, Sections& sections, int ring_index = -1, int multi_index = -1) { typedef segment segment_type; - std::size_t const n = boost::size(range); + view_type view(range); + + std::size_t const n = boost::size(view); if (n == 0) { // Zero points, no section @@ -375,10 +387,10 @@ struct sectionalize_range sectionalize_part < - Range, Point, Sections, + view_type, Point, Sections, DimensionCount, MaxCount >::apply(sections, section, index, ndi, - range, ring_index, multi_index); + view, ring_index, multi_index); // Add last section if applicable if (section.count > 0) @@ -404,7 +416,8 @@ struct sectionalize_polygon typedef typename ring_type::type ring_type; typedef sectionalize_range < - ring_type, point_type, Sections, DimensionCount, MaxCount + ring_type, closure::value, + point_type, Sections, DimensionCount, MaxCount > sectionalizer_type; typedef typename boost::range_iterator @@ -457,7 +470,7 @@ struct sectionalize_box sectionalize_range < - std::vector, + std::vector, closed, point_type, Sections, DimensionCount, @@ -539,7 +552,7 @@ struct sectionalize > : detail::sectionalize::sectionalize_range < - LineString, + LineString, closed, typename point_type::type, Sections, DimensionCount, @@ -549,16 +562,16 @@ struct sectionalize template < - typename Range, + typename Ring, typename Sections, std::size_t DimensionCount, std::size_t MaxCount > -struct sectionalize +struct sectionalize : detail::sectionalize::sectionalize_range < - Range, - typename point_type::type, + Ring, geometry::closure::value, + typename point_type::type, Sections, DimensionCount, MaxCount diff --git a/include/boost/geometry/algorithms/dissolve.hpp b/include/boost/geometry/algorithms/dissolve.hpp index d3bb143cf..1abf84ffe 100644 --- a/include/boost/geometry/algorithms/dissolve.hpp +++ b/include/boost/geometry/algorithms/dissolve.hpp @@ -76,18 +76,26 @@ struct dissolve_ring_or_polygon typename cs_tag::type >::type side_strategy_type; - enrich_intersection_points(turns, geometry, geometry, + enrich_intersection_points(turns, + detail::overlay::operation_union, + geometry, geometry, side_strategy_type()); // Traverse the polygons twice in two different directions - traverse::value>(geometry, geometry, + traverse::value>(geometry, geometry, detail::overlay::operation_union, turns, rings); clear_visit_info(turns); - traverse::value>(geometry, geometry, + enrich_intersection_points(turns, + detail::overlay::operation_intersection, + geometry, geometry, + side_strategy_type()); + + + traverse::value>(geometry, geometry, detail::overlay::operation_intersection, turns, rings); diff --git a/include/boost/geometry/algorithms/num_points.hpp b/include/boost/geometry/algorithms/num_points.hpp index 217892dce..b8bcaa870 100644 --- a/include/boost/geometry/algorithms/num_points.hpp +++ b/include/boost/geometry/algorithms/num_points.hpp @@ -14,9 +14,13 @@ #include #include +#include #include +#include #include +#include +#include #include @@ -31,16 +35,29 @@ namespace detail { namespace num_points template struct range_count { - static inline std::size_t apply(Range const& range) + static inline std::size_t apply(Range const& range, bool add_for_open) { - return boost::size(range); + std::size_t n = boost::size(range); + if (add_for_open) + { + closure_selector const s = geometry::closure::value; + + if (s == open) + { + if (geometry::disjoint(*boost::begin(range), *(boost::begin(range) + n - 1))) + { + return n + 1; + } + } + } + return n; } }; template struct other_count { - static inline std::size_t apply(Geometry const& ) + static inline std::size_t apply(Geometry const&, bool) { return D; } @@ -49,9 +66,13 @@ struct other_count template struct polygon_count { - static inline std::size_t apply(Polygon const& poly) + static inline std::size_t apply(Polygon const& poly, bool add_for_open) { - std::size_t n = boost::size(exterior_ring(poly)); + typedef typename geometry::ring_type::type ring_type; + + std::size_t n = range_count::apply( + exterior_ring(poly), add_for_open); + typedef typename boost::range_iterator < typename interior_type::type const @@ -61,7 +82,7 @@ struct polygon_count it != boost::end(interior_rings(poly)); ++it) { - n += boost::size(*it); + n += range_count::apply(*it, add_for_open); } return n; @@ -138,7 +159,7 @@ struct num_points \qbk{compliance,__ogc__} */ template -inline std::size_t num_points(Geometry const& geometry) +inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false) { concept::check(); @@ -147,7 +168,7 @@ inline std::size_t num_points(Geometry const& geometry) typename tag::type, is_linear::value, Geometry - >::apply(geometry); + >::apply(geometry, add_for_open); } }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/transform.hpp b/include/boost/geometry/algorithms/transform.hpp index a913d5ba5..6b0c8ebe9 100644 --- a/include/boost/geometry/algorithms/transform.hpp +++ b/include/boost/geometry/algorithms/transform.hpp @@ -167,16 +167,16 @@ struct transform_polygon template struct select_strategy { - typedef typename strategy_transform + typedef typename strategy::transform::services::default_strategy < - typename cs_tag::type, - typename cs_tag::type, - typename coordinate_system::type, - typename coordinate_system::type, - dimension::type::value, - dimension::type::value, - typename point_type::type, - typename point_type::type + typename cs_tag::type, + typename cs_tag::type, + typename coordinate_system::type, + typename coordinate_system::type, + dimension::type::value, + dimension::type::value, + typename point_type::type, + typename point_type::type >::type type; }; diff --git a/include/boost/geometry/algorithms/within.hpp b/include/boost/geometry/algorithms/within.hpp index 3ed4a1135..9a8344e77 100644 --- a/include/boost/geometry/algorithms/within.hpp +++ b/include/boost/geometry/algorithms/within.hpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,14 +55,14 @@ template > struct point_in_box { - static inline bool apply(Point const& p, Box const& b, Strategy const& s) + 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 false; + return -1; } return point_in_box @@ -85,9 +85,9 @@ template > struct point_in_box { - static inline bool apply(Point const& , Box const& , Strategy const& ) + static inline int apply(Point const& , Box const& , Strategy const& ) { - return true; + return 1; } }; @@ -102,14 +102,14 @@ template > struct box_in_box { - static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& s) + 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 false; + return -1; } return box_in_box @@ -132,9 +132,9 @@ template > struct box_in_box { - static inline bool apply(Box1 const& , Box2 const& , Strategy const&) + static inline int apply(Box1 const& , Box2 const& , Strategy const&) { - return true; + return 1; } }; @@ -151,12 +151,12 @@ struct point_in_ring { BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategy) ); - static inline bool apply(Point const& point, Ring const& ring, + static inline int apply(Point const& point, Ring const& ring, Strategy const& strategy) { if (boost::size(ring) < 4) { - return false; + return -1; } typedef reversible_view rev_view_type; @@ -182,10 +182,13 @@ struct point_in_ring return false; } } + return strategy.result(state); } }; + + // Polygon: in exterior ring, and if so, not within interior ring(s) template < @@ -199,22 +202,20 @@ struct point_in_polygon { BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategy) ); - static inline bool apply(Point const& point, Polygon const& poly, + static inline int apply(Point const& point, Polygon const& poly, Strategy const& strategy) { - - typedef point_in_ring + int const code = point_in_ring < Point, typename ring_type::type, Direction, Closure, Strategy - > per_ring; + >::apply(point, exterior_ring(poly), strategy); - if (per_ring::apply(point, exterior_ring(poly), strategy)) + if (code == 1) { - for (typename boost::range_iterator < typename interior_type::type const @@ -222,14 +223,25 @@ struct point_in_polygon it != boost::end(interior_rings(poly)); ++it) { - if (per_ring::apply(point, *it, strategy)) + int const interior_code = point_in_ring + < + Point, + typename ring_type::type, + Direction, + Closure, + Strategy + >::apply(point, *it, strategy); + + if (interior_code != -1) { - return false; + // If 0, return 0 (touch) + // If 1 (inside hole) return -1 (outside polygon) + // If -1 (outside hole) check other holes if any + return -interior_code; } } - return true; } - return false; + return code; } }; @@ -335,8 +347,10 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2) typedef typename point_type::type point_type1; typedef typename point_type::type point_type2; - typedef typename strategy_within + typedef typename strategy::within::services::default_strategy < + typename tag::type, + typename tag::type, typename cs_tag::type, typename cs_tag::type, point_type1, @@ -350,7 +364,7 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2) Geometry1, Geometry2, strategy_type - >::apply(geometry1, geometry2, strategy_type()); + >::apply(geometry1, geometry2, strategy_type()) == 1; } /*! @@ -387,7 +401,7 @@ inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2, Geometry1, Geometry2, Strategy - >::apply(geometry1, geometry2, strategy); + >::apply(geometry1, geometry2, strategy) == 1; } }} // namespace boost::geometry diff --git a/include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp index 840c8d56b..69730e982 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include @@ -91,7 +91,11 @@ void sectionalizing_buffer(Geometry const& geometry, iterator_type begin, end; typedef std::pair section_range; - geometry::get_section(geometry, section, begin, end); + +TODO: UPDATE: get _ section IS OBSOLETE NOW AND DISCARDED. +TAKE range_by_section AND ADD section.begin_index/section.end_index + + geometry::get _ section(geometry, section, begin, end); // get_section is DISCARDED geometry::detail::buffer::linestring_buffer < section_range, ring_type, DistanceStrategy, JoinStrategy diff --git a/include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp index 24224746e..353b5d76e 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp @@ -23,8 +23,6 @@ #include #include -#include -#include #include diff --git a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp index 57095891d..7567871c7 100644 --- a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp +++ b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp @@ -2,10 +2,11 @@ #define TTMATH_STUB #include +#include #include -#include +#include namespace ttmath { template @@ -143,4 +144,88 @@ namespace detail + +// Support for boost::numeric_cast to int and to double (necessary for SVG-mapper) +namespace boost { namespace numeric +{ + +template +< + ttmath::uint Exponent, ttmath::uint Mantissa, + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker> +{ + static inline int convert(ttmath::Big arg) + { + int v; + arg.ToInt(v); + return v; + } +}; + +template +< + ttmath::uint Exponent, ttmath::uint Mantissa, + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker> +{ + static inline double convert(ttmath::Big arg) + { + double v; + arg.ToDouble(v); + return v; + } +}; + + +template +< + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter +{ + static inline int convert(ttmath_big arg) + { + int v; + arg.ToInt(v); + return v; + } +}; + +template +< + typename Traits, + typename OverflowHandler, + typename Float2IntRounder, + typename RawConverter, + typename UserRangeChecker +> +struct converter +{ + static inline double convert(ttmath_big arg) + { + double v; + arg.ToDouble(v); + return v; + } +}; + + +}} + + #endif diff --git a/include/boost/geometry/extensions/gis/geographic/strategies/area_huiller_earth.hpp b/include/boost/geometry/extensions/gis/geographic/strategies/area_huiller_earth.hpp index b38b99454..a84856e3a 100644 --- a/include/boost/geometry/extensions/gis/geographic/strategies/area_huiller_earth.hpp +++ b/include/boost/geometry/extensions/gis/geographic/strategies/area_huiller_earth.hpp @@ -32,28 +32,33 @@ class huiller_earth public : // By default the average earth radius. // Uses can specify another radius. - // Note that the earth is still spherical + // Note that the earth is still handled spherically inline huiller_earth(double radius = 6372795.0) : huiller(radius) {} }; - -}} // namespace strategy::area - - #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS -template -struct strategy_area +namespace services { - typedef strategy::area::huiller_earth type; + +template +struct default_strategy +{ + typedef huiller_earth type; }; +} // namespace services + + #endif +}} // namespace strategy::area + + }} // namespace boost::geometry diff --git a/include/boost/geometry/geometries/linear_ring.hpp b/include/boost/geometry/geometries/linear_ring.hpp index 4024420a6..b81a5c11d 100644 --- a/include/boost/geometry/geometries/linear_ring.hpp +++ b/include/boost/geometry/geometries/linear_ring.hpp @@ -114,6 +114,104 @@ struct closure< linear_ring > } // namespace traits #endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + +// NEW APPROACH +namespace model +{ +/*! + \brief A linear_ring (linear linear_ring) is a closed line which should not be selfintersecting + \ingroup geometries + \tparam Point point type + \tparam Container optional container type, for example std::vector, std::list, std::deque + \tparam Allocator optional container-allocator-type +*/ +template +< + typename Point, + bool ClockWise = true, bool Closed = true, + template class Container = std::vector, + template class Allocator = std::allocator +> +class linear_ring : public Container > +{ + BOOST_CONCEPT_ASSERT( (concept::Point) ); +}; + +} // namespace model + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename Point, + bool ClockWise, bool Closed, + template class Container, + template class Allocator +> +struct tag > +{ + typedef ring_tag type; +}; + + +template +< + typename Point, + bool Closed, + template class Container, + template class Allocator +> +struct point_order > +{ + static const order_selector value = counterclockwise; +}; + + +template +< + typename Point, + bool Closed, + template class Container, + template class Allocator +> +struct point_order > +{ + static const order_selector value = clockwise; +}; + +template +< + typename Point, + bool PointOrder, + template class Container, + template class Allocator +> +struct closure > +{ + static const closure_selector value = closed; +}; + +template +< + typename Point, + bool PointOrder, + template class Container, + template class Allocator +> +struct closure > +{ + static const closure_selector value = open; +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_GEOMETRIES_LINEAR_RING_HPP diff --git a/include/boost/geometry/geometries/polygon.hpp b/include/boost/geometry/geometries/polygon.hpp index e3117230f..16d8fbead 100644 --- a/include/boost/geometry/geometries/polygon.hpp +++ b/include/boost/geometry/geometries/polygon.hpp @@ -139,7 +139,7 @@ template typename Point, template class PointList, template class RingList, - bool ClockWise, bool Closed, + bool ClockWise, bool Closed, template class PointAlloc, template class RingAlloc > @@ -187,6 +187,179 @@ struct interior_rings< polygon class PointList = std::vector, + template class RingList = std::vector, + template class PointAlloc = std::allocator, + template class RingAlloc = std::allocator +> +class polygon +{ + BOOST_CONCEPT_ASSERT( (concept::Point) ); + +public: + + // Member types + typedef Point point_type; + typedef linear_ring ring_type; + typedef RingList > inner_container_type; + + inline ring_type const& outer() const { return m_outer; } + inline inner_container_type const& inners() const { return m_inners; } + + inline ring_type& outer() { return m_outer; } + inline inner_container_type & inners() { return m_inners; } + + /// Utility method, clears outer and inner rings + inline void clear() + { + m_outer.clear(); + m_inners.clear(); + } + +private: + + ring_type m_outer; + inner_container_type m_inners; +}; + + +} // namespace model + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + +template +< + typename Point, + bool ClockWise, bool Closed, + template class PointList, + template class RingList, + template class PointAlloc, + template class RingAlloc +> +struct tag > +{ + typedef polygon_tag type; +}; + +template +< + typename Point, + bool ClockWise, bool Closed, + template class PointList, + template class RingList, + template class PointAlloc, + template class RingAlloc +> +struct ring_type > +{ + typedef typename model::polygon + < + Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc + >::ring_type type; +}; + +template +< + typename Point, + bool ClockWise, bool Closed, + template class PointList, + template class RingList, + template class PointAlloc, + template class RingAlloc +> +struct interior_type > +{ + typedef typename model::polygon + < + Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc + >::inner_container_type type; +}; + +template +< + typename Point, + bool ClockWise, bool Closed, + template class PointList, + template class RingList, + template class PointAlloc, + template class RingAlloc +> +struct exterior_ring > +{ + typedef model::polygon polygon_type; + + static inline typename polygon_type::ring_type& get(polygon_type& p) + { + return p.outer(); + } + + static inline typename polygon_type::ring_type const & get(polygon_type const& p) + { + return p.outer(); + } +}; + +template +< + typename Point, + bool ClockWise, bool Closed, + template class PointList, + template class RingList, + template class PointAlloc, + template class RingAlloc +> +struct interior_rings > +{ + typedef model::polygon polygon_type; + + static inline typename polygon_type::inner_container_type& get( + polygon_type& p) + { + return p.inners(); + } + + static inline typename polygon_type::inner_container_type const& get( + polygon_type const& p) + { + return p.inners(); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + + + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_GEOMETRIES_POLYGON_HPP diff --git a/include/boost/geometry/geometry.hpp b/include/boost/geometry/geometry.hpp index f9c39a315..c623adf24 100644 --- a/include/boost/geometry/geometry.hpp +++ b/include/boost/geometry/geometry.hpp @@ -58,10 +58,6 @@ #include #include -#include -#include - - // check includes all concepts #include diff --git a/include/boost/geometry/iterators/closing_iterator.hpp b/include/boost/geometry/iterators/closing_iterator.hpp index 625f250ce..9e59a43c4 100644 --- a/include/boost/geometry/iterators/closing_iterator.hpp +++ b/include/boost/geometry/iterators/closing_iterator.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include @@ -28,65 +28,120 @@ namespace boost { namespace geometry */ template struct closing_iterator - : public boost::iterator_adaptor + : public boost::iterator_facade < closing_iterator, - typename boost::range_iterator::type, - boost::use_default, - boost::forward_traversal_tag + typename boost::range_value::type const, + boost::random_access_traversal_tag > { /// Constructor including the range it is based on explicit inline closing_iterator(Range& range) - : m_range(range) - , m_beyond(false) - , m_end(boost::end(m_range)) - { - this->base_reference() = boost::begin(m_range); - } + : m_range(&range) + , m_iterator(boost::begin(range)) + , m_end(boost::end(range)) + , m_size(boost::size(range)) + , m_index(0) + {} /// Constructor to indicate the end of a range explicit inline closing_iterator(Range& range, bool) - : m_range(range) - , m_beyond(true) - , m_end(boost::end(m_range)) + : m_range(&range) + , m_iterator(boost::end(range)) + , m_end(boost::end(range)) + , m_size(boost::size(range)) + , m_index(m_size + 1) + {} + + /// Default constructor + explicit inline closing_iterator() + : m_range(NULL) + , m_size(0) + , m_index(0) + {} + + inline closing_iterator& operator=(closing_iterator const& source) { - this->base_reference() = m_end; + m_range = source.m_range; + m_iterator = source.m_iterator; + m_end = source.m_end; + m_size = source.m_size; + m_index = source.m_index; + return *this; } + typedef std::ptrdiff_t difference_type; + private: friend class boost::iterator_core_access; + inline typename boost::range_value::type const& dereference() const + { + return *m_iterator; + } + + inline difference_type distance_to(closing_iterator const& other) const + { + return other.m_index - this->m_index; + } + inline bool equal(closing_iterator const& other) const { - return this->base() == other.base() - && this->m_beyond == other.m_beyond; + return this->m_range == other.m_range + && this->m_index == other.m_index; } inline void increment() { - if (m_beyond) + if (++m_index < m_size) { - this->base_reference() = m_end; + ++m_iterator; } - else if (this->base() != m_end) + else { - (this->base_reference())++; - - if (this->base() == m_end) - { - // Now beyond last position -> set to "begin" again - // and set flag "beyond" such that next increment - // will finish traversal - this->base_reference() = boost::begin(m_range); - m_beyond = true; - } + update_iterator(); } } - Range& m_range; - bool m_beyond; + inline void decrement() + { + if (m_index-- < m_size) + { + --m_iterator; + } + else + { + update_iterator(); + } + } + + inline void advance(difference_type n) + { + if (m_index < m_size && m_index + n < m_size) + { + m_index += n; + m_iterator += n; + } + else + { + m_index += n; + update_iterator(); + } + } + + inline void update_iterator() + { + this->m_iterator = m_index <= m_size + ? boost::begin(*m_range) + (m_index % m_size) + : boost::end(*m_range) + ; + } + + Range* m_range; + typename boost::range_iterator::type m_iterator; typename boost::range_iterator::type m_end; + difference_type m_size; + difference_type m_index; }; diff --git a/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp index 805377f84..fbbad1092 100644 --- a/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp @@ -15,7 +15,6 @@ #include #include -#include #include @@ -58,7 +57,7 @@ struct get_turns_multi_polygon_cs typename boost::range_value::type, Box, Turns, TurnPolicy, InterruptPolicy - >::apply(source_id1, *it, source_id2, box, + >::apply(source_id1, *it, source_id2, box, turns, interrupt_policy, i); } } diff --git a/include/boost/geometry/multi/algorithms/detail/sections/get_full_section.hpp b/include/boost/geometry/multi/algorithms/detail/sections/get_full_section.hpp index edaf65447..185fafb10 100644 --- a/include/boost/geometry/multi/algorithms/detail/sections/get_full_section.hpp +++ b/include/boost/geometry/multi/algorithms/detail/sections/get_full_section.hpp @@ -13,6 +13,7 @@ #include #include +#include #include @@ -29,14 +30,19 @@ template < typename MultiGeometry, typename Section, - typename Iterator, typename Policy > struct full_section_multi { - static inline void apply(MultiGeometry const& multi, - Section const& section, - Iterator& begin, Iterator& end) + typedef typename geometry::ring_type::type ring_type; + typedef closeable_view + < + ring_type const, + closure::value == open // close it if it is open + > view_type; + + static inline view_type apply(MultiGeometry const& multi, + Section const& section) { BOOST_ASSERT ( @@ -44,7 +50,7 @@ struct full_section_multi && section.multi_index < boost::size(multi) ); - Policy::apply(multi[section.multi_index], section, begin, end); + return Policy::apply(multi[section.multi_index], section); } }; @@ -59,18 +65,16 @@ namespace dispatch { -template -struct get_full_section +template +struct get_full_section : detail::section::full_section_multi < MultiPolygon, Section, - Iterator, detail::section::full_section_polygon < typename boost::range_value::type, - Section, - Iterator + Section > > {}; diff --git a/include/boost/geometry/multi/algorithms/detail/sections/get_section.hpp b/include/boost/geometry/multi/algorithms/detail/sections/get_section.hpp index 0322d3069..3c450d787 100644 --- a/include/boost/geometry/multi/algorithms/detail/sections/get_section.hpp +++ b/include/boost/geometry/multi/algorithms/detail/sections/get_section.hpp @@ -10,6 +10,8 @@ #define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP +// OBSOLETE +/* #include #include #include @@ -71,5 +73,6 @@ struct get_section }} // namespace boost::geometry +*/ #endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP diff --git a/include/boost/geometry/multi/algorithms/intersection.hpp b/include/boost/geometry/multi/algorithms/intersection.hpp index 102c2b844..8c5d46f27 100644 --- a/include/boost/geometry/multi/algorithms/intersection.hpp +++ b/include/boost/geometry/multi/algorithms/intersection.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/include/boost/geometry/multi/algorithms/num_points.hpp b/include/boost/geometry/multi/algorithms/num_points.hpp index b0c6d7614..1ef3f8f40 100644 --- a/include/boost/geometry/multi/algorithms/num_points.hpp +++ b/include/boost/geometry/multi/algorithms/num_points.hpp @@ -28,7 +28,7 @@ namespace detail { namespace num_points template struct multi_count { - static inline size_t apply(MultiGeometry const& geometry) + static inline size_t apply(MultiGeometry const& geometry, bool add_for_open) { typedef typename boost::range_value::type geometry_type; typedef typename boost::range_iterator @@ -36,7 +36,7 @@ struct multi_count MultiGeometry const >::type iterator_type; - size_t n = 0; + std::size_t n = 0; for (iterator_type it = boost::begin(geometry); it != boost::end(geometry); ++it) @@ -46,7 +46,7 @@ struct multi_count typename tag::type, geometry::is_linear::value, geometry_type - >::apply(*it); + >::apply(*it, add_for_open); } return n; } diff --git a/include/boost/geometry/multi/algorithms/union.hpp b/include/boost/geometry/multi/algorithms/union.hpp index 8fccda7c0..bf11a9084 100644 --- a/include/boost/geometry/multi/algorithms/union.hpp +++ b/include/boost/geometry/multi/algorithms/union.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/include/boost/geometry/multi/algorithms/within.hpp b/include/boost/geometry/multi/algorithms/within.hpp index 438ba337a..b038f9f46 100644 --- a/include/boost/geometry/multi/algorithms/within.hpp +++ b/include/boost/geometry/multi/algorithms/within.hpp @@ -32,7 +32,7 @@ template > struct geometry_in_multi { - static inline bool apply(Geometry const& geometry, + static inline int apply(Geometry const& geometry, MultiGeometry const& multi, Strategy const& strategy) { @@ -42,12 +42,13 @@ struct geometry_in_multi ++it) { // Geometry within a multi: true if within one of them - if (Policy::apply(geometry, *it, strategy)) + int const code = Policy::apply(geometry, *it, strategy); + if (code != -1) { - return true; + return code; } } - return false; + return -1; } }; diff --git a/include/boost/geometry/multi/multi.hpp b/include/boost/geometry/multi/multi.hpp index 8a00166f2..d0097865c 100644 --- a/include/boost/geometry/multi/multi.hpp +++ b/include/boost/geometry/multi/multi.hpp @@ -43,7 +43,6 @@ #include #include -#include #include #include diff --git a/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp b/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp index 981fc061c..775e6d044 100644 --- a/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp +++ b/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp @@ -23,7 +23,7 @@ namespace boost { namespace geometry { -namespace strategy { namespace centroid_ +namespace strategy { namespace centroid { @@ -71,26 +71,30 @@ public : }; -}} // namespace strategy::centroid - - #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ template -struct strategy_centroid +struct default_strategy { - typedef strategy::centroid_::centroid_average + typedef centroid_average < Point, typename point_type::type > type; }; +} // namespace services + #endif +}} // namespace strategy::centroid + + }} // namespace boost::geometry diff --git a/include/boost/geometry/multi/strategies/centroid.hpp b/include/boost/geometry/multi/strategies/centroid.hpp index 5b39d5393..4f733d517 100644 --- a/include/boost/geometry/multi/strategies/centroid.hpp +++ b/include/boost/geometry/multi/strategies/centroid.hpp @@ -18,20 +18,24 @@ namespace boost { namespace geometry #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace strategy { namespace centroid { namespace services +{ template -struct strategy_centroid +struct default_strategy { - typedef strategy::centroid_::bashein_detmer + typedef bashein_detmer < Point, typename point_type::type > type; }; -#endif +}}} // namespace strategy::centroid::services +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + }} // namespace boost::geometry 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 0eeb2ffcd..9cf9bfa57 100644 --- a/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp +++ b/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp @@ -9,13 +9,16 @@ #ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP #define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP +#include - +#include #include -#include - +#include +#include +// TEMP! +#include namespace boost { namespace geometry { @@ -57,19 +60,20 @@ class winding /*! subclass to keep state */ class counter { - int count; - bool touches; + int m_count; + bool m_touches; - inline bool within_no_touch() const + inline int code() const { - return ! touches && count != 0; + return m_touches ? 0 : m_count == 0 ? -1 : 1; } + public : friend class winding; inline counter() - : count(0) - , touches(false) + : m_count(0) + , m_touches(false) {} }; @@ -85,7 +89,7 @@ class winding calculation_type const s2 = get(seg2); if ((s1 <= p && s2 >= p) || (s2 <= p && s1 >= p)) { - state.touches = true; + state.m_touches = true; } return 0; } @@ -140,8 +144,8 @@ public : if (side == 0) { // Point is lying on segment - state.touches = true; - state.count = 0; + state.m_touches = true; + state.m_count = 0; return false; } @@ -151,39 +155,77 @@ public : // See accompagnying figure (TODO) if (side * count > 0) { - state.count += count; + state.m_count += count; } - } - return ! state.touches; + return ! state.m_touches; } - static inline bool result(counter const& state) + static inline int result(counter const& state) { - return state.within_no_touch(); + return state.code(); } }; -}} // namespace strategy::within - #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS -template -struct strategy_within +namespace services { - typedef strategy::within::winding type; + +template +struct default_strategy +{ + typedef winding type; }; template -struct strategy_within +struct default_strategy { - typedef strategy::within::winding type; + typedef winding type; }; +template +struct default_strategy +{ + typedef winding type; +}; + +// TEMP! +// register it even for the multi here, and for the box +// future: use tag inheritance, see elsewhere +template +struct default_strategy +{ + typedef winding type; +}; + +template +struct default_strategy +{ + typedef winding type; +}; + +template +struct default_strategy +{ + typedef winding type; +}; + +template +struct default_strategy +{ + typedef winding type; +}; + +} // namespace services + #endif +}} // namespace strategy::within + + }} // namespace boost::geometry diff --git a/include/boost/geometry/strategies/area.hpp b/include/boost/geometry/strategies/area.hpp index 6b4879470..b6d662f4e 100644 --- a/include/boost/geometry/strategies/area.hpp +++ b/include/boost/geometry/strategies/area.hpp @@ -9,26 +9,37 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_AREA_HPP #define BOOST_GEOMETRY_STRATEGIES_AREA_HPP -#include +#include +#include namespace boost { namespace geometry { +namespace strategy { namespace area { namespace services +{ + /*! - \brief Traits class binding an area strategy to a coordinate system + \brief Traits class binding a default area strategy to a coordinate system \ingroup area \tparam Tag tag of coordinate system \tparam PointOfSegment point-type */ template -struct strategy_area +struct default_strategy { - typedef strategy::not_implemented type; + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE + , (types) + ); }; +}}} // namespace strategy::area::services + + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_AREA_HPP diff --git a/include/boost/geometry/strategies/area_result.hpp b/include/boost/geometry/strategies/area_result.hpp index 0dab047a7..13f6da08d 100644 --- a/include/boost/geometry/strategies/area_result.hpp +++ b/include/boost/geometry/strategies/area_result.hpp @@ -25,11 +25,15 @@ namespace boost { namespace geometry from length, where distance is sqr/sqrt, but length always squared) */ + +// TODO: rename to "default_area_result" or services::default_result + + template struct area_result { typedef typename point_type::type point_type; - typedef typename strategy_area + typedef typename strategy::area::services::default_strategy < typename cs_tag::type, point_type diff --git a/include/boost/geometry/strategies/cartesian/area_by_triangles.hpp b/include/boost/geometry/strategies/cartesian/area_by_triangles.hpp index 62748d1b0..ee17443c1 100644 --- a/include/boost/geometry/strategies/cartesian/area_by_triangles.hpp +++ b/include/boost/geometry/strategies/cartesian/area_by_triangles.hpp @@ -92,18 +92,24 @@ public : }; +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + template + struct default_strategy + { + typedef strategy::area::by_triangles type; + }; + +} // namespace services + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + }} // namespace strategy::area -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - -template -struct strategy_area -{ - typedef strategy::area::by_triangles type; -}; - -#endif }} // namespace boost::geometry diff --git a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp index a6b53d218..534c255fd 100644 --- a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -152,11 +152,12 @@ struct relate_cartesian_segments } // Degenerate cases: segments of single point, lying on other segment, non disjoint - if (math::equals(dx_a, 0) && math::equals(dy_a, 0)) + coordinate_type const zero = 0; + if (math::equals(dx_a, zero) && math::equals(dy_a, zero)) { return Policy::degenerate(a, true); } - if (math::equals(dx_b, 0) && math::equals(dy_b, 0)) + if (math::equals(dx_b, zero) && math::equals(dy_b, zero)) { return Policy::degenerate(b, false); } @@ -174,7 +175,7 @@ struct relate_cartesian_segments // Determinant d should be nonzero. // If it is zero, we have an robustness issue here, // (and besides that we cannot divide by it) - if(math::equals(d, 0) && ! collinear) + if(math::equals(d, zero) && ! collinear) //if(! collinear && sides.as_collinear()) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION @@ -208,7 +209,7 @@ struct relate_cartesian_segments if(collinear) { // Segments are collinear. We'll find out how. - if (math::equals(dx_b, 0)) + if (math::equals(dx_b, zero)) { // Vertical -> Check y-direction return relate_collinear(a, b, diff --git a/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp b/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp index a34b2ab96..eba993ae9 100644 --- a/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp +++ b/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp @@ -27,7 +27,7 @@ namespace boost { namespace geometry // Note: when calling the namespace "centroid", it sometimes, // somehow, in gcc, gives compilation problems (confusion with function centroid). -namespace strategy { namespace centroid_ +namespace strategy { namespace centroid { @@ -204,17 +204,16 @@ public : }; - -}} // namespace strategy::centroid - - #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + // Register this strategy for rings and polygons, in two dimensions template -struct strategy_centroid +struct default_strategy { - typedef strategy::centroid_::bashein_detmer + typedef bashein_detmer < Point, typename point_type::type @@ -222,16 +221,23 @@ struct strategy_centroid }; template -struct strategy_centroid +struct default_strategy { - typedef strategy::centroid_::bashein_detmer + typedef bashein_detmer < Point, typename point_type::type > type; }; -#endif + +} // namespace services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::centroid }} // namespace boost::geometry diff --git a/include/boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp b/include/boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp index c4c7aad49..44549a032 100644 --- a/include/boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp +++ b/include/boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp @@ -93,9 +93,9 @@ public : return true; } - static inline bool result(flags const& state) + static inline int result(flags const& state) { - return state.inside_flag; + return state.inside_flag ? 1 : -1; } }; diff --git a/include/boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp b/include/boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp index 664b3475c..807d5fd25 100644 --- a/include/boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp +++ b/include/boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp @@ -85,9 +85,9 @@ public : return true; } - static inline bool result(crossings const& state) + static inline int result(crossings const& state) { - return state.crosses; + return state.crosses ? 1 : -1; } }; diff --git a/include/boost/geometry/strategies/centroid.hpp b/include/boost/geometry/strategies/centroid.hpp index 5c4396074..be3b1d33f 100644 --- a/include/boost/geometry/strategies/centroid.hpp +++ b/include/boost/geometry/strategies/centroid.hpp @@ -12,6 +12,9 @@ #include +#include + +#include #include @@ -19,6 +22,17 @@ namespace boost { namespace geometry { +namespace strategy { namespace centroid +{ + +struct not_applicable_strategy +{ +}; + + +namespace services +{ + /*! \brief Traits class binding a centroid calculation strategy to a coordinate system \ingroup centroid @@ -36,11 +50,40 @@ template typename Point, typename Geometry > -struct strategy_centroid +struct default_strategy { - typedef strategy::not_implemented type; + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPES + , (types) + ); }; +// Register NA-strategy for all where not applicable +template +struct default_strategy +{ + typedef not_applicable_strategy type; +}; + +template +struct default_strategy +{ + typedef not_applicable_strategy type; +}; + +template +struct default_strategy +{ + typedef not_applicable_strategy type; +}; + + +} // namespace services + + +}} // namespace strategy::centroid + }} // namespace boost::geometry diff --git a/include/boost/geometry/strategies/concepts/within_concept.hpp b/include/boost/geometry/strategies/concepts/within_concept.hpp index f99f8787d..e52465864 100644 --- a/include/boost/geometry/strategies/concepts/within_concept.hpp +++ b/include/boost/geometry/strategies/concepts/within_concept.hpp @@ -50,8 +50,8 @@ class WithinStrategy // having a point, two segment-points, and state str->apply(*p, *sp, *sp, *st); - // 5) must implement a method result - bool r = str->result(*st); + // 5) must implement a method result returning int + int r = str->result(*st); boost::ignore_unused_variable_warning(r); boost::ignore_unused_variable_warning(str); diff --git a/include/boost/geometry/strategies/point_in_poly.hpp b/include/boost/geometry/strategies/point_in_poly.hpp deleted file mode 100644 index 773eff7f6..000000000 --- a/include/boost/geometry/strategies/point_in_poly.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) -// -// Copyright Barend Gehrels 2007-2009, Geodan, Amsterdam, the Netherlands. -// Copyright Bruno Lalande 2008, 2009 -// 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_POINT_IN_POLY_HPP -#define BOOST_GEOMETRY_STRATEGIES_POINT_IN_POLY_HPP - -#include - -namespace boost { namespace geometry -{ - - -/*! - \brief Traits class binding a within determination strategy to a coordinate system - \ingroup within - \tparam TagPoint tag of coordinate system of point-type - \tparam TagSegment tag of coordinate system of segment-type - \tparam Point point-type of input points - \tparam PointOfSegment point-type of input segment-points -*/ -template -struct strategy_within -{ - typedef strategy::not_implemented type; -}; - - - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_STRATEGIES_POINT_IN_POLY_HPP diff --git a/include/boost/geometry/strategies/spherical/area_huiller.hpp b/include/boost/geometry/strategies/spherical/area_huiller.hpp index 1190ff2da..289d8527e 100644 --- a/include/boost/geometry/strategies/spherical/area_huiller.hpp +++ b/include/boost/geometry/strategies/spherical/area_huiller.hpp @@ -143,20 +143,25 @@ private : double m_radius; }; +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + template + struct default_strategy + { + typedef strategy::area::huiller type; + }; + +} // namespace services + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + }} // namespace strategy::area -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - -template -struct strategy_area -{ - typedef strategy::area::huiller type; -}; - -#endif }} // namespace boost::geometry diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index 2828ea218..e8685f978 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -19,9 +19,9 @@ #include #include #include -#include #include #include +#include #include #include diff --git a/include/boost/geometry/strategies/strategy_transform.hpp b/include/boost/geometry/strategies/strategy_transform.hpp index 469550d68..79650cb72 100644 --- a/include/boost/geometry/strategies/strategy_transform.hpp +++ b/include/boost/geometry/strategies/strategy_transform.hpp @@ -277,84 +277,92 @@ struct from_cartesian_3_to_spherical_3 } }; -}} // namespace strategy::transform - - #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace services +{ + /// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied template -struct strategy_transform +struct default_strategy { - typedef strategy::transform::copy_direct

type; + typedef copy_direct

type; }; /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate template -struct strategy_transform +struct default_strategy { - typedef strategy::transform::copy_per_coordinate type; + typedef copy_per_coordinate type; }; /// Specialization to convert from degree to radian for any coordinate system / point type combination template class CoordSys, typename P1, typename P2> -struct strategy_transform, CoordSys, 2, 2, P1, P2> +struct default_strategy, CoordSys, 2, 2, P1, P2> { - typedef strategy::transform::degree_radian_vv type; + typedef degree_radian_vv type; }; /// Specialization to convert from radian to degree for any coordinate system / point type combination template class CoordSys, typename P1, typename P2> -struct strategy_transform, CoordSys, 2, 2, P1, P2> +struct default_strategy, CoordSys, 2, 2, P1, P2> { - typedef strategy::transform::degree_radian_vv type; + typedef degree_radian_vv type; }; /// Specialization degree->radian in 3D template class CoordSys, typename P1, typename P2> -struct strategy_transform, CoordSys, 3, 3, P1, P2> +struct default_strategy, CoordSys, 3, 3, P1, P2> { - typedef strategy::transform::degree_radian_vv_3 type; + typedef degree_radian_vv_3 type; }; /// Specialization radian->degree in 3D template class CoordSys, typename P1, typename P2> -struct strategy_transform, CoordSys, 3, 3, P1, P2> +struct default_strategy, CoordSys, 3, 3, P1, P2> { - typedef strategy::transform::degree_radian_vv_3 type; + typedef degree_radian_vv_3 type; }; /// Specialization to convert from unit sphere(phi,theta) to XYZ template -struct strategy_transform +struct default_strategy { - typedef strategy::transform::from_spherical_2_to_cartesian_3 type; + typedef from_spherical_2_to_cartesian_3 type; }; /// Specialization to convert from sphere(phi,theta,r) to XYZ template -struct strategy_transform +struct default_strategy { - typedef strategy::transform::from_spherical_3_to_cartesian_3 type; + typedef from_spherical_3_to_cartesian_3 type; }; /// Specialization to convert from XYZ to unit sphere(phi,theta) template -struct strategy_transform +struct default_strategy { - typedef strategy::transform::from_cartesian_3_to_spherical_2 type; + typedef from_cartesian_3_to_spherical_2 type; }; /// Specialization to convert from XYZ to sphere(phi,theta,r) template -struct strategy_transform +struct default_strategy { - typedef strategy::transform::from_cartesian_3_to_spherical_3 type; + typedef from_cartesian_3_to_spherical_3 type; }; + +} // namespace services + + #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace strategy::transform + + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP diff --git a/include/boost/geometry/strategies/transform.hpp b/include/boost/geometry/strategies/transform.hpp index 35282d972..c5987e8b2 100644 --- a/include/boost/geometry/strategies/transform.hpp +++ b/include/boost/geometry/strategies/transform.hpp @@ -11,11 +11,16 @@ #include +#include + #include namespace boost { namespace geometry { +namespace strategy { namespace transform { namespace services +{ + /*! \brief Traits class binding a transformation strategy to a coordinate system \ingroup transform @@ -36,11 +41,18 @@ template std::size_t Dimension1, std::size_t Dimension2, typename Point1, typename Point2 > -struct strategy_transform +struct default_strategy { - typedef strategy::not_implemented type; + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPES + , (types) + ); }; +}}} // namespace strategy::transform::services + + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_HPP diff --git a/include/boost/geometry/strategies/transform/map_transformer.hpp b/include/boost/geometry/strategies/transform/map_transformer.hpp index f454962c2..2555404ef 100644 --- a/include/boost/geometry/strategies/transform/map_transformer.hpp +++ b/include/boost/geometry/strategies/transform/map_transformer.hpp @@ -60,7 +60,10 @@ struct map_transformer private : - void set_transformation_point(double wx, double wy, double px, double py, double scalex, double scaley) + template + inline void set_transformation_point(W const& wx, W const& wy, + P const& px, P const& py, + S const& scalex, S const& scaley) { // Translate to a coordinate system centered on world coordinates (-wx, -wy) diff --git a/include/boost/geometry/strategies/within.hpp b/include/boost/geometry/strategies/within.hpp new file mode 100644 index 000000000..8302cec18 --- /dev/null +++ b/include/boost/geometry/strategies/within.hpp @@ -0,0 +1,74 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright Barend Gehrels 2007-2009, Geodan, Amsterdam, the Netherlands. +// Copyright Bruno Lalande 2008, 2009 +// 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_WITHIN_HPP +#define BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP + +#include + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace within +{ + +struct not_applicable_strategy +{ +}; + + +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 +*/ +template +< + typename TagContained, + typename TagContaining, + typename CsTagContained, + typename CsTagContaining, + typename Point, + typename PointContaining +> +struct default_strategy +{ + // If we would assert here, we would have to implement + // default strategies for all combinations, all CS, etc. + // This explosion is not convenient. + // Another option is tag inheritance / grouping (so point-in-polygon will apply for point-in-ring, point-in-polygon, point-in-multi-polygon but not for point-in-box...) + // TODO: decide about this. + + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TYPES + , (types) + ); + + + //typedef strategy::not_implemented type; +}; + + +} // namespace services + + +}} // namespace strategy::within + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP