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]
This commit is contained in:
Barend Gehrels
2010-11-08 10:18:33 +00:00
parent 2c830be09a
commit c3c238623d
57 changed files with 2412 additions and 780 deletions

View File

@@ -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<Geometry>::type area(Geometry const& geometry)
{
concept::check<Geometry const>();
typedef typename area_result<Geometry>::strategy_type strategy_type;
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
return dispatch::area
<

View File

@@ -408,7 +408,7 @@ inline void centroid(Geometry const& geometry, Point& c)
{
concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
typedef typename strategy_centroid
typedef typename strategy::centroid::services::default_strategy
<
typename cs_tag<Geometry>::type,
typename tag<Geometry>::type,

View File

@@ -102,7 +102,7 @@ struct correct_ring
{
typedef typename point_type<Ring>::type point_type;
typedef typename strategy_area
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::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<Ring>::value;
closure_selector const s = geometry::closure<Ring>::value;
if (disjoint && (s == closed))
{
@@ -132,8 +132,8 @@ struct correct_ring
}
if (! disjoint && geometry::closure<Ring>::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 <typename Tag, typename Geometry>
struct correct
struct correct
{
BOOST_MPL_ASSERT_MSG
(
@@ -188,18 +188,18 @@ struct correct
};
template <typename Point>
struct correct<point_tag, Point>
: detail::correct::correct_nop<Point>
struct correct<point_tag, Point>
: detail::correct::correct_nop<Point>
{};
template <typename LineString>
struct correct<linestring_tag, LineString>
struct correct<linestring_tag, LineString>
: detail::correct::correct_nop<LineString>
{};
template <typename Segment>
struct correct<segment_tag, Segment>
: detail::correct::correct_nop<Segment>
struct correct<segment_tag, Segment>
: detail::correct::correct_nop<Segment>
{};

View File

@@ -19,6 +19,7 @@
#include <boost/geometry/algorithms/detail/overlay/convert_ring.hpp>
#include <boost/geometry/algorithms/detail/overlay/add_to_containment.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
//#include <boost/geometry/strategies/intersection_result.hpp>
@@ -29,6 +30,8 @@
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
# include <boost/geometry/util/write_dsv.hpp>
@@ -44,6 +47,81 @@ namespace detail { namespace overlay
{
template<typename Tag, typename Point, typename Geometry>
struct within_code
{};
template<typename Point, typename Box>
struct within_code<box_tag, Point, Box>
{
static inline int apply(Point const& point, Box const& box)
{
// 1. Check outside
if (get<0>(point) < get<min_corner, 0>(box)
|| get<0>(point) > get<max_corner, 0>(box)
|| get<1>(point) < get<min_corner, 1>(box)
|| get<1>(point) > get<max_corner, 1>(box))
{
return -1;
}
// 2. Check border
if (geometry::math::equals(get<0>(point), get<min_corner, 0>(box))
|| geometry::math::equals(get<0>(point), get<max_corner, 0>(box))
|| geometry::math::equals(get<1>(point), get<min_corner, 1>(box))
|| geometry::math::equals(get<1>(point), get<max_corner, 1>(box)))
{
return 0;
}
return 1;
}
};
template<typename Point, typename Ring>
struct within_code<ring_tag, Point, Ring>
{
static inline int apply(Point const& point, Ring const& ring)
{
// Same as point_in_ring but here ALWAYS with winding.
typedef strategy::within::winding<Point> strategy_type;
return detail::within::point_in_ring
<
Point,
Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value,
strategy_type
>::apply(point, ring, strategy_type());
}
};
template<typename Point, typename Geometry>
inline int point_in_ring(Point const& point, Geometry const& geometry)
{
return within_code<typename geometry::tag<Geometry>::type, Point, Geometry>
::apply(point, geometry);
}
template<typename Point, typename Geometry>
inline bool within_or_touch(Point const& point, Geometry const& geometry)
{
return within_code<typename geometry::tag<Geometry>::type, Point, Geometry>
::apply(point, geometry) >= 0;
}
// Skip for assemble process
template <typename TurnInfo>
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 <typename TurnPoints, typename Map>
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<container_type const>::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<tag1>::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<tag2>::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<tag3>::apply(item1.ring_id, collection));
}
return false;
else
{
return false;
}
return code == 0 ? item1.area < 0 : code == 1;
}
template <typename Selection, typename Map>
@@ -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)

View File

@@ -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 <cstddef>
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template<typename Turn>
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 <typename MetaTurn>
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 <typename MetaTurns, typename MetaTurn>
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 <typename TurnPoints>
inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
bool error = false;
int index = 0;
std::vector<meta_turn<turn_point_type> > meta_turns;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
++it, ++index)
{
meta_turns.push_back(meta_turn<turn_point_type>(index, *it));
}
int cycle = 0;
for (typename boost::range_iterator<std::vector<meta_turn<turn_point_type> > > ::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

View File

@@ -42,11 +42,18 @@ namespace detail { namespace copy_segments
template <typename Ring, typename SegmentIdentifier, typename RangeOut>
struct copy_segments_ring
{
typedef closeable_view
<
Ring const,
closure<Ring>::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<Ring const>::type iterator;
view_type view(ring);
typedef typename boost::range_iterator<view_type const>::type iterator;
typedef geometry::ever_circling_iterator<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<Ring>::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<ring_tag, Ring, SegmentIdentifier, RangeOut, Order>
>
{};
template
<
typename Polygon,
@@ -236,9 +242,6 @@ struct copy_segments<box_tag, Box, SegmentIdentifier, RangeOut, Order>
#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

View File

@@ -12,12 +12,15 @@
#include <cstddef>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
//#ifdef BOOST_GEOMETRY_DEBUG_OVERLAY
#include <iostream>
#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
//#endif
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <iostream>
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
# include <boost/geometry/extensions/gis/io/wkt/wkt.hpp>
# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
#endif
#include <boost/assert.hpp>
#include <boost/range.hpp>
@@ -28,6 +31,12 @@
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_relative_order.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
namespace boost { namespace geometry
{
@@ -36,210 +45,146 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename Operation>
struct indexed_operation
// Wraps "turn_operation" from turn_info.hpp,
// giving it extra information
template <typename TurnOperation>
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 <typename IndexedTurnOperation>
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<Geometry1>::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<point_type>::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<Geometry1>::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 <typename Point, typename Operation, typename Geometry1, typename Geometry2>
inline bool swap_operations(Operation const& left, Operation const& right,
Geometry1 const& geometry1, Geometry2 const& geometry2)
template<typename Turns, typename Operations>
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<Operations>::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<Point>::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<Container const>::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<Container>::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<Geometry1>::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<IndexType>(begin_cluster, it, turn_points,
for_operation, geometry1, geometry2, strategy);
begin_cluster = boost::end(operations);
}
}
if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType>(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<IndexType> 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<Container const>::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<double>(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 <typename IndexedType, typename TurnPoints, typename MappedVector>
inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vector)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
int index = 0;
for (typename boost::range_iterator<TurnPoints const>::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<container_type const>::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<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
typedef typename boost::range_value<container_type>::type operation_type;
typedef detail::overlay::indexed_operation<operation_type> 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<indexed_type>
std::vector<indexed_turn_operation>
> 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<TurnPoints const>::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<TurnPoints>::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<container_type const>::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<indexed_turn_operation>(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<indexed_type>(mit->second, turn_points,
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-sort Ring "
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<indexed_turn_operation>(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<indexed_turn_operation>(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<indexed_turn_operation>(mit->second, turn_points, for_operation,
geometry1, geometry2, strategy);
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
//detail::overlay::check_graph(turn_points, for_operation);
#endif
}

View File

@@ -50,7 +50,6 @@
#include <boost/geometry/algorithms/combine.hpp>
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/algorithms/within.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
@@ -90,6 +89,28 @@ template
>
class get_turns_in_sections
{
typedef closeable_view
<
typename range_type<Geometry1>::type const,
closure<Geometry1>::value == open
> view_type1;
typedef closeable_view
<
typename range_type<Geometry2>::type const,
closure<Geometry2>::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<view_type1>(geometry1, sec1);
view_type2 view2 = get_full_section<view_type2>(geometry2, sec2);
typedef typename boost::range_iterator
<
typename geometry::range_type<Geometry1>::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<Geometry2>::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<range1_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<range2_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 <typename RangeIterator, typename Section, typename Geometry, typename Box>
static inline RangeIterator get_start_point_iterator(Section & section,
RangeIterator& it, RangeIterator& prev, RangeIterator& end,
template <typename Range, typename Section, typename Box>
static inline void get_start_point_iterator(Section & section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
typename boost::range_iterator<Range const>::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;
}
};

View File

@@ -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 <algorithm>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
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<Geometry1> 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<Geometry1>::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<Geometry1>::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<const point_type> segment_type;
typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
segment_type,
segment_type,
segment_intersection_points<point_type>
>
> 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<point_type> pr = policy::apply(p, r);
segment_intersection_points<point_type> 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<Geometry1>::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<std::pair<operation_type, operation_type>, 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<IndexType>(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

View File

@@ -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

View File

@@ -69,7 +69,7 @@ struct ring_properties
{
has_point = geometry::point_on_border(point, geometry, true);
typedef typename coordinate_type<Geometry>::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;
}

View File

@@ -24,11 +24,9 @@
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>

View File

@@ -36,6 +36,25 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename Turn, typename Operation>
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 <typename Turns>
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<Turns>::type & ip,
typename boost::range_iterator<Turns>::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<Order>(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<Order>(geometry1, geometry2,
if (! detail::overlay::assign_next_ip<Order>(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);
}
}

View File

@@ -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
;
}
};

View File

@@ -27,8 +27,7 @@ struct ring_identifier
: source_index(src)
, multi_index(mul)
, ring_index(rin)
{
}
{}
inline bool operator<(ring_identifier const& other) const
{

View File

@@ -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 <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/iterators/range_type.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/util/closeable_view.hpp>
@@ -30,31 +29,42 @@ namespace detail { namespace section
{
template <typename Range, typename Section, typename Iterator>
template <typename Range, typename Section>
struct full_section_range
{
static inline void apply(Range const& range, Section const& section,
Iterator& begin, Iterator& end)
typedef closeable_view
<
Range const,
closure<Range>::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 <typename Polygon, typename Section, typename Iterator>
template <typename Polygon, typename Section>
struct full_section_polygon
{
static inline void apply(Polygon const& polygon, Section const& section,
Iterator& begin, Iterator& end)
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef closeable_view
<
ring_type const,
closure<ring_type>::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<Polygon>::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 <typename LineString, typename Section, typename Iterator>
struct get_full_section<linestring_tag, LineString, Section, Iterator>
: detail::section::full_section_range<LineString, Section, Iterator>
template <typename LineString, typename Section>
struct get_full_section<linestring_tag, LineString, Section>
: detail::section::full_section_range<LineString, Section>
{};
template <typename Ring, typename Section, typename Iterator>
struct get_full_section<ring_tag, Ring, Section, Iterator>
: detail::section::full_section_range<Ring, Section, Iterator>
template <typename Ring, typename Section>
struct get_full_section<ring_tag, Ring, Section>
: detail::section::full_section_range<Ring, Section>
{};
template <typename Polygon, typename Section, typename Iterator>
struct get_full_section<polygon_tag, Polygon, Section, Iterator>
: detail::section::full_section_polygon<Polygon, Section, Iterator>
template <typename Polygon, typename Section>
struct get_full_section<polygon_tag, Polygon, Section>
: detail::section::full_section_polygon<Polygon, Section>
{};
@@ -108,42 +117,28 @@ struct get_full_section<polygon_tag, Polygon, Section, Iterator>
/*!
\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 <typename Geometry, typename Section>
inline void get_full_section(Geometry const& geometry, Section const& section,
typename boost::range_iterator
<
typename geometry::range_type<Geometry>::type const
>::type& begin,
typename boost::range_iterator
<
typename geometry::range_type<Geometry>::type const
>::type& end)
template <typename Range, typename Geometry, typename Section>
inline Range get_full_section(Geometry const& geometry, Section const& section)
{
concept::check<Geometry const>();
typedef typename boost::range_iterator
<
typename geometry::range_type<Geometry>::type const
>::type iterator_type;
dispatch::get_full_section
return dispatch::get_full_section
<
typename tag<Geometry>::type,
Geometry,
Section,
iterator_type
>::apply(geometry, section, begin, end);
Section
>::apply(geometry, section);
}

View File

@@ -9,149 +9,50 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP
// OBSOLETE
/***
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/iterators/range_type.hpp>
#include <boost/geometry/util/add_const_if_c.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// Generic case (linestring/linear ring)
template <typename Tag, typename Geometry, typename Section, bool IsConst>
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<Geometry>::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 <typename Polygon, typename Section, bool IsConst>
struct get_section<polygon_tag, Polygon, Section, IsConst>
{
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<Polygon>::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<Polygon>::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 <typename Geometry, typename Section>
inline void get_section(Geometry const& geometry, Section const& section,
typename boost::range_iterator
<
typename geometry::range_type<Geometry>::type const
>::type& begin,
typename boost::range_iterator
<
typename geometry::range_type<Geometry>::type const
>::type& end)
{
concept::check<Geometry const>();
dispatch::get_section
<
typename tag<Geometry>::type,
Geometry,
Section,
true
>::apply(geometry, section, begin, end);
template <typename Range, typename Section>
inline void get_section(Range const& range, Section const& section,
typename boost::range_iterator<Range const>::type& begin,
typename boost::range_iterator<Range const>::type& end)
{
begin = boost::begin(range) + section.begin_index;
end = boost::begin(range) + section.end_index + 1;
}
// non const version
template <typename Geometry, typename Section>
inline void get_section(Geometry& geometry, Section const& section,
typename boost::range_iterator
<
typename geometry::range_type<Geometry>::type
>::type& begin,
typename boost::range_iterator
<
typename geometry::range_type<Geometry>::type
>::type& end)
template <typename Range, typename Section>
inline void get_section(Range& range, Section const& section,
typename boost::range_iterator<Range>::type& begin,
typename boost::range_iterator<Range>::type& end)
{
concept::check<Geometry>();
dispatch::get_section
<
typename tag<Geometry>::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

View File

@@ -19,12 +19,14 @@
#include <boost/geometry/algorithms/combine.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/closeable_view.hpp>
#include <boost/geometry/geometries/segment.hpp>
@@ -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<T, DimensionCount, DimensionCount>
/// @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<Point const> segment_type;
typedef typename boost::range_value<Sections>::type section_type;
typedef typename boost::range_iterator<Range const>::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<Point const> 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<Polygon>::type ring_type;
typedef sectionalize_range
<
ring_type, point_type, Sections, DimensionCount, MaxCount
ring_type, closure<Polygon>::value,
point_type, Sections, DimensionCount, MaxCount
> sectionalizer_type;
typedef typename boost::range_iterator
@@ -457,7 +470,7 @@ struct sectionalize_box
sectionalize_range
<
std::vector<point_type>,
std::vector<point_type>, closed,
point_type,
Sections,
DimensionCount,
@@ -539,7 +552,7 @@ struct sectionalize
>
: detail::sectionalize::sectionalize_range
<
LineString,
LineString, closed,
typename point_type<LineString>::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<ring_tag, Range, Sections, DimensionCount, MaxCount>
struct sectionalize<ring_tag, Ring, Sections, DimensionCount, MaxCount>
: detail::sectionalize::sectionalize_range
<
Range,
typename point_type<Range>::type,
Ring, geometry::closure<Ring>::value,
typename point_type<Ring>::type,
Sections,
DimensionCount,
MaxCount

View File

@@ -76,18 +76,26 @@ struct dissolve_ring_or_polygon
typename cs_tag<Geometry>::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<point_order<Geometry>::value>(geometry, geometry,
traverse<point_order<Geometry>::value>(geometry, geometry,
detail::overlay::operation_union,
turns, rings);
clear_visit_info(turns);
traverse<point_order<Geometry>::value>(geometry, geometry,
enrich_intersection_points(turns,
detail::overlay::operation_intersection,
geometry, geometry,
side_strategy_type());
traverse<point_order<Geometry>::value>(geometry, geometry,
detail::overlay::operation_intersection,
turns, rings);

View File

@@ -14,9 +14,13 @@
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/is_linear.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -31,16 +35,29 @@ namespace detail { namespace num_points
template <typename Range>
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<Range>::value;
if (s == open)
{
if (geometry::disjoint(*boost::begin(range), *(boost::begin(range) + n - 1)))
{
return n + 1;
}
}
}
return n;
}
};
template <typename Geometry, std::size_t D>
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 <typename Polygon>
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<Polygon>::type ring_type;
std::size_t n = range_count<ring_type>::apply(
exterior_ring(poly), add_for_open);
typedef typename boost::range_iterator
<
typename interior_type<Polygon>::type const
@@ -61,7 +82,7 @@ struct polygon_count
it != boost::end(interior_rings(poly));
++it)
{
n += boost::size(*it);
n += range_count<ring_type>::apply(*it, add_for_open);
}
return n;
@@ -138,7 +159,7 @@ struct num_points<polygon_tag, false, Geometry>
\qbk{compliance,__ogc__}
*/
template <typename Geometry>
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<Geometry const>();
@@ -147,7 +168,7 @@ inline std::size_t num_points(Geometry const& geometry)
typename tag<Geometry>::type,
is_linear<Geometry>::value,
Geometry
>::apply(geometry);
>::apply(geometry, add_for_open);
}
}} // namespace boost::geometry

View File

@@ -167,16 +167,16 @@ struct transform_polygon
template <typename Point1, typename Point2>
struct select_strategy
{
typedef typename strategy_transform
typedef typename strategy::transform::services::default_strategy
<
typename cs_tag<Point1>::type,
typename cs_tag<Point2>::type,
typename coordinate_system<Point1>::type,
typename coordinate_system<Point2>::type,
dimension<Point1>::type::value,
dimension<Point2>::type::value,
typename point_type<Point1>::type,
typename point_type<Point2>::type
typename cs_tag<Point1>::type,
typename cs_tag<Point2>::type,
typename coordinate_system<Point1>::type,
typename coordinate_system<Point2>::type,
dimension<Point1>::type::value,
dimension<Point2>::type::value,
typename point_type<Point1>::type,
typename point_type<Point2>::type
>::type type;
};

View File

@@ -25,7 +25,7 @@
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/point_in_poly.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/concepts/within_concept.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
#include <boost/geometry/util/closeable_view.hpp>
@@ -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<Point, Box>();
if (get<Dimension>(p) <= get<min_corner, Dimension>(b)
|| get<Dimension>(p) >= get<max_corner, Dimension>(b))
{
return false;
return -1;
}
return point_in_box
@@ -85,9 +85,9 @@ template
>
struct point_in_box<Point, Box, Strategy, DimensionCount, DimensionCount>
{
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<Box1, Box2>();
if (get<min_corner, Dimension>(b1) <= get<min_corner, Dimension>(b2)
|| get<max_corner, Dimension>(b1) >= get<max_corner, Dimension>(b2))
{
return false;
return -1;
}
return box_in_box
@@ -132,9 +132,9 @@ template
>
struct box_in_box<Box1, Box2, Strategy, DimensionCount, DimensionCount>
{
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<Strategy>) );
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<Ring const, Direction> 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<Strategy>) );
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<Polygon>::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<Polygon>::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<Polygon>::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<Geometry1>::type point_type1;
typedef typename point_type<Geometry2>::type point_type2;
typedef typename strategy_within
typedef typename strategy::within::services::default_strategy
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename cs_tag<point_type1>::type,
typename cs_tag<point_type2>::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

View File

@@ -23,7 +23,7 @@
#include <boost/geometry/algorithms/detail/buffer/linestring_buffer.hpp>
#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
#include <boost/geometry/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/dissolve.hpp>
@@ -91,7 +91,11 @@ void sectionalizing_buffer(Geometry const& geometry,
iterator_type begin, end;
typedef std::pair<iterator_type, iterator_type> 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

View File

@@ -23,8 +23,6 @@
#include <boost/geometry/extensions/algorithms/buffer/linestring_buffer.hpp>
#include <boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp>
#include <boost/geometry/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/dissolve.hpp>

View File

@@ -2,10 +2,11 @@
#define TTMATH_STUB
#include <boost/math/constants/constants.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/util/math.hpp>
#include <ttmath/ttmath.h>
#include <ttmath.h>
namespace ttmath
{
template <uint Exponent, uint Mantissa>
@@ -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<int, ttmath::Big<Exponent, Mantissa>, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker>
{
static inline int convert(ttmath::Big<Exponent, Mantissa> 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<double, ttmath::Big<Exponent, Mantissa>, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker>
{
static inline double convert(ttmath::Big<Exponent, Mantissa> arg)
{
double v;
arg.ToDouble(v);
return v;
}
};
template
<
typename Traits,
typename OverflowHandler,
typename Float2IntRounder,
typename RawConverter,
typename UserRangeChecker
>
struct converter<int, ttmath_big, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker>
{
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<double, ttmath_big, Traits, OverflowHandler, Float2IntRounder, RawConverter, UserRangeChecker>
{
static inline double convert(ttmath_big arg)
{
double v;
arg.ToDouble(v);
return v;
}
};
}}
#endif

View File

@@ -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<PointOfSegment, CalculationType>(radius)
{}
};
}} // namespace strategy::area
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
template <typename Point>
struct strategy_area<geographic_tag, Point>
namespace services
{
typedef strategy::area::huiller_earth<Point> type;
template <typename Point>
struct default_strategy<geographic_tag, Point>
{
typedef huiller_earth<Point> type;
};
} // namespace services
#endif
}} // namespace strategy::area
}} // namespace boost::geometry

View File

@@ -114,6 +114,104 @@ struct closure< linear_ring<P, V, PointOrder, false, A> >
} // 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<typename, typename> class Container = std::vector,
template<typename> class Allocator = std::allocator
>
class linear_ring : public Container<Point, Allocator<Point> >
{
BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );
};
} // namespace model
#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
namespace traits
{
template
<
typename Point,
bool ClockWise, bool Closed,
template<typename, typename> class Container,
template<typename> class Allocator
>
struct tag<model::linear_ring<Point, ClockWise, Closed, Container, Allocator> >
{
typedef ring_tag type;
};
template
<
typename Point,
bool Closed,
template<typename, typename> class Container,
template<typename> class Allocator
>
struct point_order<model::linear_ring<Point, false, Closed, Container, Allocator> >
{
static const order_selector value = counterclockwise;
};
template
<
typename Point,
bool Closed,
template<typename, typename> class Container,
template<typename> class Allocator
>
struct point_order<model::linear_ring<Point, true, Closed, Container, Allocator> >
{
static const order_selector value = clockwise;
};
template
<
typename Point,
bool PointOrder,
template<typename, typename> class Container,
template<typename> class Allocator
>
struct closure<model::linear_ring<Point, PointOrder, true, Container, Allocator> >
{
static const closure_selector value = closed;
};
template
<
typename Point,
bool PointOrder,
template<typename, typename> class Container,
template<typename> class Allocator
>
struct closure<model::linear_ring<Point, PointOrder, false, Container, Allocator> >
{
static const closure_selector value = open;
};
} // namespace traits
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_GEOMETRIES_LINEAR_RING_HPP

View File

@@ -139,7 +139,7 @@ template
typename Point,
template<typename, typename> class PointList,
template<typename, typename> class RingList,
bool ClockWise, bool Closed,
bool ClockWise, bool Closed,
template<typename> class PointAlloc,
template<typename> class RingAlloc
>
@@ -187,6 +187,179 @@ struct interior_rings< polygon<Point, PointList, RingList, ClockWise, Closed, Po
} // namespace traits
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
// NEW APPROACH
namespace model
{
/*!
\brief The \b polygon contains an outer ring and zero or more inner rings.
\ingroup geometries
\tparam P point type
\tparam PointList optional container type for points,
for example std::vector, std::list, std::deque
\tparam RingList optional container type for inner rings,
for example std::vector, std::list, std::deque
\tparam ClockWise optional parameter, true for clockwise direction,
false for CounterClockWise direction
\tparam Closed optional parameter, true for closed polygons (last point == first point),
false open points
\tparam PointAlloc container-allocator-type
\tparam RingAlloc container-allocator-type
\note The container collecting the points in the rings can be different
from the container collecting the inner rings. They all default to vector.
*/
template
<
typename Point,
bool ClockWise = true,
bool Closed = true,
template<typename, typename> class PointList = std::vector,
template<typename, typename> class RingList = std::vector,
template<typename> class PointAlloc = std::allocator,
template<typename> class RingAlloc = std::allocator
>
class polygon
{
BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );
public:
// Member types
typedef Point point_type;
typedef linear_ring<Point, ClockWise, Closed, PointList, PointAlloc> ring_type;
typedef RingList<ring_type , RingAlloc<ring_type > > 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<typename, typename> class PointList,
template<typename, typename> class RingList,
template<typename> class PointAlloc,
template<typename> class RingAlloc
>
struct tag<model::polygon<Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc> >
{
typedef polygon_tag type;
};
template
<
typename Point,
bool ClockWise, bool Closed,
template<typename, typename> class PointList,
template<typename, typename> class RingList,
template<typename> class PointAlloc,
template<typename> class RingAlloc
>
struct ring_type<model::polygon<Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc> >
{
typedef typename model::polygon
<
Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc
>::ring_type type;
};
template
<
typename Point,
bool ClockWise, bool Closed,
template<typename, typename> class PointList,
template<typename, typename> class RingList,
template<typename> class PointAlloc,
template<typename> class RingAlloc
>
struct interior_type<model::polygon<Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc> >
{
typedef typename model::polygon
<
Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc
>::inner_container_type type;
};
template
<
typename Point,
bool ClockWise, bool Closed,
template<typename, typename> class PointList,
template<typename, typename> class RingList,
template<typename> class PointAlloc,
template<typename> class RingAlloc
>
struct exterior_ring<model::polygon<Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc> >
{
typedef model::polygon<Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc> 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<typename, typename> class PointList,
template<typename, typename> class RingList,
template<typename> class PointAlloc,
template<typename> class RingAlloc
>
struct interior_rings<model::polygon<Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc> >
{
typedef model::polygon<Point, ClockWise, Closed, PointList, RingList, PointAlloc, RingAlloc> 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

View File

@@ -58,10 +58,6 @@
#include <boost/geometry/algorithms/unique.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
// check includes all concepts
#include <boost/geometry/geometries/concepts/check.hpp>

View File

@@ -10,7 +10,7 @@
#include <boost/range.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_categories.hpp>
@@ -28,65 +28,120 @@ namespace boost { namespace geometry
*/
template <typename Range>
struct closing_iterator
: public boost::iterator_adaptor
: public boost::iterator_facade
<
closing_iterator<Range>,
typename boost::range_iterator<Range>::type,
boost::use_default,
boost::forward_traversal_tag
typename boost::range_value<Range>::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<Range>& operator=(closing_iterator<Range> 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<Range>::type const& dereference() const
{
return *m_iterator;
}
inline difference_type distance_to(closing_iterator<Range> const& other) const
{
return other.m_index - this->m_index;
}
inline bool equal(closing_iterator<Range> 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<Range>::type m_iterator;
typename boost::range_iterator<Range>::type m_end;
difference_type m_size;
difference_type m_index;
};

View File

@@ -15,7 +15,6 @@
#include <boost/geometry/multi/algorithms/distance.hpp>
#include <boost/geometry/multi/iterators/range_type.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>
@@ -58,7 +57,7 @@ struct get_turns_multi_polygon_cs
typename boost::range_value<Multi>::type,
Box,
Turns, TurnPolicy, InterruptPolicy
>::apply(source_id1, *it, source_id2, box,
>::apply(source_id1, *it, source_id2, box,
turns, interrupt_policy, i);
}
}

View File

@@ -13,6 +13,7 @@
#include <boost/range.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/multi/core/ring_type.hpp>
#include <boost/geometry/algorithms/detail/sections/get_full_section.hpp>
@@ -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<MultiGeometry>::type ring_type;
typedef closeable_view
<
ring_type const,
closure<MultiGeometry>::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 <typename MultiPolygon, typename Section, typename Iterator>
struct get_full_section<multi_polygon_tag, MultiPolygon, Section, Iterator>
template <typename MultiPolygon, typename Section>
struct get_full_section<multi_polygon_tag, MultiPolygon, Section>
: detail::section::full_section_multi
<
MultiPolygon,
Section,
Iterator,
detail::section::full_section_polygon
<
typename boost::range_value<MultiPolygon>::type,
Section,
Iterator
Section
>
>
{};

View File

@@ -10,6 +10,8 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP
// OBSOLETE
/*
#include <boost/assert.hpp>
#include <boost/concept/requires.hpp>
#include <boost/range.hpp>
@@ -71,5 +73,6 @@ struct get_section<multi_polygon_tag, MultiPolygon, Section, IsConst>
}} // namespace boost::geometry
*/
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_GET_SECTION_HPP

View File

@@ -20,7 +20,6 @@
#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/add_to_containment.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/get_full_section.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>

View File

@@ -28,7 +28,7 @@ namespace detail { namespace num_points
template <typename MultiGeometry>
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<MultiGeometry>::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<geometry_type>::type,
geometry::is_linear<geometry_type>::value,
geometry_type
>::apply(*it);
>::apply(*it, add_for_open);
}
return n;
}

View File

@@ -20,7 +20,6 @@
#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/add_to_containment.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/get_full_section.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>

View File

@@ -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;
}
};

View File

@@ -43,7 +43,6 @@
#include <boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp>
#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/get_section.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp>

View File

@@ -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 <typename Point, typename Geometry>
struct strategy_centroid<cartesian_tag, multi_point_tag, 2, Point, Geometry>
struct default_strategy<cartesian_tag, multi_point_tag, 2, Point, Geometry>
{
typedef strategy::centroid_::centroid_average
typedef centroid_average
<
Point,
typename point_type<Geometry>::type
> type;
};
} // namespace services
#endif
}} // namespace strategy::centroid
}} // namespace boost::geometry

View File

@@ -18,20 +18,24 @@ namespace boost { namespace geometry
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace centroid { namespace services
{
template <typename Point, typename Geometry>
struct strategy_centroid<cartesian_tag, multi_polygon_tag, 2, Point, Geometry>
struct default_strategy<cartesian_tag, multi_polygon_tag, 2, Point, Geometry>
{
typedef strategy::centroid_::bashein_detmer
typedef bashein_detmer
<
Point,
typename point_type<Geometry>::type
> type;
};
#endif
}}} // namespace strategy::centroid::services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace boost::geometry

View File

@@ -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 <boost/logic/tribool.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/point_in_poly.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/within.hpp>
// TEMP!
#include <boost/geometry/multi/core/tags.hpp>
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<D>(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 <typename Point, typename PointOfSegment>
struct strategy_within<cartesian_tag, cartesian_tag, Point, PointOfSegment>
namespace services
{
typedef strategy::within::winding<Point, PointOfSegment> type;
template <typename Point, typename PointOfSegment>
struct default_strategy<point_tag, polygon_tag, cartesian_tag, cartesian_tag, Point, PointOfSegment>
{
typedef winding<Point, PointOfSegment> type;
};
template <typename Point, typename PointOfSegment>
struct strategy_within<geographic_tag, geographic_tag, Point, PointOfSegment>
struct default_strategy<point_tag, ring_tag, cartesian_tag, cartesian_tag, Point, PointOfSegment>
{
typedef strategy::within::winding<Point, PointOfSegment> type;
typedef winding<Point, PointOfSegment> type;
};
template <typename Point, typename PointOfSegment>
struct default_strategy<point_tag, polygon_tag, spherical_tag, spherical_tag, Point, PointOfSegment>
{
typedef winding<Point, PointOfSegment> type;
};
// TEMP!
// register it even for the multi here, and for the box
// future: use tag inheritance, see elsewhere
template <typename Point, typename PointOfSegment>
struct default_strategy<point_tag, multi_polygon_tag, cartesian_tag, cartesian_tag, Point, PointOfSegment>
{
typedef winding<Point, PointOfSegment> type;
};
template <typename Point, typename PointOfSegment>
struct default_strategy<point_tag, multi_polygon_tag, spherical_tag, spherical_tag, Point, PointOfSegment>
{
typedef winding<Point, PointOfSegment> type;
};
template <typename Point, typename PointOfSegment>
struct default_strategy<point_tag, box_tag, cartesian_tag, cartesian_tag, Point, PointOfSegment>
{
typedef winding<Point, PointOfSegment> type;
};
template <typename Point, typename PointOfSegment>
struct default_strategy<point_tag, box_tag, spherical_tag, spherical_tag, Point, PointOfSegment>
{
typedef winding<Point, PointOfSegment> type;
};
} // namespace services
#endif
}} // namespace strategy::within
}} // namespace boost::geometry

View File

@@ -9,26 +9,37 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_AREA_HPP
#define BOOST_GEOMETRY_STRATEGIES_AREA_HPP
#include <boost/geometry/strategies/tags.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/strategies/tags.hpp>
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 <typename Tag, typename PointOfSegment>
struct strategy_area
struct default_strategy
{
typedef strategy::not_implemented type;
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE
, (types<PointOfSegment>)
);
};
}}} // namespace strategy::area::services
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AREA_HPP

View File

@@ -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 <typename Geometry>
struct area_result
{
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy_area
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type

View File

@@ -92,18 +92,24 @@ public :
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point>
struct default_strategy<cartesian_tag, Point>
{
typedef strategy::area::by_triangles<Point> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::area
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
template <typename Point>
struct strategy_area<cartesian_tag, Point>
{
typedef strategy::area::by_triangles<Point> type;
};
#endif
}} // namespace boost::geometry

View File

@@ -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,

View File

@@ -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 <typename Point, typename Geometry>
struct strategy_centroid<cartesian_tag, ring_tag, 2, Point, Geometry>
struct default_strategy<cartesian_tag, ring_tag, 2, Point, Geometry>
{
typedef strategy::centroid_::bashein_detmer
typedef bashein_detmer
<
Point,
typename point_type<Geometry>::type
@@ -222,16 +221,23 @@ struct strategy_centroid<cartesian_tag, ring_tag, 2, Point, Geometry>
};
template <typename Point, typename Geometry>
struct strategy_centroid<cartesian_tag, polygon_tag, 2, Point, Geometry>
struct default_strategy<cartesian_tag, polygon_tag, 2, Point, Geometry>
{
typedef strategy::centroid_::bashein_detmer
typedef bashein_detmer
<
Point,
typename point_type<Geometry>::type
> type;
};
#endif
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::centroid
}} // namespace boost::geometry

View File

@@ -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;
}
};

View File

@@ -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;
}
};

View File

@@ -12,6 +12,9 @@
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/tags.hpp>
@@ -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<Point, Geometry>)
);
};
// Register NA-strategy for all where not applicable
template <typename Point, typename Geometry, std::size_t Dimension>
struct default_strategy<cartesian_tag, point_tag, Dimension, Point, Geometry>
{
typedef not_applicable_strategy type;
};
template <typename Point, typename Geometry, std::size_t Dimension>
struct default_strategy<cartesian_tag, box_tag, Dimension, Point, Geometry>
{
typedef not_applicable_strategy type;
};
template <typename Point, typename Geometry, std::size_t Dimension>
struct default_strategy<cartesian_tag, linestring_tag, Dimension, Point, Geometry>
{
typedef not_applicable_strategy type;
};
} // namespace services
}} // namespace strategy::centroid
}} // namespace boost::geometry

View File

@@ -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);

View File

@@ -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 <boost/geometry/strategies/tags.hpp>
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 <typename TagPoint, typename TagSegment, typename Point, typename PointOfSegment>
struct strategy_within
{
typedef strategy::not_implemented type;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_POINT_IN_POLY_HPP

View File

@@ -143,20 +143,25 @@ private :
double m_radius;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point>
struct default_strategy<spherical_tag, Point>
{
typedef strategy::area::huiller<Point> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::area
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
template <typename Point>
struct strategy_area<spherical_tag, Point>
{
typedef strategy::area::huiller<Point> type;
};
#endif
}} // namespace boost::geometry

View File

@@ -19,9 +19,9 @@
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/parse.hpp>
#include <boost/geometry/strategies/point_in_poly.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/transform.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/cartesian/area_by_triangles.hpp>
#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>

View File

@@ -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 <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
struct strategy_transform<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
{
typedef strategy::transform::copy_direct<P> type;
typedef copy_direct<P> type;
};
/// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
struct strategy_transform<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
{
typedef strategy::transform::copy_per_coordinate<P1, P2> type;
typedef copy_per_coordinate<P1, P2> type;
};
/// Specialization to convert from degree to radian for any coordinate system / point type combination
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct strategy_transform<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
{
typedef strategy::transform::degree_radian_vv<P1, P2, std::multiplies> type;
typedef degree_radian_vv<P1, P2, std::multiplies> type;
};
/// Specialization to convert from radian to degree for any coordinate system / point type combination
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct strategy_transform<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
{
typedef strategy::transform::degree_radian_vv<P1, P2, std::divides> type;
typedef degree_radian_vv<P1, P2, std::divides> type;
};
/// Specialization degree->radian in 3D
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct strategy_transform<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
{
typedef strategy::transform::degree_radian_vv_3<P1, P2, std::multiplies> type;
typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
};
/// Specialization radian->degree in 3D
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct strategy_transform<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
{
typedef strategy::transform::degree_radian_vv_3<P1, P2, std::divides> type;
typedef degree_radian_vv_3<P1, P2, std::divides> type;
};
/// Specialization to convert from unit sphere(phi,theta) to XYZ
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct strategy_transform<spherical_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
struct default_strategy<spherical_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
{
typedef strategy::transform::from_spherical_2_to_cartesian_3<P1, P2> type;
typedef from_spherical_2_to_cartesian_3<P1, P2> type;
};
/// Specialization to convert from sphere(phi,theta,r) to XYZ
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct strategy_transform<spherical_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
struct default_strategy<spherical_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
{
typedef strategy::transform::from_spherical_3_to_cartesian_3<P1, P2> type;
typedef from_spherical_3_to_cartesian_3<P1, P2> type;
};
/// Specialization to convert from XYZ to unit sphere(phi,theta)
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct strategy_transform<cartesian_tag, spherical_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
struct default_strategy<cartesian_tag, spherical_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
{
typedef strategy::transform::from_cartesian_3_to_spherical_2<P1, P2> type;
typedef from_cartesian_3_to_spherical_2<P1, P2> type;
};
/// Specialization to convert from XYZ to sphere(phi,theta,r)
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct strategy_transform<cartesian_tag, spherical_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
struct default_strategy<cartesian_tag, spherical_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
{
typedef strategy::transform::from_cartesian_3_to_spherical_3<P1, P2> type;
typedef from_cartesian_3_to_spherical_3<P1, P2> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::transform
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP

View File

@@ -11,11 +11,16 @@
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/strategies/tags.hpp>
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<Point1, Point2>)
);
};
}}} // namespace strategy::transform::services
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_HPP

View File

@@ -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 <typename W, typename P, typename S>
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)

View File

@@ -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 <boost/mpl/assert.hpp>
#include <boost/geometry/strategies/tags.hpp>
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<Point, PointContaining>)
);
//typedef strategy::not_implemented type;
};
} // namespace services
}} // namespace strategy::within
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP