mirror of
https://github.com/boostorg/geometry.git
synced 2026-01-29 07:32:17 +00:00
Merge pull request #780 from barendgehrels/fix/sort-by-side-point-at-turn
Fix/sort by side point at turn
This commit is contained in:
@@ -29,7 +29,6 @@
|
||||
#include <boost/geometry/core/static_assert.hpp>
|
||||
#include <boost/geometry/core/tags.hpp>
|
||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
|
||||
#include <boost/geometry/util/range.hpp>
|
||||
#include <boost/geometry/views/closeable_view.hpp>
|
||||
#include <boost/geometry/views/reversible_view.hpp>
|
||||
@@ -43,12 +42,22 @@ namespace boost { namespace geometry
|
||||
namespace detail { namespace copy_segments
|
||||
{
|
||||
|
||||
inline signed_size_type circular_offset(signed_size_type segment_count, signed_size_type index,
|
||||
signed_size_type offset)
|
||||
{
|
||||
signed_size_type result = (index + offset) % segment_count;
|
||||
if (result < 0)
|
||||
{
|
||||
result += segment_count;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
|
||||
struct copy_segment_point_range
|
||||
{
|
||||
static inline bool apply(Range const& range,
|
||||
SegmentIdentifier const& seg_id, int offset,
|
||||
SegmentIdentifier const& seg_id, signed_size_type offset,
|
||||
PointOut& point)
|
||||
{
|
||||
typedef typename closeable_view
|
||||
@@ -66,15 +75,13 @@ struct copy_segment_point_range
|
||||
cview_type cview(range);
|
||||
rview_type view(cview);
|
||||
|
||||
typedef typename boost::range_iterator<rview_type>::type iterator;
|
||||
geometry::ever_circling_iterator<iterator> it(boost::begin(view), boost::end(view),
|
||||
boost::begin(view) + seg_id.segment_index, true);
|
||||
std::size_t const segment_count = boost::size(view) - 1;
|
||||
signed_size_type const target = circular_offset(segment_count, seg_id.segment_index, offset);
|
||||
|
||||
for (signed_size_type i = 0; i < offset; ++i, ++it)
|
||||
{
|
||||
}
|
||||
BOOST_GEOMETRY_ASSERT(target >= 0);
|
||||
BOOST_GEOMETRY_ASSERT(target < boost::size(view));
|
||||
geometry::convert(range::at(view, target), point);
|
||||
|
||||
geometry::convert(*it, point);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -84,7 +91,7 @@ template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename P
|
||||
struct copy_segment_point_polygon
|
||||
{
|
||||
static inline bool apply(Polygon const& polygon,
|
||||
SegmentIdentifier const& seg_id, int offset,
|
||||
SegmentIdentifier const& seg_id, signed_size_type offset,
|
||||
PointOut& point)
|
||||
{
|
||||
// Call ring-version with the right ring
|
||||
@@ -110,18 +117,17 @@ template <typename Box, bool Reverse, typename SegmentIdentifier, typename Point
|
||||
struct copy_segment_point_box
|
||||
{
|
||||
static inline bool apply(Box const& box,
|
||||
SegmentIdentifier const& seg_id, int offset,
|
||||
SegmentIdentifier const& seg_id, signed_size_type offset,
|
||||
PointOut& point)
|
||||
{
|
||||
signed_size_type index = seg_id.segment_index;
|
||||
for (int i = 0; i < offset; i++)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
|
||||
boost::array<typename point_type<Box>::type, 4> bp;
|
||||
assign_box_corners_oriented<Reverse>(box, bp);
|
||||
point = bp[index % 4];
|
||||
|
||||
signed_size_type const target = circular_offset(4, seg_id.segment_index, offset);
|
||||
BOOST_GEOMETRY_ASSERT(target >= 0);
|
||||
BOOST_GEOMETRY_ASSERT(target < bp.size());
|
||||
|
||||
point = bp[target];
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -137,10 +143,9 @@ template
|
||||
struct copy_segment_point_multi
|
||||
{
|
||||
static inline bool apply(MultiGeometry const& multi,
|
||||
SegmentIdentifier const& seg_id, int offset,
|
||||
SegmentIdentifier const& seg_id, signed_size_type offset,
|
||||
PointOut& point)
|
||||
{
|
||||
|
||||
BOOST_GEOMETRY_ASSERT
|
||||
(
|
||||
seg_id.multi_index >= 0
|
||||
@@ -278,16 +283,13 @@ struct copy_segment_point
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\brief Helper function, copies a point from a segment
|
||||
\ingroup overlay
|
||||
*/
|
||||
template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
|
||||
inline bool copy_segment_point(Geometry const& geometry,
|
||||
SegmentIdentifier const& seg_id, int offset,
|
||||
SegmentIdentifier const& seg_id, signed_size_type offset,
|
||||
PointOut& point_out)
|
||||
{
|
||||
concepts::check<Geometry const>();
|
||||
@@ -316,7 +318,7 @@ template
|
||||
typename PointOut
|
||||
>
|
||||
inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
|
||||
SegmentIdentifier const& seg_id, int offset,
|
||||
SegmentIdentifier const& seg_id, signed_size_type offset,
|
||||
PointOut& point_out)
|
||||
{
|
||||
concepts::check<Geometry1 const>();
|
||||
@@ -399,7 +401,6 @@ inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geo
|
||||
}
|
||||
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
|
||||
|
||||
@@ -119,13 +119,12 @@ struct get_ring<multi_polygon_tag>
|
||||
|
||||
|
||||
template <typename Geometry>
|
||||
inline std::size_t segment_count_on_ring(Geometry const& geometry,
|
||||
segment_identifier const& seg_id)
|
||||
inline std::size_t segment_count_on_ring(Geometry const& geometry, segment_identifier const& seg_id)
|
||||
{
|
||||
typedef typename geometry::tag<Geometry>::type tag;
|
||||
ring_identifier const rid(0, seg_id.multi_index, seg_id.ring_index);
|
||||
// A closed polygon, a triangle of 4 points, including starting point,
|
||||
// contains 3 segments. So handle as if closed and subtract one.
|
||||
// contains 3 segments. So handle as if it is closed, and subtract one.
|
||||
return geometry::num_points(detail::overlay::get_ring<tag>::apply(rid, geometry), true) - 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -831,7 +831,7 @@ inline bool fill_sbs(Sbs& sbs, Point& turn_point,
|
||||
}
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
sbs.add(turn.operations[i], turn_index, i, geometry1, geometry2, first);
|
||||
sbs.add(turn, turn.operations[i], turn_index, i, geometry1, geometry2, first);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
|
||||
// Internal struct to uniquely identify a segment
|
||||
// on a linestring,ring
|
||||
// or polygon (needs ring_index)
|
||||
// or multi-geometry (needs multi_index)
|
||||
// It is always used for clockwise indication (even if the original is anticlockwise)
|
||||
struct segment_identifier
|
||||
{
|
||||
inline segment_identifier()
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
|
||||
|
||||
#include <boost/geometry/util/condition.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_coordinate_type.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
@@ -66,6 +69,8 @@ struct ranked_point
|
||||
, seg_id(si)
|
||||
{}
|
||||
|
||||
using point_type = Point;
|
||||
|
||||
Point point;
|
||||
rank_type rank;
|
||||
signed_size_type zone; // index of closed zone, in uu turn there would be 2 zones
|
||||
@@ -252,12 +257,14 @@ public :
|
||||
, m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Operation>
|
||||
void add_segment_from(signed_size_type turn_index, int op_index,
|
||||
Point const& point_from,
|
||||
operation_type op, segment_identifier const& si,
|
||||
Operation const& op,
|
||||
bool is_origin)
|
||||
{
|
||||
m_ranked_points.push_back(rp(point_from, turn_index, op_index, dir_from, op, si));
|
||||
m_ranked_points.push_back(rp(point_from, turn_index, op_index,
|
||||
dir_from, op.operation, op.seg_id));
|
||||
if (is_origin)
|
||||
{
|
||||
m_origin = point_from;
|
||||
@@ -265,46 +272,104 @@ public :
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Operation>
|
||||
void add_segment_to(signed_size_type turn_index, int op_index,
|
||||
Point const& point_to,
|
||||
operation_type op, segment_identifier const& si)
|
||||
Operation const& op)
|
||||
{
|
||||
m_ranked_points.push_back(rp(point_to, turn_index, op_index, dir_to, op, si));
|
||||
m_ranked_points.push_back(rp(point_to, turn_index, op_index,
|
||||
dir_to, op.operation, op.seg_id));
|
||||
}
|
||||
|
||||
template <typename Operation>
|
||||
void add_segment(signed_size_type turn_index, int op_index,
|
||||
Point const& point_from, Point const& point_to,
|
||||
operation_type op, segment_identifier const& si,
|
||||
bool is_origin)
|
||||
Operation const& op, bool is_origin)
|
||||
{
|
||||
add_segment_from(turn_index, op_index, point_from, op, si, is_origin);
|
||||
add_segment_to(turn_index, op_index, point_to, op, si);
|
||||
add_segment_from(turn_index, op_index, point_from, op, is_origin);
|
||||
add_segment_to(turn_index, op_index, point_to, op);
|
||||
}
|
||||
|
||||
// Returns true if two points are approximately equal, tuned by a giga-epsilon constant
|
||||
// (if constant is 1.0, for type double, the boundary is about 1.0e-7)
|
||||
template <typename Point1, typename Point2, typename T>
|
||||
static inline bool approximately_equals(Point1 const& a, Point2 const& b,
|
||||
T const& limit_giga_epsilon)
|
||||
{
|
||||
// Including distance would introduce cyclic dependencies.
|
||||
using coor_t = typename select_coordinate_type<Point1, Point2>::type;
|
||||
using calc_t = typename geometry::select_most_precise <coor_t, T>::type;
|
||||
constexpr calc_t machine_giga_epsilon = 1.0e9 * std::numeric_limits<calc_t>::epsilon();
|
||||
|
||||
calc_t const& a0 = geometry::get<0>(a);
|
||||
calc_t const& b0 = geometry::get<0>(b);
|
||||
calc_t const& a1 = geometry::get<1>(a);
|
||||
calc_t const& b1 = geometry::get<1>(b);
|
||||
calc_t const one = 1.0;
|
||||
calc_t const c = math::detail::greatest(a0, b0, a1, b1, one);
|
||||
|
||||
// The maximum limit is avoid, for floating point, large limits like 400
|
||||
// (which are be calculated using eps)
|
||||
constexpr calc_t maxlimit = 1.0e-3;
|
||||
auto const limit = (std::min)(maxlimit, limit_giga_epsilon * machine_giga_epsilon * c);
|
||||
return std::abs(a0 - b0) <= limit && std::abs(a1 - b1) <= limit;
|
||||
}
|
||||
|
||||
template <typename Operation, typename Geometry1, typename Geometry2>
|
||||
Point add(Operation const& op, signed_size_type turn_index, int op_index,
|
||||
static Point walk_over_ring(Operation const& op, int offset,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2)
|
||||
{
|
||||
Point point;
|
||||
geometry::copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, op.seg_id, offset, point);
|
||||
return point;
|
||||
}
|
||||
|
||||
template <typename Turn, typename Operation, typename Geometry1, typename Geometry2>
|
||||
Point add(Turn const& turn, Operation const& op, signed_size_type turn_index, int op_index,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
bool is_origin)
|
||||
{
|
||||
Point point1, point2, point3;
|
||||
Point point_from, point2, point3;
|
||||
geometry::copy_segment_points<Reverse1, Reverse2>(geometry1, geometry2,
|
||||
op.seg_id, point1, point2, point3);
|
||||
Point const& point_to = op.fraction.is_one() ? point3 : point2;
|
||||
add_segment(turn_index, op_index, point1, point_to, op.operation, op.seg_id, is_origin);
|
||||
return point1;
|
||||
op.seg_id, point_from, point2, point3);
|
||||
Point point_to = op.fraction.is_one() ? point3 : point2;
|
||||
|
||||
|
||||
// If the point is in the neighbourhood (the limit itself is not important),
|
||||
// then take a point (or more) further back.
|
||||
// The limit of offset avoids theoretical infinite loops. In practice it currently
|
||||
// walks max 1 point back in all cases.
|
||||
int offset = 0;
|
||||
while (approximately_equals(point_from, turn.point, 1.0) && offset > -10)
|
||||
{
|
||||
point_from = walk_over_ring(op, --offset, geometry1, geometry2);
|
||||
}
|
||||
|
||||
// Similarly for the point to, walk forward
|
||||
offset = 0;
|
||||
while (approximately_equals(point_to, turn.point, 1.0) && offset < 10)
|
||||
{
|
||||
point_to = walk_over_ring(op, ++offset, geometry1, geometry2);
|
||||
}
|
||||
|
||||
add_segment(turn_index, op_index, point_from, point_to, op, is_origin);
|
||||
|
||||
return point_from;
|
||||
}
|
||||
|
||||
template <typename Operation, typename Geometry1, typename Geometry2>
|
||||
void add(Operation const& op, signed_size_type turn_index, int op_index,
|
||||
template <typename Turn, typename Operation, typename Geometry1, typename Geometry2>
|
||||
void add(Turn const& turn,
|
||||
Operation const& op, signed_size_type turn_index, int op_index,
|
||||
segment_identifier const& departure_seg_id,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
bool check_origin)
|
||||
bool is_departure)
|
||||
{
|
||||
Point const point1 = add(op, turn_index, op_index, geometry1, geometry2, false);
|
||||
Point potential_origin = add(turn, op, turn_index, op_index, geometry1, geometry2, false);
|
||||
|
||||
if (check_origin)
|
||||
if (is_departure)
|
||||
{
|
||||
bool const is_origin
|
||||
= op.seg_id.source_index == departure_seg_id.source_index
|
||||
@@ -317,7 +382,7 @@ public :
|
||||
if (m_origin_count == 0 ||
|
||||
segment_distance < m_origin_segment_distance)
|
||||
{
|
||||
m_origin = point1;
|
||||
m_origin = potential_origin;
|
||||
m_origin_segment_distance = segment_distance;
|
||||
}
|
||||
m_origin_count++;
|
||||
@@ -325,25 +390,33 @@ public :
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Operation, typename Geometry1, typename Geometry2>
|
||||
static signed_size_type segment_count_on_ring(Operation const& op,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2)
|
||||
{
|
||||
// Take wrap into account
|
||||
// Suppose point_count=10 (10 points, 9 segments), dep.seg_id=7, op.seg_id=2,
|
||||
// then distance=9-7+2=4, being segments 7,8,0,1
|
||||
return op.seg_id.source_index == 0
|
||||
? detail::overlay::segment_count_on_ring(geometry1, op.seg_id)
|
||||
: detail::overlay::segment_count_on_ring(geometry2, op.seg_id);
|
||||
}
|
||||
|
||||
template <typename Operation, typename Geometry1, typename Geometry2>
|
||||
static signed_size_type calculate_segment_distance(Operation const& op,
|
||||
segment_identifier const& departure_seg_id,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2)
|
||||
{
|
||||
BOOST_ASSERT(op.seg_id.source_index == departure_seg_id.source_index);
|
||||
signed_size_type result = op.seg_id.segment_index - departure_seg_id.segment_index;
|
||||
if (op.seg_id.segment_index >= departure_seg_id.segment_index)
|
||||
{
|
||||
// dep.seg_id=5, op.seg_id=7, distance=2, being segments 5,6
|
||||
return op.seg_id.segment_index - departure_seg_id.segment_index;
|
||||
return result;
|
||||
}
|
||||
// Take wrap into account
|
||||
// Suppose point_count=10 (10 points, 9 segments), dep.seg_id=7, op.seg_id=2,
|
||||
// then distance=9-7+2=4, being segments 7,8,0,1
|
||||
std::size_t const segment_count
|
||||
= op.seg_id.source_index == 0
|
||||
? segment_count_on_ring(geometry1, op.seg_id)
|
||||
: segment_count_on_ring(geometry2, op.seg_id);
|
||||
return segment_count - departure_seg_id.segment_index + op.seg_id.segment_index;
|
||||
return segment_count_on_ring(op, geometry1, geometry2) + result;
|
||||
}
|
||||
|
||||
void apply(Point const& turn_point)
|
||||
|
||||
@@ -748,7 +748,8 @@ public :
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
sbs.add(cluster_turn.operations[i],
|
||||
sbs.add(cluster_turn,
|
||||
cluster_turn.operations[i],
|
||||
cluster_turn_index, i, previous_seg_id,
|
||||
m_geometry1, m_geometry2,
|
||||
departure_turn);
|
||||
@@ -823,7 +824,8 @@ public :
|
||||
// Add this turn to the sort-by-side sorter
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
sbs.add(current_turn.operations[i],
|
||||
sbs.add(current_turn,
|
||||
current_turn.operations[i],
|
||||
turn_index, i, previous_seg_id,
|
||||
m_geometry1, m_geometry2,
|
||||
true);
|
||||
|
||||
@@ -346,7 +346,8 @@ static std::string const nores_wn_2
|
||||
// Other cases with wrong turn information
|
||||
static std::string const nores_wt_1
|
||||
= "MULTIPOLYGON(((0 4,0 5,1 4,0 4)),((9 3,9 4,10 4,9 3)),((9 7,10 8,10 7,9 7)),((6 7,7 8,7 7,6 7)),((0 7,0 8,1 8,0 7)),((3 6,4 6,4 5,3 4,3 6)),((3 7,2 6,2 7,3 7)),((3 7,3 8,4 8,4 7,3 7)),((3 3,4 4,4 3,3 3)),((3 3,3 2,2 2,2 3,3 3)),((2 6,2 5,1 5,1 6,2 6)),((6 4,6 3,5 3,5 4,6 4)),((6 4,7 5,7 4,6 4)),((5 1,4 0,4 1,5 1)),((5 1,5 2,6 2,6 1,5 1)))";
|
||||
|
||||
static std::string const nores_wt_2
|
||||
= "MULTIPOLYGON(((1 1,2 2,2 1,1 1)),((0 2,0 3,1 3,0 2)),((4 3,5 4,5 3,4 3)),((4 3,3 3,4 4,4 3)))";
|
||||
|
||||
static std::string const neighbouring
|
||||
= "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((10 10,10 20,20 20,20 10,10 10)))";
|
||||
@@ -558,23 +559,18 @@ void test_all()
|
||||
test_one<multi_polygon_type, polygon_type>("nores_mt_6", nores_mt_6, join_round32, end_flat, 16.9018, 1.0);
|
||||
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_1", nores_et_1, join_round32, end_flat, 18.9866, 1.0);
|
||||
|
||||
#if defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_2", nores_et_2, join_round32, end_flat, 23.8389, 1.0);
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_3", nores_et_3, join_round32, end_flat, 26.9030, 1.0);
|
||||
#endif
|
||||
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_4", nores_et_4, join_round32, end_flat, 19.9626, 1.0);
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_5", nores_et_5, join_round32, end_flat, 19.9615, 1.0);
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_6", nores_et_6, join_round32, end_flat, 96.1795, 1.0);
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_7", nores_et_7, join_round32, end_flat, 105.9577, 1.0);
|
||||
|
||||
test_one<multi_polygon_type, polygon_type>("nores_wn_1", nores_wn_1, join_round32, end_flat, 23.7659, 1.0);
|
||||
test_one<multi_polygon_type, polygon_type>("nores_wn_2", nores_wn_2, join_round32, end_flat, 18.2669, 1.0);
|
||||
|
||||
#if defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_6", nores_et_6, join_round32, end_flat, 96.1795, 1.0);
|
||||
test_one<multi_polygon_type, polygon_type>("nores_et_7", nores_et_7, join_round32, end_flat, 105.9577, 1.0);
|
||||
test_one<multi_polygon_type, polygon_type>("nores_wt_1", nores_wt_1, join_round32, end_flat, 80.1609, 1.0);
|
||||
#endif
|
||||
test_one<multi_polygon_type, polygon_type>("nores_wt_2", nores_wt_2, join_round32, end_flat, 22.1102, 1.0);
|
||||
|
||||
test_one<multi_polygon_type, polygon_type>("neighbouring_small",
|
||||
neighbouring,
|
||||
@@ -619,7 +615,7 @@ int test_main(int, char* [])
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
|
||||
BoostGeometryWriteExpectedFailures(1, 8, 2, 7);
|
||||
BoostGeometryWriteExpectedFailures(1, 1, 2, 3);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -207,7 +207,7 @@ private :
|
||||
}
|
||||
#endif
|
||||
|
||||
bg::model::ring<point_type> const& corner = piece.m_piece_border.get_full_ring();
|
||||
auto const& corner = piece.m_piece_border.get_full_ring();
|
||||
|
||||
if (m_zoom && do_pieces)
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
test-suite boost-geometry-algorithms-overlay
|
||||
:
|
||||
[ run assemble.cpp : : : : algorithms_assemble ]
|
||||
[ run copy_segment_point.cpp : : : : algorithms_copy_segment_point ]
|
||||
[ run get_turn_info.cpp : : : : algorithms_get_turn_info ]
|
||||
[ run get_turns.cpp : : : : algorithms_get_turns ]
|
||||
[ run get_turns_areal_areal.cpp : : : : algorithms_get_turns_areal_areal ]
|
||||
|
||||
132
test/algorithms/overlay/copy_segment_point.cpp
Normal file
132
test/algorithms/overlay/copy_segment_point.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
// Boost.Geometry
|
||||
// Unit Test
|
||||
|
||||
// Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <geometry_test_common.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/strategies.hpp>
|
||||
#include <boost/geometry/algorithms/disjoint.hpp>
|
||||
#include <boost/geometry/geometries/geometries.hpp>
|
||||
#include <boost/geometry/io/wkt/wkt.hpp>
|
||||
|
||||
template <typename Geometry, typename GetRing>
|
||||
void test_basic(GetRing get_ring, std::string const& case_id, int line,
|
||||
std::string const& wkt, bg::segment_identifier const& id,
|
||||
int offset, std::size_t expected_index)
|
||||
{
|
||||
using point_type = typename bg::point_type<Geometry>::type;
|
||||
|
||||
Geometry geometry;
|
||||
bg::read_wkt(wkt, geometry);
|
||||
|
||||
// Check the result
|
||||
auto ring = get_ring(geometry);
|
||||
|
||||
point_type point;
|
||||
bg::copy_segment_point<false>(geometry, id, offset, point);
|
||||
|
||||
// Sanity check
|
||||
bool const expectation_in_range = expected_index < ring.size();
|
||||
BOOST_CHECK_MESSAGE(expectation_in_range, "Expectation out of range " << expected_index);
|
||||
if (! expectation_in_range)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
point_type const expected_point = ring[expected_index];
|
||||
|
||||
bool const equal = ! bg::disjoint(point, expected_point);
|
||||
|
||||
BOOST_CHECK_MESSAGE(equal, "copy_segment_point: " << case_id
|
||||
<< " line " << line << " at index " << expected_index
|
||||
<< " not as expected: "
|
||||
<< bg::wkt(point) << " vs " << bg::wkt(expected_point));
|
||||
}
|
||||
|
||||
template <typename Geometry, typename GetRing>
|
||||
void test_geometry(std::string const& case_id, std::string const& wkt, GetRing get_ring)
|
||||
{
|
||||
// Check zero offset, all segment ids
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, {0, 0, -1, 0}, 0, 0);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, {0, 0, -1, 1}, 0, 1);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, {0, 0, -1, 2}, 0, 2);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, {0, 0, -1, 3}, 0, 3);
|
||||
|
||||
// Check positive offsets, it should endlessly loop around, regardless of direction or closure
|
||||
bg::segment_identifier const start{0, 0, -1, 0};
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, 1, 1);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, 2, 2);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, 3, 3);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, 4, 0);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, 5, 1);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, 6, 2);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, 7, 3);
|
||||
|
||||
// Check negative offsets
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, -1, 3);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, -2, 2);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, -3, 1);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, -4, 0);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, -5, 3);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, -6, 2);
|
||||
test_basic<Geometry>(get_ring, case_id, __LINE__, wkt, start, -7, 1);
|
||||
}
|
||||
|
||||
template <typename T, bool Closed>
|
||||
void test_all(std::string const& case_id, std::string const& wkt)
|
||||
{
|
||||
using point_type = bg::model::point<T, 2, bg::cs::cartesian>;
|
||||
using polygon_type = bg::model::polygon<point_type, true, Closed>;
|
||||
|
||||
test_geometry<polygon_type>(case_id, wkt, [](polygon_type const& polygon)
|
||||
{
|
||||
return bg::exterior_ring(polygon);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void test_box(std::string const& case_id, std::string const& wkt)
|
||||
{
|
||||
using point_type = bg::model::point<T, 2, bg::cs::cartesian>;
|
||||
using box_type = bg::model::box<point_type>;
|
||||
|
||||
test_geometry<box_type>(case_id, wkt, [](box_type const& box)
|
||||
{
|
||||
boost::array<point_type, 4> ring;
|
||||
bg::detail::assign_box_corners_oriented<false>(box, ring);
|
||||
return ring;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void test_circular_offset()
|
||||
{
|
||||
BOOST_CHECK_EQUAL(3, bg::detail::copy_segments::circular_offset(4, 0, -1));
|
||||
BOOST_CHECK_EQUAL(2, bg::detail::copy_segments::circular_offset(4, 0, -2));
|
||||
BOOST_CHECK_EQUAL(1, bg::detail::copy_segments::circular_offset(4, 0, -3));
|
||||
|
||||
BOOST_CHECK_EQUAL(6, bg::detail::copy_segments::circular_offset(10, 5, 1));
|
||||
BOOST_CHECK_EQUAL(6, bg::detail::copy_segments::circular_offset(10, 5, 11));
|
||||
BOOST_CHECK_EQUAL(6, bg::detail::copy_segments::circular_offset(10, 5, 21));
|
||||
|
||||
BOOST_CHECK_EQUAL(4, bg::detail::copy_segments::circular_offset(10, 5, -1));
|
||||
BOOST_CHECK_EQUAL(4, bg::detail::copy_segments::circular_offset(10, 5, -11));
|
||||
BOOST_CHECK_EQUAL(4, bg::detail::copy_segments::circular_offset(10, 5, -21));
|
||||
}
|
||||
|
||||
int test_main(int, char* [])
|
||||
{
|
||||
test_circular_offset();
|
||||
|
||||
test_all<double, true>("closed", "POLYGON((0 2,1 2,1 1,0 1,0 2))");
|
||||
test_all<double, false>("open", "POLYGON((0 2,1 2,1 1,0 1))");
|
||||
test_box<double>("box", "BOX(0 0,5 5)");
|
||||
return 0;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ std::vector<std::size_t> gather_cluster_properties(
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
turn_operation_type const& op = turn.operations[i];
|
||||
sbs.add(op, turn_index, i, geometry1, geometry2, first);
|
||||
sbs.add(turn, op, turn_index, i, geometry1, geometry2, first);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ std::vector<std::size_t> apply_get_turns(std::string const& case_id,
|
||||
has_origin = true;
|
||||
}
|
||||
|
||||
sbs.add(turn.operations[i], turn_index, i,
|
||||
sbs.add(turn, turn.operations[i], turn_index, i,
|
||||
geometry1, geometry2, is_origin);
|
||||
|
||||
}
|
||||
|
||||
@@ -624,7 +624,7 @@ int test_main(int, char* [])
|
||||
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
|
||||
// Not yet fully tested for float and long double.
|
||||
// The difference algorithm can generate (additional) slivers
|
||||
BoostGeometryWriteExpectedFailures(10, 11, 24, 15);
|
||||
BoostGeometryWriteExpectedFailures(10, 11, 24, 16);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -524,7 +524,7 @@ int test_main(int, char* [])
|
||||
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
|
||||
// Not yet fully tested for float.
|
||||
// The difference algorithm can generate (additional) slivers
|
||||
BoostGeometryWriteExpectedFailures(22, 13, 19, 7);
|
||||
BoostGeometryWriteExpectedFailures(22, 9, 20, 7);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -499,7 +499,7 @@ int test_main(int, char* [])
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
|
||||
BoostGeometryWriteExpectedFailures(9, 3, 2, 1);
|
||||
BoostGeometryWriteExpectedFailures(9, 1, 2, 1);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -489,7 +489,7 @@ int test_main(int, char* [])
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
|
||||
BoostGeometryWriteExpectedFailures(9, 2, 1, 0);
|
||||
BoostGeometryWriteExpectedFailures(9, 0, 3, 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -29,10 +29,6 @@ struct count_set
|
||||
{
|
||||
m_values.insert(static_cast<std::size_t>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "EMPTY" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
count_set(std::size_t value1, std::size_t value2)
|
||||
|
||||
Reference in New Issue
Block a user