summaryrefslogtreecommitdiff
path: root/boost/geometry
diff options
context:
space:
mode:
authorChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
committerChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
commit08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch)
tree7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/geometry
parentbb4dd8289b351fae6b55e303f189127a394a1edd (diff)
downloadboost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.gz
boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.bz2
boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.zip
Imported Upstream version 1.57.0upstream/1.57.0
Diffstat (limited to 'boost/geometry')
-rw-r--r--boost/geometry/algorithms/append.hpp175
-rw-r--r--boost/geometry/algorithms/area.hpp182
-rw-r--r--boost/geometry/algorithms/assign.hpp250
-rw-r--r--boost/geometry/algorithms/buffer.hpp183
-rw-r--r--boost/geometry/algorithms/centroid.hpp434
-rw-r--r--boost/geometry/algorithms/clear.hpp59
-rw-r--r--boost/geometry/algorithms/comparable_distance.hpp69
-rw-r--r--boost/geometry/algorithms/convert.hpp201
-rw-r--r--boost/geometry/algorithms/convex_hull.hpp262
-rw-r--r--boost/geometry/algorithms/correct.hpp100
-rw-r--r--boost/geometry/algorithms/covered_by.hpp414
-rw-r--r--boost/geometry/algorithms/crosses.hpp194
-rw-r--r--boost/geometry/algorithms/detail/assign_box_corners.hpp22
-rw-r--r--boost/geometry/algorithms/detail/assign_indexed_point.hpp2
-rw-r--r--boost/geometry/algorithms/detail/assign_values.hpp164
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp940
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_policies.hpp171
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp954
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_ring.hpp238
-rw-r--r--boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp191
-rw-r--r--boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp88
-rw-r--r--boost/geometry/algorithms/detail/buffer/parallel_continue.hpp33
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_input.hpp98
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp246
-rw-r--r--boost/geometry/algorithms/detail/calculate_null.hpp2
-rw-r--r--boost/geometry/algorithms/detail/calculate_sum.hpp18
-rw-r--r--boost/geometry/algorithms/detail/centroid/translating_transformer.hpp119
-rw-r--r--boost/geometry/algorithms/detail/check_iterator_range.hpp71
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp147
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp250
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp196
-rw-r--r--boost/geometry/algorithms/detail/comparable_distance/implementation.hpp24
-rw-r--r--boost/geometry/algorithms/detail/comparable_distance/interface.hpp363
-rw-r--r--boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp20
-rw-r--r--boost/geometry/algorithms/detail/counting.hpp107
-rw-r--r--boost/geometry/algorithms/detail/course.hpp56
-rw-r--r--boost/geometry/algorithms/detail/disjoint.hpp225
-rw-r--r--boost/geometry/algorithms/detail/disjoint/areal_areal.hpp134
-rw-r--r--boost/geometry/algorithms/detail/disjoint/box_box.hpp114
-rw-r--r--boost/geometry/algorithms/detail/disjoint/implementation.hpp36
-rw-r--r--boost/geometry/algorithms/detail/disjoint/interface.hpp187
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_areal.hpp244
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_linear.hpp174
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp195
-rw-r--r--boost/geometry/algorithms/detail/disjoint/point_box.hpp94
-rw-r--r--boost/geometry/algorithms/detail/disjoint/point_geometry.hpp111
-rw-r--r--boost/geometry/algorithms/detail/disjoint/point_point.hpp112
-rw-r--r--boost/geometry/algorithms/detail/disjoint/segment_box.hpp291
-rw-r--r--boost/geometry/algorithms/detail/distance/backward_compatibility.hpp333
-rw-r--r--boost/geometry/algorithms/detail/distance/box_to_box.hpp60
-rw-r--r--boost/geometry/algorithms/detail/distance/default_strategies.hpp137
-rw-r--r--boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp462
-rw-r--r--boost/geometry/algorithms/detail/distance/implementation.hpp35
-rw-r--r--boost/geometry/algorithms/detail/distance/interface.hpp403
-rw-r--r--boost/geometry/algorithms/detail/distance/is_comparable.hpp45
-rw-r--r--boost/geometry/algorithms/detail/distance/iterator_selector.hpp70
-rw-r--r--boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp147
-rw-r--r--boost/geometry/algorithms/detail/distance/linear_to_linear.hpp123
-rw-r--r--boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp240
-rw-r--r--boost/geometry/algorithms/detail/distance/point_to_geometry.hpp518
-rw-r--r--boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp131
-rw-r--r--boost/geometry/algorithms/detail/distance/segment_to_box.hpp886
-rw-r--r--boost/geometry/algorithms/detail/distance/segment_to_segment.hpp150
-rw-r--r--boost/geometry/algorithms/detail/equals/collect_vectors.hpp43
-rw-r--r--boost/geometry/algorithms/detail/equals/point_point.hpp52
-rw-r--r--boost/geometry/algorithms/detail/extreme_points.hpp520
-rw-r--r--boost/geometry/algorithms/detail/for_each_range.hpp116
-rw-r--r--boost/geometry/algorithms/detail/get_left_turns.hpp487
-rw-r--r--boost/geometry/algorithms/detail/get_max_size.hpp64
-rw-r--r--boost/geometry/algorithms/detail/has_self_intersections.hpp53
-rw-r--r--boost/geometry/algorithms/detail/interior_iterator.hpp71
-rw-r--r--boost/geometry/algorithms/detail/intersection/box_box.hpp54
-rw-r--r--boost/geometry/algorithms/detail/intersection/implementation.hpp22
-rw-r--r--boost/geometry/algorithms/detail/intersection/interface.hpp309
-rw-r--r--boost/geometry/algorithms/detail/intersection/multi.hpp423
-rw-r--r--boost/geometry/algorithms/detail/is_simple/always_simple.hpp83
-rw-r--r--boost/geometry/algorithms/detail/is_simple/areal.hpp141
-rw-r--r--boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp82
-rw-r--r--boost/geometry/algorithms/detail/is_simple/implementation.hpp18
-rw-r--r--boost/geometry/algorithms/detail/is_simple/interface.hpp80
-rw-r--r--boost/geometry/algorithms/detail/is_simple/linear.hpp248
-rw-r--r--boost/geometry/algorithms/detail/is_simple/multipoint.hpp84
-rw-r--r--boost/geometry/algorithms/detail/is_valid/box.hpp86
-rw-r--r--boost/geometry/algorithms/detail/is_valid/complement_graph.hpp239
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp70
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp64
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp68
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp70
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_spikes.hpp139
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp93
-rw-r--r--boost/geometry/algorithms/detail/is_valid/implementation.hpp21
-rw-r--r--boost/geometry/algorithms/detail/is_valid/interface.hpp78
-rw-r--r--boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp144
-rw-r--r--boost/geometry/algorithms/detail/is_valid/linear.hpp125
-rw-r--r--boost/geometry/algorithms/detail/is_valid/multipolygon.hpp297
-rw-r--r--boost/geometry/algorithms/detail/is_valid/pointlike.hpp62
-rw-r--r--boost/geometry/algorithms/detail/is_valid/polygon.hpp376
-rw-r--r--boost/geometry/algorithms/detail/is_valid/ring.hpp173
-rw-r--r--boost/geometry/algorithms/detail/is_valid/segment.hpp61
-rw-r--r--boost/geometry/algorithms/detail/multi_modify.hpp53
-rw-r--r--boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp52
-rw-r--r--boost/geometry/algorithms/detail/multi_sum.hpp52
-rw-r--r--boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp93
-rw-r--r--boost/geometry/algorithms/detail/occupation_info.hpp356
-rw-r--r--boost/geometry/algorithms/detail/overlay/add_rings.hpp35
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp4
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp160
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp58
-rw-r--r--boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp23
-rw-r--r--boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp64
-rw-r--r--boost/geometry/algorithms/detail/overlay/check_enrich.hpp2
-rw-r--r--boost/geometry/algorithms/detail/overlay/convert_ring.hpp21
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp94
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segments.hpp320
-rw-r--r--boost/geometry/algorithms/detail/overlay/do_reverse.hpp47
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp165
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrichment_info.hpp20
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow.hpp292
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp536
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp71
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_relative_order.hpp13
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_ring.hpp37
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp528
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp657
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp329
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp805
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp720
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp422
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp347
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp84
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp571
-rw-r--r--boost/geometry/algorithms/detail/overlay/linear_linear.hpp326
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp76
-rw-r--r--boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp435
-rw-r--r--boost/geometry/algorithms/detail/overlay/segment_identifier.hpp31
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp63
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp117
-rw-r--r--boost/geometry/algorithms/detail/overlay/stream_info.hpp3
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_info.hpp16
-rw-r--r--boost/geometry/algorithms/detail/overlay/traverse.hpp82
-rw-r--r--boost/geometry/algorithms/detail/overlay/turn_info.hpp12
-rw-r--r--boost/geometry/algorithms/detail/overlay/visit_info.hpp54
-rw-r--r--boost/geometry/algorithms/detail/partition.hpp101
-rw-r--r--boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp126
-rw-r--r--boost/geometry/algorithms/detail/point_on_border.hpp64
-rw-r--r--boost/geometry/algorithms/detail/recalculate.hpp231
-rw-r--r--boost/geometry/algorithms/detail/relate/areal_areal.hpp823
-rw-r--r--boost/geometry/algorithms/detail/relate/boundary_checker.hpp134
-rw-r--r--boost/geometry/algorithms/detail/relate/follow_helpers.hpp401
-rw-r--r--boost/geometry/algorithms/detail/relate/less.hpp79
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_areal.hpp1115
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_linear.hpp768
-rw-r--r--boost/geometry/algorithms/detail/relate/point_geometry.hpp205
-rw-r--r--boost/geometry/algorithms/detail/relate/point_point.hpp242
-rw-r--r--boost/geometry/algorithms/detail/relate/relate.hpp339
-rw-r--r--boost/geometry/algorithms/detail/relate/result.hpp1390
-rw-r--r--boost/geometry/algorithms/detail/relate/topology_check.hpp241
-rw-r--r--boost/geometry/algorithms/detail/relate/turns.hpp253
-rw-r--r--boost/geometry/algorithms/detail/ring_identifier.hpp18
-rw-r--r--boost/geometry/algorithms/detail/sections/range_by_section.hpp65
-rw-r--r--boost/geometry/algorithms/detail/sections/sectionalize.hpp450
-rw-r--r--boost/geometry/algorithms/detail/signed_index_type.hpp29
-rw-r--r--boost/geometry/algorithms/detail/single_geometry.hpp95
-rw-r--r--boost/geometry/algorithms/detail/sub_range.hpp113
-rw-r--r--boost/geometry/algorithms/detail/throw_on_empty_input.hpp8
-rw-r--r--boost/geometry/algorithms/detail/turns/compare_turns.hpp113
-rw-r--r--boost/geometry/algorithms/detail/turns/debug_turn.hpp65
-rw-r--r--boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp78
-rw-r--r--boost/geometry/algorithms/detail/turns/print_turns.hpp96
-rw-r--r--boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp62
-rw-r--r--boost/geometry/algorithms/detail/within/point_in_geometry.hpp463
-rw-r--r--boost/geometry/algorithms/detail/within/within_no_turns.hpp221
-rw-r--r--boost/geometry/algorithms/difference.hpp45
-rw-r--r--boost/geometry/algorithms/disjoint.hpp298
-rw-r--r--boost/geometry/algorithms/dispatch/disjoint.hpp70
-rw-r--r--boost/geometry/algorithms/dispatch/distance.hpp82
-rw-r--r--boost/geometry/algorithms/dispatch/is_simple.hpp38
-rw-r--r--boost/geometry/algorithms/dispatch/is_valid.hpp46
-rw-r--r--boost/geometry/algorithms/distance.hpp587
-rw-r--r--boost/geometry/algorithms/envelope.hpp249
-rw-r--r--boost/geometry/algorithms/equals.hpp361
-rw-r--r--boost/geometry/algorithms/expand.hpp158
-rw-r--r--boost/geometry/algorithms/for_each.hpp339
-rw-r--r--boost/geometry/algorithms/intersection.hpp229
-rw-r--r--boost/geometry/algorithms/intersects.hpp44
-rw-r--r--boost/geometry/algorithms/is_simple.hpp16
-rw-r--r--boost/geometry/algorithms/is_valid.hpp16
-rw-r--r--boost/geometry/algorithms/length.hpp161
-rw-r--r--boost/geometry/algorithms/not_implemented.hpp1
-rw-r--r--boost/geometry/algorithms/num_geometries.hpp103
-rw-r--r--boost/geometry/algorithms/num_interior_rings.hpp88
-rw-r--r--boost/geometry/algorithms/num_points.hpp210
-rw-r--r--boost/geometry/algorithms/num_segments.hpp204
-rw-r--r--boost/geometry/algorithms/overlaps.hpp64
-rw-r--r--boost/geometry/algorithms/perimeter.hpp192
-rw-r--r--boost/geometry/algorithms/point_on_surface.hpp327
-rw-r--r--boost/geometry/algorithms/remove_spikes.hpp280
-rw-r--r--boost/geometry/algorithms/reverse.hpp109
-rw-r--r--boost/geometry/algorithms/simplify.hpp410
-rw-r--r--boost/geometry/algorithms/sym_difference.hpp56
-rw-r--r--boost/geometry/algorithms/touches.hpp585
-rw-r--r--boost/geometry/algorithms/transform.hpp251
-rw-r--r--boost/geometry/algorithms/union.hpp263
-rw-r--r--boost/geometry/algorithms/unique.hpp85
-rw-r--r--boost/geometry/algorithms/within.hpp515
-rw-r--r--boost/geometry/arithmetic/arithmetic.hpp27
-rw-r--r--boost/geometry/arithmetic/determinant.hpp2
-rw-r--r--boost/geometry/arithmetic/dot_product.hpp16
-rw-r--r--boost/geometry/core/access.hpp29
-rw-r--r--boost/geometry/core/closure.hpp52
-rw-r--r--boost/geometry/core/coordinate_dimension.hpp20
-rw-r--r--boost/geometry/core/coordinate_system.hpp8
-rw-r--r--boost/geometry/core/coordinate_type.hpp14
-rw-r--r--boost/geometry/core/cs.hpp12
-rw-r--r--boost/geometry/core/exterior_ring.hpp2
-rw-r--r--boost/geometry/core/geometry_id.hpp31
-rw-r--r--boost/geometry/core/interior_rings.hpp13
-rw-r--r--boost/geometry/core/is_areal.hpp5
-rw-r--r--boost/geometry/core/point_order.hpp41
-rw-r--r--boost/geometry/core/point_type.hpp36
-rw-r--r--boost/geometry/core/ring_type.hpp53
-rw-r--r--boost/geometry/core/tag.hpp5
-rw-r--r--boost/geometry/core/tag_cast.hpp4
-rw-r--r--boost/geometry/core/tags.hpp45
-rw-r--r--boost/geometry/core/topological_dimension.hpp13
-rw-r--r--boost/geometry/geometries/adapted/boost_polygon/ring.hpp19
-rw-r--r--boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp2
-rw-r--r--boost/geometry/geometries/concepts/check.hpp110
-rw-r--r--boost/geometry/geometries/concepts/multi_linestring_concept.hpp91
-rw-r--r--boost/geometry/geometries/concepts/multi_point_concept.hpp90
-rw-r--r--boost/geometry/geometries/concepts/multi_polygon_concept.hpp91
-rw-r--r--boost/geometry/geometries/geometries.hpp4
-rw-r--r--boost/geometry/geometries/multi_linestring.hpp80
-rw-r--r--boost/geometry/geometries/multi_point.hpp94
-rw-r--r--boost/geometry/geometries/multi_polygon.hpp77
-rw-r--r--boost/geometry/geometries/point.hpp12
-rw-r--r--boost/geometry/geometries/pointing_segment.hpp143
-rw-r--r--boost/geometry/geometries/register/box.hpp8
-rw-r--r--boost/geometry/geometries/register/linestring.hpp4
-rw-r--r--boost/geometry/geometries/register/multi_linestring.hpp59
-rw-r--r--boost/geometry/geometries/register/multi_point.hpp59
-rw-r--r--boost/geometry/geometries/register/multi_polygon.hpp59
-rw-r--r--boost/geometry/geometries/register/ring.hpp4
-rw-r--r--boost/geometry/geometries/variant.hpp34
-rw-r--r--boost/geometry/geometry.hpp24
-rw-r--r--boost/geometry/index/adaptors/query.hpp88
-rw-r--r--boost/geometry/index/detail/algorithms/bounds.hpp90
-rw-r--r--boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp77
-rw-r--r--boost/geometry/index/detail/algorithms/comparable_distance_far.hpp66
-rw-r--r--boost/geometry/index/detail/algorithms/comparable_distance_near.hpp77
-rw-r--r--boost/geometry/index/detail/algorithms/content.hpp87
-rw-r--r--boost/geometry/index/detail/algorithms/diff_abs.hpp39
-rw-r--r--boost/geometry/index/detail/algorithms/intersection_content.hpp37
-rw-r--r--boost/geometry/index/detail/algorithms/is_valid.hpp88
-rw-r--r--boost/geometry/index/detail/algorithms/margin.hpp169
-rw-r--r--boost/geometry/index/detail/algorithms/minmaxdist.hpp119
-rw-r--r--boost/geometry/index/detail/algorithms/path_intersection.hpp119
-rw-r--r--boost/geometry/index/detail/algorithms/segment_intersection.hpp146
-rw-r--r--boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp80
-rw-r--r--boost/geometry/index/detail/algorithms/sum_for_indexable.hpp76
-rw-r--r--boost/geometry/index/detail/algorithms/union_content.hpp33
-rw-r--r--boost/geometry/index/detail/assert.hpp30
-rw-r--r--boost/geometry/index/detail/bounded_view.hpp185
-rw-r--r--boost/geometry/index/detail/config_begin.hpp21
-rw-r--r--boost/geometry/index/detail/config_end.hpp12
-rw-r--r--boost/geometry/index/detail/distance_predicates.hpp161
-rw-r--r--boost/geometry/index/detail/exception.hpp72
-rw-r--r--boost/geometry/index/detail/meta.hpp42
-rw-r--r--boost/geometry/index/detail/predicates.hpp813
-rw-r--r--boost/geometry/index/detail/rtree/adaptors.hpp54
-rw-r--r--boost/geometry/index/detail/rtree/kmeans/kmeans.hpp16
-rw-r--r--boost/geometry/index/detail/rtree/kmeans/split.hpp87
-rw-r--r--boost/geometry/index/detail/rtree/linear/linear.hpp16
-rw-r--r--boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp446
-rw-r--r--boost/geometry/index/detail/rtree/node/auto_deallocator.hpp38
-rw-r--r--boost/geometry/index/detail/rtree/node/concept.hpp85
-rw-r--r--boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp67
-rw-r--r--boost/geometry/index/detail/rtree/node/node.hpp178
-rw-r--r--boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp81
-rw-r--r--boost/geometry/index/detail/rtree/node/node_elements.hpp95
-rw-r--r--boost/geometry/index/detail/rtree/node/pairs.hpp71
-rw-r--r--boost/geometry/index/detail/rtree/node/variant_dynamic.hpp275
-rw-r--r--boost/geometry/index/detail/rtree/node/variant_static.hpp194
-rw-r--r--boost/geometry/index/detail/rtree/node/variant_visitor.hpp66
-rw-r--r--boost/geometry/index/detail/rtree/node/weak_dynamic.hpp294
-rw-r--r--boost/geometry/index/detail/rtree/node/weak_static.hpp174
-rw-r--r--boost/geometry/index/detail/rtree/node/weak_visitor.hpp67
-rw-r--r--boost/geometry/index/detail/rtree/options.hpp155
-rw-r--r--boost/geometry/index/detail/rtree/pack_create.hpp376
-rw-r--r--boost/geometry/index/detail/rtree/quadratic/quadratic.hpp16
-rw-r--r--boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp298
-rw-r--r--boost/geometry/index/detail/rtree/query_iterators.hpp599
-rw-r--r--boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp233
-rw-r--r--boost/geometry/index/detail/rtree/rstar/insert.hpp577
-rw-r--r--boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp468
-rw-r--r--boost/geometry/index/detail/rtree/rstar/rstar.hpp18
-rw-r--r--boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp142
-rw-r--r--boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp109
-rw-r--r--boost/geometry/index/detail/rtree/utilities/gl_draw.hpp243
-rw-r--r--boost/geometry/index/detail/rtree/utilities/print.hpp219
-rw-r--r--boost/geometry/index/detail/rtree/utilities/statistics.hpp105
-rw-r--r--boost/geometry/index/detail/rtree/utilities/view.hpp61
-rw-r--r--boost/geometry/index/detail/rtree/visitors/children_box.hpp55
-rw-r--r--boost/geometry/index/detail/rtree/visitors/copy.hpp92
-rw-r--r--boost/geometry/index/detail/rtree/visitors/count.hpp107
-rw-r--r--boost/geometry/index/detail/rtree/visitors/destroy.hpp70
-rw-r--r--boost/geometry/index/detail/rtree/visitors/distance_query.hpp580
-rw-r--r--boost/geometry/index/detail/rtree/visitors/insert.hpp527
-rw-r--r--boost/geometry/index/detail/rtree/visitors/is_leaf.hpp41
-rw-r--r--boost/geometry/index/detail/rtree/visitors/remove.hpp326
-rw-r--r--boost/geometry/index/detail/rtree/visitors/spatial_query.hpp206
-rw-r--r--boost/geometry/index/detail/serialization.hpp585
-rw-r--r--boost/geometry/index/detail/tags.hpp25
-rw-r--r--boost/geometry/index/detail/translator.hpp60
-rw-r--r--boost/geometry/index/detail/tuples.hpp204
-rw-r--r--boost/geometry/index/detail/utilities.hpp46
-rw-r--r--boost/geometry/index/detail/varray.hpp2203
-rw-r--r--boost/geometry/index/detail/varray_detail.hpp756
-rw-r--r--boost/geometry/index/distance_predicates.hpp204
-rw-r--r--boost/geometry/index/equal_to.hpp249
-rw-r--r--boost/geometry/index/indexable.hpp217
-rw-r--r--boost/geometry/index/inserter.hpp78
-rw-r--r--boost/geometry/index/parameters.hpp253
-rw-r--r--boost/geometry/index/predicates.hpp385
-rw-r--r--boost/geometry/index/rtree.hpp1919
-rw-r--r--boost/geometry/io/dsv/write.hpp64
-rw-r--r--boost/geometry/io/svg/svg_mapper.hpp390
-rw-r--r--boost/geometry/io/svg/write_svg.hpp279
-rw-r--r--boost/geometry/io/svg/write_svg_multi.hpp78
-rw-r--r--boost/geometry/io/wkt/detail/prefix.hpp21
-rw-r--r--boost/geometry/io/wkt/detail/wkt_multi.hpp3
-rw-r--r--boost/geometry/io/wkt/read.hpp169
-rw-r--r--boost/geometry/io/wkt/stream.hpp6
-rw-r--r--boost/geometry/io/wkt/write.hpp215
-rw-r--r--boost/geometry/iterators/closing_iterator.hpp5
-rw-r--r--boost/geometry/iterators/concatenate_iterator.hpp184
-rw-r--r--boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp66
-rw-r--r--boost/geometry/iterators/detail/point_iterator/iterator_type.hpp136
-rw-r--r--boost/geometry/iterators/detail/point_iterator/value_type.hpp47
-rw-r--r--boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp153
-rw-r--r--boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp223
-rw-r--r--boost/geometry/iterators/detail/segment_iterator/value_type.hpp43
-rw-r--r--boost/geometry/iterators/dispatch/point_iterator.hpp47
-rw-r--r--boost/geometry/iterators/dispatch/segment_iterator.hpp47
-rw-r--r--boost/geometry/iterators/ever_circling_iterator.hpp4
-rw-r--r--boost/geometry/iterators/flatten_iterator.hpp259
-rw-r--r--boost/geometry/iterators/has_one_element.hpp29
-rw-r--r--boost/geometry/iterators/point_iterator.hpp315
-rw-r--r--boost/geometry/iterators/point_reverse_iterator.hpp98
-rw-r--r--boost/geometry/iterators/segment_iterator.hpp317
-rw-r--r--boost/geometry/multi/algorithms/append.hpp45
-rw-r--r--boost/geometry/multi/algorithms/area.hpp36
-rw-r--r--boost/geometry/multi/algorithms/centroid.hpp156
-rw-r--r--boost/geometry/multi/algorithms/clear.hpp22
-rw-r--r--boost/geometry/multi/algorithms/convert.hpp107
-rw-r--r--boost/geometry/multi/algorithms/correct.hpp45
-rw-r--r--boost/geometry/multi/algorithms/covered_by.hpp55
-rw-r--r--boost/geometry/multi/algorithms/detail/extreme_points.hpp19
-rw-r--r--boost/geometry/multi/algorithms/detail/for_each_range.hpp65
-rw-r--r--boost/geometry/multi/algorithms/detail/modify.hpp34
-rw-r--r--boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp33
-rw-r--r--boost/geometry/multi/algorithms/detail/multi_sum.hpp53
-rw-r--r--boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp88
-rw-r--r--boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp88
-rw-r--r--boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp38
-rw-r--r--boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp95
-rw-r--r--boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp46
-rw-r--r--boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp40
-rw-r--r--boost/geometry/multi/algorithms/detail/point_on_border.hpp77
-rw-r--r--boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp74
-rw-r--r--boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp77
-rw-r--r--boost/geometry/multi/algorithms/disjoint.hpp21
-rw-r--r--boost/geometry/multi/algorithms/distance.hpp150
-rw-r--r--boost/geometry/multi/algorithms/envelope.hpp96
-rw-r--r--boost/geometry/multi/algorithms/equals.hpp48
-rw-r--r--boost/geometry/multi/algorithms/for_each.hpp108
-rw-r--r--boost/geometry/multi/algorithms/intersection.hpp426
-rw-r--r--boost/geometry/multi/algorithms/length.hpp36
-rw-r--r--boost/geometry/multi/algorithms/num_geometries.hpp29
-rw-r--r--boost/geometry/multi/algorithms/num_interior_rings.hpp45
-rw-r--r--boost/geometry/multi/algorithms/num_points.hpp70
-rw-r--r--boost/geometry/multi/algorithms/perimeter.hpp35
-rw-r--r--boost/geometry/multi/algorithms/remove_spikes.hpp19
-rw-r--r--boost/geometry/multi/algorithms/reverse.hpp48
-rw-r--r--boost/geometry/multi/algorithms/simplify.hpp96
-rw-r--r--boost/geometry/multi/algorithms/transform.hpp81
-rw-r--r--boost/geometry/multi/algorithms/unique.hpp81
-rw-r--r--boost/geometry/multi/algorithms/within.hpp91
-rw-r--r--boost/geometry/multi/core/closure.hpp39
-rw-r--r--boost/geometry/multi/core/geometry_id.hpp36
-rw-r--r--boost/geometry/multi/core/interior_rings.hpp33
-rw-r--r--boost/geometry/multi/core/is_areal.hpp21
-rw-r--r--boost/geometry/multi/core/point_order.hpp36
-rw-r--r--boost/geometry/multi/core/point_type.hpp42
-rw-r--r--boost/geometry/multi/core/ring_type.hpp47
-rw-r--r--boost/geometry/multi/core/tags.hpp51
-rw-r--r--boost/geometry/multi/core/topological_dimension.hpp30
-rw-r--r--boost/geometry/multi/geometries/concepts/check.hpp61
-rw-r--r--boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp66
-rw-r--r--boost/geometry/multi/geometries/concepts/multi_point_concept.hpp65
-rw-r--r--boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp66
-rw-r--r--boost/geometry/multi/geometries/multi_geometries.hpp6
-rw-r--r--boost/geometry/multi/geometries/multi_linestring.hpp67
-rw-r--r--boost/geometry/multi/geometries/multi_point.hpp75
-rw-r--r--boost/geometry/multi/geometries/multi_polygon.hpp59
-rw-r--r--boost/geometry/multi/geometries/register/multi_linestring.hpp41
-rw-r--r--boost/geometry/multi/geometries/register/multi_point.hpp41
-rw-r--r--boost/geometry/multi/geometries/register/multi_polygon.hpp41
-rw-r--r--boost/geometry/multi/io/dsv/write.hpp62
-rw-r--r--boost/geometry/multi/io/wkt/detail/prefix.hpp32
-rw-r--r--boost/geometry/multi/io/wkt/read.hpp146
-rw-r--r--boost/geometry/multi/io/wkt/wkt.hpp4
-rw-r--r--boost/geometry/multi/io/wkt/write.hpp89
-rw-r--r--boost/geometry/multi/multi.hpp118
-rw-r--r--boost/geometry/multi/strategies/cartesian/centroid_average.hpp97
-rw-r--r--boost/geometry/multi/views/detail/range_type.hpp41
-rw-r--r--boost/geometry/policies/disjoint_interrupt_policy.hpp67
-rw-r--r--boost/geometry/policies/predicate_based_interrupt_policy.hpp101
-rw-r--r--boost/geometry/policies/relate/de9im.hpp9
-rw-r--r--boost/geometry/policies/relate/direction.hpp266
-rw-r--r--boost/geometry/policies/relate/intersection_points.hpp245
-rw-r--r--boost/geometry/policies/relate/intersection_ratios.hpp127
-rw-r--r--boost/geometry/policies/relate/tupled.hpp116
-rw-r--r--boost/geometry/policies/robustness/get_rescale_policy.hpp290
-rw-r--r--boost/geometry/policies/robustness/no_rescale_policy.hpp66
-rw-r--r--boost/geometry/policies/robustness/rescale_policy.hpp83
-rw-r--r--boost/geometry/policies/robustness/robust_point_type.hpp30
-rw-r--r--boost/geometry/policies/robustness/robust_type.hpp67
-rw-r--r--boost/geometry/policies/robustness/segment_ratio.hpp239
-rw-r--r--boost/geometry/policies/robustness/segment_ratio_type.hpp28
-rw-r--r--boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp110
-rw-r--r--boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp102
-rw-r--r--boost/geometry/strategies/agnostic/hull_graham_andrew.hpp57
-rw-r--r--boost/geometry/strategies/agnostic/point_in_box_by_side.hpp22
-rw-r--r--boost/geometry/strategies/agnostic/point_in_point.hpp136
-rw-r--r--boost/geometry/strategies/agnostic/point_in_poly_winding.hpp212
-rw-r--r--boost/geometry/strategies/agnostic/relate.hpp91
-rw-r--r--boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp305
-rw-r--r--boost/geometry/strategies/buffer.hpp91
-rw-r--r--boost/geometry/strategies/cartesian/box_in_box.hpp30
-rw-r--r--boost/geometry/strategies/cartesian/buffer_end_flat.hpp112
-rw-r--r--boost/geometry/strategies/cartesian/buffer_end_round.hpp166
-rw-r--r--boost/geometry/strategies/cartesian/buffer_join_miter.hpp140
-rw-r--r--boost/geometry/strategies/cartesian/buffer_join_round.hpp177
-rw-r--r--boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp155
-rw-r--r--boost/geometry/strategies/cartesian/buffer_point_circle.hpp108
-rw-r--r--boost/geometry/strategies/cartesian/buffer_point_square.hpp109
-rw-r--r--boost/geometry/strategies/cartesian/buffer_side_straight.hpp105
-rw-r--r--boost/geometry/strategies/cartesian/cart_intersect.hpp862
-rw-r--r--boost/geometry/strategies/cartesian/centroid_average.hpp114
-rw-r--r--boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp25
-rw-r--r--boost/geometry/strategies/cartesian/centroid_weighted_length.hpp3
-rw-r--r--boost/geometry/strategies/cartesian/distance_projected_point.hpp205
-rw-r--r--boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp316
-rw-r--r--boost/geometry/strategies/cartesian/distance_pythagoras.hpp232
-rw-r--r--boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp338
-rw-r--r--boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp349
-rw-r--r--boost/geometry/strategies/cartesian/point_in_box.hpp28
-rw-r--r--boost/geometry/strategies/cartesian/side_by_triangle.hpp51
-rw-r--r--boost/geometry/strategies/comparable_distance_result.hpp196
-rw-r--r--boost/geometry/strategies/concepts/convex_hull_concept.hpp15
-rw-r--r--boost/geometry/strategies/concepts/distance_concept.hpp86
-rw-r--r--boost/geometry/strategies/concepts/simplify_concept.hpp33
-rw-r--r--boost/geometry/strategies/concepts/within_concept.hpp8
-rw-r--r--boost/geometry/strategies/covered_by.hpp2
-rw-r--r--boost/geometry/strategies/default_comparable_distance_result.hpp43
-rw-r--r--boost/geometry/strategies/default_distance_result.hpp29
-rw-r--r--boost/geometry/strategies/default_length_result.hpp65
-rw-r--r--boost/geometry/strategies/default_strategy.hpp34
-rw-r--r--boost/geometry/strategies/distance.hpp59
-rw-r--r--boost/geometry/strategies/distance_result.hpp213
-rw-r--r--boost/geometry/strategies/intersection.hpp37
-rw-r--r--boost/geometry/strategies/intersection_result.hpp53
-rw-r--r--boost/geometry/strategies/side_info.hpp21
-rw-r--r--boost/geometry/strategies/spherical/area_huiller.hpp6
-rw-r--r--boost/geometry/strategies/spherical/distance_cross_track.hpp219
-rw-r--r--boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp287
-rw-r--r--boost/geometry/strategies/spherical/distance_haversine.hpp205
-rw-r--r--boost/geometry/strategies/spherical/side_by_cross_track.hpp32
-rw-r--r--boost/geometry/strategies/spherical/ssf.hpp8
-rw-r--r--boost/geometry/strategies/strategies.hpp24
-rw-r--r--boost/geometry/strategies/strategy_transform.hpp58
-rw-r--r--boost/geometry/strategies/tags.hpp2
-rw-r--r--boost/geometry/strategies/transform/inverse_transformer.hpp19
-rw-r--r--boost/geometry/strategies/transform/map_transformer.hpp28
-rw-r--r--boost/geometry/strategies/transform/matrix_transformers.hpp199
-rw-r--r--boost/geometry/strategies/within.hpp2
-rw-r--r--boost/geometry/util/bare_type.hpp18
-rw-r--r--boost/geometry/util/calculation_type.hpp8
-rw-r--r--boost/geometry/util/combine_if.hpp78
-rw-r--r--boost/geometry/util/compress_variant.hpp98
-rw-r--r--boost/geometry/util/math.hpp193
-rw-r--r--boost/geometry/util/parameter_type_of.hpp4
-rw-r--r--boost/geometry/util/range.hpp325
-rw-r--r--boost/geometry/util/rational.hpp48
-rw-r--r--boost/geometry/util/transform_variant.hpp79
-rw-r--r--boost/geometry/views/box_view.hpp20
-rw-r--r--boost/geometry/views/closeable_view.hpp11
-rw-r--r--boost/geometry/views/detail/indexed_point_view.hpp112
-rw-r--r--boost/geometry/views/detail/normalized_view.hpp116
-rw-r--r--boost/geometry/views/detail/points_view.hpp19
-rw-r--r--boost/geometry/views/detail/range_type.hpp42
-rw-r--r--boost/geometry/views/identity_view.hpp8
-rw-r--r--boost/geometry/views/segment_view.hpp14
504 files changed, 65332 insertions, 12074 deletions
diff --git a/boost/geometry/algorithms/append.hpp b/boost/geometry/algorithms/append.hpp
index 72b2bbadab..1a8828ba4b 100644
--- a/boost/geometry/algorithms/append.hpp
+++ b/boost/geometry/algorithms/append.hpp
@@ -1,8 +1,14 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,17 +20,20 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
#define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
-#include <boost/range.hpp>
+#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
-
-#include <boost/geometry/algorithms/num_interior_rings.hpp>
-#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/geometries/variant.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -92,7 +101,7 @@ struct point_to_polygon
else if (ring_index < int(num_interior_rings(polygon)))
{
append_point<ring_type, Point>::apply(
- interior_rings(polygon)[ring_index], point);
+ range::at(interior_rings(polygon), ring_index), point);
}
}
};
@@ -104,7 +113,7 @@ struct range_to_polygon
typedef typename ring_type<Polygon>::type ring_type;
static inline void apply(Polygon& polygon, Range const& range,
- int ring_index, int )
+ int ring_index, int = 0)
{
if (ring_index == -1)
{
@@ -114,7 +123,7 @@ struct range_to_polygon
else if (ring_index < int(num_interior_rings(polygon)))
{
append_range<ring_type, Range>::apply(
- interior_rings(polygon)[ring_index], range);
+ range::at(interior_rings(polygon), ring_index), range);
}
}
};
@@ -174,7 +183,7 @@ struct append_range<polygon_tag, Polygon, Range>
: detail::append::range_to_polygon<Polygon, Range>
{};
-}
+} // namespace splitted_dispatch
// Default: append a range (or linestring or ring or whatever) to any geometry
@@ -193,12 +202,143 @@ struct append<Geometry, RangeOrPoint, point_tag>
: splitted_dispatch::append_point<typename tag<Geometry>::type, Geometry, RangeOrPoint>
{};
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace append
+{
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_to_multigeometry
+{
+ static inline void apply(MultiGeometry& multigeometry,
+ RangeOrPoint const& range_or_point,
+ int ring_index, int multi_index)
+ {
+
+ dispatch::append
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ RangeOrPoint
+ >::apply(range::at(multigeometry, multi_index), range_or_point, ring_index);
+ }
+};
+
+}} // namespace detail::append
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+namespace splitted_dispatch
+{
+
+template <typename Geometry, typename Point>
+struct append_point<multi_point_tag, Geometry, Point>
+ : detail::append::append_point<Geometry, Point>
+{};
+
+template <typename Geometry, typename Range>
+struct append_range<multi_point_tag, Geometry, Range>
+ : detail::append::append_range<Geometry, Range>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_point<multi_linestring_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_range<multi_linestring_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_point<multi_polygon_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_range<multi_polygon_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+} // namespace splitted_dispatch
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct append
+{
+ template <typename RangeOrPoint>
+ static inline void apply(Geometry& geometry,
+ RangeOrPoint const& range_or_point,
+ int ring_index,
+ int multi_index)
+ {
+ concept::check<Geometry>();
+ dispatch::append<Geometry, RangeOrPoint>::apply(geometry,
+ range_or_point,
+ ring_index,
+ multi_index);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct append<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename RangeOrPoint>
+ struct visitor: boost::static_visitor<void>
+ {
+ RangeOrPoint const& m_range_or_point;
+ int m_ring_index;
+ int m_multi_index;
+
+ visitor(RangeOrPoint const& range_or_point,
+ int ring_index,
+ int multi_index):
+ m_range_or_point(range_or_point),
+ m_ring_index(ring_index),
+ m_multi_index(multi_index)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ append<Geometry>::apply(geometry,
+ m_range_or_point,
+ m_ring_index,
+ m_multi_index);
+ }
+ };
+
+ template <typename RangeOrPoint>
+ static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant_geometry,
+ RangeOrPoint const& range_or_point,
+ int ring_index,
+ int multi_index)
+ {
+ apply_visitor(
+ visitor<RangeOrPoint>(
+ range_or_point,
+ ring_index,
+ multi_index
+ ),
+ variant_geometry
+ );
+ }
+};
+
+} // namespace resolve_variant;
+
+
/*!
\brief Appends one or more points to a linestring, ring, polygon, multi-geometry
\ingroup append
@@ -208,22 +348,17 @@ struct append<Geometry, RangeOrPoint, point_tag>
\param range_or_point The point or range to add
\param ring_index The index of the ring in case of a polygon:
exterior ring (-1, the default) or interior ring index
-\param multi_index Reserved for multi polygons or multi linestrings
+\param multi_index The index of the geometry to which the points are appended
\qbk{[include reference/algorithms/append.qbk]}
}
*/
template <typename Geometry, typename RangeOrPoint>
inline void append(Geometry& geometry, RangeOrPoint const& range_or_point,
- int ring_index = -1, int multi_index = 0)
+ int ring_index = -1, int multi_index = 0)
{
- concept::check<Geometry>();
-
- dispatch::append
- <
- Geometry,
- RangeOrPoint
- >::apply(geometry, range_or_point, ring_index, multi_index);
+ resolve_variant::append<Geometry>
+ ::apply(geometry, range_or_point, ring_index, multi_index);
}
diff --git a/boost/geometry/algorithms/area.hpp b/boost/geometry/algorithms/area.hpp
index 8193200ab9..7377798719 100644
--- a/boost/geometry/algorithms/area.hpp
+++ b/boost/geometry/algorithms/area.hpp
@@ -18,18 +18,24 @@
#include <boost/mpl/if.hpp>
#include <boost/range/functions.hpp>
#include <boost/range/metafunctions.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/algorithms/detail/calculate_sum.hpp>
// #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/strategies/default_area_result.hpp>
@@ -49,41 +55,33 @@ namespace boost { namespace geometry
namespace detail { namespace area
{
-template<typename Box, typename Strategy>
struct box_area
{
- typedef typename coordinate_type<Box>::type return_type;
-
- static inline return_type apply(Box const& box, Strategy const&)
+ template <typename Box, typename Strategy>
+ static inline typename coordinate_type<Box>::type
+ apply(Box const& box, Strategy const&)
{
// Currently only works for 2D Cartesian boxes
assert_dimension<Box, 2>();
- return_type const dx = get<max_corner, 0>(box)
- - get<min_corner, 0>(box);
- return_type const dy = get<max_corner, 1>(box)
- - get<min_corner, 1>(box);
-
- return dx * dy;
+ return (get<max_corner, 0>(box) - get<min_corner, 0>(box))
+ * (get<max_corner, 1>(box) - get<min_corner, 1>(box));
}
};
template
<
- typename Ring,
iterate_direction Direction,
- closure_selector Closure,
- typename Strategy
+ closure_selector Closure
>
struct ring_area
{
- BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<Strategy>) );
-
- typedef typename Strategy::return_type type;
-
- static inline type apply(Ring const& ring, Strategy const& strategy)
+ template <typename Ring, typename Strategy>
+ static inline typename Strategy::return_type
+ apply(Ring const& ring, Strategy const& strategy)
{
+ BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<Strategy>) );
assert_dimension<Ring, 2>();
// Ignore warning (because using static method sometimes) on strategy
@@ -92,10 +90,10 @@ struct ring_area
// An open ring has at least three points,
// A closed ring has at least four points,
// if not, there is no (zero) area
- if (int(boost::size(ring))
+ if (boost::size(ring)
< core_detail::closure::minimum_ring_size<Closure>::value)
{
- return type();
+ return typename Strategy::return_type();
}
typedef typename reversible_view<Ring const, Direction>::type rview_type;
@@ -136,77 +134,112 @@ namespace dispatch
template
<
typename Geometry,
- typename Strategy = typename strategy::area::services::default_strategy
- <
- typename cs_tag
- <
- typename point_type<Geometry>::type
- >::type,
- typename point_type<Geometry>::type
- >::type,
typename Tag = typename tag<Geometry>::type
>
-struct area
- : detail::calculate_null
- <
- typename Strategy::return_type,
- Geometry,
- Strategy
- > {};
+struct area : detail::calculate_null
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return calculate_null::apply<typename Strategy::return_type>(geometry, strategy);
+ }
+};
-template
-<
- typename Geometry,
- typename Strategy
->
-struct area<Geometry, Strategy, box_tag>
- : detail::area::box_area<Geometry, Strategy>
+template <typename Geometry>
+struct area<Geometry, box_tag> : detail::area::box_area
{};
-template
-<
- typename Ring,
- typename Strategy
->
-struct area<Ring, Strategy, ring_tag>
+template <typename Ring>
+struct area<Ring, ring_tag>
: detail::area::ring_area
<
- Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
- Strategy
+ geometry::closure<Ring>::value
>
{};
-template
-<
- typename Polygon,
- typename Strategy
->
-struct area<Polygon, Strategy, polygon_tag>
- : detail::calculate_polygon_sum
- <
+template <typename Polygon>
+struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type apply(Polygon const& polygon, Strategy const& strategy)
+ {
+ return calculate_polygon_sum::apply<
typename Strategy::return_type,
- Polygon,
- Strategy,
detail::area::ring_area
<
- typename ring_type<Polygon const>::type,
order_as_direction<geometry::point_order<Polygon>::value>::value,
- geometry::closure<Polygon>::value,
- Strategy
+ geometry::closure<Polygon>::value
>
- >
-{};
+ >(polygon, strategy);
+ }
+};
+
+
+template <typename MultiGeometry>
+struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type
+ apply(MultiGeometry const& multi, Strategy const& strategy)
+ {
+ return multi_sum::apply
+ <
+ typename Strategy::return_type,
+ area<typename boost::range_value<MultiGeometry>::type>
+ >(multi, strategy);
+ }
+};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct area
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type apply(Geometry const& geometry,
+ Strategy const& strategy)
+ {
+ return dispatch::area<Geometry>::apply(geometry, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<typename Strategy::return_type>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry>
+ typename Strategy::return_type operator()(Geometry const& geometry) const
+ {
+ return area<Geometry>::apply(geometry, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename Strategy::return_type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
/*!
\brief \brief_calc{area}
@@ -234,6 +267,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr
{
concept::check<Geometry const>();
+ // TODO put this into a resolve_strategy stage
+ // (and take the return type from resolve_variant)
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
@@ -242,11 +277,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr
>::type strategy_type;
// detail::throw_on_empty_input(geometry);
-
- return dispatch::area
- <
- Geometry
- >::apply(geometry, strategy_type());
+
+ return resolve_variant::area<Geometry>::apply(geometry, strategy_type());
}
/*!
@@ -280,12 +312,8 @@ inline typename Strategy::return_type area(
concept::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
-
- return dispatch::area
- <
- Geometry,
- Strategy
- >::apply(geometry, strategy);
+
+ return resolve_variant::area<Geometry>::apply(geometry, strategy);
}
diff --git a/boost/geometry/algorithms/assign.hpp b/boost/geometry/algorithms/assign.hpp
index 8c153c878d..32f095b9ac 100644
--- a/boost/geometry/algorithms/assign.hpp
+++ b/boost/geometry/algorithms/assign.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -40,6 +41,8 @@
#include <boost/geometry/util/for_each_coordinate.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
namespace boost { namespace geometry
{
@@ -122,9 +125,232 @@ inline void assign_zero(Geometry& geometry)
}
/*!
+\brief Assign two coordinates to a geometry (usually a 2D point)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 \param_x
+\param c2 \param_y
+
+\qbk{distinguish, 2 coordinate values}
+\qbk{
+[heading Example]
+[assign_2d_point] [assign_2d_point_output]
+
+[heading See also]
+\* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
+}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2);
+}
+
+/*!
+\brief Assign three values to a geometry (usually a 3D point)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 \param_x
+\param c2 \param_y
+\param c3 \param_z
+
+\qbk{distinguish, 3 coordinate values}
+\qbk{
+[heading Example]
+[assign_3d_point] [assign_3d_point_output]
+
+[heading See also]
+\* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
+}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry,
+ Type const& c1, Type const& c2, Type const& c3)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2, c3);
+}
+
+/*!
+\brief Assign four values to a geometry (usually a box or segment)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 First coordinate (usually x1)
+\param c2 Second coordinate (usually y1)
+\param c3 Third coordinate (usually x2)
+\param c4 Fourth coordinate (usually y2)
+
+\qbk{distinguish, 4 coordinate values}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry,
+ Type const& c1, Type const& c2, Type const& c3, Type const& c4)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2, c3, c4);
+}
+
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct assign
+{
+ static inline void
+ apply(
+ Geometry1& geometry1,
+ const Geometry2& geometry2)
+ {
+ concept::check<Geometry1>();
+ concept::check<Geometry2 const>();
+ concept::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>();
+
+ bool const same_point_order =
+ point_order<Geometry1>::value == point_order<Geometry2>::value;
+ bool const same_closure =
+ closure<Geometry1>::value == closure<Geometry2>::value;
+
+ BOOST_MPL_ASSERT_MSG
+ (
+ same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER
+ , (types<Geometry1, Geometry2>)
+ );
+ BOOST_MPL_ASSERT_MSG
+ (
+ same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE
+ , (types<Geometry1, Geometry2>)
+ );
+
+ dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: static_visitor<void>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2)
+ : m_geometry2(geometry2)
+ {}
+
+ template <typename Geometry1>
+ result_type operator()(Geometry1& geometry1) const
+ {
+ return assign
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, m_geometry2);
+ }
+ };
+
+ static inline void
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: static_visitor<void>
+ {
+ Geometry1& m_geometry1;
+
+ visitor(Geometry1 const& geometry1)
+ : m_geometry1(geometry1)
+ {}
+
+ template <typename Geometry2>
+ result_type operator()(Geometry2 const& geometry2) const
+ {
+ return assign
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (m_geometry1, geometry2);
+ }
+ };
+
+ static inline void
+ apply(Geometry1& geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
+ {
+ return apply_visitor(visitor(geometry1), geometry2);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)>
+struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> >
+{
+ struct visitor: static_visitor<void>
+ {
+ template <typename Geometry1, typename Geometry2>
+ result_type operator()(
+ Geometry1& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return assign
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, geometry2);
+ }
+ };
+
+ static inline void
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2)
+ {
+ return apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
\brief Assigns one geometry to another geometry
-\details The assign algorithm assigns one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only
-if it is possible and applicable.
+\details The assign algorithm assigns one geometry, e.g. a BOX, to another
+geometry, e.g. a RING. This only works if it is possible and applicable.
\ingroup assign
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
@@ -142,25 +368,7 @@ if it is possible and applicable.
template <typename Geometry1, typename Geometry2>
inline void assign(Geometry1& geometry1, Geometry2 const& geometry2)
{
- concept::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>();
-
- bool const same_point_order =
- point_order<Geometry1>::value == point_order<Geometry2>::value;
- bool const same_closure =
- closure<Geometry1>::value == closure<Geometry2>::value;
-
- BOOST_MPL_ASSERT_MSG
- (
- same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER
- , (types<Geometry1, Geometry2>)
- );
- BOOST_MPL_ASSERT_MSG
- (
- same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE
- , (types<Geometry1, Geometry2>)
- );
-
- dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1);
+ resolve_variant::assign<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
diff --git a/boost/geometry/algorithms/buffer.hpp b/boost/geometry/algorithms/buffer.hpp
index e22e36addc..b8b07ad4d9 100644
--- a/boost/geometry/algorithms/buffer.hpp
+++ b/boost/geometry/algorithms/buffer.hpp
@@ -17,15 +17,19 @@
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
-
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/clear.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp>
namespace boost { namespace geometry
{
@@ -75,29 +79,87 @@ inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
namespace dispatch
{
-template <typename TagIn, typename TagOut, typename Input, typename T, typename Output>
-struct buffer {};
+template
+<
+ typename Input,
+ typename Output,
+ typename TagIn = typename tag<Input>::type,
+ typename TagOut = typename tag<Output>::type
+>
+struct buffer: not_implemented<TagIn, TagOut>
+{};
-template <typename BoxIn, typename T, typename BoxOut>
-struct buffer<box_tag, box_tag, BoxIn, T, BoxOut>
+template <typename BoxIn, typename BoxOut>
+struct buffer<BoxIn, BoxOut, box_tag, box_tag>
{
- static inline void apply(BoxIn const& box_in, T const& distance,
- T const& , BoxIn& box_out)
+ template <typename Distance>
+ static inline void apply(BoxIn const& box_in, Distance const& distance,
+ Distance const& , BoxOut& box_out)
{
detail::buffer::buffer_box(box_in, distance, box_out);
}
};
-// Many things to do. Point is easy, other geometries require self intersections
-// For point, note that it should output as a polygon (like the rest). Buffers
-// of a set of geometries are often lateron combined using a "dissolve" operation.
-// Two points close to each other get a combined kidney shaped buffer then.
-
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct buffer
+{
+ template <typename Distance, typename GeometryOut>
+ static inline void apply(Geometry const& geometry,
+ Distance const& distance,
+ Distance const& chord_length,
+ GeometryOut& out)
+ {
+ dispatch::buffer<Geometry, GeometryOut>::apply(geometry, distance, chord_length, out);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct buffer<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Distance, typename GeometryOut>
+ struct visitor: boost::static_visitor<void>
+ {
+ Distance const& m_distance;
+ Distance const& m_chord_length;
+ GeometryOut& m_out;
+
+ visitor(Distance const& distance,
+ Distance const& chord_length,
+ GeometryOut& out)
+ : m_distance(distance),
+ m_chord_length(chord_length),
+ m_out(out)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ buffer<Geometry>::apply(geometry, m_distance, m_chord_length, m_out);
+ }
+ };
+
+ template <typename Distance, typename GeometryOut>
+ static inline void apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Distance const& distance,
+ Distance const& chord_length,
+ GeometryOut& out
+ )
+ {
+ boost::apply_visitor(visitor<Distance, GeometryOut>(distance, chord_length, out), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{buffer}
\ingroup buffer
@@ -109,7 +171,6 @@ struct buffer<box_tag, box_tag, BoxIn, T, BoxOut>
\param geometry_out \param_geometry
\param distance The distance to be used for the buffer
\param chord_length (optional) The length of the chord's in the generated arcs around points or bends
-\note Currently only implemented for box, the trivial case, but still useful
\qbk{[include reference/algorithms/buffer.qbk]}
*/
@@ -120,14 +181,7 @@ inline void buffer(Input const& geometry_in, Output& geometry_out,
concept::check<Input const>();
concept::check<Output>();
- dispatch::buffer
- <
- typename tag<Input>::type,
- typename tag<Output>::type,
- Input,
- Distance,
- Output
- >::apply(geometry_in, distance, chord_length, geometry_out);
+ resolve_variant::buffer<Input>::apply(geometry_in, distance, chord_length, geometry_out);
}
/*!
@@ -139,29 +193,90 @@ inline void buffer(Input const& geometry_in, Output& geometry_out,
\tparam Distance \tparam_numeric
\param geometry \param_geometry
\param distance The distance to be used for the buffer
-\param chord_length (optional) The length of the chord's in the generated arcs around points or bends
+\param chord_length (optional) The length of the chord's in the generated arcs
+ around points or bends (RESERVED, NOT YET USED)
\return \return_calc{buffer}
*/
-template <typename Output, typename Input, typename T>
-Output return_buffer(Input const& geometry, T const& distance, T const& chord_length = -1)
+template <typename Output, typename Input, typename Distance>
+Output return_buffer(Input const& geometry, Distance const& distance, Distance const& chord_length = -1)
{
concept::check<Input const>();
concept::check<Output>();
Output geometry_out;
- dispatch::buffer
- <
- typename tag<Input>::type,
- typename tag<Output>::type,
- Input,
- T,
- Output
- >::apply(geometry, distance, chord_length, geometry_out);
+ resolve_variant::buffer<Input>::apply(geometry, distance, chord_length, geometry_out);
return geometry_out;
}
+/*!
+\brief \brief_calc{buffer}
+\ingroup buffer
+\details \details_calc{buffer, \det_buffer}.
+\tparam GeometryIn \tparam_geometry
+\tparam MultiPolygon \tparam_geometry{MultiPolygon}
+\tparam DistanceStrategy A strategy defining distance (or radius)
+\tparam SideStrategy A strategy defining creation along sides
+\tparam JoinStrategy A strategy defining creation around convex corners
+\tparam EndStrategy A strategy defining creation at linestring ends
+\tparam PointStrategy A strategy defining creation around points
+\param geometry_in \param_geometry
+\param geometry_out output multi polygon (or std:: collection of polygons),
+ will contain a buffered version of the input geometry
+\param distance_strategy The distance strategy to be used
+\param side_strategy The side strategy to be used
+\param join_strategy The join strategy to be used
+\param end_strategy The end strategy to be used
+\param point_strategy The point strategy to be used
+
+\qbk{distinguish,with strategies}
+\qbk{[include reference/algorithms/buffer_with_strategies.qbk]}
+ */
+template
+<
+ typename GeometryIn,
+ typename MultiPolygon,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy
+>
+inline void buffer(GeometryIn const& geometry_in,
+ MultiPolygon& geometry_out,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy)
+{
+ typedef typename boost::range_value<MultiPolygon>::type polygon_type;
+ concept::check<GeometryIn const>();
+ concept::check<polygon_type>();
+
+ typedef typename point_type<GeometryIn>::type point_type;
+ typedef typename rescale_policy_type<point_type>::type rescale_policy_type;
+
+ geometry_out.clear();
+
+ model::box<point_type> box;
+ envelope(geometry_in, box);
+ buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy));
+
+ rescale_policy_type rescale_policy
+ = boost::geometry::get_rescale_policy<rescale_policy_type>(box);
+
+ detail::buffer::buffer_inserter<polygon_type>(geometry_in, std::back_inserter(geometry_out),
+ distance_strategy,
+ side_strategy,
+ join_strategy,
+ end_strategy,
+ point_strategy,
+ rescale_policy);
+}
+
+
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP
diff --git a/boost/geometry/algorithms/centroid.hpp b/boost/geometry/algorithms/centroid.hpp
index 69ad9fe829..65dc9c3753 100644
--- a/boost/geometry/algorithms/centroid.hpp
+++ b/boost/geometry/algorithms/centroid.hpp
@@ -3,6 +3,12 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,7 +24,9 @@
#include <cstddef>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
@@ -27,17 +35,27 @@
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/algorithms/convert.hpp>
-#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/concepts/centroid_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/multi/algorithms/num_points.hpp>
+
+#include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
namespace boost { namespace geometry
@@ -62,8 +80,15 @@ class centroid_exception : public geometry::exception
{
public:
+ /*!
+ \brief The default constructor
+ */
inline centroid_exception() {}
+ /*!
+ \brief Returns the explanatory string.
+ \return Pointer to a null-terminated string with explanatory information.
+ */
virtual char const* what() const throw()
{
return "Boost.Geometry Centroid calculation exception";
@@ -77,9 +102,9 @@ public:
namespace detail { namespace centroid
{
-template<typename Point, typename PointCentroid, typename Strategy>
struct centroid_point
{
+ template<typename Point, typename PointCentroid, typename Strategy>
static inline void apply(Point const& point, PointCentroid& centroid,
Strategy const&)
{
@@ -89,55 +114,56 @@ struct centroid_point
template
<
- typename Box,
+ typename Indexed,
typename Point,
std::size_t Dimension,
std::size_t DimensionCount
>
-struct centroid_box_calculator
+struct centroid_indexed_calculator
{
typedef typename select_coordinate_type
<
- Box, Point
+ Indexed, Point
>::type coordinate_type;
- static inline void apply(Box const& box, Point& centroid)
+ static inline void apply(Indexed const& indexed, Point& centroid)
{
- coordinate_type const c1 = get<min_corner, Dimension>(box);
- coordinate_type const c2 = get<max_corner, Dimension>(box);
+ coordinate_type const c1 = get<min_corner, Dimension>(indexed);
+ coordinate_type const c2 = get<max_corner, Dimension>(indexed);
coordinate_type m = c1 + c2;
- m /= 2.0;
+ coordinate_type const two = 2;
+ m /= two;
set<Dimension>(centroid, m);
- centroid_box_calculator
+ centroid_indexed_calculator
<
- Box, Point,
+ Indexed, Point,
Dimension + 1, DimensionCount
- >::apply(box, centroid);
+ >::apply(indexed, centroid);
}
};
-template<typename Box, typename Point, std::size_t DimensionCount>
-struct centroid_box_calculator<Box, Point, DimensionCount, DimensionCount>
+template<typename Indexed, typename Point, std::size_t DimensionCount>
+struct centroid_indexed_calculator<Indexed, Point, DimensionCount, DimensionCount>
{
- static inline void apply(Box const& , Point& )
+ static inline void apply(Indexed const& , Point& )
{
}
};
-template<typename Box, typename Point, typename Strategy>
-struct centroid_box
+struct centroid_indexed
{
- static inline void apply(Box const& box, Point& centroid,
+ template<typename Indexed, typename Point, typename Strategy>
+ static inline void apply(Indexed const& indexed, Point& centroid,
Strategy const&)
{
- centroid_box_calculator
+ centroid_indexed_calculator
<
- Box, Point,
- 0, dimension<Box>::type::value
- >::apply(box, centroid);
+ Indexed, Point,
+ 0, dimension<Indexed>::type::value
+ >::apply(indexed, centroid);
}
};
@@ -169,16 +195,19 @@ inline bool range_ok(Range const& range, Point& centroid)
return true;
}
-
/*!
- \brief Calculate the centroid of a ring.
+ \brief Calculate the centroid of a Ring or a Linestring.
*/
-template<typename Ring, closure_selector Closure, typename Strategy>
+template <closure_selector Closure>
struct centroid_range_state
{
+ template<typename Ring, typename PointTransformer, typename Strategy>
static inline void apply(Ring const& ring,
- Strategy const& strategy, typename Strategy::state_type& state)
+ PointTransformer const& transformer,
+ Strategy const& strategy,
+ typename Strategy::state_type& state)
{
+ typedef typename geometry::point_type<Ring const>::type point_type;
typedef typename closeable_view<Ring const, Closure>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator_type;
@@ -187,31 +216,42 @@ struct centroid_range_state
iterator_type it = boost::begin(view);
iterator_type end = boost::end(view);
- for (iterator_type previous = it++;
- it != end;
- ++previous, ++it)
+ typename PointTransformer::result_type
+ previous_pt = transformer.apply(*it);
+
+ for ( ++it ; it != end ; ++it)
{
- strategy.apply(*previous, *it, state);
+ typename PointTransformer::result_type
+ pt = transformer.apply(*it);
+
+ strategy.apply(static_cast<point_type const&>(previous_pt),
+ static_cast<point_type const&>(pt),
+ state);
+
+ previous_pt = pt;
}
}
};
-template<typename Range, typename Point, closure_selector Closure, typename Strategy>
+template <closure_selector Closure>
struct centroid_range
{
+ template<typename Range, typename Point, typename Strategy>
static inline void apply(Range const& range, Point& centroid,
- Strategy const& strategy)
+ Strategy const& strategy)
{
if (range_ok(range, centroid))
{
+ // prepare translation transformer
+ translating_transformer<Range> transformer(*boost::begin(range));
+
typename Strategy::state_type state;
- centroid_range_state
- <
- Range,
- Closure,
- Strategy
- >::apply(range, strategy, state);
+ centroid_range_state<Closure>::apply(range, transformer,
+ strategy, state);
strategy.result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
}
}
};
@@ -222,48 +262,112 @@ struct centroid_range
\note Because outer ring is clockwise, inners are counter clockwise,
triangle approach is OK and works for polygons with rings.
*/
-template<typename Polygon, typename Strategy>
struct centroid_polygon_state
{
- typedef typename ring_type<Polygon>::type ring_type;
-
+ template<typename Polygon, typename PointTransformer, typename Strategy>
static inline void apply(Polygon const& poly,
- Strategy const& strategy, typename Strategy::state_type& state)
+ PointTransformer const& transformer,
+ Strategy const& strategy,
+ typename Strategy::state_type& state)
{
- typedef centroid_range_state
- <
- ring_type,
- geometry::closure<ring_type>::value,
- Strategy
- > per_ring;
+ typedef typename ring_type<Polygon>::type ring_type;
+ typedef centroid_range_state<geometry::closure<ring_type>::value> per_ring;
- per_ring::apply(exterior_ring(poly), strategy, state);
+ per_ring::apply(exterior_ring(poly), transformer, strategy, state);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_ring::apply(*it, strategy, state);
+ per_ring::apply(*it, transformer, strategy, state);
}
}
};
-template<typename Polygon, typename Point, typename Strategy>
struct centroid_polygon
{
+ template<typename Polygon, typename Point, typename Strategy>
static inline void apply(Polygon const& poly, Point& centroid,
Strategy const& strategy)
{
if (range_ok(exterior_ring(poly), centroid))
{
+ // prepare translation transformer
+ translating_transformer<Polygon>
+ transformer(*boost::begin(exterior_ring(poly)));
+
typename Strategy::state_type state;
- centroid_polygon_state
- <
- Polygon,
- Strategy
- >::apply(poly, strategy, state);
+ centroid_polygon_state::apply(poly, transformer, strategy, state);
strategy.result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
+ }
+ }
+};
+
+
+/*!
+ \brief Building block of a multi-point, to be used as Policy in the
+ more generec centroid_multi
+*/
+struct centroid_multi_point_state
+{
+ template <typename Point, typename PointTransformer, typename Strategy>
+ static inline void apply(Point const& point,
+ PointTransformer const& transformer,
+ Strategy const& strategy,
+ typename Strategy::state_type& state)
+ {
+ strategy.apply(static_cast<Point const&>(transformer.apply(point)),
+ state);
+ }
+};
+
+
+/*!
+ \brief Generic implementation which calls a policy to calculate the
+ centroid of the total of its single-geometries
+ \details The Policy is, in general, the single-version, with state. So
+ detail::centroid::centroid_polygon_state is used as a policy for this
+ detail::centroid::centroid_multi
+
+*/
+template <typename Policy>
+struct centroid_multi
+{
+ template <typename Multi, typename Point, typename Strategy>
+ static inline void apply(Multi const& multi,
+ Point& centroid,
+ Strategy const& strategy)
+ {
+#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
+ // If there is nothing in any of the ranges, it is not possible
+ // to calculate the centroid
+ if (geometry::num_points(multi) == 0)
+ {
+ throw centroid_exception();
}
+#endif
+
+ // prepare translation transformer
+ translating_transformer<Multi> transformer(multi);
+
+ typename Strategy::state_type state;
+
+ for (typename boost::range_iterator<Multi const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, transformer, strategy, state);
+ }
+ Strategy::result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
}
};
@@ -278,64 +382,153 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
- typename Point,
- typename Strategy
+ typename Tag = typename tag<Geometry>::type
>
-struct centroid {};
+struct centroid: not_implemented<Tag>
+{};
-template
-<
- typename Geometry,
- typename Point,
- typename Strategy
->
-struct centroid<point_tag, Geometry, Point, Strategy>
- : detail::centroid::centroid_point<Geometry, Point, Strategy>
+template <typename Geometry>
+struct centroid<Geometry, point_tag>
+ : detail::centroid::centroid_point
{};
-template
-<
- typename Box,
- typename Point,
- typename Strategy
->
-struct centroid<box_tag, Box, Point, Strategy>
- : detail::centroid::centroid_box<Box, Point, Strategy>
+template <typename Box>
+struct centroid<Box, box_tag>
+ : detail::centroid::centroid_indexed
+{};
+
+template <typename Segment>
+struct centroid<Segment, segment_tag>
+ : detail::centroid::centroid_indexed
+{};
+
+template <typename Ring>
+struct centroid<Ring, ring_tag>
+ : detail::centroid::centroid_range<geometry::closure<Ring>::value>
+{};
+
+template <typename Linestring>
+struct centroid<Linestring, linestring_tag>
+ : detail::centroid::centroid_range<closed>
{};
-template <typename Ring, typename Point, typename Strategy>
-struct centroid<ring_tag, Ring, Point, Strategy>
- : detail::centroid::centroid_range
+template <typename Polygon>
+struct centroid<Polygon, polygon_tag>
+ : detail::centroid::centroid_polygon
+{};
+
+template <typename MultiLinestring>
+struct centroid<MultiLinestring, multi_linestring_tag>
+ : detail::centroid::centroid_multi
<
- Ring,
- Point,
- geometry::closure<Ring>::value,
- Strategy
+ detail::centroid::centroid_range_state<closed>
>
{};
-template <typename Linestring, typename Point, typename Strategy>
-struct centroid<linestring_tag, Linestring, Point, Strategy>
- : detail::centroid::centroid_range
+template <typename MultiPolygon>
+struct centroid<MultiPolygon, multi_polygon_tag>
+ : detail::centroid::centroid_multi
<
- Linestring,
- Point,
- closed,
- Strategy
+ detail::centroid::centroid_polygon_state
+ >
+{};
+
+template <typename MultiPoint>
+struct centroid<MultiPoint, multi_point_tag>
+ : detail::centroid::centroid_multi
+ <
+ detail::centroid::centroid_multi_point_state
>
- {};
+{};
-template <typename Polygon, typename Point, typename Strategy>
-struct centroid<polygon_tag, Polygon, Point, Strategy>
- : detail::centroid::centroid_polygon<Polygon, Point, Strategy>
- {};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy {
+
+template <typename Geometry>
+struct centroid
+{
+ template <typename Point, typename Strategy>
+ static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
+ {
+ dispatch::centroid<Geometry>::apply(geometry, out, strategy);
+ }
+
+ template <typename Point>
+ static inline void apply(Geometry const& geometry, Point& out, default_strategy)
+ {
+ typedef typename strategy::centroid::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type,
+ typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ pointlike_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ dimension<Geometry>::type::value,
+ Point,
+ Geometry
+ >::type strategy_type;
+
+ dispatch::centroid<Geometry>::apply(geometry, out, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct centroid
+{
+ template <typename Point, typename Strategy>
+ static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
+ {
+ concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
+ resolve_strategy::centroid<Geometry>::apply(geometry, out, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Point, typename Strategy>
+ struct visitor: boost::static_visitor<void>
+ {
+ Point& m_out;
+ Strategy const& m_strategy;
+
+ visitor(Point& out, Strategy const& strategy)
+ : m_out(out), m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ centroid<Geometry>::apply(geometry, m_out, m_strategy);
+ }
+ };
+
+ template <typename Point, typename Strategy>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Point& out,
+ Strategy const& strategy)
+ {
+ boost::apply_visitor(visitor<Point, Strategy>(out, strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{centroid} \brief_strategy
\ingroup centroid
@@ -357,21 +550,7 @@ template<typename Geometry, typename Point, typename Strategy>
inline void centroid(Geometry const& geometry, Point& c,
Strategy const& strategy)
{
- //BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
-
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
- typedef typename point_type<Geometry>::type point_type;
-
- // Call dispatch apply method. That one returns true if centroid
- // should be taken from state.
- dispatch::centroid
- <
- typename tag<Geometry>::type,
- Geometry,
- Point,
- Strategy
- >::apply(geometry, c, strategy);
+ resolve_variant::centroid<Geometry>::apply(geometry, c, strategy);
}
@@ -394,24 +573,7 @@ inline void centroid(Geometry const& geometry, Point& c,
template<typename Geometry, typename Point>
inline void centroid(Geometry const& geometry, Point& c)
{
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
- typedef typename strategy::centroid::services::default_strategy
- <
- typename cs_tag<Geometry>::type,
- typename tag_cast
- <
- typename tag<Geometry>::type,
- pointlike_tag,
- linear_tag,
- areal_tag
- >::type,
- dimension<Geometry>::type::value,
- Point,
- Geometry
- >::type strategy_type;
-
- centroid(geometry, c, strategy_type());
+ centroid(geometry, c, default_strategy());
}
@@ -429,8 +591,6 @@ inline void centroid(Geometry const& geometry, Point& c)
template<typename Point, typename Geometry>
inline Point return_centroid(Geometry const& geometry)
{
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
Point c;
centroid(geometry, c);
return c;
@@ -454,10 +614,6 @@ inline Point return_centroid(Geometry const& geometry)
template<typename Point, typename Geometry, typename Strategy>
inline Point return_centroid(Geometry const& geometry, Strategy const& strategy)
{
- //BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
-
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
Point c;
centroid(geometry, c, strategy);
return c;
diff --git a/boost/geometry/algorithms/clear.hpp b/boost/geometry/algorithms/clear.hpp
index d7336587ee..1850816b1b 100644
--- a/boost/geometry/algorithms/clear.hpp
+++ b/boost/geometry/algorithms/clear.hpp
@@ -14,15 +14,19 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
-#include <boost/mpl/assert.hpp>
+
#include <boost/type_traits/remove_const.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/tag_cast.hpp>
-
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -72,6 +76,7 @@ struct no_action
}
};
+
}} // namespace detail::clear
#endif // DOXYGEN_NO_DETAIL
@@ -84,14 +89,8 @@ template
typename Geometry,
typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type
>
-struct clear
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
-};
+struct clear: not_implemented<Tag>
+{};
// Point/box/segment do not have clear. So specialize to do nothing.
template <typename Geometry>
@@ -127,10 +126,48 @@ struct clear<Polygon, polygon_tag>
{};
+template <typename Geometry>
+struct clear<Geometry, multi_tag>
+ : detail::clear::collection_clear<Geometry>
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct clear
+{
+ static inline void apply(Geometry& geometry)
+ {
+ dispatch::clear<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct clear<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: static_visitor<void>
+ {
+ template <typename Geometry>
+ inline void operator()(Geometry& geometry) const
+ {
+ clear<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Clears a linestring, ring or polygon (exterior+interiors) or multi*
\details Generic function to clear a geometry. All points will be removed from the collection or collections
@@ -149,7 +186,7 @@ inline void clear(Geometry& geometry)
{
concept::check<Geometry>();
- dispatch::clear<Geometry>::apply(geometry);
+ resolve_variant::clear<Geometry>::apply(geometry);
}
diff --git a/boost/geometry/algorithms/comparable_distance.hpp b/boost/geometry/algorithms/comparable_distance.hpp
index 3467045ca2..6f009da3ed 100644
--- a/boost/geometry/algorithms/comparable_distance.hpp
+++ b/boost/geometry/algorithms/comparable_distance.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,61 +19,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
-
-#include <boost/geometry/algorithms/distance.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-/*!
-\brief \brief_calc2{comparable distance measurement}
-\ingroup distance
-\details The free function comparable_distance does not necessarily calculate the distance,
- but it calculates a distance measure such that two distances are comparable to each other.
- For example: for the Cartesian coordinate system, Pythagoras is used but the square root
- is not taken, which makes it faster and the results of two point pairs can still be
- compared to each other.
-\tparam Geometry1 first geometry type
-\tparam Geometry2 second geometry type
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_calc{comparable distance}
-
-\qbk{[include reference/algorithms/comparable_distance.qbk]}
- */
-template <typename Geometry1, typename Geometry2>
-inline typename default_distance_result<Geometry1, Geometry2>::type comparable_distance(
- Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- typedef typename point_type<Geometry1>::type point1_type;
- typedef typename point_type<Geometry2>::type point2_type;
-
- // Define a point-point-distance-strategy
- // for either the normal case, either the reversed case
-
- typedef typename strategy::distance::services::comparable_type
- <
- typename boost::mpl::if_c
- <
- geometry::reverse_dispatch
- <Geometry1, Geometry2>::type::value,
- typename strategy::distance::services::default_strategy
- <point_tag, point2_type, point1_type>::type,
- typename strategy::distance::services::default_strategy
- <point_tag, point1_type, point2_type>::type
- >::type
- >::type strategy_type;
-
- return distance(geometry1, geometry2, strategy_type());
-}
-
-
-}} // namespace boost::geometry
-
+#include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp>
+#include <boost/geometry/algorithms/detail/comparable_distance/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
diff --git a/boost/geometry/algorithms/convert.hpp b/boost/geometry/algorithms/convert.hpp
index fbbf74c17f..914ef8f420 100644
--- a/boost/geometry/algorithms/convert.hpp
+++ b/boost/geometry/algorithms/convert.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -20,6 +21,10 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_array.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
@@ -31,19 +36,32 @@
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/util/range.hpp>
+
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tags.hpp>
+
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+// Silence warning C4512: assignment operator could not be generated
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127 4512)
+#endif
+
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace conversion
{
@@ -95,7 +113,7 @@ struct box_to_range
assign_box_corners_oriented<Reverse>(box, range);
if (Close)
{
- range[4] = range[0];
+ range::at(range, 4) = range::at(range, 0);
}
}
};
@@ -115,22 +133,22 @@ struct segment_to_range
}
};
-template
+template
<
- typename Range1,
- typename Range2,
+ typename Range1,
+ typename Range2,
bool Reverse = false
>
struct range_to_range
{
typedef typename reversible_view
<
- Range1 const,
+ Range1 const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
typedef typename closeable_view
<
- rview_type const,
+ rview_type const,
geometry::closure<Range1>::value
>::type view_type;
@@ -144,13 +162,17 @@ struct range_to_range
// point for open output.
view_type view(rview);
- int n = boost::size(view);
+ typedef typename boost::range_size<Range1>::type size_type;
+ size_type n = boost::size(view);
if (geometry::closure<Range2>::value == geometry::open)
{
n--;
}
- int i = 0;
+ // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
+ // but ok, sice below it == end()
+
+ size_type i = 0;
for (typename boost::range_iterator<view_type const>::type it
= boost::begin(view);
it != boost::end(view) && i < n;
@@ -166,7 +188,7 @@ struct polygon_to_polygon
{
typedef range_to_range
<
- typename geometry::ring_type<Polygon1>::type,
+ typename geometry::ring_type<Polygon1>::type,
typename geometry::ring_type<Polygon2>::type,
geometry::point_order<Polygon1>::value
!= geometry::point_order<Polygon2>::value
@@ -176,7 +198,7 @@ struct polygon_to_polygon
{
// Clearing managed per ring, and in the resizing of interior rings
- per_ring::apply(geometry::exterior_ring(source),
+ per_ring::apply(geometry::exterior_ring(source),
geometry::exterior_ring(destination));
// Container should be resizeable
@@ -188,13 +210,15 @@ struct polygon_to_polygon
>::type
>::apply(interior_rings(destination), num_interior_rings(source));
- typename interior_return_type<Polygon1 const>::type rings_source
- = interior_rings(source);
- typename interior_return_type<Polygon2>::type rings_dest
- = interior_rings(destination);
+ typename interior_return_type<Polygon1 const>::type
+ rings_source = interior_rings(source);
+ typename interior_return_type<Polygon2>::type
+ rings_dest = interior_rings(destination);
- BOOST_AUTO_TPL(it_source, boost::begin(rings_source));
- BOOST_AUTO_TPL(it_dest, boost::begin(rings_dest));
+ typename detail::interior_iterator<Polygon1 const>::type
+ it_source = boost::begin(rings_source);
+ typename detail::interior_iterator<Polygon2>::type
+ it_dest = boost::begin(rings_dest);
for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
{
@@ -203,6 +227,37 @@ struct polygon_to_polygon
}
};
+template <typename Single, typename Multi, typename Policy>
+struct single_to_multi: private Policy
+{
+ static inline void apply(Single const& single, Multi& multi)
+ {
+ traits::resize<Multi>::apply(multi, 1);
+ Policy::apply(single, *boost::begin(multi));
+ }
+};
+
+
+
+template <typename Multi1, typename Multi2, typename Policy>
+struct multi_to_multi: private Policy
+{
+ static inline void apply(Multi1 const& multi1, Multi2& multi2)
+ {
+ traits::resize<Multi2>::apply(multi2, boost::size(multi1));
+
+ typename boost::range_iterator<Multi1 const>::type it1
+ = boost::begin(multi1);
+ typename boost::range_iterator<Multi2>::type it2
+ = boost::begin(multi2);
+
+ for (; it1 != boost::end(multi1); ++it1, ++it2)
+ {
+ Policy::apply(*it1, *it2);
+ }
+ }
+};
+
}} // namespace detail::conversion
#endif // DOXYGEN_NO_DETAIL
@@ -280,8 +335,8 @@ struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount,
template <typename Ring1, typename Ring2, std::size_t DimensionCount>
struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false>
: detail::conversion::range_to_range
- <
- Ring1,
+ <
+ Ring1,
Ring2,
geometry::point_order<Ring1>::value
!= geometry::point_order<Ring2>::value
@@ -302,8 +357,8 @@ template <typename Box, typename Ring>
struct convert<Box, Ring, box_tag, ring_tag, 2, false>
: detail::conversion::box_to_range
<
- Box,
- Ring,
+ Box,
+ Ring,
geometry::closure<Ring>::value == closed,
geometry::point_order<Ring>::value == counterclockwise
>
@@ -377,16 +432,108 @@ struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
};
+// Dispatch for multi <-> multi, specifying their single-version as policy.
+// Note that, even if the multi-types are mutually different, their single
+// version types might be the same and therefore we call boost::is_same again
+
+template <typename Multi1, typename Multi2, std::size_t DimensionCount>
+struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false>
+ : detail::conversion::multi_to_multi
+ <
+ Multi1,
+ Multi2,
+ convert
+ <
+ typename boost::range_value<Multi1>::type,
+ typename boost::range_value<Multi2>::type,
+ typename single_tag_of
+ <
+ typename tag<Multi1>::type
+ >::type,
+ typename single_tag_of
+ <
+ typename tag<Multi2>::type
+ >::type,
+ DimensionCount
+ >
+ >
+{};
+
+
+template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
+struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false>
+ : detail::conversion::single_to_multi
+ <
+ Single,
+ Multi,
+ convert
+ <
+ Single,
+ typename boost::range_value<Multi>::type,
+ typename tag<Single>::type,
+ typename single_tag_of
+ <
+ typename tag<Multi>::type
+ >::type,
+ DimensionCount,
+ false
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct convert
+{
+ static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
+ {
+ concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
+ dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: static_visitor<void>
+ {
+ Geometry2& m_geometry2;
+
+ visitor(Geometry2& geometry2)
+ : m_geometry2(geometry2)
+ {}
+
+ template <typename Geometry1>
+ inline void operator()(Geometry1 const& geometry1) const
+ {
+ convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
+ }
+ };
+
+ static inline void apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2& geometry2
+ )
+ {
+ apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+}
+
+
/*!
\brief Converts one geometry to another geometry
\details The convert algorithm converts one geometry, e.g. a BOX, to another
-geometry, e.g. a RING. This only if it is possible and applicable.
-If the point-order is different, or the closure is different between two
-geometry types, it will be converted correctly by explicitly reversing the
+geometry, e.g. a RING. This only works if it is possible and applicable.
+If the point-order is different, or the closure is different between two
+geometry types, it will be converted correctly by explicitly reversing the
points or closing or opening the polygon rings.
\ingroup convert
\tparam Geometry1 \tparam_geometry
@@ -399,13 +546,13 @@ points or closing or opening the polygon rings.
template <typename Geometry1, typename Geometry2>
inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
{
- concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
-
- dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
diff --git a/boost/geometry/algorithms/convex_hull.hpp b/boost/geometry/algorithms/convex_hull.hpp
index 56b87c8c15..09f4c5142d 100644
--- a/boost/geometry/algorithms/convex_hull.hpp
+++ b/boost/geometry/algorithms/convex_hull.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -15,15 +20,20 @@
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP
#include <boost/array.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/strategies/concepts/convex_hull_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
@@ -40,45 +50,34 @@ namespace boost { namespace geometry
namespace detail { namespace convex_hull
{
-template
-<
- typename Geometry,
- order_selector Order,
- typename Strategy
->
+template <order_selector Order, closure_selector Closure>
struct hull_insert
{
// Member template function (to avoid inconvenient declaration
// of output-iterator-type, from hull_to_geometry)
- template <typename OutputIterator>
+ template <typename Geometry, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry const& geometry,
OutputIterator out, Strategy const& strategy)
{
typename Strategy::state_type state;
strategy.apply(geometry, state);
- strategy.result(state, out, Order == clockwise);
+ strategy.result(state, out, Order == clockwise, Closure != open);
return out;
}
};
-template
-<
- typename Geometry,
- typename Strategy
->
struct hull_to_geometry
{
- template <typename OutputGeometry>
+ template <typename Geometry, typename OutputGeometry, typename Strategy>
static inline void apply(Geometry const& geometry, OutputGeometry& out,
Strategy const& strategy)
{
hull_insert
<
- Geometry,
geometry::point_order<OutputGeometry>::value,
- Strategy
+ geometry::closure<OutputGeometry>::value
>::apply(geometry,
std::back_inserter(
// Handle linestring, ring and polygon the same:
@@ -89,18 +88,6 @@ struct hull_to_geometry
}
};
-
-// Helper metafunction for default strategy retrieval
-template <typename Geometry>
-struct default_strategy
- : strategy_convex_hull
- <
- Geometry,
- typename point_type<Geometry>::type
- >
-{};
-
-
}} // namespace detail::convex_hull
#endif // DOXYGEN_NO_DETAIL
@@ -113,21 +100,16 @@ namespace dispatch
template
<
typename Geometry,
- typename Strategy = typename detail::convex_hull::default_strategy<Geometry>::type,
typename Tag = typename tag<Geometry>::type
>
struct convex_hull
- : detail::convex_hull::hull_to_geometry<Geometry, Strategy>
+ : detail::convex_hull::hull_to_geometry
{};
-template
-<
- typename Box,
- typename Strategy
->
-struct convex_hull<Box, Strategy, box_tag>
+template <typename Box>
+struct convex_hull<Box, box_tag>
{
- template <typename OutputGeometry>
+ template <typename OutputGeometry, typename Strategy>
static inline void apply(Box const& box, OutputGeometry& out,
Strategy const& )
{
@@ -149,13 +131,9 @@ struct convex_hull<Box, Strategy, box_tag>
-template
-<
- order_selector Order,
- typename Geometry, typename Strategy
->
+template <order_selector Order, closure_selector Closure>
struct convex_hull_insert
- : detail::convex_hull::hull_insert<Geometry, Order, Strategy>
+ : detail::convex_hull::hull_insert<Order, Closure>
{};
@@ -163,29 +141,170 @@ struct convex_hull_insert
#endif // DOXYGEN_NO_DISPATCH
-template<typename Geometry, typename OutputGeometry, typename Strategy>
-inline void convex_hull(Geometry const& geometry,
- OutputGeometry& out, Strategy const& strategy)
+namespace resolve_strategy {
+
+struct convex_hull
{
- concept::check_concepts_and_equal_dimensions
- <
+ template <typename Geometry, typename OutputGeometry, typename Strategy>
+ static inline void apply(Geometry const& geometry,
+ OutputGeometry& out,
+ Strategy const& strategy)
+ {
+ BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
+ dispatch::convex_hull<Geometry>::apply(geometry, out, strategy);
+ }
+
+ template <typename Geometry, typename OutputGeometry>
+ static inline void apply(Geometry const& geometry,
+ OutputGeometry& out,
+ default_strategy)
+ {
+ typedef typename strategy_convex_hull<
+ Geometry,
+ typename point_type<Geometry>::type
+ >::type strategy_type;
+
+ apply(geometry, out, strategy_type());
+ }
+};
+
+struct convex_hull_insert
+{
+ template <typename Geometry, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Geometry const& geometry,
+ OutputIterator& out,
+ Strategy const& strategy)
+ {
+ BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
+
+ return dispatch::convex_hull_insert<
+ geometry::point_order<Geometry>::value,
+ geometry::closure<Geometry>::value
+ >::apply(geometry, out, strategy);
+ }
+
+ template <typename Geometry, typename OutputIterator>
+ static inline OutputIterator apply(Geometry const& geometry,
+ OutputIterator& out,
+ default_strategy)
+ {
+ typedef typename strategy_convex_hull<
+ Geometry,
+ typename point_type<Geometry>::type
+ >::type strategy_type;
+
+ return apply(geometry, out, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct convex_hull
+{
+ template <typename OutputGeometry, typename Strategy>
+ static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy)
+ {
+ concept::check_concepts_and_equal_dimensions<
const Geometry,
OutputGeometry
>();
- BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
+ resolve_strategy::convex_hull::apply(geometry, out, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct convex_hull<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename OutputGeometry, typename Strategy>
+ struct visitor: boost::static_visitor<void>
+ {
+ OutputGeometry& m_out;
+ Strategy const& m_strategy;
+
+ visitor(OutputGeometry& out, Strategy const& strategy)
+ : m_out(out), m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ convex_hull<Geometry>::apply(geometry, m_out, m_strategy);
+ }
+ };
+
+ template <typename OutputGeometry, typename Strategy>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ OutputGeometry& out,
+ Strategy const& strategy)
+ {
+ boost::apply_visitor(visitor<OutputGeometry, Strategy>(out, strategy), geometry);
+ }
+};
+
+template <typename Geometry>
+struct convex_hull_insert
+{
+ template <typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, Strategy const& strategy)
+ {
+ // Concept: output point type = point type of input geometry
+ concept::check<Geometry const>();
+ concept::check<typename point_type<Geometry>::type>();
+
+ return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct convex_hull_insert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename OutputIterator, typename Strategy>
+ struct visitor: boost::static_visitor<OutputIterator>
+ {
+ OutputIterator& m_out;
+ Strategy const& m_strategy;
+
+ visitor(OutputIterator& out, Strategy const& strategy)
+ : m_out(out), m_strategy(strategy)
+ {}
+ template <typename Geometry>
+ OutputIterator operator()(Geometry const& geometry) const
+ {
+ return convex_hull_insert<Geometry>::apply(geometry, m_out, m_strategy);
+ }
+ };
+
+ template <typename OutputIterator, typename Strategy>
+ static inline OutputIterator
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ OutputIterator& out,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<OutputIterator, Strategy>(out, strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+template<typename Geometry, typename OutputGeometry, typename Strategy>
+inline void convex_hull(Geometry const& geometry,
+ OutputGeometry& out, Strategy const& strategy)
+{
if (geometry::num_points(geometry) == 0)
{
// Leave output empty
return;
}
- dispatch::convex_hull
- <
- Geometry,
- Strategy
- >::apply(geometry, out, strategy);
+ resolve_variant::convex_hull<Geometry>::apply(geometry, out, strategy);
}
@@ -193,8 +312,8 @@ inline void convex_hull(Geometry const& geometry,
\brief \brief_calc{convex hull}
\ingroup convex_hull
\details \details_calc{convex_hull,convex hull}.
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
+\tparam Geometry the input geometry type
+\tparam OutputGeometry the output geometry type
\param geometry \param_geometry, input geometry
\param hull \param_geometry \param_set{convex hull}
@@ -204,15 +323,7 @@ template<typename Geometry, typename OutputGeometry>
inline void convex_hull(Geometry const& geometry,
OutputGeometry& hull)
{
- concept::check_concepts_and_equal_dimensions
- <
- const Geometry,
- OutputGeometry
- >();
-
- typedef typename detail::convex_hull::default_strategy<Geometry>::type strategy_type;
-
- convex_hull(geometry, hull, strategy_type());
+ convex_hull(geometry, hull, default_strategy());
}
#ifndef DOXYGEN_NO_DETAIL
@@ -224,17 +335,8 @@ template<typename Geometry, typename OutputIterator, typename Strategy>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out, Strategy const& strategy)
{
- // Concept: output point type = point type of input geometry
- concept::check<Geometry const>();
- concept::check<typename point_type<Geometry>::type>();
-
- BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
-
- return dispatch::convex_hull_insert
- <
- geometry::point_order<Geometry>::value,
- Geometry, Strategy
- >::apply(geometry, out, strategy);
+ return resolve_variant::convex_hull_insert<Geometry>
+ ::apply(geometry, out, strategy);
}
@@ -255,13 +357,7 @@ template<typename Geometry, typename OutputIterator>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out)
{
- // Concept: output point type = point type of input geometry
- concept::check<Geometry const>();
- concept::check<typename point_type<Geometry>::type>();
-
- typedef typename detail::convex_hull::default_strategy<Geometry>::type strategy_type;
-
- return convex_hull_insert(geometry, out, strategy_type());
+ return convex_hull_insert(geometry, out, default_strategy());
}
diff --git a/boost/geometry/algorithms/correct.hpp b/boost/geometry/algorithms/correct.hpp
index 583e395f8e..3c61b2c0d2 100644
--- a/boost/geometry/algorithms/correct.hpp
+++ b/boost/geometry/algorithms/correct.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -21,25 +22,37 @@
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/mutable_range.hpp>
-#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
-
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace correct
{
@@ -119,10 +132,8 @@ struct correct_ring
typedef detail::area::ring_area
<
- Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
- strategy_type
+ geometry::closure<Ring>::value
> ring_area_type;
@@ -139,7 +150,7 @@ struct correct_ring
{
geometry::append(r, *boost::begin(r));
}
- if (! disjoint && geometry::closure<Ring>::value != closed)
+ if (! disjoint && s != closed)
{
// Open it by removing last point
geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
@@ -172,9 +183,10 @@ struct correct_polygon
std::less<area_result_type>
>::apply(exterior_ring(poly));
- typename interior_return_type<Polygon>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
correct_ring
<
@@ -234,10 +246,69 @@ struct correct<Polygon, polygon_tag>
{};
+template <typename MultiPoint>
+struct correct<MultiPoint, multi_point_tag>
+ : detail::correct::correct_nop<MultiPoint>
+{};
+
+
+template <typename MultiLineString>
+struct correct<MultiLineString, multi_linestring_tag>
+ : detail::correct::correct_nop<MultiLineString>
+{};
+
+
+template <typename Geometry>
+struct correct<Geometry, multi_polygon_tag>
+ : detail::multi_modify
+ <
+ Geometry,
+ detail::correct::correct_polygon
+ <
+ typename boost::range_value<Geometry>::type
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct correct
+{
+ static inline void apply(Geometry& geometry)
+ {
+ concept::check<Geometry const>();
+ dispatch::correct<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<void>
+ {
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ correct<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
@@ -253,11 +324,12 @@ struct correct<Polygon, polygon_tag>
template <typename Geometry>
inline void correct(Geometry& geometry)
{
- concept::check<Geometry const>();
-
- dispatch::correct<Geometry>::apply(geometry);
+ resolve_variant::correct<Geometry>::apply(geometry);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/covered_by.hpp b/boost/geometry/algorithms/covered_by.hpp
index c3c406c4ca..e50dc338af 100644
--- a/boost/geometry/algorithms/covered_by.hpp
+++ b/boost/geometry/algorithms/covered_by.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,21 +14,52 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
#include <cstddef>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
namespace boost { namespace geometry
{
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace covered_by {
+
+struct use_point_in_geometry
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(geometry1, geometry2, strategy) >= 0;
+ }
+};
+
+struct use_relate
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& /*strategy*/)
+ {
+ return Strategy::apply(geometry1, geometry2);
+ }
+};
+
+}} // namespace detail::covered_by
+#endif // DOXYGEN_NO_DETAIL
+
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
@@ -37,7 +71,8 @@ template
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
-struct covered_by: not_implemented<Tag1, Tag2>
+struct covered_by
+ : not_implemented<Tag1, Tag2>
{};
@@ -47,6 +82,7 @@ struct covered_by<Point, Box, point_tag, box_tag>
template <typename Strategy>
static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
{
+ ::boost::ignore_unused_variable_warning(strategy);
return strategy.apply(point, box);
}
};
@@ -58,48 +94,332 @@ struct covered_by<Box1, Box2, box_tag, box_tag>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
assert_dimension_equal<Box1, Box2>();
+ ::boost::ignore_unused_variable_warning(strategy);
return strategy.apply(box1, box2);
}
};
+// P/P
+
+template <typename Point1, typename Point2>
+struct covered_by<Point1, Point2, point_tag, point_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPoint>
+struct covered_by<Point, MultiPoint, point_tag, multi_point_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+// P/L
+
+template <typename Point, typename Segment>
+struct covered_by<Point, Segment, point_tag, segment_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename Linestring>
+struct covered_by<Point, Linestring, point_tag, linestring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiLinestring>
+struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+// P/A
template <typename Point, typename Ring>
struct covered_by<Point, Ring, point_tag, ring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename Polygon>
+struct covered_by<Point, Polygon, point_tag, polygon_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPolygon>
+struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+// L/L
+
+template <typename Linestring1, typename Linestring2>
+struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename MultiLinestring>
+struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Linestring>
+struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring1, typename MultiLinestring2>
+struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+// L/A
+
+template <typename Linestring, typename Ring>
+struct covered_by<Linestring, Ring, linestring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Ring>
+struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename Polygon>
+struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Polygon>
+struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename MultiPolygon>
+struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename MultiPolygon>
+struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+// A/A
+
+template <typename Ring1, typename Ring2>
+struct covered_by<Ring1, Ring2, ring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Ring, typename Polygon>
+struct covered_by<Ring, Polygon, ring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon, typename Ring>
+struct covered_by<Polygon, Ring, polygon_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Ring, typename MultiPolygon>
+struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon, typename Ring>
+struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon, typename MultiPolygon>
+struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon, typename Polygon>
+struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon1, typename MultiPolygon2>
+struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy {
+
+struct covered_by
{
- template <typename Strategy>
- static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy)
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
{
- return detail::within::point_in_ring
+ concept::within::check
<
- Point,
- Ring,
- order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
Strategy
- >::apply(point, ring, strategy) >= 0;
+ >();
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+ assert_dimension_equal<Geometry1, Geometry2>();
+
+ return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1,
+ geometry2,
+ strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename point_type<Geometry1>::type point_type1;
+ typedef typename point_type<Geometry2>::type point_type2;
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag<Geometry1>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return covered_by::apply(geometry1, geometry2, strategy_type());
}
};
-template <typename Point, typename Polygon>
-struct covered_by<Point, Polygon, point_tag, polygon_tag>
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct covered_by
{
template <typename Strategy>
- static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy)
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
{
- return detail::within::point_in_polygon
- <
- Point,
- Polygon,
- order_as_direction<geometry::point_order<Polygon>::value>::value,
- geometry::closure<Polygon>::value,
- Strategy
- >::apply(point, polygon, strategy) >= 0;
+ return resolve_strategy::covered_by
+ ::apply(geometry1, geometry2, strategy);
}
};
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2), m_strategy(strategy) {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1), m_strategy(strategy) {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct covered_by<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
/*!
@@ -120,36 +440,8 @@ struct covered_by<Point, Polygon, point_tag, polygon_tag>
template<typename Geometry1, typename Geometry2>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- typedef typename point_type<Geometry1>::type point_type1;
- typedef typename point_type<Geometry2>::type point_type2;
-
- typedef typename strategy::covered_by::services::default_strategy
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<Geometry1>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- typename tag_cast
- <
- typename cs_tag<point_type1>::type, spherical_tag
- >::type,
- typename tag_cast
- <
- typename cs_tag<point_type2>::type, spherical_tag
- >::type,
- Geometry1,
- Geometry2
- >::type strategy_type;
-
- return dispatch::covered_by
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy_type());
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, default_strategy());
}
/*!
@@ -172,22 +464,8 @@ template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
- concept::within::check
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- Strategy
- >();
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- return dispatch::covered_by
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy);
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/crosses.hpp b/boost/geometry/algorithms/crosses.hpp
new file mode 100644
index 0000000000..91ed3e0806
--- /dev/null
+++ b/boost/geometry/algorithms/crosses.hpp
@@ -0,0 +1,194 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
+
+#include <cstddef>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/access.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/relate.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
+>
+struct crosses
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_crosses_type,
+ Geometry1,
+ Geometry2
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+ template <typename Geometry1, typename Geometry2>
+ struct crosses
+ {
+ static inline bool
+ apply(
+ const Geometry1& geometry1,
+ const Geometry2& geometry2)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return dispatch::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+ };
+
+
+ template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+ struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+ {
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2)
+ : m_geometry2(geometry2)
+ {}
+
+ template <typename Geometry1>
+ result_type operator()(Geometry1 const& geometry1) const
+ {
+ return crosses
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, m_geometry2);
+ }
+ };
+
+ static inline bool
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return apply_visitor(visitor(geometry2), geometry1);
+ }
+ };
+
+
+ template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+ struct crosses<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+ {
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1)
+ : m_geometry1(geometry1)
+ {}
+
+ template <typename Geometry2>
+ result_type operator()(Geometry2 const& geometry2) const
+ {
+ return crosses
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (m_geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(
+ Geometry1 const& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2)
+ {
+ return apply_visitor(visitor(geometry1), geometry2);
+ }
+ };
+
+
+ template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)>
+ struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> >
+ {
+ struct visitor: static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ result_type operator()(
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return crosses
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(
+ const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2)
+ {
+ return apply_visitor(visitor(), geometry1, geometry2);
+ }
+ };
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check2{crosses}
+\ingroup crosses
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{crosses}
+
+\qbk{[include reference/algorithms/crosses.qbk]}
+*/
+template <typename Geometry1, typename Geometry2>
+inline bool crosses(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
diff --git a/boost/geometry/algorithms/detail/assign_box_corners.hpp b/boost/geometry/algorithms/detail/assign_box_corners.hpp
index 1fd41733f2..669d6d3655 100644
--- a/boost/geometry/algorithms/detail/assign_box_corners.hpp
+++ b/boost/geometry/algorithms/detail/assign_box_corners.hpp
@@ -19,14 +19,14 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
-
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
-namespace detail
+namespace detail
{
// Note: this is moved to namespace detail because the names and parameter orders
// are not yet 100% clear.
@@ -67,20 +67,34 @@ inline void assign_box_corners(Box const& box,
<max_corner, max_corner>(box, upper_right);
}
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
+
template <bool Reverse, typename Box, typename Range>
inline void assign_box_corners_oriented(Box const& box, Range& corners)
{
if (Reverse)
{
// make counterclockwise ll,lr,ur,ul
- assign_box_corners(box, corners[0], corners[1], corners[3], corners[2]);
+ assign_box_corners(box,
+ range::at(corners, 0), range::at(corners, 1),
+ range::at(corners, 3), range::at(corners, 2));
}
else
{
// make clockwise ll,ul,ur,lr
- assign_box_corners(box, corners[0], corners[3], corners[1], corners[2]);
+ assign_box_corners(box,
+ range::at(corners, 0), range::at(corners, 3),
+ range::at(corners, 1), range::at(corners, 2));
}
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
} // namespace detail
diff --git a/boost/geometry/algorithms/detail/assign_indexed_point.hpp b/boost/geometry/algorithms/detail/assign_indexed_point.hpp
index a1cffb80a7..acfc37e250 100644
--- a/boost/geometry/algorithms/detail/assign_indexed_point.hpp
+++ b/boost/geometry/algorithms/detail/assign_indexed_point.hpp
@@ -25,7 +25,7 @@ namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
-namespace detail
+namespace detail
{
/*!
diff --git a/boost/geometry/algorithms/detail/assign_values.hpp b/boost/geometry/algorithms/detail/assign_values.hpp
index ed4713493f..5e4a1795b5 100644
--- a/boost/geometry/algorithms/detail/assign_values.hpp
+++ b/boost/geometry/algorithms/detail/assign_values.hpp
@@ -46,36 +46,30 @@ namespace detail { namespace assign
{
-template
-<
- typename Box, std::size_t Index,
- std::size_t Dimension, std::size_t DimensionCount
->
+template <std::size_t Index, std::size_t Dimension, std::size_t DimensionCount>
struct initialize
{
- typedef typename coordinate_type<Box>::type coordinate_type;
-
- static inline void apply(Box& box, coordinate_type const& value)
+ template <typename Box>
+ static inline void apply(Box& box, typename coordinate_type<Box>::type const& value)
{
geometry::set<Index, Dimension>(box, value);
- initialize<Box, Index, Dimension + 1, DimensionCount>::apply(box, value);
+ initialize<Index, Dimension + 1, DimensionCount>::apply(box, value);
}
};
-template <typename Box, std::size_t Index, std::size_t DimensionCount>
-struct initialize<Box, Index, DimensionCount, DimensionCount>
+template <std::size_t Index, std::size_t DimensionCount>
+struct initialize<Index, DimensionCount, DimensionCount>
{
- typedef typename coordinate_type<Box>::type coordinate_type;
-
- static inline void apply(Box&, coordinate_type const& )
+ template <typename Box>
+ static inline void apply(Box&, typename coordinate_type<Box>::type const&)
{}
};
-template <typename Point>
struct assign_zero_point
{
+ template <typename Point>
static inline void apply(Point& point)
{
geometry::assign_value(point, 0);
@@ -83,44 +77,38 @@ struct assign_zero_point
};
-template <typename BoxOrSegment>
struct assign_inverse_box_or_segment
{
- typedef typename point_type<BoxOrSegment>::type point_type;
+ template <typename BoxOrSegment>
static inline void apply(BoxOrSegment& geometry)
{
+ typedef typename point_type<BoxOrSegment>::type point_type;
typedef typename coordinate_type<point_type>::type bound_type;
- initialize
- <
- BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
- >::apply(
- geometry, boost::numeric::bounds<bound_type>::highest());
- initialize
- <
- BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
- >::apply(
- geometry, boost::numeric::bounds<bound_type>::lowest());
+ initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, boost::numeric::bounds<bound_type>::highest()
+ );
+ initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, boost::numeric::bounds<bound_type>::lowest()
+ );
}
};
-template <typename BoxOrSegment>
struct assign_zero_box_or_segment
{
+ template <typename BoxOrSegment>
static inline void apply(BoxOrSegment& geometry)
{
typedef typename coordinate_type<BoxOrSegment>::type coordinate_type;
- initialize
- <
- BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
- >::apply(geometry, coordinate_type());
- initialize
- <
- BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
- >::apply(geometry, coordinate_type());
+ initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, coordinate_type()
+ );
+ initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, coordinate_type()
+ );
}
};
@@ -312,17 +300,17 @@ struct assign_zero {};
template <typename Point>
struct assign_zero<point_tag, Point>
- : detail::assign::assign_zero_point<Point>
+ : detail::assign::assign_zero_point
{};
template <typename Box>
struct assign_zero<box_tag, Box>
- : detail::assign::assign_zero_box_or_segment<Box>
+ : detail::assign::assign_zero_box_or_segment
{};
template <typename Segment>
struct assign_zero<segment_tag, Segment>
- : detail::assign::assign_zero_box_or_segment<Segment>
+ : detail::assign::assign_zero_box_or_segment
{};
@@ -331,112 +319,18 @@ struct assign_inverse {};
template <typename Box>
struct assign_inverse<box_tag, Box>
- : detail::assign::assign_inverse_box_or_segment<Box>
+ : detail::assign::assign_inverse_box_or_segment
{};
template <typename Segment>
struct assign_inverse<segment_tag, Segment>
- : detail::assign::assign_inverse_box_or_segment<Segment>
+ : detail::assign::assign_inverse_box_or_segment
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
-
-/*!
-\brief Assign two coordinates to a geometry (usually a 2D point)
-\ingroup assign
-\tparam Geometry \tparam_geometry
-\tparam Type \tparam_numeric to specify the coordinates
-\param geometry \param_geometry
-\param c1 \param_x
-\param c2 \param_y
-
-\qbk{distinguish, 2 coordinate values}
-\qbk{
-[heading Example]
-[assign_2d_point] [assign_2d_point_output]
-
-[heading See also]
-\* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
-}
- */
-template <typename Geometry, typename Type>
-inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
-{
- concept::check<Geometry>();
-
- dispatch::assign
- <
- typename tag<Geometry>::type,
- Geometry,
- geometry::dimension<Geometry>::type::value
- >::apply(geometry, c1, c2);
-}
-
-/*!
-\brief Assign three values to a geometry (usually a 3D point)
-\ingroup assign
-\tparam Geometry \tparam_geometry
-\tparam Type \tparam_numeric to specify the coordinates
-\param geometry \param_geometry
-\param c1 \param_x
-\param c2 \param_y
-\param c3 \param_z
-
-\qbk{distinguish, 3 coordinate values}
-\qbk{
-[heading Example]
-[assign_3d_point] [assign_3d_point_output]
-
-[heading See also]
-\* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
-}
- */
-template <typename Geometry, typename Type>
-inline void assign_values(Geometry& geometry,
- Type const& c1, Type const& c2, Type const& c3)
-{
- concept::check<Geometry>();
-
- dispatch::assign
- <
- typename tag<Geometry>::type,
- Geometry,
- geometry::dimension<Geometry>::type::value
- >::apply(geometry, c1, c2, c3);
-}
-
-/*!
-\brief Assign four values to a geometry (usually a box or segment)
-\ingroup assign
-\tparam Geometry \tparam_geometry
-\tparam Type \tparam_numeric to specify the coordinates
-\param geometry \param_geometry
-\param c1 First coordinate (usually x1)
-\param c2 Second coordinate (usually y1)
-\param c3 Third coordinate (usually x2)
-\param c4 Fourth coordinate (usually y2)
-
-\qbk{distinguish, 4 coordinate values}
- */
-template <typename Geometry, typename Type>
-inline void assign_values(Geometry& geometry,
- Type const& c1, Type const& c2, Type const& c3, Type const& c4)
-{
- concept::check<Geometry>();
-
- dispatch::assign
- <
- typename tag<Geometry>::type,
- Geometry,
- geometry::dimension<Geometry>::type::value
- >::apply(geometry, c1, c2, c3, c4);
-}
-
-
-
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
new file mode 100644
index 0000000000..c959ee849b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
@@ -0,0 +1,940 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
+
+#include <cstddef>
+#include <iterator>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/strategies/side.hpp>
+#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
+#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
+#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
+
+#include <boost/geometry/algorithms/simplify.hpp>
+
+#include <boost/geometry/views/detail/normalized_view.hpp>
+
+#if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
+#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+template <typename Range, typename DistanceStrategy>
+inline void simplify_input(Range const& range,
+ DistanceStrategy const& distance,
+ Range& simplified)
+{
+ // We have to simplify the ring before to avoid very small-scaled
+ // features in the original (convex/concave/convex) being enlarged
+ // in a very large scale and causing issues (IP's within pieces).
+ // This might be reconsidered later. Simplifying with a very small
+ // distance (1%% of the buffer) will never be visible in the result,
+ // if it is using round joins. For miter joins they are even more
+ // sensitive to small scale input features, however the result will
+ // look better.
+ // It also gets rid of duplicate points
+#if ! defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
+ geometry::simplify(range, simplified, distance.simplify_distance());
+#else
+
+ typedef typename boost::range_value<Range>::type point_type;
+ typedef strategy::distance::detail::projected_point_ax<> ax_type;
+ typedef typename strategy::distance::services::return_type
+ <
+ strategy::distance::detail::projected_point_ax<>,
+ point_type,
+ point_type
+ >::type return_type;
+
+ typedef strategy::distance::detail::projected_point_ax_less
+ <
+ return_type
+ > comparator_type;
+
+ typedef strategy::simplify::detail::douglas_peucker
+ <
+ point_type,
+ strategy::distance::detail::projected_point_ax<>,
+ comparator_type
+ > dp_ax;
+
+ return_type max_distance(distance.simplify_distance() * 2.0,
+ distance.simplify_distance());
+ comparator_type comparator(max_distance);
+ dp_ax strategy(comparator);
+
+ geometry::simplify(range, simplified, max_distance, strategy);
+#endif
+
+ if (boost::size(simplified) == 2
+ && geometry::equals(geometry::range::front(simplified),
+ geometry::range::back(simplified)))
+ {
+ traits::resize<Range>::apply(simplified, 1);
+ }
+}
+
+
+template <typename RingOutput>
+struct buffer_range
+{
+ typedef typename point_type<RingOutput>::type output_point_type;
+ typedef typename coordinate_type<RingOutput>::type coordinate_type;
+
+ template
+ <
+ typename Collection,
+ typename Point,
+ typename DistanceStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline
+ void add_join(Collection& collection,
+ Point const& penultimate_input,
+ Point const& previous_input,
+ output_point_type const& prev_perp1,
+ output_point_type const& prev_perp2,
+ Point const& input,
+ output_point_type const& perp1,
+ output_point_type const& perp2,
+ strategy::buffer::buffer_side_selector side,
+ DistanceStrategy const& distance,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ RobustPolicy const& )
+ {
+ output_point_type intersection_point;
+
+ strategy::buffer::join_selector join
+ = get_join_type(penultimate_input, previous_input, input);
+ if (join == strategy::buffer::join_convex)
+ {
+ // Calculate the intersection-point formed by the two sides.
+ // It might be that the two sides are not convex, but continue
+ // or spikey, we then change the join-type
+ join = line_line_intersection::apply(
+ perp1, perp2, prev_perp1, prev_perp2,
+ intersection_point);
+
+ }
+ switch(join)
+ {
+ case strategy::buffer::join_continue :
+ // No join, we get two consecutive sides
+ return;
+ case strategy::buffer::join_concave :
+ collection.add_piece(strategy::buffer::buffered_concave,
+ previous_input, prev_perp2, perp1);
+ return;
+ case strategy::buffer::join_spike :
+ {
+ // For linestrings, only add spike at one side to avoid
+ // duplicates
+ std::vector<output_point_type> range_out;
+ end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out);
+ collection.add_endcap(end_strategy, range_out, previous_input);
+ }
+ return;
+ case strategy::buffer::join_convex :
+ break; // All code below handles this
+ }
+
+ // The corner is convex, we create a join
+ // TODO (future) - avoid a separate vector, add the piece directly
+ std::vector<output_point_type> range_out;
+ if (join_strategy.apply(intersection_point,
+ previous_input, prev_perp2, perp1,
+ distance.apply(previous_input, input, side),
+ range_out))
+ {
+ collection.add_piece(strategy::buffer::buffered_join,
+ previous_input, range_out);
+ }
+ }
+
+ static inline strategy::buffer::join_selector get_join_type(
+ output_point_type const& p0,
+ output_point_type const& p1,
+ output_point_type const& p2)
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<output_point_type>::type
+ >::type side_strategy;
+
+ int const side = side_strategy::apply(p0, p1, p2);
+ return side == -1 ? strategy::buffer::join_convex
+ : side == 1 ? strategy::buffer::join_concave
+ : parallel_continue
+ (
+ get<0>(p2) - get<0>(p1),
+ get<1>(p2) - get<1>(p1),
+ get<0>(p1) - get<0>(p0),
+ get<1>(p1) - get<1>(p0)
+ ) ? strategy::buffer::join_continue
+ : strategy::buffer::join_spike;
+ }
+
+ template
+ <
+ typename Collection,
+ typename Iterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline bool iterate(Collection& collection,
+ Iterator begin, Iterator end,
+ strategy::buffer::buffer_side_selector side,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ RobustPolicy const& robust_policy,
+ output_point_type& first_p1,
+ output_point_type& first_p2,
+ output_point_type& last_p1,
+ output_point_type& last_p2)
+ {
+ typedef typename std::iterator_traits
+ <
+ Iterator
+ >::value_type point_type;
+
+ typedef typename robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type previous_robust_input;
+ point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
+
+ /*
+ * last.p1 last.p2 these are the "previous (last) perpendicular points"
+ * --------------
+ * | |
+ * *------------*____ <- *prev
+ * pup | | p1 "current perpendicular point 1"
+ * | |
+ * | | this forms a "side", a side is a piece
+ * | |
+ * *____| p2
+ *
+ * ^
+ * *it
+ *
+ * pup: penultimate_point
+ */
+
+ bool result = false;
+ bool first = true;
+
+ Iterator it = begin;
+
+ geometry::recalculate(previous_robust_input, *begin, robust_policy);
+
+ std::vector<output_point_type> generated_side;
+ generated_side.reserve(2);
+
+ for (Iterator prev = it++; it != end; ++it)
+ {
+ robust_point_type robust_input;
+ geometry::recalculate(robust_input, *it, robust_policy);
+ // Check on equality - however, if input is simplified, this is
+ // unlikely (though possible by rescaling or for degenerated pointlike polygons)
+ if (! detail::equals::equals_point_point(previous_robust_input, robust_input))
+ {
+ generated_side.clear();
+ side_strategy.apply(*prev, *it, side,
+ distance_strategy, generated_side);
+
+ if (generated_side.empty())
+ {
+ break;
+ }
+
+ result = true;
+
+ if (! first)
+ {
+ add_join(collection,
+ penultimate_point,
+ *prev, last_p1, last_p2,
+ *it, generated_side.front(), generated_side.back(),
+ side,
+ distance_strategy, join_strategy, end_strategy,
+ robust_policy);
+ }
+
+ collection.add_side_piece(*prev, *it, generated_side, first);
+
+ penultimate_point = *prev;
+ ultimate_point = *it;
+ last_p1 = generated_side.front();
+ last_p2 = generated_side.back();
+ prev = it;
+ if (first)
+ {
+ first = false;
+ second_point = *it;
+ first_p1 = generated_side.front();
+ first_p2 = generated_side.back();
+ }
+ }
+ previous_robust_input = robust_input;
+ }
+ return result;
+ }
+};
+
+template
+<
+ typename Multi,
+ typename PolygonOutput,
+ typename Policy
+>
+struct buffer_multi
+{
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(Multi const& multi,
+ Collection& collection,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+ {
+ for (typename boost::range_iterator<Multi const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, collection,
+ distance_strategy, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ }
+ }
+};
+
+struct visit_pieces_default_policy
+{
+ template <typename Collection>
+ static inline void apply(Collection const&, int)
+ {}
+};
+
+template
+<
+ typename OutputPointType,
+ typename Point,
+ typename Collection,
+ typename DistanceStrategy,
+ typename PointStrategy
+>
+inline void buffer_point(Point const& point, Collection& collection,
+ DistanceStrategy const& distance_strategy,
+ PointStrategy const& point_strategy)
+{
+ collection.start_new_ring();
+ std::vector<OutputPointType> range_out;
+ point_strategy.apply(point, distance_strategy, range_out);
+ collection.add_piece(strategy::buffer::buffered_point, range_out, false);
+ collection.finish_ring();
+}
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Tag,
+ typename RingInput,
+ typename RingOutput
+>
+struct buffer_inserter
+{};
+
+
+
+template
+<
+ typename Point,
+ typename RingOutput
+>
+struct buffer_inserter<point_tag, Point, RingOutput>
+{
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(Point const& point, Collection& collection,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& ,
+ JoinStrategy const& ,
+ EndStrategy const& ,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& )
+ {
+ detail::buffer::buffer_point
+ <
+ typename point_type<RingOutput>::type
+ >(point, collection, distance_strategy, point_strategy);
+ }
+};
+
+
+template
+<
+ typename RingInput,
+ typename RingOutput
+>
+struct buffer_inserter<ring_tag, RingInput, RingOutput>
+{
+ typedef typename point_type<RingOutput>::type output_point_type;
+
+ template
+ <
+ typename Collection,
+ typename Iterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline bool iterate(Collection& collection,
+ Iterator begin, Iterator end,
+ strategy::buffer::buffer_side_selector side,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ RobustPolicy const& robust_policy)
+ {
+ output_point_type first_p1, first_p2, last_p1, last_p2;
+
+ typedef detail::buffer::buffer_range<RingOutput> buffer_range;
+
+ bool result = buffer_range::iterate(collection, begin, end,
+ side,
+ distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1, first_p2, last_p1, last_p2);
+
+ // Generate closing join
+ if (result)
+ {
+ buffer_range::add_join(collection,
+ *(end - 2),
+ *(end - 1), last_p1, last_p2,
+ *(begin + 1), first_p1, first_p2,
+ side,
+ distance_strategy, join_strategy, end_strategy,
+ robust_policy);
+ }
+
+ // Buffer is closed automatically by last closing corner
+ return result;
+ }
+
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(RingInput const& ring,
+ Collection& collection,
+ DistanceStrategy const& distance,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+ {
+ RingInput simplified;
+ detail::buffer::simplify_input(ring, distance, simplified);
+
+ bool has_output = false;
+
+ std::size_t n = boost::size(simplified);
+ std::size_t const min_points = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<RingInput>::value
+ >::value;
+
+ if (n >= min_points)
+ {
+ detail::normalized_view<RingInput const> view(simplified);
+ if (distance.negative())
+ {
+ // Walk backwards (rings will be reversed afterwards)
+ // It might be that this will be changed later.
+ // TODO: decide this.
+ has_output = iterate(collection, boost::rbegin(view), boost::rend(view),
+ strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ }
+ else
+ {
+ has_output = iterate(collection, boost::begin(view), boost::end(view),
+ strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ }
+ }
+
+ if (! has_output && n >= 1)
+ {
+ // Use point_strategy to buffer degenerated ring
+ detail::buffer::buffer_point<output_point_type>
+ (
+ geometry::range::front(simplified),
+ collection, distance, point_strategy
+ );
+ }
+ }
+};
+
+
+template
+<
+ typename Linestring,
+ typename Polygon
+>
+struct buffer_inserter<linestring_tag, Linestring, Polygon>
+{
+ typedef typename ring_type<Polygon>::type output_ring_type;
+ typedef typename point_type<output_ring_type>::type output_point_type;
+ typedef typename point_type<Linestring>::type input_point_type;
+
+ template
+ <
+ typename Collection,
+ typename Iterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline bool iterate(Collection& collection,
+ Iterator begin, Iterator end,
+ strategy::buffer::buffer_side_selector side,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ RobustPolicy const& robust_policy,
+ output_point_type& first_p1)
+ {
+ input_point_type const& ultimate_point = *(end - 1);
+ input_point_type const& penultimate_point = *(end - 2);
+
+ // For the end-cap, we need to have the last perpendicular point on the
+ // other side of the linestring. If it is the second pass (right),
+ // we have it already from the first phase (left).
+ // But for the first pass, we have to generate it
+ output_point_type reverse_p1;
+ if (side == strategy::buffer::buffer_side_right)
+ {
+ reverse_p1 = first_p1;
+ }
+ else
+ {
+ std::vector<output_point_type> generated_side;
+ side_strategy.apply(ultimate_point, penultimate_point,
+ strategy::buffer::buffer_side_right,
+ distance_strategy, generated_side);
+ if (generated_side.empty())
+ {
+ return false;
+ }
+ reverse_p1 = generated_side.front();
+ }
+
+ output_point_type first_p2, last_p1, last_p2;
+
+ detail::buffer::buffer_range<output_ring_type>::iterate(collection,
+ begin, end, side,
+ distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1, first_p2, last_p1, last_p2);
+
+ std::vector<output_point_type> range_out;
+ end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
+ collection.add_endcap(end_strategy, range_out, ultimate_point);
+ return true;
+ }
+
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(Linestring const& linestring, Collection& collection,
+ DistanceStrategy const& distance,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+ {
+ Linestring simplified;
+ detail::buffer::simplify_input(linestring, distance, simplified);
+
+ bool has_output = false;
+ std::size_t n = boost::size(simplified);
+ if (n > 1)
+ {
+ collection.start_new_ring();
+ output_point_type first_p1;
+ has_output = iterate(collection,
+ boost::begin(simplified), boost::end(simplified),
+ strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1);
+
+ if (has_output)
+ {
+ iterate(collection, boost::rbegin(simplified), boost::rend(simplified),
+ strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1);
+ }
+ collection.finish_ring();
+ }
+ if (! has_output && n >= 1)
+ {
+ // Use point_strategy to buffer degenerated linestring
+ detail::buffer::buffer_point<output_point_type>
+ (
+ geometry::range::front(simplified),
+ collection, distance, point_strategy
+ );
+ }
+ }
+};
+
+
+template
+<
+ typename PolygonInput,
+ typename PolygonOutput
+>
+struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
+{
+private:
+ typedef typename ring_type<PolygonInput>::type input_ring_type;
+ typedef typename ring_type<PolygonOutput>::type output_ring_type;
+
+ typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy;
+
+
+ template
+ <
+ typename Iterator,
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline
+ void iterate(Iterator begin, Iterator end,
+ Collection& collection,
+ DistanceStrategy const& distance,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy,
+ bool is_interior)
+ {
+ for (Iterator it = begin; it != end; ++it)
+ {
+ collection.start_new_ring();
+ policy::apply(*it, collection, distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ collection.finish_ring(is_interior);
+ }
+ }
+
+ template
+ <
+ typename InteriorRings,
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline
+ void apply_interior_rings(InteriorRings const& interior_rings,
+ Collection& collection,
+ DistanceStrategy const& distance,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+ {
+ iterate(boost::begin(interior_rings), boost::end(interior_rings),
+ collection, distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy, true);
+ }
+
+public:
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(PolygonInput const& polygon,
+ Collection& collection,
+ DistanceStrategy const& distance,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+ {
+ {
+ collection.start_new_ring();
+ policy::apply(exterior_ring(polygon), collection,
+ distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ collection.finish_ring();
+ }
+
+ apply_interior_rings(interior_rings(polygon),
+ collection, distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ }
+};
+
+
+template
+<
+ typename Multi,
+ typename PolygonOutput
+>
+struct buffer_inserter<multi_tag, Multi, PolygonOutput>
+ : public detail::buffer::buffer_multi
+ <
+ Multi,
+ PolygonOutput,
+ dispatch::buffer_inserter
+ <
+ typename single_tag_of
+ <
+ typename tag<Multi>::type
+ >::type,
+ typename boost::range_value<Multi const>::type,
+ typename geometry::ring_type<PolygonOutput>::type
+ >
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+template
+<
+ typename GeometryOutput,
+ typename GeometryInput,
+ typename OutputIterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy,
+ typename VisitPiecesPolicy
+>
+inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy,
+ VisitPiecesPolicy& visit_pieces_policy
+ )
+{
+ typedef detail::buffer::buffered_piece_collection
+ <
+ typename geometry::ring_type<GeometryOutput>::type,
+ RobustPolicy
+ > collection_type;
+ collection_type collection(robust_policy);
+ collection_type const& const_collection = collection;
+
+ bool const areal = boost::is_same
+ <
+ typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
+ areal_tag
+ >::type::value;
+
+ dispatch::buffer_inserter
+ <
+ typename tag_cast
+ <
+ typename tag<GeometryInput>::type,
+ multi_tag
+ >::type,
+ GeometryInput,
+ GeometryOutput
+ >::apply(geometry_input, collection,
+ distance_strategy, side_strategy, join_strategy,
+ end_strategy, point_strategy,
+ robust_policy);
+
+ collection.get_turns();
+ if (areal)
+ {
+ collection.check_remaining_points(distance_strategy.factor());
+ }
+
+ // Visit the piece collection. This does nothing (by default), but
+ // optionally a debugging tool can be attached (e.g. console or svg),
+ // or the piece collection can be unit-tested
+ // phase 0: turns (before discarded)
+ visit_pieces_policy.apply(const_collection, 0);
+
+ collection.discard_rings();
+ collection.block_turns();
+ collection.enrich();
+ collection.traverse();
+
+ // Reverse all offsetted rings / traversed rings if:
+ // - they were generated on the negative side (deflate) of polygons
+ // - the output is counter clockwise
+ // and avoid reversing twice
+ bool reverse = distance_strategy.negative() && areal;
+ if (geometry::point_order<GeometryOutput>::value == counterclockwise)
+ {
+ reverse = ! reverse;
+ }
+ if (reverse)
+ {
+ collection.reverse();
+ }
+
+ collection.template assign<GeometryOutput>(out);
+
+ // Visit collection again
+ // phase 1: rings (after discarding and traversing)
+ visit_pieces_policy.apply(const_collection, 1);
+}
+
+template
+<
+ typename GeometryOutput,
+ typename GeometryInput,
+ typename OutputIterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+>
+inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+{
+ detail::buffer::visit_pieces_default_policy visitor;
+ buffer_inserter<GeometryOutput>(geometry_input, out,
+ distance_strategy, side_strategy, join_strategy,
+ end_strategy, point_strategy,
+ robust_policy, visitor);
+}
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace detail::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp
new file mode 100644
index 0000000000..6a2e6b32c5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp
@@ -0,0 +1,171 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+enum intersection_location_type
+{
+ location_ok, inside_buffer, inside_original
+};
+
+class backtrack_for_buffer
+{
+public :
+ typedef detail::overlay::backtrack_state state_type;
+
+ template <typename Operation, typename Rings, typename Turns, typename Geometry, typename RobustPolicy>
+ static inline void apply(std::size_t size_at_start,
+ Rings& rings, typename boost::range_value<Rings>::type& ring,
+ Turns& turns, Operation& operation,
+ std::string const& /*reason*/,
+ Geometry const& ,
+ Geometry const& ,
+ RobustPolicy const& ,
+ state_type& state
+ )
+ {
+#if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS)
+extern int g_backtrack_warning_count;
+g_backtrack_warning_count++;
+#endif
+//std::cout << "!";
+//std::cout << "WARNING " << reason << std::endl;
+
+ state.m_good = false;
+
+ // Make bad output clean
+ rings.resize(size_at_start);
+ ring.clear();
+
+ // Reject this as a starting point
+ operation.visited.set_rejected();
+
+ // And clear all visit info
+ clear_visit_info(turns);
+ }
+};
+
+// Should follow traversal-turn-concept (enrichment, visit structure)
+// and adds index in piece vector to find it back
+template <typename Point, typename SegmentRatio>
+struct buffer_turn_operation
+ : public detail::overlay::traversal_turn_operation<Point, SegmentRatio>
+{
+ int piece_index;
+ int index_in_robust_ring;
+
+ inline buffer_turn_operation()
+ : piece_index(-1)
+ , index_in_robust_ring(-1)
+ {}
+};
+
+// Version for buffer including type of location, is_opposite, and helper variables
+template <typename Point, typename RobustPoint, typename SegmentRatio>
+struct buffer_turn_info
+ : public detail::overlay::turn_info
+ <
+ Point,
+ SegmentRatio,
+ buffer_turn_operation<Point, SegmentRatio>
+ >
+{
+ typedef Point point_type;
+ typedef RobustPoint robust_point_type;
+
+ int turn_index; // TODO: this might go if partition can operate on non-const input
+
+ RobustPoint robust_point;
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // Will (most probably) be removed later
+ RobustPoint mapped_robust_point; // alas... we still need to adapt our points, offsetting them 1 integer to be co-located with neighbours
+#endif
+
+
+ inline RobustPoint const& get_robust_point() const
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ return mapped_robust_point;
+#endif
+ return robust_point;
+ }
+
+
+ intersection_location_type location;
+
+ int count_within;
+ int count_on_offsetted;
+ int count_on_helper;
+ int count_within_near_offsetted;
+
+ bool remove_on_multi;
+
+ // Obsolete:
+ int count_on_occupied;
+ int count_on_multi;
+
+ inline buffer_turn_info()
+ : turn_index(-1)
+ , location(location_ok)
+ , count_within(0)
+ , count_on_offsetted(0)
+ , count_on_helper(0)
+ , count_within_near_offsetted(0)
+ , remove_on_multi(false)
+ , count_on_occupied(0)
+ , count_on_multi(0)
+ {}
+};
+
+struct buffer_operation_less
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ segment_identifier const& sl = left.seg_id;
+ segment_identifier const& sr = right.seg_id;
+
+ // Sort them descending
+ return sl == sr
+ ? left.fraction < right.fraction
+ : sl < sr;
+ }
+};
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
new file mode 100644
index 0000000000..558a61fcb4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -0,0 +1,954 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
+
+#include <algorithm>
+#include <cstddef>
+#include <set>
+#include <boost/range.hpp>
+
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+#include <boost/geometry/geometries/ring.hpp>
+#include <boost/geometry/geometries/polygon.hpp>
+
+#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
+#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
+#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
+#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
+#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/occupation_info.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+enum segment_relation_code
+{
+ segment_relation_on_left,
+ segment_relation_on_right,
+ segment_relation_within,
+ segment_relation_disjoint
+};
+
+/*
+ * Terminology
+ *
+ * Suppose we make a buffer (using blocked corners) of this rectangle:
+ *
+ * +-------+
+ * | |
+ * | rect |
+ * | |
+ * +-------+
+ *
+ * For the sides we get these four buffered side-pieces (marked with s)
+ * and four buffered corner pieces (marked with c)
+ *
+ * c---+---s---+---c
+ * | | piece | | <- see below for details of the middle top-side-piece
+ * +---+-------+---+
+ * | | | |
+ * s | rect | s <- two side pieces left/right of rect
+ * | | | |
+ * +---+-------+---+
+ * | | piece | | <- one side-piece below, and two corner pieces
+ * c---+---s---+---c
+ *
+ * The outer part of the picture above, using all pieces,
+ * form together the offsetted ring (marked with o below)
+ * The 8 pieces are part of the piece collection and use for inside-checks
+ * The inner parts form (using 1 or 2 points per piece, often co-located)
+ * form together the robust_ring (marked with r below)
+ * The remaining piece-segments are helper-segments (marked with h)
+ *
+ * ooooooooooooooooo
+ * o h h o
+ * ohhhrrrrrrrrrhhho
+ * o r r o
+ * o r r o
+ * o r r o
+ * ohhhrrrrrrrrrhhho
+ * o h h o
+ * ooooooooooooooooo
+ *
+ */
+
+
+template <typename Ring, typename RobustPolicy>
+struct buffered_piece_collection
+{
+ typedef buffered_piece_collection<Ring, RobustPolicy> this_type;
+
+ typedef typename geometry::point_type<Ring>::type point_type;
+ typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
+ typedef typename geometry::robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // Robust ring/polygon type, always clockwise
+ typedef geometry::model::ring<robust_point_type> robust_ring_type;
+ typedef geometry::model::polygon<robust_point_type> robust_polygon_type;
+
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<point_type>::type
+ >::type side_strategy;
+
+ typedef typename geometry::rescale_policy_type
+ <
+ typename geometry::point_type<Ring>::type
+ >::type rescale_policy_type;
+
+ typedef typename geometry::segment_ratio_type
+ <
+ point_type,
+ RobustPolicy
+ >::type segment_ratio_type;
+
+ typedef buffer_turn_info
+ <
+ point_type,
+ robust_point_type,
+ segment_ratio_type
+ > buffer_turn_info_type;
+
+ typedef buffer_turn_operation
+ <
+ point_type,
+ segment_ratio_type
+ > buffer_turn_operation_type;
+
+ typedef std::vector<buffer_turn_info_type> turn_vector_type;
+
+ struct robust_turn
+ {
+ int turn_index;
+ int operation_index;
+ robust_point_type point;
+ segment_identifier seg_id;
+ segment_ratio_type fraction;
+ };
+
+ struct piece
+ {
+ strategy::buffer::piece_type type;
+ int index;
+
+ int left_index; // points to previous piece of same ring
+ int right_index; // points to next piece of same ring
+
+ // The next two members (1, 2) form together a complete clockwise ring
+ // for each piece (with one dupped point)
+ // The complete clockwise ring is also included as a robust ring (3)
+
+ // 1: half, part of offsetted_rings
+ segment_identifier first_seg_id;
+ int last_segment_index; // no segment-identifier - it is the same as first_seg_id
+ int offsetted_count; // part in robust_ring which is part of offsetted ring
+
+#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
+ // 2: half, not part of offsetted rings - part of robust ring
+ std::vector<point_type> helper_points; // 4 points for segment, 3 points for join - 0 points for flat-end
+#endif
+
+ // Robust representations
+ // 3: complete ring
+ robust_ring_type robust_ring;
+
+ geometry::model::box<robust_point_type> robust_envelope;
+
+ std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead
+ };
+
+ typedef std::vector<piece> piece_vector_type;
+
+ piece_vector_type m_pieces;
+ turn_vector_type m_turns;
+ int m_first_piece_index;
+
+ buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
+ buffered_ring_collection<robust_polygon_type> robust_polygons; // robust representation of the original(s)
+ robust_ring_type current_robust_ring;
+ buffered_ring_collection<Ring> traversed_rings;
+ segment_identifier current_segment_id;
+
+ RobustPolicy const& m_robust_policy;
+
+ struct redundant_turn
+ {
+ inline bool operator()(buffer_turn_info_type const& turn) const
+ {
+ return turn.remove_on_multi;
+ }
+ };
+
+ buffered_piece_collection(RobustPolicy const& robust_policy)
+ : m_first_piece_index(-1)
+ , m_robust_policy(robust_policy)
+ {}
+
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // Will (most probably) be removed later
+ template <typename OccupationMap>
+ inline void adapt_mapped_robust_point(OccupationMap const& map,
+ buffer_turn_info_type& turn, int distance) const
+ {
+ for (int x = -distance; x <= distance; x++)
+ {
+ for (int y = -distance; y <= distance; y++)
+ {
+ robust_point_type rp = turn.robust_point;
+ geometry::set<0>(rp, geometry::get<0>(rp) + x);
+ geometry::set<1>(rp, geometry::get<1>(rp) + y);
+ if (map.find(rp) != map.end())
+ {
+ turn.mapped_robust_point = rp;
+ return;
+ }
+ }
+ }
+ }
+#endif
+
+ inline void get_occupation(
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ int distance = 0
+#endif
+ )
+ {
+ typedef occupation_info<angle_info<robust_point_type, coordinate_type> >
+ buffer_occupation_info;
+
+ typedef std::map
+ <
+ robust_point_type,
+ buffer_occupation_info,
+ geometry::less<robust_point_type>
+ > occupation_map_type;
+
+ occupation_map_type occupation_map;
+
+ // 1: Add all intersection points to occupation map
+ typedef typename boost::range_iterator<turn_vector_type>::type
+ iterator_type;
+
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ if (it->location == location_ok)
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ if (distance > 0 && ! occupation_map.empty())
+ {
+ adapt_mapped_robust_point(occupation_map, *it, distance);
+ }
+#endif
+ occupation_map[it->get_robust_point()].count++;
+ }
+ }
+
+ // Remove all points with one or more u/u points from the map
+ // (Alternatively, we could NOT do this here and change all u/u
+ // behaviour in overlay. Currently nothing is done: each polygon is
+ // just followed there. We could also always switch polygons there. For
+ // buffer behaviour, where 3 pieces might meet of which 2 (or more) form
+ // a u/u turn, this last option would have been better, probably).
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ if (it->both(detail::overlay::operation_union))
+ {
+ typename occupation_map_type::iterator mit =
+ occupation_map.find(it->get_robust_point());
+
+ if (mit != occupation_map.end())
+ {
+ occupation_map.erase(mit);
+ }
+ }
+ }
+
+ // 2: Remove all points from map which has only one
+ typename occupation_map_type::iterator it = occupation_map.begin();
+ while (it != occupation_map.end())
+ {
+ if (it->second.count <= 1)
+ {
+ typename occupation_map_type::iterator to_erase = it;
+ ++it;
+ occupation_map.erase(to_erase);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ if (occupation_map.empty())
+ {
+ return;
+ }
+
+ // 3: Add vectors (incoming->intersection-point,
+ // intersection-point -> outgoing)
+ // for all (co-located) points still present in the map
+
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ typename occupation_map_type::iterator mit =
+ occupation_map.find(it->get_robust_point());
+
+ if (mit != occupation_map.end())
+ {
+ buffer_occupation_info& info = mit->second;
+ for (int i = 0; i < 2; i++)
+ {
+ add_incoming_and_outgoing_angles(it->get_robust_point(), *it,
+ m_pieces,
+ i, it->operations[i].seg_id,
+ info);
+ }
+
+ it->count_on_multi++;
+ }
+ }
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // X: Check rounding issues
+ if (distance == 0)
+ {
+ for (typename occupation_map_type::const_iterator it = occupation_map.begin();
+ it != occupation_map.end(); ++it)
+ {
+ if (it->second.has_rounding_issues(it->first))
+ {
+ if(distance == 0)
+ {
+ get_occupation(distance + 1);
+ return;
+ }
+ }
+ }
+ }
+#endif
+
+ // Get left turns from all clusters
+ for (typename occupation_map_type::iterator it = occupation_map.begin();
+ it != occupation_map.end(); ++it)
+ {
+ it->second.get_left_turns(it->first, m_turns);
+ }
+ }
+
+ inline void classify_turns()
+ {
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->count_within > 0)
+ {
+ it->location = inside_buffer;
+ }
+ if (it->count_within_near_offsetted > 0)
+ {
+ // Within can have in rare cases a rounding issue. We don't discard this
+ // point, so it can be used to continue started rings in traversal. But
+ // will never start a new ring from this type of points.
+ it->selectable_start = false;
+ }
+
+ }
+ }
+
+ inline void check_remaining_points(int factor)
+ {
+ // TODO: use partition
+
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location == location_ok)
+ {
+ int code = -1;
+ for (std::size_t i = 0; i < robust_polygons.size(); i++)
+ {
+ if (geometry::covered_by(it->robust_point, robust_polygons[i]))
+ {
+ code = 1;
+ break;
+ }
+ }
+ if (code * factor == 1)
+ {
+ it->location = inside_original;
+ }
+ }
+ }
+ }
+
+ inline bool assert_indices_in_robust_rings() const
+ {
+ geometry::equal_to<robust_point_type> comparator;
+ for (typename boost::range_iterator<turn_vector_type const>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ robust_point_type const &p1
+ = m_pieces[it->operations[i].piece_index].robust_ring
+ [it->operations[i].index_in_robust_ring];
+ robust_point_type const &p2 = it->robust_point;
+ if (! comparator(p1, p2))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ inline void insert_rescaled_piece_turns()
+ {
+ // Add rescaled turn points to corresponding pieces
+ // (after this, each turn occurs twice)
+ int index = 0;
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
+ {
+ geometry::recalculate(it->robust_point, it->point, m_robust_policy);
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ it->mapped_robust_point = it->robust_point;
+#endif
+
+ robust_turn turn;
+ it->turn_index = index;
+ turn.turn_index = index;
+ turn.point = it->robust_point;
+ for (int i = 0; i < 2; i++)
+ {
+ turn.operation_index = i;
+ turn.seg_id = it->operations[i].seg_id;
+ turn.fraction = it->operations[i].fraction;
+
+ piece& pc = m_pieces[it->operations[i].piece_index];
+ pc.robust_turns.push_back(turn);
+
+ // Take into account for the box (intersection points should fall inside,
+ // but in theory they can be one off because of rounding
+ geometry::expand(pc.robust_envelope, it->robust_point);
+ }
+ }
+
+ // Insert all rescaled turn-points into these rings, to form a
+ // reliable integer-based ring. All turns can be compared (inside) to this
+ // rings to see if they are inside.
+
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ piece& pc = *it;
+ int piece_segment_index = pc.first_seg_id.segment_index;
+ if (! pc.robust_turns.empty())
+ {
+ if (pc.robust_turns.size() > 1u)
+ {
+ std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
+ }
+ // Walk through them, in reverse to insert at right index
+ int index_offset = pc.robust_turns.size() - 1;
+ for (typename std::vector<robust_turn>::const_reverse_iterator
+ rit = pc.robust_turns.rbegin();
+ rit != pc.robust_turns.rend();
+ ++rit, --index_offset)
+ {
+ int const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
+ BOOST_ASSERT
+ (
+ index_in_vector > 0 && index_in_vector < pc.offsetted_count
+ );
+
+ pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
+ pc.offsetted_count++;
+
+ m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
+ }
+ }
+ }
+
+ BOOST_ASSERT(assert_indices_in_robust_rings());
+ }
+
+ inline void get_turns()
+ {
+ {
+ // Calculate the turns
+ piece_turn_visitor
+ <
+ buffered_ring_collection<buffered_ring<Ring> >,
+ turn_vector_type,
+ RobustPolicy
+ > visitor(offsetted_rings, m_turns, m_robust_policy);
+
+ geometry::partition
+ <
+ model::box<robust_point_type>, piece_get_box, piece_ovelaps_box
+ >::apply(m_pieces, visitor);
+ }
+
+ insert_rescaled_piece_turns();
+
+ {
+ // Check if it is inside any of the pieces
+ turn_in_piece_visitor
+ <
+ turn_vector_type, piece_vector_type
+ > visitor(m_turns, m_pieces);
+
+ geometry::partition
+ <
+ model::box<robust_point_type>,
+ turn_get_box, turn_ovelaps_box,
+ piece_get_box, piece_ovelaps_box
+ >::apply(m_turns, m_pieces, visitor);
+
+ }
+
+ classify_turns();
+
+ //get_occupation();
+ }
+
+ inline void start_new_ring()
+ {
+ int const n = offsetted_rings.size();
+ current_segment_id.source_index = 0;
+ current_segment_id.multi_index = n;
+ current_segment_id.ring_index = -1;
+ current_segment_id.segment_index = 0;
+
+ offsetted_rings.resize(n + 1);
+ current_robust_ring.clear();
+
+ m_first_piece_index = boost::size(m_pieces);
+ }
+
+ inline void finish_ring(bool is_interior = false)
+ {
+ if (m_first_piece_index == -1)
+ {
+ return;
+ }
+
+ if (m_first_piece_index < static_cast<int>(boost::size(m_pieces)))
+ {
+ // If piece was added
+ // Reassign left-of-first and right-of-last
+ geometry::range::at(m_pieces, m_first_piece_index).left_index
+ = boost::size(m_pieces) - 1;
+ geometry::range::back(m_pieces).right_index = m_first_piece_index;
+ }
+ m_first_piece_index = -1;
+
+ if (!current_robust_ring.empty())
+ {
+ BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back()));
+
+ if (is_interior)
+ {
+ if (!robust_polygons.empty())
+ {
+ robust_polygons.back().inners().push_back(current_robust_ring);
+ }
+ }
+ else
+ {
+ robust_polygons.resize(robust_polygons.size() + 1);
+ robust_polygons.back().outer() = current_robust_ring;
+ }
+ }
+ }
+
+ inline int add_point(point_type const& p)
+ {
+ BOOST_ASSERT
+ (
+ boost::size(offsetted_rings) > 0
+ );
+
+ current_segment_id.segment_index++;
+ offsetted_rings.back().push_back(p);
+ return offsetted_rings.back().size();
+ }
+
+ //-------------------------------------------------------------------------
+
+ inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one)
+ {
+ piece pc;
+ pc.type = type;
+ pc.index = boost::size(m_pieces);
+ pc.first_seg_id = current_segment_id;
+
+ // Assign left/right (for first/last piece per ring they will be re-assigned later)
+ pc.left_index = pc.index - 1;
+ pc.right_index = pc.index + 1;
+
+ std::size_t const n = boost::size(offsetted_rings.back());
+ pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
+
+ m_pieces.push_back(pc);
+ return m_pieces.back();
+ }
+
+ inline void init_rescale_piece(piece& pc, std::size_t helper_points_size)
+ {
+ pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index;
+ BOOST_ASSERT(pc.offsetted_count >= 0);
+
+ pc.robust_ring.reserve(pc.offsetted_count + helper_points_size);
+
+ // Add rescaled offsetted segments
+ {
+ buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index];
+
+ typedef typename boost::range_iterator<const buffered_ring<Ring> >::type it_type;
+ for (it_type it = boost::begin(ring) + pc.first_seg_id.segment_index;
+ it != boost::begin(ring) + pc.last_segment_index;
+ ++it)
+ {
+ robust_point_type point;
+ geometry::recalculate(point, *it, m_robust_policy);
+ pc.robust_ring.push_back(point);
+ }
+ }
+ }
+
+ inline robust_point_type add_helper_point(piece& pc, const point_type& point)
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
+ pc.helper_points.push_back(point);
+#endif
+
+ robust_point_type rob_point;
+ geometry::recalculate(rob_point, point, m_robust_policy);
+ pc.robust_ring.push_back(rob_point);
+ return rob_point;
+ }
+
+ inline void calculate_robust_envelope(piece& pc)
+ {
+ geometry::detail::envelope::envelope_range::apply(pc.robust_ring,
+ pc.robust_envelope);
+ }
+
+ inline void finish_piece(piece& pc)
+ {
+ init_rescale_piece(pc, 0u);
+ calculate_robust_envelope(pc);
+ }
+
+ inline void finish_piece(piece& pc,
+ const point_type& point1,
+ const point_type& point2,
+ const point_type& point3)
+ {
+ init_rescale_piece(pc, 3u);
+ add_helper_point(pc, point1);
+ robust_point_type mid_point = add_helper_point(pc, point2);
+ add_helper_point(pc, point3);
+ calculate_robust_envelope(pc);
+
+ current_robust_ring.push_back(mid_point);
+ }
+
+ inline void finish_piece(piece& pc,
+ const point_type& point1,
+ const point_type& point2,
+ const point_type& point3,
+ const point_type& point4)
+ {
+ init_rescale_piece(pc, 4u);
+ add_helper_point(pc, point1);
+ robust_point_type mid_point2 = add_helper_point(pc, point2);
+ robust_point_type mid_point1 = add_helper_point(pc, point3);
+ add_helper_point(pc, point4);
+ calculate_robust_envelope(pc);
+
+ // Add mid-points in other order to current helper_ring
+ current_robust_ring.push_back(mid_point1);
+ current_robust_ring.push_back(mid_point2);
+ }
+
+ inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
+ point_type const& b1, point_type const& b2)
+ {
+ piece& pc = create_piece(type, false);
+ add_point(b1);
+ pc.last_segment_index = add_point(b2);
+ finish_piece(pc, b2, p, b1);
+ }
+
+ template <typename Range>
+ inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
+ {
+ if (boost::size(range) == 0u)
+ {
+ return;
+ }
+
+ typename Range::const_iterator it = boost::begin(range);
+
+ // If it follows a non-join (so basically the same piece-type) point b1 should be added.
+ // There should be two intersections later and it should be discarded.
+ // But for now we need it to calculate intersections
+ if (add_front)
+ {
+ add_point(*it);
+ }
+
+ for (++it; it != boost::end(range); ++it)
+ {
+ pc.last_segment_index = add_point(*it);
+ }
+ }
+
+
+ template <typename Range>
+ inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one)
+ {
+ piece& pc = create_piece(type, decrease_segment_index_by_one);
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ finish_piece(pc);
+ }
+
+ template <typename Range>
+ inline void add_side_piece(point_type const& p1, point_type const& p2,
+ Range const& range, bool first)
+ {
+ BOOST_ASSERT(boost::size(range) >= 2u);
+
+ piece& pc = create_piece(strategy::buffer::buffered_segment, ! first);
+ add_range_to_piece(pc, range, first);
+ finish_piece(pc, range.back(), p2, p1, range.front());
+ }
+
+ template <typename Range>
+ inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& range)
+ {
+ piece& pc = create_piece(type, true);
+
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ if (boost::size(range) > 0)
+ {
+ finish_piece(pc, range.back(), p, range.front());
+ }
+ else
+ {
+ finish_piece(pc);
+ }
+ }
+
+ template <typename EndcapStrategy, typename Range>
+ inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point)
+ {
+ if (range.empty())
+ {
+ return;
+ }
+ strategy::buffer::piece_type pt = strategy.get_piece_type();
+ if (pt == strategy::buffer::buffered_flat_end)
+ {
+ // It is flat, should just be added, without helper segments
+ add_piece(pt, range, true);
+ }
+ else
+ {
+ // Normal case, it has an "inside", helper segments should be added
+ add_piece(pt, end_point, range);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+
+ inline void enrich()
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Ring>::type
+ >::type side_strategy_type;
+
+ enrich_intersection_points<false, false>(m_turns,
+ detail::overlay::operation_union,
+ offsetted_rings, offsetted_rings,
+ m_robust_policy, side_strategy_type());
+ }
+
+ // Discards all rings which do have not-OK intersection points only.
+ // Those can never be traversed and should not be part of the output.
+ inline void discard_rings()
+ {
+ for (typename boost::range_iterator<turn_vector_type const>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location != location_ok)
+ {
+ offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true;
+ offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true;
+ }
+ else if (! it->both(detail::overlay::operation_union))
+ {
+ offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true;
+ offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true;
+ }
+ }
+ }
+
+ inline void block_turns()
+ {
+ // To fix left-turn issues like #rt_u13
+ // But currently it causes more other issues than it fixes
+// m_turns.erase
+// (
+// std::remove_if(boost::begin(m_turns), boost::end(m_turns),
+// redundant_turn()),
+// boost::end(m_turns)
+// );
+
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location != location_ok)
+ {
+ // Set it to blocked. They should not be discarded, to avoid
+ // generating rings over these turns
+ // Performance goes down a tiny bit from 161 s to 173 because there
+ // are sometimes much more turns.
+ // We might speed it up a bit by keeping only one blocked
+ // intersection per segment, but that is complex to program
+ // because each turn involves two segments
+ it->operations[0].operation = detail::overlay::operation_blocked;
+ it->operations[1].operation = detail::overlay::operation_blocked;
+ }
+ }
+ }
+
+ inline void traverse()
+ {
+ typedef detail::overlay::traverse
+ <
+ false, false,
+ buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >,
+ backtrack_for_buffer
+ > traverser;
+
+ traversed_rings.clear();
+ traverser::apply(offsetted_rings, offsetted_rings,
+ detail::overlay::operation_union,
+ m_robust_policy, m_turns, traversed_rings);
+ }
+
+ inline void reverse()
+ {
+ for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings);
+ it != boost::end(offsetted_rings);
+ ++it)
+ {
+ if (! it->has_intersections())
+ {
+ std::reverse(it->begin(), it->end());
+ }
+ }
+ for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type
+ it = boost::begin(traversed_rings);
+ it != boost::end(traversed_rings);
+ ++it)
+ {
+ std::reverse(it->begin(), it->end());
+ }
+
+ }
+
+ template <typename GeometryOutput, typename OutputIterator>
+ inline OutputIterator assign(OutputIterator out) const
+ {
+ typedef detail::overlay::ring_properties<point_type> properties;
+
+ std::map<ring_identifier, properties> selected;
+
+ // Select all rings which do not have any self-intersection (other ones should be traversed)
+ int index = 0;
+ for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
+ it != boost::end(offsetted_rings);
+ ++it, ++index)
+ {
+ if (! it->has_intersections())
+ {
+ ring_identifier id(0, index, -1);
+ selected[id] = properties(*it, true);
+ }
+ }
+
+ // Select all created rings
+ index = 0;
+ for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type
+ it = boost::begin(traversed_rings);
+ it != boost::end(traversed_rings);
+ ++it, ++index)
+ {
+ ring_identifier id(2, index, -1);
+ selected[id] = properties(*it, true);
+ }
+
+ detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);
+ return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
+ }
+
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp
new file mode 100644
index 0000000000..03ec598c90
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp
@@ -0,0 +1,238 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/multi/algorithms/within.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+struct buffered_ring_collection_tag : polygonal_tag, multi_tag
+{};
+
+
+template <typename Ring>
+struct buffered_ring : public Ring
+{
+ bool has_accepted_intersections;
+ bool has_discarded_intersections;
+
+ inline buffered_ring()
+ : has_accepted_intersections(false)
+ , has_discarded_intersections(false)
+ {}
+
+ inline bool discarded() const
+ {
+ return has_discarded_intersections && ! has_accepted_intersections;
+ }
+ inline bool has_intersections() const
+ {
+ return has_discarded_intersections || has_accepted_intersections;
+ }
+};
+
+// This is a collection now special for overlay (needs vector of rings)
+template <typename Ring>
+struct buffered_ring_collection : public std::vector<Ring>
+{
+};
+
+}} // namespace detail::buffer
+
+
+// Turn off concept checking (for now)
+namespace dispatch
+{
+template <typename Geometry, bool IsConst>
+struct check<Geometry, detail::buffer::buffered_ring_collection_tag, IsConst>
+{
+};
+
+}
+
+
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+// Register the types
+namespace traits
+{
+
+
+template <typename Ring>
+struct tag<detail::buffer::buffered_ring<Ring> >
+{
+ typedef ring_tag type;
+};
+
+
+template <typename Ring>
+struct point_order<detail::buffer::buffered_ring<Ring> >
+{
+ static const order_selector value = geometry::point_order<Ring>::value;
+};
+
+
+template <typename Ring>
+struct closure<detail::buffer::buffered_ring<Ring> >
+{
+ static const closure_selector value = geometry::closure<Ring>::value;
+};
+
+
+template <typename Ring>
+struct point_type<detail::buffer::buffered_ring_collection<Ring> >
+{
+ typedef typename geometry::point_type<Ring>::type type;
+};
+
+template <typename Ring>
+struct tag<detail::buffer::buffered_ring_collection<Ring> >
+{
+ typedef detail::buffer::buffered_ring_collection_tag type;
+};
+
+
+} // namespace traits
+
+
+
+
+namespace core_dispatch
+{
+
+template <typename Ring>
+struct ring_type
+<
+ detail::buffer::buffered_ring_collection_tag,
+ detail::buffer::buffered_ring_collection<Ring>
+>
+{
+ typedef Ring type;
+};
+
+}
+
+namespace dispatch
+{
+
+template
+<
+ typename MultiRing,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ detail::buffer::buffered_ring_collection_tag,
+ MultiRing,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiRing,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_range
+ <
+ typename boost::range_value<MultiRing>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
+
+template<bool Reverse>
+struct copy_segments
+ <
+ detail::buffer::buffered_ring_collection_tag,
+ Reverse
+ >
+ : detail::copy_segments::copy_segments_multi
+ <
+ detail::copy_segments::copy_segments_ring<Reverse>
+ >
+{};
+
+template <typename Point, typename MultiGeometry>
+struct within
+<
+ Point,
+ MultiGeometry,
+ point_tag,
+ detail::buffer::buffered_ring_collection_tag
+>
+{
+ template <typename Strategy>
+ static inline bool apply(Point const& point,
+ MultiGeometry const& multi, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(point, multi, strategy) == 1;
+ }
+};
+
+
+} // namespace dispatch
+
+namespace detail { namespace overlay
+{
+
+template<>
+struct get_ring<detail::buffer::buffered_ring_collection_tag>
+{
+ template<typename MultiGeometry>
+ static inline typename ring_type<MultiGeometry>::type const& apply(
+ ring_identifier const& id,
+ MultiGeometry const& multi_ring)
+ {
+ BOOST_ASSERT
+ (
+ id.multi_index >= 0
+ && id.multi_index < int(boost::size(multi_ring))
+ );
+ return get_ring<ring_tag>::apply(id, multi_ring[id.multi_index]);
+ }
+};
+
+}}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
new file mode 100644
index 0000000000..395921ccaa
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
@@ -0,0 +1,191 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+struct piece_get_box
+{
+ template <typename Box, typename Piece>
+ static inline void apply(Box& total, Piece const& piece)
+ {
+ geometry::expand(total, piece.robust_envelope);
+ }
+};
+
+struct piece_ovelaps_box
+{
+ template <typename Box, typename Piece>
+ static inline bool apply(Box const& box, Piece const& piece)
+ {
+ return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
+ }
+};
+
+template
+<
+ typename Rings,
+ typename Turns,
+ typename RobustPolicy
+>
+class piece_turn_visitor
+{
+ Rings const& m_rings;
+ Turns& m_turns;
+ RobustPolicy const& m_robust_policy;
+
+ template <typename Piece>
+ inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const
+ {
+ if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
+ {
+ return false;
+ }
+
+ return piece1.index == piece2.left_index
+ || piece1.index == piece2.right_index;
+ }
+
+ template <typename Range, typename Iterator>
+ inline void move_to_next_point(Range const& range, Iterator& next) const
+ {
+ ++next;
+ if (next == boost::end(range))
+ {
+ next = boost::begin(range) + 1;
+ }
+ }
+
+ template <typename Range, typename Iterator>
+ inline Iterator next_point(Range const& range, Iterator it) const
+ {
+ Iterator result = it;
+ move_to_next_point(range, result);
+ // TODO: we could use either piece-boundaries, or comparison with
+ // robust points, to check if the point equals the last one
+ while(geometry::equals(*it, *result))
+ {
+ move_to_next_point(range, result);
+ }
+ return result;
+ }
+
+ template <typename Piece>
+ inline void calculate_turns(Piece const& piece1, Piece const& piece2)
+ {
+ typedef typename boost::range_value<Rings const>::type ring_type;
+ typedef typename boost::range_value<Turns const>::type turn_type;
+ typedef typename boost::range_iterator<ring_type const>::type iterator;
+
+ segment_identifier seg_id1 = piece1.first_seg_id;
+ segment_identifier seg_id2 = piece2.first_seg_id;
+
+ if (seg_id1.segment_index < 0 || seg_id2.segment_index < 0)
+ {
+ return;
+ }
+
+ ring_type const& ring1 = m_rings[seg_id1.multi_index];
+ iterator it1_first = boost::begin(ring1) + seg_id1.segment_index;
+ iterator it1_last = boost::begin(ring1) + piece1.last_segment_index;
+
+ ring_type const& ring2 = m_rings[seg_id2.multi_index];
+ iterator it2_first = boost::begin(ring2) + seg_id2.segment_index;
+ iterator it2_last = boost::begin(ring2) + piece2.last_segment_index;
+
+ turn_type the_model;
+ the_model.operations[0].piece_index = piece1.index;
+ the_model.operations[0].seg_id = piece1.first_seg_id;
+
+ iterator it1 = it1_first;
+ for (iterator prev1 = it1++;
+ it1 != it1_last;
+ prev1 = it1++, the_model.operations[0].seg_id.segment_index++)
+ {
+ the_model.operations[1].piece_index = piece2.index;
+ the_model.operations[1].seg_id = piece2.first_seg_id;
+
+ iterator next1 = next_point(ring1, it1);
+
+ iterator it2 = it2_first;
+ for (iterator prev2 = it2++;
+ it2 != it2_last;
+ prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
+ {
+ iterator next2 = next_point(ring2, it2);
+
+ // TODO: internally get_turn_info calculates robust points.
+ // But they are already calculated.
+ // We should be able to use them.
+ // this means passing them to this visitor,
+ // and iterating in sync with them...
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+ turn_policy::apply(*prev1, *it1, *next1,
+ *prev2, *it2, *next2,
+ false, false, false, false,
+ the_model, m_robust_policy,
+ std::back_inserter(m_turns));
+ }
+ }
+ }
+
+public:
+
+ piece_turn_visitor(Rings const& ring_collection,
+ Turns& turns,
+ RobustPolicy const& robust_policy)
+ : m_rings(ring_collection)
+ , m_turns(turns)
+ , m_robust_policy(robust_policy)
+ {}
+
+ template <typename Piece>
+ inline void apply(Piece const& piece1, Piece const& piece2,
+ bool first = true)
+ {
+ boost::ignore_unused_variable_warning(first);
+ if ( is_adjacent(piece1, piece2)
+ || detail::disjoint::disjoint_box_box(piece1.robust_envelope,
+ piece2.robust_envelope))
+ {
+ return;
+ }
+ calculate_turns(piece1, piece2);
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp b/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
new file mode 100644
index 0000000000..618afe5fba
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
@@ -0,0 +1,88 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
+
+
+#include <boost/geometry/arithmetic/determinant.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+// TODO: once change this to proper strategy
+// It is different from current segment intersection because these are not segments but lines
+// If we have the Line concept, we can create a strategy
+// Assumes a convex corner
+struct line_line_intersection
+{
+
+ template <typename Point>
+ static inline strategy::buffer::join_selector apply(Point const& pi, Point const& pj,
+ Point const& qi, Point const& qj, Point& ip)
+ {
+ // See http://mathworld.wolfram.com/Line-LineIntersection.html
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ coordinate_type const denominator
+ = determinant<coordinate_type>(get<0>(pi) - get<0>(pj),
+ get<1>(pi) - get<1>(pj),
+ get<0>(qi) - get<0>(qj),
+ get<1>(qi) - get<1>(qj));
+
+ // Even if the corner was checked before (so it is convex now), that
+ // was done on the original geometry. This function runs on the buffered
+ // geometries, where sides are generated and might be slightly off. In
+ // Floating Point, that slightly might just exceed the limit and we have
+ // to check it again.
+
+ // For round joins, it will not be used at all.
+ // For miter joints, there is a miter limit
+ // If segments are parallel/collinear we must be distinguish two cases:
+ // they continue each other, or they form a spike
+ if (math::equals(denominator, coordinate_type()))
+ {
+ return parallel_continue(get<0>(qj) - get<0>(qi),
+ get<1>(qj) - get<1>(qi),
+ get<0>(pj) - get<0>(pi),
+ get<1>(pj) - get<1>(pi))
+ ? strategy::buffer::join_continue
+ : strategy::buffer::join_spike
+ ;
+ }
+
+ coordinate_type d1 = determinant<coordinate_type>(get<0>(pi), get<1>(pi), get<0>(pj), get<1>(pj));
+ coordinate_type d2 = determinant<coordinate_type>(get<0>(qi), get<1>(qi), get<0>(qj), get<1>(qj));
+
+ double const multiplier = 1.0 / denominator;
+
+ set<0>(ip, determinant<coordinate_type>(d1, get<0>(pi) - get<0>(pj), d2, get<0>(qi) - get<0>(qj)) * multiplier);
+ set<1>(ip, determinant<coordinate_type>(d1, get<1>(pi) - get<1>(pj), d2, get<1>(qi) - get<1>(qj)) * multiplier);
+
+ return strategy::buffer::join_convex;
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp b/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp
new file mode 100644
index 0000000000..119d64de74
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp
@@ -0,0 +1,33 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+template <typename T>
+inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2)
+{
+ T const dot = dx1 * dx2 + dy1 * dy2;
+ return dot > 0;
+}
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp
new file mode 100644
index 0000000000..2b1c33d291
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp
@@ -0,0 +1,98 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+// Checks if an turn/intersection point is inside (or covered by) the input geometry
+
+template <typename Tag>
+struct turn_in_input
+{
+};
+
+template <>
+struct turn_in_input<polygon_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& point, Geometry const& geometry)
+ {
+ return geometry::covered_by(point, geometry) ? 1 : -1;
+ }
+};
+
+template <>
+struct turn_in_input<linestring_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+template <>
+struct turn_in_input<point_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+template <>
+struct turn_in_input<multi_polygon_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& point, Geometry const& geometry)
+ {
+ return geometry::covered_by(point, geometry) ? 1 : -1;
+ }
+};
+
+template <>
+struct turn_in_input<multi_linestring_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+template <>
+struct turn_in_input<multi_point_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
new file mode 100644
index 0000000000..c02f56de3f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
@@ -0,0 +1,246 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/arithmetic/dot_product.hpp>
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
+
+#include <boost/geometry/geometries/linestring.hpp>
+#include <boost/geometry/algorithms/comparable_distance.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+struct turn_get_box
+{
+ template <typename Box, typename Turn>
+ static inline void apply(Box& total, Turn const& turn)
+ {
+ geometry::expand(total, turn.robust_point);
+ }
+};
+
+struct turn_ovelaps_box
+{
+ template <typename Box, typename Turn>
+ static inline bool apply(Box const& box, Turn const& turn)
+ {
+ return ! dispatch::disjoint
+ <
+ typename Turn::robust_point_type,
+ Box
+ >::apply(turn.robust_point, box);
+ }
+};
+
+template <typename Turns, typename Pieces>
+class turn_in_piece_visitor
+{
+ Turns& m_turns; // because partition is currently operating on const input only
+ Pieces const& m_pieces; // to check for piece-type
+
+ typedef boost::long_long_type calculation_type;
+
+ template <typename Point>
+ static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q)
+ {
+ typedef Point vector_type;
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+
+ vector_type v = q;
+ vector_type w = subject;
+ subtract_point(v, p);
+ subtract_point(w, p);
+
+ coordinate_type const zero = coordinate_type();
+ coordinate_type const c1 = dot_product(w, v);
+
+ if (c1 < zero)
+ {
+ return false;
+ }
+ coordinate_type const c2 = dot_product(v, v);
+ if (c2 < c1)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename Point, typename Piece>
+ inline bool on_offsetted(Point const& point, Piece const& piece) const
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type side_strategy;
+ geometry::equal_to<Point> comparator;
+
+ for (int i = 1; i < piece.offsetted_count; i++)
+ {
+ Point const& previous = piece.robust_ring[i - 1];
+ Point const& current = piece.robust_ring[i];
+
+ // The robust ring contains duplicates, avoid applying side on them (will be 0)
+ if (! comparator(previous, current))
+ {
+ int const side = side_strategy::apply(previous, current, point);
+ if (side == 0)
+ {
+ // Collinear, check if projection falls on it
+ if (projection_on_segment(point, previous, current))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ template <typename Point, typename Piece>
+ static inline
+ calculation_type comparable_distance_from_offsetted(Point const& point,
+ Piece const& piece)
+ {
+ // TODO: pass subrange to dispatch to avoid making copy
+ geometry::model::linestring<Point> ls;
+ std::copy(piece.robust_ring.begin(),
+ piece.robust_ring.begin() + piece.offsetted_count,
+ std::back_inserter(ls));
+ typename default_comparable_distance_result<Point, Point>::type
+ const comp = geometry::comparable_distance(point, ls);
+
+ return static_cast<calculation_type>(comp);
+ }
+
+public:
+
+ inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces)
+ : m_turns(turns)
+ , m_pieces(pieces)
+ {}
+
+ template <typename Turn, typename Piece>
+ inline void apply(Turn const& turn, Piece const& piece, bool first = true)
+ {
+ boost::ignore_unused_variable_warning(first);
+
+ if (turn.count_within > 0)
+ {
+ // Already inside - no need to check again
+ return;
+ }
+
+ if (piece.type == strategy::buffer::buffered_flat_end
+ || piece.type == strategy::buffer::buffered_concave)
+ {
+ // Turns cannot be inside a flat end (though they can be on border)
+ // Neither we need to check if they are inside concave helper pieces
+ return;
+ }
+
+ bool neighbour = false;
+ for (int i = 0; i < 2; i++)
+ {
+ // Don't compare against one of the two source-pieces
+ if (turn.operations[i].piece_index == piece.index)
+ {
+ return;
+ }
+
+ typename boost::range_value<Pieces>::type const& pc
+ = m_pieces[turn.operations[i].piece_index];
+ if (pc.left_index == piece.index
+ || pc.right_index == piece.index)
+ {
+ if (pc.type == strategy::buffer::buffered_flat_end)
+ {
+ // If it is a flat end, don't compare against its neighbor:
+ // it will always be located on one of the helper segments
+ return;
+ }
+ neighbour = true;
+ }
+ }
+
+ int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
+
+ if (geometry_code == -1)
+ {
+ return;
+ }
+ if (geometry_code == 0 && neighbour)
+ {
+ return;
+ }
+
+ Turn& mutable_turn = m_turns[turn.turn_index];
+ if (geometry_code == 0)
+ {
+ // If it is on the border and they are not neighbours, it should be
+ // on the offsetted ring
+
+ if (! on_offsetted(turn.robust_point, piece))
+ {
+ // It is on the border but not on the offsetted ring.
+ // Then it is somewhere on the helper-segments
+ // Classify it as "within"
+ geometry_code = 1;
+ mutable_turn.count_on_helper++; // can still become "near_offsetted"
+ }
+ else
+ {
+ mutable_turn.count_on_offsetted++; // value is not used anymore
+ }
+ }
+
+ if (geometry_code == 1)
+ {
+ calculation_type const distance
+ = comparable_distance_from_offsetted(turn.robust_point, piece);
+ if (distance >= 4)
+ {
+ // This is too far from the border, it counts as "really within"
+ mutable_turn.count_within++;
+ }
+ else
+ {
+ // Other points count as still "on border" because they might be
+ // travelled through, but not used as starting point
+ mutable_turn.count_within_near_offsetted++;
+ }
+ }
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
diff --git a/boost/geometry/algorithms/detail/calculate_null.hpp b/boost/geometry/algorithms/detail/calculate_null.hpp
index 4b48d62fc2..3ebca83506 100644
--- a/boost/geometry/algorithms/detail/calculate_null.hpp
+++ b/boost/geometry/algorithms/detail/calculate_null.hpp
@@ -21,9 +21,9 @@ namespace boost { namespace geometry
namespace detail
{
-template<typename ReturnType, typename Geometry, typename Strategy>
struct calculate_null
{
+ template<typename ReturnType, typename Geometry, typename Strategy>
static inline ReturnType apply(Geometry const& , Strategy const&)
{
return ReturnType();
diff --git a/boost/geometry/algorithms/detail/calculate_sum.hpp b/boost/geometry/algorithms/detail/calculate_sum.hpp
index 2ad349080b..b23e70171b 100644
--- a/boost/geometry/algorithms/detail/calculate_sum.hpp
+++ b/boost/geometry/algorithms/detail/calculate_sum.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,9 +15,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
-
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
namespace boost { namespace geometry
{
@@ -26,20 +25,14 @@ namespace detail
{
-template
-<
- typename ReturnType,
- typename Polygon,
- typename Strategy,
- typename Policy
->
class calculate_polygon_sum
{
- template <typename Rings>
+ template <typename ReturnType, typename Policy, typename Rings, typename Strategy>
static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy)
{
ReturnType sum = ReturnType();
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename boost::range_iterator<Rings const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
sum += Policy::apply(*it, strategy);
}
@@ -47,10 +40,11 @@ class calculate_polygon_sum
}
public :
+ template <typename ReturnType, typename Policy, typename Polygon, typename Strategy>
static inline ReturnType apply(Polygon const& poly, Strategy const& strategy)
{
return Policy::apply(exterior_ring(poly), strategy)
- + sum_interior_rings(interior_rings(poly), strategy)
+ + sum_interior_rings<ReturnType, Policy>(interior_rings(poly), strategy)
;
}
};
diff --git a/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp
new file mode 100644
index 0000000000..56a7e3ec91
--- /dev/null
+++ b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp
@@ -0,0 +1,119 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
+
+
+#include <cstddef>
+
+#include <boost/core/addressof.hpp>
+#include <boost/core/ref.hpp>
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace centroid
+{
+
+
+// NOTE: There is no need to translate in other coordinate systems than
+// cartesian. But if it was needed then one should translate using
+// CS-specific technique, e.g. in spherical/geographic a translation
+// vector should contain coordinates being multiplies of 2PI or 360 deg.
+template <typename Geometry,
+ typename CastedTag = typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ areal_tag
+ >::type,
+ typename CSTag = typename cs_tag<Geometry>::type>
+struct translating_transformer
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef boost::reference_wrapper<point_type const> result_type;
+
+ explicit translating_transformer(Geometry const&) {}
+ explicit translating_transformer(point_type const&) {}
+
+ result_type apply(point_type const& pt) const
+ {
+ return result_type(pt);
+ }
+
+ template <typename ResPt>
+ void apply_reverse(ResPt &) const {}
+};
+
+// Specialization for Areal Geometries in cartesian CS
+template <typename Geometry>
+struct translating_transformer<Geometry, areal_tag, cartesian_tag>
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef point_type result_type;
+
+ explicit translating_transformer(Geometry const& geom)
+ : m_origin(NULL)
+ {
+ geometry::point_iterator<Geometry const>
+ pt_it = geometry::points_begin(geom);
+ if ( pt_it != geometry::points_end(geom) )
+ {
+ m_origin = boost::addressof(*pt_it);
+ }
+ }
+
+ explicit translating_transformer(point_type const& origin)
+ : m_origin(boost::addressof(origin))
+ {}
+
+ result_type apply(point_type const& pt) const
+ {
+ point_type res = pt;
+ if ( m_origin )
+ geometry::subtract_point(res, *m_origin);
+ return res;
+ }
+
+ template <typename ResPt>
+ void apply_reverse(ResPt & res_pt) const
+ {
+ if ( m_origin )
+ geometry::add_point(res_pt, *m_origin);
+ }
+
+ const point_type * m_origin;
+};
+
+
+}} // namespace detail::centroid
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
diff --git a/boost/geometry/algorithms/detail/check_iterator_range.hpp b/boost/geometry/algorithms/detail/check_iterator_range.hpp
new file mode 100644
index 0000000000..09ea7f79a0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/check_iterator_range.hpp
@@ -0,0 +1,71 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+// Check whether (each element of) an iterator range satisfies a given
+// predicate.
+// The predicate must be implemented as having a static apply unary
+// method that returns a bool.
+// By default an empty range is accepted
+template <typename Predicate, bool AllowEmptyRange = true>
+struct check_iterator_range
+{
+ template <typename InputIterator>
+ static inline bool apply(InputIterator first, InputIterator beyond)
+ {
+ for (InputIterator it = first; it != beyond; ++it)
+ {
+ if ( !Predicate::apply(*it) )
+ {
+ return false;
+ }
+ }
+ return AllowEmptyRange || first != beyond;
+ }
+
+
+ // version where we can pass a predicate object
+ template <typename InputIterator>
+ static inline bool apply(InputIterator first,
+ InputIterator beyond,
+ Predicate const& predicate)
+ {
+ // in case predicate's apply method is static, MSVC will
+ // complain that predicate is not used
+ boost::ignore_unused(predicate);
+
+ for (InputIterator it = first; it != beyond; ++it)
+ {
+ if ( !predicate.apply(*it) )
+ {
+ return false;
+ }
+ }
+ return AllowEmptyRange || first != beyond;
+ }
+};
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp
new file mode 100644
index 0000000000..c7558b4ff1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp
@@ -0,0 +1,147 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
+
+#include <iterator>
+
+#include <boost/assert.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace closest_feature
+{
+
+
+
+// returns the range iterator the realizes the closest
+// distance between the geometry and the element of the range
+class geometry_to_range
+{
+private:
+ template
+ <
+ typename Geometry,
+ typename RangeIterator,
+ typename Strategy,
+ typename Distance
+ >
+ static inline void apply(Geometry const& geometry,
+ RangeIterator first,
+ RangeIterator last,
+ Strategy const& strategy,
+ RangeIterator& it_min,
+ Distance& dist_min)
+ {
+ BOOST_ASSERT( first != last );
+
+ Distance const zero = Distance(0);
+
+ // start with first distance
+ it_min = first;
+ dist_min = dispatch::distance
+ <
+ Geometry,
+ typename std::iterator_traits<RangeIterator>::value_type,
+ Strategy
+ >::apply(geometry, *it_min, strategy);
+
+ // check if other elements in the range are closer
+ RangeIterator it = first;
+ for (++it; it != last; ++it)
+ {
+ Distance dist = dispatch::distance
+ <
+ Geometry,
+ typename std::iterator_traits<RangeIterator>::value_type,
+ Strategy
+ >::apply(geometry, *it, strategy);
+
+ if (geometry::math::equals(dist, zero))
+ {
+ dist_min = dist;
+ it_min = it;
+ return;
+ }
+ else if (dist < dist_min)
+ {
+ dist_min = dist;
+ it_min = it;
+ }
+ }
+ }
+
+public:
+ template
+ <
+ typename Geometry,
+ typename RangeIterator,
+ typename Strategy,
+ typename Distance
+ >
+ static inline RangeIterator apply(Geometry const& geometry,
+ RangeIterator first,
+ RangeIterator last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ RangeIterator it_min;
+ apply(geometry, first, last, strategy, it_min, dist_min);
+
+ return it_min;
+ }
+
+
+ template
+ <
+ typename Geometry,
+ typename RangeIterator,
+ typename Strategy
+ >
+ static inline RangeIterator apply(Geometry const& geometry,
+ RangeIterator first,
+ RangeIterator last,
+ Strategy const& strategy)
+ {
+ typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Geometry>::type,
+ typename point_type
+ <
+ typename std::iterator_traits
+ <
+ RangeIterator
+ >::value_type
+ >::type
+ >::type dist_min;
+
+ return apply(geometry, first, last, strategy, dist_min);
+ }
+};
+
+
+
+}} // namespace detail::closest_feature
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp
new file mode 100644
index 0000000000..91be6b0ad0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp
@@ -0,0 +1,250 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
+
+#include <utility>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/util/math.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace closest_feature
+{
+
+
+// returns the segment (pair of iterators) that realizes the closest
+// distance of the point to the range
+template
+<
+ typename Point,
+ typename Range,
+ closure_selector Closure,
+ typename Strategy
+>
+class point_to_point_range
+{
+protected:
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
+
+ template <typename Distance>
+ static inline void apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ iterator_type& it_min1,
+ iterator_type& it_min2,
+ Distance& dist_min)
+ {
+ BOOST_ASSERT( first != last );
+
+ Distance const zero = Distance(0);
+
+ iterator_type it = first;
+ iterator_type prev = it++;
+ if (it == last)
+ {
+ it_min1 = it_min2 = first;
+ dist_min = strategy.apply(point, *first, *first);
+ return;
+ }
+
+ // start with first segment distance
+ dist_min = strategy.apply(point, *prev, *it);
+ iterator_type prev_min_dist = prev;
+
+ // check if other segments are closer
+ for (++prev, ++it; it != last; ++prev, ++it)
+ {
+ Distance dist = strategy.apply(point, *prev, *it);
+ if (geometry::math::equals(dist, zero))
+ {
+ dist_min = zero;
+ it_min1 = prev;
+ it_min2 = it;
+ return;
+ }
+ else if (dist < dist_min)
+ {
+ dist_min = dist;
+ prev_min_dist = prev;
+ }
+ }
+
+ it_min1 = it_min2 = prev_min_dist;
+ ++it_min2;
+ }
+
+public:
+ typedef typename std::pair<iterator_type, iterator_type> return_type;
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ iterator_type it_min1, it_min2;
+ apply(point, first, last, strategy, it_min1, it_min2, dist_min);
+
+ return std::make_pair(it_min1, it_min2);
+ }
+
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy)
+ {
+ typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename boost::range_value<Range>::type
+ >::type dist_min;
+
+ return apply(point, first, last, strategy, dist_min);
+ }
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ return apply(point,
+ boost::begin(range),
+ boost::end(range),
+ strategy,
+ dist_min);
+ }
+
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy)
+ {
+ return apply(point, boost::begin(range), boost::end(range), strategy);
+ }
+};
+
+
+
+// specialization for open ranges
+template <typename Point, typename Range, typename Strategy>
+class point_to_point_range<Point, Range, open, Strategy>
+ : point_to_point_range<Point, Range, closed, Strategy>
+{
+private:
+ typedef point_to_point_range<Point, Range, closed, Strategy> base_type;
+ typedef typename base_type::iterator_type iterator_type;
+
+ template <typename Distance>
+ static inline void apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ iterator_type& it_min1,
+ iterator_type& it_min2,
+ Distance& dist_min)
+ {
+ BOOST_ASSERT( first != last );
+
+ base_type::apply(point, first, last, strategy,
+ it_min1, it_min2, dist_min);
+
+ iterator_type it_back = --last;
+ Distance const zero = Distance(0);
+ Distance dist = strategy.apply(point, *it_back, *first);
+
+ if (geometry::math::equals(dist, zero))
+ {
+ dist_min = zero;
+ it_min1 = it_back;
+ it_min2 = first;
+ }
+ else if (dist < dist_min)
+ {
+ dist_min = dist;
+ it_min1 = it_back;
+ it_min2 = first;
+ }
+ }
+
+public:
+ typedef typename std::pair<iterator_type, iterator_type> return_type;
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ iterator_type it_min1, it_min2;
+
+ apply(point, first, last, strategy, it_min1, it_min2, dist_min);
+
+ return std::make_pair(it_min1, it_min2);
+ }
+
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy)
+ {
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename boost::range_value<Range>::type
+ >::type distance_return_type;
+
+ distance_return_type dist_min;
+
+ return apply(point, first, last, strategy, dist_min);
+ }
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ return apply(point,
+ boost::begin(range),
+ boost::end(range),
+ strategy,
+ dist_min);
+ }
+
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy)
+ {
+ return apply(point, boost::begin(range), boost::end(range), strategy);
+ }
+};
+
+
+}} // namespace detail::closest_feature
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp
new file mode 100644
index 0000000000..90248767ec
--- /dev/null
+++ b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp
@@ -0,0 +1,196 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
+
+#include <cstddef>
+
+#include <iterator>
+#include <utility>
+
+#include <boost/assert.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+#include <boost/geometry/index/rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace closest_feature
+{
+
+
+// returns a pair of a objects where the first is an object of the
+// r-tree range and the second an object of the query range that
+// realizes the closest feature of the two ranges
+class range_to_range_rtree
+{
+private:
+ template
+ <
+ typename RTreeRangeIterator,
+ typename QueryRangeIterator,
+ typename Strategy,
+ typename RTreeValueType,
+ typename Distance
+ >
+ static inline void apply(RTreeRangeIterator rtree_first,
+ RTreeRangeIterator rtree_last,
+ QueryRangeIterator queries_first,
+ QueryRangeIterator queries_last,
+ Strategy const& strategy,
+ RTreeValueType& rtree_min,
+ QueryRangeIterator& qit_min,
+ Distance& dist_min)
+ {
+ typedef index::rtree<RTreeValueType, index::linear<8> > rtree_type;
+
+ BOOST_ASSERT( rtree_first != rtree_last );
+ BOOST_ASSERT( queries_first != queries_last );
+
+ Distance const zero = Distance(0);
+
+ // create -- packing algorithm
+ rtree_type rt(rtree_first, rtree_last);
+
+ RTreeValueType t_v;
+ bool first = true;
+
+ for (QueryRangeIterator qit = queries_first;
+ qit != queries_last; ++qit, first = false)
+ {
+ std::size_t n = rt.query(index::nearest(*qit, 1), &t_v);
+
+ BOOST_ASSERT( n > 0 );
+ // n above is unused outside BOOST_ASSERT, hence the call
+ // to boost::ignore_unused below
+ //
+ // however, t_v (initialized by the call to rt.query(...))
+ // is used below, which is why we cannot put the call to
+ // rt.query(...) inside BOOST_ASSERT
+ boost::ignore_unused(n);
+
+ Distance dist = dispatch::distance
+ <
+ RTreeValueType,
+ typename std::iterator_traits
+ <
+ QueryRangeIterator
+ >::value_type,
+ Strategy
+ >::apply(t_v, *qit, strategy);
+
+ if (first || dist < dist_min)
+ {
+ dist_min = dist;
+ rtree_min = t_v;
+ qit_min = qit;
+ if ( math::equals(dist_min, zero) )
+ {
+ return;
+ }
+ }
+ }
+ }
+
+public:
+ template <typename RTreeRangeIterator, typename QueryRangeIterator>
+ struct return_type
+ {
+ typedef std::pair
+ <
+ typename std::iterator_traits<RTreeRangeIterator>::value_type,
+ QueryRangeIterator
+ > type;
+ };
+
+
+ template
+ <
+ typename RTreeRangeIterator,
+ typename QueryRangeIterator,
+ typename Strategy,
+ typename Distance
+ >
+ static inline typename return_type
+ <
+ RTreeRangeIterator, QueryRangeIterator
+ >::type apply(RTreeRangeIterator rtree_first,
+ RTreeRangeIterator rtree_last,
+ QueryRangeIterator queries_first,
+ QueryRangeIterator queries_last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ typedef typename std::iterator_traits
+ <
+ RTreeRangeIterator
+ >::value_type rtree_value_type;
+
+ rtree_value_type rtree_min;
+ QueryRangeIterator qit_min;
+
+ apply(rtree_first, rtree_last, queries_first, queries_last,
+ strategy, rtree_min, qit_min, dist_min);
+
+ return std::make_pair(rtree_min, qit_min);
+ }
+
+
+ template
+ <
+ typename RTreeRangeIterator,
+ typename QueryRangeIterator,
+ typename Strategy
+ >
+ static inline typename return_type
+ <
+ RTreeRangeIterator, QueryRangeIterator
+ >::type apply(RTreeRangeIterator rtree_first,
+ RTreeRangeIterator rtree_last,
+ QueryRangeIterator queries_first,
+ QueryRangeIterator queries_last,
+ Strategy const& strategy)
+ {
+ typedef typename std::iterator_traits
+ <
+ RTreeRangeIterator
+ >::value_type rtree_value_type;
+
+ typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<rtree_value_type>::type,
+ typename point_type
+ <
+ typename std::iterator_traits
+ <
+ QueryRangeIterator
+ >::value_type
+ >::type
+ >::type dist_min;
+
+ return apply(rtree_first, rtree_last, queries_first, queries_last,
+ strategy, dist_min);
+ }
+};
+
+
+}} // namespace detail::closest_feature
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp b/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp
new file mode 100644
index 0000000000..b6eb7a27f1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp
@@ -0,0 +1,24 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
+
+#include <boost/geometry/algorithms/detail/distance/implementation.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp
new file mode 100644
index 0000000000..1a57c8f4b3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp
@@ -0,0 +1,363 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_COMPARABLE_DISTANCE_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/strategies/comparable_distance_result.hpp>
+#include <boost/geometry/strategies/default_comparable_distance_result.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/interface.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace resolve_strategy
+{
+
+struct comparable_distance
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline
+ typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy_type;
+
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, comparable_strategy_type
+ >::apply(geometry1,
+ geometry2,
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy));
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline typename comparable_distance_result
+ <
+ Geometry1, Geometry2, default_strategy
+ >::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::distance::services::comparable_type
+ <
+ typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type
+ >::type comparable_strategy_type;
+
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, comparable_strategy_type
+ >::apply(geometry1, geometry2, comparable_strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+
+template <typename Geometry1, typename Geometry2>
+struct comparable_distance
+{
+ template <typename Strategy>
+ static inline
+ typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return resolve_strategy::comparable_distance::apply(geometry1,
+ geometry2,
+ strategy);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct comparable_distance
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ >
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2,
+ Strategy const& strategy)
+ : m_geometry2(geometry2),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ typename comparable_distance_result
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ operator()(Geometry1 const& geometry1) const
+ {
+ return comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct comparable_distance
+ <
+ Geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename comparable_distance_result
+ <
+ Geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ >
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1,
+ Strategy const& strategy)
+ : m_geometry1(geometry1),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ typename comparable_distance_result
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ operator()(Geometry2 const& geometry2) const
+ {
+ return comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename comparable_distance_result
+ <
+ Geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+
+template
+<
+ BOOST_VARIANT_ENUM_PARAMS(typename A),
+ BOOST_VARIANT_ENUM_PARAMS(typename B)
+>
+struct comparable_distance
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ >
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ typename comparable_distance_result
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const
+ {
+ return comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+
+/*!
+\brief \brief_calc2{comparable distance measurement} \brief_strategy
+\ingroup distance
+\details The free function comparable_distance does not necessarily calculate the distance,
+ but it calculates a distance measure such that two distances are comparable to each other.
+ For example: for the Cartesian coordinate system, Pythagoras is used but the square root
+ is not taken, which makes it faster and the results of two point pairs can still be
+ compared to each other.
+\tparam Geometry1 first geometry type
+\tparam Geometry2 second geometry type
+\tparam Strategy \tparam_strategy{Distance}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{distance}
+\return \return_calc{comparable distance}
+
+\qbk{distinguish,with strategy}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type
+comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return resolve_variant::comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+
+/*!
+\brief \brief_calc2{comparable distance measurement}
+\ingroup distance
+\details The free function comparable_distance does not necessarily calculate the distance,
+ but it calculates a distance measure such that two distances are comparable to each other.
+ For example: for the Cartesian coordinate system, Pythagoras is used but the square root
+ is not taken, which makes it faster and the results of two point pairs can still be
+ compared to each other.
+\tparam Geometry1 first geometry type
+\tparam Geometry2 second geometry type
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_calc{comparable distance}
+
+\qbk{[include reference/algorithms/comparable_distance.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline typename default_comparable_distance_result<Geometry1, Geometry2>::type
+comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return comparable_distance(geometry1, geometry2, default_strategy());
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
index d39824a61d..fccdf4bb1d 100644
--- a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
+++ b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
@@ -33,9 +33,9 @@ namespace detail { namespace conversion
template
<
- typename Source,
- typename Destination,
- std::size_t Dimension,
+ typename Source,
+ typename Destination,
+ std::size_t Dimension,
std::size_t DimensionCount
>
struct indexed_to_indexed
@@ -44,25 +44,25 @@ struct indexed_to_indexed
{
typedef typename coordinate_type<Destination>::type coordinate_type;
- geometry::set<min_corner, Dimension>(destination,
+ geometry::set<min_corner, Dimension>(destination,
boost::numeric_cast<coordinate_type>(
geometry::get<min_corner, Dimension>(source)));
- geometry::set<max_corner, Dimension>(destination,
+ geometry::set<max_corner, Dimension>(destination,
boost::numeric_cast<coordinate_type>(
geometry::get<max_corner, Dimension>(source)));
-
+
indexed_to_indexed
<
- Source, Destination,
+ Source, Destination,
Dimension + 1, DimensionCount
>::apply(source, destination);
}
};
-template
+template
<
- typename Source,
- typename Destination,
+ typename Source,
+ typename Destination,
std::size_t DimensionCount
>
struct indexed_to_indexed<Source, Destination, DimensionCount, DimensionCount>
diff --git a/boost/geometry/algorithms/detail/counting.hpp b/boost/geometry/algorithms/detail/counting.hpp
new file mode 100644
index 0000000000..dc5bb26c10
--- /dev/null
+++ b/boost/geometry/algorithms/detail/counting.hpp
@@ -0,0 +1,107 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_COUNTING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace counting
+{
+
+
+template <std::size_t D>
+struct other_count
+{
+ template <typename Geometry>
+ static inline std::size_t apply(Geometry const&)
+ {
+ return D;
+ }
+
+ template <typename Geometry>
+ static inline std::size_t apply(Geometry const&, bool)
+ {
+ return D;
+ }
+};
+
+
+template <typename RangeCount>
+struct polygon_count
+{
+ template <typename Polygon>
+ static inline std::size_t apply(Polygon const& poly)
+ {
+ std::size_t n = RangeCount::apply(exterior_ring(poly));
+
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
+ {
+ n += RangeCount::apply(*it);
+ }
+
+ return n;
+ }
+};
+
+
+template <typename SingleCount>
+struct multi_count
+{
+ template <typename MultiGeometry>
+ static inline std::size_t apply(MultiGeometry const& geometry)
+ {
+ std::size_t n = 0;
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it = boost::begin(geometry);
+ it != boost::end(geometry);
+ ++it)
+ {
+ n += SingleCount::apply(*it);
+ }
+ return n;
+ }
+};
+
+
+}} // namespace detail::counting
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP
diff --git a/boost/geometry/algorithms/detail/course.hpp b/boost/geometry/algorithms/detail/course.hpp
new file mode 100644
index 0000000000..e1a74c0fee
--- /dev/null
+++ b/boost/geometry/algorithms/detail/course.hpp
@@ -0,0 +1,56 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+/// Calculate course (bearing) between two points.
+template <typename ReturnType, typename Point1, typename Point2>
+inline ReturnType course(Point1 const& p1, Point2 const& p2)
+{
+ // http://williams.best.vwh.net/avform.htm#Crs
+ ReturnType dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1);
+ ReturnType cos_p2lat = cos(get_as_radian<1>(p2));
+
+ // An optimization which should kick in often for Boxes
+ //if ( math::equals(dlon, ReturnType(0)) )
+ //if ( get<0>(p1) == get<0>(p2) )
+ //{
+ // return - sin(get_as_radian<1>(p1)) * cos_p2lat);
+ //}
+
+ // "An alternative formula, not requiring the pre-computation of d"
+ // In the formula below dlon is used as "d"
+ return atan2(sin(dlon) * cos_p2lat,
+ cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2))
+ - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon));
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint.hpp b/boost/geometry/algorithms/detail/disjoint.hpp
deleted file mode 100644
index 2ced5b1ce3..0000000000
--- a/boost/geometry/algorithms/detail/disjoint.hpp
+++ /dev/null
@@ -1,225 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
-
-// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
-// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
-
-// Note: contrary to most files, the geometry::detail::disjoint namespace
-// is partly implemented in a separate file, to avoid circular references
-// disjoint -> get_turns -> disjoint
-
-#include <cstddef>
-
-#include <boost/range.hpp>
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-
-
-#include <boost/geometry/util/math.hpp>
-
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace disjoint
-{
-
-
-struct disjoint_interrupt_policy
-{
- static bool const enabled = true;
- bool has_intersections;
-
- inline disjoint_interrupt_policy()
- : has_intersections(false)
- {}
-
- template <typename Range>
- inline bool apply(Range const& range)
- {
- // If there is any IP in the range, it is NOT disjoint
- if (boost::size(range) > 0)
- {
- has_intersections = true;
- return true;
- }
- return false;
- }
-};
-
-
-
-template
-<
- typename Point1, typename Point2,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct point_point
-{
- static inline bool apply(Point1 const& p1, Point2 const& p2)
- {
- if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
- {
- return true;
- }
- return point_point
- <
- Point1, Point2,
- Dimension + 1, DimensionCount
- >::apply(p1, p2);
- }
-};
-
-
-template <typename Point1, typename Point2, std::size_t DimensionCount>
-struct point_point<Point1, Point2, DimensionCount, DimensionCount>
-{
- static inline bool apply(Point1 const& , Point2 const& )
- {
- return false;
- }
-};
-
-
-template
-<
- typename Point, typename Box,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct point_box
-{
- static inline bool apply(Point const& point, Box const& box)
- {
- if (get<Dimension>(point) < get<min_corner, Dimension>(box)
- || get<Dimension>(point) > get<max_corner, Dimension>(box))
- {
- return true;
- }
- return point_box
- <
- Point, Box,
- Dimension + 1, DimensionCount
- >::apply(point, box);
- }
-};
-
-
-template <typename Point, typename Box, std::size_t DimensionCount>
-struct point_box<Point, Box, DimensionCount, DimensionCount>
-{
- static inline bool apply(Point const& , Box const& )
- {
- return false;
- }
-};
-
-
-template
-<
- typename Box1, typename Box2,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct box_box
-{
- static inline bool apply(Box1 const& box1, Box2 const& box2)
- {
- if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
- {
- return true;
- }
- if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
- {
- return true;
- }
- return box_box
- <
- Box1, Box2,
- Dimension + 1, DimensionCount
- >::apply(box1, box2);
- }
-};
-
-
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct box_box<Box1, Box2, DimensionCount, DimensionCount>
-{
- static inline bool apply(Box1 const& , Box2 const& )
- {
- return false;
- }
-};
-
-
-
-/*!
- \brief Internal utility function to detect of boxes are disjoint
- \note Is used from other algorithms, declared separately
- to avoid circular references
- */
-template <typename Box1, typename Box2>
-inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2)
-{
- return box_box
- <
- Box1, Box2,
- 0, dimension<Box1>::type::value
- >::apply(box1, box2);
-}
-
-
-
-/*!
- \brief Internal utility function to detect of points are disjoint
- \note To avoid circular references
- */
-template <typename Point1, typename Point2>
-inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
-{
- return point_point
- <
- Point1, Point2,
- 0, dimension<Point1>::type::value
- >::apply(point1, point2);
-}
-
-
-}} // namespace detail::disjoint
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace equals
-{
-
-/*!
- \brief Internal utility function to detect of points are disjoint
- \note To avoid circular references
- */
-template <typename Point1, typename Point2>
-inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
-{
- return ! detail::disjoint::disjoint_point_point(point1, point2);
-}
-
-
-}} // namespace detail::equals
-#endif // DOXYGEN_NO_DETAIL
-
-}} // namespace boost::geometry
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp
new file mode 100644
index 0000000000..284858a130
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp
@@ -0,0 +1,134 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_AREAL_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/detail/for_each_range.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template<typename Geometry>
+struct check_each_ring_for_within
+{
+ bool not_disjoint;
+ Geometry const& m_geometry;
+
+ inline check_each_ring_for_within(Geometry const& g)
+ : not_disjoint(false)
+ , m_geometry(g)
+ {}
+
+ template <typename Range>
+ inline void apply(Range const& range)
+ {
+ typename point_type<Range>::type pt;
+ not_disjoint = not_disjoint
+ || ( geometry::point_on_border(pt, range)
+ && geometry::covered_by(pt, m_geometry) );
+ }
+};
+
+
+
+template <typename FirstGeometry, typename SecondGeometry>
+inline bool rings_containing(FirstGeometry const& geometry1,
+ SecondGeometry const& geometry2)
+{
+ check_each_ring_for_within<FirstGeometry> checker(geometry1);
+ geometry::detail::for_each_range(geometry2, checker);
+ return checker.not_disjoint;
+}
+
+
+
+template <typename Geometry1, typename Geometry2>
+struct general_areal
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ if ( ! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2) )
+ {
+ return false;
+ }
+
+ // If there is no intersection of segments, they might located
+ // inside each other
+
+ // We check that using a point on the border (external boundary),
+ // and see if that is contained in the other geometry. And vice versa.
+
+ if ( rings_containing(geometry1, geometry2)
+ || rings_containing(geometry2, geometry1) )
+ {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Areal1, typename Areal2>
+struct disjoint<Areal1, Areal2, 2, areal_tag, areal_tag, false>
+ : detail::disjoint::general_areal<Areal1, Areal2>
+{};
+
+
+template <typename Areal, typename Box>
+struct disjoint<Areal, Box, 2, areal_tag, box_tag, false>
+ : detail::disjoint::general_areal<Areal, Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
new file mode 100644
index 0000000000..ccff9799fd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
@@ -0,0 +1,114 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_BOX_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template
+<
+ typename Box1, typename Box2,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct box_box
+{
+ static inline bool apply(Box1 const& box1, Box2 const& box2)
+ {
+ if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
+ {
+ return true;
+ }
+ if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
+ {
+ return true;
+ }
+ return box_box
+ <
+ Box1, Box2,
+ Dimension + 1, DimensionCount
+ >::apply(box1, box2);
+ }
+};
+
+
+template <typename Box1, typename Box2, std::size_t DimensionCount>
+struct box_box<Box1, Box2, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Box1 const& , Box2 const& )
+ {
+ return false;
+ }
+};
+
+
+/*!
+ \brief Internal utility function to detect of boxes are disjoint
+ \note Is used from other algorithms, declared separately
+ to avoid circular references
+ */
+template <typename Box1, typename Box2>
+inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2)
+{
+ return box_box
+ <
+ Box1, Box2,
+ 0, dimension<Box1>::type::value
+ >::apply(box1, box2);
+}
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Box1, typename Box2, std::size_t DimensionCount>
+struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, false>
+ : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/implementation.hpp b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
new file mode 100644
index 0000000000..0c8079b8e4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
@@ -0,0 +1,36 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP
+
+
+#include <boost/geometry/algorithms/detail/disjoint/areal_areal.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_areal.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/interface.hpp b/boost/geometry/algorithms/detail/disjoint/interface.hpp
new file mode 100644
index 0000000000..ec9057ba0d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/interface.hpp
@@ -0,0 +1,187 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP
+
+#include <cstddef>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ std::size_t DimensionCount,
+ typename Tag1, typename Tag2
+>
+struct disjoint<Geometry1, Geometry2, DimensionCount, Tag1, Tag2, true>
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ return disjoint
+ <
+ Geometry2, Geometry1,
+ DimensionCount,
+ Tag2, Tag1
+ >::apply(g2, g1);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct disjoint
+{
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ concept::check_concepts_and_equal_dimensions
+ <
+ Geometry1 const,
+ Geometry2 const
+ >();
+
+ return dispatch::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct disjoint<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return disjoint<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct disjoint<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return disjoint<Geometry1, Geometry2>::apply(m_geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry1), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct disjoint<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+
+/*!
+\brief \brief_check2{are disjoint}
+\ingroup disjoint
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{are disjoint}
+
+\qbk{[include reference/algorithms/disjoint.qbk]}
+*/
+template <typename Geometry1, typename Geometry2>
+inline bool disjoint(Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+{
+ return resolve_variant::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp
new file mode 100644
index 0000000000..eefd351b8d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp
@@ -0,0 +1,244 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_LINEAR_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP
+
+#include <iterator>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template<typename Geometry1, typename Geometry2>
+struct disjoint_linear_areal
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ // if there are intersections - return false
+ if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2) )
+ return false;
+
+ typedef typename point_type<Geometry1>::type point1_type;
+ point1_type p;
+ geometry::point_on_border(p, g1);
+ return !geometry::covered_by(p, g2);
+ }
+};
+
+
+
+
+template
+<
+ typename Segment,
+ typename Areal,
+ typename Tag = typename tag<Areal>::type
+>
+struct disjoint_segment_areal
+ : not_implemented<Segment, Areal>
+{};
+
+
+template <typename Segment, typename Polygon>
+class disjoint_segment_areal<Segment, Polygon, polygon_tag>
+{
+private:
+ template <typename RingIterator>
+ static inline bool check_interior_rings(RingIterator first,
+ RingIterator beyond,
+ Segment const& segment)
+ {
+ for (RingIterator it = first; it != beyond; ++it)
+ {
+ if ( !disjoint_range_segment_or_box
+ <
+ typename std::iterator_traits
+ <
+ RingIterator
+ >::value_type,
+ closure<Polygon>::value,
+ Segment
+ >::apply(*it, segment) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ template <typename InteriorRings>
+ static inline
+ bool check_interior_rings(InteriorRings const& interior_rings,
+ Segment const& segment)
+ {
+ return check_interior_rings(boost::begin(interior_rings),
+ boost::end(interior_rings),
+ segment);
+ }
+
+
+public:
+ static inline bool apply(Segment const& segment, Polygon const& polygon)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring;
+
+ if ( !disjoint_range_segment_or_box
+ <
+ ring, closure<Polygon>::value, Segment
+ >::apply(geometry::exterior_ring(polygon), segment) )
+ {
+ return false;
+ }
+
+ if ( !check_interior_rings(geometry::interior_rings(polygon), segment) )
+ {
+ return false;
+ }
+
+ typename point_type<Segment>::type p;
+ detail::assign_point_from_index<0>(segment, p);
+
+ return !geometry::covered_by(p, polygon);
+ }
+};
+
+
+template <typename Segment, typename MultiPolygon>
+struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag>
+{
+ static inline
+ bool apply(Segment const& segment, MultiPolygon const& multipolygon)
+ {
+ return disjoint_multirange_segment_or_box
+ <
+ MultiPolygon, Segment
+ >::apply(multipolygon, segment);
+ }
+};
+
+
+template <typename Segment, typename Ring>
+struct disjoint_segment_areal<Segment, Ring, ring_tag>
+{
+ static inline bool apply(Segment const& segment, Ring const& ring)
+ {
+ if ( !disjoint_range_segment_or_box
+ <
+ Ring, closure<Ring>::value, Segment
+ >::apply(ring, segment) )
+ {
+ return false;
+ }
+
+ typename point_type<Segment>::type p;
+ detail::assign_point_from_index<0>(segment, p);
+
+ return !geometry::covered_by(p, ring);
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear, typename Areal>
+struct disjoint<Linear, Areal, 2, linear_tag, areal_tag, false>
+ : public detail::disjoint::disjoint_linear_areal<Linear, Areal>
+{};
+
+
+template <typename Areal, typename Linear>
+struct disjoint<Areal, Linear, 2, areal_tag, linear_tag, false>
+{
+ static inline
+ bool apply(Areal const& areal, Linear const& linear)
+ {
+ return detail::disjoint::disjoint_linear_areal
+ <
+ Linear, Areal
+ >::apply(linear, areal);
+ }
+};
+
+
+template <typename Areal, typename Segment>
+struct disjoint<Areal, Segment, 2, areal_tag, segment_tag, false>
+{
+ static inline bool apply(Areal const& g1, Segment const& g2)
+ {
+ return detail::disjoint::disjoint_segment_areal
+ <
+ Segment, Areal
+ >::apply(g2, g1);
+ }
+};
+
+
+template <typename Segment, typename Areal>
+struct disjoint<Segment, Areal, 2, segment_tag, areal_tag, false>
+ : detail::disjoint::disjoint_segment_areal<Segment, Areal>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
new file mode 100644
index 0000000000..ad84d7191d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
@@ -0,0 +1,174 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP
+
+#include <cstddef>
+#include <deque>
+
+#include <boost/range.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+
+#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+template <typename Segment1, typename Segment2>
+struct disjoint_segment
+{
+ static inline bool apply(Segment1 const& segment1, Segment2 const& segment2)
+ {
+ typedef typename point_type<Segment1>::type point_type;
+
+ // We don't need to rescale to detect disjointness
+ typedef no_rescale_policy rescale_policy_type;
+ rescale_policy_type robust_policy;
+
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type,
+ rescale_policy_type
+ >::type
+ > intersection_return_type;
+
+ intersection_return_type is
+ = strategy::intersection::relate_cartesian_segments
+ <
+ policies::relate::segments_intersection_points
+ <
+ intersection_return_type
+ >
+ >::apply(segment1, segment2, robust_policy);
+
+ return is.count == 0;
+ }
+};
+
+
+struct assign_disjoint_policy
+{
+ // We want to include all points:
+ static bool const include_no_turn = true;
+ static bool const include_degenerate = true;
+ static bool const include_opposite = true;
+
+ // We don't assign extra info:
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(Info& , Point1 const& , Point2 const&,
+ IntersectionInfo const&, DirInfo const&)
+ {}
+};
+
+
+template <typename Geometry1, typename Geometry2>
+struct disjoint_linear
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+ std::deque<turn_info> turns;
+
+ static const bool reverse1 = overlay::do_reverse<geometry::point_order<Geometry1>::value>::value; // should be false
+ static const bool reverse2 = overlay::do_reverse<geometry::point_order<Geometry2>::value>::value; // should be false
+
+ // Specify two policies:
+ // 1) Stop at any intersection
+ // 2) In assignment, include also degenerate points (which are normally skipped)
+ disjoint_interrupt_policy policy;
+ rescale_policy_type robust_policy;
+ geometry::get_turns
+ <
+ reverse1, reverse2,
+ assign_disjoint_policy
+ >(geometry1, geometry2, robust_policy, turns, policy);
+
+ return !policy.has_intersections;
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear1, typename Linear2>
+struct disjoint<Linear1, Linear2, 2, linear_tag, linear_tag, false>
+ : detail::disjoint::disjoint_linear<Linear1, Linear2>
+{};
+
+
+template <typename Segment1, typename Segment2>
+struct disjoint<Segment1, Segment2, 2, segment_tag, segment_tag, false>
+ : detail::disjoint::disjoint_segment<Segment1, Segment2>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp
new file mode 100644
index 0000000000..d181726e2e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp
@@ -0,0 +1,195 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
+
+#include <boost/range.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+
+#include <boost/geometry/geometries/segment.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/views/closeable_view.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template <typename MultiRange, typename SegmentOrBox>
+struct disjoint_multirange_segment_or_box
+{
+ static inline
+ bool apply(MultiRange const& multirange, SegmentOrBox const& segment_or_box)
+ {
+ typedef typename boost::range_iterator
+ <
+ MultiRange const
+ >::type const_iterator;
+
+ for (const_iterator it = boost::begin(multirange);
+ it != boost::end(multirange); ++it)
+ {
+ if ( !dispatch::disjoint
+ <
+ typename boost::range_value<MultiRange>::type,
+ SegmentOrBox
+ >::apply(*it, segment_or_box) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+
+template
+<
+ typename Range,
+ closure_selector Closure,
+ typename SegmentOrBox
+>
+struct disjoint_range_segment_or_box
+{
+ static inline
+ bool apply(Range const& range, SegmentOrBox const& segment_or_box)
+ {
+ typedef typename closeable_view<Range const, Closure>::type view_type;
+
+ typedef typename ::boost::range_value<view_type>::type point_type;
+ typedef typename ::boost::range_iterator
+ <
+ view_type const
+ >::type const_iterator;
+
+ typedef typename ::boost::range_size<view_type>::type size_type;
+
+ typedef typename geometry::model::referring_segment
+ <
+ point_type const
+ > range_segment;
+
+ view_type view(range);
+
+ const size_type count = ::boost::size(view);
+
+ if ( count == 0 )
+ {
+ return false;
+ }
+ else if ( count == 1 )
+ {
+ return dispatch::disjoint
+ <
+ point_type, SegmentOrBox
+ >::apply(geometry::range::front<view_type const>(view),
+ segment_or_box);
+ }
+ else
+ {
+ const_iterator it0 = ::boost::begin(view);
+ const_iterator it1 = ::boost::begin(view) + 1;
+ const_iterator last = ::boost::end(view);
+
+ for ( ; it1 != last ; ++it0, ++it1 )
+ {
+ range_segment rng_segment(*it0, *it1);
+ if ( !dispatch::disjoint
+ <
+ range_segment, SegmentOrBox
+ >::apply(rng_segment, segment_or_box) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+};
+
+
+
+
+template
+<
+ typename Linear,
+ typename SegmentOrBox,
+ typename Tag = typename tag<Linear>::type
+>
+struct disjoint_linear_segment_or_box
+ : not_implemented<Linear, SegmentOrBox>
+{};
+
+
+template <typename Linestring, typename SegmentOrBox>
+struct disjoint_linear_segment_or_box<Linestring, SegmentOrBox, linestring_tag>
+ : disjoint_range_segment_or_box<Linestring, closed, SegmentOrBox>
+{};
+
+
+template <typename MultiLinestring, typename SegmentOrBox>
+struct disjoint_linear_segment_or_box
+ <
+ MultiLinestring, SegmentOrBox, multi_linestring_tag
+ > : disjoint_multirange_segment_or_box<MultiLinestring, SegmentOrBox>
+{};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear, typename Segment>
+struct disjoint<Linear, Segment, 2, linear_tag, segment_tag, false>
+ : detail::disjoint::disjoint_linear_segment_or_box<Linear, Segment>
+{};
+
+
+template <typename Linear, typename Box, std::size_t DimensionCount>
+struct disjoint<Linear, Box, DimensionCount, linear_tag, box_tag, false>
+ : detail::disjoint::disjoint_linear_segment_or_box<Linear, Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/point_box.hpp b/boost/geometry/algorithms/detail/disjoint/point_box.hpp
new file mode 100644
index 0000000000..ea6609a153
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/point_box.hpp
@@ -0,0 +1,94 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_POINT_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template
+<
+ typename Point, typename Box,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct point_box
+{
+ static inline bool apply(Point const& point, Box const& box)
+ {
+ if (get<Dimension>(point) < get<min_corner, Dimension>(box)
+ || get<Dimension>(point) > get<max_corner, Dimension>(box))
+ {
+ return true;
+ }
+ return point_box
+ <
+ Point, Box,
+ Dimension + 1, DimensionCount
+ >::apply(point, box);
+ }
+};
+
+
+template <typename Point, typename Box, std::size_t DimensionCount>
+struct point_box<Point, Box, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Point const& , Box const& )
+ {
+ return false;
+ }
+};
+
+
+}} // namespace detail::equals
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Point, typename Box, std::size_t DimensionCount>
+struct disjoint<Point, Box, DimensionCount, point_tag, box_tag, false>
+ : detail::disjoint::point_box<Point, Box, 0, DimensionCount>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp
new file mode 100644
index 0000000000..a58bff41da
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp
@@ -0,0 +1,111 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_POINT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP
+
+#include <boost/geometry/geometries/segment.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template<typename Point, typename Geometry>
+struct disjoint_point_linear
+{
+ static inline
+ bool apply(Point const& pt, Geometry const& g)
+ {
+ return !geometry::covered_by(pt, g);
+ }
+};
+
+
+template <typename Geometry1, typename Geometry2>
+struct reverse_covered_by
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ return !geometry::covered_by(geometry1, geometry2);
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template<typename Point, typename Linear, std::size_t DimensionCount>
+struct disjoint<Point, Linear, DimensionCount, point_tag, linear_tag, false>
+ : public detail::disjoint::disjoint_point_linear<Point, Linear>
+{};
+
+
+template <typename Point, typename Areal, std::size_t DimensionCount>
+struct disjoint<Point, Areal, DimensionCount, point_tag, areal_tag, false>
+ : detail::disjoint::reverse_covered_by<Point, Areal>
+{};
+
+
+template<typename Point, typename Segment, std::size_t DimensionCount>
+struct disjoint<Point, Segment, DimensionCount, point_tag, segment_tag, false>
+{
+ static inline bool apply(Point const& point, Segment const& segment)
+ {
+ typedef geometry::model::referring_segment<Point const> other_segment;
+
+ other_segment other(point, point);
+ return detail::disjoint::disjoint_segment
+ <
+ Segment, other_segment
+ >::apply(segment, other);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/point_point.hpp b/boost/geometry/algorithms/detail/disjoint/point_point.hpp
new file mode 100644
index 0000000000..b1d32bf95e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/point_point.hpp
@@ -0,0 +1,112 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_POINT_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+template
+<
+ typename Point1, typename Point2,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct point_point
+{
+ static inline bool apply(Point1 const& p1, Point2 const& p2)
+ {
+ if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
+ {
+ return true;
+ }
+ return point_point
+ <
+ Point1, Point2,
+ Dimension + 1, DimensionCount
+ >::apply(p1, p2);
+ }
+};
+
+
+template <typename Point1, typename Point2, std::size_t DimensionCount>
+struct point_point<Point1, Point2, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Point1 const& , Point2 const& )
+ {
+ return false;
+ }
+};
+
+
+/*!
+ \brief Internal utility function to detect of points are disjoint
+ \note To avoid circular references
+ */
+template <typename Point1, typename Point2>
+inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
+{
+ return point_point
+ <
+ Point1, Point2,
+ 0, dimension<Point1>::type::value
+ >::apply(point1, point2);
+}
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Point1, typename Point2, std::size_t DimensionCount>
+struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, false>
+ : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
new file mode 100644
index 0000000000..5368432ed4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
@@ -0,0 +1,291 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISJOINT_SEGMENT_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
+
+#include <cstddef>
+#include <utility>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/calculation_type.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template <std::size_t I>
+struct compute_tmin_tmax_per_dim
+{
+ template <typename SegmentPoint, typename Box, typename RelativeDistance>
+ static inline void apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ Box const& box,
+ RelativeDistance& ti_min,
+ RelativeDistance& ti_max,
+ RelativeDistance& diff)
+ {
+ typedef typename coordinate_type<Box>::type box_coordinate_type;
+ typedef typename coordinate_type
+ <
+ SegmentPoint
+ >::type point_coordinate_type;
+
+ RelativeDistance c_p0 = boost::numeric_cast
+ <
+ point_coordinate_type
+ >( geometry::get<I>(p0) );
+
+ RelativeDistance c_p1 = boost::numeric_cast
+ <
+ point_coordinate_type
+ >( geometry::get<I>(p1) );
+
+ RelativeDistance c_b_min = boost::numeric_cast
+ <
+ box_coordinate_type
+ >( geometry::get<geometry::min_corner, I>(box) );
+
+ RelativeDistance c_b_max = boost::numeric_cast
+ <
+ box_coordinate_type
+ >( geometry::get<geometry::max_corner, I>(box) );
+
+ if ( geometry::get<I>(p1) >= geometry::get<I>(p0) )
+ {
+ diff = c_p1 - c_p0;
+ ti_min = c_b_min - c_p0;
+ ti_max = c_b_max - c_p0;
+ }
+ else
+ {
+ diff = c_p0 - c_p1;
+ ti_min = c_p0 - c_b_max;
+ ti_max = c_p0 - c_b_min;
+ }
+ }
+};
+
+
+template
+<
+ typename RelativeDistance,
+ typename SegmentPoint,
+ typename Box,
+ std::size_t I,
+ std::size_t Dimension
+>
+struct disjoint_segment_box_impl
+{
+ template <typename RelativeDistancePair>
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ Box const& box,
+ RelativeDistancePair& t_min,
+ RelativeDistancePair& t_max)
+ {
+ RelativeDistance ti_min, ti_max, diff;
+
+ compute_tmin_tmax_per_dim<I>::apply(p0, p1, box, ti_min, ti_max, diff);
+
+ if ( geometry::math::equals(diff, 0) )
+ {
+ if ( (geometry::math::equals(t_min.second, 0)
+ && t_min.first > ti_max)
+ ||
+ (geometry::math::equals(t_max.second, 0)
+ && t_max.first < ti_min) )
+ {
+ return true;
+ }
+ }
+
+ RelativeDistance t_min_x_diff = t_min.first * diff;
+ RelativeDistance t_max_x_diff = t_max.first * diff;
+
+ if ( t_min_x_diff > ti_max * t_min.second
+ || t_max_x_diff < ti_min * t_max.second )
+ {
+ return true;
+ }
+
+ if ( ti_min * t_min.second > t_min_x_diff )
+ {
+ t_min.first = ti_min;
+ t_min.second = diff;
+ }
+ if ( ti_max * t_max.second < t_max_x_diff )
+ {
+ t_max.first = ti_max;
+ t_max.second = diff;
+ }
+
+ if ( t_min.first > t_min.second || t_max.first < 0 )
+ {
+ return true;
+ }
+
+ return disjoint_segment_box_impl
+ <
+ RelativeDistance,
+ SegmentPoint,
+ Box,
+ I + 1,
+ Dimension
+ >::apply(p0, p1, box, t_min, t_max);
+ }
+};
+
+
+template
+<
+ typename RelativeDistance,
+ typename SegmentPoint,
+ typename Box,
+ std::size_t Dimension
+>
+struct disjoint_segment_box_impl
+ <
+ RelativeDistance, SegmentPoint, Box, 0, Dimension
+ >
+{
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ Box const& box)
+ {
+ std::pair<RelativeDistance, RelativeDistance> t_min, t_max;
+ RelativeDistance diff;
+
+ compute_tmin_tmax_per_dim<0>::apply(p0, p1, box,
+ t_min.first, t_max.first, diff);
+
+ if ( geometry::math::equals(diff, 0) )
+ {
+ if ( geometry::math::equals(t_min.first, 0) ) { t_min.first = -1; }
+ if ( geometry::math::equals(t_max.first, 0) ) { t_max.first = 1; }
+ }
+
+ if ( t_min.first > diff || t_max.first < 0 )
+ {
+ return true;
+ }
+
+ t_min.second = t_max.second = diff;
+
+ return disjoint_segment_box_impl
+ <
+ RelativeDistance, SegmentPoint, Box, 1, Dimension
+ >::apply(p0, p1, box, t_min, t_max);
+ }
+};
+
+
+template
+<
+ typename RelativeDistance,
+ typename SegmentPoint,
+ typename Box,
+ std::size_t Dimension
+>
+struct disjoint_segment_box_impl
+ <
+ RelativeDistance, SegmentPoint, Box, Dimension, Dimension
+ >
+{
+ template <typename RelativeDistancePair>
+ static inline bool apply(SegmentPoint const&, SegmentPoint const&,
+ Box const&,
+ RelativeDistancePair&, RelativeDistancePair&)
+ {
+ return false;
+ }
+};
+
+
+//=========================================================================
+
+
+template <typename Segment, typename Box>
+struct disjoint_segment_box
+{
+ static inline bool apply(Segment const& segment, Box const& box)
+ {
+ assert_dimension_equal<Segment, Box>();
+
+ typedef typename util::calculation_type::geometric::binary
+ <
+ Segment, Box, void
+ >::type relative_distance_type;
+
+ typedef typename point_type<Segment>::type segment_point_type;
+ segment_point_type p0, p1;
+ geometry::detail::assign_point_from_index<0>(segment, p0);
+ geometry::detail::assign_point_from_index<1>(segment, p1);
+
+ return disjoint_segment_box_impl
+ <
+ relative_distance_type, segment_point_type, Box,
+ 0, dimension<Box>::value
+ >::apply(p0, p1, box);
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Segment, typename Box, std::size_t DimensionCount>
+struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false>
+ : detail::disjoint::disjoint_segment_box<Segment, Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp b/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp
new file mode 100644
index 0000000000..5b49e571dd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp
@@ -0,0 +1,333 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISTANCE_BACKWARD_COMPATIBILITY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
+#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template<typename Point, typename Segment, typename Strategy>
+struct point_to_segment
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename point_type<Segment>::type
+ >::type
+ apply(Point const& point, Segment const& segment, Strategy const& )
+ {
+ typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Segment>::type,
+ Strategy
+ >::type segment_strategy;
+
+ typename point_type<Segment>::type p[2];
+ geometry::detail::assign_point_from_index<0>(segment, p[0]);
+ geometry::detail::assign_point_from_index<1>(segment, p[1]);
+ return segment_strategy.apply(point, p[0], p[1]);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Point-segment version 1, with point-point strategy
+template <typename Point, typename Segment, typename Strategy>
+struct distance
+<
+ Point, Segment, Strategy,
+ point_tag, segment_tag, strategy_tag_distance_point_point,
+ false
+> : detail::distance::point_to_segment<Point, Segment, Strategy>
+{};
+
+
+// Point-line version 1, where point-point strategy is specified
+template <typename Point, typename Linestring, typename Strategy>
+struct distance
+<
+ Point, Linestring, Strategy,
+ point_tag, linestring_tag, strategy_tag_distance_point_point,
+ false
+>
+{
+
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Linestring>::type
+ >::type
+ apply(Point const& point,
+ Linestring const& linestring,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Linestring>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return detail::distance::point_to_range
+ <
+ Point, Linestring, closed, ps_strategy_type
+ >::apply(point, linestring, ps_strategy_type());
+ }
+};
+
+
+// Point-ring , where point-point strategy is specified
+template <typename Point, typename Ring, typename Strategy>
+struct distance
+<
+ Point, Ring, Strategy,
+ point_tag, ring_tag, strategy_tag_distance_point_point,
+ false
+>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Ring>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ Ring const& ring,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Ring>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return detail::distance::point_to_ring
+ <
+ Point, Ring,
+ geometry::closure<Ring>::value,
+ ps_strategy_type
+ >::apply(point, ring, ps_strategy_type());
+ }
+};
+
+
+// Point-polygon , where point-point strategy is specified
+template <typename Point, typename Polygon, typename Strategy>
+struct distance
+<
+ Point, Polygon, Strategy,
+ point_tag, polygon_tag, strategy_tag_distance_point_point,
+ false
+>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Polygon>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ Polygon const& polygon,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Polygon>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return detail::distance::point_to_polygon
+ <
+ Point,
+ Polygon,
+ geometry::closure<Polygon>::value,
+ ps_strategy_type
+ >::apply(point, polygon, ps_strategy_type());
+ }
+};
+
+
+
+
+template
+<
+ typename Point,
+ typename MultiGeometry,
+ typename MultiGeometryTag,
+ typename Strategy
+>
+struct distance
+ <
+ Point, MultiGeometry, Strategy,
+ point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_point, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<MultiGeometry>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ MultiGeometry const& multigeometry,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<MultiGeometry>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return distance
+ <
+ Point, MultiGeometry, ps_strategy_type,
+ point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_segment, false
+ >::apply(point, multigeometry, ps_strategy_type());
+ }
+};
+
+
+template
+<
+ typename Geometry,
+ typename MultiPoint,
+ typename GeometryTag,
+ typename Strategy
+>
+struct distance
+ <
+ Geometry, MultiPoint, Strategy,
+ GeometryTag, multi_point_tag,
+ strategy_tag_distance_point_point, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<Geometry>::type
+ >::type return_type;
+
+ static inline return_type apply(Geometry const& geometry,
+ MultiPoint const& multipoint,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ typename point_type<MultiPoint>::type,
+ typename point_type<Geometry>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return distance
+ <
+ Geometry, MultiPoint, ps_strategy_type,
+ GeometryTag, multi_point_tag,
+ strategy_tag_distance_point_segment, false
+ >::apply(geometry, multipoint, ps_strategy_type());
+ }
+};
+
+
+template
+<
+ typename MultiPoint,
+ typename MultiGeometry,
+ typename MultiGeometryTag,
+ typename Strategy
+>
+struct distance
+ <
+ MultiPoint, MultiGeometry, Strategy,
+ multi_point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_point, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<MultiGeometry>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ MultiGeometry const& multigeometry,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ typename point_type<MultiPoint>::type,
+ typename point_type<MultiGeometry>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return distance
+ <
+ MultiPoint, MultiGeometry, ps_strategy_type,
+ multi_point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_segment, false
+ >::apply(multipoint, multigeometry, ps_strategy_type());
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP
diff --git a/boost/geometry/algorithms/detail/distance/box_to_box.hpp b/boost/geometry/algorithms/detail/distance/box_to_box.hpp
new file mode 100644
index 0000000000..44778e9e06
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/box_to_box.hpp
@@ -0,0 +1,60 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Box1, typename Box2, typename Strategy>
+struct distance
+ <
+ Box1, Box2, Strategy, box_tag, box_tag,
+ strategy_tag_distance_box_box, false
+ >
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Box1>::type,
+ typename point_type<Box2>::type
+ >::type
+ apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ boost::ignore_unused(strategy);
+ return strategy.apply(box1, box2);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/default_strategies.hpp b/boost/geometry/algorithms/detail/distance/default_strategies.hpp
new file mode 100644
index 0000000000..a01ace2b58
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/default_strategies.hpp
@@ -0,0 +1,137 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISTANCE_DEFAULT_STRATEGIES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+
+// Helper metafunction for default strategy retrieval
+template
+<
+ typename Geometry1,
+ typename Geometry2 = Geometry1,
+ typename Tag1 = typename tag_cast
+ <
+ typename tag<Geometry1>::type, pointlike_tag
+ >::type,
+ typename Tag2 = typename tag_cast
+ <
+ typename tag<Geometry2>::type, pointlike_tag
+ >::type,
+ bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct default_strategy
+ : strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag,
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type
+ >
+{};
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1,
+ typename Tag2
+>
+struct default_strategy<Geometry1, Geometry2, Tag1, Tag2, true>
+ : default_strategy<Geometry2, Geometry1, Tag2, Tag1, false>
+{};
+
+
+template <typename Pointlike1, typename Pointlike2>
+struct default_strategy
+ <
+ Pointlike1, Pointlike2,
+ pointlike_tag, pointlike_tag, false
+ > : strategy::distance::services::default_strategy
+ <
+ point_tag, point_tag,
+ typename point_type<Pointlike1>::type,
+ typename point_type<Pointlike2>::type
+ >
+{};
+
+
+template <typename Pointlike, typename Box>
+struct default_strategy<Pointlike, Box, pointlike_tag, box_tag, false>
+ : strategy::distance::services::default_strategy
+ <
+ point_tag, box_tag,
+ typename point_type<Pointlike>::type,
+ typename point_type<Box>::type
+ >
+{};
+
+
+template <typename Box1, typename Box2>
+struct default_strategy<Box1, Box2, box_tag, box_tag, false>
+ : strategy::distance::services::default_strategy
+ <
+ box_tag, box_tag,
+ typename point_type<Box1>::type,
+ typename point_type<Box2>::type
+ >
+{};
+
+
+
+// Helper metafunction for default point-segment strategy retrieval
+template <typename Geometry1, typename Geometry2, typename Strategy>
+struct default_ps_strategy
+ : strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag,
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type,
+ typename cs_tag<typename point_type<Geometry1>::type>::type,
+ typename cs_tag<typename point_type<Geometry2>::type>::type,
+ Strategy
+ >
+{};
+
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP
diff --git a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp
new file mode 100644
index 0000000000..04d1095cba
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp
@@ -0,0 +1,462 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
+
+#include <iterator>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+#include <boost/geometry/iterators/segment_iterator.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp>
+#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+// closure of segment or box point range
+template
+<
+ typename SegmentOrBox,
+ typename Tag = typename tag<SegmentOrBox>::type
+>
+struct segment_or_box_point_range_closure
+ : not_implemented<SegmentOrBox>
+{};
+
+template <typename Segment>
+struct segment_or_box_point_range_closure<Segment, segment_tag>
+{
+ static const closure_selector value = closed;
+};
+
+template <typename Box>
+struct segment_or_box_point_range_closure<Box, box_tag>
+{
+ static const closure_selector value = open;
+};
+
+
+
+template
+<
+ typename Geometry,
+ typename SegmentOrBox,
+ typename Strategy,
+ typename Tag = typename tag<Geometry>::type
+>
+class geometry_to_segment_or_box
+{
+private:
+ typedef typename point_type<SegmentOrBox>::type segment_or_box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef detail::closest_feature::point_to_point_range
+ <
+ typename point_type<Geometry>::type,
+ std::vector<segment_or_box_point>,
+ segment_or_box_point_range_closure<SegmentOrBox>::value,
+ comparable_strategy
+ > point_to_point_range;
+
+ typedef detail::closest_feature::geometry_to_range geometry_to_range;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy,
+ typename point_type<Geometry>::type,
+ segment_or_box_point
+ >::type comparable_return_type;
+
+
+ // assign the new minimum value for an iterator of the point range
+ // of a segment or a box
+ template
+ <
+ typename SegOrBox,
+ typename SegOrBoxTag = typename tag<SegOrBox>::type
+ >
+ struct assign_new_min_iterator
+ : not_implemented<SegOrBox>
+ {};
+
+ template <typename Segment>
+ struct assign_new_min_iterator<Segment, segment_tag>
+ {
+ template <typename Iterator>
+ static inline void apply(Iterator&, Iterator)
+ {
+ }
+ };
+
+ template <typename Box>
+ struct assign_new_min_iterator<Box, box_tag>
+ {
+ template <typename Iterator>
+ static inline void apply(Iterator& it_min, Iterator it)
+ {
+ it_min = it;
+ }
+ };
+
+
+ // assign the points of a segment or a box to a range
+ template
+ <
+ typename SegOrBox,
+ typename PointRange,
+ typename SegOrBoxTag = typename tag<SegOrBox>::type
+ >
+ struct assign_segment_or_box_points
+ {};
+
+ template <typename Segment, typename PointRange>
+ struct assign_segment_or_box_points<Segment, PointRange, segment_tag>
+ {
+ static inline void apply(Segment const& segment, PointRange& range)
+ {
+ detail::assign_point_from_index<0>(segment, range[0]);
+ detail::assign_point_from_index<1>(segment, range[1]);
+ }
+ };
+
+ template <typename Box, typename PointRange>
+ struct assign_segment_or_box_points<Box, PointRange, box_tag>
+ {
+ static inline void apply(Box const& box, PointRange& range)
+ {
+ detail::assign_box_corners_oriented<true>(box, range);
+ }
+ };
+
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Geometry>::type,
+ segment_or_box_point
+ >::type return_type;
+
+ static inline return_type apply(Geometry const& geometry,
+ SegmentOrBox const& segment_or_box,
+ Strategy const& strategy,
+ bool check_intersection = true)
+ {
+ typedef geometry::point_iterator<Geometry const> point_iterator_type;
+ typedef geometry::segment_iterator
+ <
+ Geometry const
+ > segment_iterator_type;
+
+ typedef typename std::vector
+ <
+ segment_or_box_point
+ >::const_iterator seg_or_box_iterator_type;
+
+ typedef assign_new_min_iterator<SegmentOrBox> assign_new_value;
+
+
+ if (check_intersection
+ && geometry::intersects(geometry, segment_or_box))
+ {
+ return 0;
+ }
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+
+ // get all points of the segment or the box
+ std::vector<segment_or_box_point>
+ seg_or_box_points(geometry::num_points(segment_or_box));
+
+ assign_segment_or_box_points
+ <
+ SegmentOrBox,
+ std::vector<segment_or_box_point>
+ >::apply(segment_or_box, seg_or_box_points);
+
+ // consider all distances of the points in the geometry to the
+ // segment or box
+ comparable_return_type cd_min1;
+ point_iterator_type pit_min;
+ seg_or_box_iterator_type it_min1 = seg_or_box_points.begin();
+ seg_or_box_iterator_type it_min2 = ++seg_or_box_points.begin();
+ bool first = true;
+
+ for (point_iterator_type pit = points_begin(geometry);
+ pit != points_end(geometry); ++pit, first = false)
+ {
+ comparable_return_type cd;
+ std::pair
+ <
+ seg_or_box_iterator_type, seg_or_box_iterator_type
+ > it_pair
+ = point_to_point_range::apply(*pit,
+ seg_or_box_points.begin(),
+ seg_or_box_points.end(),
+ cstrategy,
+ cd);
+
+ if (first || cd < cd_min1)
+ {
+ cd_min1 = cd;
+ pit_min = pit;
+ assign_new_value::apply(it_min1, it_pair.first);
+ assign_new_value::apply(it_min2, it_pair.second);
+ }
+ }
+
+ // consider all distances of the points in the segment or box to the
+ // segments of the geometry
+ comparable_return_type cd_min2;
+ segment_iterator_type sit_min;
+ typename std::vector<segment_or_box_point>::const_iterator it_min;
+
+ first = true;
+ for (typename std::vector<segment_or_box_point>::const_iterator it
+ = seg_or_box_points.begin();
+ it != seg_or_box_points.end(); ++it, first = false)
+ {
+ comparable_return_type cd;
+ segment_iterator_type sit
+ = geometry_to_range::apply(*it,
+ segments_begin(geometry),
+ segments_end(geometry),
+ cstrategy,
+ cd);
+
+ if (first || cd < cd_min2)
+ {
+ cd_min2 = cd;
+ it_min = it;
+ sit_min = sit;
+ }
+ }
+
+ if (is_comparable<Strategy>::value)
+ {
+ return (std::min)(cd_min1, cd_min2);
+ }
+
+ if (cd_min1 < cd_min2)
+ {
+ return strategy.apply(*pit_min, *it_min1, *it_min2);
+ }
+ else
+ {
+ return dispatch::distance
+ <
+ segment_or_box_point,
+ typename std::iterator_traits
+ <
+ segment_iterator_type
+ >::value_type,
+ Strategy
+ >::apply(*it_min, *sit_min, strategy);
+ }
+ }
+
+
+ static inline return_type
+ apply(SegmentOrBox const& segment_or_box, Geometry const& geometry,
+ Strategy const& strategy, bool check_intersection = true)
+ {
+ return apply(geometry, segment_or_box, strategy, check_intersection);
+ }
+};
+
+
+
+template <typename MultiPoint, typename SegmentOrBox, typename Strategy>
+class geometry_to_segment_or_box
+ <
+ MultiPoint, SegmentOrBox, Strategy, multi_point_tag
+ >
+{
+private:
+ typedef detail::closest_feature::geometry_to_range base_type;
+
+ typedef typename boost::range_iterator
+ <
+ MultiPoint const
+ >::type iterator_type;
+
+ typedef detail::closest_feature::geometry_to_range geometry_to_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<SegmentOrBox>::type,
+ typename point_type<MultiPoint>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ SegmentOrBox const& segment_or_box,
+ Strategy const& strategy)
+ {
+ namespace sds = strategy::distance::services;
+
+ typename sds::return_type
+ <
+ typename sds::comparable_type<Strategy>::type,
+ typename point_type<SegmentOrBox>::type,
+ typename point_type<MultiPoint>::type
+ >::type cd_min;
+
+ iterator_type it_min
+ = geometry_to_range::apply(segment_or_box,
+ boost::begin(multipoint),
+ boost::end(multipoint),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd_min);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd_min
+ :
+ dispatch::distance
+ <
+ typename point_type<MultiPoint>::type,
+ SegmentOrBox,
+ Strategy
+ >::apply(*it_min, segment_or_box, strategy);
+ }
+};
+
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear, typename Segment, typename Strategy>
+struct distance
+ <
+ Linear, Segment, Strategy, linear_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Linear, Segment, Strategy>
+{};
+
+
+template <typename Areal, typename Segment, typename Strategy>
+struct distance
+ <
+ Areal, Segment, Strategy, areal_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy>
+{};
+
+
+template <typename Segment, typename Areal, typename Strategy>
+struct distance
+ <
+ Segment, Areal, Strategy, segment_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy>
+{};
+
+
+template <typename Linear, typename Box, typename Strategy>
+struct distance
+ <
+ Linear, Box, Strategy, linear_tag, box_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box
+ <
+ Linear, Box, Strategy
+ >
+{};
+
+
+template <typename Areal, typename Box, typename Strategy>
+struct distance
+ <
+ Areal, Box, Strategy, areal_tag, box_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Areal, Box, Strategy>
+{};
+
+
+template <typename MultiPoint, typename Segment, typename Strategy>
+struct distance
+ <
+ MultiPoint, Segment, Strategy,
+ multi_point_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box
+ <
+ MultiPoint, Segment, Strategy
+ >
+{};
+
+
+template <typename MultiPoint, typename Box, typename Strategy>
+struct distance
+ <
+ MultiPoint, Box, Strategy,
+ multi_point_tag, box_tag,
+ strategy_tag_distance_point_box, false
+ > : detail::distance::geometry_to_segment_or_box
+ <
+ MultiPoint, Box, Strategy
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/implementation.hpp b/boost/geometry/algorithms/detail/distance/implementation.hpp
new file mode 100644
index 0000000000..7c009f4d79
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/implementation.hpp
@@ -0,0 +1,35 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISTANCE_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP
+
+// the implementation details
+#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
+#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp>
+#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
+#include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp>
+#include <boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp>
+#include <boost/geometry/algorithms/detail/distance/segment_to_segment.hpp>
+#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>
+#include <boost/geometry/algorithms/detail/distance/box_to_box.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/backward_compatibility.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/distance/interface.hpp b/boost/geometry/algorithms/detail/distance/interface.hpp
new file mode 100644
index 0000000000..9b377f524b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/interface.hpp
@@ -0,0 +1,403 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISTANCE_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
+
+#include <boost/concept_check.hpp>
+
+#include <boost/mpl/always.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/vector.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/default_distance_result.hpp>
+#include <boost/geometry/strategies/distance_result.hpp>
+
+#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2, typename Strategy,
+ typename Tag1, typename Tag2, typename StrategyTag
+>
+struct distance
+<
+ Geometry1, Geometry2, Strategy,
+ Tag1, Tag2, StrategyTag,
+ true
+>
+ : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Geometry2>::type,
+ typename point_type<Geometry1>::type
+ >::type return_type;
+
+ static inline return_type apply(
+ Geometry1 const& g1,
+ Geometry2 const& g2,
+ Strategy const& strategy)
+ {
+ return distance
+ <
+ Geometry2, Geometry1, Strategy,
+ Tag2, Tag1, StrategyTag,
+ false
+ >::apply(g2, g1, strategy);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct distance
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, Strategy
+ >::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline
+ typename distance_result<Geometry1, Geometry2, default_strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type strategy_type;
+
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, strategy_type
+ >::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+
+template <typename Geometry1, typename Geometry2>
+struct distance
+{
+ template <typename Strategy>
+ static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return
+ resolve_strategy::distance::apply(geometry1, geometry2, strategy);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename distance_result
+ <
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ >
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2,
+ Strategy const& strategy)
+ : m_geometry2(geometry2),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ typename distance_result<Geometry1, Geometry2, Strategy>::type
+ operator()(Geometry1 const& geometry1) const
+ {
+ return distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename distance_result
+ <
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename distance_result
+ <
+ Geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ >
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1,
+ Strategy const& strategy)
+ : m_geometry1(geometry1),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ typename distance_result<Geometry1, Geometry2, Strategy>::type
+ operator()(Geometry2 const& geometry2) const
+ {
+ return distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename distance_result
+ <
+ Geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ apply(
+ Geometry1 const& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+
+template
+<
+ BOOST_VARIANT_ENUM_PARAMS(typename A),
+ BOOST_VARIANT_ENUM_PARAMS(typename B)
+>
+struct distance
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ >
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ typename distance_result<Geometry1, Geometry2, Strategy>::type
+ operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const
+ {
+ return distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_calc2{distance} \brief_strategy
+\ingroup distance
+\details
+\details \details_calc{area}. \brief_strategy. \details_strategy_reasons
+
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Distance}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{distance}
+\return \return_calc{distance}
+\note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
+ it may also be a point-segment strategy.
+
+\qbk{distinguish,with strategy}
+
+\qbk{
+[heading Available Strategies]
+\* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
+\* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
+\* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
+\* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
+\* more (currently extensions): Vincenty\, Andoyer (geographic)
+}
+ */
+
+/*
+Note, in case of a Compilation Error:
+if you get:
+ - "Failed to specialize function template ..."
+ - "error: no matching function for call to ..."
+for distance, it is probably so that there is no specialization
+for return_type<...> for your strategy.
+*/
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline typename distance_result<Geometry1, Geometry2, Strategy>::type
+distance(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ detail::throw_on_empty_input(geometry1);
+ detail::throw_on_empty_input(geometry2);
+
+ return resolve_variant::distance
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+/*!
+\brief \brief_calc2{distance}
+\ingroup distance
+\details The default strategy is used, corresponding to the coordinate system of the geometries
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_calc{distance}
+
+\qbk{[include reference/algorithms/distance.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline typename default_distance_result<Geometry1, Geometry2>::type
+distance(Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return distance(geometry1, geometry2, default_strategy());
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/distance/is_comparable.hpp b/boost/geometry/algorithms/detail/distance/is_comparable.hpp
new file mode 100644
index 0000000000..d13cc6c740
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/is_comparable.hpp
@@ -0,0 +1,45 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
+#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
+
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+// metafunction to determine is a strategy is comparable or not
+template <typename Strategy>
+struct is_comparable
+ : boost::is_same
+ <
+ Strategy,
+ typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type
+ >
+{};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
diff --git a/boost/geometry/algorithms/detail/distance/iterator_selector.hpp b/boost/geometry/algorithms/detail/distance/iterator_selector.hpp
new file mode 100644
index 0000000000..363ec465a4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/iterator_selector.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
+#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+#include <boost/geometry/iterators/segment_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+// class to choose between point_iterator and segment_iterator
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct iterator_selector
+{
+ typedef geometry::segment_iterator<Geometry> iterator_type;
+
+ static inline iterator_type begin(Geometry& geometry)
+ {
+ return segments_begin(geometry);
+ }
+
+ static inline iterator_type end(Geometry& geometry)
+ {
+ return segments_end(geometry);
+ }
+};
+
+template <typename MultiPoint>
+struct iterator_selector<MultiPoint, multi_point_tag>
+{
+ typedef geometry::point_iterator<MultiPoint> iterator_type;
+
+ static inline iterator_type begin(MultiPoint& multipoint)
+ {
+ return points_begin(multipoint);
+ }
+
+ static inline iterator_type end(MultiPoint& multipoint)
+ {
+ return points_end(multipoint);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
diff --git a/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp
new file mode 100644
index 0000000000..b63104da7d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp
@@ -0,0 +1,147 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename Linear, typename Areal, typename Strategy>
+struct linear_to_areal
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Linear>::type,
+ typename point_type<Areal>::type
+ >::type return_type;
+
+ static inline return_type apply(Linear const& linear,
+ Areal const& areal,
+ Strategy const& strategy)
+ {
+ if ( geometry::intersects(linear, areal) )
+ {
+ return 0;
+ }
+
+ return linear_to_linear
+ <
+ Linear, Areal, Strategy
+ >::apply(linear, areal, strategy, false);
+ }
+
+
+ static inline return_type apply(Areal const& areal,
+ Linear const& linear,
+ Strategy const& strategy)
+ {
+ return apply(linear, areal, strategy);
+ }
+};
+
+
+template <typename Areal1, typename Areal2, typename Strategy>
+struct areal_to_areal
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Areal1>::type,
+ typename point_type<Areal2>::type
+ >::type return_type;
+
+ static inline return_type apply(Areal1 const& areal1,
+ Areal2 const& areal2,
+ Strategy const& strategy)
+ {
+ if ( geometry::intersects(areal1, areal2) )
+ {
+ return 0;
+ }
+
+ return linear_to_linear
+ <
+ Areal1, Areal2, Strategy
+ >::apply(areal1, areal2, strategy, false);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Linear, typename Areal, typename Strategy>
+struct distance
+ <
+ Linear, Areal, Strategy,
+ linear_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::linear_to_areal
+ <
+ Linear, Areal, Strategy
+ >
+{};
+
+
+template <typename Areal, typename Linear, typename Strategy>
+struct distance
+ <
+ Areal, Linear, Strategy,
+ areal_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::linear_to_areal
+ <
+ Linear, Areal, Strategy
+ >
+{};
+
+
+template <typename Areal1, typename Areal2, typename Strategy>
+struct distance
+ <
+ Areal1, Areal2, Strategy,
+ areal_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::areal_to_areal
+ <
+ Areal1, Areal2, Strategy
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp
new file mode 100644
index 0000000000..e44b372842
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp
@@ -0,0 +1,123 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+#include <boost/geometry/iterators/segment_iterator.hpp>
+
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/num_segments.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename Linear1, typename Linear2, typename Strategy>
+struct linear_to_linear
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Linear1>::type,
+ typename point_type<Linear2>::type
+ >::type return_type;
+
+ static inline return_type apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ Strategy const& strategy,
+ bool = false)
+ {
+ if (geometry::num_points(linear1) == 1)
+ {
+ return dispatch::distance
+ <
+ typename point_type<Linear1>::type,
+ Linear2,
+ Strategy
+ >::apply(*points_begin(linear1), linear2, strategy);
+ }
+
+ if (geometry::num_points(linear2) == 1)
+ {
+ return dispatch::distance
+ <
+ typename point_type<Linear2>::type,
+ Linear1,
+ Strategy
+ >::apply(*points_begin(linear2), linear1, strategy);
+ }
+
+ if (geometry::num_segments(linear2) < geometry::num_segments(linear1))
+ {
+ return point_or_segment_range_to_geometry_rtree
+ <
+ geometry::segment_iterator<Linear2 const>,
+ Linear1,
+ Strategy
+ >::apply(geometry::segments_begin(linear2),
+ geometry::segments_end(linear2),
+ linear1,
+ strategy);
+
+ }
+
+ return point_or_segment_range_to_geometry_rtree
+ <
+ geometry::segment_iterator<Linear1 const>,
+ Linear2,
+ Strategy
+ >::apply(geometry::segments_begin(linear1),
+ geometry::segments_end(linear1),
+ linear2,
+ strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Linear1, typename Linear2, typename Strategy>
+struct distance
+ <
+ Linear1, Linear2, Strategy,
+ linear_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::linear_to_linear
+ <
+ Linear1, Linear2, Strategy
+ >
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp
new file mode 100644
index 0000000000..5f2c6e34fb
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp
@@ -0,0 +1,240 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
+struct multipoint_to_multipoint
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint1>::type,
+ typename point_type<MultiPoint2>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint1 const& multipoint1,
+ MultiPoint2 const& multipoint2,
+ Strategy const& strategy)
+ {
+ if (boost::size(multipoint2) < boost::size(multipoint1))
+
+ {
+ return point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint2 const>::type,
+ MultiPoint1,
+ Strategy
+ >::apply(boost::begin(multipoint2),
+ boost::end(multipoint2),
+ multipoint1,
+ strategy);
+ }
+
+ return point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint1 const>::type,
+ MultiPoint2,
+ Strategy
+ >::apply(boost::begin(multipoint1),
+ boost::end(multipoint1),
+ multipoint2,
+ strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename Linear, typename Strategy>
+struct multipoint_to_linear
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<Linear>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ Linear const& linear,
+ Strategy const& strategy)
+ {
+ return detail::distance::point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint const>::type,
+ Linear,
+ Strategy
+ >::apply(boost::begin(multipoint),
+ boost::end(multipoint),
+ linear,
+ strategy);
+ }
+
+ static inline return_type apply(Linear const& linear,
+ MultiPoint const& multipoint,
+ Strategy const& strategy)
+ {
+ return apply(multipoint, linear, strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename Areal, typename Strategy>
+class multipoint_to_areal
+{
+private:
+ struct within_areal
+ {
+ within_areal(Areal const& areal)
+ : m_areal(areal)
+ {}
+
+ template <typename Point>
+ inline bool apply(Point const& point) const
+ {
+ return geometry::within(point, m_areal);
+ }
+
+ Areal const& m_areal;
+ };
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<Areal>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ Areal const& areal,
+ Strategy const& strategy)
+ {
+ within_areal predicate(areal);
+
+ if (check_iterator_range
+ <
+ within_areal, false
+ >::apply(boost::begin(multipoint),
+ boost::end(multipoint),
+ predicate))
+ {
+ return 0;
+ }
+
+ return detail::distance::point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint const>::type,
+ Areal,
+ Strategy
+ >::apply(boost::begin(multipoint),
+ boost::end(multipoint),
+ areal,
+ strategy);
+ }
+
+ static inline return_type apply(Areal const& areal,
+ MultiPoint const& multipoint,
+ Strategy const& strategy)
+ {
+ return apply(multipoint, areal, strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
+struct distance
+ <
+ MultiPoint1, MultiPoint2, Strategy,
+ multi_point_tag, multi_point_tag,
+ strategy_tag_distance_point_point, false
+ > : detail::distance::multipoint_to_multipoint
+ <
+ MultiPoint1, MultiPoint2, Strategy
+ >
+{};
+
+template <typename MultiPoint, typename Linear, typename Strategy>
+struct distance
+ <
+ MultiPoint, Linear, Strategy, multi_point_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy>
+{};
+
+
+template <typename Linear, typename MultiPoint, typename Strategy>
+struct distance
+ <
+ Linear, MultiPoint, Strategy, linear_tag, multi_point_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy>
+{};
+
+
+template <typename MultiPoint, typename Areal, typename Strategy>
+struct distance
+ <
+ MultiPoint, Areal, Strategy, multi_point_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy>
+{};
+
+
+template <typename Areal, typename MultiPoint, typename Strategy>
+struct distance
+ <
+ Areal, MultiPoint, Strategy, areal_tag, multi_point_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp
new file mode 100644
index 0000000000..ab5de3d9b2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp
@@ -0,0 +1,518 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISTANCE_POINT_TO_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
+
+#include <iterator>
+
+#include <boost/core/ignore_unused.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp>
+#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename P1, typename P2, typename Strategy>
+struct point_to_point
+{
+ static inline
+ typename strategy::distance::services::return_type<Strategy, P1, P2>::type
+ apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
+ {
+ boost::ignore_unused(strategy);
+ return strategy.apply(p1, p2);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename Range,
+ closure_selector Closure,
+ typename Strategy
+>
+class point_to_range
+{
+private:
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef detail::closest_feature::point_to_point_range
+ <
+ Point, Range, Closure, comparable_strategy
+ > point_to_point_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename boost::range_value<Range>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point, Range const& range,
+ Strategy const& strategy)
+ {
+ return_type const zero = return_type(0);
+
+ if (boost::size(range) == 0)
+ {
+ return zero;
+ }
+
+ namespace sds = strategy::distance::services;
+
+ typename sds::return_type
+ <
+ comparable_strategy,
+ Point,
+ typename point_type<Range>::type
+ >::type cd_min;
+
+ std::pair
+ <
+ typename boost::range_iterator<Range const>::type,
+ typename boost::range_iterator<Range const>::type
+ > it_pair
+ = point_to_point_range::apply(point,
+ boost::begin(range),
+ boost::end(range),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd_min);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd_min
+ :
+ strategy.apply(point, *it_pair.first, *it_pair.second);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename Ring,
+ closure_selector Closure,
+ typename Strategy
+>
+struct point_to_ring
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Ring>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ Ring const& ring,
+ Strategy const& strategy)
+ {
+ if (geometry::within(point, ring))
+ {
+ return return_type(0);
+ }
+
+ return point_to_range
+ <
+ Point, Ring, closure<Ring>::value, Strategy
+ >::apply(point, ring, strategy);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename Polygon,
+ closure_selector Closure,
+ typename Strategy
+>
+class point_to_polygon
+{
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Polygon>::type
+ >::type return_type;
+
+private:
+ typedef point_to_range
+ <
+ Point, typename ring_type<Polygon>::type, Closure, Strategy
+ > per_ring;
+
+ struct distance_to_interior_rings
+ {
+ template <typename InteriorRingIterator>
+ static inline return_type apply(Point const& point,
+ InteriorRingIterator first,
+ InteriorRingIterator last,
+ Strategy const& strategy)
+ {
+ for (InteriorRingIterator it = first; it != last; ++it)
+ {
+ if (geometry::within(point, *it))
+ {
+ // the point is inside a polygon hole, so its distance
+ // to the polygon its distance to the polygon's
+ // hole boundary
+ return per_ring::apply(point, *it, strategy);
+ }
+ }
+ return 0;
+ }
+
+ template <typename InteriorRings>
+ static inline return_type apply(Point const& point,
+ InteriorRings const& interior_rings,
+ Strategy const& strategy)
+ {
+ return apply(point,
+ boost::begin(interior_rings),
+ boost::end(interior_rings),
+ strategy);
+ }
+ };
+
+
+public:
+ static inline return_type apply(Point const& point,
+ Polygon const& polygon,
+ Strategy const& strategy)
+ {
+ if (!geometry::covered_by(point, exterior_ring(polygon)))
+ {
+ // the point is outside the exterior ring, so its distance
+ // to the polygon is its distance to the polygon's exterior ring
+ return per_ring::apply(point, exterior_ring(polygon), strategy);
+ }
+
+ // Check interior rings
+ return distance_to_interior_rings::apply(point,
+ interior_rings(polygon),
+ strategy);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename MultiGeometry,
+ typename Strategy,
+ bool CheckCoveredBy = boost::is_same
+ <
+ typename tag<MultiGeometry>::type, multi_polygon_tag
+ >::value
+>
+class point_to_multigeometry
+{
+private:
+ typedef detail::closest_feature::geometry_to_range geometry_to_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename point_type<MultiGeometry>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ MultiGeometry const& multigeometry,
+ Strategy const& strategy)
+ {
+ typedef iterator_selector<MultiGeometry const> selector_type;
+
+ namespace sds = strategy::distance::services;
+
+ typename sds::return_type
+ <
+ typename sds::comparable_type<Strategy>::type,
+ Point,
+ typename point_type<MultiGeometry>::type
+ >::type cd;
+
+ typename selector_type::iterator_type it_min
+ = geometry_to_range::apply(point,
+ selector_type::begin(multigeometry),
+ selector_type::end(multigeometry),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd
+ :
+ dispatch::distance
+ <
+ Point,
+ typename std::iterator_traits
+ <
+ typename selector_type::iterator_type
+ >::value_type,
+ Strategy
+ >::apply(point, *it_min, strategy);
+ }
+};
+
+
+// this is called only for multipolygons, hence the change in the
+// template parameter name MultiGeometry to MultiPolygon
+template <typename Point, typename MultiPolygon, typename Strategy>
+struct point_to_multigeometry<Point, MultiPolygon, Strategy, true>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename point_type<MultiPolygon>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ MultiPolygon const& multipolygon,
+ Strategy const& strategy)
+ {
+ if (geometry::covered_by(point, multipolygon))
+ {
+ return 0;
+ }
+
+ return point_to_multigeometry
+ <
+ Point, MultiPolygon, Strategy, false
+ >::apply(point, multipolygon, strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Point-point
+template <typename P1, typename P2, typename Strategy>
+struct distance
+ <
+ P1, P2, Strategy, point_tag, point_tag,
+ strategy_tag_distance_point_point, false
+ > : detail::distance::point_to_point<P1, P2, Strategy>
+{};
+
+
+// Point-line version 2, where point-segment strategy is specified
+template <typename Point, typename Linestring, typename Strategy>
+struct distance
+ <
+ Point, Linestring, Strategy, point_tag, linestring_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_range<Point, Linestring, closed, Strategy>
+{};
+
+
+// Point-ring , where point-segment strategy is specified
+template <typename Point, typename Ring, typename Strategy>
+struct distance
+ <
+ Point, Ring, Strategy, point_tag, ring_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_ring
+ <
+ Point, Ring, closure<Ring>::value, Strategy
+ >
+{};
+
+
+// Point-polygon , where point-segment strategy is specified
+template <typename Point, typename Polygon, typename Strategy>
+struct distance
+ <
+ Point, Polygon, Strategy, point_tag, polygon_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_polygon
+ <
+ Point, Polygon, closure<Polygon>::value, Strategy
+ >
+{};
+
+
+// Point-segment version 2, with point-segment strategy
+template <typename Point, typename Segment, typename Strategy>
+struct distance
+ <
+ Point, Segment, Strategy, point_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ >
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Segment>::type
+ >::type apply(Point const& point,
+ Segment const& segment,
+ Strategy const& strategy)
+ {
+ typename point_type<Segment>::type p[2];
+ geometry::detail::assign_point_from_index<0>(segment, p[0]);
+ geometry::detail::assign_point_from_index<1>(segment, p[1]);
+
+ boost::ignore_unused(strategy);
+ return strategy.apply(point, p[0], p[1]);
+ }
+};
+
+
+template <typename Point, typename Box, typename Strategy>
+struct distance
+ <
+ Point, Box, Strategy, point_tag, box_tag,
+ strategy_tag_distance_point_box, false
+ >
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Box>::type
+ >::type
+ apply(Point const& point, Box const& box, Strategy const& strategy)
+ {
+ boost::ignore_unused(strategy);
+ return strategy.apply(point, box);
+ }
+};
+
+
+template<typename Point, typename MultiPoint, typename Strategy>
+struct distance
+ <
+ Point, MultiPoint, Strategy, point_tag, multi_point_tag,
+ strategy_tag_distance_point_point, false
+ > : detail::distance::point_to_multigeometry
+ <
+ Point, MultiPoint, Strategy
+ >
+{};
+
+
+template<typename Point, typename MultiLinestring, typename Strategy>
+struct distance
+ <
+ Point, MultiLinestring, Strategy, point_tag, multi_linestring_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_multigeometry
+ <
+ Point, MultiLinestring, Strategy
+ >
+{};
+
+
+template<typename Point, typename MultiPolygon, typename Strategy>
+struct distance
+ <
+ Point, MultiPolygon, Strategy, point_tag, multi_polygon_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_multigeometry
+ <
+ Point, MultiPolygon, Strategy
+ >
+{};
+
+
+template <typename Point, typename Linear, typename Strategy>
+struct distance
+ <
+ Point, Linear, Strategy, point_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ > : distance
+ <
+ Point, Linear, Strategy,
+ point_tag, typename tag<Linear>::type,
+ strategy_tag_distance_point_segment, false
+ >
+{};
+
+
+template <typename Point, typename Areal, typename Strategy>
+struct distance
+ <
+ Point, Areal, Strategy, point_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ > : distance
+ <
+ Point, Areal, Strategy,
+ point_tag, typename tag<Areal>::type,
+ strategy_tag_distance_point_segment, false
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp
new file mode 100644
index 0000000000..78189794a1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp
@@ -0,0 +1,131 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
+
+#include <iterator>
+#include <utility>
+
+#include <boost/assert.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/iterators/has_one_element.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp>
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template
+<
+ typename PointOrSegmentIterator,
+ typename Geometry,
+ typename Strategy
+>
+class point_or_segment_range_to_geometry_rtree
+{
+private:
+ typedef typename std::iterator_traits
+ <
+ PointOrSegmentIterator
+ >::value_type point_or_segment_type;
+
+ typedef iterator_selector<Geometry const> selector_type;
+
+ typedef detail::closest_feature::range_to_range_rtree range_to_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<point_or_segment_type>::type,
+ typename point_type<Geometry>::type
+ >::type return_type;
+
+ static inline return_type apply(PointOrSegmentIterator first,
+ PointOrSegmentIterator last,
+ Geometry const& geometry,
+ Strategy const& strategy)
+ {
+ namespace sds = strategy::distance::services;
+
+ BOOST_ASSERT( first != last );
+
+ if ( geometry::has_one_element(first, last) )
+ {
+ return dispatch::distance
+ <
+ point_or_segment_type, Geometry, Strategy
+ >::apply(*first, geometry, strategy);
+ }
+
+ typename sds::return_type
+ <
+ typename sds::comparable_type<Strategy>::type,
+ typename point_type<point_or_segment_type>::type,
+ typename point_type<Geometry>::type
+ >::type cd_min;
+
+ std::pair
+ <
+ point_or_segment_type,
+ typename selector_type::iterator_type
+ > closest_features
+ = range_to_range::apply(first,
+ last,
+ selector_type::begin(geometry),
+ selector_type::end(geometry),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd_min);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd_min
+ :
+ dispatch::distance
+ <
+ point_or_segment_type,
+ typename std::iterator_traits
+ <
+ typename selector_type::iterator_type
+ >::value_type,
+ Strategy
+ >::apply(closest_features.first,
+ *closest_features.second,
+ strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
diff --git a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp
new file mode 100644
index 0000000000..f64a3e9fca
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp
@@ -0,0 +1,886 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
+
+#include <cstddef>
+
+#include <functional>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/core/ignore_unused.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/calculation_type.hpp>
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename Strategy,
+ bool UsePointBoxStrategy = false
+>
+class segment_to_box_2D_generic
+{
+private:
+ typedef typename point_type<Segment>::type segment_point;
+ typedef typename point_type<Box>::type box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef detail::closest_feature::point_to_point_range
+ <
+ segment_point,
+ std::vector<box_point>,
+ open,
+ comparable_strategy
+ > point_to_point_range;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy, segment_point, box_point
+ >::type comparable_return_type;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, segment_point, box_point
+ >::type return_type;
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy,
+ bool check_intersection = true)
+ {
+ if (check_intersection && geometry::intersects(segment, box))
+ {
+ return 0;
+ }
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+
+ // get segment points
+ segment_point p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ // get box points
+ std::vector<box_point> box_points(4);
+ detail::assign_box_corners_oriented<true>(box, box_points);
+
+ comparable_return_type cd[6];
+ for (unsigned int i = 0; i < 4; ++i)
+ {
+ cd[i] = cstrategy.apply(box_points[i], p[0], p[1]);
+ }
+
+ std::pair
+ <
+ typename std::vector<box_point>::const_iterator,
+ typename std::vector<box_point>::const_iterator
+ > bit_min[2];
+
+ bit_min[0] = point_to_point_range::apply(p[0],
+ box_points.begin(),
+ box_points.end(),
+ cstrategy,
+ cd[4]);
+ bit_min[1] = point_to_point_range::apply(p[1],
+ box_points.begin(),
+ box_points.end(),
+ cstrategy,
+ cd[5]);
+
+ unsigned int imin = 0;
+ for (unsigned int i = 1; i < 6; ++i)
+ {
+ if (cd[i] < cd[imin])
+ {
+ imin = i;
+ }
+ }
+
+ if (is_comparable<Strategy>::value)
+ {
+ return cd[imin];
+ }
+
+ if (imin < 4)
+ {
+ return strategy.apply(box_points[imin], p[0], p[1]);
+ }
+ else
+ {
+ unsigned int bimin = imin - 4;
+ return strategy.apply(p[bimin],
+ *bit_min[bimin].first,
+ *bit_min[bimin].second);
+ }
+ }
+};
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename Strategy
+>
+class segment_to_box_2D_generic<Segment, Box, Strategy, true>
+{
+private:
+ typedef typename point_type<Segment>::type segment_point;
+ typedef typename point_type<Box>::type box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy, segment_point, box_point
+ >::type comparable_return_type;
+
+ typedef typename detail::distance::default_strategy
+ <
+ segment_point, Box
+ >::type point_box_strategy;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ point_box_strategy
+ >::type point_box_comparable_strategy;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, segment_point, box_point
+ >::type return_type;
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy,
+ bool check_intersection = true)
+ {
+ if (check_intersection && geometry::intersects(segment, box))
+ {
+ return 0;
+ }
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+ boost::ignore_unused(cstrategy);
+
+ // get segment points
+ segment_point p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ // get box points
+ std::vector<box_point> box_points(4);
+ detail::assign_box_corners_oriented<true>(box, box_points);
+
+ comparable_return_type cd[6];
+ for (unsigned int i = 0; i < 4; ++i)
+ {
+ cd[i] = cstrategy.apply(box_points[i], p[0], p[1]);
+ }
+
+ point_box_comparable_strategy pb_cstrategy;
+ boost::ignore_unused(pb_cstrategy);
+ cd[4] = pb_cstrategy.apply(p[0], box);
+ cd[5] = pb_cstrategy.apply(p[1], box);
+
+ unsigned int imin = 0;
+ for (unsigned int i = 1; i < 6; ++i)
+ {
+ if (cd[i] < cd[imin])
+ {
+ imin = i;
+ }
+ }
+
+ if (is_comparable<Strategy>::value)
+ {
+ return cd[imin];
+ }
+
+ if (imin < 4)
+ {
+ strategy.apply(box_points[imin], p[0], p[1]);
+ }
+ else
+ {
+ return point_box_strategy().apply(p[imin - 4], box);
+ }
+ }
+};
+
+
+
+
+template
+<
+ typename ReturnType,
+ typename SegmentPoint,
+ typename BoxPoint,
+ typename PPStrategy,
+ typename PSStrategy
+>
+class segment_to_box_2D
+{
+private:
+ template <typename Result>
+ struct cast_to_result
+ {
+ template <typename T>
+ static inline Result apply(T const& t)
+ {
+ return boost::numeric_cast<Result>(t);
+ }
+ };
+
+
+ template <typename T, bool IsLess /* true */>
+ struct compare_less_equal
+ {
+ typedef compare_less_equal<T, !IsLess> other;
+
+ template <typename T1, typename T2>
+ inline bool operator()(T1 const& t1, T2 const& t2) const
+ {
+ return std::less_equal<T>()(cast_to_result<T>::apply(t1),
+ cast_to_result<T>::apply(t2));
+ }
+ };
+
+ template <typename T>
+ struct compare_less_equal<T, false>
+ {
+ typedef compare_less_equal<T, true> other;
+
+ template <typename T1, typename T2>
+ inline bool operator()(T1 const& t1, T2 const& t2) const
+ {
+ return std::greater_equal<T>()(cast_to_result<T>::apply(t1),
+ cast_to_result<T>::apply(t2));
+ }
+ };
+
+
+ template <typename LessEqual>
+ struct other_compare
+ {
+ typedef typename LessEqual::other type;
+ };
+
+
+ // it is assumed here that p0 lies to the right of the box (so the
+ // entire segment lies to the right of the box)
+ template <typename LessEqual>
+ struct right_of_box
+ {
+ static inline ReturnType apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& bottom_right,
+ BoxPoint const& top_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ boost::ignore_unused(pp_strategy, ps_strategy);
+
+ // the implementation below is written for non-negative slope
+ // segments
+ //
+ // for negative slope segments swap the roles of bottom_right
+ // and top_right and use greater_equal instead of less_equal.
+
+ typedef cast_to_result<ReturnType> cast;
+
+ LessEqual less_equal;
+
+ if (less_equal(geometry::get<1>(top_right), geometry::get<1>(p0)))
+ {
+ // closest box point is the top-right corner
+ return cast::apply(pp_strategy.apply(p0, top_right));
+ }
+ else if (less_equal(geometry::get<1>(bottom_right),
+ geometry::get<1>(p0)))
+ {
+ // distance is realized between p0 and right-most
+ // segment of box
+ ReturnType diff = cast::apply(geometry::get<0>(p0))
+ - cast::apply(geometry::get<0>(bottom_right));
+ return strategy::distance::services::result_from_distance
+ <
+ PSStrategy, BoxPoint, SegmentPoint
+ >::apply(ps_strategy, math::abs(diff));
+ }
+ else
+ {
+ // distance is realized between the bottom-right
+ // corner of the box and the segment
+ return cast::apply(ps_strategy.apply(bottom_right, p0, p1));
+ }
+ }
+ };
+
+
+ // it is assumed here that p0 lies above the box (so the
+ // entire segment lies above the box)
+ template <typename LessEqual>
+ struct above_of_box
+ {
+ static inline ReturnType apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ PSStrategy const& ps_strategy)
+ {
+ boost::ignore_unused(ps_strategy);
+
+ // the segment lies above the box
+
+ typedef cast_to_result<ReturnType> cast;
+
+ LessEqual less_equal;
+
+ // p0 is above the upper segment of the box
+ // (and inside its band)
+ if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p0)))
+ {
+ ReturnType diff = cast::apply(geometry::get<1>(p0))
+ - cast::apply(geometry::get<1>(top_left));
+ return strategy::distance::services::result_from_distance
+ <
+ PSStrategy, SegmentPoint, BoxPoint
+ >::apply(ps_strategy, math::abs(diff));
+ }
+
+ // p0 is to the left of the box, but p1 is above the box
+ // in this case the distance is realized between the
+ // top-left corner of the box and the segment
+ return cast::apply(ps_strategy.apply(top_left, p0, p1));
+ }
+ };
+
+
+ template <typename LessEqual>
+ struct check_right_left_of_box
+ {
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy,
+ ReturnType& result)
+ {
+ // p0 lies to the right of the box
+ if (geometry::get<0>(p0) >= geometry::get<0>(top_right))
+ {
+ result = right_of_box
+ <
+ LessEqual
+ >::apply(p0, p1, bottom_right, top_right,
+ pp_strategy, ps_strategy);
+ return true;
+ }
+
+ // p1 lies to the left of the box
+ if (geometry::get<0>(p1) <= geometry::get<0>(bottom_left))
+ {
+ result = right_of_box
+ <
+ typename other_compare<LessEqual>::type
+ >::apply(p1, p0, top_left, bottom_left,
+ pp_strategy, ps_strategy);
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+
+ template <typename LessEqual>
+ struct check_above_below_of_box
+ {
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PSStrategy const& ps_strategy,
+ ReturnType& result)
+ {
+ // the segment lies below the box
+ if (geometry::get<1>(p1) < geometry::get<1>(bottom_left))
+ {
+ result = above_of_box
+ <
+ typename other_compare<LessEqual>::type
+ >::apply(p1, p0, bottom_right, ps_strategy);
+ return true;
+ }
+
+ // the segment lies above the box
+ if (geometry::get<1>(p0) > geometry::get<1>(top_right))
+ {
+ result = above_of_box
+ <
+ LessEqual
+ >::apply(p0, p1, top_left, ps_strategy);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ struct check_generic_position
+ {
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& bottom_left0,
+ BoxPoint const& top_right0,
+ BoxPoint const& bottom_left1,
+ BoxPoint const& top_right1,
+ BoxPoint const& corner1,
+ BoxPoint const& corner2,
+ PSStrategy const& ps_strategy,
+ ReturnType& result)
+ {
+ typedef cast_to_result<ReturnType> cast;
+
+ ReturnType diff0 = cast::apply(geometry::get<0>(p1))
+ - cast::apply(geometry::get<0>(p0));
+ ReturnType t_min0 = cast::apply(geometry::get<0>(bottom_left0))
+ - cast::apply(geometry::get<0>(p0));
+ ReturnType t_max0 = cast::apply(geometry::get<0>(top_right0))
+ - cast::apply(geometry::get<0>(p0));
+
+ ReturnType diff1 = cast::apply(geometry::get<1>(p1))
+ - cast::apply(geometry::get<1>(p0));
+ ReturnType t_min1 = cast::apply(geometry::get<1>(bottom_left1))
+ - cast::apply(geometry::get<1>(p0));
+ ReturnType t_max1 = cast::apply(geometry::get<1>(top_right1))
+ - cast::apply(geometry::get<1>(p0));
+
+ if (diff1 < 0)
+ {
+ diff1 = -diff1;
+ t_min1 = -t_min1;
+ t_max1 = -t_max1;
+ }
+
+ // t_min0 > t_max1
+ if (t_min0 * diff1 > t_max1 * diff0)
+ {
+ result = cast::apply(ps_strategy.apply(corner1, p0, p1));
+ return true;
+ }
+
+ // t_max0 < t_min1
+ if (t_max0 * diff1 < t_min1 * diff0)
+ {
+ result = cast::apply(ps_strategy.apply(corner2, p0, p1));
+ return true;
+ }
+ return false;
+ }
+ };
+
+ static inline ReturnType
+ non_negative_slope_segment(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ typedef compare_less_equal<ReturnType, true> less_equal;
+
+ // assert that the segment has non-negative slope
+ BOOST_ASSERT( ( math::equals(geometry::get<0>(p0), geometry::get<0>(p1))
+ && geometry::get<1>(p0) < geometry::get<1>(p1))
+ ||
+ ( geometry::get<0>(p0) < geometry::get<0>(p1)
+ && geometry::get<1>(p0) <= geometry::get<1>(p1) )
+ );
+
+ ReturnType result(0);
+
+ if (check_right_left_of_box
+ <
+ less_equal
+ >::apply(p0, p1,
+ top_left, top_right, bottom_left, bottom_right,
+ pp_strategy, ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_above_below_of_box
+ <
+ less_equal
+ >::apply(p0, p1,
+ top_left, top_right, bottom_left, bottom_right,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_generic_position::apply(p0, p1,
+ bottom_left, top_right,
+ bottom_left, top_right,
+ top_left, bottom_right,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ // in all other cases the box and segment intersect, so return 0
+ return result;
+ }
+
+
+ static inline ReturnType
+ negative_slope_segment(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ typedef compare_less_equal<ReturnType, false> greater_equal;
+
+ // assert that the segment has negative slope
+ BOOST_ASSERT( geometry::get<0>(p0) < geometry::get<0>(p1)
+ && geometry::get<1>(p0) > geometry::get<1>(p1) );
+
+ ReturnType result(0);
+
+ if (check_right_left_of_box
+ <
+ greater_equal
+ >::apply(p0, p1,
+ bottom_left, bottom_right, top_left, top_right,
+ pp_strategy, ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_above_below_of_box
+ <
+ greater_equal
+ >::apply(p1, p0,
+ top_right, top_left, bottom_right, bottom_left,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_generic_position::apply(p0, p1,
+ bottom_left, top_right,
+ top_right, bottom_left,
+ bottom_left, top_right,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ // in all other cases the box and segment intersect, so return 0
+ return result;
+ }
+
+public:
+ static inline ReturnType apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ BOOST_ASSERT( geometry::less<SegmentPoint>()(p0, p1) );
+
+ if (geometry::get<0>(p0) < geometry::get<0>(p1)
+ && geometry::get<1>(p0) > geometry::get<1>(p1))
+ {
+ return negative_slope_segment(p0, p1,
+ top_left, top_right,
+ bottom_left, bottom_right,
+ pp_strategy, ps_strategy);
+ }
+
+ return non_negative_slope_segment(p0, p1,
+ top_left, top_right,
+ bottom_left, bottom_right,
+ pp_strategy, ps_strategy);
+ }
+};
+
+
+//=========================================================================
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename std::size_t Dimension,
+ typename PPStrategy,
+ typename PSStrategy
+>
+class segment_to_box
+ : not_implemented<Segment, Box>
+{};
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename PPStrategy,
+ typename PSStrategy
+>
+class segment_to_box<Segment, Box, 2, PPStrategy, PSStrategy>
+{
+private:
+ typedef typename point_type<Segment>::type segment_point;
+ typedef typename point_type<Box>::type box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ PPStrategy
+ >::type pp_comparable_strategy;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ PSStrategy
+ >::type ps_comparable_strategy;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ ps_comparable_strategy, segment_point, box_point
+ >::type comparable_return_type;
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ PSStrategy, segment_point, box_point
+ >::type return_type;
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ segment_point p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ if (geometry::equals(p[0], p[1]))
+ {
+ typedef typename boost::mpl::if_
+ <
+ boost::is_same
+ <
+ ps_comparable_strategy,
+ PSStrategy
+ >,
+ typename strategy::distance::services::comparable_type
+ <
+ typename detail::distance::default_strategy
+ <
+ segment_point, Box
+ >::type
+ >::type,
+ typename detail::distance::default_strategy
+ <
+ segment_point, Box
+ >::type
+ >::type point_box_strategy_type;
+
+ return dispatch::distance
+ <
+ segment_point,
+ Box,
+ point_box_strategy_type
+ >::apply(p[0], box, point_box_strategy_type());
+ }
+
+ box_point top_left, top_right, bottom_left, bottom_right;
+ detail::assign_box_corners(box, bottom_left, bottom_right,
+ top_left, top_right);
+
+ if (geometry::less<segment_point>()(p[0], p[1]))
+ {
+ return segment_to_box_2D
+ <
+ return_type,
+ segment_point,
+ box_point,
+ PPStrategy,
+ PSStrategy
+ >::apply(p[0], p[1],
+ top_left, top_right, bottom_left, bottom_right,
+ pp_strategy,
+ ps_strategy);
+ }
+ else
+ {
+ return segment_to_box_2D
+ <
+ return_type,
+ segment_point,
+ box_point,
+ PPStrategy,
+ PSStrategy
+ >::apply(p[1], p[0],
+ top_left, top_right, bottom_left, bottom_right,
+ pp_strategy,
+ ps_strategy);
+ }
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Segment, typename Box, typename Strategy>
+struct distance
+ <
+ Segment, Box, Strategy, segment_tag, box_tag,
+ strategy_tag_distance_point_segment, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Segment>::type,
+ typename point_type<Box>::type
+ >::type return_type;
+
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy)
+ {
+ assert_dimension_equal<Segment, Box>();
+
+ typedef typename boost::mpl::if_
+ <
+ boost::is_same
+ <
+ typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type,
+ Strategy
+ >,
+ typename strategy::distance::services::comparable_type
+ <
+ typename detail::distance::default_strategy
+ <
+ typename point_type<Segment>::type,
+ typename point_type<Box>::type
+ >::type
+ >::type,
+ typename detail::distance::default_strategy
+ <
+ typename point_type<Segment>::type,
+ typename point_type<Box>::type
+ >::type
+ >::type pp_strategy_type;
+
+
+ return detail::distance::segment_to_box
+ <
+ Segment,
+ Box,
+ dimension<Segment>::value,
+ pp_strategy_type,
+ Strategy
+ >::apply(segment, box, pp_strategy_type(), strategy);
+ }
+};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp
new file mode 100644
index 0000000000..2dcde64946
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp
@@ -0,0 +1,150 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
+
+#include <algorithm>
+#include <iterator>
+
+#include <boost/core/addressof.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+
+// compute segment-segment distance
+template<typename Segment1, typename Segment2, typename Strategy>
+class segment_to_segment
+{
+private:
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy,
+ typename point_type<Segment1>::type,
+ typename point_type<Segment2>::type
+ >::type comparable_return_type;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Segment1>::type,
+ typename point_type<Segment2>::type
+ >::type return_type;
+
+ static inline return_type
+ apply(Segment1 const& segment1, Segment2 const& segment2,
+ Strategy const& strategy)
+ {
+ if (geometry::intersects(segment1, segment2))
+ {
+ return 0;
+ }
+
+ typename point_type<Segment1>::type p[2];
+ detail::assign_point_from_index<0>(segment1, p[0]);
+ detail::assign_point_from_index<1>(segment1, p[1]);
+
+ typename point_type<Segment2>::type q[2];
+ detail::assign_point_from_index<0>(segment2, q[0]);
+ detail::assign_point_from_index<1>(segment2, q[1]);
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+
+ comparable_return_type d[4];
+ d[0] = cstrategy.apply(q[0], p[0], p[1]);
+ d[1] = cstrategy.apply(q[1], p[0], p[1]);
+ d[2] = cstrategy.apply(p[0], q[0], q[1]);
+ d[3] = cstrategy.apply(p[1], q[0], q[1]);
+
+ std::size_t imin = std::distance(boost::addressof(d[0]),
+ std::min_element(d, d + 4));
+
+ if (is_comparable<Strategy>::value)
+ {
+ return d[imin];
+ }
+
+ switch (imin)
+ {
+ case 0:
+ return strategy.apply(q[0], p[0], p[1]);
+ case 1:
+ return strategy.apply(q[1], p[0], p[1]);
+ case 2:
+ return strategy.apply(p[0], q[0], q[1]);
+ default:
+ return strategy.apply(p[1], q[0], q[1]);
+ }
+ }
+};
+
+
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+
+// segment-segment
+template <typename Segment1, typename Segment2, typename Strategy>
+struct distance
+ <
+ Segment1, Segment2, Strategy, segment_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::segment_to_segment<Segment1, Segment2, Strategy>
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
index 9c2fe28057..5bcb5ffaa0 100644
--- a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
+++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -17,12 +18,13 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
+
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
@@ -75,9 +77,9 @@ struct collected_vector
inline bool same_direction(collected_vector<T> const& other) const
{
- // For high precision arithmetic, we have to be
+ // For high precision arithmetic, we have to be
// more relaxed then using ==
- // Because 2/sqrt( (0,0)<->(2,2) ) == 1/sqrt( (0,0)<->(1,1) )
+ // Because 2/sqrt( (0,0)<->(2,2) ) == 1/sqrt( (0,0)<->(1,1) )
// is not always true (at least, it is not for ttmath)
return math::equals_with_epsilon(dx, other.dx)
&& math::equals_with_epsilon(dy, other.dy);
@@ -111,6 +113,9 @@ struct range_collect_vectors
return;
}
+ typedef typename boost::range_size<Collection>::type collection_size_t;
+ collection_size_t c_old_size = boost::size(collection);
+
typedef typename boost::range_iterator<Range const>::type iterator;
bool first = true;
@@ -131,7 +136,7 @@ struct range_collect_vectors
// Normalize the vector -> this results in points+direction
// and is comparible between geometries
- calculation_type magnitude = sqrt(
+ calculation_type magnitude = math::sqrt(
boost::numeric_cast<calculation_type>(v.dx * v.dx + v.dy * v.dy));
// Avoid non-duplicate points (AND division by zero)
@@ -150,10 +155,19 @@ struct range_collect_vectors
}
// If first one has same direction as last one, remove first one
- if (boost::size(collection) > 1
- && collection.front().same_direction(collection.back()))
+ collection_size_t collected_count = boost::size(collection) - c_old_size;
+ if ( collected_count > 1 )
{
- collection.erase(collection.begin());
+ typedef typename boost::range_iterator<Collection>::type c_iterator;
+ c_iterator first = collection.begin() + c_old_size;
+
+ if ( first->same_direction(collection.back()) )
+ {
+ //collection.erase(first);
+ // O(1) instead of O(N)
+ *first = collection.back();
+ collection.pop_back();
+ }
}
}
};
@@ -194,9 +208,10 @@ struct polygon_collect_vectors
typedef range_collect_vectors<ring_type, Collection> per_range;
per_range::apply(collection, exterior_ring(polygon));
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
per_range::apply(collection, *it);
}
diff --git a/boost/geometry/algorithms/detail/equals/point_point.hpp b/boost/geometry/algorithms/detail/equals/point_point.hpp
new file mode 100644
index 0000000000..12daa85e9d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/equals/point_point.hpp
@@ -0,0 +1,52 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_EQUALS_POINT_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP
+
+#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace equals
+{
+
+/*!
+ \brief Internal utility function to detect of points are disjoint
+ \note To avoid circular references
+ */
+template <typename Point1, typename Point2>
+inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
+{
+ return ! detail::disjoint::disjoint_point_point(point1, point2);
+}
+
+
+}} // namespace detail::equals
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/extreme_points.hpp b/boost/geometry/algorithms/detail/extreme_points.hpp
new file mode 100644
index 0000000000..61839d296a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/extreme_points.hpp
@@ -0,0 +1,520 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.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/algorithms/detail/assign_box_corners.hpp>
+
+#include <boost/geometry/strategies/side.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace extreme_points
+{
+
+template <std::size_t Dimension>
+struct compare
+{
+ template <typename Point>
+ inline bool operator()(Point const& lhs, Point const& rhs)
+ {
+ return geometry::get<Dimension>(lhs) < geometry::get<Dimension>(rhs);
+ }
+};
+
+
+template <std::size_t Dimension, typename PointType, typename CoordinateType>
+inline void move_along_vector(PointType& point, PointType const& extreme, CoordinateType const& base_value)
+{
+ // Moves a point along the vector (point, extreme) in the direction of the extreme point
+ // This adapts the possibly uneven legs of the triangle (or trapezium-like shape)
+ // _____extreme _____
+ // / \ / \ .
+ // /base \ => / \ point .
+ // \ point .
+ //
+ // For so-called intruders, it can be used to adapt both legs to the level of "base"
+ // For the base, it can be used to adapt both legs to the level of the max-value of the intruders
+ // If there are 2 or more extreme values, use the one close to 'point' to have a correct vector
+
+ CoordinateType const value = geometry::get<Dimension>(point);
+ //if (geometry::math::equals(value, base_value))
+ if (value >= base_value)
+ {
+ return;
+ }
+
+ PointType vector = point;
+ subtract_point(vector, extreme);
+
+ CoordinateType const diff = geometry::get<Dimension>(vector);
+
+ // diff should never be zero
+ // because of the way our triangle/trapezium is build.
+ // We just return if it would be the case.
+ if (geometry::math::equals(diff, 0))
+ {
+ return;
+ }
+
+ CoordinateType const base_diff = base_value - geometry::get<Dimension>(extreme);
+
+ multiply_value(vector, base_diff);
+ divide_value(vector, diff);
+
+ // The real move:
+ point = extreme;
+ add_point(point, vector);
+}
+
+
+template <std::size_t Dimension, typename Range, typename CoordinateType>
+inline void move_along_vector(Range& range, CoordinateType const& base_value)
+{
+ if (range.size() >= 3)
+ {
+ move_along_vector<Dimension>(range.front(), *(range.begin() + 1), base_value);
+ move_along_vector<Dimension>(range.back(), *(range.rbegin() + 1), base_value);
+ }
+}
+
+
+template<typename Ring, std::size_t Dimension>
+struct extreme_points_on_ring
+{
+
+ typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
+ typedef typename boost::range_iterator<Ring const>::type range_iterator;
+ typedef typename geometry::point_type<Ring>::type point_type;
+
+ typedef typename geometry::strategy::side::services::default_strategy
+ <
+ typename geometry::cs_tag<point_type>::type
+ >::type side_strategy;
+
+
+ template <typename CirclingIterator, typename Points>
+ static inline bool extend(CirclingIterator& it,
+ std::size_t n,
+ coordinate_type max_coordinate_value,
+ Points& points, int direction)
+ {
+ std::size_t safe_index = 0;
+ do
+ {
+ it += direction;
+
+ points.push_back(*it);
+
+ if (safe_index++ >= n)
+ {
+ // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
+ return false;
+ }
+ } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
+
+ return true;
+ }
+
+ // Overload without adding to poinst
+ template <typename CirclingIterator>
+ static inline bool extend(CirclingIterator& it,
+ std::size_t n,
+ coordinate_type max_coordinate_value,
+ int direction)
+ {
+ std::size_t safe_index = 0;
+ do
+ {
+ it += direction;
+
+ if (safe_index++ >= n)
+ {
+ // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
+ return false;
+ }
+ } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
+
+ return true;
+ }
+
+ template <typename CirclingIterator>
+ static inline bool extent_both_sides(Ring const& ring,
+ point_type extreme,
+ CirclingIterator& left,
+ CirclingIterator& right)
+ {
+ std::size_t const n = boost::size(ring);
+ coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
+
+ if (! extend(left, n, max_coordinate_value, -1))
+ {
+ return false;
+ }
+ if (! extend(right, n, max_coordinate_value, +1))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename Collection, typename CirclingIterator>
+ static inline bool collect(Ring const& ring,
+ point_type extreme,
+ Collection& points,
+ CirclingIterator& left,
+ CirclingIterator& right)
+ {
+ std::size_t const n = boost::size(ring);
+ coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
+
+ // Collects first left, which is reversed (if more than one point) then adds the top itself, then right
+ if (! extend(left, n, max_coordinate_value, points, -1))
+ {
+ return false;
+ }
+ std::reverse(points.begin(), points.end());
+ points.push_back(extreme);
+ if (! extend(right, n, max_coordinate_value, points, +1))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename Extremes, typename Intruders, typename CirclingIterator>
+ static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
+ Extremes const& extremes,
+ Intruders& intruders)
+ {
+ if (boost::size(extremes) < 3)
+ {
+ return;
+ }
+ coordinate_type const min_value = geometry::get<Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<Dimension>()));
+
+ // Also select left/right (if Dimension=1)
+ coordinate_type const other_min = geometry::get<1 - Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
+ coordinate_type const other_max = geometry::get<1 - Dimension>(*std::max_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
+
+ std::size_t defensive_check_index = 0; // in case we skip over left/right check, collect modifies right too
+ std::size_t const n = boost::size(ring);
+ while (left != right && defensive_check_index < n)
+ {
+ coordinate_type const coordinate = geometry::get<Dimension>(*right);
+ coordinate_type const other_coordinate = geometry::get<1 - Dimension>(*right);
+ if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
+ {
+ int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
+ int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
+ int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
+
+ // If not lying left from any of the extemes side
+ if (first_side != 1 && last_side != 1)
+ {
+ //std::cout << "first " << first_side << " last " << last_side << std::endl;
+
+ // we start at this intrusion until it is handled, and don't affect our initial left iterator
+ CirclingIterator left_intrusion_it = right;
+ typename boost::range_value<Intruders>::type intruder;
+ collect(ring, *right, intruder, left_intrusion_it, right);
+
+ // Also moves these to base-level, makes sorting possible which can be done in case of self-tangencies
+ // (we might postpone this action, it is often not necessary. However it is not time-consuming)
+ move_along_vector<Dimension>(intruder, min_value);
+ intruders.push_back(intruder);
+ --right;
+ }
+ }
+ ++right;
+ defensive_check_index++;
+ }
+ }
+
+ template <typename Extremes, typename Intruders>
+ static inline void get_intruders(Ring const& ring,
+ Extremes const& extremes,
+ Intruders& intruders)
+ {
+ std::size_t const n = boost::size(ring);
+ if (n >= 3)
+ {
+ geometry::ever_circling_range_iterator<Ring const> left(ring);
+ geometry::ever_circling_range_iterator<Ring const> right(ring);
+ ++right;
+
+ get_intruders(ring, left, right, extremes, intruders);
+ }
+ }
+
+ template <typename Iterator>
+ static inline bool right_turn(Ring const& ring, Iterator it)
+ {
+ typename std::iterator_traits<Iterator>::difference_type const index
+ = std::distance(boost::begin(ring), it);
+ geometry::ever_circling_range_iterator<Ring const> left(ring);
+ geometry::ever_circling_range_iterator<Ring const> right(ring);
+ left += index;
+ right += index;
+
+ if (! extent_both_sides(ring, *it, left, right))
+ {
+ return false;
+ }
+
+ int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
+ int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor;
+ int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor;
+
+//std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
+
+ // Turn should not be left (actually, it should be right because extent removes horizontal/collinear cases)
+ return first_side != 1 && last_side != 1;
+ }
+
+
+ // Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring
+ template <typename Extremes, typename Intruders>
+ static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders)
+ {
+ std::size_t const n = boost::size(ring);
+ if (n < 3)
+ {
+ return false;
+ }
+
+ // Get all maxima, usually one. In case of self-tangencies, or self-crossings,
+ // the max might be is not valid. A valid max should make a right turn
+ range_iterator max_it = boost::begin(ring);
+ compare<Dimension> smaller;
+ for (range_iterator it = max_it + 1; it != boost::end(ring); ++it)
+ {
+ if (smaller(*max_it, *it) && right_turn(ring, it))
+ {
+ max_it = it;
+ }
+ }
+
+ if (max_it == boost::end(ring))
+ {
+ return false;
+ }
+
+ typename std::iterator_traits<range_iterator>::difference_type const
+ index = std::distance(boost::begin(ring), max_it);
+//std::cout << "Extreme point lies at " << index << " having " << geometry::wkt(*max_it) << std::endl;
+
+ geometry::ever_circling_range_iterator<Ring const> left(ring);
+ geometry::ever_circling_range_iterator<Ring const> right(ring);
+ left += index;
+ right += index;
+
+ // Collect all points (often 3) in a temporary vector
+ std::vector<point_type> points;
+ points.reserve(3);
+ if (! collect(ring, *max_it, points, left, right))
+ {
+ return false;
+ }
+
+//std::cout << "Built vector of " << points.size() << std::endl;
+
+ coordinate_type const front_value = geometry::get<Dimension>(points.front());
+ coordinate_type const back_value = geometry::get<Dimension>(points.back());
+ coordinate_type const base_value = (std::max)(front_value, back_value);
+ if (front_value < back_value)
+ {
+ move_along_vector<Dimension>(points.front(), *(points.begin() + 1), base_value);
+ }
+ else
+ {
+ move_along_vector<Dimension>(points.back(), *(points.rbegin() + 1), base_value);
+ }
+
+ std::copy(points.begin(), points.end(), std::back_inserter(extremes));
+
+ get_intruders(ring, left, right, extremes, intruders);
+
+ return true;
+ }
+};
+
+
+
+
+
+}} // namespace detail::extreme_points
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry,
+ std::size_t Dimension,
+ typename GeometryTag = typename tag<Geometry>::type
+>
+struct extreme_points
+{};
+
+
+template<typename Ring, std::size_t Dimension>
+struct extreme_points<Ring, Dimension, ring_tag>
+ : detail::extreme_points::extreme_points_on_ring<Ring, Dimension>
+{};
+
+
+template<typename Polygon, std::size_t Dimension>
+struct extreme_points<Polygon, Dimension, polygon_tag>
+{
+ template <typename Extremes, typename Intruders>
+ static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+ typedef detail::extreme_points::extreme_points_on_ring
+ <
+ ring_type, Dimension
+ > ring_implementation;
+
+ if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
+ {
+ return false;
+ }
+
+ // For a polygon, its interior rings can contain intruders
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
+ {
+ ring_implementation::get_intruders(*it, extremes, intruders);
+ }
+
+ return true;
+ }
+};
+
+template<typename Box>
+struct extreme_points<Box, 1, box_tag>
+{
+ template <typename Extremes, typename Intruders>
+ static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
+ {
+ extremes.resize(4);
+ geometry::detail::assign_box_corners_oriented<false>(box, extremes);
+ // ll,ul,ur,lr, contains too exactly the right info
+ return true;
+ }
+};
+
+template<typename Box>
+struct extreme_points<Box, 0, box_tag>
+{
+ template <typename Extremes, typename Intruders>
+ static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
+ {
+ extremes.resize(4);
+ geometry::detail::assign_box_corners_oriented<false>(box, extremes);
+ // ll,ul,ur,lr, rotate one to start with UL and end with LL
+ std::rotate(extremes.begin(), extremes.begin() + 1, extremes.end());
+ return true;
+ }
+};
+
+template<typename MultiPolygon, std::size_t Dimension>
+struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
+{
+ template <typename Extremes, typename Intruders>
+ static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders)
+ {
+ // Get one for the very first polygon, that is (for the moment) enough.
+ // It is not guaranteed the "extreme" then, but for the current purpose
+ // (point_on_surface) it can just be this point.
+ if (boost::size(multi) >= 1)
+ {
+ return extreme_points
+ <
+ typename boost::range_value<MultiPolygon const>::type,
+ Dimension,
+ polygon_tag
+ >::apply(*boost::begin(multi), extremes, intruders);
+ }
+
+ return false;
+ }
+};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief Returns extreme points (for Edge=1 in dimension 1, so the top,
+ for Edge=0 in dimension 0, the right side)
+\note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that.
+ */
+template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders>
+inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders)
+{
+ concept::check<Geometry const>();
+
+ // Extremes is not required to follow a geometry concept (but it should support an output iterator),
+ // but its elements should fulfil the point-concept
+ concept::check<typename boost::range_value<Extremes>::type>();
+
+ // Intruders should contain collections which value type is point-concept
+ // Extremes might be anything (supporting an output iterator), but its elements should fulfil the point-concept
+ concept::check
+ <
+ typename boost::range_value
+ <
+ typename boost::range_value<Intruders>::type
+ >::type
+ const
+ >();
+
+ return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
+}
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/for_each_range.hpp b/boost/geometry/algorithms/detail/for_each_range.hpp
index 7cb01fa9b4..e8c92160f1 100644
--- a/boost/geometry/algorithms/detail/for_each_range.hpp
+++ b/boost/geometry/algorithms/detail/for_each_range.hpp
@@ -17,9 +17,13 @@
#include <boost/mpl/assert.hpp>
#include <boost/concept/requires.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <boost/type_traits/remove_const.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/add_const_if_c.hpp>
#include <boost/geometry/views/box_view.hpp>
@@ -34,24 +38,20 @@ namespace detail { namespace for_each
{
-template <typename Range, typename Actor, bool IsConst>
+template <typename Range, typename Actor>
struct fe_range_range
{
- static inline void apply(
- typename add_const_if_c<IsConst, Range>::type& range,
- Actor& actor)
+ static inline void apply(Range & range, Actor & actor)
{
actor.apply(range);
}
};
-template <typename Polygon, typename Actor, bool IsConst>
+template <typename Polygon, typename Actor>
struct fe_range_polygon
{
- static inline void apply(
- typename add_const_if_c<IsConst, Polygon>::type& polygon,
- Actor& actor)
+ static inline void apply(Polygon & polygon, Actor & actor)
{
actor.apply(exterior_ring(polygon));
@@ -60,17 +60,27 @@ struct fe_range_polygon
}
};
-template <typename Box, typename Actor, bool IsConst>
+template <typename Box, typename Actor>
struct fe_range_box
{
- static inline void apply(
- typename add_const_if_c<IsConst, Box>::type& box,
- Actor& actor)
+ static inline void apply(Box & box, Actor & actor)
{
- actor.apply(box_view<Box>(box));
+ actor.apply(box_view<typename boost::remove_const<Box>::type>(box));
}
};
+template <typename Multi, typename Actor, typename SinglePolicy>
+struct fe_range_multi
+{
+ static inline void apply(Multi & multi, Actor & actor)
+ {
+ for ( typename boost::range_iterator<Multi>::type
+ it = boost::begin(multi); it != boost::end(multi); ++it)
+ {
+ SinglePolicy::apply(*it, actor);
+ }
+ }
+};
}} // namespace detail::for_each
#endif // DOXYGEN_NO_DETAIL
@@ -83,10 +93,9 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
typename Actor,
- bool IsConst
+ typename Tag = typename tag<Geometry>::type
>
struct for_each_range
{
@@ -98,26 +107,71 @@ struct for_each_range
};
-template <typename Linestring, typename Actor, bool IsConst>
-struct for_each_range<linestring_tag, Linestring, Actor, IsConst>
- : detail::for_each::fe_range_range<Linestring, Actor, IsConst>
+template <typename Linestring, typename Actor>
+struct for_each_range<Linestring, Actor, linestring_tag>
+ : detail::for_each::fe_range_range<Linestring, Actor>
+{};
+
+
+template <typename Ring, typename Actor>
+struct for_each_range<Ring, Actor, ring_tag>
+ : detail::for_each::fe_range_range<Ring, Actor>
+{};
+
+
+template <typename Polygon, typename Actor>
+struct for_each_range<Polygon, Actor, polygon_tag>
+ : detail::for_each::fe_range_polygon<Polygon, Actor>
+{};
+
+
+template <typename Box, typename Actor>
+struct for_each_range<Box, Actor, box_tag>
+ : detail::for_each::fe_range_box<Box, Actor>
{};
-template <typename Ring, typename Actor, bool IsConst>
-struct for_each_range<ring_tag, Ring, Actor, IsConst>
- : detail::for_each::fe_range_range<Ring, Actor, IsConst>
+template <typename MultiPoint, typename Actor>
+struct for_each_range<MultiPoint, Actor, multi_point_tag>
+ : detail::for_each::fe_range_range<MultiPoint, Actor>
{};
-template <typename Polygon, typename Actor, bool IsConst>
-struct for_each_range<polygon_tag, Polygon, Actor, IsConst>
- : detail::for_each::fe_range_polygon<Polygon, Actor, IsConst>
+template <typename Geometry, typename Actor>
+struct for_each_range<Geometry, Actor, multi_linestring_tag>
+ : detail::for_each::fe_range_multi
+ <
+ Geometry,
+ Actor,
+ detail::for_each::fe_range_range
+ <
+ typename add_const_if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::range_value<Geometry>::type
+ >::type,
+ Actor
+ >
+ >
{};
-template <typename Box, typename Actor, bool IsConst>
-struct for_each_range<box_tag, Box, Actor, IsConst>
- : detail::for_each::fe_range_box<Box, Actor, IsConst>
+
+template <typename Geometry, typename Actor>
+struct for_each_range<Geometry, Actor, multi_polygon_tag>
+ : detail::for_each::fe_range_multi
+ <
+ Geometry,
+ Actor,
+ detail::for_each::fe_range_polygon
+ <
+ typename add_const_if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::range_value<Geometry>::type
+ >::type,
+ Actor
+ >
+ >
{};
@@ -128,14 +182,12 @@ namespace detail
{
template <typename Geometry, typename Actor>
-inline void for_each_range(Geometry const& geometry, Actor& actor)
+inline void for_each_range(Geometry const& geometry, Actor & actor)
{
dispatch::for_each_range
<
- typename tag<Geometry>::type,
- Geometry,
- Actor,
- true
+ Geometry const,
+ Actor
>::apply(geometry, actor);
}
diff --git a/boost/geometry/algorithms/detail/get_left_turns.hpp b/boost/geometry/algorithms/detail/get_left_turns.hpp
index 62f0f7f0f4..0fd243d8e3 100644
--- a/boost/geometry/algorithms/detail/get_left_turns.hpp
+++ b/boost/geometry/algorithms/detail/get_left_turns.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2012-2014 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
@@ -9,7 +9,12 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/iterators/closing_iterator.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
+#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
{
@@ -21,342 +26,286 @@ namespace detail
// TODO: move this to /util/
template <typename T>
-static inline std::pair<T, T> ordered_pair(T const& first, T const& second)
+inline std::pair<T, T> ordered_pair(T const& first, T const& second)
{
return first < second ? std::make_pair(first, second) : std::make_pair(second, first);
}
-template <typename AngleInfo>
-inline void debug_left_turn(AngleInfo const& ai, AngleInfo const& previous)
+namespace left_turns
{
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
- std::cout << "Angle: " << (ai.incoming ? "i" : "o")
- << " " << si(ai.seg_id)
- << " " << (math::r2d * (ai.angle) )
- << " turn: " << ai.turn_index << "[" << ai.operation_index << "]"
- ;
-
- if (ai.turn_index != previous.turn_index
- || ai.operation_index != previous.operation_index)
- {
- std::cout << " diff: " << math::r2d * math::abs(previous.angle - ai.angle);
- }
- std::cout << std::endl;
-#endif
-}
-
-template <typename AngleInfo>
-inline void debug_left_turn(std::string const& caption, AngleInfo const& ai, AngleInfo const& previous,
- int code = -99, int code2 = -99, int code3 = -99, int code4 = -99)
-{
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
- std::cout << " " << caption
- << " turn: " << ai.turn_index << "[" << ai.operation_index << "]"
- << " " << si(ai.seg_id)
- << " " << (ai.incoming ? "i" : "o")
- << " " << (math::r2d * (ai.angle) )
- << " turn: " << previous.turn_index << "[" << previous.operation_index << "]"
- << " " << si(previous.seg_id)
- << " " << (previous.incoming ? "i" : "o")
- << " " << (math::r2d * (previous.angle) )
- ;
- if (code != -99)
- {
- std::cout << " code: " << code << " , " << code2 << " , " << code3 << " , " << code4;
- }
- std::cout << std::endl;
-#endif
-}
-template <typename Operation>
-inline bool include_operation(Operation const& op,
- segment_identifier const& outgoing_seg_id,
- segment_identifier const& incoming_seg_id)
+template <typename Vector>
+inline int get_quadrant(Vector const& vector)
{
- return op.seg_id == outgoing_seg_id
- && op.other_id == incoming_seg_id
- && (op.operation == detail::overlay::operation_union
- ||op.operation == detail::overlay::operation_continue)
- ;
+ // Return quadrant as layouted in the code below:
+ // 3 | 0
+ // -----
+ // 2 | 1
+ return geometry::get<1>(vector) >= 0
+ ? (geometry::get<0>(vector) < 0 ? 3 : 0)
+ : (geometry::get<0>(vector) < 0 ? 2 : 1)
+ ;
}
-template <typename Turn>
-inline bool process_include(segment_identifier const& outgoing_seg_id, segment_identifier const& incoming_seg_id,
- int turn_index, Turn& turn,
- std::set<int>& keep_indices, int priority)
+template <typename Vector>
+inline int squared_length(Vector const& vector)
{
- bool result = false;
- for (int i = 0; i < 2; i++)
- {
- if (include_operation(turn.operations[i], outgoing_seg_id, incoming_seg_id))
- {
- turn.operations[i].include_in_occupation_map = true;
- if (priority > turn.priority)
- {
- turn.priority = priority;
- }
- keep_indices.insert(turn_index);
- result = true;
- }
- }
- return result;
+ return geometry::get<0>(vector) * geometry::get<0>(vector)
+ + geometry::get<1>(vector) * geometry::get<1>(vector)
+ ;
}
-template <typename AngleInfo, typename Turns, typename TurnSegmentIndices>
-inline bool include_left_turn_of_all(
- AngleInfo const& outgoing, AngleInfo const& incoming,
- Turns& turns, TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& keep_indices, int priority)
+
+template <typename Point>
+struct angle_less
{
- segment_identifier const& outgoing_seg_id = turns[outgoing.turn_index].operations[outgoing.operation_index].seg_id;
- segment_identifier const& incoming_seg_id = turns[incoming.turn_index].operations[incoming.operation_index].seg_id;
+ typedef Point vector_type;
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type side_strategy_type;
- if (outgoing.turn_index == incoming.turn_index)
- {
- return process_include(outgoing_seg_id, incoming_seg_id, outgoing.turn_index, turns[outgoing.turn_index], keep_indices, priority);
- }
+ angle_less(Point const& origin)
+ : m_origin(origin)
+ {}
- bool result = false;
- std::pair<segment_identifier, segment_identifier> pair = ordered_pair(outgoing_seg_id, incoming_seg_id);
- auto it = turn_segment_indices.find(pair);
- if (it != turn_segment_indices.end())
+ template <typename Angle>
+ inline bool operator()(Angle const& p, Angle const& q) const
{
- for (auto sit = it->second.begin(); sit != it->second.end(); ++sit)
+ // Vector origin -> p and origin -> q
+ vector_type pv = p.point;
+ vector_type qv = q.point;
+ geometry::subtract_point(pv, m_origin);
+ geometry::subtract_point(qv, m_origin);
+
+ int const quadrant_p = get_quadrant(pv);
+ int const quadrant_q = get_quadrant(qv);
+ if (quadrant_p != quadrant_q)
{
- if (process_include(outgoing_seg_id, incoming_seg_id, *sit, turns[*sit], keep_indices, priority))
- {
- result = true;
- }
+ return quadrant_p < quadrant_q;
}
+ // Same quadrant, check if p is located left of q
+ int const side = side_strategy_type::apply(m_origin, q.point,
+ p.point);
+ if (side != 0)
+ {
+ return side == 1;
+ }
+ // Collinear, check if one is incoming, incoming angles come first
+ if (p.incoming != q.incoming)
+ {
+ return int(p.incoming) < int(q.incoming);
+ }
+ // Same quadrant/side/direction, return longest first
+ // TODO: maybe not necessary, decide this
+ int const length_p = squared_length(pv);
+ int const length_q = squared_length(qv);
+ if (length_p != length_q)
+ {
+ return squared_length(pv) > squared_length(qv);
+ }
+ // They are still the same. Just compare on seg_id
+ return p.seg_id < q.seg_id;
}
- return result;
-}
-template <std::size_t Index, typename Turn>
-inline bool corresponds(Turn const& turn, segment_identifier const& seg_id)
+private:
+ Point m_origin;
+};
+
+template <typename Point>
+struct angle_equal_to
{
- return turn.operations[Index].operation == detail::overlay::operation_union
- && turn.operations[Index].seg_id == seg_id;
-}
+ typedef Point vector_type;
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type side_strategy_type;
+ inline angle_equal_to(Point const& origin)
+ : m_origin(origin)
+ {}
-template <typename Turns, typename TurnSegmentIndices>
-inline bool prefer_by_other(Turns const& turns,
- TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& indices)
-{
- std::map<segment_identifier, int> map;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
+ template <typename Angle>
+ inline bool operator()(Angle const& p, Angle const& q) const
{
- map[turns[*sit].operations[0].seg_id]++;
- map[turns[*sit].operations[1].seg_id]++;
- }
+ // Vector origin -> p and origin -> q
+ vector_type pv = p.point;
+ vector_type qv = q.point;
+ geometry::subtract_point(pv, m_origin);
+ geometry::subtract_point(qv, m_origin);
- std::set<segment_identifier> segment_occuring_once;
- for (auto mit = map.begin(); mit != map.end(); ++mit)
- {
- if (mit->second == 1)
+ if (get_quadrant(pv) != get_quadrant(qv))
{
- segment_occuring_once.insert(mit->first);
+ return false;
}
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER
- std::cout << si(mit->first) << " " << mit->second << std::endl;
-#endif
+ // Same quadrant, check if p/q are collinear
+ int const side = side_strategy_type::apply(m_origin, q.point,
+ p.point);
+ return side == 0;
}
- if (segment_occuring_once.size() == 2)
- {
- // Try to find within all turns a turn with these two segments
+private:
+ Point m_origin;
+};
- std::set<segment_identifier>::const_iterator soo_it = segment_occuring_once.begin();
- segment_identifier front = *soo_it;
- soo_it++;
- segment_identifier back = *soo_it;
+template <typename AngleCollection, typename Turns>
+inline void get_left_turns(AngleCollection const& sorted_angles,
+ Turns& turns)
+{
+ std::set<int> good_incoming;
+ std::set<int> good_outgoing;
- std::pair<segment_identifier, segment_identifier> pair = ordered_pair(front, back);
- auto it = turn_segment_indices.find(pair);
- if (it != turn_segment_indices.end())
+ for (typename boost::range_iterator<AngleCollection const>::type it =
+ sorted_angles.begin(); it != sorted_angles.end(); ++it)
+ {
+ if (!it->blocked)
{
- // debug_turns_by_indices("Found", it->second);
- // Check which is the union/continue
- segment_identifier good;
- for (auto sit = it->second.begin(); sit != it->second.end(); ++sit)
+ if (it->incoming)
{
- if (turns[*sit].operations[0].operation == detail::overlay::operation_union)
- {
- good = turns[*sit].operations[0].seg_id;
- }
- else if (turns[*sit].operations[1].operation == detail::overlay::operation_union)
- {
- good = turns[*sit].operations[1].seg_id;
- }
+ good_incoming.insert(it->turn_index);
}
-
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER
- std::cout << "Good: " << si(good) << std::endl;
-#endif
-
- // Find in indexes-to-keep this segment with the union. Discard the other one
- std::set<int> ok_indices;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
+ else
{
- if (corresponds<0>(turns[*sit], good) || corresponds<1>(turns[*sit], good))
- {
- ok_indices.insert(*sit);
- }
- }
- if (ok_indices.size() > 0 && ok_indices.size() < indices.size())
- {
- indices = ok_indices;
- std::cout << "^";
- return true;
+ good_outgoing.insert(it->turn_index);
}
}
}
- return false;
-}
-template <typename Turns>
-inline void prefer_by_priority(Turns const& turns, std::set<int>& indices)
-{
- // Find max prio
- int min_prio = 1024, max_prio = 0;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
- {
- if (turns[*sit].priority > max_prio)
- {
- max_prio = turns[*sit].priority;
- }
- if (turns[*sit].priority < min_prio)
- {
- min_prio = turns[*sit].priority;
- }
- }
-
- if (min_prio == max_prio)
+ if (good_incoming.empty() || good_outgoing.empty())
{
return;
}
- // Only keep indices with high prio
- std::set<int> ok_indices;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
+ for (typename boost::range_iterator<AngleCollection const>::type it =
+ sorted_angles.begin(); it != sorted_angles.end(); ++it)
{
- if (turns[*sit].priority >= max_prio)
+ if (good_incoming.count(it->turn_index) == 0
+ || good_outgoing.count(it->turn_index) == 0)
{
- ok_indices.insert(*sit);
+ turns[it->turn_index].remove_on_multi = true;
}
}
- if (ok_indices.size() > 0 && ok_indices.size() < indices.size())
- {
- indices = ok_indices;
- std::cout << "%";
- }
}
-template <typename AngleInfo, typename Angles, typename Turns, typename TurnSegmentIndices>
-inline void calculate_left_turns(Angles const& angles,
- Turns& turns, TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& keep_indices)
-{
- bool debug_indicate_size = false;
-
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<typename AngleInfo::point_type>::type
- >::type side_strategy;
- std::size_t i = 0;
- std::size_t n = boost::size(angles);
+//! Returns the number of clusters
+template <typename Point, typename AngleCollection>
+inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin)
+{
+ // Assign same cluster_index for all turns in same direction
+ BOOST_ASSERT(boost::size(sorted) >= 4u);
- typedef geometry::ever_circling_range_iterator<Angles const> circling_iterator;
- circling_iterator cit(angles);
+ angle_equal_to<Point> comparator(origin);
+ typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
- debug_left_turn(*cit, *cit);
- for(circling_iterator prev = cit++; i < n; prev = cit++, i++)
+ std::size_t cluster_index = 0;
+ it->cluster_index = cluster_index;
+ typename boost::range_iterator<AngleCollection>::type previous = it++;
+ for (; it != sorted.end(); ++it)
{
- debug_left_turn(*cit, *prev);
-
- bool const include = ! geometry::math::equals(prev->angle, cit->angle)
- && ! prev->incoming
- && cit->incoming;
-
- if (include)
+ if (!comparator(*previous, *it))
{
- // Go back to possibly include more same left outgoing angles:
- // Because we check on side too we can take a large "epsilon"
- circling_iterator back = prev - 1;
-
- typename AngleInfo::angle_type eps = 0.00001;
- int b = 1;
- for(std::size_t d = 0;
- math::abs(prev->angle - back->angle) < eps
- && ! back->incoming
- && d < n;
- d++)
- {
- --back;
- ++b;
- }
+ cluster_index++;
+ previous = it;
+ }
+ it->cluster_index = cluster_index;
+ }
+ return cluster_index + 1;
+}
- // Same but forward to possibly include more incoming angles
- int f = 1;
- circling_iterator forward = cit + 1;
- for(std::size_t d = 0;
- math::abs(cit->angle - forward->angle) < eps
- && forward->incoming
- && d < n;
- d++)
- {
- ++forward;
- ++f;
- }
+template <typename AngleCollection>
+inline void block_turns(AngleCollection& sorted, std::size_t cluster_size)
+{
+ BOOST_ASSERT(boost::size(sorted) >= 4u && cluster_size > 0);
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
- std::cout << "HANDLE " << b << "/" << f << " ANGLES" << std::endl;
-#endif
- for(circling_iterator bit = prev; bit != back; --bit)
- {
- int code = side_strategy::apply(bit->direction_point, prev->intersection_point, prev->direction_point);
- int code2 = side_strategy::apply(prev->direction_point, bit->intersection_point, bit->direction_point);
- for(circling_iterator fit = cit; fit != forward; ++fit)
- {
- int code3 = side_strategy::apply(fit->direction_point, cit->intersection_point, cit->direction_point);
- int code4 = side_strategy::apply(cit->direction_point, fit->intersection_point, fit->direction_point);
-
- int priority = 2;
- if (code == -1 && code2 == 1)
- {
- // This segment is lying right of the other one.
- // Cannot ignore it (because of robustness, see a.o. #rt_p21 from unit test).
- // But if we find more we can prefer later by priority
- // (a.o. necessary for #rt_o2 from unit test)
- priority = 1;
- }
-
- bool included = include_left_turn_of_all(*bit, *fit, turns, turn_segment_indices, keep_indices, priority);
- debug_left_turn(included ? "KEEP" : "SKIP", *fit, *bit, code, code2, code3, code4);
- }
- }
- }
+ std::vector<std::pair<bool, bool> > directions;
+ for (std::size_t i = 0; i < cluster_size; i++)
+ {
+ directions.push_back(std::make_pair(false, false));
}
- if (debug_indicate_size)
+ for (typename boost::range_iterator<AngleCollection const>::type it = sorted.begin();
+ it != sorted.end(); ++it)
{
- std::cout << " size=" << keep_indices.size();
+ if (it->incoming)
+ {
+ directions[it->cluster_index].first = true;
+ }
+ else
+ {
+ directions[it->cluster_index].second = true;
+ }
}
- if (keep_indices.size() >= 2)
+ for (typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
+ it != sorted.end(); ++it)
{
- prefer_by_other(turns, turn_segment_indices, keep_indices);
+ int cluster_index = it->cluster_index;
+ int previous_index = cluster_index - 1;
+ if (previous_index < 0)
+ {
+ previous_index = cluster_size - 1;
+ }
+ int next_index = cluster_index + 1;
+ if (next_index >= static_cast<int>(cluster_size))
+ {
+ next_index = 0;
+ }
+
+ if (directions[cluster_index].first
+ && directions[cluster_index].second)
+ {
+ it->blocked = true;
+ }
+ else if (!directions[cluster_index].first
+ && directions[cluster_index].second
+ && directions[previous_index].second)
+ {
+ // Only outgoing, previous was also outgoing: block this one
+ it->blocked = true;
+ }
+ else if (directions[cluster_index].first
+ && !directions[cluster_index].second
+ && !directions[previous_index].first
+ && directions[previous_index].second)
+ {
+ // Only incoming, previous was only outgoing: block this one
+ it->blocked = true;
+ }
+ else if (directions[cluster_index].first
+ && !directions[cluster_index].second
+ && directions[next_index].first
+ && !directions[next_index].second)
+ {
+ // Only incoming, next also incoming, block this one
+ it->blocked = true;
+ }
}
- if (keep_indices.size() >= 2)
+}
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+template <typename AngleCollection, typename Point>
+inline bool has_rounding_issues(AngleCollection const& angles, Point const& origin)
+{
+ for (typename boost::range_iterator<AngleCollection const>::type it =
+ angles.begin(); it != angles.end(); ++it)
{
- prefer_by_priority(turns, keep_indices);
+ // Vector origin -> p and origin -> q
+ typedef Point vector_type;
+ vector_type v = it->point;
+ geometry::subtract_point(v, origin);
+ return geometry::math::abs(geometry::get<0>(v)) <= 1
+ || geometry::math::abs(geometry::get<1>(v)) <= 1
+ ;
}
+ return false;
}
+#endif
+
+
+} // namespace left_turns
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/get_max_size.hpp b/boost/geometry/algorithms/detail/get_max_size.hpp
new file mode 100644
index 0000000000..8ac43e78b8
--- /dev/null
+++ b/boost/geometry/algorithms/detail/get_max_size.hpp
@@ -0,0 +1,64 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename Box, std::size_t Dimension>
+struct get_max_size_box
+{
+ static inline typename coordinate_type<Box>::type apply(Box const& box)
+ {
+ typename coordinate_type<Box>::type s
+ = geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box));
+
+ return (std::max)(s, get_max_size_box<Box, Dimension - 1>::apply(box));
+ }
+};
+
+template <typename Box>
+struct get_max_size_box<Box, 0>
+{
+ static inline typename coordinate_type<Box>::type apply(Box const& box)
+ {
+ return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box));
+ }
+};
+
+// This might be implemented later on for other geometries too.
+// Not dispatched yet.
+template <typename Box>
+inline typename coordinate_type<Box>::type get_max_size(Box const& box)
+{
+ return get_max_size_box<Box, dimension<Box>::value - 1>::apply(box);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp
index 1e6215ed93..24746ac627 100644
--- a/boost/geometry/algorithms/detail/has_self_intersections.hpp
+++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp
@@ -17,7 +17,10 @@
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
@@ -56,26 +59,33 @@ namespace detail { namespace overlay
{
-template <typename Geometry>
-inline bool has_self_intersections(Geometry const& geometry)
+template <typename Geometry, typename RobustPolicy>
+inline bool has_self_intersections(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
+ bool throw_on_self_intersection = true)
{
typedef typename point_type<Geometry>::type point_type;
- typedef detail::overlay::turn_info<point_type> turn_info;
+ typedef turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
- geometry::self_turns<detail::overlay::assign_null_policy>(geometry, turns, policy);
-
+
+ geometry::self_turns<detail::overlay::assign_null_policy>(geometry, robust_policy, turns, policy);
+
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;
-#endif
- for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns);
+#endif
+ for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns);
it != boost::end(turns); ++it)
{
turn_info const& info = *it;
- bool const both_union_turn =
+ bool const both_union_turn =
info.operations[0].operation == detail::overlay::operation_union
&& info.operations[1].operation == detail::overlay::operation_union;
- bool const both_intersection_turn =
+ bool const both_intersection_turn =
info.operations[0].operation == detail::overlay::operation_intersection
&& info.operations[1].operation == detail::overlay::operation_intersection;
@@ -95,19 +105,40 @@ inline bool has_self_intersections(Geometry const& geometry)
for (int i = 0; i < 2; i++)
{
std::cout << " " << operation_char(info.operations[i].operation);
+ std::cout << " " << info.operations[i].seg_id;
}
std::cout << " " << geometry::dsv(info.point) << std::endl;
#endif
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
- throw overlay_invalid_input_exception();
+ if (throw_on_self_intersection)
+ {
+ throw overlay_invalid_input_exception();
+ }
#endif
+ return true;
}
}
return false;
}
+// For backward compatibility
+template <typename Geometry>
+inline bool has_self_intersections(Geometry const& geometry,
+ bool throw_on_self_intersection = true)
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef typename geometry::rescale_policy_type<point_type>::type
+ rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry);
+
+ return has_self_intersections(geometry, robust_policy,
+ throw_on_self_intersection);
+}
+
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/interior_iterator.hpp b/boost/geometry/algorithms/detail/interior_iterator.hpp
new file mode 100644
index 0000000000..3582773c3d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/interior_iterator.hpp
@@ -0,0 +1,71 @@
+// Boost.Geometry
+
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP
+
+#include <boost/range/iterator.hpp>
+#include <boost/range/value_type.hpp>
+
+#include <boost/geometry/core/interior_type.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+/*!
+\brief Structure defining the type of interior rings iterator
+\note If the Geometry is const, const iterator is defined.
+\tparam Geometry \tparam_geometry
+ */
+template <typename Geometry>
+struct interior_iterator
+{
+ typedef typename boost::range_iterator
+ <
+ typename geometry::interior_type<Geometry>::type
+ >::type type;
+};
+
+template <typename BaseT, typename T>
+struct copy_const
+{
+ typedef T type;
+};
+
+template <typename BaseT, typename T>
+struct copy_const<BaseT const, T>
+{
+ typedef T const type;
+};
+
+template <typename Geometry>
+struct interior_ring_iterator
+{
+ typedef typename boost::range_iterator
+ <
+ typename copy_const
+ <
+ typename geometry::interior_type<Geometry>::type,
+ typename boost::range_value
+ <
+ typename geometry::interior_type<Geometry>::type
+ >::type
+ >::type
+ >::type type;
+};
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/box_box.hpp b/boost/geometry/algorithms/detail/intersection/box_box.hpp
new file mode 100644
index 0000000000..30c31ff1e5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/box_box.hpp
@@ -0,0 +1,54 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP
+
+
+#include <boost/geometry/algorithms/detail/intersection/interface.hpp>
+#include <boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Box1, typename Box2, bool Reverse
+>
+struct intersection
+ <
+ Box1, Box2,
+ box_tag, box_tag,
+ Reverse
+ > : public detail::intersection::intersection_box_box
+ <
+ 0, geometry::dimension<Box1>::value
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/implementation.hpp b/boost/geometry/algorithms/detail/intersection/implementation.hpp
new file mode 100644
index 0000000000..d8fb2ec38c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/implementation.hpp
@@ -0,0 +1,22 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP
+
+
+#include <boost/geometry/algorithms/detail/intersection/box_box.hpp>
+#include <boost/geometry/algorithms/detail/intersection/multi.hpp>
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/interface.hpp b/boost/geometry/algorithms/detail/intersection/interface.hpp
new file mode 100644
index 0000000000..323ab7c850
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/interface.hpp
@@ -0,0 +1,309 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP
+
+
+// TODO: those headers probably may be removed
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// By default, all is forwarded to the intersection_insert-dispatcher
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct intersection
+{
+ template <typename RobustPolicy, typename GeometryOut, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ GeometryOut& geometry_out,
+ Strategy const& strategy)
+ {
+ typedef typename boost::range_value<GeometryOut>::type OneOut;
+
+ intersection_insert
+ <
+ Geometry1, Geometry2, OneOut,
+ overlay_intersection
+ >::apply(geometry1, geometry2, robust_policy, std::back_inserter(geometry_out), strategy);
+
+ return true;
+ }
+
+};
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2
+>
+struct intersection
+<
+ Geometry1, Geometry2,
+ Tag1, Tag2,
+ true
+>
+ : intersection<Geometry2, Geometry1, Tag2, Tag1, false>
+{
+ template <typename RobustPolicy, typename GeometryOut, typename Strategy>
+ static inline bool apply(
+ Geometry1 const& g1,
+ Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
+ GeometryOut& out,
+ Strategy const& strategy)
+ {
+ return intersection<
+ Geometry2, Geometry1,
+ Tag2, Tag1,
+ false
+ >::apply(g2, g1, robust_policy, out, strategy);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct intersection
+{
+ template <typename GeometryOut>
+ static inline bool
+ apply(
+ const Geometry1& geometry1,
+ const Geometry2& geometry2,
+ GeometryOut& geometry_out)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
+ typedef strategy_intersection
+ <
+ typename cs_tag<Geometry1>::type,
+ Geometry1,
+ Geometry2,
+ typename geometry::point_type<Geometry1>::type,
+ rescale_policy_type
+ > strategy;
+
+ return dispatch::intersection
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy());
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename GeometryOut>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ GeometryOut& m_geometry_out;
+
+ visitor(Geometry2 const& geometry2,
+ GeometryOut& geometry_out)
+ : m_geometry2(geometry2),
+ m_geometry_out(geometry_out)
+ {}
+
+ template <typename Geometry1>
+ result_type operator()(Geometry1 const& geometry1) const
+ {
+ return intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (geometry1, m_geometry2, m_geometry_out);
+ }
+ };
+
+ template <typename GeometryOut>
+ static inline bool
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ GeometryOut& geometry_out)
+ {
+ return apply_visitor(visitor<GeometryOut>(geometry2, geometry_out), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename GeometryOut>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ GeometryOut& m_geometry_out;
+
+ visitor(Geometry1 const& geometry1,
+ GeometryOut& geometry_out)
+ : m_geometry1(geometry1),
+ m_geometry_out(geometry_out)
+ {}
+
+ template <typename Geometry2>
+ result_type operator()(Geometry2 const& geometry2) const
+ {
+ return intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (m_geometry1, geometry2, m_geometry_out);
+ }
+ };
+
+ template <typename GeometryOut>
+ static inline bool
+ apply(
+ Geometry1 const& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2,
+ GeometryOut& geometry_out)
+ {
+ return apply_visitor(visitor<GeometryOut>(geometry1, geometry_out), geometry2);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)>
+struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> >
+{
+ template <typename GeometryOut>
+ struct visitor: static_visitor<bool>
+ {
+ GeometryOut& m_geometry_out;
+
+ visitor(GeometryOut& geometry_out)
+ : m_geometry_out(geometry_out)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ result_type operator()(
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (geometry1, geometry2, m_geometry_out);
+ }
+ };
+
+ template <typename GeometryOut>
+ static inline bool
+ apply(
+ const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2,
+ GeometryOut& geometry_out)
+ {
+ return apply_visitor(visitor<GeometryOut>(geometry_out), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_calc2{intersection}
+\ingroup intersection
+\details \details_calc2{intersection, spatial set theoretic intersection}.
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which
+ the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box)
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param geometry_out The output geometry, either a multi_point, multi_polygon,
+ multi_linestring, or a box (for intersection of two boxes)
+
+\qbk{[include reference/algorithms/intersection.qbk]}
+*/
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename GeometryOut
+>
+inline bool intersection(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ GeometryOut& geometry_out)
+{
+ return resolve_variant::intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (geometry1, geometry2, geometry_out);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/multi.hpp b/boost/geometry/algorithms/detail/intersection/multi.hpp
new file mode 100644
index 0000000000..b1f13862fc
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/multi.hpp
@@ -0,0 +1,423 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/geometry_id.hpp>
+#include <boost/geometry/core/is_areal.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+// TODO: those headers probably may be removed
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
+#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
+
+#include <boost/geometry/algorithms/detail/intersection/interface.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+
+// TODO: remove this after moving num_point from multi directory
+#include <boost/geometry/multi/algorithms/num_points.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+
+template <typename PointOut>
+struct intersection_multi_linestring_multi_linestring_point
+{
+ template
+ <
+ typename MultiLinestring1, typename MultiLinestring2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(MultiLinestring1 const& ml1,
+ MultiLinestring2 const& ml2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ // Note, this loop is quadratic w.r.t. number of linestrings per input.
+ // Future Enhancement: first do the sections of each, then intersect.
+ for (typename boost::range_iterator
+ <
+ MultiLinestring1 const
+ >::type it1 = boost::begin(ml1);
+ it1 != boost::end(ml1);
+ ++it1)
+ {
+ for (typename boost::range_iterator
+ <
+ MultiLinestring2 const
+ >::type it2 = boost::begin(ml2);
+ it2 != boost::end(ml2);
+ ++it2)
+ {
+ out = intersection_linestring_linestring_point<PointOut>
+ ::apply(*it1, *it2, robust_policy, out, strategy);
+ }
+ }
+
+ return out;
+ }
+};
+
+
+template <typename PointOut>
+struct intersection_linestring_multi_linestring_point
+{
+ template
+ <
+ typename Linestring, typename MultiLinestring,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linestring const& linestring,
+ MultiLinestring const& ml,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ for (typename boost::range_iterator
+ <
+ MultiLinestring const
+ >::type it = boost::begin(ml);
+ it != boost::end(ml);
+ ++it)
+ {
+ out = intersection_linestring_linestring_point<PointOut>
+ ::apply(linestring, *it, robust_policy, out, strategy);
+ }
+
+ return out;
+ }
+};
+
+
+// This loop is quite similar to the loop above, but beacuse the iterator
+// is second (above) or first (below) argument, it is not trivial to merge them.
+template
+<
+ bool ReverseAreal,
+ typename LineStringOut,
+ overlay_type OverlayType
+>
+struct intersection_of_multi_linestring_with_areal
+{
+ template
+ <
+ typename MultiLinestring, typename Areal,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ for (typename boost::range_iterator
+ <
+ MultiLinestring const
+ >::type it = boost::begin(ml);
+ it != boost::end(ml);
+ ++it)
+ {
+ out = intersection_of_linestring_with_areal
+ <
+ ReverseAreal, LineStringOut, OverlayType
+ >::apply(*it, areal, robust_policy, out, strategy);
+ }
+
+ return out;
+
+ }
+};
+
+// This one calls the one above with reversed arguments
+template
+<
+ bool ReverseAreal,
+ typename LineStringOut,
+ overlay_type OverlayType
+>
+struct intersection_of_areal_with_multi_linestring
+{
+ template
+ <
+ typename Areal, typename MultiLinestring,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ return intersection_of_multi_linestring_with_areal
+ <
+ ReverseAreal, LineStringOut, OverlayType
+ >::apply(ml, areal, robust_policy, out, strategy);
+ }
+};
+
+
+
+template <typename LinestringOut>
+struct clip_multi_linestring
+{
+ template
+ <
+ typename MultiLinestring, typename Box,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(MultiLinestring const& multi_linestring,
+ Box const& box,
+ RobustPolicy const& robust_policy,
+ OutputIterator out, Strategy const& )
+ {
+ typedef typename point_type<LinestringOut>::type point_type;
+ strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
+ for (typename boost::range_iterator<MultiLinestring const>::type it
+ = boost::begin(multi_linestring);
+ it != boost::end(multi_linestring); ++it)
+ {
+ out = detail::intersection::clip_range_with_box
+ <LinestringOut>(box, *it, robust_policy, out, lb_strategy);
+ }
+ return out;
+ }
+};
+
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Linear
+template
+<
+ typename MultiLinestring1, typename MultiLinestring2,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring1, MultiLinestring2,
+ GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_linestring_tag, multi_linestring_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_multi_linestring_multi_linestring_point
+ <
+ GeometryOut
+ >
+{};
+
+
+template
+<
+ typename Linestring, typename MultiLinestring,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Linestring, MultiLinestring,
+ GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ linestring_tag, multi_linestring_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_linestring_multi_linestring_point
+ <
+ GeometryOut
+ >
+{};
+
+
+template
+<
+ typename MultiLinestring, typename Box,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, Box,
+ GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_linestring_tag, box_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::clip_multi_linestring
+ <
+ GeometryOut
+ >
+{};
+
+
+template
+<
+ typename Linestring, typename MultiPolygon,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseLinestring, bool ReverseMultiPolygon, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Linestring, MultiPolygon,
+ GeometryOut,
+ OverlayType,
+ ReverseLinestring, ReverseMultiPolygon, ReverseOut,
+ linestring_tag, multi_polygon_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_linestring_with_areal
+ <
+ ReverseMultiPolygon,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+// Derives from areal/mls because runtime arguments are in that order.
+// areal/mls reverses it itself to mls/areal
+template
+<
+ typename Polygon, typename MultiLinestring,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReversePolygon, bool ReverseMultiLinestring, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Polygon, MultiLinestring,
+ GeometryOut,
+ OverlayType,
+ ReversePolygon, ReverseMultiLinestring, ReverseOut,
+ polygon_tag, multi_linestring_tag, linestring_tag,
+ true, false, false
+ > : detail::intersection::intersection_of_areal_with_multi_linestring
+ <
+ ReversePolygon,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiLinestring, typename Ring,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, Ring,
+ GeometryOut,
+ OverlayType,
+ ReverseMultiLinestring, ReverseRing, ReverseOut,
+ multi_linestring_tag, ring_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_multi_linestring_with_areal
+ <
+ ReverseRing,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+template
+<
+ typename MultiLinestring, typename Polygon,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, Polygon,
+ GeometryOut,
+ OverlayType,
+ ReverseMultiLinestring, ReverseRing, ReverseOut,
+ multi_linestring_tag, polygon_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_multi_linestring_with_areal
+ <
+ ReverseRing,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+
+template
+<
+ typename MultiLinestring, typename MultiPolygon,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseMultiLinestring, bool ReverseMultiPolygon, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, MultiPolygon,
+ GeometryOut,
+ OverlayType,
+ ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut,
+ multi_linestring_tag, multi_polygon_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_multi_linestring_with_areal
+ <
+ ReverseMultiPolygon,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+} // namespace dispatch
+#endif
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP
+
diff --git a/boost/geometry/algorithms/detail/is_simple/always_simple.hpp b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp
new file mode 100644
index 0000000000..91e2ef76bd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp
@@ -0,0 +1,83 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP
+
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename Geometry>
+struct always_simple
+{
+ static inline bool apply(Geometry const&)
+ {
+ return true;
+ }
+};
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A point is always simple
+template <typename Point>
+struct is_simple<Point, point_tag>
+ : detail::is_simple::always_simple<Point>
+{};
+
+
+// A valid segment is always simple.
+// A segment is a curve.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Segment>
+struct is_simple<Segment, segment_tag>
+ : detail::is_simple::always_simple<Segment>
+{};
+
+
+// A valid box is always simple
+// A box is a Polygon, and it satisfies the conditions for Polygon validity.
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Box>
+struct is_simple<Box, box_tag>
+ : detail::is_simple::always_simple<Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/areal.hpp b/boost/geometry/algorithms/detail/is_simple/areal.hpp
new file mode 100644
index 0000000000..9a1a16507a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/areal.hpp
@@ -0,0 +1,141 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.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/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename Ring>
+struct is_simple_ring
+{
+ static inline bool apply(Ring const& ring)
+ {
+ return
+ !detail::is_valid::has_duplicates
+ <
+ Ring, geometry::closure<Ring>::value
+ >::apply(ring);
+ }
+};
+
+
+template <typename Polygon>
+class is_simple_polygon
+{
+private:
+ template <typename InteriorRings>
+ static inline
+ bool are_simple_interior_rings(InteriorRings const& interior_rings)
+ {
+ return
+ detail::check_iterator_range
+ <
+ is_simple_ring
+ <
+ typename boost::range_value<InteriorRings>::type
+ >
+ >::apply(boost::begin(interior_rings),
+ boost::end(interior_rings));
+ }
+
+public:
+ static inline bool apply(Polygon const& polygon)
+ {
+ return
+ is_simple_ring
+ <
+ typename ring_type<Polygon>::type
+ >::apply(exterior_ring(polygon))
+ &&
+ are_simple_interior_rings(geometry::interior_rings(polygon));
+ }
+};
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A Ring is a Polygon.
+// A Polygon is always a simple geometric object provided that it is valid.
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Ring>
+struct is_simple<Ring, ring_tag>
+ : detail::is_simple::is_simple_ring<Ring>
+{};
+
+
+// A Polygon is always a simple geometric object provided that it is valid.
+//
+// Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1)
+template <typename Polygon>
+struct is_simple<Polygon, polygon_tag>
+ : detail::is_simple::is_simple_polygon<Polygon>
+{};
+
+
+// Not clear what the definition is.
+// Right now we consider a MultiPolygon as simple if it is valid.
+//
+// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14)
+template <typename MultiPolygon>
+struct is_simple<MultiPolygon, multi_polygon_tag>
+{
+ static inline bool apply(MultiPolygon const& multipolygon)
+ {
+ return
+ detail::check_iterator_range
+ <
+ detail::is_simple::is_simple_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type
+ >,
+ false // do not allow empty multi-polygon
+ >::apply(boost::begin(multipolygon), boost::end(multipolygon));
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp
new file mode 100644
index 0000000000..75c37c68f8
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp
@@ -0,0 +1,82 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/io/dsv/write.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_simple
+{
+
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename MultiLinestring>
+inline void debug_print_boundary_points(MultiLinestring const& multilinestring)
+{
+ typedef typename point_type<MultiLinestring>::type point_type;
+ typedef std::vector<point_type> point_vector;
+
+ point_vector boundary_points;
+ for (typename boost::range_iterator<MultiLinestring const>::type it
+ = boost::begin(multilinestring);
+ it != boost::end(multilinestring); ++it)
+ {
+ if ( boost::size(*it) > 1
+ && !geometry::equals(range::front(*it), range::back(*it)) )
+ {
+ boundary_points.push_back( range::front(*it) );
+ boundary_points.push_back( range::back(*it) );
+ }
+ }
+
+ std::sort(boundary_points.begin(), boundary_points.end(),
+ geometry::less<point_type>());
+
+ std::cout << "boundary points: ";
+ for (typename point_vector::const_iterator pit = boundary_points.begin();
+ pit != boundary_points.end(); ++pit)
+ {
+ std::cout << " " << geometry::dsv(*pit);
+ }
+ std::cout << std::endl << std::endl;
+}
+#else
+template <typename MultiLinestring>
+inline void debug_print_boundary_points(MultiLinestring const&)
+{
+}
+#endif // BOOST_GEOMETRY_TEST_DEBUG
+
+
+}} // namespace detail::is_simple
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/implementation.hpp b/boost/geometry/algorithms/detail/is_simple/implementation.hpp
new file mode 100644
index 0000000000..e69b273ce3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/implementation.hpp
@@ -0,0 +1,18 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP
+
+#include <boost/geometry/algorithms/detail/is_simple/always_simple.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/areal.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/linear.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/multipoint.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/interface.hpp b/boost/geometry/algorithms/detail/is_simple/interface.hpp
new file mode 100644
index 0000000000..4239664ed1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/interface.hpp
@@ -0,0 +1,80 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct is_simple
+{
+ static inline bool apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+ return dispatch::is_simple<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor : boost::static_visitor<bool>
+ {
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return is_simple<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+
+/*!
+\brief \brief_check{is simple}
+\ingroup is_simple
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is simple}
+
+\qbk{[include reference/algorithms/is_simple.qbk]}
+*/
+template <typename Geometry>
+inline bool is_simple(Geometry const& geometry)
+{
+ return resolve_variant::is_simple<Geometry>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp
new file mode 100644
index 0000000000..f2efcb309d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp
@@ -0,0 +1,248 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
+
+#include <algorithm>
+#include <deque>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
+
+#include <boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename Linestring, bool CheckSelfIntersections = true>
+struct is_simple_linestring
+{
+ static inline bool apply(Linestring const& linestring)
+ {
+ return !detail::is_valid::has_duplicates
+ <
+ Linestring, closed
+ >::apply(linestring)
+ && !detail::is_valid::has_spikes
+ <
+ Linestring, closed
+ >::apply(linestring)
+ && !(CheckSelfIntersections && geometry::intersects(linestring));
+ }
+};
+
+
+
+template <typename MultiLinestring>
+class is_simple_multilinestring
+{
+private:
+ class is_acceptable_turn
+ {
+ private:
+ template <typename Point, typename Linestring>
+ static inline bool is_boundary_point_of(Point const& point,
+ Linestring const& linestring)
+ {
+ BOOST_ASSERT( boost::size(linestring) > 1 );
+ return
+ !geometry::equals(range::front(linestring),
+ range::back(linestring))
+ &&
+ ( geometry::equals(point, range::front(linestring))
+ || geometry::equals(point, range::back(linestring)) );
+ }
+
+ template <typename Linestring1, typename Linestring2>
+ static inline bool have_same_boundary_points(Linestring1 const& ls1,
+ Linestring2 const& ls2)
+ {
+ return
+ geometry::equals(range::front(ls1), range::front(ls2))
+ ?
+ geometry::equals(range::back(ls1), range::back(ls2))
+ :
+ (geometry::equals(range::front(ls1), range::back(ls2))
+ &&
+ geometry::equals(range::back(ls1), range::front(ls2))
+ )
+ ;
+ }
+
+ public:
+ is_acceptable_turn(MultiLinestring const& multilinestring)
+ : m_multilinestring(multilinestring)
+ {}
+
+ template <typename Turn>
+ inline bool apply(Turn const& turn) const
+ {
+ typedef typename boost::range_value
+ <
+ MultiLinestring
+ >::type linestring;
+
+ linestring const& ls1 =
+ range::at(m_multilinestring,
+ turn.operations[0].seg_id.multi_index);
+
+ linestring const& ls2 =
+ range::at(m_multilinestring,
+ turn.operations[1].seg_id.multi_index);
+
+ return
+ is_boundary_point_of(turn.point, ls1)
+ && is_boundary_point_of(turn.point, ls2)
+ &&
+ ( boost::size(ls1) != 2
+ || boost::size(ls2) != 2
+ || !have_same_boundary_points(ls1, ls2) );
+ }
+
+ private:
+ MultiLinestring const& m_multilinestring;
+ };
+
+
+public:
+ static inline bool apply(MultiLinestring const& multilinestring)
+ {
+ typedef typename boost::range_value<MultiLinestring>::type linestring;
+ typedef typename point_type<MultiLinestring>::type point_type;
+ typedef point_type point;
+
+
+ // check each of the linestrings for simplicity
+ if ( !detail::check_iterator_range
+ <
+ is_simple_linestring<linestring>,
+ false // do not allow empty multilinestring
+ >::apply(boost::begin(multilinestring),
+ boost::end(multilinestring))
+ )
+ {
+ return false;
+ }
+
+
+ // compute self turns
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ geometry::segment_ratio
+ <
+ typename geometry::coordinate_type<point>::type
+ >
+ > turn_info;
+
+ std::deque<turn_info> turns;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::disjoint::assign_disjoint_policy
+ > turn_policy;
+
+ is_acceptable_turn predicate(multilinestring);
+ detail::overlay::predicate_based_interrupt_policy
+ <
+ is_acceptable_turn
+ > interrupt_policy(predicate);
+
+ detail::self_get_turn_points::get_turns
+ <
+ turn_policy
+ >::apply(multilinestring,
+ detail::no_rescale_policy(),
+ turns,
+ interrupt_policy);
+
+ detail::is_valid::debug_print_turns(turns.begin(), turns.end());
+ debug_print_boundary_points(multilinestring);
+
+ return !interrupt_policy.has_intersections;
+ }
+
+};
+
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// A linestring is a curve.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Linestring>
+struct is_simple<Linestring, linestring_tag>
+ : detail::is_simple::is_simple_linestring<Linestring>
+{};
+
+
+// A MultiLinestring is a MultiCurve
+// A MultiCurve is simple if all of its elements are simple and the
+// only intersections between any two elements occur at Points that
+// are on the boundaries of both elements.
+//
+// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
+template <typename MultiLinestring>
+struct is_simple<MultiLinestring, multi_linestring_tag>
+ : detail::is_simple::is_simple_multilinestring<MultiLinestring>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp
new file mode 100644
index 0000000000..d996eb64e9
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp
@@ -0,0 +1,84 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP
+
+#include <algorithm>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename MultiPoint>
+struct is_simple_multipoint
+{
+ static inline bool apply(MultiPoint const& multipoint)
+ {
+ if ( boost::size(multipoint) == 0 )
+ {
+ return false;
+ }
+
+ MultiPoint mp(multipoint);
+ std::sort(boost::begin(mp), boost::end(mp),
+ geometry::less<typename point_type<MultiPoint>::type>());
+
+ return !detail::is_valid::has_duplicates<MultiPoint, closed>::apply(mp);
+ }
+};
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A MultiPoint is simple if no two Points in the MultiPoint are equal
+// (have identical coordinate values in X and Y)
+//
+// Reference: OGC 06-103r4 (6.1.5)
+template <typename MultiPoint>
+struct is_simple<MultiPoint, multi_point_tag>
+ : detail::is_simple::is_simple_multipoint<MultiPoint>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/box.hpp b/boost/geometry/algorithms/detail/is_valid/box.hpp
new file mode 100644
index 0000000000..f82b3f9bf1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/box.hpp
@@ -0,0 +1,86 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+template <typename Box, std::size_t I>
+struct has_valid_corners
+{
+ static inline bool apply(Box const& box)
+ {
+ if ( geometry::get<geometry::max_corner, I-1>(box)
+ <=
+ geometry::get<geometry::min_corner, I-1>(box) )
+ {
+ return false;
+ }
+ return has_valid_corners<Box, I-1>::apply(box);
+ }
+};
+
+
+template <typename Box>
+struct has_valid_corners<Box, 0>
+{
+ static inline bool apply(Box const&)
+ {
+ return true;
+ }
+};
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A box is always simple
+// A box is a Polygon, and it satisfies the conditions for Polygon validity.
+//
+// The only thing we have to check is whether the max corner lies in
+// the upper-right quadrant as defined by the min corner
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Box>
+struct is_valid<Box, box_tag>
+ : detail::is_valid::has_valid_corners<Box, dimension<Box>::value>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp
new file mode 100644
index 0000000000..c59139a92e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp
@@ -0,0 +1,239 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
+
+#include <cstddef>
+
+#include <set>
+#include <stack>
+#include <utility>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/core/addressof.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+
+template <typename TurnPoint>
+class complement_graph_vertex
+{
+public:
+ complement_graph_vertex(std::size_t id)
+ : m_id(id)
+ , m_turn_point(NULL)
+ {}
+
+ complement_graph_vertex(TurnPoint const* turn_point,
+ std::size_t expected_id)
+ : m_id(expected_id)
+ , m_turn_point(turn_point)
+ {}
+
+ inline std::size_t id() const { return m_id; }
+
+ inline bool operator<(complement_graph_vertex const& other) const
+ {
+ if ( m_turn_point != NULL && other.m_turn_point != NULL )
+ {
+ return geometry::less
+ <
+ TurnPoint
+ >()(*m_turn_point, *other.m_turn_point);
+ }
+ if ( m_turn_point == NULL && other.m_turn_point == NULL )
+ {
+ return m_id < other.m_id;
+ }
+ return m_turn_point == NULL;
+ }
+
+private:
+ // the value of m_turn_point determines the type of the vertex
+ // non-NULL: vertex corresponds to an IP
+ // NULL : vertex corresponds to a hole or outer space, and the id
+ // is the ring id of the corresponding ring of the polygon
+ std::size_t m_id;
+ TurnPoint const* m_turn_point;
+};
+
+
+
+
+template <typename TurnPoint>
+class complement_graph
+{
+private:
+ typedef complement_graph_vertex<TurnPoint> vertex;
+ typedef std::set<vertex> vertex_container;
+
+public:
+ typedef typename vertex_container::const_iterator vertex_handle;
+
+private:
+ struct vertex_handle_less
+ {
+ inline bool operator()(vertex_handle v1, vertex_handle v2) const
+ {
+ return v1->id() < v2->id();
+ }
+ };
+
+ typedef std::set<vertex_handle, vertex_handle_less> neighbor_container;
+
+ class has_cycles_dfs_data
+ {
+ public:
+ has_cycles_dfs_data(std::size_t num_nodes)
+ : m_visited(num_nodes, false)
+ , m_parent_id(num_nodes, -1)
+ {}
+
+ inline signed_index_type parent_id(vertex_handle v) const
+ {
+ return m_parent_id[v->id()];
+ }
+
+ inline void set_parent_id(vertex_handle v, signed_index_type id)
+ {
+ m_parent_id[v->id()] = id;
+ }
+
+ inline bool visited(vertex_handle v) const
+ {
+ return m_visited[v->id()];
+ }
+
+ inline void set_visited(vertex_handle v, bool value)
+ {
+ m_visited[v->id()] = value;
+ }
+ private:
+ std::vector<bool> m_visited;
+ std::vector<signed_index_type> m_parent_id;
+ };
+
+
+ inline bool has_cycles(vertex_handle start_vertex,
+ has_cycles_dfs_data& data) const
+ {
+ std::stack<vertex_handle> stack;
+ stack.push(start_vertex);
+
+ while ( !stack.empty() )
+ {
+ vertex_handle v = stack.top();
+ stack.pop();
+
+ data.set_visited(v, true);
+ for (typename neighbor_container::const_iterator nit
+ = m_neighbors[v->id()].begin();
+ nit != m_neighbors[v->id()].end(); ++nit)
+ {
+ if ( static_cast<signed_index_type>((*nit)->id()) != data.parent_id(v) )
+ {
+ if ( data.visited(*nit) )
+ {
+ return true;
+ }
+ else
+ {
+ data.set_parent_id(*nit, static_cast<signed_index_type>(v->id()));
+ stack.push(*nit);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+public:
+ // num_rings: total number of rings, including the exterior ring
+ complement_graph(std::size_t num_rings)
+ : m_num_rings(num_rings)
+ , m_num_turns(0)
+ , m_vertices()
+ , m_neighbors(num_rings)
+ {}
+
+ // inserts a ring vertex in the graph and returns its handle
+ // ring id's are zero-based (so the first interior ring has id 1)
+ inline vertex_handle add_vertex(signed_index_type id)
+ {
+ return m_vertices.insert(vertex(static_cast<std::size_t>(id))).first;
+ }
+
+ // inserts an IP in the graph and returns its id
+ inline vertex_handle add_vertex(TurnPoint const& turn_point)
+ {
+ std::pair<vertex_handle, bool> res
+ = m_vertices.insert(vertex(boost::addressof(turn_point),
+ m_num_rings + m_num_turns)
+ );
+
+ if ( res.second )
+ {
+ // a new element is inserted
+ m_neighbors.push_back(neighbor_container());
+ ++m_num_turns;
+ }
+ return res.first;
+ }
+
+ inline void add_edge(vertex_handle v1, vertex_handle v2)
+ {
+ BOOST_ASSERT( v1 != m_vertices.end() );
+ BOOST_ASSERT( v2 != m_vertices.end() );
+ m_neighbors[v1->id()].insert(v2);
+ m_neighbors[v2->id()].insert(v1);
+ }
+
+ inline bool has_cycles() const
+ {
+ // initialize all vertices as non-visited and with no parent set
+ // this is done by the constructor of has_cycles_dfs_data
+ has_cycles_dfs_data data(m_num_rings + m_num_turns);
+
+ // for each non-visited vertex, start a DFS from that vertex
+ for (vertex_handle it = m_vertices.begin();
+ it != m_vertices.end(); ++it)
+ {
+ if ( !data.visited(it) && has_cycles(it, data) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template <typename OStream, typename TP>
+ friend inline
+ void debug_print_complement_graph(OStream&, complement_graph<TP> const&);
+
+private:
+ std::size_t m_num_rings, m_num_turns;
+ vertex_container m_vertices;
+ std::vector<neighbor_container> m_neighbors;
+};
+
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp
new file mode 100644
index 0000000000..60f597e296
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+#include <iostream>
+#endif
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename OutputStream, typename TurnPoint>
+inline void
+debug_print_complement_graph(OutputStream& os,
+ complement_graph<TurnPoint> const& graph)
+{
+ typedef typename complement_graph<TurnPoint>::vertex_handle vertex_handle;
+
+ os << "num rings: " << graph.m_num_rings << std::endl;
+ os << "vertex ids: {";
+ for (vertex_handle it = graph.m_vertices.begin();
+ it != graph.m_vertices.end(); ++it)
+ {
+ os << " " << it->id();
+ }
+ os << " }" << std::endl;
+
+ for (vertex_handle it = graph.m_vertices.begin();
+ it != graph.m_vertices.end(); ++it)
+ {
+ os << "neighbors of " << it->id() << ": {";
+ for (typename complement_graph
+ <
+ TurnPoint
+ >::neighbor_container::const_iterator
+ nit = graph.m_neighbors[it->id()].begin();
+ nit != graph.m_neighbors[it->id()].end(); ++nit)
+ {
+ os << " " << (*nit)->id();
+ }
+ os << "}" << std::endl;
+ }
+}
+#else
+template <typename OutputStream, typename TurnPoint>
+inline void debug_print_complement_graph(OutputStream&,
+ complement_graph<TurnPoint> const&)
+{
+}
+#endif
+
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp
new file mode 100644
index 0000000000..6824921b63
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp
@@ -0,0 +1,64 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+#include <iostream>
+
+#include <boost/geometry/io/dsv/write.hpp>
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename TurnIterator>
+inline void debug_print_turns(TurnIterator first, TurnIterator beyond)
+{
+ std::cout << "turns:";
+ for (TurnIterator tit = first; tit != beyond; ++tit)
+ {
+ std::cout << " ["
+ << geometry::method_char(tit->method)
+ << ","
+ << geometry::operation_char(tit->operations[0].operation)
+ << "/"
+ << geometry::operation_char(tit->operations[1].operation)
+ << " {"
+ << tit->operations[0].seg_id.multi_index
+ << ", "
+ << tit->operations[1].seg_id.multi_index
+ << "} {"
+ << tit->operations[0].seg_id.ring_index
+ << ", "
+ << tit->operations[1].seg_id.ring_index
+ << "} "
+ << geometry::dsv(tit->point)
+ << "]";
+ }
+ std::cout << std::endl << std::endl;
+}
+#else
+template <typename TurnIterator>
+inline void debug_print_turns(TurnIterator, TurnIterator)
+{}
+#endif // BOOST_GEOMETRY_TEST_DEBUG
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp
new file mode 100644
index 0000000000..6f1c263646
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp
@@ -0,0 +1,68 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP
+
+#ifdef GEOMETRY_TEST_DEBUG
+#include <iostream>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct debug_validity_phase
+{
+ static inline void apply(int)
+ {
+ }
+};
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename Polygon>
+struct debug_validity_phase<Polygon, polygon_tag>
+{
+ static inline void apply(int phase)
+ {
+ switch (phase)
+ {
+ case 1:
+ std::cout << "checking exterior ring..." << std::endl;
+ break;
+ case 2:
+ std::cout << "checking interior rings..." << std::endl;
+ break;
+ case 3:
+ std::cout << "computing and analyzing turns..." << std::endl;
+ break;
+ case 4:
+ std::cout << "checking if holes are inside the exterior ring..."
+ << std::endl;
+ break;
+ case 5:
+ std::cout << "checking connectivity of interior..." << std::endl;
+ break;
+ }
+ }
+};
+#endif
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp
new file mode 100644
index 0000000000..dd0922bb2b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/views/closeable_view.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+template <typename Range, closure_selector Closure>
+struct has_duplicates
+{
+ static inline bool apply(Range const& range)
+ {
+ typedef typename closeable_view<Range const, Closure>::type view_type;
+ typedef typename boost::range_iterator<view_type const>::type iterator;
+
+ view_type view(range);
+
+ if ( boost::size(view) < 2 )
+ {
+ return false;
+ }
+
+ geometry::equal_to<typename boost::range_value<Range>::type> equal;
+
+ iterator it = boost::begin(view);
+ iterator next = ++boost::begin(view);
+ for (; next != boost::end(view); ++it, ++next)
+ {
+ if ( equal(*it, *next) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
new file mode 100644
index 0000000000..9b95017482
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
@@ -0,0 +1,139 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
+
+#include <algorithm>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/views/closeable_view.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+template <typename Point>
+struct equal_to
+{
+ Point const& m_point;
+
+ equal_to(Point const& point)
+ : m_point(point)
+ {}
+
+ template <typename OtherPoint>
+ inline bool operator()(OtherPoint const& other) const
+ {
+ return geometry::equals(m_point, other);
+ }
+};
+
+template <typename Point>
+struct not_equal_to
+{
+ Point const& m_point;
+
+ not_equal_to(Point const& point)
+ : m_point(point)
+ {}
+
+ template <typename OtherPoint>
+ inline bool operator()(OtherPoint const& other) const
+ {
+ return !geometry::equals(other, m_point);
+ }
+};
+
+
+
+template <typename Range, closure_selector Closure>
+struct has_spikes
+{
+ static inline bool apply(Range const& range)
+ {
+ typedef not_equal_to<typename point_type<Range>::type> not_equal;
+
+ typedef typename closeable_view<Range const, Closure>::type view_type;
+ typedef typename boost::range_iterator<view_type const>::type iterator;
+
+ view_type const view(range);
+
+ iterator prev = boost::begin(view);
+
+ iterator cur = std::find_if(prev, boost::end(view), not_equal(*prev));
+ if ( cur == boost::end(view) )
+ {
+ // the range has only one distinct point, so it
+ // cannot have a spike
+ return false;
+ }
+
+ iterator next = std::find_if(cur, boost::end(view), not_equal(*cur));
+ if ( next == boost::end(view) )
+ {
+ // the range has only two distinct points, so it
+ // cannot have a spike
+ return false;
+ }
+
+ while ( next != boost::end(view) )
+ {
+ if ( geometry::detail::point_is_spike_or_equal(*prev,
+ *next,
+ *cur) )
+ {
+ return true;
+ }
+ prev = cur;
+ cur = next;
+ next = std::find_if(cur, boost::end(view), not_equal(*cur));
+ }
+
+ if ( geometry::equals(range::front(view), range::back(view)) )
+ {
+ iterator cur = boost::begin(view);
+ typename boost::range_reverse_iterator
+ <
+ view_type const
+ >::type prev = std::find_if(boost::rbegin(view),
+ boost::rend(view),
+ not_equal(range::back(view)));
+ iterator next =
+ std::find_if(cur, boost::end(view), not_equal(*cur));
+ return detail::point_is_spike_or_equal(*prev, *next, *cur);
+ }
+
+ return false;
+ }
+};
+
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
new file mode 100644
index 0000000000..220a67bcd1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
@@ -0,0 +1,93 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template
+<
+ typename Geometry,
+ typename IsAcceptableTurn = is_acceptable_turn<Geometry>
+>
+class has_valid_self_turns
+{
+private:
+ typedef typename point_type<Geometry>::type point_type;
+
+ typedef typename geometry::rescale_policy_type
+ <
+ point_type
+ >::type rescale_policy_type;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+public:
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type
+ <
+ point_type,
+ rescale_policy_type
+ >::type
+ > turn_type;
+
+ // returns true if all turns are valid
+ template <typename Turns>
+ static inline bool apply(Geometry const& geometry, Turns& turns)
+ {
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry);
+
+ detail::overlay::stateless_predicate_based_interrupt_policy
+ <
+ IsAcceptableTurn
+ > interrupt_policy;
+
+ geometry::self_turns<turn_policy>(geometry,
+ robust_policy,
+ turns,
+ interrupt_policy);
+
+ return !interrupt_policy.has_intersections;
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/implementation.hpp b/boost/geometry/algorithms/detail/is_valid/implementation.hpp
new file mode 100644
index 0000000000..4a515a3073
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/implementation.hpp
@@ -0,0 +1,21 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP
+
+#include <boost/geometry/algorithms/detail/is_valid/pointlike.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/linear.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/multipolygon.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/segment.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/box.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp
new file mode 100644
index 0000000000..4b232fd436
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct is_valid
+{
+ static inline bool apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+ return dispatch::is_valid<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor : boost::static_visitor<bool>
+ {
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return is_valid<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check{is valid (in the OGC sense)}
+\ingroup is_valid
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is valid (in the OGC sense)}
+
+\qbk{[include reference/algorithms/is_valid.qbk]}
+*/
+template <typename Geometry>
+inline bool is_valid(Geometry const& geometry)
+{
+ return resolve_variant::is_valid<Geometry>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
new file mode 100644
index 0000000000..f9d926770e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
@@ -0,0 +1,144 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template
+<
+ typename Geometry,
+ order_selector Order = geometry::point_order<Geometry>::value,
+ typename Tag = typename tag<Geometry>::type
+>
+struct acceptable_operation
+{};
+
+template <typename Polygon>
+struct acceptable_operation<Polygon, counterclockwise, polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_union;
+};
+
+template <typename Polygon>
+struct acceptable_operation<Polygon, clockwise, polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_intersection;
+};
+
+template <typename MultiPolygon>
+struct acceptable_operation<MultiPolygon, counterclockwise, multi_polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_intersection;
+};
+
+template <typename MultiPolygon>
+struct acceptable_operation<MultiPolygon, clockwise, multi_polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_union;
+};
+
+
+
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct is_acceptable_turn
+{};
+
+template <typename Polygon>
+class is_acceptable_turn<Polygon, polygon_tag>
+{
+protected:
+ template <typename Turn, typename Method, typename Operation>
+ static inline bool check_turn(Turn const& turn,
+ Method method,
+ Operation operation)
+ {
+ return turn.method == method
+ && turn.operations[0].operation == operation
+ && turn.operations[1].operation == operation;
+ }
+
+
+public:
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ using namespace detail::overlay;
+
+ if ( turn.operations[0].seg_id.ring_index
+ == turn.operations[1].seg_id.ring_index )
+ {
+ return false;
+ }
+
+ operation_type const op = acceptable_operation<Polygon>::value;
+
+ return check_turn(turn, method_touch_interior, op)
+ || check_turn(turn, method_touch, op)
+ ;
+ }
+};
+
+template <typename MultiPolygon>
+class is_acceptable_turn<MultiPolygon, multi_polygon_tag>
+ : is_acceptable_turn<typename boost::range_value<MultiPolygon>::type>
+{
+private:
+ typedef typename boost::range_value<MultiPolygon>::type polygon;
+ typedef is_acceptable_turn<polygon> base;
+
+public:
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ using namespace detail::overlay;
+
+ if ( turn.operations[0].seg_id.multi_index
+ == turn.operations[1].seg_id.multi_index )
+ {
+ return base::apply(turn);
+ }
+
+ operation_type const op = acceptable_operation<MultiPolygon>::value;
+
+ return base::check_turn(turn, method_touch_interior, op)
+ || base::check_turn(turn, method_touch, op)
+ ;
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp
new file mode 100644
index 0000000000..244df9b035
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp
@@ -0,0 +1,125 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
+#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template <typename Linestring, bool AllowSpikes>
+struct is_valid_linestring
+{
+ static inline bool apply(Linestring const& linestring)
+ {
+ std::size_t num_distinct = detail::num_distinct_consecutive_points
+ <
+ Linestring,
+ 3u,
+ true,
+ not_equal_to<typename point_type<Linestring>::type>
+ >::apply(linestring);
+
+ if ( num_distinct < 2u )
+ {
+ return false;
+ }
+
+ return num_distinct == 2u
+ || AllowSpikes
+ || !has_spikes<Linestring, closed>::apply(linestring);
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A linestring is a curve.
+// A curve is 1-dimensional so it has to have at least two distinct
+// points.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+//
+// There is an option here as to whether spikes are allowed for linestrings;
+// here we pass this as an additional template parameter: allow_spikes
+// If allow_spikes is set to true, spikes are allowed, false otherwise.
+// By default, spikes are disallowed
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Linestring, bool AllowSpikes>
+struct is_valid<Linestring, linestring_tag, AllowSpikes>
+ : detail::is_valid::is_valid_linestring<Linestring, AllowSpikes>
+{};
+
+
+// A MultiLinestring is a MultiCurve
+// A MultiCurve is simple if all of its elements are simple and the
+// only intersections between any two elements occur at Points that
+// are on the boundaries of both elements.
+//
+// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
+template <typename MultiLinestring, bool AllowSpikes>
+struct is_valid<MultiLinestring, multi_linestring_tag, AllowSpikes>
+{
+ static inline bool apply(MultiLinestring const& multilinestring)
+ {
+ return detail::check_iterator_range
+ <
+ detail::is_valid::is_valid_linestring
+ <
+ typename boost::range_value<MultiLinestring>::type,
+ AllowSpikes
+ >,
+ false // do not allow empty multilinestring
+ >::apply(boost::begin(multilinestring),
+ boost::end(multilinestring));
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
new file mode 100644
index 0000000000..3d0ebb5f82
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
@@ -0,0 +1,297 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP
+
+#include <deque>
+#include <vector>
+
+#include <boost/iterator/filter_iterator.hpp>
+#include <boost/range.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/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template <typename MultiPolygon, bool AllowDuplicates>
+class is_valid_multipolygon
+ : is_valid_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ AllowDuplicates,
+ true // check only the validity of rings
+ >
+{
+private:
+ typedef is_valid_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ AllowDuplicates,
+ true
+ > base;
+
+
+
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline
+ bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ // collect all polygons that have turns
+ std::set<signed_index_type> multi_indices;
+ for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
+ {
+ multi_indices.insert(tit->operations[0].seg_id.multi_index);
+ multi_indices.insert(tit->operations[1].seg_id.multi_index);
+ }
+
+ // put polygon iterators without turns in a vector
+ std::vector<PolygonIterator> polygon_iterators;
+ signed_index_type multi_index = 0;
+ for (PolygonIterator it = polygons_first; it != polygons_beyond;
+ ++it, ++multi_index)
+ {
+ if ( multi_indices.find(multi_index) == multi_indices.end() )
+ {
+ polygon_iterators.push_back(it);
+ }
+ }
+
+ typename base::item_visitor visitor;
+
+ geometry::partition
+ <
+ geometry::model::box<typename point_type<MultiPolygon>::type>,
+ typename base::expand_box,
+ typename base::overlaps_box
+ >::apply(polygon_iterators, visitor);
+
+ return !visitor.items_overlap;
+ }
+
+
+
+ class has_multi_index
+ {
+ public:
+ has_multi_index(signed_index_type multi_index)
+ : m_multi_index(multi_index)
+ {}
+
+ template <typename Turn>
+ inline bool operator()(Turn const& turn) const
+ {
+ return turn.operations[0].seg_id.multi_index == m_multi_index
+ && turn.operations[1].seg_id.multi_index == m_multi_index;
+ }
+
+ private:
+ signed_index_type const m_multi_index;
+ };
+
+
+
+ template <typename Predicate>
+ struct has_property_per_polygon
+ {
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline bool apply(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ signed_index_type multi_index = 0;
+ for (PolygonIterator it = polygons_first; it != polygons_beyond;
+ ++it, ++multi_index)
+ {
+ has_multi_index index_predicate(multi_index);
+
+ typedef boost::filter_iterator
+ <
+ has_multi_index, TurnIterator
+ > filtered_turn_iterator;
+
+ filtered_turn_iterator filtered_turns_first(index_predicate,
+ turns_first,
+ turns_beyond);
+
+ filtered_turn_iterator filtered_turns_beyond(index_predicate,
+ turns_beyond,
+ turns_beyond);
+
+ if ( !Predicate::apply(*it,
+ filtered_turns_first,
+ filtered_turns_beyond) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+
+
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline bool have_holes_inside(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ return has_property_per_polygon
+ <
+ typename base::has_holes_inside
+ >::apply(polygons_first, polygons_beyond,
+ turns_first, turns_beyond);
+ }
+
+
+
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline bool have_connected_interior(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ return has_property_per_polygon
+ <
+ typename base::has_connected_interior
+ >::apply(polygons_first, polygons_beyond,
+ turns_first, turns_beyond);
+ }
+
+
+public:
+ static inline bool apply(MultiPolygon const& multipolygon)
+ {
+ typedef debug_validity_phase<MultiPolygon> debug_phase;
+
+ // check validity of all polygons ring
+ debug_phase::apply(1);
+
+ if ( !detail::check_iterator_range
+ <
+ base,
+ false // do not allow empty multi-polygons
+ >::apply(boost::begin(multipolygon),
+ boost::end(multipolygon)) )
+ {
+ return false;
+ }
+
+
+ // compute turns and check if all are acceptable
+ debug_phase::apply(2);
+
+ typedef has_valid_self_turns<MultiPolygon> has_valid_turns;
+
+ std::deque<typename has_valid_turns::turn_type> turns;
+ bool has_invalid_turns = !has_valid_turns::apply(multipolygon, turns);
+ debug_print_turns(turns.begin(), turns.end());
+
+ if ( has_invalid_turns )
+ {
+ return false;
+ }
+
+
+ // check if each polygon's interior rings are inside the
+ // exterior and not one inside the other
+ debug_phase::apply(3);
+
+ if ( !have_holes_inside(boost::begin(multipolygon),
+ boost::end(multipolygon),
+ turns.begin(),
+ turns.end()) )
+ {
+ return false;
+ }
+
+
+ // check that each polygon's interior is connected
+ debug_phase::apply(4);
+
+ if ( !have_connected_interior(boost::begin(multipolygon),
+ boost::end(multipolygon),
+ turns.begin(),
+ turns.end()) )
+ {
+ return false;
+ }
+
+
+ // check if polygon interiors are disjoint
+ debug_phase::apply(5);
+ return are_polygon_interiors_disjoint(boost::begin(multipolygon),
+ boost::end(multipolygon),
+ turns.begin(),
+ turns.end());
+ }
+};
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Not clear what the definition is.
+// Right now we check that each element is simple (in fact valid), and
+// that the MultiPolygon is also valid.
+//
+// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14)
+template <typename MultiPolygon, bool AllowSpikes, bool AllowDuplicates>
+struct is_valid<MultiPolygon, multi_polygon_tag, AllowSpikes, AllowDuplicates>
+ : detail::is_valid::is_valid_multipolygon<MultiPolygon, AllowDuplicates>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp
new file mode 100644
index 0000000000..8a4818ef15
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp
@@ -0,0 +1,62 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// A point is always simple
+template <typename Point>
+struct is_valid<Point, point_tag>
+{
+ static inline bool apply(Point const&)
+ {
+ return true;
+ }
+};
+
+
+
+// A MultiPoint is simple if no two Points in the MultiPoint are equal
+// (have identical coordinate values in X and Y)
+//
+// Reference: OGC 06-103r4 (6.1.5)
+template <typename MultiPoint>
+struct is_valid<MultiPoint, multi_point_tag>
+{
+ static inline bool apply(MultiPoint const& multipoint)
+ {
+ return boost::size(multipoint) > 0;
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
new file mode 100644
index 0000000000..3a91999208
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
@@ -0,0 +1,376 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
+
+#include <cstddef>
+
+#include <algorithm>
+#include <deque>
+#include <iterator>
+#include <set>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.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/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template
+<
+ typename Polygon,
+ bool AllowDuplicates,
+ bool CheckRingValidityOnly = false
+>
+class is_valid_polygon
+{
+protected:
+ typedef debug_validity_phase<Polygon> debug_phase;
+
+
+
+ template <typename InteriorRings>
+ static bool has_valid_interior_rings(InteriorRings const& interior_rings)
+ {
+ return
+ detail::check_iterator_range
+ <
+ detail::is_valid::is_valid_ring
+ <
+ typename boost::range_value<InteriorRings>::type,
+ AllowDuplicates,
+ false, // do not check self-intersections
+ true // indicate that the ring is interior
+ >
+ >::apply(boost::begin(interior_rings),
+ boost::end(interior_rings));
+ }
+
+ struct has_valid_rings
+ {
+ static inline bool apply(Polygon const& polygon)
+ {
+ typedef typename ring_type<Polygon>::type ring_type;
+
+ // check validity of exterior ring
+ debug_phase::apply(1);
+
+ if ( !detail::is_valid::is_valid_ring
+ <
+ ring_type,
+ AllowDuplicates,
+ false // do not check self intersections
+ >::apply(exterior_ring(polygon)) )
+ {
+ return false;
+ }
+
+ // check validity of interior rings
+ debug_phase::apply(2);
+
+ return has_valid_interior_rings(geometry::interior_rings(polygon));
+ }
+ };
+
+
+ // structs from partition -- start
+ struct expand_box
+ {
+ template <typename Box, typename Iterator>
+ static inline void apply(Box& total, Iterator const& it)
+ {
+ geometry::expand(total, geometry::return_envelope<Box>(*it));
+ }
+
+ };
+
+ struct overlaps_box
+ {
+ template <typename Box, typename Iterator>
+ static inline bool apply(Box const& box, Iterator const& it)
+ {
+ return !geometry::disjoint(*it, box);
+ }
+ };
+
+
+ struct item_visitor
+ {
+ bool items_overlap;
+
+ item_visitor() : items_overlap(false) {}
+
+ template <typename Item1, typename Item2>
+ inline void apply(Item1 const& item1, Item2 const& item2)
+ {
+ if ( !items_overlap
+ && (geometry::within(*points_begin(*item1), *item2)
+ || geometry::within(*points_begin(*item2), *item1))
+ )
+ {
+ items_overlap = true;
+ }
+ }
+ };
+ // structs for partition -- end
+
+
+ template
+ <
+ typename RingIterator,
+ typename ExteriorRing,
+ typename TurnIterator
+ >
+ static inline bool are_holes_inside(RingIterator rings_first,
+ RingIterator rings_beyond,
+ ExteriorRing const& exterior_ring,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ // collect the interior ring indices that have turns with the
+ // exterior ring
+ std::set<signed_index_type> ring_indices;
+ for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
+ {
+ if ( tit->operations[0].seg_id.ring_index == -1 )
+ {
+ BOOST_ASSERT( tit->operations[1].seg_id.ring_index != -1 );
+ ring_indices.insert(tit->operations[1].seg_id.ring_index);
+ }
+ else if ( tit->operations[1].seg_id.ring_index == -1 )
+ {
+ BOOST_ASSERT( tit->operations[0].seg_id.ring_index != -1 );
+ ring_indices.insert(tit->operations[0].seg_id.ring_index);
+ }
+ }
+
+ signed_index_type ring_index = 0;
+ for (RingIterator it = rings_first; it != rings_beyond;
+ ++it, ++ring_index)
+ {
+ // do not examine interior rings that have turns with the
+ // exterior ring
+ if ( ring_indices.find(ring_index) == ring_indices.end()
+ && !geometry::covered_by(range::front(*it), exterior_ring) )
+ {
+ return false;
+ }
+ }
+
+ // collect all rings (exterior and/or interior) that have turns
+ for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
+ {
+ ring_indices.insert(tit->operations[0].seg_id.ring_index);
+ ring_indices.insert(tit->operations[1].seg_id.ring_index);
+ }
+
+ // put iterators for interior rings without turns in a vector
+ std::vector<RingIterator> ring_iterators;
+ ring_index = 0;
+ for (RingIterator it = rings_first; it != rings_beyond;
+ ++it, ++ring_index)
+ {
+ if ( ring_indices.find(ring_index) == ring_indices.end() )
+ {
+ ring_iterators.push_back(it);
+ }
+ }
+
+ // call partition to check is interior rings are disjoint from
+ // each other
+ item_visitor visitor;
+
+ geometry::partition
+ <
+ geometry::model::box<typename point_type<Polygon>::type>,
+ expand_box,
+ overlaps_box
+ >::apply(ring_iterators, visitor);
+
+ return !visitor.items_overlap;
+ }
+
+ template
+ <
+ typename InteriorRings,
+ typename ExteriorRing,
+ typename TurnIterator
+ >
+ static inline bool are_holes_inside(InteriorRings const& interior_rings,
+ ExteriorRing const& exterior_ring,
+ TurnIterator first,
+ TurnIterator beyond)
+ {
+ return are_holes_inside(boost::begin(interior_rings),
+ boost::end(interior_rings),
+ exterior_ring,
+ first,
+ beyond);
+ }
+
+ struct has_holes_inside
+ {
+ template <typename TurnIterator>
+ static inline bool apply(Polygon const& polygon,
+ TurnIterator first,
+ TurnIterator beyond)
+ {
+ return are_holes_inside(geometry::interior_rings(polygon),
+ geometry::exterior_ring(polygon),
+ first,
+ beyond);
+ }
+ };
+
+
+
+
+ struct has_connected_interior
+ {
+ template <typename TurnIterator>
+ static inline bool apply(Polygon const& polygon,
+ TurnIterator first,
+ TurnIterator beyond)
+ {
+ typedef typename std::iterator_traits
+ <
+ TurnIterator
+ >::value_type turn_type;
+ typedef complement_graph<typename turn_type::point_type> graph;
+
+ graph g(geometry::num_interior_rings(polygon) + 1);
+ for (TurnIterator tit = first; tit != beyond; ++tit)
+ {
+ typename graph::vertex_handle v1 = g.add_vertex
+ ( tit->operations[0].seg_id.ring_index + 1 );
+ typename graph::vertex_handle v2 = g.add_vertex
+ ( tit->operations[1].seg_id.ring_index + 1 );
+ typename graph::vertex_handle vip = g.add_vertex(tit->point);
+
+ g.add_edge(v1, vip);
+ g.add_edge(v2, vip);
+ }
+
+ debug_print_complement_graph(std::cout, g);
+
+ return !g.has_cycles();
+ }
+ };
+
+public:
+ static inline bool apply(Polygon const& polygon)
+ {
+ if ( !has_valid_rings::apply(polygon) )
+ {
+ return false;
+ }
+
+ if ( CheckRingValidityOnly )
+ {
+ return true;
+ }
+
+ // compute turns and check if all are acceptable
+ debug_phase::apply(3);
+
+ typedef has_valid_self_turns<Polygon> has_valid_turns;
+
+ std::deque<typename has_valid_turns::turn_type> turns;
+ bool has_invalid_turns = !has_valid_turns::apply(polygon, turns);
+ debug_print_turns(turns.begin(), turns.end());
+
+ if ( has_invalid_turns )
+ {
+ return false;
+ }
+
+ // check if all interior rings are inside the exterior ring
+ debug_phase::apply(4);
+
+ if ( !has_holes_inside::apply(polygon, turns.begin(), turns.end()) )
+ {
+ return false;
+ }
+
+ // check whether the interior of the polygon is a connected set
+ debug_phase::apply(5);
+
+ return has_connected_interior::apply(polygon,
+ turns.begin(),
+ turns.end());
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A Polygon is always a simple geometric object provided that it is valid.
+//
+// Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1)
+template <typename Polygon, bool AllowSpikes, bool AllowDuplicates>
+struct is_valid<Polygon, polygon_tag, AllowSpikes, AllowDuplicates>
+ : detail::is_valid::is_valid_polygon<Polygon, AllowDuplicates>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp
new file mode 100644
index 0000000000..c88df79b05
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp
@@ -0,0 +1,173 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/point_order.hpp>
+
+#include <boost/geometry/util/order_as_direction.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+
+#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+
+#include <boost/geometry/strategies/area.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+// struct to check whether a ring is topologically closed
+template <typename Ring, closure_selector Closure /* open */>
+struct is_topologically_closed
+{
+ static inline bool apply(Ring const&)
+ {
+ return true;
+ }
+};
+
+template <typename Ring>
+struct is_topologically_closed<Ring, closed>
+{
+ static inline bool apply(Ring const& ring)
+ {
+ return geometry::equals(range::front(ring), range::back(ring));
+ }
+};
+
+
+
+template <typename ResultType, bool IsInteriorRing /* false */>
+struct ring_area_predicate
+{
+ typedef std::greater<ResultType> type;
+};
+
+template <typename ResultType>
+struct ring_area_predicate<ResultType, true>
+{
+ typedef std::less<ResultType> type;
+};
+
+
+
+template <typename Ring, bool IsInteriorRing>
+struct is_properly_oriented
+{
+ typedef typename point_type<Ring>::type point_type;
+
+ typedef typename strategy::area::services::default_strategy
+ <
+ typename cs_tag<point_type>::type,
+ point_type
+ >::type strategy_type;
+
+ typedef detail::area::ring_area
+ <
+ order_as_direction<geometry::point_order<Ring>::value>::value,
+ geometry::closure<Ring>::value
+ > ring_area_type;
+
+ typedef typename default_area_result<Ring>::type area_result_type;
+
+ static inline bool apply(Ring const& ring)
+ {
+ typename ring_area_predicate
+ <
+ area_result_type, IsInteriorRing
+ >::type predicate;
+
+ // Check area
+ area_result_type const zero = area_result_type();
+ return predicate(ring_area_type::apply(ring, strategy_type()), zero);
+ }
+};
+
+
+
+template
+<
+ typename Ring,
+ bool AllowDuplicates,
+ bool CheckSelfIntersections = true,
+ bool IsInteriorRing = false
+>
+struct is_valid_ring
+{
+ static inline bool apply(Ring const& ring)
+ {
+ // return invalid if any of the following condition holds:
+ // (a) the ring's size is below the minimal one
+ // (b) the ring is not topologically closed
+ // (c) the ring has spikes
+ // (d) the ring has duplicate points (if AllowDuplicates is false)
+ // (e) the boundary of the ring has self-intersections
+ // (f) the order of the points is inconsistent with the defined order
+ //
+ // Note: no need to check if the area is zero. If this is the
+ // case, then the ring must have at least two spikes, which is
+ // checked by condition (c).
+
+ closure_selector const closure = geometry::closure<Ring>::value;
+
+ return
+ ( boost::size(ring)
+ >= core_detail::closure::minimum_ring_size<closure>::value )
+ && is_topologically_closed<Ring, closure>::apply(ring)
+ && (AllowDuplicates || !has_duplicates<Ring, closure>::apply(ring))
+ && !has_spikes<Ring, closure>::apply(ring)
+ && !(CheckSelfIntersections && geometry::intersects(ring))
+ && is_properly_oriented<Ring, IsInteriorRing>::apply(ring);
+ }
+};
+
+
+}} // namespace dispatch
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// A Ring is a Polygon with exterior boundary only.
+// The Ring's boundary must be a LinearRing (see OGC 06-103-r4,
+// 6.1.7.1, for the definition of LinearRing)
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Ring, bool AllowSpikes, bool AllowDuplicates>
+struct is_valid<Ring, ring_tag, AllowSpikes, AllowDuplicates>
+ : detail::is_valid::is_valid_ring<Ring, AllowDuplicates>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/segment.hpp b/boost/geometry/algorithms/detail/is_valid/segment.hpp
new file mode 100644
index 0000000000..486289dabe
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/segment.hpp
@@ -0,0 +1,61 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/equals.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A segment is a curve.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+// A curve is 1-dimensional, hence we have to check is the two
+// endpoints of the segment coincide, since in this case it is
+// 0-dimensional.
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Segment>
+struct is_valid<Segment, segment_tag>
+{
+ static inline bool apply(Segment const& segment)
+ {
+ typename point_type<Segment>::type p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ return !geometry::equals(p[0], p[1]);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
diff --git a/boost/geometry/algorithms/detail/multi_modify.hpp b/boost/geometry/algorithms/detail/multi_modify.hpp
new file mode 100644
index 0000000000..f0b9ddd3e6
--- /dev/null
+++ b/boost/geometry/algorithms/detail/multi_modify.hpp
@@ -0,0 +1,53 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP
+
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+
+template <typename MultiGeometry, typename Policy>
+struct multi_modify
+{
+ static inline void apply(MultiGeometry& multi)
+ {
+ typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it);
+ }
+ }
+};
+
+
+} // namespace detail
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP
diff --git a/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp b/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp
new file mode 100644
index 0000000000..c3787f9a10
--- /dev/null
+++ b/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp
@@ -0,0 +1,52 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP
+
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename MultiGeometry, typename Predicate, typename Policy>
+struct multi_modify_with_predicate
+{
+ static inline void apply(MultiGeometry& multi, Predicate const& predicate)
+ {
+ typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, predicate);
+ }
+ }
+};
+
+
+} // namespace detail
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP
diff --git a/boost/geometry/algorithms/detail/multi_sum.hpp b/boost/geometry/algorithms/detail/multi_sum.hpp
new file mode 100644
index 0000000000..af3f425c9c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/multi_sum.hpp
@@ -0,0 +1,52 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+struct multi_sum
+{
+ template <typename ReturnType, typename Policy, typename MultiGeometry, typename Strategy>
+ static inline ReturnType apply(MultiGeometry const& geometry, Strategy const& strategy)
+ {
+ ReturnType sum = ReturnType();
+ for (typename boost::range_iterator
+ <
+ MultiGeometry const
+ >::type it = boost::begin(geometry);
+ it != boost::end(geometry);
+ ++it)
+ {
+ sum += Policy::apply(*it, strategy);
+ }
+ return sum;
+ }
+};
+
+
+} // namespace detail
+#endif
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP
diff --git a/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp
new file mode 100644
index 0000000000..16fba72fe0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp
@@ -0,0 +1,93 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP
+
+#include <cstddef>
+
+#include <algorithm>
+
+#include <boost/range.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+
+// returns the number of distinct values in the range;
+// return values are 0u through MaximumNumber, where MaximumNumber
+// corresponds to MaximumNumber or more distinct values
+//
+// FUTURE: take into account topologically closed ranges;
+// add appropriate template parameter(s) to control whether
+// the closing point for topologically closed ranges is to be
+// accounted for separately or not
+template
+<
+ typename Range,
+ std::size_t MaximumNumber,
+ bool AllowDuplicates /* true */,
+ typename NotEqualTo
+>
+struct num_distinct_consecutive_points
+{
+ static inline std::size_t apply(Range const& range)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ std::size_t const size = boost::size(range);
+
+ if ( size < 2u )
+ {
+ return (size < MaximumNumber) ? size : MaximumNumber;
+ }
+
+ iterator current = boost::begin(range);
+ std::size_t counter(0);
+ do
+ {
+ ++counter;
+ iterator next = std::find_if(current,
+ boost::end(range),
+ NotEqualTo(*current));
+ current = next;
+ }
+ while ( current != boost::end(range) && counter <= MaximumNumber );
+
+ return counter;
+ }
+};
+
+
+template <typename Range, std::size_t MaximumNumber, typename NotEqualTo>
+struct num_distinct_consecutive_points<Range, MaximumNumber, false, NotEqualTo>
+{
+ static inline std::size_t apply(Range const& range)
+ {
+ std::size_t const size = boost::size(range);
+ return (size < MaximumNumber) ? size : MaximumNumber;
+ }
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp
index e147ba12d8..d90f3cf7cf 100644
--- a/boost/geometry/algorithms/detail/occupation_info.hpp
+++ b/boost/geometry/algorithms/detail/occupation_info.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2012-2014 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
@@ -9,17 +9,13 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
-#if ! defined(NDEBUG)
- #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
-#endif
-
#include <algorithm>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/iterators/closing_iterator.hpp>
#include <boost/geometry/algorithms/detail/get_left_turns.hpp>
@@ -33,291 +29,159 @@ namespace boost { namespace geometry
namespace detail
{
-template <typename P>
-class relaxed_less
-{
- typedef typename geometry::coordinate_type<P>::type coordinate_type;
-
- coordinate_type epsilon;
-
-public :
-
- inline relaxed_less()
- {
- // TODO: adapt for ttmath, and maybe build the map in another way
- // (e.g. exact constellations of segment-id's), maybe adaptive.
- epsilon = std::numeric_limits<double>::epsilon() * 100.0;
- }
-
- inline bool operator()(P const& a, P const& b) const
- {
- coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
- coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
-
-
- if (dx < epsilon && dy < epsilon)
- {
- return false;
- }
- if (dx < epsilon)
- {
- return geometry::get<1>(a) < geometry::get<1>(b);
- }
-
- return geometry::get<0>(a) < geometry::get<0>(b);
- }
-
- inline bool equals(P const& a, P const& b) const
- {
- typedef typename geometry::coordinate_type<P>::type coordinate_type;
-
- coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
- coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
-
- return dx < epsilon && dy < epsilon;
- };
-};
-
-
-template <typename T, typename P1, typename P2>
-inline T calculate_angle(P1 const& from_point, P2 const& to_point)
-{
- typedef P1 vector_type;
- vector_type v = from_point;
- geometry::subtract_point(v, to_point);
- return atan2(geometry::get<1>(v), geometry::get<0>(v));
-}
-
-template <typename Iterator, typename Vector>
-inline Iterator advance_circular(Iterator it, Vector const& vector, segment_identifier& seg_id, bool forward = true)
-{
- int const increment = forward ? 1 : -1;
- if (it == boost::begin(vector) && increment < 0)
- {
- it = boost::end(vector);
- seg_id.segment_index = boost::size(vector);
- }
- it += increment;
- seg_id.segment_index += increment;
- if (it == boost::end(vector))
- {
- seg_id.segment_index = 0;
- it = boost::begin(vector);
- }
- return it;
-}
-
template <typename Point, typename T>
struct angle_info
{
- typedef T angle_type;
+ typedef T angle_type;
typedef Point point_type;
segment_identifier seg_id;
int turn_index;
int operation_index;
+ std::size_t cluster_index;
Point intersection_point;
- Point direction_point;
- T angle;
+ Point point; // either incoming or outgoing point
bool incoming;
+ bool blocked;
+ bool included;
+
+ inline angle_info()
+ : blocked(false)
+ , included(false)
+ {}
};
template <typename AngleInfo>
class occupation_info
{
- typedef std::vector<AngleInfo> collection_type;
-
- struct angle_sort
- {
- inline bool operator()(AngleInfo const& left, AngleInfo const& right) const
- {
- // In this case we can compare even double using equals
- // return geometry::math::equals(left.angle, right.angle)
- return left.angle == right.angle
- ? int(left.incoming) < int(right.incoming)
- : left.angle < right.angle
- ;
- }
- };
-
-public :
- collection_type angles;
-private :
- bool m_occupied;
- bool m_calculated;
-
- inline bool is_occupied()
- {
- if (boost::size(angles) <= 1)
- {
- return false;
- }
-
- std::sort(angles.begin(), angles.end(), angle_sort());
-
- typedef geometry::closing_iterator<collection_type const> closing_iterator;
- closing_iterator vit(angles);
- closing_iterator end(angles, true);
-
- closing_iterator prev = vit++;
- for( ; vit != end; prev = vit++)
- {
- if (! geometry::math::equals(prev->angle, vit->angle)
- && ! prev->incoming
- && vit->incoming)
- {
- return false;
- }
- }
- return true;
- }
-
public :
- inline occupation_info()
- : m_occupied(false)
- , m_calculated(false)
- {}
+ typedef std::vector<AngleInfo> collection_type;
- template <typename PointC, typename Point1, typename Point2>
- inline void add(PointC const& map_point, Point1 const& direction_point, Point2 const& intersection_point,
+ template <typename RobustPoint>
+ inline void add(RobustPoint const& incoming_point,
+ RobustPoint const& outgoing_point,
+ RobustPoint const& intersection_point,
int turn_index, int operation_index,
- segment_identifier const& seg_id, bool incoming)
- {
- //std::cout << "-> adding angle " << geometry::wkt(direction_point) << " .. " << geometry::wkt(intersection_point) << " " << int(incoming) << std::endl;
- if (geometry::equals(direction_point, intersection_point))
- {
- //std::cout << "EQUAL! Skipping" << std::endl;
- return;
- }
+ segment_identifier const& seg_id)
+ {
+ geometry::equal_to<RobustPoint> comparator;
+ if (comparator(incoming_point, intersection_point))
+ {
+ return;
+ }
+ if (comparator(outgoing_point, intersection_point))
+ {
+ return;
+ }
AngleInfo info;
- info.incoming = incoming;
- info.angle = calculate_angle<typename AngleInfo::angle_type>(direction_point, map_point);
info.seg_id = seg_id;
info.turn_index = turn_index;
info.operation_index = operation_index;
info.intersection_point = intersection_point;
- info.direction_point = direction_point;
- angles.push_back(info);
-
- m_calculated = false;
- }
-
- inline bool occupied()
- {
- if (! m_calculated)
- {
- m_occupied = is_occupied();
- m_calculated = true;
- }
- return m_occupied;
- }
-
- template <typename Turns, typename TurnSegmentIndices>
- inline void get_left_turns(
- Turns& turns, TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& keep_indices)
- {
- std::sort(angles.begin(), angles.end(), angle_sort());
- calculate_left_turns<AngleInfo>(angles, turns, turn_segment_indices, keep_indices);
- }
-};
-
-
-template <typename Point, typename Ring, typename Info>
-inline void add_incoming_and_outgoing_angles(Point const& map_point, Point const& intersection_point,
- Ring const& ring,
- int turn_index,
- int operation_index,
- segment_identifier seg_id,
- Info& info)
-{
- typedef typename boost::range_iterator
- <
- Ring const
- >::type iterator_type;
-
- int const n = boost::size(ring);
- if (seg_id.segment_index >= n || seg_id.segment_index < 0)
- {
- return;
- }
-
- segment_identifier real_seg_id = seg_id;
- iterator_type it = boost::begin(ring) + seg_id.segment_index;
- // TODO: if we use turn-info ("to", "middle"), we know if to advance without resorting to equals
- relaxed_less<Point> comparator;
+ {
+ info.point = incoming_point;
+ info.incoming = true;
+ m_angles.push_back(info);
+ }
+ {
+ info.point = outgoing_point;
+ info.incoming = false;
+ m_angles.push_back(info);
+ }
+ }
- if (comparator.equals(intersection_point, *it))
+ template <typename RobustPoint, typename Turns>
+ inline void get_left_turns(RobustPoint const& origin, Turns& turns)
{
- // It should be equal only once. But otherwise we skip it (in "add")
- it = advance_circular(it, ring, seg_id, false);
+ // Sort on angle
+ std::sort(m_angles.begin(), m_angles.end(),
+ detail::left_turns::angle_less<typename AngleInfo::point_type>(origin));
+
+ // Group same-angled elements
+ std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin);
+ // Block all turns on the right side of any turn
+ detail::left_turns::block_turns(m_angles, cluster_size);
+ detail::left_turns::get_left_turns(m_angles, turns);
}
- info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, true);
-
- if (comparator.equals(intersection_point, *it))
- {
- it = advance_circular(it, ring, real_seg_id);
- }
- else
- {
- // Don't upgrade the ID
- it = advance_circular(it, ring, seg_id);
- }
- for (int defensive_check = 0;
- comparator.equals(intersection_point, *it) && defensive_check < n;
- defensive_check++)
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ template <typename RobustPoint>
+ inline bool has_rounding_issues(RobustPoint const& origin) const
{
- it = advance_circular(it, ring, real_seg_id);
+ return detail::left_turns::has_rounding_issues(angles, origin);
}
+#endif
- info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false);
-}
-
+private :
+ collection_type m_angles; // each turn splitted in incoming/outgoing vectors
+};
-// Map in two senses of the word: it is a std::map where the key is a point.
-// Per point an "occupation_info" record is kept
-// Used for the buffer (but will also be used for intersections/unions having complex self-tangencies)
-template <typename Point, typename OccupationInfo>
-class occupation_map
+template<typename Pieces>
+inline void move_index(Pieces const& pieces, int& index, int& piece_index, int direction)
{
-public :
- typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type;
+ BOOST_ASSERT(direction == 1 || direction == -1);
+ BOOST_ASSERT(piece_index >= 0 && piece_index < static_cast<int>(boost::size(pieces)) );
+ BOOST_ASSERT(index >= 0 && index < static_cast<int>(boost::size(pieces[piece_index].robust_ring)));
- map_type map;
- std::set<int> turn_indices;
-
- inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point)
+ index += direction;
+ if (direction == -1 && index < 0)
{
- typename map_type::iterator it = map.find(point);
- if (it == boost::end(map))
+ piece_index--;
+ if (piece_index < 0)
{
- std::pair<typename map_type::iterator, bool> pair
- = map.insert(std::make_pair(point, OccupationInfo()));
- it = pair.first;
+ piece_index = boost::size(pieces) - 1;
}
- mapped_point = it->first;
- return it->second;
+ index = boost::size(pieces[piece_index].robust_ring) - 1;
}
-
- inline bool contains(Point const& point) const
+ if (direction == 1
+ && index >= static_cast<int>(boost::size(pieces[piece_index].robust_ring)))
{
- typename map_type::const_iterator it = map.find(point);
- return it != boost::end(map);
+ piece_index++;
+ if (piece_index >= static_cast<int>(boost::size(pieces)))
+ {
+ piece_index = 0;
+ }
+ index = 0;
}
+}
- inline bool contains_turn_index(int index) const
- {
- return turn_indices.count(index) > 0;
- }
- inline void insert_turn_index(int index)
+template
+<
+ typename RobustPoint,
+ typename Turn,
+ typename Pieces,
+ typename Info
+>
+inline void add_incoming_and_outgoing_angles(
+ RobustPoint const& intersection_point, // rescaled
+ Turn const& turn,
+ Pieces const& pieces, // using rescaled offsets of it
+ int operation_index,
+ segment_identifier seg_id,
+ Info& info)
+{
+ segment_identifier real_seg_id = seg_id;
+ geometry::equal_to<RobustPoint> comparator;
+
+ // Move backward and forward
+ RobustPoint direction_points[2];
+ for (int i = 0; i < 2; i++)
{
- turn_indices.insert(index);
+ int index = turn.operations[operation_index].index_in_robust_ring;
+ int piece_index = turn.operations[operation_index].piece_index;
+ while(comparator(pieces[piece_index].robust_ring[index], intersection_point))
+ {
+ move_index(pieces, index, piece_index, i == 0 ? -1 : 1);
+ }
+ direction_points[i] = pieces[piece_index].robust_ring[index];
}
-};
+
+ info.add(direction_points[0], direction_points[1], intersection_point,
+ turn.turn_index, operation_index, real_seg_id);
+}
} // namespace detail
diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
index 74595fedd0..5ff0b57d6e 100644
--- a/boost/geometry/algorithms/detail/overlay/add_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
@@ -75,15 +75,15 @@ inline OutputIterator add_rings(SelectionMap const& map,
OutputIterator out)
{
typedef typename SelectionMap::const_iterator iterator;
- typedef typename SelectionMap::mapped_type property_type;
- typedef typename property_type::area_type area_type;
-
- area_type const zero = 0;
- std::size_t const min_num_points = core_detail::closure::minimum_ring_size
- <
- geometry::closure
- <
- typename boost::range_value
+ typedef typename SelectionMap::mapped_type property_type;
+ typedef typename property_type::area_type area_type;
+
+ area_type const zero = 0;
+ std::size_t const min_num_points = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure
+ <
+ typename boost::range_value
<
RingCollection const
>::type
@@ -117,15 +117,14 @@ inline OutputIterator add_rings(SelectionMap const& map,
}
}
- // Only add rings if they satisfy minimal requirements.
- // This cannot be done earlier (during traversal), not
- // everything is figured out yet (sum of positive/negative rings)
- // TODO: individual rings can still contain less than 3 points.
- if (geometry::num_points(result) >= min_num_points
- && math::larger(geometry::area(result), zero))
- {
- *out++ = result;
- }
+ // Only add rings if they satisfy minimal requirements.
+ // This cannot be done earlier (during traversal), not
+ // everything is figured out yet (sum of positive/negative rings)
+ if (geometry::num_points(result) >= min_num_points
+ && math::larger(geometry::area(result), zero))
+ {
+ *out++ = result;
+ }
}
}
return out;
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
index 2c0f88e2aa..0fd1fe4de9 100644
--- a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
+++ b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
@@ -13,7 +13,7 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/append.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
@@ -29,7 +29,7 @@ template <typename Range, typename Point>
inline void append_no_duplicates(Range& range, Point const& point, bool force = false)
{
if (boost::size(range) == 0
- || force
+ || force
|| ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point))
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
new file mode 100644
index 0000000000..d44db17ad3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
@@ -0,0 +1,160 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// TODO: move this / rename this
+template <typename Point1, typename Point2, typename RobustPolicy>
+inline bool points_equal_or_close(Point1 const& point1,
+ Point2 const& point2,
+ RobustPolicy const& robust_policy)
+{
+ if (detail::equals::equals_point_point(point1, point2))
+ {
+ return true;
+ }
+
+ if (! RobustPolicy::enabled)
+ {
+ return false;
+ }
+
+ // Try using specified robust policy
+ typedef typename geometry::robust_point_type
+ <
+ Point1,
+ RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type point1_rob, point2_rob;
+ geometry::recalculate(point1_rob, point1, robust_policy);
+ geometry::recalculate(point2_rob, point2, robust_policy);
+
+ return detail::equals::equals_point_point(point1_rob, point2_rob);
+}
+
+
+template <typename Range, typename Point, typename RobustPolicy>
+inline void append_no_dups_or_spikes(Range& range, Point const& point,
+ RobustPolicy const& robust_policy)
+{
+#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
+ std::cout << " add: ("
+ << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")"
+ << std::endl;
+#endif
+ // The code below thies condition checks all spikes/dups
+ // for geometries >= 3 points.
+ // So we have to check the first potential duplicate differently
+ if (boost::size(range) == 1
+ && points_equal_or_close(*(boost::begin(range)), point, robust_policy))
+ {
+ return;
+ }
+
+ traits::push_back<Range>::apply(range, point);
+
+ // If a point is equal, or forming a spike, remove the pen-ultimate point
+ // because this one caused the spike.
+ // If so, the now-new-pen-ultimate point can again cause a spike
+ // (possibly at a corner). So keep doing this.
+ // Besides spikes it will also avoid adding duplicates.
+ while(boost::size(range) >= 3
+ && point_is_spike_or_equal(point,
+ *(boost::end(range) - 3),
+ *(boost::end(range) - 2),
+ robust_policy))
+ {
+ // Use the Concept/traits, so resize and append again
+ traits::resize<Range>::apply(range, boost::size(range) - 2);
+ traits::push_back<Range>::apply(range, point);
+ }
+}
+
+template <typename Range, typename RobustPolicy>
+inline void clean_closing_dups_and_spikes(Range& range,
+ RobustPolicy const& robust_policy)
+{
+ std::size_t const minsize
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Range>::value
+ >::value;
+
+ if (boost::size(range) <= minsize)
+ {
+ return;
+ }
+
+ typedef typename boost::range_iterator<Range>::type iterator_type;
+ static bool const closed = geometry::closure<Range>::value == geometry::closed;
+
+// TODO: the following algorithm could be rewritten to first look for spikes
+// and then erase some number of points from the beginning of the Range
+
+ bool found = false;
+ do
+ {
+ found = false;
+ iterator_type first = boost::begin(range);
+ iterator_type second = first + 1;
+ iterator_type ultimate = boost::end(range) - 1;
+ if (closed)
+ {
+ ultimate--;
+ }
+
+ // Check if closing point is a spike (this is so if the second point is
+ // considered as a spike w.r.t. the last segment)
+ if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
+ {
+ range::erase(range, first);
+ if (closed)
+ {
+ // Remove closing last point
+ range::resize(range, boost::size(range) - 1);
+ // Add new closing point
+ range::push_back(range, range::front(range));
+ }
+ found = true;
+ }
+ } while(found && boost::size(range) > minsize);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
index 5063f49eb4..67b48cc471 100644
--- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -18,6 +18,10 @@
#include <boost/geometry/geometries/box.hpp>
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+# include <boost/timer.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -123,30 +127,30 @@ struct assign_visitor
template <typename Item>
inline void apply(Item const& outer, Item const& inner, bool first = true)
{
- if (first && outer.real_area < 0)
+ if (first && outer.abs_area < inner.abs_area)
{
- // Reverse arguments
+ // Apply with reversed arguments
apply(inner, outer, false);
return;
}
- if (math::larger(outer.real_area, 0))
+ if (m_check_for_orientation
+ || (math::larger(outer.real_area, 0)
+ && math::smaller(inner.real_area, 0)))
{
- if (inner.real_area < 0 || m_check_for_orientation)
- {
- ring_info_type& inner_in_map = m_ring_map[inner.id];
+ ring_info_type& inner_in_map = m_ring_map[inner.id];
- if (geometry::within(inner_in_map.point, outer.envelope)
- && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
- )
+ if (geometry::within(inner_in_map.point, outer.envelope)
+ && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
+ )
+ {
+ // Assign a parent if there was no earlier parent, or the newly
+ // found parent is smaller than the previous one
+ if (inner_in_map.parent.source_index == -1
+ || outer.abs_area < inner_in_map.parent_area)
{
- // Only assign parent if that parent is smaller (or if it is the first)
- if (inner_in_map.parent.source_index == -1
- || outer.abs_area < inner_in_map.parent_area)
- {
- inner_in_map.parent = outer.id;
- inner_in_map.parent_area = outer.abs_area;
- }
+ inner_in_map.parent = outer.id;
+ inner_in_map.parent_area = outer.abs_area;
}
}
}
@@ -243,7 +247,7 @@ inline void assign_parents(Geometry1 const& geometry1,
// a dramatic improvement (factor 5 for star_comb testcase)
ring_identifier id_of_positive = vector[index_positive].id;
ring_info_type& outer = ring_map[id_of_positive];
- std::size_t index = 0;
+ index = 0;
for (vector_iterator_type it = boost::begin(vector);
it != boost::end(vector); ++it, ++index)
{
@@ -284,13 +288,21 @@ inline void assign_parents(Geometry1 const& geometry1,
{
it->second.discarded = true;
}
- else if (it->second.parent.source_index >= 0 && it->second.get_area() > 0)
+ else if (it->second.parent.source_index >= 0
+ && math::larger(it->second.get_area(), 0))
{
- // Discard positive inner ring with parent
- it->second.discarded = true;
+ const ring_info_type& parent = ring_map[it->second.parent];
+
+ if (math::larger(parent.area, 0))
+ {
+ // Discard positive inner ring with positive parent
+ it->second.discarded = true;
+ }
+ // Remove parent ID from any positive inner ring
it->second.parent.source_index = -1;
}
- else if (it->second.parent.source_index < 0 && it->second.get_area() < 0)
+ else if (it->second.parent.source_index < 0
+ && math::smaller(it->second.get_area(), 0))
{
// Reverse negative ring without parent
it->second.reversed = true;
@@ -309,6 +321,8 @@ inline void assign_parents(Geometry1 const& geometry1,
}
}
+
+// Version for one geometry (called by buffer)
template
<
typename Geometry,
@@ -320,7 +334,7 @@ inline void assign_parents(Geometry const& geometry,
RingMap& ring_map,
bool check_for_orientation)
{
- // Call it with an empty geometry
+ // Call it with an empty geometry as second geometry (source_id == 1)
// (ring_map should be empty for source_id==1)
Geometry empty;
diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
index 012b3aca30..90901dee70 100644
--- a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
+++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
@@ -55,8 +55,8 @@ inline void clear_visit_info(Turns& turns)
struct backtrack_state
{
bool m_good;
-
- inline backtrack_state() : m_good(true) {}
+
+ inline backtrack_state() : m_good(true) {}
inline void reset() { m_good = true; }
inline bool good() const { return m_good; }
};
@@ -79,29 +79,30 @@ class backtrack_check_self_intersections
public :
typedef state state_type;
- template <typename Operation, typename Rings, typename Turns>
- static inline void apply(std::size_t size_at_start,
- Rings& rings, typename boost::range_value<Rings>::type& ring,
+ template <typename Operation, typename Rings, typename Ring, typename Turns, typename RobustPolicy>
+ static inline void apply(std::size_t size_at_start,
+ Rings& rings, Ring& ring,
Turns& turns, Operation& operation,
std::string const& ,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
state_type& state
)
{
state.m_good = false;
-
+
// Check self-intersections and throw exception if appropriate
if (! state.m_checked)
{
state.m_checked = true;
- has_self_intersections(geometry1);
- has_self_intersections(geometry2);
+ has_self_intersections(geometry1, robust_policy);
+ has_self_intersections(geometry2, robust_policy);
}
// Make bad output clean
rings.resize(size_at_start);
- ring.clear();
+ geometry::traits::clear<typename boost::range_value<Rings>::type>::apply(ring);
// Reject this as a starting point
operation.visited.set_rejected();
@@ -123,7 +124,7 @@ public :
typedef backtrack_state state_type;
template <typename Operation, typename Rings, typename Turns>
- static inline void apply(std::size_t size_at_start,
+ static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& reason,
@@ -133,7 +134,7 @@ public :
)
{
std::cout << " REJECT " << reason << std::endl;
-
+
state.m_good = false;
rings.resize(size_at_start);
diff --git a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
deleted file mode 100644
index 2003d2350d..0000000000
--- a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
-
-
-#include <boost/geometry/algorithms/comparable_distance.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace overlay
-{
-
-
-/*!
- \brief Policy calculating distance
- \details get_turn_info has an optional policy to get some
- extra information.
- This policy calculates the distance (using default distance strategy)
- */
-struct calculate_distance_policy
-{
- static bool const include_no_turn = false;
- static bool const include_degenerate = false;
- static bool const include_opposite = false;
-
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
- static inline void apply(Info& info, Point1 const& p1, Point2 const& p2,
- IntersectionInfo const&, DirInfo const&)
- {
- info.operations[0].enriched.distance
- = geometry::comparable_distance(info.point, p1);
- info.operations[1].enriched.distance
- = geometry::comparable_distance(info.point, p2);
- }
-
-};
-
-
-}} // namespace detail::overlay
-#endif //DOXYGEN_NO_DETAIL
-
-
-}} // namespace boost::geometry
-
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
index b210fd04b1..03be18e07a 100644
--- a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
+++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
@@ -137,7 +137,7 @@ inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
it != boost::end(meta_turns);
++it)
{
- if (! (it->turn->blocked() || it->turn->is_discarded()))
+ if (! (it->turn->blocked() || it->turn->discarded))
{
for (int i = 0 ; i < 2; i++)
{
diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
index 05bd721e7f..51955b515d 100644
--- a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
+++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
@@ -77,12 +77,23 @@ struct convert_ring<polygon_tag>
}
else
{
- interior_rings(destination).resize(
- interior_rings(destination).size() + 1);
- geometry::convert(source, interior_rings(destination).back());
- if (reverse)
+ // Avoid adding interior rings which are invalid
+ // because of its number of points:
+ std::size_t const min_num_points
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Destination>::value
+ >::value;
+
+ if (geometry::num_points(source) >= min_num_points)
{
- boost::reverse(interior_rings(destination).back());
+ interior_rings(destination).resize(
+ interior_rings(destination).size() + 1);
+ geometry::convert(source, interior_rings(destination).back());
+ if (reverse)
+ {
+ boost::reverse(interior_rings(destination).back());
+ }
}
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
index 5e18d0453a..20a6d7f48d 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
@@ -17,8 +17,10 @@
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
@@ -51,7 +53,7 @@ struct copy_segment_point_range
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
- int index = seg_id.segment_index;
+ signed_index_type index = seg_id.segment_index;
if (second)
{
index++;
@@ -94,8 +96,8 @@ struct copy_segment_point_polygon
>::apply
(
seg_id.ring_index < 0
- ? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[seg_id.ring_index],
+ ? geometry::exterior_ring(polygon)
+ : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, second,
point
);
@@ -110,7 +112,7 @@ struct copy_segment_point_box
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
- int index = seg_id.segment_index;
+ signed_index_type index = seg_id.segment_index;
if (second)
{
index++;
@@ -124,6 +126,30 @@ struct copy_segment_point_box
};
+template
+<
+ typename MultiGeometry,
+ typename SegmentIdentifier,
+ typename PointOut,
+ typename Policy
+>
+struct copy_segment_point_multi
+{
+ static inline bool apply(MultiGeometry const& multi,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point)
+ {
+
+ BOOST_ASSERT
+ (
+ seg_id.multi_index >= 0
+ && seg_id.multi_index < int(boost::size(multi))
+ );
+
+ // Call the single-version
+ return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, second, point);
+ }
+};
}} // namespace detail::copy_segments
@@ -188,6 +214,66 @@ struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
{};
+template
+<
+ typename MultiGeometry,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ multi_polygon_tag,
+ MultiGeometry,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiGeometry,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_polygon
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
+template
+<
+ typename MultiGeometry,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ multi_linestring_tag,
+ MultiGeometry,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiGeometry,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_range
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
index 805f3923e3..ceeb1a3b8b 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
@@ -1,6 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -10,24 +16,32 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
-#include <boost/array.hpp>
-#include <boost/mpl/assert.hpp>
#include <vector>
+#include <boost/array.hpp>
#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
+#include <boost/type_traits/integral_constant.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/ring_type.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/core/tags.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
namespace boost { namespace geometry
{
@@ -38,34 +52,38 @@ namespace detail { namespace copy_segments
{
-template
-<
- typename Ring,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_ring
{
- typedef typename closeable_view
+ template
+ <
+ typename Ring,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
+ static inline void apply(Ring const& ring,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
+ RangeOut& current_output)
+ {
+ typedef typename closeable_view
<
Ring const,
closure<Ring>::value
>::type cview_type;
- typedef typename reversible_view
+ typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
- typedef typename boost::range_iterator<rview_type const>::type iterator;
- typedef geometry::ever_circling_iterator<iterator> ec_iterator;
+ typedef typename boost::range_iterator<rview_type const>::type iterator;
+ typedef geometry::ever_circling_iterator<iterator> ec_iterator;
+
- static inline void apply(Ring const& ring,
- SegmentIdentifier const& seg_id, int to_index,
- RangeOut& current_output)
- {
cview_type cview(ring);
rview_type view(cview);
@@ -75,10 +93,10 @@ struct copy_segments_ring
// So we use the ever-circling iterator and determine when to step out
- int const from_index = seg_id.segment_index + 1;
+ signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
- BOOST_ASSERT(from_index < int(boost::size(view)));
+ BOOST_ASSERT(from_index < static_cast<signed_index_type>(boost::size(view)));
ec_iterator it(boost::begin(view), boost::end(view),
boost::begin(view) + from_index);
@@ -86,103 +104,130 @@ struct copy_segments_ring
// [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
// [1..1], travel the whole ring round
- typedef typename boost::range_difference<Ring>::type size_type;
- size_type const count = from_index <= to_index
+ signed_index_type const count = from_index <= to_index
? to_index - from_index + 1
- : int(boost::size(view)) - from_index + to_index + 1;
+ : static_cast<signed_index_type>(boost::size(view))
+ - from_index + to_index + 1;
- for (size_type i = 0; i < count; ++i, ++it)
+ for (signed_index_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_duplicates(current_output, *it);
+ detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
}
}
};
-template
-<
- typename LineString,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments_linestring
+template <bool Reverse, bool RemoveSpikes = true>
+class copy_segments_linestring
{
+private:
+ // remove spikes
+ template <typename RangeOut, typename Point, typename RobustPolicy>
+ static inline void append_to_output(RangeOut& current_output,
+ Point const& point,
+ RobustPolicy const& robust_policy,
+ boost::true_type const&)
+ {
+ detail::overlay::append_no_dups_or_spikes(current_output, point,
+ robust_policy);
+ }
- typedef typename boost::range_iterator<LineString const>::type iterator;
+ // keep spikes
+ template <typename RangeOut, typename Point, typename RobustPolicy>
+ static inline void append_to_output(RangeOut& current_output,
+ Point const& point,
+ RobustPolicy const&,
+ boost::false_type const&)
+ {
+ detail::overlay::append_no_duplicates(current_output, point);
+ }
+public:
+ template
+ <
+ typename LineString,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(LineString const& ls,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
- int const from_index = seg_id.segment_index + 1;
+ signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
- if (from_index > to_index || from_index < 0 || to_index >= int(boost::size(ls)))
+ if ( from_index > to_index
+ || from_index < 0
+ || to_index >= static_cast<signed_index_type>(boost::size(ls)) )
{
return;
}
- typedef typename boost::range_difference<LineString>::type size_type;
- size_type const count = to_index - from_index + 1;
+ signed_index_type const count = to_index - from_index + 1;
- typename boost::range_iterator<LineString const>::type it = boost::begin(ls) + from_index;
+ typename boost::range_iterator<LineString const>::type
+ it = boost::begin(ls) + from_index;
- for (size_type i = 0; i < count; ++i, ++it)
+ for (signed_index_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_duplicates(current_output, *it);
+ append_to_output(current_output, *it, robust_policy,
+ boost::integral_constant<bool, RemoveSpikes>());
}
}
};
-template
-<
- typename Polygon,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_polygon
{
+ template
+ <
+ typename Polygon,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(Polygon const& polygon,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
// Call ring-version with the right ring
- copy_segments_ring
- <
- typename geometry::ring_type<Polygon>::type,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >::apply
- (
- seg_id.ring_index < 0
+ copy_segments_ring<Reverse>::apply
+ (
+ seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[seg_id.ring_index],
- seg_id, to_index,
- current_output
- );
+ : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
+ seg_id, to_index,
+ robust_policy,
+ current_output
+ );
}
};
-template
-<
- typename Box,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_box
{
+ template
+ <
+ typename Box,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(Box const& box,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
- int index = seg_id.segment_index + 1;
+ signed_index_type index = seg_id.segment_index + 1;
BOOST_ASSERT(index < 5);
- int const count = index <= to_index
+ signed_index_type const count = index <= to_index
? to_index - index + 1
: 5 - index + to_index + 1;
@@ -193,15 +238,48 @@ struct copy_segments_box
// (possibly cyclic) copy to output
// (see comments in ring-version)
- for (int i = 0; i < count; i++, index++)
+ for (signed_index_type i = 0; i < count; i++, index++)
{
- detail::overlay::append_no_duplicates(current_output, bp[index % 5]);
+ detail::overlay::append_no_dups_or_spikes(current_output,
+ bp[index % 5], robust_policy);
}
}
};
+template<typename Policy>
+struct copy_segments_multi
+{
+ template
+ <
+ typename MultiGeometry,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
+ static inline void apply(MultiGeometry const& multi_geometry,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
+ RangeOut& current_output)
+ {
+
+ BOOST_ASSERT
+ (
+ seg_id.multi_index >= 0
+ && seg_id.multi_index < int(boost::size(multi_geometry))
+ );
+
+ // Call the single-version
+ Policy::apply(range::at(multi_geometry, seg_id.multi_index),
+ seg_id, to_index,
+ robust_policy,
+ current_output);
+ }
+};
+
+
}} // namespace detail::copy_segments
#endif // DOXYGEN_NO_DETAIL
@@ -213,82 +291,44 @@ namespace dispatch
template
<
typename Tag,
- typename GeometryIn,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
+ bool Reverse
>
-struct copy_segments
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<GeometryIn>)
- );
-};
+struct copy_segments : not_implemented<Tag>
+{};
-template
-<
- typename Ring,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<ring_tag, Ring, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_ring
- <
- Ring, Reverse, SegmentIdentifier, RangeOut
- >
+template <bool Reverse>
+struct copy_segments<ring_tag, Reverse>
+ : detail::copy_segments::copy_segments_ring<Reverse>
{};
+template <bool Reverse>
+struct copy_segments<linestring_tag, Reverse>
+ : detail::copy_segments::copy_segments_linestring<Reverse>
+{};
-template
-<
- typename LineString,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<linestring_tag, LineString, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_linestring
- <
- LineString, Reverse, SegmentIdentifier, RangeOut
- >
+template <bool Reverse>
+struct copy_segments<polygon_tag, Reverse>
+ : detail::copy_segments::copy_segments_polygon<Reverse>
{};
-template
-<
- typename Polygon,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<polygon_tag, Polygon, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_polygon
- <
- Polygon, Reverse, SegmentIdentifier, RangeOut
- >
+
+template <bool Reverse>
+struct copy_segments<box_tag, Reverse>
+ : detail::copy_segments::copy_segments_box<Reverse>
{};
-template
-<
- typename Box,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<box_tag, Box, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_box
+template<bool Reverse>
+struct copy_segments<multi_polygon_tag, Reverse>
+ : detail::copy_segments::copy_segments_multi
<
- Box, Reverse, SegmentIdentifier, RangeOut
+ detail::copy_segments::copy_segments_polygon<Reverse>
>
{};
-
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -303,10 +343,13 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
+ typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& range_out)
{
concept::check<Geometry const>();
@@ -314,11 +357,8 @@ inline void copy_segments(Geometry const& geometry,
dispatch::copy_segments
<
typename tag<Geometry>::type,
- Geometry,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >::apply(geometry, seg_id, to_index, range_out);
+ Reverse
+ >::apply(geometry, seg_id, to_index, robust_policy, range_out);
}
diff --git a/boost/geometry/algorithms/detail/overlay/do_reverse.hpp b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp
new file mode 100644
index 0000000000..15100f8d0b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp
@@ -0,0 +1,47 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
+
+#include <boost/geometry/core/point_order.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// Metafunction helper for intersection and union
+template <order_selector Selector, bool Reverse = false>
+struct do_reverse {};
+
+template <>
+struct do_reverse<clockwise, false> : boost::false_type {};
+
+template <>
+struct do_reverse<clockwise, true> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, false> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, true> : boost::false_type {};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index e4842d35f1..9484479b45 100644
--- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -27,8 +27,9 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#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>
+#include <boost/geometry/policies/robustness/robust_type.hpp>
+#include <boost/geometry/strategies/side.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
@@ -47,17 +48,23 @@ struct indexed_turn_operation
{
typedef TurnOperation type;
- int index;
- int operation_index;
+ std::size_t turn_index;
+ std::size_t operation_index;
bool discarded;
- TurnOperation subject;
-
- inline indexed_turn_operation(int i, int oi, TurnOperation const& s)
- : index(i)
+ // use pointers to avoid copies, const& is not possible because of usage in vector
+ segment_identifier const* other_seg_id; // segment id of other segment of intersection of two segments
+ TurnOperation const* subject;
+
+ inline indexed_turn_operation(std::size_t ti, std::size_t oi,
+ TurnOperation const& s,
+ segment_identifier const& oid)
+ : turn_index(ti)
, operation_index(oi)
, discarded(false)
- , subject(s)
+ , other_seg_id(&oid)
+ , subject(&s)
{}
+
};
template <typename IndexedTurnOperation>
@@ -75,19 +82,22 @@ template
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
bool Reverse1, bool Reverse2,
typename Strategy
>
-struct sort_on_segment_and_distance
+struct sort_on_segment_and_ratio
{
- inline sort_on_segment_and_distance(TurnPoints const& turn_points
+ inline sort_on_segment_and_ratio(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
+ , RobustPolicy const& robust_policy
, Strategy const& strategy
, bool* clustered)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
+ , m_robust_policy(robust_policy)
, m_strategy(strategy)
, m_clustered(clustered)
{
@@ -98,31 +108,47 @@ private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_robust_policy;
Strategy const& m_strategy;
mutable bool* m_clustered;
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+
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<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
+ left.subject->seg_id,
pi, pj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
+ *left.other_seg_id,
ri, rj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
+ *right.other_seg_id,
si, sj);
- int const order = get_relative_order
+ typedef typename strategy::side::services::default_strategy
<
- point_type
- >::apply(pi, pj,ri, rj, si, sj);
- //debug("r/o", order == -1);
- return order == -1;
+ typename cs_tag<point_type>::type
+ >::type strategy;
+
+ int const side_rj_p = strategy::apply(pi, pj, rj);
+ int const side_sj_p = strategy::apply(pi, pj, sj);
+
+ // Put the one turning left (1; right == -1) as last
+ if (side_rj_p != side_sj_p)
+ {
+ return side_rj_p < side_sj_p;
+ }
+
+ int const side_sj_r = strategy::apply(ri, rj, sj);
+ int const side_rj_s = strategy::apply(si, sj, rj);
+
+ // If they both turn left: the most left as last
+ // If they both turn right: this is not relevant, but take also here most left
+ return side_rj_s < side_sj_r;
}
public :
@@ -131,33 +157,30 @@ public :
// 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;
+ 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))
+ if (sl == sr)
{
// 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)
+ if (left.subject->fraction == right.subject->fraction)
{
- return consider_relative_order(left, right);
- }
-
- // If that is not the case, cluster it later on.
- // Indicate that this is necessary.
- *m_clustered = true;
+ // First check "real" intersection (crosses)
+ // -> distance zero due to precision, solve it by sorting
+ if (m_turn_points[left.turn_index].method == method_crosses
+ && m_turn_points[right.turn_index].method == method_crosses)
+ {
+ return consider_relative_order(left, right);
+ }
- return left.index < right.index;
+ // If that is not the case, cluster it later on.
+ // Indicate that this is necessary.
+ *m_clustered = true;
+ }
}
return sl == sr
- ? left.subject.enriched.distance < right.subject.enriched.distance
+ ? left.subject->fraction < right.subject->fraction
: sl < sr;
-
}
};
@@ -171,13 +194,13 @@ inline void update_discarded(Turns& turn_points, Operations& operations)
it != boost::end(operations);
++it)
{
- if (turn_points[it->index].discarded)
+ if (turn_points[it->turn_index].discarded)
{
it->discarded = true;
}
else if (it->discarded)
{
- turn_points[it->index].discarded = true;
+ turn_points[it->turn_index].discarded = true;
}
}
}
@@ -195,12 +218,14 @@ template
typename Container,
typename TurnPoints,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void enrich_sort(Container& operations,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename IndexType::type operations_type;
@@ -208,14 +233,15 @@ inline void enrich_sort(Container& operations,
bool clustered = false;
std::sort(boost::begin(operations),
boost::end(operations),
- sort_on_segment_and_distance
+ sort_on_segment_and_ratio
<
TurnPoints,
IndexType,
Geometry1, Geometry2,
+ RobustPolicy,
Reverse1, Reverse2,
Strategy
- >(turn_points, geometry1, geometry2, strategy, &clustered));
+ >(turn_points, geometry1, geometry2, robust_policy, 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
@@ -230,16 +256,15 @@ inline void enrich_sort(Container& operations,
it != boost::end(operations);
prev = it++)
{
- operations_type& prev_op = turn_points[prev->index]
+ operations_type& prev_op = turn_points[prev->turn_index]
.operations[prev->operation_index];
- operations_type& op = turn_points[it->index]
+ operations_type& op = turn_points[it->turn_index]
.operations[it->operation_index];
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))
+ && (turn_points[prev->turn_index].method != method_crosses
+ || turn_points[it->turn_index].method != method_crosses)
+ && prev_op.fraction == op.fraction)
{
if (begin_cluster == boost::end(operations))
{
@@ -249,14 +274,14 @@ inline void enrich_sort(Container& operations,
else if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
- for_operation, geometry1, geometry2, strategy);
+ for_operation, geometry1, geometry2, robust_policy, strategy);
begin_cluster = boost::end(operations);
}
}
if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
- for_operation, geometry1, geometry2, strategy);
+ for_operation, geometry1, geometry2, robust_policy, strategy);
}
}
@@ -315,19 +340,19 @@ inline void enrich_assign(Container& operations,
prev = it++)
{
operations_type& prev_op
- = turn_points[prev->index].operations[prev->operation_index];
+ = turn_points[prev->turn_index].operations[prev->operation_index];
operations_type& op
- = turn_points[it->index].operations[it->operation_index];
+ = turn_points[it->turn_index].operations[it->operation_index];
prev_op.enriched.travels_to_ip_index
- = it->index;
+ = static_cast<int>(it->turn_index);
prev_op.enriched.travels_to_vertex_index
- = it->subject.seg_id.segment_index;
+ = it->subject->seg_id.segment_index;
if (! first
&& prev_op.seg_id.segment_index == op.seg_id.segment_index)
{
- prev_op.enriched.next_ip_index = it->index;
+ prev_op.enriched.next_ip_index = static_cast<int>(it->turn_index);
}
first = false;
}
@@ -340,16 +365,16 @@ inline void enrich_assign(Container& operations,
it != boost::end(operations);
++it)
{
- operations_type& op = turn_points[it->index]
+ operations_type& op = turn_points[it->turn_index]
.operations[it->operation_index];
- std::cout << it->index
- << " meth: " << method_char(turn_points[it->index].method)
+ std::cout << it->turn_index
+ << " meth: " << method_char(turn_points[it->turn_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")
+ << " dst: " << op.fraction // needs define
+ << " op: " << operation_char(turn_points[it->turn_index].operations[0].operation)
+ << operation_char(turn_points[it->turn_index].operations[1].operation)
+ << " dsc: " << (turn_points[it->turn_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
@@ -370,7 +395,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
- int index = 0;
+ std::size_t index = 0;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
@@ -379,7 +404,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
// Add operations on this ring, but skip discarded ones
if (! it->discarded)
{
- int op_index = 0;
+ std::size_t op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
@@ -397,7 +422,8 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
);
mapped_vector[ring_id].push_back
(
- IndexedType(index, op_index, *op_it)
+ IndexedType(index, op_index, *op_it,
+ it->operations[1 - op_index].seg_id)
);
}
}
@@ -422,6 +448,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
\param for_operation operation_type (union or intersection)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
+\param robust_policy policy to handle robustness issues
\param strategy strategy
*/
template
@@ -429,11 +456,13 @@ template
bool Reverse1, bool Reverse2,
typename TurnPoints,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void enrich_intersection_points(TurnPoints& turn_points,
detail::overlay::operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
@@ -462,6 +491,10 @@ inline void enrich_intersection_points(TurnPoints& turn_points,
{
it->discarded = true;
}
+ if (it->both(detail::overlay::operation_none))
+ {
+ it->discarded = true;
+ }
}
@@ -484,7 +517,7 @@ inline void enrich_intersection_points(TurnPoints& turn_points,
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<indexed_turn_operation, Reverse1, Reverse2>(mit->second, turn_points, for_operation,
- geometry1, geometry2, strategy);
+ geometry1, geometry2, robust_policy, strategy);
}
for (typename mapped_vector_type::iterator mit
diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
index 8c8ed96189..ef32edeefa 100644
--- a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
@@ -10,9 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
-#include <boost/geometry/strategies/distance.hpp>
-
-
namespace boost { namespace geometry
{
@@ -31,37 +28,22 @@ namespace detail { namespace overlay
template<typename P>
struct enrichment_info
{
- typedef typename strategy::distance::services::return_type
- <
- typename strategy::distance::services::comparable_type
- <
- typename strategy::distance::services::default_strategy
- <
- point_tag,
- P
- >::type
- >::type
- >::type distance_type;
-
inline enrichment_info()
: travels_to_vertex_index(-1)
, travels_to_ip_index(-1)
, next_ip_index(-1)
- , distance(distance_type())
{}
// vertex to which is free travel after this IP,
// so from "segment_index+1" to "travels_to_vertex_index", without IP-s,
// can be -1
- int travels_to_vertex_index;
+ signed_index_type travels_to_vertex_index;
// same but now IP index, so "next IP index" but not on THIS segment
int travels_to_ip_index;
// index of next IP on this segment, -1 if there is no one
int next_ip_index;
-
- distance_type distance; // distance-measurement from segment.first to IP
};
diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp
index b110cc9602..acf38d09ab 100644
--- a/boost/geometry/algorithms/detail/overlay/follow.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -20,6 +25,7 @@
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
namespace boost { namespace geometry
@@ -32,7 +38,7 @@ namespace detail { namespace overlay
namespace following
{
-
+
template <typename Turn, typename Operation>
static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
{
@@ -44,43 +50,43 @@ static inline bool is_entering(Turn const& /* TODO remove this parameter */, Ope
;
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool last_covered_by(Turn const& turn, Operation const& op,
+static inline bool last_covered_by(Turn const& turn, Operation const& op,
LineString const& linestring, Polygon const& polygon)
{
- // Check any point between the this one and the first IP
+ // Check any point between the this one and the first IP
typedef typename geometry::point_type<LineString>::type point_type;
point_type point_in_between;
detail::point_on_border::midpoint_helper
<
point_type,
0, dimension<point_type>::value
- >::apply(point_in_between, linestring[op.seg_id.segment_index], turn.point);
+ >::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
return geometry::covered_by(point_in_between, polygon);
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool is_leaving(Turn const& turn, Operation const& op,
- bool entered, bool first,
+static inline bool is_leaving(Turn const& turn, Operation const& op,
+ bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
{
if (op.operation == operation_union)
{
- return entered
+ return entered
|| turn.method == method_crosses
|| (first && last_covered_by(turn, op, linestring, polygon))
;
@@ -89,20 +95,20 @@ static inline bool is_leaving(Turn const& turn, Operation const& op,
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool is_staying_inside(Turn const& turn, Operation const& op,
- bool entered, bool first,
+static inline bool is_staying_inside(Turn const& turn, Operation const& op,
+ bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
{
if (turn.method == method_crosses)
{
- // The normal case, this is completely covered with entering/leaving
+ // The normal case, this is completely covered with entering/leaving
// so stay out of this time consuming "covered_by"
return false;
}
@@ -115,11 +121,11 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op,
return false;
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename Linestring,
+ typename Turn,
+ typename Operation,
+ typename Linestring,
typename Polygon
>
static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
@@ -134,7 +140,7 @@ static inline bool was_entered(Turn const& turn, Operation const& op, bool first
// Template specialization structure to call the right actions for the right type
-template<overlay_type OverlayType>
+template <overlay_type OverlayType, bool RemoveSpikes = true>
struct action_selector
{
// If you get here the overlay type is not intersection or difference
@@ -142,51 +148,86 @@ struct action_selector
};
// Specialization for intersection, containing the implementation
-template<>
-struct action_selector<overlay_intersection>
+template <bool RemoveSpikes>
+struct action_selector<overlay_intersection, RemoveSpikes>
{
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
- LineString const& ,
+ LineString const& ,
segment_identifier& segment_id,
- int , Point const& point,
- Operation const& operation, OutputIterator& )
+ signed_index_type , Point const& point,
+ Operation const& operation,
+ RobustPolicy const& ,
+ OutputIterator& )
{
// On enter, append the intersection point and remember starting point
+ // TODO: we don't check on spikes for linestrings (?). Consider this.
detail::overlay::append_no_duplicates(current_piece, point);
segment_id = operation.seg_id;
}
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& , OutputIterator& out)
+ signed_index_type index, Point const& point,
+ Operation const& ,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
// On leave, copy all segments from starting point, append the intersection point
// and add the output piece
- geometry::copy_segments<false>(linestring, segment_id, index, current_piece);
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, RemoveSpikes
+ >::apply(linestring, segment_id, index, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
- if (current_piece.size() > 1)
+ if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
}
- current_piece.clear();
+
+ geometry::clear(current_piece);
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void isolated_point(LineStringOut&,
+ LineString const&,
+ segment_identifier&,
+ signed_index_type, Point const& point,
+ Operation const& , OutputIterator& out)
+ {
+ LineStringOut isolated_point_ls;
+ geometry::append(isolated_point_ls, point);
+
+#ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
+ geometry::append(isolated_point_ls, point);
+#endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
+
+ *out++ = isolated_point_ls;
}
static inline bool is_entered(bool entered)
@@ -194,8 +235,15 @@ struct action_selector<overlay_intersection>
return entered;
}
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& )
{
return geometry::covered_by(point, geometry);
}
@@ -203,45 +251,67 @@ struct action_selector<overlay_intersection>
};
// Specialization for difference, which reverses these actions
-template<>
-struct action_selector<overlay_difference>
+template <bool RemoveSpikes>
+struct action_selector<overlay_difference, RemoveSpikes>
{
- typedef action_selector<overlay_intersection> normal_action;
+ typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
- static inline void enter(LineStringOut& current_piece,
- LineString const& linestring,
- segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& operation, OutputIterator& out)
+ static inline void enter(LineStringOut& current_piece,
+ LineString const& linestring,
+ segment_identifier& segment_id,
+ signed_index_type index, Point const& point,
+ Operation const& operation,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
- normal_action::leave(current_piece, linestring, segment_id, index,
- point, operation, out);
+ normal_action::leave(current_piece, linestring, segment_id, index,
+ point, operation, robust_policy, out);
}
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& operation, OutputIterator& out)
+ signed_index_type index, Point const& point,
+ Operation const& operation,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
- point, operation, out);
+ point, operation, robust_policy, out);
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void isolated_point(LineStringOut&,
+ LineString const&,
+ segment_identifier&,
+ signed_index_type, Point const&,
+ Operation const&, OutputIterator&)
+ {
}
static inline bool is_entered(bool entered)
@@ -249,10 +319,17 @@ struct action_selector<overlay_difference>
return ! normal_action::is_entered(entered);
}
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& robust_policy)
{
- return ! normal_action::included(point, geometry);
+ return ! normal_action::included(point, geometry, robust_policy);
}
};
@@ -269,12 +346,13 @@ template
typename LineStringOut,
typename LineString,
typename Polygon,
- overlay_type OverlayType
+ overlay_type OverlayType,
+ bool RemoveSpikes = true
>
class follow
{
- template<typename Turn>
+ template <typename Turn>
struct sort_on_segment
{
// In case of turn point at the same location, we want to have continue/blocked LAST
@@ -296,15 +374,15 @@ class follow
inline bool use_operation(Turn const& left, Turn const& right) const
{
- // If they are the same, OK.
+ // If they are the same, OK.
return operation_order(left) < operation_order(right);
}
inline bool use_distance(Turn const& left, Turn const& right) const
{
- return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance)
+ return left.operations[0].fraction == right.operations[0].fraction
? use_operation(left, right)
- : left.operations[0].enriched.distance < right.operations[0].enriched.distance
+ : left.operations[0].fraction < right.operations[0].fraction
;
}
@@ -325,16 +403,33 @@ class follow
public :
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& robust_policy)
{
- return following::action_selector<OverlayType>::included(point, geometry);
+ return following::action_selector
+ <
+ OverlayType, RemoveSpikes
+ >::included(point, geometry, robust_policy);
}
- template<typename Turns, typename OutputIterator>
+ template
+ <
+ typename Turns,
+ typename OutputIterator,
+ typename RobustPolicy
+ >
static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
detail::overlay::operation_type , // TODO: this parameter might be redundant
- Turns& turns, OutputIterator out)
+ Turns& turns,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
@@ -343,7 +438,7 @@ public :
typename turn_type::container_type
>::type turn_operation_iterator_type;
- typedef following::action_selector<OverlayType> action;
+ typedef following::action_selector<OverlayType, RemoveSpikes> action;
// Sort intersection points on segments-along-linestring, and distance
// (like in enrich is done for poly/poly)
@@ -376,27 +471,38 @@ public :
debug_traverse(*it, *iit, "-> Entering");
entered = true;
- action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ action::enter(current_piece, linestring, current_segment_id,
+ iit->seg_id.segment_index, it->point, *iit,
+ robust_policy,
+ out);
}
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
{
debug_traverse(*it, *iit, "-> Leaving");
entered = false;
- action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ action::leave(current_piece, linestring, current_segment_id,
+ iit->seg_id.segment_index, it->point, *iit,
+ robust_policy,
+ out);
}
first = false;
}
if (action::is_entered(entered))
{
- geometry::copy_segments<false>(linestring, current_segment_id,
- boost::size(linestring) - 1,
- current_piece);
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, RemoveSpikes
+ >::apply(linestring,
+ current_segment_id,
+ static_cast<signed_index_type>(boost::size(linestring) - 1),
+ robust_policy,
+ current_piece);
}
// Output the last one, if applicable
- if (current_piece.size() > 1)
+ if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
}
diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
new file mode 100644
index 0000000000..85378e08b0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
@@ -0,0 +1,536 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
+
+#include <cstddef>
+#include <algorithm>
+#include <iterator>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+namespace following { namespace linear
+{
+
+
+
+
+// follower for linear/linear geometries set operations
+
+template <typename Turn, typename Operation>
+static inline bool is_entering(Turn const& turn,
+ Operation const& operation)
+{
+ if ( turn.method != method_touch && turn.method != method_touch_interior )
+ {
+ return false;
+ }
+ return operation.operation == operation_intersection;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_staying_inside(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( !entered )
+ {
+ return false;
+ }
+
+ if ( turn.method != method_equal && turn.method != method_collinear )
+ {
+ return false;
+ }
+ return operation.operation == operation_continue;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_leaving(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( !entered )
+ {
+ return false;
+ }
+
+ if ( turn.method != method_touch
+ && turn.method != method_touch_interior
+ && turn.method != method_equal
+ && turn.method != method_collinear )
+ {
+ return false;
+ }
+
+ if ( operation.operation == operation_blocked )
+ {
+ return true;
+ }
+
+ if ( operation.operation != operation_union )
+ {
+ return false;
+ }
+
+ return operation.is_collinear;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_isolated_point(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( entered )
+ {
+ return false;
+ }
+
+ if ( turn.method == method_none )
+ {
+ BOOST_ASSERT( operation.operation == operation_continue );
+ return true;
+ }
+
+ if ( turn.method == method_crosses )
+ {
+ return true;
+ }
+
+ if ( turn.method != method_touch && turn.method != method_touch_interior )
+ {
+ return false;
+ }
+
+ if ( operation.operation == operation_blocked )
+ {
+ return true;
+ }
+
+ if ( operation.operation != operation_union )
+ {
+ return false;
+ }
+
+ return !operation.is_collinear;
+}
+
+
+
+
+
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Linestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+class follow_linestring_linear_linestring
+{
+protected:
+ // allow spikes (false indicates: do not remove spikes)
+ typedef following::action_selector<OverlayType, false> action;
+
+ template
+ <
+ typename TurnIterator,
+ typename TurnOperationIterator,
+ typename SegmentIdentifier,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ process_turn(TurnIterator it,
+ TurnOperationIterator op_it,
+ bool& entered,
+ std::size_t& enter_count,
+ Linestring const& linestring,
+ LinestringOut& current_piece,
+ SegmentIdentifier& current_segment_id,
+ OutputIterator oit)
+ {
+ // We don't rescale linear/linear
+ detail::no_rescale_policy robust_policy;
+
+ if ( is_entering(*it, *op_it) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Entering");
+
+ entered = true;
+ if ( enter_count == 0 )
+ {
+ action::enter(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, robust_policy, oit);
+ }
+ ++enter_count;
+ }
+ else if ( is_leaving(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Leaving");
+
+ --enter_count;
+ if ( enter_count == 0 )
+ {
+ entered = false;
+ action::leave(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, robust_policy, oit);
+ }
+ }
+ else if ( FollowIsolatedPoints
+ && is_isolated_point(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
+
+ action::isolated_point(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, oit);
+ }
+ else if ( FollowContinueTurns
+ && is_staying_inside(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
+
+ entered = true;
+ }
+ return oit;
+ }
+
+ template
+ <
+ typename SegmentIdentifier,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ process_end(bool entered,
+ Linestring const& linestring,
+ SegmentIdentifier const& current_segment_id,
+ LinestringOut& current_piece,
+ OutputIterator oit)
+ {
+ if ( action::is_entered(entered) )
+ {
+ // We don't rescale linear/linear
+ detail::no_rescale_policy robust_policy;
+
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, false // do not reverse; do not remove spikes
+ >::apply(linestring,
+ current_segment_id,
+ static_cast<signed_index_type>(boost::size(linestring) - 1),
+ robust_policy,
+ current_piece);
+ }
+
+ // Output the last one, if applicable
+ if (::boost::size(current_piece) > 1)
+ {
+ *oit++ = current_piece;
+ }
+
+ return oit;
+ }
+
+public:
+ template <typename TurnIterator, typename OutputIterator>
+ static inline OutputIterator
+ apply(Linestring const& linestring, Linear const&,
+ TurnIterator first, TurnIterator beyond,
+ OutputIterator oit)
+ {
+ // Iterate through all intersection points (they are
+ // ordered along the each line)
+
+ LinestringOut current_piece;
+ geometry::segment_identifier current_segment_id(0, -1, -1, -1);
+
+ bool entered = false;
+ std::size_t enter_count = 0;
+
+ for (TurnIterator it = first; it != beyond; ++it)
+ {
+ oit = process_turn(it, boost::begin(it->operations),
+ entered, enter_count,
+ linestring,
+ current_piece, current_segment_id,
+ oit);
+ }
+
+ BOOST_ASSERT( enter_count == 0 );
+
+ return process_end(entered, linestring,
+ current_segment_id, current_piece,
+ oit);
+ }
+};
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename MultiLinestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+class follow_multilinestring_linear_linestring
+ : follow_linestring_linear_linestring
+ <
+ LinestringOut,
+ typename boost::range_value<MultiLinestring>::type,
+ Linear,
+ OverlayType,
+ FollowIsolatedPoints,
+ FollowContinueTurns
+ >
+{
+protected:
+ typedef typename boost::range_value<MultiLinestring>::type Linestring;
+
+ typedef follow_linestring_linear_linestring
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ > Base;
+
+ typedef following::action_selector<OverlayType> action;
+
+ typedef typename boost::range_iterator
+ <
+ MultiLinestring const
+ >::type linestring_iterator;
+
+
+ template <typename OutputIt, overlay_type OT>
+ struct copy_linestrings_in_range
+ {
+ static inline OutputIt
+ apply(linestring_iterator, linestring_iterator, OutputIt oit)
+ {
+ return oit;
+ }
+ };
+
+ template <typename OutputIt>
+ struct copy_linestrings_in_range<OutputIt, overlay_difference>
+ {
+ static inline OutputIt
+ apply(linestring_iterator first, linestring_iterator beyond,
+ OutputIt oit)
+ {
+ for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
+ {
+ LinestringOut line_out;
+ geometry::convert(*ls_it, line_out);
+ *oit++ = line_out;
+ }
+ return oit;
+ }
+ };
+
+ template <typename TurnIterator>
+ static inline signed_index_type get_multi_index(TurnIterator it)
+ {
+ return boost::begin(it->operations)->seg_id.multi_index;
+ }
+
+ class has_other_multi_id
+ {
+ private:
+ signed_index_type m_multi_id;
+
+ public:
+ has_other_multi_id(signed_index_type multi_id)
+ : m_multi_id(multi_id) {}
+
+ template <typename Turn>
+ bool operator()(Turn const& turn) const
+ {
+ return boost::begin(turn.operations)->seg_id.multi_index
+ != m_multi_id;
+ }
+ };
+
+public:
+ template <typename TurnIterator, typename OutputIterator>
+ static inline OutputIterator
+ apply(MultiLinestring const& multilinestring, Linear const& linear,
+ TurnIterator first, TurnIterator beyond,
+ OutputIterator oit)
+ {
+ BOOST_ASSERT( first != beyond );
+
+ typedef copy_linestrings_in_range
+ <
+ OutputIterator, OverlayType
+ > copy_linestrings;
+
+ linestring_iterator ls_first = boost::begin(multilinestring);
+ linestring_iterator ls_beyond = boost::end(multilinestring);
+
+ // Iterate through all intersection points (they are
+ // ordered along the each linestring)
+
+ signed_index_type current_multi_id = get_multi_index(first);
+
+ oit = copy_linestrings::apply(ls_first,
+ ls_first + current_multi_id,
+ oit);
+
+ TurnIterator per_ls_next = first;
+ do {
+ TurnIterator per_ls_current = per_ls_next;
+
+ // find turn with different multi-index
+ per_ls_next = std::find_if(per_ls_current, beyond,
+ has_other_multi_id(current_multi_id));
+
+ oit = Base::apply(*(ls_first + current_multi_id),
+ linear, per_ls_current, per_ls_next, oit);
+
+ signed_index_type next_multi_id(-1);
+ linestring_iterator ls_next = ls_beyond;
+ if ( per_ls_next != beyond )
+ {
+ next_multi_id = get_multi_index(per_ls_next);
+ ls_next = ls_first + next_multi_id;
+ }
+ oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
+ ls_next,
+ oit);
+
+ current_multi_id = next_multi_id;
+ }
+ while ( per_ls_next != beyond );
+
+ return oit;
+ }
+};
+
+
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Geometry1,
+ typename Geometry2,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns,
+ typename TagOut = typename tag<LinestringOut>::type,
+ typename TagIn1 = typename tag<Geometry1>::type
+>
+struct follow
+ : not_implemented<LinestringOut, Geometry1>
+{};
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Linestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+struct follow
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns,
+ linestring_tag, linestring_tag
+ > : follow_linestring_linear_linestring
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ >
+{};
+
+
+template
+<
+ typename LinestringOut,
+ typename MultiLinestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+struct follow
+ <
+ LinestringOut, MultiLinestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns,
+ linestring_tag, multi_linestring_tag
+ > : follow_multilinestring_linear_linestring
+ <
+ LinestringOut, MultiLinestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ >
+{};
+
+
+
+}} // namespace following::linear
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
index 019c3ba3f9..63011c7d48 100644
--- a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
@@ -17,6 +17,7 @@
#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
namespace boost { namespace geometry
{
@@ -35,32 +36,45 @@ template
>
struct get_turn_without_info
{
- typedef strategy_intersection
- <
- typename cs_tag<typename TurnInfo::point_type>::type,
- Point1,
- Point2,
- typename TurnInfo::point_type
- > si;
-
- typedef typename si::segment_intersection_strategy_type strategy;
-
-
-
- template <typename OutputIterator>
+ template <typename RobustPolicy, typename OutputIterator>
static inline OutputIterator apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& pi, Point1 const& pj, Point1 const& /*pk*/,
+ Point2 const& qi, Point2 const& qj, Point2 const& /*qk*/,
+ bool /*is_p_first*/, bool /*is_p_last*/,
+ bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& ,
+ RobustPolicy const& robust_policy,
OutputIterator out)
{
+ typedef strategy_intersection
+ <
+ typename cs_tag<typename TurnInfo::point_type>::type,
+ Point1,
+ Point2,
+ typename TurnInfo::point_type,
+ RobustPolicy
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point1 const> segment_type2;
- segment_type1 p1(pi, pj), p2(pj, pk);
- segment_type2 q1(qi, qj), q2(qj, qk);
+ segment_type1 p1(pi, pj);
+ segment_type2 q1(qi, qj);
- //
- typename strategy::return_type result = strategy::apply(p1, q1);
+ typedef typename geometry::robust_point_type
+ <
+ Point1, RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
+ geometry::recalculate(pi_rob, pi, robust_policy);
+ geometry::recalculate(pj_rob, pj, robust_policy);
+ geometry::recalculate(qi_rob, qi, robust_policy);
+ geometry::recalculate(qj_rob, qj, robust_policy);
+ typename strategy::return_type result
+ = strategy::apply(p1, q1, robust_policy,
+ pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < result.template get<0>().count; i++)
{
@@ -84,10 +98,12 @@ template
<
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Turns
>
inline void get_intersection_points(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Turns& turns)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
@@ -99,14 +115,6 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename boost::range_value<Turns>::type
> TurnPolicy;
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
-
detail::get_turns::no_interrupt_policy interrupt_policy;
boost::mpl::if_c
@@ -118,9 +126,7 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
- Turns, TurnPolicy,
- //segment_intersection_strategy_type,
- detail::get_turns::no_interrupt_policy
+ TurnPolicy
>,
dispatch::get_turns
<
@@ -128,13 +134,12 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
- Turns, TurnPolicy,
- //segment_intersection_strategy_type,
- detail::get_turns::no_interrupt_policy
+ TurnPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
+ robust_policy,
turns, interrupt_policy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
index 522ef68382..d71f4ad51f 100644
--- a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
@@ -10,8 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP
-#include <boost/geometry/algorithms/distance.hpp>
-
#include <boost/geometry/strategies/intersection.hpp>
@@ -36,15 +34,10 @@ namespace detail { namespace overlay
template <typename Point1>
struct get_relative_order
{
- typedef strategy_intersection
+ typedef typename strategy::side::services::default_strategy
<
- typename cs_tag<Point1>::type,
- Point1,
- Point1,
- Point1
- > si;
-
- typedef typename si::side_strategy_type strategy;
+ typename cs_tag<Point1>::type
+ >::type strategy;
template <typename Point>
static inline int value_via_product(Point const& ti, Point const& tj,
diff --git a/boost/geometry/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
index c2c6980577..131d58d582 100644
--- a/boost/geometry/algorithms/detail/overlay/get_ring.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
@@ -13,11 +13,13 @@
#include <boost/assert.hpp>
#include <boost/range.hpp>
-
-#include <boost/geometry/core/tags.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/core/tags.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -33,16 +35,16 @@ template<typename Tag>
struct get_ring
{};
-// A container of rings (multi-ring but that does not exist)
+// A range of rings (multi-ring but that does not exist)
// gets the "void" tag and is dispatched here.
template<>
struct get_ring<void>
{
- template<typename Container>
- static inline typename boost::range_value<Container>::type const&
- apply(ring_identifier const& id, Container const& container)
+ template<typename Range>
+ static inline typename boost::range_value<Range>::type const&
+ apply(ring_identifier const& id, Range const& container)
{
- return container[id.multi_index];
+ return range::at(container, id.multi_index);
}
};
@@ -87,7 +89,26 @@ struct get_ring<polygon_tag>
);
return id.ring_index < 0
? exterior_ring(polygon)
- : interior_rings(polygon)[id.ring_index];
+ : range::at(interior_rings(polygon), id.ring_index);
+ }
+};
+
+
+template<>
+struct get_ring<multi_polygon_tag>
+{
+ template<typename MultiPolygon>
+ static inline typename ring_type<MultiPolygon>::type const& apply(
+ ring_identifier const& id,
+ MultiPolygon const& multi_polygon)
+ {
+ BOOST_ASSERT
+ (
+ id.multi_index >= 0
+ && id.multi_index < int(boost::size(multi_polygon))
+ );
+ return get_ring<polygon_tag>::apply(id,
+ range::at(multi_polygon, id.multi_index));
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index b8320d9b7b..240b6de036 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -16,9 +16,19 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
+
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
namespace boost { namespace geometry
{
@@ -30,7 +40,7 @@ class turn_info_exception : public geometry::exception
public:
// NOTE: "char" will be replaced by enum in future version
- inline turn_info_exception(char const method)
+ inline turn_info_exception(char const method)
{
message = "Boost.Geometry Turn exception: ";
message += method;
@@ -50,7 +60,6 @@ public:
namespace detail { namespace overlay
{
-
struct base_turn_handler
{
// Returns true if both sides are opposite
@@ -91,13 +100,32 @@ struct base_turn_handler
{
both(ti, condition ? operation_union : operation_intersection);
}
+
+ template <typename TurnInfo, typename IntersectionInfo>
+ static inline void assign_point(TurnInfo& ti,
+ method_type method,
+ IntersectionInfo const& info, int index)
+ {
+ ti.method = method;
+ BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this
+ geometry::convert(info.intersections[index], ti.point);
+ ti.operations[0].fraction = info.fractions[index].robust_ra;
+ ti.operations[1].fraction = info.fractions[index].robust_rb;
+ }
+
+ template <typename IntersectionInfo>
+ static inline int non_opposite_to_index(IntersectionInfo const& info)
+ {
+ return info.fractions[0].robust_rb < info.fractions[1].robust_rb
+ ? 1 : 0;
+ }
+
};
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct touch_interior : public base_turn_handler
{
@@ -108,17 +136,18 @@ struct touch_interior : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& ,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_touch_interior;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_touch_interior, intersection_info, 0);
// Both segments of q touch segment p somewhere in its interior
// 1) We know: if q comes from LEFT or RIGHT
@@ -130,7 +159,7 @@ struct touch_interior : public base_turn_handler
static int const index_q = 1 - Index;
int const side_qi_p = dir_info.sides.template get<index_q, 0>();
- int const side_qk_p = SideStrategy::apply(pi, pj, qk);
+ int const side_qk_p = side.qk_wrt_p1();
if (side_qi_p == -side_qk_p)
{
@@ -143,7 +172,7 @@ struct touch_interior : public base_turn_handler
return;
}
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
+ int const side_qk_q = side.qk_wrt_q1();
if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
{
@@ -203,8 +232,7 @@ struct touch_interior : public base_turn_handler
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct touch : public base_turn_handler
{
@@ -227,37 +255,34 @@ struct touch : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_touch;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_touch, intersection_info, 0);
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
- int const side_qk_p1 = SideStrategy::apply(pi, pj, qk);
+ int const side_qk_p1 = side.qk_wrt_p1();
// If Qi and Qk are both at same side of Pi-Pj,
// or collinear (so: not opposite sides)
if (! opposite(side_qi_p1, side_qk_p1))
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
-
- bool const both_continue = side_pk_p == 0 && side_qk_q == 0;
- bool const robustness_issue_in_continue = both_continue && side_pk_q2 != 0;
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_q = side.qk_wrt_q1();
bool const q_turns_left = side_qk_q == 1;
bool const block_q = side_qk_p1 == 0
&& ! same(side_qi_p1, side_qk_q)
- && ! robustness_issue_in_continue
;
// If Pk at same side as Qi/Qk
@@ -276,7 +301,7 @@ struct touch : public base_turn_handler
return;
}
- int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+ int const side_pk_q1 = side.pk_wrt_q1();
// Collinear opposite case -> block P
@@ -329,9 +354,6 @@ struct touch : public base_turn_handler
else
{
// Pk at other side than Qi/Pk
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
- bool const q_turns_left = side_qk_q == 1;
-
ti.operations[0].operation = q_turns_left
? operation_intersection
: operation_union;
@@ -347,13 +369,13 @@ struct touch : public base_turn_handler
else
{
// From left to right or from right to left
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
+ int const side_pk_p = side.pk_wrt_p1();
bool const right_to_left = side_qk_p1 == 1;
// If p turns into direction of qi (1,2)
if (side_pk_p == side_qi_p1)
{
- int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+ int const side_pk_q1 = side.pk_wrt_q1();
// Collinear opposite case -> block P
if (side_pk_q1 == 0)
@@ -374,7 +396,7 @@ struct touch : public base_turn_handler
// If p turns into direction of qk (4,5)
if (side_pk_p == side_qk_p1)
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
+ int const side_pk_q2 = side.pk_wrt_q2();
// Collinear case -> lines join, continue
if (side_pk_q2 == 0)
@@ -413,8 +435,7 @@ struct touch : public base_turn_handler
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct equal : public base_turn_handler
{
@@ -423,22 +444,24 @@ struct equal : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& , Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
- IntersectionInfo const& intersection_info,
- DirInfo const& )
+ IntersectionInfo const& info,
+ DirInfo const& ,
+ SidePolicy const& side)
{
- ti.method = method_equal;
- // Copy the SECOND intersection point
- geometry::convert(intersection_info.intersections[1], ti.point);
+ // Copy the intersection point in TO direction
+ assign_point(ti, method_equal, info, non_opposite_to_index(info));
+
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_p = side.qk_wrt_p1();
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
- int const side_qk_p = SideStrategy::apply(pi, pj, qk);
// If pk is collinear with qj-qk, they continue collinearly.
// This can be on either side of p1 (== q1), or collinear
@@ -447,6 +470,7 @@ struct equal : public base_turn_handler
if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
{
both(ti, operation_continue);
+
return;
}
@@ -454,8 +478,6 @@ struct equal : public base_turn_handler
// If they turn to same side (not opposite sides)
if (! opposite(side_pk_p, side_qk_p))
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
-
// If pk is left of q2 or collinear: p: union, q: intersection
ui_else_iu(side_pk_q2 != -1, ti);
}
@@ -485,33 +507,32 @@ struct equal_opposite : public base_turn_handler
typename DirInfo
>
static inline void apply(Point1 const& pi, Point2 const& qi,
- /* by value: */ TurnInfo tp,
+ /* by value: */ TurnInfo tp,
OutputIterator& out,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
// For equal-opposite segments, normally don't do anything.
- if (AssignPolicy::include_opposite)
- {
- tp.method = method_equal;
- for (int i = 0; i < 2; i++)
- {
- tp.operations[i].operation = operation_opposite;
- }
- for (unsigned int i = 0; i < intersection_info.count; i++)
- {
- geometry::convert(intersection_info.intersections[i], tp.point);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
- *out++ = tp;
- }
- }
+ if (AssignPolicy::include_opposite)
+ {
+ tp.method = method_equal;
+ for (int i = 0; i < 2; i++)
+ {
+ tp.operations[i].operation = operation_opposite;
+ }
+ for (unsigned int i = 0; i < intersection_info.count; i++)
+ {
+ assign_point(tp, method_none, intersection_info, i);
+ AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ *out++ = tp;
+ }
+ }
}
};
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct collinear : public base_turn_handler
{
@@ -543,7 +564,7 @@ struct collinear : public base_turn_handler
ROBUSTNESS: p and q are collinear, so you would expect
that side qk//p1 == pk//q1. But that is not always the case
in near-epsilon ranges. Then decision logic is different.
- If p arrives, q is further, so the angle qk//p1 is (normally)
+ If p arrives, q is further, so the angle qk//p1 is (normally)
more precise than pk//p1
*/
@@ -552,24 +573,26 @@ struct collinear : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
- IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ IntersectionInfo const& info,
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_collinear;
- geometry::convert(intersection_info.intersections[1], ti.point);
+ // Copy the intersection point in TO direction
+ assign_point(ti, method_collinear, info, non_opposite_to_index(info));
int const arrival = dir_info.arrival[0];
// Should not be 0, this is checked before
BOOST_ASSERT(arrival != 0);
- int const side_p = SideStrategy::apply(pi, pj, pk);
- int const side_q = SideStrategy::apply(qi, qj, qk);
+ int const side_p = side.pk_wrt_p1();
+ int const side_q = side.qk_wrt_q1();
// If p arrives, use p, else use q
int const side_p_or_q = arrival == 1
@@ -577,9 +600,6 @@ struct collinear : public base_turn_handler
: side_q
;
- int const side_pk = SideStrategy::apply(qi, qj, pk);
- int const side_qk = SideStrategy::apply(pi, pj, qk);
-
// See comments above,
// resulting in a strange sort of mathematic rule here:
// The arrival-info multiplied by the relevant side
@@ -587,15 +607,7 @@ struct collinear : public base_turn_handler
int const product = arrival * side_p_or_q;
- // Robustness: side_p is supposed to be equal to side_pk (because p/q are collinear)
- // and side_q to side_qk
- bool const robustness_issue = side_pk != side_p || side_qk != side_q;
-
- if (robustness_issue)
- {
- handle_robustness(ti, arrival, side_p, side_q, side_pk, side_qk);
- }
- else if(product == 0)
+ if(product == 0)
{
both(ti, operation_continue);
}
@@ -605,43 +617,11 @@ struct collinear : public base_turn_handler
}
}
- static inline void handle_robustness(TurnInfo& ti, int arrival,
- int side_p, int side_q, int side_pk, int side_qk)
- {
- // We take the longer one, i.e. if q arrives in p (arrival == -1),
- // then p exceeds q and we should take p for a union...
-
- bool use_p_for_union = arrival == -1;
-
- // ... unless one of the sides consistently directs to the other side
- int const consistent_side_p = side_p == side_pk ? side_p : 0;
- int const consistent_side_q = side_q == side_qk ? side_q : 0;
- if (arrival == -1 && (consistent_side_p == -1 || consistent_side_q == 1))
- {
- use_p_for_union = false;
- }
- if (arrival == 1 && (consistent_side_p == 1 || consistent_side_q == -1))
- {
- use_p_for_union = true;
- }
-
- //std::cout << "ROBUSTNESS -> Collinear "
- // << " arr: " << arrival
- // << " dir: " << side_p << " " << side_q
- // << " rev: " << side_pk << " " << side_qk
- // << " cst: " << cside_p << " " << cside_q
- // << std::boolalpha << " " << use_p_for_union
- // << std::endl;
-
- ui_else_iu(use_p_for_union, ti);
- }
-
};
template
<
typename TurnInfo,
- typename SideStrategy,
typename AssignPolicy
>
struct collinear_opposite : public base_turn_handler
@@ -674,14 +654,19 @@ private :
template
<
int Index,
- typename Point,
+ typename Point1,
+ typename Point2,
typename IntersectionInfo
>
- static inline bool set_tp(Point const& ri, Point const& rj, Point const& rk,
+ static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r,
+ bool const handle_robustness,
+ Point2 const& , Point2 const& , int side_rk_s,
TurnInfo& tp, IntersectionInfo const& intersection_info)
{
- int const side_rk_r = SideStrategy::apply(ri, rj, rk);
- operation_type blocked = operation_blocked;
+ boost::ignore_unused_variable_warning(handle_robustness);
+ boost::ignore_unused_variable_warning(side_rk_s);
+
+ operation_type blocked = operation_blocked;
switch(side_rk_r)
{
@@ -699,16 +684,16 @@ private :
// two operations blocked, so the whole point does not need
// to be generated.
// So return false to indicate nothing is to be done.
- if (AssignPolicy::include_opposite)
- {
- tp.operations[Index].operation = operation_opposite;
- blocked = operation_opposite;
- }
- else
- {
- return false;
- }
- break;
+ if (AssignPolicy::include_opposite)
+ {
+ tp.operations[Index].operation = operation_opposite;
+ blocked = operation_opposite;
+ }
+ else
+ {
+ return false;
+ }
+ break;
}
// The other direction is always blocked when collinear opposite
@@ -717,18 +702,21 @@ private :
// If P arrives within Q, set info on P (which is done above, index=0),
// this turn-info belongs to the second intersection point, index=1
// (see e.g. figure CLO1)
- geometry::convert(intersection_info.intersections[1 - Index], tp.point);
+ assign_point(tp, method_collinear, intersection_info, 1 - Index);
return true;
}
public:
+ static inline void empty_transformer(TurnInfo &) {}
+
template
<
typename Point1,
typename Point2,
typename OutputIterator,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
@@ -739,46 +727,79 @@ public:
OutputIterator& out,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- TurnInfo tp = tp_model;
+ apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer);
+ }
- tp.method = method_collinear;
+public:
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename OutputIterator,
+ typename IntersectionInfo,
+ typename DirInfo,
+ typename SidePolicy,
+ typename TurnTransformer
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+
+ // Opposite collinear can deliver 2 intersection points,
+ TurnInfo const& tp_model,
+ OutputIterator& out,
+
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info,
+ SidePolicy const& side,
+ TurnTransformer turn_transformer,
+ bool const is_pk_valid = true, bool const is_qk_valid = true)
+ {
+ TurnInfo tp = tp_model;
// If P arrives within Q, there is a turn dependent on P
- if (dir_info.arrival[0] == 1
- && set_tp<0>(pi, pj, pk, tp, intersection_info))
+ if ( dir_info.arrival[0] == 1
+ && is_pk_valid
+ && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) )
{
+ turn_transformer(tp);
+
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
// If Q arrives within P, there is a turn dependent on Q
- if (dir_info.arrival[1] == 1
- && set_tp<1>(qi, qj, qk, tp, intersection_info))
+ if ( dir_info.arrival[1] == 1
+ && is_qk_valid
+ && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) )
{
+ turn_transformer(tp);
+
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
- if (AssignPolicy::include_opposite)
- {
- // Handle cases not yet handled above
- if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0)
- || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0))
- {
- for (int i = 0; i < 2; i++)
- {
- tp.operations[i].operation = operation_opposite;
- }
- for (unsigned int i = 0; i < intersection_info.count; i++)
- {
- geometry::convert(intersection_info.intersections[i], tp.point);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
- *out++ = tp;
- }
- }
- }
+ if (AssignPolicy::include_opposite)
+ {
+ // Handle cases not yet handled above
+ if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0)
+ || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0))
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ tp.operations[i].operation = operation_opposite;
+ }
+ for (unsigned int i = 0; i < intersection_info.count; i++)
+ {
+ assign_point(tp, method_collinear, intersection_info, i);
+ AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ *out++ = tp;
+ }
+ }
+ }
}
};
@@ -786,8 +807,7 @@ public:
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct crosses : public base_turn_handler
{
@@ -805,8 +825,7 @@ struct crosses : public base_turn_handler
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
- ti.method = method_crosses;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_crosses, intersection_info, 0);
// In all casees:
// If Q crosses P from left to right
@@ -820,14 +839,12 @@ struct crosses : public base_turn_handler
}
};
-template<typename TurnInfo>
-struct only_convert
+struct only_convert : public base_turn_handler
{
- template<typename IntersectionInfo>
+ template<typename TurnInfo, typename IntersectionInfo>
static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
{
- ti.method = method_collinear;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_none, intersection_info, 0); // was collinear
ti.operations[0].operation = operation_continue;
ti.operations[1].operation = operation_continue;
}
@@ -845,14 +862,14 @@ struct assign_null_policy
static bool const include_degenerate = false;
static bool const include_opposite = false;
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo const&)
{}
@@ -873,48 +890,39 @@ struct assign_null_policy
It also defines if a certain class of points
(degenerate, non-turns) should be included.
*/
-template
-<
- typename Point1,
- typename Point2,
- typename TurnInfo,
- typename AssignPolicy
->
+template<typename AssignPolicy>
struct get_turn_info
{
- typedef strategy_intersection
- <
- typename cs_tag<typename TurnInfo::point_type>::type,
- Point1,
- Point2,
- typename TurnInfo::point_type
- > si;
-
- typedef typename si::segment_intersection_strategy_type strategy;
-
// Intersect pi-pj with qi-qj
- // The points pk and qk are only used do determine more information
- // about the turn.
- template <typename OutputIterator>
+ // The points pk and qk are used do determine more information
+ // about the turn (turn left/right)
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool /*is_p_first*/, bool /*is_p_last*/,
+ bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
OutputIterator out)
{
- typedef model::referring_segment<Point1 const> segment_type1;
- typedef model::referring_segment<Point1 const> segment_type2;
- segment_type1 p1(pi, pj), p2(pj, pk);
- segment_type2 q1(qi, qj), q2(qj, qk);
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
- typename strategy::return_type result = strategy::apply(p1, q1);
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
- char const method = result.template get<1>().how;
+ char const method = inters.d_info().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
-
// Select method and apply
switch(method)
{
@@ -922,11 +930,10 @@ struct get_turn_info
case 'f' : // collinear, "from"
case 's' : // starts from the middle
if (AssignPolicy::include_no_turn
- && result.template get<0>().count > 0)
+ && inters.i_info().count > 0)
{
- only_convert<TurnInfo>::apply(tp,
- result.template get<0>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ only_convert::apply(tp, inters.i_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
@@ -938,113 +945,94 @@ struct get_turn_info
{
typedef touch_interior
<
- TurnInfo,
- typename si::side_strategy_type
+ TurnInfo
> policy;
// If Q (1) arrives (1)
- if (result.template get<1>().arrival[1] == 1)
+ if ( inters.d_info().arrival[1] == 1 )
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
}
else
{
// Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
- tp, result.template get<0>(), result.template get<1>());
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
}
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'i' :
{
- typedef crosses
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 't' :
{
// Both touch (both arrive there)
- typedef touch
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'e':
{
- if (! result.template get<1>().opposite)
+ if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
- typedef equal
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
- else
- {
+ else
+ {
equal_opposite
<
TurnInfo,
AssignPolicy
>::apply(pi, qi,
- tp, out, result.template get<0>(), result.template get<1>());
- }
+ tp, out, inters.i_info(), inters.d_info());
+ }
}
break;
case 'c' :
{
// Collinear
- if (! result.template get<1>().opposite)
+ if ( ! inters.d_info().opposite )
{
- if (result.template get<1>().arrival[0] == 0)
+ if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
- equal
- <
- TurnInfo,
- typename si::side_strategy_type
- >::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
// override assigned method
tp.method = method_collinear;
}
else
{
- collinear
- <
- TurnInfo,
- typename si::side_strategy_type
- >::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
}
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
else
@@ -1052,10 +1040,9 @@ struct get_turn_info
collinear_opposite
<
TurnInfo,
- typename si::side_strategy_type,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
- tp, out, result.template get<0>(), result.template get<1>());
+ tp, out, inters.i_info(), inters.d_info(), inters.sides());
}
}
break;
@@ -1064,14 +1051,17 @@ struct get_turn_info
// degenerate points
if (AssignPolicy::include_degenerate)
{
- only_convert<TurnInfo>::apply(tp, result.template get<0>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ only_convert::apply(tp, inters.i_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}
break;
default :
{
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
throw turn_info_exception(method);
#endif
@@ -1091,4 +1081,8 @@ struct get_turn_info
}} // namespace boost::geometry
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
new file mode 100644
index 0000000000..ca1b9d9d0c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
@@ -0,0 +1,657 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+// SEGMENT_INTERSECTION RESULT
+
+// C H0 H1 A0 A1 O IP1 IP2
+
+// D0 and D1 == 0
+
+// |--------> 2 0 0 0 0 F i/i x/x
+// |-------->
+//
+// |--------> 2 0 0 0 0 T i/x x/i
+// <--------|
+//
+// |-----> 1 0 0 0 0 T x/x
+// <-----|
+//
+
+// |---------> 2 0 0 0 1 T i/x x/i
+// <----|
+//
+// |---------> 2 0 0 0 0 F i/i x/x
+// |---->
+//
+// |---------> 2 0 0 -1 1 F i/i u/x
+// |---->
+//
+// |---------> 2 0 0 -1 0 T i/x u/i
+// <----|
+
+// |-------> 2 0 0 1 -1 F and i/i x/u
+// |-------> 2 0 0 -1 1 F symetric i/i u/x
+// |------->
+//
+// |-------> 2 0 0 -1 -1 T i/u u/i
+// <-------|
+//
+// |-------> 2 0 0 1 1 T i/x x/i
+// <-------|
+//
+// |--------> 2 0 0 -1 1 F i/i u/x
+// |---->
+//
+// |--------> 2 0 0 -1 1 T i/x u/i
+// <----|
+
+// |-----> 1 -1 -1 -1 -1 T u/u
+// <-----|
+//
+// |-----> 1 -1 0 -1 0 F and u/x
+// |-----> 1 0 -1 0 -1 F symetric x/u
+// |----->
+
+// D0 or D1 != 0
+
+// ^
+// |
+// + 1 -1 1 -1 1 F and u/x (P is vertical)
+// |--------> 1 1 -1 1 -1 F symetric x/u (P is horizontal)
+// ^
+// |
+// +
+//
+// +
+// |
+// v
+// |--------> 1 1 1 1 1 F x/x (P is vertical)
+//
+// ^
+// |
+// +
+// |--------> 1 -1 -1 -1 -1 F u/u (P is vertical)
+//
+// ^
+// |
+// +
+// |--------> 1 0 -1 0 -1 F u/u (P is vertical)
+//
+// +
+// |
+// v
+// |--------> 1 0 1 0 1 F u/x (P is vertical)
+//
+
+class linear_intersections
+{
+public:
+ template <typename Point1, typename Point2, typename IntersectionResult>
+ linear_intersections(Point1 const& pi,
+ Point2 const& qi,
+ IntersectionResult const& result,
+ bool is_p_last, bool is_q_last)
+ {
+ int arrival_a = result.template get<1>().arrival[0];
+ int arrival_b = result.template get<1>().arrival[1];
+ bool same_dirs = result.template get<1>().dir_a == 0
+ && result.template get<1>().dir_b == 0;
+
+ if ( same_dirs )
+ {
+ if ( result.template get<0>().count == 2 )
+ {
+ if ( ! result.template get<1>().opposite )
+ {
+ ips[0].p_operation = operation_intersection;
+ ips[0].q_operation = operation_intersection;
+ ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi
+ = equals::equals_point_point(
+ pi, result.template get<0>().intersections[0]);
+ ips[0].is_qi
+ = equals::equals_point_point(
+ qi, result.template get<0>().intersections[0]);
+ ips[1].is_pj = arrival_a != -1;
+ ips[1].is_qj = arrival_b != -1;
+ }
+ else
+ {
+ ips[0].p_operation = operation_intersection;
+ ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+ ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[1].q_operation = operation_intersection;
+
+ ips[0].is_pi = arrival_b != 1;
+ ips[0].is_qj = arrival_b != -1;
+ ips[1].is_pj = arrival_a != -1;
+ ips[1].is_qi = arrival_a != 1;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(result.template get<0>().count == 1);
+ ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi = arrival_a == -1;
+ ips[0].is_qi = arrival_b == -1;
+ ips[0].is_pj = arrival_a == 0;
+ ips[0].is_qj = arrival_b == 0;
+ }
+ }
+ else
+ {
+ ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last);
+ ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi = arrival_a == -1;
+ ips[0].is_qi = arrival_b == -1;
+ ips[0].is_pj = arrival_a == 1;
+ ips[0].is_qj = arrival_b == 1;
+ }
+ }
+
+ struct ip_info
+ {
+ inline ip_info()
+ : p_operation(operation_none), q_operation(operation_none)
+ , is_pi(false), is_pj(false), is_qi(false), is_qj(false)
+ {}
+
+ operation_type p_operation, q_operation;
+ bool is_pi, is_pj, is_qi, is_qj;
+ };
+
+ template <std::size_t I>
+ ip_info const& get() const
+ {
+ BOOST_STATIC_ASSERT(I < 2);
+ return ips[I];
+ }
+
+private:
+
+ // only if collinear (same_dirs)
+ static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last)
+ {
+ if ( arrival == 1 )
+ return operation_blocked;
+ else if ( arrival == -1 )
+ return operation_union;
+ else
+ return is_last ? operation_blocked : operation_union;
+ //return operation_blocked;
+ }
+
+ // only if not collinear (!same_dirs)
+ static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last)
+ {
+ if ( arrival == 1 )
+ //return operation_blocked;
+ return is_last ? operation_blocked : operation_union;
+ else
+ return operation_union;
+ }
+
+ ip_info ips[2];
+};
+
+template <typename AssignPolicy, bool EnableFirst, bool EnableLast>
+struct get_turn_info_for_endpoint
+{
+ BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
+
+ template<typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator
+ >
+ static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ method_type /*method*/,
+ OutputIterator out)
+ {
+ std::size_t ip_count = inters.i_info().count;
+ // no intersection points
+ if ( ip_count == 0 )
+ return false;
+
+ if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last )
+ return false;
+
+ linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
+
+ bool append0_last
+ = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ intersections.template get<0>(),
+ tp_model, inters, 0, out);
+
+ // NOTE: opposite && ip_count == 1 may be true!
+ bool opposite = inters.d_info().opposite;
+
+ // don't ignore only for collinear opposite
+ bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite );
+
+ if ( intersections.template get<1>().p_operation == operation_none )
+ return result_ignore_ip0;
+
+ bool append1_last
+ = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ intersections.template get<1>(),
+ tp_model, inters, 1, out);
+
+ // don't ignore only for collinear opposite
+ bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/;
+
+ return result_ignore_ip0 || result_ignore_ip1;
+ }
+
+ template <typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator>
+ static inline
+ bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ linear_intersections::ip_info const& ip_info,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ int ip_index,
+ OutputIterator out)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = result.template get<0>().intersections[ip_index];
+ BOOST_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt));
+ BOOST_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt));
+ BOOST_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt));
+ BOOST_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt));
+#endif
+
+ // TODO - calculate first/last only if needed
+ bool is_p_first_ip = is_p_first && ip_info.is_pi;
+ bool is_p_last_ip = is_p_last && ip_info.is_pj;
+ bool is_q_first_ip = is_q_first && ip_info.is_qi;
+ bool is_q_last_ip = is_q_last && ip_info.is_qj;
+ bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip);
+ bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip);
+
+ operation_type p_operation = ip_info.p_operation;
+ operation_type q_operation = ip_info.q_operation;
+
+ if ( append_first || append_last )
+ {
+ bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk,
+ inters.rpi(), inters.rpj(), inters.rpk(),
+ inters.rqi(), inters.rqj(), inters.rqk(),
+ is_p_first_ip, is_p_last_ip,
+ is_q_first_ip, is_q_last_ip,
+ ip_info.is_qi, ip_info.is_qj,
+ tp_model, inters, ip_index,
+ p_operation, q_operation);
+ if ( !handled )
+ {
+ handle_internal<1>(qi, qj, qk, pi, pj, pk,
+ inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk(),
+ is_q_first_ip, is_q_last_ip,
+ is_p_first_ip, is_p_last_ip,
+ ip_info.is_pi, ip_info.is_pj,
+ tp_model, inters, ip_index,
+ q_operation, p_operation);
+ }
+
+ if ( p_operation != operation_none )
+ {
+ method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj,
+ ip_info.is_qi, ip_info.is_qj);
+ turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip);
+ turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip);
+
+ // handle spikes
+
+ // P is spike and should be handled
+ if ( !is_p_last
+ && ip_info.is_pj // this check is redundant (also in is_spike_p) but faster
+ && inters.i_info().count == 2
+ && inters.is_spike_p() )
+ {
+ assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
+ assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
+ }
+ // Q is spike and should be handled
+ else if ( !is_q_last
+ && ip_info.is_qj // this check is redundant (also in is_spike_q) but faster
+ && inters.i_info().count == 2
+ && inters.is_spike_q() )
+ {
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
+ }
+ // no spikes
+ else
+ {
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out);
+ }
+ }
+ }
+
+ return append_last;
+ }
+
+ // TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment
+ // however now it's lazily calculated and then it would be always calculated
+
+ template<std::size_t G1Index,
+ typename Point1,
+ typename Point2,
+ typename RobustPoint1,
+ typename RobustPoint2,
+ typename TurnInfo,
+ typename IntersectionInfo
+ >
+ static inline bool handle_internal(Point1 const& /*i1*/, Point1 const& /*j1*/, Point1 const& /*k1*/,
+ Point2 const& i2, Point2 const& j2, Point2 const& /*k2*/,
+ RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/,
+ RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2,
+ bool first1, bool last1, bool first2, bool last2,
+ bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
+ IntersectionInfo const& inters, int ip_index,
+ operation_type & op1, operation_type & op2)
+ {
+ boost::ignore_unused_variable_warning(i2);
+ boost::ignore_unused_variable_warning(j2);
+ boost::ignore_unused_variable_warning(ip_index);
+ boost::ignore_unused_variable_warning(tp_model);
+
+ if ( !first2 && !last2 )
+ {
+ if ( first1 )
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = inters.i_info().intersections[ip_index];
+ BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
+ BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
+#endif
+ if ( ip_i2 )
+ {
+ // don't output this IP - for the first point of other geometry segment
+ op1 = operation_none;
+ op2 = operation_none;
+ return true;
+ }
+ else if ( ip_j2 )
+ {
+ side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
+ side_calc(ri2, ri1, rj1, ri2, rj2, rk2);
+
+ std::pair<operation_type, operation_type>
+ operations = operations_of_equal(side_calc);
+
+// TODO: must the above be calculated?
+// wouldn't it be enough to check if segments are collinear?
+
+ if ( operations_both(operations, operation_continue) )
+ {
+ if ( op1 != operation_union
+ || op2 != operation_union
+ || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
+ {
+ // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
+ bool opposite = inters.d_info().opposite;
+
+ op1 = operation_intersection;
+ op2 = opposite ? operation_union : operation_intersection;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union));
+ //op1 = operation_union;
+ //op2 = operation_union;
+ }
+
+ return true;
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+ else if ( last1 )
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = inters.i_info().intersections[ip_index];
+ BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
+ BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
+#endif
+ if ( ip_i2 )
+ {
+ // don't output this IP - for the first point of other geometry segment
+ op1 = operation_none;
+ op2 = operation_none;
+ return true;
+ }
+ else if ( ip_j2 )
+ {
+ side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
+ side_calc(ri2, rj1, ri1, ri2, rj2, rk2);
+
+ std::pair<operation_type, operation_type>
+ operations = operations_of_equal(side_calc);
+
+// TODO: must the above be calculated?
+// wouldn't it be enough to check if segments are collinear?
+
+ if ( operations_both(operations, operation_continue) )
+ {
+ if ( op1 != operation_blocked
+ || op2 != operation_union
+ || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
+ {
+ // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
+ bool second_going_out = inters.i_info().count > 1;
+
+ op1 = operation_blocked;
+ op2 = second_going_out ? operation_union : operation_intersection;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union));
+ //op1 = operation_blocked;
+ //op2 = operation_union;
+ }
+
+ return true;
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+
+ return false;
+ }
+
+ static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj)
+ {
+ if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) )
+ return method_touch;
+ else
+ return method_touch_interior;
+ }
+
+ static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j)
+ {
+ return is_ip_first_i ? position_front :
+ ( is_ip_last_j ? position_back : position_middle );
+ }
+
+ template <typename Point1,
+ typename Point2,
+ typename IntersectionResult,
+ typename TurnInfo,
+ typename OutputIterator>
+ static inline void assign(Point1 const& pi, Point2 const& qi,
+ IntersectionResult const& result,
+ int ip_index,
+ method_type method,
+ operation_type op0, operation_type op1,
+ turn_position pos0, turn_position pos1,
+ bool is_p_first_ip, bool is_q_first_ip,
+ bool is_p_spike, bool is_q_spike,
+ TurnInfo const& tp_model,
+ OutputIterator out)
+ {
+ TurnInfo tp = tp_model;
+
+ //geometry::convert(ip, tp.point);
+ //tp.method = method;
+ base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index);
+
+ tp.operations[0].operation = op0;
+ tp.operations[1].operation = op1;
+ tp.operations[0].position = pos0;
+ tp.operations[1].position = pos1;
+
+ if ( result.template get<0>().count > 1 )
+ {
+ // NOTE: is_collinear is NOT set for the first endpoint
+ // for which there is no preceding segment
+
+ //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
+ if ( ! is_p_first_ip )
+ {
+ tp.operations[0].is_collinear = op0 != operation_intersection
+ || is_p_spike;
+ }
+
+ if ( ! is_q_first_ip )
+ {
+ tp.operations[1].is_collinear = op1 != operation_intersection
+ || is_q_spike;
+ }
+ }
+ else //if ( result.template get<0>().count == 1 )
+ {
+ if ( op0 == operation_blocked && op1 == operation_intersection )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else if ( op0 == operation_intersection && op1 == operation_blocked )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+
+ AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ *out++ = tp;
+ }
+
+ template <typename SidePolicy>
+ static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side)
+ {
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_p = side.qk_wrt_p1();
+
+ // If pk is collinear with qj-qk, they continue collinearly.
+ // This can be on either side of p1 (== q1), or collinear
+ // The second condition checks if they do not continue
+ // oppositely
+ if ( side_pk_q2 == 0 && side_pk_p == side_qk_p )
+ {
+ return std::make_pair(operation_continue, operation_continue);
+ }
+
+ // If they turn to same side (not opposite sides)
+ if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) )
+ {
+ // If pk is left of q2 or collinear: p: union, q: intersection
+ if ( side_pk_q2 != -1 )
+ {
+ return std::make_pair(operation_union, operation_intersection);
+ }
+ else
+ {
+ return std::make_pair(operation_intersection, operation_union);
+ }
+ }
+ else
+ {
+ // They turn opposite sides. If p turns left (or collinear),
+ // p: union, q: intersection
+ if ( side_pk_p != -1 )
+ {
+ return std::make_pair(operation_union, operation_intersection);
+ }
+ else
+ {
+ return std::make_pair(operation_intersection, operation_union);
+ }
+ }
+ }
+
+ static inline bool operations_both(
+ std::pair<operation_type, operation_type> const& operations,
+ operation_type const op)
+ {
+ return operations.first == op && operations.second == op;
+ }
+
+ static inline bool operations_combination(
+ std::pair<operation_type, operation_type> const& operations,
+ operation_type const op1, operation_type const op2)
+ {
+ return ( operations.first == op1 && operations.second == op2 )
+ || ( operations.first == op2 && operations.second == op1 );
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
new file mode 100644
index 0000000000..eead0d719b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
@@ -0,0 +1,329 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
+
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+enum turn_position { position_middle, position_front, position_back };
+
+template <typename SegmentRatio>
+struct turn_operation_linear
+ : public turn_operation<SegmentRatio>
+{
+ turn_operation_linear()
+ : position(position_middle)
+ , is_collinear(false)
+ {}
+
+ turn_position position;
+ bool is_collinear; // valid only for Linear geometry
+};
+
+template <typename PointP, typename PointQ,
+ typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
+ typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
+>
+struct side_calculator
+{
+ typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
+
+ inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
+ Qi const& qi, Qj const& qj, Qk const& qk)
+ : m_pi(pi), m_pj(pj), m_pk(pk)
+ , m_qi(qi), m_qj(qj), m_qk(qk)
+ {}
+
+ inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); }
+ inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); }
+ inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); }
+ inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); }
+
+ inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
+ inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
+
+ Pi const& m_pi;
+ Pj const& m_pj;
+ Pk const& m_pk;
+ Qi const& m_qi;
+ Qj const& m_qj;
+ Qk const& m_qk;
+};
+
+template <typename Point1, typename Point2, typename RobustPolicy>
+struct robust_points
+{
+ typedef typename geometry::robust_point_type
+ <
+ Point1, RobustPolicy
+ >::type robust_point1_type;
+ // TODO: define robust_point2_type using Point2?
+ typedef robust_point1_type robust_point2_type;
+
+ inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ {
+ geometry::recalculate(m_rpi, pi, robust_policy);
+ geometry::recalculate(m_rpj, pj, robust_policy);
+ geometry::recalculate(m_rpk, pk, robust_policy);
+ geometry::recalculate(m_rqi, qi, robust_policy);
+ geometry::recalculate(m_rqj, qj, robust_policy);
+ geometry::recalculate(m_rqk, qk, robust_policy);
+ }
+
+ robust_point1_type m_rpi, m_rpj, m_rpk;
+ robust_point2_type m_rqi, m_rqj, m_rqk;
+};
+
+template <typename Point1, typename Point2, typename RobustPolicy>
+class intersection_info_base
+ : private robust_points<Point1, Point2, RobustPolicy>
+{
+ typedef robust_points<Point1, Point2, RobustPolicy> base_t;
+
+public:
+ typedef Point1 point1_type;
+ typedef Point2 point2_type;
+
+ typedef typename base_t::robust_point1_type robust_point1_type;
+ typedef typename base_t::robust_point2_type robust_point2_type;
+
+ typedef side_calculator<robust_point1_type, robust_point2_type> side_calculator_type;
+
+ intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ : base_t(pi, pj, pk, qi, qj, qk, robust_policy)
+ , m_side_calc(base_t::m_rpi, base_t::m_rpj, base_t::m_rpk,
+ base_t::m_rqi, base_t::m_rqj, base_t::m_rqk)
+ , m_pi(pi), m_pj(pj), m_pk(pk)
+ , m_qi(qi), m_qj(qj), m_qk(qk)
+ {}
+
+ inline Point1 const& pi() const { return m_pi; }
+ inline Point1 const& pj() const { return m_pj; }
+ inline Point1 const& pk() const { return m_pk; }
+
+ inline Point2 const& qi() const { return m_qi; }
+ inline Point2 const& qj() const { return m_qj; }
+ inline Point2 const& qk() const { return m_qk; }
+
+ inline robust_point1_type const& rpi() const { return base_t::m_rpi; }
+ inline robust_point1_type const& rpj() const { return base_t::m_rpj; }
+ inline robust_point1_type const& rpk() const { return base_t::m_rpk; }
+
+ inline robust_point2_type const& rqi() const { return base_t::m_rqi; }
+ inline robust_point2_type const& rqj() const { return base_t::m_rqj; }
+ inline robust_point2_type const& rqk() const { return base_t::m_rqk; }
+
+ inline side_calculator_type const& sides() const { return m_side_calc; }
+
+private:
+ side_calculator_type m_side_calc;
+
+ point1_type const& m_pi;
+ point1_type const& m_pj;
+ point1_type const& m_pk;
+ point2_type const& m_qi;
+ point2_type const& m_qj;
+ point2_type const& m_qk;
+};
+
+template <typename Point1, typename Point2>
+class intersection_info_base<Point1, Point2, detail::no_rescale_policy>
+{
+public:
+ typedef Point1 point1_type;
+ typedef Point2 point2_type;
+
+ typedef Point1 robust_point1_type;
+ typedef Point2 robust_point2_type;
+
+ typedef side_calculator<Point1, Point2> side_calculator_type;
+
+ intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ no_rescale_policy const& /*robust_policy*/)
+ : m_side_calc(pi, pj, pk, qi, qj, qk)
+ {}
+
+ inline Point1 const& pi() const { return m_side_calc.m_pi; }
+ inline Point1 const& pj() const { return m_side_calc.m_pj; }
+ inline Point1 const& pk() const { return m_side_calc.m_pk; }
+
+ inline Point2 const& qi() const { return m_side_calc.m_qi; }
+ inline Point2 const& qj() const { return m_side_calc.m_qj; }
+ inline Point2 const& qk() const { return m_side_calc.m_qk; }
+
+ inline Point1 const& rpi() const { return pi(); }
+ inline Point1 const& rpj() const { return pj(); }
+ inline Point1 const& rpk() const { return pk(); }
+
+ inline Point2 const& rqi() const { return qi(); }
+ inline Point2 const& rqj() const { return qj(); }
+ inline Point2 const& rqk() const { return qk(); }
+
+ inline side_calculator_type const& sides() const { return m_side_calc; }
+
+private:
+ side_calculator_type m_side_calc;
+};
+
+
+template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
+class intersection_info
+ : public intersection_info_base<Point1, Point2, RobustPolicy>
+{
+ typedef intersection_info_base<Point1, Point2, RobustPolicy> base_t;
+
+ typedef typename strategy_intersection
+ <
+ typename cs_tag<TurnPoint>::type,
+ Point1,
+ Point2,
+ TurnPoint,
+ RobustPolicy
+ >::segment_intersection_strategy_type strategy;
+
+public:
+ typedef model::referring_segment<Point1 const> segment_type1;
+ typedef model::referring_segment<Point2 const> segment_type2;
+ typedef typename base_t::side_calculator_type side_calculator_type;
+
+ typedef typename strategy::return_type result_type;
+ typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
+ typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
+
+ intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ : base_t(pi, pj, pk, qi, qj, qk, robust_policy)
+ , m_result(strategy::apply(segment_type1(pi, pj),
+ segment_type2(qi, qj),
+ robust_policy))
+ , m_robust_policy(robust_policy)
+ {}
+
+ inline result_type const& result() const { return m_result; }
+ inline i_info_type const& i_info() const { return m_result.template get<0>(); }
+ inline d_info_type const& d_info() const { return m_result.template get<1>(); }
+
+ // TODO: it's more like is_spike_ip_p
+ inline bool is_spike_p() const
+ {
+ if ( base_t::sides().pk_wrt_p1() == 0 )
+ {
+ if ( ! is_ip_j<0>() )
+ return false;
+
+ int const qk_p1 = base_t::sides().qk_wrt_p1();
+ int const qk_p2 = base_t::sides().qk_wrt_p2();
+
+ if ( qk_p1 == -qk_p2 )
+ {
+ if ( qk_p1 == 0 )
+ {
+ return is_spike_of_collinear(base_t::pi(), base_t::pj(), base_t::pk());
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // TODO: it's more like is_spike_ip_q
+ inline bool is_spike_q() const
+ {
+ if ( base_t::sides().qk_wrt_q1() == 0 )
+ {
+ if ( ! is_ip_j<1>() )
+ return false;
+
+ int const pk_q1 = base_t::sides().pk_wrt_q1();
+ int const pk_q2 = base_t::sides().pk_wrt_q2();
+
+ if ( pk_q1 == -pk_q2 )
+ {
+ if ( pk_q1 == 0 )
+ {
+ return is_spike_of_collinear(base_t::qi(), base_t::qj(), base_t::qk());
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+private:
+ template <typename Point>
+ inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
+ {
+ typedef model::referring_segment<Point const> seg_t;
+
+ typedef strategy_intersection
+ <
+ typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
+ typename strategy::return_type result
+ = strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
+
+ return result.template get<0>().count == 2;
+ }
+
+ template <std::size_t OpId>
+ bool is_ip_j() const
+ {
+ int arrival = d_info().arrival[OpId];
+ bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
+
+ if ( same_dirs )
+ {
+ if ( i_info().count == 2 )
+ {
+ return arrival != -1;
+ }
+ else
+ {
+ return arrival == 0;
+ }
+ }
+ else
+ {
+ return arrival == 1;
+ }
+ }
+
+ result_type m_result;
+ RobustPolicy const& m_robust_policy;
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
new file mode 100644
index 0000000000..873567bbf5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
@@ -0,0 +1,805 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
+
+// TEMP, for spikes detector
+//#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+template<typename AssignPolicy>
+struct get_turn_info_linear_areal
+{
+ static const bool handle_spikes = true;
+
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
+ {
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
+
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
+
+ char const method = inters.d_info().how;
+
+ // Copy, to copy possibly extended fields
+ TurnInfo tp = tp_model;
+
+ // Select method and apply
+ switch(method)
+ {
+ case 'a' : // collinear, "at"
+ case 'f' : // collinear, "from"
+ case 's' : // starts from the middle
+ get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_none, out);
+ break;
+
+ case 'd' : // disjoint: never do anything
+ break;
+
+ case 'm' :
+ {
+ if ( get_turn_info_for_endpoint<false, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch_interior, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ typedef touch_interior
+ <
+ TurnInfo
+ > policy;
+
+ // If Q (1) arrives (1)
+ if ( inters.d_info().arrival[1] == 1 )
+ {
+ policy::template apply<0>(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
+ }
+ else
+ {
+ // Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
+ policy::template apply<1>(qi, qj, qk, pi, pj, pk,
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
+ }
+
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ // this function assumes that 'u' must be set for a spike
+ calculate_spike_operation(tp.operations[0].operation,
+ inters, is_p_last);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ *out++ = tp;
+ }
+ }
+ break;
+ case 'i' :
+ {
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+
+ replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ break;
+ case 't' :
+ {
+ // Both touch (both arrive there)
+ if ( get_turn_info_for_endpoint<false, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ // workarounds for touch<> not taking spikes into account starts here
+ // those was discovered empirically
+ // touch<> is not symmetrical!
+ // P spikes and Q spikes may produce various operations!
+ // Only P spikes are valid for L/A
+ // TODO: this is not optimal solution - think about rewriting touch<>
+
+ if ( tp.operations[0].operation == operation_blocked )
+ {
+ // a spike on P on the same line with Q1
+ if ( inters.is_spike_p() )
+ {
+ if ( inters.sides().qk_wrt_p1() == 0 )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[0].operation = operation_union;
+ }
+ }
+ }
+ else if ( tp.operations[0].operation == operation_continue
+ && tp.operations[1].operation == operation_continue )
+ {
+ // P spike on the same line with Q2 (opposite)
+ if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
+ && inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_none
+ && tp.operations[1].operation == operation_none )
+ {
+ // spike not handled by touch<>
+ if ( inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_union;
+
+ if ( inters.sides().pk_wrt_q2() == 0 )
+ {
+ tp.operations[0].operation = operation_continue; // will be converted to i
+ tp.operations[0].is_collinear = true;
+ }
+ }
+ }
+
+ // workarounds for touch<> not taking spikes into account ends here
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ bool ignore_spike
+ = calculate_spike_operation(tp.operations[0].operation,
+ inters, is_p_last);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ if ( ! handle_spikes
+ || ignore_spike
+ || ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i???
+ tp, inters, is_p_last, is_q_last, out) )
+ {
+ *out++ = tp;
+ }
+ }
+ }
+ break;
+ case 'e':
+ {
+ if ( get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_equal, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ // Both equal
+ // or collinear-and-ending at intersection point
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ turn_transformer_ec<false> transformer(method_touch);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
+ method_touch, append_equal, out) )
+ {
+ *out++ = tp; // no spikes
+ }
+ }
+ else
+ {
+ equal_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, qi,
+ tp, out, inters.i_info(), inters.d_info());
+ }
+ }
+ }
+ break;
+ case 'c' :
+ {
+ // Collinear
+ if ( get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_collinear, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ method_type method_replace = method_touch_interior;
+ append_version_c version = append_collinear;
+
+ if ( inters.d_info().arrival[0] == 0 )
+ {
+ // Collinear, but similar thus handled as equal
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ method_replace = method_touch;
+ version = append_equal;
+ }
+ else
+ {
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ //method_replace = method_touch_interior;
+ //version = append_collinear;
+ }
+
+ turn_transformer_ec<false> transformer(method_replace);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
+ method_replace, version, out) )
+ {
+ // no spikes
+ *out++ = tp;
+ }
+ }
+ else
+ {
+ // Is this always 'm' ?
+ turn_transformer_ec<false> transformer(method_touch_interior);
+
+ // conditionally handle spikes
+ if ( handle_spikes )
+ {
+ append_opposite_spikes<append_collinear_opposite>(
+ tp, inters, is_p_last, is_q_last, out);
+ }
+
+ // TODO: ignore for spikes?
+ // E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
+ // the same with is_q_valid
+
+ collinear_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, out, inters.i_info(), inters.d_info(),
+ inters.sides(), transformer);
+ }
+ }
+ }
+ break;
+ case '0' :
+ {
+ // degenerate points
+ if (AssignPolicy::include_degenerate)
+ {
+ only_convert::apply(tp, inters.i_info());
+
+ if ( is_p_first
+ && equals::equals_point_point(pi, tp.point) )
+ {
+ tp.operations[0].position = position_front;
+ }
+ else if ( is_p_last
+ && equals::equals_point_point(pj, tp.point) )
+ {
+ tp.operations[0].position = position_back;
+ }
+ // tp.operations[1].position = position_middle;
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ default :
+ {
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw turn_info_exception(method);
+#endif
+ }
+ break;
+ }
+
+ return out;
+ }
+
+ template <typename Operation,
+ typename IntersectionInfo>
+ static inline bool calculate_spike_operation(Operation & op,
+ IntersectionInfo const& inters,
+ bool is_p_last)
+ {
+ bool is_p_spike = ( op == operation_union || op == operation_intersection )
+ && ! is_p_last
+ && inters.is_spike_p();
+
+ if ( is_p_spike )
+ {
+ bool going_in = false, going_out = false;
+
+ int const pk_q1 = inters.sides().pk_wrt_q1();
+ int const pk_q2 = inters.sides().pk_wrt_q2();
+
+ if ( inters.sides().qk_wrt_q1() <= 0 ) // Q turning R or C
+ {
+ going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both
+ going_out = pk_q1 > 0 || pk_q2 > 0; // Pk on the left of one of them
+ }
+ else
+ {
+ going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them
+ going_out = pk_q1 > 0 && pk_q2 > 0; // Pk on the left of both
+ }
+
+ if ( going_in )
+ {
+ op = operation_intersection;
+ return true;
+ }
+ else if ( going_out )
+ {
+ op = operation_union;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ enum append_version_c { append_equal, append_collinear };
+
+ template <typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_collinear_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool /*is_q_last*/,
+ method_type method, append_version_c version,
+ OutIt out)
+ {
+ // method == touch || touch_interior
+ // both position == middle
+
+ bool is_p_spike = ( version == append_equal ?
+ ( tp.operations[0].operation == operation_union
+ || tp.operations[0].operation == operation_intersection ) :
+ tp.operations[0].operation == operation_continue )
+ && ! is_p_last
+ && inters.is_spike_p();
+
+ // TODO: throw an exception for spike in Areal?
+ /*bool is_q_spike = tp.operations[1].operation == spike_op
+ && ! is_q_last
+ && inters.is_spike_q();*/
+
+ if ( is_p_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_union;
+ *out++ = tp;
+ tp.operations[0].operation = operation_continue; // boundary
+ //tp.operations[1].operation = operation_union;
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ enum append_version_o { append_touches, append_collinear_opposite };
+
+ template <append_version_o Version,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_opposite_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool /*is_q_last*/,
+ OutIt out)
+ {
+ bool is_p_spike = ( Version == append_touches ?
+ ( tp.operations[0].operation == operation_continue
+ || tp.operations[0].operation == operation_intersection ) : // i ???
+ true )
+ && ! is_p_last
+ && inters.is_spike_p();
+ // TODO: throw an exception for spike in Areal?
+ /*bool is_q_spike = ( Version == append_touches ?
+ ( tp.operations[1].operation == operation_continue
+ || tp.operations[1].operation == operation_intersection ) :
+ true )
+ && ! is_q_last
+ && inters.is_spike_q();*/
+
+ if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = true;
+ //tp.operations[1].is_collinear = false;
+ tp.method = method_touch;
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ //tp.operations[1].is_collinear = false;
+
+ BOOST_ASSERT(inters.i_info().count > 1);
+ base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_continue; // boundary
+ *out++ = tp;
+ tp.operations[0].operation = operation_continue; // boundary
+ //tp.operations[1].operation = operation_continue; // boundary
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static inline void replace_method_and_operations_tm(method_type & method,
+ operation_type & op0,
+ operation_type & op1)
+ {
+ if ( op0 == operation_blocked && op1 == operation_blocked )
+ {
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ method = (method == method_touch ? method_equal : method_collinear);
+ }
+
+ // Assuming G1 is always Linear
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_continue;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_continue;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ // spikes in 'm'
+ if ( method == method_error )
+ {
+ method = method_touch_interior;
+ op0 = operation_union;
+ op1 = operation_union;
+ }
+ }
+
+ template <bool IsFront>
+ class turn_transformer_ec
+ {
+ public:
+ explicit turn_transformer_ec(method_type method_t_or_m)
+ : m_method(method_t_or_m)
+ {}
+
+ template <typename Turn>
+ void operator()(Turn & turn) const
+ {
+ operation_type & op0 = turn.operations[0].operation;
+ operation_type & op1 = turn.operations[1].operation;
+
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ if ( IsFront
+ || op0 == operation_intersection || op0 == operation_union
+ || op1 == operation_intersection || op1 == operation_union )
+ {
+ turn.method = m_method;
+ }
+
+ turn.operations[0].is_collinear = op0 != operation_blocked;
+
+ // Assuming G1 is always Linear
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_continue;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_continue;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+ }
+
+ private:
+ method_type m_method;
+ };
+
+ static inline void replace_operations_i(operation_type & /*op0*/, operation_type & op1)
+ {
+ // assuming Linear is always the first one
+ op1 = operation_union;
+ }
+
+ // NOTE: Spikes may NOT be handled for Linear endpoints because it's not
+ // possible to define a spike on an endpoint. Areal geometries must
+ // NOT have spikes at all. One thing that could be done is to throw
+ // an exception when spike is detected in Areal geometry.
+
+ template <bool EnableFirst,
+ bool EnableLast,
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator>
+ static inline bool get_turn_info_for_endpoint(
+ Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/,
+ Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/,
+ bool is_p_first, bool is_p_last,
+ bool /*is_q_first*/, bool is_q_last,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ method_type /*method*/,
+ OutputIterator out)
+ {
+ namespace ov = overlay;
+ typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e;
+
+ const std::size_t ip_count = inters.i_info().count;
+ // no intersection points
+ if ( ip_count == 0 )
+ return false;
+
+ if ( !is_p_first && !is_p_last )
+ return false;
+
+// TODO: is_q_last could probably be replaced by false and removed from parameters
+
+ linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
+ linear_intersections::ip_info const& ip0 = intersections.template get<0>();
+ linear_intersections::ip_info const& ip1 = intersections.template get<1>();
+
+ const bool opposite = inters.d_info().opposite;
+
+ // ANALYSE AND ASSIGN FIRST
+
+ // IP on the first point of Linear Geometry
+ if ( EnableFirst && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication
+ {
+ TurnInfo tp = tp_model;
+ tp.operations[0].position = position_front;
+ tp.operations[1].position = position_middle;
+
+ if ( opposite ) // opposite -> collinear
+ {
+ tp.operations[0].operation = operation_continue;
+ tp.operations[1].operation = operation_union;
+ tp.method = ip0.is_qj ? method_touch : method_touch_interior;
+ }
+ else
+ {
+ method_type replaced_method = method_touch_interior;
+
+ if ( ip0.is_qj )
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
+ inters.rqi(), inters.rqj(), inters.rqk());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+
+ replaced_method = method_touch;
+ }
+ else
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
+ inters.rqi(), inters.rpi(), inters.rqj());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+ }
+
+ turn_transformer_ec<true> transformer(replaced_method);
+ transformer(tp);
+ }
+
+ // equals<> or collinear<> will assign the second point,
+ // we'd like to assign the first one
+ base_turn_handler::assign_point(tp, tp.method, inters.i_info(), 0);
+
+ // NOTE: is_collinear is not set for the first endpoint of L
+ // for which there is no preceding segment
+ // here is_p_first_ip == true
+ tp.operations[0].is_collinear = false;
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+
+ // ANALYSE AND ASSIGN LAST
+
+ // IP on the last point of Linear Geometry
+ if ( EnableLast
+ && is_p_last
+ && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication
+ {
+ TurnInfo tp = tp_model;
+
+ if ( inters.i_info().count > 1 )
+ {
+ //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].operation = opposite ? operation_continue : operation_union;
+ }
+ else //if ( result.template get<0>().count == 1 )
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpj(), inters.rpi(),
+ inters.rqi(), inters.rqj(), inters.rqk());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+
+ turn_transformer_ec<false> transformer(method_none);
+ transformer(tp);
+
+ tp.operations[0].is_collinear = tp.both(operation_continue);
+ }
+
+ tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[0].position = position_back;
+ tp.operations[1].position = position_middle;
+
+ // equals<> or collinear<> will assign the second point,
+ // we'd like to assign the first one
+ int ip_index = ip_count > 1 ? 1 : 0;
+ base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+
+ return true;
+ }
+
+ // don't ignore anything for now
+ return false;
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
new file mode 100644
index 0000000000..4f0384877f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
@@ -0,0 +1,720 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+template<typename AssignPolicy>
+struct get_turn_info_linear_linear
+{
+ static const bool handle_spikes = true;
+
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
+ {
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
+
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
+
+ char const method = inters.d_info().how;
+
+ // Copy, to copy possibly extended fields
+ TurnInfo tp = tp_model;
+
+ // Select method and apply
+ switch(method)
+ {
+ case 'a' : // collinear, "at"
+ case 'f' : // collinear, "from"
+ case 's' : // starts from the middle
+ get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_none, out);
+ break;
+
+ case 'd' : // disjoint: never do anything
+ break;
+
+ case 'm' :
+ {
+ if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch_interior, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ typedef touch_interior
+ <
+ TurnInfo
+ > policy;
+
+ // If Q (1) arrives (1)
+ if ( inters.d_info().arrival[1] == 1)
+ {
+ policy::template apply<0>(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
+ }
+ else
+ {
+ // Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
+
+ policy::template apply<1>(qi, qj, qk, pi, pj, pk,
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
+ }
+
+ if ( tp.operations[0].operation == operation_blocked )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ case 'i' :
+ {
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+
+ replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ break;
+ case 't' :
+ {
+ // Both touch (both arrive there)
+ if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ // workarounds for touch<> not taking spikes into account starts here
+ // those was discovered empirically
+ // touch<> is not symmetrical!
+ // P spikes and Q spikes may produce various operations!
+ // TODO: this is not optimal solution - think about rewriting touch<>
+
+ if ( tp.operations[0].operation == operation_blocked
+ && tp.operations[1].operation == operation_blocked )
+ {
+ // two touching spikes on the same line
+ if ( inters.is_spike_p() && inters.is_spike_q() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_blocked )
+ {
+ // a spike on P on the same line with Q1
+ if ( inters.is_spike_p() )
+ {
+ if ( inters.sides().qk_wrt_p1() == 0 )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[0].operation = operation_union;
+ }
+ }
+ else
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[1].operation == operation_blocked )
+ {
+ // a spike on Q on the same line with P1
+ if ( inters.is_spike_q() )
+ {
+ if ( inters.sides().pk_wrt_q1() == 0 )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_continue
+ && tp.operations[1].operation == operation_continue )
+ {
+ // P spike on the same line with Q2 (opposite)
+ if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
+ && inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_none
+ && tp.operations[1].operation == operation_none )
+ {
+ // spike not handled by touch<>
+ bool const is_p = inters.is_spike_p();
+ bool const is_q = inters.is_spike_q();
+
+ if ( is_p || is_q )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+
+ if ( inters.sides().pk_wrt_q2() == 0 )
+ {
+ tp.operations[0].operation = operation_continue; // will be converted to i
+ if ( is_p )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ }
+
+ if ( inters.sides().qk_wrt_p2() == 0 )
+ {
+ tp.operations[1].operation = operation_continue; // will be converted to i
+ if ( is_q )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ }
+ }
+
+ // workarounds for touch<> not taking spikes into account ends here
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ if ( ! handle_spikes
+ || ! append_opposite_spikes<append_touches>(tp, inters,
+ is_p_last, is_q_last,
+ out) )
+ {
+ *out++ = tp;
+ }
+ }
+ }
+ break;
+ case 'e':
+ {
+ if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_equal, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ // Both equal
+ // or collinear-and-ending at intersection point
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ // transform turn
+ turn_transformer_ec transformer(method_touch);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters,
+ is_p_last, is_q_last,
+ method_touch, operation_union,
+ out) )
+ {
+ *out++ = tp; // no spikes
+ }
+ }
+ else
+ {
+ // TODO: ignore for spikes or generate something else than opposite?
+
+ equal_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, qi, tp, out, inters.i_info(), inters.d_info());
+ }
+ }
+ }
+ break;
+ case 'c' :
+ {
+ // Collinear
+ if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_collinear, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ // NOTE: this is for spikes since those are set in the turn_transformer_ec
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ method_type method_replace = method_touch_interior;
+ operation_type spike_op = operation_continue;
+
+ if ( inters.d_info().arrival[0] == 0 )
+ {
+ // Collinear, but similar thus handled as equal
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ method_replace = method_touch;
+ spike_op = operation_union;
+ }
+ else
+ {
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ //method_replace = method_touch_interior;
+ //spike_op = operation_continue;
+ }
+
+ // transform turn
+ turn_transformer_ec transformer(method_replace);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters,
+ is_p_last, is_q_last,
+ method_replace, spike_op,
+ out) )
+ {
+ // no spikes
+ *out++ = tp;
+ }
+ }
+ else
+ {
+ // If this always 'm' ?
+ turn_transformer_ec transformer(method_touch_interior);
+
+ // conditionally handle spikes
+ if ( handle_spikes )
+ {
+ append_opposite_spikes<append_collinear_opposite>(tp, inters,
+ is_p_last, is_q_last,
+ out);
+ }
+
+ // TODO: ignore for spikes?
+ // E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
+ // the same with is_q_valid
+
+ collinear_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, out, inters.i_info(), inters.d_info(), inters.sides(),
+ transformer, !is_p_last, !is_q_last);
+ }
+ }
+ }
+ break;
+ case '0' :
+ {
+ // degenerate points
+ if (AssignPolicy::include_degenerate)
+ {
+ only_convert::apply(tp, inters.i_info());
+
+ // if any, only one of those should be true
+ if ( is_p_first
+ && equals::equals_point_point(pi, tp.point) )
+ {
+ tp.operations[0].position = position_front;
+ }
+ else if ( is_p_last
+ && equals::equals_point_point(pj, tp.point) )
+ {
+ tp.operations[0].position = position_back;
+ }
+ else if ( is_q_first
+ && equals::equals_point_point(qi, tp.point) )
+ {
+ tp.operations[1].position = position_front;
+ }
+ else if ( is_q_last
+ && equals::equals_point_point(qj, tp.point) )
+ {
+ tp.operations[1].position = position_back;
+ }
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ default :
+ {
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw turn_info_exception(method);
+#endif
+ }
+ break;
+ }
+
+ return out;
+ }
+
+ template <typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_collinear_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters_info,
+ bool is_p_last, bool is_q_last,
+ method_type method, operation_type spike_op,
+ OutIt out)
+ {
+ // method == touch || touch_interior
+ // both position == middle
+
+ bool is_p_spike = tp.operations[0].operation == spike_op
+ && ! is_p_last
+ && inters_info.is_spike_p();
+ bool is_q_spike = tp.operations[1].operation == spike_op
+ && ! is_q_last
+ && inters_info.is_spike_q();
+
+ if ( is_p_spike && is_q_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ return true;
+ }
+ else if ( is_p_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_union;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ //tp.operations[1].operation = operation_union;
+ *out++ = tp;
+
+ return true;
+ }
+ else if ( is_q_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ //tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ enum append_version { append_touches, append_collinear_opposite };
+
+ template <append_version Version,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_opposite_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool is_q_last,
+ OutIt out)
+ {
+ bool is_p_spike = ( Version == append_touches ?
+ ( tp.operations[0].operation == operation_continue
+ || tp.operations[0].operation == operation_intersection ) :
+ true )
+ && ! is_p_last
+ && inters.is_spike_p();
+ bool is_q_spike = ( Version == append_touches ?
+ ( tp.operations[1].operation == operation_continue
+ || tp.operations[1].operation == operation_intersection ) :
+ true )
+ && ! is_q_last
+ && inters.is_spike_q();
+
+ bool res = false;
+
+ if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = false;
+ tp.method = method_touch;
+ }
+ else // Version == append_collinear_opposite
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = false;
+
+ BOOST_ASSERT(inters.i_info().count > 1);
+
+ base_turn_handler::assign_point(tp, method_touch_interior,
+ inters.i_info(), 1);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(),
+ inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ //tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ res = true;
+ }
+
+ if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = false;
+ tp.operations[1].is_collinear = true;
+ tp.method = method_touch;
+ }
+ else // Version == append_collinear_opposite
+ {
+ tp.operations[0].is_collinear = false;
+ tp.operations[1].is_collinear = true;
+
+ BOOST_ASSERT(inters.i_info().count > 0);
+
+ base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(),
+ inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ //tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ res = true;
+ }
+
+ return res;
+ }
+
+ static inline void replace_method_and_operations_tm(method_type & method,
+ operation_type & op0,
+ operation_type & op1)
+ {
+ if ( op0 == operation_blocked && op1 == operation_blocked )
+ {
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ method = (method == method_touch ? method_equal : method_collinear);
+ op0 = operation_continue;
+ op1 = operation_continue;
+ }
+ else
+ {
+ if ( op0 == operation_continue || op0 == operation_blocked )
+ {
+ op0 = operation_intersection;
+ }
+ else if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_continue || op1 == operation_blocked )
+ {
+ op1 = operation_intersection;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ // spikes in 'm'
+ if ( method == method_error )
+ {
+ method = method_touch_interior;
+ op0 = operation_union;
+ op1 = operation_union;
+ }
+ }
+ }
+
+ class turn_transformer_ec
+ {
+ public:
+ explicit turn_transformer_ec(method_type method_t_or_m)
+ : m_method(method_t_or_m)
+ {}
+
+ template <typename Turn>
+ void operator()(Turn & turn) const
+ {
+ operation_type & op0 = turn.operations[0].operation;
+ operation_type & op1 = turn.operations[1].operation;
+
+ BOOST_ASSERT(op0 != operation_blocked || op1 != operation_blocked );
+
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_intersection;
+ }
+ else if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_intersection;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ if ( op0 == operation_intersection || op0 == operation_union
+ || op1 == operation_intersection || op1 == operation_union )
+ {
+ turn.method = m_method;
+ }
+
+// TODO: is this correct?
+// it's equivalent to comparing to operation_blocked at the beginning of the function
+ turn.operations[0].is_collinear = op0 != operation_intersection;
+ turn.operations[1].is_collinear = op1 != operation_intersection;
+ }
+
+ private:
+ method_type m_method;
+ };
+
+ static inline void replace_operations_i(operation_type & op0, operation_type & op1)
+ {
+ if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index 26629043cb..a96538c43a 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -1,11 +1,17 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// 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)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
@@ -14,19 +20,17 @@
#include <map>
#include <boost/array.hpp>
+#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-
-#include <boost/tuple/tuple.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -44,17 +48,22 @@
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
-
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/expand.hpp>
-#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
# include <sstream>
@@ -65,6 +74,12 @@
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace get_turns
@@ -88,9 +103,7 @@ template
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Section1, typename Section2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
class get_turns_in_sections
{
@@ -138,16 +151,21 @@ class get_turns_in_sections
// About first condition: will be optimized by compiler (static)
// It checks if it is areal (box,ring,(multi)polygon
int const n = int(section.range_count);
+
+ boost::ignore_unused_variable_warning(n);
+ boost::ignore_unused_variable_warning(index1);
+ boost::ignore_unused_variable_warning(index2);
+
return boost::is_same
<
typename tag_cast
<
- typename geometry::point_type<Geometry1>::type,
+ typename geometry::tag<Geometry>::type,
areal_tag
- >::type,
+ >::type,
areal_tag
>::value
- && index1 == 0
+ && index1 == 0
&& index2 >= n - 2
;
}
@@ -155,13 +173,27 @@ class get_turns_in_sections
public :
// Returns true if terminated, false if interrupted
+ template <typename Turns, typename RobustPolicy, typename InterruptPolicy>
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
bool skip_larger,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
+ boost::ignore_unused_variable_warning(interrupt_policy);
+
+ if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count)
+ || (sec2.duplicate && (sec2.count + 1) < sec2.range_count))
+ {
+ // Skip sections containig only duplicates.
+ // They are still important (can indicate non-disjointness)
+ // but they will be found processing adjacent sections.
+ // Do NOT skip if they are the ONLY section
+ return true;
+ }
+
cview_type1 cview1(range_by_section(geometry1, sec1));
cview_type2 cview2(range_by_section(geometry2, sec2));
view_type1 view1(cview1);
@@ -186,7 +218,7 @@ public :
range1_iterator prev1, it1, end1;
get_start_point_iterator(sec1, view1, prev1, it1, end1,
- index1, ndi1, dir1, sec2.bounding_box);
+ index1, ndi1, dir1, sec2.bounding_box, robust_policy);
// We need a circular iterator because it might run through the closing point.
// One circle is actually enough but this one is just convenient.
@@ -197,12 +229,12 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
- it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box);
+ it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
begin_range_1, end_range_1, next1, true);
- advance_to_non_duplicate_next(nd_next1, it1, sec1);
+ advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy);
int index2 = sec2.begin_index;
int ndi2 = sec2.non_duplicate_index;
@@ -210,12 +242,12 @@ public :
range2_iterator prev2, it2, end2;
get_start_point_iterator(sec2, view2, prev2, it2, end2,
- index2, ndi2, dir2, sec1.bounding_box);
+ index2, ndi2, dir2, sec1.bounding_box, robust_policy);
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);
+ it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
@@ -241,24 +273,28 @@ public :
// Move to the "non duplicate next"
ever_circling_iterator<range2_iterator> nd_next2(
begin_range_2, end_range_2, next2, true);
- advance_to_non_duplicate_next(nd_next2, it2, sec2);
+ advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy);
typedef typename boost::range_value<Turns>::type turn_info;
- typedef typename turn_info::point_type ip;
turn_info ti;
- ti.operations[0].seg_id = segment_identifier(source_id1,
- sec1.ring_id.multi_index, sec1.ring_id.ring_index, index1),
- ti.operations[1].seg_id = segment_identifier(source_id2,
- sec2.ring_id.multi_index, sec2.ring_id.ring_index, index2),
-
- ti.operations[0].other_id = ti.operations[1].seg_id;
- ti.operations[1].other_id = ti.operations[0].seg_id;
+ ti.operations[0].seg_id
+ = segment_identifier(source_id1, sec1.ring_id.multi_index,
+ sec1.ring_id.ring_index, index1);
+ ti.operations[1].seg_id
+ = segment_identifier(source_id2, sec2.ring_id.multi_index,
+ sec2.ring_id.ring_index, index2);
std::size_t const size_before = boost::size(turns);
+ bool const is_1_first = sec1.is_non_duplicate_first && index1 == sec1.begin_index;
+ bool const is_1_last = sec1.is_non_duplicate_last && index1+1 >= sec1.end_index;
+ bool const is_2_first = sec2.is_non_duplicate_first && index2 == sec2.begin_index;
+ bool const is_2_last = sec2.is_non_duplicate_last && index2+1 >= sec2.end_index;
+
TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2,
- ti, std::back_inserter(turns));
+ is_1_first, is_1_last, is_2_first, is_2_last,
+ ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -283,24 +319,34 @@ private :
typedef typename model::referring_segment<point2_type const> segment2_type;
- template <size_t Dim, typename Point, typename Box>
- static inline bool preceding(int dir, Point const& point, Box const& box)
+ template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
+ static inline bool preceding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
- return (dir == 1 && get<Dim>(point) < get<min_corner, Dim>(box))
- || (dir == -1 && get<Dim>(point) > get<max_corner, Dim>(box));
+ typename robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dim>(robust_point) < get<min_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(robust_point) > get<max_corner, Dim>(box));
}
- template <size_t Dim, typename Point, typename Box>
- static inline bool exceeding(int dir, Point const& point, Box const& box)
+ template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
+ static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
- return (dir == 1 && get<Dim>(point) > get<max_corner, Dim>(box))
- || (dir == -1 && get<Dim>(point) < get<min_corner, Dim>(box));
+ typename robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dim>(robust_point) > get<max_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(robust_point) < get<min_corner, Dim>(box));
}
- template <typename Iterator, typename RangeIterator, typename Section>
+ template <typename Iterator, typename RangeIterator, typename Section, typename RobustPolicy>
static inline void advance_to_non_duplicate_next(Iterator& next,
- RangeIterator const& it, Section const& section)
+ RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy)
{
+ typedef typename robust_point_type<point1_type, RobustPolicy>::type robust_point_type;
+ robust_point_type robust_point_from_it;
+ robust_point_type robust_point_from_next;
+ geometry::recalculate(robust_point_from_it, *it, robust_policy);
+ geometry::recalculate(robust_point_from_next, *next, robust_policy);
+
// To see where the next segments bend to, in case of touch/intersections
// on end points, we need (in case of degenerate/duplicate points) an extra
// iterator which moves to the REAL next point, so non duplicate.
@@ -311,10 +357,14 @@ private :
// So advance to the "non duplicate next"
// (the check is defensive, to avoid endless loops)
std::size_t check = 0;
- while(! detail::disjoint::disjoint_point_point(*it, *next)
+ while(! detail::disjoint::disjoint_point_point
+ (
+ robust_point_from_it, robust_point_from_next
+ )
&& check++ < section.range_count)
{
next++;
+ geometry::recalculate(robust_point_from_next, *next, robust_policy);
}
}
@@ -322,14 +372,14 @@ 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 Range, typename Section, typename Box>
+ template <typename Range, typename Section, typename Box, typename RobustPolicy>
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,
- int dir, Box const& other_bounding_box)
+ int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy)
{
it = boost::begin(range) + section.begin_index;
end = boost::begin(range) + section.end_index + 1;
@@ -337,7 +387,7 @@ private :
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
- for(; it != end && preceding<0>(dir, *it, other_bounding_box);
+ for(; it != end && preceding<0>(dir, *it, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -369,6 +419,7 @@ template
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
+ typename RobustPolicy,
typename InterruptPolicy
>
struct section_visitor
@@ -377,14 +428,17 @@ struct section_visitor
Geometry1 const& m_geometry1;
int m_source_id2;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
section_visitor(int id1, Geometry1 const& g1,
int id2, Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& ip)
: m_source_id1(id1), m_geometry1(g1)
, m_source_id2(id2), m_geometry2(g2)
+ , m_rescale_policy(robust_policy)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
@@ -400,13 +454,12 @@ struct section_visitor
Geometry2,
Reverse1, Reverse2,
Section, Section,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>::apply(
m_source_id1, m_geometry1, sec1,
m_source_id2, m_geometry2, sec2,
false,
+ m_rescale_policy,
m_turns, m_interrupt_policy);
}
return true;
@@ -418,37 +471,45 @@ template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
class get_turns_generic
{
public:
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& geometry1,
int source_id2, Geometry2 const& geometry2,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
{
// First create monotonic sections...
typedef typename boost::range_value<Turns>::type ip_type;
typedef typename ip_type::point_type point_type;
- typedef model::box<point_type> box_type;
+
+ typedef model::box
+ <
+ typename geometry::robust_point_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > box_type;
typedef typename geometry::sections<box_type, 2> sections_type;
sections_type sec1, sec2;
- geometry::sectionalize<Reverse1>(geometry1, sec1, 0);
- geometry::sectionalize<Reverse2>(geometry2, sec2, 1);
+ geometry::sectionalize<Reverse1>(geometry1, robust_policy, true, sec1, 0);
+ geometry::sectionalize<Reverse2>(geometry2, robust_policy, true, sec2, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
<
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy, InterruptPolicy
- > visitor(source_id1, geometry1, source_id2, geometry2, turns, interrupt_policy);
+ Turns, TurnPolicy, RobustPolicy, InterruptPolicy
+ > visitor(source_id1, geometry1, source_id2, geometry2, robust_policy, turns, interrupt_policy);
geometry::partition
<
@@ -463,13 +524,10 @@ template
<
typename Range, typename Box,
bool ReverseRange, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_cs
{
- typedef typename boost::range_value<Turns>::type turn_info;
typedef typename geometry::point_type<Range>::type point_type;
typedef typename geometry::point_type<Box>::type box_point_type;
@@ -491,14 +549,16 @@ struct get_turns_cs
>::type iterator_type;
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Range const& range,
int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int multi_index = -1, int ring_index = -1)
{
- if (boost::size(range) <= 1)
+ if ( boost::size(range) <= 1)
{
return;
}
@@ -509,6 +569,8 @@ struct get_turns_cs
cview_type cview(range);
view_type view(cview);
+ typename boost::range_size<view_type>::type segments_count1 = boost::size(view) - 1;
+
iterator_type it = boost::begin(view);
ever_circling_iterator<iterator_type> next(
@@ -557,9 +619,13 @@ struct get_turns_cs
get_turns_with_box(seg_id, source_id2,
*prev, *it, *next,
bp[0], bp[1], bp[2], bp[3],
+ // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes
+ index == 0,
+ unsigned(index) == segments_count1,
+ robust_policy,
turns, interrupt_policy);
- // Future performance enhancement:
- // return if told by the interrupt policy
+ // Future performance enhancement:
+ // return if told by the interrupt policy
}
}
}
@@ -585,6 +651,7 @@ private:
else return 0;
}
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
// Points from a range:
point_type const& rp0,
@@ -595,34 +662,45 @@ private:
box_point_type const& bp1,
box_point_type const& bp2,
box_point_type const& bp3,
+ bool const is_range_first,
+ bool const is_range_last,
+ RobustPolicy const& robust_policy,
// Output
Turns& turns,
InterruptPolicy& interrupt_policy)
{
+ boost::ignore_unused_variable_warning(interrupt_policy);
+
// Depending on code some relations can be left out
typedef typename boost::range_value<Turns>::type turn_info;
turn_info ti;
ti.operations[0].seg_id = seg_id;
- ti.operations[0].other_id = ti.operations[1].seg_id;
- ti.operations[1].other_id = seg_id;
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ true, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, true,
+ ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -638,15 +716,15 @@ template
<
typename Polygon, typename Box,
bool Reverse, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_polygon_cs
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Polygon const& polygon,
int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy,
int multi_index = -1)
{
@@ -656,32 +734,118 @@ struct get_turns_polygon_cs
<
ring_type, Box,
Reverse, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> intersector_type;
intersector_type::apply(
source_id1, geometry::exterior_ring(polygon),
- source_id2, box, turns, interrupt_policy,
+ source_id2, box,
+ robust_policy,
+ turns, interrupt_policy,
multi_index, -1);
int i = 0;
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
- ++it, ++i)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
{
intersector_type::apply(
source_id1, *it,
- source_id2, box, turns, interrupt_policy,
+ source_id2, box,
+ robust_policy,
+ turns, interrupt_policy,
multi_index, i);
}
}
};
+
+template
+<
+ typename Multi, typename Box,
+ bool Reverse, bool ReverseBox,
+ typename TurnPolicy
+>
+struct get_turns_multi_polygon_cs
+{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
+ static inline void apply(
+ int source_id1, Multi const& multi,
+ int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
+ Turns& turns, InterruptPolicy& interrupt_policy)
+ {
+ typedef typename boost::range_iterator
+ <
+ Multi const
+ >::type iterator_type;
+
+ int i = 0;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, ++i)
+ {
+ // Call its single version
+ get_turns_polygon_cs
+ <
+ typename boost::range_value<Multi>::type, Box,
+ Reverse, ReverseBox,
+ TurnPolicy
+ >::apply(source_id1, *it, source_id2, box,
+ robust_policy, turns, interrupt_policy, i);
+ }
+ }
+};
+
+
+// GET_TURN_INFO_TYPE
+
+template <typename Geometry>
+struct topological_tag_base
+{
+ typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type;
+};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy,
+ typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
+ typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
+struct get_turn_info_type
+ : overlay::get_turn_info<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
+struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag>
+ : overlay::get_turn_info_linear_linear<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
+struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag>
+ : overlay::get_turn_info_linear_areal<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio,
+ typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
+ typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
+struct turn_operation_type
+{
+ typedef overlay::turn_operation<SegmentRatio> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
+struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
+{
+ typedef overlay::turn_operation_linear<SegmentRatio> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
+struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
+{
+ typedef overlay::turn_operation_linear<SegmentRatio> type;
+};
+
}} // namespace detail::get_turns
#endif // DOXYGEN_NO_DETAIL
@@ -697,18 +861,14 @@ template
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
: detail::get_turns::get_turns_generic
<
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
{};
@@ -717,23 +877,19 @@ template
<
typename Polygon, typename Box,
bool ReversePolygon, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
<
polygon_tag, box_tag,
Polygon, Box,
ReversePolygon, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> : detail::get_turns::get_turns_polygon_cs
<
Polygon, Box,
ReversePolygon, ReverseBox,
- Turns, TurnPolicy, InterruptPolicy
+ TurnPolicy
>
{};
@@ -742,22 +898,18 @@ template
<
typename Ring, typename Box,
bool ReverseRing, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
<
ring_tag, box_tag,
Ring, Box,
ReverseRing, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> : detail::get_turns::get_turns_cs
<
Ring, Box, ReverseRing, ReverseBox,
- Turns, TurnPolicy, InterruptPolicy
+ TurnPolicy
>
{};
@@ -765,28 +917,52 @@ struct get_turns
template
<
+ typename MultiPolygon,
+ typename Box,
+ bool ReverseMultiPolygon, bool ReverseBox,
+ typename TurnPolicy
+>
+struct get_turns
+ <
+ multi_polygon_tag, box_tag,
+ MultiPolygon, Box,
+ ReverseMultiPolygon, ReverseBox,
+ TurnPolicy
+ >
+ : detail::get_turns::get_turns_multi_polygon_cs
+ <
+ MultiPolygon, Box,
+ ReverseMultiPolygon, ReverseBox,
+ TurnPolicy
+ >
+{};
+
+
+template
+<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_reversed
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& g1,
int source_id2, Geometry2 const& g2,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
{
get_turns
<
GeometryTag2, GeometryTag1,
Geometry2, Geometry1,
Reverse2, Reverse1,
- Turns, TurnPolicy,
- InterruptPolicy
- >::apply(source_id2, g2, source_id1, g1, turns, interrupt_policy);
+ TurnPolicy
+ >::apply(source_id2, g2, source_id1, g1, robust_policy,
+ turns, interrupt_policy);
}
};
@@ -804,6 +980,7 @@ struct get_turns_reversed
\tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
+\param robust_policy policy to handle robustness issues
\param turns container which will contain turn points
\param interrupt_policy policy determining if process is stopped
when intersection is found
@@ -814,31 +991,20 @@ template
typename AssignPolicy,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void get_turns(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type,
- typename boost::range_value<Turns>::type,
- AssignPolicy
- > TurnPolicy;
+ typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
+ //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
boost::mpl::if_c
<
@@ -849,8 +1015,7 @@ inline void get_turns(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>,
dispatch::get_turns
<
@@ -858,15 +1023,18 @@ inline void get_turns(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
+ robust_policy,
turns, interrupt_policy);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
index 1e878ca525..085933dd7a 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
@@ -14,7 +14,17 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/robust_type.hpp>
+
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#endif
+
+#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
@@ -31,6 +41,7 @@ template
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
bool Reverse1, bool Reverse2,
typename Strategy
>
@@ -39,10 +50,12 @@ struct sort_in_cluster
inline sort_in_cluster(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
+ , RobustPolicy const& robust_policy
, Strategy const& strategy)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
+ , m_rescale_policy(robust_policy)
, m_strategy(strategy)
{}
@@ -51,49 +64,100 @@ private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_rescale_policy;
Strategy const& m_strategy;
typedef typename Indexed::type turn_operation_type;
typedef typename geometry::point_type<Geometry1>::type point_type;
- typedef model::referring_segment<point_type const> segment_type;
+
+ typedef typename geometry::robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // Still necessary in some situations,
+ // for example #case_102_multi, #case_107_multi, #case_recursive_boxes_3
+ inline void get_situation_map(Indexed const& left, Indexed const& right,
+ robust_point_type& pi_rob, robust_point_type& pj_rob,
+ robust_point_type& ri_rob, robust_point_type& rj_rob,
+ robust_point_type& si_rob, robust_point_type& sj_rob) const
+ {
+ point_type pi, pj, ri, rj, si, sj;
+
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject->seg_id,
+ pi, pj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ *left.other_seg_id,
+ ri, rj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ *right.other_seg_id,
+ si, sj);
+
+ geometry::recalculate(pi_rob, pi, m_rescale_policy);
+ geometry::recalculate(pj_rob, pj, m_rescale_policy);
+ geometry::recalculate(ri_rob, ri, m_rescale_policy);
+ geometry::recalculate(rj_rob, rj, m_rescale_policy);
+ geometry::recalculate(si_rob, si, m_rescale_policy);
+ geometry::recalculate(sj_rob, sj, m_rescale_policy);
+ }
+
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
+ // This method was still called but did no effect whatsoever on the results,
+ // with or without robustness-rescaling.
+ // Probable cause: we rescale in this file ourselves, ignoring passed policy
+ // TODO: check this more.
+ // Besides this, it currently does not compile for yet unknown reasons
+ // (does not find specialization for segment_ratio_type)
+ // It is currently only called from the Unit Test "multi_intersection.cpp"
// Determine how p/r and p/s are located.
- template <typename P>
- static inline void overlap_info(P const& pi, P const& pj,
- P const& ri, P const& rj,
- P const& si, P const& sj,
- bool& pr_overlap, bool& ps_overlap, bool& rs_overlap)
+ inline void overlap_info(
+ robust_point_type const& pi, robust_point_type const& pj,
+ robust_point_type const& ri, robust_point_type const& rj,
+ robust_point_type const& si, robust_point_type const& sj,
+ bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) const
{
// Determine how p/r and p/s are located.
// One of them is coming from opposite direction.
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > intersection_return_type;
+
typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
- segment_type,
- segment_type,
- segment_intersection_points<point_type>
+ intersection_return_type
>
> policy;
+ typedef model::referring_segment<robust_point_type const> segment_type;
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);
- segment_intersection_points<point_type> rs = policy::apply(r, s);
+ intersection_return_type pr = policy::apply(p, r, m_rescale_policy, pi, pj, ri, rj);
+ intersection_return_type ps = policy::apply(p, s, m_rescale_policy, pi, pj, si, sj);
+ intersection_return_type rs = policy::apply(r, s, m_rescale_policy, ri, rj, si, sj);
// Check on overlap
pr_overlap = pr.count == 2;
ps_overlap = ps.count == 2;
rs_overlap = rs.count == 2;
}
+#endif
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES
inline void debug_consider(int order, Indexed const& left,
Indexed const& right, std::string const& header,
bool skip = true,
@@ -102,19 +166,15 @@ private :
{
if (skip) return;
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ std::cout << "Case: " << header << " for " << left.turn_index << " / " << right.turn_index << std::endl;
+
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
bool prc = false, psc = false, rsc = false;
overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc);
+#endif
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_rj_p = m_strategy.apply(pi, pj, rj);
@@ -123,8 +183,7 @@ private :
int const side_si_r = m_strategy.apply(ri, rj, si);
int const side_sj_r = m_strategy.apply(ri, rj, sj);
- std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl;
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH_MORE
+#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES_MORE
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;
@@ -136,13 +195,15 @@ private :
std::cout << header
//<< " order: " << order
- << " ops: " << operation_char(left.subject.operation)
- << "/" << operation_char(right.subject.operation)
+ << " 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
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
<< " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc)
- //<< " idx: " << left.index << "/" << right.index
+#endif
+ //<< " idx: " << left.turn_index << "/" << right.turn_index
;
if (! extra.empty())
@@ -167,23 +228,23 @@ private :
, std::string const& // header
) const
{
- bool ret = left.index < right.index;
+ bool ret = left.turn_index < right.turn_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)
+ 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)
+ else if (left.subject->operation == operation_blocked
+ && right.subject->operation == operation_union)
{
ret = false;
}
else
{
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << "ux/ux unhandled" << std::endl;
#endif
}
@@ -201,32 +262,32 @@ private :
{
bool ret = false;
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_union)
+ 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)
+ 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)
+ else if (right.subject->operation == operation_union
+ && left.subject->operation == operation_blocked)
{
ret = false;
}
- else if (left.subject.operation == operation_union)
+ else if (left.subject->operation == operation_union)
{
ret = true;
}
- else if (right.subject.operation == operation_union)
+ else if (right.subject->operation == operation_union)
{
ret = false;
}
else
{
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
// this still happens in the traverse.cpp test
std::cout << " iu/ux unhandled" << std::endl;
#endif
@@ -245,43 +306,61 @@ private :
{
//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
+ 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_ix_ix(Indexed const& left, Indexed const& right
+ , std::string const& // header
+ ) const
+ {
+ // Take first intersection, then blocked.
+ if (left.subject->operation == operation_intersection
+ && right.subject->operation == operation_blocked)
+ {
+ return true;
+ }
+ else if (left.subject->operation == operation_blocked
+ && right.subject->operation == operation_intersection)
+ {
+ return false;
+ }
+
+ // Default case, should not occur
+
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+ std::cout << "ix/ix unhandled" << std::endl;
+#endif
+ //debug_consider(0, left, right, header, false, "-> return", ret);
+
+ return left.turn_index < right.turn_index;
+ }
+
inline bool consider_iu_iu(Indexed const& left, Indexed const& right,
- std::string const& header) const
+ std::string const& header, bool redo = false) const
{
//debug_consider(0, left, right, header);
// In general, order it like "union, intersection".
- if (left.subject.operation == operation_intersection
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_intersection
+ && right.subject->operation == operation_union)
{
//debug_consider(0, left, right, header, false, "i,u", false);
return false;
}
- else if (left.subject.operation == operation_union
- && right.subject.operation == operation_intersection)
+ else if (left.subject->operation == operation_union
+ && right.subject->operation == operation_intersection)
{
//debug_consider(0, left, right, header, false, "u,i", true);
return true;
}
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
@@ -291,8 +370,8 @@ private :
if (side_ri_p * side_si_p == 1 && side_si_r != 0)
{
// Take the most left one
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_union
+ && right.subject->operation == operation_union)
{
bool ret = side_si_r == 1;
//debug_consider(0, left, right, header, false, "same side", ret);
@@ -311,14 +390,18 @@ private :
debug_consider(0, left, right, header, false, "opp.", ret);
return ret;
}
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << " iu/iu coming from opposite unhandled" << std::endl;
#endif
}
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
// We need EXTRA information here: are p/r/s overlapping?
bool pr_ov = false, ps_ov = false, rs_ov = false;
overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov);
+#else
+ // std::cout << "Boost.Geometry: skipping overlap_info" << std::endl;
+#endif
// One coming from right (#83,#90)
// One coming from left (#90, #94, #95)
@@ -326,12 +409,14 @@ private :
{
bool ret = false;
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov || ps_ov)
{
int r = side_ri_p != 0 ? side_ri_p : side_si_p;
ret = r * side_si_r == 1;
}
else
+#endif
{
ret = side_si_r == 1;
}
@@ -348,6 +433,7 @@ private :
// Take the one NOT overlapping
bool ret = false;
bool found = false;
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov && ! ps_ov)
{
ret = true;
@@ -358,6 +444,7 @@ private :
ret = false;
found = true;
}
+#endif
debug_consider(0, left, right, header, false, "aligned", ret);
if (found)
@@ -366,11 +453,18 @@ private :
}
}
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << " iu/iu unhandled" << std::endl;
- debug_consider(0, left, right, header, false, "unhandled", left.index < right.index);
+ debug_consider(0, left, right, header, false, "unhandled", left.turn_index < right.turn_index);
#endif
- return left.index < right.index;
+ if (! redo)
+ {
+ // In some cases behaviour is not symmetrical. TODO: fix this properly
+ // OR: alternatively we might consider calling all these functions one-way anyway
+ return ! consider_iu_iu(right, left, header, true);
+ }
+
+ return left.turn_index < right.turn_index;
}
inline bool consider_ii(Indexed const& left, Indexed const& right,
@@ -378,16 +472,8 @@ private :
{
debug_consider(0, left, right, header);
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
@@ -402,84 +488,89 @@ private :
bool const ret = side_si_r != 1;
return ret;
}
- return left.index < right.index;
+ return left.turn_index < right.turn_index;
}
public :
inline bool operator()(Indexed const& left, Indexed const& right) const
{
- bool const default_order = left.index < right.index;
+ bool const default_order = left.turn_index < right.turn_index;
- if ((m_turn_points[left.index].discarded || left.discarded)
- && (m_turn_points[right.index].discarded || right.discarded))
+ if ((m_turn_points[left.turn_index].discarded || left.discarded)
+ && (m_turn_points[right.turn_index].discarded || right.discarded))
{
return default_order;
}
- else if (m_turn_points[left.index].discarded || left.discarded)
+ else if (m_turn_points[left.turn_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)
+ else if (m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].combination(operation_blocked, operation_union)
+ && m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].both(operation_union)
+ && m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked))
+ {
+ return consider_ix_ix(left, right, "ix/ix");
+ }
+ else if (m_turn_points[left.turn_index].both(operation_intersection)
+ && m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].combination(operation_union, operation_blocked)
+ && m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
+ && m_turn_points[right.turn_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))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_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
+ else if (m_turn_points[left.turn_index].method != method_equal
+ && m_turn_points[right.turn_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
+ else if (m_turn_points[left.turn_index].method == method_equal
+ && m_turn_points[right.turn_index].method != method_equal
)
{
return true;
@@ -487,13 +578,13 @@ public :
// 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
- << std::cout;
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+ std::cout << " Consider: " << operation_char(m_turn_points[left.turn_index].operations[0].operation)
+ << operation_char(m_turn_points[left.turn_index].operations[1].operation)
+ << "/" << operation_char(m_turn_points[right.turn_index].operations[0].operation)
+ << operation_char(m_turn_points[right.turn_index].operations[1].operation)
+ << " " << " Take " << left.turn_index << " < " << right.turn_index
+ << std::endl;
#endif
return default_order;
@@ -523,8 +614,8 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
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;
+ operation_type first = turn_points[it->turn_index].operations[0].operation;
+ operation_type second = turn_points[it->turn_index].operations[1].operation;
if (first > second)
{
std::swap(first, second);
@@ -553,7 +644,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
// 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))
+ if (turn_points[it->turn_index].combination(operation_intersection, operation_union))
{
it->discarded = true;
}
@@ -569,7 +660,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
if (! it->discarded)
{
nd_count++;
- if (turn_points[it->index].both(operation_continue))
+ if (turn_points[it->turn_index].both(operation_continue))
{
cc_count++;
}
@@ -585,7 +676,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
{
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- if (turn_points[it->index].both(operation_continue))
+ if (turn_points[it->turn_index].both(operation_continue))
{
it->discarded = true;
}
@@ -602,12 +693,14 @@ template
typename TurnPoints,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
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,
+ RobustPolicy& robust_policy,
Strategy const& strategy)
{
// First inspect and (possibly) discard rows
@@ -622,31 +715,31 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints,
IndexType,
Geometry1, Geometry2,
+ RobustPolicy,
Reverse1, Reverse2,
Strategy
- >(turn_points, geometry1, geometry2, strategy));
-
+ >(turn_points, geometry1, geometry2, robust_policy, strategy));
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
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 ";
+ operations_type const& op = turn_points[begin_cluster->turn_index].operations[begin_cluster->operation_index];
+ std::cout << std::endl << "Clustered points on equal distance " << op.fraction << std::endl;
+ std::cout << "->Indexes ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- std::cout << " " << it->index;
+ std::cout << " " << it->turn_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 << " " << method_char(turn_points[it->turn_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 << " " << operation_char(turn_points[it->turn_index].operations[0].operation)
+ << operation_char(turn_points[it->turn_index].operations[1].operation);
}
std::cout << std::endl << "->Discarded: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
@@ -656,7 +749,7 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
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)
+ //<< geometry::distance(turn_points[prev->turn_index].point, turn_points[it->turn_index].point)
#endif
}
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp
new file mode 100644
index 0000000000..dd041b0d7d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp
@@ -0,0 +1,84 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+template <std::size_t Dimension, std::size_t DimensionCount>
+struct intersection_box_box
+{
+ template
+ <
+ typename Box1, typename Box2,
+ typename RobustPolicy,
+ typename BoxOut,
+ typename Strategy
+ >
+ static inline bool apply(Box1 const& box1,
+ Box2 const& box2,
+ RobustPolicy const& robust_policy,
+ BoxOut& box_out,
+ Strategy const& strategy)
+ {
+ typedef typename coordinate_type<BoxOut>::type ct;
+
+ ct min1 = get<min_corner, Dimension>(box1);
+ ct min2 = get<min_corner, Dimension>(box2);
+ ct max1 = get<max_corner, Dimension>(box1);
+ ct max2 = get<max_corner, Dimension>(box2);
+
+ if (max1 < min2 || max2 < min1)
+ {
+ return false;
+ }
+ // Set dimensions of output coordinate
+ set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1);
+ set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
+
+ return intersection_box_box<Dimension + 1, DimensionCount>
+ ::apply(box1, box2, robust_policy, box_out, strategy);
+ }
+};
+
+template <std::size_t DimensionCount>
+struct intersection_box_box<DimensionCount, DimensionCount>
+{
+ template
+ <
+ typename Box1, typename Box2,
+ typename RobustPolicy,
+ typename BoxOut,
+ typename Strategy
+ >
+ static inline bool apply(Box1 const&, Box2 const&,
+ RobustPolicy const&, BoxOut&, Strategy const&)
+ {
+ return true;
+ }
+};
+
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
index 8bca790d74..a13a627456 100644
--- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -28,8 +33,17 @@
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
+
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
#include <boost/geometry/views/segment_view.hpp>
+#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
+
+
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
#include <boost/foreach.hpp>
#endif
@@ -41,31 +55,64 @@ namespace boost { namespace geometry
namespace detail { namespace intersection
{
-template
-<
- typename Segment1, typename Segment2,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
+template <typename PointOut>
struct intersection_segment_segment_point
{
+ template
+ <
+ typename Segment1, typename Segment2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(Segment1 const& segment1,
- Segment2 const& segment2, OutputIterator out,
+ Segment2 const& segment2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
+ typedef typename geometry::robust_point_type
+ <
+ typename geometry::point_type<Segment1>::type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // TODO: rescale segment -> robust points
+ robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
+ {
+ // Workaround:
+ point_type pi, pj, qi, qj;
+ assign_point_from_index<0>(segment1, pi);
+ assign_point_from_index<1>(segment1, pj);
+ assign_point_from_index<0>(segment2, qi);
+ assign_point_from_index<1>(segment2, qj);
+ geometry::recalculate(pi_rob, pi, robust_policy);
+ geometry::recalculate(pj_rob, pj, robust_policy);
+ geometry::recalculate(qi_rob, qi, robust_policy);
+ geometry::recalculate(qj_rob, qj, robust_policy);
+ }
+
// Get the intersection point (or two points)
- segment_intersection_points<point_type> is
- = strategy::intersection::relate_cartesian_segments
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > intersection_return_type;
+
+ typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
- Segment1,
- Segment2,
- segment_intersection_points<point_type>
+ intersection_return_type
>
- >::apply(segment1, segment2);
+ > policy;
+
+ intersection_return_type is = policy::apply(segment1, segment2,
+ robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < is.count; i++)
{
@@ -77,24 +124,31 @@ struct intersection_segment_segment_point
}
};
-template
-<
- typename Linestring1, typename Linestring2,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
+template <typename PointOut>
struct intersection_linestring_linestring_point
{
+ template
+ <
+ typename Linestring1, typename Linestring2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(Linestring1 const& linestring1,
- Linestring2 const& linestring2, OutputIterator out,
+ Linestring2 const& linestring2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
- typedef detail::overlay::turn_info<point_type> turn_info;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
- geometry::get_intersection_points(linestring1, linestring2, turns);
+ geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns);
for (typename boost::range_iterator<std::deque<turn_info> const>::type
it = boost::begin(turns); it != boost::end(turns); ++it)
@@ -112,25 +166,15 @@ struct intersection_linestring_linestring_point
*/
template
<
- typename LineString, typename Areal,
bool ReverseAreal,
- typename OutputIterator, typename LineStringOut,
- overlay_type OverlayType,
- typename Strategy
+ typename LineStringOut,
+ overlay_type OverlayType
>
struct intersection_of_linestring_with_areal
{
- typedef detail::overlay::follow
- <
- LineStringOut,
- LineString,
- Areal,
- OverlayType
- > follower;
-
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
template <typename Turn, typename Operation>
- static inline void debug_follow(Turn const& turn, Operation op,
+ static inline void debug_follow(Turn const& turn, Operation op,
int index)
{
std::cout << index
@@ -145,7 +189,14 @@ struct intersection_of_linestring_with_areal
}
#endif
+ template
+ <
+ typename LineString, typename Areal,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(LineString const& linestring, Areal const& areal,
+ RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
@@ -154,9 +205,20 @@ struct intersection_of_linestring_with_areal
return out;
}
- typedef typename point_type<LineStringOut>::type point_type;
+ typedef detail::overlay::follow
+ <
+ LineStringOut,
+ LineString,
+ Areal,
+ OverlayType
+ > follower;
- typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ typedef typename point_type<LineStringOut>::type point_type;
+ typedef detail::overlay::traversal_turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
@@ -164,12 +226,12 @@ struct intersection_of_linestring_with_areal
<
false,
(OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal),
- detail::overlay::calculate_distance_policy
- >(linestring, areal, turns, policy);
+ detail::overlay::assign_null_policy
+ >(linestring, areal, robust_policy, turns, policy);
if (turns.empty())
{
- // No intersection points, it is either completely
+ // No intersection points, it is either completely
// inside (interior + borders)
// or completely outside
@@ -181,8 +243,7 @@ struct intersection_of_linestring_with_areal
return out;
}
-
- if (follower::included(border_point, areal))
+ if (follower::included(border_point, areal, robust_policy))
{
LineStringOut copy;
geometry::convert(linestring, copy);
@@ -203,7 +264,7 @@ struct intersection_of_linestring_with_areal
(
linestring, areal,
geometry::detail::overlay::operation_intersection,
- turns, out
+ turns, robust_policy, out
);
}
};
@@ -220,18 +281,22 @@ namespace dispatch
template
<
- // tag dispatching:
- typename TagIn1, typename TagIn2, typename TagOut,
- // orientation
- // metafunction finetuning helpers:
- bool Areal1, bool Areal2, bool ArealOut,
// real types
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ // orientation
+ bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ bool ReverseOut = detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
+ // tag dispatching:
+ typename TagIn1 = typename geometry::tag<Geometry1>::type,
+ typename TagIn2 = typename geometry::tag<Geometry2>::type,
+ typename TagOut = typename geometry::tag<GeometryOut>::type,
+ // metafunction finetuning helpers:
+ bool Areal1 = geometry::is_areal<Geometry1>::value,
+ bool Areal2 = geometry::is_areal<Geometry2>::value,
+ bool ArealOut = geometry::is_areal<GeometryOut>::value
>
struct intersection_insert
{
@@ -245,124 +310,106 @@ struct intersection_insert
template
<
- typename TagIn1, typename TagIn2, typename TagOut,
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn1, typename TagIn2, typename TagOut
>
struct intersection_insert
<
- TagIn1, TagIn2, TagOut,
- true, true, true,
Geometry1, Geometry2,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ TagIn1, TagIn2, TagOut,
+ true, true, true
> : detail::overlay::overlay
- <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+ <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
// Any areal type with box:
template
<
- typename TagIn, typename TagOut,
typename Geometry, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn, typename TagOut
>
struct intersection_insert
<
- TagIn, box_tag, TagOut,
- true, true, true,
Geometry, Box,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ TagIn, box_tag, TagOut,
+ true, true, true
> : detail::overlay::overlay
- <Geometry, Box, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+ <Geometry, Box, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
template
<
typename Segment1, typename Segment2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- segment_tag, segment_tag, point_tag,
- false, false, false,
Segment1, Segment2,
+ GeometryOut,
+ OverlayType,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType, Strategy
- > : detail::intersection::intersection_segment_segment_point
- <
- Segment1, Segment2,
- OutputIterator, GeometryOut,
- Strategy
- >
+ segment_tag, segment_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_segment_segment_point<GeometryOut>
{};
template
<
typename Linestring1, typename Linestring2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, linestring_tag, point_tag,
- false, false, false,
Linestring1, Linestring2,
+ GeometryOut,
+ OverlayType,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType, Strategy
- > : detail::intersection::intersection_linestring_linestring_point
- <
- Linestring1, Linestring2,
- OutputIterator, GeometryOut,
- Strategy
- >
+ linestring_tag, linestring_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_linestring_linestring_point<GeometryOut>
{};
template
<
typename Linestring, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
+ typename GeometryOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, box_tag, linestring_tag,
- false, true, false,
Linestring, Box,
+ GeometryOut,
+ overlay_intersection,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ linestring_tag, box_tag, linestring_tag,
+ false, true, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Linestring const& linestring,
- Box const& box, OutputIterator out, Strategy const& )
+ Box const& box,
+ RobustPolicy const& ,
+ OutputIterator out, Strategy const& )
{
typedef typename point_type<GeometryOut>::type point_type;
strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
@@ -375,27 +422,23 @@ struct intersection_insert
template
<
typename Linestring, typename Polygon,
- bool ReverseLinestring, bool ReversePolygon, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool ReverseLinestring, bool ReversePolygon, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, polygon_tag, linestring_tag,
- false, true, false,
Linestring, Polygon,
- ReverseLinestring, ReversePolygon, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ ReverseLinestring, ReversePolygon, ReverseOut,
+ linestring_tag, polygon_tag, linestring_tag,
+ false, true, false
> : detail::intersection::intersection_of_linestring_with_areal
<
- Linestring, Polygon,
ReversePolygon,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ GeometryOut,
+ OverlayType
>
{};
@@ -403,51 +446,48 @@ struct intersection_insert
template
<
typename Linestring, typename Ring,
- bool ReverseLinestring, bool ReverseRing, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool ReverseLinestring, bool ReverseRing, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, ring_tag, linestring_tag,
- false, true, false,
Linestring, Ring,
- ReverseLinestring, ReverseRing, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ ReverseLinestring, ReverseRing, ReverseOut,
+ linestring_tag, ring_tag, linestring_tag,
+ false, true, false
> : detail::intersection::intersection_of_linestring_with_areal
<
- Linestring, Ring,
ReverseRing,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ GeometryOut,
+ OverlayType
>
{};
template
<
typename Segment, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- segment_tag, box_tag, linestring_tag,
- false, true, false,
Segment, Box,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ segment_tag, box_tag, linestring_tag,
+ false, true, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Segment const& segment,
- Box const& box, OutputIterator out, Strategy const& )
+ Box const& box,
+ RobustPolicy const& ,// TODO: propagate to clip_range_with_box
+ OutputIterator out, Strategy const& )
{
geometry::segment_view<Segment> range(segment);
@@ -460,37 +500,42 @@ struct intersection_insert
template
<
- typename Tag1, typename Tag2,
- bool Areal1, bool Areal2,
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename PointOut,
+ typename PointOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename Tag1, typename Tag2,
+ bool Areal1, bool Areal2
>
struct intersection_insert
<
- Tag1, Tag2, point_tag,
- Areal1, Areal2, false,
Geometry1, Geometry2,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, PointOut,
+ PointOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ Tag1, Tag2, point_tag,
+ Areal1, Areal2, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out, Strategy const& )
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out, Strategy const& )
{
- typedef detail::overlay::turn_info<PointOut> turn_info;
+ typedef detail::overlay::turn_info
+ <
+ PointOut,
+ typename segment_ratio_type<PointOut, RobustPolicy>::type
+ > turn_info;
std::vector<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
geometry::get_turns
<
false, false, detail::overlay::assign_null_policy
- >(geometry1, geometry2, turns, policy);
+ >(geometry1, geometry2, robust_policy, turns, policy);
for (typename std::vector<turn_info>::const_iterator it
= turns.begin(); it != turns.end(); ++it)
{
@@ -504,35 +549,156 @@ struct intersection_insert
template
<
- typename GeometryTag1, typename GeometryTag2, typename GeometryTag3,
- bool Areal1, bool Areal2, bool ArealOut,
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename Geometry1, typename Geometry2, typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert_reversed
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& g1,
- Geometry2 const& g2, OutputIterator out,
+ Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& strategy)
{
return intersection_insert
<
- GeometryTag2, GeometryTag1, GeometryTag3,
- Areal2, Areal1, ArealOut,
- Geometry2, Geometry1,
- Reverse2, Reverse1, ReverseOut,
- OutputIterator, GeometryOut,
+ Geometry2, Geometry1, GeometryOut,
OverlayType,
- Strategy
- >::apply(g2, g1, out, strategy);
+ Reverse2, Reverse1, ReverseOut
+ >::apply(g2, g1, robust_policy, out, strategy);
}
};
+// dispatch for non-areal geometries
+template
+<
+ typename Geometry1, typename Geometry2, typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn1, typename TagIn2
+>
+struct intersection_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ TagIn1, TagIn2, linestring_tag,
+ false, false, false
+ > : intersection_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type,
+ typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type,
+ linestring_tag,
+ false, false, false
+ >
+{};
+
+
+// dispatch for difference/intersection of linear geometries
+template
+<
+ typename Linear1, typename Linear2, typename LineStringOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Linear1, Linear2, LineStringOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ linear_tag, linear_tag, linestring_tag,
+ false, false, false
+ > : detail::overlay::linear_linear_linestring
+ <
+ Linear1, Linear2, LineStringOut, OverlayType
+ >
+{};
+
+
+// dispatch for difference/intersection of point-like geometries
+
+template
+<
+ typename Point1, typename Point2, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Point1, Point2, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ point_tag, point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::point_point_point
+ <
+ Point1, Point2, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint, typename Point, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiPoint, Point, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_point_tag, point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::multipoint_point_point
+ <
+ MultiPoint, Point, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename Point, typename MultiPoint, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Point, MultiPoint, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ point_tag, multi_point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::point_multipoint_point
+ <
+ Point, MultiPoint, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint1, typename MultiPoint2, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_point_tag, multi_point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::multipoint_multipoint_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -548,50 +714,37 @@ template
bool ReverseSecond,
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return boost::mpl::if_c
+ <
+ geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
+ geometry::dispatch::intersection_insert_reversed
<
- geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
- geometry::dispatch::intersection_insert_reversed
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
- overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >,
- geometry::dispatch::intersection_insert
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
- >::type::apply(geometry1, geometry2, out, strategy);
+ Geometry1, Geometry2,
+ GeometryOut,
+ OverlayType,
+ overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
+ overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
+ >,
+ geometry::dispatch::intersection_insert
+ <
+ Geometry1, Geometry2,
+ GeometryOut,
+ OverlayType,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value
+ >
+ >::type::apply(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -630,10 +783,14 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
+ typedef typename Strategy::rescale_policy_type rescale_policy_type;
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
return detail::intersection::insert
<
GeometryOut, false, overlay_intersection
- >(geometry1, geometry2, out, strategy);
+ >(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -667,12 +824,18 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
+ typedef typename geometry::rescale_policy_type
+ <
+ typename geometry::point_type<Geometry1>::type // TODO from both
+ >::type rescale_policy_type;
+
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ rescale_policy_type
> strategy;
return intersection_insert<GeometryOut>(geometry1, geometry2, out,
diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
new file mode 100644
index 0000000000..3a7a7a7f3e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
@@ -0,0 +1,326 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+
+#include <boost/geometry/algorithms/detail/turns/compare_turns.hpp>
+#include <boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp>
+#include <boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template
+<
+ typename LineStringOut,
+ overlay_type OverlayType,
+ typename Geometry,
+ typename GeometryTag
+>
+struct linear_linear_no_intersections;
+
+
+template <typename LineStringOut, typename LineString>
+struct linear_linear_no_intersections
+ <
+ LineStringOut, overlay_difference, LineString, linestring_tag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(LineString const& linestring,
+ OutputIterator oit)
+ {
+ LineStringOut ls_out;
+ geometry::convert(linestring, ls_out);
+ *oit++ = ls_out;
+ return oit;
+ }
+};
+
+
+template <typename LineStringOut, typename MultiLineString>
+struct linear_linear_no_intersections
+ <
+ LineStringOut,
+ overlay_difference,
+ MultiLineString,
+ multi_linestring_tag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(MultiLineString const& multilinestring,
+ OutputIterator oit)
+ {
+ for (typename boost::range_iterator<MultiLineString const>::type
+ it = boost::begin(multilinestring);
+ it != boost::end(multilinestring); ++it)
+ {
+ LineStringOut ls_out;
+ geometry::convert(*it, ls_out);
+ *oit++ = ls_out;
+ }
+ return oit;
+ }
+};
+
+
+template <typename LineStringOut, typename Geometry, typename GeometryTag>
+struct linear_linear_no_intersections
+ <
+ LineStringOut, overlay_intersection, Geometry, GeometryTag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(Geometry const&,
+ OutputIterator oit)
+ {
+ return oit;
+ }
+};
+
+
+
+
+
+
+
+template
+<
+ typename Linear1,
+ typename Linear2,
+ typename LinestringOut,
+ overlay_type OverlayType,
+ bool EnableFilterContinueTurns = false,
+ bool EnableRemoveDuplicateTurns = false,
+ bool EnableDegenerateTurns = true,
+#ifdef BOOST_GEOMETRY_INTERSECTION_DO_NOT_INCLUDE_ISOLATED_POINTS
+ bool EnableFollowIsolatedPoints = false
+#else
+ bool EnableFollowIsolatedPoints = true
+#endif
+>
+class linear_linear_linestring
+{
+protected:
+ struct assign_policy
+ {
+ static bool const include_no_turn = false;
+ static bool const include_degenerate = EnableDegenerateTurns;
+ static bool const include_opposite = false;
+
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(Info& , Point1 const& , Point2 const& ,
+ IntersectionInfo const& , DirInfo const& )
+ {
+ }
+ };
+
+
+ template
+ <
+ typename Turns,
+ typename LinearGeometry1,
+ typename LinearGeometry2
+ >
+ static inline void compute_turns(Turns& turns,
+ LinearGeometry1 const& linear1,
+ LinearGeometry2 const& linear2)
+ {
+ turns.clear();
+ geometry::detail::relate::turns::get_turns
+ <
+ LinearGeometry1,
+ LinearGeometry2,
+ detail::get_turns::get_turn_info_type
+ <
+ LinearGeometry1,
+ LinearGeometry2,
+ assign_policy
+ >
+ >::apply(turns, linear1, linear2);
+ }
+
+
+ template
+ <
+ overlay_type OverlayTypeForFollow,
+ bool FollowIsolatedPoints,
+ typename Turns,
+ typename LinearGeometry1,
+ typename LinearGeometry2,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ sort_and_follow_turns(Turns& turns,
+ LinearGeometry1 const& linear1,
+ LinearGeometry2 const& linear2,
+ OutputIterator oit)
+ {
+ // remove turns that have no added value
+ turns::filter_continue_turns
+ <
+ Turns,
+ EnableFilterContinueTurns && OverlayType != overlay_intersection
+ >::apply(turns);
+
+ // sort by seg_id, distance, and operation
+ std::sort(boost::begin(turns), boost::end(turns),
+ detail::turns::less_seg_fraction_other_op<>());
+
+ // remove duplicate turns
+ turns::remove_duplicate_turns
+ <
+ Turns, EnableRemoveDuplicateTurns
+ >::apply(turns);
+
+ return detail::overlay::following::linear::follow
+ <
+ LinestringOut,
+ LinearGeometry1,
+ LinearGeometry2,
+ OverlayTypeForFollow,
+ FollowIsolatedPoints,
+ !EnableFilterContinueTurns || OverlayType == overlay_intersection
+ >::apply(linear1, linear2, boost::begin(turns), boost::end(turns),
+ oit);
+ }
+
+public:
+ template
+ <
+ typename RobustPolicy, typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ RobustPolicy const&,
+ OutputIterator oit,
+ Strategy const& )
+ {
+ typedef typename detail::relate::turns::get_turns
+ <
+ Linear1, Linear2
+ >::turn_info turn_info;
+
+ typedef std::vector<turn_info> turns_container;
+
+ turns_container turns;
+ compute_turns(turns, linear1, linear2);
+
+ if ( turns.empty() )
+ {
+ // the two linear geometries are disjoint
+ return linear_linear_no_intersections
+ <
+ LinestringOut,
+ OverlayType,
+ Linear1,
+ typename tag<Linear1>::type
+ >::apply(linear1, oit);
+ }
+
+ return sort_and_follow_turns
+ <
+ OverlayType,
+ EnableFollowIsolatedPoints
+ && OverlayType == overlay_intersection
+ >(turns, linear1, linear2, oit);
+ }
+};
+
+
+
+
+template
+<
+ typename Linear1,
+ typename Linear2,
+ typename LinestringOut,
+ bool EnableFilterContinueTurns,
+ bool EnableRemoveDuplicateTurns,
+ bool EnableDegenerateTurns,
+ bool EnableFollowIsolatedPoints
+>
+struct linear_linear_linestring
+ <
+ Linear1, Linear2, LinestringOut, overlay_union,
+ EnableFilterContinueTurns, EnableRemoveDuplicateTurns,
+ EnableDegenerateTurns, EnableFollowIsolatedPoints
+ >
+{
+ template
+ <
+ typename RobustPolicy, typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ oit = linear_linear_no_intersections
+ <
+ LinestringOut,
+ overlay_difference,
+ Linear1,
+ typename tag<Linear1>::type
+ >::apply(linear1, oit);
+
+ return linear_linear_linestring
+ <
+ Linear2, Linear1, LinestringOut, overlay_difference,
+ EnableFilterContinueTurns, EnableRemoveDuplicateTurns,
+ EnableDegenerateTurns, EnableFollowIsolatedPoints
+ >::apply(linear2, linear1, robust_policy, oit, strategy);
+ }
+};
+
+
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
index 41665e0af1..44b5a0df3c 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,7 +18,6 @@
#include <boost/mpl/assert.hpp>
-#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
@@ -26,6 +26,7 @@
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
@@ -34,12 +35,19 @@
#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
# include <boost/geometry/io/dsv/write.hpp>
#endif
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+# include <boost/timer.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -66,19 +74,17 @@ inline void map_turns(Map& map, TurnPoints const& turn_points)
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)
+ ++it)
{
if (! skip(*it))
{
- 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)
+ ++op_it)
{
ring_identifier ring_id
(
@@ -110,6 +116,12 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
// Union: return either of them
// Intersection: return nothing
// Difference: return first of them
@@ -120,6 +132,11 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
return out;
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+
std::map<ring_identifier, int> empty;
std::map<ring_identifier, properties> all_of_one_of_them;
@@ -134,25 +151,26 @@ template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type Direction,
- typename Strategy
+ typename GeometryOut,
+ overlay_type Direction
>
struct overlay
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
- if (geometry::num_points(geometry1) == 0
- && geometry::num_points(geometry2) == 0)
+ if ( geometry::num_points(geometry1) == 0
+ && geometry::num_points(geometry2) == 0 )
{
return out;
}
- if (geometry::num_points(geometry1) == 0
- || geometry::num_points(geometry2) == 0)
+ if ( geometry::num_points(geometry1) == 0
+ || geometry::num_points(geometry2) == 0 )
{
return return_if_one_input_is_empty
<
@@ -161,7 +179,11 @@ struct overlay
}
typedef typename geometry::point_type<GeometryOut>::type point_type;
- typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ typedef detail::overlay::traversal_turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
typedef std::deque<turn_info> container_type;
typedef std::deque
@@ -182,8 +204,8 @@ std::cout << "get turns" << std::endl;
geometry::get_turns
<
Reverse1, Reverse2,
- detail::overlay::calculate_distance_policy
- >(geometry1, geometry2, turn_points, policy);
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, robust_policy, turn_points, policy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "get_turns: " << timer.elapsed() << std::endl;
@@ -198,6 +220,7 @@ std::cout << "enrich" << std::endl;
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
geometry1, geometry2,
+ robust_policy,
side_strategy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
@@ -218,6 +241,7 @@ std::cout << "traverse" << std::endl;
Direction == overlay_union
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
+ robust_policy,
turn_points, rings
);
@@ -248,8 +272,8 @@ std::cout << "traverse" << std::endl;
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
- it != boost::end(rings);
- ++it)
+ it != boost::end(rings);
+ ++it)
{
selected[id] = properties(*it, true);
selected[id].reversed = ReverseOut;
@@ -273,24 +297,6 @@ std::cout << "traverse" << std::endl;
};
-// Metafunction helper for intersection and union
-template <order_selector Selector, bool Reverse = false>
-struct do_reverse {};
-
-template <>
-struct do_reverse<clockwise, false> : boost::false_type {};
-
-template <>
-struct do_reverse<clockwise, true> : boost::true_type {};
-
-template <>
-struct do_reverse<counterclockwise, false> : boost::true_type {};
-
-template <>
-struct do_reverse<counterclockwise, true> : boost::false_type {};
-
-
-
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
new file mode 100644
index 0000000000..0af062d271
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
@@ -0,0 +1,435 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+// struct for copying points of the pointlike geometries to output
+template
+<
+ typename PointOut,
+ typename GeometryIn,
+ typename TagIn = typename tag<GeometryIn>::type
+>
+struct copy_points
+ : not_implemented<PointOut, GeometryIn>
+{};
+
+template <typename PointOut, typename PointIn>
+struct copy_points<PointOut, PointIn, point_tag>
+{
+ template <typename OutputIterator>
+ static inline void apply(PointIn const& point_in,
+ OutputIterator& oit)
+ {
+ PointOut point_out;
+ geometry::convert(point_in, point_out);
+ *oit++ = point_out;
+ }
+};
+
+
+template <typename PointOut, typename MultiPointIn>
+struct copy_points<PointOut, MultiPointIn, multi_point_tag>
+{
+ template <typename OutputIterator>
+ static inline void apply(MultiPointIn const& multi_point_in,
+ OutputIterator& oit)
+ {
+ for (typename boost::range_iterator<MultiPointIn const>::type
+ it = boost::begin(multi_point_in);
+ it != boost::end(multi_point_in); ++it)
+ {
+ PointOut point_out;
+ geometry::convert(*it, point_out);
+ *oit++ = point_out;
+ }
+ }
+};
+
+
+
+// action struct for difference/intersection
+template <typename PointOut, overlay_type OverlayType>
+struct action_selector_pl_pl
+{};
+
+template <typename PointOut>
+struct action_selector_pl_pl<PointOut, overlay_intersection>
+{
+ template
+ <
+ typename Point,
+ typename OutputIterator
+ >
+ static inline void apply(Point const& point,
+ bool is_common,
+ OutputIterator& oit)
+ {
+ if ( is_common )
+ {
+ copy_points<PointOut, Point>::apply(point, oit);
+ }
+ }
+};
+
+
+
+template <typename PointOut>
+struct action_selector_pl_pl<PointOut, overlay_difference>
+{
+ template
+ <
+ typename Point,
+ typename OutputIterator
+ >
+ static inline void apply(Point const& point,
+ bool is_common,
+ OutputIterator& oit)
+ {
+ if ( !is_common )
+ {
+ copy_points<PointOut, Point>::apply(point, oit);
+ }
+ }
+};
+
+
+//===========================================================================
+
+// difference/intersection of point-point
+template
+<
+ typename Point1,
+ typename Point2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct point_point_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Point1 const& point1,
+ Point2 const& point2,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(point1,
+ detail::equals::equals_point_point(point1, point2),
+ oit);
+
+ return oit;
+ }
+};
+
+
+
+// difference of multipoint-point
+//
+// the apply method in the following struct is called only for
+// difference; for intersection the reversal will
+// always call the point-multipoint version
+template
+<
+ typename MultiPoint,
+ typename Point,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct multipoint_point_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(MultiPoint const& multipoint,
+ Point const& point,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ BOOST_ASSERT( OverlayType == overlay_difference );
+
+ for (typename boost::range_iterator<MultiPoint const>::type
+ it = boost::begin(multipoint);
+ it != boost::end(multipoint); ++it)
+ {
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(*it,
+ detail::equals::equals_point_point(*it, point),
+ oit);
+ }
+
+ return oit;
+ }
+};
+
+
+// difference/intersection of point-multipoint
+template
+<
+ typename Point,
+ typename MultiPoint,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct point_multipoint_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Point const& point,
+ MultiPoint const& multipoint,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ typedef action_selector_pl_pl<PointOut, OverlayType> action;
+
+ for (typename boost::range_iterator<MultiPoint const>::type
+ it = boost::begin(multipoint);
+ it != boost::end(multipoint); ++it)
+ {
+ if ( detail::equals::equals_point_point(*it, point) )
+ {
+ action::apply(point, true, oit);
+ return oit;
+ }
+ }
+
+ action::apply(point, false, oit);
+ return oit;
+ }
+};
+
+
+
+// difference/intersection of multipoint-multipoint
+template
+<
+ typename MultiPoint1,
+ typename MultiPoint2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct multipoint_multipoint_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(MultiPoint1 const& multipoint1,
+ MultiPoint2 const& multipoint2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ if ( OverlayType != overlay_difference
+ && boost::size(multipoint1) > boost::size(multipoint2) )
+ {
+ return multipoint_multipoint_point
+ <
+ MultiPoint2, MultiPoint1, PointOut, OverlayType
+ >::apply(multipoint2, multipoint1, robust_policy, oit, strategy);
+ }
+
+ std::vector<typename point_type<MultiPoint2>::type>
+ points2(boost::begin(multipoint2), boost::end(multipoint2));
+
+ std::sort(points2.begin(), points2.end(), detail::relate::less());
+
+ for (typename boost::range_iterator<MultiPoint1 const>::type
+ it1 = boost::begin(multipoint1);
+ it1 != boost::end(multipoint1); ++it1)
+ {
+ bool found = std::binary_search(points2.begin(), points2.end(),
+ *it1, detail::relate::less());
+
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(*it1, found, oit);
+ }
+ return oit;
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+//===========================================================================
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch { namespace overlay
+{
+
+// dispatch struct for pointlike-pointlike difference/intersection
+// computation
+template
+<
+ typename PointLike1,
+ typename PointLike2,
+ typename PointOut,
+ overlay_type OverlayType,
+ typename Tag1,
+ typename Tag2
+>
+struct pointlike_pointlike_point
+ : not_implemented<PointLike1, PointLike2, PointOut>
+{};
+
+
+template
+<
+ typename Point1,
+ typename Point2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ Point1, Point2, PointOut, OverlayType,
+ point_tag, point_tag
+ > : detail::overlay::point_point_point
+ <
+ Point1, Point2, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename Point,
+ typename MultiPoint,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ Point, MultiPoint, PointOut, OverlayType,
+ point_tag, multi_point_tag
+ > : detail::overlay::point_multipoint_point
+ <
+ Point, MultiPoint, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint,
+ typename Point,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ MultiPoint, Point, PointOut, OverlayType,
+ multi_point_tag, point_tag
+ > : detail::overlay::multipoint_point_point
+ <
+ MultiPoint, Point, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint1,
+ typename MultiPoint2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType,
+ multi_point_tag, multi_point_tag
+ > : detail::overlay::multipoint_multipoint_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType
+ >
+{};
+
+
+}} // namespace detail_dispatch::overlay
+#endif // DOXYGEN_NO_DISPATCH
+
+
+//===========================================================================
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+// generic pointlike-pointlike union implementation
+template
+<
+ typename PointLike1,
+ typename PointLike2,
+ typename PointOut
+>
+struct union_pointlike_pointlike_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(PointLike1 const& pointlike1,
+ PointLike2 const& pointlike2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ copy_points<PointOut, PointLike1>::apply(pointlike1, oit);
+
+ return detail_dispatch::overlay::pointlike_pointlike_point
+ <
+ PointLike2, PointLike1, PointOut, overlay_difference,
+ typename tag<PointLike2>::type,
+ typename tag<PointLike1>::type
+ >::apply(pointlike2, pointlike1, robust_policy, oit, strategy);
+ }
+
+};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
index 007113ffba..516ec349e8 100644
--- a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
+++ b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
@@ -14,19 +14,19 @@
# define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
#endif
+#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
+#include <iostream>
+#endif
-#include <vector>
-
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/algorithms/detail/signed_index_type.hpp>
namespace boost { namespace geometry
{
+
// Internal struct to uniquely identify a segment
// on a linestring,ring
// or polygon (needs ring_index)
@@ -40,7 +40,10 @@ struct segment_identifier
, segment_index(-1)
{}
- inline segment_identifier(int src, int mul, int rin, int seg)
+ inline segment_identifier(signed_index_type src,
+ signed_index_type mul,
+ signed_index_type rin,
+ signed_index_type seg)
: source_index(src)
, multi_index(mul)
, ring_index(rin)
@@ -68,20 +71,20 @@ struct segment_identifier
#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
friend std::ostream& operator<<(std::ostream &os, segment_identifier const& seg_id)
{
- std::cout
+ os
<< "s:" << seg_id.source_index
- << ", v:" << seg_id.segment_index // ~vertex
+ << ", v:" << seg_id.segment_index // v:vertex because s is used for source
;
- if (seg_id.ring_index >= 0) std::cout << ", r:" << seg_id.ring_index;
- if (seg_id.multi_index >= 0) std::cout << ", m:" << seg_id.multi_index;
+ if (seg_id.ring_index >= 0) os << ", r:" << seg_id.ring_index;
+ if (seg_id.multi_index >= 0) os << ", m:" << seg_id.multi_index;
return os;
}
#endif
- int source_index;
- int multi_index;
- int ring_index;
- int segment_index;
+ signed_index_type source_index;
+ signed_index_type multi_index;
+ signed_index_type ring_index;
+ signed_index_type segment_index;
};
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
index f664b19514..385658a190 100644
--- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -9,11 +10,16 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
+
#include <map>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
@@ -40,14 +46,14 @@ namespace dispatch
struct select_rings<box_tag, Box>
{
template <typename Geometry, typename Map>
- static inline void apply(Box const& box, Geometry const& ,
+ static inline void apply(Box const& box, Geometry const& ,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
}
template <typename Map>
- static inline void apply(Box const& box,
+ static inline void apply(Box const& box,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
@@ -68,7 +74,7 @@ namespace dispatch
}
template <typename Map>
- static inline void apply(Ring const& ring,
+ static inline void apply(Ring const& ring,
ring_identifier const& id, Map& map, bool midpoint)
{
if (boost::size(ring) > 0)
@@ -91,9 +97,10 @@ namespace dispatch
per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, geometry, id, map, midpoint);
@@ -109,16 +116,42 @@ namespace dispatch
per_ring::apply(exterior_ring(polygon), id, map, midpoint);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, id, map, midpoint);
}
}
};
-}
+
+ template <typename Multi>
+ struct select_rings<multi_polygon_tag, Multi>
+ {
+ template <typename Geometry, typename Map>
+ static inline void apply(Multi const& multi, Geometry const& geometry,
+ ring_identifier id, Map& map, bool midpoint)
+ {
+ typedef typename boost::range_iterator
+ <
+ Multi const
+ >::type iterator_type;
+
+ typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon;
+
+ id.multi_index = 0;
+ for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
+ {
+ id.ring_index = -1;
+ per_polygon::apply(*it, geometry, id, map, midpoint);
+ id.multi_index++;
+ }
+ }
+ };
+
+} // namespace dispatch
template<overlay_type OverlayType>
@@ -213,7 +246,7 @@ inline void update_selection_map(Geometry1 const& geometry1,
typename SelectionMap::mapped_type properties = it->second; // Copy by value
// Calculate the "within code" (previously this was done earlier but is
- // must efficienter here - it can be even more efficient doing it all at once,
+ // much efficienter here - it can be even more efficient doing it all at once,
// using partition, TODO)
// So though this is less elegant than before, it avoids many unused point-in-poly calculations
switch(id.source_index)
@@ -248,7 +281,7 @@ template
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
- IntersectionMap const& intersection_map,
+ IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry1>::type tag1;
@@ -271,16 +304,16 @@ template
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry const& geometry,
- IntersectionMap const& intersection_map,
+ IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry>::type tag;
SelectionMap map_with_all;
- dispatch::select_rings<tag, Geometry>::apply(geometry,
+ dispatch::select_rings<tag, Geometry>::apply(geometry,
ring_identifier(0, -1, -1), map_with_all, midpoint);
- update_selection_map<OverlayType>(geometry, geometry, intersection_map,
+ update_selection_map<OverlayType>(geometry, geometry, intersection_map,
map_with_all, selection_map);
}
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
index 9c4c99394e..8dffeae283 100644
--- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -9,16 +9,18 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
+
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
@@ -55,17 +57,21 @@ template
typename Geometry,
typename Turns,
typename TurnPolicy,
+ typename RobustPolicy,
typename InterruptPolicy
>
struct self_section_visitor
{
Geometry const& m_geometry;
+ RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
inline self_section_visitor(Geometry const& g,
+ RobustPolicy const& rp,
Turns& turns, InterruptPolicy& ip)
: m_geometry(g)
+ , m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
@@ -82,12 +88,12 @@ struct self_section_visitor
Geometry, Geometry,
false, false,
Section, Section,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>::apply(
0, m_geometry, sec1,
0, m_geometry, sec2,
false,
+ m_rescale_policy,
m_turns, m_interrupt_policy);
}
if (m_interrupt_policy.has_intersections)
@@ -103,17 +109,13 @@ struct self_section_visitor
-template
-<
- typename Geometry,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
->
+template<typename TurnPolicy>
struct get_turns
{
+ template <typename Geometry, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Geometry const& geometry,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
@@ -127,20 +129,20 @@ struct get_turns
> sections_type;
sections_type sec;
- geometry::sectionalize<false>(geometry, sec);
+ geometry::sectionalize<false>(geometry, robust_policy, false, sec);
self_section_visitor
<
Geometry,
- Turns, TurnPolicy, InterruptPolicy
- > visitor(geometry, turns, interrupt_policy);
+ Turns, TurnPolicy, RobustPolicy, InterruptPolicy
+ > visitor(geometry, robust_policy, turns, interrupt_policy);
try
{
geometry::partition
<
- box_type,
- detail::get_turns::get_section_box,
+ box_type,
+ detail::get_turns::get_section_box,
detail::get_turns::ovelaps_section_box
>::apply(sec, visitor);
}
@@ -166,9 +168,7 @@ template
<
typename GeometryTag,
typename Geometry,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
{
@@ -178,44 +178,32 @@ struct self_get_turn_points
template
<
typename Ring,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
ring_tag, Ring,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
- : detail::self_get_turn_points::get_turns
- <
- Ring,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
{};
template
<
typename Box,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
box_tag, Box,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Box const& ,
+ RobustPolicy const& ,
Turns& ,
InterruptPolicy& )
{
@@ -227,24 +215,28 @@ struct self_get_turn_points
template
<
typename Polygon,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
polygon_tag, Polygon,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
+ >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
+{};
+
+
+template
+<
+ typename MultiPolygon,
+ typename TurnPolicy
+>
+struct self_get_turn_points
+ <
+ multi_polygon_tag, MultiPolygon,
+ TurnPolicy
>
- : detail::self_get_turn_points::get_turns
- <
- Polygon,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
{};
@@ -259,6 +251,7 @@ struct self_get_turn_points
\tparam Turns type of intersection container
(e.g. vector of "intersection/turn point"'s)
\param geometry geometry
+ \param robust_policy policy to handle robustness issues
\param turns container which will contain intersection points
\param interrupt_policy policy determining if process is stopped
when intersection is found
@@ -267,38 +260,24 @@ template
<
typename AssignPolicy,
typename Geometry,
+ typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy)
{
concept::check<Geometry const>();
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry>::type,
- Geometry,
- Geometry,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type strategy_type;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry>::type,
- typename point_type<Geometry>::type,
- typename boost::range_value<Turns>::type,
- detail::overlay::assign_null_policy
- > TurnPolicy;
+ typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
dispatch::self_get_turn_points
<
typename tag<Geometry>::type,
Geometry,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >::apply(geometry, turns, interrupt_policy);
+ turn_policy
+ >::apply(geometry, robust_policy, turns, interrupt_policy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
index eebe381944..51fd1b3dca 100644
--- a/boost/geometry/algorithms/detail/overlay/stream_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
@@ -35,7 +35,6 @@ namespace detail { namespace overlay
template <typename P>
std::ostream& operator<<(std::ostream &os, turn_info<P> const& info)
{
- typename geometry::coordinate_type<P>::type d = info.distance;
os << "\t"
<< " src " << info.seg_id.source_index
<< " seg " << info.seg_id.segment_index
@@ -54,7 +53,7 @@ namespace detail { namespace overlay
<< " nxt seg " << info.travels_to_vertex_index
<< " , ip " << info.travels_to_ip_index
<< " , or " << info.next_ip_index
- << " dst " << double(d)
+ << " frac " << info.fraction
<< info.visit_state;
if (info.flagged)
{
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
index 810a27af04..6ee32c17c0 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
@@ -24,15 +24,21 @@ namespace detail { namespace overlay
{
-template <typename P>
-struct traversal_turn_operation : public turn_operation
+template <typename Point, typename SegmentRatio>
+struct traversal_turn_operation : public turn_operation<SegmentRatio>
{
- enrichment_info<P> enriched;
+ enrichment_info<Point> enriched;
visit_info visited;
};
-template <typename P>
-struct traversal_turn_info : public turn_info<P, traversal_turn_operation<P> >
+template <typename Point, typename SegmentRatio>
+struct traversal_turn_info
+ : public turn_info
+ <
+ Point,
+ SegmentRatio,
+ traversal_turn_operation<Point, SegmentRatio>
+ >
{};
diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp
index 12daafa0cf..59d2ba703e 100644
--- a/boost/geometry/algorithms/detail/overlay/traverse.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp
@@ -13,11 +13,12 @@
#include <boost/range.hpp>
-#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -38,7 +39,7 @@ namespace detail { namespace overlay
template <typename Turn, typename Operation>
#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
-inline void debug_traverse(Turn const& turn, Operation op,
+inline void debug_traverse(Turn const& turn, Operation op,
std::string const& header)
{
std::cout << header
@@ -57,7 +58,7 @@ inline void debug_traverse(Turn const& turn, Operation op,
}
}
#else
-inline void debug_traverse(Turn const& , Operation, std::string const& )
+inline void debug_traverse(Turn const& , Operation, const char*)
{
}
#endif
@@ -92,14 +93,16 @@ template
typename G1,
typename G2,
typename Turns,
- typename IntersectionInfo
+ typename IntersectionInfo,
+ typename RobustPolicy
>
inline bool assign_next_ip(G1 const& g1, G2 const& g2,
Turns& turns,
typename boost::range_iterator<Turns>::type& ip,
GeometryOut& current_output,
IntersectionInfo& info,
- segment_identifier& seg_id)
+ segment_identifier& seg_id,
+ RobustPolicy const& robust_policy)
{
info.visited.set_visited();
set_visited_for_continue(*ip, info);
@@ -107,7 +110,7 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
// If there is no next IP on this segment
if (info.enriched.next_ip_index < 0)
{
- if (info.enriched.travels_to_vertex_index < 0
+ if (info.enriched.travels_to_vertex_index < 0
|| info.enriched.travels_to_ip_index < 0)
{
return false;
@@ -120,12 +123,14 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
{
geometry::copy_segments<Reverse1>(g1, info.seg_id,
info.enriched.travels_to_vertex_index,
+ robust_policy,
current_output);
}
else
{
geometry::copy_segments<Reverse2>(g2, info.seg_id,
info.enriched.travels_to_vertex_index,
+ robust_policy,
current_output);
}
seg_id = info.seg_id;
@@ -137,12 +142,16 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
seg_id = info.seg_id;
}
- detail::overlay::append_no_duplicates(current_output, ip->point);
+ detail::overlay::append_no_dups_or_spikes(current_output, ip->point,
+ robust_policy);
+
return true;
}
-inline bool select_source(operation_type operation, int source1, int source2)
+inline bool select_source(operation_type operation,
+ signed_index_type source1,
+ signed_index_type source2)
{
return (operation == operation_intersection && source1 != source2)
|| (operation == operation_union && source1 == source2)
@@ -227,12 +236,14 @@ template
class traverse
{
public :
- template <typename Turns, typename Rings>
+ template <typename RobustPolicy, typename Turns, typename Rings>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
detail::overlay::operation_type operation,
+ RobustPolicy const& robust_policy,
Turns& turns, Rings& rings)
{
+ typedef typename boost::range_value<Rings>::type ring_type;
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename boost::range_iterator
@@ -240,6 +251,12 @@ public :
typename turn_type::container_type
>::type turn_operation_iterator_type;
+ std::size_t const min_num_points
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<ring_type>::value
+ >::value;
+
std::size_t size_at_start = boost::size(rings);
typename Backtrack::state_type state;
@@ -253,7 +270,7 @@ public :
++it)
{
// Skip discarded ones
- if (! (it->is_discarded() || it->blocked()))
+ if (! (it->discarded || ! it->selectable_start || it->blocked()))
{
for (turn_operation_iterator_type iit = boost::begin(it->operations);
state.good() && iit != boost::end(it->operations);
@@ -267,9 +284,9 @@ public :
{
set_visited_for_continue(*it, *iit);
- typename boost::range_value<Rings>::type current_output;
- detail::overlay::append_no_duplicates(current_output,
- it->point, true);
+ ring_type current_output;
+ detail::overlay::append_no_dups_or_spikes(current_output,
+ it->point, robust_policy);
turn_iterator current = it;
turn_operation_iterator_type current_iit = iit;
@@ -279,13 +296,14 @@ public :
geometry1, geometry2,
turns,
current, current_output,
- *iit, current_seg_id))
+ *iit, current_seg_id,
+ robust_policy))
{
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *current_iit,
"No next IP",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
if (! detail::overlay::select_next_ip(
@@ -295,10 +313,10 @@ public :
current_iit))
{
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Dead end at start",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
else
{
@@ -308,7 +326,7 @@ public :
detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
- unsigned int i = 0;
+ typename boost::range_size<Turns>::type i = 0;
while (current_iit != iit && state.good())
{
@@ -317,10 +335,10 @@ public :
// It visits a visited node again, without passing the start node.
// This makes it suspicious for endless loops
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Visit again",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
else
{
@@ -339,7 +357,8 @@ public :
detail::overlay::assign_next_ip<Reverse1, Reverse2>(
geometry1, geometry2,
turns, current, current_output,
- *current_iit, current_seg_id);
+ *current_iit, current_seg_id,
+ robust_policy);
if (! detail::overlay::select_next_ip(
operation,
@@ -351,12 +370,15 @@ public :
// Should not occur in self-intersecting polygons without spikes
// Might occur in polygons with spikes
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Dead end",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
+ }
+ else
+ {
+ detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
}
- detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
if (i++ > 2 + 2 * turns.size())
{
@@ -364,10 +386,10 @@ public :
// than turn points.
// Turn points marked as "ii" can be visited twice.
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Endless loop",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
}
}
@@ -376,7 +398,11 @@ public :
{
iit->visited.set_finished();
detail::overlay::debug_traverse(*current, *iit, "->Finished");
- rings.push_back(current_output);
+ if (geometry::num_points(current_output) >= min_num_points)
+ {
+ clean_closing_dups_and_spikes(current_output, robust_policy);
+ rings.push_back(current_output);
+ }
}
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
index 89a60b21ab..26669a4b1f 100644
--- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
@@ -54,11 +54,12 @@ enum method_type
The class is to be included in the turn_info class, either direct
or a derived or similar class with more (e.g. enrichment) information.
*/
+template <typename SegmentRatio>
struct turn_operation
{
operation_type operation;
segment_identifier seg_id;
- segment_identifier other_id;
+ SegmentRatio fraction;
inline turn_operation()
: operation(operation_none)
@@ -78,7 +79,8 @@ struct turn_operation
template
<
typename Point,
- typename Operation = turn_operation,
+ typename SegmentRatio,
+ typename Operation = turn_operation<SegmentRatio>,
typename Container = boost::array<Operation, 2>
>
struct turn_info
@@ -90,6 +92,7 @@ struct turn_info
Point point;
method_type method;
bool discarded;
+ bool selectable_start; // Can be used as starting-turn in traverse
Container operations;
@@ -97,13 +100,14 @@ struct turn_info
inline turn_info()
: method(method_none)
, discarded(false)
+ , selectable_start(true)
{}
inline bool both(operation_type type) const
{
return has12(type, type);
}
-
+
inline bool has(operation_type type) const
{
return this->operations[0].operation == type
@@ -115,8 +119,6 @@ struct turn_info
return has12(type1, type2) || has12(type2, type1);
}
-
- inline bool is_discarded() const { return discarded; }
inline bool blocked() const
{
return both(operation_blocked);
diff --git a/boost/geometry/algorithms/detail/overlay/visit_info.hpp b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
index 6be63f42b4..4284a801a1 100644
--- a/boost/geometry/algorithms/detail/overlay/visit_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
@@ -10,11 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP
-#ifdef BOOST_GEOMETRY_USE_MSM
-# include <boost/geometry/algorithms/detail/overlay/msm_state.hpp>
-#endif
-
-
namespace boost { namespace geometry
{
@@ -22,9 +17,6 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
-
-#if ! defined(BOOST_GEOMETRY_USE_MSM)
-
class visit_info
{
private :
@@ -66,8 +58,6 @@ public:
}
}
-
-
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
{
@@ -82,50 +72,6 @@ public:
};
-#else
-
-
-class visit_info
-{
-
-private :
-
-#ifndef USE_MSM_MINI
- mutable
-#endif
- traverse_state state;
-
-public :
- inline visit_info()
- {
- state.start();
- }
-
- inline void set_none() { state.process_event(none()); } // Not Yet Implemented!
- inline void set_visited() { state.process_event(visit()); }
- inline void set_started() { state.process_event(starting()); }
- inline void set_finished() { state.process_event(finish()); }
-
-#ifdef USE_MSM_MINI
- inline bool none() const { return state.flag_none(); }
- inline bool visited() const { return state.flag_visited(); }
- inline bool started() const { return state.flag_started(); }
-#else
- inline bool none() const { return state.is_flag_active<is_init>(); }
- inline bool visited() const { return state.is_flag_active<is_visited>(); }
- inline bool started() const { return state.is_flag_active<is_started>(); }
-#endif
-
-#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
- friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
- {
- return os;
- }
-#endif
-};
-#endif
-
-
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp
index 45ff52ccb1..a44d5637bc 100644
--- a/boost/geometry/algorithms/detail/partition.hpp
+++ b/boost/geometry/algorithms/detail/partition.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2011-2014 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
@@ -10,6 +10,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
#include <vector>
+#include <boost/assert.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
@@ -23,7 +24,7 @@ namespace detail { namespace partition
typedef std::vector<std::size_t> index_vector_type;
template <int Dimension, typename Box>
-inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
+void divide_box(Box const& box, Box& lower_box, Box& upper_box)
{
typedef typename coordinate_type<Box>::type ctype;
@@ -39,10 +40,10 @@ inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
}
// Divide collection into three subsets: lower, upper and oversized
-// (not-fitting)
+// (not-fitting)
// (lower == left or bottom, upper == right or top)
template <typename OverlapsPolicy, typename InputCollection, typename Box>
-static inline void divide_into_subsets(Box const& lower_box,
+inline void divide_into_subsets(Box const& lower_box,
Box const& upper_box,
InputCollection const& collection,
index_vector_type const& input,
@@ -79,14 +80,14 @@ static inline void divide_into_subsets(Box const& lower_box,
else
{
// Is nowhere! Should not occur!
- BOOST_ASSERT(true);
+ BOOST_ASSERT(false);
}
}
}
// Match collection with itself
template <typename InputCollection, typename Policy>
-static inline void handle_one(InputCollection const& collection,
+inline void handle_one(InputCollection const& collection,
index_vector_type const& input,
Policy& policy)
{
@@ -106,10 +107,15 @@ static inline void handle_one(InputCollection const& collection,
}
// Match collection 1 with collection 2
-template <typename InputCollection, typename Policy>
-static inline void handle_two(
- InputCollection const& collection1, index_vector_type const& input1,
- InputCollection const& collection2, index_vector_type const& input2,
+template
+<
+ typename InputCollection1,
+ typename InputCollection2,
+ typename Policy
+>
+inline void handle_two(
+ InputCollection1 const& collection1, index_vector_type const& input1,
+ InputCollection2 const& collection2, index_vector_type const& input2,
Policy& policy)
{
typedef boost::range_iterator
@@ -209,7 +215,8 @@ template
<
int Dimension,
typename Box,
- typename OverlapsPolicy,
+ typename OverlapsPolicy1,
+ typename OverlapsPolicy2,
typename VisitBoxPolicy
>
class partition_two_collections
@@ -220,15 +227,21 @@ class partition_two_collections
<
1 - Dimension,
Box,
- OverlapsPolicy,
+ OverlapsPolicy1,
+ OverlapsPolicy2,
VisitBoxPolicy
> sub_divide;
- template <typename InputCollection, typename Policy>
+ template
+ <
+ typename InputCollection1,
+ typename InputCollection2,
+ typename Policy
+ >
static inline void next_level(Box const& box,
- InputCollection const& collection1,
+ InputCollection1 const& collection1,
index_vector_type const& input1,
- InputCollection const& collection2,
+ InputCollection2 const& collection2,
index_vector_type const& input2,
int level, std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
@@ -252,10 +265,15 @@ class partition_two_collections
}
public :
- template <typename InputCollection, typename Policy>
+ template
+ <
+ typename InputCollection1,
+ typename InputCollection2,
+ typename Policy
+ >
static inline void apply(Box const& box,
- InputCollection const& collection1, index_vector_type const& input1,
- InputCollection const& collection2, index_vector_type const& input2,
+ InputCollection1 const& collection1, index_vector_type const& input1,
+ InputCollection2 const& collection2, index_vector_type const& input2,
int level,
std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
@@ -267,9 +285,9 @@ public :
index_vector_type lower1, upper1, exceeding1;
index_vector_type lower2, upper2, exceeding2;
- divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection1,
+ divide_into_subsets<OverlapsPolicy1>(lower_box, upper_box, collection1,
input1, lower1, upper1, exceeding1);
- divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection2,
+ divide_into_subsets<OverlapsPolicy2>(lower_box, upper_box, collection2,
input2, lower2, upper2, exceeding2);
if (boost::size(exceeding1) > 0)
@@ -308,15 +326,17 @@ struct visit_no_policy
template
<
typename Box,
- typename ExpandPolicy,
- typename OverlapsPolicy,
+ typename ExpandPolicy1,
+ typename OverlapsPolicy1,
+ typename ExpandPolicy2 = ExpandPolicy1,
+ typename OverlapsPolicy2 = OverlapsPolicy1,
typename VisitBoxPolicy = visit_no_policy
>
class partition
{
typedef std::vector<std::size_t> index_vector_type;
- template <typename InputCollection>
+ template <typename ExpandPolicy, typename InputCollection>
static inline void expand_to_collection(InputCollection const& collection,
Box& total, index_vector_type& index_vector)
{
@@ -344,12 +364,12 @@ public :
index_vector_type index_vector;
Box total;
assign_inverse(total);
- expand_to_collection(collection, total, index_vector);
+ expand_to_collection<ExpandPolicy1>(collection, total, index_vector);
detail::partition::partition_one_collection
<
0, Box,
- OverlapsPolicy,
+ OverlapsPolicy1,
VisitBoxPolicy
>::apply(total, collection, index_vector, 0, min_elements,
visitor, box_visitor);
@@ -373,9 +393,14 @@ public :
}
}
- template <typename InputCollection, typename VisitPolicy>
- static inline void apply(InputCollection const& collection1,
- InputCollection const& collection2,
+ template
+ <
+ typename InputCollection1,
+ typename InputCollection2,
+ typename VisitPolicy
+ >
+ static inline void apply(InputCollection1 const& collection1,
+ InputCollection2 const& collection2,
VisitPolicy& visitor,
std::size_t min_elements = 16,
VisitBoxPolicy box_visitor = visit_no_policy()
@@ -387,12 +412,12 @@ public :
index_vector_type index_vector1, index_vector2;
Box total;
assign_inverse(total);
- expand_to_collection(collection1, total, index_vector1);
- expand_to_collection(collection2, total, index_vector2);
+ expand_to_collection<ExpandPolicy1>(collection1, total, index_vector1);
+ expand_to_collection<ExpandPolicy2>(collection2, total, index_vector2);
detail::partition::partition_two_collections
<
- 0, Box, OverlapsPolicy, VisitBoxPolicy
+ 0, Box, OverlapsPolicy1, OverlapsPolicy2, VisitBoxPolicy
>::apply(total,
collection1, index_vector1,
collection2, index_vector2,
@@ -402,13 +427,17 @@ public :
{
typedef typename boost::range_iterator
<
- InputCollection const
- >::type iterator_type;
- for(iterator_type it1 = boost::begin(collection1);
+ InputCollection1 const
+ >::type iterator_type1;
+ typedef typename boost::range_iterator
+ <
+ InputCollection2 const
+ >::type iterator_type2;
+ for(iterator_type1 it1 = boost::begin(collection1);
it1 != boost::end(collection1);
++it1)
{
- for(iterator_type it2 = boost::begin(collection2);
+ for(iterator_type2 it2 = boost::begin(collection2);
it2 != boost::end(collection2);
++it2)
{
@@ -417,9 +446,9 @@ public :
}
}
}
-
};
+
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
diff --git a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
new file mode 100644
index 0000000000..cd3acb5ba4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
@@ -0,0 +1,126 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP
+
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/strategies/side.hpp>
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+// Checks if a point ("last_point") causes a spike w.r.t.
+// the specified two other points (segment_a, segment_b)
+//
+// x-------x------x
+// a lp b
+//
+// Above, lp generates a spike w.r.t. segment(a,b)
+// So specify last point first, then (a,b) (this is unordered, so unintuitive)
+template <typename Point1, typename Point2, typename Point3>
+static inline bool point_is_spike_or_equal(Point1 const& last_point,
+ Point2 const& segment_a,
+ Point3 const& segment_b)
+{
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point1>::type
+ >::type side_strategy;
+
+ typedef Point1 vector_type;
+
+ int const side = side_strategy::apply(last_point, segment_a, segment_b);
+ if (side == 0)
+ {
+ // Last point is collinear w.r.t previous segment.
+ // Check if it is equal
+ vector_type diff1;
+ conversion::convert_point_to_point(last_point, diff1);
+ geometry::subtract_point(diff1, segment_b);
+ int const sgn_x1 = math::sign(geometry::get<0>(diff1));
+ int const sgn_y1 = math::sign(geometry::get<1>(diff1));
+ if (sgn_x1 == 0 && sgn_y1 == 0)
+ {
+ return true;
+ }
+
+ // Check if it moves forward
+ vector_type diff2;
+ conversion::convert_point_to_point(segment_b, diff2);
+ geometry::subtract_point(diff2, segment_a);
+ int const sgn_x2 = math::sign(geometry::get<0>(diff2));
+ int const sgn_y2 = math::sign(geometry::get<1>(diff2));
+
+ return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
+ }
+ return false;
+}
+
+template
+<
+ typename Point1,
+ typename Point2,
+ typename Point3,
+ typename RobustPolicy
+>
+static inline bool point_is_spike_or_equal(Point1 const& last_point,
+ Point2 const& segment_a,
+ Point3 const& segment_b,
+ RobustPolicy const& robust_policy)
+{
+ if (point_is_spike_or_equal(last_point, segment_a, segment_b))
+ {
+ return true;
+ }
+
+ if (! RobustPolicy::enabled)
+ {
+ return false;
+ }
+
+ // Try using specified robust policy
+ typedef typename geometry::robust_point_type
+ <
+ Point1,
+ RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type last_point_rob, segment_a_rob, segment_b_rob;
+ geometry::recalculate(last_point_rob, last_point, robust_policy);
+ geometry::recalculate(segment_a_rob, segment_a, robust_policy);
+ geometry::recalculate(segment_b_rob, segment_b, robust_policy);
+
+ return point_is_spike_or_equal
+ (
+ last_point_rob,
+ segment_a_rob,
+ segment_b_rob
+ );
+}
+
+
+} // namespace detail
+#endif
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP
diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp
index b7e15ba3f9..24b88a8d19 100644
--- a/boost/geometry/algorithms/detail/point_on_border.hpp
+++ b/boost/geometry/algorithms/detail/point_on_border.hpp
@@ -19,6 +19,7 @@
#include <boost/range.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
@@ -26,7 +27,7 @@
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
namespace boost { namespace geometry
@@ -153,6 +154,35 @@ struct point_on_box
};
+template
+<
+ typename Point,
+ typename MultiGeometry,
+ typename Policy
+>
+struct point_on_multi
+{
+ static inline bool apply(Point& point, MultiGeometry const& multi, bool midpoint)
+ {
+ // Take a point on the first multi-geometry
+ // (i.e. the first that is not empty)
+ for (typename boost::range_iterator
+ <
+ MultiGeometry const
+ >::type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ if (Policy::apply(point, *it, midpoint))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+
}} // namespace detail::point_on_border
#endif // DOXYGEN_NO_DETAIL
@@ -203,6 +233,36 @@ struct point_on_border<box_tag, Point, Box>
{};
+template<typename Point, typename Multi>
+struct point_on_border<multi_polygon_tag, Point, Multi>
+ : detail::point_on_border::point_on_multi
+ <
+ Point,
+ Multi,
+ detail::point_on_border::point_on_polygon
+ <
+ Point,
+ typename boost::range_value<Multi>::type
+ >
+ >
+{};
+
+
+template<typename Point, typename Multi>
+struct point_on_border<multi_linestring_tag, Point, Multi>
+ : detail::point_on_border::point_on_multi
+ <
+ Point,
+ Multi,
+ detail::point_on_border::point_on_range
+ <
+ Point,
+ typename boost::range_value<Multi>::type
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -229,8 +289,6 @@ inline bool point_on_border(Point& point,
concept::check<Point>();
concept::check<Geometry const>();
- typedef typename point_type<Geometry>::type point_type;
-
return dispatch::point_on_border
<
typename tag<Geometry>::type,
diff --git a/boost/geometry/algorithms/detail/recalculate.hpp b/boost/geometry/algorithms/detail/recalculate.hpp
new file mode 100644
index 0000000000..2c3ea7413b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/recalculate.hpp
@@ -0,0 +1,231 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP
+
+
+#include <cstddef>
+
+#include <boost/concept/requires.hpp>
+#include <boost/concept_check.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/numeric/conversion/bounds.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/type_traits.hpp>
+
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace recalculate
+{
+
+template <std::size_t Dimension>
+struct recalculate_point
+{
+ template <typename Point1, typename Point2, typename Strategy>
+ static inline void apply(Point1& point1, Point2 const& point2, Strategy const& strategy)
+ {
+ std::size_t const dim = Dimension - 1;
+ geometry::set<dim>(point1, strategy.template apply<dim>(geometry::get<dim>(point2)));
+ recalculate_point<dim>::apply(point1, point2, strategy);
+ }
+};
+
+template <>
+struct recalculate_point<0>
+{
+ template <typename Point1, typename Point2, typename Strategy>
+ static inline void apply(Point1&, Point2 const&, Strategy const&)
+ {
+ }
+};
+
+
+template <std::size_t Dimension>
+struct recalculate_indexed
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline void apply(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // Do it for both indices in one dimension
+ static std::size_t const dim = Dimension - 1;
+ geometry::set<0, dim>(geometry1, strategy.template apply<dim>(geometry::get<0, dim>(geometry2)));
+ geometry::set<1, dim>(geometry1, strategy.template apply<dim>(geometry::get<1, dim>(geometry2)));
+ recalculate_indexed<dim>::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <>
+struct recalculate_indexed<0>
+{
+
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline void apply(Geometry1& , Geometry2 const& , Strategy const& )
+ {
+ }
+};
+
+struct range_to_range
+{
+ template
+ <
+ typename Range1,
+ typename Range2,
+ typename Strategy
+ >
+ static inline void apply(Range1& destination, Range2 const& source,
+ Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Range2>::type point_type;
+ typedef recalculate_point<geometry::dimension<point_type>::value> per_point;
+ geometry::clear(destination);
+
+ for (typename boost::range_iterator<Range2 const>::type it
+ = boost::begin(source);
+ it != boost::end(source);
+ ++it)
+ {
+ point_type p;
+ per_point::apply(p, *it, strategy);
+ geometry::append(destination, p);
+ }
+ }
+};
+
+struct polygon_to_polygon
+{
+private:
+ template
+ <
+ typename IteratorIn,
+ typename IteratorOut,
+ typename Strategy
+ >
+ static inline void iterate(IteratorIn begin, IteratorIn end,
+ IteratorOut it_out,
+ Strategy const& strategy)
+ {
+ for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out)
+ {
+ range_to_range::apply(*it_out, *it_in, strategy);
+ }
+ }
+
+ template
+ <
+ typename InteriorRingsOut,
+ typename InteriorRingsIn,
+ typename Strategy
+ >
+ static inline void apply_interior_rings(
+ InteriorRingsOut& interior_rings_out,
+ InteriorRingsIn const& interior_rings_in,
+ Strategy const& strategy)
+ {
+ traits::resize<InteriorRingsOut>::apply(interior_rings_out,
+ boost::size(interior_rings_in));
+
+ iterate(
+ boost::begin(interior_rings_in), boost::end(interior_rings_in),
+ boost::begin(interior_rings_out),
+ strategy);
+ }
+
+public:
+ template
+ <
+ typename Polygon1,
+ typename Polygon2,
+ typename Strategy
+ >
+ static inline void apply(Polygon1& destination, Polygon2 const& source,
+ Strategy const& strategy)
+ {
+ range_to_range::apply(geometry::exterior_ring(destination),
+ geometry::exterior_ring(source), strategy);
+
+ apply_interior_rings(geometry::interior_rings(destination),
+ geometry::interior_rings(source), strategy);
+ }
+};
+
+}} // namespace detail::recalculate
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type
+>
+struct recalculate : not_implemented<Tag1, Tag2>
+{};
+
+template <typename Point1, typename Point2>
+struct recalculate<Point1, Point2, point_tag, point_tag>
+ : detail::recalculate::recalculate_point<geometry::dimension<Point1>::value>
+{};
+
+template <typename Box1, typename Box2>
+struct recalculate<Box1, Box2, box_tag, box_tag>
+ : detail::recalculate::recalculate_indexed<geometry::dimension<Box1>::value>
+{};
+
+template <typename Segment1, typename Segment2>
+struct recalculate<Segment1, Segment2, segment_tag, segment_tag>
+ : detail::recalculate::recalculate_indexed<geometry::dimension<Segment1>::value>
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct recalculate<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : detail::recalculate::polygon_to_polygon
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline void recalculate(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+{
+ concept::check<Geometry1>();
+ concept::check<Geometry2 const>();
+
+ // static assert dimensions (/types) are the same
+
+ dispatch::recalculate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP
diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp
new file mode 100644
index 0000000000..31d206ac99
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/areal_areal.hpp
@@ -0,0 +1,823 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
+
+#include <boost/geometry/core/topological_dimension.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/single_geometry.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
+#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// WARNING!
+// TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM)
+// Use the rtree in this case!
+
+// may be used to set EI and EB for an Areal geometry for which no turns were generated
+template <typename OtherAreal, typename Result, bool TransposeResult>
+class no_turns_aa_pred
+{
+public:
+ no_turns_aa_pred(OtherAreal const& other_areal, Result & res)
+ : m_result(res)
+ , m_other_areal(other_areal)
+ , m_flags(0)
+ {
+ // check which relations must be analysed
+
+ if ( ! may_update<interior, interior, '2', TransposeResult>(m_result)
+ && ! may_update<boundary, interior, '1', TransposeResult>(m_result)
+ && ! may_update<exterior, interior, '2', TransposeResult>(m_result) )
+ {
+ m_flags |= 1;
+ }
+
+ if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result)
+ && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
+ {
+ m_flags |= 2;
+ }
+ }
+
+ template <typename Areal>
+ bool operator()(Areal const& areal)
+ {
+ // if those flags are set nothing will change
+ if ( m_flags == 3 )
+ {
+ return false;
+ }
+
+ typedef typename geometry::point_type<Areal>::type point_type;
+ point_type pt;
+ bool const ok = boost::geometry::point_on_border(pt, areal);
+
+ // TODO: for now ignore, later throw an exception?
+ if ( !ok )
+ {
+ return true;
+ }
+
+ // check if the areal is inside the other_areal
+ // TODO: This is O(N)
+ // Run in a loop O(NM) - optimize!
+ int const pig = detail::within::point_in_geometry(pt, m_other_areal);
+ //BOOST_ASSERT( pig != 0 );
+
+ // inside
+ if ( pig > 0 )
+ {
+ update<interior, interior, '2', TransposeResult>(m_result);
+ update<boundary, interior, '1', TransposeResult>(m_result);
+ update<exterior, interior, '2', TransposeResult>(m_result);
+ m_flags |= 1;
+
+ // TODO: OPTIMIZE!
+ // Only the interior rings of other ONE single geometry must be checked
+ // NOT all geometries
+
+ // Check if any interior ring is outside
+ ring_identifier ring_id(0, -1, 0);
+ int const irings_count = boost::numeric_cast<int>(
+ geometry::num_interior_rings(areal) );
+ for ( ; ring_id.ring_index < irings_count ; ++ring_id.ring_index )
+ {
+ typename detail::sub_range_return_type<Areal const>::type
+ range_ref = detail::sub_range(areal, ring_id);
+
+ if ( boost::empty(range_ref) )
+ {
+ // TODO: throw exception?
+ continue; // ignore
+ }
+
+ // TODO: O(N)
+ // Optimize!
+ int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal);
+
+ // hole outside
+ if ( hpig < 0 )
+ {
+ update<interior, exterior, '2', TransposeResult>(m_result);
+ update<boundary, exterior, '1', TransposeResult>(m_result);
+ m_flags |= 2;
+ break;
+ }
+ }
+ }
+ // outside
+ else
+ {
+ update<interior, exterior, '2', TransposeResult>(m_result);
+ update<boundary, exterior, '1', TransposeResult>(m_result);
+ m_flags |= 2;
+
+ // Check if any interior ring is inside
+ ring_identifier ring_id(0, -1, 0);
+ int const irings_count = boost::numeric_cast<int>(
+ geometry::num_interior_rings(areal) );
+ for ( ; ring_id.ring_index < irings_count ; ++ring_id.ring_index )
+ {
+ typename detail::sub_range_return_type<Areal const>::type
+ range_ref = detail::sub_range(areal, ring_id);
+
+ if ( boost::empty(range_ref) )
+ {
+ // TODO: throw exception?
+ continue; // ignore
+ }
+
+ // TODO: O(N)
+ // Optimize!
+ int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal);
+
+ // hole inside
+ if ( hpig > 0 )
+ {
+ update<interior, interior, '2', TransposeResult>(m_result);
+ update<boundary, interior, '1', TransposeResult>(m_result);
+ update<exterior, interior, '2', TransposeResult>(m_result);
+ m_flags |= 1;
+ break;
+ }
+ }
+ }
+
+ return m_flags != 3 && !m_result.interrupt;
+ }
+
+private:
+ Result & m_result;
+ OtherAreal const& m_other_areal;
+ int m_flags;
+};
+
+// The implementation of an algorithm calculating relate() for A/A
+template <typename Geometry1, typename Geometry2>
+struct areal_areal
+{
+ // check Linear / Areal
+ BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2
+ && topological_dimension<Geometry2>::value == 2);
+
+ static const bool interruption_enabled = true;
+
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+// TODO: If Areal geometry may have infinite size, change the following line:
+
+ // The result should be FFFFFFFFF
+ relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T
+
+ if ( result.interrupt )
+ return;
+
+ // get and analyse turns
+ typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
+ std::vector<turn_type> turns;
+
+ interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
+
+ turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
+ if ( result.interrupt )
+ return;
+
+ no_turns_aa_pred<Geometry2, Result, false> pred1(geometry2, result);
+ for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
+ if ( result.interrupt )
+ return;
+
+ no_turns_aa_pred<Geometry1, Result, true> pred2(geometry1, result);
+ for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
+ if ( result.interrupt )
+ return;
+
+ if ( turns.empty() )
+ return;
+
+ if ( may_update<interior, interior, '2'>(result)
+ || may_update<interior, exterior, '2'>(result)
+ || may_update<boundary, interior, '1'>(result)
+ || may_update<boundary, exterior, '1'>(result)
+ || may_update<exterior, interior, '2'>(result) )
+ {
+ // sort turns
+ typedef turns::less<0, turns::less_op_areal_areal<0> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ /*if ( may_update<interior, exterior, '2'>(result)
+ || may_update<boundary, exterior, '1'>(result)
+ || may_update<boundary, interior, '1'>(result)
+ || may_update<exterior, interior, '2'>(result) )*/
+ {
+ // analyse sorted turns
+ turns_analyser<turn_type, 0> analyser;
+ analyse_each_turn(result, analyser, turns.begin(), turns.end());
+
+ if ( result.interrupt )
+ return;
+ }
+
+ if ( may_update<interior, interior, '2'>(result)
+ || may_update<interior, exterior, '2'>(result)
+ || may_update<boundary, interior, '1'>(result)
+ || may_update<boundary, exterior, '1'>(result)
+ || may_update<exterior, interior, '2'>(result) )
+ {
+ // analyse rings for which turns were not generated
+ // or only i/i or u/u was generated
+ uncertain_rings_analyser<0, Result, Geometry1, Geometry2> rings_analyser(result, geometry1, geometry2);
+ analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end());
+
+ if ( result.interrupt )
+ return;
+ }
+ }
+
+ if ( may_update<interior, interior, '2', true>(result)
+ || may_update<interior, exterior, '2', true>(result)
+ || may_update<boundary, interior, '1', true>(result)
+ || may_update<boundary, exterior, '1', true>(result)
+ || may_update<exterior, interior, '2', true>(result) )
+ {
+ // sort turns
+ typedef turns::less<1, turns::less_op_areal_areal<1> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ /*if ( may_update<interior, exterior, '2', true>(result)
+ || may_update<boundary, exterior, '1', true>(result)
+ || may_update<boundary, interior, '1', true>(result)
+ || may_update<exterior, interior, '2', true>(result) )*/
+ {
+ // analyse sorted turns
+ turns_analyser<turn_type, 1> analyser;
+ analyse_each_turn(result, analyser, turns.begin(), turns.end());
+
+ if ( result.interrupt )
+ return;
+ }
+
+ if ( may_update<interior, interior, '2', true>(result)
+ || may_update<interior, exterior, '2', true>(result)
+ || may_update<boundary, interior, '1', true>(result)
+ || may_update<boundary, exterior, '1', true>(result)
+ || may_update<exterior, interior, '2', true>(result) )
+ {
+ // analyse rings for which turns were not generated
+ // or only i/i or u/u was generated
+ uncertain_rings_analyser<1, Result, Geometry2, Geometry1> rings_analyser(result, geometry2, geometry1);
+ analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end());
+
+ //if ( result.interrupt )
+ // return;
+ }
+ }
+ }
+
+ // interrupt policy which may be passed to get_turns to interrupt the analysis
+ // based on the info in the passed result/mask
+ template <typename Result>
+ class interrupt_policy_areal_areal
+ {
+ public:
+ static bool const enabled = true;
+
+ interrupt_policy_areal_areal(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Result & result)
+ : m_result(result)
+ , m_geometry1(geometry1)
+ , m_geometry2(geometry2)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& turns)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
+ {
+ per_turn<0>(*it);
+ per_turn<1>(*it);
+ }
+
+ return m_result.interrupt;
+ }
+
+ private:
+ template <std::size_t OpId, typename Turn>
+ inline void per_turn(Turn const& turn)
+ {
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static const bool transpose_result = OpId != 0;
+
+ overlay::operation_type const op = turn.operations[OpId].operation;
+
+ if ( op == overlay::operation_union )
+ {
+ // ignore u/u
+ /*if ( turn.operations[other_op_id].operation != overlay::operation_union )
+ {
+ update<interior, exterior, '2', transpose_result>(m_result);
+ update<boundary, exterior, '1', transpose_result>(m_result);
+ }*/
+
+ update<boundary, boundary, '0', transpose_result>(m_result);
+ }
+ else if ( op == overlay::operation_intersection )
+ {
+ // ignore i/i
+ if ( turn.operations[other_op_id].operation != overlay::operation_intersection )
+ {
+ update<interior, interior, '2', transpose_result>(m_result);
+ //update<boundary, interior, '1', transpose_result>(m_result);
+ }
+
+ update<boundary, boundary, '0', transpose_result>(m_result);
+ }
+ else if ( op == overlay::operation_continue )
+ {
+ update<boundary, boundary, '1', transpose_result>(m_result);
+ update<interior, interior, '2', transpose_result>(m_result);
+ }
+ else if ( op == overlay::operation_blocked )
+ {
+ update<boundary, boundary, '1', transpose_result>(m_result);
+ update<interior, exterior, '2', transpose_result>(m_result);
+ }
+ }
+
+ Result & m_result;
+ Geometry1 const& m_geometry1;
+ Geometry2 const& m_geometry2;
+ };
+
+ // This analyser should be used like Input or SinglePass Iterator
+ // IMPORTANT! It should be called also for the end iterator - last
+ template <typename TurnInfo, std::size_t OpId>
+ class turns_analyser
+ {
+ typedef typename TurnInfo::point_type turn_point_type;
+
+ static const std::size_t op_id = OpId;
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static const bool transpose_result = OpId != 0;
+
+ public:
+ turns_analyser()
+ : m_previous_turn_ptr(0)
+ , m_previous_operation(overlay::operation_none)
+ , m_enter_detected(false)
+ , m_exit_detected(false)
+ {}
+
+ template <typename Result,
+ typename TurnIt>
+ void apply(Result & result, TurnIt it)
+ {
+ //BOOST_ASSERT( it != last );
+
+ overlay::operation_type const op = it->operations[op_id].operation;
+
+ if ( op != overlay::operation_union
+ && op != overlay::operation_intersection
+ && op != overlay::operation_blocked
+ && op != overlay::operation_continue )
+ {
+ return;
+ }
+
+ segment_identifier const& seg_id = it->operations[op_id].seg_id;
+ //segment_identifier const& other_id = it->operations[other_op_id].seg_id;
+
+ const bool first_in_range = m_seg_watcher.update(seg_id);
+
+ if ( m_previous_turn_ptr )
+ {
+ if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
+ {
+ // real exit point - may be multiple
+ if ( first_in_range
+ || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) )
+ {
+ update_exit(result);
+ m_exit_detected = false;
+ }
+ // fake exit point, reset state
+ else if ( op != overlay::operation_union )
+ {
+ m_exit_detected = false;
+ }
+ }
+ /*else*/
+ if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
+ {
+ // real entry point
+ if ( first_in_range
+ || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) )
+ {
+ update_enter(result);
+ m_enter_detected = false;
+ }
+ // fake entry point, reset state
+ else if ( op != overlay::operation_intersection )
+ {
+ m_enter_detected = false;
+ }
+ }
+ }
+
+ if ( op == overlay::operation_union )
+ {
+ // already set in interrupt policy
+ //update<boundary, boundary, '0', transpose_result>(m_result);
+
+ // ignore u/u
+ //if ( it->operations[other_op_id].operation != overlay::operation_union )
+ {
+ m_exit_detected = true;
+ }
+ }
+ else if ( op == overlay::operation_intersection )
+ {
+ // ignore i/i
+ if ( it->operations[other_op_id].operation != overlay::operation_intersection )
+ {
+ // already set in interrupt policy
+ //update<interior, interior, '2', transpose_result>(result);
+ //update<boundary, boundary, '0', transpose_result>(result);
+ m_enter_detected = true;
+ }
+ }
+ else if ( op == overlay::operation_blocked )
+ {
+ // already set in interrupt policy
+ }
+ else // if ( op == overlay::operation_continue )
+ {
+ // already set in interrupt policy
+ }
+
+ // store ref to previously analysed (valid) turn
+ m_previous_turn_ptr = boost::addressof(*it);
+ // and previously analysed (valid) operation
+ m_previous_operation = op;
+ }
+
+ // it == last
+ template <typename Result>
+ void apply(Result & result)
+ {
+ //BOOST_ASSERT( first != last );
+
+ if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
+ {
+ update_exit(result);
+ m_exit_detected = false;
+ }
+
+ if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
+ {
+ update_enter(result);
+ m_enter_detected = false;
+ }
+ }
+
+ template <typename Result>
+ static inline void update_exit(Result & result)
+ {
+ update<interior, exterior, '2', transpose_result>(result);
+ update<boundary, exterior, '1', transpose_result>(result);
+ }
+
+ template <typename Result>
+ static inline void update_enter(Result & result)
+ {
+ update<boundary, interior, '1', transpose_result>(result);
+ update<exterior, interior, '2', transpose_result>(result);
+ }
+
+ private:
+ segment_watcher<same_ring> m_seg_watcher;
+ TurnInfo * m_previous_turn_ptr;
+ overlay::operation_type m_previous_operation;
+ bool m_enter_detected;
+ bool m_exit_detected;
+ };
+
+ // call analyser.apply() for each turn in range
+ // IMPORTANT! The analyser is also called for the end iterator - last
+ template <typename Result,
+ typename Analyser,
+ typename TurnIt>
+ static inline void analyse_each_turn(Result & res,
+ Analyser & analyser,
+ TurnIt first, TurnIt last)
+ {
+ if ( first == last )
+ return;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ analyser.apply(res, it);
+
+ if ( res.interrupt )
+ return;
+ }
+
+ analyser.apply(res);
+ }
+
+ template <std::size_t OpId, typename Result, typename Geometry, typename OtherGeometry>
+ class uncertain_rings_analyser
+ {
+ static const bool transpose_result = OpId != 0;
+ static const int other_id = (OpId + 1) % 2;
+
+ public:
+ inline uncertain_rings_analyser(Result & result,
+ Geometry const& geom,
+ OtherGeometry const& other_geom)
+ : geometry(geom), other_geometry(other_geom)
+ , interrupt(result.interrupt) // just in case, could be false as well
+ , m_result(result)
+ , m_flags(0)
+ {
+ // check which relations must be analysed
+
+ if ( ! may_update<interior, interior, '2', transpose_result>(m_result)
+ && ! may_update<boundary, interior, '1', transpose_result>(m_result) )
+ {
+ m_flags |= 1;
+ }
+
+ if ( ! may_update<interior, exterior, '2', transpose_result>(m_result)
+ && ! may_update<boundary, exterior, '1', transpose_result>(m_result) )
+ {
+ m_flags |= 2;
+ }
+
+ if ( ! may_update<boundary, interior, '1', transpose_result>(m_result)
+ && ! may_update<exterior, interior, '2', transpose_result>(m_result) )
+ {
+ m_flags |= 4;
+ }
+ }
+
+ inline void no_turns(segment_identifier const& seg_id)
+ {
+ // if those flags are set nothing will change
+ if ( (m_flags & 3) == 3 )
+ {
+ return;
+ }
+
+ typename detail::sub_range_return_type<Geometry const>::type
+ range_ref = detail::sub_range(geometry, seg_id);
+
+ if ( boost::empty(range_ref) )
+ {
+ // TODO: throw an exception?
+ return; // ignore
+ }
+
+ // TODO: possible optimization
+ // if the range is an interior ring we may use other IPs generated for this single geometry
+ // to know which other single geometries should be checked
+
+ // TODO: optimize! e.g. use spatial index
+ // O(N) - running it in a loop would gives O(NM)
+ int const pig = detail::within::point_in_geometry(range::front(range_ref), other_geometry);
+
+ //BOOST_ASSERT(pig != 0);
+ if ( pig > 0 )
+ {
+ update<boundary, interior, '1', transpose_result>(m_result);
+ update<interior, interior, '2', transpose_result>(m_result);
+ m_flags |= 1;
+ }
+ else
+ {
+ update<boundary, exterior, '1', transpose_result>(m_result);
+ update<interior, exterior, '2', transpose_result>(m_result);
+ m_flags |= 2;
+ }
+
+// TODO: break if all things are set
+// also some of them could be checked outside, before the analysis
+// In this case we shouldn't relay just on dummy flags
+// Flags should be initialized with proper values
+// or the result should be checked directly
+// THIS IS ALSO TRUE FOR OTHER ANALYSERS! in L/L and L/A
+
+ interrupt = m_flags == 7 || m_result.interrupt;
+ }
+
+ template <typename TurnIt>
+ inline void turns(TurnIt first, TurnIt last)
+ {
+ // if those flags are set nothing will change
+ if ( (m_flags & 6) == 6 )
+ {
+ return;
+ }
+
+ bool found_ii = false;
+ bool found_uu = false;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ if ( it->operations[0].operation == overlay::operation_intersection
+ && it->operations[1].operation == overlay::operation_intersection )
+ {
+ // ignore exterior ring
+ if ( it->operations[OpId].seg_id.ring_index >= 0 )
+ {
+ found_ii = true;
+ }
+ }
+ else if ( it->operations[0].operation == overlay::operation_union
+ && it->operations[1].operation == overlay::operation_union )
+ {
+ // ignore if u/u is for holes
+ //if ( it->operations[OpId].seg_id.ring_index >= 0
+ // && it->operations[other_id].seg_id.ring_index >= 0 )
+ {
+ found_uu = true;
+ }
+ }
+ else // ignore
+ {
+ return; // don't interrupt
+ }
+ }
+
+ // only i/i was generated for this ring
+ if ( found_ii )
+ {
+ //update<interior, interior, '0', transpose_result>(m_result);
+ //update<boundary, boundary, '0', transpose_result>(m_result);
+ update<boundary, interior, '1', transpose_result>(m_result);
+ update<exterior, interior, '2', transpose_result>(m_result);
+ m_flags |= 4;
+ }
+
+ // only u/u was generated for this ring
+ if ( found_uu )
+ {
+ update<boundary, exterior, '1', transpose_result>(m_result);
+ update<interior, exterior, '2', transpose_result>(m_result);
+ m_flags |= 2;
+
+ // not necessary since this will be checked in the next iteration
+ // but increases the pruning strength
+ // WARNING: this is not reflected in flags
+ update<exterior, boundary, '1', transpose_result>(m_result);
+ update<exterior, interior, '2', transpose_result>(m_result);
+ }
+
+ interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future
+ }
+
+ Geometry const& geometry;
+ OtherGeometry const& other_geometry;
+ bool interrupt;
+
+ private:
+ Result & m_result;
+ int m_flags;
+ };
+
+ template <std::size_t OpId>
+ class analyse_uncertain_rings
+ {
+ public:
+ template <typename Analyser, typename TurnIt>
+ static inline void apply(Analyser & analyser, TurnIt first, TurnIt last)
+ {
+ if ( first == last )
+ return;
+
+ for_preceding_rings(analyser, *first);
+ //analyser.per_turn(*first);
+
+ TurnIt prev = first;
+ for ( ++first ; first != last ; ++first, ++prev )
+ {
+ // same multi
+ if ( prev->operations[OpId].seg_id.multi_index
+ == first->operations[OpId].seg_id.multi_index )
+ {
+ // same ring
+ if ( prev->operations[OpId].seg_id.ring_index
+ == first->operations[OpId].seg_id.ring_index )
+ {
+ //analyser.per_turn(*first);
+ }
+ // same multi, next ring
+ else
+ {
+ //analyser.end_ring(*prev);
+ analyser.turns(prev, first);
+
+ //if ( prev->operations[OpId].seg_id.ring_index + 1
+ // < first->operations[OpId].seg_id.ring_index)
+ {
+ for_no_turns_rings(analyser,
+ *first,
+ prev->operations[OpId].seg_id.ring_index + 1,
+ first->operations[OpId].seg_id.ring_index);
+ }
+
+ //analyser.per_turn(*first);
+ }
+ }
+ // next multi
+ else
+ {
+ //analyser.end_ring(*prev);
+ analyser.turns(prev, first);
+ for_following_rings(analyser, *prev);
+ for_preceding_rings(analyser, *first);
+ //analyser.per_turn(*first);
+ }
+
+ if ( analyser.interrupt )
+ {
+ return;
+ }
+ }
+
+ //analyser.end_ring(*prev);
+ analyser.turns(prev, first); // first == last
+ for_following_rings(analyser, *prev);
+ }
+
+ private:
+ template <typename Analyser, typename Turn>
+ static inline void for_preceding_rings(Analyser & analyser, Turn const& turn)
+ {
+ segment_identifier const& seg_id = turn.operations[OpId].seg_id;
+
+ for_no_turns_rings(analyser, turn, -1, seg_id.ring_index);
+ }
+
+ template <typename Analyser, typename Turn>
+ static inline void for_following_rings(Analyser & analyser, Turn const& turn)
+ {
+ segment_identifier const& seg_id = turn.operations[OpId].seg_id;
+
+ int count = boost::numeric_cast<int>(
+ geometry::num_interior_rings(
+ detail::single_geometry(analyser.geometry, seg_id)));
+
+ for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count);
+ }
+
+ template <typename Analyser, typename Turn>
+ static inline void for_no_turns_rings(Analyser & analyser, Turn const& turn, int first, int last)
+ {
+ segment_identifier seg_id = turn.operations[OpId].seg_id;
+
+ for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index )
+ {
+ analyser.no_turns(seg_id);
+ }
+ }
+ };
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/relate/boundary_checker.hpp b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp
new file mode 100644
index 0000000000..f98c3e9b82
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp
@@ -0,0 +1,134 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
+
+#include <boost/geometry/util/range.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+enum boundary_query { boundary_front, boundary_back, boundary_any };
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+class boundary_checker {};
+
+template <typename Geometry>
+class boundary_checker<Geometry, linestring_tag>
+{
+ typedef typename point_type<Geometry>::type point_type;
+
+public:
+ boundary_checker(Geometry const& g)
+ : has_boundary( boost::size(g) >= 2
+ && !detail::equals::equals_point_point(range::front(g), range::back(g)) )
+ , geometry(g)
+ {}
+
+ template <boundary_query BoundaryQuery>
+ bool is_endpoint_boundary(point_type const& pt) const
+ {
+ boost::ignore_unused_variable_warning(pt);
+#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
+ // may give false positives for INT
+ BOOST_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
+ && detail::equals::equals_point_point(pt, range::front(geometry))
+ || (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
+ && detail::equals::equals_point_point(pt, range::back(geometry)) );
+#endif
+ return has_boundary;
+ }
+
+private:
+ bool has_boundary;
+ Geometry const& geometry;
+};
+
+template <typename Geometry>
+class boundary_checker<Geometry, multi_linestring_tag>
+{
+ typedef typename point_type<Geometry>::type point_type;
+
+public:
+ boundary_checker(Geometry const& g)
+ : is_filled(false), geometry(g)
+ {}
+
+ // First call O(NlogN)
+ // Each next call O(logN)
+ template <boundary_query BoundaryQuery>
+ bool is_endpoint_boundary(point_type const& pt) const
+ {
+ typedef typename boost::range_size<Geometry>::type size_type;
+ size_type multi_count = boost::size(geometry);
+
+ if ( multi_count < 1 )
+ return false;
+
+ if ( ! is_filled )
+ {
+ //boundary_points.clear();
+ boundary_points.reserve(multi_count * 2);
+
+ typedef typename boost::range_iterator<Geometry const>::type multi_iterator;
+ for ( multi_iterator it = boost::begin(geometry) ;
+ it != boost::end(geometry) ; ++ it )
+ {
+ // empty or point - no boundary
+ if ( boost::size(*it) < 2 )
+ continue;
+
+ // linear ring or point - no boundary
+ if ( equals::equals_point_point(range::front(*it), range::back(*it)) )
+ continue;
+
+ boundary_points.push_back(range::front(*it));
+ boundary_points.push_back(range::back(*it));
+ }
+
+ std::sort(boundary_points.begin(), boundary_points.end(), geometry::less<point_type>());
+
+ is_filled = true;
+ }
+
+ std::size_t equal_points_count
+ = boost::size(
+ std::equal_range(boundary_points.begin(),
+ boundary_points.end(),
+ pt,
+ geometry::less<point_type>())
+ );
+
+ return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
+ }
+
+private:
+ mutable bool is_filled;
+ // TODO: store references/pointers instead of points?
+ mutable std::vector<point_type> boundary_points;
+
+ Geometry const& geometry;
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
diff --git a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp
new file mode 100644
index 0000000000..78fa03798d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp
@@ -0,0 +1,401 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
+
+#include <boost/geometry/util/range.hpp>
+//#include <boost/geometry/algorithms/detail/sub_range.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// NOTE: This iterates through single geometries for which turns were not generated.
+// It doesn't mean that the geometry is disjoint, only that no turns were detected.
+
+template <std::size_t OpId,
+ typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type,
+ bool IsMulti = boost::is_base_of<multi_tag, Tag>::value
+>
+struct for_each_disjoint_geometry_if
+ : public not_implemented<Tag>
+{};
+
+template <std::size_t OpId, typename Geometry, typename Tag>
+struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, false>
+{
+ template <typename TurnIt, typename Pred>
+ static inline bool apply(TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ Pred & pred)
+ {
+ if ( first != last )
+ return false;
+ pred(geometry);
+ return true;
+ }
+};
+
+template <std::size_t OpId, typename Geometry, typename Tag>
+struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
+{
+ template <typename TurnIt, typename Pred>
+ static inline bool apply(TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ Pred & pred)
+ {
+ if ( first != last )
+ return for_turns(first, last, geometry, pred);
+ else
+ return for_empty(geometry, pred);
+ }
+
+ template <typename Pred>
+ static inline bool for_empty(Geometry const& geometry,
+ Pred & pred)
+ {
+ typedef typename boost::range_iterator<Geometry const>::type iterator;
+
+ // O(N)
+ // check predicate for each contained geometry without generated turn
+ for ( iterator it = boost::begin(geometry) ;
+ it != boost::end(geometry) ; ++it )
+ {
+ bool cont = pred(*it);
+ if ( !cont )
+ break;
+ }
+
+ return !boost::empty(geometry);
+ }
+
+ template <typename TurnIt, typename Pred>
+ static inline bool for_turns(TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ Pred & pred)
+ {
+ BOOST_ASSERT(first != last);
+
+ const std::size_t count = boost::size(geometry);
+ boost::ignore_unused_variable_warning(count);
+
+ // O(I)
+ // gather info about turns generated for contained geometries
+ std::vector<bool> detected_intersections(count, false);
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ int multi_index = it->operations[OpId].seg_id.multi_index;
+ BOOST_ASSERT(multi_index >= 0);
+ std::size_t index = static_cast<std::size_t>(multi_index);
+ BOOST_ASSERT(index < count);
+ detected_intersections[index] = true;
+ }
+
+ bool found = false;
+
+ // O(N)
+ // check predicate for each contained geometry without generated turn
+ for ( std::vector<bool>::iterator it = detected_intersections.begin() ;
+ it != detected_intersections.end() ; ++it )
+ {
+ // if there were no intersections for this multi_index
+ if ( *it == false )
+ {
+ found = true;
+ bool cont = pred(range::at(geometry,
+ std::distance(detected_intersections.begin(), it)));
+ if ( !cont )
+ break;
+ }
+ }
+
+ return found;
+ }
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+template <typename Point>
+class point_info
+{
+public:
+ point_info() : sid_ptr(NULL), pt_ptr(NULL) {}
+ point_info(Point const& pt, segment_identifier const& sid)
+ : sid_ptr(boost::addressof(sid))
+ , pt_ptr(boost::addressof(pt))
+ {}
+ segment_identifier const& seg_id() const
+ {
+ BOOST_ASSERT(sid_ptr);
+ return *sid_ptr;
+ }
+ Point const& point() const
+ {
+ BOOST_ASSERT(pt_ptr);
+ return *pt_ptr;
+ }
+
+ //friend bool operator==(point_identifier const& l, point_identifier const& r)
+ //{
+ // return l.seg_id() == r.seg_id()
+ // && detail::equals::equals_point_point(l.point(), r.point());
+ //}
+
+private:
+ const segment_identifier * sid_ptr;
+ const Point * pt_ptr;
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+class same_single
+{
+public:
+ same_single(segment_identifier const& sid)
+ : sid_ptr(boost::addressof(sid))
+ {}
+
+ bool operator()(segment_identifier const& sid) const
+ {
+ return sid.multi_index == sid_ptr->multi_index;
+ }
+
+ template <typename Point>
+ bool operator()(point_info<Point> const& pid) const
+ {
+ return operator()(pid.seg_id());
+ }
+
+private:
+ const segment_identifier * sid_ptr;
+};
+
+class same_ring
+{
+public:
+ same_ring(segment_identifier const& sid)
+ : sid_ptr(boost::addressof(sid))
+ {}
+
+ bool operator()(segment_identifier const& sid) const
+ {
+ return sid.multi_index == sid_ptr->multi_index
+ && sid.ring_index == sid_ptr->ring_index;
+ }
+
+private:
+ const segment_identifier * sid_ptr;
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+template <typename SameRange = same_single>
+class segment_watcher
+{
+public:
+ segment_watcher()
+ : m_seg_id_ptr(NULL)
+ {}
+
+ bool update(segment_identifier const& seg_id)
+ {
+ bool result = m_seg_id_ptr == 0 || !SameRange(*m_seg_id_ptr)(seg_id);
+ m_seg_id_ptr = boost::addressof(seg_id);
+ return result;
+ }
+
+private:
+ const segment_identifier * m_seg_id_ptr;
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+template <typename TurnInfo, std::size_t OpId>
+class exit_watcher
+{
+ static const std::size_t op_id = OpId;
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+
+ typedef typename TurnInfo::point_type point_type;
+ typedef detail::relate::point_info<point_type> point_info;
+
+public:
+ exit_watcher()
+ : m_exit_operation(overlay::operation_none)
+ , m_exit_turn_ptr(NULL)
+ {}
+
+ void enter(TurnInfo const& turn)
+ {
+ m_other_entry_points.push_back(
+ point_info(turn.point, turn.operations[other_op_id].seg_id) );
+ }
+
+ // TODO: exit_per_geometry parameter looks not very safe
+ // wrong value may be easily passed
+
+ void exit(TurnInfo const& turn, bool exit_per_geometry = true)
+ {
+ //segment_identifier const& seg_id = turn.operations[op_id].seg_id;
+ segment_identifier const& other_id = turn.operations[other_op_id].seg_id;
+ overlay::operation_type exit_op = turn.operations[op_id].operation;
+
+ typedef typename std::vector<point_info>::iterator point_iterator;
+ // search for the entry point in the same range of other geometry
+ point_iterator entry_it = std::find_if(m_other_entry_points.begin(),
+ m_other_entry_points.end(),
+ same_single(other_id));
+
+ // this end point has corresponding entry point
+ if ( entry_it != m_other_entry_points.end() )
+ {
+ // erase the corresponding entry point
+ m_other_entry_points.erase(entry_it);
+
+ if ( exit_per_geometry || m_other_entry_points.empty() )
+ {
+ // here we know that we possibly left LS
+ // we must still check if we didn't get back on the same point
+ m_exit_operation = exit_op;
+ m_exit_turn_ptr = boost::addressof(turn);
+ }
+ }
+ }
+
+ bool is_outside() const
+ {
+ // if we didn't entered anything in the past, we're outside
+ return m_other_entry_points.empty();
+ }
+
+ bool is_outside(TurnInfo const& turn) const
+ {
+ return m_other_entry_points.empty()
+ || std::find_if(m_other_entry_points.begin(),
+ m_other_entry_points.end(),
+ same_single(
+ turn.operations[other_op_id].seg_id))
+ == m_other_entry_points.end();
+ }
+
+ overlay::operation_type get_exit_operation() const
+ {
+ return m_exit_operation;
+ }
+
+ point_type const& get_exit_point() const
+ {
+ BOOST_ASSERT(m_exit_operation != overlay::operation_none);
+ BOOST_ASSERT(m_exit_turn_ptr);
+ return m_exit_turn_ptr->point;
+ }
+
+ TurnInfo const& get_exit_turn() const
+ {
+ BOOST_ASSERT(m_exit_operation != overlay::operation_none);
+ BOOST_ASSERT(m_exit_turn_ptr);
+ return *m_exit_turn_ptr;
+ }
+
+ void reset_detected_exit()
+ {
+ m_exit_operation = overlay::operation_none;
+ }
+
+ void reset()
+ {
+ m_exit_operation = overlay::operation_none;
+ m_other_entry_points.clear();
+ }
+
+private:
+ overlay::operation_type m_exit_operation;
+ const TurnInfo * m_exit_turn_ptr;
+ std::vector<point_info> m_other_entry_points; // TODO: use map here or sorted vector?
+};
+
+template <std::size_t OpId, typename Turn>
+inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn)
+{
+ segment_identifier const& prev_seg_id = prev_turn.operations[OpId].seg_id;
+ segment_identifier const& curr_seg_id = curr_turn.operations[OpId].seg_id;
+
+ if ( prev_seg_id.multi_index != curr_seg_id.multi_index
+ || prev_seg_id.ring_index != curr_seg_id.ring_index )
+ {
+ return false;
+ }
+
+ // TODO: will this work if between segments there will be some number of degenerated ones?
+
+ if ( prev_seg_id.segment_index != curr_seg_id.segment_index
+ && ( ! curr_turn.operations[OpId].fraction.is_zero()
+ || prev_seg_id.segment_index + 1 != curr_seg_id.segment_index ) )
+ {
+ return false;
+ }
+
+ return detail::equals::equals_point_point(prev_turn.point, curr_turn.point);
+}
+
+template <boundary_query BoundaryQuery,
+ typename Point,
+ typename BoundaryChecker>
+static inline bool is_endpoint_on_boundary(Point const& pt,
+ BoundaryChecker & boundary_checker)
+{
+ return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt);
+}
+
+template <boundary_query BoundaryQuery,
+ typename IntersectionPoint,
+ typename OperationInfo,
+ typename BoundaryChecker>
+static inline bool is_ip_on_boundary(IntersectionPoint const& ip,
+ OperationInfo const& operation_info,
+ BoundaryChecker & boundary_checker,
+ segment_identifier const& seg_id)
+{
+ boost::ignore_unused_variable_warning(seg_id);
+
+ bool res = false;
+
+ // IP on the last point of the linestring
+ if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
+ && operation_info.position == overlay::position_back )
+ {
+ // check if this point is a boundary
+ res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
+ }
+ // IP on the last point of the linestring
+ else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
+ && operation_info.position == overlay::position_front )
+ {
+ // check if this point is a boundary
+ res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip);
+ }
+
+ return res;
+}
+
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
diff --git a/boost/geometry/algorithms/detail/relate/less.hpp b/boost/geometry/algorithms/detail/relate/less.hpp
new file mode 100644
index 0000000000..3f11d4e87d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/less.hpp
@@ -0,0 +1,79 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch { namespace relate {
+
+// TODO: Integrate it with geometry::less?
+
+template <typename Point1,
+ typename Point2,
+ std::size_t I = 0,
+ std::size_t D = geometry::dimension<Point1>::value>
+struct less
+{
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ typename geometry::coordinate_type<Point1>::type
+ cleft = geometry::get<I>(left);
+ typename geometry::coordinate_type<Point2>::type
+ cright = geometry::get<I>(right);
+
+ if ( geometry::math::equals(cleft, cright) )
+ {
+ return less<Point1, Point2, I + 1, D>::apply(left, right);
+ }
+ else
+ {
+ return cleft < cright;
+ }
+ }
+};
+
+template <typename Point1, typename Point2, std::size_t D>
+struct less<Point1, Point2, D, D>
+{
+ static inline bool apply(Point1 const&, Point2 const&)
+ {
+ return false;
+ }
+};
+
+}} // namespace detail_dispatch::relate
+
+#endif
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+struct less
+{
+ template <typename Point1, typename Point2>
+ inline bool operator()(Point1 const& point1, Point2 const& point2) const
+ {
+ return detail_dispatch::relate::less<Point1, Point2>::apply(point1, point2);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
new file mode 100644
index 0000000000..3159ab329d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
@@ -0,0 +1,1115 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+#include <boost/geometry/core/topological_dimension.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/single_geometry.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
+#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
+
+#include <boost/geometry/views/detail/normalized_view.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// WARNING!
+// TODO: In the worst case calling this Pred in a loop for MultiLinestring/MultiPolygon may take O(NM)
+// Use the rtree in this case!
+
+// may be used to set IE and BE for a Linear geometry for which no turns were generated
+template <typename Geometry2, typename Result, typename BoundaryChecker, bool TransposeResult>
+class no_turns_la_linestring_pred
+{
+public:
+ no_turns_la_linestring_pred(Geometry2 const& geometry2,
+ Result & res,
+ BoundaryChecker const& boundary_checker)
+ : m_geometry2(geometry2)
+ , m_result(res)
+ , m_boundary_checker(boundary_checker)
+ , m_interrupt_flags(0)
+ {
+ if ( ! may_update<interior, interior, '1', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 1;
+ }
+
+ if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 2;
+ }
+
+ if ( ! may_update<boundary, interior, '0', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 4;
+ }
+
+ if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 8;
+ }
+ }
+
+ template <typename Linestring>
+ bool operator()(Linestring const& linestring)
+ {
+ std::size_t const count = boost::size(linestring);
+
+ // invalid input
+ if ( count < 2 )
+ {
+ // ignore
+ // TODO: throw an exception?
+ return true;
+ }
+
+ // if those flags are set nothing will change
+ if ( m_interrupt_flags == 0xF )
+ {
+ return false;
+ }
+
+ int const pig = detail::within::point_in_geometry(range::front(linestring), m_geometry2);
+ //BOOST_ASSERT_MSG(pig != 0, "There should be no IPs");
+
+ if ( pig > 0 )
+ {
+ update<interior, interior, '1', TransposeResult>(m_result);
+ m_interrupt_flags |= 1;
+ }
+ else
+ {
+ update<interior, exterior, '1', TransposeResult>(m_result);
+ m_interrupt_flags |= 2;
+ }
+
+ // check if there is a boundary
+ if ( ( m_interrupt_flags & 0xC ) != 0xC // if wasn't already set
+ && ( m_boundary_checker.template
+ is_endpoint_boundary<boundary_front>(range::front(linestring))
+ || m_boundary_checker.template
+ is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
+ {
+ if ( pig > 0 )
+ {
+ update<boundary, interior, '0', TransposeResult>(m_result);
+ m_interrupt_flags |= 4;
+ }
+ else
+ {
+ update<boundary, exterior, '0', TransposeResult>(m_result);
+ m_interrupt_flags |= 8;
+ }
+ }
+
+ return m_interrupt_flags != 0xF
+ && ! m_result.interrupt;
+ }
+
+private:
+ Geometry2 const& m_geometry2;
+ Result & m_result;
+ BoundaryChecker const& m_boundary_checker;
+ unsigned m_interrupt_flags;
+};
+
+// may be used to set EI and EB for an Areal geometry for which no turns were generated
+template <typename Result, bool TransposeResult>
+class no_turns_la_areal_pred
+{
+public:
+ no_turns_la_areal_pred(Result & res)
+ : m_result(res)
+ , interrupt(! may_update<interior, exterior, '2', TransposeResult>(m_result)
+ && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
+ {}
+
+ template <typename Areal>
+ bool operator()(Areal const& areal)
+ {
+ if ( interrupt )
+ {
+ return false;
+ }
+
+ // TODO:
+ // handle empty/invalid geometries in a different way than below?
+
+ typedef typename geometry::point_type<Areal>::type point_type;
+ point_type dummy;
+ bool const ok = boost::geometry::point_on_border(dummy, areal);
+
+ // TODO: for now ignore, later throw an exception?
+ if ( !ok )
+ {
+ return true;
+ }
+
+ update<interior, exterior, '2', TransposeResult>(m_result);
+ update<boundary, exterior, '1', TransposeResult>(m_result);
+
+ return false;
+ }
+
+private:
+ Result & m_result;
+ bool const interrupt;
+};
+
+// The implementation of an algorithm calculating relate() for L/A
+template <typename Geometry1, typename Geometry2, bool TransposeResult = false>
+struct linear_areal
+{
+ // check Linear / Areal
+ BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 1
+ && topological_dimension<Geometry2>::value == 2);
+
+ static const bool interruption_enabled = true;
+
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+// TODO: If Areal geometry may have infinite size, change the following line:
+
+ // The result should be FFFFFFFFF
+ relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
+
+ if ( result.interrupt )
+ return;
+
+ // get and analyse turns
+ typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
+ std::vector<turn_type> turns;
+
+ interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result);
+
+ turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
+ if ( result.interrupt )
+ return;
+
+ boundary_checker<Geometry1> boundary_checker1(geometry1);
+ no_turns_la_linestring_pred
+ <
+ Geometry2,
+ Result,
+ boundary_checker<Geometry1>,
+ TransposeResult
+ > pred1(geometry2, result, boundary_checker1);
+ for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
+ if ( result.interrupt )
+ return;
+
+ no_turns_la_areal_pred<Result, !TransposeResult> pred2(result);
+ for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
+ if ( result.interrupt )
+ return;
+
+ if ( turns.empty() )
+ return;
+
+ // This is set here because in the case if empty Areal geometry were passed
+ // those shouldn't be set
+ relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
+ if ( result.interrupt )
+ return;
+
+ {
+ // for different multi or same ring id: x, u, i, c
+ // for same multi and different ring id: c, i, u, x
+ typedef turns::less<0, turns::less_op_linear_areal<0> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ turns_analyser<turn_type> analyser;
+ analyse_each_turn(result, analyser,
+ turns.begin(), turns.end(),
+ geometry1, geometry2,
+ boundary_checker1);
+
+ if ( result.interrupt )
+ return;
+ }
+
+ // If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings
+ if ( !interrupt_policy.is_boundary_found )
+ {
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ }
+ // Don't calculate it if it's required
+ else if ( may_update<exterior, boundary, '1', TransposeResult>(result) )
+ {
+// TODO: REVISE THIS CODE AND PROBABLY REWRITE SOME PARTS TO BE MORE HUMAN-READABLE
+// IN GENERAL IT ANALYSES THE RINGS OF AREAL GEOMETRY AND DETECTS THE ONES THAT
+// MAY OVERLAP THE INTERIOR OF LINEAR GEOMETRY (NO IPs OR NON-FAKE 'u' OPERATION)
+// NOTE: For one case std::sort may be called again to sort data by operations for data already sorted by ring index
+// In the worst case scenario the complexity will be O( NlogN + R*(N/R)log(N/R) )
+// So always should remain O(NlogN) -> for R==1 <-> 1(N/1)log(N/1), for R==N <-> N(N/N)log(N/N)
+// Some benchmarking should probably be done to check if only one std::sort should be used
+
+ // sort by multi_index and rind_index
+ std::sort(turns.begin(), turns.end(), less_ring());
+
+ typedef typename std::vector<turn_type>::iterator turn_iterator;
+
+ turn_iterator it = turns.begin();
+ segment_identifier * prev_seg_id_ptr = NULL;
+ // for each ring
+ for ( ; it != turns.end() ; )
+ {
+ // it's the next single geometry
+ if ( prev_seg_id_ptr == NULL
+ || prev_seg_id_ptr->multi_index != it->operations[1].seg_id.multi_index )
+ {
+ // if the first ring has no IPs
+ if ( it->operations[1].seg_id.ring_index > -1 )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ // if there was some previous ring
+ if ( prev_seg_id_ptr != NULL )
+ {
+ int const next_ring_index = prev_seg_id_ptr->ring_index + 1;
+ BOOST_ASSERT(next_ring_index >= 0);
+
+ // if one of the last rings of previous single geometry was ommited
+ if ( static_cast<std::size_t>(next_ring_index)
+ < geometry::num_interior_rings(
+ single_geometry(geometry2, *prev_seg_id_ptr)) )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ }
+ }
+ // if it's the same single geometry
+ else /*if ( previous_multi_index == it->operations[1].seg_id.multi_index )*/
+ {
+ // and we jumped over one of the rings
+ if ( prev_seg_id_ptr != NULL // just in case
+ && prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ }
+
+ prev_seg_id_ptr = boost::addressof(it->operations[1].seg_id);
+
+ // find the next ring first iterator and check if the analysis should be performed
+ has_boundary_intersection has_boundary_inters;
+ turn_iterator next = find_next_ring(it, turns.end(), has_boundary_inters);
+
+ // if there is no 1d overlap with the boundary
+ if ( !has_boundary_inters.result )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ // else there is 1d overlap with the boundary so we must analyse the boundary
+ else
+ {
+ // u, c
+ typedef turns::less<1, turns::less_op_areal_linear<1> > less;
+ std::sort(it, next, less());
+
+ // analyse
+ areal_boundary_analyser<turn_type> analyser;
+ for ( turn_iterator rit = it ; rit != next ; ++rit )
+ {
+ // if the analyser requests, break the search
+ if ( !analyser.apply(it, rit, next) )
+ break;
+ }
+
+ // if the boundary of Areal goes out of the Linear
+ if ( analyser.is_union_detected )
+ {
+ // we can be sure that the boundary of Areal overlaps the exterior of Linear
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ }
+
+ it = next;
+ }
+
+ // if there was some previous ring
+ if ( prev_seg_id_ptr != NULL )
+ {
+ int const next_ring_index = prev_seg_id_ptr->ring_index + 1;
+ BOOST_ASSERT(next_ring_index >= 0);
+
+ // if one of the last rings of previous single geometry was ommited
+ if ( static_cast<std::size_t>(next_ring_index)
+ < geometry::num_interior_rings(
+ single_geometry(geometry2, *prev_seg_id_ptr)) )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ }
+ }
+ }
+ }
+
+ // interrupt policy which may be passed to get_turns to interrupt the analysis
+ // based on the info in the passed result/mask
+ template <typename Areal, typename Result>
+ class interrupt_policy_linear_areal
+ {
+ public:
+ static bool const enabled = true;
+
+ interrupt_policy_linear_areal(Areal const& areal, Result & result)
+ : m_result(result), m_areal(areal)
+ , is_boundary_found(false)
+ {}
+
+// TODO: since we update result for some operations here, we may not do it in the analyser!
+
+ template <typename Range>
+ inline bool apply(Range const& turns)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
+ {
+ if ( it->operations[0].operation == overlay::operation_intersection )
+ {
+ bool const no_interior_rings
+ = geometry::num_interior_rings(
+ single_geometry(m_areal, it->operations[1].seg_id)) == 0;
+
+ // WARNING! THIS IS TRUE ONLY IF THE POLYGON IS SIMPLE!
+ // OR WITHOUT INTERIOR RINGS (AND OF COURSE VALID)
+ if ( no_interior_rings )
+ update<interior, interior, '1', TransposeResult>(m_result);
+ }
+ else if ( it->operations[0].operation == overlay::operation_continue )
+ {
+ update<interior, boundary, '1', TransposeResult>(m_result);
+ is_boundary_found = true;
+ }
+ else if ( ( it->operations[0].operation == overlay::operation_union
+ || it->operations[0].operation == overlay::operation_blocked )
+ && it->operations[0].position == overlay::position_middle )
+ {
+// TODO: here we could also check the boundaries and set BB at this point
+ update<interior, boundary, '0', TransposeResult>(m_result);
+ }
+ }
+
+ return m_result.interrupt;
+ }
+
+ private:
+ Result & m_result;
+ Areal const& m_areal;
+
+ public:
+ bool is_boundary_found;
+ };
+
+ // This analyser should be used like Input or SinglePass Iterator
+ // IMPORTANT! It should be called also for the end iterator - last
+ template <typename TurnInfo>
+ class turns_analyser
+ {
+ typedef typename TurnInfo::point_type turn_point_type;
+
+ static const std::size_t op_id = 0;
+ static const std::size_t other_op_id = 1;
+
+ public:
+ turns_analyser()
+ : m_previous_turn_ptr(NULL)
+ , m_previous_operation(overlay::operation_none)
+ , m_boundary_counter(0)
+ , m_interior_detected(false)
+ , m_first_interior_other_id_ptr(NULL)
+ {}
+
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker>
+ void apply(Result & res, TurnIt it,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker)
+ {
+ overlay::operation_type op = it->operations[op_id].operation;
+
+ if ( op != overlay::operation_union
+ && op != overlay::operation_intersection
+ && op != overlay::operation_blocked
+ && op != overlay::operation_continue ) // operation_boundary / operation_boundary_intersection
+ {
+ return;
+ }
+
+ segment_identifier const& seg_id = it->operations[op_id].seg_id;
+ segment_identifier const& other_id = it->operations[other_op_id].seg_id;
+
+ const bool first_in_range = m_seg_watcher.update(seg_id);
+
+ // handle possible exit
+ bool fake_enter_detected = false;
+ if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
+ {
+ // real exit point - may be multiple
+ // we know that we entered and now we exit
+ if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ m_exit_watcher.reset_detected_exit();
+
+ // not the last IP
+ update<interior, exterior, '1', TransposeResult>(res);
+ }
+ // fake exit point, reset state
+ else if ( op == overlay::operation_intersection
+ || op == overlay::operation_continue ) // operation_boundary
+ {
+ m_exit_watcher.reset_detected_exit();
+ fake_enter_detected = true;
+ }
+ }
+ else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
+ {
+ // ignore multiple BLOCKs
+ if ( op == overlay::operation_blocked )
+ return;
+
+ if ( ( op == overlay::operation_intersection
+ || op == overlay::operation_continue )
+ && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ fake_enter_detected = true;
+ }
+
+ m_exit_watcher.reset_detected_exit();
+ }
+
+// NOTE: THE WHOLE m_interior_detected HANDLING IS HERE BECAUSE WE CAN'T EFFICIENTLY SORT TURNS (CORRECTLY)
+// BECAUSE THE SAME IP MAY BE REPRESENTED BY TWO SEGMENTS WITH DIFFERENT DISTANCES
+// IT WOULD REQUIRE THE CALCULATION OF MAX DISTANCE
+// TODO: WE COULD GET RID OF THE TEST IF THE DISTANCES WERE NORMALIZED
+
+// TODO: THIS IS POTENTIALLY ERROREOUS!
+// THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS
+// IT WOULD GIVE WRONG RESULTS E.G.
+// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u'
+
+ // handle the interior overlap
+ if ( m_interior_detected )
+ {
+ // real interior overlap
+ if ( ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) )
+ {
+ update<interior, interior, '1', TransposeResult>(res);
+ m_interior_detected = false;
+ }
+ // fake interior overlap
+ else if ( op == overlay::operation_continue )
+ {
+ m_interior_detected = false;
+ }
+ else if ( op == overlay::operation_union )
+ {
+// TODO: this probably is not a good way of handling the interiors/enters
+// the solution similar to exit_watcher would be more robust
+// all enters should be kept and handled.
+// maybe integrate it with the exit_watcher -> enter_exit_watcher
+ if ( m_first_interior_other_id_ptr
+ && m_first_interior_other_id_ptr->multi_index == other_id.multi_index )
+ {
+ m_interior_detected = false;
+ }
+ }
+ }
+
+ // i/u, c/u
+ if ( op == overlay::operation_intersection
+ || op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection
+ {
+ bool no_enters_detected = m_exit_watcher.is_outside();
+ m_exit_watcher.enter(*it);
+
+ if ( op == overlay::operation_intersection )
+ {
+ if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
+ --m_boundary_counter;
+
+ if ( m_boundary_counter == 0 )
+ {
+ // interiors overlaps
+ //update<interior, interior, '1', TransposeResult>(res);
+
+// TODO: think about the implementation of the more robust version
+// this way only the first enter will be handled
+ if ( !m_interior_detected )
+ {
+ // don't update now
+ // we might enter a boundary of some other ring on the same IP
+ m_interior_detected = true;
+ m_first_interior_other_id_ptr = boost::addressof(other_id);
+ }
+ }
+ }
+ else // operation_boundary
+ {
+ // don't add to the count for all met boundaries
+ // only if this is the "new" boundary
+ if ( first_in_range || !it->operations[op_id].is_collinear )
+ ++m_boundary_counter;
+
+ update<interior, boundary, '1', TransposeResult>(res);
+ }
+
+ bool const this_b
+ = is_ip_on_boundary<boundary_front>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+ // going inside on boundary point
+ if ( this_b )
+ {
+ update<boundary, boundary, '0', TransposeResult>(res);
+ }
+ // going inside on non-boundary point
+ else
+ {
+ update<interior, boundary, '0', TransposeResult>(res);
+
+ // if we didn't enter in the past, we were outside
+ if ( no_enters_detected
+ && ! fake_enter_detected
+ && it->operations[op_id].position != overlay::position_front )
+ {
+// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
+ bool const from_inside = first_in_range
+ && calculate_from_inside(geometry,
+ other_geometry,
+ *it);
+
+ if ( from_inside )
+ update<interior, interior, '1', TransposeResult>(res);
+ else
+ update<interior, exterior, '1', TransposeResult>(res);
+
+ // if it's the first IP then the first point is outside
+ if ( first_in_range )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ if ( from_inside )
+ update<boundary, interior, '0', TransposeResult>(res);
+ else
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
+ }
+ }
+ }
+ // u/u, x/u
+ else if ( op == overlay::operation_union || op == overlay::operation_blocked )
+ {
+ bool const op_blocked = op == overlay::operation_blocked;
+ bool const no_enters_detected = m_exit_watcher.is_outside()
+// TODO: is this condition ok?
+// TODO: move it into the exit_watcher?
+ && m_exit_watcher.get_exit_operation() == overlay::operation_none;
+
+ if ( op == overlay::operation_union )
+ {
+ if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
+ --m_boundary_counter;
+ }
+ else // overlay::operation_blocked
+ {
+ m_boundary_counter = 0;
+ }
+
+ // we're inside, possibly going out right now
+ if ( ! no_enters_detected )
+ {
+ if ( op_blocked
+ && it->operations[op_id].position == overlay::position_back ) // ignore spikes!
+ {
+ // check if this is indeed the boundary point
+ // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
+ if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
+ {
+ update<boundary, boundary, '0', TransposeResult>(res);
+ }
+ }
+ // union, inside, but no exit -> collinear on self-intersection point
+ // not needed since we're already inside the boundary
+ /*else if ( !exit_detected )
+ {
+ update<interior, boundary, '0', TransposeResult>(res);
+ }*/
+ }
+ // we're outside or inside and this is the first turn
+ else
+ {
+ bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+ // if current IP is on boundary of the geometry
+ if ( this_b )
+ {
+ update<boundary, boundary, '0', TransposeResult>(res);
+ }
+ // if current IP is not on boundary of the geometry
+ else
+ {
+ update<interior, boundary, '0', TransposeResult>(res);
+ }
+
+ // TODO: very similar code is used in the handling of intersection
+ if ( it->operations[op_id].position != overlay::position_front )
+ {
+// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
+ bool const first_from_inside = first_in_range
+ && calculate_from_inside(geometry,
+ other_geometry,
+ *it);
+ if ( first_from_inside )
+ {
+ update<interior, interior, '1', TransposeResult>(res);
+
+ // notify the exit_watcher that we started inside
+ m_exit_watcher.enter(*it);
+ }
+ else
+ {
+ update<interior, exterior, '1', TransposeResult>(res);
+ }
+
+ // first IP on the last segment point - this means that the first point is outside or inside
+ if ( first_in_range && ( !this_b || op_blocked ) )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ if ( first_from_inside )
+ update<boundary, interior, '0', TransposeResult>(res);
+ else
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
+ }
+ }
+
+ // if we're going along a boundary, we exit only if the linestring was collinear
+ if ( m_boundary_counter == 0
+ || it->operations[op_id].is_collinear )
+ {
+ // notify the exit watcher about the possible exit
+ m_exit_watcher.exit(*it);
+ }
+ }
+
+ // store ref to previously analysed (valid) turn
+ m_previous_turn_ptr = boost::addressof(*it);
+ // and previously analysed (valid) operation
+ m_previous_operation = op;
+ }
+
+ // it == last
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker>
+ void apply(Result & res,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& /*other_geometry*/,
+ BoundaryChecker const& boundary_checker)
+ {
+ boost::ignore_unused(first, last);
+ //BOOST_ASSERT( first != last );
+
+ // here, the possible exit is the real one
+ // we know that we entered and now we exit
+ if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
+ ||*/ m_previous_operation == overlay::operation_union
+ && !m_interior_detected )
+ {
+ // for sure
+ update<interior, exterior, '1', TransposeResult>(res);
+
+ BOOST_ASSERT(first != last);
+ BOOST_ASSERT(m_previous_turn_ptr);
+
+ segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
+
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
+ // we might enter some Areal and didn't go out,
+ else if ( m_previous_operation == overlay::operation_intersection
+ || m_interior_detected )
+ {
+ // just in case
+ update<interior, interior, '1', TransposeResult>(res);
+ m_interior_detected = false;
+
+ BOOST_ASSERT(first != last);
+ BOOST_ASSERT(m_previous_turn_ptr);
+
+ segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
+
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, interior, '0', TransposeResult>(res);
+ }
+ }
+
+ BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue,
+ "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)");
+
+ // Reset exit watcher before the analysis of the next Linestring
+ m_exit_watcher.reset();
+ m_boundary_counter = 0;
+ }
+
+ // check if the passed turn's segment of Linear geometry arrived
+ // from the inside or the outside of the Areal geometry
+ template <typename Turn>
+ static inline bool calculate_from_inside(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Turn const& turn)
+ {
+ if ( turn.operations[op_id].position == overlay::position_front )
+ return false;
+
+ typename sub_range_return_type<Geometry1 const>::type
+ range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
+
+ typedef detail::normalized_view<Geometry2 const> const range2_type;
+ typedef typename boost::range_iterator<range2_type>::type range2_iterator;
+ range2_type range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
+
+ BOOST_ASSERT(boost::size(range1));
+ std::size_t const s2 = boost::size(range2);
+ BOOST_ASSERT(s2 > 2);
+ std::size_t const seg_count2 = s2 - 1;
+
+ std::size_t const p_seg_ij = turn.operations[op_id].seg_id.segment_index;
+ std::size_t const q_seg_ij = turn.operations[other_op_id].seg_id.segment_index;
+
+ BOOST_ASSERT(p_seg_ij + 1 < boost::size(range1));
+ BOOST_ASSERT(q_seg_ij + 1 < s2);
+
+ point1_type const& pi = range::at(range1, p_seg_ij);
+ point2_type const& qi = range::at(range2, q_seg_ij);
+ point2_type const& qj = range::at(range2, q_seg_ij + 1);
+ point1_type qi_conv;
+ geometry::convert(qi, qi_conv);
+ bool const is_ip_qj = equals::equals_point_point(turn.point, qj);
+// TODO: test this!
+// BOOST_ASSERT(!equals::equals_point_point(turn.point, pi));
+// BOOST_ASSERT(!equals::equals_point_point(turn.point, qi));
+ point1_type new_pj;
+ geometry::convert(turn.point, new_pj);
+
+ if ( is_ip_qj )
+ {
+ std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2;
+// TODO: the following function should return immediately, however the worst case complexity is O(N)
+// It would be good to replace it with some O(1) mechanism
+ range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2),
+ boost::begin(range2) + q_seg_jk,
+ boost::end(range2));
+
+ // Will this sequence of points be always correct?
+ overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it);
+
+ return calculate_from_inside_sides(side_calc);
+ }
+ else
+ {
+ point1_type new_qj;
+ geometry::convert(turn.point, new_qj);
+
+ overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, new_qj, qj);
+
+ return calculate_from_inside_sides(side_calc);
+ }
+ }
+
+ template <typename It>
+ static inline It find_next_non_duplicated(It first, It current, It last)
+ {
+ BOOST_ASSERT( current != last );
+
+ It it = current;
+
+ for ( ++it ; it != last ; ++it )
+ {
+ if ( !equals::equals_point_point(*current, *it) )
+ return it;
+ }
+
+ // if not found start from the beginning
+ for ( it = first ; it != current ; ++it )
+ {
+ if ( !equals::equals_point_point(*current, *it) )
+ return it;
+ }
+
+ return current;
+ }
+
+ // calculate inside or outside based on side_calc
+ // this is simplified version of a check from equal<>
+ template <typename SideCalc>
+ static inline bool calculate_from_inside_sides(SideCalc const& side_calc)
+ {
+ int const side_pk_p = side_calc.pk_wrt_p1();
+ int const side_qk_p = side_calc.qk_wrt_p1();
+ // If they turn to same side (not opposite sides)
+ if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
+ {
+ int const side_pk_q2 = side_calc.pk_wrt_q2();
+ return side_pk_q2 == -1;
+ }
+ else
+ {
+ return side_pk_p == -1;
+ }
+ }
+
+ private:
+ exit_watcher<TurnInfo, op_id> m_exit_watcher;
+ segment_watcher<same_single> m_seg_watcher;
+ TurnInfo * m_previous_turn_ptr;
+ overlay::operation_type m_previous_operation;
+ unsigned m_boundary_counter;
+ bool m_interior_detected;
+ const segment_identifier * m_first_interior_other_id_ptr;
+ };
+
+ // call analyser.apply() for each turn in range
+ // IMPORTANT! The analyser is also called for the end iterator - last
+ template <typename Result,
+ typename TurnIt,
+ typename Analyser,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker>
+ static inline void analyse_each_turn(Result & res,
+ Analyser & analyser,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker)
+ {
+ if ( first == last )
+ return;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ analyser.apply(res, it,
+ geometry, other_geometry,
+ boundary_checker);
+
+ if ( res.interrupt )
+ return;
+ }
+
+ analyser.apply(res, first, last,
+ geometry, other_geometry,
+ boundary_checker);
+ }
+
+ // less comparator comparing multi_index then ring_index
+ // may be used to sort turns by ring
+ struct less_ring
+ {
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ return left.operations[1].seg_id.multi_index < right.operations[1].seg_id.multi_index
+ || ( left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index
+ && left.operations[1].seg_id.ring_index < right.operations[1].seg_id.ring_index );
+ }
+ };
+
+ // policy/functor checking if a turn's operation is operation_continue
+ struct has_boundary_intersection
+ {
+ has_boundary_intersection()
+ : result(false) {}
+
+ template <typename Turn>
+ inline void operator()(Turn const& turn)
+ {
+ if ( turn.operations[1].operation == overlay::operation_continue )
+ result = true;
+ }
+
+ bool result;
+ };
+
+ // iterate through the range and search for the different multi_index or ring_index
+ // also call fun for each turn in the current range
+ template <typename It, typename Fun>
+ static inline It find_next_ring(It first, It last, Fun & fun)
+ {
+ if ( first == last )
+ return last;
+
+ int const multi_index = first->operations[1].seg_id.multi_index;
+ int const ring_index = first->operations[1].seg_id.ring_index;
+
+ fun(*first);
+ ++first;
+
+ for ( ; first != last ; ++first )
+ {
+ if ( multi_index != first->operations[1].seg_id.multi_index
+ || ring_index != first->operations[1].seg_id.ring_index )
+ {
+ return first;
+ }
+
+ fun(*first);
+ }
+
+ return last;
+ }
+
+ // analyser which called for turns sorted by seg/distance/operation
+ // checks if the boundary of Areal geometry really got out
+ // into the exterior of Linear geometry
+ template <typename TurnInfo>
+ class areal_boundary_analyser
+ {
+ public:
+ areal_boundary_analyser()
+ : is_union_detected(false)
+ , m_previous_turn_ptr(NULL)
+ {}
+
+ template <typename TurnIt>
+ bool apply(TurnIt /*first*/, TurnIt it, TurnIt last)
+ {
+ overlay::operation_type op = it->operations[1].operation;
+
+ if ( it != last )
+ {
+ if ( op != overlay::operation_union
+ && op != overlay::operation_continue )
+ {
+ return true;
+ }
+
+ if ( is_union_detected )
+ {
+ BOOST_ASSERT(m_previous_turn_ptr != NULL);
+ if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point) )
+ {
+ // break
+ return false;
+ }
+ else if ( op == overlay::operation_continue ) // operation_boundary
+ {
+ is_union_detected = false;
+ }
+ }
+
+ if ( op == overlay::operation_union )
+ {
+ is_union_detected = true;
+ m_previous_turn_ptr = boost::addressof(*it);
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ bool is_union_detected;
+
+ private:
+ const TurnInfo * m_previous_turn_ptr;
+ };
+};
+
+template <typename Geometry1, typename Geometry2>
+struct areal_linear
+{
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+ linear_areal<Geometry2, Geometry1, true>::apply(geometry2, geometry1, result);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp
new file mode 100644
index 0000000000..263c82de56
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/linear_linear.hpp
@@ -0,0 +1,768 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/single_geometry.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
+#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+template <typename Result, typename BoundaryChecker, bool TransposeResult>
+class disjoint_linestring_pred
+{
+public:
+ disjoint_linestring_pred(Result & res,
+ BoundaryChecker const& boundary_checker)
+ : m_result(res)
+ , m_boundary_checker(boundary_checker)
+ , m_flags(0)
+ {
+ if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) )
+ {
+ m_flags |= 1;
+ }
+ if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) )
+ {
+ m_flags |= 2;
+ }
+ }
+
+ template <typename Linestring>
+ bool operator()(Linestring const& linestring)
+ {
+ if ( m_flags == 3 )
+ {
+ return false;
+ }
+
+ std::size_t const count = boost::size(linestring);
+
+ // invalid input
+ if ( count < 2 )
+ {
+ // ignore
+ // TODO: throw an exception?
+ return true;
+ }
+
+ // point-like linestring
+ if ( count == 2
+ && equals::equals_point_point(range::front(linestring),
+ range::back(linestring)) )
+ {
+ update<interior, exterior, '0', TransposeResult>(m_result);
+ }
+ else
+ {
+ update<interior, exterior, '1', TransposeResult>(m_result);
+ m_flags |= 1;
+
+ // check if there is a boundary
+ if ( m_flags < 2
+ && ( m_boundary_checker.template
+ is_endpoint_boundary<boundary_front>(range::front(linestring))
+ || m_boundary_checker.template
+ is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
+ {
+ update<boundary, exterior, '0', TransposeResult>(m_result);
+ m_flags |= 2;
+ }
+ }
+
+ return m_flags != 3
+ && ! m_result.interrupt;
+ }
+
+private:
+ Result & m_result;
+ BoundaryChecker const& m_boundary_checker;
+ unsigned m_flags;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct linear_linear
+{
+ static const bool interruption_enabled = true;
+
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+ // The result should be FFFFFFFFF
+ relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T
+ if ( result.interrupt )
+ return;
+
+ // get and analyse turns
+ typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
+ std::vector<turn_type> turns;
+
+ interrupt_policy_linear_linear<Result> interrupt_policy(result);
+
+ turns::get_turns
+ <
+ Geometry1,
+ Geometry2,
+ detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> >
+ >::apply(turns, geometry1, geometry2, interrupt_policy);
+
+ if ( result.interrupt )
+ return;
+
+ boundary_checker<Geometry1> boundary_checker1(geometry1);
+ disjoint_linestring_pred<Result, boundary_checker<Geometry1>, false> pred1(result, boundary_checker1);
+ for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
+ if ( result.interrupt )
+ return;
+
+ boundary_checker<Geometry2> boundary_checker2(geometry2);
+ disjoint_linestring_pred<Result, boundary_checker<Geometry2>, true> pred2(result, boundary_checker2);
+ for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
+ if ( result.interrupt )
+ return;
+
+ if ( turns.empty() )
+ return;
+
+ // TODO: turns must be sorted and followed only if it's possible to go out and in on the same point
+ // for linear geometries union operation must be detected which I guess would be quite often
+
+ if ( may_update<interior, interior, '1'>(result)
+ || may_update<interior, boundary, '0'>(result)
+ || may_update<interior, exterior, '1'>(result)
+ || may_update<boundary, interior, '0'>(result)
+ || may_update<boundary, boundary, '0'>(result)
+ || may_update<boundary, exterior, '0'>(result) )
+ {
+ typedef turns::less<0, turns::less_op_linear_linear<0> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ turns_analyser<turn_type, 0> analyser;
+ analyse_each_turn(result, analyser,
+ turns.begin(), turns.end(),
+ geometry1, geometry2,
+ boundary_checker1, boundary_checker2);
+ }
+
+ if ( result.interrupt )
+ return;
+
+ if ( may_update<interior, interior, '1', true>(result)
+ || may_update<interior, boundary, '0', true>(result)
+ || may_update<interior, exterior, '1', true>(result)
+ || may_update<boundary, interior, '0', true>(result)
+ || may_update<boundary, boundary, '0', true>(result)
+ || may_update<boundary, exterior, '0', true>(result) )
+ {
+ typedef turns::less<1, turns::less_op_linear_linear<1> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ turns_analyser<turn_type, 1> analyser;
+ analyse_each_turn(result, analyser,
+ turns.begin(), turns.end(),
+ geometry2, geometry1,
+ boundary_checker2, boundary_checker1);
+ }
+ }
+
+ template <typename Result>
+ class interrupt_policy_linear_linear
+ {
+ public:
+ static bool const enabled = true;
+
+ explicit interrupt_policy_linear_linear(Result & result)
+ : m_result(result)
+ {}
+
+// TODO: since we update result for some operations here, we may not do it in the analyser!
+
+ template <typename Range>
+ inline bool apply(Range const& turns)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
+ {
+ if ( it->operations[0].operation == overlay::operation_intersection
+ || it->operations[1].operation == overlay::operation_intersection )
+ {
+ update<interior, interior, '1'>(m_result);
+ }
+ else if ( ( it->operations[0].operation == overlay::operation_union
+ || it->operations[0].operation == overlay::operation_blocked
+ || it->operations[1].operation == overlay::operation_union
+ || it->operations[1].operation == overlay::operation_blocked )
+ && it->operations[0].position == overlay::position_middle
+ && it->operations[1].position == overlay::position_middle )
+ {
+// TODO: here we could also check the boundaries and set IB,BI,BB at this point
+ update<interior, interior, '0'>(m_result);
+ }
+ }
+
+ return m_result.interrupt;
+ }
+
+ private:
+ Result & m_result;
+ };
+
+ // This analyser should be used like Input or SinglePass Iterator
+ template <typename TurnInfo, std::size_t OpId>
+ class turns_analyser
+ {
+ typedef typename TurnInfo::point_type turn_point_type;
+
+ static const std::size_t op_id = OpId;
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static const bool transpose_result = OpId != 0;
+
+ public:
+ turns_analyser()
+ : m_previous_turn_ptr(NULL)
+ , m_previous_operation(overlay::operation_none)
+ , m_degenerated_turn_ptr(NULL)
+ {}
+
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ void apply(Result & res, TurnIt it,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& other_boundary_checker)
+ {
+ overlay::operation_type const op = it->operations[op_id].operation;
+
+ segment_identifier const& seg_id = it->operations[op_id].seg_id;
+ segment_identifier const& other_id = it->operations[other_op_id].seg_id;
+
+ bool const first_in_range = m_seg_watcher.update(seg_id);
+
+ if ( op != overlay::operation_union
+ && op != overlay::operation_intersection
+ && op != overlay::operation_blocked )
+ {
+ // degenerated turn
+ if ( op == overlay::operation_continue
+ && it->method == overlay::method_none
+ && m_exit_watcher.is_outside(*it)
+ /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none
+ || ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ )
+ {
+ // TODO: rewrite the above condition
+
+ // WARNING! For spikes the above condition may be TRUE
+ // When degenerated turns are be marked in a different way than c,c/c
+ // different condition will be checked
+
+ handle_degenerated(res, *it,
+ geometry, other_geometry,
+ boundary_checker, other_boundary_checker,
+ first_in_range);
+
+ // TODO: not elegant solution! should be rewritten.
+ if ( it->operations[op_id].position == overlay::position_back )
+ {
+ m_previous_operation = overlay::operation_blocked;
+ m_exit_watcher.reset_detected_exit();
+ }
+ }
+
+ return;
+ }
+
+ // reset
+ m_degenerated_turn_ptr = NULL;
+
+ // handle possible exit
+ bool fake_enter_detected = false;
+ if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
+ {
+ // real exit point - may be multiple
+ // we know that we entered and now we exit
+ if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ m_exit_watcher.reset_detected_exit();
+
+ // not the last IP
+ update<interior, exterior, '1', transpose_result>(res);
+ }
+ // fake exit point, reset state
+ else if ( op == overlay::operation_intersection )
+ {
+ m_exit_watcher.reset_detected_exit();
+ fake_enter_detected = true;
+ }
+ }
+ else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
+ {
+ // ignore multiple BLOCKs
+ if ( op == overlay::operation_blocked )
+ return;
+
+ if ( op == overlay::operation_intersection
+ && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ fake_enter_detected = true;
+ }
+
+ m_exit_watcher.reset_detected_exit();
+ }
+
+ // i/i, i/x, i/u
+ if ( op == overlay::operation_intersection )
+ {
+ bool const was_outside = m_exit_watcher.is_outside();
+ m_exit_watcher.enter(*it);
+
+ // interiors overlaps
+ update<interior, interior, '1', transpose_result>(res);
+
+ bool const this_b = it->operations[op_id].position == overlay::position_front // ignore spikes!
+ && is_ip_on_boundary<boundary_front>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+
+ // going inside on boundary point
+ // may be front only
+ if ( this_b )
+ {
+ // may be front and back
+ bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[other_op_id],
+ other_boundary_checker,
+ other_id);
+
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<boundary, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ }
+ // going inside on non-boundary point
+ else
+ {
+ // if we didn't enter in the past, we were outside
+ if ( was_outside
+ && ! fake_enter_detected
+ && it->operations[op_id].position != overlay::position_front )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ // if it's the first IP then the first point is outside
+ if ( first_in_range )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+ }
+ }
+ // u/i, u/u, u/x, x/i, x/u, x/x
+ else if ( op == overlay::operation_union || op == overlay::operation_blocked )
+ {
+ // TODO: is exit watcher still needed?
+ // couldn't is_collinear and some going inside counter be used instead?
+
+ bool const is_collinear = it->operations[op_id].is_collinear;
+ bool const was_outside = m_exit_watcher.is_outside()
+ && m_exit_watcher.get_exit_operation() == overlay::operation_none;
+// TODO: move the above condition into the exit_watcher?
+
+ // to exit we must be currently inside and the current segment must be collinear
+ if ( !was_outside && is_collinear )
+ {
+ m_exit_watcher.exit(*it, false);
+ }
+
+ bool const op_blocked = op == overlay::operation_blocked;
+
+ // we're inside and going out from inside
+ // possibly going out right now
+ if ( ! was_outside && is_collinear )
+ {
+ if ( op_blocked
+ && it->operations[op_id].position == overlay::position_back ) // ignore spikes!
+ {
+ // check if this is indeed the boundary point
+ // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
+ if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
+ {
+ // may be front and back
+ bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[other_op_id],
+ other_boundary_checker,
+ other_id);
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<boundary, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ }
+ }
+ }
+ // we're outside or intersects some segment from the outside
+ else
+ {
+ // if we are truly outside
+ if ( was_outside
+ && it->operations[op_id].position != overlay::position_front
+ /*&& !is_collinear*/ )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+ }
+
+ // boundaries don't overlap - just an optimization
+ if ( it->method == overlay::method_crosses )
+ {
+ // the L1 is going from one side of the L2 to the other through the point
+ update<interior, interior, '0', transpose_result>(res);
+
+ // it's the first point in range
+ if ( first_in_range )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+ // method other than crosses, check more conditions
+ else
+ {
+ bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+
+ bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[other_op_id],
+ other_boundary_checker,
+ other_id);
+
+ // if current IP is on boundary of the geometry
+ if ( this_b )
+ {
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<boundary, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ }
+ // if current IP is not on boundary of the geometry
+ else
+ {
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<interior, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<interior, interior, '0', transpose_result>(res);
+ }
+ }
+
+ // first IP on the last segment point - this means that the first point is outside
+ if ( first_in_range
+ && ( !this_b || op_blocked )
+ && was_outside
+ && it->operations[op_id].position != overlay::position_front
+ /*&& !is_collinear*/ )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+
+ }
+ }
+ }
+
+ // store ref to previously analysed (valid) turn
+ m_previous_turn_ptr = boost::addressof(*it);
+ // and previously analysed (valid) operation
+ m_previous_operation = op;
+ }
+
+ // Called for last
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ void apply(Result & res,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& /*other_geometry*/,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& /*other_boundary_checker*/)
+ {
+ boost::ignore_unused(first, last);
+ //BOOST_ASSERT( first != last );
+
+ // here, the possible exit is the real one
+ // we know that we entered and now we exit
+ if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
+ ||*/ m_previous_operation == overlay::operation_union
+ || m_degenerated_turn_ptr )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ BOOST_ASSERT(first != last);
+
+ const TurnInfo * turn_ptr = NULL;
+ if ( m_degenerated_turn_ptr )
+ turn_ptr = m_degenerated_turn_ptr;
+ else if ( m_previous_turn_ptr )
+ turn_ptr = m_previous_turn_ptr;
+
+ if ( turn_ptr )
+ {
+ segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id;
+
+ //BOOST_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id)));
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+
+ // Just in case,
+ // reset exit watcher before the analysis of the next Linestring
+ // note that if there are some enters stored there may be some error above
+ m_exit_watcher.reset();
+
+ m_previous_turn_ptr = NULL;
+ m_previous_operation = overlay::operation_none;
+ m_degenerated_turn_ptr = NULL;
+ }
+
+ template <typename Result,
+ typename Turn,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ void handle_degenerated(Result & res,
+ Turn const& turn,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& /*other_boundary_checker*/,
+ bool first_in_range)
+ {
+ typename detail::single_geometry_return_type<Geometry const>::type
+ ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id);
+ typename detail::single_geometry_return_type<OtherGeometry const>::type
+ ls2_ref = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id);
+
+ // only one of those should be true:
+
+ if ( turn.operations[op_id].position == overlay::position_front )
+ {
+ // valid, point-sized
+ if ( boost::size(ls2_ref) == 2 )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker);
+
+ if ( front_b )
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<interior, interior, '0', transpose_result>(res);
+ }
+
+ // operation 'c' should be last for the same IP so we know that the next point won't be the same
+ update<interior, exterior, '1', transpose_result>(res);
+
+ m_degenerated_turn_ptr = boost::addressof(turn);
+ }
+ }
+ else if ( turn.operations[op_id].position == overlay::position_back )
+ {
+ // valid, point-sized
+ if ( boost::size(ls2_ref) == 2 )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker);
+
+ if ( back_b )
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<interior, interior, '0', transpose_result>(res);
+ }
+
+ if ( first_in_range )
+ {
+ //BOOST_ASSERT(!boost::empty(ls1_ref));
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(ls1_ref), boundary_checker);
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+ }
+ else if ( turn.operations[op_id].position == overlay::position_middle
+ && turn.operations[other_op_id].position == overlay::position_middle )
+ {
+ update<interior, interior, '0', transpose_result>(res);
+
+ // here we don't know which one is degenerated
+
+ bool const is_point1 = boost::size(ls1_ref) == 2
+ && equals::equals_point_point(range::front(ls1_ref), range::back(ls1_ref));
+ bool const is_point2 = boost::size(ls2_ref) == 2
+ && equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref));
+
+ // if the second one is degenerated
+ if ( !is_point1 && is_point2 )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ if ( first_in_range )
+ {
+ //BOOST_ASSERT(!boost::empty(ls1_ref));
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(ls1_ref), boundary_checker);
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+
+ m_degenerated_turn_ptr = boost::addressof(turn);
+ }
+ }
+
+ // NOTE: other.position == front and other.position == back
+ // will be handled later, for the other geometry
+ }
+
+ private:
+ exit_watcher<TurnInfo, OpId> m_exit_watcher;
+ segment_watcher<same_single> m_seg_watcher;
+ const TurnInfo * m_previous_turn_ptr;
+ overlay::operation_type m_previous_operation;
+ const TurnInfo * m_degenerated_turn_ptr;
+ };
+
+ template <typename Result,
+ typename TurnIt,
+ typename Analyser,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ static inline void analyse_each_turn(Result & res,
+ Analyser & analyser,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& other_boundary_checker)
+ {
+ if ( first == last )
+ return;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ analyser.apply(res, it,
+ geometry, other_geometry,
+ boundary_checker, other_boundary_checker);
+
+ if ( res.interrupt )
+ return;
+ }
+
+ analyser.apply(res, first, last,
+ geometry, other_geometry,
+ boundary_checker, other_boundary_checker);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
new file mode 100644
index 0000000000..86c236d357
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
@@ -0,0 +1,205 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
+
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+//#include <boost/geometry/algorithms/within.hpp>
+//#include <boost/geometry/algorithms/covered_by.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// non-point geometry
+template <typename Point, typename Geometry, bool Transpose = false>
+struct point_geometry
+{
+ // TODO: interrupt only if the topology check is complex
+
+ static const bool interruption_enabled = true;
+
+ template <typename Result>
+ static inline void apply(Point const& point, Geometry const& geometry, Result & result)
+ {
+ int pig = detail::within::point_in_geometry(point, geometry);
+
+ if ( pig > 0 ) // within
+ {
+ set<interior, interior, '0', Transpose>(result);
+ }
+ else if ( pig == 0 )
+ {
+ set<interior, boundary, '0', Transpose>(result);
+ }
+ else // pig < 0 - not within
+ {
+ set<interior, exterior, '0', Transpose>(result);
+ }
+
+ set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
+
+ if ( result.interrupt )
+ return;
+
+ // the point is on the boundary
+ if ( pig == 0 )
+ {
+ // NOTE: even for MLs, if there is at least one boundary point,
+ // somewhere there must be another one
+
+ // check if there are other boundaries outside
+ typedef detail::relate::topology_check<Geometry> tc_t;
+ //tc_t tc(geometry, point);
+ //if ( tc.has_interior )
+ set<exterior, interior, tc_t::interior, Transpose>(result);
+ //if ( tc.has_boundary )
+ set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ else
+ {
+ // check if there is a boundary in Geometry
+ typedef detail::relate::topology_check<Geometry> tc_t;
+ tc_t tc(geometry);
+ if ( tc.has_interior )
+ set<exterior, interior, tc_t::interior, Transpose>(result);
+ if ( tc.has_boundary )
+ set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ }
+};
+
+// transposed result of point_geometry
+template <typename Geometry, typename Point>
+struct geometry_point
+{
+ // TODO: interrupt only if the topology check is complex
+
+ static const bool interruption_enabled = true;
+
+ template <typename Result>
+ static inline void apply(Geometry const& geometry, Point const& point, Result & result)
+ {
+ point_geometry<Point, Geometry, true>::apply(point, geometry, result);
+ }
+};
+
+// TODO: rewrite the folowing:
+
+//// NOTE: Those tests should be consistent with within(Point, Box) and covered_by(Point, Box)
+//// There is no EPS used in those functions, values are compared using < or <=
+//// so comparing MIN and MAX in the same way should be fine
+//
+//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
+//struct box_has_interior
+//{
+// static inline bool apply(Box const& box)
+// {
+// return geometry::get<min_corner, I>(box) < geometry::get<max_corner, I>(box)
+// && box_has_interior<Box, I + 1, D>::apply(box);
+// }
+//};
+//
+//template <typename Box, std::size_t D>
+//struct box_has_interior<Box, D, D>
+//{
+// static inline bool apply(Box const&) { return true; }
+//};
+//
+//// NOTE: especially important here (see the NOTE above).
+//
+//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
+//struct box_has_equal_min_max
+//{
+// static inline bool apply(Box const& box)
+// {
+// return geometry::get<min_corner, I>(box) == geometry::get<max_corner, I>(box)
+// && box_has_equal_min_max<Box, I + 1, D>::apply(box);
+// }
+//};
+//
+//template <typename Box, std::size_t D>
+//struct box_has_equal_min_max<Box, D, D>
+//{
+// static inline bool apply(Box const&) { return true; }
+//};
+//
+//template <typename Point, typename Box>
+//struct point_box
+//{
+// static inline result apply(Point const& point, Box const& box)
+// {
+// result res;
+//
+// if ( geometry::within(point, box) ) // this also means that the box has interior
+// {
+// return result("0FFFFFTTT");
+// }
+// else if ( geometry::covered_by(point, box) ) // point is on the boundary
+// {
+// //if ( box_has_interior<Box>::apply(box) )
+// //{
+// // return result("F0FFFFTTT");
+// //}
+// //else if ( box_has_equal_min_max<Box>::apply(box) ) // no boundary outside point
+// //{
+// // return result("F0FFFFFFT");
+// //}
+// //else // no interior outside point
+// //{
+// // return result("F0FFFFFTT");
+// //}
+// return result("F0FFFF**T");
+// }
+// else
+// {
+// /*if ( box_has_interior<Box>::apply(box) )
+// {
+// return result("FF0FFFTTT");
+// }
+// else
+// {
+// return result("FF0FFFFTT");
+// }*/
+// return result("FF0FFF*TT");
+// }
+//
+// return res;
+// }
+//};
+//
+//template <typename Box, typename Point>
+//struct box_point
+//{
+// static inline result apply(Box const& box, Point const& point)
+// {
+// if ( geometry::within(point, box) )
+// return result("0FTFFTFFT");
+// else if ( geometry::covered_by(point, box) )
+// return result("FF*0F*FFT");
+// else
+// return result("FF*FFT0FT");
+// }
+//};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp
new file mode 100644
index 0000000000..e623868b92
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/point_point.hpp
@@ -0,0 +1,242 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+template <typename Point1, typename Point2>
+struct point_point
+{
+ static const bool interruption_enabled = false;
+
+ template <typename Result>
+ static inline void apply(Point1 const& point1, Point2 const& point2, Result & result)
+ {
+ bool equal = detail::equals::equals_point_point(point1, point2);
+ if ( equal )
+ {
+ set<interior, interior, '0'>(result);
+ }
+ else
+ {
+ set<interior, exterior, '0'>(result);
+ set<exterior, interior, '0'>(result);
+ }
+
+ set<exterior, exterior, result_dimension<Point1>::value>(result);
+ }
+};
+
+template <typename Point, typename MultiPoint>
+std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint const& multi_point)
+{
+ bool found_inside = false;
+ bool found_outside = false;
+
+ // point_in_geometry could be used here but why iterate over MultiPoint twice?
+ // we must search for a point in the exterior because all points in MultiPoint can be equal
+
+ typedef typename boost::range_iterator<MultiPoint const>::type iterator;
+ iterator it = boost::begin(multi_point);
+ iterator last = boost::end(multi_point);
+ for ( ; it != last ; ++it )
+ {
+ bool ii = detail::equals::equals_point_point(point, *it);
+
+ if ( ii )
+ found_inside = true;
+ else
+ found_outside = true;
+
+ if ( found_inside && found_outside )
+ break;
+ }
+
+ return std::make_pair(found_inside, found_outside);
+}
+
+template <typename Point, typename MultiPoint, bool Transpose = false>
+struct point_multipoint
+{
+ static const bool interruption_enabled = false;
+
+ template <typename Result>
+ static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result)
+ {
+ if ( boost::empty(multi_point) )
+ {
+ // TODO: throw on empty input?
+ set<interior, exterior, '0', Transpose>(result);
+ return;
+ }
+
+ std::pair<bool, bool> rel = point_multipoint_check(point, multi_point);
+
+ if ( rel.first ) // some point of MP is equal to P
+ {
+ set<interior, interior, '0', Transpose>(result);
+
+ if ( rel.second ) // a point of MP was found outside P
+ {
+ set<exterior, interior, '0', Transpose>(result);
+ }
+ }
+ else
+ {
+ set<interior, exterior, '0', Transpose>(result);
+ set<exterior, interior, '0', Transpose>(result);
+ }
+
+ set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
+ }
+};
+
+template <typename MultiPoint, typename Point>
+struct multipoint_point
+{
+ static const bool interruption_enabled = false;
+
+ template <typename Result>
+ static inline void apply(MultiPoint const& multi_point, Point const& point, Result & result)
+ {
+ point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result);
+ }
+};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct multipoint_multipoint
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result>
+ static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result)
+ {
+ {
+ // TODO: throw on empty input?
+ bool empty1 = boost::empty(multi_point1);
+ bool empty2 = boost::empty(multi_point2);
+ if ( empty1 && empty2 )
+ {
+ return;
+ }
+ else if ( empty1 )
+ {
+ set<exterior, interior, '0'>(result);
+ return;
+ }
+ else if ( empty2 )
+ {
+ set<interior, exterior, '0'>(result);
+ return;
+ }
+ }
+
+// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED
+
+// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
+// so if e.g. only I/I must be analysed we musn't check the other MPt
+
+// TODO: Also, the geometry with the smaller number of points may be analysed first
+ //if ( boost::size(multi_point1) < boost::size(multi_point2) )
+
+ // NlogN + MlogN
+ bool all_handled = search<false>(multi_point1, multi_point2, result);
+
+ if ( all_handled || result.interrupt )
+ return;
+
+ // MlogM + NlogM
+ search<true>(multi_point2, multi_point1, result);
+ }
+
+ template <bool Transpose,
+ typename SortedMultiPoint,
+ typename IteratedMultiPoint,
+ typename Result>
+ static inline bool search(SortedMultiPoint const& sorted_mpt,
+ IteratedMultiPoint const& iterated_mpt,
+ Result & result)
+ {
+ // sort points from the 1 MPt
+ typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
+ std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt));
+ std::sort(points.begin(), points.end(), less());
+
+ bool found_inside = false;
+ bool found_outside = false;
+
+ // for each point in the second MPt
+ typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator;
+ for ( iterator it = boost::begin(iterated_mpt) ;
+ it != boost::end(iterated_mpt) ; ++it )
+ {
+ bool ii =
+ std::binary_search(points.begin(), points.end(), *it, less());
+ if ( ii )
+ found_inside = true;
+ else
+ found_outside = true;
+
+ if ( found_inside && found_outside )
+ break;
+ }
+
+ // an optimization
+ bool all_handled = false;
+
+ if ( found_inside ) // some point of MP2 is equal to some of MP1
+ {
+// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
+// so if e.g. only I/I must be analysed we musn't check the other MPt
+
+ set<interior, interior, '0', Transpose>(result);
+
+ if ( found_outside ) // some point of MP2 was found outside of MP1
+ {
+ set<exterior, interior, '0', Transpose>(result);
+ }
+ }
+ else
+ {
+ set<interior, exterior, '0', Transpose>(result);
+ set<exterior, interior, '0', Transpose>(result);
+
+ // if no point is intersecting the other MPt then we musn't analyse the reversed case
+ all_handled = true;
+ }
+
+ set<exterior, exterior, result_dimension<point_type>::value, Transpose>(result);
+
+ return all_handled;
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/relate/relate.hpp b/boost/geometry/algorithms/detail/relate/relate.hpp
new file mode 100644
index 0000000000..946653452a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/relate.hpp
@@ -0,0 +1,339 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP
+
+#include <cstddef>
+
+#include <boost/concept_check.hpp>
+#include <boost/range.hpp>
+
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/or.hpp>
+#include <boost/type_traits/is_base_of.hpp>
+
+#include <boost/geometry/algorithms/make.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/strategies/concepts/within_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/within.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/order_as_direction.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/result.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_point.hpp>
+#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp>
+#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// Those are used only to allow dispatch::relate to produce compile-time error
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+struct is_supported_by_generic
+{
+ static const bool value
+ = boost::is_same<Tag, linestring_tag>::value
+ || boost::is_same<Tag, multi_linestring_tag>::value
+ || boost::is_same<Tag, ring_tag>::value
+ || boost::is_same<Tag, polygon_tag>::value
+ || boost::is_same<Tag, multi_polygon_tag>::value;
+};
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type>
+struct is_generic
+{
+ static const bool value = is_supported_by_generic<Geometry1>::value
+ && is_supported_by_generic<Geometry2>::value;
+};
+
+
+template <typename Point, typename Geometry, typename Tag>
+struct is_generic<Point, Geometry, point_tag, Tag>
+{
+ static const bool value = is_supported_by_generic<Geometry>::value;
+};
+
+template <typename Geometry, typename Point, typename Tag>
+struct is_generic<Geometry, Point, Tag, point_tag>
+{
+ static const bool value = is_supported_by_generic<Geometry>::value;
+};
+
+template <typename Point1, typename Point2>
+struct is_generic<Point1, Point2, point_tag, point_tag>
+{
+ static const bool value = false;
+};
+
+
+}} // namespace detail::relate
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch { namespace relate {
+
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type,
+ int TopDim1 = geometry::topological_dimension<Geometry1>::value,
+ int TopDim2 = geometry::topological_dimension<Geometry2>::value,
+ bool IsGeneric = detail::relate::is_generic<Geometry1, Geometry2>::value
+>
+struct relate : not_implemented<Tag1, Tag2>
+{};
+
+
+template <typename Point1, typename Point2>
+struct relate<Point1, Point2, point_tag, point_tag, 0, 0, false>
+ : detail::relate::point_point<Point1, Point2>
+{};
+
+template <typename Point, typename MultiPoint>
+struct relate<Point, MultiPoint, point_tag, multi_point_tag, 0, 0, false>
+ : detail::relate::point_multipoint<Point, MultiPoint>
+{};
+
+template <typename MultiPoint, typename Point>
+struct relate<MultiPoint, Point, multi_point_tag, point_tag, 0, 0, false>
+ : detail::relate::multipoint_point<MultiPoint, Point>
+{};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct relate<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, 0, 0, false>
+ : detail::relate::multipoint_multipoint<MultiPoint1, MultiPoint2>
+{};
+
+//template <typename Point, typename Box, int TopDim2>
+//struct relate<Point, Box, point_tag, box_tag, 0, TopDim2, false>
+// : detail::relate::point_box<Point, Box>
+//{};
+//
+//template <typename Box, typename Point, int TopDim1>
+//struct relate<Box, Point, box_tag, point_tag, TopDim1, 0, false>
+// : detail::relate::box_point<Box, Point>
+//{};
+
+
+template <typename Point, typename Geometry, typename Tag2, int TopDim2>
+struct relate<Point, Geometry, point_tag, Tag2, 0, TopDim2, true>
+ : detail::relate::point_geometry<Point, Geometry>
+{};
+
+template <typename Geometry, typename Point, typename Tag1, int TopDim1>
+struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true>
+ : detail::relate::geometry_point<Geometry, Point>
+{};
+
+
+template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
+struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true>
+ : detail::relate::linear_linear<Linear1, Linear2>
+{};
+
+
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct relate<Linear, Areal, Tag1, Tag2, 1, 2, true>
+ : detail::relate::linear_areal<Linear, Areal>
+{};
+
+template <typename Areal, typename Linear, typename Tag1, typename Tag2>
+struct relate<Areal, Linear, Tag1, Tag2, 2, 1, true>
+ : detail::relate::areal_linear<Areal, Linear>
+{};
+
+
+template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
+struct relate<Areal1, Areal2, Tag1, Tag2, 2, 2, true>
+ : detail::relate::areal_areal<Areal1, Areal2>
+{};
+
+
+}} // namespace detail_dispatch::relate
+#endif // DOXYGEN_NO_DISPATCH
+
+namespace detail { namespace relate {
+
+template <typename Geometry1, typename Geometry2>
+struct interruption_enabled
+{
+ static const bool value =
+ detail_dispatch::relate::relate<Geometry1, Geometry2>::interruption_enabled;
+};
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Result,
+ bool IsSequence = boost::mpl::is_sequence<Result>::value>
+struct result_handler_type
+ : not_implemented<Result>
+{};
+
+template <typename Geometry1, typename Geometry2>
+struct result_handler_type<Geometry1, Geometry2, matrix9, false>
+{
+ typedef matrix_handler<matrix9> type;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct result_handler_type<Geometry1, Geometry2, mask9, false>
+{
+ typedef mask_handler
+ <
+ mask9,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename Geometry1, typename Geometry2, typename Head, typename Tail>
+struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail>, false>
+{
+ typedef mask_handler
+ <
+ boost::tuples::cons<Head, Tail>,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename Geometry1, typename Geometry2,
+ char II, char IB, char IE,
+ char BI, char BB, char BE,
+ char EI, char EB, char EE>
+struct result_handler_type<Geometry1, Geometry2, static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>, false>
+{
+ typedef static_mask_handler
+ <
+ static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename Geometry1, typename Geometry2, typename StaticSequence>
+struct result_handler_type<Geometry1, Geometry2, StaticSequence, true>
+{
+ typedef static_mask_handler
+ <
+ StaticSequence,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename MatrixOrMask, typename Geometry1, typename Geometry2>
+inline
+typename result_handler_type
+ <
+ Geometry1,
+ Geometry2,
+ MatrixOrMask
+ >::type::result_type
+relate(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ MatrixOrMask const& matrix_or_mask = MatrixOrMask())
+{
+ typedef typename result_handler_type
+ <
+ Geometry1,
+ Geometry2,
+ MatrixOrMask
+ >::type handler_type;
+
+ handler_type handler(matrix_or_mask);
+ detail_dispatch::relate::relate<Geometry1, Geometry2>::apply(geometry1, geometry2, handler);
+ return handler.result();
+}
+
+struct implemented_tag {};
+
+template <template <typename, typename> class StaticMaskTrait,
+ typename Geometry1,
+ typename Geometry2>
+struct relate_base
+ : boost::mpl::if_
+ <
+ boost::mpl::or_
+ <
+ boost::is_base_of
+ <
+ nyi::not_implemented_tag,
+ StaticMaskTrait<Geometry1, Geometry2>
+ >,
+ boost::is_base_of
+ <
+ nyi::not_implemented_tag,
+ detail_dispatch::relate::relate<Geometry1, Geometry2>
+ >
+ >,
+ not_implemented
+ <
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type
+ >,
+ implemented_tag
+ >::type
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ typedef typename StaticMaskTrait<Geometry1, Geometry2>::type static_mask;
+ return detail::relate::relate<static_mask>(g1, g2);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP
diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp
new file mode 100644
index 0000000000..1bcb5275d2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/result.hpp
@@ -0,0 +1,1390 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
+
+#include <boost/tuple/tuple.hpp>
+
+#include <boost/mpl/is_sequence.hpp>
+#include <boost/mpl/begin.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/next.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/vector_c.hpp>
+
+#include <boost/geometry/core/topological_dimension.hpp>
+
+// TEMP - move this header to geometry/detail
+#include <boost/geometry/index/detail/tuples.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+enum field { interior = 0, boundary = 1, exterior = 2 };
+
+// TODO: IF THE RESULT IS UPDATED WITH THE MAX POSSIBLE VALUE FOR SOME PAIR OF GEOEMTRIES
+// THE VALUE ALREADY STORED MUSN'T BE CHECKED
+// update() calls chould be replaced with set() in those cases
+// but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that
+// so some additional function could be added, e.g. set_dim()
+
+// matrix
+
+// TODO add height?
+
+template <std::size_t Width>
+class matrix
+{
+ BOOST_STATIC_ASSERT(Width == 2 || Width == 3);
+
+public:
+
+ static const std::size_t size = Width * Width;
+
+ inline matrix()
+ {
+ ::memset(m_array, 'F', size);
+ }
+
+ template <field F1, field F2>
+ inline char get() const
+ {
+ static const bool in_bounds = F1 * Width + F2 < size;
+ return get_dispatch<F1, F2>(integral_constant<bool, in_bounds>());
+ }
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ static const bool in_bounds = F1 * Width + F2 < size;
+ set_dispatch<F1, F2, V>(integral_constant<bool, in_bounds>());
+ }
+
+ template <field F1, field F2, char D>
+ inline void update()
+ {
+ static const bool in_bounds = F1 * Width + F2 < size;
+ update_dispatch<F1, F2, D>(integral_constant<bool, in_bounds>());
+ }
+
+ inline const char * data() const
+ {
+ return m_array;
+ }
+
+private:
+ template <field F1, field F2>
+ inline char get_dispatch(integral_constant<bool, true>) const
+ {
+ return m_array[F1 * Width + F2];
+ }
+ template <field F1, field F2>
+ inline char get_dispatch(integral_constant<bool, false>) const
+ {
+ return 'F';
+ }
+
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<bool, true>)
+ {
+ BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F');
+ m_array[F1 * Width + F2] = V;
+ }
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<bool, false>)
+ {}
+
+ template <field F1, field F2, char D>
+ inline void update_dispatch(integral_constant<bool, true>)
+ {
+ BOOST_STATIC_ASSERT('0' <= D && D <= '9');
+ char c = m_array[F1 * Width + F2];
+ if ( D > c || c > '9')
+ m_array[F1 * Width + F2] = D;
+ }
+ template <field F1, field F2, char D>
+ inline void update_dispatch(integral_constant<bool, false>)
+ {}
+
+ char m_array[size];
+};
+
+// TODO add EnableDimensions parameter?
+
+struct matrix9 {};
+//struct matrix4 {};
+
+// matrix_width
+
+template <typename MatrixOrMask>
+struct matrix_width
+ : not_implemented<MatrixOrMask>
+{};
+
+template <>
+struct matrix_width<matrix9>
+{
+ static const std::size_t value = 3;
+};
+
+// matrix_handler
+
+template <typename Matrix>
+class matrix_handler
+ : private matrix<matrix_width<Matrix>::value>
+{
+ typedef matrix<matrix_width<Matrix>::value> base_t;
+
+public:
+ typedef std::string result_type;
+
+ static const bool interrupt = false;
+
+ matrix_handler(Matrix const&)
+ {}
+
+ result_type result() const
+ {
+ return std::string(this->data(),
+ this->data() + base_t::size);
+ }
+
+ template <field F1, field F2, char D>
+ inline bool may_update() const
+ {
+ BOOST_STATIC_ASSERT('0' <= D && D <= '9');
+
+ char const c = static_cast<base_t const&>(*this).template get<F1, F2>();
+ return D > c || c > '9';
+ }
+
+ //template <field F1, field F2>
+ //inline char get() const
+ //{
+ // return static_cast<base_t const&>(*this).template get<F1, F2>();
+ //}
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ static_cast<base_t&>(*this).template set<F1, F2, V>();
+ }
+
+ template <field F1, field F2, char D>
+ inline void update()
+ {
+ static_cast<base_t&>(*this).template update<F1, F2, D>();
+ }
+};
+
+// RUN-TIME MASKS
+
+// mask9
+
+class mask9
+{
+public:
+ static const std::size_t width = 3; // TEMP
+
+ inline mask9(std::string const& de9im_mask)
+ {
+ // TODO: throw an exception here?
+ BOOST_ASSERT(de9im_mask.size() == 9);
+ ::memcpy(m_mask, de9im_mask.c_str(), 9);
+ }
+
+ template <field F1, field F2>
+ inline char get() const
+ {
+ return m_mask[F1 * 3 + F2];
+ }
+
+private:
+ char m_mask[9];
+};
+
+// interrupt()
+
+template <typename Mask, bool InterruptEnabled>
+struct interrupt_dispatch
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Mask const&)
+ {
+ return false;
+ }
+};
+
+template <typename Mask>
+struct interrupt_dispatch<Mask, true>
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Mask const& mask)
+ {
+ char m = mask.template get<F1, F2>();
+ return check<V>(m);
+ }
+
+ template <char V>
+ static inline bool check(char m)
+ {
+ if ( V >= '0' && V <= '9' )
+ {
+ return m == 'F' || ( m < V && m >= '0' && m <= '9' );
+ }
+ else if ( V == 'T' )
+ {
+ return m == 'F';
+ }
+ return false;
+ }
+};
+
+template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
+struct interrupt_dispatch_tuple
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Masks const& masks)
+ {
+ typedef typename boost::tuples::element<I, Masks>::type mask_type;
+ mask_type const& mask = boost::get<I>(masks);
+ return interrupt_dispatch<mask_type, true>::template apply<F1, F2, V>(mask)
+ && interrupt_dispatch_tuple<Masks, I+1>::template apply<F1, F2, V>(masks);
+ }
+};
+
+template <typename Masks, int N>
+struct interrupt_dispatch_tuple<Masks, N, N>
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Masks const& )
+ {
+ return true;
+ }
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct interrupt_dispatch<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, true>
+{
+ typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
+
+ template <field F1, field F2, char V>
+ static inline bool apply(mask_type const& mask)
+ {
+ return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
+ }
+};
+
+template <typename Head, typename Tail>
+struct interrupt_dispatch<boost::tuples::cons<Head, Tail>, true>
+{
+ typedef boost::tuples::cons<Head, Tail> mask_type;
+
+ template <field F1, field F2, char V>
+ static inline bool apply(mask_type const& mask)
+ {
+ return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
+ }
+};
+
+template <field F1, field F2, char V, bool InterruptEnabled, typename Mask>
+inline bool interrupt(Mask const& mask)
+{
+ return interrupt_dispatch<Mask, InterruptEnabled>
+ ::template apply<F1, F2, V>(mask);
+}
+
+// may_update()
+
+template <typename Mask>
+struct may_update_dispatch
+{
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(Mask const& mask, Matrix const& matrix)
+ {
+ BOOST_STATIC_ASSERT('0' <= D && D <= '9');
+
+ char const m = mask.template get<F1, F2>();
+
+ if ( m == 'F' )
+ {
+ return true;
+ }
+ else if ( m == 'T' )
+ {
+ char const c = matrix.template get<F1, F2>();
+ return c == 'F'; // if it's T or between 0 and 9, the result will be the same
+ }
+ else if ( m >= '0' && m <= '9' )
+ {
+ char const c = matrix.template get<F1, F2>();
+ return D > c || c > '9';
+ }
+
+ return false;
+ }
+};
+
+template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
+struct may_update_dispatch_tuple
+{
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(Masks const& masks, Matrix const& matrix)
+ {
+ typedef typename boost::tuples::element<I, Masks>::type mask_type;
+ mask_type const& mask = boost::get<I>(masks);
+ return may_update_dispatch<mask_type>::template apply<F1, F2, D>(mask, matrix)
+ || may_update_dispatch_tuple<Masks, I+1>::template apply<F1, F2, D>(masks, matrix);
+ }
+};
+
+template <typename Masks, int N>
+struct may_update_dispatch_tuple<Masks, N, N>
+{
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(Masks const& , Matrix const& )
+ {
+ return false;
+ }
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct may_update_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+{
+ typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
+
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix);
+ }
+};
+
+template <typename Head, typename Tail>
+struct may_update_dispatch< boost::tuples::cons<Head, Tail> >
+{
+ typedef boost::tuples::cons<Head, Tail> mask_type;
+
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix);
+ }
+};
+
+template <field F1, field F2, char D, typename Mask, typename Matrix>
+inline bool may_update(Mask const& mask, Matrix const& matrix)
+{
+ return may_update_dispatch<Mask>
+ ::template apply<F1, F2, D>(mask, matrix);
+}
+
+// check()
+
+template <typename Mask>
+struct check_dispatch
+{
+ template <typename Matrix>
+ static inline bool apply(Mask const& mask, Matrix const& matrix)
+ {
+ return per_one<interior, interior>(mask, matrix)
+ && per_one<interior, boundary>(mask, matrix)
+ && per_one<interior, exterior>(mask, matrix)
+ && per_one<boundary, interior>(mask, matrix)
+ && per_one<boundary, boundary>(mask, matrix)
+ && per_one<boundary, exterior>(mask, matrix)
+ && per_one<exterior, interior>(mask, matrix)
+ && per_one<exterior, boundary>(mask, matrix)
+ && per_one<exterior, exterior>(mask, matrix);
+ }
+
+ template <field F1, field F2, typename Matrix>
+ static inline bool per_one(Mask const& mask, Matrix const& matrix)
+ {
+ const char mask_el = mask.template get<F1, F2>();
+ const char el = matrix.template get<F1, F2>();
+
+ if ( mask_el == 'F' )
+ {
+ return el == 'F';
+ }
+ else if ( mask_el == 'T' )
+ {
+ return el == 'T' || ( el >= '0' && el <= '9' );
+ }
+ else if ( mask_el >= '0' && mask_el <= '9' )
+ {
+ return el == mask_el;
+ }
+
+ return true;
+ }
+};
+
+template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
+struct check_dispatch_tuple
+{
+ template <typename Matrix>
+ static inline bool apply(Masks const& masks, Matrix const& matrix)
+ {
+ typedef typename boost::tuples::element<I, Masks>::type mask_type;
+ mask_type const& mask = boost::get<I>(masks);
+ return check_dispatch<mask_type>::apply(mask, matrix)
+ || check_dispatch_tuple<Masks, I+1>::apply(masks, matrix);
+ }
+};
+
+template <typename Masks, int N>
+struct check_dispatch_tuple<Masks, N, N>
+{
+ template <typename Matrix>
+ static inline bool apply(Masks const&, Matrix const&)
+ {
+ return false;
+ }
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct check_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+{
+ typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
+
+ template <typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return check_dispatch_tuple<mask_type>::apply(mask, matrix);
+ }
+};
+
+template <typename Head, typename Tail>
+struct check_dispatch< boost::tuples::cons<Head, Tail> >
+{
+ typedef boost::tuples::cons<Head, Tail> mask_type;
+
+ template <typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return check_dispatch_tuple<mask_type>::apply(mask, matrix);
+ }
+};
+
+template <typename Mask, typename Matrix>
+inline bool check(Mask const& mask, Matrix const& matrix)
+{
+ return check_dispatch<Mask>::apply(mask, matrix);
+}
+
+// matrix_width
+
+template <>
+struct matrix_width<mask9>
+{
+ static const std::size_t value = 3;
+};
+
+template <typename Tuple,
+ int I = 0,
+ int N = boost::tuples::length<Tuple>::value>
+struct matrix_width_tuple
+{
+ static const std::size_t
+ current = matrix_width<typename boost::tuples::element<I, Tuple>::type>::value;
+ static const std::size_t
+ next = matrix_width_tuple<Tuple, I+1>::value;
+
+ static const std::size_t
+ value = current > next ? current : next;
+};
+
+template <typename Tuple, int N>
+struct matrix_width_tuple<Tuple, N, N>
+{
+ static const std::size_t value = 0;
+};
+
+template <typename Head, typename Tail>
+struct matrix_width< boost::tuples::cons<Head, Tail> >
+{
+ static const std::size_t
+ value = matrix_width_tuple< boost::tuples::cons<Head, Tail> >::value;
+};
+
+// matrix_handler
+
+template <typename Mask, bool Interrupt>
+class mask_handler
+ : private matrix<matrix_width<Mask>::value>
+{
+ typedef matrix<matrix_width<Mask>::value> base_t;
+
+public:
+ typedef bool result_type;
+
+ bool interrupt;
+
+ inline mask_handler(Mask const& m)
+ : interrupt(false)
+ , m_mask(m)
+ {}
+
+ result_type result() const
+ {
+ return !interrupt
+ && check(m_mask, static_cast<base_t const&>(*this));
+ }
+
+ template <field F1, field F2, char D>
+ inline bool may_update() const
+ {
+ return detail::relate::may_update<F1, F2, D>(
+ m_mask, static_cast<base_t const&>(*this)
+ );
+ }
+
+ //template <field F1, field F2>
+ //inline char get() const
+ //{
+ // return static_cast<base_t const&>(*this).template get<F1, F2>();
+ //}
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
+ {
+ interrupt = true;
+ }
+ else
+ {
+ base_t::template set<F1, F2, V>();
+ }
+ }
+
+ template <field F1, field F2, char V>
+ inline void update()
+ {
+ if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
+ {
+ interrupt = true;
+ }
+ else
+ {
+ base_t::template update<F1, F2, V>();
+ }
+ }
+
+private:
+ Mask const& m_mask;
+};
+
+// STATIC MASKS
+
+// static_mask
+
+template <char II, char IB, char IE,
+ char BI, char BB, char BE,
+ char EI, char EB, char EE>
+class static_mask
+{
+ typedef boost::mpl::vector_c
+ <
+ char, II, IB, IE, BI, BB, BE, EI, EB, EE
+ > vector_type;
+
+public:
+ template <field F1, field F2>
+ struct get
+ {
+ BOOST_STATIC_ASSERT(F1 * 3 + F2 < boost::mpl::size<vector_type>::value);
+
+ static const char value
+ = boost::mpl::at_c<vector_type, F1 * 3 + F2>::type::value;
+ };
+};
+
+// static_should_handle_element
+
+template <typename StaticMask, field F1, field F2, bool IsSequence>
+struct static_should_handle_element_dispatch
+{
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+ static const bool value = mask_el == 'F'
+ || mask_el == 'T'
+ || ( mask_el >= '0' && mask_el <= '9' );
+};
+
+template <typename First, typename Last, field F1, field F2>
+struct static_should_handle_element_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ static const bool value
+ = static_should_handle_element_dispatch
+ <
+ StaticMask,
+ F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value
+ || static_should_handle_element_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last,
+ F1, F2
+ >::value;
+};
+
+template <typename Last, field F1, field F2>
+struct static_should_handle_element_sequence<Last, Last, F1, F2>
+{
+ static const bool value = false;
+};
+
+template <typename StaticMask, field F1, field F2>
+struct static_should_handle_element_dispatch<StaticMask, F1, F2, true>
+{
+ static const bool value
+ = static_should_handle_element_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type,
+ F1, F2
+ >::value;
+};
+
+template <typename StaticMask, field F1, field F2>
+struct static_should_handle_element
+{
+ static const bool value
+ = static_should_handle_element_dispatch
+ <
+ StaticMask,
+ F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value;
+};
+
+// static_interrupt
+
+template <typename StaticMask, char V, field F1, field F2, bool InterruptEnabled, bool IsSequence>
+struct static_interrupt_dispatch
+{
+ static const bool value = false;
+};
+
+template <typename StaticMask, char V, field F1, field F2, bool IsSequence>
+struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsSequence>
+{
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+
+ static const bool value
+ = ( V >= '0' && V <= '9' ) ?
+ ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) :
+ ( ( V == 'T' ) ? mask_el == 'F' : false );
+};
+
+template <typename First, typename Last, char V, field F1, field F2>
+struct static_interrupt_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ static const bool value
+ = static_interrupt_dispatch
+ <
+ StaticMask,
+ V, F1, F2,
+ true,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value
+ && static_interrupt_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last,
+ V, F1, F2
+ >::value;
+};
+
+template <typename Last, char V, field F1, field F2>
+struct static_interrupt_sequence<Last, Last, V, F1, F2>
+{
+ static const bool value = true;
+};
+
+template <typename StaticMask, char V, field F1, field F2>
+struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, true>
+{
+ static const bool value
+ = static_interrupt_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type,
+ V, F1, F2
+ >::value;
+};
+
+template <typename StaticMask, char V, field F1, field F2, bool EnableInterrupt>
+struct static_interrupt
+{
+ static const bool value
+ = static_interrupt_dispatch
+ <
+ StaticMask,
+ V, F1, F2,
+ EnableInterrupt,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value;
+};
+
+// static_may_update
+
+template <typename StaticMask, char D, field F1, field F2, bool IsSequence>
+struct static_may_update_dispatch
+{
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+ static const int version
+ = mask_el == 'F' ? 0
+ : mask_el == 'T' ? 1
+ : mask_el >= '0' && mask_el <= '9' ? 2
+ : 3;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return apply_dispatch(matrix, integral_constant<int, version>());
+ }
+
+ // mask_el == 'F'
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const& , integral_constant<int, 0>)
+ {
+ return true;
+ }
+ // mask_el == 'T'
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 1>)
+ {
+ char const c = matrix.template get<F1, F2>();
+ return c == 'F'; // if it's T or between 0 and 9, the result will be the same
+ }
+ // mask_el >= '0' && mask_el <= '9'
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 2>)
+ {
+ char const c = matrix.template get<F1, F2>();
+ return D > c || c > '9';
+ }
+ // else
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const&, integral_constant<int, 3>)
+ {
+ return false;
+ }
+};
+
+template <typename First, typename Last, char D, field F1, field F2>
+struct static_may_update_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_may_update_dispatch
+ <
+ StaticMask,
+ D, F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix)
+ || static_may_update_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last,
+ D, F1, F2
+ >::apply(matrix);
+ }
+};
+
+template <typename Last, char D, field F1, field F2>
+struct static_may_update_sequence<Last, Last, D, F1, F2>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& /*matrix*/)
+ {
+ return false;
+ }
+};
+
+template <typename StaticMask, char D, field F1, field F2>
+struct static_may_update_dispatch<StaticMask, D, F1, F2, true>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_may_update_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type,
+ D, F1, F2
+ >::apply(matrix);
+ }
+};
+
+template <typename StaticMask, char D, field F1, field F2>
+struct static_may_update
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_may_update_dispatch
+ <
+ StaticMask,
+ D, F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix);
+ }
+};
+
+// static_check
+
+template <typename StaticMask, bool IsSequence>
+struct static_check_dispatch
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return per_one<interior, interior>::apply(matrix)
+ && per_one<interior, boundary>::apply(matrix)
+ && per_one<interior, exterior>::apply(matrix)
+ && per_one<boundary, interior>::apply(matrix)
+ && per_one<boundary, boundary>::apply(matrix)
+ && per_one<boundary, exterior>::apply(matrix)
+ && per_one<exterior, interior>::apply(matrix)
+ && per_one<exterior, boundary>::apply(matrix)
+ && per_one<exterior, exterior>::apply(matrix);
+ }
+
+ template <field F1, field F2>
+ struct per_one
+ {
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+ static const int version
+ = mask_el == 'F' ? 0
+ : mask_el == 'T' ? 1
+ : mask_el >= '0' && mask_el <= '9' ? 2
+ : 3;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ const char el = matrix.template get<F1, F2>();
+ return apply_dispatch(el, integral_constant<int, version>());
+ }
+
+ // mask_el == 'F'
+ static inline bool apply_dispatch(char el, integral_constant<int, 0>)
+ {
+ return el == 'F';
+ }
+ // mask_el == 'T'
+ static inline bool apply_dispatch(char el, integral_constant<int, 1>)
+ {
+ return el == 'T' || ( el >= '0' && el <= '9' );
+ }
+ // mask_el >= '0' && mask_el <= '9'
+ static inline bool apply_dispatch(char el, integral_constant<int, 2>)
+ {
+ return el == mask_el;
+ }
+ // else
+ static inline bool apply_dispatch(char /*el*/, integral_constant<int, 3>)
+ {
+ return true;
+ }
+ };
+};
+
+template <typename First, typename Last>
+struct static_check_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_check_dispatch
+ <
+ StaticMask,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix)
+ || static_check_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last
+ >::apply(matrix);
+ }
+};
+
+template <typename Last>
+struct static_check_sequence<Last, Last>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& /*matrix*/)
+ {
+ return false;
+ }
+};
+
+template <typename StaticMask>
+struct static_check_dispatch<StaticMask, true>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_check_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type
+ >::apply(matrix);
+ }
+};
+
+template <typename StaticMask>
+struct static_check
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_check_dispatch
+ <
+ StaticMask,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix);
+ }
+};
+
+// static_mask_handler
+
+template <typename StaticMask, bool Interrupt>
+class static_mask_handler
+ : private matrix<3>
+{
+ typedef matrix<3> base_t;
+
+public:
+ typedef bool result_type;
+
+ bool interrupt;
+
+ inline static_mask_handler(StaticMask const& /*dummy*/)
+ : interrupt(false)
+ {}
+
+ result_type result() const
+ {
+ return (!Interrupt || !interrupt)
+ && static_check<StaticMask>::
+ apply(static_cast<base_t const&>(*this));
+ }
+
+ template <field F1, field F2, char D>
+ inline bool may_update() const
+ {
+ return static_may_update<StaticMask, D, F1, F2>::
+ apply(static_cast<base_t const&>(*this));
+ }
+
+ template <field F1, field F2>
+ static inline bool expects()
+ {
+ return static_should_handle_element<StaticMask, F1, F2>::value;
+ }
+
+ //template <field F1, field F2>
+ //inline char get() const
+ //{
+ // return base_t::template get<F1, F2>();
+ //}
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
+ static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
+ static const int version = interrupt_c ? 0
+ : should_handle ? 1
+ : 2;
+
+ set_dispatch<F1, F2, V>(integral_constant<int, version>());
+ }
+
+ template <field F1, field F2, char V>
+ inline void update()
+ {
+ static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
+ static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
+ static const int version = interrupt_c ? 0
+ : should_handle ? 1
+ : 2;
+
+ update_dispatch<F1, F2, V>(integral_constant<int, version>());
+ }
+
+private:
+ // Interrupt && interrupt
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<int, 0>)
+ {
+ interrupt = true;
+ }
+ // else should_handle
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<int, 1>)
+ {
+ base_t::template set<F1, F2, V>();
+ }
+ // else
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<int, 2>)
+ {}
+
+ // Interrupt && interrupt
+ template <field F1, field F2, char V>
+ inline void update_dispatch(integral_constant<int, 0>)
+ {
+ interrupt = true;
+ }
+ // else should_handle
+ template <field F1, field F2, char V>
+ inline void update_dispatch(integral_constant<int, 1>)
+ {
+ base_t::template update<F1, F2, V>();
+ }
+ // else
+ template <field F1, field F2, char V>
+ inline void update_dispatch(integral_constant<int, 2>)
+ {}
+};
+
+// OPERATORS
+
+template <typename Mask1, typename Mask2> inline
+boost::tuples::cons<
+ Mask1,
+ boost::tuples::cons<Mask2, boost::tuples::null_type>
+>
+operator||(Mask1 const& m1, Mask2 const& m2)
+{
+ namespace bt = boost::tuples;
+
+ return
+ bt::cons< Mask1, bt::cons<Mask2, bt::null_type> >
+ ( m1, bt::cons<Mask2, bt::null_type>(m2, bt::null_type()) );
+}
+
+template <typename Head, typename Tail, typename Mask> inline
+typename index::detail::tuples::push_back<
+ boost::tuples::cons<Head, Tail>, Mask
+>::type
+operator||(boost::tuples::cons<Head, Tail> const& t, Mask const& m)
+{
+ namespace bt = boost::tuples;
+
+ return
+ index::detail::tuples::push_back<
+ bt::cons<Head, Tail>, Mask
+ >::apply(t, m);
+}
+
+// PREDEFINED MASKS
+
+// TODO:
+// 1. specialize for simplified masks if available
+// e.g. for TOUCHES use 1 mask for A/A
+// 2. Think about dimensions > 2 e.g. should TOUCHES be true
+// if the interior of the Areal overlaps the boundary of the Volumetric
+// like it's true for Linear/Areal
+
+// EQUALS
+template <typename Geometry1, typename Geometry2>
+struct static_mask_equals_type
+{
+ typedef static_mask<'T', '*', 'F', '*', '*', 'F', 'F', 'F', '*'> type; // wikipedia
+ //typedef static_mask<'T', 'F', 'F', 'F', 'T', 'F', 'F', 'F', 'T'> type; // OGC
+};
+
+// DISJOINT
+typedef static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> static_mask_disjoint;
+
+// TOUCHES - NOT P/P
+template <typename Geometry1,
+ typename Geometry2,
+ std::size_t Dim1 = topological_dimension<Geometry1>::value,
+ std::size_t Dim2 = topological_dimension<Geometry2>::value>
+struct static_mask_touches_impl
+{
+ typedef boost::mpl::vector<
+ static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>,
+ static_mask<'F', '*', '*', 'T', '*', '*', '*', '*', '*'>,
+ static_mask<'F', '*', '*', '*', 'T', '*', '*', '*', '*'>
+ > type;
+};
+// According to OGC, doesn't apply to P/P
+// Using the above mask the result would be always false
+template <typename Geometry1, typename Geometry2>
+struct static_mask_touches_impl<Geometry1, Geometry2, 0, 0>
+ : not_implemented<typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type>
+{};
+
+template <typename Geometry1, typename Geometry2>
+struct static_mask_touches_type
+ : static_mask_touches_impl<Geometry1, Geometry2>
+{};
+
+// WITHIN
+typedef static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> static_mask_within;
+
+// COVERED_BY (non OGC)
+typedef boost::mpl::vector<
+ static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>,
+ static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>,
+ static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>,
+ static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'>
+ > static_mask_covered_by;
+
+// CROSSES
+// dim(G1) < dim(G2) - P/L P/A L/A
+template <typename Geometry1,
+ typename Geometry2,
+ std::size_t Dim1 = topological_dimension<Geometry1>::value,
+ std::size_t Dim2 = topological_dimension<Geometry2>::value,
+ bool D1LessD2 = (Dim1 < Dim2)
+>
+struct static_mask_crosses_impl
+{
+ typedef static_mask<'T', '*', 'T', '*', '*', '*', '*', '*', '*'> type;
+};
+// TODO: I'm not sure if this one below should be available!
+// dim(G1) > dim(G2) - L/P A/P A/L
+template <typename Geometry1, typename Geometry2,
+ std::size_t Dim1, std::size_t Dim2
+>
+struct static_mask_crosses_impl<Geometry1, Geometry2, Dim1, Dim2, false>
+{
+ typedef static_mask<'T', '*', '*', '*', '*', '*', 'T', '*', '*'> type;
+};
+// dim(G1) == dim(G2) - P/P A/A
+template <typename Geometry1, typename Geometry2,
+ std::size_t Dim
+>
+struct static_mask_crosses_impl<Geometry1, Geometry2, Dim, Dim, false>
+ : not_implemented<typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type>
+{};
+// dim(G1) == 1 && dim(G2) == 1 - L/L
+template <typename Geometry1, typename Geometry2>
+struct static_mask_crosses_impl<Geometry1, Geometry2, 1, 1, false>
+{
+ typedef static_mask<'0', '*', '*', '*', '*', '*', '*', '*', '*'> type;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct static_mask_crosses_type
+ : static_mask_crosses_impl<Geometry1, Geometry2>
+{};
+
+// OVERLAPS
+
+// dim(G1) != dim(G2) - NOT P/P, L/L, A/A
+template <typename Geometry1,
+ typename Geometry2,
+ std::size_t Dim1 = topological_dimension<Geometry1>::value,
+ std::size_t Dim2 = topological_dimension<Geometry2>::value
+>
+struct static_mask_overlaps_impl
+ : not_implemented<typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type>
+{};
+// dim(G1) == D && dim(G2) == D - P/P A/A
+template <typename Geometry1, typename Geometry2, std::size_t Dim>
+struct static_mask_overlaps_impl<Geometry1, Geometry2, Dim, Dim>
+{
+ typedef static_mask<'T', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
+};
+// dim(G1) == 1 && dim(G2) == 1 - L/L
+template <typename Geometry1, typename Geometry2>
+struct static_mask_overlaps_impl<Geometry1, Geometry2, 1, 1>
+{
+ typedef static_mask<'1', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct static_mask_overlaps_type
+ : static_mask_overlaps_impl<Geometry1, Geometry2>
+{};
+
+// RESULTS/HANDLERS UTILS
+
+template <field F1, field F2, char V, typename Result>
+inline void set(Result & res)
+{
+ res.template set<F1, F2, V>();
+}
+
+template <field F1, field F2, char V, bool Transpose>
+struct set_dispatch
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ res.template set<F1, F2, V>();
+ }
+};
+
+template <field F1, field F2, char V>
+struct set_dispatch<F1, F2, V, true>
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ res.template set<F2, F1, V>();
+ }
+};
+
+template <field F1, field F2, char V, bool Transpose, typename Result>
+inline void set(Result & res)
+{
+ set_dispatch<F1, F2, V, Transpose>::apply(res);
+}
+
+template <char V, typename Result>
+inline void set(Result & res)
+{
+ res.template set<interior, interior, V>();
+ res.template set<interior, boundary, V>();
+ res.template set<interior, exterior, V>();
+ res.template set<boundary, interior, V>();
+ res.template set<boundary, boundary, V>();
+ res.template set<boundary, exterior, V>();
+ res.template set<exterior, interior, V>();
+ res.template set<exterior, boundary, V>();
+ res.template set<exterior, exterior, V>();
+}
+
+template <char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE, typename Result>
+inline void set(Result & res)
+{
+ res.template set<interior, interior, II>();
+ res.template set<interior, boundary, IB>();
+ res.template set<interior, exterior, IE>();
+ res.template set<boundary, interior, BI>();
+ res.template set<boundary, boundary, BB>();
+ res.template set<boundary, exterior, BE>();
+ res.template set<exterior, interior, EI>();
+ res.template set<exterior, boundary, EB>();
+ res.template set<exterior, exterior, EE>();
+}
+
+template <field F1, field F2, char D, typename Result>
+inline void update(Result & res)
+{
+ res.template update<F1, F2, D>();
+}
+
+template <field F1, field F2, char D, bool Transpose>
+struct update_result_dispatch
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ update<F1, F2, D>(res);
+ }
+};
+
+template <field F1, field F2, char D>
+struct update_result_dispatch<F1, F2, D, true>
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ update<F2, F1, D>(res);
+ }
+};
+
+template <field F1, field F2, char D, bool Transpose, typename Result>
+inline void update(Result & res)
+{
+ update_result_dispatch<F1, F2, D, Transpose>::apply(res);
+}
+
+template <field F1, field F2, char D, typename Result>
+inline bool may_update(Result const& res)
+{
+ return res.template may_update<F1, F2, D>();
+}
+
+template <field F1, field F2, char D, bool Transpose>
+struct may_update_result_dispatch
+{
+ template <typename Result>
+ static inline bool apply(Result const& res)
+ {
+ return may_update<F1, F2, D>(res);
+ }
+};
+
+template <field F1, field F2, char D>
+struct may_update_result_dispatch<F1, F2, D, true>
+{
+ template <typename Result>
+ static inline bool apply(Result const& res)
+ {
+ return may_update<F2, F1, D>(res);
+ }
+};
+
+template <field F1, field F2, char D, bool Transpose, typename Result>
+inline bool may_update(Result const& res)
+{
+ return may_update_result_dispatch<F1, F2, D, Transpose>::apply(res);
+}
+
+template <typename Result, char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE>
+inline Result return_result()
+{
+ Result res;
+ set<II, IB, IE, BI, BB, BE, EI, EB, EE>(res);
+ return res;
+}
+
+template <typename Geometry>
+struct result_dimension
+{
+ BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0);
+ static const char value
+ = ( geometry::dimension<Geometry>::value <= 9 ) ?
+ ( '0' + geometry::dimension<Geometry>::value ) :
+ 'T';
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp
new file mode 100644
index 0000000000..98b857a488
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp
@@ -0,0 +1,241 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/policies/compare.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// TODO: change the name for e.g. something with the word "exterior"
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+struct topology_check
+ : not_implemented<Tag>
+{};
+
+//template <typename Point>
+//struct topology_check<Point, point_tag>
+//{
+// static const char interior = '0';
+// static const char boundary = 'F';
+//
+// static const bool has_interior = true;
+// static const bool has_boundary = false;
+//
+// topology_check(Point const&) {}
+// template <typename IgnoreBoundaryPoint>
+// topology_check(Point const&, IgnoreBoundaryPoint const&) {}
+//};
+
+template <typename Linestring>
+struct topology_check<Linestring, linestring_tag>
+{
+ static const char interior = '1';
+ static const char boundary = '0';
+
+ bool has_interior;
+ bool has_boundary;
+
+ topology_check(Linestring const& ls)
+ {
+ init(ls, 0); /*dummy param*/
+ }
+
+ template <typename IgnoreBoundaryPoint>
+ topology_check(Linestring const& ls, IgnoreBoundaryPoint const& ibp)
+ {
+ init(ls, ibp); /*dummy param, won't be used*/
+ }
+
+ // Even if some point is on the boundary, if the Linestring has the boundary,
+ // there will be second boundary point different than IgnoreBoundaryPoint
+ template <typename IgnoreBoundaryPoint>
+ void init(Linestring const& ls, IgnoreBoundaryPoint const&)
+ {
+ std::size_t count = boost::size(ls);
+ has_interior = count > 0;
+ // NOTE: Linestring with all points equal is treated as 1d linear ring
+ has_boundary = count > 1
+ && ! detail::equals::equals_point_point(range::front(ls), range::back(ls));
+ }
+};
+
+template <typename MultiLinestring>
+struct topology_check<MultiLinestring, multi_linestring_tag>
+{
+ static const char interior = '1';
+ static const char boundary = '0';
+
+ bool has_interior;
+ bool has_boundary;
+
+ topology_check(MultiLinestring const& mls)
+ {
+ init(mls, not_ignoring_counter());
+ }
+
+ template <typename IgnoreBoundaryPoint>
+ topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp)
+ {
+ init(mls, ignoring_counter<IgnoreBoundaryPoint>(ibp));
+ }
+
+ template <typename OddCounter>
+ void init(MultiLinestring const& mls, OddCounter const& odd_counter)
+ {
+ typedef typename geometry::point_type<MultiLinestring>::type point_type;
+ std::vector<point_type> endpoints;
+ endpoints.reserve(boost::size(mls) * 2);
+
+ typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
+ for ( ls_iterator it = boost::begin(mls) ; it != boost::end(mls) ; ++it )
+ {
+ std::size_t count = boost::size(*it);
+
+ if ( count > 0 )
+ {
+ has_interior = true;
+ }
+
+ if ( count > 1 )
+ {
+ // don't store boundaries of linear rings, this doesn't change anything
+ if ( ! equals::equals_point_point(range::front(*it), range::back(*it)) )
+ {
+ endpoints.push_back(range::front(*it));
+ endpoints.push_back(range::back(*it));
+ }
+ }
+ }
+
+ has_boundary = false;
+
+ if ( !endpoints.empty() )
+ {
+ std::sort(endpoints.begin(), endpoints.end(), geometry::less<point_type>());
+ has_boundary = odd_counter(endpoints.begin(), endpoints.end());
+ }
+ }
+
+ struct not_ignoring_counter
+ {
+ template <typename It>
+ bool operator()(It first, It last) const
+ {
+ return find_odd_count(first, last);
+ }
+ };
+
+ template <typename Point>
+ struct ignoring_counter
+ {
+ ignoring_counter(Point const& pt) : m_pt(pt) {}
+
+ template <typename It>
+ bool operator()(It first, It last) const
+ {
+ typedef typename std::iterator_traits<It>::value_type point_type;
+
+ std::pair<It, It> ignore_range
+ = std::equal_range(first, last, m_pt,
+ geometry::less<point_type>());
+
+ if ( find_odd_count(first, ignore_range.first) )
+ return true;
+
+ return find_odd_count(ignore_range.second, last);
+ }
+
+ Point const& m_pt;
+ };
+
+ template <typename It>
+ static inline bool find_odd_count(It first, It last)
+ {
+ if ( first == last )
+ return false;
+
+ std::size_t count = 1;
+ It prev = first;
+ ++first;
+ for ( ; first != last ; ++first, ++prev )
+ {
+ // the end of the equal points subrange
+ if ( ! equals::equals_point_point(*first, *prev) )
+ {
+ if ( count % 2 != 0 )
+ return true;
+
+ count = 1;
+ }
+ else
+ {
+ ++count;
+ }
+ }
+
+ return count % 2 != 0;
+ }
+};
+
+template <typename Ring>
+struct topology_check<Ring, ring_tag>
+{
+ static const char interior = '2';
+ static const char boundary = '1';
+ static const bool has_interior = true;
+ static const bool has_boundary = true;
+
+ topology_check(Ring const&) {}
+ template <typename P>
+ topology_check(Ring const&, P const&) {}
+};
+
+template <typename Polygon>
+struct topology_check<Polygon, polygon_tag>
+{
+ static const char interior = '2';
+ static const char boundary = '1';
+ static const bool has_interior = true;
+ static const bool has_boundary = true;
+
+ topology_check(Polygon const&) {}
+ template <typename P>
+ topology_check(Polygon const&, P const&) {}
+};
+
+template <typename MultiPolygon>
+struct topology_check<MultiPolygon, multi_polygon_tag>
+{
+ static const char interior = '2';
+ static const char boundary = '1';
+ static const bool has_interior = true;
+ static const bool has_boundary = true;
+
+ topology_check(MultiPolygon const&) {}
+ template <typename P>
+ topology_check(MultiPolygon const&, P const&) {}
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
diff --git a/boost/geometry/algorithms/detail/relate/turns.hpp b/boost/geometry/algorithms/detail/relate/turns.hpp
new file mode 100644
index 0000000000..a2e56a8882
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/turns.hpp
@@ -0,0 +1,253 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+
+#include <boost/type_traits/is_base_of.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate { namespace turns {
+
+template <bool IncludeDegenerate = false>
+struct assign_policy
+ : overlay::assign_null_policy
+{
+ static bool const include_degenerate = IncludeDegenerate;
+};
+
+// GET_TURNS
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename GetTurnPolicy
+ = detail::get_turns::get_turn_info_type<Geometry1, Geometry2, assign_policy<> > >
+struct get_turns
+{
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+
+ typedef overlay::turn_info
+ <
+ point1_type,
+ typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type,
+ typename detail::get_turns::turn_operation_type
+ <
+ Geometry1, Geometry2,
+ typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type
+ >::type
+ > turn_info;
+
+ template <typename Turns>
+ static inline void apply(Turns & turns,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ detail::get_turns::no_interrupt_policy interrupt_policy;
+
+ apply(turns, geometry1, geometry2, interrupt_policy);
+ }
+
+ template <typename Turns, typename InterruptPolicy>
+ static inline void apply(Turns & turns,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ InterruptPolicy & interrupt_policy)
+ {
+ static const bool reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value;
+ static const bool reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value;
+
+ dispatch::get_turns
+ <
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type,
+ Geometry1,
+ Geometry2,
+ reverse1,
+ reverse2,
+ GetTurnPolicy
+ >::apply(0, geometry1, 1, geometry2,
+ detail::no_rescale_policy(), turns, interrupt_policy);
+ }
+};
+
+// TURNS SORTING AND SEARCHING
+
+template <int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0>
+struct op_to_int
+{
+ template <typename SegmentRatio>
+ inline int operator()(detail::overlay::turn_operation<SegmentRatio> const& op) const
+ {
+ switch(op.operation)
+ {
+ case detail::overlay::operation_none : return N;
+ case detail::overlay::operation_union : return U;
+ case detail::overlay::operation_intersection : return I;
+ case detail::overlay::operation_blocked : return B;
+ case detail::overlay::operation_continue : return C;
+ case detail::overlay::operation_opposite : return O;
+ }
+ return -1;
+ }
+};
+
+template <std::size_t OpId, typename OpToInt>
+struct less_op_xxx_linear
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ static OpToInt op_to_int;
+ return op_to_int(left.operations[OpId]) < op_to_int(right.operations[OpId]);
+ }
+};
+
+template <std::size_t OpId>
+struct less_op_linear_linear
+ : less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> >
+{};
+
+template <std::size_t OpId>
+struct less_op_linear_areal
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic;
+ static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc;
+
+ segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
+ segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
+
+ if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index )
+ {
+ typedef typename Turn::turn_operation_type operation_type;
+ operation_type const& left_operation = left.operations[OpId];
+ operation_type const& right_operation = right.operations[OpId];
+
+ if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
+ {
+ return op_to_int_xuic(left_operation)
+ < op_to_int_xuic(right_operation);
+ }
+ else
+ {
+ return op_to_int_xiuc(left_operation)
+ < op_to_int_xiuc(right_operation);
+ }
+ }
+ else
+ {
+ //return op_to_int_xuic(left.operations[OpId]) < op_to_int_xuic(right.operations[OpId]);
+ return left_other_seg_id.multi_index < right_other_seg_id.multi_index;
+ }
+ }
+};
+
+template <std::size_t OpId>
+struct less_op_areal_linear
+ : less_op_xxx_linear< OpId, op_to_int<0,1,0,0,2,0> >
+{};
+
+template <std::size_t OpId>
+struct less_op_areal_areal
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static op_to_int<0, 1, 2, 3, 4, 0> op_to_int_uixc;
+ static op_to_int<0, 2, 1, 3, 4, 0> op_to_int_iuxc;
+
+ segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
+ segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
+
+ typedef typename Turn::turn_operation_type operation_type;
+ operation_type const& left_operation = left.operations[OpId];
+ operation_type const& right_operation = right.operations[OpId];
+
+ if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index )
+ {
+ if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
+ {
+ return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
+ }
+ else
+ {
+ if ( left_other_seg_id.ring_index == -1 )
+ {
+ if ( left_operation.operation == overlay::operation_union )
+ return false;
+ else if ( left_operation.operation == overlay::operation_intersection )
+ return true;
+ }
+ else if ( right_other_seg_id.ring_index == -1 )
+ {
+ if ( right_operation.operation == overlay::operation_union )
+ return true;
+ else if ( right_operation.operation == overlay::operation_intersection )
+ return false;
+ }
+
+ return op_to_int_iuxc(left_operation) < op_to_int_iuxc(right_operation);
+ }
+ }
+ else
+ {
+ return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
+ }
+ }
+};
+
+// sort turns by G1 - source_index == 0 by:
+// seg_id -> distance -> operation
+template <std::size_t OpId = 0,
+ typename LessOp = less_op_xxx_linear< OpId, op_to_int<> > >
+struct less
+{
+ BOOST_STATIC_ASSERT(OpId < 2);
+
+ template <typename Turn>
+ static inline bool use_fraction(Turn const& left, Turn const& right)
+ {
+ static LessOp less_op;
+
+ return left.operations[OpId].fraction < right.operations[OpId].fraction
+ || ( left.operations[OpId].fraction == right.operations[OpId].fraction
+ && less_op(left, right) );
+ }
+
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ segment_identifier const& sl = left.operations[OpId].seg_id;
+ segment_identifier const& sr = right.operations[OpId].seg_id;
+
+ return sl < sr || ( sl == sr && use_fraction(left, right) );
+ }
+};
+
+}}} // namespace detail::relate::turns
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/ring_identifier.hpp b/boost/geometry/algorithms/detail/ring_identifier.hpp
index 9209ee0304..bc3fe1fef3 100644
--- a/boost/geometry/algorithms/detail/ring_identifier.hpp
+++ b/boost/geometry/algorithms/detail/ring_identifier.hpp
@@ -10,6 +10,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP
+#if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
+#include <iostream>
+#endif
+
+
+#include <boost/geometry/algorithms/detail/signed_index_type.hpp>
+
+
namespace boost { namespace geometry
{
@@ -24,7 +32,9 @@ struct ring_identifier
, ring_index(-1)
{}
- inline ring_identifier(int src, int mul, int rin)
+ inline ring_identifier(signed_index_type src,
+ signed_index_type mul,
+ signed_index_type rin)
: source_index(src)
, multi_index(mul)
, ring_index(rin)
@@ -58,9 +68,9 @@ struct ring_identifier
#endif
- int source_index;
- int multi_index;
- int ring_index;
+ signed_index_type source_index;
+ signed_index_type multi_index;
+ signed_index_type ring_index;
};
diff --git a/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
index ad62f232bd..63feb12a71 100644
--- a/boost/geometry/algorithms/detail/sections/range_by_section.hpp
+++ b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
@@ -7,14 +7,19 @@
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
// 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)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
-
+#include <boost/assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
@@ -22,7 +27,10 @@
#include <boost/geometry/core/closure.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/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -50,7 +58,29 @@ struct full_section_polygon
{
return section.ring_id.ring_index < 0
? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[section.ring_id.ring_index];
+ : range::at(geometry::interior_rings(polygon), section.ring_id.ring_index);
+ }
+};
+
+
+template
+<
+ typename MultiGeometry,
+ typename Section,
+ typename Policy
+>
+struct full_section_multi
+{
+ static inline typename ring_return_type<MultiGeometry const>::type apply(
+ MultiGeometry const& multi, Section const& section)
+ {
+ BOOST_ASSERT
+ (
+ section.ring_id.multi_index >= 0
+ && section.ring_id.multi_index < int(boost::size(multi))
+ );
+
+ return Policy::apply(range::at(multi, section.ring_id.multi_index), section);
}
};
@@ -98,6 +128,35 @@ struct range_by_section<polygon_tag, Polygon, Section>
{};
+template <typename MultiPolygon, typename Section>
+struct range_by_section<multi_polygon_tag, MultiPolygon, Section>
+ : detail::section::full_section_multi
+ <
+ MultiPolygon,
+ Section,
+ detail::section::full_section_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ Section
+ >
+ >
+{};
+
+template <typename MultiLinestring, typename Section>
+struct range_by_section<multi_linestring_tag, MultiLinestring, Section>
+ : detail::section::full_section_multi
+ <
+ MultiLinestring,
+ Section,
+ detail::section::full_section_range
+ <
+ typename boost::range_value<MultiLinestring>::type,
+ Section
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif
diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
index a6e6837fe4..250577c0c2 100644
--- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp
+++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
@@ -3,6 +3,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,33 +15,39 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
#include <cstddef>
#include <vector>
+#include <boost/concept/requires.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.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/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/geometries/segment.hpp>
-
namespace boost { namespace geometry
{
@@ -71,6 +81,9 @@ struct section
bool duplicate;
int non_duplicate_index;
+ bool is_non_duplicate_first;
+ bool is_non_duplicate_last;
+
inline section()
: id(-1)
, begin_index(-1)
@@ -79,9 +92,11 @@ struct section
, range_count(0)
, duplicate(false)
, non_duplicate_index(-1)
+ , is_non_duplicate_first(false)
+ , is_non_duplicate_last(false)
{
assign_inverse(bounding_box);
- for (register std::size_t i = 0; i < DimensionCount; i++)
+ for (std::size_t i = 0; i < DimensionCount; i++)
{
directions[i] = 0;
}
@@ -107,14 +122,14 @@ struct sections : std::vector<section<Box, DimensionCount> >
namespace detail { namespace sectionalize
{
-template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
+template <std::size_t Dimension, std::size_t DimensionCount>
struct get_direction_loop
{
- typedef typename coordinate_type<Segment>::type coordinate_type;
-
+ template <typename Segment>
static inline void apply(Segment const& seg,
int directions[DimensionCount])
{
+ typedef typename coordinate_type<Segment>::type coordinate_type;
coordinate_type const diff =
geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg);
@@ -123,14 +138,15 @@ struct get_direction_loop
get_direction_loop
<
- Segment, Dimension + 1, DimensionCount
+ Dimension + 1, DimensionCount
>::apply(seg, directions);
}
};
-template <typename Segment, std::size_t DimensionCount>
-struct get_direction_loop<Segment, DimensionCount, DimensionCount>
+template <std::size_t DimensionCount>
+struct get_direction_loop<DimensionCount, DimensionCount>
{
+ template <typename Segment>
static inline void apply(Segment const&, int [DimensionCount])
{}
};
@@ -182,16 +198,15 @@ struct compare_loop<T, DimensionCount, DimensionCount>
};
-template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
+template <std::size_t Dimension, std::size_t DimensionCount>
struct check_duplicate_loop
{
- typedef typename coordinate_type<Segment>::type coordinate_type;
-
+ template <typename Segment>
static inline bool apply(Segment const& seg)
{
if (! geometry::math::equals
(
- geometry::get<0, Dimension>(seg),
+ geometry::get<0, Dimension>(seg),
geometry::get<1, Dimension>(seg)
)
)
@@ -201,14 +216,15 @@ struct check_duplicate_loop
return check_duplicate_loop
<
- Segment, Dimension + 1, DimensionCount
+ Dimension + 1, DimensionCount
>::apply(seg);
}
};
-template <typename Segment, std::size_t DimensionCount>
-struct check_duplicate_loop<Segment, DimensionCount, DimensionCount>
+template <std::size_t DimensionCount>
+struct check_duplicate_loop<DimensionCount, DimensionCount>
{
+ template <typename Segment>
static inline bool apply(Segment const&)
{
return true;
@@ -236,48 +252,62 @@ struct assign_loop<T, DimensionCount, DimensionCount>
/// @brief Helper class to create sections of a part of a range, on the fly
template
<
- typename Range, // Can be closeable_view
typename Point,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_part
{
- typedef model::referring_segment<Point const> segment_type;
- typedef typename boost::range_value<Sections>::type section_type;
+ template
+ <
+ typename Range, // Can be closeable_view
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Sections& sections,
+ Range const& range,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ ring_identifier ring_id,
+ std::size_t max_count)
+ {
+ boost::ignore_unused_variable_warning(robust_policy);
+ boost::ignore_unused_variable_warning(make_rescaled_boxes);
- typedef typename boost::range_iterator<Range const>::type iterator_type;
+ typedef model::referring_segment<Point const> segment_type;
+ typedef typename boost::range_value<Sections>::type section_type;
+ typedef model::segment
+ <
+ typename robust_point_type<Point, RobustPolicy>::type
+ > robust_segment_type;
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
- static inline void apply(Sections& sections, section_type& section,
- int& index, int& ndi,
- Range const& range,
- ring_identifier ring_id)
- {
- if (int(boost::size(range)) <= index)
+ if ( boost::empty(range) )
{
return;
}
- if (index == 0)
- {
- ndi = 0;
- }
+ int index = 0;
+ int ndi = 0; // non duplicate index
+ section_type section;
- iterator_type it = boost::begin(range);
- it += index;
+ bool mark_first_non_duplicated = true;
+ std::size_t last_non_duplicate_index = sections.size();
+ iterator_type it = boost::begin(range);
+
for(iterator_type previous = it++;
it != boost::end(range);
++previous, ++it, index++)
{
segment_type segment(*previous, *it);
+ robust_segment_type robust_segment;
+ geometry::recalculate(robust_segment, segment, robust_policy);
int direction_classes[DimensionCount] = {0};
get_direction_loop
<
- segment_type, 0, DimensionCount
- >::apply(segment, direction_classes);
+ 0, DimensionCount
+ >::apply(robust_segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
// Those sections might be omitted, if wished, lateron
@@ -290,8 +320,8 @@ struct sectionalize_part
// (DimensionCount might be < dimension<P>::value)
if (check_duplicate_loop
<
- segment_type, 0, geometry::dimension<Point>::type::value
- >::apply(segment)
+ 0, geometry::dimension<Point>::type::value
+ >::apply(robust_segment)
)
{
duplicate = true;
@@ -312,10 +342,15 @@ struct sectionalize_part
<
int, 0, DimensionCount
>::apply(direction_classes, section.directions)
- || section.count > MaxCount
+ || section.count > max_count
)
)
{
+ if ( !section.duplicate )
+ {
+ last_non_duplicate_index = sections.size();
+ }
+
sections.push_back(section);
section = section_type();
}
@@ -328,14 +363,21 @@ struct sectionalize_part
section.non_duplicate_index = ndi;
section.range_count = boost::size(range);
+ if ( mark_first_non_duplicated && !duplicate )
+ {
+ section.is_non_duplicate_first = true;
+ mark_first_non_duplicated = false;
+ }
+
copy_loop
<
int, 0, DimensionCount
>::apply(direction_classes, section.directions);
- geometry::expand(section.bounding_box, *previous);
+
+ expand_box(*previous, robust_policy, section);
}
- geometry::expand(section.bounding_box, *it);
+ expand_box(*it, robust_policy, section);
section.end_index = index + 1;
section.count++;
if (! duplicate)
@@ -343,20 +385,58 @@ struct sectionalize_part
ndi++;
}
}
+
+ // Add last section if applicable
+ if (section.count > 0)
+ {
+ if ( !section.duplicate )
+ {
+ last_non_duplicate_index = sections.size();
+ }
+
+ sections.push_back(section);
+ }
+
+ if ( last_non_duplicate_index < sections.size()
+ && !sections[last_non_duplicate_index].duplicate )
+ {
+ sections[last_non_duplicate_index].is_non_duplicate_last = true;
+ }
+ }
+
+ template <typename InputPoint, typename RobustPolicy, typename Section>
+ static inline void expand_box(InputPoint const& point,
+ RobustPolicy const& robust_policy,
+ Section& section)
+ {
+ typename geometry::point_type<typename Section::box_type>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ geometry::expand(section.bounding_box, robust_point);
}
};
template
<
- typename Range, closure_selector Closure, bool Reverse,
+ closure_selector Closure, bool Reverse,
typename Point,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_range
{
+ template
+ <
+ typename Range,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Range const& range,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections,
+ ring_identifier ring_id,
+ std::size_t max_count)
+ {
typedef typename closeable_view<Range const, Closure>::type cview_type;
typedef typename reversible_view
<
@@ -364,11 +444,6 @@ struct sectionalize_range
Reverse ? iterate_reverse : iterate_forward
>::type view_type;
- static inline void apply(Range const& range, Sections& sections,
- ring_identifier ring_id)
- {
- typedef model::referring_segment<Point const> segment_type;
-
cview_type cview(range);
view_type view(cview);
@@ -385,72 +460,69 @@ struct sectionalize_range
return;
}
- int index = 0;
- int ndi = 0; // non duplicate index
-
- typedef typename boost::range_value<Sections>::type section_type;
- section_type section;
-
- sectionalize_part
- <
- view_type, Point, Sections,
- DimensionCount, MaxCount
- >::apply(sections, section, index, ndi,
- view, ring_id);
-
- // Add last section if applicable
- if (section.count > 0)
- {
- sections.push_back(section);
- }
+ sectionalize_part<Point, DimensionCount>
+ ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count);
}
};
template
<
- typename Polygon,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_polygon
{
- static inline void apply(Polygon const& poly, Sections& sections,
- ring_identifier ring_id)
+ template
+ <
+ typename Polygon,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Polygon const& poly,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections,
+ ring_identifier ring_id, std::size_t max_count)
{
typedef typename point_type<Polygon>::type point_type;
- typedef typename ring_type<Polygon>::type ring_type;
+ //typedef typename ring_type<Polygon>::type ring_type;
typedef sectionalize_range
<
- ring_type, closure<Polygon>::value, Reverse,
- point_type, Sections, DimensionCount, MaxCount
- > sectionalizer_type;
+ closure<Polygon>::value, Reverse,
+ point_type, DimensionCount
+ > per_range;
ring_id.ring_index = -1;
- sectionalizer_type::apply(exterior_ring(poly), sections, ring_id);//-1, multi_index);
+ per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
ring_id.ring_index++;
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
- ++it, ++ring_id.ring_index)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
{
- sectionalizer_type::apply(*it, sections, ring_id);
+ per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
}
}
};
template
<
- typename Box,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_box
{
- static inline void apply(Box const& box, Sections& sections, ring_identifier const& ring_id)
+ template
+ <
+ typename Box,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Box const& box,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections,
+ ring_identifier const& ring_id, std::size_t max_count)
{
typedef typename point_type<Box>::type point_type;
@@ -462,7 +534,7 @@ struct sectionalize_box
// (or polygon would be a helper-type).
// Therefore we mimic a linestring/std::vector of 5 points
- // TODO: might be replaced by assign_box_corners_oriented
+ // TODO: might be replaced by assign_box_corners_oriented
// or just "convert"
point_type ll, lr, ul, ur;
geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
@@ -476,12 +548,36 @@ struct sectionalize_box
sectionalize_range
<
- std::vector<point_type>, closed, false,
+ closed, false,
point_type,
- Sections,
- DimensionCount,
- MaxCount
- >::apply(points, sections, ring_id);
+ DimensionCount
+ >::apply(points, robust_policy, make_rescaled_boxes, sections,
+ ring_id, max_count);
+ }
+};
+
+template <std::size_t DimensionCount, typename Policy>
+struct sectionalize_multi
+{
+ template
+ <
+ typename MultiGeometry,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(MultiGeometry const& multi,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections, ring_identifier ring_id, std::size_t max_count)
+ {
+ ring_id.multi_index = 0;
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, ++ring_id.multi_index)
+ {
+ Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
+ }
}
};
@@ -498,6 +594,29 @@ inline void set_section_unique_ids(Sections& sections)
}
}
+template <typename Sections>
+inline void enlarge_sections(Sections& sections)
+{
+ // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border)
+ // Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1")
+ // Drawback: not really, range is now completely inside the section. Section is a tiny bit too large,
+ // which might cause (a small number) of more comparisons
+ // TODO: make dimension-agnostic
+ for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
+ it != boost::end(sections);
+ ++it)
+ {
+ typedef typename boost::range_value<Sections>::type section_type;
+ typedef typename section_type::box_type box_type;
+ typedef typename geometry::coordinate_type<box_type>::type coordinate_type;
+ coordinate_type const reps = math::relaxed_epsilon(10.0);
+ geometry::set<0, 0>(it->bounding_box, geometry::get<0, 0>(it->bounding_box) - reps);
+ geometry::set<0, 1>(it->bounding_box, geometry::get<0, 1>(it->bounding_box) - reps);
+ geometry::set<1, 0>(it->bounding_box, geometry::get<1, 0>(it->bounding_box) + reps);
+ geometry::set<1, 1>(it->bounding_box, geometry::get<1, 1>(it->bounding_box) + reps);
+ }
+}
+
}} // namespace detail::sectionalize
#endif // DOXYGEN_NO_DETAIL
@@ -512,9 +631,7 @@ template
typename Tag,
typename Geometry,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize
{
@@ -529,43 +646,29 @@ template
<
typename Box,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
-struct sectionalize<box_tag, Box, Reverse, Sections, DimensionCount, MaxCount>
- : detail::sectionalize::sectionalize_box
- <
- Box,
- Sections,
- DimensionCount,
- MaxCount
- >
+struct sectionalize<box_tag, Box, Reverse, DimensionCount>
+ : detail::sectionalize::sectionalize_box<DimensionCount>
{};
template
<
typename LineString,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize
<
linestring_tag,
LineString,
false,
- Sections,
- DimensionCount,
- MaxCount
+ DimensionCount
>
: detail::sectionalize::sectionalize_range
<
- LineString, closed, false,
+ closed, false,
typename point_type<LineString>::type,
- Sections,
- DimensionCount,
- MaxCount
+ DimensionCount
>
{};
@@ -573,18 +676,14 @@ template
<
typename Ring,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
-struct sectionalize<ring_tag, Ring, Reverse, Sections, DimensionCount, MaxCount>
+struct sectionalize<ring_tag, Ring, Reverse, DimensionCount>
: detail::sectionalize::sectionalize_range
<
- Ring, geometry::closure<Ring>::value, Reverse,
+ geometry::closure<Ring>::value, Reverse,
typename point_type<Ring>::type,
- Sections,
- DimensionCount,
- MaxCount
+ DimensionCount
>
{};
@@ -592,17 +691,54 @@ template
<
typename Polygon,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
-struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, MaxCount>
+struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount>
: detail::sectionalize::sectionalize_polygon
<
- Polygon, Reverse, Sections, DimensionCount, MaxCount
+ Reverse, DimensionCount
>
{};
+template
+<
+ typename MultiPolygon,
+ bool Reverse,
+ std::size_t DimensionCount
+>
+struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionCount>
+ : detail::sectionalize::sectionalize_multi
+ <
+ DimensionCount,
+ detail::sectionalize::sectionalize_polygon
+ <
+ Reverse,
+ DimensionCount
+ >
+ >
+
+{};
+
+template
+<
+ typename MultiLinestring,
+ bool Reverse,
+ std::size_t DimensionCount
+>
+struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCount>
+ : detail::sectionalize::sectionalize_multi
+ <
+ DimensionCount,
+ detail::sectionalize::sectionalize_range
+ <
+ closed, false,
+ typename point_type<MultiLinestring>::type,
+ DimensionCount
+ >
+ >
+
+{};
+
} // namespace dispatch
#endif
@@ -613,33 +749,55 @@ struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, Max
\tparam Geometry type of geometry to check
\tparam Sections type of sections to create
\param geometry geometry to create sections from
+ \param robust_policy policy to handle robustness issues
+ \param enlarge_secion_boxes if true, boxes are enlarged a tiny bit to be sure
+ they really contain all geometries (w.r.t. robustness)
\param sections structure with sections
\param source_index index to assign to the ring_identifiers
*/
-template<bool Reverse, typename Geometry, typename Sections>
-inline void sectionalize(Geometry const& geometry, Sections& sections, int source_index = 0)
+template<bool Reverse, typename Geometry, typename Sections, typename RobustPolicy>
+inline void sectionalize(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
+ bool enlarge_secion_boxes,
+ Sections& sections,
+ int source_index = 0)
{
concept::check<Geometry const>();
- // TODO: review use of this constant (see below) as causing problems with GCC 4.6 --mloskot
+ sections.clear();
+
+ ring_identifier ring_id;
+ ring_id.source_index = source_index;
+
// A maximum of 10 segments per section seems to give the fastest results
- //static std::size_t const max_segments_per_section = 10;
- typedef dispatch::sectionalize
+ dispatch::sectionalize
<
typename tag<Geometry>::type,
Geometry,
Reverse,
- Sections,
- Sections::value,
- 10 // TODO: max_segments_per_section
- > sectionalizer_type;
+ Sections::value
+ >::apply(geometry, robust_policy, enlarge_secion_boxes, sections, ring_id, 10);
- sections.clear();
- ring_identifier ring_id;
- ring_id.source_index = source_index;
- sectionalizer_type::apply(geometry, sections, ring_id);
detail::sectionalize::set_section_unique_ids(sections);
+ if (! enlarge_secion_boxes)
+ {
+ detail::sectionalize::enlarge_sections(sections);
+ }
+}
+
+
+#if defined(BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE)
+// Backwards compatibility
+template<bool Reverse, typename Geometry, typename Sections>
+inline void sectionalize(Geometry const& geometry,
+ Sections& sections,
+ int source_index = 0)
+{
+ return geometry::sectionalize<Reverse>(geometry, detail::no_rescale_policy(),
+ false, sections,
+ source_index);
}
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/signed_index_type.hpp b/boost/geometry/algorithms/detail/signed_index_type.hpp
new file mode 100644
index 0000000000..36dcf4de4c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/signed_index_type.hpp
@@ -0,0 +1,29 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_INDEX_TYPE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_INDEX_TYPE_HPP
+
+
+#include <cstddef>
+#include <boost/type_traits/make_signed.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+typedef boost::make_signed<std::size_t>::type signed_index_type;
+//typedef std::ptrdiff_t signed_index_type;
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_INDEX_TYPE_HPP
diff --git a/boost/geometry/algorithms/detail/single_geometry.hpp b/boost/geometry/algorithms/detail/single_geometry.hpp
new file mode 100644
index 0000000000..c65ff8bf84
--- /dev/null
+++ b/boost/geometry/algorithms/detail/single_geometry.hpp
@@ -0,0 +1,95 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP
+
+#include <boost/type_traits/is_base_of.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/util/range.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch {
+
+// Returns single geometry by Id
+// for single geometries returns the geometry itself
+template <typename Geometry,
+ bool IsMulti = boost::is_base_of
+ <
+ multi_tag,
+ typename geometry::tag<Geometry>::type
+ >::value
+>
+struct single_geometry
+{
+ typedef Geometry & return_type;
+
+ template <typename Id>
+ static inline return_type apply(Geometry & g, Id const& ) { return g; }
+};
+
+// for multi geometries returns one of the stored single geometries
+template <typename Geometry>
+struct single_geometry<Geometry, true>
+{
+ typedef typename boost::mpl::if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::range_value<Geometry>::type const&,
+ typename boost::range_value<Geometry>::type
+ >::type return_type;
+
+ template <typename Id>
+ static inline return_type apply(Geometry & g, Id const& id)
+ {
+ BOOST_ASSERT(id.multi_index >= 0);
+ return range::at(g, id.multi_index);
+ }
+};
+
+} // namespace detail_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail {
+
+template <typename Geometry>
+struct single_geometry_return_type
+{
+ typedef typename detail_dispatch::single_geometry<Geometry>::return_type type;
+};
+
+template <typename Geometry, typename Id>
+inline
+typename single_geometry_return_type<Geometry>::type
+single_geometry(Geometry & geometry, Id const& id)
+{
+ return detail_dispatch::single_geometry<Geometry>::apply(geometry, id);
+}
+
+template <typename Geometry, typename Id>
+inline
+typename single_geometry_return_type<Geometry const>::type
+single_geometry(Geometry const& geometry, Id const& id)
+{
+ return detail_dispatch::single_geometry<Geometry const>::apply(geometry, id);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/sub_range.hpp b/boost/geometry/algorithms/detail/sub_range.hpp
new file mode 100644
index 0000000000..a68f31362a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/sub_range.hpp
@@ -0,0 +1,113 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP
+
+#include <boost/geometry/util/range.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch {
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type,
+ bool IsMulti = boost::is_base_of<multi_tag, Tag>::value>
+struct sub_range : not_implemented<Tag>
+{};
+
+template <typename Geometry, typename Tag>
+struct sub_range<Geometry, Tag, false>
+{
+ typedef Geometry & return_type;
+
+ template <typename Id> static inline
+ return_type apply(Geometry & geometry, Id const&)
+ {
+ return geometry;
+ }
+};
+
+template <typename Geometry>
+struct sub_range<Geometry, polygon_tag, false>
+{
+ typedef typename geometry::ring_type<Geometry>::type & return_type;
+
+ template <typename Id> static inline
+ return_type apply(Geometry & geometry, Id const& id)
+ {
+ if ( id.ring_index < 0 )
+ {
+ return geometry::exterior_ring(geometry);
+ }
+ else
+ {
+ std::size_t ri = static_cast<std::size_t>(id.ring_index);
+ return range::at(geometry::interior_rings(geometry), ri);
+ }
+ }
+};
+
+template <typename Geometry, typename Tag>
+struct sub_range<Geometry, Tag, true>
+{
+ typedef typename boost::range_value<Geometry>::type value_type;
+ typedef typename boost::mpl::if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::add_const<value_type>::type,
+ value_type
+ >::type sub_type;
+
+ typedef detail_dispatch::sub_range<sub_type> sub_sub_range;
+
+ // TODO: shouldn't it be return_type?
+ typedef typename sub_sub_range::return_type return_type;
+
+ template <typename Id> static inline
+ return_type apply(Geometry & geometry, Id const& id)
+ {
+ BOOST_ASSERT(0 <= id.multi_index);
+ return sub_sub_range::apply(range::at(geometry, id.multi_index), id);
+ }
+};
+
+} // namespace detail_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+namespace detail {
+
+template <typename Geometry>
+struct sub_range_return_type
+{
+ typedef typename detail_dispatch::sub_range<Geometry>::return_type type;
+};
+
+// This function also works for geometry::segment_identifier
+
+template <typename Geometry, typename Id> inline
+typename sub_range_return_type<Geometry>::type
+sub_range(Geometry & geometry, Id const& id)
+{
+ return detail_dispatch::sub_range<Geometry>::apply(geometry, id);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
index 62328a0d87..21f5fe40b7 100644
--- a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
+++ b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
@@ -16,7 +16,7 @@
// BSG 2012-02-06: we use this currently only for distance.
// For other scalar results area,length,perimeter it is commented on purpose.
-// Reason is that for distance there is no other choice. distance of two
+// Reason is that for distance there is no other choice. distance of two
// empty geometries (or one empty) should NOT return any value.
// But for area it is no problem to be 0.
// Suppose: area(intersection(a,b)). We (probably) don't want a throw there...
@@ -24,6 +24,10 @@
// So decided that at least for Boost 1.49 this is commented for
// scalar results, except distance.
+#if defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW)
+#include <boost/core/ignore_unused.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -39,6 +43,8 @@ inline void throw_on_empty_input(Geometry const& geometry)
{
throw empty_input_exception();
}
+#else
+ boost::ignore_unused(geometry);
#endif
}
diff --git a/boost/geometry/algorithms/detail/turns/compare_turns.hpp b/boost/geometry/algorithms/detail/turns/compare_turns.hpp
new file mode 100644
index 0000000000..c29d5863b7
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/compare_turns.hpp
@@ -0,0 +1,113 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP
+
+#include <cstddef>
+#include <functional>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+// TURNS SORTING AND SEARCHING
+
+// sort turns by G1 - source_index == 0 by:
+// seg_id -> fraction -> other_id -> operation
+template
+<
+ typename IdLess = std::less<signed_index_type>,
+ int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0,
+ std::size_t OpId = 0
+>
+struct less_seg_fraction_other_op
+{
+ BOOST_STATIC_ASSERT(OpId < 2);
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+
+ template <typename Op>
+ static inline int order_op(Op const& op)
+ {
+ switch (op.operation)
+ {
+ case detail::overlay::operation_none : return N;
+ case detail::overlay::operation_union : return U;
+ case detail::overlay::operation_intersection : return I;
+ case detail::overlay::operation_blocked : return B;
+ case detail::overlay::operation_continue : return C;
+ case detail::overlay::operation_opposite : return O;
+ }
+ return -1;
+ }
+
+ template <typename Op>
+ static inline bool use_operation(Op const& left, Op const& right)
+ {
+ return order_op(left) < order_op(right);
+ }
+
+ template <typename Turn>
+ static inline bool use_other_id(Turn const& left, Turn const& right)
+ {
+ segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
+ segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
+
+ if ( left_other_seg_id.multi_index != right_other_seg_id.multi_index )
+ {
+ return left_other_seg_id.multi_index < right_other_seg_id.multi_index;
+ }
+ if ( left_other_seg_id.ring_index != right_other_seg_id.ring_index )
+ {
+ return left_other_seg_id.ring_index != right_other_seg_id.ring_index;
+ }
+ if ( left_other_seg_id.segment_index != right_other_seg_id.segment_index )
+ {
+ return IdLess()(left_other_seg_id.segment_index,
+ right_other_seg_id.segment_index);
+ }
+ return use_operation(left.operations[OpId], right.operations[OpId]);
+ }
+
+ template <typename Turn>
+ static inline bool use_fraction(Turn const& left, Turn const& right)
+ {
+ return left.operations[OpId].fraction < right.operations[OpId].fraction
+ || ( geometry::math::equals(left.operations[OpId].fraction, right.operations[OpId].fraction)
+ && use_other_id(left, right)
+ );
+ }
+
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ segment_identifier const& sl = left.operations[OpId].seg_id;
+ segment_identifier const& sr = right.operations[OpId].seg_id;
+
+ return sl < sr || ( sl == sr && use_fraction(left, right) );
+ }
+};
+
+
+
+
+
+}} // namespace detail::turns
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/turns/debug_turn.hpp b/boost/geometry/algorithms/detail/turns/debug_turn.hpp
new file mode 100644
index 0000000000..5c4f03277a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/debug_turn.hpp
@@ -0,0 +1,65 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP
+
+#ifdef BOOST_GEOMETRY_DEBUG_TURNS
+#include <iostream>
+#include <string>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <boost/geometry/io/wkt/write.hpp>
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#endif // BOOST_GEOMETRY_DEBUG_TURNS
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace turns
+{
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_TURNS
+template <typename Turn, typename Operation>
+inline void debug_turn(Turn const& turn, Operation op,
+ std::string const& header)
+{
+ std::cout << header
+ << " at " << op.seg_id
+ << " meth: " << method_char(turn.method)
+ << " op: " << operation_char(op.operation)
+ << " of: " << operation_char(turn.operations[0].operation)
+ << operation_char(turn.operations[1].operation)
+ << " " << geometry::wkt(turn.point)
+ << std::endl;
+
+ if (boost::contains(header, "Finished"))
+ {
+ std::cout << std::endl;
+ }
+}
+#else
+template <typename Turn, typename Operation>
+inline void debug_turn(Turn const& , Operation, const char*)
+{
+}
+#endif // BOOST_GEOMETRY_DEBUG_TURNS
+
+
+}} // namespace detail::turns
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost:geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP
diff --git a/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp b/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp
new file mode 100644
index 0000000000..17fbd65ddc
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP
+
+#include <algorithm>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+
+template <typename Turns, bool Enable>
+struct filter_continue_turns
+{
+ static inline void apply(Turns&) {}
+};
+
+
+template <typename Turns>
+class filter_continue_turns<Turns, true>
+{
+private:
+ class IsContinueTurn
+ {
+ private:
+ template <typename Operation>
+ inline bool is_continue_or_opposite(Operation const& operation) const
+ {
+ return operation == detail::overlay::operation_continue
+ || operation == detail::overlay::operation_opposite;
+ }
+
+ public:
+ template <typename Turn>
+ bool operator()(Turn const& turn) const
+ {
+ if ( turn.method != detail::overlay::method_collinear
+ && turn.method != detail::overlay::method_equal )
+ {
+ return false;
+ }
+
+ return is_continue_or_opposite(turn.operations[0].operation)
+ && is_continue_or_opposite(turn.operations[1].operation);
+ }
+ };
+
+
+public:
+ static inline void apply(Turns& turns)
+ {
+ turns.erase( std::remove_if(turns.begin(), turns.end(),
+ IsContinueTurn()),
+ turns.end()
+ );
+ }
+};
+
+
+}} // namespace detail::turns
+
+}} // namespect boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/turns/print_turns.hpp b/boost/geometry/algorithms/detail/turns/print_turns.hpp
new file mode 100644
index 0000000000..b339e11c94
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/print_turns.hpp
@@ -0,0 +1,96 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP
+
+#include <iostream>
+
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#include <boost/geometry/io/wkt/write.hpp>
+#include <boost/geometry/io/dsv/write.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+
+
+template <typename Geometry1, typename Geometry2, typename Turns>
+static inline void print_turns(Geometry1 const& g1,
+ Geometry2 const& g2,
+ Turns const& turns)
+{
+ typedef typename boost::range_value<Turns>::type turn_info;
+
+ std::cout << geometry::wkt(g1) << std::endl;
+ std::cout << geometry::wkt(g2) << std::endl;
+ int index = 0;
+ BOOST_FOREACH(turn_info const& turn, turns)
+ {
+ std::ostream& out = std::cout;
+ out << index
+ << ": " << geometry::method_char(turn.method);
+
+ if ( turn.discarded )
+ out << " (discarded)\n";
+ else if ( turn.blocked() )
+ out << " (blocked)\n";
+ else
+ out << '\n';
+
+ double fraction[2];
+
+ fraction[0] = turn.operations[0].fraction.numerator()
+ / turn.operations[0].fraction.denominator();
+
+ out << geometry::operation_char(turn.operations[0].operation)
+ <<": seg: " << turn.operations[0].seg_id.source_index
+ << ", m: " << turn.operations[0].seg_id.multi_index
+ << ", r: " << turn.operations[0].seg_id.ring_index
+ << ", s: " << turn.operations[0].seg_id.segment_index << ", ";
+ out << ", fr: " << fraction[0];
+ out << ", col?: " << turn.operations[0].is_collinear;
+ out << ' ' << geometry::dsv(turn.point) << ' ';
+
+ out << '\n';
+
+ fraction[1] = turn.operations[1].fraction.numerator()
+ / turn.operations[1].fraction.denominator();
+
+ out << geometry::operation_char(turn.operations[1].operation)
+ << ": seg: " << turn.operations[1].seg_id.source_index
+ << ", m: " << turn.operations[1].seg_id.multi_index
+ << ", r: " << turn.operations[1].seg_id.ring_index
+ << ", s: " << turn.operations[1].seg_id.segment_index << ", ";
+ out << ", fr: " << fraction[1];
+ out << ", col?: " << turn.operations[1].is_collinear;
+ out << ' ' << geometry::dsv(turn.point) << ' ';
+
+ ++index;
+ std::cout << std::endl;
+ }
+}
+
+
+
+
+}} // namespace detail::turns
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp
new file mode 100644
index 0000000000..ccb19efb73
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp
@@ -0,0 +1,62 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP
+
+#include <algorithm>
+#include <boost/geometry/algorithms/equals.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+template <typename Turns, bool Enable>
+struct remove_duplicate_turns
+{
+ static inline void apply(Turns&) {}
+};
+
+
+
+template <typename Turns>
+class remove_duplicate_turns<Turns, true>
+{
+private:
+ struct TurnEqualsTo
+ {
+ template <typename Turn>
+ bool operator()(Turn const& t1, Turn const& t2) const
+ {
+ return geometry::equals(t1.point, t2.point)
+ && t1.operations[0].seg_id == t2.operations[0].seg_id
+ && t1.operations[1].seg_id == t2.operations[1].seg_id;
+ }
+ };
+
+public:
+ static inline void apply(Turns& turns)
+ {
+ turns.erase( std::unique(turns.begin(), turns.end(),
+ TurnEqualsTo()),
+ turns.end()
+ );
+ }
+};
+
+
+
+}} // namespace detail::turns
+
+}} // namespect boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
new file mode 100644
index 0000000000..6f1c1816cb
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
@@ -0,0 +1,463 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
+
+#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/strategies/concepts/within_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/within.hpp>
+#include <boost/geometry/strategies/covered_by.hpp>
+
+#include <boost/geometry/views/detail/normalized_view.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace within {
+
+// TODO: is this needed?
+inline int check_result_type(int result)
+{
+ return result;
+}
+
+template <typename T>
+inline T check_result_type(T result)
+{
+ BOOST_ASSERT(false);
+ return result;
+}
+
+template <typename Point, typename Range, typename Strategy> inline
+int point_in_range(Point const& point, Range const& range, Strategy const& strategy)
+{
+ boost::ignore_unused_variable_warning(strategy);
+
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
+ typename Strategy::state_type state;
+ iterator_type it = boost::begin(range);
+ iterator_type end = boost::end(range);
+
+ for ( iterator_type previous = it++ ; it != end ; ++previous, ++it )
+ {
+ if ( ! strategy.apply(point, *previous, *it, state) )
+ {
+ break;
+ }
+ }
+
+ return check_result_type(strategy.result(state));
+}
+
+template <typename Geometry, typename Point, typename Range>
+inline int point_in_range(Point const& point, Range const& range)
+{
+ typedef typename point_type<Point>::type point_type1;
+ typedef typename point_type<Geometry>::type point_type2;
+
+ typedef typename strategy::within::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type;
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type2;
+
+ static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
+ BOOST_MPL_ASSERT_MSG((same_strategies),
+ DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
+ (strategy_type, strategy_type2));
+
+ return point_in_range(point, range, strategy_type());
+}
+
+}} // namespace detail::within
+
+namespace detail_dispatch { namespace within {
+
+// checks the relation between a point P and geometry G
+// returns 1 if P is in the interior of G
+// returns 0 if P is on the boundry of G
+// returns -1 if P is in the exterior of G
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+struct point_in_geometry
+ : not_implemented<Tag>
+{};
+
+template <typename Point2>
+struct point_in_geometry<Point2, point_tag>
+{
+ template <typename Point1, typename Strategy> static inline
+ int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
+ {
+ boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(point1, point2) ? 1 : -1;
+ }
+};
+
+template <typename Segment>
+struct point_in_geometry<Segment, segment_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Segment const& segment, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Segment>::type point_type;
+ point_type p0, p1;
+// TODO: don't copy points
+ detail::assign_point_from_index<0>(segment, p0);
+ detail::assign_point_from_index<1>(segment, p1);
+
+ typename Strategy::state_type state;
+ strategy.apply(point, p0, p1, state);
+ int r = detail::within::check_result_type(strategy.result(state));
+
+ if ( r != 0 )
+ return -1; // exterior
+
+ // if the point is equal to the one of the terminal points
+ if ( detail::equals::equals_point_point(point, p0)
+ || detail::equals::equals_point_point(point, p1) )
+ return 0; // boundary
+ else
+ return 1; // interior
+ }
+};
+
+
+template <typename Linestring>
+struct point_in_geometry<Linestring, linestring_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Linestring const& linestring, Strategy const& strategy)
+ {
+ std::size_t count = boost::size(linestring);
+ if ( count > 1 )
+ {
+ if ( detail::within::point_in_range(point, linestring, strategy) != 0 )
+ return -1; // exterior
+
+ // if the linestring doesn't have a boundary
+ if ( detail::equals::equals_point_point(*boost::begin(linestring), *(--boost::end(linestring))) )
+ return 1; // interior
+ // else if the point is equal to the one of the terminal points
+ else if ( detail::equals::equals_point_point(point, *boost::begin(linestring))
+ || detail::equals::equals_point_point(point, *(--boost::end(linestring))) )
+ return 0; // boundary
+ else
+ return 1; // interior
+ }
+// TODO: for now degenerated linestrings are ignored
+// throw an exception here?
+ /*else if ( count == 1 )
+ {
+ if ( detail::equals::equals_point_point(point, *boost::begin(linestring)) )
+ return 1;
+ }*/
+
+ return -1; // exterior
+ }
+};
+
+template <typename Ring>
+struct point_in_geometry<Ring, ring_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Ring const& ring, Strategy const& strategy)
+ {
+ if ( boost::size(ring) < core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Ring>::value
+ >::value )
+ {
+ return -1;
+ }
+
+ detail::normalized_view<Ring const> view(ring);
+ return detail::within::point_in_range(point, view, strategy);
+ }
+};
+
+// Polygon: in exterior ring, and if so, not within interior ring(s)
+template <typename Polygon>
+struct point_in_geometry<Polygon, polygon_tag>
+{
+ template <typename Point, typename Strategy>
+ static inline int apply(Point const& point, Polygon const& polygon,
+ Strategy const& strategy)
+ {
+ int const code = point_in_geometry
+ <
+ typename ring_type<Polygon>::type
+ >::apply(point, exterior_ring(polygon), strategy);
+
+ if (code == 1)
+ {
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings);
+ it != boost::end(rings);
+ ++it)
+ {
+ int const interior_code = point_in_geometry
+ <
+ typename ring_type<Polygon>::type
+ >::apply(point, *it, strategy);
+
+ if (interior_code != -1)
+ {
+ // 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 code;
+ }
+};
+
+template <typename Geometry>
+struct point_in_geometry<Geometry, multi_point_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ typedef typename boost::range_value<Geometry>::type point_type;
+ typedef typename boost::range_const_iterator<Geometry>::type iterator;
+ for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
+ {
+ int pip = point_in_geometry<point_type>::apply(point, *it, strategy);
+
+ //BOOST_ASSERT(pip != 0);
+ if ( pip > 0 ) // inside
+ return 1;
+ }
+
+ return -1; // outside
+ }
+};
+
+template <typename Geometry>
+struct point_in_geometry<Geometry, multi_linestring_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ int pip = -1; // outside
+
+ typedef typename boost::range_value<Geometry>::type linestring_type;
+ typedef typename boost::range_value<linestring_type>::type point_type;
+ typedef typename boost::range_iterator<Geometry const>::type iterator;
+ iterator it = boost::begin(geometry);
+ for ( ; it != boost::end(geometry) ; ++it )
+ {
+ pip = point_in_geometry<linestring_type>::apply(point, *it, strategy);
+
+ // inside or on the boundary
+ if ( pip >= 0 )
+ {
+ ++it;
+ break;
+ }
+ }
+
+ // outside
+ if ( pip < 0 )
+ return -1;
+
+ // TODO: the following isn't needed for covered_by()
+
+ unsigned boundaries = pip == 0 ? 1 : 0;
+
+ for ( ; it != boost::end(geometry) ; ++it )
+ {
+ if ( boost::size(*it) < 2 )
+ continue;
+
+ point_type const& front = *boost::begin(*it);
+ point_type const& back = *(--boost::end(*it));
+
+ // is closed_ring - no boundary
+ if ( detail::equals::equals_point_point(front, back) )
+ continue;
+
+ // is point on boundary
+ if ( detail::equals::equals_point_point(point, front)
+ || detail::equals::equals_point_point(point, back) )
+ {
+ ++boundaries;
+ }
+ }
+
+ // if the number of boundaries is odd, the point is on the boundary
+ return boundaries % 2 ? 0 : 1;
+ }
+};
+
+template <typename Geometry>
+struct point_in_geometry<Geometry, multi_polygon_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ // For invalid multipolygons
+ //int res = -1; // outside
+
+ typedef typename boost::range_value<Geometry>::type polygon_type;
+ typedef typename boost::range_const_iterator<Geometry>::type iterator;
+ for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
+ {
+ int pip = point_in_geometry<polygon_type>::apply(point, *it, strategy);
+
+ // inside or on the boundary
+ if ( pip >= 0 )
+ return pip;
+
+ // For invalid multi-polygons
+ //if ( 1 == pip ) // inside polygon
+ // return 1;
+ //else if ( res < pip ) // point must be inside at least one polygon
+ // res = pip;
+ }
+
+ return -1; // for valid multipolygons
+ //return res; // for invalid multipolygons
+ }
+};
+
+}} // namespace detail_dispatch::within
+
+namespace detail { namespace within {
+
+// 1 - in the interior
+// 0 - in the boundry
+// -1 - in the exterior
+template <typename Point, typename Geometry, typename Strategy>
+inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy)
+{
+ concept::within::check
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ Strategy
+ >();
+
+ return detail_dispatch::within::point_in_geometry<Geometry>::apply(point, geometry, strategy);
+}
+
+template <typename Point, typename Geometry>
+inline int point_in_geometry(Point const& point, Geometry const& geometry)
+{
+ typedef typename point_type<Point>::type point_type1;
+ typedef typename point_type<Geometry>::type point_type2;
+
+ typedef typename strategy::within::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type;
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type2;
+
+ static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
+ BOOST_MPL_ASSERT_MSG((same_strategies),
+ DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
+ (strategy_type, strategy_type2));
+
+ return point_in_geometry(point, geometry, strategy_type());
+}
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/within/within_no_turns.hpp b/boost/geometry/algorithms/detail/within/within_no_turns.hpp
new file mode 100644
index 0000000000..8da05e58fd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/within_no_turns.hpp
@@ -0,0 +1,221 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP
+
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail_dispatch { namespace within {
+
+// returns true if G1 is within G2
+// this function should be called only if there are no intersection points
+// otherwise it may return invalid result
+// e.g. when non-first point of G1 is outside G2 or when some rings of G1 are the same as rings of G2
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type>
+struct within_no_turns
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, geometry1) )
+ return false;
+
+ return detail::within::point_in_geometry(p, geometry2, strategy) >= 0;
+ }
+};
+
+template <typename Geometry1, typename Geometry2>
+struct within_no_turns<Geometry1, Geometry2, ring_tag, polygon_tag>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, geometry1) )
+ return false;
+ // check if one of ring points is outside the polygon
+ if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 )
+ return false;
+ // Now check if holes of G2 aren't inside G1
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type<Geometry2>::type
+ >::type iterator;
+ for ( iterator it = boost::begin(geometry::interior_rings(geometry2)) ;
+ it != boost::end(geometry::interior_rings(geometry2)) ;
+ ++it )
+ {
+ point2_type p;
+ if ( !geometry::point_on_border(p, *it) )
+ return false;
+ if ( detail::within::point_in_geometry(p, geometry1, strategy) > 0 )
+ return false;
+ }
+ return true;
+ }
+};
+
+template <typename Geometry1, typename Geometry2>
+struct within_no_turns<Geometry1, Geometry2, polygon_tag, polygon_tag>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, geometry1) )
+ return false;
+ // check if one of ring points is outside the polygon
+ if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 )
+ return false;
+ // Now check if holes of G2 aren't inside G1
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type<Geometry2>::type
+ >::type iterator2;
+ for ( iterator2 it = boost::begin(geometry::interior_rings(geometry2)) ;
+ it != boost::end(geometry::interior_rings(geometry2)) ;
+ ++it )
+ {
+ point2_type p2;
+ if ( !geometry::point_on_border(p2, *it) )
+ return false;
+ // if the hole of G2 is inside G1
+ if ( detail::within::point_in_geometry(p2, geometry1, strategy) > 0 )
+ {
+ // if it's also inside one of the G1 holes, it's ok
+ bool ok = false;
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type<Geometry1>::type
+ >::type iterator1;
+ for ( iterator1 it1 = boost::begin(geometry::interior_rings(geometry1)) ;
+ it1 != boost::end(geometry::interior_rings(geometry1)) ;
+ ++it1 )
+ {
+ if ( detail::within::point_in_geometry(p2, *it1, strategy) < 0 )
+ {
+ ok = true;
+ break;
+ }
+ }
+ if ( !ok )
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type,
+ bool IsMulti1 = boost::is_base_of<geometry::multi_tag, Tag1>::value,
+ bool IsMulti2 = boost::is_base_of<geometry::multi_tag, Tag2>::value>
+struct within_no_turns_multi
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ return within_no_turns<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, false>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // All values of G1 must be inside G2
+ typedef typename boost::range_value<Geometry1>::type subgeometry1;
+ typedef typename boost::range_const_iterator<Geometry1>::type iterator;
+ for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it )
+ {
+ if ( !within_no_turns<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) )
+ return false;
+ }
+ return true;
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, false, true>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // G1 must be within at least one value of G2
+ typedef typename boost::range_value<Geometry2>::type subgeometry2;
+ typedef typename boost::range_const_iterator<Geometry2>::type iterator;
+ for ( iterator it = boost::begin(geometry2) ; it != boost::end(geometry2) ; ++it )
+ {
+ if ( within_no_turns<Geometry1, subgeometry2>::apply(geometry1, *it, strategy) )
+ return true;
+ }
+ return false;
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, true>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // each value of G1 must be inside at least one value of G2
+ typedef typename boost::range_value<Geometry1>::type subgeometry1;
+ typedef typename boost::range_const_iterator<Geometry1>::type iterator;
+ for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it )
+ {
+ if ( !within_no_turns_multi<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) )
+ return false;
+ }
+ return true;
+ }
+};
+
+}} // namespace detail_dispatch::within
+
+namespace detail { namespace within {
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool within_no_turns(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+{
+ return detail_dispatch::within::within_no_turns_multi<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+}
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP
diff --git a/boost/geometry/algorithms/difference.hpp b/boost/geometry/algorithms/difference.hpp
index 480dd928de..780436f015 100644
--- a/boost/geometry/algorithms/difference.hpp
+++ b/boost/geometry/algorithms/difference.hpp
@@ -12,6 +12,7 @@
#include <algorithm>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
namespace boost { namespace geometry
{
@@ -43,33 +44,28 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
-
+
return geometry::dispatch::intersection_insert
<
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
Geometry1, Geometry2,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
+ GeometryOut,
overlay_difference,
- Strategy
- >::apply(geometry1, geometry2, out, strategy);
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value
+ >::apply(geometry1, geometry2, robust_policy, out, strategy);
}
/*!
@@ -93,10 +89,13 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out)
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
@@ -107,11 +106,12 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1,
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ RobustPolicy
> strategy;
return difference_insert<GeometryOut>(geometry1, geometry2,
- out, strategy());
+ robust_policy, out, strategy());
}
@@ -148,8 +148,17 @@ inline void difference(Geometry1 const& geometry1,
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
detail::difference::difference_insert<geometry_out>(
- geometry1, geometry2,
+ geometry1, geometry2, robust_policy,
std::back_inserter(output_collection));
}
diff --git a/boost/geometry/algorithms/disjoint.hpp b/boost/geometry/algorithms/disjoint.hpp
index f986cc24af..f997487c71 100644
--- a/boost/geometry/algorithms/disjoint.hpp
+++ b/boost/geometry/algorithms/disjoint.hpp
@@ -1,8 +1,15 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,288 +21,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP
-#include <cstddef>
-#include <deque>
-
-#include <boost/mpl/if.hpp>
-#include <boost/range.hpp>
-
-#include <boost/static_assert.hpp>
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
-#include <boost/geometry/algorithms/detail/for_each_range.hpp>
-#include <boost/geometry/algorithms/detail/point_on_border.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
-#include <boost/geometry/algorithms/within.hpp>
-
-#include <boost/geometry/geometries/concepts/check.hpp>
-
-#include <boost/geometry/util/math.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace disjoint
-{
-
-template<typename Geometry>
-struct check_each_ring_for_within
-{
- bool has_within;
- Geometry const& m_geometry;
-
- inline check_each_ring_for_within(Geometry const& g)
- : has_within(false)
- , m_geometry(g)
- {}
-
- template <typename Range>
- inline void apply(Range const& range)
- {
- typename geometry::point_type<Range>::type p;
- geometry::point_on_border(p, range);
- if (geometry::within(p, m_geometry))
- {
- has_within = true;
- }
- }
-};
-
-template <typename FirstGeometry, typename SecondGeometry>
-inline bool rings_containing(FirstGeometry const& geometry1,
- SecondGeometry const& geometry2)
-{
- check_each_ring_for_within<FirstGeometry> checker(geometry1);
- geometry::detail::for_each_range(geometry2, checker);
- return checker.has_within;
-}
-
-
-struct assign_disjoint_policy
-{
- // We want to include all points:
- static bool const include_no_turn = true;
- static bool const include_degenerate = true;
- static bool const include_opposite = true;
-
- // We don't assign extra info:
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
- static inline void apply(Info& , Point1 const& , Point2 const&,
- IntersectionInfo const&, DirInfo const&)
- {}
-};
-
-
-template <typename Geometry1, typename Geometry2>
-struct disjoint_linear
-{
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
- {
- typedef typename geometry::point_type<Geometry1>::type point_type;
-
- typedef overlay::turn_info<point_type> turn_info;
- std::deque<turn_info> turns;
-
- // Specify two policies:
- // 1) Stop at any intersection
- // 2) In assignment, include also degenerate points (which are normally skipped)
- disjoint_interrupt_policy policy;
- geometry::get_turns
- <
- false, false,
- assign_disjoint_policy
- >(geometry1, geometry2, turns, policy);
- if (policy.has_intersections)
- {
- return false;
- }
-
- return true;
- }
-};
-
-template <typename Segment1, typename Segment2>
-struct disjoint_segment
-{
- static inline bool apply(Segment1 const& segment1, Segment2 const& segment2)
- {
- typedef typename point_type<Segment1>::type point_type;
-
- segment_intersection_points<point_type> is
- = strategy::intersection::relate_cartesian_segments
- <
- policies::relate::segments_intersection_points
- <
- Segment1,
- Segment2,
- segment_intersection_points<point_type>
- >
- >::apply(segment1, segment2);
-
- return is.count == 0;
- }
-};
-
-template <typename Geometry1, typename Geometry2>
-struct general_areal
-{
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
- {
- if (! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2))
- {
- return false;
- }
-
- // If there is no intersection of segments, they might located
- // inside each other
- if (rings_containing(geometry1, geometry2)
- || rings_containing(geometry2, geometry1))
- {
- return false;
- }
-
- return true;
- }
-};
-
-
-}} // namespace detail::disjoint
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename GeometryTag1, typename GeometryTag2,
- typename Geometry1, typename Geometry2,
- std::size_t DimensionCount
->
-struct disjoint
- : detail::disjoint::general_areal<Geometry1, Geometry2>
-{};
-
-
-template <typename Point1, typename Point2, std::size_t DimensionCount>
-struct disjoint<point_tag, point_tag, Point1, Point2, DimensionCount>
- : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount>
-{};
-
-
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct disjoint<box_tag, box_tag, Box1, Box2, DimensionCount>
- : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount>
-{};
-
-
-template <typename Point, typename Box, std::size_t DimensionCount>
-struct disjoint<point_tag, box_tag, Point, Box, DimensionCount>
- : detail::disjoint::point_box<Point, Box, 0, DimensionCount>
-{};
-
-template <typename Linestring1, typename Linestring2>
-struct disjoint<linestring_tag, linestring_tag, Linestring1, Linestring2, 2>
- : detail::disjoint::disjoint_linear<Linestring1, Linestring2>
-{};
-
-template <typename Linestring1, typename Linestring2>
-struct disjoint<segment_tag, segment_tag, Linestring1, Linestring2, 2>
- : detail::disjoint::disjoint_segment<Linestring1, Linestring2>
-{};
-
-template <typename Linestring, typename Segment>
-struct disjoint<linestring_tag, segment_tag, Linestring, Segment, 2>
- : detail::disjoint::disjoint_linear<Linestring, Segment>
-{};
-
-
-template
-<
- typename GeometryTag1, typename GeometryTag2,
- typename Geometry1, typename Geometry2,
- std::size_t DimensionCount
->
-struct disjoint_reversed
-{
- static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
- {
- return disjoint
- <
- GeometryTag2, GeometryTag1,
- Geometry2, Geometry1,
- DimensionCount
- >::apply(g2, g1);
- }
-};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-
-/*!
-\brief \brief_check2{are disjoint}
-\ingroup disjoint
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_check2{are disjoint}
-
-\qbk{[include reference/algorithms/disjoint.qbk]}
-*/
-template <typename Geometry1, typename Geometry2>
-inline bool disjoint(Geometry1 const& geometry1,
- Geometry2 const& geometry2)
-{
- concept::check_concepts_and_equal_dimensions
- <
- Geometry1 const,
- Geometry2 const
- >();
-
- return boost::mpl::if_c
- <
- reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::disjoint_reversed
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >,
- dispatch::disjoint
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >
- >::type::apply(geometry1, geometry2);
-}
-
-
-}} // namespace boost::geometry
-
+#include <boost/geometry/algorithms/detail/disjoint/interface.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP
diff --git a/boost/geometry/algorithms/dispatch/disjoint.hpp b/boost/geometry/algorithms/dispatch/disjoint.hpp
new file mode 100644
index 0000000000..627bcff83c
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/disjoint.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISPATCH_DISJOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ std::size_t DimensionCount = dimension<Geometry1>::type::value,
+ typename Tag1 = typename tag_cast
+ <
+ typename tag<Geometry1>::type,
+ segment_tag, box_tag, linear_tag, areal_tag
+ >::type,
+ typename Tag2 = typename tag_cast
+ <
+ typename tag<Geometry2>::type,
+ segment_tag, box_tag, linear_tag, areal_tag
+ >::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct disjoint
+ : not_implemented<Geometry1, Geometry2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP
diff --git a/boost/geometry/algorithms/dispatch/distance.hpp b/boost/geometry/algorithms/dispatch/distance.hpp
new file mode 100644
index 0000000000..cae3ebd0c9
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/distance.hpp
@@ -0,0 +1,82 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISPATCH_DISTANCE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP
+
+
+#include <boost/geometry/core/reverse_dispatch.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Strategy = typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type,
+ typename Tag1 = typename tag_cast
+ <
+ typename tag<Geometry1>::type,
+ segment_tag,
+ box_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ typename Tag2 = typename tag_cast
+ <
+ typename tag<Geometry2>::type,
+ segment_tag,
+ box_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ typename StrategyTag = typename strategy::distance::services::tag
+ <
+ Strategy
+ >::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct distance: not_implemented<Tag1, Tag2>
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP
diff --git a/boost/geometry/algorithms/dispatch/is_simple.hpp b/boost/geometry/algorithms/dispatch/is_simple.hpp
new file mode 100644
index 0000000000..2ac92256b3
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/is_simple.hpp
@@ -0,0 +1,38 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
+
+#include <boost/geometry/core/tag.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct is_simple
+ : not_implemented<Geometry>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
diff --git a/boost/geometry/algorithms/dispatch/is_valid.hpp b/boost/geometry/algorithms/dispatch/is_valid.hpp
new file mode 100644
index 0000000000..266bab9181
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/is_valid.hpp
@@ -0,0 +1,46 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
+
+#include <boost/geometry/core/tag.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type,
+ // for linear geometries: determines if spikes are allowed
+ bool AllowSpikes = true,
+ // for areal geometries: determines if duplicate points are allowed
+ bool AllowDuplicates = true
+>
+struct is_valid
+ : not_implemented<Geometry>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
diff --git a/boost/geometry/algorithms/distance.hpp b/boost/geometry/algorithms/distance.hpp
index 11c2bc929b..dcfe597cd0 100644
--- a/boost/geometry/algorithms/distance.hpp
+++ b/boost/geometry/algorithms/distance.hpp
@@ -1,8 +1,14 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,578 +20,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
-
-#include <boost/mpl/if.hpp>
-#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-#include <boost/geometry/core/tag_cast.hpp>
-
-#include <boost/geometry/algorithms/not_implemented.hpp>
-#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
-
-#include <boost/geometry/geometries/segment.hpp>
-#include <boost/geometry/geometries/concepts/check.hpp>
-
-#include <boost/geometry/strategies/distance.hpp>
-#include <boost/geometry/strategies/default_distance_result.hpp>
-#include <boost/geometry/algorithms/assign.hpp>
-#include <boost/geometry/algorithms/within.hpp>
-
-#include <boost/geometry/views/closeable_view.hpp>
-#include <boost/geometry/util/math.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace distance
-{
-
-// To avoid spurious namespaces here:
-using strategy::distance::services::return_type;
-
-template <typename P1, typename P2, typename Strategy>
-struct point_to_point
-{
- static inline typename return_type<Strategy>::type apply(P1 const& p1,
- P2 const& p2, Strategy const& strategy)
- {
- return strategy.apply(p1, p2);
- }
-};
-
-
-template<typename Point, typename Segment, typename Strategy>
-struct point_to_segment
-{
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Segment const& segment, Strategy const& )
- {
- typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Segment>::type,
- typename cs_tag<Point>::type,
- typename cs_tag<typename point_type<Segment>::type>::type,
- Strategy
- >::type segment_strategy;
-
- typename point_type<Segment>::type p[2];
- geometry::detail::assign_point_from_index<0>(segment, p[0]);
- geometry::detail::assign_point_from_index<1>(segment, p[1]);
- return segment_strategy.apply(point, p[0], p[1]);
- }
-};
-
-
-template
-<
- typename Point,
- typename Range,
- closure_selector Closure,
- typename PPStrategy,
- typename PSStrategy
->
-struct point_to_range
-{
- typedef typename return_type<PSStrategy>::type return_type;
-
- static inline return_type apply(Point const& point, Range const& range,
- PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
- {
- return_type const zero = return_type(0);
-
- if (boost::size(range) == 0)
- {
- return zero;
- }
-
- typedef typename closeable_view<Range const, Closure>::type view_type;
-
- view_type view(range);
-
- // line of one point: return point distance
- typedef typename boost::range_iterator<view_type const>::type iterator_type;
- iterator_type it = boost::begin(view);
- iterator_type prev = it++;
- if (it == boost::end(view))
- {
- return pp_strategy.apply(point, *boost::begin(view));
- }
-
- // Create comparable (more efficient) strategy
- typedef typename strategy::distance::services::comparable_type<PSStrategy>::type eps_strategy_type;
- eps_strategy_type eps_strategy = strategy::distance::services::get_comparable<PSStrategy>::apply(ps_strategy);
-
- // start with first segment distance
- return_type d = eps_strategy.apply(point, *prev, *it);
- return_type rd = ps_strategy.apply(point, *prev, *it);
-
- // check if other segments are closer
- for (++prev, ++it; it != boost::end(view); ++prev, ++it)
- {
- return_type const ds = eps_strategy.apply(point, *prev, *it);
- if (geometry::math::equals(ds, zero))
- {
- return ds;
- }
- else if (ds < d)
- {
- d = ds;
- rd = ps_strategy.apply(point, *prev, *it);
- }
- }
-
- return rd;
- }
-};
-
-
-template
-<
- typename Point,
- typename Ring,
- closure_selector Closure,
- typename PPStrategy,
- typename PSStrategy
->
-struct point_to_ring
-{
- typedef std::pair
- <
- typename return_type<PPStrategy>::type, bool
- > distance_containment;
-
- static inline distance_containment apply(Point const& point,
- Ring const& ring,
- PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
- {
- return distance_containment
- (
- point_to_range
- <
- Point,
- Ring,
- Closure,
- PPStrategy,
- PSStrategy
- >::apply(point, ring, pp_strategy, ps_strategy),
- geometry::within(point, ring)
- );
- }
-};
-
-
-
-template
-<
- typename Point,
- typename Polygon,
- closure_selector Closure,
- typename PPStrategy,
- typename PSStrategy
->
-struct point_to_polygon
-{
- typedef typename return_type<PPStrategy>::type return_type;
- typedef std::pair<return_type, bool> distance_containment;
-
- static inline distance_containment apply(Point const& point,
- Polygon const& polygon,
- PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
- {
- // Check distance to all rings
- typedef point_to_ring
- <
- Point,
- typename ring_type<Polygon>::type,
- Closure,
- PPStrategy,
- PSStrategy
- > per_ring;
-
- distance_containment dc = per_ring::apply(point,
- exterior_ring(polygon), pp_strategy, ps_strategy);
-
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
- {
- distance_containment dcr = per_ring::apply(point,
- *it, pp_strategy, ps_strategy);
- if (dcr.first < dc.first)
- {
- dc.first = dcr.first;
- }
- // If it was inside, and also inside inner ring,
- // turn off the inside-flag, it is outside the polygon
- if (dc.second && dcr.second)
- {
- dc.second = false;
- }
- }
- return dc;
- }
-};
-
-
-// Helper metafunction for default strategy retrieval
-template <typename Geometry1, typename Geometry2>
-struct default_strategy
- : strategy::distance::services::default_strategy
- <
- point_tag,
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type
- >
-{};
-
-
-}} // namespace detail::distance
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-using strategy::distance::services::return_type;
-
-
-template
-<
- typename Geometry1, typename Geometry2,
- typename Strategy = typename detail::distance::default_strategy<Geometry1, Geometry2>::type,
- typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
- typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
- typename StrategyTag = typename strategy::distance::services::tag<Strategy>::type,
- bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
->
-struct distance: not_implemented<Tag1, Tag2>
-{};
-
-
-// If reversal is needed, perform it
-template
-<
- typename Geometry1, typename Geometry2, typename Strategy,
- typename Tag1, typename Tag2, typename StrategyTag
->
-struct distance
-<
- Geometry1, Geometry2, Strategy,
- Tag1, Tag2, StrategyTag,
- true
->
- : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false>
-{
- static inline typename return_type<Strategy>::type apply(
- Geometry1 const& g1,
- Geometry2 const& g2,
- Strategy const& strategy)
- {
- return distance
- <
- Geometry2, Geometry1, Strategy,
- Tag2, Tag1, StrategyTag,
- false
- >::apply(g2, g1, strategy);
- }
-};
-
-// If reversal is needed and we got the strategy by default, invert it before
-// proceeding to the reversal.
-template
-<
- typename Geometry1, typename Geometry2,
- typename Tag1, typename Tag2, typename StrategyTag
->
-struct distance
-<
- Geometry1, Geometry2,
- typename detail::distance::default_strategy<Geometry1, Geometry2>::type,
- Tag1, Tag2, StrategyTag,
- true
->
- : distance
- <
- Geometry2, Geometry1,
- typename detail::distance::default_strategy<Geometry2, Geometry1>::type,
- Tag2, Tag1, StrategyTag,
- false
- >
-{
- typedef typename detail::distance::default_strategy<Geometry2, Geometry1>::type reversed_strategy;
-
- static inline typename strategy::distance::services::return_type<reversed_strategy>::type apply(
- Geometry1 const& g1,
- Geometry2 const& g2,
- typename detail::distance::default_strategy<Geometry1, Geometry2>::type const&)
- {
- return distance
- <
- Geometry2, Geometry1, reversed_strategy,
- Tag2, Tag1, StrategyTag,
- false
- >::apply(g2, g1, reversed_strategy());
- }
-};
-
-
-// Point-point
-template <typename P1, typename P2, typename Strategy>
-struct distance
- <
- P1, P2, Strategy,
- point_tag, point_tag, strategy_tag_distance_point_point,
- false
- >
- : detail::distance::point_to_point<P1, P2, Strategy>
-{};
-
-
-// Point-line version 1, where point-point strategy is specified
-template <typename Point, typename Linestring, typename Strategy>
-struct distance
-<
- Point, Linestring, Strategy,
- point_tag, linestring_tag, strategy_tag_distance_point_point,
- false
->
-{
-
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Linestring const& linestring,
- Strategy const& strategy)
- {
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Linestring>::type
- >::type ps_strategy_type;
-
- return detail::distance::point_to_range
- <
- Point, Linestring, closed, Strategy, ps_strategy_type
- >::apply(point, linestring, strategy, ps_strategy_type());
- }
-};
-
-
-// Point-line version 2, where point-segment strategy is specified
-template <typename Point, typename Linestring, typename Strategy>
-struct distance
-<
- Point, Linestring, Strategy,
- point_tag, linestring_tag, strategy_tag_distance_point_segment,
- false
->
-{
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Linestring const& linestring,
- Strategy const& strategy)
- {
- typedef typename Strategy::point_strategy_type pp_strategy_type;
- return detail::distance::point_to_range
- <
- Point, Linestring, closed, pp_strategy_type, Strategy
- >::apply(point, linestring, pp_strategy_type(), strategy);
- }
-};
-
-// Point-ring , where point-segment strategy is specified
-template <typename Point, typename Ring, typename Strategy>
-struct distance
-<
- Point, Ring, Strategy,
- point_tag, ring_tag, strategy_tag_distance_point_point,
- false
->
-{
- typedef typename return_type<Strategy>::type return_type;
-
- static inline return_type apply(Point const& point,
- Ring const& ring,
- Strategy const& strategy)
- {
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Ring>::type
- >::type ps_strategy_type;
-
- std::pair<return_type, bool>
- dc = detail::distance::point_to_ring
- <
- Point, Ring,
- geometry::closure<Ring>::value,
- Strategy, ps_strategy_type
- >::apply(point, ring, strategy, ps_strategy_type());
-
- return dc.second ? return_type(0) : dc.first;
- }
-};
-
-
-// Point-polygon , where point-segment strategy is specified
-template <typename Point, typename Polygon, typename Strategy>
-struct distance
-<
- Point, Polygon, Strategy,
- point_tag, polygon_tag, strategy_tag_distance_point_point,
- false
->
-{
- typedef typename return_type<Strategy>::type return_type;
-
- static inline return_type apply(Point const& point,
- Polygon const& polygon,
- Strategy const& strategy)
- {
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Polygon>::type
- >::type ps_strategy_type;
-
- std::pair<return_type, bool>
- dc = detail::distance::point_to_polygon
- <
- Point, Polygon,
- geometry::closure<Polygon>::value,
- Strategy, ps_strategy_type
- >::apply(point, polygon, strategy, ps_strategy_type());
-
- return dc.second ? return_type(0) : dc.first;
- }
-};
-
-
-
-// Point-segment version 1, with point-point strategy
-template <typename Point, typename Segment, typename Strategy>
-struct distance
-<
- Point, Segment, Strategy,
- point_tag, segment_tag, strategy_tag_distance_point_point,
- false
-> : detail::distance::point_to_segment<Point, Segment, Strategy>
-{};
-
-// Point-segment version 2, with point-segment strategy
-template <typename Point, typename Segment, typename Strategy>
-struct distance
-<
- Point, Segment, Strategy,
- point_tag, segment_tag, strategy_tag_distance_point_segment,
- false
->
-{
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Segment const& segment, Strategy const& strategy)
- {
-
- typename point_type<Segment>::type p[2];
- geometry::detail::assign_point_from_index<0>(segment, p[0]);
- geometry::detail::assign_point_from_index<1>(segment, p[1]);
- return strategy.apply(point, p[0], p[1]);
- }
-};
-
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-/*!
-\brief \brief_calc2{distance} \brief_strategy
-\ingroup distance
-\details
-\details \details_calc{area}. \brief_strategy. \details_strategy_reasons
-
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam Strategy \tparam_strategy{Distance}
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param strategy \param_strategy{distance}
-\return \return_calc{distance}
-\note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
- it may also be a point-segment strategy.
-
-\qbk{distinguish,with strategy}
-
-\qbk{
-[heading Available Strategies]
-\* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
-\* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
-\* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
-\* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
-\* more (currently extensions): Vincenty\, Andoyer (geographic)
-}
- */
-
-/*
-Note, in case of a Compilation Error:
-if you get:
- - "Failed to specialize function template ..."
- - "error: no matching function for call to ..."
-for distance, it is probably so that there is no specialization
-for return_type<...> for your strategy.
-*/
-template <typename Geometry1, typename Geometry2, typename Strategy>
-inline typename strategy::distance::services::return_type<Strategy>::type distance(
- Geometry1 const& geometry1, Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- detail::throw_on_empty_input(geometry1);
- detail::throw_on_empty_input(geometry2);
-
- return dispatch::distance
- <
- Geometry1,
- Geometry2,
- Strategy
- >::apply(geometry1, geometry2, strategy);
-}
-
-
-/*!
-\brief \brief_calc2{distance}
-\ingroup distance
-\details The default strategy is used, corresponding to the coordinate system of the geometries
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_calc{distance}
-
-\qbk{[include reference/algorithms/distance.qbk]}
- */
-template <typename Geometry1, typename Geometry2>
-inline typename default_distance_result<Geometry1, Geometry2>::type distance(
- Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- return distance(geometry1, geometry2,
- typename detail::distance::default_strategy<Geometry1, Geometry2>::type());
-}
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/detail/distance/interface.hpp>
+#include <boost/geometry/algorithms/detail/distance/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
diff --git a/boost/geometry/algorithms/envelope.hpp b/boost/geometry/algorithms/envelope.hpp
index da34f6a783..e06ed71e81 100644
--- a/boost/geometry/algorithms/envelope.hpp
+++ b/boost/geometry/algorithms/envelope.hpp
@@ -14,15 +14,22 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP
-#include <boost/mpl/assert.hpp>
-#include <boost/range.hpp>
+#include <vector>
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -35,9 +42,9 @@ namespace detail { namespace envelope
/// Calculate envelope of an 2D or 3D segment
-template<typename Geometry, typename Box>
struct envelope_expand_one
{
+ template<typename Geometry, typename Box>
static inline void apply(Geometry const& geometry, Box& mbr)
{
assign_inverse(mbr);
@@ -63,10 +70,10 @@ inline void envelope_range_additional(Range const& range, Box& mbr)
/// Generic range dispatching struct
-template <typename Range, typename Box>
struct envelope_range
{
/// Calculate envelope of range using a strategy
+ template <typename Range, typename Box>
static inline void apply(Range const& range, Box& mbr)
{
assign_inverse(mbr);
@@ -74,6 +81,42 @@ struct envelope_range
}
};
+
+struct envelope_multi_linestring
+{
+ template<typename MultiLinestring, typename Box>
+ static inline void apply(MultiLinestring const& mp, Box& mbr)
+ {
+ assign_inverse(mbr);
+ for (typename boost::range_iterator<MultiLinestring const>::type
+ it = mp.begin();
+ it != mp.end();
+ ++it)
+ {
+ envelope_range_additional(*it, mbr);
+ }
+ }
+};
+
+
+// version for multi_polygon: outer ring's of all polygons
+struct envelope_multi_polygon
+{
+ template<typename MultiPolygon, typename Box>
+ static inline void apply(MultiPolygon const& mp, Box& mbr)
+ {
+ assign_inverse(mbr);
+ for (typename boost::range_const_iterator<MultiPolygon>::type
+ it = mp.begin();
+ it != mp.end();
+ ++it)
+ {
+ envelope_range_additional(exterior_ring(*it), mbr);
+ }
+ }
+};
+
+
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
@@ -82,131 +125,125 @@ namespace dispatch
{
-// Note, the strategy is for future use (less/greater -> compare spherical
-// using other methods), defaults are OK for now.
-// However, they are already in the template methods
-
template
<
- typename Tag1, typename Tag2,
- typename Geometry, typename Box,
- typename StrategyLess, typename StrategyGreater
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
>
-struct envelope
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
-};
+struct envelope: not_implemented<Tag>
+{};
-template
-<
- typename Point, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- point_tag, box_tag,
- Point, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_expand_one<Point, Box>
+template <typename Point>
+struct envelope<Point, point_tag>
+ : detail::envelope::envelope_expand_one
{};
-template
-<
- typename BoxIn, typename BoxOut,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- box_tag, box_tag,
- BoxIn, BoxOut,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_expand_one<BoxIn, BoxOut>
+template <typename Box>
+struct envelope<Box, box_tag>
+ : detail::envelope::envelope_expand_one
{};
-template
-<
- typename Segment, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- segment_tag, box_tag,
- Segment, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_expand_one<Segment, Box>
+template <typename Segment>
+struct envelope<Segment, segment_tag>
+ : detail::envelope::envelope_expand_one
{};
-template
-<
- typename Linestring, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- linestring_tag, box_tag,
- Linestring, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_range<Linestring, Box>
+template <typename Linestring>
+struct envelope<Linestring, linestring_tag>
+ : detail::envelope::envelope_range
{};
-template
-<
- typename Ring, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- ring_tag, box_tag,
- Ring, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_range<Ring, Box>
+template <typename Ring>
+struct envelope<Ring, ring_tag>
+ : detail::envelope::envelope_range
{};
-template
-<
- typename Polygon, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- polygon_tag, box_tag,
- Polygon, Box,
- StrategyLess, StrategyGreater
- >
+template <typename Polygon>
+struct envelope<Polygon, polygon_tag>
+ : detail::envelope::envelope_range
{
+ template <typename Box>
static inline void apply(Polygon const& poly, Box& mbr)
{
// For polygon, inspecting outer ring is sufficient
-
- detail::envelope::envelope_range
- <
- typename ring_type<Polygon>::type,
- Box
- >::apply(exterior_ring(poly), mbr);
+ detail::envelope::envelope_range::apply(exterior_ring(poly), mbr);
}
};
+template <typename Multi>
+struct envelope<Multi, multi_point_tag>
+ : detail::envelope::envelope_range
+{};
+
+
+template <typename Multi>
+struct envelope<Multi, multi_linestring_tag>
+ : detail::envelope::envelope_multi_linestring
+{};
+
+
+template <typename Multi>
+struct envelope<Multi, multi_polygon_tag>
+ : detail::envelope::envelope_multi_polygon
+{};
+
+
} // namespace dispatch
#endif
+namespace resolve_variant {
+
+template <typename Geometry>
+struct envelope
+{
+ template <typename Box>
+ static inline void apply(Geometry const& geometry, Box& box)
+ {
+ concept::check<Geometry const>();
+ concept::check<Box>();
+
+ dispatch::envelope<Geometry>::apply(geometry, box);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Box>
+ struct visitor: boost::static_visitor<void>
+ {
+ Box& m_box;
+
+ visitor(Box& box): m_box(box) {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ envelope<Geometry>::apply(geometry, m_box);
+ }
+ };
+
+ template <typename Box>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Box& box)
+ {
+ boost::apply_visitor(visitor<Box>(box), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{envelope}
\ingroup envelope
@@ -225,15 +262,7 @@ struct envelope
template<typename Geometry, typename Box>
inline void envelope(Geometry const& geometry, Box& mbr)
{
- concept::check<Geometry const>();
- concept::check<Box>();
-
- dispatch::envelope
- <
- typename tag<Geometry>::type, typename tag<Box>::type,
- Geometry, Box,
- void, void
- >::apply(geometry, mbr);
+ resolve_variant::envelope<Geometry>::apply(geometry, mbr);
}
@@ -255,16 +284,8 @@ inline void envelope(Geometry const& geometry, Box& mbr)
template<typename Box, typename Geometry>
inline Box return_envelope(Geometry const& geometry)
{
- concept::check<Geometry const>();
- concept::check<Box>();
-
Box mbr;
- dispatch::envelope
- <
- typename tag<Geometry>::type, typename tag<Box>::type,
- Geometry, Box,
- void, void
- >::apply(geometry, mbr);
+ resolve_variant::envelope<Geometry>::apply(geometry, mbr);
return mbr;
}
diff --git a/boost/geometry/algorithms/equals.hpp b/boost/geometry/algorithms/equals.hpp
index 6b094f76d0..c6b718da1b 100644
--- a/boost/geometry/algorithms/equals.hpp
+++ b/boost/geometry/algorithms/equals.hpp
@@ -3,6 +3,12 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,18 +24,19 @@
#include <cstddef>
#include <vector>
-#include <boost/mpl/if.hpp>
-#include <boost/static_assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/geometry_id.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/not.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
// For trivial checks
#include <boost/geometry/algorithms/area.hpp>
@@ -39,7 +46,12 @@
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate.hpp>
+#include <boost/geometry/views/detail/indexed_point_view.hpp>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
namespace boost { namespace geometry
{
@@ -51,13 +63,12 @@ namespace detail { namespace equals
template
<
- typename Box1,
- typename Box2,
std::size_t Dimension,
std::size_t DimensionCount
>
struct box_box
{
+ template <typename Box1, typename Box2>
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
@@ -65,13 +76,14 @@ struct box_box
{
return false;
}
- return box_box<Box1, Box2, Dimension + 1, DimensionCount>::apply(box1, box2);
+ return box_box<Dimension + 1, DimensionCount>::apply(box1, box2);
}
};
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct box_box<Box1, Box2, DimensionCount, DimensionCount>
+template <std::size_t DimensionCount>
+struct box_box<DimensionCount, DimensionCount>
{
+ template <typename Box1, typename Box2>
static inline bool apply(Box1 const& , Box2 const& )
{
return true;
@@ -79,6 +91,28 @@ struct box_box<Box1, Box2, DimensionCount, DimensionCount>
};
+struct segment_segment
+{
+ template <typename Segment1, typename Segment2>
+ static inline bool apply(Segment1 const& segment1, Segment2 const& segment2)
+ {
+ return equals::equals_point_point(
+ indexed_point_view<Segment1 const, 0>(segment1),
+ indexed_point_view<Segment2 const, 0>(segment2) )
+ ? equals::equals_point_point(
+ indexed_point_view<Segment1 const, 1>(segment1),
+ indexed_point_view<Segment2 const, 1>(segment2) )
+ : ( equals::equals_point_point(
+ indexed_point_view<Segment1 const, 0>(segment1),
+ indexed_point_view<Segment2 const, 1>(segment2) )
+ && equals::equals_point_point(
+ indexed_point_view<Segment1 const, 1>(segment1),
+ indexed_point_view<Segment2 const, 0>(segment2) )
+ );
+ }
+};
+
+
struct area_check
{
template <typename Geometry1, typename Geometry2>
@@ -103,9 +137,10 @@ struct length_check
};
-template <typename Geometry1, typename Geometry2, typename TrivialCheck>
+template <typename TrivialCheck>
struct equals_by_collection
{
+ template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
if (! TrivialCheck::apply(geometry1, geometry2))
@@ -141,6 +176,15 @@ struct equals_by_collection
}
};
+template<typename Geometry1, typename Geometry2>
+struct equals_by_relate
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_equals_type,
+ Geometry1,
+ Geometry2
+ >
+{};
}} // namespace detail::equals
#endif // DOXYGEN_NO_DETAIL
@@ -152,17 +196,42 @@ namespace dispatch
template
<
- typename Tag1, typename Tag2,
typename Geometry1,
typename Geometry2,
- std::size_t DimensionCount
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type,
+ std::size_t DimensionCount = dimension<Geometry1>::type::value,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
>
-struct equals
+struct equals: not_implemented<Tag1, Tag2>
{};
-template <typename P1, typename P2, std::size_t DimensionCount>
-struct equals<point_tag, point_tag, P1, P2, DimensionCount>
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2,
+ std::size_t DimensionCount
+>
+struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true>
+ : equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false>
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ return equals
+ <
+ Geometry2, Geometry1,
+ Tag2, Tag1,
+ DimensionCount,
+ false
+ >::apply(g2, g1);
+ }
+};
+
+
+template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
+struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
: geometry::detail::not_
<
P1,
@@ -172,104 +241,208 @@ struct equals<point_tag, point_tag, P1, P2, DimensionCount>
{};
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct equals<box_tag, box_tag, Box1, Box2, DimensionCount>
- : detail::equals::box_box<Box1, Box2, 0, DimensionCount>
+template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
+struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse>
+ : detail::equals::box_box<0, DimensionCount>
{};
-template <typename Ring1, typename Ring2>
-struct equals<ring_tag, ring_tag, Ring1, Ring2, 2>
- : detail::equals::equals_by_collection
- <
- Ring1, Ring2,
- detail::equals::area_check
- >
+template <typename Ring1, typename Ring2, bool Reverse>
+struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
{};
-template <typename Polygon1, typename Polygon2>
-struct equals<polygon_tag, polygon_tag, Polygon1, Polygon2, 2>
- : detail::equals::equals_by_collection
- <
- Polygon1, Polygon2,
- detail::equals::area_check
- >
+template <typename Polygon1, typename Polygon2, bool Reverse>
+struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
{};
-template <typename LineString1, typename LineString2>
-struct equals<linestring_tag, linestring_tag, LineString1, LineString2, 2>
- : detail::equals::equals_by_collection
- <
- LineString1, LineString2,
- detail::equals::length_check
- >
+template <typename Polygon, typename Ring, bool Reverse>
+struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
{};
-template <typename Polygon, typename Ring>
-struct equals<polygon_tag, ring_tag, Polygon, Ring, 2>
- : detail::equals::equals_by_collection
- <
- Polygon, Ring,
- detail::equals::area_check
- >
+template <typename Ring, typename Box, bool Reverse>
+struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
{};
-template <typename Ring, typename Box>
-struct equals<ring_tag, box_tag, Ring, Box, 2>
- : detail::equals::equals_by_collection
- <
- Ring, Box,
- detail::equals::area_check
- >
+template <typename Polygon, typename Box, bool Reverse>
+struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
{};
+template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse>
+struct equals<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, Reverse>
+ : detail::equals::segment_segment
+{};
-template <typename Polygon, typename Box>
-struct equals<polygon_tag, box_tag, Polygon, Box, 2>
- : detail::equals::equals_by_collection
- <
- Polygon, Box,
- detail::equals::area_check
- >
+template <typename LineString1, typename LineString2, bool Reverse>
+struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse>
+ //: detail::equals::equals_by_collection<detail::equals::length_check>
+ : detail::equals::equals_by_relate<LineString1, LineString2>
{};
+template <typename LineString, typename MultiLineString, bool Reverse>
+struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<LineString, MultiLineString>
+{};
-template
-<
- typename Tag1, typename Tag2,
- typename Geometry1,
- typename Geometry2,
- std::size_t DimensionCount
->
-struct equals_reversed
+template <typename MultiLineString1, typename MultiLineString2, bool Reverse>
+struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<MultiLineString1, MultiLineString2>
+{};
+
+
+template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse>
+struct equals
+ <
+ MultiPolygon1, MultiPolygon2,
+ multi_polygon_tag, multi_polygon_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection<detail::equals::area_check>
+{};
+
+
+template <typename Polygon, typename MultiPolygon, bool Reverse>
+struct equals
+ <
+ Polygon, MultiPolygon,
+ polygon_tag, multi_polygon_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection<detail::equals::area_check>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct equals
{
- static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
{
- return equals
- <
- Tag2, Tag1,
- Geometry2, Geometry1,
- DimensionCount
- >::apply(g2, g1);
+ concept::check_concepts_and_equal_dimensions
+ <
+ Geometry1 const,
+ Geometry2 const
+ >();
+
+ return dispatch::equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
}
};
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2)
+ : m_geometry2(geometry2)
+ {}
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+ template <typename Geometry1>
+ inline bool operator()(Geometry1 const& geometry1) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, m_geometry2);
+ }
+
+ };
+
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2
+ )
+ {
+ return apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1)
+ : m_geometry1(geometry1)
+ {}
+
+ template <typename Geometry2>
+ inline bool operator()(Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(m_geometry1, geometry2);
+ }
+
+ };
+
+ static inline bool apply(
+ Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2
+ )
+ {
+ return apply_visitor(visitor(geometry1), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct equals<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ struct visitor: static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ inline bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
+ }
+
+ };
+
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2
+ )
+ {
+ return apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
/*!
\brief \brief_check{are spatially equal}
-\details \details_check12{equals, is spatially equal}. Spatially equal means
+\details \details_check12{equals, is spatially equal}. Spatially equal means
that the same point set is included. A box can therefore be spatially equal
- to a ring or a polygon, or a linestring can be spatially equal to a
- multi-linestring or a segment. This only theoretically, not all combinations
- are implemented yet.
+ to a ring or a polygon, or a linestring can be spatially equal to a
+ multi-linestring or a segment. This only works theoretically, not all
+ combinations are implemented yet.
\ingroup equals
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
@@ -283,32 +456,8 @@ struct equals_reversed
template <typename Geometry1, typename Geometry2>
inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check_concepts_and_equal_dimensions
- <
- Geometry1 const,
- Geometry2 const
- >();
-
- return boost::mpl::if_c
- <
- reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::equals_reversed
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >,
- dispatch::equals
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >
- >::type::apply(geometry1, geometry2);
+ return resolve_variant::equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
}
diff --git a/boost/geometry/algorithms/expand.hpp b/boost/geometry/algorithms/expand.hpp
index da7442b593..19e40aa2d0 100644
--- a/boost/geometry/algorithms/expand.hpp
+++ b/boost/geometry/algorithms/expand.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -19,6 +20,7 @@
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -27,6 +29,9 @@
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/policies/compare.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+
namespace boost { namespace geometry
{
@@ -38,26 +43,26 @@ namespace detail { namespace expand
template
<
- typename Box, typename Point,
typename StrategyLess, typename StrategyGreater,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_loop
{
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyLess, 1, Point, Dimension
- >::type less_type;
+ template <typename Box, typename Point>
+ static inline void apply(Box& box, Point const& source)
+ {
+ typedef typename strategy::compare::detail::select_strategy
+ <
+ StrategyLess, 1, Point, Dimension
+ >::type less_type;
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyGreater, -1, Point, Dimension
- >::type greater_type;
+ typedef typename strategy::compare::detail::select_strategy
+ <
+ StrategyGreater, -1, Point, Dimension
+ >::type greater_type;
- typedef typename select_coordinate_type<Point, Box>::type coordinate_type;
+ typedef typename select_coordinate_type<Point, Box>::type coordinate_type;
- static inline void apply(Box& box, Point const& source)
- {
less_type less;
greater_type greater;
@@ -75,7 +80,6 @@ struct point_loop
point_loop
<
- Box, Point,
StrategyLess, StrategyGreater,
Dimension + 1, DimensionCount
>::apply(box, source);
@@ -85,49 +89,47 @@ struct point_loop
template
<
- typename Box, typename Point,
typename StrategyLess, typename StrategyGreater,
std::size_t DimensionCount
>
struct point_loop
<
- Box, Point,
StrategyLess, StrategyGreater,
DimensionCount, DimensionCount
>
{
+ template <typename Box, typename Point>
static inline void apply(Box&, Point const&) {}
};
template
<
- typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater,
std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
struct indexed_loop
{
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyLess, 1, Box, Dimension
- >::type less_type;
-
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyGreater, -1, Box, Dimension
- >::type greater_type;
+ template <typename Box, typename Geometry>
+ static inline void apply(Box& box, Geometry const& source)
+ {
+ typedef typename strategy::compare::detail::select_strategy
+ <
+ StrategyLess, 1, Box, Dimension
+ >::type less_type;
- typedef typename select_coordinate_type
+ typedef typename strategy::compare::detail::select_strategy
<
- Box,
- Geometry
- >::type coordinate_type;
+ StrategyGreater, -1, Box, Dimension
+ >::type greater_type;
+ typedef typename select_coordinate_type
+ <
+ Box,
+ Geometry
+ >::type coordinate_type;
- static inline void apply(Box& box, Geometry const& source)
- {
less_type less;
greater_type greater;
@@ -145,7 +147,6 @@ struct indexed_loop
indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
Index, Dimension + 1, DimensionCount
>::apply(box, source);
@@ -155,17 +156,16 @@ struct indexed_loop
template
<
- typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater,
std::size_t Index, std::size_t DimensionCount
>
struct indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
Index, DimensionCount, DimensionCount
>
{
+ template <typename Box, typename Geometry>
static inline void apply(Box&, Geometry const&) {}
};
@@ -174,23 +174,21 @@ struct indexed_loop
// Changes a box such that the other box is also contained by the box
template
<
- typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater
>
struct expand_indexed
{
+ template <typename Box, typename Geometry>
static inline void apply(Box& box, Geometry const& geometry)
{
indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
0, 0, dimension<Geometry>::type::value
>::apply(box, geometry);
indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
1, 0, dimension<Geometry>::type::value
>::apply(box, geometry);
@@ -206,11 +204,13 @@ namespace dispatch
template
<
- typename Tag,
- typename BoxOut, typename Geometry,
- typename StrategyLess, typename StrategyGreater
+ typename GeometryOut, typename Geometry,
+ typename StrategyLess = strategy::compare::default_strategy,
+ typename StrategyGreater = strategy::compare::default_strategy,
+ typename TagOut = typename tag<GeometryOut>::type,
+ typename Tag = typename tag<Geometry>::type
>
-struct expand
+struct expand: not_implemented<TagOut, Tag>
{};
@@ -220,10 +220,9 @@ template
typename BoxOut, typename Point,
typename StrategyLess, typename StrategyGreater
>
-struct expand<point_tag, BoxOut, Point, StrategyLess, StrategyGreater>
+struct expand<BoxOut, Point, StrategyLess, StrategyGreater, box_tag, point_tag>
: detail::expand::point_loop
<
- BoxOut, Point,
StrategyLess, StrategyGreater,
0, dimension<Point>::type::value
>
@@ -236,9 +235,8 @@ template
typename BoxOut, typename BoxIn,
typename StrategyLess, typename StrategyGreater
>
-struct expand<box_tag, BoxOut, BoxIn, StrategyLess, StrategyGreater>
- : detail::expand::expand_indexed
- <BoxOut, BoxIn, StrategyLess, StrategyGreater>
+struct expand<BoxOut, BoxIn, StrategyLess, StrategyGreater, box_tag, box_tag>
+ : detail::expand::expand_indexed<StrategyLess, StrategyGreater>
{};
template
@@ -246,9 +244,8 @@ template
typename Box, typename Segment,
typename StrategyLess, typename StrategyGreater
>
-struct expand<segment_tag, Box, Segment, StrategyLess, StrategyGreater>
- : detail::expand::expand_indexed
- <Box, Segment, StrategyLess, StrategyGreater>
+struct expand<Box, Segment, StrategyLess, StrategyGreater, box_tag, segment_tag>
+ : detail::expand::expand_indexed<StrategyLess, StrategyGreater>
{};
@@ -256,6 +253,51 @@ struct expand<segment_tag, Box, Segment, StrategyLess, StrategyGreater>
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct expand
+{
+ template <typename Box>
+ static inline void apply(Box& box, Geometry const& geometry)
+ {
+ concept::check<Box>();
+ concept::check<Geometry const>();
+ concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
+
+ dispatch::expand<Box, Geometry>::apply(box, geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct expand<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Box>
+ struct visitor: boost::static_visitor<void>
+ {
+ Box& m_box;
+
+ visitor(Box& box) : m_box(box) {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ return expand<Geometry>::apply(m_box, geometry);
+ }
+ };
+
+ template <class Box>
+ static inline void
+ apply(Box& box,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor<Box>(box), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/***
*!
\brief Expands a box using the extend (envelope) of another geometry (box, point)
@@ -279,13 +321,7 @@ inline void expand(Box& box, Geometry const& geometry,
{
concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
- dispatch::expand
- <
- typename tag<Geometry>::type,
- Box,
- Geometry,
- StrategyLess, StrategyGreater
- >::apply(box, geometry);
+ dispatch::expand<Box, Geometry>::apply(box, geometry);
}
***/
@@ -303,15 +339,7 @@ inline void expand(Box& box, Geometry const& geometry,
template <typename Box, typename Geometry>
inline void expand(Box& box, Geometry const& geometry)
{
- concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
-
- dispatch::expand
- <
- typename tag<Geometry>::type,
- Box, Geometry,
- strategy::compare::default_strategy,
- strategy::compare::default_strategy
- >::apply(box, geometry);
+ resolve_variant::expand<Geometry>::apply(box, geometry);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/for_each.hpp b/boost/geometry/algorithms/for_each.hpp
index 671f26a70d..c5c099b1ad 100644
--- a/boost/geometry/algorithms/for_each.hpp
+++ b/boost/geometry/algorithms/for_each.hpp
@@ -1,8 +1,14 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,17 +24,24 @@
#include <algorithm>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/util/add_const_if_c.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -39,127 +52,162 @@ namespace detail { namespace for_each
{
-template <typename Point, typename Functor, bool IsConst>
struct fe_point_per_point
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Point>::type& point, Functor f)
+ template <typename Point, typename Functor>
+ static inline void apply(Point& point, Functor& f)
{
f(point);
- return f;
}
};
-template <typename Point, typename Functor, bool IsConst>
struct fe_point_per_segment
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Point>::type& , Functor f)
+ template <typename Point, typename Functor>
+ static inline void apply(Point& , Functor& /*f*/)
{
// TODO: if non-const, we should extract the points from the segment
// and call the functor on those two points
- return f;
}
};
-template <typename Range, typename Functor, bool IsConst>
struct fe_range_per_point
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Range>::type& range,
- Functor f)
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
{
- return (std::for_each(boost::begin(range), boost::end(range), f));
+ // The previous implementation called the std library:
+ // return (std::for_each(boost::begin(range), boost::end(range), f));
+ // But that is not accepted for capturing lambda's.
+ // It needs to do it like that to return the state of Functor f (f is passed by value in std::for_each).
+
+ // So we now loop manually.
+
+ for (typename boost::range_iterator<Range>::type
+ it = boost::begin(range); it != boost::end(range); ++it)
+ {
+ f(*it);
+ }
}
};
-template <typename Range, typename Functor, bool IsConst>
-struct fe_range_per_segment
+template <closure_selector Closure>
+struct fe_range_per_segment_with_closure
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Range>::type& range,
- Functor f)
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
{
typedef typename add_const_if_c
<
- IsConst,
+ is_const<Range>::value,
typename point_type<Range>::type
>::type point_type;
- BOOST_AUTO_TPL(it, boost::begin(range));
- BOOST_AUTO_TPL(previous, it++);
+ typedef typename boost::range_iterator<Range>::type iterator_type;
+
+ iterator_type it = boost::begin(range);
+ iterator_type previous = it++;
while(it != boost::end(range))
{
model::referring_segment<point_type> s(*previous, *it);
f(s);
previous = it++;
}
+ }
+};
+
- return f;
+template <>
+struct fe_range_per_segment_with_closure<open>
+{
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
+ {
+ fe_range_per_segment_with_closure<closed>::apply(range, f);
+
+ model::referring_segment
+ <
+ typename add_const_if_c
+ <
+ is_const<Range>::value,
+ typename point_type<Range>::type
+ >::type
+ > s(range::back(range), range::front(range));
+
+ f(s);
}
};
-template <typename Polygon, typename Functor, bool IsConst>
-struct fe_polygon_per_point
+struct fe_range_per_segment
{
- typedef typename add_const_if_c<IsConst, Polygon>::type poly_type;
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
+ {
+ fe_range_per_segment_with_closure
+ <
+ closure<Range>::value
+ >::apply(range, f);
+ }
+};
+
- static inline Functor apply(poly_type& poly, Functor f)
+struct fe_polygon_per_point
+{
+ template <typename Polygon, typename Functor>
+ static inline void apply(Polygon& poly, Functor& f)
{
- typedef fe_range_per_point
- <
- typename ring_type<Polygon>::type,
- Functor,
- IsConst
- > per_ring;
+ fe_range_per_point::apply(exterior_ring(poly), f);
- f = per_ring::apply(exterior_ring(poly), f);
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(poly);
- typename interior_return_type<poly_type>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- f = per_ring::apply(*it, f);
+ fe_range_per_point::apply(*it, f);
}
-
- return f;
}
};
-
-template <typename Polygon, typename Functor, bool IsConst>
struct fe_polygon_per_segment
{
- typedef typename add_const_if_c<IsConst, Polygon>::type poly_type;
-
- static inline Functor apply(poly_type& poly, Functor f)
+ template <typename Polygon, typename Functor>
+ static inline void apply(Polygon& poly, Functor& f)
{
- typedef fe_range_per_segment
- <
- typename ring_type<Polygon>::type,
- Functor,
- IsConst
- > per_ring;
+ fe_range_per_segment::apply(exterior_ring(poly), f);
- f = per_ring::apply(exterior_ring(poly), f);
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(poly);
- typename interior_return_type<poly_type>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- f = per_ring::apply(*it, f);
+ fe_range_per_segment::apply(*it, f);
}
-
- return f;
}
};
+// Implementation of multi, for both point and segment,
+// just calling the single version.
+template <typename Policy>
+struct for_each_multi
+{
+ template <typename MultiGeometry, typename Functor>
+ static inline void apply(MultiGeometry& multi, Functor& f)
+ {
+ for (typename boost::range_iterator<MultiGeometry>::type
+ it = boost::begin(multi); it != boost::end(multi); ++it)
+ {
+ Policy::apply(*it, f);
+ }
+ }
+};
}} // namespace detail::for_each
#endif // DOXYGEN_NO_DETAIL
@@ -171,102 +219,105 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
- typename Functor,
- bool IsConst
+ typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type
>
-struct for_each_point {};
+struct for_each_point: not_implemented<Tag>
+{};
-template <typename Point, typename Functor, bool IsConst>
-struct for_each_point<point_tag, Point, Functor, IsConst>
- : detail::for_each::fe_point_per_point<Point, Functor, IsConst>
+template <typename Point>
+struct for_each_point<Point, point_tag>
+ : detail::for_each::fe_point_per_point
{};
-template <typename Linestring, typename Functor, bool IsConst>
-struct for_each_point<linestring_tag, Linestring, Functor, IsConst>
- : detail::for_each::fe_range_per_point<Linestring, Functor, IsConst>
+template <typename Linestring>
+struct for_each_point<Linestring, linestring_tag>
+ : detail::for_each::fe_range_per_point
{};
-template <typename Ring, typename Functor, bool IsConst>
-struct for_each_point<ring_tag, Ring, Functor, IsConst>
- : detail::for_each::fe_range_per_point<Ring, Functor, IsConst>
+template <typename Ring>
+struct for_each_point<Ring, ring_tag>
+ : detail::for_each::fe_range_per_point
{};
-template <typename Polygon, typename Functor, bool IsConst>
-struct for_each_point<polygon_tag, Polygon, Functor, IsConst>
- : detail::for_each::fe_polygon_per_point<Polygon, Functor, IsConst>
+template <typename Polygon>
+struct for_each_point<Polygon, polygon_tag>
+ : detail::for_each::fe_polygon_per_point
{};
template
<
- typename Tag,
typename Geometry,
- typename Functor,
- bool IsConst
+ typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type
>
-struct for_each_segment {};
+struct for_each_segment: not_implemented<Tag>
+{};
-template <typename Point, typename Functor, bool IsConst>
-struct for_each_segment<point_tag, Point, Functor, IsConst>
- : detail::for_each::fe_point_per_segment<Point, Functor, IsConst>
+template <typename Point>
+struct for_each_segment<Point, point_tag>
+ : detail::for_each::fe_point_per_segment
{};
-template <typename Linestring, typename Functor, bool IsConst>
-struct for_each_segment<linestring_tag, Linestring, Functor, IsConst>
- : detail::for_each::fe_range_per_segment<Linestring, Functor, IsConst>
+template <typename Linestring>
+struct for_each_segment<Linestring, linestring_tag>
+ : detail::for_each::fe_range_per_segment
{};
-template <typename Ring, typename Functor, bool IsConst>
-struct for_each_segment<ring_tag, Ring, Functor, IsConst>
- : detail::for_each::fe_range_per_segment<Ring, Functor, IsConst>
+template <typename Ring>
+struct for_each_segment<Ring, ring_tag>
+ : detail::for_each::fe_range_per_segment
{};
-template <typename Polygon, typename Functor, bool IsConst>
-struct for_each_segment<polygon_tag, Polygon, Functor, IsConst>
- : detail::for_each::fe_polygon_per_segment<Polygon, Functor, IsConst>
+template <typename Polygon>
+struct for_each_segment<Polygon, polygon_tag>
+ : detail::for_each::fe_polygon_per_segment
{};
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+template <typename MultiGeometry>
+struct for_each_point<MultiGeometry, multi_tag>
+ : detail::for_each::for_each_multi
+ <
+ // Specify the dispatch of the single-version as policy
+ for_each_point
+ <
+ typename add_const_if_c
+ <
+ is_const<MultiGeometry>::value,
+ typename boost::range_value<MultiGeometry>::type
+ >::type
+ >
+ >
+{};
-/*!
-\brief \brf_for_each{point}
-\details \det_for_each{point}
-\ingroup for_each
-\param geometry \param_geometry
-\param f \par_for_each_f{const point}
-\tparam Geometry \tparam_geometry
-\tparam Functor \tparam_functor
+template <typename MultiGeometry>
+struct for_each_segment<MultiGeometry, multi_tag>
+ : detail::for_each::for_each_multi
+ <
+ // Specify the dispatch of the single-version as policy
+ for_each_segment
+ <
+ typename add_const_if_c
+ <
+ is_const<MultiGeometry>::value,
+ typename boost::range_value<MultiGeometry>::type
+ >::type
+ >
+ >
+{};
-\qbk{distinguish,const version}
-\qbk{[include reference/algorithms/for_each_point.qbk]}
-\qbk{[heading Example]}
-\qbk{[for_each_point_const] [for_each_point_const_output]}
-*/
-template<typename Geometry, typename Functor>
-inline Functor for_each_point(Geometry const& geometry, Functor f)
-{
- concept::check<Geometry const>();
- return dispatch::for_each_point
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- true
- >::apply(geometry, f);
-}
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
/*!
@@ -281,19 +332,15 @@ inline Functor for_each_point(Geometry const& geometry, Functor f)
\qbk{[include reference/algorithms/for_each_point.qbk]}
\qbk{[heading Example]}
\qbk{[for_each_point] [for_each_point_output]}
+\qbk{[for_each_point_const] [for_each_point_const_output]}
*/
template<typename Geometry, typename Functor>
inline Functor for_each_point(Geometry& geometry, Functor f)
{
concept::check<Geometry>();
- return dispatch::for_each_point
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- false
- >::apply(geometry, f);
+ dispatch::for_each_point<Geometry>::apply(geometry, f);
+ return f;
}
@@ -302,53 +349,21 @@ inline Functor for_each_point(Geometry& geometry, Functor f)
\details \det_for_each{segment}
\ingroup for_each
\param geometry \param_geometry
-\param f \par_for_each_f{const segment}
+\param f \par_for_each_f{segment}
\tparam Geometry \tparam_geometry
\tparam Functor \tparam_functor
-\qbk{distinguish,const version}
\qbk{[include reference/algorithms/for_each_segment.qbk]}
\qbk{[heading Example]}
\qbk{[for_each_segment_const] [for_each_segment_const_output]}
*/
template<typename Geometry, typename Functor>
-inline Functor for_each_segment(Geometry const& geometry, Functor f)
-{
- concept::check<Geometry const>();
-
- return dispatch::for_each_segment
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- true
- >::apply(geometry, f);
-}
-
-
-/*!
-\brief \brf_for_each{segment}
-\details \det_for_each{segment}
-\ingroup for_each
-\param geometry \param_geometry
-\param f \par_for_each_f{segment}
-\tparam Geometry \tparam_geometry
-\tparam Functor \tparam_functor
-
-\qbk{[include reference/algorithms/for_each_segment.qbk]}
-*/
-template<typename Geometry, typename Functor>
inline Functor for_each_segment(Geometry& geometry, Functor f)
{
concept::check<Geometry>();
- return dispatch::for_each_segment
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- false
- >::apply(geometry, f);
+ dispatch::for_each_segment<Geometry>::apply(geometry, f);
+ return f;
}
diff --git a/boost/geometry/algorithms/intersection.hpp b/boost/geometry/algorithms/intersection.hpp
index 8d3dd68b3a..0169f12db1 100644
--- a/boost/geometry/algorithms/intersection.hpp
+++ b/boost/geometry/algorithms/intersection.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -10,228 +15,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
-#include <boost/geometry/algorithms/intersects.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace intersection
-{
-
-template
-<
- typename Box1, typename Box2,
- typename BoxOut,
- typename Strategy,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct intersection_box_box
-{
- static inline bool apply(Box1 const& box1,
- Box2 const& box2, BoxOut& box_out,
- Strategy const& strategy)
- {
- typedef typename coordinate_type<BoxOut>::type ct;
-
- ct min1 = get<min_corner, Dimension>(box1);
- ct min2 = get<min_corner, Dimension>(box2);
- ct max1 = get<max_corner, Dimension>(box1);
- ct max2 = get<max_corner, Dimension>(box2);
-
- if (max1 < min2 || max2 < min1)
- {
- return false;
- }
- // Set dimensions of output coordinate
- set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1);
- set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
-
- return intersection_box_box
- <
- Box1, Box2, BoxOut, Strategy,
- Dimension + 1, DimensionCount
- >::apply(box1, box2, box_out, strategy);
- }
-};
-
-template
-<
- typename Box1, typename Box2,
- typename BoxOut,
- typename Strategy,
- std::size_t DimensionCount
->
-struct intersection_box_box<Box1, Box2, BoxOut, Strategy, DimensionCount, DimensionCount>
-{
- static inline bool apply(Box1 const&, Box2 const&, BoxOut&, Strategy const&)
- {
- return true;
- }
-};
-
-
-}} // namespace detail::intersection
-#endif // DOXYGEN_NO_DETAIL
-
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-// By default, all is forwarded to the intersection_insert-dispatcher
-template
-<
- typename Tag1, typename Tag2, typename TagOut,
- typename Geometry1, typename Geometry2,
- typename GeometryOut,
- typename Strategy
->
-struct intersection
-{
- typedef std::back_insert_iterator<GeometryOut> output_iterator;
-
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- GeometryOut& geometry_out,
- Strategy const& strategy)
- {
- typedef typename boost::range_value<GeometryOut>::type OneOut;
-
- intersection_insert
- <
- Tag1, Tag2, typename geometry::tag<OneOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<OneOut>::value,
- Geometry1, Geometry2,
- detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, false>::value,
- detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, false>::value,
- detail::overlay::do_reverse<geometry::point_order<OneOut>::value>::value,
- output_iterator, OneOut,
- overlay_intersection,
- Strategy
- >::apply(geometry1, geometry2, std::back_inserter(geometry_out), strategy);
-
- return true;
- }
-
-};
-
-
-template
-<
- typename Box1, typename Box2,
- typename BoxOut,
- typename Strategy
->
-struct intersection
- <
- box_tag, box_tag, box_tag,
- Box1, Box2, BoxOut,
- Strategy
- > : public detail::intersection::intersection_box_box
- <
- Box1, Box2, BoxOut,
- Strategy,
- 0, geometry::dimension<Box1>::value
- >
-{};
-
-
-template
-<
- typename Tag1, typename Tag2, typename TagOut,
- typename Geometry1, typename Geometry2,
- typename GeometryOut,
- typename Strategy
->
-struct intersection_reversed
-{
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- GeometryOut& geometry_out,
- Strategy const& strategy)
- {
- return intersection
- <
- Tag2, Tag1, TagOut,
- Geometry2, Geometry1,
- GeometryOut, Strategy
- >::apply(geometry2, geometry1, geometry_out, strategy);
- }
-};
-
-
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-/*!
-\brief \brief_calc2{intersection}
-\ingroup intersection
-\details \details_calc2{intersection, spatial set theoretic intersection}.
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which
- the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box)
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param geometry_out The output geometry, either a multi_point, multi_polygon,
- multi_linestring, or a box (for intersection of two boxes)
-
-\qbk{[include reference/algorithms/intersection.qbk]}
-*/
-template
-<
- typename Geometry1,
- typename Geometry2,
- typename GeometryOut
->
-inline bool intersection(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- GeometryOut& geometry_out)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- typedef strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename geometry::point_type<Geometry1>::type
- > strategy;
-
-
- return boost::mpl::if_c
- <
- geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::intersection_reversed
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- Geometry1, Geometry2, GeometryOut, strategy
- >,
- dispatch::intersection
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- Geometry1, Geometry2, GeometryOut, strategy
- >
- >::type::apply(geometry1, geometry2, geometry_out, strategy());
-}
-
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/detail/intersection/interface.hpp>
+#include <boost/geometry/algorithms/detail/intersection/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP
diff --git a/boost/geometry/algorithms/intersects.hpp b/boost/geometry/algorithms/intersects.hpp
index f367f2e258..1bb85aa3bb 100644
--- a/boost/geometry/algorithms/intersects.hpp
+++ b/boost/geometry/algorithms/intersects.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -21,6 +26,9 @@
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+
namespace boost { namespace geometry
{
@@ -43,37 +51,29 @@ inline bool intersects(Geometry const& geometry)
{
concept::check<Geometry const>();
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
typedef detail::overlay::turn_info
<
- typename geometry::point_type<Geometry>::type
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
> turn_info;
- std::deque<turn_info> turns;
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry>::type,
- Geometry,
- Geometry,
- typename geometry::point_type<Geometry>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
+ std::deque<turn_info> turns;
typedef detail::overlay::get_turn_info
<
- typename point_type<Geometry>::type,
- typename point_type<Geometry>::type,
- turn_info,
detail::overlay::assign_null_policy
- > TurnPolicy;
+ > turn_policy;
+
+ rescale_policy_type robust_policy;
detail::disjoint::disjoint_interrupt_policy policy;
detail::self_get_turn_points::get_turns
- <
- Geometry,
- std::deque<turn_info>,
- TurnPolicy,
- detail::disjoint::disjoint_interrupt_policy
- >::apply(geometry, turns, policy);
+ <
+ turn_policy
+ >::apply(geometry, robust_policy, turns, policy);
return policy.has_intersections;
}
diff --git a/boost/geometry/algorithms/is_simple.hpp b/boost/geometry/algorithms/is_simple.hpp
new file mode 100644
index 0000000000..f48c957dfc
--- /dev/null
+++ b/boost/geometry/algorithms/is_simple.hpp
@@ -0,0 +1,16 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
+
+#include <boost/geometry/algorithms/detail/is_simple/interface.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/implementation.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
diff --git a/boost/geometry/algorithms/is_valid.hpp b/boost/geometry/algorithms/is_valid.hpp
new file mode 100644
index 0000000000..24dc5f7737
--- /dev/null
+++ b/boost/geometry/algorithms/is_valid.hpp
@@ -0,0 +1,16 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
+
+#include <boost/geometry/algorithms/detail/is_valid/interface.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/implementation.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
diff --git a/boost/geometry/algorithms/length.hpp b/boost/geometry/algorithms/length.hpp
index de53a39e8f..6cbec5303e 100644
--- a/boost/geometry/algorithms/length.hpp
+++ b/boost/geometry/algorithms/length.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -16,18 +21,32 @@
#include <iterator>
+#include <boost/concept_check.hpp>
#include <boost/range.hpp>
+#include <boost/mpl/fold.hpp>
+#include <boost/mpl/greater.hpp>
#include <boost/mpl/if.hpp>
+#include <boost/mpl/insert.hpp>
+#include <boost/mpl/int.hpp>
+#include <boost/mpl/set.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/transform.hpp>
#include <boost/type_traits.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
// #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/strategies/distance.hpp>
@@ -43,9 +62,10 @@ namespace detail { namespace length
{
-template<typename Segment, typename Strategy>
+template<typename Segment>
struct segment_length
{
+ template <typename Strategy>
static inline typename default_length_result<Segment>::type apply(
Segment const& segment, Strategy const& strategy)
{
@@ -63,14 +83,16 @@ struct segment_length
\note for_each could be used here, now that point_type is changed by boost
range iterator
*/
-template<typename Range, typename Strategy, closure_selector Closure>
+template<typename Range, closure_selector Closure>
struct range_length
{
typedef typename default_length_result<Range>::type return_type;
+ template <typename Strategy>
static inline return_type apply(
Range const& range, Strategy const& strategy)
{
+ boost::ignore_unused_variable_warning(strategy);
typedef typename closeable_view<Range const, Closure>::type view_type;
typedef typename boost::range_iterator
<
@@ -106,35 +128,111 @@ namespace dispatch
{
-template <typename Tag, typename Geometry, typename Strategy>
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct length : detail::calculate_null
- <
- typename default_length_result<Geometry>::type,
- Geometry,
- Strategy
- >
-{};
+{
+ typedef typename default_length_result<Geometry>::type return_type;
+ template <typename Strategy>
+ static inline return_type apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return calculate_null::apply<return_type>(geometry, strategy);
+ }
+};
-template <typename Geometry, typename Strategy>
-struct length<linestring_tag, Geometry, Strategy>
- : detail::length::range_length<Geometry, Strategy, closed>
+
+template <typename Geometry>
+struct length<Geometry, linestring_tag>
+ : detail::length::range_length<Geometry, closed>
{};
// RING: length is currently 0; it might be argued that it is the "perimeter"
-template <typename Geometry, typename Strategy>
-struct length<segment_tag, Geometry, Strategy>
- : detail::length::segment_length<Geometry, Strategy>
+template <typename Geometry>
+struct length<Geometry, segment_tag>
+ : detail::length::segment_length<Geometry>
{};
+template <typename MultiLinestring>
+struct length<MultiLinestring, multi_linestring_tag> : detail::multi_sum
+{
+ template <typename Strategy>
+ static inline typename default_length_result<MultiLinestring>::type
+ apply(MultiLinestring const& multi, Strategy const& strategy)
+ {
+ return multi_sum::apply
+ <
+ typename default_length_result<MultiLinestring>::type,
+ detail::length::range_length
+ <
+ typename boost::range_value<MultiLinestring>::type,
+ closed // no need to close it explicitly
+ >
+ >(multi, strategy);
+
+ }
+};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct length
+{
+ template <typename Strategy>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return dispatch::length<Geometry>::apply(geometry, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct length<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ typedef typename default_length_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>
+ >::type result_type;
+
+ template <typename Strategy>
+ struct visitor
+ : static_visitor<result_type>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ inline typename default_length_result<Geometry>::type
+ operator()(Geometry const& geometry) const
+ {
+ return length<Geometry>::apply(geometry, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline result_type apply(
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Strategy const& strategy
+ )
+ {
+ return apply_visitor(visitor<Strategy>(strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{length}
\ingroup length
@@ -147,24 +245,20 @@ struct length<segment_tag, Geometry, Strategy>
\qbk{[length] [length_output]}
*/
template<typename Geometry>
-inline typename default_length_result<Geometry>::type length(
- Geometry const& geometry)
+inline typename default_length_result<Geometry>::type
+length(Geometry const& geometry)
{
concept::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
+ // TODO put this into a resolve_strategy stage
typedef typename strategy::distance::services::default_strategy
<
- point_tag, typename point_type<Geometry>::type
+ point_tag, point_tag, typename point_type<Geometry>::type
>::type strategy_type;
- return dispatch::length
- <
- typename tag<Geometry>::type,
- Geometry,
- strategy_type
- >::apply(geometry, strategy_type());
+ return resolve_variant::length<Geometry>::apply(geometry, strategy_type());
}
@@ -183,19 +277,14 @@ inline typename default_length_result<Geometry>::type length(
\qbk{[length_with_strategy] [length_with_strategy_output]}
*/
template<typename Geometry, typename Strategy>
-inline typename default_length_result<Geometry>::type length(
- Geometry const& geometry, Strategy const& strategy)
+inline typename default_length_result<Geometry>::type
+length(Geometry const& geometry, Strategy const& strategy)
{
concept::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
-
- return dispatch::length
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, strategy);
+
+ return resolve_variant::length<Geometry>::apply(geometry, strategy);
}
diff --git a/boost/geometry/algorithms/not_implemented.hpp b/boost/geometry/algorithms/not_implemented.hpp
index 008f111cc8..cd40a2772f 100644
--- a/boost/geometry/algorithms/not_implemented.hpp
+++ b/boost/geometry/algorithms/not_implemented.hpp
@@ -18,7 +18,6 @@
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/tags.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
namespace boost { namespace geometry
diff --git a/boost/geometry/algorithms/num_geometries.hpp b/boost/geometry/algorithms/num_geometries.hpp
index 20f35e90d2..d37d0bfabe 100644
--- a/boost/geometry/algorithms/num_geometries.hpp
+++ b/boost/geometry/algorithms/num_geometries.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -17,7 +22,12 @@
#include <cstddef>
-#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -25,6 +35,8 @@
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/detail/counting.hpp>
+
namespace boost { namespace geometry
{
@@ -35,30 +47,74 @@ namespace dispatch
{
-template <typename Tag, typename Geometry>
-struct num_geometries
+template
+<
+ typename Geometry,
+ typename Tag = typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ single_tag,
+ multi_tag
+ >::type
+>
+struct num_geometries: not_implemented<Tag>
+{};
+
+
+template <typename Geometry>
+struct num_geometries<Geometry, single_tag>
+ : detail::counting::other_count<1>
+{};
+
+
+template <typename MultiGeometry>
+struct num_geometries<MultiGeometry, multi_tag>
{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
+ static inline std::size_t apply(MultiGeometry const& multi_geometry)
+ {
+ return boost::size(multi_geometry);
+ }
};
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+
template <typename Geometry>
-struct num_geometries<single_tag, Geometry>
+struct num_geometries
{
- static inline std::size_t apply(Geometry const&)
+ static inline std::size_t apply(Geometry const& geometry)
{
- return 1;
+ concept::check<Geometry const>();
+
+ return dispatch::num_geometries<Geometry>::apply(geometry);
}
};
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_geometries<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_geometries<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
-
-} // namespace dispatch
-#endif
+} // namespace resolve_variant
/*!
@@ -74,18 +130,7 @@ struct num_geometries<single_tag, Geometry>
template <typename Geometry>
inline std::size_t num_geometries(Geometry const& geometry)
{
- concept::check<Geometry const>();
-
- return dispatch::num_geometries
- <
- typename tag_cast
- <
- typename tag<Geometry>::type,
- single_tag,
- multi_tag
- >::type,
- Geometry
- >::apply(geometry);
+ return resolve_variant::num_geometries<Geometry>::apply(geometry);
}
diff --git a/boost/geometry/algorithms/num_interior_rings.hpp b/boost/geometry/algorithms/num_interior_rings.hpp
index 2149f46576..e198b37a75 100644
--- a/boost/geometry/algorithms/num_interior_rings.hpp
+++ b/boost/geometry/algorithms/num_interior_rings.hpp
@@ -1,8 +1,14 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,11 +24,19 @@
#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/counting.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
namespace boost { namespace geometry
{
@@ -32,19 +46,15 @@ namespace dispatch
{
-template <typename Tag, typename Geometry>
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct num_interior_rings
-{
- static inline std::size_t apply(Geometry const& )
- {
- return 0;
- }
-};
+ : detail::counting::other_count<0>
+{};
template <typename Polygon>
-struct num_interior_rings<polygon_tag, Polygon>
+struct num_interior_rings<Polygon, polygon_tag>
{
static inline std::size_t apply(Polygon const& polygon)
{
@@ -54,8 +64,56 @@ struct num_interior_rings<polygon_tag, Polygon>
};
+template <typename MultiPolygon>
+struct num_interior_rings<MultiPolygon, multi_polygon_tag>
+ : detail::counting::multi_count
+ <
+ num_interior_rings
+ <
+ typename boost::range_value<MultiPolygon const>::type
+ >
+ >
+{};
+
+
} // namespace dispatch
-#endif
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct num_interior_rings
+{
+ static inline std::size_t apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+
+ return dispatch::num_interior_rings<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_interior_rings<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_interior_rings<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
/*!
@@ -74,11 +132,7 @@ struct num_interior_rings<polygon_tag, Polygon>
template <typename Geometry>
inline std::size_t num_interior_rings(Geometry const& geometry)
{
- return dispatch::num_interior_rings
- <
- typename tag<Geometry>::type,
- Geometry
- >::apply(geometry);
+ return resolve_variant::num_interior_rings<Geometry>::apply(geometry);
}
diff --git a/boost/geometry/algorithms/num_points.hpp b/boost/geometry/algorithms/num_points.hpp
index c480068f43..4c2ad3b08c 100644
--- a/boost/geometry/algorithms/num_points.hpp
+++ b/boost/geometry/algorithms/num_points.hpp
@@ -1,8 +1,14 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -16,76 +22,55 @@
#include <cstddef>
-#include <boost/mpl/assert.hpp>
+#include <boost/mpl/size_t.hpp>
+
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.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/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/counting.hpp>
-#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace num_points
{
-template <typename Range>
+template <bool AddForOpen>
struct range_count
{
- static inline std::size_t apply(Range const& range, bool add_for_open)
+ template <typename Range>
+ static inline std::size_t apply(Range const& range)
{
std::size_t n = boost::size(range);
- if (add_for_open && n > 0)
- {
- 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&, bool)
- {
- return D;
- }
-};
-
-template <typename Polygon>
-struct polygon_count
-{
- static inline std::size_t apply(Polygon const& poly, bool add_for_open)
- {
- typedef typename geometry::ring_type<Polygon>::type ring_type;
-
- std::size_t n = range_count<ring_type>::apply(
- exterior_ring(poly), add_for_open);
-
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ if (AddForOpen
+ && n > 0
+ && geometry::closure<Range>::value == open
+ )
{
- n += range_count<ring_type>::apply(*it, add_for_open);
+ return n + 1;
}
-
return n;
}
};
@@ -98,50 +83,107 @@ struct polygon_count
namespace dispatch
{
-template <typename GeometryTag, typename Geometry>
-struct num_points
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
-};
+template
+<
+ typename Geometry,
+ bool AddForOpen,
+ typename Tag = typename tag_cast
+ <
+ typename tag<Geometry>::type, multi_tag
+ >::type
+>
+struct num_points: not_implemented<Tag>
+{};
-template <typename Geometry>
-struct num_points<point_tag, Geometry>
- : detail::num_points::other_count<Geometry, 1>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, point_tag>
+ : detail::counting::other_count<1>
{};
-template <typename Geometry>
-struct num_points<box_tag, Geometry>
- : detail::num_points::other_count<Geometry, 4>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, box_tag>
+ : detail::counting::other_count<(1 << geometry::dimension<Geometry>::value)>
{};
-template <typename Geometry>
-struct num_points<segment_tag, Geometry>
- : detail::num_points::other_count<Geometry, 2>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, segment_tag>
+ : detail::counting::other_count<2>
{};
-template <typename Geometry>
-struct num_points<linestring_tag, Geometry>
- : detail::num_points::range_count<Geometry>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, linestring_tag>
+ : detail::num_points::range_count<AddForOpen>
{};
-template <typename Geometry>
-struct num_points<ring_tag, Geometry>
- : detail::num_points::range_count<Geometry>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, ring_tag>
+ : detail::num_points::range_count<AddForOpen>
{};
-template <typename Geometry>
-struct num_points<polygon_tag, Geometry>
- : detail::num_points::polygon_count<Geometry>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, polygon_tag>
+ : detail::counting::polygon_count
+ <
+ detail::num_points::range_count<AddForOpen>
+ >
+{};
+
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, multi_tag>
+ : detail::counting::multi_count
+ <
+ num_points<typename boost::range_value<Geometry>::type, AddForOpen>
+ >
{};
} // namespace dispatch
#endif
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct num_points
+{
+ static inline std::size_t apply(Geometry const& geometry,
+ bool add_for_open)
+ {
+ concept::check<Geometry const>();
+
+ return add_for_open
+ ? dispatch::num_points<Geometry, true>::apply(geometry)
+ : dispatch::num_points<Geometry, false>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_points<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ bool m_add_for_open;
+
+ visitor(bool add_for_open): m_add_for_open(add_for_open) {}
+
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_points<Geometry>::apply(geometry, m_add_for_open);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ bool add_for_open)
+ {
+ return boost::apply_visitor(visitor(add_for_open), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{number of points}
\ingroup num_points
@@ -156,15 +198,13 @@ struct num_points<polygon_tag, Geometry>
template <typename Geometry>
inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false)
{
- concept::check<Geometry const>();
-
- return dispatch::num_points
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry
- >::apply(geometry, add_for_open);
+ return resolve_variant::num_points<Geometry>::apply(geometry, add_for_open);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/num_segments.hpp b/boost/geometry/algorithms/num_segments.hpp
new file mode 100644
index 0000000000..cbb5685967
--- /dev/null
+++ b/boost/geometry/algorithms/num_segments.hpp
@@ -0,0 +1,204 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP
+
+#include <cstddef>
+
+#include <boost/mpl/size_t.hpp>
+#include <boost/mpl/times.hpp>
+
+#include <boost/range.hpp>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/counting.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace num_segments
+{
+
+
+struct range_count
+{
+ template <typename Range>
+ static inline std::size_t apply(Range const& range)
+ {
+ std::size_t n = boost::size(range);
+ if ( n <= 1 )
+ {
+ return 0;
+ }
+
+ return
+ geometry::closure<Range>::value == open
+ ?
+ n
+ :
+ static_cast<std::size_t>(n - 1);
+ }
+};
+
+}} // namespace detail::num_segments
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct num_segments
+ : not_implemented<Tag>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, point_tag>
+ : detail::counting::other_count<0>
+{};
+
+// the number of segments (1-dimensional faces) of the hypercube is
+// given by the formula: d * 2^(d-1), where d is the dimension of the
+// hypercube; see also:
+// http://en.wikipedia.org/wiki/Hypercube
+template <typename Geometry>
+struct num_segments<Geometry, box_tag>
+ : detail::counting::other_count
+ <
+ geometry::dimension<Geometry>::value
+ * (1 << (geometry::dimension<Geometry>::value - 1))
+ >
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, segment_tag>
+ : detail::counting::other_count<1>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, linestring_tag>
+ : detail::num_segments::range_count
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, ring_tag>
+ : detail::num_segments::range_count
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, polygon_tag>
+ : detail::counting::polygon_count<detail::num_segments::range_count>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, multi_point_tag>
+ : detail::counting::other_count<0>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, multi_linestring_tag>
+ : detail::counting::multi_count
+ <
+ num_segments< typename boost::range_value<Geometry>::type>
+ >
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, multi_polygon_tag>
+ : detail::counting::multi_count
+ <
+ num_segments< typename boost::range_value<Geometry>::type>
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+namespace resolve_variant
+{
+
+
+template <typename Geometry>
+struct num_segments
+{
+ static inline std::size_t apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+
+ return dispatch::num_segments<Geometry>::apply(geometry);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_segments<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_segments<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+
+} // namespace resolve_variant
+
+
+
+/*!
+\brief \brief_calc{number of segments}
+\ingroup num_segments
+\details \details_calc{num_segments, number of segments}.
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_calc{number of segments}
+
+\qbk{[include reference/algorithms/num_segments.qbk]}
+*/
+template <typename Geometry>
+inline std::size_t num_segments(Geometry const& geometry)
+{
+ return resolve_variant::num_segments<Geometry>::apply(geometry);
+}
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP
diff --git a/boost/geometry/algorithms/overlaps.hpp b/boost/geometry/algorithms/overlaps.hpp
index 2f854b4fdd..f724a544fd 100644
--- a/boost/geometry/algorithms/overlaps.hpp
+++ b/boost/geometry/algorithms/overlaps.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,18 +14,22 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP
#include <cstddef>
-#include <boost/mpl/assert.hpp>
-
#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate.hpp>
+
namespace boost { namespace geometry
{
@@ -32,13 +39,12 @@ namespace detail { namespace overlaps
template
<
- typename Box1,
- typename Box2,
std::size_t Dimension,
std::size_t DimensionCount
>
struct box_box_loop
{
+ template <typename Box1, typename Box2>
static inline void apply(Box1 const& b1, Box2 const& b2,
bool& overlaps, bool& one_in_two, bool& two_in_one)
{
@@ -84,8 +90,6 @@ struct box_box_loop
box_box_loop
<
- Box1,
- Box2,
Dimension + 1,
DimensionCount
>::apply(b1, b2, overlaps, one_in_two, two_in_one);
@@ -94,24 +98,19 @@ struct box_box_loop
template
<
- typename Box1,
- typename Box2,
std::size_t DimensionCount
>
-struct box_box_loop<Box1, Box2, DimensionCount, DimensionCount>
+struct box_box_loop<DimensionCount, DimensionCount>
{
+ template <typename Box1, typename Box2>
static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&)
{
}
};
-template
-<
- typename Box1,
- typename Box2
->
struct box_box
{
+ template <typename Box1, typename Box2>
static inline bool apply(Box1 const& b1, Box2 const& b2)
{
bool overlaps = true;
@@ -119,8 +118,6 @@ struct box_box
bool within2 = true;
box_box_loop
<
- Box1,
- Box2,
0,
dimension<Box1>::type::value
>::apply(b1, b2, overlaps, within1, within2);
@@ -134,8 +131,6 @@ struct box_box
}
};
-
-
}} // namespace detail::overlaps
#endif // DOXYGEN_NO_DETAIL
@@ -148,29 +143,26 @@ namespace dispatch
template
<
- typename Tag1,
- typename Tag2,
typename Geometry1,
- typename Geometry2
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
>
struct overlaps
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry1, Geometry2>)
- );
-};
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_overlaps_type,
+ Geometry1,
+ Geometry2
+ >
+{};
template <typename Box1, typename Box2>
-struct overlaps<box_tag, box_tag, Box1, Box2>
- : detail::overlaps::box_box<Box1, Box2>
+struct overlaps<Box1, Box2, box_tag, box_tag>
+ : detail::overlaps::box_box
{};
-
-
-
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -178,6 +170,10 @@ struct overlaps<box_tag, box_tag, Box1, Box2>
/*!
\brief \brief_check2{overlap}
\ingroup overlaps
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
\return \return_check2{overlap}
\qbk{[include reference/algorithms/overlaps.qbk]}
@@ -190,8 +186,6 @@ inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2)
return dispatch::overlaps
<
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
Geometry1,
Geometry2
>::apply(geometry1, geometry2);
diff --git a/boost/geometry/algorithms/perimeter.hpp b/boost/geometry/algorithms/perimeter.hpp
index adeb0b05b0..0ec153c1f4 100644
--- a/boost/geometry/algorithms/perimeter.hpp
+++ b/boost/geometry/algorithms/perimeter.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,16 +19,22 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP
+#include <boost/range/metafunctions.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/strategies/default_length_result.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/algorithms/detail/calculate_sum.hpp>
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
// #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
-
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/strategies/default_length_result.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
namespace boost { namespace geometry
{
@@ -33,40 +44,59 @@ namespace dispatch
{
// Default perimeter is 0.0, specializations implement calculated values
-template <typename Tag, typename Geometry, typename Strategy>
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct perimeter : detail::calculate_null
- <
- typename default_length_result<Geometry>::type,
- Geometry,
- Strategy
- >
-{};
+{
+ typedef typename default_length_result<Geometry>::type return_type;
+
+ template <typename Strategy>
+ static inline return_type apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return calculate_null::apply<return_type>(geometry, strategy);
+ }
+};
-template <typename Geometry, typename Strategy>
-struct perimeter<ring_tag, Geometry, Strategy>
+template <typename Geometry>
+struct perimeter<Geometry, ring_tag>
: detail::length::range_length
<
Geometry,
- Strategy,
closure<Geometry>::value
>
{};
-template <typename Polygon, typename Strategy>
-struct perimeter<polygon_tag, Polygon, Strategy>
- : detail::calculate_polygon_sum
- <
- typename default_length_result<Polygon>::type,
- Polygon,
- Strategy,
- detail::length::range_length
+template <typename Polygon>
+struct perimeter<Polygon, polygon_tag> : detail::calculate_polygon_sum
+{
+ typedef typename default_length_result<Polygon>::type return_type;
+ typedef detail::length::range_length
<
typename ring_type<Polygon>::type,
- Strategy,
closure<Polygon>::value
- >
- >
-{};
+ > policy;
+
+ template <typename Strategy>
+ static inline return_type apply(Polygon const& polygon, Strategy const& strategy)
+ {
+ return calculate_polygon_sum::apply<return_type, policy>(polygon, strategy);
+ }
+};
+
+template <typename MultiPolygon>
+struct perimeter<MultiPolygon, multi_polygon_tag> : detail::multi_sum
+{
+ typedef typename default_length_result<MultiPolygon>::type return_type;
+
+ template <typename Strategy>
+ static inline return_type apply(MultiPolygon const& multi, Strategy const& strategy)
+ {
+ return multi_sum::apply
+ <
+ return_type,
+ perimeter<typename boost::range_value<MultiPolygon>::type>
+ >(multi, strategy);
+ }
+};
// box,n-sphere: to be implemented
@@ -75,6 +105,82 @@ struct perimeter<polygon_tag, Polygon, Strategy>
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy {
+
+struct perimeter
+{
+ template <typename Geometry, typename Strategy>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return dispatch::perimeter<Geometry>::apply(geometry, strategy);
+ }
+
+ template <typename Geometry>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, default_strategy)
+ {
+ typedef typename strategy::distance::services::default_strategy
+ <
+ point_tag, point_tag, typename point_type<Geometry>::type
+ >::type strategy_type;
+
+ return dispatch::perimeter<Geometry>::apply(geometry, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct perimeter
+{
+ template <typename Strategy>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ concept::check<Geometry const>();
+ return resolve_strategy::perimeter::apply(geometry, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct perimeter<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ typedef typename default_length_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>
+ >::type result_type;
+
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<result_type>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry>
+ typename default_length_result<Geometry>::type
+ operator()(Geometry const& geometry) const
+ {
+ return perimeter<Geometry>::apply(geometry, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline result_type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{perimeter}
\ingroup perimeter
@@ -90,22 +196,8 @@ template<typename Geometry>
inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry)
{
- concept::check<Geometry const>();
-
- typedef typename point_type<Geometry>::type point_type;
- typedef typename strategy::distance::services::default_strategy
- <
- point_tag, point_type
- >::type strategy_type;
-
// detail::throw_on_empty_input(geometry);
-
- return dispatch::perimeter
- <
- typename tag<Geometry>::type,
- Geometry,
- strategy_type
- >::apply(geometry, strategy_type());
+ return resolve_variant::perimeter<Geometry>::apply(geometry, default_strategy());
}
/*!
@@ -126,16 +218,8 @@ template<typename Geometry, typename Strategy>
inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry, Strategy const& strategy)
{
- concept::check<Geometry const>();
-
// detail::throw_on_empty_input(geometry);
-
- return dispatch::perimeter
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, strategy);
+ return resolve_variant::perimeter<Geometry>::apply(geometry, strategy);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/point_on_surface.hpp b/boost/geometry/algorithms/point_on_surface.hpp
new file mode 100644
index 0000000000..3fa83bfe6f
--- /dev/null
+++ b/boost/geometry/algorithms/point_on_surface.hpp
@@ -0,0 +1,327 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP
+
+
+#include <cstddef>
+
+#include <numeric>
+
+#include <boost/concept_check.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/extreme_points.hpp>
+
+#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace point_on_surface
+{
+
+template <typename CoordinateType, int Dimension>
+struct specific_coordinate_first
+{
+ CoordinateType const m_value_to_be_first;
+
+ inline specific_coordinate_first(CoordinateType value_to_be_skipped)
+ : m_value_to_be_first(value_to_be_skipped)
+ {}
+
+ template <typename Point>
+ inline bool operator()(Point const& lhs, Point const& rhs)
+ {
+ CoordinateType const lh = geometry::get<Dimension>(lhs);
+ CoordinateType const rh = geometry::get<Dimension>(rhs);
+
+ // If both lhs and rhs equal m_value_to_be_first,
+ // we should handle conform if lh < rh = FALSE
+ // The first condition meets that, keep it first
+ if (geometry::math::equals(rh, m_value_to_be_first))
+ {
+ // Handle conform lh < -INF, which is always false
+ return false;
+ }
+
+ if (geometry::math::equals(lh, m_value_to_be_first))
+ {
+ // Handle conform -INF < rh, which is always true
+ return true;
+ }
+
+ return lh < rh;
+ }
+};
+
+template <int Dimension, typename Collection, typename Value, typename Predicate>
+inline bool max_value(Collection const& collection, Value& the_max, Predicate const& predicate)
+{
+ bool first = true;
+ for (typename Collection::const_iterator it = collection.begin(); it != collection.end(); ++it)
+ {
+ if (! it->empty())
+ {
+ Value the_value = geometry::get<Dimension>(*std::max_element(it->begin(), it->end(), predicate));
+ if (first || the_value > the_max)
+ {
+ the_max = the_value;
+ first = false;
+ }
+ }
+ }
+ return ! first;
+}
+
+
+template <int Dimension, typename Value>
+struct select_below
+{
+ Value m_value;
+ inline select_below(Value const& v)
+ : m_value(v)
+ {}
+
+ template <typename Intruder>
+ inline bool operator()(Intruder const& intruder) const
+ {
+ if (intruder.empty())
+ {
+ return true;
+ }
+ Value max = geometry::get<Dimension>(*std::max_element(intruder.begin(), intruder.end(), detail::extreme_points::compare<Dimension>()));
+ return geometry::math::equals(max, m_value) || max < m_value;
+ }
+};
+
+template <int Dimension, typename Value>
+struct adapt_base
+{
+ Value m_value;
+ inline adapt_base(Value const& v)
+ : m_value(v)
+ {}
+
+ template <typename Intruder>
+ inline void operator()(Intruder& intruder) const
+ {
+ if (intruder.size() >= 3)
+ {
+ detail::extreme_points::move_along_vector<Dimension>(intruder, m_value);
+ }
+ }
+};
+
+template <int Dimension, typename Value>
+struct min_of_intruder
+{
+ template <typename Intruder>
+ inline bool operator()(Intruder const& lhs, Intruder const& rhs) const
+ {
+ Value lhs_min = geometry::get<Dimension>(*std::min_element(lhs.begin(), lhs.end(), detail::extreme_points::compare<Dimension>()));
+ Value rhs_min = geometry::get<Dimension>(*std::min_element(rhs.begin(), rhs.end(), detail::extreme_points::compare<Dimension>()));
+ return lhs_min < rhs_min;
+ }
+};
+
+
+template <typename Point, typename P>
+inline void calculate_average(Point& point, std::vector<P> const& points)
+{
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+ typedef typename std::vector<P>::const_iterator iterator_type;
+ typedef typename std::vector<P>::size_type size_type;
+
+ coordinate_type x = 0;
+ coordinate_type y = 0;
+
+ iterator_type end = points.end();
+ for ( iterator_type it = points.begin() ; it != end ; ++it)
+ {
+ x += geometry::get<0>(*it);
+ y += geometry::get<1>(*it);
+ }
+
+ size_type const count = points.size();
+ geometry::set<0>(point, x / count);
+ geometry::set<1>(point, y / count);
+}
+
+
+template <int Dimension, typename Extremes, typename Intruders, typename CoordinateType>
+inline void replace_extremes_for_self_tangencies(Extremes& extremes, Intruders& intruders, CoordinateType const& max_intruder)
+{
+ // This function handles self-tangencies.
+ // Self-tangencies use, as usual, the major part of code...
+
+ // ___ e
+ // /|\ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // / /\ | \ \ .
+ // i2 i1
+
+ // The picture above shows the extreme (outside, "e") and two intruders ("i1","i2")
+ // Assume that "i1" is self-tangent with the extreme, in one point at the top
+ // Now the "penultimate" value is searched, this is is the top of i2
+ // Then everything including and below (this is "i2" here) is removed
+ // Then the base of "i1" and of "e" is adapted to this penultimate value
+ // It then looks like:
+
+ // b ___ e
+ // /|\ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // a c i1
+
+ // Then intruders (here "i1" but there may be more) are sorted from left to right
+ // Finally points "a","b" and "c" (in this order) are selected as a new triangle.
+ // This triangle will have a centroid which is inside (assumed that intruders left segment
+ // is not equal to extremes left segment, but that polygon would be invalid)
+
+ // Find highest non-self tangent intrusion, if any
+ CoordinateType penultimate_value;
+ specific_coordinate_first<CoordinateType, Dimension> pu_compare(max_intruder);
+ if (max_value<Dimension>(intruders, penultimate_value, pu_compare))
+ {
+ // Throw away all intrusions <= this value, and of the kept one set this as base.
+ select_below<Dimension, CoordinateType> predicate(penultimate_value);
+ intruders.erase
+ (
+ std::remove_if(boost::begin(intruders), boost::end(intruders), predicate),
+ boost::end(intruders)
+ );
+ adapt_base<Dimension, CoordinateType> fe_predicate(penultimate_value);
+ // Sort from left to right (or bottom to top if Dimension=0)
+ std::for_each(boost::begin(intruders), boost::end(intruders), fe_predicate);
+
+ // Also adapt base of extremes
+ detail::extreme_points::move_along_vector<Dimension>(extremes, penultimate_value);
+ }
+ // Then sort in 1-Dim. Take first to calc centroid.
+ std::sort(boost::begin(intruders), boost::end(intruders), min_of_intruder<1 - Dimension, CoordinateType>());
+
+ Extremes triangle;
+ triangle.reserve(3);
+
+ // Make a triangle of first two points of extremes (the ramp, from left to right), and last point of first intruder (which goes from right to left)
+ std::copy(extremes.begin(), extremes.begin() + 2, std::back_inserter(triangle));
+ triangle.push_back(intruders.front().back());
+
+ // (alternatively we could use the last two points of extremes, and first point of last intruder...):
+ //// ALTERNATIVE: std::copy(extremes.rbegin(), extremes.rbegin() + 2, std::back_inserter(triangle));
+ //// ALTERNATIVE: triangle.push_back(intruders.back().front());
+
+ // Now replace extremes with this smaller subset, a triangle, such that centroid calculation will result in a point inside
+ extremes = triangle;
+}
+
+template <int Dimension, typename Geometry, typename Point>
+inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
+ std::vector<point_type> extremes;
+
+ typedef std::vector<std::vector<point_type> > intruders_type;
+ intruders_type intruders;
+ geometry::extreme_points<Dimension>(geometry, extremes, intruders);
+
+ if (extremes.size() < 3)
+ {
+ return false;
+ }
+
+ // If there are intruders, find the max.
+ if (! intruders.empty())
+ {
+ coordinate_type max_intruder;
+ detail::extreme_points::compare<Dimension> compare;
+ if (max_value<Dimension>(intruders, max_intruder, compare))
+ {
+ coordinate_type max_extreme = geometry::get<Dimension>(*std::max_element(extremes.begin(), extremes.end(), detail::extreme_points::compare<Dimension>()));
+ if (max_extreme > max_intruder)
+ {
+ detail::extreme_points::move_along_vector<Dimension>(extremes, max_intruder);
+ }
+ else
+ {
+ replace_extremes_for_self_tangencies<Dimension>(extremes, intruders, max_intruder);
+ }
+ }
+ }
+
+ // Now calculate the average/centroid of the (possibly adapted) extremes
+ calculate_average(point, extremes);
+
+ return true;
+}
+
+}} // namespace detail::point_on_surface
+#endif // DOXYGEN_NO_DETAIL
+
+
+/*!
+\brief Assigns a Point guaranteed to lie on the surface of the Geometry
+\tparam Geometry geometry type. This also defines the type of the output point
+\param geometry Geometry to take point from
+\param point Point to assign
+ */
+template <typename Geometry, typename Point>
+inline void point_on_surface(Geometry const& geometry, Point & point)
+{
+ concept::check<Point>();
+ concept::check<Geometry const>();
+
+ // First try in Y-direction (which should always succeed for valid polygons)
+ if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point))
+ {
+ // For invalid polygons, we might try X-direction
+ detail::point_on_surface::calculate_point_on_surface<0>(geometry, point);
+ }
+}
+
+/*!
+\brief Returns point guaranteed to lie on the surface of the Geometry
+\tparam Geometry geometry type. This also defines the type of the output point
+\param geometry Geometry to take point from
+\return The Point guaranteed to lie on the surface of the Geometry
+ */
+template<typename Geometry>
+inline typename geometry::point_type<Geometry>::type
+return_point_on_surface(Geometry const& geometry)
+{
+ typename geometry::point_type<Geometry>::type result;
+ geometry::point_on_surface(geometry, result);
+ return result;
+}
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP
diff --git a/boost/geometry/algorithms/remove_spikes.hpp b/boost/geometry/algorithms/remove_spikes.hpp
new file mode 100644
index 0000000000..e62ea9fe3d
--- /dev/null
+++ b/boost/geometry/algorithms/remove_spikes.hpp
@@ -0,0 +1,280 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
+
+#include <deque>
+
+#include <boost/range.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
+
+
+/*
+Remove spikes from a ring/polygon.
+Ring (having 8 vertices, including closing vertex)
++------+
+| |
+| +--+
+| | ^this "spike" is removed, can be located outside/inside the ring
++------+
+(the actualy determination if it is removed is done by a strategy)
+
+*/
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace remove_spikes
+{
+
+
+template <typename Range>
+struct range_remove_spikes
+{
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Range>::type
+ >::type side_strategy;
+
+ typedef typename coordinate_type<Range>::type coordinate_type;
+ typedef typename point_type<Range>::type point_type;
+
+
+ static inline void apply(Range& range)
+ {
+ std::size_t n = boost::size(range);
+ std::size_t const min_num_points = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Range>::value
+ >::value - 1; // subtract one: a polygon with only one spike should result into one point
+ if (n < min_num_points)
+ {
+ return;
+ }
+
+ std::deque<point_type> cleaned;
+ for (typename boost::range_iterator<Range const>::type it = boost::begin(range);
+ it != boost::end(range); ++it)
+ {
+ // Add point
+ cleaned.push_back(*it);
+
+ while(cleaned.size() >= 3
+ && detail::point_is_spike_or_equal(cleaned.back(), *(cleaned.end() - 3), *(cleaned.end() - 2)))
+ {
+ // Remove pen-ultimate point causing the spike (or which was equal)
+ cleaned.erase(cleaned.end() - 2);
+ }
+ }
+
+ // For a closed-polygon, remove closing point, this makes checking first point(s) easier and consistent
+ if (geometry::closure<Range>::value == geometry::closed)
+ {
+ cleaned.pop_back();
+ }
+
+ bool found = false;
+ do
+ {
+ found = false;
+ // Check for spike in first point
+ int const penultimate = 2;
+ while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back()))
+ {
+ cleaned.pop_back();
+ found = true;
+ }
+ // Check for spike in second point
+ while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front()))
+ {
+ cleaned.pop_front();
+ found = true;
+ }
+ }
+ while (found);
+
+ if (cleaned.size() == 2)
+ {
+ // Ticket #9871: open polygon with only two points.
+ // the second point forms, by definition, a spike
+ cleaned.pop_back();
+ }
+
+ // Close if necessary
+ if (geometry::closure<Range>::value == geometry::closed)
+ {
+ cleaned.push_back(cleaned.front());
+ }
+
+ // Copy output
+ geometry::clear(range);
+ std::copy(cleaned.begin(), cleaned.end(), std::back_inserter(range));
+ }
+};
+
+
+template <typename Polygon>
+struct polygon_remove_spikes
+{
+ static inline void apply(Polygon& polygon)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+
+ typedef range_remove_spikes<ring_type> per_range;
+ per_range::apply(exterior_ring(polygon));
+
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(polygon);
+
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
+ {
+ per_range::apply(*it);
+ }
+ }
+};
+
+
+template <typename MultiGeometry, typename SingleVersion>
+struct multi_remove_spikes
+{
+ static inline void apply(MultiGeometry& multi)
+ {
+ for (typename boost::range_iterator<MultiGeometry>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ SingleVersion::apply(*it);
+ }
+ }
+};
+
+
+}} // namespace detail::remove_spikes
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct remove_spikes
+{
+ static inline void apply(Geometry&)
+ {}
+};
+
+
+template <typename Ring>
+struct remove_spikes<Ring, ring_tag>
+ : detail::remove_spikes::range_remove_spikes<Ring>
+{};
+
+
+
+template <typename Polygon>
+struct remove_spikes<Polygon, polygon_tag>
+ : detail::remove_spikes::polygon_remove_spikes<Polygon>
+{};
+
+
+template <typename MultiPolygon>
+struct remove_spikes<MultiPolygon, multi_polygon_tag>
+ : detail::remove_spikes::multi_remove_spikes
+ <
+ MultiPolygon,
+ detail::remove_spikes::polygon_remove_spikes
+ <
+ typename boost::range_value<MultiPolygon>::type
+ >
+ >
+{};
+
+
+} // namespace dispatch
+#endif
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct remove_spikes
+{
+ static void apply(Geometry& geometry)
+ {
+ concept::check<Geometry>();
+ dispatch::remove_spikes<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<void>
+ {
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ remove_spikes<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+ \ingroup remove_spikes
+ \tparam Geometry geometry type
+ \param geometry the geometry to make remove_spikes
+*/
+template <typename Geometry>
+inline void remove_spikes(Geometry& geometry)
+{
+ resolve_variant::remove_spikes<Geometry>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
diff --git a/boost/geometry/algorithms/reverse.hpp b/boost/geometry/algorithms/reverse.hpp
index bf0ef2d9a9..17b23ffdfb 100644
--- a/boost/geometry/algorithms/reverse.hpp
+++ b/boost/geometry/algorithms/reverse.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -17,9 +18,15 @@
#include <algorithm>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -32,9 +39,9 @@ namespace detail { namespace reverse
{
-template <typename Range>
struct range_reverse
{
+ template <typename Range>
static inline void apply(Range& range)
{
std::reverse(boost::begin(range), boost::end(range));
@@ -42,21 +49,20 @@ struct range_reverse
};
-template <typename Polygon>
-struct polygon_reverse
+struct polygon_reverse: private range_reverse
{
+ template <typename Polygon>
static inline void apply(Polygon& polygon)
{
- typedef typename geometry::ring_type<Polygon>::type ring_type;
+ range_reverse::apply(exterior_ring(polygon));
- typedef range_reverse<ring_type> per_range;
- per_range::apply(exterior_ring(polygon));
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(polygon);
- typename interior_return_type<Polygon>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_range::apply(*it);
+ range_reverse::apply(*it);
}
}
};
@@ -71,11 +77,7 @@ namespace dispatch
{
-template
-<
- typename Tag,
- typename Geometry
->
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct reverse
{
static inline void apply(Geometry&)
@@ -84,27 +86,82 @@ struct reverse
template <typename Ring>
-struct reverse<ring_tag, Ring>
- : detail::reverse::range_reverse<Ring>
+struct reverse<Ring, ring_tag>
+ : detail::reverse::range_reverse
{};
template <typename LineString>
-struct reverse<linestring_tag, LineString>
- : detail::reverse::range_reverse<LineString>
+struct reverse<LineString, linestring_tag>
+ : detail::reverse::range_reverse
{};
template <typename Polygon>
-struct reverse<polygon_tag, Polygon>
- : detail::reverse::polygon_reverse<Polygon>
+struct reverse<Polygon, polygon_tag>
+ : detail::reverse::polygon_reverse
{};
+template <typename Geometry>
+struct reverse<Geometry, multi_linestring_tag>
+ : detail::multi_modify
+ <
+ Geometry,
+ detail::reverse::range_reverse
+ >
+{};
+
+
+template <typename Geometry>
+struct reverse<Geometry, multi_polygon_tag>
+ : detail::multi_modify
+ <
+ Geometry,
+ detail::reverse::polygon_reverse
+ >
+{};
+
+
+
} // namespace dispatch
#endif
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct reverse
+{
+ static void apply(Geometry& geometry)
+ {
+ concept::check<Geometry>();
+ dispatch::reverse<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct reverse<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<void>
+ {
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ reverse<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Reverses the points within a geometry
\details Generic function to reverse a geometry. It resembles the std::reverse
@@ -119,13 +176,7 @@ struct reverse<polygon_tag, Polygon>
template <typename Geometry>
inline void reverse(Geometry& geometry)
{
- concept::check<Geometry>();
-
- dispatch::reverse
- <
- typename tag<Geometry>::type,
- Geometry
- >::apply(geometry);
+ resolve_variant::reverse<Geometry>::apply(geometry);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/simplify.hpp b/boost/geometry/algorithms/simplify.hpp
index 225321d303..101b1324e1 100644
--- a/boost/geometry/algorithms/simplify.hpp
+++ b/boost/geometry/algorithms/simplify.hpp
@@ -14,27 +14,30 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
-
#include <cstddef>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
#include <boost/geometry/strategies/concepts/simplify_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
-#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
namespace boost { namespace geometry
{
@@ -43,12 +46,11 @@ namespace boost { namespace geometry
namespace detail { namespace simplify
{
-template<typename Range, typename Strategy>
struct simplify_range_insert
{
- template <typename OutputIterator, typename Distance>
+ template<typename Range, typename Strategy, typename OutputIterator, typename Distance>
static inline void apply(Range const& range, OutputIterator out,
- Distance const& max_distance, Strategy const& strategy)
+ Distance const& max_distance, Strategy const& strategy)
{
if (boost::size(range) <= 2 || max_distance < 0)
{
@@ -62,12 +64,11 @@ struct simplify_range_insert
};
-template<typename Range, typename Strategy>
struct simplify_copy
{
- template <typename Distance>
+ template <typename Range, typename Strategy, typename Distance>
static inline void apply(Range const& range, Range& out,
- Distance const& , Strategy const& )
+ Distance const& , Strategy const& )
{
std::copy
(
@@ -77,10 +78,10 @@ struct simplify_copy
};
-template<typename Range, typename Strategy, std::size_t Minimum>
+template<std::size_t Minimum>
struct simplify_range
{
- template <typename Distance>
+ template <typename Range, typename Strategy, typename Distance>
static inline void apply(Range const& range, Range& out,
Distance const& max_distance, Strategy const& strategy)
{
@@ -101,14 +102,11 @@ struct simplify_range
if (boost::size(range) <= int(Minimum) || max_distance < 0.0)
{
- simplify_copy<Range, Strategy>::apply
- (
- range, out, max_distance, strategy
- );
+ simplify_copy::apply(range, out, max_distance, strategy);
}
else
{
- simplify_range_insert<Range, Strategy>::apply
+ simplify_range_insert::apply
(
range, std::back_inserter(out), max_distance, strategy
);
@@ -116,16 +114,56 @@ struct simplify_range
}
};
-template<typename Polygon, typename Strategy>
struct simplify_polygon
{
- template <typename Distance>
- static inline void apply(Polygon const& poly_in, Polygon& poly_out,
+private:
+
+ template
+ <
+ std::size_t Minimum,
+ typename IteratorIn,
+ typename IteratorOut,
+ typename Distance,
+ typename Strategy
+ >
+ static inline void iterate(IteratorIn begin, IteratorIn end,
+ IteratorOut it_out,
+ Distance const& max_distance, Strategy const& strategy)
+ {
+ for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out)
+ {
+ simplify_range<Minimum>::apply(*it_in, *it_out, max_distance, strategy);
+ }
+ }
+
+ template
+ <
+ std::size_t Minimum,
+ typename InteriorRingsIn,
+ typename InteriorRingsOut,
+ typename Distance,
+ typename Strategy
+ >
+ static inline void apply_interior_rings(
+ InteriorRingsIn const& interior_rings_in,
+ InteriorRingsOut& interior_rings_out,
Distance const& max_distance, Strategy const& strategy)
{
- typedef typename ring_type<Polygon>::type ring_type;
+ traits::resize<InteriorRingsOut>::apply(interior_rings_out,
+ boost::size(interior_rings_in));
- int const Minimum = core_detail::closure::minimum_ring_size
+ iterate<Minimum>(
+ boost::begin(interior_rings_in), boost::end(interior_rings_in),
+ boost::begin(interior_rings_out),
+ max_distance, strategy);
+ }
+
+public:
+ template <typename Polygon, typename Strategy, typename Distance>
+ static inline void apply(Polygon const& poly_in, Polygon& poly_out,
+ Distance const& max_distance, Strategy const& strategy)
+ {
+ std::size_t const minimum = core_detail::closure::minimum_ring_size
<
geometry::closure<Polygon>::value
>::value;
@@ -133,29 +171,34 @@ struct simplify_polygon
// Note that if there are inner rings, and distance is too large,
// they might intersect with the outer ring in the output,
// while it didn't in the input.
- simplify_range<ring_type, Strategy, Minimum>::apply(exterior_ring(poly_in),
- exterior_ring(poly_out),
- max_distance, strategy);
+ simplify_range<minimum>::apply(exterior_ring(poly_in),
+ exterior_ring(poly_out),
+ max_distance, strategy);
- traits::resize
- <
- typename boost::remove_reference
- <
- typename traits::interior_mutable_type<Polygon>::type
- >::type
- >::apply(interior_rings(poly_out), num_interior_rings(poly_in));
-
- typename interior_return_type<Polygon const>::type rings_in
- = interior_rings(poly_in);
- typename interior_return_type<Polygon>::type rings_out
- = interior_rings(poly_out);
- BOOST_AUTO_TPL(it_out, boost::begin(rings_out));
- for (BOOST_AUTO_TPL(it_in, boost::begin(rings_in));
- it_in != boost::end(rings_in);
- ++it_in, ++it_out)
+ apply_interior_rings<minimum>(interior_rings(poly_in),
+ interior_rings(poly_out),
+ max_distance, strategy);
+ }
+};
+
+
+template<typename Policy>
+struct simplify_multi
+{
+ template <typename MultiGeometry, typename Strategy, typename Distance>
+ static inline void apply(MultiGeometry const& multi, MultiGeometry& out,
+ Distance const& max_distance, Strategy const& strategy)
+ {
+ traits::resize<MultiGeometry>::apply(out, boost::size(multi));
+
+ typename boost::range_iterator<MultiGeometry>::type it_out
+ = boost::begin(out);
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it_in = boost::begin(multi);
+ it_in != boost::end(multi);
+ ++it_in, ++it_out)
{
- simplify_range<ring_type, Strategy, Minimum>::apply(*it_in,
- *it_out, max_distance, strategy);
+ Policy::apply(*it_in, *it_out, max_distance, strategy);
}
}
};
@@ -169,15 +212,18 @@ struct simplify_polygon
namespace dispatch
{
-template <typename Tag, typename Geometry, typename Strategy>
-struct simplify
-{
-};
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct simplify: not_implemented<Tag>
+{};
-template <typename Point, typename Strategy>
-struct simplify<point_tag, Point, Strategy>
+template <typename Point>
+struct simplify<Point, point_tag>
{
- template <typename Distance>
+ template <typename Distance, typename Strategy>
static inline void apply(Point const& point, Point& out,
Distance const& , Strategy const& )
{
@@ -186,22 +232,15 @@ struct simplify<point_tag, Point, Strategy>
};
-template <typename Linestring, typename Strategy>
-struct simplify<linestring_tag, Linestring, Strategy>
- : detail::simplify::simplify_range
- <
- Linestring,
- Strategy,
- 2
- >
+template <typename Linestring>
+struct simplify<Linestring, linestring_tag>
+ : detail::simplify::simplify_range<2>
{};
-template <typename Ring, typename Strategy>
-struct simplify<ring_tag, Ring, Strategy>
+template <typename Ring>
+struct simplify<Ring, ring_tag>
: detail::simplify::simplify_range
<
- Ring,
- Strategy,
core_detail::closure::minimum_ring_size
<
geometry::closure<Ring>::value
@@ -209,38 +248,46 @@ struct simplify<ring_tag, Ring, Strategy>
>
{};
-template <typename Polygon, typename Strategy>
-struct simplify<polygon_tag, Polygon, Strategy>
+template <typename Polygon>
+struct simplify<Polygon, polygon_tag>
: detail::simplify::simplify_polygon
- <
- Polygon,
- Strategy
- >
{};
-template <typename Tag, typename Geometry, typename Strategy>
-struct simplify_insert
-{
-};
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct simplify_insert: not_implemented<Tag>
+{};
-template <typename Linestring, typename Strategy>
-struct simplify_insert<linestring_tag, Linestring, Strategy>
+template <typename Linestring>
+struct simplify_insert<Linestring, linestring_tag>
: detail::simplify::simplify_range_insert
- <
- Linestring,
- Strategy
- >
{};
-template <typename Ring, typename Strategy>
-struct simplify_insert<ring_tag, Ring, Strategy>
+template <typename Ring>
+struct simplify_insert<Ring, ring_tag>
: detail::simplify::simplify_range_insert
- <
- Ring,
- Strategy
- >
+{};
+
+template <typename MultiPoint>
+struct simplify<MultiPoint, multi_point_tag>
+ : detail::simplify::simplify_copy
+{};
+
+
+template <typename MultiLinestring>
+struct simplify<MultiLinestring, multi_linestring_tag>
+ : detail::simplify::simplify_multi<detail::simplify::simplify_range<2> >
+{};
+
+
+template <typename MultiPolygon>
+struct simplify<MultiPolygon, multi_polygon_tag>
+ : detail::simplify::simplify_multi<detail::simplify::simplify_polygon>
{};
@@ -248,6 +295,146 @@ struct simplify_insert<ring_tag, Ring, Strategy>
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy
+{
+
+struct simplify
+{
+ template <typename Geometry, typename Distance, typename Strategy>
+ static inline void apply(Geometry const& geometry,
+ Geometry& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ dispatch::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
+ }
+
+ template <typename Geometry, typename Distance>
+ static inline void apply(Geometry const& geometry,
+ Geometry& out,
+ Distance const& max_distance,
+ default_strategy)
+ {
+ typedef typename point_type<Geometry>::type point_type;
+
+ typedef typename strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag, point_type
+ >::type ds_strategy_type;
+
+ typedef strategy::simplify::douglas_peucker
+ <
+ point_type, ds_strategy_type
+ > strategy_type;
+
+ BOOST_CONCEPT_ASSERT(
+ (concept::SimplifyStrategy<strategy_type, point_type>)
+ );
+
+ apply(geometry, out, max_distance, strategy_type());
+ }
+};
+
+struct simplify_insert
+{
+ template
+ <
+ typename Geometry,
+ typename OutputIterator,
+ typename Distance,
+ typename Strategy
+ >
+ static inline void apply(Geometry const& geometry,
+ OutputIterator& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy);
+ }
+
+ template <typename Geometry, typename OutputIterator, typename Distance>
+ static inline void apply(Geometry const& geometry,
+ OutputIterator& out,
+ Distance const& max_distance,
+ default_strategy)
+ {
+ typedef typename point_type<Geometry>::type point_type;
+
+ typedef typename strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag, point_type
+ >::type ds_strategy_type;
+
+ typedef strategy::simplify::douglas_peucker
+ <
+ point_type, ds_strategy_type
+ > strategy_type;
+
+ BOOST_CONCEPT_ASSERT(
+ (concept::SimplifyStrategy<strategy_type, point_type>)
+ );
+
+ apply(geometry, out, max_distance, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct simplify
+{
+ template <typename Distance, typename Strategy>
+ static inline void apply(Geometry const& geometry,
+ Geometry& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ resolve_strategy::simplify::apply(geometry, out, max_distance, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct simplify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Distance, typename Strategy>
+ struct visitor: boost::static_visitor<void>
+ {
+ Distance const& m_max_distance;
+ Strategy const& m_strategy;
+
+ visitor(Distance const& max_distance, Strategy const& strategy)
+ : m_max_distance(max_distance)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry, Geometry& out) const
+ {
+ simplify<Geometry>::apply(geometry, out, m_max_distance, m_strategy);
+ }
+ };
+
+ template <typename Distance, typename Strategy>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ boost::apply_visitor(
+ visitor<Distance, Strategy>(max_distance, strategy),
+ geometry,
+ out
+ );
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Simplify a geometry using a specified strategy
\ingroup simplify
@@ -271,16 +458,9 @@ inline void simplify(Geometry const& geometry, Geometry& out,
{
concept::check<Geometry>();
- BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) );
-
geometry::clear(out);
- dispatch::simplify
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, out, max_distance, strategy);
+ resolve_variant::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
}
@@ -306,18 +486,7 @@ inline void simplify(Geometry const& geometry, Geometry& out,
{
concept::check<Geometry>();
- typedef typename point_type<Geometry>::type point_type;
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag, point_type
- >::type ds_strategy_type;
-
- typedef strategy::simplify::douglas_peucker
- <
- point_type, ds_strategy_type
- > strategy_type;
-
- simplify(geometry, out, max_distance, strategy_type());
+ simplify(geometry, out, max_distance, default_strategy());
}
@@ -343,17 +512,11 @@ namespace detail { namespace simplify
*/
template<typename Geometry, typename OutputIterator, typename Distance, typename Strategy>
inline void simplify_insert(Geometry const& geometry, OutputIterator out,
- Distance const& max_distance, Strategy const& strategy)
+ Distance const& max_distance, Strategy const& strategy)
{
concept::check<Geometry const>();
- BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) );
- dispatch::simplify_insert
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, out, max_distance, strategy);
+ resolve_strategy::simplify_insert::apply(geometry, out, max_distance, strategy);
}
/*!
@@ -369,30 +532,13 @@ inline void simplify_insert(Geometry const& geometry, OutputIterator out,
*/
template<typename Geometry, typename OutputIterator, typename Distance>
inline void simplify_insert(Geometry const& geometry, OutputIterator out,
- Distance const& max_distance)
+ Distance const& max_distance)
{
- typedef typename point_type<Geometry>::type point_type;
-
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
- concept::check<point_type>();
+ concept::check<typename point_type<Geometry>::type>();
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag, point_type
- >::type ds_strategy_type;
-
- typedef strategy::simplify::douglas_peucker
- <
- point_type, ds_strategy_type
- > strategy_type;
-
- dispatch::simplify_insert
- <
- typename tag<Geometry>::type,
- Geometry,
- strategy_type
- >::apply(geometry, out, max_distance, strategy_type());
+ simplify_insert(geometry, out, max_distance, default_strategy());
}
}} // namespace detail::simplify
diff --git a/boost/geometry/algorithms/sym_difference.hpp b/boost/geometry/algorithms/sym_difference.hpp
index 6394576de4..de34c9c7b0 100644
--- a/boost/geometry/algorithms/sym_difference.hpp
+++ b/boost/geometry/algorithms/sym_difference.hpp
@@ -46,11 +46,14 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
@@ -59,36 +62,21 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
out = geometry::dispatch::intersection_insert
<
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
Geometry1, Geometry2,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
+ GeometryOut,
overlay_difference,
- Strategy
- >::apply(geometry1, geometry2, out, strategy);
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value
+ >::apply(geometry1, geometry2, robust_policy, out, strategy);
out = geometry::dispatch::intersection_insert
<
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<GeometryOut>::value,
Geometry2, Geometry1,
+ GeometryOut,
+ overlay_difference,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, true>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- overlay_difference,
- Strategy
- >::apply(geometry2, geometry1, out, strategy);
+ geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
+ >::apply(geometry2, geometry1, robust_policy, out, strategy);
return out;
}
@@ -112,10 +100,12 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out)
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy, OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
@@ -126,10 +116,11 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ RobustPolicy
> strategy_type;
- return sym_difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type());
+ return sym_difference_insert<GeometryOut>(geometry1, geometry2, robust_policy, out, strategy_type());
}
}} // namespace detail::sym_difference
@@ -165,8 +156,17 @@ inline void sym_difference(Geometry1 const& geometry1,
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
detail::sym_difference::sym_difference_insert<geometry_out>(
- geometry1, geometry2,
+ geometry1, geometry2, robust_policy,
std::back_inserter(output_collection));
}
diff --git a/boost/geometry/algorithms/touches.hpp b/boost/geometry/algorithms/touches.hpp
index 7d424af428..a06071d428 100644
--- a/boost/geometry/algorithms/touches.hpp
+++ b/boost/geometry/algorithms/touches.hpp
@@ -3,6 +3,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,6 +15,8 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
@@ -18,70 +24,511 @@
#include <deque>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/detail/for_each_range.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/num_geometries.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate.hpp>
namespace boost { namespace geometry
{
-namespace detail { namespace touches
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace touches
{
-template <typename Turn>
-inline bool ok_for_touch(Turn const& turn)
-{
- return turn.both(detail::overlay::operation_union)
- || turn.both(detail::overlay::operation_blocked)
- || turn.combination(detail::overlay::operation_union, detail::overlay::operation_blocked)
- ;
-}
+// Box/Box
-template <typename Turns>
-inline bool has_only_turns(Turns const& turns)
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box_loop
{
- bool has_touch = false;
- typedef typename boost::range_iterator<Turns const>::type iterator_type;
- for (iterator_type it = boost::begin(turns); it != boost::end(turns); ++it)
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
{
- if (it->has(detail::overlay::operation_intersection))
+ typedef typename coordinate_type<Box1>::type coordinate_type1;
+ typedef typename coordinate_type<Box2>::type coordinate_type2;
+
+ coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
+ coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
+ coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
+ coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
+
+ // TODO assert or exception?
+ //BOOST_ASSERT(min1 <= max1 && min2 <= max2);
+
+ if ( max1 < min2 || max2 < min1 )
{
return false;
}
- switch(it->method)
+ if ( max1 == min2 || max2 == min1 )
+ {
+ touch = true;
+ }
+
+ return box_box_loop
+ <
+ Dimension + 1,
+ DimensionCount
+ >::apply(b1, b2, touch);
+ }
+};
+
+template
+<
+ std::size_t DimensionCount
+>
+struct box_box_loop<DimensionCount, DimensionCount>
+{
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& , Box2 const&, bool &)
+ {
+ return true;
+ }
+};
+
+struct box_box
+{
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& b1, Box2 const& b2)
+ {
+ BOOST_STATIC_ASSERT((boost::is_same
+ <
+ typename geometry::coordinate_system<Box1>::type,
+ typename geometry::coordinate_system<Box2>::type
+ >::value
+ ));
+ assert_dimension_equal<Box1, Box2>();
+
+ bool touches = false;
+ bool ok = box_box_loop
+ <
+ 0,
+ dimension<Box1>::type::value
+ >::apply(b1, b2, touches);
+
+ return ok && touches;
+ }
+};
+
+// Areal/Areal
+
+struct areal_interrupt_policy
+{
+ static bool const enabled = true;
+ bool found_touch;
+ bool found_not_touch;
+
+ // dummy variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
+ inline bool result()
+ {
+ return found_touch && !found_not_touch;
+ }
+
+ inline areal_interrupt_policy()
+ : found_touch(false), found_not_touch(false)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // if already rejected (temp workaround?)
+ if ( found_not_touch )
+ return true;
+
+ typedef typename boost::range_iterator<Range const>::type iterator;
+ for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
+ {
+ if ( it->has(overlay::operation_intersection) )
+ {
+ found_not_touch = true;
+ return true;
+ }
+
+ switch(it->method)
+ {
+ case overlay::method_crosses:
+ found_not_touch = true;
+ return true;
+ case overlay::method_equal:
+ // Segment spatially equal means: at the right side
+ // the polygon internally overlaps. So return false.
+ found_not_touch = true;
+ return true;
+ case overlay::method_touch:
+ case overlay::method_touch_interior:
+ case overlay::method_collinear:
+ if ( ok_for_touch(*it) )
+ {
+ found_touch = true;
+ }
+ else
+ {
+ found_not_touch = true;
+ return true;
+ }
+ break;
+ case overlay::method_none :
+ case overlay::method_disjoint :
+ case overlay::method_error :
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ template <typename Turn>
+ inline bool ok_for_touch(Turn const& turn)
+ {
+ return turn.both(overlay::operation_union)
+ || turn.both(overlay::operation_blocked)
+ || turn.combination(overlay::operation_union, overlay::operation_blocked)
+ ;
+ }
+};
+
+template<typename Geometry>
+struct check_each_ring_for_within
+{
+ bool has_within;
+ Geometry const& m_geometry;
+
+ inline check_each_ring_for_within(Geometry const& g)
+ : has_within(false)
+ , m_geometry(g)
+ {}
+
+ template <typename Range>
+ inline void apply(Range const& range)
+ {
+ typename geometry::point_type<Range>::type p;
+ geometry::point_on_border(p, range);
+ if ( !has_within && geometry::within(p, m_geometry) )
{
- case detail::overlay::method_crosses:
- return false;
- case detail::overlay::method_equal:
- // Segment spatially equal means: at the right side
- // the polygon internally overlaps. So return false.
- return false;
- case detail::overlay::method_touch:
- case detail::overlay::method_touch_interior:
- case detail::overlay::method_collinear:
- if (ok_for_touch(*it))
- {
- has_touch = true;
- }
- else
- {
- return false;
- }
- break;
- case detail::overlay::method_none :
- case detail::overlay::method_disjoint :
- case detail::overlay::method_error :
- break;
+ has_within = true;
}
}
- return has_touch;
+};
+
+template <typename FirstGeometry, typename SecondGeometry>
+inline bool rings_containing(FirstGeometry const& geometry1,
+ SecondGeometry const& geometry2)
+{
+ check_each_ring_for_within<FirstGeometry> checker(geometry1);
+ geometry::detail::for_each_range(geometry2, checker);
+ return checker.has_within;
}
+template <typename Geometry1, typename Geometry2>
+struct areal_areal
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ std::deque<turn_info> turns;
+ detail::touches::areal_interrupt_policy policy;
+ rescale_policy_type robust_policy;
+ boost::geometry::get_turns
+ <
+ detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, robust_policy, turns, policy);
+
+ return policy.result()
+ && ! geometry::detail::touches::rings_containing(geometry1, geometry2)
+ && ! geometry::detail::touches::rings_containing(geometry2, geometry1);
+ }
+};
+
+// P/*
+
+struct use_point_in_geometry
+{
+ template <typename Point, typename Geometry>
+ static inline bool apply(Point const& point, Geometry const& geometry)
+ {
+ return detail::within::point_in_geometry(point, geometry) == 0;
+ }
+};
+
}}
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch {
+
+// TODO: Since CastedTags are used is Reverse needed?
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type,
+ typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type,
+ typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct touches
+ : not_implemented<Tag1, Tag2>
+{};
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2,
+ typename CastedTag1, typename CastedTag2
+>
+struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true>
+ : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false>
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ return touches<Geometry2, Geometry1>::apply(g2, g1);
+ }
+};
+
+// P/P
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct touches<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, pointlike_tag, false>
+{
+ static inline bool apply(Geometry1 const& , Geometry2 const& )
+ {
+ return false;
+ }
+};
+
+// P/*
+
+template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
+struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
+ : detail::touches::use_point_in_geometry
+{};
+
+// TODO: support touches(MPt, Linear/Areal)
+
+// Box/Box
+
+template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
+struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
+ : detail::touches::box_box
+{};
+
+template <typename Box1, typename Box2>
+struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
+ : detail::touches::box_box
+{};
+
+// L/L
+
+template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
+struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_touches_type,
+ Linear1,
+ Linear2
+ >
+{};
+
+// L/A
+
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_touches_type,
+ Linear,
+ Areal
+ >
+{};
+
+// A/L
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, true>
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_touches_type,
+ Areal,
+ Linear
+ >
+{};
+
+// A/A
+
+template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
+struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
+ : detail::touches::areal_areal<Areal1, Areal2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct touches
+{
+ static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return dispatch::touches<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry1), geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)>
+struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+template <typename Geometry>
+struct self_touches
+{
+ static bool apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > policy_type;
+
+ std::deque<turn_info> turns;
+ detail::touches::areal_interrupt_policy policy;
+ rescale_policy_type robust_policy;
+ detail::self_get_turn_points::get_turns
+ <
+ policy_type
+ >::apply(geometry, robust_policy, turns, policy);
+
+ return policy.result();
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return self_touches<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
/*!
\brief \brief_check{has at least one touching point (self-tangency)}
@@ -99,32 +546,7 @@ inline bool has_only_turns(Turns const& turns)
template <typename Geometry>
inline bool touches(Geometry const& geometry)
{
- concept::check<Geometry const>();
-
- typedef detail::overlay::turn_info
- <
- typename geometry::point_type<Geometry>::type
- > turn_info;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry>::type,
- typename point_type<Geometry>::type,
- turn_info,
- detail::overlay::assign_null_policy
- > policy_type;
-
- std::deque<turn_info> turns;
- detail::self_get_turn_points::no_interrupt_policy policy;
- detail::self_get_turn_points::get_turns
- <
- Geometry,
- std::deque<turn_info>,
- policy_type,
- detail::self_get_turn_points::no_interrupt_policy
- >::apply(geometry, turns, policy);
-
- return detail::touches::has_only_turns(turns);
+ return resolve_variant::self_touches<Geometry>::apply(geometry);
}
@@ -143,39 +565,10 @@ inline bool touches(Geometry const& geometry)
template <typename Geometry1, typename Geometry2>
inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
-
- typedef detail::overlay::turn_info
- <
- typename geometry::point_type<Geometry1>::type
- > turn_info;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type,
- turn_info,
- detail::overlay::assign_null_policy
- > policy_type;
-
- std::deque<turn_info> turns;
- detail::get_turns::no_interrupt_policy policy;
- boost::geometry::get_turns
- <
- false, false,
- detail::overlay::assign_null_policy
- >(geometry1, geometry2, turns, policy);
-
- return detail::touches::has_only_turns(turns)
- && ! geometry::detail::disjoint::rings_containing(geometry1, geometry2)
- && ! geometry::detail::disjoint::rings_containing(geometry2, geometry1)
- ;
+ return resolve_variant::touches<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
-
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
diff --git a/boost/geometry/algorithms/transform.hpp b/boost/geometry/algorithms/transform.hpp
index 22b45dc77e..1d6e8d0a35 100644
--- a/boost/geometry/algorithms/transform.hpp
+++ b/boost/geometry/algorithms/transform.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,10 +19,14 @@
#include <iterator>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/core/cs.hpp>
@@ -30,7 +35,9 @@
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/transform.hpp>
@@ -41,9 +48,9 @@ namespace boost { namespace geometry
namespace detail { namespace transform
{
-template <typename Point1, typename Point2, typename Strategy>
struct transform_point
{
+ template <typename Point1, typename Point2, typename Strategy>
static inline bool apply(Point1 const& p1, Point2& p2,
Strategy const& strategy)
{
@@ -52,9 +59,9 @@ struct transform_point
};
-template <typename Box1, typename Box2, typename Strategy>
struct transform_box
{
+ template <typename Box1, typename Box2, typename Strategy>
static inline bool apply(Box1 const& b1, Box2& b2,
Strategy const& strategy)
{
@@ -91,9 +98,9 @@ struct transform_box
}
};
-template <typename Geometry1, typename Geometry2, typename Strategy>
struct transform_box_or_segment
{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& source, Geometry2& target,
Strategy const& strategy)
{
@@ -133,12 +140,7 @@ inline bool transform_range_out(Range const& range,
it != boost::end(range);
++it)
{
- if (! transform_point
- <
- typename point_type<Range>::type,
- PointOut,
- Strategy
- >::apply(*it, point_out, strategy))
+ if (! transform_point::apply(*it, point_out, strategy))
{
return false;
}
@@ -148,14 +150,12 @@ inline bool transform_range_out(Range const& range,
}
-template <typename Polygon1, typename Polygon2, typename Strategy>
struct transform_polygon
{
+ template <typename Polygon1, typename Polygon2, typename Strategy>
static inline bool apply(Polygon1 const& poly1, Polygon2& poly2,
Strategy const& strategy)
{
- typedef typename ring_type<Polygon1>::type ring1_type;
- typedef typename ring_type<Polygon2>::type ring2_type;
typedef typename point_type<Polygon2>::type point2_type;
geometry::clear(poly2);
@@ -175,16 +175,20 @@ struct transform_polygon
>::type
>::apply(interior_rings(poly2), num_interior_rings(poly1));
- typename interior_return_type<Polygon1 const>::type rings1
- = interior_rings(poly1);
- typename interior_return_type<Polygon2>::type rings2
- = interior_rings(poly2);
- BOOST_AUTO_TPL(it1, boost::begin(rings1));
- BOOST_AUTO_TPL(it2, boost::begin(rings2));
- for ( ; it1 != boost::end(interior_rings(poly1)); ++it1, ++it2)
+ typename interior_return_type<Polygon1 const>::type
+ rings1 = interior_rings(poly1);
+ typename interior_return_type<Polygon2>::type
+ rings2 = interior_rings(poly2);
+
+ typename detail::interior_iterator<Polygon1 const>::type
+ it1 = boost::begin(rings1);
+ typename detail::interior_iterator<Polygon2>::type
+ it2 = boost::begin(rings2);
+ for ( ; it1 != boost::end(rings1); ++it1, ++it2)
{
- if (!transform_range_out<point2_type>(*it1,
- std::back_inserter(*it2), strategy))
+ if ( ! transform_range_out<point2_type>(*it1,
+ std::back_inserter(*it2),
+ strategy) )
{
return false;
}
@@ -211,9 +215,9 @@ struct select_strategy
>::type type;
};
-template <typename Range1, typename Range2, typename Strategy>
struct transform_range
{
+ template <typename Range1, typename Range2, typename Strategy>
static inline bool apply(Range1 const& range1,
Range2& range2, Strategy const& strategy)
{
@@ -226,6 +230,36 @@ struct transform_range
}
};
+
+/*!
+ \brief Is able to transform any multi-geometry, calling the single-version as policy
+*/
+template <typename Policy>
+struct transform_multi
+{
+ template <typename Multi1, typename Multi2, typename S>
+ static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy)
+ {
+ traits::resize<Multi2>::apply(multi2, boost::size(multi1));
+
+ typename boost::range_iterator<Multi1 const>::type it1
+ = boost::begin(multi1);
+ typename boost::range_iterator<Multi2>::type it2
+ = boost::begin(multi2);
+
+ for (; it1 != boost::end(multi1); ++it1, ++it2)
+ {
+ if (! Policy::apply(*it1, *it2, strategy))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+
}} // namespace detail::transform
#endif // DOXYGEN_NO_DETAIL
@@ -236,58 +270,166 @@ namespace dispatch
template
<
- typename Tag1, typename Tag2,
typename Geometry1, typename Geometry2,
- typename Strategy
+ typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
+ typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type
>
struct transform {};
-template <typename Point1, typename Point2, typename Strategy>
-struct transform<point_tag, point_tag, Point1, Point2, Strategy>
- : detail::transform::transform_point<Point1, Point2, Strategy>
+template <typename Point1, typename Point2>
+struct transform<Point1, Point2, point_tag, point_tag>
+ : detail::transform::transform_point
{
};
-template <typename Linestring1, typename Linestring2, typename Strategy>
+template <typename Linestring1, typename Linestring2>
struct transform
<
- linestring_tag, linestring_tag,
- Linestring1, Linestring2, Strategy
+ Linestring1, Linestring2,
+ linestring_tag, linestring_tag
>
- : detail::transform::transform_range<Linestring1, Linestring2, Strategy>
+ : detail::transform::transform_range
{
};
-template <typename Range1, typename Range2, typename Strategy>
-struct transform<ring_tag, ring_tag, Range1, Range2, Strategy>
- : detail::transform::transform_range<Range1, Range2, Strategy>
+template <typename Range1, typename Range2>
+struct transform<Range1, Range2, ring_tag, ring_tag>
+ : detail::transform::transform_range
{
};
-template <typename Polygon1, typename Polygon2, typename Strategy>
-struct transform<polygon_tag, polygon_tag, Polygon1, Polygon2, Strategy>
- : detail::transform::transform_polygon<Polygon1, Polygon2, Strategy>
+template <typename Polygon1, typename Polygon2>
+struct transform<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : detail::transform::transform_polygon
{
};
-template <typename Box1, typename Box2, typename Strategy>
-struct transform<box_tag, box_tag, Box1, Box2, Strategy>
- : detail::transform::transform_box<Box1, Box2, Strategy>
+template <typename Box1, typename Box2>
+struct transform<Box1, Box2, box_tag, box_tag>
+ : detail::transform::transform_box
{
};
-template <typename Segment1, typename Segment2, typename Strategy>
-struct transform<segment_tag, segment_tag, Segment1, Segment2, Strategy>
- : detail::transform::transform_box_or_segment<Segment1, Segment2, Strategy>
+template <typename Segment1, typename Segment2>
+struct transform<Segment1, Segment2, segment_tag, segment_tag>
+ : detail::transform::transform_box_or_segment
{
};
+template <typename Multi1, typename Multi2>
+struct transform
+ <
+ Multi1, Multi2,
+ multi_tag, multi_tag
+ >
+ : detail::transform::transform_multi
+ <
+ dispatch::transform
+ <
+ typename boost::range_value<Multi1>::type,
+ typename boost::range_value<Multi2>::type
+ >
+ >
+{};
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy {
+
+struct transform
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2& geometry2,
+ Strategy const& strategy)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2>();
+
+ return dispatch::transform<Geometry1, Geometry2>::apply(
+ geometry1,
+ geometry2,
+ strategy
+ );
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2& geometry2,
+ default_strategy)
+ {
+ return apply(
+ geometry1,
+ geometry2,
+ typename detail::transform::select_strategy<Geometry1, Geometry2>::type()
+ );
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct transform
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2& geometry2,
+ Strategy const& strategy)
+ {
+ return resolve_strategy::transform::apply(
+ geometry1,
+ geometry2,
+ strategy
+ );
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct transform<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ inline bool operator()(Geometry1 const& geometry1) const
+ {
+ return transform<Geometry1, Geometry2>::apply(
+ geometry1,
+ m_geometry2,
+ m_strategy
+ );
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Transforms from one geometry to another geometry \brief_strategy
\ingroup transform
@@ -307,19 +449,8 @@ template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2,
Strategy const& strategy)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2>();
-
- typedef dispatch::transform
- <
- typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
- typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
- Geometry1,
- Geometry2,
- Strategy
- > transform_type;
-
- return transform_type::apply(geometry1, geometry2, strategy);
+ return resolve_variant::transform<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, strategy);
}
@@ -337,11 +468,7 @@ inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2,
template <typename Geometry1, typename Geometry2>
inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2>();
-
- typename detail::transform::select_strategy<Geometry1, Geometry2>::type strategy;
- return transform(geometry1, geometry2, strategy);
+ return transform(geometry1, geometry2, default_strategy());
}
diff --git a/boost/geometry/algorithms/union.hpp b/boost/geometry/algorithms/union.hpp
index 28d8e5dc0b..ff16c60ea1 100644
--- a/boost/geometry/algorithms/union.hpp
+++ b/boost/geometry/algorithms/union.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -10,15 +15,18 @@
#define BOOST_GEOMETRY_ALGORITHMS_UNION_HPP
-#include <boost/mpl/if.hpp>
-
#include <boost/range/metafunctions.hpp>
#include <boost/geometry/core/is_areal.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
namespace boost { namespace geometry
@@ -30,170 +38,146 @@ namespace dispatch
template
<
- // tag dispatching:
+ typename Geometry1, typename Geometry2, typename GeometryOut,
+ typename TagIn1 = typename tag<Geometry1>::type,
+ typename TagIn2 = typename tag<Geometry2>::type,
+ typename TagOut = typename tag<GeometryOut>::type,
+ bool Areal1 = geometry::is_areal<Geometry1>::value,
+ bool Areal2 = geometry::is_areal<Geometry2>::value,
+ bool ArealOut = geometry::is_areal<GeometryOut>::value,
+ bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ bool ReverseOut = detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
+ bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct union_insert: not_implemented<TagIn1, TagIn2, TagOut>
+{};
+
+
+// If reversal is needed, perform it first
+
+template
+<
+ typename Geometry1, typename Geometry2, typename GeometryOut,
typename TagIn1, typename TagIn2, typename TagOut,
- // metafunction finetuning helpers:
bool Areal1, bool Areal2, bool ArealOut,
- // real types
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
- typename GeometryOut,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct union_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ TagIn1, TagIn2, TagOut,
+ Areal1, Areal2, ArealOut,
+ Reverse1, Reverse2, ReverseOut,
+ true
+ >: union_insert<Geometry2, Geometry1, GeometryOut>
{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES
- , (types<Geometry1, Geometry2, GeometryOut>)
- );
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Geometry1 const& g1,
+ Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ return union_insert
+ <
+ Geometry2, Geometry1, GeometryOut
+ >::apply(g2, g1, robust_policy, out, strategy);
+ }
};
template
<
+ typename Geometry1, typename Geometry2, typename GeometryOut,
typename TagIn1, typename TagIn2, typename TagOut,
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
- typename GeometryOut,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct union_insert
<
+ Geometry1, Geometry2, GeometryOut,
TagIn1, TagIn2, TagOut,
true, true, true,
- Geometry1, Geometry2,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- Strategy
+ false
> : detail::overlay::overlay
- <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, overlay_union, Strategy>
+ <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, overlay_union>
{};
-
+// dispatch for union of non-areal geometries
template
<
- typename GeometryTag1, typename GeometryTag2, typename GeometryTag3,
- bool Areal1, bool Areal2, bool ArealOut,
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- typename Strategy
+ typename Geometry1, typename Geometry2, typename GeometryOut,
+ typename TagIn1, typename TagIn2, typename TagOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
-struct union_insert_reversed
-{
- static inline OutputIterator apply(Geometry1 const& g1,
- Geometry2 const& g2, OutputIterator out,
- Strategy const& strategy)
- {
- return union_insert
- <
- GeometryTag2, GeometryTag1, GeometryTag3,
- Areal2, Areal1, ArealOut,
- Geometry2, Geometry1,
- Reverse2, Reverse1, ReverseOut,
- OutputIterator, GeometryOut,
- Strategy
- >::apply(g2, g1, out, strategy);
- }
-};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+struct union_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ TagIn1, TagIn2, TagOut,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ > : union_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type,
+ typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type,
+ TagOut,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ >
+{};
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace union_
-{
+// dispatch for union of linear geometries
template
<
- typename GeometryOut,
- typename Geometry1, typename Geometry2,
- typename OutputIterator,
- typename Strategy
+ typename Linear1, typename Linear2, typename LineStringOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
-inline OutputIterator insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- OutputIterator out,
- Strategy const& strategy)
-{
- return boost::mpl::if_c
+struct union_insert
+ <
+ Linear1, Linear2, LineStringOut,
+ linear_tag, linear_tag, linestring_tag,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ > : detail::overlay::linear_linear_linestring
<
- geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::union_insert_reversed
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
- overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- Strategy
- >,
- dispatch::union_insert
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
- overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- Strategy
- >
- >::type::apply(geometry1, geometry2, out, strategy);
-}
+ Linear1, Linear2, LineStringOut, overlay_union
+ >
+{};
-/*!
-\brief_calc2{union} \brief_strategy
-\ingroup union
-\details \details_calc2{union_insert, spatial set theoretic union}
- \brief_strategy. details_insert{union}
-\tparam GeometryOut output geometry type, must be specified
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam OutputIterator output iterator
-\tparam Strategy \tparam_strategy_overlay
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param out \param_out{union}
-\param strategy \param_strategy{union}
-\return \return_out
-\qbk{distinguish,with strategy}
-*/
+// dispatch for point-like geometries
template
<
- typename GeometryOut,
- typename Geometry1,
- typename Geometry2,
- typename OutputIterator,
- typename Strategy
+ typename PointLike1, typename PointLike2, typename PointOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
-inline OutputIterator union_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- OutputIterator out,
- Strategy const& strategy)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- concept::check<GeometryOut>();
+struct union_insert
+ <
+ PointLike1, PointLike2, PointOut,
+ pointlike_tag, pointlike_tag, point_tag,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ > : detail::overlay::union_pointlike_pointlike_point
+ <
+ PointLike1, PointLike2, PointOut
+ >
+{};
- return detail::union_::insert<GeometryOut>(geometry1, geometry2, out, strategy);
-}
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace union_
+{
/*!
\brief_calc2{union}
@@ -224,15 +208,28 @@ inline OutputIterator union_insert(Geometry1 const& geometry1,
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ rescale_policy_type
> strategy;
- return union_insert<GeometryOut>(geometry1, geometry2, out, strategy());
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
+ return dispatch::union_insert
+ <
+ Geometry1, Geometry2, GeometryOut
+ >::apply(geometry1, geometry2, robust_policy, out, strategy());
}
diff --git a/boost/geometry/algorithms/unique.hpp b/boost/geometry/algorithms/unique.hpp
index 3bbf479f9b..fed9f8af4b 100644
--- a/boost/geometry/algorithms/unique.hpp
+++ b/boost/geometry/algorithms/unique.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -17,10 +18,12 @@
#include <algorithm>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/policies/compare.hpp>
@@ -34,9 +37,9 @@ namespace detail { namespace unique
{
-template <typename Range, typename ComparePolicy>
struct range_unique
{
+ template <typename Range, typename ComparePolicy>
static inline void apply(Range& range, ComparePolicy const& policy)
{
typename boost::range_iterator<Range>::type it
@@ -52,26 +55,41 @@ struct range_unique
};
-template <typename Polygon, typename ComparePolicy>
struct polygon_unique
{
+ template <typename Polygon, typename ComparePolicy>
static inline void apply(Polygon& polygon, ComparePolicy const& policy)
{
- typedef typename geometry::ring_type<Polygon>::type ring_type;
+ range_unique::apply(exterior_ring(polygon), policy);
- typedef range_unique<ring_type, ComparePolicy> per_range;
- per_range::apply(exterior_ring(polygon), policy);
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(polygon);
- typename interior_return_type<Polygon>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_range::apply(*it, policy);
+ range_unique::apply(*it, policy);
}
}
};
+template <typename Policy>
+struct multi_unique
+{
+ template <typename MultiGeometry, typename ComparePolicy>
+ static inline void apply(MultiGeometry& multi, ComparePolicy const& compare)
+ {
+ for (typename boost::range_iterator<MultiGeometry>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, compare);
+ }
+ }
+};
+
}} // namespace detail::unique
#endif // DOXYGEN_NO_DETAIL
@@ -85,32 +103,50 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
- typename ComparePolicy
+ typename Tag = typename tag<Geometry>::type
>
struct unique
{
+ template <typename ComparePolicy>
static inline void apply(Geometry&, ComparePolicy const& )
{}
};
-template <typename Ring, typename ComparePolicy>
-struct unique<ring_tag, Ring, ComparePolicy>
- : detail::unique::range_unique<Ring, ComparePolicy>
+template <typename Ring>
+struct unique<Ring, ring_tag>
+ : detail::unique::range_unique
+{};
+
+
+template <typename LineString>
+struct unique<LineString, linestring_tag>
+ : detail::unique::range_unique
+{};
+
+
+template <typename Polygon>
+struct unique<Polygon, polygon_tag>
+ : detail::unique::polygon_unique
{};
-template <typename LineString, typename ComparePolicy>
-struct unique<linestring_tag, LineString, ComparePolicy>
- : detail::unique::range_unique<LineString, ComparePolicy>
+// For points, unique is not applicable and does nothing
+// (Note that it is not "spatially unique" but that it removes duplicate coordinates,
+// like std::unique does). Spatially unique is "dissolve" which can (or will be)
+// possible for multi-points as well, removing points at the same location.
+
+
+template <typename MultiLineString>
+struct unique<MultiLineString, multi_linestring_tag>
+ : detail::unique::multi_unique<detail::unique::range_unique>
{};
-template <typename Polygon, typename ComparePolicy>
-struct unique<polygon_tag, Polygon, ComparePolicy>
- : detail::unique::polygon_unique<Polygon, ComparePolicy>
+template <typename MultiPolygon>
+struct unique<MultiPolygon, multi_polygon_tag>
+ : detail::unique::multi_unique<detail::unique::polygon_unique>
{};
@@ -139,12 +175,7 @@ inline void unique(Geometry& geometry)
> policy;
- dispatch::unique
- <
- typename tag<Geometry>::type,
- Geometry,
- policy
- >::apply(geometry, policy());
+ dispatch::unique<Geometry>::apply(geometry, policy());
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/within.hpp b/boost/geometry/algorithms/within.hpp
index f1f0993d77..f66b1ed1c6 100644
--- a/boost/geometry/algorithms/within.hpp
+++ b/boost/geometry/algorithms/within.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,14 +14,19 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP
#define BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP
#include <cstddef>
+#include <boost/concept_check.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/make.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
@@ -34,131 +42,47 @@
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/concepts/within_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+#include <deque>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace within
-{
+namespace detail { namespace within {
-
-template
-<
- typename Point,
- typename Ring,
- iterate_direction Direction,
- closure_selector Closure,
- typename Strategy
->
-struct point_in_ring
+struct use_point_in_geometry
{
- BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) );
-
- static inline int apply(Point const& point, Ring const& ring,
- Strategy const& strategy)
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
- if (int(boost::size(ring))
- < core_detail::closure::minimum_ring_size<Closure>::value)
- {
- return -1;
- }
-
- typedef typename reversible_view<Ring const, Direction>::type rev_view_type;
- typedef typename closeable_view
- <
- rev_view_type const, Closure
- >::type cl_view_type;
- typedef typename boost::range_iterator<cl_view_type const>::type iterator_type;
-
- rev_view_type rev_view(ring);
- cl_view_type view(rev_view);
- typename Strategy::state_type state;
- iterator_type it = boost::begin(view);
- iterator_type end = boost::end(view);
-
- bool stop = false;
- for (iterator_type previous = it++;
- it != end && ! stop;
- ++previous, ++it)
- {
- if (! strategy.apply(point, *previous, *it, state))
- {
- stop = true;
- }
- }
-
- return strategy.result(state);
+ return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1;
}
};
-
-// Polygon: in exterior ring, and if so, not within interior ring(s)
-template
-<
- typename Point,
- typename Polygon,
- iterate_direction Direction,
- closure_selector Closure,
- typename Strategy
->
-struct point_in_polygon
+struct use_relate
{
- BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) );
-
- static inline int apply(Point const& point, Polygon const& poly,
- Strategy const& strategy)
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& /*strategy*/)
{
- int const code = point_in_ring
- <
- Point,
- typename ring_type<Polygon>::type,
- Direction,
- Closure,
- Strategy
- >::apply(point, exterior_ring(poly), strategy);
-
- if (code == 1)
- {
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings));
- it != boost::end(rings);
- ++it)
- {
- int const interior_code = point_in_ring
- <
- Point,
- typename ring_type<Polygon>::type,
- Direction,
- Closure,
- Strategy
- >::apply(point, *it, strategy);
-
- if (interior_code != -1)
- {
- // 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 code;
+ return Strategy::apply(geometry1, geometry2);
}
};
}} // namespace detail::within
#endif // DOXYGEN_NO_DETAIL
-
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
@@ -170,7 +94,8 @@ template
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
-struct within: not_implemented<Tag1, Tag2>
+struct within
+ : not_implemented<Tag1, Tag2>
{};
@@ -180,6 +105,7 @@ struct within<Point, Box, point_tag, box_tag>
template <typename Strategy>
static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
{
+ boost::ignore_unused_variable_warning(strategy);
return strategy.apply(point, box);
}
};
@@ -191,48 +117,349 @@ struct within<Box1, Box2, box_tag, box_tag>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
assert_dimension_equal<Box1, Box2>();
+ boost::ignore_unused_variable_warning(strategy);
return strategy.apply(box1, box2);
}
};
+// P/P
+template <typename Point1, typename Point2>
+struct within<Point1, Point2, point_tag, point_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPoint>
+struct within<Point, MultiPoint, point_tag, multi_point_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+// P/L
+
+template <typename Point, typename Segment>
+struct within<Point, Segment, point_tag, segment_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename Linestring>
+struct within<Point, Linestring, point_tag, linestring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiLinestring>
+struct within<Point, MultiLinestring, point_tag, multi_linestring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+// P/A
template <typename Point, typename Ring>
struct within<Point, Ring, point_tag, ring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename Polygon>
+struct within<Point, Polygon, point_tag, polygon_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPolygon>
+struct within<Point, MultiPolygon, point_tag, multi_polygon_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+// L/L
+
+template <typename Linestring1, typename Linestring2>
+struct within<Linestring1, Linestring2, linestring_tag, linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename MultiLinestring>
+struct within<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Linestring>
+struct within<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring1, typename MultiLinestring2>
+struct within<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
+ : public detail::within::use_relate
+{};
+
+// L/A
+
+template <typename Linestring, typename Ring>
+struct within<Linestring, Ring, linestring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Ring>
+struct within<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename Polygon>
+struct within<Linestring, Polygon, linestring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Polygon>
+struct within<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename MultiPolygon>
+struct within<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename MultiPolygon>
+struct within<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+// A/A
+
+template <typename Ring1, typename Ring2>
+struct within<Ring1, Ring2, ring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Ring, typename Polygon>
+struct within<Ring, Polygon, ring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon, typename Ring>
+struct within<Polygon, Ring, polygon_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct within<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Ring, typename MultiPolygon>
+struct within<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon, typename Ring>
+struct within<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon, typename MultiPolygon>
+struct within<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon, typename Polygon>
+struct within<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon1, typename MultiPolygon2>
+struct within<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
{
- template <typename Strategy>
- static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy)
+
+struct within
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
{
- return detail::within::point_in_ring
+ concept::within::check
<
- Point,
- Ring,
- order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
Strategy
- >::apply(point, ring, strategy) == 1;
+ >();
+
+ return dispatch::within<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename point_type<Geometry1>::type point_type1;
+ typedef typename point_type<Geometry2>::type point_type2;
+
+ typedef typename strategy::within::services::default_strategy
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag<Geometry1>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return apply(geometry1, geometry2, strategy_type());
}
};
-template <typename Point, typename Polygon>
-struct within<Point, Polygon, point_tag, polygon_tag>
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct within
{
template <typename Strategy>
- static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy)
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
{
- return detail::within::point_in_polygon
- <
- Point,
- Polygon,
- order_as_direction<geometry::point_order<Polygon>::value>::value,
- geometry::closure<Polygon>::value,
- Strategy
- >::apply(point, polygon, strategy) == 1;
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+ assert_dimension_equal<Geometry1, Geometry2>();
+
+ return resolve_strategy::within::apply(geometry1,
+ geometry2,
+ strategy);
}
};
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy):
+ m_geometry2(geometry2),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return within<Geometry1, Geometry2>::apply(geometry1,
+ m_geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(
+ visitor<Strategy>(geometry2, strategy),
+ geometry1
+ );
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy):
+ m_geometry1(geometry1),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return within<Geometry1, Geometry2>::apply(m_geometry1,
+ geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(
+ visitor<Strategy>(geometry1, strategy),
+ geometry2
+ );
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct within<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return within<Geometry1, Geometry2>::apply(geometry1,
+ geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(
+ visitor<Strategy>(strategy),
+ geometry1, geometry2
+ );
+ }
+};
+
+}
/*!
@@ -259,36 +486,11 @@ struct within<Point, Polygon, point_tag, polygon_tag>
template<typename Geometry1, typename Geometry2>
inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- typedef typename point_type<Geometry1>::type point_type1;
- typedef typename point_type<Geometry2>::type point_type2;
-
- typedef typename strategy::within::services::default_strategy
+ return resolve_variant::within
<
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<Geometry1>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- typename tag_cast
- <
- typename cs_tag<point_type1>::type, spherical_tag
- >::type,
- typename tag_cast
- <
- typename cs_tag<point_type2>::type, spherical_tag
- >::type,
Geometry1,
Geometry2
- >::type strategy_type;
-
- return dispatch::within
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy_type());
+ >::apply(geometry1, geometry2, default_strategy());
}
/*!
@@ -321,18 +523,7 @@ template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
- concept::within::check
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- Strategy
- >();
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- return dispatch::within
+ return resolve_variant::within
<
Geometry1,
Geometry2
diff --git a/boost/geometry/arithmetic/arithmetic.hpp b/boost/geometry/arithmetic/arithmetic.hpp
index 6479ecc4a6..6eb31f488e 100644
--- a/boost/geometry/arithmetic/arithmetic.hpp
+++ b/boost/geometry/arithmetic/arithmetic.hpp
@@ -117,6 +117,7 @@ struct point_assignment
\brief Adds the same value to each coordinate of a point
\ingroup arithmetic
\details
+ \tparam Point \tparam_point
\param p point
\param value value to add
*/
@@ -133,13 +134,15 @@ inline void add_value(Point& p, typename detail::param<Point>::type value)
\ingroup arithmetic
\details The coordinates of the second point will be added to those of the first point.
The second point is not modified.
+ \tparam Point1 \tparam_point
+ \tparam Point2 \tparam_point
\param p1 first point
\param p2 second point
*/
template <typename Point1, typename Point2>
inline void add_point(Point1& p1, Point2 const& p2)
{
- BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) );
+ BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );
for_each_coordinate(p1, detail::point_operation<Point2, std::plus>(p2));
@@ -149,6 +152,7 @@ inline void add_point(Point1& p1, Point2 const& p2)
\brief Subtracts the same value to each coordinate of a point
\ingroup arithmetic
\details
+ \tparam Point \tparam_point
\param p point
\param value value to subtract
*/
@@ -165,13 +169,15 @@ inline void subtract_value(Point& p, typename detail::param<Point>::type value)
\ingroup arithmetic
\details The coordinates of the second point will be subtracted to those of the first point.
The second point is not modified.
+ \tparam Point1 \tparam_point
+ \tparam Point2 \tparam_point
\param p1 first point
\param p2 second point
*/
template <typename Point1, typename Point2>
inline void subtract_point(Point1& p1, Point2 const& p2)
{
- BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) );
+ BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );
for_each_coordinate(p1, detail::point_operation<Point2, std::minus>(p2));
@@ -181,6 +187,7 @@ inline void subtract_point(Point1& p1, Point2 const& p2)
\brief Multiplies each coordinate of a point by the same value
\ingroup arithmetic
\details
+ \tparam Point \tparam_point
\param p point
\param value value to multiply by
*/
@@ -197,6 +204,8 @@ inline void multiply_value(Point& p, typename detail::param<Point>::type value)
\ingroup arithmetic
\details The coordinates of the first point will be multiplied by those of the second point.
The second point is not modified.
+ \tparam Point1 \tparam_point
+ \tparam Point2 \tparam_point
\param p1 first point
\param p2 second point
\note This is *not* a dot, cross or wedge product. It is a mere field-by-field multiplication.
@@ -204,7 +213,7 @@ inline void multiply_value(Point& p, typename detail::param<Point>::type value)
template <typename Point1, typename Point2>
inline void multiply_point(Point1& p1, Point2 const& p2)
{
- BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) );
+ BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );
for_each_coordinate(p1, detail::point_operation<Point2, std::multiplies>(p2));
@@ -214,6 +223,7 @@ inline void multiply_point(Point1& p1, Point2 const& p2)
\brief Divides each coordinate of the same point by a value
\ingroup arithmetic
\details
+ \tparam Point \tparam_point
\param p point
\param value value to divide by
*/
@@ -230,13 +240,15 @@ inline void divide_value(Point& p, typename detail::param<Point>::type value)
\ingroup arithmetic
\details The coordinates of the first point will be divided by those of the second point.
The second point is not modified.
+ \tparam Point1 \tparam_point
+ \tparam Point2 \tparam_point
\param p1 first point
\param p2 second point
*/
template <typename Point1, typename Point2>
inline void divide_point(Point1& p1, Point2 const& p2)
{
- BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) );
+ BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );
for_each_coordinate(p1, detail::point_operation<Point2, std::divides>(p2));
@@ -246,6 +258,7 @@ inline void divide_point(Point1& p1, Point2 const& p2)
\brief Assign each coordinate of a point the same value
\ingroup arithmetic
\details
+ \tparam Point \tparam_point
\param p point
\param value value to assign
*/
@@ -262,13 +275,15 @@ inline void assign_value(Point& p, typename detail::param<Point>::type value)
\ingroup arithmetic
\details The coordinates of the first point will be assigned those of the second point.
The second point is not modified.
+ \tparam Point1 \tparam_point
+ \tparam Point2 \tparam_point
\param p1 first point
\param p2 second point
*/
template <typename Point1, typename Point2>
-inline void assign_point(Point1& p1, const Point2& p2)
+inline void assign_point(Point1& p1, Point2 const& p2)
{
- BOOST_CONCEPT_ASSERT( (concept::Point<Point2>) );
+ BOOST_CONCEPT_ASSERT( (concept::Point<Point1>) );
BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );
for_each_coordinate(p1, detail::point_assignment<Point2>(p2));
diff --git a/boost/geometry/arithmetic/determinant.hpp b/boost/geometry/arithmetic/determinant.hpp
index db3b867096..14edea7182 100644
--- a/boost/geometry/arithmetic/determinant.hpp
+++ b/boost/geometry/arithmetic/determinant.hpp
@@ -62,7 +62,7 @@ inline ReturnType determinant(U const& u, V const& v)
return calculate_determinant
<
- ReturnType,
+ ReturnType,
typename geometry::coordinate_type<U>::type,
typename geometry::coordinate_type<V>::type
>::apply(get<0>(u), get<1>(u), get<0>(v), get<1>(v));
diff --git a/boost/geometry/arithmetic/dot_product.hpp b/boost/geometry/arithmetic/dot_product.hpp
index 13fe968779..fc2b3844e6 100644
--- a/boost/geometry/arithmetic/dot_product.hpp
+++ b/boost/geometry/arithmetic/dot_product.hpp
@@ -59,21 +59,23 @@ struct dot_product_maker<P1, P2, DimensionCount, DimensionCount>
/*!
\brief Computes the dot product (or scalar product) of 2 vectors (points).
\ingroup arithmetic
+ \tparam Point1 \tparam_point
+ \tparam Point2 \tparam_point
\param p1 first point
\param p2 second point
\return the dot product
*/
-template <typename P1, typename P2>
-inline typename select_coordinate_type<P1, P2>::type dot_product(
- P1 const& p1, P2 const& p2)
+template <typename Point1, typename Point2>
+inline typename select_coordinate_type<Point1, Point2>::type dot_product(
+ Point1 const& p1, Point2 const& p2)
{
- BOOST_CONCEPT_ASSERT( (concept::ConstPoint<P1>) );
- BOOST_CONCEPT_ASSERT( (concept::ConstPoint<P2>) );
+ BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point1>) );
+ BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );
return detail::dot_product_maker
<
- P1, P2,
- 0, dimension<P1>::type::value - 1
+ Point1, Point2,
+ 0, dimension<Point1>::type::value - 1
>::apply(p1, p2);
}
diff --git a/boost/geometry/core/access.hpp b/boost/geometry/core/access.hpp
index cdc8ff9cff..57f925763d 100644
--- a/boost/geometry/core/access.hpp
+++ b/boost/geometry/core/access.hpp
@@ -137,8 +137,8 @@ template
typename Geometry,
typename
CoordinateType,
- std::size_t Dimension,
- typename IsPointer
+ std::size_t Dimension,
+ typename IsPointer
>
struct access
{
@@ -153,7 +153,7 @@ template
typename CoordinateType,
std::size_t Index,
std::size_t Dimension,
- typename IsPointer
+ typename IsPointer
>
struct indexed_access
{
@@ -260,13 +260,15 @@ struct signature_getset_index_dimension {};
\tparam Dimension \tparam_dimension_required
\tparam Geometry \tparam_geometry (usually a Point Concept)
\param geometry \param_geometry (usually a point)
-\param dummy \qbk_skip
\return The coordinate value of specified dimension of specified geometry
+
\qbk{[include reference/core/get_point.qbk]}
*/
template <std::size_t Dimension, typename Geometry>
inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
, detail::signature_getset_dimension* dummy = 0
+#endif
)
{
boost::ignore_unused_variable_warning(dummy);
@@ -277,7 +279,7 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
typename geometry::util::bare_type<Geometry>::type,
typename coordinate_type<Geometry>::type,
Dimension,
- typename boost::is_pointer<Geometry>::type
+ typename boost::is_pointer<Geometry>::type
> coord_access_type;
return coord_access_type::get(geometry);
@@ -292,7 +294,6 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
\param geometry geometry to assign coordinate to
\param geometry \param_geometry (usually a point)
\param value The coordinate value to set
-\param dummy \qbk_skip
\ingroup set
\qbk{[include reference/core/set_point.qbk]}
@@ -300,7 +301,9 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
template <std::size_t Dimension, typename Geometry>
inline void set(Geometry& geometry
, typename coordinate_type<Geometry>::type const& value
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
, detail::signature_getset_dimension* dummy = 0
+#endif
)
{
boost::ignore_unused_variable_warning(dummy);
@@ -311,7 +314,7 @@ inline void set(Geometry& geometry
typename geometry::util::bare_type<Geometry>::type,
typename coordinate_type<Geometry>::type,
Dimension,
- typename boost::is_pointer<Geometry>::type
+ typename boost::is_pointer<Geometry>::type
> coord_access_type;
coord_access_type::set(geometry, value);
@@ -325,7 +328,6 @@ inline void set(Geometry& geometry
\tparam Dimension \tparam_dimension_required
\tparam Geometry \tparam_box_or_segment
\param geometry \param_geometry
-\param dummy \qbk_skip
\return coordinate value
\ingroup get
@@ -334,7 +336,9 @@ inline void set(Geometry& geometry
*/
template <std::size_t Index, std::size_t Dimension, typename Geometry>
inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
, detail::signature_getset_index_dimension* dummy = 0
+#endif
)
{
boost::ignore_unused_variable_warning(dummy);
@@ -346,7 +350,7 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
typename coordinate_type<Geometry>::type,
Index,
Dimension,
- typename boost::is_pointer<Geometry>::type
+ typename boost::is_pointer<Geometry>::type
> coord_access_type;
return coord_access_type::get(geometry);
@@ -361,7 +365,6 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
\param geometry geometry to assign coordinate to
\param geometry \param_geometry
\param value The coordinate value to set
-\param dummy \qbk_skip
\ingroup set
\qbk{distinguish,with index}
@@ -370,19 +373,21 @@ inline typename coordinate_type<Geometry>::type get(Geometry const& geometry
template <std::size_t Index, std::size_t Dimension, typename Geometry>
inline void set(Geometry& geometry
, typename coordinate_type<Geometry>::type const& value
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
, detail::signature_getset_index_dimension* dummy = 0
+#endif
)
{
boost::ignore_unused_variable_warning(dummy);
typedef core_dispatch::indexed_access
<
- typename tag<Geometry>::type,
+ typename tag<Geometry>::type,
typename geometry::util::bare_type<Geometry>::type,
typename coordinate_type<Geometry>::type,
Index,
Dimension,
- typename boost::is_pointer<Geometry>::type
+ typename boost::is_pointer<Geometry>::type
> coord_access_type;
coord_access_type::set(geometry, value);
diff --git a/boost/geometry/core/closure.hpp b/boost/geometry/core/closure.hpp
index aab02e7871..b69dcda140 100644
--- a/boost/geometry/core/closure.hpp
+++ b/boost/geometry/core/closure.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,10 +19,9 @@
#ifndef BOOST_GEOMETRY_CORE_CLOSURE_HPP
#define BOOST_GEOMETRY_CORE_CLOSURE_HPP
-
#include <boost/mpl/assert.hpp>
-#include <boost/mpl/int.hpp>
-#include <boost/range.hpp>
+#include <boost/mpl/size_t.hpp>
+#include <boost/range/value_type.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/geometry/core/ring_type.hpp>
@@ -32,10 +36,10 @@ namespace boost { namespace geometry
\brief Enumerates options for defining if polygons are open or closed
\ingroup enum
\details The enumeration closure_selector describes options for if a polygon is
- open or closed. In a closed polygon the very first point (per ring) should
+ open or closed. In a closed polygon the very first point (per ring) should
be equal to the very last point.
- The specific closing property of a polygon type is defined by the closure
- metafunction. The closure metafunction defines a value, which is one of the
+ The specific closing property of a polygon type is defined by the closure
+ metafunction. The closure metafunction defines a value, which is one of the
values enumerated in the closure_selector
\qbk{
@@ -45,12 +49,12 @@ namespace boost { namespace geometry
*/
enum closure_selector
{
- /// Rings are open: first point and last point are different, algorithms
+ /// Rings are open: first point and last point are different, algorithms
/// close them explicitly on the fly
open = 0,
/// Rings are closed: first point and last point must be the same
closed = 1,
- /// (Not yet implemented): algorithms first figure out if ring must be
+ /// (Not yet implemented): algorithms first figure out if ring must be
/// closed on the fly
closure_undertermined = -1
};
@@ -93,10 +97,10 @@ template <closure_selector Closure>
struct minimum_ring_size {};
template <>
-struct minimum_ring_size<geometry::closed> : boost::mpl::int_<4> {};
+struct minimum_ring_size<geometry::closed> : boost::mpl::size_t<4> {};
template <>
-struct minimum_ring_size<geometry::open> : boost::mpl::int_<3> {};
+struct minimum_ring_size<geometry::open> : boost::mpl::size_t<3> {};
}} // namespace detail::point_order
@@ -128,18 +132,18 @@ template <typename Box>
struct closure<segment_tag, Box> : public core_detail::closure::closed {};
template <typename LineString>
-struct closure<linestring_tag, LineString>
+struct closure<linestring_tag, LineString>
: public core_detail::closure::closed {};
template <typename Ring>
struct closure<ring_tag, Ring>
{
- static const closure_selector value
+ static const closure_selector value
= geometry::traits::closure<Ring>::value;
};
-// Specialization for polygon: the closure is the closure of its rings
+// Specialization for Polygon: the closure is the closure of its rings
template <typename Polygon>
struct closure<polygon_tag, Polygon>
{
@@ -150,13 +154,31 @@ struct closure<polygon_tag, Polygon>
>::value ;
};
+template <typename MultiPoint>
+struct closure<multi_point_tag, MultiPoint>
+ : public core_detail::closure::closed {};
+
+template <typename MultiLinestring>
+struct closure<multi_linestring_tag, MultiLinestring>
+ : public core_detail::closure::closed {};
+
+// Specialization for MultiPolygon: the closure is the closure of Polygon's rings
+template <typename MultiPolygon>
+struct closure<multi_polygon_tag, MultiPolygon>
+{
+ static const closure_selector value = core_dispatch::closure
+ <
+ polygon_tag,
+ typename boost::range_value<MultiPolygon>::type
+ >::value ;
+};
} // namespace core_dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
-\brief \brief_meta{value, closure (clockwise\, counterclockwise),
+\brief \brief_meta{value, closure (clockwise\, counterclockwise),
\meta_geometry_type}
\tparam Geometry \tparam_geometry
\ingroup core
@@ -169,7 +191,7 @@ struct closure
static const closure_selector value = core_dispatch::closure
<
typename tag<Geometry>::type,
- typename boost::remove_const<Geometry>::type
+ typename util::bare_type<Geometry>::type
>::value;
};
diff --git a/boost/geometry/core/coordinate_dimension.hpp b/boost/geometry/core/coordinate_dimension.hpp
index 2f3c914601..85da6b424e 100644
--- a/boost/geometry/core/coordinate_dimension.hpp
+++ b/boost/geometry/core/coordinate_dimension.hpp
@@ -58,7 +58,15 @@ template <typename T, typename G>
struct dimension : dimension<point_tag, typename point_type<T, G>::type> {};
template <typename P>
-struct dimension<point_tag, P> : traits::dimension<typename geometry::util::bare_type<P>::type> {};
+struct dimension<point_tag, P>
+ : traits::dimension<typename geometry::util::bare_type<P>::type>
+{
+ BOOST_MPL_ASSERT_MSG(
+ (traits::dimension<typename geometry::util::bare_type<P>::type>::value > 0),
+ INVALID_DIMENSION_VALUE,
+ (traits::dimension<typename geometry::util::bare_type<P>::type>)
+ );
+};
} // namespace core_dispatch
#endif
@@ -75,7 +83,7 @@ struct dimension
: core_dispatch::dimension
<
typename tag<Geometry>::type,
- typename geometry::util::bare_type<Geometry>::type
+ typename geometry::util::bare_type<Geometry>::type
>
{};
@@ -89,7 +97,7 @@ inline void assert_dimension()
BOOST_STATIC_ASSERT((
boost::mpl::equal_to
<
- geometry::dimension<Geometry>,
+ boost::mpl::int_<geometry::dimension<Geometry>::value>,
boost::mpl::int_<Dimensions>
>::type::value
));
@@ -102,13 +110,13 @@ inline void assert_dimension()
template <typename Geometry, int Dimensions>
inline void assert_dimension_less_equal()
{
- BOOST_STATIC_ASSERT(( dimension<Geometry>::type::value <= Dimensions ));
+ BOOST_STATIC_ASSERT(( static_cast<int>(dimension<Geometry>::type::value) <= Dimensions ));
}
template <typename Geometry, int Dimensions>
inline void assert_dimension_greater_equal()
{
- BOOST_STATIC_ASSERT(( dimension<Geometry>::type::value >= Dimensions ));
+ BOOST_STATIC_ASSERT(( static_cast<int>(dimension<Geometry>::type::value) >= Dimensions ));
}
/*!
@@ -118,7 +126,7 @@ inline void assert_dimension_greater_equal()
template <typename G1, typename G2>
inline void assert_dimension_equal()
{
- BOOST_STATIC_ASSERT(( dimension<G1>::type::value == dimension<G2>::type::value ));
+ BOOST_STATIC_ASSERT(( static_cast<size_t>(dimension<G1>::type::value) == static_cast<size_t>(dimension<G2>::type::value) ));
}
}} // namespace boost::geometry
diff --git a/boost/geometry/core/coordinate_system.hpp b/boost/geometry/core/coordinate_system.hpp
index 01e5ad1dd7..d33353f4b4 100644
--- a/boost/geometry/core/coordinate_system.hpp
+++ b/boost/geometry/core/coordinate_system.hpp
@@ -66,9 +66,9 @@ namespace core_dispatch
struct coordinate_system<point_tag, Point>
{
typedef typename traits::coordinate_system
- <
- typename geometry::util::bare_type<Point>::type
- >::type type;
+ <
+ typename geometry::util::bare_type<Point>::type
+ >::type type;
};
@@ -89,7 +89,7 @@ struct coordinate_system
typedef typename core_dispatch::coordinate_system
<
typename tag<Geometry>::type,
- typename geometry::util::bare_type<Geometry>::type
+ typename geometry::util::bare_type<Geometry>::type
>::type type;
};
diff --git a/boost/geometry/core/coordinate_type.hpp b/boost/geometry/core/coordinate_type.hpp
index d17f66ab73..f138d59c8a 100644
--- a/boost/geometry/core/coordinate_type.hpp
+++ b/boost/geometry/core/coordinate_type.hpp
@@ -65,9 +65,9 @@ template <typename Point>
struct coordinate_type<point_tag, Point>
{
typedef typename traits::coordinate_type
- <
+ <
typename geometry::util::bare_type<Point>::type
- >::type type;
+ >::type type;
};
@@ -85,11 +85,11 @@ struct coordinate_type<point_tag, Point>
template <typename Geometry>
struct coordinate_type
{
- typedef typename core_dispatch::coordinate_type
- <
- typename tag<Geometry>::type,
- typename geometry::util::bare_type<Geometry>::type
- >::type type;
+ typedef typename core_dispatch::coordinate_type
+ <
+ typename tag<Geometry>::type,
+ typename geometry::util::bare_type<Geometry>::type
+ >::type type;
};
template <typename Geometry>
diff --git a/boost/geometry/core/cs.hpp b/boost/geometry/core/cs.hpp
index 3588ed1a86..cf6c56b53c 100644
--- a/boost/geometry/core/cs.hpp
+++ b/boost/geometry/core/cs.hpp
@@ -28,7 +28,7 @@ namespace boost { namespace geometry
/*!
\brief Unit of plane angle: Degrees
\details Tag defining the unit of plane angle for spherical coordinate systems.
- This tag specifies that coordinates are defined in degrees (-180 .. 180).
+ This tag specifies that coordinates are defined in degrees (-180 .. 180).
It has to be specified for some coordinate systems.
\qbk{[include reference/core/degree_radian.qbk]}
*/
@@ -38,7 +38,7 @@ struct degree {};
/*!
\brief Unit of plane angle: Radians
\details Tag defining the unit of plane angle for spherical coordinate systems.
- This tag specifies that coordinates are defined in radians (-PI .. PI).
+ This tag specifies that coordinates are defined in radians (-PI .. PI).
It has to be specified for some coordinate systems.
\qbk{[include reference/core/degree_radian.qbk]}
*/
@@ -106,7 +106,7 @@ struct spherical
/*!
\brief Spherical equatorial coordinate system, in degree or in radian
\details This one resembles the geographic coordinate system, and has latitude
- up from zero at the equator, to 90 at the pole
+ up from zero at the equator, to 90 at the pole
(opposite to the spherical(polar) coordinate system).
Used in astronomy and in GIS (but there is also the geographic)
@@ -185,20 +185,22 @@ struct cs_tag<cs::cartesian>
/*!
\brief Meta-function returning coordinate system tag (cs family) of any geometry
+\tparam Geometry \tparam_geometry
\ingroup core
*/
-template <typename G>
+template <typename Geometry>
struct cs_tag
{
typedef typename traits::cs_tag
<
- typename geometry::coordinate_system<G>::type
+ typename geometry::coordinate_system<Geometry>::type
>::type type;
};
/*!
\brief Meta-function to verify if a coordinate system is radian
+\tparam CoordinateSystem Any coordinate system.
\ingroup core
*/
template <typename CoordinateSystem>
diff --git a/boost/geometry/core/exterior_ring.hpp b/boost/geometry/core/exterior_ring.hpp
index 70012c22db..e5c97dd301 100644
--- a/boost/geometry/core/exterior_ring.hpp
+++ b/boost/geometry/core/exterior_ring.hpp
@@ -101,7 +101,7 @@ struct exterior_ring<polygon_tag, Polygon>
\brief Function to get the exterior_ring ring of a polygon
\ingroup exterior_ring
\note OGC compliance: instead of ExteriorRing
- \tparam P polygon type
+ \tparam Polygon polygon type
\param polygon the polygon to get the exterior ring from
\return a reference to the exterior ring
*/
diff --git a/boost/geometry/core/geometry_id.hpp b/boost/geometry/core/geometry_id.hpp
index 369c5cfa1a..5fc5a80050 100644
--- a/boost/geometry/core/geometry_id.hpp
+++ b/boost/geometry/core/geometry_id.hpp
@@ -18,8 +18,6 @@
#include <boost/mpl/assert.hpp>
#include <boost/mpl/int.hpp>
-#include <boost/type_traits.hpp>
-
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -45,28 +43,39 @@ struct geometry_id
template <>
-struct geometry_id<point_tag> : boost::mpl::int_<1> {};
+struct geometry_id<point_tag> : boost::mpl::int_<1> {};
template <>
-struct geometry_id<linestring_tag> : boost::mpl::int_<2> {};
+struct geometry_id<linestring_tag> : boost::mpl::int_<2> {};
template <>
-struct geometry_id<polygon_tag> : boost::mpl::int_<3> {};
+struct geometry_id<polygon_tag> : boost::mpl::int_<3> {};
template <>
-struct geometry_id<segment_tag> : boost::mpl::int_<92> {};
+struct geometry_id<multi_point_tag> : boost::mpl::int_<4> {};
template <>
-struct geometry_id<ring_tag> : boost::mpl::int_<93> {};
+struct geometry_id<multi_linestring_tag> : boost::mpl::int_<5> {};
template <>
-struct geometry_id<box_tag> : boost::mpl::int_<94> {};
+struct geometry_id<multi_polygon_tag> : boost::mpl::int_<6> {};
+
+
+template <>
+struct geometry_id<segment_tag> : boost::mpl::int_<92> {};
+
+template <>
+struct geometry_id<ring_tag> : boost::mpl::int_<93> {};
+
+
+template <>
+struct geometry_id<box_tag> : boost::mpl::int_<94> {};
} // namespace core_dispatch
@@ -76,9 +85,9 @@ struct geometry_id<box_tag> : boost::mpl::int_<94> {};
/*!
\brief Meta-function returning the id of a geometry type
-\details The meta-function geometry_id defines a numerical ID (based on
- boost::mpl::int_<...> ) for each geometry concept. A numerical ID is
- sometimes useful, and within Boost.Geometry it is used for the
+\details The meta-function geometry_id defines a numerical ID (based on
+ boost::mpl::int_<...> ) for each geometry concept. A numerical ID is
+ sometimes useful, and within Boost.Geometry it is used for the
reverse_dispatch metafuntion.
\note Used for e.g. reverse meta-function
\ingroup core
diff --git a/boost/geometry/core/interior_rings.hpp b/boost/geometry/core/interior_rings.hpp
index 10af2ae4ee..798f415779 100644
--- a/boost/geometry/core/interior_rings.hpp
+++ b/boost/geometry/core/interior_rings.hpp
@@ -17,7 +17,7 @@
#include <cstddef>
#include <boost/mpl/assert.hpp>
-#include <boost/range.hpp>
+#include <boost/range/value_type.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/geometry/core/tag.hpp>
@@ -85,6 +85,17 @@ struct interior_rings<polygon_tag, Polygon>
};
+template <typename MultiPolygon>
+struct interior_type<multi_polygon_tag, MultiPolygon>
+{
+ typedef typename core_dispatch::interior_type
+ <
+ polygon_tag,
+ typename boost::range_value<MultiPolygon>::type
+ >::type type;
+};
+
+
} // namespace core_dispatch
#endif
diff --git a/boost/geometry/core/is_areal.hpp b/boost/geometry/core/is_areal.hpp
index 5ddfa753bc..23858605f4 100644
--- a/boost/geometry/core/is_areal.hpp
+++ b/boost/geometry/core/is_areal.hpp
@@ -16,8 +16,7 @@
#define BOOST_GEOMETRY_CORE_IS_AREAL_HPP
-#include <boost/type_traits.hpp>
-
+#include <boost/type_traits/integral_constant.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -36,7 +35,7 @@ template <typename GeometryTag> struct is_areal : boost::false_type {};
template <> struct is_areal<ring_tag> : boost::true_type {};
template <> struct is_areal<box_tag> : boost::true_type {};
template <> struct is_areal<polygon_tag> : boost::true_type {};
-
+template <> struct is_areal<multi_polygon_tag> : boost::true_type {};
} // namespace core_dispatch
#endif
diff --git a/boost/geometry/core/point_order.hpp b/boost/geometry/core/point_order.hpp
index f09086a9d4..d43adbd03a 100644
--- a/boost/geometry/core/point_order.hpp
+++ b/boost/geometry/core/point_order.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -16,7 +21,7 @@
#include <boost/mpl/assert.hpp>
-#include <boost/range.hpp>
+#include <boost/range/value_type.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/geometry/core/ring_type.hpp>
@@ -29,10 +34,10 @@ namespace boost { namespace geometry
/*!
\brief Enumerates options for the order of points within polygons
\ingroup enum
-\details The enumeration order_selector describes options for the order of
- points within a polygon. Polygons can be ordered either clockwise or
- counterclockwise. The specific order of a polygon type is defined by the
- point_order metafunction. The point_order metafunction defines a value,
+\details The enumeration order_selector describes options for the order of
+ points within a polygon. Polygons can be ordered either clockwise or
+ counterclockwise. The specific order of a polygon type is defined by the
+ point_order metafunction. The point_order metafunction defines a value,
which is one of the values enumerated in the order_selector
\qbk{
@@ -120,7 +125,7 @@ struct point_order<linestring_tag, LineString>
template <typename Ring>
struct point_order<ring_tag, Ring>
{
- static const order_selector value
+ static const order_selector value
= geometry::traits::point_order<Ring>::value;
};
@@ -135,12 +140,32 @@ struct point_order<polygon_tag, Polygon>
>::value ;
};
+template <typename MultiPoint>
+struct point_order<multi_point_tag, MultiPoint>
+ : public detail::point_order::clockwise {};
+
+template <typename MultiLinestring>
+struct point_order<multi_linestring_tag, MultiLinestring>
+ : public detail::point_order::clockwise {};
+
+
+// Specialization for multi_polygon: the order is the order of its polygons
+template <typename MultiPolygon>
+struct point_order<multi_polygon_tag, MultiPolygon>
+{
+ static const order_selector value = core_dispatch::point_order
+ <
+ polygon_tag,
+ typename boost::range_value<MultiPolygon>::type
+ >::value ;
+};
+
} // namespace core_dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
-\brief \brief_meta{value, point order (clockwise\, counterclockwise),
+\brief \brief_meta{value, point order (clockwise\, counterclockwise),
\meta_geometry_type}
\tparam Geometry \tparam_geometry
\ingroup core
@@ -153,7 +178,7 @@ struct point_order
static const order_selector value = core_dispatch::point_order
<
typename tag<Geometry>::type,
- typename boost::remove_const<Geometry>::type
+ typename util::bare_type<Geometry>::type
>::value;
};
diff --git a/boost/geometry/core/point_type.hpp b/boost/geometry/core/point_type.hpp
index e148c84a57..f70e1fedd5 100644
--- a/boost/geometry/core/point_type.hpp
+++ b/boost/geometry/core/point_type.hpp
@@ -16,7 +16,7 @@
#include <boost/mpl/assert.hpp>
-#include <boost/range.hpp>
+#include <boost/range/value_type.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/geometry/core/ring_type.hpp>
@@ -102,13 +102,45 @@ struct point_type<polygon_tag, Polygon>
};
+template <typename MultiPoint>
+struct point_type<multi_point_tag, MultiPoint>
+{
+ typedef typename boost::range_value
+ <
+ MultiPoint
+ >::type type;
+};
+
+
+template <typename MultiLinestring>
+struct point_type<multi_linestring_tag, MultiLinestring>
+{
+ typedef typename point_type
+ <
+ linestring_tag,
+ typename boost::range_value<MultiLinestring>::type
+ >::type type;
+};
+
+
+template <typename MultiPolygon>
+struct point_type<multi_polygon_tag, MultiPolygon>
+{
+ typedef typename point_type
+ <
+ polygon_tag,
+ typename boost::range_value<MultiPolygon>::type
+ >::type type;
+};
+
+
} // namespace core_dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_meta{type, point_type, \meta_geometry_type}
-\tparam Geometry \tparam_geometry
+\tparam Geometry \tparam_geometry
\ingroup core
\qbk{[include reference/core/point_type.qbk]}
diff --git a/boost/geometry/core/ring_type.hpp b/boost/geometry/core/ring_type.hpp
index 9b984faf3c..fe551f060f 100644
--- a/boost/geometry/core/ring_type.hpp
+++ b/boost/geometry/core/ring_type.hpp
@@ -18,8 +18,10 @@
#include <boost/mpl/assert.hpp>
#include <boost/mpl/if.hpp>
+#include <boost/range/value_type.hpp>
+#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/remove_const.hpp>
-
+#include <boost/type_traits/remove_reference.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -102,6 +104,38 @@ struct ring_return_type<polygon_tag, Polygon>
};
+template <typename MultiLinestring>
+struct ring_return_type<multi_linestring_tag, MultiLinestring>
+{
+ typedef typename ring_return_type
+ <
+ linestring_tag,
+ typename mpl::if_
+ <
+ boost::is_const<MultiLinestring>,
+ typename boost::range_value<MultiLinestring>::type const,
+ typename boost::range_value<MultiLinestring>::type
+ >::type
+ >::type type;
+};
+
+
+template <typename MultiPolygon>
+struct ring_return_type<multi_polygon_tag, MultiPolygon>
+{
+ typedef typename ring_return_type
+ <
+ polygon_tag,
+ typename mpl::if_
+ <
+ boost::is_const<MultiPolygon>,
+ typename boost::range_value<MultiPolygon>::type const,
+ typename boost::range_value<MultiPolygon>::type
+ >::type
+ >::type type;
+};
+
+
template <typename GeometryTag, typename Geometry>
struct ring_type
{};
@@ -124,7 +158,24 @@ struct ring_type<polygon_tag, Polygon>
};
+template <typename MultiLinestring>
+struct ring_type<multi_linestring_tag, MultiLinestring>
+{
+ typedef typename boost::remove_reference
+ <
+ typename ring_return_type<multi_linestring_tag, MultiLinestring>::type
+ >::type type;
+};
+
+template <typename MultiPolygon>
+struct ring_type<multi_polygon_tag, MultiPolygon>
+{
+ typedef typename boost::remove_reference
+ <
+ typename ring_return_type<multi_polygon_tag, MultiPolygon>::type
+ >::type type;
+};
} // namespace core_dispatch
diff --git a/boost/geometry/core/tag.hpp b/boost/geometry/core/tag.hpp
index 4c790fdc9e..6bffcb932d 100644
--- a/boost/geometry/core/tag.hpp
+++ b/boost/geometry/core/tag.hpp
@@ -14,7 +14,6 @@
#ifndef BOOST_GEOMETRY_CORE_TAG_HPP
#define BOOST_GEOMETRY_CORE_TAG_HPP
-
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -52,7 +51,7 @@ struct tag
\brief \brief_meta{type, tag, \meta_geometry_type}
\details With Boost.Geometry, tags are the driving force of the tag dispatching
mechanism. The tag metafunction is therefore used in every free function.
-\tparam Geometry \tparam_geometry
+\tparam Geometry \tparam_geometry
\ingroup core
\qbk{[include reference/core/tag.qbk]}
@@ -62,7 +61,7 @@ struct tag
{
typedef typename traits::tag
<
- typename geometry::util::bare_type<Geometry>::type
+ typename geometry::util::bare_type<Geometry>::type
>::type type;
};
diff --git a/boost/geometry/core/tag_cast.hpp b/boost/geometry/core/tag_cast.hpp
index 47a2e834f1..cafd13cba9 100644
--- a/boost/geometry/core/tag_cast.hpp
+++ b/boost/geometry/core/tag_cast.hpp
@@ -25,10 +25,10 @@ namespace boost { namespace geometry
\brief Metafunction defining a type being either the specified tag, or one
of the specified basetags if the type inherits from them.
\details Tags can inherit each other. A multi_point inherits, for example,
- both the multi_tag and the pointlike tag. Often behaviour can be shared
+ both the multi_tag and the pointlike_tag. Often behaviour can be shared
between different geometry types. A tag, found by the metafunction tag,
can be casted to a more basic tag, and then dispatched by that tag.
-\ingroup core
+\ingroup core
\tparam Tag The tag to be casted to one of the base tags
\tparam BaseTag First base tag
\tparam BaseTag2 Optional second base tag
diff --git a/boost/geometry/core/tags.hpp b/boost/geometry/core/tags.hpp
index 9272858ed2..160477b8c4 100644
--- a/boost/geometry/core/tags.hpp
+++ b/boost/geometry/core/tags.hpp
@@ -57,7 +57,7 @@ struct linear_tag {};
struct areal_tag {};
// Subset of areal types (polygon, multi_polygon, ring)
-struct polygonal_tag : areal_tag {};
+struct polygonal_tag : areal_tag {};
/// For volume types (also box (?), polyhedron)
struct volumetric_tag {};
@@ -88,6 +88,49 @@ struct box_tag : single_tag, areal_tag {};
struct segment_tag : single_tag, linear_tag {};
+/// OGC Multi point identifying tag
+struct multi_point_tag : multi_tag, pointlike_tag {};
+
+/// OGC Multi linestring identifying tag
+struct multi_linestring_tag : multi_tag, linear_tag {};
+
+/// OGC Multi polygon identifying tag
+struct multi_polygon_tag : multi_tag, polygonal_tag {};
+
+/// OGC Geometry Collection identifying tag
+struct geometry_collection_tag : multi_tag {};
+
+
+/*!
+\brief Meta-function to get for a tag of a multi-geometry
+ the tag of the corresponding single-geometry
+*/
+template <typename Tag>
+struct single_tag_of
+{};
+
+#ifndef DOXYGEN_NO_DETAIL
+
+template <>
+struct single_tag_of<multi_point_tag>
+{
+ typedef point_tag type;
+};
+
+template <>
+struct single_tag_of<multi_linestring_tag>
+{
+ typedef linestring_tag type;
+};
+
+template <>
+struct single_tag_of<multi_polygon_tag>
+{
+ typedef polygon_tag type;
+};
+
+#endif
+
}} // namespace boost::geometry
diff --git a/boost/geometry/core/topological_dimension.hpp b/boost/geometry/core/topological_dimension.hpp
index 02f1ed341e..22ed676fc6 100644
--- a/boost/geometry/core/topological_dimension.hpp
+++ b/boost/geometry/core/topological_dimension.hpp
@@ -49,10 +49,12 @@ struct top_dim<segment_tag> : boost::mpl::int_<1> {};
// ring: topological dimension of two, but some people say: 1 !!
+// NOTE: This is not OGC LinearRing!
template <>
struct top_dim<ring_tag> : boost::mpl::int_<2> {};
+// TODO: This is wrong! Boxes may have various topological dimensions
template <>
struct top_dim<box_tag> : boost::mpl::int_<2> {};
@@ -61,6 +63,17 @@ template <>
struct top_dim<polygon_tag> : boost::mpl::int_<2> {};
+template <>
+struct top_dim<multi_point_tag> : boost::mpl::int_<0> {};
+
+
+template <>
+struct top_dim<multi_linestring_tag> : boost::mpl::int_<1> {};
+
+
+template <>
+struct top_dim<multi_polygon_tag> : boost::mpl::int_<2> {};
+
} // namespace core_dispatch
#endif
diff --git a/boost/geometry/geometries/adapted/boost_polygon/ring.hpp b/boost/geometry/geometries/adapted/boost_polygon/ring.hpp
index 93b21fee94..490fa45fe9 100644
--- a/boost/geometry/geometries/adapted/boost_polygon/ring.hpp
+++ b/boost/geometry/geometries/adapted/boost_polygon/ring.hpp
@@ -69,7 +69,26 @@ struct push_back<boost::polygon::polygon_data<CoordinateType> >
}
};
+template <typename CoordinateType>
+struct resize<boost::polygon::polygon_data<CoordinateType> >
+{
+ typedef boost::polygon::point_data<CoordinateType> point_type;
+ static inline void apply(boost::polygon::polygon_data<CoordinateType>& data,
+ std::size_t new_size)
+ {
+ // Boost.Polygon's polygons are not resizable. So create a temporary vector,
+ // resize it and set it to the original. Of course: this is not efficient.
+ // But there seems no other way (without using a wrapper)
+ std::vector<point_type> temporary_vector
+ (
+ boost::polygon::begin_points(data),
+ boost::polygon::end_points(data)
+ );
+ temporary_vector.resize(new_size);
+ data.set(temporary_vector.begin(), temporary_vector.end());
+ }
+};
} // namespace traits
diff --git a/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp b/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp
index 825ef8061f..1616369da1 100644
--- a/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp
+++ b/boost/geometry/geometries/adapted/boost_polygon/ring_proxy.hpp
@@ -150,7 +150,7 @@ public :
}
}
- void resize(std::size_t new_size)
+ void resize(std::size_t /*new_size*/)
{
if (m_do_hole)
{
diff --git a/boost/geometry/geometries/concepts/check.hpp b/boost/geometry/geometries/concepts/check.hpp
index f8001f0d12..07ef84f4a4 100644
--- a/boost/geometry/geometries/concepts/check.hpp
+++ b/boost/geometry/geometries/concepts/check.hpp
@@ -18,17 +18,23 @@
#include <boost/concept_check.hpp>
#include <boost/concept/requires.hpp>
-
#include <boost/type_traits/is_const.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/box_concept.hpp>
#include <boost/geometry/geometries/concepts/linestring_concept.hpp>
+#include <boost/geometry/geometries/concepts/multi_point_concept.hpp>
+#include <boost/geometry/geometries/concepts/multi_linestring_concept.hpp>
+#include <boost/geometry/geometries/concepts/multi_polygon_concept.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/concepts/polygon_concept.hpp>
#include <boost/geometry/geometries/concepts/ring_concept.hpp>
+#include <boost/geometry/geometries/concepts/segment_concept.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
namespace boost { namespace geometry
{
@@ -53,59 +59,122 @@ class check
namespace dispatch
{
-template <typename GeometryTag, typename Geometry, bool IsConst>
-struct check
+template
+<
+ typename Geometry,
+ typename GeometryTag = typename geometry::tag<Geometry>::type,
+ bool IsConst = boost::is_const<Geometry>::type::value
+>
+struct check : not_implemented<GeometryTag>
{};
template <typename Geometry>
-struct check<point_tag, Geometry, true>
+struct check<Geometry, point_tag, true>
: detail::concept_check::check<concept::ConstPoint<Geometry> >
{};
template <typename Geometry>
-struct check<point_tag, Geometry, false>
+struct check<Geometry, point_tag, false>
: detail::concept_check::check<concept::Point<Geometry> >
{};
template <typename Geometry>
-struct check<linestring_tag, Geometry, true>
+struct check<Geometry, linestring_tag, true>
: detail::concept_check::check<concept::ConstLinestring<Geometry> >
{};
template <typename Geometry>
-struct check<linestring_tag, Geometry, false>
+struct check<Geometry, linestring_tag, false>
: detail::concept_check::check<concept::Linestring<Geometry> >
{};
template <typename Geometry>
-struct check<polygon_tag, Geometry, true>
+struct check<Geometry, ring_tag, true>
+ : detail::concept_check::check<concept::ConstRing<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, ring_tag, false>
+ : detail::concept_check::check<concept::Ring<Geometry> >
+{};
+
+template <typename Geometry>
+struct check<Geometry, polygon_tag, true>
: detail::concept_check::check<concept::ConstPolygon<Geometry> >
{};
template <typename Geometry>
-struct check<polygon_tag, Geometry, false>
+struct check<Geometry, polygon_tag, false>
: detail::concept_check::check<concept::Polygon<Geometry> >
{};
template <typename Geometry>
-struct check<box_tag, Geometry, true>
+struct check<Geometry, box_tag, true>
: detail::concept_check::check<concept::ConstBox<Geometry> >
{};
template <typename Geometry>
-struct check<box_tag, Geometry, false>
+struct check<Geometry, box_tag, false>
: detail::concept_check::check<concept::Box<Geometry> >
{};
+template <typename Geometry>
+struct check<Geometry, segment_tag, true>
+ : detail::concept_check::check<concept::ConstSegment<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, segment_tag, false>
+ : detail::concept_check::check<concept::Segment<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, multi_point_tag, true>
+ : detail::concept_check::check<concept::ConstMultiPoint<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, multi_point_tag, false>
+ : detail::concept_check::check<concept::MultiPoint<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, multi_linestring_tag, true>
+ : detail::concept_check::check<concept::ConstMultiLinestring<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, multi_linestring_tag, false>
+ : detail::concept_check::check<concept::MultiLinestring<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, multi_polygon_tag, true>
+ : detail::concept_check::check<concept::ConstMultiPolygon<Geometry> >
+{};
+
+
+template <typename Geometry>
+struct check<Geometry, multi_polygon_tag, false>
+ : detail::concept_check::check<concept::MultiPolygon<Geometry> >
+{};
+
} // namespace dispatch
#endif
@@ -122,13 +191,16 @@ namespace detail
{
-template <typename Geometry, bool IsConst>
-struct checker : dispatch::check
- <
- typename tag<Geometry>::type,
- Geometry,
- IsConst
- >
+template <typename Geometry>
+struct checker : dispatch::check<Geometry>
+{};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct checker<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct checker<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const>
{};
@@ -143,7 +215,7 @@ struct checker : dispatch::check
template <typename Geometry>
inline void check()
{
- detail::checker<Geometry, boost::is_const<Geometry>::type::value> c;
+ detail::checker<Geometry> c;
boost::ignore_unused_variable_warning(c);
}
diff --git a/boost/geometry/geometries/concepts/multi_linestring_concept.hpp b/boost/geometry/geometries/concepts/multi_linestring_concept.hpp
new file mode 100644
index 0000000000..f13f7ac7e8
--- /dev/null
+++ b/boost/geometry/geometries/concepts/multi_linestring_concept.hpp
@@ -0,0 +1,91 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP
+
+
+#include <boost/concept_check.hpp>
+#include <boost/range/concepts.hpp>
+#include <boost/range/metafunctions.hpp>
+
+
+#include <boost/geometry/geometries/concepts/linestring_concept.hpp>
+
+
+namespace boost { namespace geometry { namespace concept
+{
+
+
+/*!
+\brief multi-linestring concept
+\ingroup concepts
+\par Formal definition:
+The multi linestring concept is defined as following:
+- there must be a specialization of traits::tag defining multi_linestring_tag as
+ type
+- it must behave like a Boost.Range
+- its range value must fulfil the Linestring concept
+
+*/
+template <typename Geometry>
+class MultiLinestring
+{
+#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
+ typedef typename boost::range_value<Geometry>::type linestring_type;
+
+ BOOST_CONCEPT_ASSERT( (concept::Linestring<linestring_type>) );
+ BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
+
+
+public :
+
+ BOOST_CONCEPT_USAGE(MultiLinestring)
+ {
+ Geometry* mls = 0;
+ traits::clear<Geometry>::apply(*mls);
+ traits::resize<Geometry>::apply(*mls, 0);
+ linestring_type* ls = 0;
+ traits::push_back<Geometry>::apply(*mls, *ls);
+ }
+#endif
+};
+
+
+/*!
+\brief concept for multi-linestring (const version)
+\ingroup const_concepts
+*/
+template <typename Geometry>
+class ConstMultiLinestring
+{
+#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
+ typedef typename boost::range_value<Geometry>::type linestring_type;
+
+ BOOST_CONCEPT_ASSERT( (concept::ConstLinestring<linestring_type>) );
+ BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
+
+
+public :
+
+ BOOST_CONCEPT_USAGE(ConstMultiLinestring)
+ {
+ }
+#endif
+};
+
+}}} // namespace boost::geometry::concept
+
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP
diff --git a/boost/geometry/geometries/concepts/multi_point_concept.hpp b/boost/geometry/geometries/concepts/multi_point_concept.hpp
new file mode 100644
index 0000000000..81c087166f
--- /dev/null
+++ b/boost/geometry/geometries/concepts/multi_point_concept.hpp
@@ -0,0 +1,90 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP
+
+
+#include <boost/concept_check.hpp>
+#include <boost/range/concepts.hpp>
+#include <boost/range/metafunctions.hpp>
+
+
+#include <boost/geometry/geometries/concepts/point_concept.hpp>
+
+
+namespace boost { namespace geometry { namespace concept
+{
+
+
+/*!
+\brief MultiPoint concept
+\ingroup concepts
+\par Formal definition:
+The multi point concept is defined as following:
+- there must be a specialization of traits::tag defining multi_point_tag as type
+- it must behave like a Boost.Range
+- its range value must fulfil the Point concept
+
+*/
+template <typename Geometry>
+class MultiPoint
+{
+#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
+ typedef typename boost::range_value<Geometry>::type point_type;
+
+ BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) );
+ BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
+
+
+public :
+
+ BOOST_CONCEPT_USAGE(MultiPoint)
+ {
+ Geometry* mp = 0;
+ traits::clear<Geometry>::apply(*mp);
+ traits::resize<Geometry>::apply(*mp, 0);
+ point_type* point = 0;
+ traits::push_back<Geometry>::apply(*mp, *point);
+ }
+#endif
+};
+
+
+/*!
+\brief concept for multi-point (const version)
+\ingroup const_concepts
+*/
+template <typename Geometry>
+class ConstMultiPoint
+{
+#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
+ typedef typename boost::range_value<Geometry>::type point_type;
+
+ BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) );
+ BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
+
+
+public :
+
+ BOOST_CONCEPT_USAGE(ConstMultiPoint)
+ {
+ }
+#endif
+};
+
+}}} // namespace boost::geometry::concept
+
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP
diff --git a/boost/geometry/geometries/concepts/multi_polygon_concept.hpp b/boost/geometry/geometries/concepts/multi_polygon_concept.hpp
new file mode 100644
index 0000000000..b13d330f3c
--- /dev/null
+++ b/boost/geometry/geometries/concepts/multi_polygon_concept.hpp
@@ -0,0 +1,91 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP
+
+
+#include <boost/concept_check.hpp>
+#include <boost/range/concepts.hpp>
+#include <boost/range/metafunctions.hpp>
+
+#include <boost/geometry/geometries/concepts/polygon_concept.hpp>
+
+
+namespace boost { namespace geometry { namespace concept
+{
+
+
+/*!
+\brief multi-polygon concept
+\ingroup concepts
+\par Formal definition:
+The multi polygon concept is defined as following:
+- there must be a specialization of traits::tag defining multi_polygon_tag
+ as type
+- it must behave like a Boost.Range
+- its range value must fulfil the Polygon concept
+
+*/
+template <typename Geometry>
+class MultiPolygon
+{
+#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
+ typedef typename boost::range_value<Geometry>::type polygon_type;
+
+ BOOST_CONCEPT_ASSERT( (concept::Polygon<polygon_type>) );
+ BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
+
+
+public :
+
+ BOOST_CONCEPT_USAGE(MultiPolygon)
+ {
+ Geometry* mp = 0;
+ traits::clear<Geometry>::apply(*mp);
+ traits::resize<Geometry>::apply(*mp, 0);
+ polygon_type* poly = 0;
+ traits::push_back<Geometry>::apply(*mp, *poly);
+ }
+#endif
+};
+
+
+/*!
+\brief concept for multi-polygon (const version)
+\ingroup const_concepts
+*/
+template <typename Geometry>
+class ConstMultiPolygon
+{
+#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
+ typedef typename boost::range_value<Geometry>::type polygon_type;
+
+ BOOST_CONCEPT_ASSERT( (concept::ConstPolygon<polygon_type>) );
+ BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
+
+
+public :
+
+ BOOST_CONCEPT_USAGE(ConstMultiPolygon)
+ {
+ }
+#endif
+};
+
+
+}}} // namespace boost::geometry::concept
+
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP
diff --git a/boost/geometry/geometries/geometries.hpp b/boost/geometry/geometries/geometries.hpp
index cda55c1d28..de9e2b1fd9 100644
--- a/boost/geometry/geometries/geometries.hpp
+++ b/boost/geometry/geometries/geometries.hpp
@@ -18,6 +18,10 @@
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
+#include <boost/geometry/geometries/multi_point.hpp>
+#include <boost/geometry/geometries/multi_linestring.hpp>
+#include <boost/geometry/geometries/multi_polygon.hpp>
+
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/geometries/segment.hpp>
diff --git a/boost/geometry/geometries/multi_linestring.hpp b/boost/geometry/geometries/multi_linestring.hpp
new file mode 100644
index 0000000000..2ba8e7196b
--- /dev/null
+++ b/boost/geometry/geometries/multi_linestring.hpp
@@ -0,0 +1,80 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_MULTI_LINESTRING_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_MULTI_LINESTRING_HPP
+
+#include <memory>
+#include <vector>
+
+#include <boost/concept/requires.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/linestring_concept.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace model
+{
+
+/*!
+\brief multi_line, a collection of linestring
+\details Multi-linestring can be used to group lines belonging to each other,
+ e.g. a highway (with interruptions)
+\ingroup geometries
+
+\qbk{before.synopsis,
+[heading Model of]
+[link geometry.reference.concepts.concept_multi_linestring MultiLineString Concept]
+}
+*/
+template
+<
+ typename LineString,
+ template<typename, typename> class Container = std::vector,
+ template<typename> class Allocator = std::allocator
+>
+class multi_linestring : public Container<LineString, Allocator<LineString> >
+{
+ BOOST_CONCEPT_ASSERT( (concept::Linestring<LineString>) );
+};
+
+
+} // namespace model
+
+
+#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+namespace traits
+{
+
+template
+<
+ typename LineString,
+ template<typename, typename> class Container,
+ template<typename> class Allocator
+>
+struct tag< model::multi_linestring<LineString, Container, Allocator> >
+{
+ typedef multi_linestring_tag type;
+};
+
+} // namespace traits
+#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_MULTI_LINESTRING_HPP
diff --git a/boost/geometry/geometries/multi_point.hpp b/boost/geometry/geometries/multi_point.hpp
new file mode 100644
index 0000000000..d0a782a1de
--- /dev/null
+++ b/boost/geometry/geometries/multi_point.hpp
@@ -0,0 +1,94 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_MULTI_POINT_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_MULTI_POINT_HPP
+
+#include <memory>
+#include <vector>
+
+#include <boost/concept/requires.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/point_concept.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace model
+{
+
+
+/*!
+\brief multi_point, a collection of points
+\ingroup geometries
+\tparam Point \tparam_point
+\tparam Container \tparam_container
+\tparam Allocator \tparam_allocator
+\details Multipoint can be used to group points belonging to each other,
+ e.g. a constellation, or the result set of an intersection
+\qbk{before.synopsis,
+[heading Model of]
+[link geometry.reference.concepts.concept_multi_point MultiPoint Concept]
+}
+*/
+template
+<
+ typename Point,
+ template<typename, typename> class Container = std::vector,
+ template<typename> class Allocator = std::allocator
+>
+class multi_point : public Container<Point, Allocator<Point> >
+{
+ BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );
+
+ typedef Container<Point, Allocator<Point> > base_type;
+
+public :
+ /// \constructor_default{multi_point}
+ inline multi_point()
+ : base_type()
+ {}
+
+ /// \constructor_begin_end{multi_point}
+ template <typename Iterator>
+ inline multi_point(Iterator begin, Iterator end)
+ : base_type(begin, end)
+ {}
+};
+
+} // namespace model
+
+
+#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+namespace traits
+{
+
+template
+<
+ typename Point,
+ template<typename, typename> class Container,
+ template<typename> class Allocator
+>
+struct tag< model::multi_point<Point, Container, Allocator> >
+{
+ typedef multi_point_tag type;
+};
+
+} // namespace traits
+#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_MULTI_POINT_HPP
diff --git a/boost/geometry/geometries/multi_polygon.hpp b/boost/geometry/geometries/multi_polygon.hpp
new file mode 100644
index 0000000000..228074cd34
--- /dev/null
+++ b/boost/geometry/geometries/multi_polygon.hpp
@@ -0,0 +1,77 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_MULTI_POLYGON_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_MULTI_POLYGON_HPP
+
+#include <memory>
+#include <vector>
+
+#include <boost/concept/requires.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/polygon_concept.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace model
+{
+
+/*!
+\brief multi_polygon, a collection of polygons
+\details Multi-polygon can be used to group polygons belonging to each other,
+ e.g. Hawaii
+\ingroup geometries
+
+\qbk{before.synopsis,
+[heading Model of]
+[link geometry.reference.concepts.concept_multi_polygon MultiPolygon Concept]
+}
+*/
+template
+<
+ typename Polygon,
+ template<typename, typename> class Container = std::vector,
+ template<typename> class Allocator = std::allocator
+>
+class multi_polygon : public Container<Polygon, Allocator<Polygon> >
+{
+ BOOST_CONCEPT_ASSERT( (concept::Polygon<Polygon>) );
+};
+
+
+} // namespace model
+
+
+#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+namespace traits
+{
+
+template
+<
+ typename Polygon,
+ template<typename, typename> class Container,
+ template<typename> class Allocator
+>
+struct tag< model::multi_polygon<Polygon, Container, Allocator> >
+{
+ typedef multi_polygon_tag type;
+};
+
+} // namespace traits
+#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_MULTI_POLYGON_HPP
diff --git a/boost/geometry/geometries/point.hpp b/boost/geometry/geometries/point.hpp
index b40a47355d..a25340c463 100644
--- a/boost/geometry/geometries/point.hpp
+++ b/boost/geometry/geometries/point.hpp
@@ -28,6 +28,12 @@
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
namespace model
{
@@ -65,7 +71,7 @@ public:
{}
/// @brief Constructor to set one, two or three values
- inline point(CoordinateType const& v0, CoordinateType const& v1 = 0, CoordinateType const& v2 = 0)
+ explicit inline point(CoordinateType const& v0, CoordinateType const& v1 = 0, CoordinateType const& v2 = 0)
{
if (DimensionCount >= 1) m_values[0] = v0;
if (DimensionCount >= 2) m_values[1] = v1;
@@ -173,6 +179,10 @@ struct access<model::point<CoordinateType, DimensionCount, CoordinateSystem>, Di
} // namespace traits
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_GEOMETRIES_POINT_HPP
diff --git a/boost/geometry/geometries/pointing_segment.hpp b/boost/geometry/geometries/pointing_segment.hpp
new file mode 100644
index 0000000000..681752ef2d
--- /dev/null
+++ b/boost/geometry/geometries/pointing_segment.hpp
@@ -0,0 +1,143 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_POINTING_SEGMENT_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_POINTING_SEGMENT_HPP
+
+#include <cstddef>
+
+#include <boost/assert.hpp>
+#include <boost/concept/assert.hpp>
+#include <boost/core/addressof.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_const.hpp>
+
+#include <boost/geometry/geometries/concepts/point_concept.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace model
+{
+
+// const or non-const segment type that is meant to be
+// * default constructible
+// * copy constructible
+// * assignable
+// referring_segment does not fit these requirements, hence the
+// pointing_segment class
+//
+// this class is used by the segment_iterator as its value type
+template <typename ConstOrNonConstPoint>
+class pointing_segment
+{
+ BOOST_CONCEPT_ASSERT( (
+ typename boost::mpl::if_
+ <
+ boost::is_const<ConstOrNonConstPoint>,
+ concept::Point<ConstOrNonConstPoint>,
+ concept::ConstPoint<ConstOrNonConstPoint>
+ >
+ ) );
+
+ typedef ConstOrNonConstPoint point_type;
+
+public:
+ point_type* first;
+ point_type* second;
+
+ inline pointing_segment()
+ : first(NULL)
+ , second(NULL)
+ {}
+
+ inline pointing_segment(point_type const& p1, point_type const& p2)
+ : first(boost::addressof(p1))
+ , second(boost::addressof(p2))
+ {}
+};
+
+
+} // namespace model
+
+
+// Traits specializations for segment above
+#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+namespace traits
+{
+
+template <typename Point>
+struct tag<model::pointing_segment<Point> >
+{
+ typedef segment_tag type;
+};
+
+template <typename Point>
+struct point_type<model::pointing_segment<Point> >
+{
+ typedef Point type;
+};
+
+template <typename Point, std::size_t Dimension>
+struct indexed_access<model::pointing_segment<Point>, 0, Dimension>
+{
+ typedef model::pointing_segment<Point> segment_type;
+ typedef typename geometry::coordinate_type
+ <
+ segment_type
+ >::type coordinate_type;
+
+ static inline coordinate_type get(segment_type const& s)
+ {
+ BOOST_ASSERT( s.first != NULL );
+ return geometry::get<Dimension>(*s.first);
+ }
+
+ static inline void set(segment_type& s, coordinate_type const& value)
+ {
+ BOOST_ASSERT( s.first != NULL );
+ geometry::set<Dimension>(*s.first, value);
+ }
+};
+
+
+template <typename Point, std::size_t Dimension>
+struct indexed_access<model::pointing_segment<Point>, 1, Dimension>
+{
+ typedef model::pointing_segment<Point> segment_type;
+ typedef typename geometry::coordinate_type
+ <
+ segment_type
+ >::type coordinate_type;
+
+ static inline coordinate_type get(segment_type const& s)
+ {
+ BOOST_ASSERT( s.second != NULL );
+ return geometry::get<Dimension>(*s.second);
+ }
+
+ static inline void set(segment_type& s, coordinate_type const& value)
+ {
+ BOOST_ASSERT( s.second != NULL );
+ geometry::set<Dimension>(*s.second, value);
+ }
+};
+
+
+
+} // namespace traits
+#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_POINTING_SEGMENT_HPP
diff --git a/boost/geometry/geometries/register/box.hpp b/boost/geometry/geometries/register/box.hpp
index 838c2bb5fc..71a7077a66 100644
--- a/boost/geometry/geometries/register/box.hpp
+++ b/boost/geometry/geometries/register/box.hpp
@@ -105,7 +105,7 @@ template <> struct indexed_access<Box, max_corner, 1> \
/*!
\brief \brief_macro{box}
\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX, box} The
+\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX, box} The
box may contain template parameters, which must be specified then.
\param Box \param_macro_type{Box}
\param Point Point type on which box is based. Might be two or three-dimensional
@@ -128,7 +128,7 @@ namespace boost { namespace geometry { namespace traits { \
/*!
\brief \brief_macro{box}
\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_TEMPLATED, box}
+\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_TEMPLATED, box}
\details_macro_templated{box, point}
\param Box \param_macro_type{Box}
\param MinCorner minimum corner (should be public member or method)
@@ -149,10 +149,10 @@ namespace boost { namespace geometry { namespace traits { \
/*!
\brief \brief_macro{box}
\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_2D_4VALUES, box}
+\details \details_macro{BOOST_GEOMETRY_REGISTER_BOX_2D_4VALUES, box}
\param Box \param_macro_type{Box}
\param Point Point type reported as point_type by box. Must be two dimensional.
- Note that these box tyeps do not contain points, but they must have a
+ Note that these box tyeps do not contain points, but they must have a
related point_type
\param Left Left side (must be public member or method)
\param Bottom Bottom side (must be public member or method)
diff --git a/boost/geometry/geometries/register/linestring.hpp b/boost/geometry/geometries/register/linestring.hpp
index b064398746..cfc7dcaed2 100644
--- a/boost/geometry/geometries/register/linestring.hpp
+++ b/boost/geometry/geometries/register/linestring.hpp
@@ -22,7 +22,7 @@
/*!
\brief \brief_macro{linestring}
\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING, linestring} The
+\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING, linestring} The
linestring may contain template parameters, which must be specified then.
\param Linestring \param_macro_type{linestring}
@@ -41,7 +41,7 @@ namespace boost { namespace geometry { namespace traits { \
/*!
\brief \brief_macro{templated linestring}
\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED, templated linestring}
+\details \details_macro{BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED, templated linestring}
\details_macro_templated{linestring, point}
\param Linestring \param_macro_type{linestring (without template parameters)}
diff --git a/boost/geometry/geometries/register/multi_linestring.hpp b/boost/geometry/geometries/register/multi_linestring.hpp
new file mode 100644
index 0000000000..ad11289d11
--- /dev/null
+++ b/boost/geometry/geometries/register/multi_linestring.hpp
@@ -0,0 +1,59 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+/*!
+\brief \brief_macro{multi_linestring}
+\ingroup register
+\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING, multi_linestring} The
+ multi_linestring may contain template parameters, which must be specified then.
+\param MultiLineString \param_macro_type{multi_linestring}
+
+\qbk{
+[heading Example]
+[register_multi_linestring]
+[register_multi_linestring_output]
+}
+*/
+#define BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING(MultiLineString) \
+namespace boost { namespace geometry { namespace traits { \
+ template<> struct tag<MultiLineString> { typedef multi_linestring_tag type; }; \
+}}}
+
+
+/*!
+\brief \brief_macro{templated multi_linestring}
+\ingroup register
+\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING_TEMPLATED, templated multi_linestring}
+ \details_macro_templated{multi_linestring, linestring}
+\param MultiLineString \param_macro_type{multi_linestring (without template parameters)}
+
+\qbk{
+[heading Example]
+[register_multi_linestring_templated]
+[register_multi_linestring_templated_output]
+}
+*/
+#define BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING_TEMPLATED(MultiLineString) \
+namespace boost { namespace geometry { namespace traits { \
+ template<typename LineString> struct tag< MultiLineString<LineString> > { typedef multi_linestring_tag type; }; \
+}}}
+
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP
diff --git a/boost/geometry/geometries/register/multi_point.hpp b/boost/geometry/geometries/register/multi_point.hpp
new file mode 100644
index 0000000000..4e875ae0cd
--- /dev/null
+++ b/boost/geometry/geometries/register/multi_point.hpp
@@ -0,0 +1,59 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POINT_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POINT_HPP
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+/*!
+\brief \brief_macro{multi_point}
+\ingroup register
+\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POINT, multi_point} The
+ multi_point may contain template parameters, which must be specified then.
+\param MultiPoint \param_macro_type{multi_point}
+
+\qbk{
+[heading Example]
+[register_multi_point]
+[register_multi_point_output]
+}
+*/
+#define BOOST_GEOMETRY_REGISTER_MULTI_POINT(MultiPoint) \
+namespace boost { namespace geometry { namespace traits { \
+ template<> struct tag<MultiPoint> { typedef multi_point_tag type; }; \
+}}}
+
+
+/*!
+\brief \brief_macro{templated multi_point}
+\ingroup register
+\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED, templated multi_point}
+ \details_macro_templated{multi_point, point}
+\param MultiPoint \param_macro_type{multi_point (without template parameters)}
+
+\qbk{
+[heading Example]
+[register_multi_point_templated]
+[register_multi_point_templated_output]
+}
+*/
+#define BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED(MultiPoint) \
+namespace boost { namespace geometry { namespace traits { \
+ template<typename Point> struct tag< MultiPoint<Point> > { typedef multi_point_tag type; }; \
+}}}
+
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POINT_HPP
diff --git a/boost/geometry/geometries/register/multi_polygon.hpp b/boost/geometry/geometries/register/multi_polygon.hpp
new file mode 100644
index 0000000000..1c3818b551
--- /dev/null
+++ b/boost/geometry/geometries/register/multi_polygon.hpp
@@ -0,0 +1,59 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+/*!
+\brief \brief_macro{multi_polygon}
+\ingroup register
+\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POLYGON, multi_polygon} The
+ multi_polygon may contain template parameters, which must be specified then.
+\param MultiPolygon \param_macro_type{multi_polygon}
+
+\qbk{
+[heading Example]
+[register_multi_polygon]
+[register_multi_polygon_output]
+}
+*/
+#define BOOST_GEOMETRY_REGISTER_MULTI_POLYGON(MultiPolygon) \
+namespace boost { namespace geometry { namespace traits { \
+ template<> struct tag<MultiPolygon> { typedef multi_polygon_tag type; }; \
+}}}
+
+
+/*!
+\brief \brief_macro{templated multi_polygon}
+\ingroup register
+\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POLYGON_TEMPLATED, templated multi_polygon}
+ \details_macro_templated{multi_polygon, polygon}
+\param MultiPolygon \param_macro_type{multi_polygon (without template parameters)}
+
+\qbk{
+[heading Example]
+[register_multi_polygon_templated]
+[register_multi_polygon_templated_output]
+}
+*/
+#define BOOST_GEOMETRY_REGISTER_MULTI_POLYGON_TEMPLATED(MultiPolygon) \
+namespace boost { namespace geometry { namespace traits { \
+ template<typename Polygon> struct tag< MultiPolygon<Polygon> > { typedef multi_polygon_tag type; }; \
+}}}
+
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP
diff --git a/boost/geometry/geometries/register/ring.hpp b/boost/geometry/geometries/register/ring.hpp
index fb6cb67200..761e46fbc4 100644
--- a/boost/geometry/geometries/register/ring.hpp
+++ b/boost/geometry/geometries/register/ring.hpp
@@ -22,7 +22,7 @@
/*!
\brief \brief_macro{ring}
\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_RING, ring} The
+\details \details_macro{BOOST_GEOMETRY_REGISTER_RING, ring} The
ring may contain template parameters, which must be specified then.
\param Ring \param_macro_type{ring}
@@ -41,7 +41,7 @@ namespace boost { namespace geometry { namespace traits { \
/*!
\brief \brief_macro{templated ring}
\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_RING_TEMPLATED, templated ring}
+\details \details_macro{BOOST_GEOMETRY_REGISTER_RING_TEMPLATED, templated ring}
\details_macro_templated{ring, point}
\param Ring \param_macro_type{ring (without template parameters)}
diff --git a/boost/geometry/geometries/variant.hpp b/boost/geometry/geometries/variant.hpp
new file mode 100644
index 0000000000..9db11d5a82
--- /dev/null
+++ b/boost/geometry/geometries/variant.hpp
@@ -0,0 +1,34 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_GEOMETRIES_VARIANT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_GEOMETRIES_VARIANT_GEOMETRY_HPP
+
+
+#include <boost/variant/variant_fwd.hpp>
+
+
+namespace boost { namespace geometry {
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct point_type<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+ : point_type<T0>
+{};
+
+
+} // namespace geometry
+} // namespace boost
+
+
+#endif // BOOST_GEOMETRY_GEOMETRIES_VARIANT_GEOMETRY_HPP
diff --git a/boost/geometry/geometry.hpp b/boost/geometry/geometry.hpp
index b696b652cf..110f0e60ff 100644
--- a/boost/geometry/geometry.hpp
+++ b/boost/geometry/geometry.hpp
@@ -16,7 +16,15 @@
// Shortcut to include all header files
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/coordinate_system.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/interior_type.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -45,6 +53,7 @@
#include <boost/geometry/algorithms/convex_hull.hpp>
#include <boost/geometry/algorithms/correct.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/crosses.hpp>
#include <boost/geometry/algorithms/difference.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/distance.hpp>
@@ -54,13 +63,17 @@
#include <boost/geometry/algorithms/for_each.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/is_simple.hpp>
+#include <boost/geometry/algorithms/is_valid.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/algorithms/make.hpp>
#include <boost/geometry/algorithms/num_geometries.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/num_segments.hpp>
#include <boost/geometry/algorithms/overlaps.hpp>
#include <boost/geometry/algorithms/perimeter.hpp>
+#include <boost/geometry/algorithms/remove_spikes.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
#include <boost/geometry/algorithms/simplify.hpp>
#include <boost/geometry/algorithms/sym_difference.hpp>
@@ -79,13 +92,20 @@
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/math.hpp>
-#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
-#include <boost/geometry/io/dsv/write.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/views/box_view.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/identity_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/segment_view.hpp>
#include <boost/geometry/io/io.hpp>
+#include <boost/geometry/io/dsv/write.hpp>
+#include <boost/geometry/io/svg/svg_mapper.hpp>
+#include <boost/geometry/io/svg/write_svg.hpp>
+#include <boost/geometry/io/wkt/read.hpp>
+#include <boost/geometry/io/wkt/write.hpp>
#endif // BOOST_GEOMETRY_GEOMETRY_HPP
diff --git a/boost/geometry/index/adaptors/query.hpp b/boost/geometry/index/adaptors/query.hpp
new file mode 100644
index 0000000000..472b3693b1
--- /dev/null
+++ b/boost/geometry/index/adaptors/query.hpp
@@ -0,0 +1,88 @@
+// Boost.Geometry Index
+//
+// Query range adaptor
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP
+#define BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP
+
+/*!
+\defgroup adaptors Adaptors (boost::geometry::index::adaptors::)
+*/
+
+namespace boost { namespace geometry { namespace index {
+
+namespace adaptors {
+
+namespace detail {
+
+template <typename Index>
+class query_range
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_INDEX,
+ (query_range));
+
+ typedef int* iterator;
+ typedef const int* const_iterator;
+
+ template <typename Predicates>
+ inline query_range(
+ Index const&,
+ Predicates const&)
+ {}
+
+ inline iterator begin() { return 0; }
+ inline iterator end() { return 0; }
+ inline const_iterator begin() const { return 0; }
+ inline const_iterator end() const { return 0; }
+};
+
+// TODO: awulkiew - consider removing reference from predicates
+
+template<typename Predicates>
+struct query
+{
+ inline explicit query(Predicates const& pred)
+ : predicates(pred)
+ {}
+
+ Predicates const& predicates;
+};
+
+template<typename Index, typename Predicates>
+index::adaptors::detail::query_range<Index>
+operator|(
+ Index const& si,
+ index::adaptors::detail::query<Predicates> const& f)
+{
+ return index::adaptors::detail::query_range<Index>(si, f.predicates);
+}
+
+} // namespace detail
+
+/*!
+\brief The query index adaptor generator.
+
+\ingroup adaptors
+
+\param pred Predicates.
+*/
+template <typename Predicates>
+detail::query<Predicates>
+queried(Predicates const& pred)
+{
+ return detail::query<Predicates>(pred);
+}
+
+} // namespace adaptors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP
diff --git a/boost/geometry/index/detail/algorithms/bounds.hpp b/boost/geometry/index/detail/algorithms/bounds.hpp
new file mode 100644
index 0000000000..4d2416e98d
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/bounds.hpp
@@ -0,0 +1,90 @@
+// Boost.Geometry Index
+//
+// n-dimensional bounds
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP
+
+#include <boost/geometry/index/detail/bounded_view.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+namespace dispatch {
+
+template <typename Geometry,
+ typename Bounds,
+ typename TagGeometry = typename geometry::tag<Geometry>::type,
+ typename TagBounds = typename geometry::tag<Bounds>::type>
+struct bounds
+{
+ static inline void apply(Geometry const& g, Bounds & b)
+ {
+ geometry::convert(g, b);
+ }
+};
+
+template <typename Geometry, typename Bounds>
+struct bounds<Geometry, Bounds, segment_tag, box_tag>
+{
+ static inline void apply(Geometry const& g, Bounds & b)
+ {
+ index::detail::bounded_view<Geometry, Bounds> v(g);
+ geometry::convert(v, b);
+ }
+};
+
+} // namespace dispatch
+
+template <typename Geometry, typename Bounds>
+inline void bounds(Geometry const& g, Bounds & b)
+{
+ concept::check_concepts_and_equal_dimensions<Geometry const, Bounds>();
+ dispatch::bounds<Geometry, Bounds>::apply(g, b);
+}
+
+namespace dispatch {
+
+template <typename Geometry,
+ typename TagGeometry = typename geometry::tag<Geometry>::type>
+struct return_ref_or_bounds
+{
+ typedef Geometry const& result_type;
+
+ static inline result_type apply(Geometry const& g)
+ {
+ return g;
+ }
+};
+
+template <typename Geometry>
+struct return_ref_or_bounds<Geometry, segment_tag>
+{
+ typedef typename point_type<Geometry>::type point_type;
+ typedef geometry::model::box<point_type> bounds_type;
+ typedef index::detail::bounded_view<Geometry, bounds_type> result_type;
+
+ static inline result_type apply(Geometry const& g)
+ {
+ return result_type(g);
+ }
+};
+
+} // namespace dispatch
+
+template <typename Geometry>
+inline
+typename dispatch::return_ref_or_bounds<Geometry>::result_type
+return_ref_or_bounds(Geometry const& g)
+{
+ return dispatch::return_ref_or_bounds<Geometry>::apply(g);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP
diff --git a/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp b/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp
new file mode 100644
index 0000000000..c4e44cae18
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp
@@ -0,0 +1,77 @@
+// Boost.Geometry Index
+//
+// squared distance between point and centroid of the box or point
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP
+
+#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
+#include <boost/geometry/index/detail/algorithms/diff_abs.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+struct comparable_distance_centroid_tag {};
+
+template <
+ typename Point,
+ typename PointIndexable,
+ size_t N>
+struct sum_for_indexable<Point, PointIndexable, point_tag, comparable_distance_centroid_tag, N>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, PointIndexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, PointIndexable const& i)
+ {
+ return geometry::comparable_distance(pt, i);
+ }
+};
+
+template <
+ typename Point,
+ typename BoxIndexable,
+ size_t DimensionIndex>
+struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_centroid_tag, DimensionIndex>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, BoxIndexable const& i)
+ {
+ typedef typename coordinate_type<Point>::type point_coord_t;
+ typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
+
+ point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
+ indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
+ indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
+
+ indexable_coord_t ind_c_avg = ind_c_min + (ind_c_max - ind_c_min) / 2;
+ // TODO: awulkiew - is (ind_c_min + ind_c_max) / 2 safe?
+
+ result_type diff = detail::diff_abs(ind_c_avg, pt_c);
+
+ return diff * diff;
+ }
+};
+
+template <typename Point, typename Indexable>
+typename geometry::default_comparable_distance_result<Point, Indexable>::type
+comparable_distance_centroid(Point const& pt, Indexable const& i)
+{
+ return detail::sum_for_indexable<
+ Point,
+ Indexable,
+ typename tag<Indexable>::type,
+ detail::comparable_distance_centroid_tag,
+ dimension<Indexable>::value
+ >::apply(pt, i);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP
+
diff --git a/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp b/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp
new file mode 100644
index 0000000000..214fbf6aaf
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp
@@ -0,0 +1,66 @@
+// Boost.Geometry Index
+//
+// squared distance between point and furthest point of the box or point
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP
+
+#include <boost/geometry/index/detail/algorithms/diff_abs.hpp>
+#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+// minmaxdist component
+
+struct comparable_distance_far_tag {};
+
+template <
+ typename Point,
+ typename BoxIndexable,
+ size_t DimensionIndex>
+struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_far_tag, DimensionIndex>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, BoxIndexable const& i)
+ {
+ typedef typename coordinate_type<Point>::type point_coord_t;
+ typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
+
+ point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
+ indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
+ indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
+
+ result_type further_diff = 0;
+
+ if ( (ind_c_min + ind_c_max) / 2 <= pt_c )
+ further_diff = pt_c - ind_c_min;
+ else
+ further_diff = detail::diff_abs(pt_c, ind_c_max); // unsigned values protection
+
+ return further_diff * further_diff;
+ }
+};
+
+template <typename Point, typename Indexable>
+typename geometry::default_comparable_distance_result<Point, Indexable>::type
+comparable_distance_far(Point const& pt, Indexable const& i)
+{
+ return detail::sum_for_indexable<
+ Point,
+ Indexable,
+ typename tag<Indexable>::type,
+ detail::comparable_distance_far_tag,
+ dimension<Indexable>::value
+ >::apply(pt, i);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP
diff --git a/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp b/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp
new file mode 100644
index 0000000000..15368a7d24
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp
@@ -0,0 +1,77 @@
+// Boost.Geometry Index
+//
+// squared distance between point and nearest point of the box or point
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP
+
+#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+struct comparable_distance_near_tag {};
+
+template <
+ typename Point,
+ typename PointIndexable,
+ size_t N>
+struct sum_for_indexable<Point, PointIndexable, point_tag, comparable_distance_near_tag, N>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, PointIndexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, PointIndexable const& i)
+ {
+ return geometry::comparable_distance(pt, i);
+ }
+};
+
+template <
+ typename Point,
+ typename BoxIndexable,
+ size_t DimensionIndex>
+struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_near_tag, DimensionIndex>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, BoxIndexable const& i)
+ {
+ typedef typename coordinate_type<Point>::type point_coord_t;
+ typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
+
+ point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
+ indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
+ indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
+
+ result_type diff = 0;
+
+ if ( pt_c < ind_c_min )
+ diff = ind_c_min - pt_c;
+ else if ( ind_c_max < pt_c )
+ diff = pt_c - ind_c_max;
+
+ return diff * diff;
+ }
+};
+
+template <typename Point, typename Indexable>
+typename geometry::default_comparable_distance_result<Point, Indexable>::type
+comparable_distance_near(Point const& pt, Indexable const& i)
+{
+ return detail::sum_for_indexable<
+ Point,
+ Indexable,
+ typename tag<Indexable>::type,
+ detail::comparable_distance_near_tag,
+ dimension<Indexable>::value
+ >::apply(pt, i);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP
diff --git a/boost/geometry/index/detail/algorithms/content.hpp b/boost/geometry/index/detail/algorithms/content.hpp
new file mode 100644
index 0000000000..028113e0ef
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/content.hpp
@@ -0,0 +1,87 @@
+// Boost.Geometry Index
+//
+// n-dimensional content (hypervolume) - 2d area, 3d volume, ...
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename Indexable>
+struct default_content_result
+{
+ typedef typename select_most_precise<
+ typename coordinate_type<Indexable>::type,
+ long double
+ >::type type;
+};
+
+namespace dispatch {
+
+template <typename Box,
+ std::size_t CurrentDimension = dimension<Box>::value>
+struct content_box
+{
+ BOOST_STATIC_ASSERT(0 < CurrentDimension);
+
+ static inline typename detail::default_content_result<Box>::type apply(Box const& b)
+ {
+ return content_box<Box, CurrentDimension - 1>::apply(b) *
+ ( get<max_corner, CurrentDimension - 1>(b) - get<min_corner, CurrentDimension - 1>(b) );
+ }
+};
+
+template <typename Box>
+struct content_box<Box, 1>
+{
+ static inline typename detail::default_content_result<Box>::type apply(Box const& b)
+ {
+ return get<max_corner, 0>(b) - get<min_corner, 0>(b);
+ }
+};
+
+template <typename Indexable, typename Tag>
+struct content
+{
+ BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_AND_TAG, (Indexable, Tag));
+};
+
+template <typename Indexable>
+struct content<Indexable, point_tag>
+{
+ static typename detail::default_content_result<Indexable>::type apply(Indexable const&)
+ {
+ return 0;
+ }
+};
+
+template <typename Indexable>
+struct content<Indexable, box_tag>
+{
+ static typename default_content_result<Indexable>::type apply(Indexable const& b)
+ {
+ return dispatch::content_box<Indexable>::apply(b);
+ }
+};
+
+} // namespace dispatch
+
+template <typename Indexable>
+typename default_content_result<Indexable>::type content(Indexable const& b)
+{
+ return dispatch::content
+ <
+ Indexable,
+ typename tag<Indexable>::type
+ >::apply(b);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP
diff --git a/boost/geometry/index/detail/algorithms/diff_abs.hpp b/boost/geometry/index/detail/algorithms/diff_abs.hpp
new file mode 100644
index 0000000000..ec63bd9a5d
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/diff_abs.hpp
@@ -0,0 +1,39 @@
+// Boost.Geometry Index
+//
+// Abs of difference
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename T>
+inline T diff_abs_dispatch(T const& v1, T const& v2, boost::mpl::bool_<true> const& /*is_integral*/)
+{
+ return v1 < v2 ? v2 - v1 : v1 - v2;
+}
+
+template <typename T>
+inline T diff_abs_dispatch(T const& v1, T const& v2, boost::mpl::bool_<false> const& /*is_integral*/)
+{
+ return ::fabs(v1 - v2);
+}
+
+template <typename T>
+inline T diff_abs(T const& v1, T const& v2)
+{
+ typedef boost::mpl::bool_<
+ boost::is_integral<T>::value
+ > is_integral;
+ return diff_abs_dispatch(v1, v2, is_integral());
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP
diff --git a/boost/geometry/index/detail/algorithms/intersection_content.hpp b/boost/geometry/index/detail/algorithms/intersection_content.hpp
new file mode 100644
index 0000000000..4afb40479c
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/intersection_content.hpp
@@ -0,0 +1,37 @@
+// Boost.Geometry Index
+//
+// boxes union/intersection area/volume
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP
+
+#include <boost/geometry/algorithms/intersection.hpp>
+#include <boost/geometry/strategies/intersection.hpp>
+#include <boost/geometry/index/detail/algorithms/content.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+/**
+ * \brief Compute the area of the intersection of b1 and b2
+ */
+template <typename Box>
+inline typename default_content_result<Box>::type intersection_content(Box const& box1, Box const& box2)
+{
+ if ( geometry::intersects(box1, box2) )
+ {
+ Box box_intersection;
+ if ( geometry::intersection(box1, box2, box_intersection) )
+ return detail::content(box_intersection);
+ }
+ return 0;
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP
diff --git a/boost/geometry/index/detail/algorithms/is_valid.hpp b/boost/geometry/index/detail/algorithms/is_valid.hpp
new file mode 100644
index 0000000000..d85ac56d69
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/is_valid.hpp
@@ -0,0 +1,88 @@
+// Boost.Geometry Index
+//
+// n-dimensional Indexable validity check
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_IS_VALID_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_IS_VALID_HPP
+
+#include <cstddef>
+#include <boost/geometry/core/access.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+namespace dispatch {
+
+template <typename Box,
+ std::size_t Dimension = geometry::dimension<Box>::value>
+struct is_valid_box
+{
+ static inline bool apply(Box const& b)
+ {
+ return is_valid_box<Box, Dimension - 1>::apply(b) &&
+ ( get<min_corner, Dimension - 1>(b) <= get<max_corner, Dimension - 1>(b) );
+ }
+};
+
+template <typename Box>
+struct is_valid_box<Box, 1>
+{
+ static inline bool apply(Box const& b)
+ {
+ return get<min_corner, 0>(b) <= get<max_corner, 0>(b);
+ }
+};
+
+template <typename Indexable,
+ typename Tag = typename geometry::tag<Indexable>::type>
+struct is_valid
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_INDEXABLE,
+ (is_valid));
+};
+
+template <typename Indexable>
+struct is_valid<Indexable, point_tag>
+{
+ static inline bool apply(Indexable const&)
+ {
+ return true;
+ }
+};
+
+template <typename Indexable>
+struct is_valid<Indexable, box_tag>
+{
+ static inline bool apply(Indexable const& b)
+ {
+ return dispatch::is_valid_box<Indexable>::apply(b);
+ }
+};
+
+template <typename Indexable>
+struct is_valid<Indexable, segment_tag>
+{
+ static inline bool apply(Indexable const&)
+ {
+ return true;
+ }
+};
+
+} // namespace dispatch
+
+template <typename Indexable>
+inline bool is_valid(Indexable const& b)
+{
+ return dispatch::is_valid<Indexable>::apply(b);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_DETAIL_INDEX_ALGORITHMS_IS_VALID_HPP
diff --git a/boost/geometry/index/detail/algorithms/margin.hpp b/boost/geometry/index/detail/algorithms/margin.hpp
new file mode 100644
index 0000000000..d4876600ac
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/margin.hpp
@@ -0,0 +1,169 @@
+// Boost.Geometry Index
+//
+// n-dimensional box's margin value (hypersurface), 2d perimeter, 3d surface, etc...
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
+
+// WARNING! comparable_margin() will work only if the same Geometries are compared
+// so it shouldn't be used in the case of Variants!
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename Box>
+struct default_margin_result
+{
+ typedef typename select_most_precise<
+ typename coordinate_type<Box>::type,
+ long double
+ >::type type;
+};
+
+//template <typename Box,
+// std::size_t CurrentDimension,
+// std::size_t EdgeDimension = dimension<Box>::value>
+//struct margin_for_each_edge
+//{
+// BOOST_STATIC_ASSERT(0 < CurrentDimension);
+// BOOST_STATIC_ASSERT(0 < EdgeDimension);
+//
+// static inline typename default_margin_result<Box>::type apply(Box const& b)
+// {
+// return margin_for_each_edge<Box, CurrentDimension, EdgeDimension - 1>::apply(b) *
+// ( geometry::get<max_corner, EdgeDimension - 1>(b) - geometry::get<min_corner, EdgeDimension - 1>(b) );
+// }
+//};
+//
+//template <typename Box, std::size_t CurrentDimension>
+//struct margin_for_each_edge<Box, CurrentDimension, CurrentDimension>
+//{
+// BOOST_STATIC_ASSERT(0 < CurrentDimension);
+//
+// static inline typename default_margin_result<Box>::type apply(Box const& b)
+// {
+// return margin_for_each_edge<Box, CurrentDimension, CurrentDimension - 1>::apply(b);
+// }
+//};
+//
+//template <typename Box, std::size_t CurrentDimension>
+//struct margin_for_each_edge<Box, CurrentDimension, 1>
+//{
+// BOOST_STATIC_ASSERT(0 < CurrentDimension);
+//
+// static inline typename default_margin_result<Box>::type apply(Box const& b)
+// {
+// return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b);
+// }
+//};
+//
+//template <typename Box>
+//struct margin_for_each_edge<Box, 1, 1>
+//{
+// static inline typename default_margin_result<Box>::type apply(Box const& /*b*/)
+// {
+// return 1;
+// }
+//};
+//
+//template <typename Box,
+// std::size_t CurrentDimension = dimension<Box>::value>
+//struct margin_for_each_dimension
+//{
+// BOOST_STATIC_ASSERT(0 < CurrentDimension);
+//
+// static inline typename default_margin_result<Box>::type apply(Box const& b)
+// {
+// return margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) +
+// margin_for_each_edge<Box, CurrentDimension>::apply(b);
+// }
+//};
+//
+//template <typename Box>
+//struct margin_for_each_dimension<Box, 1>
+//{
+// static inline typename default_margin_result<Box>::type apply(Box const& b)
+// {
+// return margin_for_each_edge<Box, 1>::apply(b);
+// }
+//};
+
+// TODO - test if this definition of margin is ok for Dimension > 2
+// Now it's sum of edges lengths
+// maybe margin_for_each_dimension should be used to get more or less hypersurface?
+
+template <typename Box,
+ std::size_t CurrentDimension = dimension<Box>::value>
+struct simple_margin_for_each_dimension
+{
+ BOOST_STATIC_ASSERT(0 < CurrentDimension);
+
+ static inline typename default_margin_result<Box>::type apply(Box const& b)
+ {
+ return simple_margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) +
+ geometry::get<max_corner, CurrentDimension - 1>(b) - geometry::get<min_corner, CurrentDimension - 1>(b);
+ }
+};
+
+template <typename Box>
+struct simple_margin_for_each_dimension<Box, 1>
+{
+ static inline typename default_margin_result<Box>::type apply(Box const& b)
+ {
+ return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b);
+ }
+};
+
+namespace dispatch {
+
+template <typename Geometry, typename Tag>
+struct comparable_margin
+{
+ BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (Geometry, Tag));
+};
+
+template <typename Geometry>
+struct comparable_margin<Geometry, point_tag>
+{
+ typedef typename default_margin_result<Geometry>::type result_type;
+
+ static inline result_type apply(Geometry const& ) { return 0; }
+};
+
+template <typename Box>
+struct comparable_margin<Box, box_tag>
+{
+ typedef typename default_margin_result<Box>::type result_type;
+
+ static inline result_type apply(Box const& g)
+ {
+ //return detail::margin_for_each_dimension<Box>::apply(g);
+ return detail::simple_margin_for_each_dimension<Box>::apply(g);
+ }
+};
+
+} // namespace dispatch
+
+template <typename Geometry>
+typename default_margin_result<Geometry>::type comparable_margin(Geometry const& g)
+{
+ return dispatch::comparable_margin<
+ Geometry,
+ typename tag<Geometry>::type
+ >::apply(g);
+}
+
+//template <typename Box>
+//typename default_margin_result<Box>::type margin(Box const& b)
+//{
+// return 2 * detail::margin_for_each_dimension<Box>::apply(b);
+//}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
diff --git a/boost/geometry/index/detail/algorithms/minmaxdist.hpp b/boost/geometry/index/detail/algorithms/minmaxdist.hpp
new file mode 100644
index 0000000000..ab6291504f
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/minmaxdist.hpp
@@ -0,0 +1,119 @@
+// Boost.Geometry Index
+//
+// minmaxdist used in R-tree k nearest neighbors query
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP
+
+#include <boost/geometry/algorithms/distance.hpp>
+#include <boost/geometry/algorithms/comparable_distance.hpp>
+
+#include <boost/geometry/index/detail/algorithms/diff_abs.hpp>
+#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
+#include <boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+struct minmaxdist_tag {};
+
+template <
+ typename Point,
+ typename BoxIndexable,
+ size_t DimensionIndex>
+struct smallest_for_indexable_dimension<Point, BoxIndexable, box_tag, minmaxdist_tag, DimensionIndex>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, BoxIndexable const& i, result_type const& maxd)
+ {
+ typedef typename coordinate_type<Point>::type point_coord_t;
+ typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
+
+ point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
+ indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
+ indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
+
+ indexable_coord_t ind_c_avg = ind_c_min + (ind_c_max - ind_c_min) / 2;
+ // TODO: awulkiew - is (ind_c_min + ind_c_max) / 2 safe?
+
+ // TODO: awulkiew - optimize! don't calculate 2x pt_c <= ind_c_avg
+ // take particular case pt_c == ind_c_avg into account
+
+ result_type closer_comp = 0;
+ if ( pt_c <= ind_c_avg )
+ closer_comp = detail::diff_abs(pt_c, ind_c_min); // unsigned values protection
+ else
+ closer_comp = ind_c_max - pt_c;
+
+ result_type further_comp = 0;
+ if ( ind_c_avg <= pt_c )
+ further_comp = pt_c - ind_c_min;
+ else
+ further_comp = detail::diff_abs(pt_c, ind_c_max); // unsigned values protection
+
+ return (maxd + closer_comp * closer_comp) - further_comp * further_comp;
+ }
+};
+
+template <typename Point, typename Indexable, typename IndexableTag>
+struct minmaxdist_impl
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE,
+ (minmaxdist_impl));
+};
+
+template <typename Point, typename Indexable>
+struct minmaxdist_impl<Point, Indexable, point_tag>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, Indexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, Indexable const& i)
+ {
+ return geometry::comparable_distance(pt, i);
+ }
+};
+
+template <typename Point, typename Indexable>
+struct minmaxdist_impl<Point, Indexable, box_tag>
+{
+ typedef typename geometry::default_comparable_distance_result<Point, Indexable>::type result_type;
+
+ inline static result_type apply(Point const& pt, Indexable const& i)
+ {
+ result_type maxd = geometry::comparable_distance(pt, i);
+
+ return smallest_for_indexable<
+ Point,
+ Indexable,
+ box_tag,
+ minmaxdist_tag,
+ dimension<Indexable>::value
+ >::apply(pt, i, maxd);
+ }
+};
+
+/**
+ * This is comparable distace.
+ */
+template <typename Point, typename Indexable>
+typename geometry::default_comparable_distance_result<Point, Indexable>::type
+minmaxdist(Point const& pt, Indexable const& i)
+{
+ return detail::minmaxdist_impl<
+ Point,
+ Indexable,
+ typename tag<Indexable>::type
+ >::apply(pt, i);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP
diff --git a/boost/geometry/index/detail/algorithms/path_intersection.hpp b/boost/geometry/index/detail/algorithms/path_intersection.hpp
new file mode 100644
index 0000000000..fe92596ba2
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/path_intersection.hpp
@@ -0,0 +1,119 @@
+// Boost.Geometry Index
+//
+// n-dimensional box-linestring intersection
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP
+
+#include <boost/geometry/index/detail/algorithms/segment_intersection.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+namespace dispatch {
+
+template <typename Indexable, typename Geometry, typename IndexableTag, typename GeometryTag>
+struct path_intersection
+{
+ BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_OR_INDEXABLE, (path_intersection));
+};
+
+// TODO: FP type must be used as a relative distance type!
+// and default_distance_result can be some user-defined int type
+// BUT! This code is experimental and probably won't be released at all
+// since more flexible user-defined-nearest predicate should be added instead
+
+template <typename Indexable, typename Segment>
+struct path_intersection<Indexable, Segment, box_tag, segment_tag>
+{
+ typedef typename default_distance_result<typename point_type<Segment>::type>::type comparable_distance_type;
+
+ static inline bool apply(Indexable const& b, Segment const& segment, comparable_distance_type & comparable_distance)
+ {
+ typedef typename point_type<Segment>::type point_type;
+ point_type p1, p2;
+ geometry::detail::assign_point_from_index<0>(segment, p1);
+ geometry::detail::assign_point_from_index<1>(segment, p2);
+ return index::detail::segment_intersection(b, p1, p2, comparable_distance);
+ }
+};
+
+template <typename Indexable, typename Linestring>
+struct path_intersection<Indexable, Linestring, box_tag, linestring_tag>
+{
+ typedef typename default_length_result<Linestring>::type comparable_distance_type;
+
+ static inline bool apply(Indexable const& b, Linestring const& path, comparable_distance_type & comparable_distance)
+ {
+ typedef typename ::boost::range_value<Linestring>::type point_type;
+ typedef typename ::boost::range_const_iterator<Linestring>::type const_iterator;
+ typedef typename ::boost::range_size<Linestring>::type size_type;
+
+ const size_type count = ::boost::size(path);
+
+ if ( count == 2 )
+ {
+ return index::detail::segment_intersection(b, *::boost::begin(path), *(::boost::begin(path)+1), comparable_distance);
+ }
+ else if ( 2 < count )
+ {
+ const_iterator it0 = ::boost::begin(path);
+ const_iterator it1 = ::boost::begin(path) + 1;
+ const_iterator last = ::boost::end(path);
+
+ comparable_distance = 0;
+
+ for ( ; it1 != last ; ++it0, ++it1 )
+ {
+ typename default_distance_result<point_type, point_type>::type
+ dist = geometry::distance(*it0, *it1);
+
+ comparable_distance_type rel_dist;
+ if ( index::detail::segment_intersection(b, *it0, *it1, rel_dist) )
+ {
+ comparable_distance += dist * rel_dist;
+ return true;
+ }
+ else
+ comparable_distance += dist;
+ }
+ }
+
+ return false;
+ }
+};
+
+} // namespace dispatch
+
+template <typename Indexable, typename SegmentOrLinestring>
+struct default_path_intersection_distance_type
+{
+ typedef typename dispatch::path_intersection<
+ Indexable, SegmentOrLinestring,
+ typename tag<Indexable>::type,
+ typename tag<SegmentOrLinestring>::type
+ >::comparable_distance_type type;
+};
+
+template <typename Indexable, typename SegmentOrLinestring> inline
+bool path_intersection(Indexable const& b,
+ SegmentOrLinestring const& path,
+ typename default_path_intersection_distance_type<Indexable, SegmentOrLinestring>::type & comparable_distance)
+{
+ // TODO check Indexable and Linestring concepts
+
+ return dispatch::path_intersection<
+ Indexable, SegmentOrLinestring,
+ typename tag<Indexable>::type,
+ typename tag<SegmentOrLinestring>::type
+ >::apply(b, path, comparable_distance);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP
diff --git a/boost/geometry/index/detail/algorithms/segment_intersection.hpp b/boost/geometry/index/detail/algorithms/segment_intersection.hpp
new file mode 100644
index 0000000000..ec7a88f490
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/segment_intersection.hpp
@@ -0,0 +1,146 @@
+// Boost.Geometry Index
+//
+// n-dimensional box-segment intersection
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+//template <typename Indexable, typename Point>
+//struct default_relative_distance_type
+//{
+// typedef typename select_most_precise<
+// typename select_most_precise<
+// typename coordinate_type<Indexable>::type,
+// typename coordinate_type<Point>::type
+// >::type,
+// float // TODO - use bigger type, calculated from the size of coordinate types
+// >::type type;
+//
+//
+// BOOST_MPL_ASSERT_MSG((!::boost::is_unsigned<type>::value),
+// THIS_TYPE_SHOULDNT_BE_UNSIGNED, (type));
+//};
+
+namespace dispatch {
+
+template <typename Box, typename Point, size_t I>
+struct box_segment_intersection_dim
+{
+ BOOST_STATIC_ASSERT(0 <= dimension<Box>::value);
+ BOOST_STATIC_ASSERT(0 <= dimension<Point>::value);
+ BOOST_STATIC_ASSERT(I < size_t(dimension<Box>::value));
+ BOOST_STATIC_ASSERT(I < size_t(dimension<Point>::value));
+ BOOST_STATIC_ASSERT(dimension<Point>::value == dimension<Box>::value);
+
+ // WARNING! - RelativeDistance must be IEEE float for this to work
+
+ template <typename RelativeDistance>
+ static inline bool apply(Box const& b, Point const& p0, Point const& p1,
+ RelativeDistance & t_near, RelativeDistance & t_far)
+ {
+ RelativeDistance ray_d = geometry::get<I>(p1) - geometry::get<I>(p0);
+ RelativeDistance tn = ( geometry::get<min_corner, I>(b) - geometry::get<I>(p0) ) / ray_d;
+ RelativeDistance tf = ( geometry::get<max_corner, I>(b) - geometry::get<I>(p0) ) / ray_d;
+ if ( tf < tn )
+ ::std::swap(tn, tf);
+
+ if ( t_near < tn )
+ t_near = tn;
+ if ( tf < t_far )
+ t_far = tf;
+
+ return 0 <= t_far && t_near <= t_far;
+ }
+};
+
+template <typename Box, typename Point, size_t CurrentDimension>
+struct box_segment_intersection
+{
+ BOOST_STATIC_ASSERT(0 < CurrentDimension);
+
+ typedef box_segment_intersection_dim<Box, Point, CurrentDimension - 1> for_dim;
+
+ template <typename RelativeDistance>
+ static inline bool apply(Box const& b, Point const& p0, Point const& p1,
+ RelativeDistance & t_near, RelativeDistance & t_far)
+ {
+ return box_segment_intersection<Box, Point, CurrentDimension - 1>::apply(b, p0, p1, t_near, t_far)
+ && for_dim::apply(b, p0, p1, t_near, t_far);
+ }
+};
+
+template <typename Box, typename Point>
+struct box_segment_intersection<Box, Point, 1>
+{
+ typedef box_segment_intersection_dim<Box, Point, 0> for_dim;
+
+ template <typename RelativeDistance>
+ static inline bool apply(Box const& b, Point const& p0, Point const& p1,
+ RelativeDistance & t_near, RelativeDistance & t_far)
+ {
+ return for_dim::apply(b, p0, p1, t_near, t_far);
+ }
+};
+
+template <typename Indexable, typename Point, typename Tag>
+struct segment_intersection
+{
+ BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (segment_intersection));
+};
+
+template <typename Indexable, typename Point>
+struct segment_intersection<Indexable, Point, point_tag>
+{
+ BOOST_MPL_ASSERT_MSG((false), SEGMENT_POINT_INTERSECTION_UNAVAILABLE, (segment_intersection));
+};
+
+template <typename Indexable, typename Point>
+struct segment_intersection<Indexable, Point, box_tag>
+{
+ typedef dispatch::box_segment_intersection<Indexable, Point, dimension<Indexable>::value> impl;
+
+ template <typename RelativeDistance>
+ static inline bool apply(Indexable const& b, Point const& p0, Point const& p1, RelativeDistance & relative_distance)
+ {
+
+// TODO: this ASSERT CHECK is wrong for user-defined CoordinateTypes!
+
+ static const bool check = !::boost::is_integral<RelativeDistance>::value;
+ BOOST_MPL_ASSERT_MSG(check, RELATIVE_DISTANCE_MUST_BE_FLOATING_POINT_TYPE, (RelativeDistance));
+
+ RelativeDistance t_near = -(::std::numeric_limits<RelativeDistance>::max)();
+ RelativeDistance t_far = (::std::numeric_limits<RelativeDistance>::max)();
+
+ return impl::apply(b, p0, p1, t_near, t_far) &&
+ (t_near <= 1) &&
+ ( relative_distance = 0 < t_near ? t_near : 0, true );
+ }
+};
+
+} // namespace dispatch
+
+template <typename Indexable, typename Point, typename RelativeDistance> inline
+bool segment_intersection(Indexable const& b,
+ Point const& p0,
+ Point const& p1,
+ RelativeDistance & relative_distance)
+{
+ // TODO check Indexable and Point concepts
+
+ return dispatch::segment_intersection<
+ Indexable, Point,
+ typename tag<Indexable>::type
+ >::apply(b, p0, p1, relative_distance);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP
diff --git a/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp b/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp
new file mode 100644
index 0000000000..3ca335d5a7
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp
@@ -0,0 +1,80 @@
+// Boost.Geometry Index
+//
+// Get smallest value calculated for indexable's dimensions, used in R-tree k nearest neighbors query
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <
+ typename Geometry,
+ typename Indexable,
+ typename IndexableTag,
+ typename AlgoTag,
+ size_t DimensionIndex>
+struct smallest_for_indexable_dimension
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE,
+ (smallest_for_indexable_dimension));
+};
+
+template <
+ typename Geometry,
+ typename Indexable,
+ typename IndexableTag,
+ typename AlgoTag,
+ size_t N>
+struct smallest_for_indexable
+{
+ typedef typename smallest_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, N - 1
+ >::result_type result_type;
+
+ template <typename Data>
+ inline static result_type apply(Geometry const& g, Indexable const& i, Data const& data)
+ {
+ result_type r1 = smallest_for_indexable<
+ Geometry, Indexable, IndexableTag, AlgoTag, N - 1
+ >::apply(g, i, data);
+
+ result_type r2 = smallest_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, N - 1
+ >::apply(g, i, data);
+
+ return r1 < r2 ? r1 : r2;
+ }
+};
+
+template <
+ typename Geometry,
+ typename Indexable,
+ typename IndexableTag,
+ typename AlgoTag>
+struct smallest_for_indexable<Geometry, Indexable, IndexableTag, AlgoTag, 1>
+{
+ typedef typename smallest_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, 0
+ >::result_type result_type;
+
+ template <typename Data>
+ inline static result_type apply(Geometry const& g, Indexable const& i, Data const& data)
+ {
+ return
+ smallest_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, 0
+ >::apply(g, i, data);
+ }
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP
diff --git a/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp b/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp
new file mode 100644
index 0000000000..4aef36352e
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp
@@ -0,0 +1,76 @@
+// Boost.Geometry Index
+//
+// Sum values calculated for indexable's dimensions, used e.g. in R-tree k nearest neighbors query
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <
+ typename Geometry,
+ typename Indexable,
+ typename IndexableTag,
+ typename AlgoTag,
+ size_t DimensionIndex>
+struct sum_for_indexable_dimension
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE,
+ (sum_for_indexable_dimension));
+};
+
+template <
+ typename Geometry,
+ typename Indexable,
+ typename IndexableTag,
+ typename AlgoTag,
+ size_t N>
+struct sum_for_indexable
+{
+ typedef typename sum_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, N - 1
+ >::result_type result_type;
+
+ inline static result_type apply(Geometry const& g, Indexable const& i)
+ {
+ return
+ sum_for_indexable<
+ Geometry, Indexable, IndexableTag, AlgoTag, N - 1
+ >::apply(g, i) +
+ sum_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, N - 1
+ >::apply(g, i);
+ }
+};
+
+template <
+ typename Geometry,
+ typename Indexable,
+ typename IndexableTag,
+ typename AlgoTag>
+struct sum_for_indexable<Geometry, Indexable, IndexableTag, AlgoTag, 1>
+{
+ typedef typename sum_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, 0
+ >::result_type result_type;
+
+ inline static result_type apply(Geometry const& g, Indexable const& i)
+ {
+ return
+ sum_for_indexable_dimension<
+ Geometry, Indexable, IndexableTag, AlgoTag, 0
+ >::apply(g, i);
+ }
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP
diff --git a/boost/geometry/index/detail/algorithms/union_content.hpp b/boost/geometry/index/detail/algorithms/union_content.hpp
new file mode 100644
index 0000000000..3acdc3d198
--- /dev/null
+++ b/boost/geometry/index/detail/algorithms/union_content.hpp
@@ -0,0 +1,33 @@
+// Boost.Geometry Index
+//
+// boxes union/sum area/volume
+//
+// Copyright (c) 2008 Federico J. Fernandez.
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP
+
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/index/detail/algorithms/content.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+/**
+ * \brief Compute the area of the union of b1 and b2
+ */
+template <typename Box, typename Geometry>
+inline typename default_content_result<Box>::type union_content(Box const& b, Geometry const& g)
+{
+ Box expanded_box(b);
+ geometry::expand(expanded_box, g);
+ return detail::content(expanded_box);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP
diff --git a/boost/geometry/index/detail/assert.hpp b/boost/geometry/index/detail/assert.hpp
new file mode 100644
index 0000000000..22af315bc8
--- /dev/null
+++ b/boost/geometry/index/detail/assert.hpp
@@ -0,0 +1,30 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP
+
+#include <boost/assert.hpp>
+
+#define BOOST_GEOMETRY_INDEX_ASSERT(CONDITION, TEXT_MSG) \
+ BOOST_ASSERT_MSG(CONDITION, TEXT_MSG)
+
+// TODO - change it to something like:
+// BOOST_ASSERT((CONDITION) && (TEXT_MSG))
+
+#if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG)
+
+#define BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(PARAM)
+
+#else
+
+#define BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(PARAM) PARAM
+
+#endif
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP
diff --git a/boost/geometry/index/detail/bounded_view.hpp b/boost/geometry/index/detail/bounded_view.hpp
new file mode 100644
index 0000000000..572368e273
--- /dev/null
+++ b/boost/geometry/index/detail/bounded_view.hpp
@@ -0,0 +1,185 @@
+// Boost.Geometry Index
+//
+// This view makes possible to treat some simple primitives as its bounding geometry
+// e.g. box, nsphere, etc.
+//
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP
+
+namespace boost { namespace geometry {
+
+namespace index { namespace detail {
+
+template <typename Geometry,
+ typename BoundingGeometry,
+ typename Tag = typename geometry::tag<Geometry>::type,
+ typename BoundingTag = typename geometry::tag<BoundingGeometry>::type>
+struct bounded_view
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THOSE_GEOMETRIES,
+ (BoundingTag, Tag));
+};
+
+
+// Segment -> Box
+
+template <typename Segment, typename Box>
+struct bounded_view<Segment, Box, segment_tag, box_tag>
+{
+public:
+ typedef typename geometry::coordinate_type<Box>::type coordinate_type;
+
+ explicit bounded_view(Segment const& segment)
+ : m_segment(segment)
+ {}
+
+ template <std::size_t Dimension>
+ inline coordinate_type get_min() const
+ {
+ return boost::numeric_cast<coordinate_type>(
+ (std::min)( geometry::get<0, Dimension>(m_segment),
+ geometry::get<1, Dimension>(m_segment) ) );
+ }
+
+ template <std::size_t Dimension>
+ inline coordinate_type get_max() const
+ {
+ return boost::numeric_cast<coordinate_type>(
+ (std::max)( geometry::get<0, Dimension>(m_segment),
+ geometry::get<1, Dimension>(m_segment) ) );
+ }
+
+private:
+ Segment const& m_segment;
+};
+
+// Box -> Box
+
+template <typename BoxIn, typename Box>
+struct bounded_view<BoxIn, Box, box_tag, box_tag>
+{
+public:
+ typedef typename geometry::coordinate_type<Box>::type coordinate_type;
+
+ explicit bounded_view(BoxIn const& box)
+ : m_box(box)
+ {}
+
+ template <std::size_t Dimension>
+ inline coordinate_type get_min() const
+ {
+ return boost::numeric_cast<coordinate_type>(
+ geometry::get<min_corner, Dimension>(m_box) );
+ }
+
+ template <std::size_t Dimension>
+ inline coordinate_type get_max() const
+ {
+ return boost::numeric_cast<coordinate_type>(
+ geometry::get<max_corner, Dimension>(m_box) );
+ }
+
+private:
+ BoxIn const& m_box;
+};
+
+// Point -> Box
+
+template <typename Point, typename Box>
+struct bounded_view<Point, Box, point_tag, box_tag>
+{
+public:
+ typedef typename geometry::coordinate_type<Box>::type coordinate_type;
+
+ explicit bounded_view(Point const& point)
+ : m_point(point)
+ {}
+
+ template <std::size_t Dimension>
+ inline coordinate_type get_min() const
+ {
+ return boost::numeric_cast<coordinate_type>(
+ geometry::get<Dimension>(m_point) );
+ }
+
+ template <std::size_t Dimension>
+ inline coordinate_type get_max() const
+ {
+ return boost::numeric_cast<coordinate_type>(
+ geometry::get<Dimension>(m_point) );
+ }
+
+private:
+ Point const& m_point;
+};
+
+}} // namespace index::detail
+
+// XXX -> Box
+
+#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+namespace traits
+{
+
+template <typename Geometry, typename Box, typename Tag>
+struct tag< index::detail::bounded_view<Geometry, Box, Tag, box_tag> >
+{
+ typedef box_tag type;
+};
+
+template <typename Segment, typename Box, typename Tag>
+struct point_type< index::detail::bounded_view<Segment, Box, Tag, box_tag> >
+{
+ typedef typename point_type<Box>::type type;
+};
+
+template <typename Segment, typename Box, typename Tag, std::size_t Dimension>
+struct indexed_access<index::detail::bounded_view<Segment, Box, Tag, box_tag>,
+ min_corner, Dimension>
+{
+ typedef index::detail::bounded_view<Segment, Box, Tag, box_tag> box_type;
+ typedef typename geometry::coordinate_type<Box>::type coordinate_type;
+
+ static inline coordinate_type get(box_type const& b)
+ {
+ return b.template get_min<Dimension>();
+ }
+
+ //static inline void set(box_type & b, coordinate_type const& value)
+ //{
+ // BOOST_ASSERT(false);
+ //}
+};
+
+template <typename Segment, typename Box, typename Tag, std::size_t Dimension>
+struct indexed_access<index::detail::bounded_view<Segment, Box, Tag, box_tag>,
+ max_corner, Dimension>
+{
+ typedef index::detail::bounded_view<Segment, Box, Tag, box_tag> box_type;
+ typedef typename geometry::coordinate_type<Box>::type coordinate_type;
+
+ static inline coordinate_type get(box_type const& b)
+ {
+ return b.template get_max<Dimension>();
+ }
+
+ //static inline void set(box_type & b, coordinate_type const& value)
+ //{
+ // BOOST_ASSERT(false);
+ //}
+};
+
+} // namespace traits
+#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP
diff --git a/boost/geometry/index/detail/config_begin.hpp b/boost/geometry/index/detail/config_begin.hpp
new file mode 100644
index 0000000000..21c346012b
--- /dev/null
+++ b/boost/geometry/index/detail/config_begin.hpp
@@ -0,0 +1,21 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/config.hpp>
+
+#ifdef BOOST_MSVC
+
+ #pragma warning (push)
+ #pragma warning (disable : 4512) // assignment operator could not be generated
+ #pragma warning (disable : 4127) // conditional expression is constant
+
+ // temporary?
+ #pragma warning (disable : 4180) // qualifier applied to function type has no meaning
+
+#endif //BOOST_MSVC
+
diff --git a/boost/geometry/index/detail/config_end.hpp b/boost/geometry/index/detail/config_end.hpp
new file mode 100644
index 0000000000..d144c33698
--- /dev/null
+++ b/boost/geometry/index/detail/config_end.hpp
@@ -0,0 +1,12 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#if defined BOOST_MSVC
+ #pragma warning (pop)
+#endif
+
diff --git a/boost/geometry/index/detail/distance_predicates.hpp b/boost/geometry/index/detail/distance_predicates.hpp
new file mode 100644
index 0000000000..3e057290a6
--- /dev/null
+++ b/boost/geometry/index/detail/distance_predicates.hpp
@@ -0,0 +1,161 @@
+// Boost.Geometry Index
+//
+// Spatial index distance predicates, calculators and checkers
+// used in nearest query - specialized for envelopes
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_DISTANCE_PREDICATES_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_DISTANCE_PREDICATES_HPP
+
+#include <boost/geometry/index/detail/algorithms/comparable_distance_near.hpp>
+#include <boost/geometry/index/detail/algorithms/comparable_distance_far.hpp>
+#include <boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp>
+#include <boost/geometry/index/detail/algorithms/path_intersection.hpp>
+
+#include <boost/geometry/index/detail/tags.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+// ------------------------------------------------------------------ //
+// relations
+// ------------------------------------------------------------------ //
+
+template <typename T>
+struct to_nearest
+{
+ to_nearest(T const& v) : value(v) {}
+ T value;
+};
+
+template <typename T>
+struct to_centroid
+{
+ to_centroid(T const& v) : value(v) {}
+ T value;
+};
+
+template <typename T>
+struct to_furthest
+{
+ to_furthest(T const& v) : value(v) {}
+ T value;
+};
+
+// tags
+
+struct to_nearest_tag {};
+struct to_centroid_tag {};
+struct to_furthest_tag {};
+
+// ------------------------------------------------------------------ //
+// relation traits and access
+// ------------------------------------------------------------------ //
+
+template <typename T>
+struct relation
+{
+ typedef T value_type;
+ typedef to_nearest_tag tag;
+ static inline T const& value(T const& v) { return v; }
+ static inline T & value(T & v) { return v; }
+};
+
+template <typename T>
+struct relation< to_nearest<T> >
+{
+ typedef T value_type;
+ typedef to_nearest_tag tag;
+ static inline T const& value(to_nearest<T> const& r) { return r.value; }
+ static inline T & value(to_nearest<T> & r) { return r.value; }
+};
+
+template <typename T>
+struct relation< to_centroid<T> >
+{
+ typedef T value_type;
+ typedef to_centroid_tag tag;
+ static inline T const& value(to_centroid<T> const& r) { return r.value; }
+ static inline T & value(to_centroid<T> & r) { return r.value; }
+};
+
+template <typename T>
+struct relation< to_furthest<T> >
+{
+ typedef T value_type;
+ typedef to_furthest_tag tag;
+ static inline T const& value(to_furthest<T> const& r) { return r.value; }
+ static inline T & value(to_furthest<T> & r) { return r.value; }
+};
+
+// ------------------------------------------------------------------ //
+// calculate_distance
+// ------------------------------------------------------------------ //
+
+template <typename Predicate, typename Indexable, typename Tag>
+struct calculate_distance
+{
+ BOOST_MPL_ASSERT_MSG((false), INVALID_PREDICATE_OR_TAG, (calculate_distance));
+};
+
+// this handles nearest() with default Point parameter, to_nearest() and bounds
+template <typename PointRelation, typename Indexable, typename Tag>
+struct calculate_distance< nearest<PointRelation>, Indexable, Tag >
+{
+ typedef detail::relation<PointRelation> relation;
+ typedef typename relation::value_type point_type;
+ typedef typename geometry::default_comparable_distance_result<point_type, Indexable>::type result_type;
+
+ static inline bool apply(nearest<PointRelation> const& p, Indexable const& i, result_type & result)
+ {
+ result = geometry::comparable_distance(relation::value(p.point_or_relation), i);
+ return true;
+ }
+};
+
+template <typename Point, typename Indexable>
+struct calculate_distance< nearest< to_centroid<Point> >, Indexable, value_tag>
+{
+ typedef Point point_type;
+ typedef typename geometry::default_comparable_distance_result<point_type, Indexable>::type result_type;
+
+ static inline bool apply(nearest< to_centroid<Point> > const& p, Indexable const& i, result_type & result)
+ {
+ result = index::detail::comparable_distance_centroid(p.point_or_relation.value, i);
+ return true;
+ }
+};
+
+template <typename Point, typename Indexable>
+struct calculate_distance< nearest< to_furthest<Point> >, Indexable, value_tag>
+{
+ typedef Point point_type;
+ typedef typename geometry::default_comparable_distance_result<point_type, Indexable>::type result_type;
+
+ static inline bool apply(nearest< to_furthest<Point> > const& p, Indexable const& i, result_type & result)
+ {
+ result = index::detail::comparable_distance_far(p.point_or_relation.value, i);
+ return true;
+ }
+};
+
+template <typename SegmentOrLinestring, typename Indexable, typename Tag>
+struct calculate_distance< path<SegmentOrLinestring>, Indexable, Tag>
+{
+ typedef typename index::detail::default_path_intersection_distance_type<
+ Indexable, SegmentOrLinestring
+ >::type result_type;
+
+ static inline bool apply(path<SegmentOrLinestring> const& p, Indexable const& i, result_type & result)
+ {
+ return index::detail::path_intersection(i, p.geometry, result);
+ }
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_RTREE_DISTANCE_PREDICATES_HPP
diff --git a/boost/geometry/index/detail/exception.hpp b/boost/geometry/index/detail/exception.hpp
new file mode 100644
index 0000000000..c3ea0e1923
--- /dev/null
+++ b/boost/geometry/index/detail/exception.hpp
@@ -0,0 +1,72 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP
+
+#ifndef BOOST_NO_EXCEPTIONS
+#include <stdexcept>
+#else
+#include <cstdlib>
+#endif
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+#ifndef BOOST_NO_EXCEPTIONS
+
+inline void throw_runtime_error(const char * str)
+{
+ throw std::runtime_error(str);
+}
+
+inline void throw_logic_error(const char * str)
+{
+ throw std::logic_error(str);
+}
+
+inline void throw_invalid_argument(const char * str)
+{
+ throw std::invalid_argument(str);
+}
+
+inline void throw_length_error(const char * str)
+{
+ throw std::length_error(str);
+}
+
+#else
+
+inline void throw_runtime_error(const char * str)
+{
+ BOOST_ASSERT_MSG(!"runtime_error thrown", str);
+ std::abort();
+}
+
+inline void throw_logic_error(const char * str)
+{
+ BOOST_ASSERT_MSG(!"logic_error thrown", str);
+ std::abort();
+}
+
+inline void throw_invalid_argument(const char * str)
+{
+ BOOST_ASSERT_MSG(!"invalid_argument thrown", str);
+ std::abort();
+}
+
+inline void throw_length_error(const char * str)
+{
+ BOOST_ASSERT_MSG(!"length_error thrown", str);
+ std::abort();
+}
+
+#endif
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP
diff --git a/boost/geometry/index/detail/meta.hpp b/boost/geometry/index/detail/meta.hpp
new file mode 100644
index 0000000000..bec1380b06
--- /dev/null
+++ b/boost/geometry/index/detail/meta.hpp
@@ -0,0 +1,42 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/range.hpp>
+#include <boost/mpl/aux_/has_type.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/and.hpp>
+//#include <boost/type_traits/is_convertible.hpp>
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_META_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_META_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename T>
+struct is_range
+ : ::boost::mpl::aux::has_type< ::boost::range_iterator<T> >
+{};
+
+//template <typename T, typename V, bool IsRange>
+//struct is_range_of_convertible_values_impl
+// : ::boost::is_convertible<typename ::boost::range_value<T>::type, V>
+//{};
+//
+//template <typename T, typename V>
+//struct is_range_of_convertible_values_impl<T, V, false>
+// : ::boost::mpl::bool_<false>
+//{};
+//
+//template <typename T, typename V>
+//struct is_range_of_convertible_values
+// : is_range_of_convertible_values_impl<T, V, is_range<T>::value>
+//{};
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_META_HPP
diff --git a/boost/geometry/index/detail/predicates.hpp b/boost/geometry/index/detail/predicates.hpp
new file mode 100644
index 0000000000..b92256649a
--- /dev/null
+++ b/boost/geometry/index/detail/predicates.hpp
@@ -0,0 +1,813 @@
+// Boost.Geometry Index
+//
+// Spatial query predicates definition and checks.
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP
+
+#include <boost/geometry/index/predicates.hpp>
+#include <boost/geometry/index/detail/tags.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+// ------------------------------------------------------------------ //
+// predicates
+// ------------------------------------------------------------------ //
+
+template <typename Fun, bool IsFunction>
+struct satisfies_impl
+{
+ satisfies_impl(Fun f) : fun(f) {}
+ Fun * fun;
+};
+
+template <typename Fun>
+struct satisfies_impl<Fun, false>
+{
+ satisfies_impl(Fun const& f) : fun(f) {}
+ Fun fun;
+};
+
+template <typename Fun, bool Negated>
+struct satisfies
+ : satisfies_impl<Fun, ::boost::is_function<Fun>::value>
+{
+ typedef satisfies_impl<Fun, ::boost::is_function<Fun>::value> base;
+
+ satisfies(Fun const& f) : base(f) {}
+ satisfies(base const& b) : base(b) {}
+};
+
+// ------------------------------------------------------------------ //
+
+struct contains_tag {};
+struct covered_by_tag {};
+struct covers_tag {};
+struct disjoint_tag {};
+struct intersects_tag {};
+struct overlaps_tag {};
+struct touches_tag {};
+struct within_tag {};
+
+template <typename Geometry, typename Tag, bool Negated>
+struct spatial_predicate
+{
+ spatial_predicate(Geometry const& g) : geometry(g) {}
+ Geometry geometry;
+};
+
+// ------------------------------------------------------------------ //
+
+// CONSIDER: separated nearest<> and path<> may be replaced by
+// nearest_predicate<Geometry, Tag>
+// where Tag = point_tag | path_tag
+// IMPROVEMENT: user-defined nearest predicate allowing to define
+// all or only geometrical aspects of the search
+
+template <typename PointOrRelation>
+struct nearest
+{
+ nearest(PointOrRelation const& por, unsigned k)
+ : point_or_relation(por)
+ , count(k)
+ {}
+ PointOrRelation point_or_relation;
+ unsigned count;
+};
+
+template <typename SegmentOrLinestring>
+struct path
+{
+ path(SegmentOrLinestring const& g, unsigned k)
+ : geometry(g)
+ , count(k)
+ {}
+ SegmentOrLinestring geometry;
+ unsigned count;
+};
+
+// ------------------------------------------------------------------ //
+// predicate_check
+// ------------------------------------------------------------------ //
+
+template <typename Predicate, typename Tag>
+struct predicate_check
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_PREDICATE_OR_TAG,
+ (predicate_check));
+};
+
+// ------------------------------------------------------------------ //
+
+template <typename Fun>
+struct predicate_check<satisfies<Fun, false>, value_tag>
+{
+ template <typename Value, typename Indexable>
+ static inline bool apply(satisfies<Fun, false> const& p, Value const& v, Indexable const&)
+ {
+ return p.fun(v);
+ }
+};
+
+template <typename Fun>
+struct predicate_check<satisfies<Fun, true>, value_tag>
+{
+ template <typename Value, typename Indexable>
+ static inline bool apply(satisfies<Fun, true> const& p, Value const& v, Indexable const&)
+ {
+ return !p.fun(v);
+ }
+};
+
+// ------------------------------------------------------------------ //
+
+template <typename Tag>
+struct spatial_predicate_call
+{
+ BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag));
+};
+
+template <>
+struct spatial_predicate_call<contains_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::within(g2, g1);
+ }
+};
+
+template <>
+struct spatial_predicate_call<covered_by_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::covered_by(g1, g2);
+ }
+};
+
+template <>
+struct spatial_predicate_call<covers_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::covered_by(g2, g1);
+ }
+};
+
+template <>
+struct spatial_predicate_call<disjoint_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::disjoint(g1, g2);
+ }
+};
+
+template <>
+struct spatial_predicate_call<intersects_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::intersects(g1, g2);
+ }
+};
+
+template <>
+struct spatial_predicate_call<overlaps_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::overlaps(g1, g2);
+ }
+};
+
+template <>
+struct spatial_predicate_call<touches_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::touches(g1, g2);
+ }
+};
+
+template <>
+struct spatial_predicate_call<within_tag>
+{
+ template <typename G1, typename G2>
+ static inline bool apply(G1 const& g1, G2 const& g2)
+ {
+ return geometry::within(g1, g2);
+ }
+};
+
+// ------------------------------------------------------------------ //
+
+// spatial predicate
+template <typename Geometry, typename Tag>
+struct predicate_check<spatial_predicate<Geometry, Tag, false>, value_tag>
+{
+ typedef spatial_predicate<Geometry, Tag, false> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return spatial_predicate_call<Tag>::apply(i, p.geometry);
+ }
+};
+
+// negated spatial predicate
+template <typename Geometry, typename Tag>
+struct predicate_check<spatial_predicate<Geometry, Tag, true>, value_tag>
+{
+ typedef spatial_predicate<Geometry, Tag, true> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return !spatial_predicate_call<Tag>::apply(i, p.geometry);
+ }
+};
+
+// ------------------------------------------------------------------ //
+
+template <typename DistancePredicates>
+struct predicate_check<nearest<DistancePredicates>, value_tag>
+{
+ template <typename Value, typename Box>
+ static inline bool apply(nearest<DistancePredicates> const&, Value const&, Box const&)
+ {
+ return true;
+ }
+};
+
+template <typename Linestring>
+struct predicate_check<path<Linestring>, value_tag>
+{
+ template <typename Value, typename Box>
+ static inline bool apply(path<Linestring> const&, Value const&, Box const&)
+ {
+ return true;
+ }
+};
+
+// ------------------------------------------------------------------ //
+// predicates_check for bounds
+// ------------------------------------------------------------------ //
+
+template <typename Fun, bool Negated>
+struct predicate_check<satisfies<Fun, Negated>, bounds_tag>
+{
+ template <typename Value, typename Box>
+ static bool apply(satisfies<Fun, Negated> const&, Value const&, Box const&)
+ {
+ return true;
+ }
+};
+
+// ------------------------------------------------------------------ //
+
+// NOT NEGATED
+// value_tag bounds_tag
+// ---------------------------
+// contains(I,G) contains(I,G)
+// covered_by(I,G) intersects(I,G)
+// covers(I,G) covers(I,G)
+// disjoint(I,G) !covered_by(I,G)
+// intersects(I,G) intersects(I,G)
+// overlaps(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false
+// touches(I,G) intersects(I,G)
+// within(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false
+
+// spatial predicate - default
+template <typename Geometry, typename Tag>
+struct predicate_check<spatial_predicate<Geometry, Tag, false>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, Tag, false> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return spatial_predicate_call<intersects_tag>::apply(i, p.geometry);
+ }
+};
+
+// spatial predicate - contains
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, contains_tag, false>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, contains_tag, false> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return spatial_predicate_call<contains_tag>::apply(i, p.geometry);
+ }
+};
+
+// spatial predicate - covers
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, covers_tag, false>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, covers_tag, false> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return spatial_predicate_call<covers_tag>::apply(i, p.geometry);
+ }
+};
+
+// spatial predicate - disjoint
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, disjoint_tag, false>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, disjoint_tag, false> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return !spatial_predicate_call<covered_by_tag>::apply(i, p.geometry);
+ }
+};
+
+// NEGATED
+// value_tag bounds_tag
+// ---------------------------
+// !contains(I,G) TRUE
+// !covered_by(I,G) !covered_by(I,G)
+// !covers(I,G) TRUE
+// !disjoint(I,G) !disjoint(I,G)
+// !intersects(I,G) !covered_by(I,G)
+// !overlaps(I,G) TRUE
+// !touches(I,G) !intersects(I,G)
+// !within(I,G) !within(I,G)
+
+// negated spatial predicate - default
+template <typename Geometry, typename Tag>
+struct predicate_check<spatial_predicate<Geometry, Tag, true>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, Tag, true> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return !spatial_predicate_call<Tag>::apply(i, p.geometry);
+ }
+};
+
+// negated spatial predicate - contains
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, contains_tag, true>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, contains_tag, true> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& , Value const&, Indexable const& )
+ {
+ return true;
+ }
+};
+
+// negated spatial predicate - covers
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, covers_tag, true>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, covers_tag, true> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& , Value const&, Indexable const& )
+ {
+ return true;
+ }
+};
+
+// negated spatial predicate - intersects
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, intersects_tag, true>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, intersects_tag, true> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return !spatial_predicate_call<covered_by_tag>::apply(i, p.geometry);
+ }
+};
+
+// negated spatial predicate - overlaps
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, overlaps_tag, true>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, overlaps_tag, true> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& , Value const&, Indexable const& )
+ {
+ return true;
+ }
+};
+
+// negated spatial predicate - touches
+template <typename Geometry>
+struct predicate_check<spatial_predicate<Geometry, touches_tag, true>, bounds_tag>
+{
+ typedef spatial_predicate<Geometry, touches_tag, true> Pred;
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Pred const& p, Value const&, Indexable const& i)
+ {
+ return !spatial_predicate_call<intersects_tag>::apply(i, p.geometry);
+ }
+};
+
+// ------------------------------------------------------------------ //
+
+template <typename DistancePredicates>
+struct predicate_check<nearest<DistancePredicates>, bounds_tag>
+{
+ template <typename Value, typename Box>
+ static inline bool apply(nearest<DistancePredicates> const&, Value const&, Box const&)
+ {
+ return true;
+ }
+};
+
+template <typename Linestring>
+struct predicate_check<path<Linestring>, bounds_tag>
+{
+ template <typename Value, typename Box>
+ static inline bool apply(path<Linestring> const&, Value const&, Box const&)
+ {
+ return true;
+ }
+};
+
+// ------------------------------------------------------------------ //
+// predicates_length
+// ------------------------------------------------------------------ //
+
+template <typename T>
+struct predicates_length
+{
+ static const unsigned value = 1;
+};
+
+//template <typename F, typename S>
+//struct predicates_length< std::pair<F, S> >
+//{
+// static const unsigned value = 2;
+//};
+
+//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
+//struct predicates_length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+//{
+// static const unsigned value = boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value;
+//};
+
+template <typename Head, typename Tail>
+struct predicates_length< boost::tuples::cons<Head, Tail> >
+{
+ static const unsigned value = boost::tuples::length< boost::tuples::cons<Head, Tail> >::value;
+};
+
+// ------------------------------------------------------------------ //
+// predicates_element
+// ------------------------------------------------------------------ //
+
+template <unsigned I, typename T>
+struct predicates_element
+{
+ BOOST_MPL_ASSERT_MSG((I < 1), INVALID_INDEX, (predicates_element));
+ typedef T type;
+ static type const& get(T const& p) { return p; }
+};
+
+//template <unsigned I, typename F, typename S>
+//struct predicates_element< I, std::pair<F, S> >
+//{
+// BOOST_MPL_ASSERT_MSG((I < 2), INVALID_INDEX, (predicates_element));
+//
+// typedef F type;
+// static type const& get(std::pair<F, S> const& p) { return p.first; }
+//};
+//
+//template <typename F, typename S>
+//struct predicates_element< 1, std::pair<F, S> >
+//{
+// typedef S type;
+// static type const& get(std::pair<F, S> const& p) { return p.second; }
+//};
+//
+//template <unsigned I, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
+//struct predicates_element< I, boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+//{
+// typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> predicate_type;
+//
+// typedef typename boost::tuples::element<I, predicate_type>::type type;
+// static type const& get(predicate_type const& p) { return boost::get<I>(p); }
+//};
+
+template <unsigned I, typename Head, typename Tail>
+struct predicates_element< I, boost::tuples::cons<Head, Tail> >
+{
+ typedef boost::tuples::cons<Head, Tail> predicate_type;
+
+ typedef typename boost::tuples::element<I, predicate_type>::type type;
+ static type const& get(predicate_type const& p) { return boost::get<I>(p); }
+};
+
+// ------------------------------------------------------------------ //
+// predicates_check
+// ------------------------------------------------------------------ //
+
+//template <typename PairPredicates, typename Tag, unsigned First, unsigned Last>
+//struct predicates_check_pair {};
+//
+//template <typename PairPredicates, typename Tag, unsigned I>
+//struct predicates_check_pair<PairPredicates, Tag, I, I>
+//{
+// template <typename Value, typename Indexable>
+// static inline bool apply(PairPredicates const& , Value const& , Indexable const& )
+// {
+// return true;
+// }
+//};
+//
+//template <typename PairPredicates, typename Tag>
+//struct predicates_check_pair<PairPredicates, Tag, 0, 1>
+//{
+// template <typename Value, typename Indexable>
+// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i)
+// {
+// return predicate_check<typename PairPredicates::first_type, Tag>::apply(p.first, v, i);
+// }
+//};
+//
+//template <typename PairPredicates, typename Tag>
+//struct predicates_check_pair<PairPredicates, Tag, 1, 2>
+//{
+// template <typename Value, typename Indexable>
+// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i)
+// {
+// return predicate_check<typename PairPredicates::second_type, Tag>::apply(p.second, v, i);
+// }
+//};
+//
+//template <typename PairPredicates, typename Tag>
+//struct predicates_check_pair<PairPredicates, Tag, 0, 2>
+//{
+// template <typename Value, typename Indexable>
+// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i)
+// {
+// return predicate_check<typename PairPredicates::first_type, Tag>::apply(p.first, v, i)
+// && predicate_check<typename PairPredicates::second_type, Tag>::apply(p.second, v, i);
+// }
+//};
+
+template <typename TuplePredicates, typename Tag, unsigned First, unsigned Last>
+struct predicates_check_tuple
+{
+ template <typename Value, typename Indexable>
+ static inline bool apply(TuplePredicates const& p, Value const& v, Indexable const& i)
+ {
+ return
+ predicate_check<
+ typename boost::tuples::element<First, TuplePredicates>::type,
+ Tag
+ >::apply(boost::get<First>(p), v, i) &&
+ predicates_check_tuple<TuplePredicates, Tag, First+1, Last>::apply(p, v, i);
+ }
+};
+
+template <typename TuplePredicates, typename Tag, unsigned First>
+struct predicates_check_tuple<TuplePredicates, Tag, First, First>
+{
+ template <typename Value, typename Indexable>
+ static inline bool apply(TuplePredicates const& , Value const& , Indexable const& )
+ {
+ return true;
+ }
+};
+
+template <typename Predicate, typename Tag, unsigned First, unsigned Last>
+struct predicates_check_impl
+{
+ static const bool check = First < 1 && Last <= 1 && First <= Last;
+ BOOST_MPL_ASSERT_MSG((check), INVALID_INDEXES, (predicates_check_impl));
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(Predicate const& p, Value const& v, Indexable const& i)
+ {
+ return predicate_check<Predicate, Tag>::apply(p, v, i);
+ }
+};
+
+//template <typename Predicate1, typename Predicate2, typename Tag, size_t First, size_t Last>
+//struct predicates_check_impl<std::pair<Predicate1, Predicate2>, Tag, First, Last>
+//{
+// BOOST_MPL_ASSERT_MSG((First < 2 && Last <= 2 && First <= Last), INVALID_INDEXES, (predicates_check_impl));
+//
+// template <typename Value, typename Indexable>
+// static inline bool apply(std::pair<Predicate1, Predicate2> const& p, Value const& v, Indexable const& i)
+// {
+// return predicate_check<Predicate1, Tag>::apply(p.first, v, i)
+// && predicate_check<Predicate2, Tag>::apply(p.second, v, i);
+// }
+//};
+//
+//template <
+// typename T0, typename T1, typename T2, typename T3, typename T4,
+// typename T5, typename T6, typename T7, typename T8, typename T9,
+// typename Tag, unsigned First, unsigned Last
+//>
+//struct predicates_check_impl<
+// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
+// Tag, First, Last
+//>
+//{
+// typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> predicates_type;
+//
+// static const unsigned pred_len = boost::tuples::length<predicates_type>::value;
+// BOOST_MPL_ASSERT_MSG((First < pred_len && Last <= pred_len && First <= Last), INVALID_INDEXES, (predicates_check_impl));
+//
+// template <typename Value, typename Indexable>
+// static inline bool apply(predicates_type const& p, Value const& v, Indexable const& i)
+// {
+// return predicates_check_tuple<
+// predicates_type,
+// Tag, First, Last
+// >::apply(p, v, i);
+// }
+//};
+
+template <typename Head, typename Tail, typename Tag, unsigned First, unsigned Last>
+struct predicates_check_impl<
+ boost::tuples::cons<Head, Tail>,
+ Tag, First, Last
+>
+{
+ typedef boost::tuples::cons<Head, Tail> predicates_type;
+
+ static const unsigned pred_len = boost::tuples::length<predicates_type>::value;
+ static const bool check = First < pred_len && Last <= pred_len && First <= Last;
+ BOOST_MPL_ASSERT_MSG((check), INVALID_INDEXES, (predicates_check_impl));
+
+ template <typename Value, typename Indexable>
+ static inline bool apply(predicates_type const& p, Value const& v, Indexable const& i)
+ {
+ return predicates_check_tuple<
+ predicates_type,
+ Tag, First, Last
+ >::apply(p, v, i);
+ }
+};
+
+template <typename Tag, unsigned First, unsigned Last, typename Predicates, typename Value, typename Indexable>
+inline bool predicates_check(Predicates const& p, Value const& v, Indexable const& i)
+{
+ return detail::predicates_check_impl<Predicates, Tag, First, Last>
+ ::apply(p, v, i);
+}
+
+// ------------------------------------------------------------------ //
+// nearest predicate helpers
+// ------------------------------------------------------------------ //
+
+// predicates_is_nearest
+
+template <typename P>
+struct predicates_is_distance
+{
+ static const unsigned value = 0;
+};
+
+template <typename DistancePredicates>
+struct predicates_is_distance< nearest<DistancePredicates> >
+{
+ static const unsigned value = 1;
+};
+
+template <typename Linestring>
+struct predicates_is_distance< path<Linestring> >
+{
+ static const unsigned value = 1;
+};
+
+// predicates_count_nearest
+
+template <typename T>
+struct predicates_count_distance
+{
+ static const unsigned value = predicates_is_distance<T>::value;
+};
+
+//template <typename F, typename S>
+//struct predicates_count_distance< std::pair<F, S> >
+//{
+// static const unsigned value = predicates_is_distance<F>::value
+// + predicates_is_distance<S>::value;
+//};
+
+template <typename Tuple, unsigned N>
+struct predicates_count_distance_tuple
+{
+ static const unsigned value =
+ predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value
+ + predicates_count_distance_tuple<Tuple, N-1>::value;
+};
+
+template <typename Tuple>
+struct predicates_count_distance_tuple<Tuple, 1>
+{
+ static const unsigned value =
+ predicates_is_distance<typename boost::tuples::element<0, Tuple>::type>::value;
+};
+
+//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
+//struct predicates_count_distance< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+//{
+// static const unsigned value = predicates_count_distance_tuple<
+// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
+// boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value
+// >::value;
+//};
+
+template <typename Head, typename Tail>
+struct predicates_count_distance< boost::tuples::cons<Head, Tail> >
+{
+ static const unsigned value = predicates_count_distance_tuple<
+ boost::tuples::cons<Head, Tail>,
+ boost::tuples::length< boost::tuples::cons<Head, Tail> >::value
+ >::value;
+};
+
+// predicates_find_nearest
+
+template <typename T>
+struct predicates_find_distance
+{
+ static const unsigned value = predicates_is_distance<T>::value ? 0 : 1;
+};
+
+//template <typename F, typename S>
+//struct predicates_find_distance< std::pair<F, S> >
+//{
+// static const unsigned value = predicates_is_distance<F>::value ? 0 :
+// (predicates_is_distance<S>::value ? 1 : 2);
+//};
+
+template <typename Tuple, unsigned N>
+struct predicates_find_distance_tuple
+{
+ static const bool is_found = predicates_find_distance_tuple<Tuple, N-1>::is_found
+ || predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value;
+
+ static const unsigned value = predicates_find_distance_tuple<Tuple, N-1>::is_found ?
+ predicates_find_distance_tuple<Tuple, N-1>::value :
+ (predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value ?
+ N-1 : boost::tuples::length<Tuple>::value);
+};
+
+template <typename Tuple>
+struct predicates_find_distance_tuple<Tuple, 1>
+{
+ static const bool is_found = predicates_is_distance<typename boost::tuples::element<0, Tuple>::type>::value;
+ static const unsigned value = is_found ? 0 : boost::tuples::length<Tuple>::value;
+};
+
+//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
+//struct predicates_find_distance< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+//{
+// static const unsigned value = predicates_find_distance_tuple<
+// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
+// boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value
+// >::value;
+//};
+
+template <typename Head, typename Tail>
+struct predicates_find_distance< boost::tuples::cons<Head, Tail> >
+{
+ static const unsigned value = predicates_find_distance_tuple<
+ boost::tuples::cons<Head, Tail>,
+ boost::tuples::length< boost::tuples::cons<Head, Tail> >::value
+ >::value;
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP
diff --git a/boost/geometry/index/detail/rtree/adaptors.hpp b/boost/geometry/index/detail/rtree/adaptors.hpp
new file mode 100644
index 0000000000..4e0eb9ba0a
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/adaptors.hpp
@@ -0,0 +1,54 @@
+// Boost.Geometry Index
+//
+// R-tree queries range adaptors
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP
+
+#include <deque>
+#include <boost/static_assert.hpp>
+
+#include <boost/geometry/index/adaptors/query.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+template <typename Value, typename Options, typename IndexableGetter, typename EqualTo, typename Allocator>
+class rtree;
+
+namespace adaptors { namespace detail {
+
+template <typename Value, typename Options, typename IndexableGetter, typename EqualTo, typename Allocator>
+class query_range< index::rtree<Value, Options, IndexableGetter, EqualTo, Allocator> >
+{
+public:
+ typedef std::vector<Value> result_type;
+ typedef typename result_type::iterator iterator;
+ typedef typename result_type::const_iterator const_iterator;
+
+ template <typename Predicates> inline
+ query_range(index::rtree<Value, Options, IndexableGetter, EqualTo, Allocator> const& rtree,
+ Predicates const& pred)
+ {
+ rtree.query(pred, std::back_inserter(m_result));
+ }
+
+ inline iterator begin() { return m_result.begin(); }
+ inline iterator end() { return m_result.end(); }
+ inline const_iterator begin() const { return m_result.begin(); }
+ inline const_iterator end() const { return m_result.end(); }
+
+private:
+ result_type m_result;
+};
+
+}} // namespace adaptors::detail
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP
diff --git a/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp b/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp
new file mode 100644
index 0000000000..3f61482b27
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp
@@ -0,0 +1,16 @@
+// Boost.Geometry Index
+//
+// R-tree kmeans algorithm implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP
+
+#include <boost/geometry/index/rtree/kmeans/split.hpp>
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP
diff --git a/boost/geometry/index/detail/rtree/kmeans/split.hpp b/boost/geometry/index/detail/rtree/kmeans/split.hpp
new file mode 100644
index 0000000000..f19654972e
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/kmeans/split.hpp
@@ -0,0 +1,87 @@
+// Boost.Geometry Index
+//
+// R-tree kmeans split algorithm implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP
+
+#include <boost/geometry/index/rtree/node/node.hpp>
+#include <boost/geometry/index/rtree/visitors/insert.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+namespace kmeans {
+
+// some details
+
+} // namespace kmeans
+
+// split_kmeans_tag
+// OR
+// split_clusters_tag and redistribute_kmeans_tag - then redistribute will probably slightly different interface
+// or some other than "redistribute"
+
+// 1. for this algorithm one probably MUST USE NON-STATIC NODES with node_default_tag
+// or the algorithm must be changed somehow - to not store additional nodes in the current node
+// but return excessive element/elements container instead (possibly pushable_array<1> or std::vector)
+// this would also cause building of smaller trees since +1 element in nodes wouldn't be needed in different redistributing algorithms
+// 2. it is probably possible to add e.g. 2 levels of tree in one insert
+
+// Edge case is that every node split generates M + 1 children, in parent containing M nodes
+// result is 2M + 1 nodes in parent on this level
+// On next level the same, next the same and so on.
+// We have Depth*M+1 nodes in the root
+// The tree may then gain some > 1 levels in one insert
+// split::apply() manages this but special attention is required
+
+// which algorithm should be used to choose current node in traversing while inserting?
+// some of the currently used ones or some using mean values as well?
+
+// TODO
+// 1. Zmienic troche algorytm zeby przekazywal nadmiarowe elementy do split
+// i pobieral ze split nadmiarowe elementy rodzica
+// W zaleznosci od algorytmu w rozny sposob - l/q/r* powinny zwracac np pushable_array<1>
+// wtedy tez is_overerflow (z R* insert?) bedzie nieportrzebne
+// Dla kmeans zapewne std::vector, jednak w wezlach nadal moglaby byc pushable_array
+// 2. Fajnie byloby tez uproscic te wszystkie parametry root,parent,index itd. Mozliwe ze okazalyby sie zbedne
+// 3. Sprawdzyc czasy wykonywania i zajetosc pamieci
+// 4. Pamietac o parametryzacji kontenera z nadmiarowymi elementami
+// PS. Z R* reinsertami moze byc masakra
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class split<Value, Options, Translator, Box, Allocators, split_kmeans_tag>
+{
+protected:
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+
+public:
+ template <typename Node>
+ static inline void apply(node* & root_node,
+ size_t & leafs_level,
+ Node & n,
+ internal_node *parent_node,
+ size_t current_child_index,
+ Translator const& tr,
+ Allocators & allocators)
+ {
+
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP
diff --git a/boost/geometry/index/detail/rtree/linear/linear.hpp b/boost/geometry/index/detail/rtree/linear/linear.hpp
new file mode 100644
index 0000000000..1461692a1e
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/linear/linear.hpp
@@ -0,0 +1,16 @@
+// Boost.Geometry Index
+//
+// R-tree linear algorithm implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP
+
+#include <boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp>
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp
new file mode 100644
index 0000000000..05a64c7b72
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp
@@ -0,0 +1,446 @@
+// Boost.Geometry Index
+//
+// R-tree linear split algorithm implementation
+//
+// Copyright (c) 2008 Federico J. Fernandez.
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP
+
+#include <boost/type_traits/is_unsigned.hpp>
+
+#include <boost/geometry/index/detail/algorithms/content.hpp>
+#include <boost/geometry/index/detail/bounded_view.hpp>
+
+#include <boost/geometry/index/detail/rtree/node/node.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+namespace linear {
+
+template <typename R, typename T>
+inline R difference_dispatch(T const& from, T const& to, ::boost::mpl::bool_<false> const& /*is_unsigned*/)
+{
+ return to - from;
+}
+
+template <typename R, typename T>
+inline R difference_dispatch(T const& from, T const& to, ::boost::mpl::bool_<true> const& /*is_unsigned*/)
+{
+ return from <= to ? R(to - from) : -R(from - to);
+}
+
+template <typename R, typename T>
+inline R difference(T const& from, T const& to)
+{
+ BOOST_MPL_ASSERT_MSG(!boost::is_unsigned<R>::value, RESULT_CANT_BE_UNSIGNED, (R));
+
+ typedef ::boost::mpl::bool_<
+ boost::is_unsigned<T>::value
+ > is_unsigned;
+
+ return difference_dispatch<R>(from, to, is_unsigned());
+}
+
+// TODO: awulkiew
+// In general, all aerial Indexables in the tree with box-like nodes will be analyzed as boxes
+// because they must fit into larger box. Therefore the algorithm could be the same for Bounds type.
+// E.g. if Bounds type is sphere, Indexables probably should be analyzed as spheres.
+// 1. View could be provided to 'see' all Indexables as Bounds type.
+// Not ok in the case of big types like Ring, however it's possible that Rings won't be supported,
+// only simple types. Even then if we consider storing Box inside the Sphere we must calculate
+// the bounding sphere 2x for each box because there are 2 loops. For each calculation this means
+// 4-2d or 8-3d expansions or -, / and sqrt().
+// 2. Additional container could be used and reused if the Indexable type is other than the Bounds type.
+
+// IMPORTANT!
+// Still probably the best way would be providing specialized algorithms for each Indexable-Bounds pair!
+// Probably on pick_seeds algorithm level - For Bounds=Sphere seeds would be choosen differently
+
+// TODO: awulkiew
+// there are loops inside find_greatest_normalized_separation::apply()
+// iteration is done for each DimensionIndex.
+// Separations and seeds for all DimensionIndex(es) could be calculated at once, stored, then the greatest would be choosen.
+
+// The following struct/method was adapted for the preliminary version of the R-tree. Then it was called:
+// void find_normalized_separations(std::vector<Box> const& boxes, T& separation, unsigned int& first, unsigned int& second) const
+
+template <typename Elements, typename Parameters, typename Translator, typename Tag, size_t DimensionIndex>
+struct find_greatest_normalized_separation
+{
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+ typedef typename coordinate_type<indexable_type>::type coordinate_type;
+
+ typedef typename boost::mpl::if_c<
+ boost::is_integral<coordinate_type>::value,
+ double,
+ coordinate_type
+ >::type separation_type;
+
+ typedef typename geometry::point_type<indexable_type>::type point_type;
+ typedef geometry::model::box<point_type> bounds_type;
+ typedef index::detail::bounded_view<indexable_type, bounds_type> bounded_view_type;
+
+ static inline void apply(Elements const& elements,
+ Parameters const& parameters,
+ Translator const& translator,
+ separation_type & separation,
+ size_t & seed1,
+ size_t & seed2)
+ {
+ const size_t elements_count = parameters.get_max_elements() + 1;
+ BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements");
+ BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
+
+ // find the lowest low, highest high
+ bounded_view_type bounded_indexable_0(rtree::element_indexable(elements[0], translator));
+ coordinate_type lowest_low = geometry::get<min_corner, DimensionIndex>(bounded_indexable_0);
+ coordinate_type highest_high = geometry::get<max_corner, DimensionIndex>(bounded_indexable_0);
+
+ // and the lowest high
+ coordinate_type lowest_high = highest_high;
+ size_t lowest_high_index = 0;
+ for ( size_t i = 1 ; i < elements_count ; ++i )
+ {
+ bounded_view_type bounded_indexable(rtree::element_indexable(elements[i], translator));
+ coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(bounded_indexable);
+ coordinate_type max_coord = geometry::get<max_corner, DimensionIndex>(bounded_indexable);
+
+ if ( max_coord < lowest_high )
+ {
+ lowest_high = max_coord;
+ lowest_high_index = i;
+ }
+
+ if ( min_coord < lowest_low )
+ lowest_low = min_coord;
+
+ if ( highest_high < max_coord )
+ highest_high = max_coord;
+ }
+
+ // find the highest low
+ size_t highest_low_index = lowest_high_index == 0 ? 1 : 0;
+ bounded_view_type bounded_indexable_hl(rtree::element_indexable(elements[highest_low_index], translator));
+ coordinate_type highest_low = geometry::get<min_corner, DimensionIndex>(bounded_indexable_hl);
+ for ( size_t i = highest_low_index ; i < elements_count ; ++i )
+ {
+ bounded_view_type bounded_indexable(rtree::element_indexable(elements[i], translator));
+ coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(bounded_indexable);
+ if ( highest_low < min_coord &&
+ i != lowest_high_index )
+ {
+ highest_low = min_coord;
+ highest_low_index = i;
+ }
+ }
+
+ coordinate_type const width = highest_high - lowest_low;
+
+ // highest_low - lowest_high
+ separation = difference<separation_type>(lowest_high, highest_low);
+ // BOOST_ASSERT(0 <= width);
+ if ( std::numeric_limits<coordinate_type>::epsilon() < width )
+ separation /= width;
+
+ seed1 = highest_low_index;
+ seed2 = lowest_high_index;
+
+ ::boost::ignore_unused_variable_warning(parameters);
+ }
+};
+
+// Version for points doesn't calculate normalized separation since it would always be equal to 1
+// It returns two seeds most distant to each other, separation is equal to distance
+template <typename Elements, typename Parameters, typename Translator, size_t DimensionIndex>
+struct find_greatest_normalized_separation<Elements, Parameters, Translator, point_tag, DimensionIndex>
+{
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+ typedef typename coordinate_type<indexable_type>::type coordinate_type;
+
+ typedef coordinate_type separation_type;
+
+ static inline void apply(Elements const& elements,
+ Parameters const& parameters,
+ Translator const& translator,
+ separation_type & separation,
+ size_t & seed1,
+ size_t & seed2)
+ {
+ const size_t elements_count = parameters.get_max_elements() + 1;
+ BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements");
+ BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
+
+ // find the lowest low, highest high
+ coordinate_type lowest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator));
+ coordinate_type highest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator));
+ size_t lowest_index = 0;
+ size_t highest_index = 0;
+ for ( size_t i = 1 ; i < elements_count ; ++i )
+ {
+ coordinate_type coord = geometry::get<DimensionIndex>(rtree::element_indexable(elements[i], translator));
+
+ if ( coord < lowest )
+ {
+ lowest = coord;
+ lowest_index = i;
+ }
+
+ if ( highest < coord )
+ {
+ highest = coord;
+ highest_index = i;
+ }
+ }
+
+ separation = highest - lowest;
+ seed1 = lowest_index;
+ seed2 = highest_index;
+
+ if ( lowest_index == highest_index )
+ seed2 = (lowest_index + 1) % elements_count; // % is just in case since if this is true lowest_index is 0
+
+ ::boost::ignore_unused_variable_warning(parameters);
+ }
+};
+
+template <typename Elements, typename Parameters, typename Translator, size_t Dimension>
+struct pick_seeds_impl
+{
+ BOOST_STATIC_ASSERT(0 < Dimension);
+
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+
+ typedef find_greatest_normalized_separation<
+ Elements, Parameters, Translator,
+ typename tag<indexable_type>::type, Dimension - 1
+ > find_norm_sep;
+
+ typedef typename find_norm_sep::separation_type separation_type;
+
+ static inline void apply(Elements const& elements,
+ Parameters const& parameters,
+ Translator const& tr,
+ separation_type & separation,
+ size_t & seed1,
+ size_t & seed2)
+ {
+ pick_seeds_impl<Elements, Parameters, Translator, Dimension - 1>::apply(elements, parameters, tr, separation, seed1, seed2);
+
+ separation_type current_separation;
+ size_t s1, s2;
+ find_norm_sep::apply(elements, parameters, tr, current_separation, s1, s2);
+
+ // in the old implementation different operator was used: <= (y axis prefered)
+ if ( separation < current_separation )
+ {
+ separation = current_separation;
+ seed1 = s1;
+ seed2 = s2;
+ }
+ }
+};
+
+template <typename Elements, typename Parameters, typename Translator>
+struct pick_seeds_impl<Elements, Parameters, Translator, 1>
+{
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+ typedef typename coordinate_type<indexable_type>::type coordinate_type;
+
+ typedef find_greatest_normalized_separation<
+ Elements, Parameters, Translator,
+ typename tag<indexable_type>::type, 0
+ > find_norm_sep;
+
+ typedef typename find_norm_sep::separation_type separation_type;
+
+ static inline void apply(Elements const& elements,
+ Parameters const& parameters,
+ Translator const& tr,
+ separation_type & separation,
+ size_t & seed1,
+ size_t & seed2)
+ {
+ find_norm_sep::apply(elements, parameters, tr, separation, seed1, seed2);
+ }
+};
+
+// from void linear_pick_seeds(node_pointer const& n, unsigned int &seed1, unsigned int &seed2) const
+
+template <typename Elements, typename Parameters, typename Translator>
+inline void pick_seeds(Elements const& elements,
+ Parameters const& parameters,
+ Translator const& tr,
+ size_t & seed1,
+ size_t & seed2)
+{
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+
+ typedef pick_seeds_impl
+ <
+ Elements, Parameters, Translator,
+ geometry::dimension<indexable_type>::value
+ > impl;
+ typedef typename impl::separation_type separation_type;
+
+ separation_type separation = 0;
+ impl::apply(elements, parameters, tr, separation, seed1, seed2);
+}
+
+} // namespace linear
+
+// from void split_node(node_pointer const& n, node_pointer& n1, node_pointer& n2) const
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear_tag>
+{
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ template <typename Node>
+ static inline void apply(Node & n,
+ Node & second_node,
+ Box & box1,
+ Box & box2,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators)
+ {
+ typedef typename rtree::elements_type<Node>::type elements_type;
+ typedef typename elements_type::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ elements_type & elements1 = rtree::elements(n);
+ elements_type & elements2 = rtree::elements(second_node);
+ const size_t elements1_count = parameters.get_max_elements() + 1;
+
+ BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected number of elements");
+
+ // copy original elements - use in-memory storage (std::allocator)
+ // TODO: move if noexcept
+ typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
+ container_type;
+ container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
+
+ // calculate initial seeds
+ size_t seed1 = 0;
+ size_t seed2 = 0;
+ linear::pick_seeds(elements_copy, parameters, translator, seed1, seed2);
+
+ // prepare nodes' elements containers
+ elements1.clear();
+ BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "unexpected container state");
+
+ BOOST_TRY
+ {
+ // add seeds
+ elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
+ elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
+
+ // calculate boxes
+ detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1);
+ detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2);
+
+ // initialize areas
+ content_type content1 = index::detail::content(box1);
+ content_type content2 = index::detail::content(box2);
+
+ BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements1_count, "unexpected elements number");
+ size_t remaining = elements1_count - 2;
+
+ // redistribute the rest of the elements
+ for ( size_t i = 0 ; i < elements1_count ; ++i )
+ {
+ if (i != seed1 && i != seed2)
+ {
+ element_type const& elem = elements_copy[i];
+ indexable_type const& indexable = rtree::element_indexable(elem, translator);
+
+ // if there is small number of elements left and the number of elements in node is lesser than min_elems
+ // just insert them to this node
+ if ( elements1.size() + remaining <= parameters.get_min_elements() )
+ {
+ elements1.push_back(elem); // MAY THROW, STRONG (copy)
+ geometry::expand(box1, indexable);
+ content1 = index::detail::content(box1);
+ }
+ else if ( elements2.size() + remaining <= parameters.get_min_elements() )
+ {
+ elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
+ geometry::expand(box2, indexable);
+ content2 = index::detail::content(box2);
+ }
+ // choose better node and insert element
+ else
+ {
+ // calculate enlarged boxes and areas
+ Box enlarged_box1(box1);
+ Box enlarged_box2(box2);
+ geometry::expand(enlarged_box1, indexable);
+ geometry::expand(enlarged_box2, indexable);
+ content_type enlarged_content1 = index::detail::content(enlarged_box1);
+ content_type enlarged_content2 = index::detail::content(enlarged_box2);
+
+ content_type content_increase1 = enlarged_content1 - content1;
+ content_type content_increase2 = enlarged_content2 - content2;
+
+ // choose group which box content have to be enlarged least or has smaller content or has fewer elements
+ if ( content_increase1 < content_increase2 ||
+ ( content_increase1 == content_increase2 &&
+ ( content1 < content2 ||
+ ( content1 == content2 && elements1.size() <= elements2.size() ) ) ) )
+ {
+ elements1.push_back(elem); // MAY THROW, STRONG (copy)
+ box1 = enlarged_box1;
+ content1 = enlarged_content1;
+ }
+ else
+ {
+ elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
+ box2 = enlarged_box2;
+ content2 = enlarged_content2;
+ }
+ }
+
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "unexpected value");
+ --remaining;
+ }
+ }
+ }
+ BOOST_CATCH(...)
+ {
+ elements1.clear();
+ elements2.clear();
+
+ rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
+ //elements_copy.clear();
+
+ BOOST_RETHROW // RETHROW, BASIC
+ }
+ BOOST_CATCH_END
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP
diff --git a/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp b/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp
new file mode 100644
index 0000000000..dd55c6d76c
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp
@@ -0,0 +1,38 @@
+// Boost.Geometry Index
+//
+// R-tree auto deallocator
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+template <typename Alloc>
+class auto_deallocator
+{
+ auto_deallocator(auto_deallocator const&);
+ auto_deallocator & operator=(auto_deallocator const&);
+public:
+ typedef typename Alloc::pointer pointer;
+ inline auto_deallocator(Alloc & a, pointer p) : m_alloc(a), m_ptr(p) {}
+ inline ~auto_deallocator() { if ( m_ptr ) boost::container::allocator_traits<Alloc>::deallocate(m_alloc, m_ptr, 1); }
+ inline void release() { m_ptr = 0; }
+ inline pointer ptr() { return m_ptr; }
+private:
+ Alloc & m_alloc;
+ pointer m_ptr;
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP
diff --git a/boost/geometry/index/detail/rtree/node/concept.hpp b/boost/geometry/index/detail/rtree/node/concept.hpp
new file mode 100644
index 0000000000..30fa44d263
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/concept.hpp
@@ -0,0 +1,85 @@
+// Boost.Geometry Index
+//
+// R-tree node concept
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct node
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
+ (node));
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct internal_node
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
+ (internal_node));
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct leaf
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
+ (leaf));
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst>
+struct visitor
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
+ (visitor));
+};
+
+template <typename Allocator, typename Value, typename Parameters, typename Box, typename Tag>
+class allocators
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
+ (allocators));
+};
+
+template <typename Allocators, typename Node>
+struct create_node
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_NODE_TYPE,
+ (create_node));
+};
+
+template <typename Allocators, typename Node>
+struct destroy_node
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_NODE_TYPE,
+ (destroy_node));
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP
diff --git a/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp b/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp
new file mode 100644
index 0000000000..43dff56bcb
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp
@@ -0,0 +1,67 @@
+// Boost.Geometry Index
+//
+// R-tree nodes weak visitor and nodes base type
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// empty visitor
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst>
+struct weak_visitor {};
+
+// node
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_node {};
+
+// nodes variants forward declarations
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_internal_node;
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_leaf;
+
+// nodes conversion
+
+template <typename Derived, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+inline Derived & get(weak_node<Value, Parameters, Box, Allocators, Tag> & n)
+{
+ return static_cast<Derived&>(n);
+}
+
+// apply visitor
+
+template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+inline void apply_visitor(Visitor & v,
+ raw_node<Value, Parameters, Box, Allocators, Tag> & n,
+ bool is_internal_node)
+{
+ BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr");
+ if ( is_internal_node )
+ {
+ typedef raw_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node;
+ v(get<internal_node>(n));
+ }
+ else
+ {
+ typedef raw_leaf<Value, Parameters, Box, Allocators, Tag> leaf;
+ v(get<leaf>(n));
+ }
+}
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP
diff --git a/boost/geometry/index/detail/rtree/node/node.hpp b/boost/geometry/index/detail/rtree/node/node.hpp
new file mode 100644
index 0000000000..a632ece66a
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/node.hpp
@@ -0,0 +1,178 @@
+// Boost.Geometry Index
+//
+// R-tree nodes
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP
+
+#include <boost/container/vector.hpp>
+#include <boost/geometry/index/detail/varray.hpp>
+
+#include <boost/geometry/index/detail/rtree/node/concept.hpp>
+#include <boost/geometry/index/detail/rtree/node/pairs.hpp>
+#include <boost/geometry/index/detail/rtree/node/auto_deallocator.hpp>
+#include <boost/geometry/index/detail/rtree/node/node_elements.hpp>
+
+//#include <boost/geometry/index/detail/rtree/node/weak_visitor.hpp>
+//#include <boost/geometry/index/detail/rtree/node/weak_dynamic.hpp>
+//#include <boost/geometry/index/detail/rtree/node/weak_static.hpp>
+
+#include <boost/geometry/index/detail/rtree/node/variant_visitor.hpp>
+#include <boost/geometry/index/detail/rtree/node/variant_dynamic.hpp>
+#include <boost/geometry/index/detail/rtree/node/variant_static.hpp>
+
+#include <boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp>
+
+#include <boost/geometry/algorithms/expand.hpp>
+
+#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
+
+#include <boost/geometry/index/detail/algorithms/bounds.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// elements box
+
+template <typename Box, typename FwdIter, typename Translator>
+inline Box elements_box(FwdIter first, FwdIter last, Translator const& tr)
+{
+ Box result;
+
+ if ( first == last )
+ {
+ geometry::assign_inverse(result);
+ return result;
+ }
+
+ detail::bounds(element_indexable(*first, tr), result);
+ ++first;
+
+ for ( ; first != last ; ++first )
+ geometry::expand(result, element_indexable(*first, tr));
+
+ return result;
+}
+
+// destroys subtree if the element is internal node's element
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct destroy_element
+{
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+
+ inline static void apply(typename internal_node::elements_type::value_type & element, Allocators & allocators)
+ {
+ node_auto_ptr dummy(element.second, allocators);
+ element.second = 0;
+ }
+
+ inline static void apply(typename leaf::elements_type::value_type &, Allocators &) {}
+};
+
+// destroys stored subtrees if internal node's elements are passed
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct destroy_elements
+{
+ template <typename Range>
+ inline static void apply(Range & elements, Allocators & allocators)
+ {
+ apply(boost::begin(elements), boost::end(elements), allocators);
+ }
+
+ template <typename It>
+ inline static void apply(It first, It last, Allocators & allocators)
+ {
+ typedef boost::mpl::bool_<
+ boost::is_same<
+ Value, typename std::iterator_traits<It>::value_type
+ >::value
+ > is_range_of_values;
+
+ apply_dispatch(first, last, allocators, is_range_of_values());
+ }
+
+private:
+ template <typename It>
+ inline static void apply_dispatch(It first, It last, Allocators & allocators,
+ boost::mpl::bool_<false> const& /*is_range_of_values*/)
+ {
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+
+ for ( ; first != last ; ++first )
+ {
+ node_auto_ptr dummy(first->second, allocators);
+ first->second = 0;
+ }
+ }
+
+ template <typename It>
+ inline static void apply_dispatch(It /*first*/, It /*last*/, Allocators & /*allocators*/,
+ boost::mpl::bool_<true> const& /*is_range_of_values*/)
+ {}
+};
+
+// clears node, deletes all subtrees stored in node
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct clear_node
+{
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ inline static void apply(node & node, Allocators & allocators)
+ {
+ rtree::visitors::is_leaf<Value, Options, Box, Allocators> ilv;
+ rtree::apply_visitor(ilv, node);
+ if ( ilv.result )
+ {
+ apply(rtree::get<leaf>(node), allocators);
+ }
+ else
+ {
+ apply(rtree::get<internal_node>(node), allocators);
+ }
+ }
+
+ inline static void apply(internal_node & internal_node, Allocators & allocators)
+ {
+ destroy_elements<Value, Options, Translator, Box, Allocators>::apply(rtree::elements(internal_node), allocators);
+ rtree::elements(internal_node).clear();
+ }
+
+ inline static void apply(leaf & leaf, Allocators &)
+ {
+ rtree::elements(leaf).clear();
+ }
+};
+
+template <typename Container, typename Iterator>
+void move_from_back(Container & container, Iterator it)
+{
+ BOOST_GEOMETRY_INDEX_ASSERT(!container.empty(), "cannot copy from empty container");
+ Iterator back_it = container.end();
+ --back_it;
+ if ( it != back_it )
+ {
+ *it = boost::move(*back_it); // MAY THROW (copy)
+ }
+}
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP
diff --git a/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp b/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp
new file mode 100644
index 0000000000..c19e123b62
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp
@@ -0,0 +1,81 @@
+// Boost.Geometry Index
+//
+// R-tree node auto ptr
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP
+
+#include <boost/geometry/index/detail/rtree/visitors/destroy.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// TODO - change the name to node_scoped_ptr
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class node_auto_ptr
+{
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename Allocators::node_pointer pointer;
+
+ node_auto_ptr(node_auto_ptr const&);
+ node_auto_ptr & operator=(node_auto_ptr const&);
+
+public:
+ node_auto_ptr(pointer ptr, Allocators & allocators)
+ : m_ptr(ptr)
+ , m_allocators(allocators)
+ {}
+
+ ~node_auto_ptr()
+ {
+ reset();
+ }
+
+ void reset(pointer ptr = 0)
+ {
+ if ( m_ptr )
+ {
+ detail::rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(m_ptr, m_allocators);
+ detail::rtree::apply_visitor(del_v, *m_ptr);
+ }
+ m_ptr = ptr;
+ }
+
+ void release()
+ {
+ m_ptr = 0;
+ }
+
+ pointer get() const
+ {
+ return m_ptr;
+ }
+
+ node & operator*() const
+ {
+ return *m_ptr;
+ }
+
+ pointer operator->() const
+ {
+ return m_ptr;
+ }
+
+private:
+ pointer m_ptr;
+ Allocators & m_allocators;
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP
diff --git a/boost/geometry/index/detail/rtree/node/node_elements.hpp b/boost/geometry/index/detail/rtree/node/node_elements.hpp
new file mode 100644
index 0000000000..e3bfb701f8
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/node_elements.hpp
@@ -0,0 +1,95 @@
+// Boost.Geometry Index
+//
+// R-tree node elements access
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_ELEMENTS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_ELEMENTS_HPP
+
+#include <boost/container/vector.hpp>
+#include <boost/geometry/index/detail/varray.hpp>
+#include <boost/geometry/index/detail/rtree/node/pairs.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// element's indexable type
+
+template <typename Element, typename Translator>
+struct element_indexable_type
+{
+ typedef typename indexable_type<Translator>::type type;
+};
+
+template <typename First, typename Pointer, typename Translator>
+struct element_indexable_type<
+ rtree::ptr_pair<First, Pointer>,
+ Translator
+>
+{
+ typedef First type;
+};
+
+// element's indexable getter
+
+template <typename Element, typename Translator>
+typename result_type<Translator>::type
+element_indexable(Element const& el, Translator const& tr)
+{
+ return tr(el);
+}
+
+template <typename First, typename Pointer, typename Translator>
+First const&
+element_indexable(rtree::ptr_pair<First, Pointer> const& el, Translator const& /*tr*/)
+{
+ return el.first;
+}
+
+// nodes elements
+
+template <typename Node>
+struct elements_type
+{
+ typedef typename Node::elements_type type;
+};
+
+template <typename Node>
+inline typename elements_type<Node>::type &
+elements(Node & n)
+{
+ return n.elements;
+}
+
+template <typename Node>
+inline typename elements_type<Node>::type const&
+elements(Node const& n)
+{
+ return n.elements;
+}
+
+// elements derived type
+
+template <typename Elements, typename NewValue>
+struct container_from_elements_type
+{
+ typedef boost::container::vector<NewValue> type;
+};
+
+template <typename OldValue, size_t N, typename NewValue>
+struct container_from_elements_type<detail::varray<OldValue, N>, NewValue>
+{
+ typedef detail::varray<NewValue, N> type;
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_ELEMENTS_HPP
diff --git a/boost/geometry/index/detail/rtree/node/pairs.hpp b/boost/geometry/index/detail/rtree/node/pairs.hpp
new file mode 100644
index 0000000000..dc088ec29b
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/pairs.hpp
@@ -0,0 +1,71 @@
+// Boost.Geometry Index
+//
+// Pairs intended to be used internally in nodes.
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP
+
+#include <boost/move/move.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+template <typename First, typename Pointer>
+class ptr_pair
+{
+public:
+ typedef First first_type;
+ typedef Pointer second_type;
+ ptr_pair(First const& f, Pointer s) : first(f), second(s) {}
+ //ptr_pair(ptr_pair const& p) : first(p.first), second(p.second) {}
+ //ptr_pair & operator=(ptr_pair const& p) { first = p.first; second = p.second; return *this; }
+
+ first_type first;
+ second_type second;
+};
+
+template <typename First, typename Pointer> inline
+ptr_pair<First, Pointer>
+make_ptr_pair(First const& f, Pointer s)
+{
+ return ptr_pair<First, Pointer>(f, s);
+}
+
+// TODO: It this will be used, rename it to unique_ptr_pair and possibly use unique_ptr.
+
+template <typename First, typename Pointer>
+class exclusive_ptr_pair
+{
+ BOOST_MOVABLE_BUT_NOT_COPYABLE(exclusive_ptr_pair)
+public:
+ typedef First first_type;
+ typedef Pointer second_type;
+ exclusive_ptr_pair(First const& f, Pointer s) : first(f), second(s) {}
+
+ // INFO - members aren't really moved!
+ exclusive_ptr_pair(BOOST_RV_REF(exclusive_ptr_pair) p) : first(p.first), second(p.second) { p.second = 0; }
+ exclusive_ptr_pair & operator=(BOOST_RV_REF(exclusive_ptr_pair) p) { first = p.first; second = p.second; p.second = 0; return *this; }
+
+ first_type first;
+ second_type second;
+};
+
+template <typename First, typename Pointer> inline
+exclusive_ptr_pair<First, Pointer>
+make_exclusive_ptr_pair(First const& f, Pointer s)
+{
+ return exclusive_ptr_pair<First, Pointer>(f, s);
+}
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP
diff --git a/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp b/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp
new file mode 100644
index 0000000000..f13dd10360
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp
@@ -0,0 +1,275 @@
+// Boost.Geometry Index
+//
+// R-tree nodes based on Boost.Variant, storing dynamic-size containers
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// nodes default types
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct variant_internal_node
+{
+ typedef boost::container::vector
+ <
+ rtree::ptr_pair<Box, typename Allocators::node_pointer>,
+ typename Allocators::node_allocator_type::template rebind
+ <
+ rtree::ptr_pair<Box, typename Allocators::node_pointer>
+ >::other
+ > elements_type;
+
+ template <typename Al>
+ inline variant_internal_node(Al const& al)
+ : elements(al)
+ {}
+
+ elements_type elements;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct variant_leaf
+{
+ typedef boost::container::vector
+ <
+ Value,
+ typename Allocators::node_allocator_type::template rebind
+ <
+ Value
+ >::other
+ > elements_type;
+
+ template <typename Al>
+ inline variant_leaf(Al const& al)
+ : elements(al)
+ {}
+
+ elements_type elements;
+};
+
+// nodes traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
+{
+ typedef boost::variant<
+ variant_leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>,
+ variant_internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
+ > type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
+{
+ typedef variant_internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
+{
+ typedef variant_leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> type;
+};
+
+// visitor traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
+struct visitor<Value, Parameters, Box, Allocators, node_variant_dynamic_tag, IsVisitableConst>
+{
+ typedef static_visitor<> type;
+};
+
+// allocators
+
+template <typename Allocator, typename Value, typename Parameters, typename Box>
+class allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag>
+ : public Allocator::template rebind<
+ typename node<
+ Value, Parameters, Box,
+ allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag>,
+ node_variant_dynamic_tag>::type
+ >::other
+{
+ typedef typename Allocator::template rebind<
+ Value
+ >::other value_allocator_type;
+
+public:
+ typedef Allocator allocator_type;
+
+ typedef Value value_type;
+ typedef typename value_allocator_type::reference reference;
+ typedef typename value_allocator_type::const_reference const_reference;
+ typedef typename value_allocator_type::size_type size_type;
+ typedef typename value_allocator_type::difference_type difference_type;
+ typedef typename value_allocator_type::pointer pointer;
+ typedef typename value_allocator_type::const_pointer const_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename node<Value, Parameters, Box, allocators, node_variant_dynamic_tag>::type
+ >::other::pointer node_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename node<Value, Parameters, Box, allocators, node_variant_dynamic_tag>::type
+ >::other node_allocator_type;
+
+ inline allocators()
+ : node_allocator_type()
+ {}
+
+ template <typename Alloc>
+ inline explicit allocators(Alloc const& alloc)
+ : node_allocator_type(alloc)
+ {}
+
+ inline allocators(BOOST_FWD_REF(allocators) a)
+ : node_allocator_type(boost::move(a.node_allocator()))
+ {}
+
+ inline allocators & operator=(BOOST_FWD_REF(allocators) a)
+ {
+ node_allocator() = boost::move(a.node_allocator());
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ inline allocators & operator=(allocators const& a)
+ {
+ node_allocator() = a.node_allocator();
+ return *this;
+ }
+#endif
+
+ void swap(allocators & a)
+ {
+ boost::swap(node_allocator(), a.node_allocator());
+ }
+
+ bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); }
+ template <typename Alloc>
+ bool operator==(Alloc const& a) const { return node_allocator() == node_allocator_type(a); }
+
+ Allocator allocator() const { return Allocator(node_allocator()); }
+
+ node_allocator_type & node_allocator() { return *this; }
+ node_allocator_type const& node_allocator() const { return *this; }
+};
+
+// create_node_variant
+
+template <typename VariantPtr, typename Node>
+struct create_variant_node
+{
+ template <typename AllocNode>
+ static inline VariantPtr apply(AllocNode & alloc_node)
+ {
+ typedef boost::container::allocator_traits<AllocNode> Al;
+ typedef typename Al::pointer P;
+
+ P p = Al::allocate(alloc_node, 1);
+
+ if ( 0 == p )
+ throw_runtime_error("boost::geometry::index::rtree node creation failed");
+
+ auto_deallocator<AllocNode> deallocator(alloc_node, p);
+
+ Al::construct(alloc_node, boost::addressof(*p), Node(alloc_node)); // implicit cast to Variant
+
+ deallocator.release();
+ return p;
+ }
+};
+
+// destroy_node_variant
+
+template <typename Node>
+struct destroy_variant_node
+{
+ template <typename AllocNode, typename VariantPtr>
+ static inline void apply(AllocNode & alloc_node, VariantPtr n)
+ {
+ typedef boost::container::allocator_traits<AllocNode> Al;
+
+ Al::destroy(alloc_node, boost::addressof(*n));
+ Al::deallocate(alloc_node, n, 1);
+ }
+};
+
+// create_node
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct create_node<
+ Allocators,
+ variant_internal_node<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline typename Allocators::node_pointer
+ apply(Allocators & allocators)
+ {
+ return create_variant_node<
+ typename Allocators::node_pointer,
+ variant_internal_node<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.node_allocator());
+ }
+};
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct create_node<
+ Allocators,
+ variant_leaf<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline typename Allocators::node_pointer
+ apply(Allocators & allocators)
+ {
+ return create_variant_node<
+ typename Allocators::node_pointer,
+ variant_leaf<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.node_allocator());
+ }
+};
+
+// destroy_node
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct destroy_node<
+ Allocators,
+ variant_internal_node<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
+ {
+ destroy_variant_node<
+ variant_internal_node<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.node_allocator(), n);
+ }
+};
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct destroy_node<
+ Allocators,
+ variant_leaf<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
+ {
+ destroy_variant_node<
+ variant_leaf<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.node_allocator(), n);
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_HPP
diff --git a/boost/geometry/index/detail/rtree/node/variant_static.hpp b/boost/geometry/index/detail/rtree/node/variant_static.hpp
new file mode 100644
index 0000000000..f6e9761b2d
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/variant_static.hpp
@@ -0,0 +1,194 @@
+// Boost.Geometry Index
+//
+// R-tree nodes based on Boost.Variant, storing static-size containers
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// nodes default types
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
+{
+ typedef detail::varray<
+ rtree::ptr_pair<Box, typename Allocators::node_pointer>,
+ Parameters::max_elements + 1
+ > elements_type;
+
+ template <typename Alloc>
+ inline variant_internal_node(Alloc const&) {}
+
+ elements_type elements;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>
+{
+ typedef detail::varray<
+ Value,
+ Parameters::max_elements + 1
+ > elements_type;
+
+ template <typename Alloc>
+ inline variant_leaf(Alloc const&) {}
+
+ elements_type elements;
+};
+
+// nodes traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct node<Value, Parameters, Box, Allocators, node_variant_static_tag>
+{
+ typedef boost::variant<
+ variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>,
+ variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
+ > type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
+{
+ typedef variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>
+{
+ typedef variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag> type;
+};
+
+// visitor traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
+struct visitor<Value, Parameters, Box, Allocators, node_variant_static_tag, IsVisitableConst>
+{
+ typedef static_visitor<> type;
+};
+
+// allocators
+
+template <typename Allocator, typename Value, typename Parameters, typename Box>
+struct allocators<Allocator, Value, Parameters, Box, node_variant_static_tag>
+ : public Allocator::template rebind<
+ typename node<
+ Value, Parameters, Box,
+ allocators<Allocator, Value, Parameters, Box, node_variant_static_tag>,
+ node_variant_static_tag
+ >::type
+ >::other
+{
+ typedef typename Allocator::template rebind<
+ Value
+ >::other value_allocator_type;
+
+public:
+ typedef Allocator allocator_type;
+
+ typedef Value value_type;
+ typedef value_type & reference;
+ typedef const value_type & const_reference;
+ typedef typename value_allocator_type::size_type size_type;
+ typedef typename value_allocator_type::difference_type difference_type;
+ typedef typename value_allocator_type::pointer pointer;
+ typedef typename value_allocator_type::const_pointer const_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename node<Value, Parameters, Box, allocators, node_variant_static_tag>::type
+ >::other::pointer node_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename node<Value, Parameters, Box, allocators, node_variant_static_tag>::type
+ >::other node_allocator_type;
+
+ inline allocators()
+ : node_allocator_type()
+ {}
+
+ template <typename Alloc>
+ inline explicit allocators(Alloc const& alloc)
+ : node_allocator_type(alloc)
+ {}
+
+ inline allocators(BOOST_FWD_REF(allocators) a)
+ : node_allocator_type(boost::move(a.node_allocator()))
+ {}
+
+ inline allocators & operator=(BOOST_FWD_REF(allocators) a)
+ {
+ node_allocator() = boost::move(a.node_allocator());
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ inline allocators & operator=(allocators const& a)
+ {
+ node_allocator() = a.node_allocator();
+ return *this;
+ }
+#endif
+
+ void swap(allocators & a)
+ {
+ boost::swap(node_allocator(), a.node_allocator());
+ }
+
+ bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); }
+ template <typename Alloc>
+ bool operator==(Alloc const& a) const { return node_allocator() == node_allocator_type(a); }
+
+ Allocator allocator() const { return Allocator(node_allocator()); }
+
+ node_allocator_type & node_allocator() { return *this; }
+ node_allocator_type const& node_allocator() const { return *this; }
+};
+
+// create_node
+
+template <typename Allocators, typename Value, typename Parameters, typename Box>
+struct create_node<
+ Allocators,
+ variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
+>
+{
+ static inline typename Allocators::node_pointer
+ apply(Allocators & allocators)
+ {
+ return create_variant_node<
+ typename Allocators::node_pointer,
+ variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
+ >::apply(allocators.node_allocator());
+ }
+};
+
+template <typename Allocators, typename Value, typename Parameters, typename Box>
+struct create_node<
+ Allocators,
+ variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>
+>
+{
+ static inline typename Allocators::node_pointer
+ apply(Allocators & allocators)
+ {
+ return create_variant_node<
+ typename Allocators::node_pointer,
+ variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>
+ >::apply(allocators.node_allocator());
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP
diff --git a/boost/geometry/index/detail/rtree/node/variant_visitor.hpp b/boost/geometry/index/detail/rtree/node/variant_visitor.hpp
new file mode 100644
index 0000000000..ffd67039d2
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/variant_visitor.hpp
@@ -0,0 +1,66 @@
+// Boost.Geometry Index
+//
+// R-tree nodes static visitor related code
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_VISITOR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_VISITOR_HPP
+
+#include <boost/variant.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// nodes variants forward declarations
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct variant_internal_node;
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct variant_leaf;
+
+// nodes conversion
+
+template <typename V, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+inline V & get(
+ boost::variant<
+ variant_leaf<Value, Parameters, Box, Allocators, Tag>,
+ variant_internal_node<Value, Parameters, Box, Allocators, Tag>
+ > & v)
+{
+ return boost::get<V>(v);
+}
+
+// apply visitor
+
+template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+inline void apply_visitor(Visitor & v,
+ boost::variant<
+ variant_leaf<Value, Parameters, Box, Allocators, Tag>,
+ variant_internal_node<Value, Parameters, Box, Allocators, Tag>
+ > & n)
+{
+ boost::apply_visitor(v, n);
+}
+
+template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+inline void apply_visitor(Visitor & v,
+ boost::variant<
+ variant_leaf<Value, Parameters, Box, Allocators, Tag>,
+ variant_internal_node<Value, Parameters, Box, Allocators, Tag>
+ > const& n)
+{
+ boost::apply_visitor(v, n);
+}
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_VISITOR_HPP
diff --git a/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp b/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp
new file mode 100644
index 0000000000..b828b35f45
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp
@@ -0,0 +1,294 @@
+// Boost.Geometry Index
+//
+// R-tree nodes based on static conversion, storing dynamic-size containers
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_internal_node
+ : public weak_node<Value, Parameters, Box, Allocators, Tag>
+{
+ typedef boost::container::vector
+ <
+ rtree::ptr_pair<Box, typename Allocators::node_pointer>,
+ typename Allocators::internal_node_allocator_type::template rebind
+ <
+ rtree::ptr_pair<Box, typename Allocators::node_pointer>
+ >::other
+ > elements_type;
+
+ template <typename Al>
+ inline weak_internal_node(Al const& al)
+ : elements(al)
+ {}
+
+ elements_type elements;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_leaf
+ : public weak_node<Value, Parameters, Box, Allocators, Tag>
+{
+ typedef boost::container::vector
+ <
+ Value,
+ typename Allocators::leaf_allocator_type::template rebind
+ <
+ Value
+ >::other
+ > elements_type;
+
+ template <typename Al>
+ inline weak_leaf(Al const& al)
+ : elements(al)
+ {}
+
+ elements_type elements;
+};
+
+// nodes traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag>
+{
+ typedef weak_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct internal_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag>
+{
+ typedef weak_internal_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct leaf<Value, Parameters, Box, Allocators, node_weak_dynamic_tag>
+{
+ typedef weak_leaf<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type;
+};
+
+// visitor traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
+struct visitor<Value, Parameters, Box, Allocators, node_weak_dynamic_tag, IsVisitableConst>
+{
+ typedef weak_visitor<Value, Parameters, Box, Allocators, node_weak_dynamic_tag, IsVisitableConst> type;
+};
+
+// allocators
+
+template <typename Allocator, typename Value, typename Parameters, typename Box>
+class allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>
+ : public Allocator::template rebind<
+ typename internal_node<
+ Value, Parameters, Box,
+ allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>,
+ node_weak_dynamic_tag
+ >::type
+ >::other
+ , public Allocator::template rebind<
+ typename leaf<
+ Value, Parameters, Box,
+ allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>,
+ node_weak_dynamic_tag
+ >::type
+ >::other
+{
+ typedef typename Allocator::template rebind<
+ Value
+ >::other value_allocator_type;
+
+public:
+ typedef Allocator allocator_type;
+
+ typedef Value value_type;
+ typedef typename value_allocator_type::reference reference;
+ typedef typename value_allocator_type::const_reference const_reference;
+ typedef typename value_allocator_type::size_type size_type;
+ typedef typename value_allocator_type::difference_type difference_type;
+ typedef typename value_allocator_type::pointer pointer;
+ typedef typename value_allocator_type::const_pointer const_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename node<Value, Parameters, Box, allocators, node_weak_dynamic_tag>::type
+ >::other::pointer node_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename internal_node<Value, Parameters, Box, allocators, node_weak_dynamic_tag>::type
+ >::other internal_node_allocator_type;
+
+ typedef typename Allocator::template rebind<
+ typename leaf<Value, Parameters, Box, allocators, node_weak_dynamic_tag>::type
+ >::other leaf_allocator_type;
+
+ inline allocators()
+ : internal_node_allocator_type()
+ , leaf_allocator_type()
+ {}
+
+ template <typename Alloc>
+ inline explicit allocators(Alloc const& alloc)
+ : internal_node_allocator_type(alloc)
+ , leaf_allocator_type(alloc)
+ {}
+
+ inline allocators(BOOST_FWD_REF(allocators) a)
+ : internal_node_allocator_type(boost::move(a.internal_node_allocator()))
+ , leaf_allocator_type(boost::move(a.leaf_allocator()))
+ {}
+
+ inline allocators & operator=(BOOST_FWD_REF(allocators) a)
+ {
+ internal_node_allocator() = ::boost::move(a.internal_node_allocator());
+ leaf_allocator() = ::boost::move(a.leaf_allocator());
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ inline allocators & operator=(allocators const& a)
+ {
+ internal_node_allocator() = a.internal_node_allocator();
+ leaf_allocator() = a.leaf_allocator();
+ return *this;
+ }
+#endif
+
+ void swap(allocators & a)
+ {
+ boost::swap(internal_node_allocator(), a.internal_node_allocator());
+ boost::swap(leaf_allocator(), a.leaf_allocator());
+ }
+
+ bool operator==(allocators const& a) const { return leaf_allocator() == a.leaf_allocator(); }
+ template <typename Alloc>
+ bool operator==(Alloc const& a) const { return leaf_allocator() == leaf_allocator_type(a); }
+
+ Allocator allocator() const { return Allocator(leaf_allocator()); }
+
+ internal_node_allocator_type & internal_node_allocator() { return *this; }
+ internal_node_allocator_type const& internal_node_allocator() const { return *this; }
+ leaf_allocator_type & leaf_allocator() { return *this; }
+ leaf_allocator_type const& leaf_allocator() const { return *this; }
+};
+
+// create_node_impl
+
+template <typename BaseNodePtr, typename Node>
+struct create_weak_node
+{
+ template <typename AllocNode>
+ static inline BaseNodePtr apply(AllocNode & alloc_node)
+ {
+ typedef boost::container::allocator_traits<AllocNode> Al;
+ typedef typename Al::pointer P;
+
+ P p = Al::allocate(alloc_node, 1);
+
+ if ( 0 == p )
+ throw_runtime_error("boost::geometry::index::rtree node creation failed");
+
+ auto_deallocator<AllocNode> deallocator(alloc_node, p);
+
+ Al::construct(alloc_node, boost::addressof(*p), alloc_node);
+
+ deallocator.release();
+ return p;
+ }
+};
+
+// destroy_node_impl
+
+template <typename Node>
+struct destroy_weak_node
+{
+ template <typename AllocNode, typename BaseNodePtr>
+ static inline void apply(AllocNode & alloc_node, BaseNodePtr n)
+ {
+ typedef boost::container::allocator_traits<AllocNode> Al;
+ typedef typename Al::pointer P;
+
+ P p(&static_cast<Node&>(rtree::get<Node>(*n)));
+ Al::destroy(alloc_node, boost::addressof(*p));
+ Al::deallocate(alloc_node, p, 1);
+ }
+};
+
+// create_node
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct create_node<
+ Allocators,
+ weak_internal_node<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline typename Allocators::node_pointer
+ apply(Allocators & allocators)
+ {
+ return create_weak_node<
+ typename Allocators::node_pointer,
+ weak_internal_node<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.internal_node_allocator());
+ }
+};
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct create_node<
+ Allocators,
+ weak_leaf<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline typename Allocators::node_pointer
+ apply(Allocators & allocators)
+ {
+ return create_weak_node<
+ typename Allocators::node_pointer,
+ weak_leaf<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.leaf_allocator());
+ }
+};
+
+// destroy_node
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct destroy_node<
+ Allocators,
+ weak_internal_node<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
+ {
+ destroy_weak_node<
+ weak_internal_node<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.internal_node_allocator(), n);
+ }
+};
+
+template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
+struct destroy_node<
+ Allocators,
+ weak_leaf<Value, Parameters, Box, Allocators, Tag>
+>
+{
+ static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
+ {
+ destroy_weak_node<
+ weak_leaf<Value, Parameters, Box, Allocators, Tag>
+ >::apply(allocators.leaf_allocator(), n);
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP
diff --git a/boost/geometry/index/detail/rtree/node/weak_static.hpp b/boost/geometry/index/detail/rtree/node/weak_static.hpp
new file mode 100644
index 0000000000..632e35678a
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/weak_static.hpp
@@ -0,0 +1,174 @@
+// Boost.Geometry Index
+//
+// R-tree nodes based on static conversion, storing static-size containers
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct weak_internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
+ : public weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
+{
+ typedef detail::varray<
+ rtree::ptr_pair<Box, typename Allocators::node_pointer>,
+ Parameters::max_elements + 1
+ > elements_type;
+
+ template <typename Alloc>
+ inline weak_internal_node(Alloc const&) {}
+
+ elements_type elements;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct weak_leaf<Value, Parameters, Box, Allocators, node_weak_static_tag>
+ : public weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
+{
+ typedef detail::varray<
+ Value,
+ Parameters::max_elements + 1
+ > elements_type;
+
+ template <typename Alloc>
+ inline weak_leaf(Alloc const&) {}
+
+ elements_type elements;
+};
+
+// nodes traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct node<Value, Parameters, Box, Allocators, node_weak_static_tag>
+{
+ typedef weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
+{
+ typedef weak_internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct leaf<Value, Parameters, Box, Allocators, node_weak_static_tag>
+{
+ typedef weak_leaf<Value, Parameters, Box, Allocators, node_weak_static_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
+struct visitor<Value, Parameters, Box, Allocators, node_weak_static_tag, IsVisitableConst>
+{
+ typedef weak_visitor<Value, Parameters, Box, Allocators, node_weak_static_tag, IsVisitableConst> type;
+};
+
+// allocators
+
+template <typename Allocator, typename Value, typename Parameters, typename Box>
+class allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>
+ : public Allocator::template rebind<
+ typename internal_node<
+ Value, Parameters, Box,
+ allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>,
+ node_weak_static_tag
+ >::type
+ >::other
+ , public Allocator::template rebind<
+ typename leaf<
+ Value, Parameters, Box,
+ allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>,
+ node_weak_static_tag
+ >::type
+ >::other
+{
+ typedef typename Allocator::template rebind<
+ Value
+ >::other value_allocator_type;
+
+public:
+ typedef Allocator allocator_type;
+
+ typedef Value value_type;
+ typedef value_type & reference;
+ typedef const value_type & const_reference;
+ typedef typename value_allocator_type::size_type size_type;
+ typedef typename value_allocator_type::difference_type difference_type;
+ typedef typename value_allocator_type::pointer pointer;
+ typedef typename value_allocator_type::const_pointer const_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename node<Value, Parameters, Box, allocators, node_weak_static_tag>::type
+ >::other::pointer node_pointer;
+
+ typedef typename Allocator::template rebind<
+ typename internal_node<Value, Parameters, Box, allocators, node_weak_static_tag>::type
+ >::other internal_node_allocator_type;
+
+ typedef typename Allocator::template rebind<
+ typename leaf<Value, Parameters, Box, allocators, node_weak_static_tag>::type
+ >::other leaf_allocator_type;
+
+ inline allocators()
+ : internal_node_allocator_type()
+ , leaf_allocator_type()
+ {}
+
+ template <typename Alloc>
+ inline explicit allocators(Alloc const& alloc)
+ : internal_node_allocator_type(alloc)
+ , leaf_allocator_type(alloc)
+ {}
+
+ inline allocators(BOOST_FWD_REF(allocators) a)
+ : internal_node_allocator_type(boost::move(a.internal_node_allocator()))
+ , leaf_allocator_type(boost::move(a.leaf_allocator()))
+ {}
+
+ inline allocators & operator=(BOOST_FWD_REF(allocators) a)
+ {
+ internal_node_allocator() = ::boost::move(a.internal_node_allocator());
+ leaf_allocator() = ::boost::move(a.leaf_allocator());
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ inline allocators & operator=(allocators const& a)
+ {
+ internal_node_allocator() = a.internal_node_allocator();
+ leaf_allocator() = a.leaf_allocator();
+ return *this;
+ }
+#endif
+
+ void swap(allocators & a)
+ {
+ boost::swap(internal_node_allocator(), a.internal_node_allocator());
+ boost::swap(leaf_allocator(), a.leaf_allocator());
+ }
+
+ bool operator==(allocators const& a) const { return leaf_allocator() == a.leaf_allocator(); }
+ template <typename Alloc>
+ bool operator==(Alloc const& a) const { return leaf_allocator() == leaf_allocator_type(a); }
+
+ Allocator allocator() const { return Allocator(leaf_allocator()); }
+
+ internal_node_allocator_type & internal_node_allocator() { return *this; }
+ internal_node_allocator_type const& internal_node_allocator() const { return *this; }
+ leaf_allocator_type & leaf_allocator() { return *this; }
+ leaf_allocator_type const& leaf_allocator() const{ return *this; }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP
diff --git a/boost/geometry/index/detail/rtree/node/weak_visitor.hpp b/boost/geometry/index/detail/rtree/node/weak_visitor.hpp
new file mode 100644
index 0000000000..08d84778e6
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/node/weak_visitor.hpp
@@ -0,0 +1,67 @@
+// Boost.Geometry Index
+//
+// R-tree nodes weak visitor and nodes base type
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// empty visitor
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst>
+struct weak_visitor {};
+
+// node
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_node {};
+
+// nodes variants forward declarations
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_internal_node;
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+struct weak_leaf;
+
+// nodes conversion
+
+template <typename Derived, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+inline Derived & get(weak_node<Value, Parameters, Box, Allocators, Tag> & n)
+{
+ return static_cast<Derived&>(n);
+}
+
+// apply visitor
+
+template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
+inline void apply_visitor(Visitor & v,
+ weak_node<Value, Parameters, Box, Allocators, Tag> & n,
+ bool is_internal_node)
+{
+ BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr");
+ if ( is_internal_node )
+ {
+ typedef weak_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node;
+ v(get<internal_node>(n));
+ }
+ else
+ {
+ typedef weak_leaf<Value, Parameters, Box, Allocators, Tag> leaf;
+ v(get<leaf>(n));
+ }
+}
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP
diff --git a/boost/geometry/index/detail/rtree/options.hpp b/boost/geometry/index/detail/rtree/options.hpp
new file mode 100644
index 0000000000..ff772834d7
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/options.hpp
@@ -0,0 +1,155 @@
+// Boost.Geometry Index
+//
+// R-tree options, algorithms, parameters
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP
+
+#include <boost/geometry/index/parameters.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// InsertTag
+struct insert_default_tag {};
+struct insert_reinsert_tag {};
+
+// ChooseNextNodeTag
+struct choose_by_content_diff_tag {};
+struct choose_by_overlap_diff_tag {};
+
+// SplitTag
+struct split_default_tag {};
+//struct split_kmeans_tag {};
+
+// RedistributeTag
+struct linear_tag {};
+struct quadratic_tag {};
+struct rstar_tag {};
+
+// NodeTag
+struct node_variant_dynamic_tag {};
+struct node_variant_static_tag {};
+//struct node_weak_dynamic_tag {};
+//struct node_weak_static_tag {};
+
+template <typename Parameters, typename InsertTag, typename ChooseNextNodeTag, typename SplitTag, typename RedistributeTag, typename NodeTag>
+struct options
+{
+ typedef Parameters parameters_type;
+ typedef InsertTag insert_tag;
+ typedef ChooseNextNodeTag choose_next_node_tag;
+ typedef SplitTag split_tag;
+ typedef RedistributeTag redistribute_tag;
+ typedef NodeTag node_tag;
+};
+
+template <typename Parameters>
+struct options_type
+{
+ // TODO: awulkiew - use static assert
+};
+
+template <size_t MaxElements, size_t MinElements>
+struct options_type< index::linear<MaxElements, MinElements> >
+{
+ typedef options<
+ index::linear<MaxElements, MinElements>,
+ insert_default_tag,
+ choose_by_content_diff_tag,
+ split_default_tag,
+ linear_tag,
+ node_variant_static_tag
+ > type;
+};
+
+template <size_t MaxElements, size_t MinElements>
+struct options_type< index::quadratic<MaxElements, MinElements> >
+{
+ typedef options<
+ index::quadratic<MaxElements, MinElements>,
+ insert_default_tag,
+ choose_by_content_diff_tag,
+ split_default_tag,
+ quadratic_tag,
+ node_variant_static_tag
+ > type;
+};
+
+template <size_t MaxElements, size_t MinElements, size_t OverlapCostThreshold, size_t ReinsertedElements>
+struct options_type< index::rstar<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements> >
+{
+ typedef options<
+ index::rstar<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements>,
+ insert_reinsert_tag,
+ choose_by_overlap_diff_tag,
+ split_default_tag,
+ rstar_tag,
+ node_variant_static_tag
+ > type;
+};
+
+//template <size_t MaxElements, size_t MinElements>
+//struct options_type< kmeans<MaxElements, MinElements> >
+//{
+// typedef options<
+// kmeans<MaxElements, MinElements>,
+// insert_default_tag,
+// choose_by_content_diff_tag, // change it?
+// split_kmeans_tag,
+// int, // dummy tag - not used for now
+// node_variant_static_tag
+// > type;
+//};
+
+template <>
+struct options_type< index::dynamic_linear >
+{
+ typedef options<
+ index::dynamic_linear,
+ insert_default_tag,
+ choose_by_content_diff_tag,
+ split_default_tag,
+ linear_tag,
+ node_variant_dynamic_tag
+ > type;
+};
+
+template <>
+struct options_type< index::dynamic_quadratic >
+{
+ typedef options<
+ index::dynamic_quadratic,
+ insert_default_tag,
+ choose_by_content_diff_tag,
+ split_default_tag,
+ quadratic_tag,
+ node_variant_dynamic_tag
+ > type;
+};
+
+template <>
+struct options_type< index::dynamic_rstar >
+{
+ typedef options<
+ index::dynamic_rstar,
+ insert_reinsert_tag,
+ choose_by_overlap_diff_tag,
+ split_default_tag,
+ rstar_tag,
+ node_variant_dynamic_tag
+ > type;
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP
diff --git a/boost/geometry/index/detail/rtree/pack_create.hpp b/boost/geometry/index/detail/rtree/pack_create.hpp
new file mode 100644
index 0000000000..46bf357fc4
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/pack_create.hpp
@@ -0,0 +1,376 @@
+// Boost.Geometry Index
+//
+// R-tree initial packing
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
+
+namespace pack_utils {
+
+template <std::size_t Dimension>
+struct biggest_edge
+{
+ BOOST_STATIC_ASSERT(0 < Dimension);
+ template <typename Box>
+ static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index)
+ {
+ biggest_edge<Dimension-1>::apply(box, length, dim_index);
+ typename coordinate_type<Box>::type curr
+ = geometry::get<max_corner, Dimension-1>(box) - geometry::get<min_corner, Dimension-1>(box);
+ if ( length < curr )
+ {
+ dim_index = Dimension - 1;
+ length = curr;
+ }
+ }
+};
+
+template <>
+struct biggest_edge<1>
+{
+ template <typename Box>
+ static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index)
+ {
+ dim_index = 0;
+ length = geometry::get<max_corner, 0>(box) - geometry::get<min_corner, 0>(box);
+ }
+};
+
+template <std::size_t I>
+struct point_entries_comparer
+{
+ template <typename PointEntry>
+ bool operator()(PointEntry const& e1, PointEntry const& e2) const
+ {
+ return geometry::get<I>(e1.first) < geometry::get<I>(e2.first);
+ }
+};
+
+template <std::size_t I, std::size_t Dimension>
+struct nth_element_and_half_boxes
+{
+ template <typename EIt, typename Box>
+ static inline void apply(EIt first, EIt median, EIt last, Box const& box, Box & left, Box & right, std::size_t dim_index)
+ {
+ if ( I == dim_index )
+ {
+ std::nth_element(first, median, last, point_entries_comparer<I>());
+
+ geometry::convert(box, left);
+ geometry::convert(box, right);
+ typename coordinate_type<Box>::type edge_len
+ = geometry::get<max_corner, I>(box) - geometry::get<min_corner, I>(box);
+ typename coordinate_type<Box>::type median
+ = geometry::get<min_corner, I>(box) + edge_len / 2;
+ geometry::set<max_corner, I>(left, median);
+ geometry::set<min_corner, I>(right, median);
+ }
+ else
+ nth_element_and_half_boxes<I+1, Dimension>::apply(first, median, last, box, left, right, dim_index);
+ }
+};
+
+template <std::size_t Dimension>
+struct nth_element_and_half_boxes<Dimension, Dimension>
+{
+ template <typename EIt, typename Box>
+ static inline void apply(EIt , EIt , EIt , Box const& , Box & , Box & , std::size_t ) {}
+};
+
+} // namespace pack_utils
+
+// STR leafs number are calculated as rcount/max
+// and the number of splitting planes for each dimension as (count/max)^(1/dimension)
+// <-> for dimension==2 -> sqrt(count/max)
+//
+// The main flaw of this algorithm is that the resulting tree will have bad structure for:
+// 1. non-uniformly distributed elements
+// Statistic check could be performed, e.g. based on variance of lengths of elements edges for each dimension
+// 2. elements distributed mainly along one axis
+// Calculate bounding box of all elements and then number of dividing planes for a dimension
+// from the length of BB edge for this dimension (more or less assuming that elements are uniformly-distributed squares)
+//
+// Another thing is that the last node may have less elements than Max or even Min.
+// The number of splitting planes must be chosen more carefully than count/max
+//
+// This algorithm is something between STR and TGS
+// it is more similar to the top-down recursive kd-tree creation algorithm
+// using object median split and split axis of greatest BB edge
+// BB is only used as a hint (assuming objects are distributed uniformly)
+//
+// Implemented algorithm guarantees that the number of elements in nodes will be between Min and Max
+// and that nodes are packed as tightly as possible
+// e.g. for 177 values Max = 5 and Min = 2 it will construct the following tree:
+// ROOT 177
+// L1 125 52
+// L2 25 25 25 25 25 25 17 10
+// L3 5x5 5x5 5x5 5x5 5x5 5x5 3x5+2 2x5
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class pack
+{
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+ typedef typename Allocators::size_type size_type;
+
+ typedef typename geometry::point_type<Box>::type point_type;
+ typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
+ typedef typename detail::default_content_result<Box>::type content_type;
+ typedef typename Options::parameters_type parameters_type;
+ static const std::size_t dimension = geometry::dimension<point_type>::value;
+
+ typedef typename rtree::container_from_elements_type<
+ typename rtree::elements_type<leaf>::type,
+ std::size_t
+ >::type values_counts_container;
+
+ typedef typename rtree::elements_type<internal_node>::type internal_elements;
+ typedef typename internal_elements::value_type internal_element;
+
+public:
+ // Arbitrary iterators
+ template <typename InIt> inline static
+ node_pointer apply(InIt first, InIt last, size_type & values_count, size_type & leafs_level,
+ parameters_type const& parameters, Translator const& translator, Allocators & allocators)
+ {
+ typedef typename std::iterator_traits<InIt>::difference_type diff_type;
+
+ diff_type diff = std::distance(first, last);
+ if ( diff <= 0 )
+ return node_pointer(0);
+
+ typedef std::pair<point_type, InIt> entry_type;
+ std::vector<entry_type> entries;
+
+ values_count = static_cast<size_type>(diff);
+ entries.reserve(values_count);
+
+ Box hint_box;
+ geometry::assign_inverse(hint_box);
+ for ( ; first != last ; ++first )
+ {
+ geometry::expand(hint_box, translator(*first));
+
+ point_type pt;
+ geometry::centroid(translator(*first), pt);
+ entries.push_back(std::make_pair(pt, first));
+ }
+
+ subtree_elements_counts subtree_counts = calculate_subtree_elements_counts(values_count, parameters, leafs_level);
+ internal_element el = per_level(entries.begin(), entries.end(), hint_box, values_count, subtree_counts,
+ parameters, translator, allocators);
+
+ return el.second;
+ }
+
+private:
+ struct subtree_elements_counts
+ {
+ subtree_elements_counts(std::size_t ma, std::size_t mi) : maxc(ma), minc(mi) {}
+ std::size_t maxc;
+ std::size_t minc;
+ };
+
+ template <typename EIt> inline static
+ internal_element per_level(EIt first, EIt last, Box const& hint_box, std::size_t values_count, subtree_elements_counts const& subtree_counts,
+ parameters_type const& parameters, Translator const& translator, Allocators & allocators)
+ {
+ BOOST_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count);
+
+ if ( subtree_counts.maxc <= 1 )
+ {
+ // ROOT or LEAF
+ BOOST_ASSERT(values_count <= parameters.get_max_elements());
+ // if !root check m_parameters.get_min_elements() <= count
+
+ // create new leaf node
+ node_pointer n = rtree::create_node<Allocators, leaf>::apply(allocators); // MAY THROW (A)
+ node_auto_ptr auto_remover(n, allocators);
+ leaf & l = rtree::get<leaf>(*n);
+
+ // reserve space for values
+ rtree::elements(l).reserve(values_count); // MAY THROW (A)
+ // calculate values box and copy values
+ Box elements_box;
+ geometry::assign_inverse(elements_box);
+ for ( ; first != last ; ++first )
+ {
+ rtree::elements(l).push_back(*(first->second)); // MAY THROW (A?,C)
+ geometry::expand(elements_box, translator(*(first->second)));
+ }
+
+ auto_remover.release();
+ return internal_element(elements_box, n);
+ }
+
+ // calculate next max and min subtree counts
+ subtree_elements_counts next_subtree_counts = subtree_counts;
+ next_subtree_counts.maxc /= parameters.get_max_elements();
+ next_subtree_counts.minc /= parameters.get_max_elements();
+
+ // create new internal node
+ node_pointer n = rtree::create_node<Allocators, internal_node>::apply(allocators); // MAY THROW (A)
+ node_auto_ptr auto_remover(n, allocators);
+ internal_node & in = rtree::get<internal_node>(*n);
+
+ // reserve space for values
+ std::size_t nodes_count = calculate_nodes_count(values_count, subtree_counts);
+ rtree::elements(in).reserve(nodes_count); // MAY THROW (A)
+ // calculate values box and copy values
+ Box elements_box;
+ geometry::assign_inverse(elements_box);
+
+ per_level_packets(first, last, hint_box, values_count, subtree_counts, next_subtree_counts,
+ rtree::elements(in), elements_box,
+ parameters, translator, allocators);
+
+ auto_remover.release();
+ return internal_element(elements_box, n);
+ }
+
+ template <typename EIt> inline static
+ void per_level_packets(EIt first, EIt last, Box const& hint_box,
+ std::size_t values_count,
+ subtree_elements_counts const& subtree_counts,
+ subtree_elements_counts const& next_subtree_counts,
+ internal_elements & elements, Box & elements_box,
+ parameters_type const& parameters, Translator const& translator, Allocators & allocators)
+ {
+ BOOST_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count);
+
+ BOOST_ASSERT_MSG( subtree_counts.minc <= values_count, "too small number of elements");
+
+ // only one packet
+ if ( values_count <= subtree_counts.maxc )
+ {
+ // the end, move to the next level
+ internal_element el = per_level(first, last, hint_box, values_count, next_subtree_counts,
+ parameters, translator, allocators);
+
+ // in case if push_back() do throw here
+ // and even if this is not probable (previously reserved memory, nonthrowing pairs copy)
+ // this case is also tested by exceptions test.
+ node_auto_ptr auto_remover(el.second, allocators);
+ // this container should have memory allocated, reserve() called outside
+ elements.push_back(el); // MAY THROW (A?,C) - however in normal conditions shouldn't
+ auto_remover.release();
+
+ geometry::expand(elements_box, el.first);
+ return;
+ }
+
+ std::size_t median_count = calculate_median_count(values_count, subtree_counts);
+ EIt median = first + median_count;
+
+ coordinate_type greatest_length;
+ std::size_t greatest_dim_index = 0;
+ pack_utils::biggest_edge<dimension>::apply(hint_box, greatest_length, greatest_dim_index);
+ Box left, right;
+ pack_utils::nth_element_and_half_boxes<0, dimension>
+ ::apply(first, median, last, hint_box, left, right, greatest_dim_index);
+
+ per_level_packets(first, median, left,
+ median_count, subtree_counts, next_subtree_counts,
+ elements, elements_box,
+ parameters, translator, allocators);
+ per_level_packets(median, last, right,
+ values_count - median_count, subtree_counts, next_subtree_counts,
+ elements, elements_box,
+ parameters, translator, allocators);
+ }
+
+ inline static
+ subtree_elements_counts calculate_subtree_elements_counts(std::size_t elements_count, parameters_type const& parameters, size_type & leafs_level)
+ {
+ boost::ignore_unused_variable_warning(parameters);
+
+ subtree_elements_counts res(1, 1);
+ leafs_level = 0;
+
+ std::size_t smax = parameters.get_max_elements();
+ for ( ; smax < elements_count ; smax *= parameters.get_max_elements(), ++leafs_level )
+ res.maxc = smax;
+
+ res.minc = parameters.get_min_elements() * (res.maxc / parameters.get_max_elements());
+
+ return res;
+ }
+
+ inline static
+ std::size_t calculate_nodes_count(std::size_t count,
+ subtree_elements_counts const& subtree_counts)
+ {
+ std::size_t n = count / subtree_counts.maxc;
+ std::size_t r = count % subtree_counts.maxc;
+
+ if ( 0 < r && r < subtree_counts.minc )
+ {
+ std::size_t count_minus_min = count - subtree_counts.minc;
+ n = count_minus_min / subtree_counts.maxc;
+ r = count_minus_min % subtree_counts.maxc;
+ ++n;
+ }
+
+ if ( 0 < r )
+ ++n;
+
+ return n;
+ }
+
+ inline static
+ std::size_t calculate_median_count(std::size_t count,
+ subtree_elements_counts const& subtree_counts)
+ {
+ // e.g. for max = 5, min = 2, count = 52, subtree_max = 25, subtree_min = 10
+
+ std::size_t n = count / subtree_counts.maxc; // e.g. 52 / 25 = 2
+ std::size_t r = count % subtree_counts.maxc; // e.g. 52 % 25 = 2
+ std::size_t median_count = (n / 2) * subtree_counts.maxc; // e.g. 2 / 2 * 25 = 25
+
+ if ( 0 != r ) // e.g. 0 != 2
+ {
+ if ( subtree_counts.minc <= r ) // e.g. 10 <= 2 == false
+ {
+ //BOOST_ASSERT_MSG(0 < n, "unexpected value");
+ median_count = ((n+1)/2) * subtree_counts.maxc; // if calculated ((2+1)/2) * 25 which would be ok, but not in all cases
+ }
+ else // r < subtree_counts.second // e.g. 2 < 10 == true
+ {
+ std::size_t count_minus_min = count - subtree_counts.minc; // e.g. 52 - 10 = 42
+ n = count_minus_min / subtree_counts.maxc; // e.g. 42 / 25 = 1
+ r = count_minus_min % subtree_counts.maxc; // e.g. 42 % 25 = 17
+ if ( r == 0 ) // e.g. false
+ {
+ // n can't be equal to 0 because then there wouldn't be any element in the other node
+ //BOOST_ASSERT_MSG(0 < n, "unexpected value");
+ median_count = ((n+1)/2) * subtree_counts.maxc; // if calculated ((1+1)/2) * 25 which would be ok, but not in all cases
+ }
+ else
+ {
+ if ( n == 0 ) // e.g. false
+ median_count = r; // if calculated -> 17 which is wrong!
+ else
+ median_count = ((n+2)/2) * subtree_counts.maxc; // e.g. ((1+2)/2) * 25 = 25
+ }
+ }
+ }
+
+ return median_count;
+ }
+};
+
+}}}}} // namespace boost::geometry::index::detail::rtree
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP
diff --git a/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp b/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp
new file mode 100644
index 0000000000..837ddbeecb
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp
@@ -0,0 +1,16 @@
+// Boost.Geometry Index
+//
+// R-tree quadratic algorithm implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP
+
+#include <boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp>
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP
diff --git a/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp
new file mode 100644
index 0000000000..634d879864
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp
@@ -0,0 +1,298 @@
+// Boost.Geometry Index
+//
+// R-tree quadratic split algorithm implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
+
+#include <algorithm>
+
+#include <boost/geometry/index/detail/algorithms/content.hpp>
+#include <boost/geometry/index/detail/algorithms/union_content.hpp>
+
+#include <boost/geometry/index/detail/bounded_view.hpp>
+
+#include <boost/geometry/index/detail/rtree/node/node.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+namespace quadratic {
+
+template <typename Box, typename Elements, typename Parameters, typename Translator>
+inline void pick_seeds(Elements const& elements,
+ Parameters const& parameters,
+ Translator const& tr,
+ size_t & seed1,
+ size_t & seed2)
+{
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+ typedef Box box_type;
+ typedef typename index::detail::default_content_result<box_type>::type content_type;
+ typedef index::detail::bounded_view<indexable_type, box_type> bounded_indexable_view;
+
+ const size_t elements_count = parameters.get_max_elements() + 1;
+ BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "wrong number of elements");
+ BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
+
+ content_type greatest_free_content = 0;
+ seed1 = 0;
+ seed2 = 1;
+
+ for ( size_t i = 0 ; i < elements_count - 1 ; ++i )
+ {
+ for ( size_t j = i + 1 ; j < elements_count ; ++j )
+ {
+ indexable_type const& ind1 = rtree::element_indexable(elements[i], tr);
+ indexable_type const& ind2 = rtree::element_indexable(elements[j], tr);
+
+ box_type enlarged_box;
+ //geometry::convert(ind1, enlarged_box);
+ detail::bounds(ind1, enlarged_box);
+ geometry::expand(enlarged_box, ind2);
+
+ bounded_indexable_view bounded_ind1(ind1);
+ bounded_indexable_view bounded_ind2(ind2);
+ content_type free_content = ( index::detail::content(enlarged_box)
+ - index::detail::content(bounded_ind1) )
+ - index::detail::content(bounded_ind2);
+
+ if ( greatest_free_content < free_content )
+ {
+ greatest_free_content = free_content;
+ seed1 = i;
+ seed2 = j;
+ }
+ }
+ }
+
+ ::boost::ignore_unused_variable_warning(parameters);
+}
+
+} // namespace quadratic
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadratic_tag>
+{
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Node>
+ static inline void apply(Node & n,
+ Node & second_node,
+ Box & box1,
+ Box & box2,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators)
+ {
+ typedef typename rtree::elements_type<Node>::type elements_type;
+ typedef typename elements_type::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+
+ elements_type & elements1 = rtree::elements(n);
+ elements_type & elements2 = rtree::elements(second_node);
+
+ BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == parameters.get_max_elements() + 1, "unexpected elements number");
+
+ // copy original elements - use in-memory storage (std::allocator)
+ // TODO: move if noexcept
+ typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
+ container_type;
+ container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
+ container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
+
+ // calculate initial seeds
+ size_t seed1 = 0;
+ size_t seed2 = 0;
+ quadratic::pick_seeds<Box>(elements_copy, parameters, translator, seed1, seed2);
+
+ // prepare nodes' elements containers
+ elements1.clear();
+ BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "second node's elements container should be empty");
+
+ BOOST_TRY
+ {
+ // add seeds
+ elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
+ elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
+
+ // calculate boxes
+ //geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
+ detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1);
+ //geometry::convert(rtree::element_indexable(elements_copy[seed2], translator), box2);
+ detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2);
+
+ // remove seeds
+ if (seed1 < seed2)
+ {
+ rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
+ elements_copy.pop_back();
+ rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
+ elements_copy.pop_back();
+ }
+ else
+ {
+ rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
+ elements_copy.pop_back();
+ rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
+ elements_copy.pop_back();
+ }
+
+ // initialize areas
+ content_type content1 = index::detail::content(box1);
+ content_type content2 = index::detail::content(box2);
+
+ size_t remaining = elements_copy.size();
+
+ // redistribute the rest of the elements
+ while ( !elements_copy.empty() )
+ {
+ typename container_type::reverse_iterator el_it = elements_copy.rbegin();
+ bool insert_into_group1 = false;
+
+ size_t elements1_count = elements1.size();
+ size_t elements2_count = elements2.size();
+
+ // if there is small number of elements left and the number of elements in node is lesser than min_elems
+ // just insert them to this node
+ if ( elements1_count + remaining <= parameters.get_min_elements() )
+ {
+ insert_into_group1 = true;
+ }
+ else if ( elements2_count + remaining <= parameters.get_min_elements() )
+ {
+ insert_into_group1 = false;
+ }
+ // insert the best element
+ else
+ {
+ // find element with minimum groups areas increses differences
+ content_type content_increase1 = 0;
+ content_type content_increase2 = 0;
+ el_it = pick_next(elements_copy.rbegin(), elements_copy.rend(),
+ box1, box2, content1, content2, translator,
+ content_increase1, content_increase2);
+
+ if ( content_increase1 < content_increase2 ||
+ ( content_increase1 == content_increase2 && ( content1 < content2 ||
+ ( content1 == content2 && elements1_count <= elements2_count ) )
+ ) )
+ {
+ insert_into_group1 = true;
+ }
+ else
+ {
+ insert_into_group1 = false;
+ }
+ }
+
+ // move element to the choosen group
+ element_type const& elem = *el_it;
+ indexable_type const& indexable = rtree::element_indexable(elem, translator);
+
+ if ( insert_into_group1 )
+ {
+ elements1.push_back(elem); // MAY THROW, STRONG (copy)
+ geometry::expand(box1, indexable);
+ content1 = index::detail::content(box1);
+ }
+ else
+ {
+ elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
+ geometry::expand(box2, indexable);
+ content2 = index::detail::content(box2);
+ }
+
+ BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements");
+ typename container_type::iterator el_it_base = el_it.base();
+ rtree::move_from_back(elements_copy, --el_it_base); // MAY THROW, STRONG (copy)
+ elements_copy.pop_back();
+
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
+ --remaining;
+ }
+ }
+ BOOST_CATCH(...)
+ {
+ //elements_copy.clear();
+ elements1.clear();
+ elements2.clear();
+
+ rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
+ //elements_backup.clear();
+
+ BOOST_RETHROW // RETHROW, BASIC
+ }
+ BOOST_CATCH_END
+ }
+
+ // TODO: awulkiew - change following function to static member of the pick_next class?
+
+ template <typename It>
+ static inline It pick_next(It first, It last,
+ Box const& box1, Box const& box2,
+ content_type const& content1, content_type const& content2,
+ Translator const& translator,
+ content_type & out_content_increase1, content_type & out_content_increase2)
+ {
+ typedef typename boost::iterator_value<It>::type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+
+ content_type greatest_content_incrase_diff = 0;
+ It out_it = first;
+ out_content_increase1 = 0;
+ out_content_increase2 = 0;
+
+ // find element with greatest difference between increased group's boxes areas
+ for ( It el_it = first ; el_it != last ; ++el_it )
+ {
+ indexable_type const& indexable = rtree::element_indexable(*el_it, translator);
+
+ // calculate enlarged boxes and areas
+ Box enlarged_box1(box1);
+ Box enlarged_box2(box2);
+ geometry::expand(enlarged_box1, indexable);
+ geometry::expand(enlarged_box2, indexable);
+ content_type enlarged_content1 = index::detail::content(enlarged_box1);
+ content_type enlarged_content2 = index::detail::content(enlarged_box2);
+
+ content_type content_incrase1 = (enlarged_content1 - content1);
+ content_type content_incrase2 = (enlarged_content2 - content2);
+
+ content_type content_incrase_diff = content_incrase1 < content_incrase2 ?
+ content_incrase2 - content_incrase1 : content_incrase1 - content_incrase2;
+
+ if ( greatest_content_incrase_diff < content_incrase_diff )
+ {
+ greatest_content_incrase_diff = content_incrase_diff;
+ out_it = el_it;
+ out_content_increase1 = content_incrase1;
+ out_content_increase2 = content_incrase2;
+ }
+ }
+
+ return out_it;
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
diff --git a/boost/geometry/index/detail/rtree/query_iterators.hpp b/boost/geometry/index/detail/rtree/query_iterators.hpp
new file mode 100644
index 0000000000..8366fca191
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/query_iterators.hpp
@@ -0,0 +1,599 @@
+// Boost.Geometry Index
+//
+// R-tree query iterators
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP
+
+#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_VIRTUAL
+//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_FUNCTION
+//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_TYPE_ERASURE
+//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
+
+template <typename Value, typename Allocators>
+struct end_query_iterator
+{
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ reference operator*() const
+ {
+ BOOST_ASSERT_MSG(false, "iterator not dereferencable");
+ pointer p(0);
+ return *p;
+ }
+
+ const value_type * operator->() const
+ {
+ BOOST_ASSERT_MSG(false, "iterator not dereferencable");
+ const value_type * p = 0;
+ return p;
+ }
+
+ end_query_iterator & operator++()
+ {
+ BOOST_ASSERT_MSG(false, "iterator not incrementable");
+ return *this;
+ }
+
+ end_query_iterator operator++(int)
+ {
+ BOOST_ASSERT_MSG(false, "iterator not incrementable");
+ return *this;
+ }
+
+ friend bool operator==(end_query_iterator const& /*l*/, end_query_iterator const& /*r*/)
+ {
+ return true;
+ }
+};
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates>
+class spatial_query_iterator
+{
+ typedef visitors::spatial_query_incremental<Value, Options, Translator, Box, Allocators, Predicates> visitor_type;
+ typedef typename visitor_type::node_pointer node_pointer;
+
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ inline spatial_query_iterator(Translator const& t, Predicates const& p)
+ : m_visitor(t, p)
+ {}
+
+ inline spatial_query_iterator(node_pointer root, Translator const& t, Predicates const& p)
+ : m_visitor(t, p)
+ {
+ m_visitor.initialize(root);
+ }
+
+ reference operator*() const
+ {
+ return m_visitor.dereference();
+ }
+
+ const value_type * operator->() const
+ {
+ return boost::addressof(m_visitor.dereference());
+ }
+
+ spatial_query_iterator & operator++()
+ {
+ m_visitor.increment();
+ return *this;
+ }
+
+ spatial_query_iterator operator++(int)
+ {
+ spatial_query_iterator temp = *this;
+ this->operator++();
+ return temp;
+ }
+
+ friend bool operator==(spatial_query_iterator const& l, spatial_query_iterator const& r)
+ {
+ return l.m_visitor == r.m_visitor;
+ }
+
+ friend bool operator==(spatial_query_iterator const& l, end_query_iterator<Value, Allocators> const& /*r*/)
+ {
+ return l.m_visitor.is_end();
+ }
+
+ friend bool operator==(end_query_iterator<Value, Allocators> const& /*l*/, spatial_query_iterator const& r)
+ {
+ return r.m_visitor.is_end();
+ }
+
+private:
+ visitor_type m_visitor;
+};
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates, unsigned NearestPredicateIndex>
+class distance_query_iterator
+{
+ typedef visitors::distance_query_incremental<Value, Options, Translator, Box, Allocators, Predicates, NearestPredicateIndex> visitor_type;
+ typedef typename visitor_type::node_pointer node_pointer;
+
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ inline distance_query_iterator(Translator const& t, Predicates const& p)
+ : m_visitor(t, p)
+ {}
+
+ inline distance_query_iterator(node_pointer root, Translator const& t, Predicates const& p)
+ : m_visitor(t, p)
+ {
+ m_visitor.initialize(root);
+ }
+
+ reference operator*() const
+ {
+ return m_visitor.dereference();
+ }
+
+ const value_type * operator->() const
+ {
+ return boost::addressof(m_visitor.dereference());
+ }
+
+ distance_query_iterator & operator++()
+ {
+ m_visitor.increment();
+ return *this;
+ }
+
+ distance_query_iterator operator++(int)
+ {
+ distance_query_iterator temp = *this;
+ this->operator++();
+ return temp;
+ }
+
+ friend bool operator==(distance_query_iterator const& l, distance_query_iterator const& r)
+ {
+ return l.m_visitor == r.m_visitor;
+ }
+
+ friend bool operator==(distance_query_iterator const& l, end_query_iterator<Value, Allocators> const& /*r*/)
+ {
+ return l.m_visitor.is_end();
+ }
+
+ friend bool operator==(end_query_iterator<Value, Allocators> const& /*l*/, distance_query_iterator const& r)
+ {
+ return r.m_visitor.is_end();
+ }
+
+private:
+ visitor_type m_visitor;
+};
+
+template <typename L, typename R>
+inline bool operator!=(L const& l, R const& r)
+{
+ return !(l == r);
+}
+
+}}}}}} // namespace boost::geometry::index::detail::rtree::iterators
+
+#if defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_VIRTUAL) || defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_FUNCTION)
+
+#if defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_VIRTUAL)
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
+
+template <typename Value, typename Allocators>
+class query_iterator_base
+{
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ virtual ~query_iterator_base() {}
+
+ virtual query_iterator_base * clone() const = 0;
+
+ virtual bool is_end() const = 0;
+ virtual reference dereference() const = 0;
+ virtual void increment() = 0;
+ virtual bool equals(query_iterator_base const&) const = 0;
+};
+
+template <typename Value, typename Allocators, typename Iterator>
+class query_iterator_wrapper
+ : public query_iterator_base<Value, Allocators>
+{
+ typedef query_iterator_base<Value, Allocators> base_t;
+
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ explicit query_iterator_wrapper(Iterator const& it) : m_iterator(it) {}
+
+ virtual base_t * clone() const { return new query_iterator_wrapper(m_iterator); }
+
+ virtual bool is_end() const { return m_iterator == end_query_iterator<Value, Allocators>(); }
+ virtual reference dereference() const { return *m_iterator; }
+ virtual void increment() { ++m_iterator; }
+ virtual bool equals(base_t const& r) const
+ {
+ const query_iterator_wrapper * p = dynamic_cast<const query_iterator_wrapper *>(boost::addressof(r));
+ BOOST_ASSERT_MSG(p, "those iterators can't be compared");
+ return m_iterator == p->m_iterator;
+ }
+
+private:
+ Iterator m_iterator;
+};
+
+#elif defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_FUNCTION)
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
+
+template <typename Value, typename Allocators>
+class query_iterator_base
+{
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ virtual ~query_iterator_base() {}
+
+ boost::function<query_iterator_base*()> clone;
+ boost::function<bool()> is_end;
+ boost::function<reference()> dereference;
+ boost::function<void()> increment;
+ boost::function<bool(query_iterator_base const&)> equals;
+};
+
+template <typename Value, typename Allocators, typename Iterator>
+class query_iterator_wrapper
+ : public query_iterator_base<Value, Allocators>
+{
+ typedef query_iterator_base<Value, Allocators> base_t;
+
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ explicit query_iterator_wrapper(Iterator const& it)
+ : m_iterator(it)
+ {
+ base_t::clone = boost::bind(&query_iterator_wrapper::clone_, this);
+ base_t::is_end = boost::bind(&query_iterator_wrapper::is_end_, this);
+ base_t::dereference = boost::bind(&query_iterator_wrapper::dereference_, this);
+ base_t::increment = boost::bind(&query_iterator_wrapper::increment_, this);
+ base_t::equals = boost::bind(&query_iterator_wrapper::equals_, this, _1);
+ }
+
+private:
+ base_t * clone_() const { return new query_iterator_wrapper(m_iterator); }
+
+ bool is_end_() const { return m_iterator == end_query_iterator<Value, Allocators>(); }
+ reference dereference_() const { return *m_iterator; }
+ void increment_() { ++m_iterator; }
+ bool equals_(base_t const& r) const
+ {
+ const query_iterator_wrapper * p = dynamic_cast<const query_iterator_wrapper *>(boost::addressof(r));
+ BOOST_ASSERT_MSG(p, "those iterators can't be compared");
+ return m_iterator == p->m_iterator;
+ }
+
+private:
+ Iterator m_iterator;
+};
+
+#endif
+
+template <typename Value, typename Allocators>
+class query_iterator
+{
+ typedef query_iterator_base<Value, Allocators> iterator_base;
+ typedef std::auto_ptr<iterator_base> iterator_ptr;
+
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+ query_iterator() {}
+
+ template <typename It>
+ query_iterator(It const& it)
+ : m_ptr(static_cast<iterator_base*>(
+ new query_iterator_wrapper<Value, Allocators, It>(it) ))
+ {}
+
+ query_iterator(end_query_iterator<Value, Allocators> const& /*it*/)
+ {}
+
+ query_iterator(query_iterator const& o)
+ : m_ptr(o.m_ptr.get() ? o.m_ptr->clone() : 0)
+ {}
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
+ query_iterator & operator=(query_iterator const& o)
+ {
+ m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0);
+ return *this;
+ }
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ query_iterator(query_iterator && o)
+ : m_ptr(o.m_ptr.get())
+ {
+ o.m_ptr.release();
+ }
+ query_iterator & operator=(query_iterator && o)
+ {
+ if ( this != boost::addressof(o) )
+ {
+ m_ptr.reset(o.m_ptr.get());
+ o.m_ptr.release();
+ }
+ return *this;
+ }
+#endif
+#else // !BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
+private:
+ BOOST_COPYABLE_AND_MOVABLE(query_iterator)
+public:
+ query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o)
+ {
+ m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0);
+ return *this;
+ }
+ query_iterator(BOOST_RV_REF(query_iterator) o)
+ : m_ptr(o.m_ptr.get())
+ {
+ o.m_ptr.release();
+ }
+ query_iterator & operator=(BOOST_RV_REF(query_iterator) o)
+ {
+ if ( this != boost::addressof(o) )
+ {
+ m_ptr.reset(o.m_ptr.get());
+ o.m_ptr.release();
+ }
+ return *this;
+ }
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
+
+ reference operator*() const
+ {
+ return m_ptr->dereference();
+ }
+
+ const value_type * operator->() const
+ {
+ return boost::addressof(m_ptr->dereference());
+ }
+
+ query_iterator & operator++()
+ {
+ m_ptr->increment();
+ return *this;
+ }
+
+ query_iterator operator++(int)
+ {
+ query_iterator temp = *this;
+ this->operator++();
+ return temp;
+ }
+
+ friend bool operator==(query_iterator const& l, query_iterator const& r)
+ {
+ if ( l.m_ptr.get() )
+ {
+ if ( r.m_ptr.get() )
+ return l.m_ptr->equals(*r.m_ptr);
+ else
+ return l.m_ptr->is_end();
+ }
+ else
+ {
+ if ( r.m_ptr.get() )
+ return r.m_ptr->is_end();
+ else
+ return true;
+ }
+ }
+
+private:
+ iterator_ptr m_ptr;
+};
+
+}}}}}} // namespace boost::geometry::index::detail::rtree::iterators
+
+#elif defined(BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_TYPE_ERASURE)
+
+#include <boost/type_erasure/any.hpp>
+#include <boost/type_erasure/operators.hpp>
+#include <boost/type_erasure/is_empty.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
+
+template<typename T, typename Value, typename Allocators>
+struct single_pass_iterator_concept :
+ ::boost::mpl::vector<
+ ::boost::type_erasure::copy_constructible<T>,
+ ::boost::type_erasure::equality_comparable<T>,
+ ::boost::type_erasure::dereferenceable<typename Allocators::const_reference, T>,
+ ::boost::type_erasure::assignable<T>,
+ ::boost::type_erasure::incrementable<T>,
+ ::boost::type_erasure::equality_comparable<T, end_query_iterator<Value, Allocators> >,
+ ::boost::type_erasure::relaxed // default ctor
+ >
+{};
+
+template <typename Value, typename Allocators>
+struct single_pass_iterator_type
+{
+ typedef ::boost::type_erasure::any<
+ single_pass_iterator_concept<
+ ::boost::type_erasure::_self, Value, Allocators
+ >
+ > type;
+};
+
+}}}}}} // namespace boost::geometry::index::detail::rtree::iterators
+
+namespace boost { namespace type_erasure {
+
+template<typename T, typename Value, typename Allocators, typename Base>
+struct concept_interface<
+ ::boost::geometry::index::detail::rtree::single_pass_iterator_concept<
+ T, Value, Allocators
+ >, Base, T>
+ : Base
+{
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::const_pointer pointer;
+ typedef typename Allocators::difference_type difference_type;
+ typedef ::std::input_iterator_tag iterator_category;
+};
+
+}} // boost::type_erasure
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
+
+template <typename Value, typename Allocators>
+class query_iterator
+{
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename Allocators::const_reference reference;
+ typedef typename Allocators::difference_type difference_type;
+ typedef typename Allocators::const_pointer pointer;
+
+private:
+ typedef typename rtree::single_pass_iterator_type<Value, Allocators>::type iterator_type;
+
+public:
+
+ query_iterator() {}
+
+ template <typename It>
+ query_iterator(It const& it)
+ : m_iterator(it)
+ {}
+
+ query_iterator(end_query_iterator<Value, Allocators> const& /*it*/)
+ {}
+
+#ifdef BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
+private:
+ BOOST_COPYABLE_AND_MOVABLE(query_iterator)
+public:
+ query_iterator(query_iterator const& o)
+ : m_iterator(o.m_iterator)
+ {}
+ query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o)
+ {
+ m_iterator = o.m_iterator;
+ return *this;
+ }
+ query_iterator(BOOST_RV_REF(query_iterator) o)
+ : m_iterator(boost::move(o.m_iterator))
+ {}
+ query_iterator & operator=(BOOST_RV_REF(query_iterator) o)
+ {
+ if ( this != boost::addressof(o) )
+ {
+ m_iterator = boost::move(o.m_iterator);
+ }
+ return *this;
+ }
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
+
+ reference operator*() const
+ {
+ return *m_iterator;
+ }
+
+ const value_type * operator->() const
+ {
+ return boost::addressof(*m_iterator);
+ }
+
+ query_iterator & operator++()
+ {
+ ++m_iterator;
+ return *this;
+ }
+
+ query_iterator operator++(int)
+ {
+ query_iterator temp = *this;
+ ++m_iterator;
+ return temp;
+ }
+
+ friend bool operator==(query_iterator const& l, query_iterator const& r)
+ {
+ if ( !::boost::type_erasure::is_empty(l.m_iterator) )
+ {
+ if ( !::boost::type_erasure::is_empty(r.m_iterator) )
+ return l.m_iterator == r.m_iterator;
+ else
+ return l.m_iterator == end_query_iterator<Value, Allocators>();
+ }
+ else
+ {
+ if ( !::boost::type_erasure::is_empty(r.m_iterator) )
+ return r.m_iterator == end_query_iterator<Value, Allocators>();
+ else
+ return true;
+ }
+ }
+
+private:
+ iterator_type m_iterator;
+};
+
+}}}}}} // namespace boost::geometry::index::detail::rtree::iterators
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_TYPE_ERASURE
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP
diff --git a/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp b/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp
new file mode 100644
index 0000000000..7a96986a27
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp
@@ -0,0 +1,233 @@
+// Boost.Geometry Index
+//
+// R-tree R*-tree next node choosing algorithm implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
+
+#include <algorithm>
+
+#include <boost/geometry/algorithms/expand.hpp>
+
+#include <boost/geometry/index/detail/algorithms/content.hpp>
+#include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
+#include <boost/geometry/index/detail/algorithms/union_content.hpp>
+
+#include <boost/geometry/index/detail/rtree/node/node.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+template <typename Value, typename Options, typename Box, typename Allocators>
+class choose_next_node<Value, Options, Box, Allocators, choose_by_overlap_diff_tag>
+{
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename rtree::elements_type<internal_node>::type children_type;
+ typedef typename children_type::value_type child_type;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+public:
+ template <typename Indexable>
+ static inline size_t apply(internal_node & n,
+ Indexable const& indexable,
+ parameters_type const& parameters,
+ size_t node_relative_level)
+ {
+ ::boost::ignore_unused_variable_warning(parameters);
+
+ children_type & children = rtree::elements(n);
+
+ // children are leafs
+ if ( node_relative_level <= 1 )
+ {
+ return choose_by_minimum_overlap_cost(children, indexable, parameters.get_overlap_cost_threshold());
+ }
+ // children are internal nodes
+ else
+ return choose_by_minimum_content_cost(children, indexable);
+ }
+
+private:
+ template <typename Indexable>
+ static inline size_t choose_by_minimum_overlap_cost(children_type const& children,
+ Indexable const& indexable,
+ size_t overlap_cost_threshold)
+ {
+ const size_t children_count = children.size();
+
+ content_type min_content_diff = (std::numeric_limits<content_type>::max)();
+ content_type min_content = (std::numeric_limits<content_type>::max)();
+ size_t choosen_index = 0;
+
+ // create container of children sorted by content enlargement needed to include the new value
+ typedef boost::tuple<size_t, content_type, content_type> child_contents;
+
+ typename rtree::container_from_elements_type<children_type, child_contents>::type children_contents;
+ children_contents.resize(children_count);
+
+ for ( size_t i = 0 ; i < children_count ; ++i )
+ {
+ child_type const& ch_i = children[i];
+
+ // expanded child node's box
+ Box box_exp(ch_i.first);
+ geometry::expand(box_exp, indexable);
+
+ // areas difference
+ content_type content = index::detail::content(box_exp);
+ content_type content_diff = content - index::detail::content(ch_i.first);
+
+ children_contents[i] = boost::make_tuple(i, content_diff, content);
+
+ if ( content_diff < min_content_diff ||
+ (content_diff == min_content_diff && content < min_content) )
+ {
+ min_content_diff = content_diff;
+ min_content = content;
+ choosen_index = i;
+ }
+ }
+
+ // is this assumption ok? if min_content_diff == 0 there is no overlap increase?
+
+ if ( min_content_diff < -std::numeric_limits<double>::epsilon() || std::numeric_limits<double>::epsilon() < min_content_diff )
+ {
+ size_t first_n_children_count = children_count;
+ if ( 0 < overlap_cost_threshold && overlap_cost_threshold < children.size() )
+ {
+ first_n_children_count = overlap_cost_threshold;
+ // rearrange by content_diff
+ // in order to calculate nearly minimum overlap cost
+ std::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less);
+ }
+
+ // calculate minimum or nearly minimum overlap cost
+ choosen_index = choose_by_minimum_overlap_cost_first_n(children, indexable, first_n_children_count, children_count, children_contents);
+ }
+
+ return choosen_index;
+ }
+
+ static inline bool content_diff_less(boost::tuple<size_t, content_type, content_type> const& p1, boost::tuple<size_t, content_type, content_type> const& p2)
+ {
+ return boost::get<1>(p1) < boost::get<1>(p2) ||
+ (boost::get<1>(p1) == boost::get<1>(p2) && boost::get<2>(p1) < boost::get<2>(p2));
+ }
+
+ template <typename Indexable, typename ChildrenContents>
+ static inline size_t choose_by_minimum_overlap_cost_first_n(children_type const& children,
+ Indexable const& indexable,
+ size_t const first_n_children_count,
+ size_t const children_count,
+ ChildrenContents const& children_contents)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(first_n_children_count <= children_count, "unexpected value");
+ BOOST_GEOMETRY_INDEX_ASSERT(children_contents.size() == children_count, "unexpected number of elements");
+
+ // choose index with smallest overlap change value, or content change or smallest content
+ size_t choosen_index = 0;
+ content_type smallest_overlap_diff = (std::numeric_limits<content_type>::max)();
+ content_type smallest_content_diff = (std::numeric_limits<content_type>::max)();
+ content_type smallest_content = (std::numeric_limits<content_type>::max)();
+
+ // for each child node
+ for (size_t i = 0 ; i < first_n_children_count ; ++i )
+ {
+ child_type const& ch_i = children[i];
+
+ Box box_exp(ch_i.first);
+ // calculate expanded box of child node ch_i
+ geometry::expand(box_exp, indexable);
+
+ content_type overlap_diff = 0;
+
+ // calculate overlap
+ for ( size_t j = 0 ; j < children_count ; ++j )
+ {
+ if ( i != j )
+ {
+ child_type const& ch_j = children[j];
+
+ content_type overlap_exp = index::detail::intersection_content(box_exp, ch_j.first);
+ if ( overlap_exp < -std::numeric_limits<content_type>::epsilon() || std::numeric_limits<content_type>::epsilon() < overlap_exp )
+ {
+ overlap_diff += overlap_exp - index::detail::intersection_content(ch_i.first, ch_j.first);
+ }
+ }
+ }
+
+ content_type content = boost::get<2>(children_contents[i]);
+ content_type content_diff = boost::get<1>(children_contents[i]);
+
+ // update result
+ if ( overlap_diff < smallest_overlap_diff ||
+ ( overlap_diff == smallest_overlap_diff && ( content_diff < smallest_content_diff ||
+ ( content_diff == smallest_content_diff && content < smallest_content ) )
+ ) )
+ {
+ smallest_overlap_diff = overlap_diff;
+ smallest_content_diff = content_diff;
+ smallest_content = content;
+ choosen_index = i;
+ }
+ }
+
+ return choosen_index;
+ }
+
+ template <typename Indexable>
+ static inline size_t choose_by_minimum_content_cost(children_type const& children, Indexable const& indexable)
+ {
+ size_t children_count = children.size();
+
+ // choose index with smallest content change or smallest content
+ size_t choosen_index = 0;
+ content_type smallest_content_diff = (std::numeric_limits<content_type>::max)();
+ content_type smallest_content = (std::numeric_limits<content_type>::max)();
+
+ // choose the child which requires smallest box expansion to store the indexable
+ for ( size_t i = 0 ; i < children_count ; ++i )
+ {
+ child_type const& ch_i = children[i];
+
+ // expanded child node's box
+ Box box_exp(ch_i.first);
+ geometry::expand(box_exp, indexable);
+
+ // areas difference
+ content_type content = index::detail::content(box_exp);
+ content_type content_diff = content - index::detail::content(ch_i.first);
+
+ // update the result
+ if ( content_diff < smallest_content_diff ||
+ ( content_diff == smallest_content_diff && content < smallest_content ) )
+ {
+ smallest_content_diff = content_diff;
+ smallest_content = content;
+ choosen_index = i;
+ }
+ }
+
+ return choosen_index;
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
diff --git a/boost/geometry/index/detail/rtree/rstar/insert.hpp b/boost/geometry/index/detail/rtree/rstar/insert.hpp
new file mode 100644
index 0000000000..e544d6dd1e
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/rstar/insert.hpp
@@ -0,0 +1,577 @@
+// Boost.Geometry Index
+//
+// R-tree R*-tree insert algorithm implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
+
+#include <boost/geometry/index/detail/algorithms/content.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+namespace rstar {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class remove_elements_to_reinsert
+{
+public:
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ //typedef typename Allocators::internal_node_pointer internal_node_pointer;
+ typedef internal_node * internal_node_pointer;
+
+ template <typename ResultElements, typename Node>
+ static inline void apply(ResultElements & result_elements,
+ Node & n,
+ internal_node_pointer parent,
+ size_t current_child_index,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators)
+ {
+ typedef typename rtree::elements_type<Node>::type elements_type;
+ typedef typename elements_type::value_type element_type;
+ typedef typename geometry::point_type<Box>::type point_type;
+ // TODO: awulkiew - change second point_type to the point type of the Indexable?
+ typedef typename
+ geometry::default_comparable_distance_result<point_type>::type
+ comparable_distance_type;
+
+ elements_type & elements = rtree::elements(n);
+
+ const size_t elements_count = parameters.get_max_elements() + 1;
+ const size_t reinserted_elements_count = (::std::min)(parameters.get_reinserted_elements(), elements_count - parameters.get_min_elements());
+
+ BOOST_GEOMETRY_INDEX_ASSERT(parent, "node shouldn't be the root node");
+ BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected elements number");
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < reinserted_elements_count, "wrong value of elements to reinsert");
+
+ // calculate current node's center
+ point_type node_center;
+ geometry::centroid(rtree::elements(*parent)[current_child_index].first, node_center);
+
+ // fill the container of centers' distances of children from current node's center
+ typedef typename index::detail::rtree::container_from_elements_type<
+ elements_type,
+ std::pair<comparable_distance_type, element_type>
+ >::type sorted_elements_type;
+
+ sorted_elements_type sorted_elements;
+ // If constructor is used instead of resize() MS implementation leaks here
+ sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
+
+ for ( typename elements_type::const_iterator it = elements.begin() ;
+ it != elements.end() ; ++it )
+ {
+ point_type element_center;
+ geometry::centroid( rtree::element_indexable(*it, translator), element_center);
+ sorted_elements.push_back(std::make_pair(
+ geometry::comparable_distance(node_center, element_center),
+ *it)); // MAY THROW (V, E: copy)
+ }
+
+ // sort elements by distances from center
+ std::partial_sort(
+ sorted_elements.begin(),
+ sorted_elements.begin() + reinserted_elements_count,
+ sorted_elements.end(),
+ distances_dsc<comparable_distance_type, element_type>); // MAY THROW, BASIC (V, E: copy)
+
+ // copy elements which will be reinserted
+ result_elements.clear();
+ result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
+ for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ;
+ it != sorted_elements.begin() + reinserted_elements_count ; ++it )
+ {
+ result_elements.push_back(it->second); // MAY THROW (V, E: copy)
+ }
+
+ BOOST_TRY
+ {
+ // copy remaining elements to the current node
+ elements.clear();
+ elements.reserve(elements_count - reinserted_elements_count); // SHOULDN'T THROW (new_size <= old size)
+ for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() + reinserted_elements_count;
+ it != sorted_elements.end() ; ++it )
+ {
+ elements.push_back(it->second); // MAY THROW (V, E: copy)
+ }
+ }
+ BOOST_CATCH(...)
+ {
+ elements.clear();
+
+ for ( typename sorted_elements_type::iterator it = sorted_elements.begin() ;
+ it != sorted_elements.end() ; ++it )
+ {
+ destroy_element<Value, Options, Translator, Box, Allocators>::apply(it->second, allocators);
+ }
+
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+
+ ::boost::ignore_unused_variable_warning(parameters);
+ }
+
+private:
+ template <typename Distance, typename El>
+ static inline bool distances_asc(
+ std::pair<Distance, El> const& d1,
+ std::pair<Distance, El> const& d2)
+ {
+ return d1.first < d2.first;
+ }
+
+ template <typename Distance, typename El>
+ static inline bool distances_dsc(
+ std::pair<Distance, El> const& d1,
+ std::pair<Distance, El> const& d2)
+ {
+ return d1.first > d2.first;
+ }
+};
+
+template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Box, typename Allocators>
+struct level_insert_elements_type
+{
+ typedef typename rtree::elements_type<
+ typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type
+ >::type type;
+};
+
+template <typename Value, typename Options, typename Box, typename Allocators>
+struct level_insert_elements_type<0, Value, Value, Options, Box, Allocators>
+{
+ typedef typename rtree::elements_type<
+ typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type
+ >::type type;
+};
+
+template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct level_insert_base
+ : public detail::insert<Element, Value, Options, Translator, Box, Allocators>
+{
+ typedef detail::insert<Element, Value, Options, Translator, Box, Allocators> base;
+ typedef typename base::node node;
+ typedef typename base::internal_node internal_node;
+ typedef typename base::leaf leaf;
+
+ typedef typename level_insert_elements_type<InsertIndex, Element, Value, Options, Box, Allocators>::type elements_type;
+ typedef typename index::detail::rtree::container_from_elements_type<
+ elements_type,
+ typename elements_type::value_type
+ >::type result_elements_type;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef typename Allocators::size_type size_type;
+
+ inline level_insert_base(node_pointer & root,
+ size_type & leafs_level,
+ Element const& element,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level)
+ : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
+ , result_relative_level(0)
+ {}
+
+ template <typename Node>
+ inline void handle_possible_reinsert_or_split_of_root(Node &n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(result_elements.empty(), "reinsert should be handled only once for level");
+
+ result_relative_level = base::m_leafs_level - base::m_traverse_data.current_level;
+
+ // overflow
+ if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
+ {
+ // node isn't root node
+ if ( !base::m_traverse_data.current_is_root() )
+ {
+ // NOTE: exception-safety
+ // After an exception result_elements may contain garbage, don't use it
+ rstar::remove_elements_to_reinsert<Value, Options, Translator, Box, Allocators>::apply(
+ result_elements, n,
+ base::m_traverse_data.parent, base::m_traverse_data.current_child_index,
+ base::m_parameters, base::m_translator, base::m_allocators); // MAY THROW, BASIC (V, E: alloc, copy)
+ }
+ // node is root node
+ else
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*base::m_root_node), "node should be the root node");
+ base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
+ }
+ }
+ }
+
+ template <typename Node>
+ inline void handle_possible_split(Node &n) const
+ {
+ // overflow
+ if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
+ {
+ base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
+ }
+ }
+
+ template <typename Node>
+ inline void recalculate_aabb_if_necessary(Node &n) const
+ {
+ if ( !result_elements.empty() && !base::m_traverse_data.current_is_root() )
+ {
+ // calulate node's new box
+ base::m_traverse_data.current_element().first =
+ elements_box<Box>(rtree::elements(n).begin(), rtree::elements(n).end(), base::m_translator);
+ }
+ }
+
+ size_type result_relative_level;
+ result_elements_type result_elements;
+};
+
+template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct level_insert
+ : public level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators>
+{
+ typedef level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators> base;
+ typedef typename base::node node;
+ typedef typename base::internal_node internal_node;
+ typedef typename base::leaf leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef typename Allocators::size_type size_type;
+
+ inline level_insert(node_pointer & root,
+ size_type & leafs_level,
+ Element const& element,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level)
+ : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
+ {}
+
+ inline void operator()(internal_node & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
+
+ if ( base::m_traverse_data.current_level < base::m_level )
+ {
+ // next traversing step
+ base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc)
+
+ // further insert
+ if ( 0 < InsertIndex )
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
+
+ if ( base::m_traverse_data.current_level == base::m_level - 1 )
+ {
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
+ }
+ }
+ }
+ else
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level");
+
+ BOOST_TRY
+ {
+ // push new child node
+ rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy)
+ }
+ BOOST_CATCH(...)
+ {
+ // NOTE: exception-safety
+ // if the insert fails above, the element won't be stored in the tree, so delete it
+
+ rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(base::m_element.second, base::m_allocators);
+ rtree::apply_visitor(del_v, *base::m_element.second);
+
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+
+ // first insert
+ if ( 0 == InsertIndex )
+ {
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
+ }
+ // not the first insert
+ else
+ {
+ base::handle_possible_split(n); // MAY THROW (E: alloc, N: alloc)
+ }
+ }
+
+ base::recalculate_aabb_if_necessary(n);
+ }
+
+ inline void operator()(leaf &)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf");
+ }
+};
+
+template <size_t InsertIndex, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct level_insert<InsertIndex, Value, Value, Options, Translator, Box, Allocators>
+ : public level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators>
+{
+ typedef level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators> base;
+ typedef typename base::node node;
+ typedef typename base::internal_node internal_node;
+ typedef typename base::leaf leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef typename Allocators::size_type size_type;
+
+ inline level_insert(node_pointer & root,
+ size_type & leafs_level,
+ Value const& v,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level)
+ : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
+ {}
+
+ inline void operator()(internal_node & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
+
+ // next traversing step
+ base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
+
+ if ( base::m_traverse_data.current_level == base::m_level - 1 )
+ {
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
+ }
+
+ base::recalculate_aabb_if_necessary(n);
+ }
+
+ inline void operator()(leaf & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
+ "unexpected level");
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
+ base::m_level == (std::numeric_limits<size_t>::max)(),
+ "unexpected level");
+
+ rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
+
+ base::handle_possible_split(n); // MAY THROW (V: alloc, copy, N: alloc)
+ }
+};
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct level_insert<0, Value, Value, Options, Translator, Box, Allocators>
+ : public level_insert_base<0, Value, Value, Options, Translator, Box, Allocators>
+{
+ typedef level_insert_base<0, Value, Value, Options, Translator, Box, Allocators> base;
+ typedef typename base::node node;
+ typedef typename base::internal_node internal_node;
+ typedef typename base::leaf leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef typename Allocators::size_type size_type;
+
+ inline level_insert(node_pointer & root,
+ size_type & leafs_level,
+ Value const& v,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level)
+ : base(root, leafs_level, v, parameters, translator, allocators, relative_level)
+ {}
+
+ inline void operator()(internal_node & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level,
+ "unexpected level");
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level,
+ "unexpected level");
+
+ // next traversing step
+ base::traverse(*this, n); // MAY THROW (V: alloc, copy, N: alloc)
+
+ base::recalculate_aabb_if_necessary(n);
+ }
+
+ inline void operator()(leaf & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
+ "unexpected level");
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
+ base::m_level == (std::numeric_limits<size_t>::max)(),
+ "unexpected level");
+
+ rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
+
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (V: alloc, copy, N: alloc)
+
+ base::recalculate_aabb_if_necessary(n);
+ }
+};
+
+} // namespace rstar
+
+// R*-tree insert visitor
+// After passing the Element to insert visitor the Element is managed by the tree
+// I.e. one should not delete the node passed to the insert visitor after exception is thrown
+// because this visitor may delete it
+template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class insert<Element, Value, Options, Translator, Box, Allocators, insert_reinsert_tag>
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
+{
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef typename Allocators::size_type size_type;
+
+public:
+ inline insert(node_pointer & root,
+ size_type & leafs_level,
+ Element const& element,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level = 0)
+ : m_root(root), m_leafs_level(leafs_level), m_element(element)
+ , m_parameters(parameters), m_translator(translator)
+ , m_relative_level(relative_level), m_allocators(allocators)
+ {}
+
+ inline void operator()(internal_node & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n))
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root), "current node should be the root");
+
+ // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
+ if ( m_parameters.get_reinserted_elements() > 0 )
+ {
+ rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v(
+ m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
+
+ rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ if ( !lins_v.result_elements.empty() )
+ {
+ recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
+ }
+ }
+ else
+ {
+ visitors::insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag> ins_v(
+ m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
+
+ rtree::apply_visitor(ins_v, *m_root);
+ }
+ }
+
+ inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n))
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<leaf>(*m_root), "current node should be the root");
+
+ // Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
+ if ( m_parameters.get_reinserted_elements() > 0 )
+ {
+ rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v(
+ m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
+
+ rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ // we're in the root, so root should be split and there should be no elements to reinsert
+ BOOST_GEOMETRY_INDEX_ASSERT(lins_v.result_elements.empty(), "unexpected state");
+ }
+ else
+ {
+ visitors::insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag> ins_v(
+ m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
+
+ rtree::apply_visitor(ins_v, *m_root);
+ }
+ }
+
+private:
+ template <typename Elements>
+ inline void recursive_reinsert(Elements & elements, size_t relative_level)
+ {
+ typedef typename Elements::value_type element_type;
+
+ // reinsert children starting from the minimum distance
+ typename Elements::reverse_iterator it = elements.rbegin();
+ for ( ; it != elements.rend() ; ++it)
+ {
+ rstar::level_insert<1, element_type, Value, Options, Translator, Box, Allocators> lins_v(
+ m_root, m_leafs_level, *it, m_parameters, m_translator, m_allocators, relative_level);
+
+ BOOST_TRY
+ {
+ rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
+ }
+ BOOST_CATCH(...)
+ {
+ ++it;
+ for ( ; it != elements.rend() ; ++it)
+ rtree::destroy_element<Value, Options, Translator, Box, Allocators>::apply(*it, m_allocators);
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+
+ BOOST_GEOMETRY_INDEX_ASSERT(relative_level + 1 == lins_v.result_relative_level, "unexpected level");
+
+ // non-root relative level
+ if ( lins_v.result_relative_level < m_leafs_level && !lins_v.result_elements.empty())
+ {
+ recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
+ }
+ }
+ }
+
+ node_pointer & m_root;
+ size_type & m_leafs_level;
+ Element const& m_element;
+
+ parameters_type const& m_parameters;
+ Translator const& m_translator;
+
+ size_type m_relative_level;
+
+ Allocators & m_allocators;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
diff --git a/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp b/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp
new file mode 100644
index 0000000000..8f270537fb
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp
@@ -0,0 +1,468 @@
+// Boost.Geometry Index
+//
+// R-tree R*-tree split algorithm implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
+
+#include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
+#include <boost/geometry/index/detail/algorithms/union_content.hpp>
+#include <boost/geometry/index/detail/algorithms/margin.hpp>
+
+#include <boost/geometry/index/detail/bounded_view.hpp>
+
+#include <boost/geometry/index/detail/rtree/node/node.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+namespace rstar {
+
+template <typename Element, typename Translator, typename Tag, size_t Corner, size_t AxisIndex>
+class element_axis_corner_less
+{
+ typedef typename rtree::element_indexable_type<Element, Translator>::type indexable_type;
+ typedef typename geometry::point_type<indexable_type>::type point_type;
+ typedef geometry::model::box<point_type> bounds_type;
+ typedef index::detail::bounded_view<indexable_type, bounds_type> bounded_view_type;
+
+public:
+ element_axis_corner_less(Translator const& tr)
+ : m_tr(tr)
+ {}
+
+ bool operator()(Element const& e1, Element const& e2) const
+ {
+ bounded_view_type bounded_ind1(rtree::element_indexable(e1, m_tr));
+ bounded_view_type bounded_ind2(rtree::element_indexable(e2, m_tr));
+
+ return geometry::get<Corner, AxisIndex>(bounded_ind1)
+ < geometry::get<Corner, AxisIndex>(bounded_ind2);
+ }
+
+private:
+ Translator const& m_tr;
+};
+
+template <typename Element, typename Translator, size_t Corner, size_t AxisIndex>
+class element_axis_corner_less<Element, Translator, box_tag, Corner, AxisIndex>
+{
+public:
+ element_axis_corner_less(Translator const& tr)
+ : m_tr(tr)
+ {}
+
+ bool operator()(Element const& e1, Element const& e2) const
+ {
+ return geometry::get<Corner, AxisIndex>(rtree::element_indexable(e1, m_tr))
+ < geometry::get<Corner, AxisIndex>(rtree::element_indexable(e2, m_tr));
+ }
+
+private:
+ Translator const& m_tr;
+};
+
+template <typename Element, typename Translator, size_t Corner, size_t AxisIndex>
+class element_axis_corner_less<Element, Translator, point_tag, Corner, AxisIndex>
+{
+public:
+ element_axis_corner_less(Translator const& tr)
+ : m_tr(tr)
+ {}
+
+ bool operator()(Element const& e1, Element const& e2) const
+ {
+ return geometry::get<AxisIndex>(rtree::element_indexable(e1, m_tr))
+ < geometry::get<AxisIndex>(rtree::element_indexable(e2, m_tr));
+ }
+
+private:
+ Translator const& m_tr;
+};
+
+template <typename Box, size_t Corner, size_t AxisIndex>
+struct choose_split_axis_and_index_for_corner
+{
+ typedef typename index::detail::default_margin_result<Box>::type margin_type;
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Elements, typename Parameters, typename Translator>
+ static inline void apply(Elements const& elements,
+ size_t & choosen_index,
+ margin_type & sum_of_margins,
+ content_type & smallest_overlap,
+ content_type & smallest_content,
+ Parameters const& parameters,
+ Translator const& translator)
+ {
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+ typedef typename tag<indexable_type>::type indexable_tag;
+
+ BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements");
+
+ // copy elements
+ Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy)
+
+ size_t const index_first = parameters.get_min_elements();
+ size_t const index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2;
+
+ // sort elements
+ element_axis_corner_less<element_type, Translator, indexable_tag, Corner, AxisIndex> elements_less(translator);
+ std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
+// {
+// typename Elements::iterator f = elements_copy.begin() + index_first;
+// typename Elements::iterator l = elements_copy.begin() + index_last;
+// std::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
+// std::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
+// std::sort(f, l, elements_less); // MAY THROW, BASIC (copy)
+// }
+
+ // init outputs
+ choosen_index = index_first;
+ sum_of_margins = 0;
+ smallest_overlap = (std::numeric_limits<content_type>::max)();
+ smallest_content = (std::numeric_limits<content_type>::max)();
+
+ // calculate sum of margins for all distributions
+ for ( size_t i = index_first ; i < index_last ; ++i )
+ {
+ // TODO - awulkiew: may be optimized - box of group 1 may be initialized with
+ // box of min_elems number of elements and expanded for each iteration by another element
+
+ Box box1 = rtree::elements_box<Box>(elements_copy.begin(), elements_copy.begin() + i, translator);
+ Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(), translator);
+
+ sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2);
+
+ content_type ovl = index::detail::intersection_content(box1, box2);
+ content_type con = index::detail::content(box1) + index::detail::content(box2);
+
+ // TODO - shouldn't here be < instead of <= ?
+ if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) )
+ {
+ choosen_index = i;
+ smallest_overlap = ovl;
+ smallest_content = con;
+ }
+ }
+
+ ::boost::ignore_unused_variable_warning(parameters);
+ }
+};
+
+//template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
+//struct choose_split_axis_and_index_for_axis
+//{
+// BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (ElementIndexableTag));
+//};
+
+template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
+struct choose_split_axis_and_index_for_axis
+{
+ typedef typename index::detail::default_margin_result<Box>::type margin_type;
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Elements, typename Parameters, typename Translator>
+ static inline void apply(Elements const& elements,
+ size_t & choosen_corner,
+ size_t & choosen_index,
+ margin_type & sum_of_margins,
+ content_type & smallest_overlap,
+ content_type & smallest_content,
+ Parameters const& parameters,
+ Translator const& translator)
+ {
+ size_t index1 = 0;
+ margin_type som1 = 0;
+ content_type ovl1 = (std::numeric_limits<content_type>::max)();
+ content_type con1 = (std::numeric_limits<content_type>::max)();
+
+ choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
+ ::apply(elements, index1,
+ som1, ovl1, con1,
+ parameters, translator); // MAY THROW, STRONG
+
+ size_t index2 = 0;
+ margin_type som2 = 0;
+ content_type ovl2 = (std::numeric_limits<content_type>::max)();
+ content_type con2 = (std::numeric_limits<content_type>::max)();
+
+ choose_split_axis_and_index_for_corner<Box, max_corner, AxisIndex>
+ ::apply(elements, index2,
+ som2, ovl2, con2,
+ parameters, translator); // MAY THROW, STRONG
+
+ sum_of_margins = som1 + som2;
+
+ if ( ovl1 < ovl2 || (ovl1 == ovl2 && con1 <= con2) )
+ {
+ choosen_corner = min_corner;
+ choosen_index = index1;
+ smallest_overlap = ovl1;
+ smallest_content = con1;
+ }
+ else
+ {
+ choosen_corner = max_corner;
+ choosen_index = index2;
+ smallest_overlap = ovl2;
+ smallest_content = con2;
+ }
+ }
+};
+
+template <typename Box, size_t AxisIndex>
+struct choose_split_axis_and_index_for_axis<Box, AxisIndex, point_tag>
+{
+ typedef typename index::detail::default_margin_result<Box>::type margin_type;
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Elements, typename Parameters, typename Translator>
+ static inline void apply(Elements const& elements,
+ size_t & choosen_corner,
+ size_t & choosen_index,
+ margin_type & sum_of_margins,
+ content_type & smallest_overlap,
+ content_type & smallest_content,
+ Parameters const& parameters,
+ Translator const& translator)
+ {
+ choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
+ ::apply(elements, choosen_index,
+ sum_of_margins, smallest_overlap, smallest_content,
+ parameters, translator); // MAY THROW, STRONG
+
+ choosen_corner = min_corner;
+ }
+};
+
+template <typename Box, size_t Dimension>
+struct choose_split_axis_and_index
+{
+ BOOST_STATIC_ASSERT(0 < Dimension);
+
+ typedef typename index::detail::default_margin_result<Box>::type margin_type;
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Elements, typename Parameters, typename Translator>
+ static inline void apply(Elements const& elements,
+ size_t & choosen_axis,
+ size_t & choosen_corner,
+ size_t & choosen_index,
+ margin_type & smallest_sum_of_margins,
+ content_type & smallest_overlap,
+ content_type & smallest_content,
+ Parameters const& parameters,
+ Translator const& translator)
+ {
+ typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
+
+ choose_split_axis_and_index<Box, Dimension - 1>
+ ::apply(elements, choosen_axis, choosen_corner, choosen_index,
+ smallest_sum_of_margins, smallest_overlap, smallest_content,
+ parameters, translator); // MAY THROW, STRONG
+
+ margin_type sum_of_margins = 0;
+
+ size_t corner = min_corner;
+ size_t index = 0;
+
+ content_type overlap_val = (std::numeric_limits<content_type>::max)();
+ content_type content_val = (std::numeric_limits<content_type>::max)();
+
+ choose_split_axis_and_index_for_axis<
+ Box,
+ Dimension - 1,
+ typename tag<element_indexable_type>::type
+ >::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW, STRONG
+
+ if ( sum_of_margins < smallest_sum_of_margins )
+ {
+ choosen_axis = Dimension - 1;
+ choosen_corner = corner;
+ choosen_index = index;
+ smallest_sum_of_margins = sum_of_margins;
+ smallest_overlap = overlap_val;
+ smallest_content = content_val;
+ }
+ }
+};
+
+template <typename Box>
+struct choose_split_axis_and_index<Box, 1>
+{
+ typedef typename index::detail::default_margin_result<Box>::type margin_type;
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Elements, typename Parameters, typename Translator>
+ static inline void apply(Elements const& elements,
+ size_t & choosen_axis,
+ size_t & choosen_corner,
+ size_t & choosen_index,
+ margin_type & smallest_sum_of_margins,
+ content_type & smallest_overlap,
+ content_type & smallest_content,
+ Parameters const& parameters,
+ Translator const& translator)
+ {
+ typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
+
+ choosen_axis = 0;
+
+ choose_split_axis_and_index_for_axis<
+ Box,
+ 0,
+ typename tag<element_indexable_type>::type
+ >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW
+ }
+};
+
+template <size_t Corner, size_t Dimension, size_t I = 0>
+struct nth_element
+{
+ BOOST_STATIC_ASSERT(0 < Dimension);
+ BOOST_STATIC_ASSERT(I < Dimension);
+
+ template <typename Elements, typename Translator>
+ static inline void apply(Elements & elements, const size_t axis, const size_t index, Translator const& tr)
+ {
+ //BOOST_GEOMETRY_INDEX_ASSERT(axis < Dimension, "unexpected axis value");
+
+ if ( axis != I )
+ {
+ nth_element<Corner, Dimension, I + 1>::apply(elements, axis, index, tr); // MAY THROW, BASIC (copy)
+ }
+ else
+ {
+ typedef typename Elements::value_type element_type;
+ typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
+ typedef typename tag<indexable_type>::type indexable_tag;
+
+ element_axis_corner_less<element_type, Translator, indexable_tag, Corner, I> less(tr);
+ std::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
+ }
+ }
+};
+
+template <size_t Corner, size_t Dimension>
+struct nth_element<Corner, Dimension, Dimension>
+{
+ template <typename Elements, typename Translator>
+ static inline void apply(Elements & /*elements*/, const size_t /*axis*/, const size_t /*index*/, Translator const& /*tr*/)
+ {}
+};
+
+} // namespace rstar
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_tag>
+{
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ static const size_t dimension = geometry::dimension<Box>::value;
+
+ typedef typename index::detail::default_margin_result<Box>::type margin_type;
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Node>
+ static inline void apply(
+ Node & n,
+ Node & second_node,
+ Box & box1,
+ Box & box2,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators)
+ {
+ typedef typename rtree::elements_type<Node>::type elements_type;
+ typedef typename elements_type::value_type element_type;
+
+ elements_type & elements1 = rtree::elements(n);
+ elements_type & elements2 = rtree::elements(second_node);
+
+ // copy original elements - use in-memory storage (std::allocator)
+ // TODO: move if noexcept
+ typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
+ container_type;
+ container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG
+ container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG
+
+ size_t split_axis = 0;
+ size_t split_corner = 0;
+ size_t split_index = parameters.get_min_elements();
+ margin_type smallest_sum_of_margins = (std::numeric_limits<margin_type>::max)();
+ content_type smallest_overlap = (std::numeric_limits<content_type>::max)();
+ content_type smallest_content = (std::numeric_limits<content_type>::max)();
+
+ // NOTE: this function internally copies passed elements
+ // why not pass mutable elements and use the same container for all axes/corners
+ // and again, the same below calling partial_sort/nth_element
+ // It would be even possible to not re-sort/find nth_element if the axis/corner
+ // was found for the last sorting - last combination of axis/corner
+ rstar::choose_split_axis_and_index<Box, dimension>
+ ::apply(elements_copy,
+ split_axis, split_corner, split_index,
+ smallest_sum_of_margins, smallest_overlap, smallest_content,
+ parameters, translator); // MAY THROW, STRONG
+
+ // TODO: awulkiew - get rid of following static_casts?
+ BOOST_GEOMETRY_INDEX_ASSERT(split_axis < dimension, "unexpected value");
+ BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast<size_t>(min_corner) || split_corner == static_cast<size_t>(max_corner), "unexpected value");
+ BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value");
+
+ // TODO: consider using nth_element
+ if ( split_corner == static_cast<size_t>(min_corner) )
+ {
+ rstar::nth_element<min_corner, dimension>
+ ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
+ }
+ else
+ {
+ rstar::nth_element<max_corner, dimension>
+ ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
+ }
+
+ BOOST_TRY
+ {
+ // copy elements to nodes
+ elements1.assign(elements_copy.begin(), elements_copy.begin() + split_index); // MAY THROW, BASIC
+ elements2.assign(elements_copy.begin() + split_index, elements_copy.end()); // MAY THROW, BASIC
+
+ // calculate boxes
+ box1 = rtree::elements_box<Box>(elements1.begin(), elements1.end(), translator);
+ box2 = rtree::elements_box<Box>(elements2.begin(), elements2.end(), translator);
+ }
+ BOOST_CATCH(...)
+ {
+ //elements_copy.clear();
+ elements1.clear();
+ elements2.clear();
+
+ rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
+ //elements_backup.clear();
+
+ BOOST_RETHROW // RETHROW, BASIC
+ }
+ BOOST_CATCH_END
+ }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
diff --git a/boost/geometry/index/detail/rtree/rstar/rstar.hpp b/boost/geometry/index/detail/rtree/rstar/rstar.hpp
new file mode 100644
index 0000000000..ed3959c89d
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/rstar/rstar.hpp
@@ -0,0 +1,18 @@
+// Boost.Geometry Index
+//
+// R-tree R*-tree algorithm implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP
+
+#include <boost/geometry/index/detail/rtree/rstar/insert.hpp>
+#include <boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp>
+#include <boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp>
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP
diff --git a/boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp b/boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp
new file mode 100644
index 0000000000..d2caa36707
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp
@@ -0,0 +1,142 @@
+// Boost.Geometry Index
+//
+// R-tree boxes validating visitor implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/index/detail/rtree/node/node.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities {
+
+namespace visitors {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class are_boxes_ok
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+public:
+ are_boxes_ok(Translator const& tr, bool exact_match)
+ : result(false), m_tr(tr), m_is_root(true), m_exact_match(exact_match)
+ {}
+
+ void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ if (elements.empty())
+ {
+ result = false;
+ return;
+ }
+
+ Box box_bckup = m_box;
+ bool is_root_bckup = m_is_root;
+
+ m_is_root = false;
+
+ for ( typename elements_type::const_iterator it = elements.begin();
+ it != elements.end() ; ++it)
+ {
+ m_box = it->first;
+
+ rtree::apply_visitor(*this, *it->second);
+
+ if ( result == false )
+ return;
+ }
+
+ m_box = box_bckup;
+ m_is_root = is_root_bckup;
+
+ Box box_exp;
+ geometry::convert(elements.front().first, box_exp);
+ for( typename elements_type::const_iterator it = elements.begin() + 1;
+ it != elements.end() ; ++it)
+ {
+ geometry::expand(box_exp, it->first);
+ }
+
+ if ( m_exact_match )
+ result = m_is_root || geometry::equals(box_exp, m_box);
+ else
+ result = m_is_root || geometry::covered_by(box_exp, m_box);
+ }
+
+ void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // non-root node
+ if (!m_is_root)
+ {
+ if ( elements.empty() )
+ {
+ result = false;
+ return;
+ }
+
+ Box box_exp;
+ geometry::convert(
+ index::detail::return_ref_or_bounds(m_tr(elements.front())),
+ box_exp);
+ for(typename elements_type::const_iterator it = elements.begin() + 1;
+ it != elements.end() ; ++it)
+ {
+ geometry::expand(box_exp, m_tr(*it));
+ }
+
+ if ( m_exact_match )
+ result = geometry::equals(box_exp, m_box);
+ else
+ result = geometry::covered_by(box_exp, m_box);
+ }
+ else
+ result = true;
+ }
+
+ bool result;
+
+private:
+ Translator const& m_tr;
+ Box m_box;
+ bool m_is_root;
+ bool m_exact_match;
+};
+
+} // namespace visitors
+
+template <typename Rtree> inline
+bool are_boxes_ok(Rtree const& tree, bool exact_match = true)
+{
+ typedef utilities::view<Rtree> RTV;
+ RTV rtv(tree);
+
+ visitors::are_boxes_ok<
+ typename RTV::value_type,
+ typename RTV::options_type,
+ typename RTV::translator_type,
+ typename RTV::box_type,
+ typename RTV::allocators_type
+ > v(rtv.translator(), exact_match);
+
+ rtv.apply_visitor(v);
+
+ return v.result;
+}
+
+}}}}}} // namespace boost::geometry::index::detail::rtree::utilities
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP
diff --git a/boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp b/boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp
new file mode 100644
index 0000000000..4860dbcb9b
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp
@@ -0,0 +1,109 @@
+// Boost.Geometry Index
+//
+// R-tree levels validating visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP
+
+#include <boost/geometry/index/detail/rtree/node/node.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities {
+
+namespace visitors {
+
+template <typename Value, typename Options, typename Box, typename Allocators>
+class are_levels_ok
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+public:
+ inline are_levels_ok()
+ : result(true), m_leafs_level((std::numeric_limits<size_t>::max)()), m_current_level(0)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ if (elements.empty())
+ {
+ result = false;
+ return;
+ }
+
+ size_t current_level_backup = m_current_level;
+ ++m_current_level;
+
+ for ( typename elements_type::const_iterator it = elements.begin();
+ it != elements.end() ; ++it)
+ {
+ rtree::apply_visitor(*this, *it->second);
+
+ if ( result == false )
+ return;
+ }
+
+ m_current_level = current_level_backup;
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // empty leaf in non-root node
+ if (0 < m_current_level && elements.empty())
+ {
+ result = false;
+ return;
+ }
+
+ if ( m_leafs_level == (std::numeric_limits<size_t>::max)() )
+ {
+ m_leafs_level = m_current_level;
+ }
+ else if ( m_leafs_level != m_current_level )
+ {
+ result = false;
+ }
+ }
+
+ bool result;
+
+private:
+ size_t m_leafs_level;
+ size_t m_current_level;
+};
+
+} // namespace visitors
+
+template <typename Rtree> inline
+bool are_levels_ok(Rtree const& tree)
+{
+ typedef utilities::view<Rtree> RTV;
+ RTV rtv(tree);
+
+ visitors::are_levels_ok<
+ typename RTV::value_type,
+ typename RTV::options_type,
+ typename RTV::box_type,
+ typename RTV::allocators_type
+ > v;
+
+ rtv.apply_visitor(v);
+
+ return v.result;
+}
+
+}}}}}} // namespace boost::geometry::index::detail::rtree::utilities
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP
diff --git a/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp b/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp
new file mode 100644
index 0000000000..84201b6afe
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp
@@ -0,0 +1,243 @@
+// Boost.Geometry Index
+//
+// R-tree OpenGL drawing visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP
+
+#include <boost/mpl/assert.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+namespace utilities {
+
+namespace dispatch {
+
+template <typename Point, size_t Dimension>
+struct gl_draw_point
+{};
+
+template <typename Point>
+struct gl_draw_point<Point, 2>
+{
+ static inline void apply(Point const& p, typename coordinate_type<Point>::type z)
+ {
+ typename coordinate_type<Point>::type const& x = geometry::get<0>(p);
+ typename coordinate_type<Point>::type const& y = geometry::get<1>(p);
+ /*glBegin(GL_POINT);
+ glVertex3f(x, y, z);
+ glEnd();*/
+ glBegin(GL_QUADS);
+ glVertex3f(x+1, y, z);
+ glVertex3f(x, y+1, z);
+ glVertex3f(x-1, y, z);
+ glVertex3f(x, y-1, z);
+ glEnd();
+ }
+};
+
+template <typename Box, size_t Dimension>
+struct gl_draw_box
+{};
+
+template <typename Box>
+struct gl_draw_box<Box, 2>
+{
+ static inline void apply(Box const& b, typename coordinate_type<Box>::type z)
+ {
+ glBegin(GL_LINE_LOOP);
+ glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<min_corner, 1>(b), z);
+ glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<min_corner, 1>(b), z);
+ glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<max_corner, 1>(b), z);
+ glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<max_corner, 1>(b), z);
+ glEnd();
+ }
+};
+
+template <typename Segment, size_t Dimension>
+struct gl_draw_segment
+{};
+
+template <typename Segment>
+struct gl_draw_segment<Segment, 2>
+{
+ static inline void apply(Segment const& s, typename coordinate_type<Segment>::type z)
+ {
+ glBegin(GL_LINES);
+ glVertex3f(geometry::get<0, 0>(s), geometry::get<0, 1>(s), z);
+ glVertex3f(geometry::get<1, 0>(s), geometry::get<1, 1>(s), z);
+ glEnd();
+ }
+};
+
+template <typename Indexable, typename Tag>
+struct gl_draw_indexable
+{
+ BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag));
+};
+
+template <typename Box>
+struct gl_draw_indexable<Box, box_tag>
+ : gl_draw_box<Box, geometry::dimension<Box>::value>
+{};
+
+template <typename Point>
+struct gl_draw_indexable<Point, point_tag>
+ : gl_draw_point<Point, geometry::dimension<Point>::value>
+{};
+
+template <typename Segment>
+struct gl_draw_indexable<Segment, segment_tag>
+ : gl_draw_segment<Segment, geometry::dimension<Segment>::value>
+{};
+
+} // namespace dispatch
+
+template <typename Indexable> inline
+void gl_draw_indexable(Indexable const& i, typename coordinate_type<Indexable>::type z)
+{
+ dispatch::gl_draw_indexable<
+ Indexable,
+ typename tag<Indexable>::type
+ >::apply(i, z);
+}
+
+} // namespace utilities
+
+namespace rtree { namespace utilities {
+
+namespace visitors {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct gl_draw : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ inline gl_draw(Translator const& t,
+ size_t level_first = 0,
+ size_t level_last = (std::numeric_limits<size_t>::max)(),
+ typename coordinate_type<Box>::type z_coord_level_multiplier = 1
+ )
+ : tr(t)
+ , level_f(level_first)
+ , level_l(level_last)
+ , z_mul(z_coord_level_multiplier)
+ , level(0)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ if ( level_f <= level )
+ {
+ size_t level_rel = level - level_f;
+
+ if ( level_rel == 0 )
+ glColor3f(0.75f, 0.0f, 0.0f);
+ else if ( level_rel == 1 )
+ glColor3f(0.0f, 0.75f, 0.0f);
+ else if ( level_rel == 2 )
+ glColor3f(0.0f, 0.0f, 0.75f);
+ else if ( level_rel == 3 )
+ glColor3f(0.75f, 0.75f, 0.0f);
+ else if ( level_rel == 4 )
+ glColor3f(0.75f, 0.0f, 0.75f);
+ else if ( level_rel == 5 )
+ glColor3f(0.0f, 0.75f, 0.75f);
+ else
+ glColor3f(0.5f, 0.5f, 0.5f);
+
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ detail::utilities::gl_draw_indexable(it->first, level_rel * z_mul);
+ }
+ }
+
+ size_t level_backup = level;
+ ++level;
+
+ if ( level < level_l )
+ {
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ rtree::apply_visitor(*this, *it->second);
+ }
+ }
+
+ level = level_backup;
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ if ( level_f <= level )
+ {
+ size_t level_rel = level - level_f;
+
+ glColor3f(0.25f, 0.25f, 0.25f);
+
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ detail::utilities::gl_draw_indexable(tr(*it), level_rel * z_mul);
+ }
+ }
+ }
+
+ Translator const& tr;
+ size_t level_f;
+ size_t level_l;
+ typename coordinate_type<Box>::type z_mul;
+
+ size_t level;
+};
+
+} // namespace visitors
+
+template <typename Rtree> inline
+void gl_draw(Rtree const& tree,
+ size_t level_first = 0,
+ size_t level_last = (std::numeric_limits<size_t>::max)(),
+ typename coordinate_type<
+ typename Rtree::bounds_type
+ >::type z_coord_level_multiplier = 1
+ )
+{
+ typedef utilities::view<Rtree> RTV;
+ RTV rtv(tree);
+
+ if ( !tree.empty() )
+ {
+ glColor3f(0.75f, 0.75f, 0.75f);
+ detail::utilities::gl_draw_indexable(tree.bounds(), 0);
+ }
+
+ visitors::gl_draw<
+ typename RTV::value_type,
+ typename RTV::options_type,
+ typename RTV::translator_type,
+ typename RTV::box_type,
+ typename RTV::allocators_type
+ > gl_draw_v(rtv.translator(), level_first, level_last, z_coord_level_multiplier);
+
+ rtv.apply_visitor(gl_draw_v);
+}
+
+}} // namespace rtree::utilities
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP
diff --git a/boost/geometry/index/detail/rtree/utilities/print.hpp b/boost/geometry/index/detail/rtree/utilities/print.hpp
new file mode 100644
index 0000000000..4c42659c64
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/utilities/print.hpp
@@ -0,0 +1,219 @@
+// Boost.Geometry Index
+//
+// R-tree ostreaming visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP
+
+#include <iostream>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+namespace utilities {
+
+namespace dispatch {
+
+template <typename Point, size_t Dimension>
+struct print_point
+{
+ BOOST_STATIC_ASSERT(0 < Dimension);
+
+ static inline void apply(std::ostream & os, Point const& p)
+ {
+ print_point<Point, Dimension - 1>::apply(os, p);
+
+ os << ", " << geometry::get<Dimension - 1>(p);
+ }
+};
+
+template <typename Point>
+struct print_point<Point, 1>
+{
+ static inline void apply(std::ostream & os, Point const& p)
+ {
+ os << geometry::get<0>(p);
+ }
+};
+
+template <typename Box, size_t Corner, size_t Dimension>
+struct print_corner
+{
+ BOOST_STATIC_ASSERT(0 < Dimension);
+
+ static inline void apply(std::ostream & os, Box const& b)
+ {
+ print_corner<Box, Corner, Dimension - 1>::apply(os, b);
+
+ os << ", " << geometry::get<Corner, Dimension - 1>(b);
+ }
+};
+
+template <typename Box, size_t Corner>
+struct print_corner<Box, Corner, 1>
+{
+ static inline void apply(std::ostream & os, Box const& b)
+ {
+ os << geometry::get<Corner, 0>(b);
+ }
+};
+
+template <typename Indexable, typename Tag>
+struct print_indexable
+{
+ BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag));
+};
+
+template <typename Indexable>
+struct print_indexable<Indexable, box_tag>
+{
+ static const size_t dimension = geometry::dimension<Indexable>::value;
+
+ static inline void apply(std::ostream &os, Indexable const& i)
+ {
+ os << '(';
+ print_corner<Indexable, min_corner, dimension>::apply(os, i);
+ os << ")x(";
+ print_corner<Indexable, max_corner, dimension>::apply(os, i);
+ os << ')';
+ }
+};
+
+template <typename Indexable>
+struct print_indexable<Indexable, point_tag>
+{
+ static const size_t dimension = geometry::dimension<Indexable>::value;
+
+ static inline void apply(std::ostream &os, Indexable const& i)
+ {
+ os << '(';
+ print_point<Indexable, dimension>::apply(os, i);
+ os << ')';
+ }
+};
+
+template <typename Indexable>
+struct print_indexable<Indexable, segment_tag>
+{
+ static const size_t dimension = geometry::dimension<Indexable>::value;
+
+ static inline void apply(std::ostream &os, Indexable const& i)
+ {
+ os << '(';
+ print_corner<Indexable, 0, dimension>::apply(os, i);
+ os << ")-(";
+ print_corner<Indexable, 1, dimension>::apply(os, i);
+ os << ')';
+ }
+};
+
+} // namespace dispatch
+
+template <typename Indexable> inline
+void print_indexable(std::ostream & os, Indexable const& i)
+{
+ dispatch::print_indexable<
+ Indexable,
+ typename tag<Indexable>::type
+ >::apply(os, i);
+}
+
+} // namespace utilities
+
+namespace rtree { namespace utilities {
+
+namespace visitors {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct print : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ inline print(std::ostream & o, Translator const& t)
+ : os(o), tr(t), level(0)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ spaces(level) << "INTERNAL NODE - L:" << level << " Ch:" << elements.size() << " @:" << &n << '\n';
+
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ spaces(level);
+ detail::utilities::print_indexable(os, it->first);
+ os << " ->" << it->second << '\n';
+ }
+
+ size_t level_backup = level;
+ ++level;
+
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ rtree::apply_visitor(*this, *it->second);
+ }
+
+ level = level_backup;
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ spaces(level) << "LEAF - L:" << level << " V:" << elements.size() << " @:" << &n << '\n';
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ spaces(level);
+ detail::utilities::print_indexable(os, tr(*it));
+ os << '\n';
+ }
+ }
+
+ inline std::ostream & spaces(size_t level)
+ {
+ for ( size_t i = 0 ; i < 2 * level ; ++i )
+ os << ' ';
+ return os;
+ }
+
+ std::ostream & os;
+ Translator const& tr;
+
+ size_t level;
+};
+
+} // namespace visitors
+
+template <typename Rtree> inline
+void print(std::ostream & os, Rtree const& tree)
+{
+ typedef utilities::view<Rtree> RTV;
+ RTV rtv(tree);
+
+ visitors::print<
+ typename RTV::value_type,
+ typename RTV::options_type,
+ typename RTV::translator_type,
+ typename RTV::box_type,
+ typename RTV::allocators_type
+ > print_v(os, rtv.translator());
+ rtv.apply_visitor(print_v);
+}
+
+}} // namespace rtree::utilities
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP
diff --git a/boost/geometry/index/detail/rtree/utilities/statistics.hpp b/boost/geometry/index/detail/rtree/utilities/statistics.hpp
new file mode 100644
index 0000000000..bbaed8100e
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/utilities/statistics.hpp
@@ -0,0 +1,105 @@
+// Boost.Geometry Index
+//
+// R-tree visitor collecting basic statistics
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2013 Mateusz Loskot, London, UK.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP
+
+#include <algorithm>
+#include <boost/tuple/tuple.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities {
+
+namespace visitors {
+
+template <typename Value, typename Options, typename Box, typename Allocators>
+struct statistics : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ inline statistics()
+ : level(0)
+ , levels(1) // count root
+ , nodes(0)
+ , leaves(0)
+ , values(0)
+ , values_min(0)
+ , values_max(0)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ ++nodes; // count node
+
+ size_t const level_backup = level;
+ ++level;
+
+ levels += level++ > levels ? 1 : 0; // count level (root already counted)
+
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ rtree::apply_visitor(*this, *it->second);
+ }
+
+ level = level_backup;
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ ++leaves; // count leaves
+
+ std::size_t const v = elements.size();
+ // count values spread per node and total
+ values_min = (std::min)(values_min == 0 ? v : values_min, v);
+ values_max = (std::max)(values_max, v);
+ values += v;
+ }
+
+ std::size_t level;
+ std::size_t levels;
+ std::size_t nodes;
+ std::size_t leaves;
+ std::size_t values;
+ std::size_t values_min;
+ std::size_t values_max;
+};
+
+} // namespace visitors
+
+template <typename Rtree> inline
+boost::tuple<std::size_t, std::size_t, std::size_t, std::size_t, std::size_t, std::size_t>
+statistics(Rtree const& tree)
+{
+ typedef utilities::view<Rtree> RTV;
+ RTV rtv(tree);
+
+ visitors::statistics<
+ typename RTV::value_type,
+ typename RTV::options_type,
+ typename RTV::box_type,
+ typename RTV::allocators_type
+ > stats_v;
+
+ rtv.apply_visitor(stats_v);
+
+ return boost::make_tuple(stats_v.levels, stats_v.nodes, stats_v.leaves, stats_v.values, stats_v.values_min, stats_v.values_max);
+}
+
+}}}}}} // namespace boost::geometry::index::detail::rtree::utilities
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP
diff --git a/boost/geometry/index/detail/rtree/utilities/view.hpp b/boost/geometry/index/detail/rtree/utilities/view.hpp
new file mode 100644
index 0000000000..6dbbd07bfe
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/utilities/view.hpp
@@ -0,0 +1,61 @@
+// Boost.Geometry Index
+//
+// Rtree utilities view
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace utilities {
+
+template <typename Rtree>
+class view
+{
+public:
+ typedef typename Rtree::size_type size_type;
+
+ typedef typename Rtree::translator_type translator_type;
+ typedef typename Rtree::value_type value_type;
+ typedef typename Rtree::options_type options_type;
+ typedef typename Rtree::box_type box_type;
+ typedef typename Rtree::allocators_type allocators_type;
+
+ view(Rtree const& rt) : m_rtree(rt) {}
+
+ template <typename Visitor>
+ void apply_visitor(Visitor & vis) const
+ {
+ m_rtree.apply_visitor(vis);
+ }
+
+ // This will most certainly be removed in the future
+ translator_type translator() const
+ {
+ return m_rtree.translator();
+ }
+
+ // This will probably be removed in the future
+ size_type depth() const
+ {
+ return m_rtree.depth();
+ }
+
+private:
+ view(view const&);
+ view & operator=(view const&);
+
+ Rtree const& m_rtree;
+};
+
+}}} // namespace detail::rtree::utilities
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/children_box.hpp b/boost/geometry/index/detail/rtree/visitors/children_box.hpp
new file mode 100644
index 0000000000..93726063b4
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/children_box.hpp
@@ -0,0 +1,55 @@
+// Boost.Geometry Index
+//
+// R-tree node children box calculating visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class children_box
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+public:
+ inline children_box(Box & result, Translator const& tr)
+ : m_result(result), m_tr(tr)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ m_result = rtree::elements_box<Box>(elements.begin(), elements.end(), m_tr);
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ m_result = rtree::elements_box<Box>(elements.begin(), elements.end(), m_tr);
+ }
+
+private:
+ Box & m_result;
+ Translator const& m_tr;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/copy.hpp b/boost/geometry/index/detail/rtree/visitors/copy.hpp
new file mode 100644
index 0000000000..8fc25ac803
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/copy.hpp
@@ -0,0 +1,92 @@
+// Boost.Geometry Index
+//
+// R-tree deep copying visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class copy
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
+{
+public:
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+ typedef typename Allocators::node_pointer node_pointer;
+
+ explicit inline copy(Allocators & allocators)
+ : result(0)
+ , m_allocators(allocators)
+ {}
+
+ inline void operator()(internal_node & n)
+ {
+ node_pointer raw_new_node = rtree::create_node<Allocators, internal_node>::apply(m_allocators); // MAY THROW, STRONG (N: alloc)
+ node_auto_ptr new_node(raw_new_node, m_allocators);
+
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type & elements = rtree::elements(n);
+
+ elements_type & elements_dst = rtree::elements(rtree::get<internal_node>(*new_node));
+
+ for (typename elements_type::iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ rtree::apply_visitor(*this, *it->second); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ // for exception safety
+ node_auto_ptr auto_result(result, m_allocators);
+
+ elements_dst.push_back( rtree::make_ptr_pair(it->first, result) ); // MAY THROW, STRONG (E: alloc, copy)
+
+ auto_result.release();
+ }
+
+ result = new_node.get();
+ new_node.release();
+ }
+
+ inline void operator()(leaf & l)
+ {
+ node_pointer raw_new_node = rtree::create_node<Allocators, leaf>::apply(m_allocators); // MAY THROW, STRONG (N: alloc)
+ node_auto_ptr new_node(raw_new_node, m_allocators);
+
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type & elements = rtree::elements(l);
+
+ elements_type & elements_dst = rtree::elements(rtree::get<leaf>(*new_node));
+
+ for (typename elements_type::iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ elements_dst.push_back(*it); // MAY THROW, STRONG (V: alloc, copy)
+ }
+
+ result = new_node.get();
+ new_node.release();
+ }
+
+ node_pointer result;
+
+private:
+ Allocators & m_allocators;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/count.hpp b/boost/geometry/index/detail/rtree/visitors/count.hpp
new file mode 100644
index 0000000000..7efd5b7028
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/count.hpp
@@ -0,0 +1,107 @@
+// Boost.Geometry Index
+//
+// R-tree count visitor implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+template <typename Indexable, typename Value>
+struct count_helper
+{
+ template <typename Translator>
+ static inline typename Translator::result_type indexable(Indexable const& i, Translator const&)
+ {
+ return i;
+ }
+ template <typename Translator>
+ static inline bool equals(Indexable const& i, Value const& v, Translator const& tr)
+ {
+ return geometry::equals(i, tr(v));
+ }
+};
+
+template <typename Value>
+struct count_helper<Value, Value>
+{
+ template <typename Translator>
+ static inline typename Translator::result_type indexable(Value const& v, Translator const& tr)
+ {
+ return tr(v);
+ }
+ template <typename Translator>
+ static inline bool equals(Value const& v1, Value const& v2, Translator const& tr)
+ {
+ return tr.equals(v1, v2);
+ }
+};
+
+template <typename ValueOrIndexable, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct count
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef count_helper<ValueOrIndexable, Value> count_help;
+
+ inline count(ValueOrIndexable const& vori, Translator const& t)
+ : value_or_indexable(vori), tr(t), found_count(0)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // traverse nodes meeting predicates
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ if ( geometry::covered_by(
+ return_ref_or_bounds(
+ count_help::indexable(value_or_indexable, tr)),
+ it->first) )
+ {
+ rtree::apply_visitor(*this, *it->second);
+ }
+ }
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // get all values meeting predicates
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ // if value meets predicates
+ if ( count_help::equals(value_or_indexable, *it, tr) )
+ {
+ ++found_count;
+ }
+ }
+ }
+
+ ValueOrIndexable const& value_or_indexable;
+ Translator const& tr;
+ typename Allocators::size_type found_count;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/destroy.hpp b/boost/geometry/index/detail/rtree/visitors/destroy.hpp
new file mode 100644
index 0000000000..62722b97a8
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/destroy.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry Index
+//
+// R-tree destroying visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class destroy
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
+{
+public:
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Allocators::node_pointer node_pointer;
+
+ inline destroy(node_pointer root_node, Allocators & allocators)
+ : m_current_node(root_node)
+ , m_allocators(allocators)
+ {}
+
+ inline void operator()(internal_node & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_current_node), "invalid pointers");
+
+ node_pointer node_to_destroy = m_current_node;
+
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type & elements = rtree::elements(n);
+
+ for (typename elements_type::iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ m_current_node = it->second;
+ rtree::apply_visitor(*this, *m_current_node);
+ it->second = 0;
+ }
+
+ rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, node_to_destroy);
+ }
+
+ inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(l))
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(&l == &rtree::get<leaf>(*m_current_node), "invalid pointers");
+
+ rtree::destroy_node<Allocators, leaf>::apply(m_allocators, m_current_node);
+ }
+
+private:
+ node_pointer m_current_node;
+ Allocators & m_allocators;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/distance_query.hpp b/boost/geometry/index/detail/rtree/visitors/distance_query.hpp
new file mode 100644
index 0000000000..342cc4bbc3
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/distance_query.hpp
@@ -0,0 +1,580 @@
+// Boost.Geometry Index
+//
+// R-tree distance (knn, path, etc. ) query visitor implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+template <typename Value, typename Translator, typename DistanceType, typename OutIt>
+class distance_query_result
+{
+public:
+ typedef DistanceType distance_type;
+
+ inline explicit distance_query_result(size_t k, OutIt out_it)
+ : m_count(k), m_out_it(out_it)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < m_count, "Number of neighbors should be greater than 0");
+
+ m_neighbors.reserve(m_count);
+ }
+
+ inline void store(Value const& val, distance_type const& curr_comp_dist)
+ {
+ if ( m_neighbors.size() < m_count )
+ {
+ m_neighbors.push_back(std::make_pair(curr_comp_dist, val));
+
+ if ( m_neighbors.size() == m_count )
+ std::make_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
+ }
+ else
+ {
+ if ( curr_comp_dist < m_neighbors.front().first )
+ {
+ std::pop_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
+ m_neighbors.back().first = curr_comp_dist;
+ m_neighbors.back().second = val;
+ std::push_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
+ }
+ }
+ }
+
+ inline bool has_enough_neighbors() const
+ {
+ return m_count <= m_neighbors.size();
+ }
+
+ inline distance_type greatest_comparable_distance() const
+ {
+ // greatest distance is in the first neighbor only
+ // if there is at least m_count values found
+ // this is just for safety reasons since is_comparable_distance_valid() is checked earlier
+ // TODO - may be replaced by ASSERT
+ return m_neighbors.size() < m_count
+ ? (std::numeric_limits<distance_type>::max)()
+ : m_neighbors.front().first;
+ }
+
+ inline size_t finish()
+ {
+ typedef typename std::vector< std::pair<distance_type, Value> >::const_iterator neighbors_iterator;
+ for ( neighbors_iterator it = m_neighbors.begin() ; it != m_neighbors.end() ; ++it, ++m_out_it )
+ *m_out_it = it->second;
+
+ return m_neighbors.size();
+ }
+
+private:
+ inline static bool neighbors_less(
+ std::pair<distance_type, Value> const& p1,
+ std::pair<distance_type, Value> const& p2)
+ {
+ return p1.first < p2.first;
+ }
+
+ size_t m_count;
+ OutIt m_out_it;
+
+ std::vector< std::pair<distance_type, Value> > m_neighbors;
+};
+
+template <
+ typename Value,
+ typename Options,
+ typename Translator,
+ typename Box,
+ typename Allocators,
+ typename Predicates,
+ unsigned DistancePredicateIndex,
+ typename OutIter
+>
+class distance_query
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+public:
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
+ typedef typename nearest_predicate_access::type nearest_predicate_type;
+ typedef typename indexable_type<Translator>::type indexable_type;
+
+ typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, value_tag> calculate_value_distance;
+ typedef index::detail::calculate_distance<nearest_predicate_type, Box, bounds_tag> calculate_node_distance;
+ typedef typename calculate_value_distance::result_type value_distance_type;
+ typedef typename calculate_node_distance::result_type node_distance_type;
+
+ static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
+
+ inline distance_query(parameters_type const& parameters, Translator const& translator, Predicates const& pred, OutIter out_it)
+ : m_parameters(parameters), m_translator(translator)
+ , m_pred(pred)
+ , m_result(nearest_predicate_access::get(m_pred).count, out_it)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+
+ // array of active nodes
+ typedef typename index::detail::rtree::container_from_elements_type<
+ elements_type,
+ std::pair<node_distance_type, typename Allocators::node_pointer>
+ >::type active_branch_list_type;
+
+ active_branch_list_type active_branch_list;
+ active_branch_list.reserve(m_parameters.get_max_elements());
+
+ elements_type const& elements = rtree::elements(n);
+
+ // fill array of nodes meeting predicates
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ // if current node meets predicates
+ // 0 - dummy value
+ if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) )
+ {
+ // calculate node's distance(s) for distance predicate
+ node_distance_type node_distance;
+ // if distance isn't ok - move to the next node
+ if ( !calculate_node_distance::apply(predicate(), it->first, node_distance) )
+ {
+ continue;
+ }
+
+ // if current node is further than found neighbors - don't analyze it
+ if ( m_result.has_enough_neighbors() &&
+ is_node_prunable(m_result.greatest_comparable_distance(), node_distance) )
+ {
+ continue;
+ }
+
+ // add current node's data into the list
+ active_branch_list.push_back( std::make_pair(node_distance, it->second) );
+ }
+ }
+
+ // if there aren't any nodes in ABL - return
+ if ( active_branch_list.empty() )
+ return;
+
+ // sort array
+ std::sort(active_branch_list.begin(), active_branch_list.end(), abl_less);
+
+ // recursively visit nodes
+ for ( typename active_branch_list_type::const_iterator it = active_branch_list.begin();
+ it != active_branch_list.end() ; ++it )
+ {
+ // if current node is further than furthest neighbor, the rest of nodes also will be further
+ if ( m_result.has_enough_neighbors() &&
+ is_node_prunable(m_result.greatest_comparable_distance(), it->first) )
+ break;
+
+ rtree::apply_visitor(*this, *(it->second));
+ }
+
+ // ALTERNATIVE VERSION - use heap instead of sorted container
+ // It seems to be faster for greater MaxElements and slower otherwise
+ // CONSIDER: using one global container/heap for active branches
+ // instead of a sorted container per level
+ // This would also change the way how branches are traversed!
+ // The same may be applied to the iterative version which btw suffers
+ // from the copying of the whole containers on resize of the ABLs container
+
+ //// make a heap
+ //std::make_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater);
+
+ //// recursively visit nodes
+ //while ( !active_branch_list.empty() )
+ //{
+ // //if current node is further than furthest neighbor, the rest of nodes also will be further
+ // if ( m_result.has_enough_neighbors()
+ // && is_node_prunable(m_result.greatest_comparable_distance(), active_branch_list.front().first) )
+ // {
+ // break;
+ // }
+
+ // rtree::apply_visitor(*this, *(active_branch_list.front().second));
+
+ // std::pop_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater);
+ // active_branch_list.pop_back();
+ //}
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // search leaf for closest value meeting predicates
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ // if value meets predicates
+ if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, *it, m_translator(*it)) )
+ {
+ // calculate values distance for distance predicate
+ value_distance_type value_distance;
+ // if distance is ok
+ if ( calculate_value_distance::apply(predicate(), m_translator(*it), value_distance) )
+ {
+ // store value
+ m_result.store(*it, value_distance);
+ }
+ }
+ }
+ }
+
+ inline size_t finish()
+ {
+ return m_result.finish();
+ }
+
+private:
+ static inline bool abl_less(
+ std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
+ std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
+ {
+ return p1.first < p2.first;
+ }
+
+ //static inline bool abl_greater(
+ // std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
+ // std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
+ //{
+ // return p1.first > p2.first;
+ //}
+
+ template <typename Distance>
+ static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d)
+ {
+ return greatest_dist <= d;
+ }
+
+ nearest_predicate_type const& predicate() const
+ {
+ return nearest_predicate_access::get(m_pred);
+ }
+
+ parameters_type const& m_parameters;
+ Translator const& m_translator;
+
+ Predicates m_pred;
+ distance_query_result<Value, Translator, value_distance_type, OutIter> m_result;
+};
+
+template <
+ typename Value,
+ typename Options,
+ typename Translator,
+ typename Box,
+ typename Allocators,
+ typename Predicates,
+ unsigned DistancePredicateIndex
+>
+class distance_query_incremental
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+public:
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
+ typedef typename nearest_predicate_access::type nearest_predicate_type;
+ typedef typename indexable_type<Translator>::type indexable_type;
+
+ typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, value_tag> calculate_value_distance;
+ typedef index::detail::calculate_distance<nearest_predicate_type, Box, bounds_tag> calculate_node_distance;
+ typedef typename calculate_value_distance::result_type value_distance_type;
+ typedef typename calculate_node_distance::result_type node_distance_type;
+
+ typedef typename Allocators::size_type size_type;
+ typedef typename Allocators::const_reference const_reference;
+ typedef typename Allocators::node_pointer node_pointer;
+
+ static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
+
+ typedef typename rtree::elements_type<internal_node>::type internal_elements;
+ typedef typename internal_elements::const_iterator internal_iterator;
+ typedef typename rtree::elements_type<leaf>::type leaf_elements;
+
+ typedef std::pair<node_distance_type, node_pointer> branch_data;
+ typedef typename index::detail::rtree::container_from_elements_type<
+ internal_elements, branch_data
+ >::type active_branch_list_type;
+ struct internal_stack_element
+ {
+ internal_stack_element() : current_branch(0) {}
+#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
+ // Required in c++03 for containers using Boost.Move
+ internal_stack_element & operator=(internal_stack_element const& o)
+ {
+ branches = o.branches;
+ current_branch = o.current_branch;
+ return *this;
+ }
+#endif
+ active_branch_list_type branches;
+ typename active_branch_list_type::size_type current_branch;
+ };
+ typedef std::vector<internal_stack_element> internal_stack_type;
+
+ inline distance_query_incremental(Translator const& translator, Predicates const& pred)
+ : m_translator(::boost::addressof(translator))
+ , m_pred(pred)
+ , current_neighbor((std::numeric_limits<size_type>::max)())
+
+ , next_closest_node_distance((std::numeric_limits<node_distance_type>::max)())
+ {
+ BOOST_ASSERT_MSG(0 < max_count(), "k must be greather than 0");
+ }
+
+ const_reference dereference() const
+ {
+ return *(neighbors[current_neighbor].second);
+ }
+
+ void initialize(node_pointer root)
+ {
+ rtree::apply_visitor(*this, *root);
+ increment();
+ }
+
+ void increment()
+ {
+ for (;;)
+ {
+ size_type new_neighbor = current_neighbor == (std::numeric_limits<size_type>::max)() ? 0 : current_neighbor + 1;
+
+ if ( internal_stack.empty() )
+ {
+ if ( new_neighbor < neighbors.size() )
+ current_neighbor = new_neighbor;
+ else
+ {
+ current_neighbor = (std::numeric_limits<size_type>::max)();
+ // clear() is used to disable the condition above
+ neighbors.clear();
+ }
+
+ return;
+ }
+ else
+ {
+ active_branch_list_type & branches = internal_stack.back().branches;
+ typename active_branch_list_type::size_type & current_branch = internal_stack.back().current_branch;
+
+ if ( branches.size() <= current_branch )
+ {
+ internal_stack.pop_back();
+ continue;
+ }
+
+ // if there are no nodes which can have closer values, set new value
+ if ( new_neighbor < neighbors.size() &&
+ // here must be < because otherwise neighbours may be sorted in different order
+ // if there is another value with equal distance
+ neighbors[new_neighbor].first < next_closest_node_distance )
+ {
+ current_neighbor = new_neighbor;
+ return;
+ }
+
+ // if node is further than the furthest neighbour, following nodes also will be further
+ BOOST_ASSERT_MSG(neighbors.size() <= max_count(), "unexpected neighbours count");
+ if ( max_count() <= neighbors.size() &&
+ is_node_prunable(neighbors.back().first, branches[current_branch].first) )
+ {
+ // stop traversing current level
+ internal_stack.pop_back();
+ continue;
+ }
+ else
+ {
+ // new level - must increment current_branch before traversing of another level (mem reallocation)
+ ++current_branch;
+ rtree::apply_visitor(*this, *(branches[current_branch - 1].second));
+
+ next_closest_node_distance = calc_closest_node_distance(internal_stack.begin(), internal_stack.end());
+ }
+ }
+ }
+ }
+
+ bool is_end() const
+ {
+ return (std::numeric_limits<size_type>::max)() == current_neighbor;
+ }
+
+ friend bool operator==(distance_query_incremental const& l, distance_query_incremental const& r)
+ {
+ BOOST_ASSERT_MSG(l.current_neighbor != r.current_neighbor ||
+ (std::numeric_limits<size_type>::max)() == l.current_neighbor ||
+ l.neighbors[l.current_neighbor].second == r.neighbors[r.current_neighbor].second,
+ "not corresponding iterators");
+ return l.current_neighbor == r.current_neighbor;
+ }
+
+ // Put node's elements into the list of active branches if those elements meets predicates
+ // and distance predicates(currently not used)
+ // and aren't further than found neighbours (if there is enough neighbours)
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // add new element
+ internal_stack.resize(internal_stack.size()+1);
+
+ // fill active branch list array of nodes meeting predicates
+ for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it )
+ {
+ // if current node meets predicates
+ // 0 - dummy value
+ if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) )
+ {
+ // calculate node's distance(s) for distance predicate
+ node_distance_type node_distance;
+ // if distance isn't ok - move to the next node
+ if ( !calculate_node_distance::apply(predicate(), it->first, node_distance) )
+ {
+ continue;
+ }
+
+ // if current node is further than found neighbors - don't analyze it
+ if ( max_count() <= neighbors.size() &&
+ is_node_prunable(neighbors.back().first, node_distance) )
+ {
+ continue;
+ }
+
+ // add current node's data into the list
+ internal_stack.back().branches.push_back( std::make_pair(node_distance, it->second) );
+ }
+ }
+
+ if ( internal_stack.back().branches.empty() )
+ internal_stack.pop_back();
+ else
+ // sort array
+ std::sort(internal_stack.back().branches.begin(), internal_stack.back().branches.end(), abl_less);
+ }
+
+ // Put values into the list of neighbours if those values meets predicates
+ // and distance predicates(currently not used)
+ // and aren't further than already found neighbours (if there is enough neighbours)
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // store distance to the furthest neighbour
+ bool not_enough_neighbors = neighbors.size() < max_count();
+ value_distance_type greatest_distance = !not_enough_neighbors ? neighbors.back().first : (std::numeric_limits<value_distance_type>::max)();
+
+ // search leaf for closest value meeting predicates
+ for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
+ {
+ // if value meets predicates
+ if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, *it, (*m_translator)(*it)) )
+ {
+ // calculate values distance for distance predicate
+ value_distance_type value_distance;
+ // if distance is ok
+ if ( calculate_value_distance::apply(predicate(), (*m_translator)(*it), value_distance) )
+ {
+ // if there is not enough values or current value is closer than furthest neighbour
+ if ( not_enough_neighbors || value_distance < greatest_distance )
+ {
+ neighbors.push_back(std::make_pair(value_distance, boost::addressof(*it)));
+ }
+ }
+ }
+ }
+
+ // sort array
+ std::sort(neighbors.begin(), neighbors.end(), neighbors_less);
+ // remove furthest values
+ if ( max_count() < neighbors.size() )
+ neighbors.resize(max_count());
+ }
+
+private:
+ static inline bool abl_less(std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
+ std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
+ {
+ return p1.first < p2.first;
+ }
+
+ static inline bool neighbors_less(std::pair<value_distance_type, const Value *> const& p1,
+ std::pair<value_distance_type, const Value *> const& p2)
+ {
+ return p1.first < p2.first;
+ }
+
+ node_distance_type
+ calc_closest_node_distance(typename internal_stack_type::const_iterator first,
+ typename internal_stack_type::const_iterator last)
+ {
+ node_distance_type result = (std::numeric_limits<node_distance_type>::max)();
+ for ( ; first != last ; ++first )
+ {
+ if ( first->branches.size() <= first->current_branch )
+ continue;
+
+ node_distance_type curr_dist = first->branches[first->current_branch].first;
+ if ( curr_dist < result )
+ result = curr_dist;
+ }
+ return result;
+ }
+
+ template <typename Distance>
+ static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d)
+ {
+ return greatest_dist <= d;
+ }
+
+ inline unsigned max_count() const
+ {
+ return nearest_predicate_access::get(m_pred).count;
+ }
+
+ nearest_predicate_type const& predicate() const
+ {
+ return nearest_predicate_access::get(m_pred);
+ }
+
+ const Translator * m_translator;
+
+ Predicates m_pred;
+
+ internal_stack_type internal_stack;
+ std::vector< std::pair<value_distance_type, const Value *> > neighbors;
+ size_type current_neighbor;
+ node_distance_type next_closest_node_distance;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/insert.hpp b/boost/geometry/index/detail/rtree/visitors/insert.hpp
new file mode 100644
index 0000000000..388b3193f6
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/insert.hpp
@@ -0,0 +1,527 @@
+// Boost.Geometry Index
+//
+// R-tree inserting visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP
+
+#include <boost/geometry/index/detail/algorithms/content.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree {
+
+// Default choose_next_node
+template <typename Value, typename Options, typename Box, typename Allocators, typename ChooseNextNodeTag>
+class choose_next_node;
+
+template <typename Value, typename Options, typename Box, typename Allocators>
+class choose_next_node<Value, Options, Box, Allocators, choose_by_content_diff_tag>
+{
+public:
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename rtree::elements_type<internal_node>::type children_type;
+
+ typedef typename index::detail::default_content_result<Box>::type content_type;
+
+ template <typename Indexable>
+ static inline size_t apply(internal_node & n,
+ Indexable const& indexable,
+ parameters_type const& /*parameters*/,
+ size_t /*node_relative_level*/)
+ {
+ children_type & children = rtree::elements(n);
+
+ BOOST_GEOMETRY_INDEX_ASSERT(!children.empty(), "can't choose the next node if children are empty");
+
+ size_t children_count = children.size();
+
+ // choose index with smallest content change or smallest content
+ size_t choosen_index = 0;
+ content_type smallest_content_diff = (std::numeric_limits<content_type>::max)();
+ content_type smallest_content = (std::numeric_limits<content_type>::max)();
+
+ // caculate areas and areas of all nodes' boxes
+ for ( size_t i = 0 ; i < children_count ; ++i )
+ {
+ typedef typename children_type::value_type child_type;
+ child_type const& ch_i = children[i];
+
+ // expanded child node's box
+ Box box_exp(ch_i.first);
+ geometry::expand(box_exp, indexable);
+
+ // areas difference
+ content_type content = index::detail::content(box_exp);
+ content_type content_diff = content - index::detail::content(ch_i.first);
+
+ // update the result
+ if ( content_diff < smallest_content_diff ||
+ ( content_diff == smallest_content_diff && content < smallest_content ) )
+ {
+ smallest_content_diff = content_diff;
+ smallest_content = content;
+ choosen_index = i;
+ }
+ }
+
+ return choosen_index;
+ }
+};
+
+// ----------------------------------------------------------------------- //
+
+// Not implemented here
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename RedistributeTag>
+struct redistribute_elements
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_REDISTRIBUTE_TAG_TYPE,
+ (redistribute_elements));
+};
+
+// ----------------------------------------------------------------------- //
+
+// Split algorithm
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename SplitTag>
+class split
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_SPLIT_TAG_TYPE,
+ (split));
+};
+
+// Default split algorithm
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class split<Value, Options, Translator, Box, Allocators, split_default_tag>
+{
+protected:
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+
+public:
+ typedef index::detail::varray<
+ typename rtree::elements_type<internal_node>::type::value_type,
+ 1
+ > nodes_container_type;
+
+ template <typename Node>
+ static inline void apply(nodes_container_type & additional_nodes,
+ Node & n,
+ Box & n_box,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators)
+ {
+ // TODO - consider creating nodes always with sufficient memory allocated
+
+ // create additional node, use auto ptr for automatic destruction on exception
+ node_auto_ptr second_node(rtree::create_node<Allocators, Node>::apply(allocators), allocators); // MAY THROW, STRONG (N: alloc)
+ // create reference to the newly created node
+ Node & n2 = rtree::get<Node>(*second_node);
+
+ // NOTE: thread-safety
+ // After throwing an exception by redistribute_elements the original node may be not changed or
+ // both nodes may be empty. In both cases the tree won't be valid r-tree.
+ // The alternative is to create 2 (or more) additional nodes here and store backup info
+ // in the original node, then, if exception was thrown, the node would always have more than max
+ // elements.
+ // The alternative is to use moving semantics in the implementations of redistribute_elements,
+ // it will be possible to throw from boost::move() in the case of e.g. static size nodes.
+
+ // redistribute elements
+ Box box2;
+ redistribute_elements<
+ Value,
+ Options,
+ Translator,
+ Box,
+ Allocators,
+ typename Options::redistribute_tag
+ >::apply(n, n2, n_box, box2, parameters, translator, allocators); // MAY THROW (V, E: alloc, copy, copy)
+
+ // check numbers of elements
+ BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n).size() &&
+ rtree::elements(n).size() <= parameters.get_max_elements(),
+ "unexpected number of elements");
+ BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n2).size() &&
+ rtree::elements(n2).size() <= parameters.get_max_elements(),
+ "unexpected number of elements");
+
+ // return the list of newly created nodes (this algorithm returns one)
+ additional_nodes.push_back(rtree::make_ptr_pair(box2, second_node.get())); // MAY THROW, STRONG (alloc, copy)
+
+ // release the ptr
+ second_node.release();
+ }
+};
+
+// ----------------------------------------------------------------------- //
+
+namespace visitors { namespace detail {
+
+template <typename InternalNode, typename InternalNodePtr, typename SizeType>
+struct insert_traverse_data
+{
+ typedef typename rtree::elements_type<InternalNode>::type elements_type;
+ typedef typename elements_type::value_type element_type;
+ typedef typename elements_type::size_type elements_size_type;
+ typedef SizeType size_type;
+
+ insert_traverse_data()
+ : parent(0), current_child_index(0), current_level(0)
+ {}
+
+ void move_to_next_level(InternalNodePtr new_parent,
+ elements_size_type new_child_index)
+ {
+ parent = new_parent;
+ current_child_index = new_child_index;
+ ++current_level;
+ }
+
+ bool current_is_root() const
+ {
+ return 0 == parent;
+ }
+
+ elements_type & parent_elements() const
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer");
+ return rtree::elements(*parent);
+ }
+
+ element_type & current_element() const
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer");
+ return rtree::elements(*parent)[current_child_index];
+ }
+
+ InternalNodePtr parent;
+ elements_size_type current_child_index;
+ size_type current_level;
+};
+
+// Default insert visitor
+template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class insert
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
+{
+protected:
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef typename Allocators::size_type size_type;
+
+ //typedef typename Allocators::internal_node_pointer internal_node_pointer;
+ typedef internal_node * internal_node_pointer;
+
+ inline insert(node_pointer & root,
+ size_type & leafs_level,
+ Element const& element,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level = 0
+ )
+ : m_element(element)
+ , m_parameters(parameters)
+ , m_translator(translator)
+ , m_relative_level(relative_level)
+ , m_level(leafs_level - relative_level)
+ , m_root_node(root)
+ , m_leafs_level(leafs_level)
+ , m_traverse_data()
+ , m_allocators(allocators)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(m_relative_level <= leafs_level, "unexpected level value");
+ BOOST_GEOMETRY_INDEX_ASSERT(m_level <= m_leafs_level, "unexpected level value");
+ BOOST_GEOMETRY_INDEX_ASSERT(0 != m_root_node, "there is no root node");
+ // TODO
+ // assert - check if Box is correct
+ }
+
+ template <typename Visitor>
+ inline void traverse(Visitor & visitor, internal_node & n)
+ {
+ // choose next node
+ size_t choosen_node_index = rtree::choose_next_node<Value, Options, Box, Allocators, typename Options::choose_next_node_tag>::
+ apply(n, rtree::element_indexable(m_element, m_translator), m_parameters, m_leafs_level - m_traverse_data.current_level);
+
+ // expand the node to contain value
+ geometry::expand(
+ rtree::elements(n)[choosen_node_index].first,
+ rtree::element_indexable(m_element, m_translator));
+
+ // next traversing step
+ traverse_apply_visitor(visitor, n, choosen_node_index); // MAY THROW (V, E: alloc, copy, N:alloc)
+ }
+
+ // TODO: awulkiew - change post_traverse name to handle_overflow or overflow_treatment?
+
+ template <typename Node>
+ inline void post_traverse(Node &n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(m_traverse_data.current_is_root() ||
+ &n == &rtree::get<Node>(*m_traverse_data.current_element().second),
+ "if node isn't the root current_child_index should be valid");
+
+ // handle overflow
+ if ( m_parameters.get_max_elements() < rtree::elements(n).size() )
+ {
+ // NOTE: If the exception is thrown current node may contain more than MAX elements or be empty.
+ // Furthermore it may be empty root - internal node.
+ split(n); // MAY THROW (V, E: alloc, copy, N:alloc)
+ }
+ }
+
+ template <typename Visitor>
+ inline void traverse_apply_visitor(Visitor & visitor, internal_node &n, size_t choosen_node_index)
+ {
+ // save previous traverse inputs and set new ones
+ insert_traverse_data<internal_node, internal_node_pointer, size_type>
+ backup_traverse_data = m_traverse_data;
+
+ // calculate new traverse inputs
+ m_traverse_data.move_to_next_level(&n, choosen_node_index);
+
+ // next traversing step
+ rtree::apply_visitor(visitor, *rtree::elements(n)[choosen_node_index].second); // MAY THROW (V, E: alloc, copy, N:alloc)
+
+ // restore previous traverse inputs
+ m_traverse_data = backup_traverse_data;
+ }
+
+ // TODO: consider - split result returned as OutIter is faster than reference to the container. Why?
+
+ template <typename Node>
+ inline void split(Node & n) const
+ {
+ typedef rtree::split<Value, Options, Translator, Box, Allocators, typename Options::split_tag> split_algo;
+
+ typename split_algo::nodes_container_type additional_nodes;
+ Box n_box;
+
+ split_algo::apply(additional_nodes, n, n_box, m_parameters, m_translator, m_allocators); // MAY THROW (V, E: alloc, copy, N:alloc)
+
+ BOOST_GEOMETRY_INDEX_ASSERT(additional_nodes.size() == 1, "unexpected number of additional nodes");
+
+ // TODO add all additional nodes
+ // For kmeans algorithm:
+ // elements number may be greater than node max elements count
+ // split and reinsert must take node with some elements count
+ // and container of additional elements (std::pair<Box, node*>s or Values)
+ // and translator + allocators
+ // where node_elements_count + additional_elements > node_max_elements_count
+ // What with elements other than std::pair<Box, node*> ?
+ // Implement template <node_tag> struct node_element_type or something like that
+
+ // for exception safety
+ node_auto_ptr additional_node_ptr(additional_nodes[0].second, m_allocators);
+
+ // node is not the root - just add the new node
+ if ( !m_traverse_data.current_is_root() )
+ {
+ // update old node's box
+ m_traverse_data.current_element().first = n_box;
+ // add new node to parent's children
+ m_traverse_data.parent_elements().push_back(additional_nodes[0]); // MAY THROW, STRONG (V, E: alloc, copy)
+ }
+ // node is the root - add level
+ else
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*m_root_node), "node should be the root");
+
+ // create new root and add nodes
+ node_auto_ptr new_root(rtree::create_node<Allocators, internal_node>::apply(m_allocators), m_allocators); // MAY THROW, STRONG (N:alloc)
+
+ BOOST_TRY
+ {
+ rtree::elements(rtree::get<internal_node>(*new_root)).push_back(rtree::make_ptr_pair(n_box, m_root_node)); // MAY THROW, STRONG (E:alloc, copy)
+ rtree::elements(rtree::get<internal_node>(*new_root)).push_back(additional_nodes[0]); // MAY THROW, STRONG (E:alloc, copy)
+ }
+ BOOST_CATCH(...)
+ {
+ // clear new root to not delete in the ~node_auto_ptr() potentially stored old root node
+ rtree::elements(rtree::get<internal_node>(*new_root)).clear();
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+
+ m_root_node = new_root.get();
+ ++m_leafs_level;
+
+ new_root.release();
+ }
+
+ additional_node_ptr.release();
+ }
+
+ // TODO: awulkiew - implement dispatchable split::apply to enable additional nodes creation
+
+ Element const& m_element;
+ parameters_type const& m_parameters;
+ Translator const& m_translator;
+ size_type const m_relative_level;
+ size_type const m_level;
+
+ node_pointer & m_root_node;
+ size_type & m_leafs_level;
+
+ // traversing input parameters
+ insert_traverse_data<internal_node, internal_node_pointer, size_type> m_traverse_data;
+
+ Allocators & m_allocators;
+};
+
+} // namespace detail
+
+// Insert visitor forward declaration
+template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename InsertTag>
+class insert;
+
+// Default insert visitor used for nodes elements
+// After passing the Element to insert visitor the Element is managed by the tree
+// I.e. one should not delete the node passed to the insert visitor after exception is thrown
+// because this visitor may delete it
+template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class insert<Element, Value, Options, Translator, Box, Allocators, insert_default_tag>
+ : public detail::insert<Element, Value, Options, Translator, Box, Allocators>
+{
+public:
+ typedef detail::insert<Element, Value, Options, Translator, Box, Allocators> base;
+ typedef typename base::node node;
+ typedef typename base::internal_node internal_node;
+ typedef typename base::leaf leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+ typedef typename base::node_pointer node_pointer;
+ typedef typename base::size_type size_type;
+
+ inline insert(node_pointer & root,
+ size_type & leafs_level,
+ Element const& element,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level = 0
+ )
+ : base(root, leafs_level, element, parameters, translator, allocators, relative_level)
+ {}
+
+ inline void operator()(internal_node & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
+
+ if ( base::m_traverse_data.current_level < base::m_level )
+ {
+ // next traversing step
+ base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc)
+ }
+ else
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level");
+
+ BOOST_TRY
+ {
+ // push new child node
+ rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy)
+ }
+ BOOST_CATCH(...)
+ {
+ // if the insert fails above, the element won't be stored in the tree
+
+ rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(base::m_element.second, base::m_allocators);
+ rtree::apply_visitor(del_v, *base::m_element.second);
+
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ base::post_traverse(n); // MAY THROW (E: alloc, copy, N: alloc)
+ }
+
+ inline void operator()(leaf &)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf");
+ }
+};
+
+// Default insert visitor specialized for Values elements
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class insert<Value, Value, Options, Translator, Box, Allocators, insert_default_tag>
+ : public detail::insert<Value, Value, Options, Translator, Box, Allocators>
+{
+public:
+ typedef detail::insert<Value, Value, Options, Translator, Box, Allocators> base;
+ typedef typename base::node node;
+ typedef typename base::internal_node internal_node;
+ typedef typename base::leaf leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+ typedef typename base::node_pointer node_pointer;
+ typedef typename base::size_type size_type;
+
+ inline insert(node_pointer & root,
+ size_type & leafs_level,
+ Value const& value,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators,
+ size_type relative_level = 0
+ )
+ : base(root, leafs_level, value, parameters, translator, allocators, relative_level)
+ {}
+
+ inline void operator()(internal_node & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
+
+ // next traversing step
+ base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ base::post_traverse(n); // MAY THROW (E: alloc, copy, N: alloc)
+ }
+
+ inline void operator()(leaf & n)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level, "unexpected level");
+ BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
+ base::m_level == (std::numeric_limits<size_t>::max)(), "unexpected level");
+
+ rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
+
+ base::post_traverse(n); // MAY THROW (V: alloc, copy, N: alloc)
+ }
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp b/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp
new file mode 100644
index 0000000000..6d21afd99e
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp
@@ -0,0 +1,41 @@
+// Boost.Geometry Index
+//
+// R-tree leaf node checking visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+template <typename Value, typename Options, typename Box, typename Allocators>
+struct is_leaf : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ inline void operator()(internal_node const&)
+ {
+ result = false;
+ }
+
+ inline void operator()(leaf const&)
+ {
+ result = true;
+ }
+
+ bool result;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/remove.hpp b/boost/geometry/index/detail/rtree/visitors/remove.hpp
new file mode 100644
index 0000000000..d4890a368b
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/remove.hpp
@@ -0,0 +1,326 @@
+// Boost.Geometry Index
+//
+// R-tree removing visitor implementation
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP
+
+#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+// Default remove algorithm
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class remove
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
+{
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef typename Allocators::size_type size_type;
+
+ typedef typename rtree::elements_type<internal_node>::type::size_type internal_size_type;
+
+ //typedef typename Allocators::internal_node_pointer internal_node_pointer;
+ typedef internal_node * internal_node_pointer;
+
+public:
+ inline remove(node_pointer & root,
+ size_type & leafs_level,
+ Value const& value,
+ parameters_type const& parameters,
+ Translator const& translator,
+ Allocators & allocators)
+ : m_value(value)
+ , m_parameters(parameters)
+ , m_translator(translator)
+ , m_allocators(allocators)
+ , m_root_node(root)
+ , m_leafs_level(leafs_level)
+ , m_is_value_removed(false)
+ , m_parent(0)
+ , m_current_child_index(0)
+ , m_current_level(0)
+ , m_is_underflow(false)
+ {
+ // TODO
+ // assert - check if Value/Box is correct
+ }
+
+ inline void operator()(internal_node & n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type children_type;
+ children_type & children = rtree::elements(n);
+
+ // traverse children which boxes intersects value's box
+ internal_size_type child_node_index = 0;
+ for ( ; child_node_index < children.size() ; ++child_node_index )
+ {
+ if ( geometry::covered_by(
+ return_ref_or_bounds(m_translator(m_value)),
+ children[child_node_index].first) )
+ {
+ // next traversing step
+ traverse_apply_visitor(n, child_node_index); // MAY THROW
+
+ if ( m_is_value_removed )
+ break;
+ }
+ }
+
+ // value was found and removed
+ if ( m_is_value_removed )
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ typedef typename elements_type::iterator element_iterator;
+ elements_type & elements = rtree::elements(n);
+
+ // underflow occured - child node should be removed
+ if ( m_is_underflow )
+ {
+ element_iterator underfl_el_it = elements.begin() + child_node_index;
+ size_type relative_level = m_leafs_level - m_current_level;
+
+ // move node to the container - store node's relative level as well and return new underflow state
+ m_is_underflow = store_underflowed_node(elements, underfl_el_it, relative_level); // MAY THROW (E: alloc, copy)
+ }
+
+ // n is not root - adjust aabb
+ if ( 0 != m_parent )
+ {
+ // underflow state should be ok here
+ // note that there may be less than min_elems elements in root
+ // so this condition should be checked only here
+ BOOST_GEOMETRY_INDEX_ASSERT((elements.size() < m_parameters.get_min_elements()) == m_is_underflow, "unexpected state");
+
+ rtree::elements(*m_parent)[m_current_child_index].first
+ = rtree::elements_box<Box>(elements.begin(), elements.end(), m_translator);
+ }
+ // n is root node
+ else
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root_node), "node must be the root");
+
+ // reinsert elements from removed nodes (underflows)
+ reinsert_removed_nodes_elements(); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ // shorten the tree
+ if ( rtree::elements(n).size() == 1 )
+ {
+ node_pointer root_to_destroy = m_root_node;
+ m_root_node = rtree::elements(n)[0].second;
+ --m_leafs_level;
+
+ rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, root_to_destroy);
+ }
+ }
+ }
+ }
+
+ inline void operator()(leaf & n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type & elements = rtree::elements(n);
+
+ // find value and remove it
+ for ( typename elements_type::iterator it = elements.begin() ; it != elements.end() ; ++it )
+ {
+ if ( m_translator.equals(*it, m_value) )
+ {
+ rtree::move_from_back(elements, it); // MAY THROW (V: copy)
+ elements.pop_back();
+ m_is_value_removed = true;
+ break;
+ }
+ }
+
+ // if value was removed
+ if ( m_is_value_removed )
+ {
+ BOOST_ASSERT_MSG(0 < m_parameters.get_min_elements(), "min number of elements is too small");
+
+ // calc underflow
+ m_is_underflow = elements.size() < m_parameters.get_min_elements();
+
+ // n is not root - adjust aabb
+ if ( 0 != m_parent )
+ {
+ rtree::elements(*m_parent)[m_current_child_index].first
+ = rtree::elements_box<Box>(elements.begin(), elements.end(), m_translator);
+ }
+ }
+ }
+
+ bool is_value_removed() const
+ {
+ return m_is_value_removed;
+ }
+
+private:
+
+ typedef std::vector< std::pair<size_type, node_pointer> > UnderflowNodes;
+
+ void traverse_apply_visitor(internal_node &n, internal_size_type choosen_node_index)
+ {
+ // save previous traverse inputs and set new ones
+ internal_node_pointer parent_bckup = m_parent;
+ internal_size_type current_child_index_bckup = m_current_child_index;
+ size_type current_level_bckup = m_current_level;
+
+ m_parent = &n;
+ m_current_child_index = choosen_node_index;
+ ++m_current_level;
+
+ // next traversing step
+ rtree::apply_visitor(*this, *rtree::elements(n)[choosen_node_index].second); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ // restore previous traverse inputs
+ m_parent = parent_bckup;
+ m_current_child_index = current_child_index_bckup;
+ m_current_level = current_level_bckup;
+ }
+
+ bool store_underflowed_node(
+ typename rtree::elements_type<internal_node>::type & elements,
+ typename rtree::elements_type<internal_node>::type::iterator underfl_el_it,
+ size_type relative_level)
+ {
+ // move node to the container - store node's relative level as well
+ m_underflowed_nodes.push_back(std::make_pair(relative_level, underfl_el_it->second)); // MAY THROW (E: alloc, copy)
+
+ BOOST_TRY
+ {
+ // NOTE: those are elements of the internal node which means that copy/move shouldn't throw
+ // Though it's safer in case if the pointer type could throw in copy ctor.
+ // In the future this try-catch block could be removed.
+ rtree::move_from_back(elements, underfl_el_it); // MAY THROW (E: copy)
+ elements.pop_back();
+ }
+ BOOST_CATCH(...)
+ {
+ m_underflowed_nodes.pop_back();
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+
+ // calc underflow
+ return elements.size() < m_parameters.get_min_elements();
+ }
+
+ void reinsert_removed_nodes_elements()
+ {
+ typename UnderflowNodes::reverse_iterator it = m_underflowed_nodes.rbegin();
+
+ BOOST_TRY
+ {
+ // reinsert elements from removed nodes
+ // begin with levels closer to the root
+ for ( ; it != m_underflowed_nodes.rend() ; ++it )
+ {
+ is_leaf<Value, Options, Box, Allocators> ilv;
+ rtree::apply_visitor(ilv, *it->second);
+ if ( ilv.result )
+ {
+ reinsert_node_elements(rtree::get<leaf>(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ rtree::destroy_node<Allocators, leaf>::apply(m_allocators, it->second);
+ }
+ else
+ {
+ reinsert_node_elements(rtree::get<internal_node>(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, it->second);
+ }
+ }
+
+ //m_underflowed_nodes.clear();
+ }
+ BOOST_CATCH(...)
+ {
+ // destroy current and remaining nodes
+ for ( ; it != m_underflowed_nodes.rend() ; ++it )
+ {
+ node_auto_ptr dummy(it->second, m_allocators);
+ }
+
+ //m_underflowed_nodes.clear();
+
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ template <typename Node>
+ void reinsert_node_elements(Node &n, size_type node_relative_level)
+ {
+ typedef typename rtree::elements_type<Node>::type elements_type;
+ elements_type & elements = rtree::elements(n);
+
+ typename elements_type::iterator it = elements.begin();
+ BOOST_TRY
+ {
+ for ( ; it != elements.end() ; ++it )
+ {
+ visitors::insert<
+ typename elements_type::value_type,
+ Value, Options, Translator, Box, Allocators,
+ typename Options::insert_tag
+ > insert_v(
+ m_root_node, m_leafs_level, *it,
+ m_parameters, m_translator, m_allocators,
+ node_relative_level - 1);
+
+ rtree::apply_visitor(insert_v, *m_root_node); // MAY THROW (V, E: alloc, copy, N: alloc)
+ }
+ }
+ BOOST_CATCH(...)
+ {
+ ++it;
+ rtree::destroy_elements<Value, Options, Translator, Box, Allocators>
+ ::apply(it, elements.end(), m_allocators);
+ elements.clear();
+ BOOST_RETHROW // RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ Value const& m_value;
+ parameters_type const& m_parameters;
+ Translator const& m_translator;
+ Allocators & m_allocators;
+
+ node_pointer & m_root_node;
+ size_type & m_leafs_level;
+
+ bool m_is_value_removed;
+ UnderflowNodes m_underflowed_nodes;
+
+ // traversing input parameters
+ internal_node_pointer m_parent;
+ internal_size_type m_current_child_index;
+ size_type m_current_level;
+
+ // traversing output parameters
+ bool m_is_underflow;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP
diff --git a/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp b/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp
new file mode 100644
index 0000000000..0a43111ac4
--- /dev/null
+++ b/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp
@@ -0,0 +1,206 @@
+// Boost.Geometry Index
+//
+// R-tree spatial query visitor implementation
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail { namespace rtree { namespace visitors {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates, typename OutIter>
+struct spatial_query
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Allocators::size_type size_type;
+
+ static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
+
+ inline spatial_query(Translator const& t, Predicates const& p, OutIter out_it)
+ : tr(t), pred(p), out_iter(out_it), found_count(0)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // traverse nodes meeting predicates
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ // if node meets predicates
+ // 0 - dummy value
+ if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(pred, 0, it->first) )
+ rtree::apply_visitor(*this, *it->second);
+ }
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // get all values meeting predicates
+ for (typename elements_type::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ // if value meets predicates
+ if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(pred, *it, tr(*it)) )
+ {
+ *out_iter = *it;
+ ++out_iter;
+
+ ++found_count;
+ }
+ }
+ }
+
+ Translator const& tr;
+
+ Predicates pred;
+
+ OutIter out_iter;
+ size_type found_count;
+};
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates>
+class spatial_query_incremental
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+public:
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Allocators::size_type size_type;
+ typedef typename Allocators::const_reference const_reference;
+ typedef typename Allocators::node_pointer node_pointer;
+
+ typedef typename rtree::elements_type<internal_node>::type::const_iterator internal_iterator;
+ typedef typename rtree::elements_type<leaf>::type leaf_elements;
+ typedef typename rtree::elements_type<leaf>::type::const_iterator leaf_iterator;
+
+ static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
+
+ inline spatial_query_incremental(Translator const& t, Predicates const& p)
+ : m_translator(::boost::addressof(t))
+ , m_pred(p)
+ , m_values(0)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ m_internal_stack.push_back(std::make_pair(elements.begin(), elements.end()));
+ }
+
+ inline void operator()(leaf const& n)
+ {
+ m_values = ::boost::addressof(rtree::elements(n));
+ m_current = rtree::elements(n).begin();
+ }
+
+ const_reference dereference() const
+ {
+ BOOST_ASSERT_MSG(m_values, "not dereferencable");
+ return *m_current;
+ }
+
+ void initialize(node_pointer root)
+ {
+ rtree::apply_visitor(*this, *root);
+ search_value();
+ }
+
+ void increment()
+ {
+ ++m_current;
+ search_value();
+ }
+
+ void search_value()
+ {
+ for (;;)
+ {
+ // if leaf is choosen, move to the next value in leaf
+ if ( m_values )
+ {
+ if ( m_current != m_values->end() )
+ {
+ // return if next value is found
+ Value const& v = *m_current;
+ if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, v, (*m_translator)(v)) )
+ return;
+
+ ++m_current;
+ }
+ // no more values, clear current leaf
+ else
+ {
+ m_values = 0;
+ }
+ }
+ // if leaf isn't choosen, move to the next leaf
+ else
+ {
+ // return if there is no more nodes to traverse
+ if ( m_internal_stack.empty() )
+ return;
+
+ // no more children in current node, remove it from stack
+ if ( m_internal_stack.back().first == m_internal_stack.back().second )
+ {
+ m_internal_stack.pop_back();
+ continue;
+ }
+
+ internal_iterator it = m_internal_stack.back().first;
+ ++m_internal_stack.back().first;
+
+ // next node is found, push it to the stack
+ if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) )
+ rtree::apply_visitor(*this, *(it->second));
+ }
+ }
+ }
+
+ bool is_end() const
+ {
+ return 0 == m_values;
+ }
+
+ friend bool operator==(spatial_query_incremental const& l, spatial_query_incremental const& r)
+ {
+ return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current );
+ }
+
+private:
+
+ const Translator * m_translator;
+
+ Predicates m_pred;
+
+ std::vector< std::pair<internal_iterator, internal_iterator> > m_internal_stack;
+ const leaf_elements * m_values;
+ leaf_iterator m_current;
+};
+
+}}} // namespace detail::rtree::visitors
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP
diff --git a/boost/geometry/index/detail/serialization.hpp b/boost/geometry/index/detail/serialization.hpp
new file mode 100644
index 0000000000..34036e3904
--- /dev/null
+++ b/boost/geometry/index/detail/serialization.hpp
@@ -0,0 +1,585 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP
+
+//#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/split_member.hpp>
+#include <boost/serialization/version.hpp>
+//#include <boost/serialization/nvp.hpp>
+
+// TODO
+// how about using the unsigned type capable of storing Max in compile-time versions?
+
+// TODO
+// - add wrappers for Point and Box and implement serialize for those wrappers instead of
+// raw geometries
+// PROBLEM: after implementing this, how Values would be set?
+// - store the name of the parameters to know how to load and detect errors
+// - in the header, once store info about the Indexable and Bounds types (geometry type, point CS, Dim, etc.)
+// each geometry save without this info
+
+// TODO - move to index/detail/serialization.hpp
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+// TODO - use boost::move?
+template<typename T>
+class serialization_storage
+{
+public:
+ template <typename Archive>
+ serialization_storage(Archive & ar, unsigned int version)
+ {
+ boost::serialization::load_construct_data_adl(ar, this->address(), version);
+ }
+ ~serialization_storage()
+ {
+ this->address()->~T();
+ }
+ T * address()
+ {
+ return static_cast<T*>(m_storage.address());
+ }
+private:
+ boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value> m_storage;
+};
+
+// TODO - save and load item_version? see: collections_load_imp and collections_save_imp
+// this should be done once for the whole container
+// versions of all used types should be stored
+
+template <typename T, typename Archive> inline
+T serialization_load(const char * name, Archive & ar)
+{
+ namespace bs = boost::serialization;
+ serialization_storage<T> storage(ar, bs::version<T>::value); // load_construct_data
+ ar >> boost::serialization::make_nvp(name, *storage.address()); // serialize
+ //ar >> *storage.address(); // serialize
+ return *storage.address();
+}
+
+template <typename T, typename Archive> inline
+void serialization_save(T const& t, const char * name, Archive & ar)
+{
+ namespace bs = boost::serialization;
+ bs::save_construct_data_adl(ar, boost::addressof(t), bs::version<T>::value); // save_construct_data
+ ar << boost::serialization::make_nvp(name, t); // serialize
+ //ar << t; // serialize
+}
+
+}}}}
+
+// TODO - move to index/serialization/rtree.hpp
+namespace boost { namespace serialization {
+
+// boost::geometry::index::linear
+
+template<class Archive, size_t Max, size_t Min>
+void save_construct_data(Archive & ar, const boost::geometry::index::linear<Max, Min> * params, unsigned int )
+{
+ size_t max = params->get_max_elements(), min = params->get_min_elements();
+ ar << boost::serialization::make_nvp("max", max);
+ ar << boost::serialization::make_nvp("min", min);
+}
+template<class Archive, size_t Max, size_t Min>
+void load_construct_data(Archive & ar, boost::geometry::index::linear<Max, Min> * params, unsigned int )
+{
+ size_t max, min;
+ ar >> boost::serialization::make_nvp("max", max);
+ ar >> boost::serialization::make_nvp("min", min);
+ if ( max != params->get_max_elements() || min != params->get_min_elements() )
+ // TODO change exception type
+ BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
+ // the constructor musn't be called for this type
+ //::new(params)boost::geometry::index::linear<Max, Min>();
+}
+template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::linear<Max, Min> &, unsigned int) {}
+
+// boost::geometry::index::quadratic
+
+template<class Archive, size_t Max, size_t Min>
+void save_construct_data(Archive & ar, const boost::geometry::index::quadratic<Max, Min> * params, unsigned int )
+{
+ size_t max = params->get_max_elements(), min = params->get_min_elements();
+ ar << boost::serialization::make_nvp("max", max);
+ ar << boost::serialization::make_nvp("min", min);
+}
+template<class Archive, size_t Max, size_t Min>
+void load_construct_data(Archive & ar, boost::geometry::index::quadratic<Max, Min> * params, unsigned int )
+{
+ size_t max, min;
+ ar >> boost::serialization::make_nvp("max", max);
+ ar >> boost::serialization::make_nvp("min", min);
+ if ( max != params->get_max_elements() || min != params->get_min_elements() )
+ // TODO change exception type
+ BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
+ // the constructor musn't be called for this type
+ //::new(params)boost::geometry::index::quadratic<Max, Min>();
+}
+template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::quadratic<Max, Min> &, unsigned int) {}
+
+// boost::geometry::index::rstar
+
+template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
+void save_construct_data(Archive & ar, const boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int )
+{
+ size_t max = params->get_max_elements()
+ , min = params->get_min_elements()
+ , re = params->get_reinserted_elements()
+ , oct = params->get_overlap_cost_threshold();
+ ar << boost::serialization::make_nvp("max", max);
+ ar << boost::serialization::make_nvp("min", min);
+ ar << boost::serialization::make_nvp("re", re);
+ ar << boost::serialization::make_nvp("oct", oct);
+}
+template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
+void load_construct_data(Archive & ar, boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int )
+{
+ size_t max, min, re, oct;
+ ar >> boost::serialization::make_nvp("max", max);
+ ar >> boost::serialization::make_nvp("min", min);
+ ar >> boost::serialization::make_nvp("re", re);
+ ar >> boost::serialization::make_nvp("oct", oct);
+ if ( max != params->get_max_elements() || min != params->get_min_elements() ||
+ re != params->get_reinserted_elements() || oct != params->get_overlap_cost_threshold() )
+ // TODO change exception type
+ BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
+ // the constructor musn't be called for this type
+ //::new(params)boost::geometry::index::rstar<Max, Min, RE, OCT>();
+}
+template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
+void serialize(Archive &, boost::geometry::index::rstar<Max, Min, RE, OCT> &, unsigned int) {}
+
+// boost::geometry::index::dynamic_linear
+
+template<class Archive>
+inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_linear * params, unsigned int )
+{
+ size_t max = params->get_max_elements(), min = params->get_min_elements();
+ ar << boost::serialization::make_nvp("max", max);
+ ar << boost::serialization::make_nvp("min", min);
+}
+template<class Archive>
+inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_linear * params, unsigned int )
+{
+ size_t max, min;
+ ar >> boost::serialization::make_nvp("max", max);
+ ar >> boost::serialization::make_nvp("min", min);
+ ::new(params)boost::geometry::index::dynamic_linear(max, min);
+}
+template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_linear &, unsigned int) {}
+
+// boost::geometry::index::dynamic_quadratic
+
+template<class Archive>
+inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_quadratic * params, unsigned int )
+{
+ size_t max = params->get_max_elements(), min = params->get_min_elements();
+ ar << boost::serialization::make_nvp("max", max);
+ ar << boost::serialization::make_nvp("min", min);
+}
+template<class Archive>
+inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_quadratic * params, unsigned int )
+{
+ size_t max, min;
+ ar >> boost::serialization::make_nvp("max", max);
+ ar >> boost::serialization::make_nvp("min", min);
+ ::new(params)boost::geometry::index::dynamic_quadratic(max, min);
+}
+template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_quadratic &, unsigned int) {}
+
+// boost::geometry::index::dynamic_rstar
+
+template<class Archive>
+inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_rstar * params, unsigned int )
+{
+ size_t max = params->get_max_elements()
+ , min = params->get_min_elements()
+ , re = params->get_reinserted_elements()
+ , oct = params->get_overlap_cost_threshold();
+ ar << boost::serialization::make_nvp("max", max);
+ ar << boost::serialization::make_nvp("min", min);
+ ar << boost::serialization::make_nvp("re", re);
+ ar << boost::serialization::make_nvp("oct", oct);
+}
+template<class Archive>
+inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_rstar * params, unsigned int )
+{
+ size_t max, min, re, oct;
+ ar >> boost::serialization::make_nvp("max", max);
+ ar >> boost::serialization::make_nvp("min", min);
+ ar >> boost::serialization::make_nvp("re", re);
+ ar >> boost::serialization::make_nvp("oct", oct);
+ ::new(params)boost::geometry::index::dynamic_rstar(max, min, re, oct);
+}
+template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_rstar &, unsigned int) {}
+
+}} // boost::serialization
+
+// TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename P, size_t I = 0, size_t D = geometry::dimension<P>::value>
+struct serialize_point
+{
+ template <typename Archive>
+ static inline void save(Archive & ar, P const& p, unsigned int version)
+ {
+ typename coordinate_type<P>::type c = get<I>(p);
+ ar << boost::serialization::make_nvp("c", c);
+ serialize_point<P, I+1, D>::save(ar, p, version);
+ }
+
+ template <typename Archive>
+ static inline void load(Archive & ar, P & p, unsigned int version)
+ {
+ typename geometry::coordinate_type<P>::type c;
+ ar >> boost::serialization::make_nvp("c", c);
+ set<I>(p, c);
+ serialize_point<P, I+1, D>::load(ar, p, version);
+ }
+};
+
+template <typename P, size_t D>
+struct serialize_point<P, D, D>
+{
+ template <typename Archive> static inline void save(Archive &, P const&, unsigned int) {}
+ template <typename Archive> static inline void load(Archive &, P &, unsigned int) {}
+};
+
+}}}}
+
+// TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp
+namespace boost { namespace serialization {
+
+template<class Archive, typename T, size_t D, typename C>
+void save(Archive & ar, boost::geometry::model::point<T, D, C> const& p, unsigned int version)
+{
+ boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::save(ar, p, version);
+}
+template<class Archive, typename T, size_t D, typename C>
+void load(Archive & ar, boost::geometry::model::point<T, D, C> & p, unsigned int version)
+{
+ boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::load(ar, p, version);
+}
+template<class Archive, typename T, size_t D, typename C>
+inline void serialize(Archive & ar, boost::geometry::model::point<T, D, C> & o, const unsigned int version) { split_free(ar, o, version); }
+
+template<class Archive, typename P>
+inline void serialize(Archive & ar, boost::geometry::model::box<P> & b, const unsigned int)
+{
+ ar & boost::serialization::make_nvp("min", b.min_corner());
+ ar & boost::serialization::make_nvp("max", b.max_corner());
+}
+
+}} // boost::serialization
+
+// TODO - move to index/detail/rtree/visitors/save.hpp
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors {
+
+// TODO move saving and loading of the rtree outside the rtree, this will require adding some kind of members_view
+
+template <typename Archive, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class save
+ : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
+{
+public:
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ save(Archive & archive, unsigned int version)
+ : m_archive(archive), m_version(version)
+ {}
+
+ inline void operator()(internal_node const& n)
+ {
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ elements_type const& elements = rtree::elements(n);
+
+ // CONSIDER: change to elements_type::size_type or size_type
+ // or use fixed-size type like uint32 or even uint16?
+ size_t s = elements.size();
+ m_archive << boost::serialization::make_nvp("s", s);
+
+ for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
+ {
+ serialization_save(it->first, "b", m_archive);
+
+ rtree::apply_visitor(*this, *it->second);
+ }
+ }
+
+ inline void operator()(leaf const& l)
+ {
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ //typedef typename elements_type::size_type elements_size;
+ elements_type const& elements = rtree::elements(l);
+
+ // CONSIDER: change to elements_type::size_type or size_type
+ // or use fixed-size type like uint32 or even uint16?
+ size_t s = elements.size();
+ m_archive << boost::serialization::make_nvp("s", s);
+
+ for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
+ {
+ serialization_save(*it, "v", m_archive);
+ }
+ }
+
+private:
+ Archive & m_archive;
+ unsigned int m_version;
+};
+
+}}}}}} // boost::geometry::index::detail::rtree::visitors
+
+// TODO - move to index/detail/rtree/load.hpp
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
+
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+class load
+{
+ typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
+ typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename Allocators::node_pointer node_pointer;
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+ typedef typename Allocators::size_type size_type;
+
+public:
+ template <typename Archive> inline static
+ node_pointer apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, Translator const& translator, Allocators & allocators)
+ {
+ values_count = 0;
+ return raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators);
+ }
+
+private:
+ template <typename Archive> inline static
+ node_pointer raw_apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, Translator const& translator, Allocators & allocators, size_type current_level = 0)
+ {
+ //BOOST_GEOMETRY_INDEX_ASSERT(current_level <= leafs_level, "invalid parameter");
+
+ typedef typename rtree::elements_type<internal_node>::type elements_type;
+ typedef typename elements_type::value_type element_type;
+ //typedef typename elements_type::size_type elements_size;
+
+ // CONSIDER: change to elements_type::size_type or size_type
+ // or use fixed-size type like uint32 or even uint16?
+ size_t elements_count;
+ ar >> boost::serialization::make_nvp("s", elements_count);
+
+ if ( elements_count < parameters.get_min_elements() || parameters.get_max_elements() < elements_count )
+ BOOST_THROW_EXCEPTION(std::runtime_error("rtree loading error"));
+
+ if ( current_level < leafs_level )
+ {
+ node_pointer n = rtree::create_node<Allocators, internal_node>::apply(allocators); // MAY THROW (A)
+ node_auto_ptr auto_remover(n, allocators);
+ internal_node & in = rtree::get<internal_node>(*n);
+
+ elements_type & elements = rtree::elements(in);
+
+ elements.reserve(elements_count); // MAY THROW (A)
+
+ for ( size_t i = 0 ; i < elements_count ; ++i )
+ {
+ typedef typename elements_type::value_type::first_type box_type;
+ box_type b = serialization_load<box_type>("b", ar);
+ node_pointer n = raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators, current_level+1); // recursive call
+ elements.push_back(element_type(b, n));
+ }
+
+ auto_remover.release();
+ return n;
+ }
+ else
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(current_level == leafs_level, "unexpected value");
+
+ node_pointer n = rtree::create_node<Allocators, leaf>::apply(allocators); // MAY THROW (A)
+ node_auto_ptr auto_remover(n, allocators);
+ leaf & l = rtree::get<leaf>(*n);
+
+ typedef typename rtree::elements_type<leaf>::type elements_type;
+ typedef typename elements_type::value_type element_type;
+ elements_type & elements = rtree::elements(l);
+
+ values_count += elements_count;
+
+ elements.reserve(elements_count); // MAY THROW (A)
+
+ for ( size_t i = 0 ; i < elements_count ; ++i )
+ {
+ element_type el = serialization_load<element_type>("v", ar); // MAY THROW (C)
+ elements.push_back(el); // MAY THROW (C)
+ }
+
+ auto_remover.release();
+ return n;
+ }
+ }
+};
+
+}}}}} // boost::geometry::index::detail::rtree
+
+// TODO - move to index/detail/rtree/private_view.hpp
+namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
+
+template <typename Rtree>
+class const_private_view
+{
+public:
+ typedef typename Rtree::size_type size_type;
+
+ typedef typename Rtree::translator_type translator_type;
+ typedef typename Rtree::value_type value_type;
+ typedef typename Rtree::options_type options_type;
+ typedef typename Rtree::box_type box_type;
+ typedef typename Rtree::allocators_type allocators_type;
+
+ const_private_view(Rtree const& rt) : m_rtree(rt) {}
+
+ typedef typename Rtree::members_holder members_holder;
+
+ members_holder const& members() const { return m_rtree.m_members; }
+
+private:
+ const_private_view(const_private_view const&);
+ const_private_view & operator=(const_private_view const&);
+
+ Rtree const& m_rtree;
+};
+
+template <typename Rtree>
+class private_view
+{
+public:
+ typedef typename Rtree::size_type size_type;
+
+ typedef typename Rtree::translator_type translator_type;
+ typedef typename Rtree::value_type value_type;
+ typedef typename Rtree::options_type options_type;
+ typedef typename Rtree::box_type box_type;
+ typedef typename Rtree::allocators_type allocators_type;
+
+ private_view(Rtree & rt) : m_rtree(rt) {}
+
+ typedef typename Rtree::members_holder members_holder;
+
+ members_holder & members() { return m_rtree.m_members; }
+ members_holder const& members() const { return m_rtree.m_members; }
+
+private:
+ private_view(private_view const&);
+ private_view & operator=(private_view const&);
+
+ Rtree & m_rtree;
+};
+
+}}}}} // namespace boost::geometry::index::detail::rtree
+
+// TODO - move to index/serialization/rtree.hpp
+namespace boost { namespace serialization {
+
+template<class Archive, typename V, typename P, typename I, typename E, typename A>
+void save(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version)
+{
+ namespace detail = boost::geometry::index::detail;
+
+ typedef boost::geometry::index::rtree<V, P, I, E, A> rtree;
+ typedef detail::rtree::const_private_view<rtree> view;
+ typedef typename view::translator_type translator_type;
+ typedef typename view::value_type value_type;
+ typedef typename view::options_type options_type;
+ typedef typename view::box_type box_type;
+ typedef typename view::allocators_type allocators_type;
+
+ view tree(rt);
+
+ detail::serialization_save(tree.members().parameters(), "parameters", ar);
+
+ ar << boost::serialization::make_nvp("values_count", tree.members().values_count);
+ ar << boost::serialization::make_nvp("leafs_level", tree.members().leafs_level);
+
+ if ( tree.members().values_count )
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(tree.members().root, "root shouldn't be null_ptr");
+
+ detail::rtree::visitors::save<Archive, value_type, options_type, translator_type, box_type, allocators_type> save_v(ar, version);
+ detail::rtree::apply_visitor(save_v, *tree.members().root);
+ }
+}
+
+template<class Archive, typename V, typename P, typename I, typename E, typename A>
+void load(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version)
+{
+ namespace detail = boost::geometry::index::detail;
+
+ typedef boost::geometry::index::rtree<V, P, I, E, A> rtree;
+ typedef detail::rtree::private_view<rtree> view;
+ typedef typename view::size_type size_type;
+ typedef typename view::translator_type translator_type;
+ typedef typename view::value_type value_type;
+ typedef typename view::options_type options_type;
+ typedef typename view::box_type box_type;
+ typedef typename view::allocators_type allocators_type;
+
+ typedef typename options_type::parameters_type parameters_type;
+ typedef typename allocators_type::node_pointer node_pointer;
+ typedef detail::rtree::node_auto_ptr<value_type, options_type, translator_type, box_type, allocators_type> node_auto_ptr;
+
+ view tree(rt);
+
+ parameters_type params = detail::serialization_load<parameters_type>("parameters", ar);
+
+ size_type values_count, leafs_level;
+ ar >> boost::serialization::make_nvp("values_count", values_count);
+ ar >> boost::serialization::make_nvp("leafs_level", leafs_level);
+
+ node_pointer n(0);
+ if ( 0 < values_count )
+ {
+ size_type loaded_values_count = 0;
+ n = detail::rtree::load<value_type, options_type, translator_type, box_type, allocators_type>
+ ::apply(ar, version, leafs_level, loaded_values_count, params, tree.members().translator(), tree.members().allocators()); // MAY THROW
+
+ node_auto_ptr remover(n, tree.members().allocators());
+ if ( loaded_values_count != values_count )
+ BOOST_THROW_EXCEPTION(std::runtime_error("unexpected number of values")); // TODO change exception type
+ remover.release();
+ }
+
+ tree.members().parameters() = params;
+ tree.members().values_count = values_count;
+ tree.members().leafs_level = leafs_level;
+
+ node_auto_ptr remover(tree.members().root, tree.members().allocators());
+ tree.members().root = n;
+}
+
+template<class Archive, typename V, typename P, typename I, typename E, typename A> inline
+void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version)
+{
+ split_free(ar, rt, version);
+}
+
+template<class Archive, typename V, typename P, typename I, typename E, typename A> inline
+void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version)
+{
+ split_free(ar, rt, version);
+}
+
+}} // boost::serialization
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP
diff --git a/boost/geometry/index/detail/tags.hpp b/boost/geometry/index/detail/tags.hpp
new file mode 100644
index 0000000000..e1a1716bed
--- /dev/null
+++ b/boost/geometry/index/detail/tags.hpp
@@ -0,0 +1,25 @@
+// Boost.Geometry Index
+//
+// Tags used by the predicates checks implementation.
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_TAGS_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_TAGS_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail {
+
+struct value_tag {};
+struct bounds_tag {};
+
+} // namespace detail
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_RTREE_TAGS_HPP
diff --git a/boost/geometry/index/detail/translator.hpp b/boost/geometry/index/detail/translator.hpp
new file mode 100644
index 0000000000..f377c720aa
--- /dev/null
+++ b/boost/geometry/index/detail/translator.hpp
@@ -0,0 +1,60 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail {
+
+template <typename IndexableGetter, typename EqualTo>
+struct translator
+ : public IndexableGetter
+ , public EqualTo
+{
+ typedef typename IndexableGetter::result_type result_type;
+
+ translator(IndexableGetter const& i, EqualTo const& e)
+ : IndexableGetter(i), EqualTo(e)
+ {}
+
+ template <typename Value>
+ result_type operator()(Value const& value) const
+ {
+ return IndexableGetter::operator()(value);
+ }
+
+ template <typename Value>
+ bool equals(Value const& v1, Value const& v2) const
+ {
+ return EqualTo::operator()(v1, v2);
+ }
+};
+
+template <typename IndexableGetter>
+struct result_type
+{
+ typedef typename IndexableGetter::result_type type;
+};
+
+template <typename IndexableGetter>
+struct indexable_type
+{
+ typedef typename boost::remove_const<
+ typename boost::remove_reference<
+ typename result_type<IndexableGetter>::type
+ >::type
+ >::type type;
+};
+
+} // namespace detail
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP
diff --git a/boost/geometry/index/detail/tuples.hpp b/boost/geometry/index/detail/tuples.hpp
new file mode 100644
index 0000000000..e7f6d22357
--- /dev/null
+++ b/boost/geometry/index/detail/tuples.hpp
@@ -0,0 +1,204 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_TUPLES_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_TUPLES_HPP
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+// TODO move this to index/tuples and separate algorithms
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+namespace tuples {
+
+// find_index
+
+namespace detail {
+
+template <typename Tuple, typename El, size_t N>
+struct find_index;
+
+template <typename Tuple, typename El, size_t N, typename CurrentEl>
+struct find_index_impl
+{
+ static const size_t value = find_index<Tuple, El, N - 1>::value;
+};
+
+template <typename Tuple, typename El, size_t N>
+struct find_index_impl<Tuple, El, N, El>
+{
+ static const size_t value = N - 1;
+};
+
+template <typename Tuple, typename El, typename CurrentEl>
+struct find_index_impl<Tuple, El, 1, CurrentEl>
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ ELEMENT_NOT_FOUND,
+ (find_index_impl));
+};
+
+template <typename Tuple, typename El>
+struct find_index_impl<Tuple, El, 1, El>
+{
+ static const size_t value = 0;
+};
+
+template <typename Tuple, typename El, size_t N>
+struct find_index
+{
+ static const size_t value =
+ find_index_impl<
+ Tuple,
+ El,
+ N,
+ typename boost::tuples::element<N - 1, Tuple>::type
+ >::value;
+};
+
+} // namespace detail
+
+template <typename Tuple, typename El>
+struct find_index
+{
+ static const size_t value =
+ detail::find_index<
+ Tuple,
+ El,
+ boost::tuples::length<Tuple>::value
+ >::value;
+};
+
+// has
+
+namespace detail {
+
+template <typename Tuple, typename El, size_t N>
+struct has
+{
+ static const bool value
+ = boost::is_same<
+ typename boost::tuples::element<N - 1, Tuple>::type,
+ El
+ >::value
+ || has<Tuple, El, N - 1>::value;
+};
+
+template <typename Tuple, typename El>
+struct has<Tuple, El, 1>
+{
+ static const bool value
+ = boost::is_same<
+ typename boost::tuples::element<0, Tuple>::type,
+ El
+ >::value;
+};
+
+} // namespace detail
+
+template <typename Tuple, typename El>
+struct has
+{
+ static const bool value
+ = detail::has<
+ Tuple,
+ El,
+ boost::tuples::length<Tuple>::value
+ >::value;
+};
+
+// add
+
+template <typename Tuple, typename El>
+struct add
+{
+ BOOST_MPL_ASSERT_MSG(
+ (false),
+ NOT_IMPLEMENTED_FOR_THIS_TUPLE_TYPE,
+ (add));
+};
+
+template <typename T1, typename T>
+struct add<boost::tuple<T1>, T>
+{
+ typedef boost::tuple<T1, T> type;
+};
+
+template <typename T1, typename T2, typename T>
+struct add<boost::tuple<T1, T2>, T>
+{
+ typedef boost::tuple<T1, T2, T> type;
+};
+
+// add_if
+
+template <typename Tuple, typename El, bool Cond>
+struct add_if
+{
+ typedef Tuple type;
+};
+
+template <typename Tuple, typename El>
+struct add_if<Tuple, El, true>
+{
+ typedef typename add<Tuple, El>::type type;
+};
+
+// add_unique
+
+template <typename Tuple, typename El>
+struct add_unique
+{
+ typedef typename add_if<
+ Tuple,
+ El,
+ !has<Tuple, El>::value
+ >::type type;
+};
+
+template <typename Tuple,
+ typename T,
+ size_t I = 0,
+ size_t N = boost::tuples::length<Tuple>::value>
+struct push_back
+{
+ typedef
+ boost::tuples::cons<
+ typename boost::tuples::element<I, Tuple>::type,
+ typename push_back<Tuple, T, I+1, N>::type
+ > type;
+
+ static type apply(Tuple const& tup, T const& t)
+ {
+ return
+ type(
+ boost::get<I>(tup),
+ push_back<Tuple, T, I+1, N>::apply(tup, t)
+ );
+ }
+};
+
+template <typename Tuple, typename T, size_t N>
+struct push_back<Tuple, T, N, N>
+{
+ typedef boost::tuples::cons<T, boost::tuples::null_type> type;
+
+ static type apply(Tuple const&, T const& t)
+ {
+ return type(t, boost::tuples::null_type());
+ }
+};
+
+} // namespace tuples
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_TAGS_HPP
diff --git a/boost/geometry/index/detail/utilities.hpp b/boost/geometry/index/detail/utilities.hpp
new file mode 100644
index 0000000000..26f0780016
--- /dev/null
+++ b/boost/geometry/index/detail/utilities.hpp
@@ -0,0 +1,46 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/swap.hpp>
+//#include <boost/type_traits/is_empty.hpp>
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template<class T>
+static inline void assign_cond(T & l, T const& r, boost::mpl::bool_<true> const&)
+{
+ l = r;
+}
+
+template<class T>
+static inline void assign_cond(T &, T const&, boost::mpl::bool_<false> const&) {}
+
+template<class T>
+static inline void move_cond(T & l, T & r, boost::mpl::bool_<true> const&)
+{
+ l = ::boost::move(r);
+}
+
+template<class T>
+static inline void move_cond(T &, T &, boost::mpl::bool_<false> const&) {}
+
+template <typename T> inline
+void swap_cond(T & l, T & r, boost::mpl::bool_<true> const&)
+{
+ ::boost::swap(l, r);
+}
+
+template <typename T> inline
+void swap_cond(T &, T &, boost::mpl::bool_<false> const&) {}
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP
diff --git a/boost/geometry/index/detail/varray.hpp b/boost/geometry/index/detail/varray.hpp
new file mode 100644
index 0000000000..63577e64a7
--- /dev/null
+++ b/boost/geometry/index/detail/varray.hpp
@@ -0,0 +1,2203 @@
+// Boost.Container varray
+//
+// Copyright (c) 2012-2014 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2011-2013 Andrew Hundt.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP
+
+// TODO - REMOVE/CHANGE
+#include <boost/container/detail/config_begin.hpp>
+#include <boost/container/detail/workaround.hpp>
+#include <boost/container/detail/preprocessor.hpp>
+
+#include <boost/config.hpp>
+#include <boost/swap.hpp>
+#include <boost/integer.hpp>
+
+#include <boost/mpl/assert.hpp>
+
+#include <boost/type_traits/is_unsigned.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+#include <boost/type_traits/aligned_storage.hpp>
+
+// TODO - use std::reverse_iterator and std::iterator_traits
+// instead Boost.Iterator to remove dependency?
+// or boost/detail/iterator.hpp ?
+#include <boost/iterator/reverse_iterator.hpp>
+#include <boost/iterator/iterator_concepts.hpp>
+
+#include <boost/geometry/index/detail/assert.hpp>
+
+#include <boost/geometry/index/detail/assert.hpp>
+#include <boost/geometry/index/detail/varray_detail.hpp>
+
+#include <boost/concept_check.hpp>
+#include <boost/throw_exception.hpp>
+
+/*!
+\defgroup varray_non_member varray non-member functions
+*/
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+namespace varray_detail {
+
+template <typename Value, std::size_t Capacity>
+struct varray_traits
+{
+ typedef Value value_type;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef Value * pointer;
+ typedef const Value * const_pointer;
+ typedef Value & reference;
+ typedef const Value & const_reference;
+
+ typedef boost::false_type use_memop_in_swap_and_move;
+ typedef boost::false_type use_optimized_swap;
+ typedef boost::false_type disable_trivial_init;
+};
+
+template <typename Varray>
+struct checker
+{
+ typedef typename Varray::size_type size_type;
+ typedef typename Varray::const_iterator const_iterator;
+
+ static inline void check_capacity(Varray const& v, size_type s)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(s <= v.capacity(), "size too big");
+
+ ::boost::ignore_unused_variable_warning(v);
+ ::boost::ignore_unused_variable_warning(s);
+ }
+
+ static inline void throw_out_of_bounds(Varray const& v, size_type i)
+ {
+//#ifndef BOOST_NO_EXCEPTIONS
+ if ( v.size() <= i )
+ BOOST_THROW_EXCEPTION(std::out_of_range("index out of bounds"));
+//#else // BOOST_NO_EXCEPTIONS
+// BOOST_GEOMETRY_INDEX_ASSERT(i < v.size(), "index out of bounds");
+//#endif // BOOST_NO_EXCEPTIONS
+
+ ::boost::ignore_unused_variable_warning(v);
+ ::boost::ignore_unused_variable_warning(i);
+ }
+
+ static inline void check_index(Varray const& v, size_type i)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(i < v.size(), "index out of bounds");
+
+ ::boost::ignore_unused_variable_warning(v);
+ ::boost::ignore_unused_variable_warning(i);
+ }
+
+ static inline void check_not_empty(Varray const& v)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(!v.empty(), "the container is empty");
+
+ ::boost::ignore_unused_variable_warning(v);
+ }
+
+ static inline void check_iterator_end_neq(Varray const& v, const_iterator position)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(v.begin() <= position && position < v.end(), "iterator out of bounds");
+
+ ::boost::ignore_unused_variable_warning(v);
+ ::boost::ignore_unused_variable_warning(position);
+ }
+
+ static inline void check_iterator_end_eq(Varray const& v, const_iterator position)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(v.begin() <= position && position <= v.end(), "iterator out of bounds");
+
+ ::boost::ignore_unused_variable_warning(v);
+ ::boost::ignore_unused_variable_warning(position);
+ }
+};
+
+} // namespace varray_detail
+
+/*!
+\brief A variable-size array container with fixed capacity.
+
+varray is a sequence container like boost::container::vector with contiguous storage that can
+change in size, along with the static allocation, low overhead, and fixed capacity of boost::array.
+
+A varray is a sequence that supports random access to elements, constant time insertion and
+removal of elements at the end, and linear time insertion and removal of elements at the beginning or
+in the middle. The number of elements in a varray may vary dynamically up to a fixed capacity
+because elements are stored within the object itself similarly to an array. However, objects are
+initialized as they are inserted into varray unlike C arrays or std::array which must construct
+all elements on instantiation. The behavior of varray enables the use of statically allocated
+elements in cases with complex object lifetime requirements that would otherwise not be trivially
+possible.
+
+\par Error Handling
+ Insertion beyond the capacity and out of bounds errors result in undefined behavior unless
+ otherwise specified. In this respect if size() == capacity(), then varray::push_back()
+ behaves like std::vector pop_front() if size() == empty(). The reason for this difference
+ is because unlike vectors, varray does not perform allocation.
+
+\par Advanced Usage
+ Error handling behavior can be modified to more closely match std::vector exception behavior
+ when exceeding bounds by providing an alternate Strategy and varray_traits instantiation.
+
+\tparam Value The type of element that will be stored.
+\tparam Capacity The maximum number of elements varray can store, fixed at compile time.
+\tparam Strategy Defines the public typedefs and error handlers,
+ implements StaticVectorStrategy and has some similarities
+ to an Allocator.
+*/
+template <typename Value, std::size_t Capacity>
+class varray
+{
+ typedef varray_detail::varray_traits<Value, Capacity> vt;
+ typedef varray_detail::checker<varray> errh;
+
+ BOOST_MPL_ASSERT_MSG(
+ ( boost::is_unsigned<typename vt::size_type>::value &&
+ sizeof(typename boost::uint_value_t<Capacity>::least) <= sizeof(typename vt::size_type) ),
+ SIZE_TYPE_IS_TOO_SMALL_FOR_SPECIFIED_CAPACITY,
+ (varray)
+ );
+
+ typedef boost::aligned_storage<
+ sizeof(Value[Capacity]),
+ boost::alignment_of<Value[Capacity]>::value
+ > aligned_storage_type;
+
+ template <typename V, std::size_t C>
+ friend class varray;
+
+ BOOST_COPYABLE_AND_MOVABLE(varray)
+
+#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
+public:
+ template <std::size_t C>
+ varray & operator=(varray<Value, C> & sv)
+ {
+ typedef varray<Value, C> other;
+ this->operator=(static_cast<const ::boost::rv<other> &>(const_cast<const other &>(sv)));
+ return *this;
+ }
+#endif
+
+public:
+ //! @brief The type of elements stored in the container.
+ typedef typename vt::value_type value_type;
+ //! @brief The unsigned integral type used by the container.
+ typedef typename vt::size_type size_type;
+ //! @brief The pointers difference type.
+ typedef typename vt::difference_type difference_type;
+ //! @brief The pointer type.
+ typedef typename vt::pointer pointer;
+ //! @brief The const pointer type.
+ typedef typename vt::const_pointer const_pointer;
+ //! @brief The value reference type.
+ typedef typename vt::reference reference;
+ //! @brief The value const reference type.
+ typedef typename vt::const_reference const_reference;
+
+ //! @brief The iterator type.
+ typedef pointer iterator;
+ //! @brief The const iterator type.
+ typedef const_pointer const_iterator;
+ //! @brief The reverse iterator type.
+ typedef boost::reverse_iterator<iterator> reverse_iterator;
+ //! @brief The const reverse iterator.
+ typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ //! @brief Constructs an empty varray.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ varray()
+ : m_size(0)
+ {}
+
+ //! @pre <tt>count <= capacity()</tt>
+ //!
+ //! @brief Constructs a varray containing count default constructed Values.
+ //!
+ //! @param count The number of values which will be contained in the container.
+ //!
+ //! @par Throws
+ //! If Value's default constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ explicit varray(size_type count)
+ : m_size(0)
+ {
+ this->resize(count); // may throw
+ }
+
+ //! @pre <tt>count <= capacity()</tt>
+ //!
+ //! @brief Constructs a varray containing count copies of value.
+ //!
+ //! @param count The number of copies of a values that will be contained in the container.
+ //! @param value The value which will be used to copy construct values.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ varray(size_type count, value_type const& value)
+ : m_size(0)
+ {
+ this->resize(count, value); // may throw
+ }
+
+ //! @pre
+ //! @li <tt>distance(first, last) <= capacity()</tt>
+ //! @li Iterator must meet the \c ForwardTraversalIterator concept.
+ //!
+ //! @brief Constructs a varray containing copy of a range <tt>[first, last)</tt>.
+ //!
+ //! @param first The iterator to the first element in range.
+ //! @param last The iterator to the one after the last element in range.
+ //!
+ //! @par Throws
+ //! If Value's constructor taking a dereferenced Iterator throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <typename Iterator>
+ varray(Iterator first, Iterator last)
+ : m_size(0)
+ {
+ BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal<Iterator>)); // Make sure you passed a ForwardIterator
+
+ this->assign(first, last); // may throw
+ }
+
+ //! @brief Constructs a copy of other varray.
+ //!
+ //! @param other The varray which content will be copied to this one.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor throws.
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ varray(varray const& other)
+ : m_size(other.size())
+ {
+ namespace sv = varray_detail;
+ sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw
+ }
+
+ //! @pre <tt>other.size() <= capacity()</tt>.
+ //!
+ //! @brief Constructs a copy of other varray.
+ //!
+ //! @param other The varray which content will be copied to this one.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <std::size_t C>
+ varray(varray<value_type, C> const& other)
+ : m_size(other.size())
+ {
+ errh::check_capacity(*this, other.size()); // may throw
+
+ namespace sv = varray_detail;
+ sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw
+ }
+
+ //! @brief Copy assigns Values stored in the other varray to this one.
+ //!
+ //! @param other The varray which content will be copied to this one.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor or copy assignment throws.
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ varray & operator=(BOOST_COPY_ASSIGN_REF(varray) other)
+ {
+ this->assign(other.begin(), other.end()); // may throw
+
+ return *this;
+ }
+
+ //! @pre <tt>other.size() <= capacity()</tt>
+ //!
+ //! @brief Copy assigns Values stored in the other varray to this one.
+ //!
+ //! @param other The varray which content will be copied to this one.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor or copy assignment throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <std::size_t C>
+ varray & operator=(BOOST_COPY_ASSIGN_REF_2_TEMPL_ARGS(varray, value_type, C) other)
+ {
+ this->assign(other.begin(), other.end()); // may throw
+
+ return *this;
+ }
+
+ //! @brief Move constructor. Moves Values stored in the other varray to this one.
+ //!
+ //! @param other The varray which content will be moved to this one.
+ //!
+ //! @par Throws
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor throws.
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor throws.
+ //! @internal
+ //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default.
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ varray(BOOST_RV_REF(varray) other)
+ {
+ typedef typename
+ vt::use_memop_in_swap_and_move use_memop_in_swap_and_move;
+
+ this->move_ctor_dispatch(other, use_memop_in_swap_and_move());
+ }
+
+ //! @pre <tt>other.size() <= capacity()</tt>
+ //!
+ //! @brief Move constructor. Moves Values stored in the other varray to this one.
+ //!
+ //! @param other The varray which content will be moved to this one.
+ //!
+ //! @par Throws
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor throws.
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor throws.
+ //! @internal
+ //! @li It throws only if \c use_memop_in_swap_and_move is false_type - default.
+ //! @endinternal
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <std::size_t C>
+ varray(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other)
+ : m_size(other.m_size)
+ {
+ errh::check_capacity(*this, other.size()); // may throw
+
+ typedef typename
+ vt::use_memop_in_swap_and_move use_memop_in_swap_and_move;
+
+ this->move_ctor_dispatch(other, use_memop_in_swap_and_move());
+ }
+
+ //! @brief Move assignment. Moves Values stored in the other varray to this one.
+ //!
+ //! @param other The varray which content will be moved to this one.
+ //!
+ //! @par Throws
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws.
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws.
+ //! @internal
+ //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default.
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ varray & operator=(BOOST_RV_REF(varray) other)
+ {
+ if ( &other == this )
+ return *this;
+
+ typedef typename
+ vt::use_memop_in_swap_and_move use_memop_in_swap_and_move;
+
+ this->move_assign_dispatch(other, use_memop_in_swap_and_move());
+
+ return *this;
+ }
+
+ //! @pre <tt>other.size() <= capacity()</tt>
+ //!
+ //! @brief Move assignment. Moves Values stored in the other varray to this one.
+ //!
+ //! @param other The varray which content will be moved to this one.
+ //!
+ //! @par Throws
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws.
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws.
+ //! @internal
+ //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default.
+ //! @endinternal
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <std::size_t C>
+ varray & operator=(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other)
+ {
+ errh::check_capacity(*this, other.size()); // may throw
+
+ typedef typename
+ vt::use_memop_in_swap_and_move use_memop_in_swap_and_move;
+
+ this->move_assign_dispatch(other, use_memop_in_swap_and_move());
+
+ return *this;
+ }
+
+ //! @brief Destructor. Destroys Values stored in this container.
+ //!
+ //! @par Throws
+ //! Nothing
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ ~varray()
+ {
+ namespace sv = varray_detail;
+ sv::destroy(this->begin(), this->end());
+ }
+
+ //! @brief Swaps contents of the other varray and this one.
+ //!
+ //! @param other The varray which content will be swapped with this one's content.
+ //!
+ //! @par Throws
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws,
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws,
+ //! @internal
+ //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default.
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ void swap(varray & other)
+ {
+ typedef typename
+ vt::use_optimized_swap use_optimized_swap;
+
+ this->swap_dispatch(other, use_optimized_swap());
+ }
+
+ //! @pre <tt>other.size() <= capacity() && size() <= other.capacity()</tt>
+ //!
+ //! @brief Swaps contents of the other varray and this one.
+ //!
+ //! @param other The varray which content will be swapped with this one's content.
+ //!
+ //! @par Throws
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws,
+ //! @li If \c boost::has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws,
+ //! @internal
+ //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default.
+ //! @endinternal
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <std::size_t C>
+ void swap(varray<value_type, C> & other)
+ {
+ errh::check_capacity(*this, other.size());
+ errh::check_capacity(other, this->size());
+
+ typedef typename
+ vt::use_optimized_swap use_optimized_swap;
+
+ this->swap_dispatch(other, use_optimized_swap());
+ }
+
+ //! @pre <tt>count <= capacity()</tt>
+ //!
+ //! @brief Inserts or erases elements at the end such that
+ //! the size becomes count. New elements are default constructed.
+ //!
+ //! @param count The number of elements which will be stored in the container.
+ //!
+ //! @par Throws
+ //! If Value's default constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ void resize(size_type count)
+ {
+ namespace sv = varray_detail;
+ typedef typename vt::disable_trivial_init dti;
+
+ if ( count < m_size )
+ {
+ sv::destroy(this->begin() + count, this->end());
+ }
+ else
+ {
+ errh::check_capacity(*this, count); // may throw
+
+ sv::uninitialized_fill(this->end(), this->begin() + count, dti()); // may throw
+ }
+ m_size = count; // update end
+ }
+
+ //! @pre <tt>count <= capacity()</tt>
+ //!
+ //! @brief Inserts or erases elements at the end such that
+ //! the size becomes count. New elements are copy constructed from value.
+ //!
+ //! @param count The number of elements which will be stored in the container.
+ //! @param value The value used to copy construct the new element.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ void resize(size_type count, value_type const& value)
+ {
+ if ( count < m_size )
+ {
+ namespace sv = varray_detail;
+ sv::destroy(this->begin() + count, this->end());
+ }
+ else
+ {
+ errh::check_capacity(*this, count); // may throw
+
+ std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw
+ }
+ m_size = count; // update end
+ }
+
+ //! @pre <tt>count <= capacity()</tt>
+ //!
+ //! @brief This call has no effect because the Capacity of this container is constant.
+ //!
+ //! @param count The number of elements which the container should be able to contain.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ void reserve(size_type count)
+ {
+ errh::check_capacity(*this, count); // may throw
+ }
+
+ //! @pre <tt>size() < capacity()</tt>
+ //!
+ //! @brief Adds a copy of value at the end.
+ //!
+ //! @param value The value used to copy construct the new element.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ void push_back(value_type const& value)
+ {
+ typedef typename vt::disable_trivial_init dti;
+
+ errh::check_capacity(*this, m_size + 1); // may throw
+
+ namespace sv = varray_detail;
+ sv::construct(dti(), this->end(), value); // may throw
+ ++m_size; // update end
+ }
+
+ //! @pre <tt>size() < capacity()</tt>
+ //!
+ //! @brief Moves value to the end.
+ //!
+ //! @param value The value to move construct the new element.
+ //!
+ //! @par Throws
+ //! If Value's move constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ void push_back(BOOST_RV_REF(value_type) value)
+ {
+ typedef typename vt::disable_trivial_init dti;
+
+ errh::check_capacity(*this, m_size + 1); // may throw
+
+ namespace sv = varray_detail;
+ sv::construct(dti(), this->end(), ::boost::move(value)); // may throw
+ ++m_size; // update end
+ }
+
+ //! @pre <tt>!empty()</tt>
+ //!
+ //! @brief Destroys last value and decreases the size.
+ //!
+ //! @par Throws
+ //! Nothing by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ void pop_back()
+ {
+ errh::check_not_empty(*this);
+
+ namespace sv = varray_detail;
+ sv::destroy(this->end() - 1);
+ --m_size; // update end
+ }
+
+ //! @pre
+ //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>.
+ //! @li <tt>size() < capacity()</tt>
+ //!
+ //! @brief Inserts a copy of element at position.
+ //!
+ //! @param position The position at which the new value will be inserted.
+ //! @param value The value used to copy construct the new element.
+ //!
+ //! @par Throws
+ //! @li If Value's copy constructor or copy assignment throws
+ //! @li If Value's move constructor or move assignment throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Constant or linear.
+ iterator insert(iterator position, value_type const& value)
+ {
+ typedef typename vt::disable_trivial_init dti;
+ namespace sv = varray_detail;
+
+ errh::check_iterator_end_eq(*this, position);
+ errh::check_capacity(*this, m_size + 1); // may throw
+
+ if ( position == this->end() )
+ {
+ sv::construct(dti(), position, value); // may throw
+ ++m_size; // update end
+ }
+ else
+ {
+ // TODO - should move be used only if it's nonthrowing?
+ value_type & r = *(this->end() - 1);
+ sv::construct(dti(), this->end(), boost::move(r)); // may throw
+ ++m_size; // update end
+ sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw
+ sv::assign(position, value); // may throw
+ }
+
+ return position;
+ }
+
+ //! @pre
+ //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>.
+ //! @li <tt>size() < capacity()</tt>
+ //!
+ //! @brief Inserts a move-constructed element at position.
+ //!
+ //! @param position The position at which the new value will be inserted.
+ //! @param value The value used to move construct the new element.
+ //!
+ //! @par Throws
+ //! If Value's move constructor or move assignment throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Constant or linear.
+ iterator insert(iterator position, BOOST_RV_REF(value_type) value)
+ {
+ typedef typename vt::disable_trivial_init dti;
+ namespace sv = varray_detail;
+
+ errh::check_iterator_end_eq(*this, position);
+ errh::check_capacity(*this, m_size + 1); // may throw
+
+ if ( position == this->end() )
+ {
+ sv::construct(dti(), position, boost::move(value)); // may throw
+ ++m_size; // update end
+ }
+ else
+ {
+ // TODO - should move be used only if it's nonthrowing?
+ value_type & r = *(this->end() - 1);
+ sv::construct(dti(), this->end(), boost::move(r)); // may throw
+ ++m_size; // update end
+ sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw
+ sv::assign(position, boost::move(value)); // may throw
+ }
+
+ return position;
+ }
+
+ //! @pre
+ //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>.
+ //! @li <tt>size() + count <= capacity()</tt>
+ //!
+ //! @brief Inserts a count copies of value at position.
+ //!
+ //! @param position The position at which new elements will be inserted.
+ //! @param count The number of new elements which will be inserted.
+ //! @param value The value used to copy construct new elements.
+ //!
+ //! @par Throws
+ //! @li If Value's copy constructor or copy assignment throws.
+ //! @li If Value's move constructor or move assignment throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ iterator insert(iterator position, size_type count, value_type const& value)
+ {
+ errh::check_iterator_end_eq(*this, position);
+ errh::check_capacity(*this, m_size + count); // may throw
+
+ if ( position == this->end() )
+ {
+ std::uninitialized_fill(position, position + count, value); // may throw
+ m_size += count; // update end
+ }
+ else
+ {
+ namespace sv = varray_detail;
+
+ difference_type to_move = std::distance(position, this->end());
+
+ // TODO - should following lines check for exception and revert to the old size?
+
+ if ( count < static_cast<size_type>(to_move) )
+ {
+ sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw
+ m_size += count; // update end
+ sv::move_backward(position, position + to_move - count, this->end() - count); // may throw
+ std::fill_n(position, count, value); // may throw
+ }
+ else
+ {
+ std::uninitialized_fill(this->end(), position + count, value); // may throw
+ m_size += count - to_move; // update end
+ sv::uninitialized_move(position, position + to_move, position + count); // may throw
+ m_size += to_move; // update end
+ std::fill_n(position, to_move, value); // may throw
+ }
+ }
+
+ return position;
+ }
+
+ //! @pre
+ //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>.
+ //! @li <tt>distance(first, last) <= capacity()</tt>
+ //! @li \c Iterator must meet the \c ForwardTraversalIterator concept.
+ //!
+ //! @brief Inserts a copy of a range <tt>[first, last)</tt> at position.
+ //!
+ //! @param position The position at which new elements will be inserted.
+ //! @param first The iterator to the first element of a range used to construct new elements.
+ //! @param last The iterator to the one after the last element of a range used to construct new elements.
+ //!
+ //! @par Throws
+ //! @li If Value's constructor and assignment taking a dereferenced \c Iterator.
+ //! @li If Value's move constructor or move assignment throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <typename Iterator>
+ iterator insert(iterator position, Iterator first, Iterator last)
+ {
+ BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal<Iterator>)); // Make sure you passed a ForwardIterator
+
+ typedef typename boost::iterator_traversal<Iterator>::type traversal;
+ this->insert_dispatch(position, first, last, traversal());
+
+ return position;
+ }
+
+ //! @pre \c position must be a valid iterator of \c *this in range <tt>[begin(), end())</tt>
+ //!
+ //! @brief Erases Value from position.
+ //!
+ //! @param position The position of the element which will be erased from the container.
+ //!
+ //! @par Throws
+ //! If Value's move assignment throws.
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ iterator erase(iterator position)
+ {
+ namespace sv = varray_detail;
+
+ errh::check_iterator_end_neq(*this, position);
+
+ //TODO - add empty check?
+ //errh::check_empty(*this);
+
+ sv::move(position + 1, this->end(), position); // may throw
+ sv::destroy(this->end() - 1);
+ --m_size;
+
+ return position;
+ }
+
+ //! @pre
+ //! @li \c first and \c last must define a valid range
+ //! @li iterators must be in range <tt>[begin(), end()]</tt>
+ //!
+ //! @brief Erases Values from a range <tt>[first, last)</tt>.
+ //!
+ //! @param first The position of the first element of a range which will be erased from the container.
+ //! @param last The position of the one after the last element of a range which will be erased from the container.
+ //!
+ //! @par Throws
+ //! If Value's move assignment throws.
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ iterator erase(iterator first, iterator last)
+ {
+ namespace sv = varray_detail;
+
+ errh::check_iterator_end_eq(*this, first);
+ errh::check_iterator_end_eq(*this, last);
+
+ difference_type n = std::distance(first, last);
+
+ //TODO - add invalid range check?
+ //BOOST_ASSERT_MSG(0 <= n, "invalid range");
+ //TODO - add this->size() check?
+ //BOOST_ASSERT_MSG(n <= this->size(), "invalid range");
+
+ sv::move(last, this->end(), first); // may throw
+ sv::destroy(this->end() - n, this->end());
+ m_size -= n;
+
+ return first;
+ }
+
+ //! @pre <tt>distance(first, last) <= capacity()</tt>
+ //!
+ //! @brief Assigns a range <tt>[first, last)</tt> of Values to this container.
+ //!
+ //! @param first The iterator to the first element of a range used to construct new content of this container.
+ //! @param last The iterator to the one after the last element of a range used to construct new content of this container.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor or copy assignment throws,
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ template <typename Iterator>
+ void assign(Iterator first, Iterator last)
+ {
+ BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversal<Iterator>)); // Make sure you passed a ForwardIterator
+
+ typedef typename boost::iterator_traversal<Iterator>::type traversal;
+ this->assign_dispatch(first, last, traversal()); // may throw
+ }
+
+ //! @pre <tt>count <= capacity()</tt>
+ //!
+ //! @brief Assigns a count copies of value to this container.
+ //!
+ //! @param count The new number of elements which will be container in the container.
+ //! @param value The value which will be used to copy construct the new content.
+ //!
+ //! @par Throws
+ //! If Value's copy constructor or copy assignment throws.
+ //!
+ //! @par Complexity
+ //! Linear O(N).
+ void assign(size_type count, value_type const& value)
+ {
+ if ( count < m_size )
+ {
+ namespace sv = varray_detail;
+
+ std::fill_n(this->begin(), count, value); // may throw
+ sv::destroy(this->begin() + count, this->end());
+ }
+ else
+ {
+ errh::check_capacity(*this, count); // may throw
+
+ std::fill_n(this->begin(), m_size, value); // may throw
+ std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw
+ }
+ m_size = count; // update end
+ }
+
+#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE)
+#if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
+ //! @pre <tt>size() < capacity()</tt>
+ //!
+ //! @brief Inserts a Value constructed with
+ //! \c std::forward<Args>(args)... in the end of the container.
+ //!
+ //! @param args The arguments of the constructor of the new element which will be created at the end of the container.
+ //!
+ //! @par Throws
+ //! If in-place constructor throws or Value's move constructor throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ template<class ...Args>
+ void emplace_back(BOOST_FWD_REF(Args) ...args)
+ {
+ typedef typename vt::disable_trivial_init dti;
+
+ errh::check_capacity(*this, m_size + 1); // may throw
+
+ namespace sv = varray_detail;
+ sv::construct(dti(), this->end(), ::boost::forward<Args>(args)...); // may throw
+ ++m_size; // update end
+ }
+
+ //! @pre
+ //! @li \c position must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>
+ //! @li <tt>size() < capacity()</tt>
+ //!
+ //! @brief Inserts a Value constructed with
+ //! \c std::forward<Args>(args)... before position
+ //!
+ //! @param position The position at which new elements will be inserted.
+ //! @param args The arguments of the constructor of the new element.
+ //!
+ //! @par Throws
+ //! If in-place constructor throws or if Value's move constructor or move assignment throws.
+ //! @internal
+ //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default).
+ //! @endinternal
+ //!
+ //! @par Complexity
+ //! Constant or linear.
+ template<class ...Args>
+ iterator emplace(iterator position, BOOST_FWD_REF(Args) ...args)
+ {
+ typedef typename vt::disable_trivial_init dti;
+
+ namespace sv = varray_detail;
+
+ errh::check_iterator_end_eq(*this, position);
+ errh::check_capacity(*this, m_size + 1); // may throw
+
+ if ( position == this->end() )
+ {
+ sv::construct(dti(), position, ::boost::forward<Args>(args)...); // may throw
+ ++m_size; // update end
+ }
+ else
+ {
+ // TODO - should following lines check for exception and revert to the old size?
+
+ // TODO - should move be used only if it's nonthrowing?
+ value_type & r = *(this->end() - 1);
+ sv::construct(dti(), this->end(), boost::move(r)); // may throw
+ ++m_size; // update end
+ sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw
+
+ aligned_storage<sizeof(value_type), alignment_of<value_type>::value> temp_storage;
+ value_type * val_p = static_cast<value_type *>(temp_storage.address());
+ sv::construct(dti(), val_p, ::boost::forward<Args>(args)...); // may throw
+ sv::scoped_destructor<value_type> d(val_p);
+ sv::assign(position, ::boost::move(*val_p)); // may throw
+ }
+
+ return position;
+ }
+
+#else // BOOST_CONTAINER_PERFECT_FORWARDING || BOOST_CONTAINER_DOXYGEN_INVOKED
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \
+ void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \
+ { \
+ typedef typename vt::disable_trivial_init dti; \
+ \
+ errh::check_capacity(*this, m_size + 1); /*may throw*/\
+ \
+ namespace sv = varray_detail; \
+ sv::construct(dti(), this->end() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\
+ ++m_size; /*update end*/ \
+ } \
+ //
+ #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \
+ iterator emplace(iterator position BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \
+ { \
+ typedef typename vt::disable_trivial_init dti; \
+ namespace sv = varray_detail; \
+ \
+ errh::check_iterator_end_eq(*this, position); \
+ errh::check_capacity(*this, m_size + 1); /*may throw*/\
+ \
+ if ( position == this->end() ) \
+ { \
+ sv::construct(dti(), position BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\
+ ++m_size; /*update end*/ \
+ } \
+ else \
+ { \
+ /* TODO - should following lines check for exception and revert to the old size? */ \
+ /* TODO - should move be used only if it's nonthrowing? */ \
+ \
+ value_type & r = *(this->end() - 1); \
+ sv::construct(dti(), this->end(), boost::move(r)); /*may throw*/\
+ ++m_size; /*update end*/ \
+ sv::move_backward(position, this->end() - 2, this->end() - 1); /*may throw*/\
+ \
+ aligned_storage<sizeof(value_type), alignment_of<value_type>::value> temp_storage; \
+ value_type * val_p = static_cast<value_type *>(temp_storage.address()); \
+ sv::construct(dti(), val_p BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); /*may throw*/\
+ sv::scoped_destructor<value_type> d(val_p); \
+ sv::assign(position, ::boost::move(*val_p)); /*may throw*/\
+ } \
+ \
+ return position; \
+ } \
+ //
+ #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+#endif // BOOST_CONTAINER_PERFECT_FORWARDING || BOOST_CONTAINER_DOXYGEN_INVOKED
+#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE
+
+ //! @brief Removes all elements from the container.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ void clear()
+ {
+ namespace sv = varray_detail;
+ sv::destroy(this->begin(), this->end());
+ m_size = 0; // update end
+ }
+
+ //! @pre <tt>i < size()</tt>
+ //!
+ //! @brief Returns reference to the i-th element.
+ //!
+ //! @param i The element's index.
+ //!
+ //! @return reference to the i-th element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! \c std::out_of_range exception by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ reference at(size_type i)
+ {
+ errh::throw_out_of_bounds(*this, i); // may throw
+ return *(this->begin() + i);
+ }
+
+ //! @pre <tt>i < size()</tt>
+ //!
+ //! @brief Returns const reference to the i-th element.
+ //!
+ //! @param i The element's index.
+ //!
+ //! @return const reference to the i-th element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! \c std::out_of_range exception by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reference at(size_type i) const
+ {
+ errh::throw_out_of_bounds(*this, i); // may throw
+ return *(this->begin() + i);
+ }
+
+ //! @pre <tt>i < size()</tt>
+ //!
+ //! @brief Returns reference to the i-th element.
+ //!
+ //! @param i The element's index.
+ //!
+ //! @return reference to the i-th element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! Nothing by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ reference operator[](size_type i)
+ {
+ // TODO: Remove bounds check? std::vector and std::array operator[] don't check.
+ errh::check_index(*this, i);
+ return *(this->begin() + i);
+ }
+
+ //! @pre <tt>i < size()</tt>
+ //!
+ //! @brief Returns const reference to the i-th element.
+ //!
+ //! @param i The element's index.
+ //!
+ //! @return const reference to the i-th element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! Nothing by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reference operator[](size_type i) const
+ {
+ errh::check_index(*this, i);
+ return *(this->begin() + i);
+ }
+
+ //! @pre \c !empty()
+ //!
+ //! @brief Returns reference to the first element.
+ //!
+ //! @return reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! Nothing by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ reference front()
+ {
+ errh::check_not_empty(*this);
+ return *(this->begin());
+ }
+
+ //! @pre \c !empty()
+ //!
+ //! @brief Returns const reference to the first element.
+ //!
+ //! @return const reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! Nothing by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reference front() const
+ {
+ errh::check_not_empty(*this);
+ return *(this->begin());
+ }
+
+ //! @pre \c !empty()
+ //!
+ //! @brief Returns reference to the last element.
+ //!
+ //! @return reference to the last element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! Nothing by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ reference back()
+ {
+ errh::check_not_empty(*this);
+ return *(this->end() - 1);
+ }
+
+ //! @pre \c !empty()
+ //!
+ //! @brief Returns const reference to the first element.
+ //!
+ //! @return const reference to the last element
+ //! from the beginning of the container.
+ //!
+ //! @par Throws
+ //! Nothing by default.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reference back() const
+ {
+ errh::check_not_empty(*this);
+ return *(this->end() - 1);
+ }
+
+ //! @brief Pointer such that <tt>[data(), data() + size())</tt> is a valid range.
+ //! For a non-empty vector <tt>data() == &front()</tt>.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ Value * data()
+ {
+ return boost::addressof(*(this->ptr()));
+ }
+
+ //! @brief Const pointer such that <tt>[data(), data() + size())</tt> is a valid range.
+ //! For a non-empty vector <tt>data() == &front()</tt>.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const Value * data() const
+ {
+ return boost::addressof(*(this->ptr()));
+ }
+
+
+ //! @brief Returns iterator to the first element.
+ //!
+ //! @return iterator to the first element contained in the vector.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ iterator begin() { return this->ptr(); }
+
+ //! @brief Returns const iterator to the first element.
+ //!
+ //! @return const_iterator to the first element contained in the vector.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_iterator begin() const { return this->ptr(); }
+
+ //! @brief Returns const iterator to the first element.
+ //!
+ //! @return const_iterator to the first element contained in the vector.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_iterator cbegin() const { return this->ptr(); }
+
+ //! @brief Returns iterator to the one after the last element.
+ //!
+ //! @return iterator pointing to the one after the last element contained in the vector.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ iterator end() { return this->begin() + m_size; }
+
+ //! @brief Returns const iterator to the one after the last element.
+ //!
+ //! @return const_iterator pointing to the one after the last element contained in the vector.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_iterator end() const { return this->begin() + m_size; }
+
+ //! @brief Returns const iterator to the one after the last element.
+ //!
+ //! @return const_iterator pointing to the one after the last element contained in the vector.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_iterator cend() const { return this->cbegin() + m_size; }
+
+ //! @brief Returns reverse iterator to the first element of the reversed container.
+ //!
+ //! @return reverse_iterator pointing to the beginning
+ //! of the reversed varray.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ reverse_iterator rbegin() { return reverse_iterator(this->end()); }
+
+ //! @brief Returns const reverse iterator to the first element of the reversed container.
+ //!
+ //! @return const_reverse_iterator pointing to the beginning
+ //! of the reversed varray.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reverse_iterator rbegin() const { return const_reverse_iterator(this->end()); }
+
+ //! @brief Returns const reverse iterator to the first element of the reversed container.
+ //!
+ //! @return const_reverse_iterator pointing to the beginning
+ //! of the reversed varray.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reverse_iterator crbegin() const { return const_reverse_iterator(this->end()); }
+
+ //! @brief Returns reverse iterator to the one after the last element of the reversed container.
+ //!
+ //! @return reverse_iterator pointing to the one after the last element
+ //! of the reversed varray.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ reverse_iterator rend() { return reverse_iterator(this->begin()); }
+
+ //! @brief Returns const reverse iterator to the one after the last element of the reversed container.
+ //!
+ //! @return const_reverse_iterator pointing to the one after the last element
+ //! of the reversed varray.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reverse_iterator rend() const { return const_reverse_iterator(this->begin()); }
+
+ //! @brief Returns const reverse iterator to the one after the last element of the reversed container.
+ //!
+ //! @return const_reverse_iterator pointing to the one after the last element
+ //! of the reversed varray.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ const_reverse_iterator crend() const { return const_reverse_iterator(this->begin()); }
+
+ //! @brief Returns container's capacity.
+ //!
+ //! @return container's capacity.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ static size_type capacity() { return Capacity; }
+
+ //! @brief Returns container's capacity.
+ //!
+ //! @return container's capacity.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ static size_type max_size() { return Capacity; }
+
+ //! @brief Returns the number of stored elements.
+ //!
+ //! @return Number of elements contained in the container.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ size_type size() const { return m_size; }
+
+ //! @brief Queries if the container contains elements.
+ //!
+ //! @return true if the number of elements contained in the
+ //! container is equal to 0.
+ //!
+ //! @par Throws
+ //! Nothing.
+ //!
+ //! @par Complexity
+ //! Constant O(1).
+ bool empty() const { return 0 == m_size; }
+
+private:
+
+ // @par Throws
+ // Nothing.
+ // @par Complexity
+ // Linear O(N).
+ template <std::size_t C>
+ void move_ctor_dispatch(varray<value_type, C> & other, boost::true_type /*use_memop*/)
+ {
+ ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
+ m_size = other.m_size;
+ }
+
+ // @par Throws
+ // @li If boost::has_nothrow_move<Value>::value is true and Value's move constructor throws
+ // @li If boost::has_nothrow_move<Value>::value is false and Value's copy constructor throws.
+ // @par Complexity
+ // Linear O(N).
+ template <std::size_t C>
+ void move_ctor_dispatch(varray<value_type, C> & other, boost::false_type /*use_memop*/)
+ {
+ namespace sv = varray_detail;
+ sv::uninitialized_move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw
+ m_size = other.m_size;
+ }
+
+ // @par Throws
+ // Nothing.
+ // @par Complexity
+ // Linear O(N).
+ template <std::size_t C>
+ void move_assign_dispatch(varray<value_type, C> & other, boost::true_type /*use_memop*/)
+ {
+ this->clear();
+
+ ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
+ std::swap(m_size, other.m_size);
+ }
+
+ // @par Throws
+ // @li If boost::has_nothrow_move<Value>::value is true and Value's move constructor or move assignment throws
+ // @li If boost::has_nothrow_move<Value>::value is false and Value's copy constructor or move assignment throws.
+ // @par Complexity
+ // Linear O(N).
+ template <std::size_t C>
+ void move_assign_dispatch(varray<value_type, C> & other, boost::false_type /*use_memop*/)
+ {
+ namespace sv = varray_detail;
+ if ( m_size <= static_cast<size_type>(other.size()) )
+ {
+ sv::move_if_noexcept(other.begin(), other.begin() + m_size, this->begin()); // may throw
+ // TODO - perform uninitialized_copy first?
+ sv::uninitialized_move_if_noexcept(other.begin() + m_size, other.end(), this->end()); // may throw
+ }
+ else
+ {
+ sv::move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw
+ sv::destroy(this->begin() + other.size(), this->end());
+ }
+ m_size = other.size(); // update end
+ }
+
+ // @par Throws
+ // Nothing.
+ // @par Complexity
+ // Linear O(N).
+ template <std::size_t C>
+ void swap_dispatch(varray<value_type, C> & other, boost::true_type const& /*use_optimized_swap*/)
+ {
+ typedef typename
+ boost::mpl::if_c<
+ Capacity < C,
+ aligned_storage_type,
+ typename varray<value_type, C>::aligned_storage_type
+ >::type
+ storage_type;
+
+ storage_type temp;
+ Value * temp_ptr = reinterpret_cast<Value*>(temp.address());
+
+ ::memcpy(temp_ptr, this->data(), sizeof(Value) * this->size());
+ ::memcpy(this->data(), other.data(), sizeof(Value) * other.size());
+ ::memcpy(other.data(), temp_ptr, sizeof(Value) * this->size());
+
+ std::swap(m_size, other.m_size);
+ }
+
+ // @par Throws
+ // If Value's move constructor or move assignment throws
+ // but only if use_memop_in_swap_and_move is false_type - default.
+ // @par Complexity
+ // Linear O(N).
+ template <std::size_t C>
+ void swap_dispatch(varray<value_type, C> & other, boost::false_type const& /*use_optimized_swap*/)
+ {
+ namespace sv = varray_detail;
+
+ typedef typename
+ vt::use_memop_in_swap_and_move use_memop_in_swap_and_move;
+
+ if ( this->size() < other.size() )
+ swap_dispatch_impl(this->begin(), this->end(), other.begin(), other.end(), use_memop_in_swap_and_move()); // may throw
+ else
+ swap_dispatch_impl(other.begin(), other.end(), this->begin(), this->end(), use_memop_in_swap_and_move()); // may throw
+ std::swap(m_size, other.m_size);
+ }
+
+ // @par Throws
+ // Nothing.
+ // @par Complexity
+ // Linear O(N).
+ void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, boost::true_type const& /*use_memop*/)
+ {
+ //BOOST_ASSERT_MSG(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la));
+
+ namespace sv = varray_detail;
+ for (; first_sm != last_sm ; ++first_sm, ++first_la)
+ {
+ boost::aligned_storage<
+ sizeof(value_type),
+ boost::alignment_of<value_type>::value
+ > temp_storage;
+ value_type * temp_ptr = reinterpret_cast<value_type*>(temp_storage.address());
+
+ ::memcpy(temp_ptr, boost::addressof(*first_sm), sizeof(value_type));
+ ::memcpy(boost::addressof(*first_sm), boost::addressof(*first_la), sizeof(value_type));
+ ::memcpy(boost::addressof(*first_la), temp_ptr, sizeof(value_type));
+ }
+
+ ::memcpy(first_sm, first_la, sizeof(value_type) * std::distance(first_la, last_la));
+ }
+
+ // @par Throws
+ // If Value's move constructor or move assignment throws.
+ // @par Complexity
+ // Linear O(N).
+ void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, boost::false_type const& /*use_memop*/)
+ {
+ //BOOST_ASSERT_MSG(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la));
+
+ namespace sv = varray_detail;
+ for (; first_sm != last_sm ; ++first_sm, ++first_la)
+ {
+ //boost::swap(*first_sm, *first_la); // may throw
+ value_type temp(boost::move(*first_sm)); // may throw
+ *first_sm = boost::move(*first_la); // may throw
+ *first_la = boost::move(temp); // may throw
+ }
+ sv::uninitialized_move(first_la, last_la, first_sm); // may throw
+ sv::destroy(first_la, last_la);
+ }
+
+ // insert
+
+ // @par Throws
+ // If Value's move constructor, move assignment throws
+ // or if Value's copy constructor or copy assignment throws.
+ // @par Complexity
+ // Linear O(N).
+ template <typename Iterator>
+ void insert_dispatch(iterator position, Iterator first, Iterator last, boost::random_access_traversal_tag const&)
+ {
+ BOOST_CONCEPT_ASSERT((boost_concepts::RandomAccessTraversal<Iterator>)); // Make sure you passed a RandomAccessIterator
+
+ errh::check_iterator_end_eq(*this, position);
+
+ typename boost::iterator_difference<Iterator>::type
+ count = std::distance(first, last);
+
+ errh::check_capacity(*this, m_size + count); // may throw
+
+ if ( position == this->end() )
+ {
+ namespace sv = varray_detail;
+
+ sv::uninitialized_copy(first, last, position); // may throw
+ m_size += count; // update end
+ }
+ else
+ {
+ this->insert_in_the_middle(position, first, last, count); // may throw
+ }
+ }
+
+ // @par Throws
+ // If Value's move constructor, move assignment throws
+ // or if Value's copy constructor or copy assignment throws.
+ // @par Complexity
+ // Linear O(N).
+ template <typename Iterator, typename Traversal>
+ void insert_dispatch(iterator position, Iterator first, Iterator last, Traversal const& /*not_random_access*/)
+ {
+ errh::check_iterator_end_eq(*this, position);
+
+ if ( position == this->end() )
+ {
+ namespace sv = varray_detail;
+
+ std::ptrdiff_t d = std::distance(position, this->begin() + Capacity);
+ std::size_t count = sv::uninitialized_copy_s(first, last, position, d); // may throw
+
+ errh::check_capacity(*this, count <= static_cast<std::size_t>(d) ? m_size + count : Capacity + 1); // may throw
+
+ m_size += count;
+ }
+ else
+ {
+ typename boost::iterator_difference<Iterator>::type
+ count = std::distance(first, last);
+
+ errh::check_capacity(*this, m_size + count); // may throw
+
+ this->insert_in_the_middle(position, first, last, count); // may throw
+ }
+ }
+
+ // @par Throws
+ // If Value's move constructor, move assignment throws
+ // or if Value's copy constructor or copy assignment throws.
+ // @par Complexity
+ // Linear O(N).
+ template <typename Iterator>
+ void insert_in_the_middle(iterator position, Iterator first, Iterator last, difference_type count)
+ {
+ namespace sv = varray_detail;
+
+ difference_type to_move = std::distance(position, this->end());
+
+ // TODO - should following lines check for exception and revert to the old size?
+
+ if ( count < to_move )
+ {
+ sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw
+ m_size += count; // update end
+ sv::move_backward(position, position + to_move - count, this->end() - count); // may throw
+ sv::copy(first, last, position); // may throw
+ }
+ else
+ {
+ Iterator middle_iter = first;
+ std::advance(middle_iter, to_move);
+
+ sv::uninitialized_copy(middle_iter, last, this->end()); // may throw
+ m_size += count - to_move; // update end
+ sv::uninitialized_move(position, position + to_move, position + count); // may throw
+ m_size += to_move; // update end
+ sv::copy(first, middle_iter, position); // may throw
+ }
+ }
+
+ // assign
+
+ // @par Throws
+ // If Value's constructor or assignment taking dereferenced Iterator throws.
+ // @par Complexity
+ // Linear O(N).
+ template <typename Iterator>
+ void assign_dispatch(Iterator first, Iterator last, boost::random_access_traversal_tag const& /*not_random_access*/)
+ {
+ namespace sv = varray_detail;
+
+ typename boost::iterator_difference<Iterator>::type
+ s = std::distance(first, last);
+
+ errh::check_capacity(*this, s); // may throw
+
+ if ( m_size <= static_cast<size_type>(s) )
+ {
+ sv::copy(first, first + m_size, this->begin()); // may throw
+ // TODO - perform uninitialized_copy first?
+ sv::uninitialized_copy(first + m_size, last, this->end()); // may throw
+ }
+ else
+ {
+ sv::copy(first, last, this->begin()); // may throw
+ sv::destroy(this->begin() + s, this->end());
+ }
+ m_size = s; // update end
+ }
+
+ // @par Throws
+ // If Value's constructor or assignment taking dereferenced Iterator throws.
+ // @par Complexity
+ // Linear O(N).
+ template <typename Iterator, typename Traversal>
+ void assign_dispatch(Iterator first, Iterator last, Traversal const& /*not_random_access*/)
+ {
+ namespace sv = varray_detail;
+
+ size_type s = 0;
+ iterator it = this->begin();
+
+ for ( ; it != this->end() && first != last ; ++it, ++first, ++s )
+ *it = *first; // may throw
+
+ sv::destroy(it, this->end());
+
+ std::ptrdiff_t d = std::distance(it, this->begin() + Capacity);
+ std::size_t count = sv::uninitialized_copy_s(first, last, it, d); // may throw
+ s += count;
+
+ errh::check_capacity(*this, count <= static_cast<std::size_t>(d) ? s : Capacity + 1); // may throw
+
+ m_size = s; // update end
+ }
+
+ pointer ptr()
+ {
+ return pointer(static_cast<Value*>(m_storage.address()));
+ }
+
+ const_pointer ptr() const
+ {
+ return const_pointer(static_cast<const Value*>(m_storage.address()));
+ }
+
+ size_type m_size;
+ aligned_storage_type m_storage;
+};
+
+#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
+
+template<typename Value>
+class varray<Value, 0>
+{
+ typedef varray_detail::varray_traits<Value, 0> vt;
+ typedef varray_detail::checker<varray> errh;
+
+public:
+ typedef typename vt::value_type value_type;
+ typedef typename vt::size_type size_type;
+ typedef typename vt::difference_type difference_type;
+ typedef typename vt::pointer pointer;
+ typedef typename vt::const_pointer const_pointer;
+ typedef typename vt::reference reference;
+ typedef typename vt::const_reference const_reference;
+
+ typedef pointer iterator;
+ typedef const_pointer const_iterator;
+ typedef boost::reverse_iterator<iterator> reverse_iterator;
+ typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ // nothrow
+ varray() {}
+
+ // strong
+ explicit varray(size_type count)
+ {
+ errh::check_capacity(*this, count); // may throw
+ }
+
+ // strong
+ varray(size_type count, value_type const&)
+ {
+ errh::check_capacity(*this, count); // may throw
+ }
+
+ // strong
+ varray(varray const& /*other*/)
+ {
+ //errh::check_capacity(*this, count);
+ }
+
+ // strong
+ template <std::size_t C>
+ varray(varray<value_type, C> const& other)
+ {
+ errh::check_capacity(*this, other.size()); // may throw
+ }
+
+ // strong
+ template <typename Iterator>
+ varray(Iterator first, Iterator last)
+ {
+ errh::check_capacity(*this, std::distance(first, last)); // may throw
+ }
+
+ // basic
+ varray & operator=(varray const& /*other*/)
+ {
+ //errh::check_capacity(*this, other.size());
+ return *this;
+ }
+
+ // basic
+ template <size_t C>
+ varray & operator=(varray<value_type, C> const& other)
+ {
+ errh::check_capacity(*this, other.size()); // may throw
+ return *this;
+ }
+
+ // nothrow
+ ~varray() {}
+
+ // strong
+ void resize(size_type count)
+ {
+ errh::check_capacity(*this, count); // may throw
+ }
+
+ // strong
+ void resize(size_type count, value_type const&)
+ {
+ errh::check_capacity(*this, count); // may throw
+ }
+
+
+ // nothrow
+ void reserve(size_type count)
+ {
+ errh::check_capacity(*this, count); // may throw
+ }
+
+ // strong
+ void push_back(value_type const&)
+ {
+ errh::check_capacity(*this, 1); // may throw
+ }
+
+ // nothrow
+ void pop_back()
+ {
+ errh::check_not_empty(*this);
+ }
+
+ // basic
+ void insert(iterator position, value_type const&)
+ {
+ errh::check_iterator_end_eq(*this, position);
+ errh::check_capacity(*this, 1); // may throw
+ }
+
+ // basic
+ void insert(iterator position, size_type count, value_type const&)
+ {
+ errh::check_iterator_end_eq(*this, position);
+ errh::check_capacity(*this, count); // may throw
+ }
+
+ // basic
+ template <typename Iterator>
+ void insert(iterator, Iterator first, Iterator last)
+ {
+ // TODO - add MPL_ASSERT, check if Iterator is really an iterator
+ errh::check_capacity(*this, std::distance(first, last)); // may throw
+ }
+
+ // basic
+ void erase(iterator position)
+ {
+ errh::check_iterator_end_neq(*this, position);
+ }
+
+ // basic
+ void erase(iterator first, iterator last)
+ {
+ errh::check_iterator_end_eq(*this, first);
+ errh::check_iterator_end_eq(*this, last);
+
+ //BOOST_ASSERT_MSG(0 <= n, "invalid range");
+ }
+
+ // basic
+ template <typename Iterator>
+ void assign(Iterator first, Iterator last)
+ {
+ // TODO - add MPL_ASSERT, check if Iterator is really an iterator
+ errh::check_capacity(*this, std::distance(first, last)); // may throw
+ }
+
+ // basic
+ void assign(size_type count, value_type const&)
+ {
+ errh::check_capacity(*this, count); // may throw
+ }
+
+ // nothrow
+ void clear() {}
+
+ // strong
+ reference at(size_type i)
+ {
+ errh::throw_out_of_bounds(*this, i); // may throw
+ return *(this->begin() + i);
+ }
+
+ // strong
+ const_reference at(size_type i) const
+ {
+ errh::throw_out_of_bounds(*this, i); // may throw
+ return *(this->begin() + i);
+ }
+
+ // nothrow
+ reference operator[](size_type i)
+ {
+ errh::check_index(*this, i);
+ return *(this->begin() + i);
+ }
+
+ // nothrow
+ const_reference operator[](size_type i) const
+ {
+ errh::check_index(*this, i);
+ return *(this->begin() + i);
+ }
+
+ // nothrow
+ reference front()
+ {
+ errh::check_not_empty(*this);
+ return *(this->begin());
+ }
+
+ // nothrow
+ const_reference front() const
+ {
+ errh::check_not_empty(*this);
+ return *(this->begin());
+ }
+
+ // nothrow
+ reference back()
+ {
+ errh::check_not_empty(*this);
+ return *(this->end() - 1);
+ }
+
+ // nothrow
+ const_reference back() const
+ {
+ errh::check_not_empty(*this);
+ return *(this->end() - 1);
+ }
+
+ // nothrow
+ Value * data() { return boost::addressof(*(this->ptr())); }
+ const Value * data() const { return boost::addressof(*(this->ptr())); }
+
+ // nothrow
+ iterator begin() { return this->ptr(); }
+ const_iterator begin() const { return this->ptr(); }
+ const_iterator cbegin() const { return this->ptr(); }
+ iterator end() { return this->begin(); }
+ const_iterator end() const { return this->begin(); }
+ const_iterator cend() const { return this->cbegin(); }
+ // nothrow
+ reverse_iterator rbegin() { return reverse_iterator(this->end()); }
+ const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); }
+ const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); }
+ reverse_iterator rend() { return reverse_iterator(this->begin()); }
+ const_reverse_iterator rend() const { return reverse_iterator(this->begin()); }
+ const_reverse_iterator crend() const { return reverse_iterator(this->begin()); }
+
+ // nothrow
+ size_type capacity() const { return 0; }
+ size_type max_size() const { return 0; }
+ size_type size() const { return 0; }
+ bool empty() const { return true; }
+
+private:
+ pointer ptr()
+ {
+ return pointer(reinterpret_cast<Value*>(this));
+ }
+
+ const_pointer ptr() const
+ {
+ return const_pointer(reinterpret_cast<const Value*>(this));
+ }
+};
+
+#endif // !BOOST_CONTAINER_DOXYGEN_INVOKED
+
+//! @brief Checks if contents of two varrays are equal.
+//!
+//! @ingroup varray_non_member
+//!
+//! @param x The first varray.
+//! @param y The second varray.
+//!
+//! @return \c true if containers have the same size and elements in both containers are equal.
+//!
+//! @par Complexity
+//! Linear O(N).
+template<typename V, std::size_t C1, std::size_t C2>
+bool operator== (varray<V, C1> const& x, varray<V, C2> const& y)
+{
+ return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin());
+}
+
+//! @brief Checks if contents of two varrays are not equal.
+//!
+//! @ingroup varray_non_member
+//!
+//! @param x The first varray.
+//! @param y The second varray.
+//!
+//! @return \c true if containers have different size or elements in both containers are not equal.
+//!
+//! @par Complexity
+//! Linear O(N).
+template<typename V, std::size_t C1, std::size_t C2>
+bool operator!= (varray<V, C1> const& x, varray<V, C2> const& y)
+{
+ return !(x==y);
+}
+
+//! @brief Lexicographically compares varrays.
+//!
+//! @ingroup varray_non_member
+//!
+//! @param x The first varray.
+//! @param y The second varray.
+//!
+//! @return \c true if x compares lexicographically less than y.
+//!
+//! @par Complexity
+//! Linear O(N).
+template<typename V, std::size_t C1, std::size_t C2>
+bool operator< (varray<V, C1> const& x, varray<V, C2> const& y)
+{
+ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
+}
+
+//! @brief Lexicographically compares varrays.
+//!
+//! @ingroup varray_non_member
+//!
+//! @param x The first varray.
+//! @param y The second varray.
+//!
+//! @return \c true if y compares lexicographically less than x.
+//!
+//! @par Complexity
+//! Linear O(N).
+template<typename V, std::size_t C1, std::size_t C2>
+bool operator> (varray<V, C1> const& x, varray<V, C2> const& y)
+{
+ return y<x;
+}
+
+//! @brief Lexicographically compares varrays.
+//!
+//! @ingroup varray_non_member
+//!
+//! @param x The first varray.
+//! @param y The second varray.
+//!
+//! @return \c true if y don't compare lexicographically less than x.
+//!
+//! @par Complexity
+//! Linear O(N).
+template<typename V, std::size_t C1, std::size_t C2>
+bool operator<= (varray<V, C1> const& x, varray<V, C2> const& y)
+{
+ return !(y<x);
+}
+
+//! @brief Lexicographically compares varrays.
+//!
+//! @ingroup varray_non_member
+//!
+//! @param x The first varray.
+//! @param y The second varray.
+//!
+//! @return \c true if x don't compare lexicographically less than y.
+//!
+//! @par Complexity
+//! Linear O(N).
+template<typename V, std::size_t C1, std::size_t C2>
+bool operator>= (varray<V, C1> const& x, varray<V, C2> const& y)
+{
+ return !(x<y);
+}
+
+//! @brief Swaps contents of two varrays.
+//!
+//! This function calls varray::swap().
+//!
+//! @ingroup varray_non_member
+//!
+//! @param x The first varray.
+//! @param y The second varray.
+//!
+//! @par Complexity
+//! Linear O(N).
+template<typename V, std::size_t C1, std::size_t C2>
+inline void swap(varray<V, C1> & x, varray<V, C2> & y)
+{
+ x.swap(y);
+}
+
+}}}} // namespace boost::geometry::index::detail
+
+// TODO - REMOVE/CHANGE
+#include <boost/container/detail/config_end.hpp>
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP
diff --git a/boost/geometry/index/detail/varray_detail.hpp b/boost/geometry/index/detail/varray_detail.hpp
new file mode 100644
index 0000000000..962d4d8288
--- /dev/null
+++ b/boost/geometry/index/detail/varray_detail.hpp
@@ -0,0 +1,756 @@
+// Boost.Geometry
+//
+// varray details
+//
+// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2011-2013 Andrew Hundt.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP
+#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP
+
+#include <cstddef>
+#include <cstring>
+#include <memory>
+#include <limits>
+
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/and.hpp>
+#include <boost/mpl/or.hpp>
+#include <boost/mpl/int.hpp>
+
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/remove_const.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/type_traits/has_trivial_assign.hpp>
+#include <boost/type_traits/has_trivial_copy.hpp>
+#include <boost/type_traits/has_trivial_constructor.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/type_traits/has_trivial_move_constructor.hpp>
+#include <boost/type_traits/has_trivial_move_assign.hpp>
+//#include <boost/type_traits/has_nothrow_constructor.hpp>
+//#include <boost/type_traits/has_nothrow_copy.hpp>
+//#include <boost/type_traits/has_nothrow_assign.hpp>
+//#include <boost/type_traits/has_nothrow_destructor.hpp>
+
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/config.hpp>
+#include <boost/move/move.hpp>
+#include <boost/utility/addressof.hpp>
+#include <boost/iterator/iterator_traits.hpp>
+
+// TODO - move vectors iterators optimization to the other, optional file instead of checking defines?
+
+#if defined(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS)
+#include <vector>
+#include <boost/container/vector.hpp>
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION && !BOOST_NO_EXCEPTIONS
+
+namespace boost { namespace geometry { namespace index { namespace detail { namespace varray_detail {
+
+template <typename I>
+struct are_elements_contiguous : boost::is_pointer<I>
+{};
+
+// EXPERIMENTAL - not finished
+// Conditional setup - mark vector iterators defined in known implementations
+// as iterators pointing to contiguous ranges
+
+#if defined(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS)
+
+template <typename Pointer>
+struct are_elements_contiguous<
+ boost::container::container_detail::vector_const_iterator<Pointer>
+> : boost::true_type
+{};
+
+template <typename Pointer>
+struct are_elements_contiguous<
+ boost::container::container_detail::vector_iterator<Pointer>
+> : boost::true_type
+{};
+
+#if defined(BOOST_DINKUMWARE_STDLIB)
+
+template <typename T>
+struct are_elements_contiguous<
+ std::_Vector_const_iterator<T>
+> : boost::true_type
+{};
+
+template <typename T>
+struct are_elements_contiguous<
+ std::_Vector_iterator<T>
+> : boost::true_type
+{};
+
+#elif defined(BOOST_GNU_STDLIB)
+
+template <typename P, typename T, typename A>
+struct are_elements_contiguous<
+ __gnu_cxx::__normal_iterator<P, std::vector<T, A> >
+> : boost::true_type
+{};
+
+#elif defined(_LIBCPP_VERSION)
+
+// TODO - test it first
+//template <typename P>
+//struct are_elements_contiguous<
+// __wrap_iter<P>
+//> : boost::true_type
+//{};
+
+#else // OTHER_STDLIB
+
+// TODO - add other iterators implementations
+
+#endif // STDLIB
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION && !BOOST_NO_EXCEPTIONS
+
+// True if iterator values are the same and both iterators points to the ranges of contiguous elements
+
+template <typename I, typename O>
+struct are_corresponding :
+ ::boost::mpl::and_<
+ ::boost::is_same<
+ ::boost::remove_const<
+ typename ::boost::iterator_value<I>::type
+ >,
+ ::boost::remove_const<
+ typename ::boost::iterator_value<O>::type
+ >
+ >,
+ are_elements_contiguous<I>,
+ are_elements_contiguous<O>
+ >
+{};
+
+template <typename I, typename V>
+struct is_corresponding_value :
+ ::boost::is_same<
+ ::boost::remove_const<
+ typename ::boost::iterator_value<I>::type
+ >,
+ ::boost::remove_const<V>
+ >
+{};
+
+// destroy(I, I)
+
+template <typename I>
+void destroy_dispatch(I /*first*/, I /*last*/,
+ boost::true_type const& /*has_trivial_destructor*/)
+{}
+
+template <typename I>
+void destroy_dispatch(I first, I last,
+ boost::false_type const& /*has_trivial_destructor*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ for ( ; first != last ; ++first )
+ first->~value_type();
+}
+
+template <typename I>
+void destroy(I first, I last)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ destroy_dispatch(first, last, has_trivial_destructor<value_type>());
+}
+
+// destroy(I)
+
+template <typename I>
+void destroy_dispatch(I /*pos*/,
+ boost::true_type const& /*has_trivial_destructor*/)
+{}
+
+template <typename I>
+void destroy_dispatch(I pos,
+ boost::false_type const& /*has_trivial_destructor*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ pos->~value_type();
+}
+
+template <typename I>
+void destroy(I pos)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ destroy_dispatch(pos, has_trivial_destructor<value_type>());
+}
+
+// copy(I, I, O)
+
+template <typename I, typename O>
+inline O copy_dispatch(I first, I last, O dst,
+ boost::mpl::bool_<true> const& /*use_memmove*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ typename boost::iterator_difference<I>::type d = std::distance(first, last);
+
+ ::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
+ return dst + d;
+}
+
+template <typename I, typename O>
+inline O copy_dispatch(I first, I last, O dst,
+ boost::mpl::bool_<false> const& /*use_memmove*/)
+{
+ return std::copy(first, last, dst); // may throw
+}
+
+template <typename I, typename O>
+inline O copy(I first, I last, O dst)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ are_corresponding<I, O>,
+ ::boost::has_trivial_assign<
+ typename ::boost::iterator_value<O>::type
+ >
+ >::type
+ use_memmove;
+
+ return copy_dispatch(first, last, dst, use_memmove()); // may throw
+}
+
+// uninitialized_copy(I, I, O)
+
+template <typename I, typename O>
+inline
+O uninitialized_copy_dispatch(I first, I last, O dst,
+ boost::mpl::bool_<true> const& /*use_memcpy*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ typename boost::iterator_difference<I>::type d = std::distance(first, last);
+
+ ::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
+ return dst + d;
+}
+
+template <typename I, typename F>
+inline
+F uninitialized_copy_dispatch(I first, I last, F dst,
+ boost::mpl::bool_<false> const& /*use_memcpy*/)
+{
+ return std::uninitialized_copy(first, last, dst); // may throw
+}
+
+template <typename I, typename F>
+inline
+F uninitialized_copy(I first, I last, F dst)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ are_corresponding<I, F>,
+ ::boost::has_trivial_copy<
+ typename ::boost::iterator_value<F>::type
+ >
+ >::type
+ use_memcpy;
+
+ return uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw
+}
+
+// uninitialized_move(I, I, O)
+
+template <typename I, typename O>
+inline
+O uninitialized_move_dispatch(I first, I last, O dst,
+ boost::mpl::bool_<true> const& /*use_memcpy*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ typename boost::iterator_difference<I>::type d = std::distance(first, last);
+
+ ::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
+ return dst + d;
+}
+
+template <typename I, typename O>
+inline
+O uninitialized_move_dispatch(I first, I last, O dst,
+ boost::mpl::bool_<false> const& /*use_memcpy*/)
+{
+ //return boost::uninitialized_move(first, last, dst); // may throw
+
+ O o = dst;
+
+ BOOST_TRY
+ {
+ typedef typename std::iterator_traits<O>::value_type value_type;
+ for (; first != last; ++first, ++o )
+ new (boost::addressof(*o)) value_type(boost::move(*first));
+ }
+ BOOST_CATCH(...)
+ {
+ destroy(dst, o);
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+
+ return dst;
+}
+
+template <typename I, typename O>
+inline
+O uninitialized_move(I first, I last, O dst)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ are_corresponding<I, O>,
+ ::boost::has_trivial_copy<
+ typename ::boost::iterator_value<O>::type
+ >
+ >::type
+ use_memcpy;
+
+ return uninitialized_move_dispatch(first, last, dst, use_memcpy()); // may throw
+}
+
+// TODO - move uses memmove - implement 2nd version using memcpy?
+
+// move(I, I, O)
+
+template <typename I, typename O>
+inline
+O move_dispatch(I first, I last, O dst,
+ boost::mpl::bool_<true> const& /*use_memmove*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ typename boost::iterator_difference<I>::type d = std::distance(first, last);
+
+ ::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
+ return dst + d;
+}
+
+template <typename I, typename O>
+inline
+O move_dispatch(I first, I last, O dst,
+ boost::mpl::bool_<false> const& /*use_memmove*/)
+{
+ return boost::move(first, last, dst); // may throw
+}
+
+template <typename I, typename O>
+inline
+O move(I first, I last, O dst)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ are_corresponding<I, O>,
+ ::boost::has_trivial_assign<
+ typename ::boost::iterator_value<O>::type
+ >
+ >::type
+ use_memmove;
+
+ return move_dispatch(first, last, dst, use_memmove()); // may throw
+}
+
+// move_backward(BDI, BDI, BDO)
+
+template <typename BDI, typename BDO>
+inline
+BDO move_backward_dispatch(BDI first, BDI last, BDO dst,
+ boost::mpl::bool_<true> const& /*use_memmove*/)
+{
+ typedef typename boost::iterator_value<BDI>::type value_type;
+ typename boost::iterator_difference<BDI>::type d = std::distance(first, last);
+
+ BDO foo(dst - d);
+ ::memmove(boost::addressof(*foo), boost::addressof(*first), sizeof(value_type) * d);
+ return foo;
+}
+
+template <typename BDI, typename BDO>
+inline
+BDO move_backward_dispatch(BDI first, BDI last, BDO dst,
+ boost::mpl::bool_<false> const& /*use_memmove*/)
+{
+ return boost::move_backward(first, last, dst); // may throw
+}
+
+template <typename BDI, typename BDO>
+inline
+BDO move_backward(BDI first, BDI last, BDO dst)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ are_corresponding<BDI, BDO>,
+ ::boost::has_trivial_assign<
+ typename ::boost::iterator_value<BDO>::type
+ >
+ >::type
+ use_memmove;
+
+ return move_backward_dispatch(first, last, dst, use_memmove()); // may throw
+}
+
+template <typename T>
+struct has_nothrow_move : public
+ ::boost::mpl::or_<
+ boost::mpl::bool_<
+ ::boost::has_nothrow_move<
+ typename ::boost::remove_const<T>::type
+ >::value
+ >,
+ boost::mpl::bool_<
+ ::boost::has_nothrow_move<T>::value
+ >
+ >
+{};
+
+// uninitialized_move_if_noexcept(I, I, O)
+
+template <typename I, typename O>
+inline
+O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/)
+{ return varray_detail::uninitialized_move(first, last, dst); }
+
+template <typename I, typename O>
+inline
+O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/)
+{ return varray_detail::uninitialized_copy(first, last, dst); }
+
+template <typename I, typename O>
+inline
+O uninitialized_move_if_noexcept(I first, I last, O dst)
+{
+ typedef typename has_nothrow_move<
+ typename ::boost::iterator_value<O>::type
+ >::type use_move;
+
+ return uninitialized_move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw
+}
+
+// move_if_noexcept(I, I, O)
+
+template <typename I, typename O>
+inline
+O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/)
+{ return move(first, last, dst); }
+
+template <typename I, typename O>
+inline
+O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/)
+{ return copy(first, last, dst); }
+
+template <typename I, typename O>
+inline
+O move_if_noexcept(I first, I last, O dst)
+{
+ typedef typename has_nothrow_move<
+ typename ::boost::iterator_value<O>::type
+ >::type use_move;
+
+ return move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw
+}
+
+// uninitialized_fill(I, I)
+
+template <typename I>
+inline
+void uninitialized_fill_dispatch(I /*first*/, I /*last*/,
+ boost::true_type const& /*has_trivial_constructor*/,
+ boost::true_type const& /*disable_trivial_init*/)
+{}
+
+template <typename I>
+inline
+void uninitialized_fill_dispatch(I first, I last,
+ boost::true_type const& /*has_trivial_constructor*/,
+ boost::false_type const& /*disable_trivial_init*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ for ( ; first != last ; ++first )
+ new (boost::addressof(*first)) value_type();
+}
+
+template <typename I, typename DisableTrivialInit>
+inline
+void uninitialized_fill_dispatch(I first, I last,
+ boost::false_type const& /*has_trivial_constructor*/,
+ DisableTrivialInit const& /*not_used*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ I it = first;
+
+ BOOST_TRY
+ {
+ for ( ; it != last ; ++it )
+ new (boost::addressof(*it)) value_type(); // may throw
+ }
+ BOOST_CATCH(...)
+ {
+ destroy(first, it);
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+}
+
+template <typename I, typename DisableTrivialInit>
+inline
+void uninitialized_fill(I first, I last, DisableTrivialInit const& disable_trivial_init)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ uninitialized_fill_dispatch(first, last, boost::has_trivial_constructor<value_type>(), disable_trivial_init); // may throw
+}
+
+// construct(I)
+
+template <typename I>
+inline
+void construct_dispatch(boost::mpl::bool_<true> const& /*dont_init*/, I /*pos*/)
+{}
+
+template <typename I>
+inline
+void construct_dispatch(boost::mpl::bool_<false> const& /*dont_init*/, I pos)
+{
+ typedef typename ::boost::iterator_value<I>::type value_type;
+ new (static_cast<void*>(::boost::addressof(*pos))) value_type(); // may throw
+}
+
+template <typename DisableTrivialInit, typename I>
+inline
+void construct(DisableTrivialInit const&, I pos)
+{
+ typedef typename ::boost::iterator_value<I>::type value_type;
+ typedef typename ::boost::mpl::and_<
+ boost::has_trivial_constructor<value_type>,
+ DisableTrivialInit
+ >::type dont_init;
+
+ construct_dispatch(dont_init(), pos); // may throw
+}
+
+// construct(I, V)
+
+template <typename I, typename V>
+inline
+void construct_copy_dispatch(I pos, V const& v,
+ boost::mpl::bool_<true> const& /*use_memcpy*/)
+{
+ ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
+}
+
+template <typename I, typename P>
+inline
+void construct_copy_dispatch(I pos, P const& p,
+ boost::mpl::bool_<false> const& /*use_memcpy*/)
+{
+ typedef typename boost::iterator_value<I>::type V;
+ new (static_cast<void*>(boost::addressof(*pos))) V(p); // may throw
+}
+
+template <typename DisableTrivialInit, typename I, typename P>
+inline
+void construct(DisableTrivialInit const&,
+ I pos, P const& p)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ is_corresponding_value<I, P>,
+ ::boost::has_trivial_copy<P>
+ >::type
+ use_memcpy;
+
+ construct_copy_dispatch(pos, p, use_memcpy()); // may throw
+}
+
+// Needed by push_back(V &&)
+
+template <typename I, typename V>
+inline
+void construct_move_dispatch(I pos, V const& v,
+ boost::mpl::bool_<true> const& /*use_memcpy*/)
+{
+ ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
+}
+
+template <typename I, typename P>
+inline
+void construct_move_dispatch(I pos, BOOST_RV_REF(P) p,
+ boost::mpl::bool_<false> const& /*use_memcpy*/)
+{
+ typedef typename boost::iterator_value<I>::type V;
+ new (static_cast<void*>(boost::addressof(*pos))) V(::boost::move(p)); // may throw
+}
+
+template <typename DisableTrivialInit, typename I, typename P>
+inline
+void construct(DisableTrivialInit const&, I pos, BOOST_RV_REF(P) p)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ is_corresponding_value<I, P>,
+ ::boost::has_trivial_move_constructor<P>
+ >::type
+ use_memcpy;
+
+ construct_move_dispatch(pos, ::boost::move(p), use_memcpy()); // may throw
+}
+
+// Needed by emplace_back() and emplace()
+
+#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE)
+#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+
+template <typename DisableTrivialInit, typename I, class ...Args>
+inline
+void construct(DisableTrivialInit const&,
+ I pos,
+ BOOST_FWD_REF(Args) ...args)
+{
+ typedef typename boost::iterator_value<I>::type V;
+ new (static_cast<void*>(boost::addressof(*pos))) V(::boost::forward<Args>(args)...); // may throw
+}
+
+#else // !BOOST_NO_CXX11_VARIADIC_TEMPLATES
+
+// BOOST_NO_CXX11_RVALUE_REFERENCES -> P0 const& p0
+// !BOOST_NO_CXX11_RVALUE_REFERENCES -> P0 && p0
+// which means that version with one parameter may take V const& v
+
+#define BOOST_PP_LOCAL_MACRO(n) \
+template <typename DisableTrivialInit, typename I, typename P BOOST_PP_ENUM_TRAILING_PARAMS(n, typename P) > \
+inline \
+void construct(DisableTrivialInit const&, \
+ I pos, \
+ BOOST_CONTAINER_PP_PARAM(P, p) \
+ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \
+{ \
+ typedef typename boost::iterator_value<I>::type V; \
+ new \
+ (static_cast<void*>(boost::addressof(*pos))) \
+ V(p, BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); /*may throw*/ \
+} \
+//
+#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
+#include BOOST_PP_LOCAL_ITERATE()
+
+#endif // !BOOST_NO_CXX11_VARIADIC_TEMPLATES
+#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE
+
+// assign(I, V)
+
+template <typename I, typename V>
+inline
+void assign_copy_dispatch(I pos, V const& v,
+ boost::mpl::bool_<true> const& /*use_memcpy*/)
+{
+// TODO - use memmove here?
+ ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
+}
+
+template <typename I, typename V>
+inline
+void assign_copy_dispatch(I pos, V const& v,
+ boost::mpl::bool_<false> const& /*use_memcpy*/)
+{
+ *pos = v; // may throw
+}
+
+template <typename I, typename V>
+inline
+void assign(I pos, V const& v)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ is_corresponding_value<I, V>,
+ ::boost::has_trivial_assign<V>
+ >::type
+ use_memcpy;
+
+ assign_copy_dispatch(pos, v, use_memcpy()); // may throw
+}
+
+template <typename I, typename V>
+inline
+void assign_move_dispatch(I pos, V const& v,
+ boost::mpl::bool_<true> const& /*use_memcpy*/)
+{
+// TODO - use memmove here?
+ ::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
+}
+
+template <typename I, typename V>
+inline
+void assign_move_dispatch(I pos, BOOST_RV_REF(V) v,
+ boost::mpl::bool_<false> const& /*use_memcpy*/)
+{
+ *pos = boost::move(v); // may throw
+}
+
+template <typename I, typename V>
+inline
+void assign(I pos, BOOST_RV_REF(V) v)
+{
+ typedef typename
+ ::boost::mpl::and_<
+ is_corresponding_value<I, V>,
+ ::boost::has_trivial_move_assign<V>
+ >::type
+ use_memcpy;
+
+ assign_move_dispatch(pos, ::boost::move(v), use_memcpy());
+}
+
+// uninitialized_copy_s
+
+template <typename I, typename F>
+inline std::size_t uninitialized_copy_s(I first, I last, F dest, std::size_t max_count)
+{
+ std::size_t count = 0;
+ F it = dest;
+
+ BOOST_TRY
+ {
+ for ( ; first != last ; ++it, ++first, ++count )
+ {
+ if ( max_count <= count )
+ return (std::numeric_limits<std::size_t>::max)();
+
+ // dummy 0 as DisableTrivialInit
+ construct(0, it, *first); // may throw
+ }
+ }
+ BOOST_CATCH(...)
+ {
+ destroy(dest, it);
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+
+ return count;
+}
+
+// scoped_destructor
+
+template<class T>
+class scoped_destructor
+{
+public:
+ scoped_destructor(T * ptr) : m_ptr(ptr) {}
+
+ ~scoped_destructor()
+ {
+ if(m_ptr)
+ destroy(m_ptr);
+ }
+
+ void release() { m_ptr = 0; }
+
+private:
+ T * m_ptr;
+};
+
+}}}}} // namespace boost::geometry::index::detail::varray_detail
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP
diff --git a/boost/geometry/index/distance_predicates.hpp b/boost/geometry/index/distance_predicates.hpp
new file mode 100644
index 0000000000..59b32af475
--- /dev/null
+++ b/boost/geometry/index/distance_predicates.hpp
@@ -0,0 +1,204 @@
+// Boost.Geometry Index
+//
+// Spatial index distance predicates, calculators and checkers used in nearest neighbor query
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP
+#define BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP
+
+#include <boost/geometry/index/detail/distance_predicates.hpp>
+
+/*!
+\defgroup nearest_relations Nearest relations (boost::geometry::index::)
+*/
+
+namespace boost { namespace geometry { namespace index {
+
+// relations generators
+
+#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+
+/*!
+\brief Generate to_nearest() relationship.
+
+Generate a nearest query Point and Value's Indexable relationship while calculating
+distances. This function may be used to define that knn query should calculate distances
+as smallest as possible between query Point and Indexable's points. In other words it
+should be the distance to the nearest Indexable's point. This function may be also used
+to define distances bounds which indicates that Indexable's nearest point should be
+closer or further than value v. This is default relation.
+
+\ingroup nearest_relations
+
+\tparam T Type of wrapped object. This may be a Point for PointRelation or CoordinateType for
+ MinRelation or MaxRelation
+
+\param v Point or distance value.
+*/
+template <typename T>
+detail::to_nearest<T> to_nearest(T const& v)
+{
+ return detail::to_nearest<T>(v);
+}
+
+/*!
+\brief Generate to_centroid() relationship.
+
+Generate a nearest query Point and Value's Indexable relationship while calculating
+distances. This function may be used to define that knn query should calculate distances
+between query Point and Indexable's centroid. This function may be also used
+to define distances bounds which indicates that Indexable's centroid should be
+closer or further than value v.
+
+\ingroup nearest_relations
+
+\tparam T Type of wrapped object. This may be a Point for PointRelation or some CoordinateType for
+ MinRelation or MaxRelation
+
+\param v Point or distance value.
+*/
+template <typename T>
+detail::to_centroid<T> to_centroid(T const& v)
+{
+ return detail::to_centroid<T>(v);
+}
+
+/*!
+\brief Generate to_furthest() relationship.
+
+Generate a nearest query Point and Value's Indexable relationship while calculating
+distances. This function may be used to define that knn query should calculate distances
+as biggest as possible between query Point and Indexable's points. In other words it
+should be the distance to the furthest Indexable's point. This function may be also used
+to define distances bounds which indicates that Indexable's furthest point should be
+closer or further than value v.
+
+\ingroup nearest_relations
+
+\tparam T Type of wrapped object. This may be a Point for PointRelation or some CoordinateType for
+ MinRelation or MaxRelation
+
+\param v Point or distance value.
+*/
+template <typename T>
+detail::to_furthest<T> to_furthest(T const& v)
+{
+ return detail::to_furthest<T>(v);
+}
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+
+// distance predicates generators
+
+/*!
+\brief Generate unbounded() distance predicate.
+
+Generate a distance predicate. This defines distances bounds which are used by knn query.
+This function indicates that there is no distance bounds and Values should be returned
+if distances between Point and Indexable are the smallest. Distance calculation is defined
+by PointRelation. This is default nearest predicate.
+
+\ingroup distance_predicates
+
+\tparam PointRelation PointRelation type.
+
+\param pr The point relation. This may be generated by \c index::to_nearest(),
+ \c index::to_centroid() or \c index::to_furthest() with \c Point passed as a parameter.
+*/
+//template <typename PointRelation>
+//inline detail::unbounded<PointRelation>
+//unbounded(PointRelation const& pr)
+//{
+// return detail::unbounded<PointRelation>(pr);
+//}
+
+/*!
+\brief Generate min_bounded() distance predicate.
+
+Generate a distance predicate. This defines distances bounds which are used by knn query.
+This function indicates that Values should be returned only if distances between Point and
+Indexable are greater or equal to some min_distance passed in MinRelation. Check for closest Value is
+defined by PointRelation. So it is possible e.g. to return Values with centroids closest to some
+Point but only if nearest points are further than some distance.
+
+\ingroup distance_predicates
+
+\tparam PointRelation PointRelation type.
+\tparam MinRelation MinRelation type.
+
+\param pr The point relation. This may be generated by \c to_nearest(),
+ \c to_centroid() or \c to_furthest() with \c Point passed as a parameter.
+\param minr The minimum bound relation. This may be generated by \c to_nearest(),
+ \c to_centroid() or \c to_furthest() with distance value passed as a parameter.
+*/
+//template <typename PointRelation, typename MinRelation>
+//inline detail::min_bounded<PointRelation, MinRelation>
+//min_bounded(PointRelation const& pr, MinRelation const& minr)
+//{
+// return detail::min_bounded<PointRelation, MinRelation>(pr, minr);
+//}
+
+/*!
+\brief Generate max_bounded() distance predicate.
+
+Generate a distance predicate. This defines distances bounds which are used by knn query.
+This function indicates that Values should be returned only if distances between Point and
+Indexable are lesser or equal to some max_distance passed in MaxRelation. Check for closest Value is
+defined by PointRelation. So it is possible e.g. to return Values with centroids closest to some
+Point but only if nearest points are closer than some distance.
+
+\ingroup distance_predicates
+
+\tparam PointRelation PointRelation type.
+\tparam MaxRelation MaxRelation type.
+
+\param pr The point relation. This may be generated by \c to_nearest(),
+ \c to_centroid() or \c to_furthest() with \c Point passed as a parameter.
+\param maxr The maximum bound relation. This may be generated by \c to_nearest(),
+ \c to_centroid() or \c to_furthest() with distance value passed as a parameter.
+*/
+//template <typename PointRelation, typename MaxRelation>
+//inline detail::max_bounded<PointRelation, MaxRelation>
+//max_bounded(PointRelation const& pr, MaxRelation const& maxr)
+//{
+// return detail::max_bounded<PointRelation, MaxRelation>(pr, maxr);
+//}
+
+/*!
+\brief Generate bounded() distance predicate.
+
+Generate a distance predicate. This defines distances bounds which are used by knn query.
+This function indicates that Values should be returned only if distances between Point and
+Indexable are greater or equal to some min_distance passed in MinRelation and lesser or equal to
+some max_distance passed in MaxRelation. Check for closest Value is defined by PointRelation.
+So it is possible e.g. to return Values with centroids closest to some Point but only if nearest
+points are further than some distance and closer than some other distance.
+
+\ingroup distance_predicates
+
+\tparam PointRelation PointRelation type.
+\tparam MinRelation MinRelation type.
+\tparam MaxRelation MaxRelation type.
+
+\param pr The point relation. This may be generated by \c to_nearest(),
+ \c to_centroid() or \c to_furthest() with \c Point passed as a parameter.
+\param minr The minimum bound relation. This may be generated by \c to_nearest(),
+ \c to_centroid() or \c to_furthest() with distance value passed as a parameter.
+\param maxr The maximum bound relation. This may be generated by \c to_nearest(),
+ \c to_centroid() or \c to_furthest() with distance value passed as a parameter.
+*/
+//template <typename PointRelation, typename MinRelation, typename MaxRelation>
+//inline detail::bounded<PointRelation, MinRelation, MaxRelation>
+//bounded(PointRelation const& pr, MinRelation const& minr, MaxRelation const& maxr)
+//{
+// return detail::bounded<PointRelation, MinRelation, MaxRelation>(pr, minr, maxr);
+//}
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP
diff --git a/boost/geometry/index/equal_to.hpp b/boost/geometry/index/equal_to.hpp
new file mode 100644
index 0000000000..5fbaa8209f
--- /dev/null
+++ b/boost/geometry/index/equal_to.hpp
@@ -0,0 +1,249 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP
+#define BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/index/indexable.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+struct equals
+{
+ inline static bool apply(Geometry const& g1, Geometry const& g2)
+ {
+ return geometry::equals(g1, g2);
+ }
+};
+
+template <typename T>
+struct equals<T, void>
+{
+ inline static bool apply(T const& v1, T const& v2)
+ {
+ return v1 == v2;
+ }
+};
+
+template <typename Tuple, size_t I, size_t N>
+struct tuple_equals
+{
+ inline static bool apply(Tuple const& t1, Tuple const& t2)
+ {
+ typedef typename boost::tuples::element<I, Tuple>::type T;
+
+ return equals<T>::apply(boost::get<I>(t1), boost::get<I>(t2))
+ && tuple_equals<Tuple, I+1, N>::apply(t1, t2);
+ }
+};
+
+template <typename Tuple, size_t I>
+struct tuple_equals<Tuple, I, I>
+{
+ inline static bool apply(Tuple const&, Tuple const&)
+ {
+ return true;
+ }
+};
+
+// TODO: Consider this: Since equal_to<> is using geometry::equals() it's possible that
+// two compared Indexables are not exactly the same! They will be spatially equal
+// but not strictly equal. Consider 2 Segments with reversed order of points.
+// Therefore it's possible that during the Value removal different value will be
+// removed than the one that was passed.
+
+/*!
+\brief The function object comparing Values.
+
+It compares Geometries using geometry::equals() function. Other types are compared using operator==.
+The default version handles Values which are Indexables.
+This template is also specialized for std::pair<T1, T2> and boost::tuple<...>.
+
+\tparam Value The type of objects which are compared by this function object.
+\tparam IsIndexable If true, Values are compared using boost::geometry::equals() functions.
+*/
+template <typename Value,
+ bool IsIndexable = is_indexable<Value>::value>
+struct equal_to
+{
+ /*! \brief The type of result returned by function object. */
+ typedef bool result_type;
+
+ /*!
+ \brief Compare values. If Value is a Geometry geometry::equals() function is used.
+
+ \param l First value.
+ \param r Second value.
+ \return true if values are equal.
+ */
+ inline bool operator()(Value const& l, Value const& r) const
+ {
+ return detail::equals<Value>::apply(l ,r);
+ }
+};
+
+/*!
+\brief The function object comparing Values.
+
+This specialization compares values of type std::pair<T1, T2>.
+It compares pairs' first values, then second values.
+
+\tparam T1 The first type.
+\tparam T2 The second type.
+*/
+template <typename T1, typename T2>
+struct equal_to<std::pair<T1, T2>, false>
+{
+ /*! \brief The type of result returned by function object. */
+ typedef bool result_type;
+
+ /*!
+ \brief Compare values. If pair<> Value member is a Geometry geometry::equals() function is used.
+
+ \param l First value.
+ \param r Second value.
+ \return true if values are equal.
+ */
+ inline bool operator()(std::pair<T1, T2> const& l, std::pair<T1, T2> const& r) const
+ {
+ return detail::equals<T1>::apply(l.first, r.first)
+ && detail::equals<T2>::apply(l.second, r.second);
+ }
+};
+
+/*!
+\brief The function object comparing Values.
+
+This specialization compares values of type boost::tuple<...>.
+It compares all members of the tuple from the first one to the last one.
+*/
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct equal_to<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, false>
+{
+ typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> value_type;
+
+ /*! \brief The type of result returned by function object. */
+ typedef bool result_type;
+
+ /*!
+ \brief Compare values. If tuple<> Value member is a Geometry geometry::equals() function is used.
+
+ \param l First value.
+ \param r Second value.
+ \return true if values are equal.
+ */
+ inline bool operator()(value_type const& l, value_type const& r) const
+ {
+ return detail::tuple_equals<
+ value_type, 0, boost::tuples::length<value_type>::value
+ >::apply(l ,r);
+ }
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+
+#include <tuple>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename Tuple, size_t I, size_t N>
+struct std_tuple_equals
+{
+ inline static bool apply(Tuple const& t1, Tuple const& t2)
+ {
+ typedef typename std::tuple_element<I, Tuple>::type T;
+
+ return equals<T>::apply(std::get<I>(t1), std::get<I>(t2))
+ && std_tuple_equals<Tuple, I+1, N>::apply(t1, t2);
+ }
+};
+
+template <typename Tuple, size_t I>
+struct std_tuple_equals<Tuple, I, I>
+{
+ inline static bool apply(Tuple const&, Tuple const&)
+ {
+ return true;
+ }
+};
+
+/*!
+\brief The function object comparing Values.
+
+This specialization compares values of type std::tuple<Args...>.
+It's defined if the compiler supports tuples and variadic templates.
+It compares all members of the tuple from the first one to the last one.
+*/
+template <typename ...Args>
+struct equal_to<std::tuple<Args...>, false>
+{
+ typedef std::tuple<Args...> value_type;
+
+ /*! \brief The type of result returned by function object. */
+ typedef bool result_type;
+
+ /*!
+ \brief Compare values. If tuple<> Value member is a Geometry geometry::equals() function is used.
+
+ \param l First value.
+ \param r Second value.
+ \return true if values are equal.
+ */
+ bool operator()(value_type const& l, value_type const& r) const
+ {
+ return detail::std_tuple_equals<
+ value_type, 0, std::tuple_size<value_type>::value
+ >::apply(l ,r);
+ }
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+
+namespace boost { namespace geometry { namespace index {
+
+/*!
+\brief The function object comparing Values.
+
+The default version handles Values which are Indexables, std::pair<T1, T2>, boost::tuple<...>
+and std::tuple<...> if STD tuples and variadic templates are supported.
+All members are compared from left to right, Geometries using boost::geometry::equals() function,
+other types using operator==.
+
+\tparam Value The type of objects which are compared by this function object.
+*/
+template <typename Value>
+struct equal_to
+ : detail::equal_to<Value>
+{
+ /*! \brief The type of result returned by function object. */
+ typedef typename detail::equal_to<Value>::result_type result_type;
+
+ /*!
+ \brief Compare Values.
+
+ \param l First value.
+ \param r Second value.
+ \return true if Values are equal.
+ */
+ inline bool operator()(Value const& l, Value const& r) const
+ {
+ return detail::equal_to<Value>::operator()(l ,r);
+ }
+};
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP
diff --git a/boost/geometry/index/indexable.hpp b/boost/geometry/index/indexable.hpp
new file mode 100644
index 0000000000..391b544f37
--- /dev/null
+++ b/boost/geometry/index/indexable.hpp
@@ -0,0 +1,217 @@
+// Boost.Geometry Index
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_INDEXABLE_HPP
+#define BOOST_GEOMETRY_INDEX_INDEXABLE_HPP
+
+#include <boost/mpl/assert.hpp>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+template <typename Geometry, typename GeometryTag>
+struct is_indexable_impl { static const bool value = false; };
+
+template <typename Point>
+struct is_indexable_impl<Point, geometry::point_tag> { static const bool value = true; };
+
+template <typename Box>
+struct is_indexable_impl<Box, geometry::box_tag> { static const bool value = true; };
+
+template <typename Segment>
+struct is_indexable_impl<Segment, geometry::segment_tag> { static const bool value = true; };
+
+template <typename Indexable>
+struct is_indexable
+{
+ static const bool value =
+ is_indexable_impl
+ <
+ Indexable,
+ typename geometry::tag<Indexable>::type
+ >::value;
+};
+
+/*!
+\brief The function object extracting Indexable from Value.
+
+It translates Value object to Indexable object. The default version handles Values which are Indexables.
+This template is also specialized for std::pair<Indexable, T2>, boost::tuple<Indexable, ...>
+and std::tuple<Indexable, ...>.
+
+\tparam Value The Value type which may be translated directly to the Indexable.
+\tparam IsIndexable If true, the const reference to Value is returned.
+*/
+template <typename Value, bool IsIndexable = is_indexable<Value>::value>
+struct indexable
+{
+ BOOST_MPL_ASSERT_MSG(
+ (detail::is_indexable<Value>::value),
+ NOT_VALID_INDEXABLE_TYPE,
+ (Value)
+ );
+
+ /*! \brief The type of result returned by function object. */
+ typedef Value const& result_type;
+
+ /*!
+ \brief Return indexable extracted from the value.
+
+ \param v The value.
+ \return The indexable.
+ */
+ inline result_type operator()(Value const& v) const
+ {
+ return v;
+ }
+};
+
+/*!
+\brief The function object extracting Indexable from Value.
+
+This specialization translates from std::pair<Indexable, T2>.
+
+\tparam Indexable The Indexable type.
+\tparam T2 The second type.
+*/
+template <typename Indexable, typename T2>
+struct indexable<std::pair<Indexable, T2>, false>
+{
+ BOOST_MPL_ASSERT_MSG(
+ (detail::is_indexable<Indexable>::value),
+ NOT_VALID_INDEXABLE_TYPE,
+ (Indexable)
+ );
+
+ /*! \brief The type of result returned by function object. */
+ typedef Indexable const& result_type;
+
+ /*!
+ \brief Return indexable extracted from the value.
+
+ \param v The value.
+ \return The indexable.
+ */
+ inline result_type operator()(std::pair<Indexable, T2> const& v) const
+ {
+ return v.first;
+ }
+};
+
+/*!
+\brief The function object extracting Indexable from Value.
+
+This specialization translates from boost::tuple<Indexable, ...>.
+
+\tparam Indexable The Indexable type.
+*/
+template <typename Indexable, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct indexable<boost::tuple<Indexable, T1, T2, T3, T4, T5, T6, T7, T8, T9>, false>
+{
+ typedef boost::tuple<Indexable, T1, T2, T3, T4, T5, T6, T7, T8, T9> value_type;
+
+ BOOST_MPL_ASSERT_MSG(
+ (detail::is_indexable<Indexable>::value),
+ NOT_VALID_INDEXABLE_TYPE,
+ (Indexable)
+ );
+
+ /*! \brief The type of result returned by function object. */
+ typedef Indexable const& result_type;
+
+ /*!
+ \brief Return indexable extracted from the value.
+
+ \param v The value.
+ \return The indexable.
+ */
+ inline result_type operator()(value_type const& v) const
+ {
+ return boost::get<0>(v);
+ }
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+
+#include <tuple>
+
+namespace boost { namespace geometry { namespace index { namespace detail {
+
+/*!
+\brief The function object extracting Indexable from Value.
+
+This specialization translates from std::tuple<Indexable, Args...>.
+It's defined if the compiler supports tuples and variadic templates.
+
+\tparam Indexable The Indexable type.
+*/
+template <typename Indexable, typename ...Args>
+struct indexable<std::tuple<Indexable, Args...>, false>
+{
+ typedef std::tuple<Indexable, Args...> value_type;
+
+ BOOST_MPL_ASSERT_MSG(
+ (detail::is_indexable<Indexable>::value),
+ NOT_VALID_INDEXABLE_TYPE,
+ (Indexable)
+ );
+
+ /*! \brief The type of result returned by function object. */
+ typedef Indexable const& result_type;
+
+ /*!
+ \brief Return indexable extracted from the value.
+
+ \param v The value.
+ \return The indexable.
+ */
+ result_type operator()(value_type const& v) const
+ {
+ return std::get<0>(v);
+ }
+};
+
+}}}} // namespace boost::geometry::index::detail
+
+#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+
+namespace boost { namespace geometry { namespace index {
+
+/*!
+\brief The function object extracting Indexable from Value.
+
+It translates Value object to Indexable object. By default, it can handle Values which are Indexables,
+std::pair<Indexable, T2>, boost::tuple<Indexable, ...> and std::tuple<Indexable, ...> if STD tuples
+and variadic templates are supported.
+
+\tparam Value The Value type which may be translated directly to the Indexable.
+*/
+template <typename Value>
+struct indexable
+ : detail::indexable<Value>
+{
+ /*! \brief The type of result returned by function object. It should be const Indexable reference. */
+ typedef typename detail::indexable<Value>::result_type result_type;
+
+ /*!
+ \brief Return indexable extracted from the value.
+
+ \param v The value.
+ \return The indexable.
+ */
+ inline result_type operator()(Value const& v) const
+ {
+ return detail::indexable<Value>::operator()(v);
+ }
+};
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_INDEXABLE_HPP
diff --git a/boost/geometry/index/inserter.hpp b/boost/geometry/index/inserter.hpp
new file mode 100644
index 0000000000..7c489bc3f1
--- /dev/null
+++ b/boost/geometry/index/inserter.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry Index
+//
+// Insert iterator
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_INSERTER_HPP
+#define BOOST_GEOMETRY_INDEX_INSERTER_HPP
+
+#include <iterator>
+
+/*!
+\defgroup inserters Inserters (boost::geometry::index::)
+*/
+
+namespace boost { namespace geometry { namespace index {
+
+template <class Container>
+class insert_iterator :
+ public std::iterator<std::output_iterator_tag, void, void, void, void>
+{
+public:
+ typedef Container container_type;
+
+ inline explicit insert_iterator(Container & c)
+ : container(&c)
+ {}
+
+ insert_iterator & operator=(typename Container::value_type const& value)
+ {
+ container->insert(value);
+ return *this;
+ }
+
+ insert_iterator & operator* ()
+ {
+ return *this;
+ }
+
+ insert_iterator & operator++ ()
+ {
+ return *this;
+ }
+
+ insert_iterator operator++(int)
+ {
+ return *this;
+ }
+
+private:
+ Container * container;
+};
+
+/*!
+\brief Insert iterator generator.
+
+Returns insert iterator capable to insert values to the container
+(spatial index) which has member function insert(value_type const&) defined.
+
+\ingroup inserters
+
+\param c The reference to the container (spatial index) to which values will be inserted.
+
+\return The insert iterator inserting values to the container.
+*/
+template <typename Container>
+insert_iterator<Container> inserter(Container & c)
+{
+ return insert_iterator<Container>(c);
+}
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_INSERTER_HPP
diff --git a/boost/geometry/index/parameters.hpp b/boost/geometry/index/parameters.hpp
new file mode 100644
index 0000000000..fd6df716ee
--- /dev/null
+++ b/boost/geometry/index/parameters.hpp
@@ -0,0 +1,253 @@
+// Boost.Geometry Index
+//
+// R-tree algorithms parameters
+//
+// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_PARAMETERS_HPP
+#define BOOST_GEOMETRY_INDEX_PARAMETERS_HPP
+
+#include <limits>
+
+namespace boost { namespace geometry { namespace index {
+
+namespace detail {
+
+template <size_t MaxElements>
+struct default_min_elements_s
+{
+ static const size_t raw_value = (MaxElements * 3) / 10;
+ static const size_t value = 1 <= raw_value ? raw_value : 1;
+};
+
+inline size_t default_min_elements_d()
+{
+ return (std::numeric_limits<size_t>::max)();
+}
+
+inline size_t default_min_elements_d_calc(size_t max_elements, size_t min_elements)
+{
+ if ( default_min_elements_d() == min_elements )
+ {
+ size_t raw_value = (max_elements * 3) / 10;
+ return 1 <= raw_value ? raw_value : 1;
+ }
+
+ return min_elements;
+}
+
+template <size_t MaxElements>
+struct default_rstar_reinserted_elements_s
+{
+ static const size_t value = (MaxElements * 3) / 10;
+};
+
+inline size_t default_rstar_reinserted_elements_d()
+{
+ return (std::numeric_limits<size_t>::max)();
+}
+
+inline size_t default_rstar_reinserted_elements_d_calc(size_t max_elements, size_t reinserted_elements)
+{
+ if ( default_rstar_reinserted_elements_d() == reinserted_elements )
+ {
+ return (max_elements * 3) / 10;
+ }
+
+ return reinserted_elements;
+}
+
+} // namespace detail
+
+/*!
+\brief Linear r-tree creation algorithm parameters.
+
+\tparam MaxElements Maximum number of elements in nodes.
+\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max.
+*/
+template <size_t MaxElements,
+ size_t MinElements = detail::default_min_elements_s<MaxElements>::value
+>
+struct linear
+{
+ BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1),
+ INVALID_STATIC_MIN_MAX_PARAMETERS, (linear));
+
+ static const size_t max_elements = MaxElements;
+ static const size_t min_elements = MinElements;
+
+ static size_t get_max_elements() { return MaxElements; }
+ static size_t get_min_elements() { return MinElements; }
+};
+
+/*!
+\brief Quadratic r-tree creation algorithm parameters.
+
+\tparam MaxElements Maximum number of elements in nodes.
+\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max.
+*/
+template <size_t MaxElements,
+ size_t MinElements = detail::default_min_elements_s<MaxElements>::value>
+struct quadratic
+{
+ BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1),
+ INVALID_STATIC_MIN_MAX_PARAMETERS, (quadratic));
+
+ static const size_t max_elements = MaxElements;
+ static const size_t min_elements = MinElements;
+
+ static size_t get_max_elements() { return MaxElements; }
+ static size_t get_min_elements() { return MinElements; }
+};
+
+/*!
+\brief R*-tree creation algorithm parameters.
+
+\tparam MaxElements Maximum number of elements in nodes.
+\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max.
+\tparam ReinsertedElements The number of elements reinserted by forced reinsertions algorithm.
+ If 0 forced reinsertions are disabled. Maximum value is Max+1-Min.
+ Greater values are truncated. Default: 0.3*Max.
+\tparam OverlapCostThreshold The number of most suitable leafs taken into account while choosing
+ the leaf node to which currently inserted value will be added. If
+ value is in range (0, MaxElements) - the algorithm calculates
+ nearly minimum overlap cost, otherwise all leafs are analyzed
+ and true minimum overlap cost is calculated. Default: 32.
+*/
+template <size_t MaxElements,
+ size_t MinElements = detail::default_min_elements_s<MaxElements>::value,
+ size_t ReinsertedElements = detail::default_rstar_reinserted_elements_s<MaxElements>::value,
+ size_t OverlapCostThreshold = 32>
+struct rstar
+{
+ BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1),
+ INVALID_STATIC_MIN_MAX_PARAMETERS, (rstar));
+
+ static const size_t max_elements = MaxElements;
+ static const size_t min_elements = MinElements;
+ static const size_t reinserted_elements = ReinsertedElements;
+ static const size_t overlap_cost_threshold = OverlapCostThreshold;
+
+ static size_t get_max_elements() { return MaxElements; }
+ static size_t get_min_elements() { return MinElements; }
+ static size_t get_reinserted_elements() { return ReinsertedElements; }
+ static size_t get_overlap_cost_threshold() { return OverlapCostThreshold; }
+};
+
+//template <size_t MaxElements, size_t MinElements>
+//struct kmeans
+//{
+// static const size_t max_elements = MaxElements;
+// static const size_t min_elements = MinElements;
+//};
+
+/*!
+\brief Linear r-tree creation algorithm parameters - run-time version.
+*/
+class dynamic_linear
+{
+public:
+ /*!
+ \brief The constructor.
+
+ \param max_elements Maximum number of elements in nodes.
+ \param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
+ */
+ dynamic_linear(size_t max_elements,
+ size_t min_elements = detail::default_min_elements_d())
+ : m_max_elements(max_elements)
+ , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
+ {
+ if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1))
+ detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_linear");
+ }
+
+ size_t get_max_elements() const { return m_max_elements; }
+ size_t get_min_elements() const { return m_min_elements; }
+
+private:
+ size_t m_max_elements;
+ size_t m_min_elements;
+};
+
+/*!
+\brief Quadratic r-tree creation algorithm parameters - run-time version.
+*/
+class dynamic_quadratic
+{
+public:
+ /*!
+ \brief The constructor.
+
+ \param max_elements Maximum number of elements in nodes.
+ \param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
+ */
+ dynamic_quadratic(size_t max_elements,
+ size_t min_elements = detail::default_min_elements_d())
+ : m_max_elements(max_elements)
+ , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
+ {
+ if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1))
+ detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_quadratic");
+ }
+
+ size_t get_max_elements() const { return m_max_elements; }
+ size_t get_min_elements() const { return m_min_elements; }
+
+private:
+ size_t m_max_elements;
+ size_t m_min_elements;
+};
+
+/*!
+\brief R*-tree creation algorithm parameters - run-time version.
+*/
+class dynamic_rstar
+{
+public:
+ /*!
+ \brief The constructor.
+
+ \param max_elements Maximum number of elements in nodes.
+ \param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
+ \param reinserted_elements The number of elements reinserted by forced reinsertions algorithm.
+ If 0 forced reinsertions are disabled. Maximum value is Max-Min+1.
+ Greater values are truncated. Default: 0.3*Max.
+ \param overlap_cost_threshold The number of most suitable leafs taken into account while choosing
+ the leaf node to which currently inserted value will be added. If
+ value is in range (0, MaxElements) - the algorithm calculates
+ nearly minimum overlap cost, otherwise all leafs are analyzed
+ and true minimum overlap cost is calculated. Default: 32.
+ */
+ dynamic_rstar(size_t max_elements,
+ size_t min_elements = detail::default_min_elements_d(),
+ size_t reinserted_elements = detail::default_rstar_reinserted_elements_d(),
+ size_t overlap_cost_threshold = 32)
+ : m_max_elements(max_elements)
+ , m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
+ , m_reinserted_elements(detail::default_rstar_reinserted_elements_d_calc(max_elements, reinserted_elements))
+ , m_overlap_cost_threshold(overlap_cost_threshold)
+ {
+ if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1))
+ detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_rstar");
+ }
+
+ size_t get_max_elements() const { return m_max_elements; }
+ size_t get_min_elements() const { return m_min_elements; }
+ size_t get_reinserted_elements() const { return m_reinserted_elements; }
+ size_t get_overlap_cost_threshold() const { return m_overlap_cost_threshold; }
+
+private:
+ size_t m_max_elements;
+ size_t m_min_elements;
+ size_t m_reinserted_elements;
+ size_t m_overlap_cost_threshold;
+};
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_PARAMETERS_HPP
diff --git a/boost/geometry/index/predicates.hpp b/boost/geometry/index/predicates.hpp
new file mode 100644
index 0000000000..10033abff8
--- /dev/null
+++ b/boost/geometry/index/predicates.hpp
@@ -0,0 +1,385 @@
+// Boost.Geometry Index
+//
+// Spatial query predicates
+//
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_PREDICATES_HPP
+#define BOOST_GEOMETRY_INDEX_PREDICATES_HPP
+
+#include <utility>
+#include <boost/tuple/tuple.hpp>
+#include <boost/mpl/assert.hpp>
+
+#include <boost/geometry/index/detail/predicates.hpp>
+#include <boost/geometry/index/detail/tuples.hpp>
+
+/*!
+\defgroup predicates Predicates (boost::geometry::index::)
+*/
+
+namespace boost { namespace geometry { namespace index {
+
+/*!
+\brief Generate \c contains() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::within(Geometry, Indexable)</tt>
+returns true.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::contains(box), std::back_inserter(result));
+\endverbatim
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::contains_tag, false>
+contains(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::contains_tag, false>(g);
+}
+
+/*!
+\brief Generate \c covered_by() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::covered_by(Indexable, Geometry)</tt>
+returns true.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::covered_by(box), std::back_inserter(result));
+\endverbatim
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::covered_by_tag, false>
+covered_by(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::covered_by_tag, false>(g);
+}
+
+/*!
+\brief Generate \c covers() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::covered_by(Geometry, Indexable)</tt>
+returns true.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::covers(box), std::back_inserter(result));
+\endverbatim
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::covers_tag, false>
+covers(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::covers_tag, false>(g);
+}
+
+/*!
+\brief Generate \c disjoint() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::disjoint(Indexable, Geometry)</tt>
+returns true.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::disjoint(box), std::back_inserter(result));
+\endverbatim
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::disjoint_tag, false>
+disjoint(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::disjoint_tag, false>(g);
+}
+
+/*!
+\brief Generate \c intersects() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::intersects(Indexable, Geometry)</tt>
+returns true.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::intersects(box), std::back_inserter(result));
+bgi::query(spatial_index, bgi::intersects(ring), std::back_inserter(result));
+bgi::query(spatial_index, bgi::intersects(polygon), std::back_inserter(result));
+\endverbatim
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::intersects_tag, false>
+intersects(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::intersects_tag, false>(g);
+}
+
+/*!
+\brief Generate \c overlaps() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::overlaps(Indexable, Geometry)</tt>
+returns true.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::overlaps(box), std::back_inserter(result));
+\endverbatim
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::overlaps_tag, false>
+overlaps(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::overlaps_tag, false>(g);
+}
+
+#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+
+/*!
+\brief Generate \c touches() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::touches(Indexable, Geometry)</tt>
+returns true.
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::touches_tag, false>
+touches(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::touches_tag, false>(g);
+}
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+
+/*!
+\brief Generate \c within() predicate.
+
+Generate a predicate defining Value and Geometry relationship.
+Value will be returned by the query if <tt>bg::within(Indexable, Geometry)</tt>
+returns true.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::within(box), std::back_inserter(result));
+\endverbatim
+
+\ingroup predicates
+
+\tparam Geometry The Geometry type.
+
+\param g The Geometry object.
+*/
+template <typename Geometry> inline
+detail::spatial_predicate<Geometry, detail::within_tag, false>
+within(Geometry const& g)
+{
+ return detail::spatial_predicate<Geometry, detail::within_tag, false>(g);
+}
+
+/*!
+\brief Generate satisfies() predicate.
+
+A wrapper around user-defined UnaryPredicate checking if Value should be returned by spatial query.
+
+\par Example
+\verbatim
+bool is_red(Value const& v) { return v.is_red(); }
+
+struct is_red_o {
+template <typename Value> bool operator()(Value const& v) { return v.is_red(); }
+}
+
+// ...
+
+rt.query(index::intersects(box) && index::satisfies(is_red),
+std::back_inserter(result));
+
+rt.query(index::intersects(box) && index::satisfies(is_red_o()),
+std::back_inserter(result));
+
+#ifndef BOOST_NO_CXX11_LAMBDAS
+rt.query(index::intersects(box) && index::satisfies([](Value const& v) { return v.is_red(); }),
+std::back_inserter(result));
+#endif
+\endverbatim
+
+\ingroup predicates
+
+\tparam UnaryPredicate A type of unary predicate function or function object.
+
+\param pred The unary predicate function or function object.
+*/
+template <typename UnaryPredicate> inline
+detail::satisfies<UnaryPredicate, false>
+satisfies(UnaryPredicate const& pred)
+{
+ return detail::satisfies<UnaryPredicate, false>(pred);
+}
+
+/*!
+\brief Generate nearest() predicate.
+
+When nearest predicate is passed to the query, k-nearest neighbour search will be performed.
+\c nearest() predicate takes a \c Geometry from which distances to \c Values are calculated
+and the maximum number of \c Values that should be returned. Internally
+boost::geometry::comparable_distance() is used to perform the calculation.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::nearest(pt, 5), std::back_inserter(result));
+bgi::query(spatial_index, bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result));
+bgi::query(spatial_index, bgi::nearest(box, 5), std::back_inserter(result));
+\endverbatim
+
+\warning
+Only one \c nearest() predicate may be used in a query.
+
+\ingroup predicates
+
+\param geometry The geometry from which distance is calculated.
+\param k The maximum number of values to return.
+*/
+template <typename Geometry> inline
+detail::nearest<Geometry>
+nearest(Geometry const& geometry, unsigned k)
+{
+ return detail::nearest<Geometry>(geometry, k);
+}
+
+#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+
+/*!
+\brief Generate path() predicate.
+
+When path predicate is passed to the query, the returned values are k values along the path closest to
+its begin. \c path() predicate takes a \c Segment or a \c Linestring defining the path and the maximum
+number of \c Values that should be returned.
+
+\par Example
+\verbatim
+bgi::query(spatial_index, bgi::path(segment, 5), std::back_inserter(result));
+bgi::query(spatial_index, bgi::path(linestring, 5) && bgi::intersects(box), std::back_inserter(result));
+\endverbatim
+
+\warning
+Only one distance predicate (\c nearest() or \c path()) may be used in a query.
+
+\ingroup predicates
+
+\param linestring The path along which distance is calculated.
+\param k The maximum number of values to return.
+*/
+template <typename SegmentOrLinestring> inline
+detail::path<SegmentOrLinestring>
+path(SegmentOrLinestring const& linestring, unsigned k)
+{
+ return detail::path<SegmentOrLinestring>(linestring, k);
+}
+
+#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+
+namespace detail {
+
+// operator! generators
+
+template <typename Fun, bool Negated> inline
+satisfies<Fun, !Negated>
+operator!(satisfies<Fun, Negated> const& p)
+{
+ return satisfies<Fun, !Negated>(p);
+}
+
+template <typename Geometry, typename Tag, bool Negated> inline
+spatial_predicate<Geometry, Tag, !Negated>
+operator!(spatial_predicate<Geometry, Tag, Negated> const& p)
+{
+ return spatial_predicate<Geometry, Tag, !Negated>(p.geometry);
+}
+
+// operator&& generators
+
+template <typename Pred1, typename Pred2> inline
+boost::tuples::cons<
+ Pred1,
+ boost::tuples::cons<Pred2, boost::tuples::null_type>
+>
+operator&&(Pred1 const& p1, Pred2 const& p2)
+{
+ /*typedef typename boost::mpl::if_c<is_predicate<Pred1>::value, Pred1, Pred1 const&>::type stored1;
+ typedef typename boost::mpl::if_c<is_predicate<Pred2>::value, Pred2, Pred2 const&>::type stored2;*/
+ namespace bt = boost::tuples;
+
+ return
+ bt::cons< Pred1, bt::cons<Pred2, bt::null_type> >
+ ( p1, bt::cons<Pred2, bt::null_type>(p2, bt::null_type()) );
+}
+
+template <typename Head, typename Tail, typename Pred> inline
+typename tuples::push_back<
+ boost::tuples::cons<Head, Tail>, Pred
+>::type
+operator&&(boost::tuples::cons<Head, Tail> const& t, Pred const& p)
+{
+ //typedef typename boost::mpl::if_c<is_predicate<Pred>::value, Pred, Pred const&>::type stored;
+ namespace bt = boost::tuples;
+
+ return
+ tuples::push_back<
+ bt::cons<Head, Tail>, Pred
+ >::apply(t, p);
+}
+
+} // namespace detail
+
+}}} // namespace boost::geometry::index
+
+#endif // BOOST_GEOMETRY_INDEX_PREDICATES_HPP
diff --git a/boost/geometry/index/rtree.hpp b/boost/geometry/index/rtree.hpp
new file mode 100644
index 0000000000..503f47b89f
--- /dev/null
+++ b/boost/geometry/index/rtree.hpp
@@ -0,0 +1,1919 @@
+// Boost.Geometry Index
+//
+// R-tree implementation
+//
+// Copyright (c) 2008 Federico J. Fernandez.
+// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_INDEX_RTREE_HPP
+#define BOOST_GEOMETRY_INDEX_RTREE_HPP
+
+// STD
+#include <algorithm>
+
+// Boost
+#include <boost/tuple/tuple.hpp>
+#include <boost/move/move.hpp>
+
+// Boost.Geometry
+#include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp>
+#include <boost/geometry/algorithms/centroid.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/overlaps.hpp>
+#include <boost/geometry/algorithms/touches.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/geometries/point.hpp>
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/strategies/strategies.hpp>
+
+// Boost.Geometry.Index
+#include <boost/geometry/index/detail/config_begin.hpp>
+
+#include <boost/geometry/index/detail/assert.hpp>
+#include <boost/geometry/index/detail/exception.hpp>
+
+#include <boost/geometry/index/detail/rtree/options.hpp>
+
+#include <boost/geometry/index/indexable.hpp>
+#include <boost/geometry/index/equal_to.hpp>
+
+#include <boost/geometry/index/detail/translator.hpp>
+
+#include <boost/geometry/index/predicates.hpp>
+#include <boost/geometry/index/distance_predicates.hpp>
+#include <boost/geometry/index/detail/rtree/adaptors.hpp>
+
+#include <boost/geometry/index/detail/meta.hpp>
+#include <boost/geometry/index/detail/utilities.hpp>
+#include <boost/geometry/index/detail/rtree/node/node.hpp>
+
+#include <boost/geometry/index/detail/algorithms/is_valid.hpp>
+
+#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/remove.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/copy.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/destroy.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/spatial_query.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/distance_query.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/count.hpp>
+#include <boost/geometry/index/detail/rtree/visitors/children_box.hpp>
+
+#include <boost/geometry/index/detail/rtree/linear/linear.hpp>
+#include <boost/geometry/index/detail/rtree/quadratic/quadratic.hpp>
+#include <boost/geometry/index/detail/rtree/rstar/rstar.hpp>
+//#include <boost/geometry/extensions/index/detail/rtree/kmeans/kmeans.hpp>
+
+#include <boost/geometry/index/detail/rtree/pack_create.hpp>
+
+#include <boost/geometry/index/inserter.hpp>
+
+#include <boost/geometry/index/detail/rtree/utilities/view.hpp>
+
+#include <boost/geometry/index/detail/rtree/query_iterators.hpp>
+
+#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+// serialization
+#include <boost/geometry/index/detail/serialization.hpp>
+#endif
+
+// TODO change the name to bounding_tree
+
+/*!
+\defgroup rtree_functions R-tree free functions (boost::geometry::index::)
+*/
+
+namespace boost { namespace geometry { namespace index {
+
+/*!
+\brief The R-tree spatial index.
+
+This is self-balancing spatial index capable to store various types of Values and balancing algorithms.
+
+\par Parameters
+The user must pass a type defining the Parameters which will
+be used in rtree creation process. This type is used e.g. to specify balancing algorithm
+with specific parameters like min and max number of elements in node.
+
+\par
+Predefined algorithms with compile-time parameters are:
+\li <tt>boost::geometry::index::linear</tt>,
+ \li <tt>boost::geometry::index::quadratic</tt>,
+ \li <tt>boost::geometry::index::rstar</tt>.
+
+\par
+Predefined algorithms with run-time parameters are:
+ \li \c boost::geometry::index::dynamic_linear,
+ \li \c boost::geometry::index::dynamic_quadratic,
+ \li \c boost::geometry::index::dynamic_rstar.
+
+\par IndexableGetter
+The object of IndexableGetter type translates from Value to Indexable each time r-tree requires it. Which means that this
+operation is done for each Value access. Therefore the IndexableGetter should return the Indexable by
+const reference instead of a value. Default one can translate all types adapted to Point, Box or Segment
+concepts (called Indexables). It also handles <tt>std::pair<Indexable, T></tt> and
+<tt>boost::tuple<Indexable, ...></tt>. For example, if <tt>std::pair<Box, int></tt> is stored in the
+container, the default IndexableGetter translates from <tt>std::pair<Box, int> const&</tt> to <tt>Box const&</tt>.
+
+\par EqualTo
+The object of EqualTo type compares Values and returns <tt>true</tt> if they're equal. It's similar to <tt>std::equal_to<></tt>.
+The default EqualTo returns the result of <tt>boost::geometry::equals()</tt> for types adapted to some Geometry concept
+defined in Boost.Geometry and the result of operator= for other types. Components of Pairs and Tuples are compared left-to-right.
+
+\tparam Value The type of objects stored in the container.
+\tparam Parameters Compile-time parameters.
+\tparam IndexableGetter The function object extracting Indexable from Value.
+\tparam EqualTo The function object comparing objects of type Value.
+\tparam Allocator The allocator used to allocate/deallocate memory, construct/destroy nodes and Values.
+*/
+template <
+ typename Value,
+ typename Parameters,
+ typename IndexableGetter = index::indexable<Value>,
+ typename EqualTo = index::equal_to<Value>,
+ typename Allocator = std::allocator<Value>
+>
+class rtree
+{
+ BOOST_COPYABLE_AND_MOVABLE(rtree)
+
+public:
+ /*! \brief The type of Value stored in the container. */
+ typedef Value value_type;
+ /*! \brief R-tree parameters type. */
+ typedef Parameters parameters_type;
+ /*! \brief The function object extracting Indexable from Value. */
+ typedef IndexableGetter indexable_getter;
+ /*! \brief The function object comparing objects of type Value. */
+ typedef EqualTo value_equal;
+ /*! \brief The type of allocator used by the container. */
+ typedef Allocator allocator_type;
+
+ // TODO: SHOULD THIS TYPE BE REMOVED?
+ /*! \brief The Indexable type to which Value is translated. */
+ typedef typename index::detail::indexable_type<
+ detail::translator<IndexableGetter, EqualTo>
+ >::type indexable_type;
+
+ /*! \brief The Box type used by the R-tree. */
+ typedef geometry::model::box<
+ geometry::model::point<
+ typename coordinate_type<indexable_type>::type,
+ dimension<indexable_type>::value,
+ typename coordinate_system<indexable_type>::type
+ >
+ >
+ bounds_type;
+
+private:
+
+ typedef detail::translator<IndexableGetter, EqualTo> translator_type;
+
+ typedef bounds_type box_type;
+ typedef typename detail::rtree::options_type<Parameters>::type options_type;
+ typedef typename options_type::node_tag node_tag;
+ typedef detail::rtree::allocators<allocator_type, value_type, typename options_type::parameters_type, box_type, node_tag> allocators_type;
+
+ typedef typename detail::rtree::node<value_type, typename options_type::parameters_type, box_type, allocators_type, node_tag>::type node;
+ typedef typename detail::rtree::internal_node<value_type, typename options_type::parameters_type, box_type, allocators_type, node_tag>::type internal_node;
+ typedef typename detail::rtree::leaf<value_type, typename options_type::parameters_type, box_type, allocators_type, node_tag>::type leaf;
+
+ typedef typename allocators_type::node_pointer node_pointer;
+ typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
+ typedef detail::rtree::node_auto_ptr<value_type, options_type, translator_type, box_type, allocators_type> node_auto_ptr;
+
+ friend class detail::rtree::utilities::view<rtree>;
+#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+ friend class detail::rtree::private_view<rtree>;
+ friend class detail::rtree::const_private_view<rtree>;
+#endif
+
+public:
+
+ /*! \brief Type of reference to Value. */
+ typedef typename allocators_type::reference reference;
+ /*! \brief Type of reference to const Value. */
+ typedef typename allocators_type::const_reference const_reference;
+ /*! \brief Type of pointer to Value. */
+ typedef typename allocators_type::pointer pointer;
+ /*! \brief Type of pointer to const Value. */
+ typedef typename allocators_type::const_pointer const_pointer;
+ /*! \brief Type of difference type. */
+ typedef typename allocators_type::difference_type difference_type;
+ /*! \brief Unsigned integral type used by the container. */
+ typedef typename allocators_type::size_type size_type;
+
+ /*! \brief Type of const query iterator. */
+ typedef index::detail::rtree::iterators::query_iterator<value_type, allocators_type> const_query_iterator;
+
+public:
+
+ /*!
+ \brief The constructor.
+
+ \param parameters The parameters object.
+ \param getter The function object extracting Indexable from Value.
+ \param equal The function object comparing Values.
+
+ \par Throws
+ If allocator default constructor throws.
+ */
+ inline explicit rtree(parameters_type const& parameters = parameters_type(),
+ indexable_getter const& getter = indexable_getter(),
+ value_equal const& equal = value_equal())
+ : m_members(getter, equal, parameters)
+ {}
+
+ /*!
+ \brief The constructor.
+
+ \param parameters The parameters object.
+ \param getter The function object extracting Indexable from Value.
+ \param equal The function object comparing Values.
+ \param allocator The allocator object.
+
+ \par Throws
+ If allocator copy constructor throws.
+ */
+ inline rtree(parameters_type const& parameters,
+ indexable_getter const& getter,
+ value_equal const& equal,
+ allocator_type const& allocator)
+ : m_members(getter, equal, parameters, allocator)
+ {}
+
+ /*!
+ \brief The constructor.
+
+ The tree is created using packing algorithm.
+
+ \param first The beginning of the range of Values.
+ \param last The end of the range of Values.
+ \param parameters The parameters object.
+ \param getter The function object extracting Indexable from Value.
+ \param equal The function object comparing Values.
+ \param allocator The allocator object.
+
+ \par Throws
+ \li If allocator copy constructor throws.
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+ */
+ template<typename Iterator>
+ inline rtree(Iterator first, Iterator last,
+ parameters_type const& parameters = parameters_type(),
+ indexable_getter const& getter = indexable_getter(),
+ value_equal const& equal = value_equal(),
+ allocator_type const& allocator = allocator_type())
+ : m_members(getter, equal, parameters, allocator)
+ {
+ typedef detail::rtree::pack<value_type, options_type, translator_type, box_type, allocators_type> pack;
+ size_type vc = 0, ll = 0;
+ m_members.root = pack::apply(first, last, vc, ll,
+ m_members.parameters(), m_members.translator(), m_members.allocators());
+ m_members.values_count = vc;
+ m_members.leafs_level = ll;
+ }
+
+ /*!
+ \brief The constructor.
+
+ The tree is created using packing algorithm.
+
+ \param rng The range of Values.
+ \param parameters The parameters object.
+ \param getter The function object extracting Indexable from Value.
+ \param equal The function object comparing Values.
+ \param allocator The allocator object.
+
+ \par Throws
+ \li If allocator copy constructor throws.
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+ */
+ template<typename Range>
+ inline explicit rtree(Range const& rng,
+ parameters_type const& parameters = parameters_type(),
+ indexable_getter const& getter = indexable_getter(),
+ value_equal const& equal = value_equal(),
+ allocator_type const& allocator = allocator_type())
+ : m_members(getter, equal, parameters, allocator)
+ {
+ typedef detail::rtree::pack<value_type, options_type, translator_type, box_type, allocators_type> pack;
+ size_type vc = 0, ll = 0;
+ m_members.root = pack::apply(::boost::begin(rng), ::boost::end(rng), vc, ll,
+ m_members.parameters(), m_members.translator(), m_members.allocators());
+ m_members.values_count = vc;
+ m_members.leafs_level = ll;
+ }
+
+ /*!
+ \brief The destructor.
+
+ \par Throws
+ Nothing.
+ */
+ inline ~rtree()
+ {
+ this->raw_destroy(*this);
+ }
+
+ /*!
+ \brief The copy constructor.
+
+ It uses parameters, translator and allocator from the source tree.
+
+ \param src The rtree which content will be copied.
+
+ \par Throws
+ \li If allocator copy constructor throws.
+ \li If Value copy constructor throws.
+ \li If allocation throws or returns invalid value.
+ */
+ inline rtree(rtree const& src)
+ : m_members(src.m_members.indexable_getter(),
+ src.m_members.equal_to(),
+ src.m_members.parameters(),
+ allocator_traits_type::select_on_container_copy_construction(src.get_allocator()))
+ {
+ this->raw_copy(src, *this, false);
+ }
+
+ /*!
+ \brief The copy constructor.
+
+ It uses Parameters and translator from the source tree.
+
+ \param src The rtree which content will be copied.
+ \param allocator The allocator which will be used.
+
+ \par Throws
+ \li If allocator copy constructor throws.
+ \li If Value copy constructor throws.
+ \li If allocation throws or returns invalid value.
+ */
+ inline rtree(rtree const& src, allocator_type const& allocator)
+ : m_members(src.m_members.indexable_getter(),
+ src.m_members.equal_to(),
+ src.m_members.parameters(), allocator)
+ {
+ this->raw_copy(src, *this, false);
+ }
+
+ /*!
+ \brief The moving constructor.
+
+ It uses parameters, translator and allocator from the source tree.
+
+ \param src The rtree which content will be moved.
+
+ \par Throws
+ Nothing.
+ */
+ inline rtree(BOOST_RV_REF(rtree) src)
+ : m_members(src.m_members.indexable_getter(),
+ src.m_members.equal_to(),
+ src.m_members.parameters(),
+ boost::move(src.m_members.allocators()))
+ {
+ boost::swap(m_members.values_count, src.m_members.values_count);
+ boost::swap(m_members.leafs_level, src.m_members.leafs_level);
+ boost::swap(m_members.root, src.m_members.root);
+ }
+
+ /*!
+ \brief The moving constructor.
+
+ It uses parameters and translator from the source tree.
+
+ \param src The rtree which content will be moved.
+ \param allocator The allocator.
+
+ \par Throws
+ \li If allocator copy constructor throws.
+ \li If Value copy constructor throws (only if allocators aren't equal).
+ \li If allocation throws or returns invalid value (only if allocators aren't equal).
+ */
+ inline rtree(BOOST_RV_REF(rtree) src, allocator_type const& allocator)
+ : m_members(src.m_members.indexable_getter(),
+ src.m_members.equal_to(),
+ src.m_members.parameters(),
+ allocator)
+ {
+ if ( src.m_members.allocators() == allocator )
+ {
+ boost::swap(m_members.values_count, src.m_members.values_count);
+ boost::swap(m_members.leafs_level, src.m_members.leafs_level);
+ boost::swap(m_members.root, src.m_members.root);
+ }
+ else
+ {
+ this->raw_copy(src, *this, false);
+ }
+ }
+
+ /*!
+ \brief The assignment operator.
+
+ It uses parameters and translator from the source tree.
+
+ \param src The rtree which content will be copied.
+
+ \par Throws
+ \li If Value copy constructor throws.
+ \li If allocation throws.
+ \li If allocation throws or returns invalid value.
+ */
+ inline rtree & operator=(BOOST_COPY_ASSIGN_REF(rtree) src)
+ {
+ if ( &src != this )
+ {
+ allocators_type & this_allocs = m_members.allocators();
+ allocators_type const& src_allocs = src.m_members.allocators();
+
+ // NOTE: if propagate is true for std allocators on darwin 4.2.1, glibc++
+ // (allocators stored as base classes of members_holder)
+ // copying them changes values_count, in this case it doesn't cause errors since data must be copied
+
+ typedef boost::mpl::bool_<
+ allocator_traits_type::propagate_on_container_copy_assignment::value
+ > propagate;
+
+ if ( propagate::value && !(this_allocs == src_allocs) )
+ this->raw_destroy(*this);
+ detail::assign_cond(this_allocs, src_allocs, propagate());
+
+ // It uses m_allocators
+ this->raw_copy(src, *this, true);
+ }
+
+ return *this;
+ }
+
+ /*!
+ \brief The moving assignment.
+
+ It uses parameters and translator from the source tree.
+
+ \param src The rtree which content will be moved.
+
+ \par Throws
+ Only if allocators aren't equal.
+ \li If Value copy constructor throws.
+ \li If allocation throws or returns invalid value.
+ */
+ inline rtree & operator=(BOOST_RV_REF(rtree) src)
+ {
+ if ( &src != this )
+ {
+ allocators_type & this_allocs = m_members.allocators();
+ allocators_type & src_allocs = src.m_members.allocators();
+
+ if ( this_allocs == src_allocs )
+ {
+ this->raw_destroy(*this);
+
+ m_members.indexable_getter() = src.m_members.indexable_getter();
+ m_members.equal_to() = src.m_members.equal_to();
+ m_members.parameters() = src.m_members.parameters();
+
+ boost::swap(m_members.values_count, src.m_members.values_count);
+ boost::swap(m_members.leafs_level, src.m_members.leafs_level);
+ boost::swap(m_members.root, src.m_members.root);
+
+ // NOTE: if propagate is true for std allocators on darwin 4.2.1, glibc++
+ // (allocators stored as base classes of members_holder)
+ // moving them changes values_count
+
+ typedef boost::mpl::bool_<
+ allocator_traits_type::propagate_on_container_move_assignment::value
+ > propagate;
+ detail::move_cond(this_allocs, src_allocs, propagate());
+ }
+ else
+ {
+// TODO - shouldn't here propagate_on_container_copy_assignment be checked like in operator=(const&)?
+
+ // It uses m_allocators
+ this->raw_copy(src, *this, true);
+ }
+ }
+
+ return *this;
+ }
+
+ /*!
+ \brief Swaps contents of two rtrees.
+
+ Parameters, translator and allocators are swapped as well.
+
+ \param other The rtree which content will be swapped with this rtree content.
+
+ \par Throws
+ If allocators swap throws.
+ */
+ void swap(rtree & other)
+ {
+ boost::swap(m_members.indexable_getter(), other.m_members.indexable_getter());
+ boost::swap(m_members.equal_to(), other.m_members.equal_to());
+ boost::swap(m_members.parameters(), other.m_members.parameters());
+
+ // NOTE: if propagate is true for std allocators on darwin 4.2.1, glibc++
+ // (allocators stored as base classes of members_holder)
+ // swapping them changes values_count
+
+ typedef boost::mpl::bool_<
+ allocator_traits_type::propagate_on_container_swap::value
+ > propagate;
+ detail::swap_cond(m_members.allocators(), other.m_members.allocators(), propagate());
+
+ boost::swap(m_members.values_count, other.m_members.values_count);
+ boost::swap(m_members.leafs_level, other.m_members.leafs_level);
+ boost::swap(m_members.root, other.m_members.root);
+ }
+
+ /*!
+ \brief Insert a value to the index.
+
+ \param value The value which will be stored in the container.
+
+ \par Throws
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+
+ \warning
+ This operation only guarantees that there will be no memory leaks.
+ After an exception is thrown the R-tree may be left in an inconsistent state,
+ elements must not be inserted or removed. Other operations are allowed however
+ some of them may return invalid data.
+ */
+ inline void insert(value_type const& value)
+ {
+ if ( !m_members.root )
+ this->raw_create();
+
+ this->raw_insert(value);
+ }
+
+ /*!
+ \brief Insert a range of values to the index.
+
+ \param first The beginning of the range of values.
+ \param last The end of the range of values.
+
+ \par Throws
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+
+ \warning
+ This operation only guarantees that there will be no memory leaks.
+ After an exception is thrown the R-tree may be left in an inconsistent state,
+ elements must not be inserted or removed. Other operations are allowed however
+ some of them may return invalid data.
+ */
+ template <typename Iterator>
+ inline void insert(Iterator first, Iterator last)
+ {
+ if ( !m_members.root )
+ this->raw_create();
+
+ for ( ; first != last ; ++first )
+ this->raw_insert(*first);
+ }
+
+ /*!
+ \brief Insert a value created using convertible object or a range of values to the index.
+
+ \param conv_or_rng An object of type convertible to value_type or a range of values.
+
+ \par Throws
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+
+ \warning
+ This operation only guarantees that there will be no memory leaks.
+ After an exception is thrown the R-tree may be left in an inconsistent state,
+ elements must not be inserted or removed. Other operations are allowed however
+ some of them may return invalid data.
+ */
+ template <typename ConvertibleOrRange>
+ inline void insert(ConvertibleOrRange const& conv_or_rng)
+ {
+ typedef boost::mpl::bool_
+ <
+ boost::is_convertible<ConvertibleOrRange, value_type>::value
+ > is_conv_t;
+
+ this->insert_dispatch(conv_or_rng, is_conv_t());
+ }
+
+ /*!
+ \brief Remove a value from the container.
+
+ In contrast to the \c std::set or <tt>std::map erase()</tt> method
+ this method removes only one value from the container.
+
+ \param value The value which will be removed from the container.
+
+ \return 1 if the value was removed, 0 otherwise.
+
+ \par Throws
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+
+ \warning
+ This operation only guarantees that there will be no memory leaks.
+ After an exception is thrown the R-tree may be left in an inconsistent state,
+ elements must not be inserted or removed. Other operations are allowed however
+ some of them may return invalid data.
+ */
+ inline size_type remove(value_type const& value)
+ {
+ return this->raw_remove(value);
+ }
+
+ /*!
+ \brief Remove a range of values from the container.
+
+ In contrast to the \c std::set or <tt>std::map erase()</tt> method
+ it doesn't take iterators pointing to values stored in this container. It removes values equal
+ to these passed as a range. Furthermore this method removes only one value for each one passed
+ in the range, not all equal values.
+
+ \param first The beginning of the range of values.
+ \param last The end of the range of values.
+
+ \return The number of removed values.
+
+ \par Throws
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+
+ \warning
+ This operation only guarantees that there will be no memory leaks.
+ After an exception is thrown the R-tree may be left in an inconsistent state,
+ elements must not be inserted or removed. Other operations are allowed however
+ some of them may return invalid data.
+ */
+ template <typename Iterator>
+ inline size_type remove(Iterator first, Iterator last)
+ {
+ size_type result = 0;
+ for ( ; first != last ; ++first )
+ result += this->raw_remove(*first);
+ return result;
+ }
+
+ /*!
+ \brief Remove value corresponding to an object convertible to it or a range of values from the container.
+
+ In contrast to the \c std::set or <tt>std::map erase()</tt> method
+ it removes values equal to these passed as a range. Furthermore, this method removes only
+ one value for each one passed in the range, not all equal values.
+
+ \param conv_or_rng The object of type convertible to value_type or a range of values.
+
+ \return The number of removed values.
+
+ \par Throws
+ \li If Value copy constructor or copy assignment throws.
+ \li If allocation throws or returns invalid value.
+
+ \warning
+ This operation only guarantees that there will be no memory leaks.
+ After an exception is thrown the R-tree may be left in an inconsistent state,
+ elements must not be inserted or removed. Other operations are allowed however
+ some of them may return invalid data.
+ */
+ template <typename ConvertibleOrRange>
+ inline size_type remove(ConvertibleOrRange const& conv_or_rng)
+ {
+ typedef boost::mpl::bool_
+ <
+ boost::is_convertible<ConvertibleOrRange, value_type>::value
+ > is_conv_t;
+
+ return this->remove_dispatch(conv_or_rng, is_conv_t());
+ }
+
+ /*!
+ \brief Finds values meeting passed predicates e.g. nearest to some Point and/or intersecting some Box.
+
+ This query function performs spatial and k-nearest neighbor searches. It allows to pass a set of predicates.
+ Values will be returned only if all predicates are met.
+
+ <b>Spatial predicates</b>
+
+ Spatial predicates may be generated by one of the functions listed below:
+ \li \c boost::geometry::index::contains(),
+ \li \c boost::geometry::index::covered_by(),
+ \li \c boost::geometry::index::covers(),
+ \li \c boost::geometry::index::disjoint(),
+ \li \c boost::geometry::index::intersects(),
+ \li \c boost::geometry::index::overlaps(),
+ \li \c boost::geometry::index::within(),
+
+ It is possible to negate spatial predicates:
+ \li <tt>! boost::geometry::index::contains()</tt>,
+ \li <tt>! boost::geometry::index::covered_by()</tt>,
+ \li <tt>! boost::geometry::index::covers()</tt>,
+ \li <tt>! boost::geometry::index::disjoint()</tt>,
+ \li <tt>! boost::geometry::index::intersects()</tt>,
+ \li <tt>! boost::geometry::index::overlaps()</tt>,
+ \li <tt>! boost::geometry::index::within()</tt>
+
+ <b>Satisfies predicate</b>
+
+ This is a special kind of predicate which allows to pass a user-defined function or function object which checks
+ if Value should be returned by the query. It's generated by:
+ \li \c boost::geometry::index::satisfies().
+
+ <b>Nearest predicate</b>
+
+ If the nearest predicate is passed a k-nearest neighbor search will be performed. This query will result
+ in returning k values to the output iterator. Only one nearest predicate may be passed to the query.
+ It may be generated by:
+ \li \c boost::geometry::index::nearest().
+
+ <b>Connecting predicates</b>
+
+ Predicates may be passed together connected with \c operator&&().
+
+ \par Example
+ \verbatim
+ // return elements intersecting box
+ tree.query(bgi::intersects(box), std::back_inserter(result));
+ // return elements intersecting poly but not within box
+ tree.query(bgi::intersects(poly) && !bgi::within(box), std::back_inserter(result));
+ // return elements overlapping box and meeting my_fun unary predicate
+ tree.query(bgi::overlaps(box) && bgi::satisfies(my_fun), std::back_inserter(result));
+ // return 5 elements nearest to pt and elements are intersecting box
+ tree.query(bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result));
+ \endverbatim
+
+ \par Throws
+ If Value copy constructor or copy assignment throws.
+ If predicates copy throws.
+
+ \warning
+ Only one \c nearest() perdicate may be passed to the query. Passing more of them results in compile-time error.
+
+ \param predicates Predicates.
+ \param out_it The output iterator, e.g. generated by std::back_inserter().
+
+ \return The number of values found.
+ */
+ template <typename Predicates, typename OutIter>
+ size_type query(Predicates const& predicates, OutIter out_it) const
+ {
+ if ( !m_members.root )
+ return 0;
+
+ static const unsigned distance_predicates_count = detail::predicates_count_distance<Predicates>::value;
+ static const bool is_distance_predicate = 0 < distance_predicates_count;
+ BOOST_MPL_ASSERT_MSG((distance_predicates_count <= 1), PASS_ONLY_ONE_DISTANCE_PREDICATE, (Predicates));
+
+ return query_dispatch(predicates, out_it, boost::mpl::bool_<is_distance_predicate>());
+ }
+
+ /*!
+ \brief Returns the query iterator pointing at the begin of the query range.
+
+ This method returns the iterator which may be used to perform iterative queries. For the information
+ about the predicates which may be passed to this method see query().
+
+ \par Example
+ \verbatim
+ for ( Rtree::const_query_iterator it = tree.qbegin(bgi::nearest(pt, 10000)) ;
+ it != tree.qend() ; ++it )
+ {
+ // do something with value
+ if ( has_enough_nearest_values() )
+ break;
+ }
+ \endverbatim
+
+ \par Throws
+ If predicates copy throws.
+ If allocation throws.
+
+ \param predicates Predicates.
+
+ \return The iterator pointing at the begin of the query range.
+ */
+ template <typename Predicates>
+ const_query_iterator qbegin(Predicates const& predicates) const
+ {
+ return const_query_iterator(qbegin_(predicates));
+ }
+
+ /*!
+ \brief Returns the query iterator pointing at the end of the query range.
+
+ This method returns the iterator which may be used to check if the query has ended.
+
+ \par Example
+ \verbatim
+ for ( Rtree::const_query_iterator it = tree.qbegin(bgi::nearest(pt, 10000)) ;
+ it != tree.qend() ; ++it )
+ {
+ // do something with value
+ if ( has_enough_nearest_values() )
+ break;
+ }
+ \endverbatim
+
+ \par Throws
+ Nothing
+
+ \return The iterator pointing at the end of the query range.
+ */
+ const_query_iterator qend() const
+ {
+ return const_query_iterator();
+ }
+
+#ifndef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
+private:
+#endif
+ /*!
+ \brief Returns the query iterator pointing at the begin of the query range.
+
+ This method returns the iterator which may be used to perform iterative queries. For the information
+ about the predicates which may be passed to this method see query().
+
+ The type of the returned iterator depends on the type of passed Predicates but the iterator of this type
+ may be assigned to the variable of const_query_iterator type. If you'd like to use the type of the iterator
+ returned by this method you may get the type e.g. by using C++11 decltype or Boost.Typeof library.
+ This iterator may be compared with iterators returned by both versions of qend() method.
+
+ \par Example
+ \verbatim
+ // Store the result in the container using std::copy() - it requires both iterators of the same type
+ std::copy(tree.qbegin(bgi::intersects(box)), tree.qend(bgi::intersects(box)), std::back_inserter(result));
+
+ // Store the result in the container using std::copy() and type-erased iterators
+ Rtree::const_query_iterator first = tree.qbegin(bgi::intersects(box));
+ Rtree::const_query_iterator last = tree.qend();
+ std::copy(first, last, std::back_inserter(result));
+
+ // Boost.Typeof
+ typedef BOOST_TYPEOF(tree.qbegin(bgi::nearest(pt, 10000))) Iter;
+ for ( Iter it = tree.qbegin(bgi::nearest(pt, 10000)) ; it != tree.qend() ; ++it )
+ {
+ // do something with value
+ if ( has_enough_nearest_values() )
+ break;
+ }
+ \endverbatim
+
+ \par Throws
+ If predicates copy throws.
+ If allocation throws.
+
+ \param predicates Predicates.
+
+ \return The iterator pointing at the begin of the query range.
+ */
+ template <typename Predicates>
+ typename boost::mpl::if_c<
+ detail::predicates_count_distance<Predicates>::value == 0,
+ detail::rtree::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>,
+ detail::rtree::iterators::distance_query_iterator<
+ value_type, options_type, translator_type, box_type, allocators_type, Predicates,
+ detail::predicates_find_distance<Predicates>::value
+ >
+ >::type
+ qbegin_(Predicates const& predicates) const
+ {
+ static const unsigned distance_predicates_count = detail::predicates_count_distance<Predicates>::value;
+ BOOST_MPL_ASSERT_MSG((distance_predicates_count <= 1), PASS_ONLY_ONE_DISTANCE_PREDICATE, (Predicates));
+
+ typedef typename boost::mpl::if_c<
+ detail::predicates_count_distance<Predicates>::value == 0,
+ detail::rtree::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>,
+ detail::rtree::iterators::distance_query_iterator<
+ value_type, options_type, translator_type, box_type, allocators_type, Predicates,
+ detail::predicates_find_distance<Predicates>::value
+ >
+ >::type iterator_type;
+
+ if ( !m_members.root )
+ return iterator_type(m_members.translator(), predicates);
+
+ return iterator_type(m_members.root, m_members.translator(), predicates);
+ }
+
+ /*!
+ \brief Returns the query iterator pointing at the end of the query range.
+
+ This method returns the iterator which may be used to perform iterative queries. For the information
+ about the predicates which may be passed to this method see query().
+
+ The type of the returned iterator depends on the type of passed Predicates but the iterator of this type
+ may be assigned to the variable of const_query_iterator type. If you'd like to use the type of the iterator
+ returned by this method you may get the type e.g. by using C++11 decltype or Boost.Typeof library.
+
+ The type of the iterator returned by this method is the same as the one returned by qbegin() to which
+ the same predicates were passed.
+
+ \par Example
+ \verbatim
+ // Store the result in the container using std::copy() - it requires both iterators of the same type
+ std::copy(tree.qbegin(bgi::intersects(box)), tree.qend(bgi::intersects(box)), std::back_inserter(result));
+ \endverbatim
+
+ \par Throws
+ If predicates copy throws.
+
+ \param predicates Predicates.
+
+ \return The iterator pointing at the end of the query range.
+ */
+ template <typename Predicates>
+ typename boost::mpl::if_c<
+ detail::predicates_count_distance<Predicates>::value == 0,
+ detail::rtree::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>,
+ detail::rtree::iterators::distance_query_iterator<
+ value_type, options_type, translator_type, box_type, allocators_type, Predicates,
+ detail::predicates_find_distance<Predicates>::value
+ >
+ >::type
+ qend_(Predicates const& predicates) const
+ {
+ static const unsigned distance_predicates_count = detail::predicates_count_distance<Predicates>::value;
+ BOOST_MPL_ASSERT_MSG((distance_predicates_count <= 1), PASS_ONLY_ONE_DISTANCE_PREDICATE, (Predicates));
+
+ typedef typename boost::mpl::if_c<
+ detail::predicates_count_distance<Predicates>::value == 0,
+ detail::rtree::iterators::spatial_query_iterator<value_type, options_type, translator_type, box_type, allocators_type, Predicates>,
+ detail::rtree::iterators::distance_query_iterator<
+ value_type, options_type, translator_type, box_type, allocators_type, Predicates,
+ detail::predicates_find_distance<Predicates>::value
+ >
+ >::type iterator_type;
+
+ return iterator_type(m_members.translator(), predicates);
+ }
+
+ /*!
+ \brief Returns the query iterator pointing at the end of the query range.
+
+ This method returns the iterator which may be compared with the iterator returned by qbegin() in order to
+ check if the query has ended.
+
+ The type of the returned iterator is different than the type returned by qbegin() but the iterator of this type
+ may be assigned to the variable of const_query_iterator type. If you'd like to use the type of the iterator returned by this
+ method, which most certainly will be faster than the type-erased iterator, you may get the type
+ e.g. by using C++11 decltype or Boost.Typeof library.
+
+ The type of the iterator returned by this method is dfferent than the type returned by qbegin().
+
+ \par Example
+ \verbatim
+ // Store the result in the container using std::copy() and type-erased iterators
+ Rtree::const_query_iterator first = tree.qbegin(bgi::intersects(box));
+ Rtree::const_query_iterator last = tree.qend();
+ std::copy(first, last, std::back_inserter(result));
+
+ // Boost.Typeof
+ typedef BOOST_TYPEOF(tree.qbegin(bgi::nearest(pt, 10000))) Iter;
+ for ( Iter it = tree.qbegin(bgi::nearest(pt, 10000)) ; it != tree.qend() ; ++it )
+ {
+ // do something with value
+ if ( has_enough_nearest_values() )
+ break;
+ }
+ \endverbatim
+
+ \par Throws
+ Nothing
+
+ \return The iterator pointing at the end of the query range.
+ */
+ detail::rtree::iterators::end_query_iterator<value_type, allocators_type>
+ qend_() const
+ {
+ return detail::rtree::iterators::end_query_iterator<value_type, allocators_type>();
+ }
+
+public:
+
+ /*!
+ \brief Returns the number of stored values.
+
+ \return The number of stored values.
+
+ \par Throws
+ Nothing.
+ */
+ inline size_type size() const
+ {
+ return m_members.values_count;
+ }
+
+ /*!
+ \brief Query if the container is empty.
+
+ \return true if the container is empty.
+
+ \par Throws
+ Nothing.
+ */
+ inline bool empty() const
+ {
+ return 0 == m_members.values_count;
+ }
+
+ /*!
+ \brief Removes all values stored in the container.
+
+ \par Throws
+ Nothing.
+ */
+ inline void clear()
+ {
+ this->raw_destroy(*this);
+ }
+
+ /*!
+ \brief Returns the box able to contain all values stored in the container.
+
+ Returns the box able to contain all values stored in the container.
+ If the container is empty the result of \c geometry::assign_inverse() is returned.
+
+ \return The box able to contain all values stored in the container or an invalid box if
+ there are no values in the container.
+
+ \par Throws
+ Nothing.
+ */
+ inline bounds_type bounds() const
+ {
+ bounds_type result;
+ if ( !m_members.root )
+ {
+ geometry::assign_inverse(result);
+ return result;
+ }
+
+ detail::rtree::visitors::children_box<value_type, options_type, translator_type, box_type, allocators_type>
+ box_v(result, m_members.translator());
+ detail::rtree::apply_visitor(box_v, *m_members.root);
+
+ return result;
+ }
+
+ /*!
+ \brief Count Values or Indexables stored in the container.
+
+ For indexable_type it returns the number of values which indexables equals the parameter.
+ For value_type it returns the number of values which equals the parameter.
+
+ \param vori The value or indexable which will be counted.
+
+ \return The number of values found.
+
+ \par Throws
+ Nothing.
+ */
+ template <typename ValueOrIndexable>
+ size_type count(ValueOrIndexable const& vori) const
+ {
+ enum { as_val = 0, as_ind, dont_know };
+ typedef boost::mpl::int_
+ <
+ boost::is_same<ValueOrIndexable, value_type>::value ?
+ as_val :
+ boost::is_same<ValueOrIndexable, indexable_type>::value ?
+ as_ind :
+ boost::is_convertible<ValueOrIndexable, indexable_type>::value ?
+ as_ind :
+ boost::is_convertible<ValueOrIndexable, value_type>::value ?
+ as_val :
+ dont_know
+ > variant;
+
+ BOOST_MPL_ASSERT_MSG((variant::value != dont_know),
+ PASSED_OBJECT_NOT_CONVERTIBLE_TO_VALUE_NOR_INDEXABLE_TYPE,
+ (ValueOrIndexable));
+
+ typedef typename boost::mpl::if_c
+ <
+ variant::value == as_val,
+ value_type,
+ indexable_type
+ >::type value_or_indexable;
+
+ if ( !m_members.root )
+ return 0;
+
+ detail::rtree::visitors::count<value_or_indexable, value_type, options_type, translator_type, box_type, allocators_type>
+ count_v(vori, m_members.translator());
+
+ detail::rtree::apply_visitor(count_v, *m_members.root);
+
+ return count_v.found_count;
+ }
+
+ /*!
+ \brief Returns parameters.
+
+ \return The parameters object.
+
+ \par Throws
+ Nothing.
+ */
+ inline parameters_type parameters() const
+ {
+ return m_members.parameters();
+ }
+
+ /*!
+ \brief Returns function retrieving Indexable from Value.
+
+ \return The indexable_getter object.
+
+ \par Throws
+ Nothing.
+ */
+ indexable_getter indexable_get() const
+ {
+ return m_members.indexable_getter();
+ }
+
+ /*!
+ \brief Returns function comparing Values
+
+ \return The value_equal function.
+
+ \par Throws
+ Nothing.
+ */
+ value_equal value_eq() const
+ {
+ return m_members.equal_to();
+ }
+
+ /*!
+ \brief Returns allocator used by the rtree.
+
+ \return The allocator.
+
+ \par Throws
+ If allocator copy constructor throws.
+ */
+ allocator_type get_allocator() const
+ {
+ return m_members.allocators().allocator();
+ }
+
+private:
+
+ /*!
+ \brief Returns the translator object.
+
+ \return The translator object.
+
+ \par Throws
+ Nothing.
+ */
+ inline translator_type translator() const
+ {
+ return m_members.translator();
+ }
+
+ /*!
+ \brief Apply a visitor to the nodes structure in order to perform some operator.
+
+ This function is not a part of the 'official' interface. However it makes
+ possible e.g. to pass a visitor drawing the tree structure.
+
+ \param visitor The visitor object.
+
+ \par Throws
+ If Visitor::operator() throws.
+ */
+ template <typename Visitor>
+ inline void apply_visitor(Visitor & visitor) const
+ {
+ if ( m_members.root )
+ detail::rtree::apply_visitor(visitor, *m_members.root);
+ }
+
+ /*!
+ \brief Returns the depth of the R-tree.
+
+ This function is not a part of the 'official' interface.
+
+ \return The depth of the R-tree.
+
+ \par Throws
+ Nothing.
+ */
+ inline size_type depth() const
+ {
+ return m_members.leafs_level;
+ }
+
+private:
+
+ /*!
+ \pre Root node must exist - m_root != 0.
+
+ \brief Insert a value to the index.
+
+ \param value The value which will be stored in the container.
+
+ \par Exception-safety
+ basic
+ */
+ inline void raw_insert(value_type const& value)
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist");
+ BOOST_GEOMETRY_INDEX_ASSERT(detail::is_valid(m_members.translator()(value)), "Indexable is invalid");
+
+ detail::rtree::visitors::insert<
+ value_type,
+ value_type, options_type, translator_type, box_type, allocators_type,
+ typename options_type::insert_tag
+ > insert_v(m_members.root, m_members.leafs_level, value,
+ m_members.parameters(), m_members.translator(), m_members.allocators());
+
+ detail::rtree::apply_visitor(insert_v, *m_members.root);
+
+// TODO
+// Think about this: If exception is thrown, may the root be removed?
+// Or it is just cleared?
+
+// TODO
+// If exception is thrown, m_values_count may be invalid
+ ++m_members.values_count;
+ }
+
+ /*!
+ \brief Remove the value from the container.
+
+ \param value The value which will be removed from the container.
+
+ \par Exception-safety
+ basic
+ */
+ inline size_type raw_remove(value_type const& value)
+ {
+ // TODO: awulkiew - assert for correct value (indexable) ?
+ BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist");
+
+ detail::rtree::visitors::remove<
+ value_type, options_type, translator_type, box_type, allocators_type
+ > remove_v(m_members.root, m_members.leafs_level, value,
+ m_members.parameters(), m_members.translator(), m_members.allocators());
+
+ detail::rtree::apply_visitor(remove_v, *m_members.root);
+
+ // If exception is thrown, m_values_count may be invalid
+
+ if ( remove_v.is_value_removed() )
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < m_members.values_count, "unexpected state");
+
+ --m_members.values_count;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /*!
+ \brief Create an empty R-tree i.e. new empty root node and clear other attributes.
+
+ \par Exception-safety
+ strong
+ */
+ inline void raw_create()
+ {
+ BOOST_GEOMETRY_INDEX_ASSERT(0 == m_members.root, "the tree is already created");
+
+ m_members.root = detail::rtree::create_node<allocators_type, leaf>::apply(m_members.allocators()); // MAY THROW (N: alloc)
+ m_members.values_count = 0;
+ m_members.leafs_level = 0;
+ }
+
+ /*!
+ \brief Destroy the R-tree i.e. all nodes and clear attributes.
+
+ \param t The container which is going to be destroyed.
+
+ \par Exception-safety
+ nothrow
+ */
+ inline void raw_destroy(rtree & t)
+ {
+ if ( t.m_members.root )
+ {
+ detail::rtree::visitors::destroy<value_type, options_type, translator_type, box_type, allocators_type>
+ del_v(t.m_members.root, t.m_members.allocators());
+ detail::rtree::apply_visitor(del_v, *t.m_members.root);
+
+ t.m_members.root = 0;
+ }
+ t.m_members.values_count = 0;
+ t.m_members.leafs_level = 0;
+ }
+
+ /*!
+ \brief Copy the R-tree i.e. whole nodes structure, values and other attributes.
+ It uses destination's allocators to create the new structure.
+
+ \param src The source R-tree.
+ \param dst The destination R-tree.
+ \param copy_tr_and_params If true, translator and parameters will also be copied.
+
+ \par Exception-safety
+ strong
+ */
+ inline void raw_copy(rtree const& src, rtree & dst, bool copy_tr_and_params) const
+ {
+ detail::rtree::visitors::copy<value_type, options_type, translator_type, box_type, allocators_type>
+ copy_v(dst.m_members.allocators());
+
+ if ( src.m_members.root )
+ detail::rtree::apply_visitor(copy_v, *src.m_members.root); // MAY THROW (V, E: alloc, copy, N: alloc)
+
+ if ( copy_tr_and_params )
+ {
+ dst.m_members.indexable_getter() = src.m_members.indexable_getter();
+ dst.m_members.equal_to() = src.m_members.equal_to();
+ dst.m_members.parameters() = src.m_members.parameters();
+ }
+
+ // TODO use node_auto_ptr
+ if ( dst.m_members.root )
+ {
+ detail::rtree::visitors::destroy<value_type, options_type, translator_type, box_type, allocators_type>
+ del_v(dst.m_members.root, dst.m_members.allocators());
+ detail::rtree::apply_visitor(del_v, *dst.m_members.root);
+ dst.m_members.root = 0;
+ }
+
+ dst.m_members.root = copy_v.result;
+ dst.m_members.values_count = src.m_members.values_count;
+ dst.m_members.leafs_level = src.m_members.leafs_level;
+ }
+
+ /*!
+ \brief Insert a value corresponding to convertible object into the index.
+
+ \param val_conv The object convertible to value.
+
+ \par Exception-safety
+ basic
+ */
+ template <typename ValueConvertible>
+ inline void insert_dispatch(ValueConvertible const& val_conv,
+ boost::mpl::bool_<true> const& /*is_convertible*/)
+ {
+ if ( !m_members.root )
+ this->raw_create();
+
+ this->raw_insert(val_conv);
+ }
+
+ /*!
+ \brief Insert a range of values into the index.
+
+ \param rng The range of values.
+
+ \par Exception-safety
+ basic
+ */
+ template <typename Range>
+ inline void insert_dispatch(Range const& rng,
+ boost::mpl::bool_<false> const& /*is_convertible*/)
+ {
+ BOOST_MPL_ASSERT_MSG((detail::is_range<Range>::value),
+ PASSED_OBJECT_IS_NOT_CONVERTIBLE_TO_VALUE_NOR_A_RANGE,
+ (Range));
+
+ if ( !m_members.root )
+ this->raw_create();
+
+ typedef typename boost::range_const_iterator<Range>::type It;
+ for ( It it = boost::const_begin(rng); it != boost::const_end(rng) ; ++it )
+ this->raw_insert(*it);
+ }
+
+ /*!
+ \brief Remove a value corresponding to convertible object from the index.
+
+ \param val_conv The object convertible to value.
+
+ \par Exception-safety
+ basic
+ */
+ template <typename ValueConvertible>
+ inline size_type remove_dispatch(ValueConvertible const& val_conv,
+ boost::mpl::bool_<true> const& /*is_convertible*/)
+ {
+ return this->raw_remove(val_conv);
+ }
+
+ /*!
+ \brief Remove a range of values from the index.
+
+ \param rng The range of values which will be removed from the container.
+
+ \par Exception-safety
+ basic
+ */
+ template <typename Range>
+ inline size_type remove_dispatch(Range const& rng,
+ boost::mpl::bool_<false> const& /*is_convertible*/)
+ {
+ BOOST_MPL_ASSERT_MSG((detail::is_range<Range>::value),
+ PASSED_OBJECT_IS_NOT_CONVERTIBLE_TO_VALUE_NOR_A_RANGE,
+ (Range));
+
+ size_type result = 0;
+ typedef typename boost::range_const_iterator<Range>::type It;
+ for ( It it = boost::const_begin(rng); it != boost::const_end(rng) ; ++it )
+ result += this->raw_remove(*it);
+ return result;
+ }
+
+ /*!
+ \brief Return values meeting predicates.
+
+ \par Exception-safety
+ strong
+ */
+ template <typename Predicates, typename OutIter>
+ size_type query_dispatch(Predicates const& predicates, OutIter out_it, boost::mpl::bool_<false> const& /*is_distance_predicate*/) const
+ {
+ detail::rtree::visitors::spatial_query<value_type, options_type, translator_type, box_type, allocators_type, Predicates, OutIter>
+ find_v(m_members.translator(), predicates, out_it);
+
+ detail::rtree::apply_visitor(find_v, *m_members.root);
+
+ return find_v.found_count;
+ }
+
+ /*!
+ \brief Perform nearest neighbour search.
+
+ \par Exception-safety
+ strong
+ */
+ template <typename Predicates, typename OutIter>
+ size_type query_dispatch(Predicates const& predicates, OutIter out_it, boost::mpl::bool_<true> const& /*is_distance_predicate*/) const
+ {
+ static const unsigned distance_predicate_index = detail::predicates_find_distance<Predicates>::value;
+ detail::rtree::visitors::distance_query<
+ value_type,
+ options_type,
+ translator_type,
+ box_type,
+ allocators_type,
+ Predicates,
+ distance_predicate_index,
+ OutIter
+ > distance_v(m_members.parameters(), m_members.translator(), predicates, out_it);
+
+ detail::rtree::apply_visitor(distance_v, *m_members.root);
+
+ return distance_v.finish();
+ }
+
+ struct members_holder
+ : public translator_type
+ , public Parameters
+ , public allocators_type
+ {
+ private:
+ members_holder(members_holder const&);
+ members_holder & operator=(members_holder const&);
+
+ public:
+ template <typename IndGet, typename ValEq, typename Alloc>
+ members_holder(IndGet const& ind_get,
+ ValEq const& val_eq,
+ Parameters const& parameters,
+ BOOST_FWD_REF(Alloc) alloc)
+ : translator_type(ind_get, val_eq)
+ , Parameters(parameters)
+ , allocators_type(boost::forward<Alloc>(alloc))
+ , values_count(0)
+ , leafs_level(0)
+ , root(0)
+ {}
+
+ template <typename IndGet, typename ValEq>
+ members_holder(IndGet const& ind_get,
+ ValEq const& val_eq,
+ Parameters const& parameters)
+ : translator_type(ind_get, val_eq)
+ , Parameters(parameters)
+ , allocators_type()
+ , values_count(0)
+ , leafs_level(0)
+ , root(0)
+ {}
+
+ translator_type const& translator() const { return *this; }
+
+ IndexableGetter const& indexable_getter() const { return *this; }
+ IndexableGetter & indexable_getter() { return *this; }
+ EqualTo const& equal_to() const { return *this; }
+ EqualTo & equal_to() { return *this; }
+ Parameters const& parameters() const { return *this; }
+ Parameters & parameters() { return *this; }
+ allocators_type const& allocators() const { return *this; }
+ allocators_type & allocators() { return *this; }
+
+ size_type values_count;
+ size_type leafs_level;
+ node_pointer root;
+ };
+
+ members_holder m_members;
+};
+
+/*!
+\brief Insert a value to the index.
+
+It calls <tt>rtree::insert(value_type const&)</tt>.
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+\param v The value which will be stored in the index.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator>
+inline void insert(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree,
+ Value const& v)
+{
+ tree.insert(v);
+}
+
+/*!
+\brief Insert a range of values to the index.
+
+It calls <tt>rtree::insert(Iterator, Iterator)</tt>.
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+\param first The beginning of the range of values.
+\param last The end of the range of values.
+*/
+template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator,
+ typename Iterator>
+inline void insert(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree,
+ Iterator first, Iterator last)
+{
+ tree.insert(first, last);
+}
+
+/*!
+\brief Insert a value created using convertible object or a range of values to the index.
+
+It calls <tt>rtree::insert(ConvertibleOrRange const&)</tt>.
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+\param conv_or_rng The object of type convertible to value_type or a range of values.
+*/
+template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator,
+ typename ConvertibleOrRange>
+inline void insert(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree,
+ ConvertibleOrRange const& conv_or_rng)
+{
+ tree.insert(conv_or_rng);
+}
+
+/*!
+\brief Remove a value from the container.
+
+Remove a value from the container. In contrast to the \c std::set or <tt>std::map erase()</tt> method
+this function removes only one value from the container.
+
+It calls <tt>rtree::remove(value_type const&)</tt>.
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+\param v The value which will be removed from the index.
+
+\return 1 if value was removed, 0 otherwise.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator>
+inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type
+remove(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree,
+ Value const& v)
+{
+ return tree.remove(v);
+}
+
+/*!
+\brief Remove a range of values from the container.
+
+Remove a range of values from the container. In contrast to the \c std::set or <tt>std::map erase()</tt> method
+it doesn't take iterators pointing to values stored in this container. It removes values equal
+to these passed as a range. Furthermore this function removes only one value for each one passed
+in the range, not all equal values.
+
+It calls <tt>rtree::remove(Iterator, Iterator)</tt>.
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+\param first The beginning of the range of values.
+\param last The end of the range of values.
+
+\return The number of removed values.
+*/
+template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator,
+ typename Iterator>
+inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type
+remove(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree,
+ Iterator first, Iterator last)
+{
+ return tree.remove(first, last);
+}
+
+/*!
+\brief Remove a value corresponding to an object convertible to it or a range of values from the container.
+
+Remove a value corresponding to an object convertible to it or a range of values from the container.
+In contrast to the \c std::set or <tt>std::map erase()</tt> method
+it removes values equal to these passed as a range. Furthermore this method removes only
+one value for each one passed in the range, not all equal values.
+
+It calls <tt>rtree::remove(ConvertibleOrRange const&)</tt>.
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+\param conv_or_rng The object of type convertible to value_type or the range of values.
+
+\return The number of removed values.
+*/
+template<typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator,
+ typename ConvertibleOrRange>
+inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type
+remove(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree,
+ ConvertibleOrRange const& conv_or_rng)
+{
+ return tree.remove(conv_or_rng);
+}
+
+/*!
+\brief Finds values meeting passed predicates e.g. nearest to some Point and/or intersecting some Box.
+
+This query function performs spatial and k-nearest neighbor searches. It allows to pass a set of predicates.
+Values will be returned only if all predicates are met.
+
+<b>Spatial predicates</b>
+
+Spatial predicates may be generated by one of the functions listed below:
+\li \c boost::geometry::index::contains(),
+\li \c boost::geometry::index::covered_by(),
+\li \c boost::geometry::index::covers(),
+\li \c boost::geometry::index::disjoint(),
+\li \c boost::geometry::index::intersects(),
+\li \c boost::geometry::index::overlaps(),
+\li \c boost::geometry::index::within(),
+
+It is possible to negate spatial predicates:
+\li <tt>! boost::geometry::index::contains()</tt>,
+\li <tt>! boost::geometry::index::covered_by()</tt>,
+\li <tt>! boost::geometry::index::covers()</tt>,
+\li <tt>! boost::geometry::index::disjoint()</tt>,
+\li <tt>! boost::geometry::index::intersects()</tt>,
+\li <tt>! boost::geometry::index::overlaps()</tt>,
+\li <tt>! boost::geometry::index::within()</tt>
+
+<b>Satisfies predicate</b>
+
+This is a special kind of predicate which allows to pass a user-defined function or function object which checks
+if Value should be returned by the query. It's generated by:
+\li \c boost::geometry::index::satisfies().
+
+<b>Nearest predicate</b>
+
+If the nearest predicate is passed a k-nearest neighbor search will be performed. This query will result
+in returning k values to the output iterator. Only one nearest predicate may be passed to the query.
+It may be generated by:
+\li \c boost::geometry::index::nearest().
+
+<b>Connecting predicates</b>
+
+Predicates may be passed together connected with \c operator&&().
+
+\par Example
+\verbatim
+// return elements intersecting box
+bgi::query(tree, bgi::intersects(box), std::back_inserter(result));
+// return elements intersecting poly but not within box
+bgi::query(tree, bgi::intersects(poly) && !bgi::within(box), std::back_inserter(result));
+// return elements overlapping box and meeting my_fun value predicate
+bgi::query(tree, bgi::overlaps(box) && bgi::satisfies(my_fun), std::back_inserter(result));
+// return 5 elements nearest to pt and elements are intersecting box
+bgi::query(tree, bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result));
+\endverbatim
+
+\par Throws
+If Value copy constructor or copy assignment throws.
+
+\warning
+Only one \c nearest() perdicate may be passed to the query. Passing more of them results in compile-time error.
+
+\ingroup rtree_functions
+
+\param tree The rtree.
+\param predicates Predicates.
+\param out_it The output iterator, e.g. generated by std::back_inserter().
+
+\return The number of values found.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator,
+ typename Predicates, typename OutIter> inline
+typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::size_type
+query(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree,
+ Predicates const& predicates,
+ OutIter out_it)
+{
+ return tree.query(predicates, out_it);
+}
+
+/*!
+\brief Returns the query iterator pointing at the begin of the query range.
+
+This method returns the iterator which may be used to perform iterative queries. For the information
+about the predicates which may be passed to this method see query().
+
+\par Example
+\verbatim
+
+for ( Rtree::const_query_iterator it = qbegin(tree, bgi::nearest(pt, 10000)) ;
+ it != qend(tree) ; ++it )
+{
+ // do something with value
+ if ( has_enough_nearest_values() )
+ break;
+}
+\endverbatim
+
+\par Throws
+If predicates copy throws.
+If allocation throws.
+
+\ingroup rtree_functions
+
+\param tree The rtree.
+\param predicates Predicates.
+
+\return The iterator pointing at the begin of the query range.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator,
+ typename Predicates> inline
+typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::const_query_iterator
+qbegin(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree,
+ Predicates const& predicates)
+{
+ return tree.qbegin(predicates);
+}
+
+/*!
+\brief Returns the query iterator pointing at the end of the query range.
+
+This method returns the iterator which may be used to check if the query has ended.
+
+\par Example
+\verbatim
+
+for ( Rtree::const_query_iterator it = qbegin(tree, bgi::nearest(pt, 10000)) ;
+ it != qend(tree) ; ++it )
+{
+ // do something with value
+ if ( has_enough_nearest_values() )
+ break;
+}
+\endverbatim
+
+\par Throws
+Nothing
+
+\ingroup rtree_functions
+
+\return The iterator pointing at the end of the query range.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator> inline
+typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::const_query_iterator
+qend(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree)
+{
+ return tree.qend();
+}
+
+/*!
+\brief Remove all values from the index.
+
+It calls \c rtree::clear().
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator>
+inline void clear(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & tree)
+{
+ return tree.clear();
+}
+
+/*!
+\brief Get the number of values stored in the index.
+
+It calls \c rtree::size().
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+
+\return The number of values stored in the index.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator>
+inline size_t size(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree)
+{
+ return tree.size();
+}
+
+/*!
+\brief Query if there are no values stored in the index.
+
+It calls \c rtree::empty().
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+
+\return true if there are no values in the index.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator>
+inline bool empty(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree)
+{
+ return tree.bounds();
+}
+
+/*!
+\brief Get the box containing all stored values or an invalid box if the index has no values.
+
+It calls \c rtree::envelope().
+
+\ingroup rtree_functions
+
+\param tree The spatial index.
+
+\return The box containing all stored values or an invalid box.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator>
+inline typename rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator>::bounds_type
+bounds(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> const& tree)
+{
+ return tree.bounds();
+}
+
+/*!
+\brief Exchanges the contents of the container with those of other.
+
+It calls \c rtree::swap().
+
+\ingroup rtree_functions
+
+\param l The first rtree.
+\param r The second rtree.
+*/
+template <typename Value, typename Parameters, typename IndexableGetter, typename EqualTo, typename Allocator>
+inline void swap(rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & l,
+ rtree<Value, Parameters, IndexableGetter, EqualTo, Allocator> & r)
+{
+ return l.swap(r);
+}
+
+}}} // namespace boost::geometry::index
+
+// TODO: don't include the implementation at the end of the file
+#include <boost/geometry/algorithms/detail/comparable_distance/implementation.hpp>
+
+#include <boost/geometry/index/detail/config_end.hpp>
+
+#endif // BOOST_GEOMETRY_INDEX_RTREE_HPP
diff --git a/boost/geometry/io/dsv/write.hpp b/boost/geometry/io/dsv/write.hpp
index 62929f8073..f39a2489ad 100644
--- a/boost/geometry/io/dsv/write.hpp
+++ b/boost/geometry/io/dsv/write.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -20,12 +21,14 @@
#include <boost/concept_check.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.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/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -209,9 +212,10 @@ struct dsv_poly
dsv_range<ring>::apply(os, exterior_ring(poly), settings);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
os << settings.list_separator;
dsv_range<ring>::apply(os, *it, settings);
@@ -339,9 +343,61 @@ private:
dsv_settings m_settings;
};
+
+template <typename MultiGeometry>
+struct dsv_multi
+{
+ typedef dispatch::dsv
+ <
+ typename single_tag_of
+ <
+ typename tag<MultiGeometry>::type
+ >::type,
+ typename boost::range_value<MultiGeometry>::type
+ > dispatch_one;
+
+ typedef typename boost::range_iterator
+ <
+ MultiGeometry const
+ >::type iterator;
+
+
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ MultiGeometry const& multi,
+ dsv_settings const& settings)
+ {
+ os << settings.list_open;
+
+ bool first = true;
+ for(iterator it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, first = false)
+ {
+ os << (first ? "" : settings.list_separator);
+ dispatch_one::apply(os, *it, settings);
+ }
+ os << settings.list_close;
+ }
+};
+
}} // namespace detail::dsv
#endif // DOXYGEN_NO_DETAIL
+// TODO: The alternative to this could be a forward declaration of dispatch::dsv<>
+// or braking the code into the interface and implementation part
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Geometry>
+struct dsv<multi_tag, Geometry>
+ : detail::dsv::dsv_multi<Geometry>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
/*!
\brief Main DSV-streaming function
\details DSV stands for Delimiter Separated Values. Geometries can be streamed
diff --git a/boost/geometry/io/svg/svg_mapper.hpp b/boost/geometry/io/svg/svg_mapper.hpp
new file mode 100644
index 0000000000..b53fef2ceb
--- /dev/null
+++ b/boost/geometry/io/svg/svg_mapper.hpp
@@ -0,0 +1,390 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
+#define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
+
+#include <cstdio>
+
+#include <vector>
+
+#include <boost/mpl/assert.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/remove_const.hpp>
+
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
+
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/transform.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/strategies/transform.hpp>
+#include <boost/geometry/strategies/transform/map_transformer.hpp>
+#include <boost/geometry/views/segment_view.hpp>
+
+#include <boost/geometry/multi/algorithms/envelope.hpp>
+#include <boost/geometry/multi/algorithms/num_points.hpp>
+
+#include <boost/geometry/io/svg/write_svg.hpp>
+
+// Helper geometries (all points are transformed to integer-points)
+#include <boost/geometry/geometries/geometries.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace svg
+{
+ typedef model::point<int, 2, cs::cartesian> svg_point_type;
+}}
+#endif
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+
+template <typename GeometryTag, typename Geometry>
+struct svg_map
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (Geometry)
+ );
+};
+
+
+template <typename Point>
+struct svg_map<point_tag, Point>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Point const& point, TransformStrategy const& strategy)
+ {
+ detail::svg::svg_point_type ipoint;
+ geometry::transform(point, ipoint, strategy);
+ stream << geometry::svg(ipoint, style, size) << std::endl;
+ }
+};
+
+template <typename Box>
+struct svg_map<box_tag, Box>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Box const& box, TransformStrategy const& strategy)
+ {
+ model::box<detail::svg::svg_point_type> ibox;
+ geometry::transform(box, ibox, strategy);
+
+ stream << geometry::svg(ibox, style, size) << std::endl;
+ }
+};
+
+
+template <typename Range1, typename Range2>
+struct svg_map_range
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Range1 const& range, TransformStrategy const& strategy)
+ {
+ Range2 irange;
+ geometry::transform(range, irange, strategy);
+ stream << geometry::svg(irange, style, size) << std::endl;
+ }
+};
+
+template <typename Segment>
+struct svg_map<segment_tag, Segment>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Segment const& segment, TransformStrategy const& strategy)
+ {
+ typedef segment_view<Segment> view_type;
+ view_type range(segment);
+ svg_map_range
+ <
+ view_type,
+ model::linestring<detail::svg::svg_point_type>
+ >::apply(stream, style, size, range, strategy);
+ }
+};
+
+
+template <typename Ring>
+struct svg_map<ring_tag, Ring>
+ : svg_map_range<Ring, model::ring<detail::svg::svg_point_type> >
+{};
+
+
+template <typename Linestring>
+struct svg_map<linestring_tag, Linestring>
+ : svg_map_range<Linestring, model::linestring<detail::svg::svg_point_type> >
+{};
+
+
+template <typename Polygon>
+struct svg_map<polygon_tag, Polygon>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Polygon const& polygon, TransformStrategy const& strategy)
+ {
+ model::polygon<detail::svg::svg_point_type> ipoly;
+ geometry::transform(polygon, ipoly, strategy);
+ stream << geometry::svg(ipoly, style, size) << std::endl;
+ }
+};
+
+
+template <typename Multi>
+struct svg_map<multi_tag, Multi>
+{
+ typedef typename single_tag_of
+ <
+ typename geometry::tag<Multi>::type
+ >::type stag;
+
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Multi const& multi, TransformStrategy const& strategy)
+ {
+ for (typename boost::range_iterator<Multi const>::type it
+ = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ svg_map
+ <
+ stag,
+ typename boost::range_value<Multi>::type
+ >::apply(stream, style, size, *it, strategy);
+ }
+ }
+};
+
+
+} // namespace dispatch
+#endif
+
+
+template <typename Geometry, typename TransformStrategy>
+inline void svg_map(std::ostream& stream,
+ std::string const& style, int size,
+ Geometry const& geometry, TransformStrategy const& strategy)
+{
+ dispatch::svg_map
+ <
+ typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ multi_tag
+ >::type,
+ typename boost::remove_const<Geometry>::type
+ >::apply(stream, style, size, geometry, strategy);
+}
+
+
+/*!
+\brief Helper class to create SVG maps
+\tparam Point Point type, for input geometries.
+\tparam SameScale Boolean flag indicating if horizontal and vertical scale should
+ be the same. The default value is true
+\ingroup svg
+
+\qbk{[include reference/io/svg.qbk]}
+*/
+template <typename Point, bool SameScale = true>
+class svg_mapper : boost::noncopyable
+{
+ typedef typename geometry::select_most_precise
+ <
+ typename coordinate_type<Point>::type,
+ double
+ >::type calculation_type;
+
+ typedef strategy::transform::map_transformer
+ <
+ calculation_type,
+ geometry::dimension<Point>::type::value,
+ geometry::dimension<Point>::type::value,
+ true,
+ SameScale
+ > transformer_type;
+
+ model::box<Point> m_bounding_box;
+ boost::scoped_ptr<transformer_type> m_matrix;
+ std::ostream& m_stream;
+ int m_width, m_height;
+ std::string m_width_height; // for <svg> tag only, defaults to 2x 100%
+
+ void init_matrix()
+ {
+ if (! m_matrix)
+ {
+ m_matrix.reset(new transformer_type(m_bounding_box,
+ m_width, m_height));
+
+
+ m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
+ << std::endl
+ << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
+ << std::endl
+ << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
+ << std::endl
+ << "<svg " << m_width_height << " version=\"1.1\""
+ << std::endl
+ << "xmlns=\"http://www.w3.org/2000/svg\""
+ << std::endl
+ << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
+ << ">"
+ << std::endl;
+ }
+ }
+
+public :
+
+ /*!
+ \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
+ Should be called explicitly.
+ \param stream Output stream, should be a stream already open
+ \param width Width of the SVG map (in SVG pixels)
+ \param height Height of the SVG map (in SVG pixels)
+ \param width_height Optional information to increase width and/or height
+ */
+ explicit svg_mapper(std::ostream& stream, int width, int height
+ , std::string const& width_height = "width=\"100%\" height=\"100%\"")
+ : m_stream(stream)
+ , m_width(width)
+ , m_height(height)
+ , m_width_height(width_height)
+ {
+ assign_inverse(m_bounding_box);
+ }
+
+ /*!
+ \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
+ */
+ virtual ~svg_mapper()
+ {
+ m_stream << "</svg>" << std::endl;
+ }
+
+ /*!
+ \brief Adds a geometry to the transformation matrix. After doing this,
+ the specified geometry can be mapped fully into the SVG map
+ \tparam Geometry \tparam_geometry
+ \param geometry \param_geometry
+ */
+ template <typename Geometry>
+ void add(Geometry const& geometry)
+ {
+ if (num_points(geometry) > 0)
+ {
+ expand(m_bounding_box,
+ return_envelope
+ <
+ model::box<Point>
+ >(geometry));
+ }
+ }
+
+ /*!
+ \brief Maps a geometry into the SVG map using the specified style
+ \tparam Geometry \tparam_geometry
+ \param geometry \param_geometry
+ \param style String containing verbatim SVG style information
+ \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
+ specify linewidth in the SVG style information
+ */
+ template <typename Geometry>
+ void map(Geometry const& geometry, std::string const& style,
+ int size = -1)
+ {
+ init_matrix();
+ svg_map(m_stream, style, size, geometry, *m_matrix);
+ }
+
+ /*!
+ \brief Adds a text to the SVG map
+ \tparam TextPoint \tparam_point
+ \param point Location of the text (in map units)
+ \param s The text itself
+ \param style String containing verbatim SVG style information, of the text
+ \param offset_x Offset in SVG pixels, defaults to 0
+ \param offset_y Offset in SVG pixels, defaults to 0
+ \param lineheight Line height in SVG pixels, in case the text contains \n
+ */
+ template <typename TextPoint>
+ void text(TextPoint const& point, std::string const& s,
+ std::string const& style,
+ int offset_x = 0, int offset_y = 0, int lineheight = 10)
+ {
+ init_matrix();
+ detail::svg::svg_point_type map_point;
+ transform(point, map_point, *m_matrix);
+ m_stream
+ << "<text style=\"" << style << "\""
+ << " x=\"" << get<0>(map_point) + offset_x << "\""
+ << " y=\"" << get<1>(map_point) + offset_y << "\""
+ << ">";
+ if (s.find("\n") == std::string::npos)
+ {
+ m_stream << s;
+ }
+ else
+ {
+ // Multi-line modus
+
+ std::vector<std::string> splitted;
+ boost::split(splitted, s, boost::is_any_of("\n"));
+ for (std::vector<std::string>::const_iterator it
+ = splitted.begin();
+ it != splitted.end();
+ ++it, offset_y += lineheight)
+ {
+ m_stream
+ << "<tspan x=\"" << get<0>(map_point) + offset_x
+ << "\""
+ << " y=\"" << get<1>(map_point) + offset_y
+ << "\""
+ << ">" << *it << "</tspan>";
+ }
+ }
+ m_stream << "</text>" << std::endl;
+ }
+};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
diff --git a/boost/geometry/io/svg/write_svg.hpp b/boost/geometry/io/svg/write_svg.hpp
new file mode 100644
index 0000000000..fba3cbebaf
--- /dev/null
+++ b/boost/geometry/io/svg/write_svg.hpp
@@ -0,0 +1,279 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
+#define BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
+
+#include <ostream>
+#include <string>
+
+#include <boost/config.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.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/geometries/concepts/check.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace svg
+{
+
+
+template <typename Point>
+struct svg_point
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Point const& p, std::string const& style, int size)
+ {
+ os << "<circle cx=\"" << geometry::get<0>(p)
+ << "\" cy=\"" << geometry::get<1>(p)
+ << "\" r=\"" << (size < 0 ? 5 : size)
+ << "\" style=\"" << style << "\"/>";
+ }
+};
+
+
+template <typename Box>
+struct svg_box
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Box const& box, std::string const& style, int )
+ {
+ // Prevent invisible boxes, making them >=1, using "max"
+ BOOST_USING_STD_MAX();
+
+ typedef typename coordinate_type<Box>::type ct;
+ ct x = geometry::get<geometry::min_corner, 0>(box);
+ ct y = geometry::get<geometry::min_corner, 1>(box);
+ ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION(1,
+ geometry::get<geometry::max_corner, 0>(box) - x);
+ ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (1,
+ geometry::get<geometry::max_corner, 1>(box) - y);
+
+ os << "<rect x=\"" << x << "\" y=\"" << y
+ << "\" width=\"" << width << "\" height=\"" << height
+ << "\" style=\"" << style << "\"/>";
+ }
+};
+
+
+/*!
+\brief Stream ranges as SVG
+\note policy is used to select type (polyline/polygon)
+*/
+template <typename Range, typename Policy>
+struct svg_range
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Range const& range, std::string const& style, int )
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ bool first = true;
+
+ os << "<" << Policy::prefix() << " points=\"";
+
+ for (iterator it = boost::begin(range);
+ it != boost::end(range);
+ ++it, first = false)
+ {
+ os << (first ? "" : " " )
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
+ }
+ os << "\" style=\"" << style << Policy::style() << "\"/>";
+ }
+};
+
+
+
+template <typename Polygon>
+struct svg_poly
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Polygon const& polygon, std::string const& style, int )
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+ typedef typename boost::range_iterator<ring_type const>::type iterator_type;
+
+ bool first = true;
+ os << "<g fill-rule=\"evenodd\"><path d=\"";
+
+ ring_type const& ring = geometry::exterior_ring(polygon);
+ for (iterator_type it = boost::begin(ring);
+ it != boost::end(ring);
+ ++it, first = false)
+ {
+ os << (first ? "M" : " L") << " "
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
+ }
+
+ // Inner rings:
+ {
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ rit = boost::begin(rings); rit != boost::end(rings); ++rit)
+ {
+ first = true;
+ for (typename detail::interior_ring_iterator<Polygon const>::type
+ it = boost::begin(*rit); it != boost::end(*rit);
+ ++it, first = false)
+ {
+ os << (first ? "M" : " L") << " "
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
+ }
+ }
+ }
+ os << " z \" style=\"" << style << "\"/></g>";
+
+ }
+};
+
+
+
+struct prefix_linestring
+{
+ static inline const char* prefix() { return "polyline"; }
+ static inline const char* style() { return ";fill:none"; }
+};
+
+
+struct prefix_ring
+{
+ static inline const char* prefix() { return "polygon"; }
+ static inline const char* style() { return ""; }
+};
+
+
+
+}} // namespace detail::svg
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+/*!
+\brief Dispatching base struct for SVG streaming, specialized below per geometry type
+\details Specializations should implement a static method "stream" to stream a geometry
+The static method should have the signature:
+
+template <typename Char, typename Traits>
+static inline void apply(std::basic_ostream<Char, Traits>& os, G const& geometry)
+*/
+template <typename GeometryTag, typename Geometry>
+struct svg
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (Geometry)
+ );
+};
+
+template <typename Point>
+struct svg<point_tag, Point> : detail::svg::svg_point<Point> {};
+
+template <typename Box>
+struct svg<box_tag, Box> : detail::svg::svg_box<Box> {};
+
+template <typename Linestring>
+struct svg<linestring_tag, Linestring>
+ : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {};
+
+template <typename Ring>
+struct svg<ring_tag, Ring>
+ : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {};
+
+template <typename Polygon>
+struct svg<polygon_tag, Polygon>
+ : detail::svg::svg_poly<Polygon> {};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief Generic geometry template manipulator class, takes corresponding output class from traits class
+\ingroup svg
+\details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics)
+*/
+template <typename G>
+class svg_manipulator
+{
+public:
+
+ inline svg_manipulator(G const& g, std::string const& style, int size)
+ : m_geometry(g)
+ , m_style(style)
+ , m_size(size)
+ {}
+
+ template <typename Char, typename Traits>
+ inline friend std::basic_ostream<Char, Traits>& operator<<(
+ std::basic_ostream<Char, Traits>& os, svg_manipulator const& m)
+ {
+ dispatch::svg
+ <
+ typename tag<G>::type, G
+ >::apply(os, m.m_geometry, m.m_style, m.m_size);
+ os.flush();
+ return os;
+ }
+
+private:
+ G const& m_geometry;
+ std::string const& m_style;
+ int m_size;
+};
+
+/*!
+\brief Manipulator to stream geometries as SVG
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\param style String containing verbatim SVG style information
+\param size Optional size (used for SVG points) in SVG pixels. For linestrings,
+ specify linewidth in the SVG style information
+\ingroup svg
+*/
+template <typename Geometry>
+inline svg_manipulator<Geometry> svg(Geometry const& geometry, std::string const& style, int size = -1)
+{
+ concept::check<Geometry const>();
+
+ return svg_manipulator<Geometry>(geometry, style, size);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
diff --git a/boost/geometry/io/svg/write_svg_multi.hpp b/boost/geometry/io/svg/write_svg_multi.hpp
new file mode 100644
index 0000000000..a794120c06
--- /dev/null
+++ b/boost/geometry/io/svg/write_svg_multi.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP
+#define BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP
+
+
+#include <boost/geometry/io/svg/write_svg.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace svg
+{
+
+
+template <typename MultiGeometry, typename Policy>
+struct svg_multi
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ MultiGeometry const& multi, std::string const& style, int size)
+ {
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(os, *it, style, size);
+ }
+
+ }
+
+};
+
+
+
+}} // namespace detail::svg
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename MultiPolygon>
+struct svg<multi_polygon_tag, MultiPolygon>
+ : detail::svg::svg_multi
+ <
+ MultiPolygon,
+ detail::svg::svg_poly
+ <
+ typename boost::range_value<MultiPolygon>::type
+ >
+
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP
diff --git a/boost/geometry/io/wkt/detail/prefix.hpp b/boost/geometry/io/wkt/detail/prefix.hpp
index 45e43b88d4..b566e02aa6 100644
--- a/boost/geometry/io/wkt/detail/prefix.hpp
+++ b/boost/geometry/io/wkt/detail/prefix.hpp
@@ -17,10 +17,16 @@
namespace boost { namespace geometry
{
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace wkt
{
+struct prefix_null
+{
+ static inline const char* apply() { return ""; }
+};
+
struct prefix_point
{
static inline const char* apply() { return "POINT"; }
@@ -36,6 +42,21 @@ struct prefix_linestring
static inline const char* apply() { return "LINESTRING"; }
};
+struct prefix_multipoint
+{
+ static inline const char* apply() { return "MULTIPOINT"; }
+};
+
+struct prefix_multilinestring
+{
+ static inline const char* apply() { return "MULTILINESTRING"; }
+};
+
+struct prefix_multipolygon
+{
+ static inline const char* apply() { return "MULTIPOLYGON"; }
+};
+
}} // namespace wkt::impl
#endif
diff --git a/boost/geometry/io/wkt/detail/wkt_multi.hpp b/boost/geometry/io/wkt/detail/wkt_multi.hpp
index 0e5abbca81..2b2d1946ad 100644
--- a/boost/geometry/io/wkt/detail/wkt_multi.hpp
+++ b/boost/geometry/io/wkt/detail/wkt_multi.hpp
@@ -14,9 +14,8 @@
#ifndef BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP
#define BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP
-
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/domains/gis/io/wkt/write.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
namespace boost { namespace geometry
diff --git a/boost/geometry/io/wkt/read.hpp b/boost/geometry/io/wkt/read.hpp
index e926939d51..748eecdbe6 100644
--- a/boost/geometry/io/wkt/read.hpp
+++ b/boost/geometry/io/wkt/read.hpp
@@ -14,6 +14,7 @@
#ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP
#define BOOST_GEOMETRY_IO_WKT_READ_HPP
+#include <cstddef>
#include <string>
#include <boost/lexical_cast.hpp>
@@ -36,6 +37,8 @@
#include <boost/geometry/core/geometry_id.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -306,8 +309,6 @@ struct ring_parser
};
-
-
/*!
\brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))"
\note used for parsing polygons and multi-polygons
@@ -358,6 +359,7 @@ struct polygon_parser
}
};
+
inline bool one_of(tokenizer::iterator const& it, std::string const& value,
bool& is_present)
{
@@ -423,10 +425,21 @@ inline bool initialize(tokenizer const& tokens,
handle_empty_z_m(it, tokens.end(), has_empty, has_z, has_m);
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
if (has_z && dimension<Geometry>::type::value < 3)
{
throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt);
}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
if (has_empty)
{
check_end(it, tokens.end(), wkt);
@@ -458,7 +471,101 @@ struct geometry_parser
};
+template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
+struct multi_parser
+{
+ static inline void apply(std::string const& wkt, MultiGeometry& geometry)
+ {
+ traits::clear<MultiGeometry>::apply(geometry);
+
+ tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
+ tokenizer::iterator it;
+ if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
+ {
+ handle_open_parenthesis(it, tokens.end(), wkt);
+
+ // Parse sub-geometries
+ while(it != tokens.end() && *it != ")")
+ {
+ traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
+ Parser
+ <
+ typename boost::range_value<MultiGeometry>::type
+ >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
+ if (it != tokens.end() && *it == ",")
+ {
+ // Skip "," after multi-element is parsed
+ ++it;
+ }
+ }
+
+ handle_close_parenthesis(it, tokens.end(), wkt);
+ }
+
+ check_end(it, tokens.end(), wkt);
+ }
+};
+
+template <typename P>
+struct noparenthesis_point_parser
+{
+ static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
+ std::string const& wkt, P& point)
+ {
+ parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt);
+ }
+};
+
+template <typename MultiGeometry, typename PrefixPolicy>
+struct multi_point_parser
+{
+ static inline void apply(std::string const& wkt, MultiGeometry& geometry)
+ {
+ traits::clear<MultiGeometry>::apply(geometry);
+
+ tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
+ tokenizer::iterator it;
+ if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
+ {
+ handle_open_parenthesis(it, tokens.end(), wkt);
+
+ // If first point definition starts with "(" then parse points as (x y)
+ // otherwise as "x y"
+ bool using_brackets = (it != tokens.end() && *it == "(");
+
+ while(it != tokens.end() && *it != ")")
+ {
+ traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
+
+ if (using_brackets)
+ {
+ point_parser
+ <
+ typename boost::range_value<MultiGeometry>::type
+ >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
+ }
+ else
+ {
+ noparenthesis_point_parser
+ <
+ typename boost::range_value<MultiGeometry>::type
+ >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
+ }
+
+ if (it != tokens.end() && *it == ",")
+ {
+ // Skip "," after point is parsed
+ ++it;
+ }
+ }
+
+ handle_close_parenthesis(it, tokens.end(), wkt);
+ }
+
+ check_end(it, tokens.end(), wkt);
+ }
+};
/*!
@@ -511,7 +618,7 @@ struct box_parser
check_end(it, end, wkt);
int index = 0;
- int n = boost::size(points);
+ std::size_t n = boost::size(points);
if (n == 2)
{
index = 1;
@@ -578,7 +685,6 @@ struct segment_parser
};
-
}} // namespace detail::wkt
#endif // DOXYGEN_NO_DETAIL
@@ -632,6 +738,36 @@ struct read_wkt<polygon_tag, Geometry>
{};
+template <typename MultiGeometry>
+struct read_wkt<multi_point_tag, MultiGeometry>
+ : detail::wkt::multi_point_parser
+ <
+ MultiGeometry,
+ detail::wkt::prefix_multipoint
+ >
+{};
+
+template <typename MultiGeometry>
+struct read_wkt<multi_linestring_tag, MultiGeometry>
+ : detail::wkt::multi_parser
+ <
+ MultiGeometry,
+ detail::wkt::linestring_parser,
+ detail::wkt::prefix_multilinestring
+ >
+{};
+
+template <typename MultiGeometry>
+struct read_wkt<multi_polygon_tag, MultiGeometry>
+ : detail::wkt::multi_parser
+ <
+ MultiGeometry,
+ detail::wkt::polygon_parser,
+ detail::wkt::prefix_multipolygon
+ >
+{};
+
+
// Box (Non-OGC)
template <typename Box>
struct read_wkt<box_tag, Box>
@@ -651,28 +787,11 @@ struct read_wkt<segment_tag, Segment>
/*!
\brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry)
\ingroup wkt
+\tparam Geometry \tparam_geometry
\param wkt string containing \ref WKT
-\param geometry output geometry
-\par Example:
-\note It is case insensitive and can have the WKT forms "point", "point m", "point z", "point zm", "point mz"
-\note Empty sequences can have forms as "LINESTRING ()" or "POLYGON(())"
-Small example showing how to use read_wkt to build a point
-\dontinclude doxygen_1.cpp
-\skip example_from_wkt_point
-\line {
-\until }
-\par Example:
-Small example showing how to use read_wkt to build a linestring
-\dontinclude doxygen_1.cpp
-\skip example_from_wkt_linestring
-\line {
-\until }
-\par Example:
-Small example showing how to use read_wkt to build a polygon
-\dontinclude doxygen_1.cpp
-\skip example_from_wkt_polygon
-\line {
-\until }
+\param geometry \param_geometry output geometry
+\ingroup wkt
+\qbk{[include reference/io/read_wkt.qbk]}
*/
template <typename Geometry>
inline void read_wkt(std::string const& wkt, Geometry& geometry)
diff --git a/boost/geometry/io/wkt/stream.hpp b/boost/geometry/io/wkt/stream.hpp
index 86e49fdaf1..3849dda594 100644
--- a/boost/geometry/io/wkt/stream.hpp
+++ b/boost/geometry/io/wkt/stream.hpp
@@ -22,10 +22,8 @@
// Don't use namespace boost::geometry, to enable the library to stream custom
// geometries which are living outside the namespace boost::geometry
-/*!
-\brief Streams a geometry as Well-Known Text
-\ingroup wkt
-*/
+// This is currently not documented on purpose: the Doxygen 2 QBK generator
+// should be updated w.r.t. << which in the end ruins the DocBook XML
template<typename Char, typename Traits, typename Geometry>
inline std::basic_ostream<Char, Traits>& operator<<
(
diff --git a/boost/geometry/io/wkt/write.hpp b/boost/geometry/io/wkt/write.hpp
index a3e3173d05..6c1a2e153e 100644
--- a/boost/geometry/io/wkt/write.hpp
+++ b/boost/geometry/io/wkt/write.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,24 +19,36 @@
#include <string>
#include <boost/array.hpp>
-#include <boost/concept/assert.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/not_implemented.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/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/io/wkt/detail/prefix.hpp>
+
namespace boost { namespace geometry
{
+// Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4512)
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace wkt
{
@@ -109,31 +122,49 @@ struct wkt_range
{
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
- Range const& range)
+ Range const& range, bool force_closed)
{
typedef typename boost::range_iterator<Range const>::type iterator_type;
+ typedef stream_coordinate
+ <
+ point_type, 0, dimension<point_type>::type::value
+ > stream_type;
+
bool first = true;
os << PrefixPolicy::apply();
// TODO: check EMPTY here
- for (iterator_type it = boost::begin(range);
- it != boost::end(range);
- ++it)
+ iterator_type begin = boost::begin(range);
+ iterator_type end = boost::end(range);
+ for (iterator_type it = begin; it != end; ++it)
{
os << (first ? "" : ",");
- stream_coordinate
- <
- point_type, 0, dimension<point_type>::type::value
- >::apply(os, *it);
+ stream_type::apply(os, *it);
first = false;
}
+ // optionally, close range to ring by repeating the first point
+ if (force_closed
+ && boost::size(range) > 1
+ && geometry::disjoint(*begin, *(end - 1)))
+ {
+ os << ",";
+ stream_type::apply(os, *begin);
+ }
+
os << SuffixPolicy::apply();
}
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Range const& range)
+ {
+ apply(os, range, false);
+ }
+
private:
typedef typename boost::range_value<Range>::type point_type;
};
@@ -160,23 +191,52 @@ struct wkt_poly
Polygon const& poly)
{
typedef typename ring_type<Polygon const>::type ring;
+ bool const force_closed = true;
os << PrefixPolicy::apply();
// TODO: check EMPTY here
os << "(";
- wkt_sequence<ring>::apply(os, exterior_ring(poly));
+ wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closed);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
os << ",";
- wkt_sequence<ring>::apply(os, *it);
+ wkt_sequence<ring>::apply(os, *it, force_closed);
}
os << ")";
}
};
+template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
+struct wkt_multi
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Multi const& geometry)
+ {
+ os << PrefixPolicy::apply();
+ // TODO: check EMPTY here
+ os << "(";
+
+ for (typename boost::range_iterator<Multi const>::type
+ it = boost::begin(geometry);
+ it != boost::end(geometry);
+ ++it)
+ {
+ if (it != boost::begin(geometry))
+ {
+ os << ",";
+ }
+ StreamPolicy::apply(os, *it);
+ }
+
+ os << ")";
+ }
+};
+
template <typename Box>
struct wkt_box
{
@@ -240,18 +300,12 @@ struct wkt_segment
namespace dispatch
{
-template <typename Tag, typename Geometry>
-struct wkt
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
-};
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct wkt: not_implemented<Tag>
+{};
template <typename Point>
-struct wkt<point_tag, Point>
+struct wkt<Point, point_tag>
: detail::wkt::wkt_point
<
Point,
@@ -260,7 +314,7 @@ struct wkt<point_tag, Point>
{};
template <typename Linestring>
-struct wkt<linestring_tag, Linestring>
+struct wkt<Linestring, linestring_tag>
: detail::wkt::wkt_range
<
Linestring,
@@ -275,12 +329,12 @@ struct wkt<linestring_tag, Linestring>
It is therefore streamed as a polygon
*/
template <typename Box>
-struct wkt<box_tag, Box>
+struct wkt<Box, box_tag>
: detail::wkt::wkt_box<Box>
{};
template <typename Segment>
-struct wkt<segment_tag, Segment>
+struct wkt<Segment, segment_tag>
: detail::wkt::wkt_segment<Segment>
{};
@@ -291,7 +345,7 @@ A ring is equivalent to a polygon without inner rings
It is therefore streamed as a polygon
*/
template <typename Ring>
-struct wkt<ring_tag, Ring>
+struct wkt<Ring, ring_tag>
: detail::wkt::wkt_range
<
Ring,
@@ -304,7 +358,7 @@ struct wkt<ring_tag, Ring>
\brief Specialization to stream polygon as WKT
*/
template <typename Polygon>
-struct wkt<polygon_tag, Polygon>
+struct wkt<Polygon, polygon_tag>
: detail::wkt::wkt_poly
<
Polygon,
@@ -312,6 +366,88 @@ struct wkt<polygon_tag, Polygon>
>
{};
+template <typename Multi>
+struct wkt<Multi, multi_point_tag>
+ : detail::wkt::wkt_multi
+ <
+ Multi,
+ detail::wkt::wkt_point
+ <
+ typename boost::range_value<Multi>::type,
+ detail::wkt::prefix_null
+ >,
+ detail::wkt::prefix_multipoint
+ >
+{};
+
+template <typename Multi>
+struct wkt<Multi, multi_linestring_tag>
+ : detail::wkt::wkt_multi
+ <
+ Multi,
+ detail::wkt::wkt_sequence
+ <
+ typename boost::range_value<Multi>::type
+ >,
+ detail::wkt::prefix_multilinestring
+ >
+{};
+
+template <typename Multi>
+struct wkt<Multi, multi_polygon_tag>
+ : detail::wkt::wkt_multi
+ <
+ Multi,
+ detail::wkt::wkt_poly
+ <
+ typename boost::range_value<Multi>::type,
+ detail::wkt::prefix_null
+ >,
+ detail::wkt::prefix_multipolygon
+ >
+{};
+
+
+template <typename Geometry>
+struct devarianted_wkt
+{
+ template <typename OutputStream>
+ static inline void apply(OutputStream& os, Geometry const& geometry)
+ {
+ wkt<Geometry>::apply(os, geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename OutputStream>
+ struct visitor: static_visitor<void>
+ {
+ OutputStream& m_os;
+
+ visitor(OutputStream& os)
+ : m_os(os)
+ {}
+
+ template <typename Geometry>
+ inline void operator()(Geometry const& geometry) const
+ {
+ devarianted_wkt<Geometry>::apply(m_os, geometry);
+ }
+ };
+
+ template <typename OutputStream>
+ static inline void apply(
+ OutputStream& os,
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
+ )
+ {
+ apply_visitor(visitor<OutputStream>(os), geometry);
+ }
+};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -340,11 +476,7 @@ public:
std::basic_ostream<Char, Traits>& os,
wkt_manipulator const& m)
{
- dispatch::wkt
- <
- typename tag<Geometry>::type,
- Geometry
- >::apply(os, m.m_geometry);
+ dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
os.flush();
return os;
}
@@ -355,13 +487,10 @@ private:
/*!
\brief Main WKT-streaming function
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
\ingroup wkt
-\par Example:
-Small example showing how to use the wkt helper function
-\dontinclude doxygen_1.cpp
-\skip example_as_wkt_vector
-\line {
-\until }
+\qbk{[include reference/io/wkt.qbk]}
*/
template <typename Geometry>
inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
@@ -371,6 +500,10 @@ inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
return wkt_manipulator<Geometry>(geometry);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP
diff --git a/boost/geometry/iterators/closing_iterator.hpp b/boost/geometry/iterators/closing_iterator.hpp
index 7cd8fa0150..a9f67d4788 100644
--- a/boost/geometry/iterators/closing_iterator.hpp
+++ b/boost/geometry/iterators/closing_iterator.hpp
@@ -28,8 +28,9 @@ namespace boost { namespace geometry
\brief Iterator which iterates through a range, but adds first element at end of the range
\tparam Range range on which this class is based on
\ingroup iterators
-\note Use with "closing_iterator<Range> or "closing_iterator<Range const>
- to get non-const / const behaviour
+\note It's const iterator treating the Range as one containing non-mutable elements.
+ For both "closing_iterator<Range> and "closing_iterator<Range const>
+ const reference is always returned when dereferenced.
\note This class is normally used from "closeable_view" if Close==true
*/
template <typename Range>
diff --git a/boost/geometry/iterators/concatenate_iterator.hpp b/boost/geometry/iterators/concatenate_iterator.hpp
new file mode 100644
index 0000000000..20112b4c4c
--- /dev/null
+++ b/boost/geometry/iterators/concatenate_iterator.hpp
@@ -0,0 +1,184 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP
+
+#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/iterator.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator/iterator_categories.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+
+template
+<
+ typename Iterator1,
+ typename Iterator2,
+ typename Value,
+ typename Reference = Value&
+>
+class concatenate_iterator
+ : public boost::iterator_facade
+ <
+ concatenate_iterator<Iterator1, Iterator2, Value, Reference>,
+ Value,
+ boost::bidirectional_traversal_tag,
+ Reference
+ >
+{
+private:
+ Iterator1 m_it1, m_end1;
+ Iterator2 m_begin2, m_it2;
+
+public:
+ typedef Iterator1 first_iterator_type;
+ typedef Iterator2 second_iterator_type;
+
+ // default constructor
+ concatenate_iterator() {}
+
+ // for begin
+ concatenate_iterator(Iterator1 it1, Iterator1 end1,
+ Iterator2 begin2, Iterator2 it2)
+ : m_it1(it1), m_end1(end1), m_begin2(begin2), m_it2(it2)
+ {}
+
+ // for end
+ concatenate_iterator(Iterator1 end1, Iterator2 begin2, Iterator2 end2)
+ : m_it1(end1), m_end1(end1), m_begin2(begin2), m_it2(end2)
+ {}
+
+ template
+ <
+ typename OtherIt1,
+ typename OtherIt2,
+ typename OtherValue,
+ typename OtherReference
+ >
+ concatenate_iterator(concatenate_iterator
+ <
+ OtherIt1,
+ OtherIt2,
+ OtherValue,
+ OtherReference
+ > const& other)
+ : m_it1(other.m_it1)
+ , m_end1(other.m_end1)
+ , m_begin2(other.m_begin2)
+ , m_it2(other.m_it2)
+ {
+ static const bool are_conv
+ = boost::is_convertible<OtherIt1, Iterator1>::value
+ && boost::is_convertible<OtherIt2, Iterator2>::value;
+
+ BOOST_MPL_ASSERT_MSG((are_conv),
+ NOT_CONVERTIBLE,
+ (types<OtherIt1, OtherIt2>));
+ }
+
+ template
+ <
+ typename OtherIt1,
+ typename OtherIt2,
+ typename OtherValue,
+ typename OtherReference
+ >
+ concatenate_iterator operator=(concatenate_iterator
+ <
+ OtherIt1,
+ OtherIt2,
+ OtherValue,
+ OtherReference
+ > const& other)
+ {
+ static const bool are_conv
+ = boost::is_convertible<OtherIt1, Iterator1>::value
+ && boost::is_convertible<OtherIt2, Iterator2>::value;
+
+ BOOST_MPL_ASSERT_MSG((are_conv),
+ NOT_CONVERTIBLE,
+ (types<OtherIt1, OtherIt2>));
+
+ m_it1 = other.m_it1;
+ m_end1 = other.m_end1;
+ m_begin2 = other.m_begin2;
+ m_it2 = other.m_it2;
+ return *this;
+ }
+
+private:
+ friend class boost::iterator_core_access;
+
+ template <typename It1, typename It2, typename V, typename R>
+ friend class concatenate_iterator;
+
+ inline Reference dereference() const
+ {
+ if ( m_it1 == m_end1 )
+ {
+ return *m_it2;
+ }
+ return *m_it1;
+ }
+
+ template
+ <
+ typename OtherIt1,
+ typename OtherIt2,
+ typename OtherValue,
+ typename OtherReference
+ >
+ inline bool equal(concatenate_iterator
+ <
+ OtherIt1,
+ OtherIt2,
+ OtherValue,
+ OtherReference
+ > const& other) const
+ {
+ return m_it1 == other.m_it1 && m_it2 == other.m_it2;
+ }
+
+ inline void increment()
+ {
+ if ( m_it1 == m_end1 )
+ {
+ ++m_it2;
+ }
+ else
+ {
+ ++m_it1;
+ }
+ }
+
+ inline void decrement()
+ {
+ if ( m_it2 == m_begin2 )
+ {
+ --m_it1;
+ }
+ else
+ {
+ --m_it2;
+ }
+ }
+};
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP
diff --git a/boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp b/boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp
new file mode 100644
index 0000000000..b2239fb8dd
--- /dev/null
+++ b/boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp
@@ -0,0 +1,66 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_INNER_RANGE_TYPE_HPP
+#define BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_INNER_RANGE_TYPE_HPP
+
+#include <boost/range.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <boost/mpl/if.hpp>
+
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace point_iterator
+{
+
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct inner_range_type
+{
+ typedef typename boost::mpl::if_c
+ <
+ !boost::is_const<Geometry>::type::value,
+ typename boost::range_value<Geometry>::type,
+ typename boost::range_value<Geometry>::type const
+ >::type type;
+};
+
+
+template <typename Polygon>
+struct inner_range_type<Polygon, polygon_tag>
+{
+ typedef typename boost::mpl::if_c
+ <
+ !boost::is_const<Polygon>::type::value,
+ typename geometry::ring_type<Polygon>::type,
+ typename geometry::ring_type<Polygon>::type const
+ >::type type;
+};
+
+
+}} // namespace detail::point_iterator
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_INNER_RANGE_TYPE_HPP
diff --git a/boost/geometry/iterators/detail/point_iterator/iterator_type.hpp b/boost/geometry/iterators/detail/point_iterator/iterator_type.hpp
new file mode 100644
index 0000000000..a7805b127b
--- /dev/null
+++ b/boost/geometry/iterators/detail/point_iterator/iterator_type.hpp
@@ -0,0 +1,136 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_ITERATOR_TYPE_HPP
+#define BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_ITERATOR_TYPE_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/iterators/flatten_iterator.hpp>
+#include <boost/geometry/iterators/concatenate_iterator.hpp>
+
+#include <boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp>
+#include <boost/geometry/iterators/detail/point_iterator/value_type.hpp>
+
+#include <boost/geometry/iterators/dispatch/point_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace point_iterator
+{
+
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct iterator_type
+ : not_implemented<Geometry>
+{};
+
+
+
+
+template <typename Linestring>
+struct iterator_type<Linestring, linestring_tag>
+{
+ typedef typename boost::range_iterator<Linestring>::type type;
+};
+
+
+template <typename Ring>
+struct iterator_type<Ring, ring_tag>
+{
+ typedef typename boost::range_iterator<Ring>::type type;
+};
+
+
+template <typename Polygon>
+class iterator_type<Polygon, polygon_tag>
+{
+private:
+ typedef typename inner_range_type<Polygon>::type inner_range;
+
+public:
+ typedef concatenate_iterator
+ <
+ typename boost::range_iterator<inner_range>::type,
+ flatten_iterator
+ <
+ typename boost::range_iterator
+ <
+ typename geometry::interior_type<Polygon>::type
+ >::type,
+ typename iterator_type<inner_range>::type,
+ typename value_type<Polygon>::type,
+ dispatch::points_begin<inner_range>,
+ dispatch::points_end<inner_range>
+ >,
+ typename value_type<Polygon>::type
+ > type;
+};
+
+
+template <typename MultiPoint>
+struct iterator_type<MultiPoint, multi_point_tag>
+{
+ typedef typename boost::range_iterator<MultiPoint>::type type;
+};
+
+
+template <typename MultiLinestring>
+class iterator_type<MultiLinestring, multi_linestring_tag>
+{
+private:
+ typedef typename inner_range_type<MultiLinestring>::type inner_range;
+
+public:
+ typedef flatten_iterator
+ <
+ typename boost::range_iterator<MultiLinestring>::type,
+ typename iterator_type<inner_range>::type,
+ typename value_type<MultiLinestring>::type,
+ dispatch::points_begin<inner_range>,
+ dispatch::points_end<inner_range>
+ > type;
+};
+
+
+template <typename MultiPolygon>
+class iterator_type<MultiPolygon, multi_polygon_tag>
+{
+private:
+ typedef typename inner_range_type<MultiPolygon>::type inner_range;
+
+public:
+ typedef flatten_iterator
+ <
+ typename boost::range_iterator<MultiPolygon>::type,
+ typename iterator_type<inner_range>::type,
+ typename value_type<MultiPolygon>::type,
+ dispatch::points_begin<inner_range>,
+ dispatch::points_end<inner_range>
+ > type;
+};
+
+
+}} // namespace detail::point_iterator
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_ITERATOR_TYPE_HPP
diff --git a/boost/geometry/iterators/detail/point_iterator/value_type.hpp b/boost/geometry/iterators/detail/point_iterator/value_type.hpp
new file mode 100644
index 0000000000..7cdf366391
--- /dev/null
+++ b/boost/geometry/iterators/detail/point_iterator/value_type.hpp
@@ -0,0 +1,47 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_VALUE_TYPE_HPP
+#define BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_VALUE_TYPE_HPP
+
+#include <boost/type_traits/is_const.hpp>
+#include <boost/mpl/if.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace point_iterator
+{
+
+
+template <typename Geometry>
+struct value_type
+{
+ typedef typename boost::mpl::if_c
+ <
+ !boost::is_const<Geometry>::type::value,
+ typename geometry::point_type<Geometry>::type,
+ typename geometry::point_type<Geometry>::type const
+ >::type type;
+};
+
+
+}} // namespace detail::point_iterator
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_POINT_ITERATOR_VALUE_TYPE_HPP
diff --git a/boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp b/boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp
new file mode 100644
index 0000000000..57a524e7e4
--- /dev/null
+++ b/boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp
@@ -0,0 +1,153 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_ITERATOR_TYPE_HPP
+#define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_ITERATOR_TYPE_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/interior_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/iterators/concatenate_iterator.hpp>
+#include <boost/geometry/iterators/flatten_iterator.hpp>
+#include <boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp>
+
+#include <boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp>
+#include <boost/geometry/iterators/detail/segment_iterator/value_type.hpp>
+
+#include <boost/geometry/iterators/dispatch/segment_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace segment_iterator
+{
+
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct iterator_type
+ : not_implemented<Geometry>
+{};
+
+
+template <typename Linestring>
+struct iterator_type<Linestring, linestring_tag>
+{
+ typedef range_segment_iterator
+ <
+ Linestring, typename value_type<Linestring>::type
+ > type;
+};
+
+
+template <typename Ring>
+struct iterator_type<Ring, ring_tag>
+{
+ typedef range_segment_iterator
+ <
+ Ring, typename value_type<Ring>::type
+ > type;
+};
+
+
+template <typename Polygon>
+class iterator_type<Polygon, polygon_tag>
+{
+private:
+ typedef typename detail::point_iterator::inner_range_type
+ <
+ Polygon
+ >::type inner_range;
+
+public:
+ typedef concatenate_iterator
+ <
+ range_segment_iterator
+ <
+ inner_range,
+ typename value_type<Polygon>::type
+ >,
+ flatten_iterator
+ <
+ typename boost::range_iterator
+ <
+ typename geometry::interior_type<Polygon>::type
+ >::type,
+ typename iterator_type<inner_range>::type,
+ typename value_type<Polygon>::type,
+ dispatch::segments_begin<inner_range>,
+ dispatch::segments_end<inner_range>,
+ typename value_type<Polygon>::type
+ >,
+ typename value_type<Polygon>::type,
+ typename value_type<Polygon>::type
+ > type;
+};
+
+
+template <typename MultiLinestring>
+class iterator_type<MultiLinestring, multi_linestring_tag>
+{
+private:
+ typedef typename detail::point_iterator::inner_range_type
+ <
+ MultiLinestring
+ >::type inner_range;
+
+public:
+ typedef flatten_iterator
+ <
+ typename boost::range_iterator<MultiLinestring>::type,
+ typename iterator_type<inner_range>::type,
+ typename value_type<MultiLinestring>::type,
+ dispatch::segments_begin<inner_range>,
+ dispatch::segments_end<inner_range>,
+ typename value_type<MultiLinestring>::type
+ > type;
+};
+
+
+template <typename MultiPolygon>
+class iterator_type<MultiPolygon, multi_polygon_tag>
+{
+private:
+ typedef typename detail::point_iterator::inner_range_type
+ <
+ MultiPolygon
+ >::type inner_range;
+public:
+ typedef flatten_iterator
+ <
+ typename boost::range_iterator<MultiPolygon>::type,
+ typename iterator_type<inner_range>::type,
+ typename value_type<MultiPolygon>::type,
+ dispatch::segments_begin<inner_range>,
+ dispatch::segments_end<inner_range>,
+ typename value_type<MultiPolygon>::type
+ > type;
+};
+
+
+
+}} // namespace detail::segment_iterator
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_ITERATOR_TYPE_HPP
diff --git a/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp b/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp
new file mode 100644
index 0000000000..d79fda84d9
--- /dev/null
+++ b/boost/geometry/iterators/detail/segment_iterator/range_segment_iterator.hpp
@@ -0,0 +1,223 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP
+
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/iterator.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator/iterator_categories.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/iterators/closing_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace segment_iterator
+{
+
+
+template <typename Range, closure_selector Closure = closure<Range>::value>
+struct range_iterator_type
+{
+ typedef typename boost::range_iterator<Range>::type type;
+};
+
+template <typename Range>
+struct range_iterator_type<Range, open>
+{
+ typedef closing_iterator<Range> type;
+};
+
+
+
+template <typename Range, closure_selector Closure = closure<Range>::value>
+struct range_iterator_begin
+{
+ static inline typename range_iterator_type<Range, Closure>::type
+ apply(Range& range)
+ {
+ return boost::begin(range);
+ }
+};
+
+template <typename Range>
+struct range_iterator_begin<Range, open>
+{
+ static inline typename range_iterator_type<Range, open>::type
+ apply(Range& range)
+ {
+ return closing_iterator<Range>(range);
+ }
+};
+
+
+
+template <typename Range, closure_selector Closure = closure<Range>::value>
+struct range_iterator_end
+{
+ static inline typename range_iterator_type<Range, Closure>::type
+ apply(Range& range)
+ {
+ return boost::end(range);
+ }
+};
+
+template <typename Range>
+struct range_iterator_end<Range, open>
+{
+ static inline typename range_iterator_type<Range, open>::type
+ apply(Range& range)
+ {
+ return closing_iterator<Range>(range, true);
+ }
+};
+
+
+
+
+
+
+template <typename Range, typename Value, typename Reference = Value>
+class range_segment_iterator
+ : public boost::iterator_facade
+ <
+ range_segment_iterator<Range, Value, Reference>,
+ Value,
+ boost::bidirectional_traversal_tag,
+ Reference
+ >
+{
+public:
+ typedef typename range_iterator_type<Range>::type iterator_type;
+
+ // default constructor
+ range_segment_iterator()
+ : m_it()
+ {}
+
+ // for begin
+ range_segment_iterator(Range& r)
+ : m_it(range_iterator_begin<Range>::apply(r))
+ {}
+
+ // for end
+ range_segment_iterator(Range& r, bool)
+ : m_it(--range_iterator_end<Range>::apply(r))
+ {}
+
+ template
+ <
+ typename OtherRange,
+ typename OtherValue,
+ typename OtherReference
+ >
+ range_segment_iterator(range_segment_iterator
+ <
+ OtherRange,
+ OtherValue,
+ OtherReference
+ > const& other)
+ : m_it(other.m_it)
+ {
+ typedef typename range_segment_iterator
+ <
+ OtherRange, OtherValue, OtherReference
+ >::iterator_type other_iterator_type;
+
+ static const bool are_conv
+ = boost::is_convertible<other_iterator_type, iterator_type>::value;
+
+ BOOST_MPL_ASSERT_MSG((are_conv), NOT_CONVERTIBLE, (types<OtherRange>));
+ }
+
+ template
+ <
+ typename OtherRange,
+ typename OtherValue,
+ typename OtherReference
+ >
+ range_segment_iterator operator=(range_segment_iterator
+ <
+ OtherRange,
+ OtherValue,
+ OtherReference
+ > const& other)
+ {
+ typedef typename range_segment_iterator
+ <
+ OtherRange, OtherValue, OtherReference
+ >::iterator_type other_iterator_type;
+
+ static const bool are_conv
+ = boost::is_convertible<other_iterator_type, iterator_type>::value;
+
+ BOOST_MPL_ASSERT_MSG((are_conv), NOT_CONVERTIBLE, (types<OtherRange>));
+
+ m_it = other.m_it;
+ return *this;
+ }
+
+private:
+ friend class boost::iterator_core_access;
+
+ template <typename Rng, typename V, typename R>
+ friend class range_segment_iterator;
+
+ inline Reference dereference() const
+ {
+ iterator_type next(m_it);
+ ++next;
+ return Reference(*m_it, *next);
+ }
+
+ template
+ <
+ typename OtherRange,
+ typename OtherValue,
+ typename OtherReference
+ >
+ inline bool equal(range_segment_iterator
+ <
+ OtherRange,
+ OtherValue,
+ OtherReference
+ > const& other) const
+ {
+ return m_it == other.m_it;
+ }
+
+ inline void increment()
+ {
+ ++m_it;
+ }
+
+ inline void decrement()
+ {
+ --m_it;
+ }
+
+private:
+ iterator_type m_it;
+};
+
+
+}} // namespace detail::segment_iterator
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_RANGE_SEGMENT_ITERATOR_HPP
diff --git a/boost/geometry/iterators/detail/segment_iterator/value_type.hpp b/boost/geometry/iterators/detail/segment_iterator/value_type.hpp
new file mode 100644
index 0000000000..0b3c66670c
--- /dev/null
+++ b/boost/geometry/iterators/detail/segment_iterator/value_type.hpp
@@ -0,0 +1,43 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_VALUE_TYPE_HPP
+#define BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_VALUE_TYPE_HPP
+
+#include <boost/geometry/iterators/detail/point_iterator/value_type.hpp>
+#include <boost/geometry/geometries/pointing_segment.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace segment_iterator
+{
+
+template <typename Geometry>
+struct value_type
+{
+ typedef typename detail::point_iterator::value_type
+ <
+ Geometry
+ >::type point_iterator_value_type;
+
+ typedef geometry::model::pointing_segment
+ <
+ point_iterator_value_type
+ > type;
+};
+
+}} // namespace detail::segment_iterator
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ITERATORS_DETAIL_SEGMENT_ITERATOR_VALUE_TYPE_HPP
diff --git a/boost/geometry/iterators/dispatch/point_iterator.hpp b/boost/geometry/iterators/dispatch/point_iterator.hpp
new file mode 100644
index 0000000000..938dfd8ebc
--- /dev/null
+++ b/boost/geometry/iterators/dispatch/point_iterator.hpp
@@ -0,0 +1,47 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// dispatch for points_begin
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct points_begin
+ : not_implemented<Geometry>
+{};
+
+
+
+// dispatch for points_end
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct points_end
+ : not_implemented<Geometry>
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP
diff --git a/boost/geometry/iterators/dispatch/segment_iterator.hpp b/boost/geometry/iterators/dispatch/segment_iterator.hpp
new file mode 100644
index 0000000000..0c0a1b09a7
--- /dev/null
+++ b/boost/geometry/iterators/dispatch/segment_iterator.hpp
@@ -0,0 +1,47 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_DISPATCH_SEGMENT_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_DISPATCH_SEGMENT_ITERATOR_HPP
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// dispatch for segments_begin
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct segments_begin
+ : not_implemented<Geometry>
+{};
+
+
+
+// dispatch for segments_end
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct segments_end
+ : not_implemented<Geometry>
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ITERATORS_DISPATCH_SEGMENT_ITERATOR_HPP
diff --git a/boost/geometry/iterators/ever_circling_iterator.hpp b/boost/geometry/iterators/ever_circling_iterator.hpp
index 566669e26d..50b20480cd 100644
--- a/boost/geometry/iterators/ever_circling_iterator.hpp
+++ b/boost/geometry/iterators/ever_circling_iterator.hpp
@@ -177,7 +177,7 @@ private:
inline void advance(difference_type n)
{
- if (m_index >= 0 && m_index < m_size
+ if (m_index >= 0 && m_index < m_size
&& m_index + n >= 0 && m_index + n < m_size)
{
m_index += n;
@@ -196,7 +196,7 @@ private:
{
m_index += m_size;
}
- m_index = m_index % m_size;
+ m_index = m_index % m_size;
this->m_iterator = boost::begin(*m_range) + m_index;
}
diff --git a/boost/geometry/iterators/flatten_iterator.hpp b/boost/geometry/iterators/flatten_iterator.hpp
new file mode 100644
index 0000000000..078079dc2c
--- /dev/null
+++ b/boost/geometry/iterators/flatten_iterator.hpp
@@ -0,0 +1,259 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
+
+#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/iterator.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator/iterator_categories.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+
+template
+<
+ typename OuterIterator,
+ typename InnerIterator,
+ typename Value,
+ typename AccessInnerBegin,
+ typename AccessInnerEnd,
+ typename Reference = Value&
+>
+class flatten_iterator
+ : public boost::iterator_facade
+ <
+ flatten_iterator
+ <
+ OuterIterator,
+ InnerIterator,
+ Value,
+ AccessInnerBegin,
+ AccessInnerEnd,
+ Reference
+ >,
+ Value,
+ boost::bidirectional_traversal_tag,
+ Reference
+ >
+{
+private:
+ OuterIterator m_outer_it, m_outer_end;
+ InnerIterator m_inner_it;
+
+public:
+ typedef OuterIterator outer_iterator_type;
+ typedef InnerIterator inner_iterator_type;
+
+ // default constructor
+ flatten_iterator() {}
+
+ // for begin
+ flatten_iterator(OuterIterator outer_it, OuterIterator outer_end)
+ : m_outer_it(outer_it), m_outer_end(outer_end)
+ {
+ advance_through_empty();
+ }
+
+ // for end
+ flatten_iterator(OuterIterator outer_end)
+ : m_outer_it(outer_end), m_outer_end(outer_end)
+ {}
+
+ template
+ <
+ typename OtherOuterIterator, typename OtherInnerIterator,
+ typename OtherValue,
+ typename OtherAccessInnerBegin, typename OtherAccessInnerEnd,
+ typename OtherReference
+ >
+ flatten_iterator(flatten_iterator
+ <
+ OtherOuterIterator,
+ OtherInnerIterator,
+ OtherValue,
+ OtherAccessInnerBegin,
+ OtherAccessInnerEnd,
+ OtherReference
+ > const& other)
+ : m_outer_it(other.m_outer_it),
+ m_outer_end(other.m_outer_end),
+ m_inner_it(other.m_inner_it)
+ {
+ static const bool are_conv
+ = boost::is_convertible
+ <
+ OtherOuterIterator, OuterIterator
+ >::value
+ && boost::is_convertible
+ <
+ OtherInnerIterator, InnerIterator
+ >::value;
+
+ BOOST_MPL_ASSERT_MSG((are_conv),
+ NOT_CONVERTIBLE,
+ (types<OtherOuterIterator, OtherInnerIterator>));
+ }
+
+ template
+ <
+ typename OtherOuterIterator,
+ typename OtherInnerIterator,
+ typename OtherValue,
+ typename OtherAccessInnerBegin,
+ typename OtherAccessInnerEnd,
+ typename OtherReference
+ >
+ flatten_iterator operator=(flatten_iterator
+ <
+ OtherOuterIterator,
+ OtherInnerIterator,
+ OtherValue,
+ OtherAccessInnerBegin,
+ OtherAccessInnerEnd,
+ OtherReference
+ > const& other)
+ {
+ static const bool are_conv
+ = boost::is_convertible
+ <
+ OtherOuterIterator, OuterIterator
+ >::value
+ && boost::is_convertible
+ <
+ OtherInnerIterator, InnerIterator
+ >::value;
+
+ BOOST_MPL_ASSERT_MSG((are_conv),
+ NOT_CONVERTIBLE,
+ (types<OtherOuterIterator, OtherInnerIterator>));
+
+ m_outer_it = other.m_outer_it;
+ m_outer_end = other.m_outer_end;
+ m_inner_it = other.m_inner_it;
+ return *this;
+ }
+
+private:
+ friend class boost::iterator_core_access;
+
+ template
+ <
+ typename Outer,
+ typename Inner,
+ typename V,
+ typename InnerBegin,
+ typename InnerEnd,
+ typename R
+ >
+ friend class flatten_iterator;
+
+ static inline bool empty(OuterIterator outer_it)
+ {
+ return
+ AccessInnerBegin::apply(*outer_it) == AccessInnerEnd::apply(*outer_it);
+ }
+
+ inline void advance_through_empty()
+ {
+ while ( m_outer_it != m_outer_end && empty(m_outer_it) )
+ {
+ ++m_outer_it;
+ }
+
+ if ( m_outer_it != m_outer_end )
+ {
+ m_inner_it = AccessInnerBegin::apply(*m_outer_it);
+ }
+ }
+
+ inline Reference dereference() const
+ {
+ BOOST_ASSERT( m_outer_it != m_outer_end );
+ BOOST_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) );
+ return *m_inner_it;
+ }
+
+
+ template
+ <
+ typename OtherOuterIterator,
+ typename OtherInnerIterator,
+ typename OtherValue,
+ typename OtherAccessInnerBegin,
+ typename OtherAccessInnerEnd,
+ typename OtherReference
+ >
+ inline bool equal(flatten_iterator
+ <
+ OtherOuterIterator,
+ OtherInnerIterator,
+ OtherValue,
+ OtherAccessInnerBegin,
+ OtherAccessInnerEnd,
+ OtherReference
+ > const& other) const
+ {
+ if ( m_outer_it != other.m_outer_it )
+ {
+ return false;
+ }
+
+ if ( m_outer_it == m_outer_end )
+ {
+ return true;
+ }
+
+ return m_inner_it == other.m_inner_it;
+ }
+
+ inline void increment()
+ {
+ BOOST_ASSERT( m_outer_it != m_outer_end );
+ BOOST_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) );
+
+ ++m_inner_it;
+ if ( m_inner_it == AccessInnerEnd::apply(*m_outer_it) )
+ {
+ ++m_outer_it;
+ advance_through_empty();
+ }
+ }
+
+ inline void decrement()
+ {
+ if ( m_outer_it == m_outer_end
+ || m_inner_it == AccessInnerBegin::apply(*m_outer_it) )
+ {
+ do
+ {
+ --m_outer_it;
+ }
+ while ( empty(m_outer_it) );
+ m_inner_it = --AccessInnerEnd::apply(*m_outer_it);
+ }
+ else
+ {
+ --m_inner_it;
+ }
+ }
+};
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
diff --git a/boost/geometry/iterators/has_one_element.hpp b/boost/geometry/iterators/has_one_element.hpp
new file mode 100644
index 0000000000..2f9acefc1e
--- /dev/null
+++ b/boost/geometry/iterators/has_one_element.hpp
@@ -0,0 +1,29 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_HAS_ONE_ELEMENT_HPP
+#define BOOST_GEOMETRY_ITERATORS_HAS_ONE_ELEMENT_HPP
+
+
+namespace boost { namespace geometry
+{
+
+
+// free function to test if an iterator range has a single element
+template <typename Iterator>
+inline bool has_one_element(Iterator first, Iterator beyond)
+{
+ return first != beyond && ++first == beyond;
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ITERATORS_HAS_ONE_ELEMENT_HPP
diff --git a/boost/geometry/iterators/point_iterator.hpp b/boost/geometry/iterators/point_iterator.hpp
new file mode 100644
index 0000000000..075339aa58
--- /dev/null
+++ b/boost/geometry/iterators/point_iterator.hpp
@@ -0,0 +1,315 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP
+
+#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/iterators/dispatch/point_iterator.hpp>
+#include <boost/geometry/iterators/detail/point_iterator/iterator_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// specializations for points_begin
+
+
+template <typename Linestring>
+struct points_begin<Linestring, linestring_tag>
+{
+ static inline typename detail::point_iterator::iterator_type
+ <
+ Linestring
+ >::type
+ apply(Linestring& linestring)
+ {
+ return boost::begin(linestring);
+ }
+};
+
+
+template <typename Ring>
+struct points_begin<Ring, ring_tag>
+{
+ static inline typename detail::point_iterator::iterator_type<Ring>::type
+ apply(Ring& ring)
+ {
+ return boost::begin(ring);
+ }
+};
+
+
+template <typename Polygon>
+struct points_begin<Polygon, polygon_tag>
+{
+ typedef typename detail::point_iterator::iterator_type
+ <
+ Polygon
+ >::type return_type;
+
+ static inline return_type apply(Polygon& polygon)
+ {
+ typedef typename return_type::second_iterator_type flatten_iterator;
+
+ return return_type
+ (boost::begin(geometry::exterior_ring(polygon)),
+ boost::end(geometry::exterior_ring(polygon)),
+ flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
+ boost::end(geometry::interior_rings(polygon))
+ ),
+ flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
+ boost::end(geometry::interior_rings(polygon))
+ )
+ );
+ }
+};
+
+
+template <typename MultiPoint>
+struct points_begin<MultiPoint, multi_point_tag>
+{
+ static inline typename detail::point_iterator::iterator_type
+ <
+ MultiPoint
+ >::type
+ apply(MultiPoint& multipoint)
+ {
+ return boost::begin(multipoint);
+ }
+};
+
+
+template <typename MultiLinestring>
+struct points_begin<MultiLinestring, multi_linestring_tag>
+{
+ typedef typename detail::point_iterator::iterator_type
+ <
+ MultiLinestring
+ >::type return_type;
+
+ static inline return_type apply(MultiLinestring& multilinestring)
+ {
+ return return_type(boost::begin(multilinestring),
+ boost::end(multilinestring));
+ }
+};
+
+
+template <typename MultiPolygon>
+struct points_begin<MultiPolygon, multi_polygon_tag>
+{
+ typedef typename detail::point_iterator::iterator_type
+ <
+ MultiPolygon
+ >::type return_type;
+
+ static inline return_type apply(MultiPolygon& multipolygon)
+ {
+ return return_type(boost::begin(multipolygon),
+ boost::end(multipolygon));
+ }
+};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// specializations for points_end
+
+
+template <typename Linestring>
+struct points_end<Linestring, linestring_tag>
+{
+ static inline typename detail::point_iterator::iterator_type
+ <
+ Linestring
+ >::type
+ apply(Linestring& linestring)
+ {
+ return boost::end(linestring);
+ }
+};
+
+
+template <typename Ring>
+struct points_end<Ring, ring_tag>
+{
+ static inline typename detail::point_iterator::iterator_type<Ring>::type
+ apply(Ring& ring)
+ {
+ return boost::end(ring);
+ }
+};
+
+
+template <typename Polygon>
+struct points_end<Polygon, polygon_tag>
+{
+ typedef typename detail::point_iterator::iterator_type
+ <
+ Polygon
+ >::type return_type;
+
+ static inline return_type apply(Polygon& polygon)
+ {
+ typedef typename return_type::second_iterator_type flatten_iterator;
+
+ return return_type
+ (boost::end(geometry::exterior_ring(polygon)),
+ flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
+ boost::end(geometry::interior_rings(polygon))
+ ),
+ flatten_iterator( boost::end(geometry::interior_rings(polygon)) )
+ );
+ }
+};
+
+
+template <typename MultiPoint>
+struct points_end<MultiPoint, multi_point_tag>
+{
+ static inline typename detail::point_iterator::iterator_type
+ <
+ MultiPoint
+ >::type
+ apply(MultiPoint& multipoint)
+ {
+ return boost::end(multipoint);
+ }
+};
+
+
+template <typename MultiLinestring>
+struct points_end<MultiLinestring, multi_linestring_tag>
+{
+ typedef typename detail::point_iterator::iterator_type
+ <
+ MultiLinestring
+ >::type return_type;
+
+ static inline return_type apply(MultiLinestring& multilinestring)
+ {
+ return return_type(boost::end(multilinestring));
+ }
+};
+
+
+template <typename MultiPolygon>
+struct points_end<MultiPolygon, multi_polygon_tag>
+{
+ typedef typename detail::point_iterator::iterator_type
+ <
+ MultiPolygon
+ >::type return_type;
+
+ static inline return_type apply(MultiPolygon& multipolygon)
+ {
+ return return_type(boost::end(multipolygon));
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+class point_iterator
+ : public detail::point_iterator::iterator_type<Geometry>::type
+{
+private:
+ typedef typename detail::point_iterator::iterator_type<Geometry>::type base;
+
+ inline base* base_ptr()
+ {
+ return this;
+ }
+
+ inline base const* base_ptr() const
+ {
+ return this;
+ }
+
+ template <typename OtherGeometry> friend class point_iterator;
+ template <typename G> friend inline point_iterator<G> points_begin(G&);
+ template <typename G> friend inline point_iterator<G> points_end(G&);
+
+ inline point_iterator(base const& base_it) : base(base_it) {}
+
+public:
+ inline point_iterator() {}
+
+ template <typename OtherGeometry>
+ inline point_iterator(point_iterator<OtherGeometry> const& other)
+ : base(*other.base_ptr())
+ {
+ static const bool is_conv
+ = boost::is_convertible<
+ typename detail::point_iterator::iterator_type
+ <
+ OtherGeometry
+ >::type,
+ typename detail::point_iterator::iterator_type
+ <
+ Geometry
+ >::type
+ >::value;
+
+ BOOST_MPL_ASSERT_MSG((is_conv),
+ NOT_CONVERTIBLE,
+ (point_iterator<OtherGeometry>));
+ }
+};
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+inline point_iterator<Geometry>
+points_begin(Geometry& geometry)
+{
+ return dispatch::points_begin<Geometry>::apply(geometry);
+}
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+inline point_iterator<Geometry>
+points_end(Geometry& geometry)
+{
+ return dispatch::points_end<Geometry>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP
diff --git a/boost/geometry/iterators/point_reverse_iterator.hpp b/boost/geometry/iterators/point_reverse_iterator.hpp
new file mode 100644
index 0000000000..1c2ac0169d
--- /dev/null
+++ b/boost/geometry/iterators/point_reverse_iterator.hpp
@@ -0,0 +1,98 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_POINT_REVERSE_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_POINT_REVERSE_ITERATOR_HPP
+
+#include <iterator>
+
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+class point_reverse_iterator
+ : public std::reverse_iterator<point_iterator<Geometry> >
+{
+private:
+ typedef std::reverse_iterator<point_iterator<Geometry> > base;
+
+ inline base* base_ptr()
+ {
+ return this;
+ }
+
+ inline base const* base_ptr() const
+ {
+ return this;
+ }
+
+ template <typename OtherGeometry> friend class point_reverse_iterator;
+ template <typename G>
+ friend inline point_reverse_iterator<G> points_rbegin(G&);
+
+ template <typename G>
+ friend inline point_reverse_iterator<G> points_rend(G&);
+
+ inline point_reverse_iterator(base const& base_it) : base(base_it) {}
+
+public:
+ inline point_reverse_iterator() {}
+
+ template <typename OtherGeometry>
+ inline
+ point_reverse_iterator(point_reverse_iterator<OtherGeometry> const& other)
+ : base(*other.base_ptr())
+ {
+ static const bool is_conv = boost::is_convertible
+ <
+ std::reverse_iterator<point_iterator<Geometry> >,
+ std::reverse_iterator<point_iterator<OtherGeometry> >
+ >::value;
+
+ BOOST_MPL_ASSERT_MSG((is_conv),
+ NOT_CONVERTIBLE,
+ (point_reverse_iterator<OtherGeometry>));
+ }
+};
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+inline point_reverse_iterator<Geometry>
+points_rbegin(Geometry& geometry)
+{
+ return std::reverse_iterator
+ <
+ point_iterator<Geometry>
+ >(points_end(geometry));
+}
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+inline point_reverse_iterator<Geometry>
+points_rend(Geometry& geometry)
+{
+ return std::reverse_iterator
+ <
+ point_iterator<Geometry>
+ >(points_begin(geometry));
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ITERATORS_POINT_REVERSE_ITERATOR_HPP
diff --git a/boost/geometry/iterators/segment_iterator.hpp b/boost/geometry/iterators/segment_iterator.hpp
new file mode 100644
index 0000000000..206d7fc503
--- /dev/null
+++ b/boost/geometry/iterators/segment_iterator.hpp
@@ -0,0 +1,317 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP
+#define BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP
+
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp>
+#include <boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp>
+
+#include <boost/geometry/iterators/dispatch/segment_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// specializations for segments_begin
+
+
+template <typename Linestring>
+struct segments_begin<Linestring, linestring_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ Linestring
+ >::type return_type;
+
+ static inline return_type apply(Linestring& linestring)
+ {
+ return return_type(linestring);
+ }
+};
+
+
+template <typename Ring>
+struct segments_begin<Ring, ring_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ Ring
+ >::type return_type;
+
+ static inline return_type apply(Ring& ring)
+ {
+ return return_type(ring);
+ }
+};
+
+
+template <typename Polygon>
+struct segments_begin<Polygon, polygon_tag>
+{
+ typedef typename detail::point_iterator::inner_range_type
+ <
+ Polygon
+ >::type inner_range;
+
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ Polygon
+ >::type return_type;
+
+ static inline return_type apply(Polygon& polygon)
+ {
+ typedef typename return_type::second_iterator_type flatten_iterator;
+
+ return return_type
+ (segments_begin
+ <
+ inner_range
+ >::apply(geometry::exterior_ring(polygon)),
+ segments_end
+ <
+ inner_range
+ >::apply(geometry::exterior_ring(polygon)),
+ flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
+ boost::end(geometry::interior_rings(polygon))
+ ),
+ flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
+ boost::end(geometry::interior_rings(polygon))
+ )
+ );
+ }
+};
+
+
+template <typename MultiLinestring>
+struct segments_begin<MultiLinestring, multi_linestring_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ MultiLinestring
+ >::type return_type;
+
+ static inline return_type apply(MultiLinestring& multilinestring)
+ {
+ return return_type(boost::begin(multilinestring),
+ boost::end(multilinestring));
+ }
+};
+
+
+template <typename MultiPolygon>
+struct segments_begin<MultiPolygon, multi_polygon_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ MultiPolygon
+ >::type return_type;
+
+ static inline return_type apply(MultiPolygon& multipolygon)
+ {
+ return return_type(boost::begin(multipolygon),
+ boost::end(multipolygon));
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// specializations for segments_end
+
+
+template <typename Linestring>
+struct segments_end<Linestring, linestring_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ Linestring
+ >::type return_type;
+
+ static inline return_type apply(Linestring& linestring)
+ {
+ return return_type(linestring, true);
+ }
+};
+
+
+template <typename Ring>
+struct segments_end<Ring, ring_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ Ring
+ >::type return_type;
+
+ static inline return_type apply(Ring& ring)
+ {
+ return return_type(ring, true);
+ }
+};
+
+
+template <typename Polygon>
+struct segments_end<Polygon, polygon_tag>
+{
+ typedef typename detail::point_iterator::inner_range_type
+ <
+ Polygon
+ >::type inner_range;
+
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ Polygon
+ >::type return_type;
+
+ static inline return_type apply(Polygon& polygon)
+ {
+ typedef typename return_type::second_iterator_type flatten_iterator;
+
+ return return_type
+ (segments_end
+ <
+ inner_range
+ >::apply(geometry::exterior_ring(polygon)),
+ flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
+ boost::end(geometry::interior_rings(polygon))
+ ),
+ flatten_iterator( boost::end(geometry::interior_rings(polygon)) )
+ );
+ }
+};
+
+
+template <typename MultiLinestring>
+struct segments_end<MultiLinestring, multi_linestring_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ MultiLinestring
+ >::type return_type;
+
+ static inline return_type apply(MultiLinestring& multilinestring)
+ {
+ return return_type(boost::end(multilinestring));
+ }
+};
+
+
+template <typename MultiPolygon>
+struct segments_end<MultiPolygon, multi_polygon_tag>
+{
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ MultiPolygon
+ >::type return_type;
+
+ static inline return_type apply(MultiPolygon& multipolygon)
+ {
+ return return_type(boost::end(multipolygon));
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+class segment_iterator
+ : public detail::segment_iterator::iterator_type<Geometry>::type
+{
+private:
+ typedef typename detail::segment_iterator::iterator_type
+ <
+ Geometry
+ >::type base;
+
+ inline base const* base_ptr() const
+ {
+ return this;
+ }
+
+ template <typename OtherGeometry> friend class segment_iterator;
+
+ template <typename G>
+ friend inline segment_iterator<G const> segments_begin(G const&);
+
+ template <typename G>
+ friend inline segment_iterator<G const> segments_end(G const&);
+
+ inline segment_iterator(base const& base_it) : base(base_it) {}
+
+public:
+ inline segment_iterator() {}
+
+ template <typename OtherGeometry>
+ inline segment_iterator(segment_iterator<OtherGeometry> const& other)
+ : base(*other.base_ptr())
+ {
+ static const bool is_conv
+ = boost::is_convertible<
+ typename detail::segment_iterator::iterator_type
+ <
+ OtherGeometry
+ >::type,
+ typename detail::segment_iterator::iterator_type<Geometry>::type
+ >::value;
+
+ BOOST_MPL_ASSERT_MSG((is_conv),
+ NOT_CONVERTIBLE,
+ (segment_iterator<OtherGeometry>));
+ }
+};
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+inline segment_iterator<Geometry const>
+segments_begin(Geometry const& geometry)
+{
+ return dispatch::segments_begin<Geometry const>::apply(geometry);
+}
+
+
+// MK:: need to add doc here
+template <typename Geometry>
+inline segment_iterator<Geometry const>
+segments_end(Geometry const& geometry)
+{
+ return dispatch::segments_end<Geometry const>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP
diff --git a/boost/geometry/multi/algorithms/append.hpp b/boost/geometry/multi/algorithms/append.hpp
index e72be036ae..d1589aca84 100644
--- a/boost/geometry/multi/algorithms/append.hpp
+++ b/boost/geometry/multi/algorithms/append.hpp
@@ -1,8 +1,14 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,39 +20,8 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP
-#include <boost/geometry/algorithms/append.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-namespace splitted_dispatch
-{
-template <typename Geometry, typename Point>
-struct append_point<multi_point_tag, Geometry, Point>
- : detail::append::append_point<Geometry, Point>
-{};
-
-template <typename Geometry, typename Range>
-struct append_range<multi_point_tag, Geometry, Range>
- : detail::append::append_range<Geometry, Range>
-{};
-
-}
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/append.hpp>
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_APPEND_HPP
diff --git a/boost/geometry/multi/algorithms/area.hpp b/boost/geometry/multi/algorithms/area.hpp
index 6695686358..0e25ffc64e 100644
--- a/boost/geometry/multi/algorithms/area.hpp
+++ b/boost/geometry/multi/algorithms/area.hpp
@@ -15,43 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_AREA_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/algorithms/area.hpp>
-#include <boost/geometry/multi/core/point_type.hpp>
-#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp>
-#include <boost/geometry/multi/algorithms/num_points.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-template <typename MultiGeometry, typename Strategy>
-struct area<MultiGeometry, Strategy, multi_polygon_tag>
- : detail::multi_sum
- <
- typename Strategy::return_type,
- MultiGeometry,
- Strategy,
- area
- <
- typename boost::range_value<MultiGeometry>::type,
- Strategy,
- polygon_tag
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_AREA_HPP
diff --git a/boost/geometry/multi/algorithms/centroid.hpp b/boost/geometry/multi/algorithms/centroid.hpp
index 855ed22fda..1c9902f2bf 100644
--- a/boost/geometry/multi/algorithms/centroid.hpp
+++ b/boost/geometry/multi/algorithms/centroid.hpp
@@ -15,163 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CENTROID_HPP
-#include <boost/range.hpp>
-
#include <boost/geometry/algorithms/centroid.hpp>
-#include <boost/geometry/multi/core/point_type.hpp>
-#include <boost/geometry/multi/algorithms/num_points.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace centroid
-{
-
-
-/*!
- \brief Building block of a multi-point, to be used as Policy in the
- more generec centroid_multi
-*/
-template
-<
- typename Point,
- typename Strategy
->
-struct centroid_multi_point_state
-{
- static inline void apply(Point const& point,
- Strategy const& strategy, typename Strategy::state_type& state)
- {
- strategy.apply(point, state);
- }
-};
-
-
-
-/*!
- \brief Generic implementation which calls a policy to calculate the
- centroid of the total of its single-geometries
- \details The Policy is, in general, the single-version, with state. So
- detail::centroid::centroid_polygon_state is used as a policy for this
- detail::centroid::centroid_multi
-
-*/
-template
-<
- typename Multi,
- typename Point,
- typename Strategy,
- typename Policy
->
-struct centroid_multi
-{
- static inline void apply(Multi const& multi, Point& centroid,
- Strategy const& strategy)
- {
-#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
- // If there is nothing in any of the ranges, it is not possible
- // to calculate the centroid
- if (geometry::num_points(multi) == 0)
- {
- throw centroid_exception();
- }
-#endif
-
- typename Strategy::state_type state;
-
- for (typename boost::range_iterator<Multi const>::type
- it = boost::begin(multi);
- it != boost::end(multi);
- ++it)
- {
- Policy::apply(*it, strategy, state);
- }
- Strategy::result(state, centroid);
- }
-};
-
-
-
-}} // namespace detail::centroid
-#endif // DOXYGEN_NO_DETAIL
-
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- typename MultiLinestring,
- typename Point,
- typename Strategy
->
-struct centroid<multi_linestring_tag, MultiLinestring, Point, Strategy>
- : detail::centroid::centroid_multi
- <
- MultiLinestring,
- Point,
- Strategy,
- detail::centroid::centroid_range_state
- <
- typename boost::range_value<MultiLinestring>::type,
- closed,
- Strategy
- >
- >
-{};
-
-template
-<
- typename MultiPolygon,
- typename Point,
- typename Strategy
->
-struct centroid<multi_polygon_tag, MultiPolygon, Point, Strategy>
- : detail::centroid::centroid_multi
- <
- MultiPolygon,
- Point,
- Strategy,
- detail::centroid::centroid_polygon_state
- <
- typename boost::range_value<MultiPolygon>::type,
- Strategy
- >
- >
-{};
-
-
-template
-<
- typename MultiPoint,
- typename Point,
- typename Strategy
->
-struct centroid<multi_point_tag, MultiPoint, Point, Strategy>
- : detail::centroid::centroid_multi
- <
- MultiPoint,
- Point,
- Strategy,
- detail::centroid::centroid_multi_point_state
- <
- typename boost::range_value<MultiPoint>::type,
- Strategy
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CENTROID_HPP
diff --git a/boost/geometry/multi/algorithms/clear.hpp b/boost/geometry/multi/algorithms/clear.hpp
index 0b14b6ce9c..6d9e284d0a 100644
--- a/boost/geometry/multi/algorithms/clear.hpp
+++ b/boost/geometry/multi/algorithms/clear.hpp
@@ -15,29 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CLEAR_HPP
-#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/clear.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename Geometry>
-struct clear<Geometry, multi_tag>
- : detail::clear::collection_clear<Geometry>
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CLEAR_HPP
diff --git a/boost/geometry/multi/algorithms/convert.hpp b/boost/geometry/multi/algorithms/convert.hpp
index 4745791135..0e7b2946d4 100644
--- a/boost/geometry/multi/algorithms/convert.hpp
+++ b/boost/geometry/multi/algorithms/convert.hpp
@@ -15,114 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/algorithms/convert.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace conversion
-{
-
-template <typename Single, typename Multi, typename Policy>
-struct single_to_multi: private Policy
-{
- static inline void apply(Single const& single, Multi& multi)
- {
- traits::resize<Multi>::apply(multi, 1);
- Policy::apply(single, *boost::begin(multi));
- }
-};
-
-
-
-template <typename Multi1, typename Multi2, typename Policy>
-struct multi_to_multi: private Policy
-{
- static inline void apply(Multi1 const& multi1, Multi2& multi2)
- {
- traits::resize<Multi2>::apply(multi2, boost::size(multi1));
-
- typename boost::range_iterator<Multi1 const>::type it1
- = boost::begin(multi1);
- typename boost::range_iterator<Multi2>::type it2
- = boost::begin(multi2);
-
- for (; it1 != boost::end(multi1); ++it1, ++it2)
- {
- Policy::apply(*it1, *it2);
- }
- }
-};
-
-
-}} // namespace detail::convert
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-// Dispatch for multi <-> multi, specifying their single-version as policy.
-// Note that, even if the multi-types are mutually different, their single
-// version types might be the same and therefore we call boost::is_same again
-
-template <typename Multi1, typename Multi2, std::size_t DimensionCount>
-struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false>
- : detail::conversion::multi_to_multi
- <
- Multi1,
- Multi2,
- convert
- <
- typename boost::range_value<Multi1>::type,
- typename boost::range_value<Multi2>::type,
- typename single_tag_of
- <
- typename tag<Multi1>::type
- >::type,
- typename single_tag_of
- <
- typename tag<Multi2>::type
- >::type,
- DimensionCount
- >
- >
-{};
-
-template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
-struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false>
- : detail::conversion::single_to_multi
- <
- Single,
- Multi,
- convert
- <
- Single,
- typename boost::range_value<Multi>::type,
- typename tag<Single>::type,
- typename single_tag_of
- <
- typename tag<Multi>::type
- >::type,
- DimensionCount,
- false
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CONVERT_HPP
diff --git a/boost/geometry/multi/algorithms/correct.hpp b/boost/geometry/multi/algorithms/correct.hpp
index d0c3e10753..83d26ca60c 100644
--- a/boost/geometry/multi/algorithms/correct.hpp
+++ b/boost/geometry/multi/algorithms/correct.hpp
@@ -15,52 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_CORRECT_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/algorithms/correct.hpp>
-#include <boost/geometry/multi/algorithms/detail/modify.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename MultiPoint>
-struct correct<MultiPoint, multi_point_tag>
- : detail::correct::correct_nop<MultiPoint>
-{};
-
-
-template <typename MultiLineString>
-struct correct<MultiLineString, multi_linestring_tag>
- : detail::correct::correct_nop<MultiLineString>
-{};
-
-
-template <typename Geometry>
-struct correct<Geometry, multi_polygon_tag>
- : detail::multi_modify
- <
- Geometry,
- detail::correct::correct_polygon
- <
- typename boost::range_value<Geometry>::type
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_CORRECT_HPP
diff --git a/boost/geometry/multi/algorithms/covered_by.hpp b/boost/geometry/multi/algorithms/covered_by.hpp
index ba398c0f42..706bc78475 100644
--- a/boost/geometry/multi/algorithms/covered_by.hpp
+++ b/boost/geometry/multi/algorithms/covered_by.hpp
@@ -3,6 +3,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,60 +15,13 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP
#include <boost/geometry/algorithms/covered_by.hpp>
-#include <boost/geometry/multi/core/closure.hpp>
-#include <boost/geometry/multi/core/point_order.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/algorithms/within.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename Point, typename MultiPolygon>
-struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
-{
- template <typename Strategy>
- static inline bool apply(Point const& point,
- MultiPolygon const& multi_polygon, Strategy const& strategy)
- {
- return detail::within::geometry_multi_within_code
- <
- Point,
- MultiPolygon,
- Strategy,
- detail::within::point_in_polygon
- <
- Point,
- typename boost::range_value<MultiPolygon>::type,
- order_as_direction
- <
- geometry::point_order<MultiPolygon>::value
- >::value,
- geometry::closure<MultiPolygon>::value,
- Strategy
- >
- >::apply(point, multi_polygon, strategy) >= 0;
- }
-};
-
-
-} // namespace dispatch
-
-
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_COVERED_BY_HPP
diff --git a/boost/geometry/multi/algorithms/detail/extreme_points.hpp b/boost/geometry/multi/algorithms/detail/extreme_points.hpp
new file mode 100644
index 0000000000..da2ac5e9fa
--- /dev/null
+++ b/boost/geometry/multi/algorithms/detail/extreme_points.hpp
@@ -0,0 +1,19 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
+#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
+
+
+#include <boost/geometry/algorithms/detail/extreme_points.hpp>
+
+
+#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
diff --git a/boost/geometry/multi/algorithms/detail/for_each_range.hpp b/boost/geometry/multi/algorithms/detail/for_each_range.hpp
index 08ab14bd69..2fe475ed58 100644
--- a/boost/geometry/multi/algorithms/detail/for_each_range.hpp
+++ b/boost/geometry/multi/algorithms/detail/for_each_range.hpp
@@ -15,72 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP
-#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-
#include <boost/geometry/algorithms/detail/for_each_range.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace for_each
-{
-
-
-template <typename Multi, typename Actor, bool IsConst>
-struct fe_range_multi
-{
- static inline void apply(
- typename add_const_if_c<IsConst, Multi>::type& multi,
- Actor& actor)
- {
- for(BOOST_AUTO_TPL(it, boost::begin(multi)); it != boost::end(multi); ++it)
- {
- geometry::detail::for_each_range(*it, actor);
- }
- }
-};
-
-
-
-}} // namespace detail::for_each
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template <typename MultiPoint, typename Actor, bool IsConst>
-struct for_each_range<multi_point_tag, MultiPoint, Actor, IsConst>
- : detail::for_each::fe_range_range<MultiPoint, Actor, IsConst>
-{};
-
-template <typename Geometry, typename Actor, bool IsConst>
-struct for_each_range<multi_linestring_tag, Geometry, Actor, IsConst>
- :
- detail::for_each::fe_range_multi<Geometry, Actor, IsConst>
-{};
-
-template <typename Geometry, typename Actor, bool IsConst>
-struct for_each_range<multi_polygon_tag, Geometry, Actor, IsConst>
- :
- detail::for_each::fe_range_multi<Geometry, Actor, IsConst>
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP
diff --git a/boost/geometry/multi/algorithms/detail/modify.hpp b/boost/geometry/multi/algorithms/detail/modify.hpp
index b52efd2512..ae52e002f0 100644
--- a/boost/geometry/multi/algorithms/detail/modify.hpp
+++ b/boost/geometry/multi/algorithms/detail/modify.hpp
@@ -15,39 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_HPP
-#include <boost/range.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail
-{
-
-
-template <typename MultiGeometry, typename Policy>
-struct multi_modify
-{
- static inline void apply(MultiGeometry& multi)
- {
- typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
- for (iterator_type it = boost::begin(multi);
- it != boost::end(multi);
- ++it)
- {
- Policy::apply(*it);
- }
- }
-};
-
-
-} // namespace detail
-#endif
-
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_HPP
diff --git a/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp b/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp
index 4ae79058da..1a82a67142 100644
--- a/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp
+++ b/boost/geometry/multi/algorithms/detail/modify_with_predicate.hpp
@@ -15,38 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_WITH_PREDICATE_HPP
-#include <boost/range.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail
-{
-
-template <typename MultiGeometry, typename Predicate, typename Policy>
-struct multi_modify_with_predicate
-{
- static inline void apply(MultiGeometry& multi, Predicate const& predicate)
- {
- typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
- for (iterator_type it = boost::begin(multi);
- it != boost::end(multi);
- ++it)
- {
- Policy::apply(*it, predicate);
- }
- }
-};
-
-
-} // namespace detail
-#endif
-
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp>
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MODIFY_WITH_PREDICATE_HPP
diff --git a/boost/geometry/multi/algorithms/detail/multi_sum.hpp b/boost/geometry/multi/algorithms/detail/multi_sum.hpp
index a47685ceb1..b91970a164 100644
--- a/boost/geometry/multi/algorithms/detail/multi_sum.hpp
+++ b/boost/geometry/multi/algorithms/detail/multi_sum.hpp
@@ -11,48 +11,11 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-#ifndef BOOST_GEOMETRY_MULTI_SUM_HPP
-#define BOOST_GEOMETRY_MULTI_SUM_HPP
-
-#include <boost/range.hpp>
-
-
-namespace boost { namespace geometry
-{
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail
-{
-
-template
-<
- typename ReturnType,
- typename MultiGeometry,
- typename Strategy,
- typename Policy
->
-struct multi_sum
-{
- static inline ReturnType apply(MultiGeometry const& geometry, Strategy const& strategy)
- {
- ReturnType sum = ReturnType();
- for (typename boost::range_iterator
- <
- MultiGeometry const
- >::type it = boost::begin(geometry);
- it != boost::end(geometry);
- ++it)
- {
- sum += Policy::apply(*it, strategy);
- }
- return sum;
- }
-};
-
-
-} // namespace detail
-#endif
-
-}} // namespace boost::geometry
-
-
-#endif // BOOST_GEOMETRY_MULTI_SUM_HPP
+#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MULTI_SUM_HPP
+#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MULTI_SUM_HPP
+
+
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
+
+
+#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_MULTI_SUM_HPP
diff --git a/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp
index 72be5ddbf4..5e23cf4bad 100644
--- a/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp
+++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp
@@ -2,6 +2,9 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// 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)
@@ -10,92 +13,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
-#include <boost/range.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace copy_segments
-{
-
-
-template
-<
- typename MultiGeometry,
- typename SegmentIdentifier,
- typename PointOut,
- typename Policy
->
-struct copy_segment_point_multi
-{
- static inline bool apply(MultiGeometry const& multi,
- SegmentIdentifier const& seg_id, bool second,
- PointOut& point)
- {
-
- BOOST_ASSERT
- (
- seg_id.multi_index >= 0
- && seg_id.multi_index < int(boost::size(multi))
- );
-
- // Call the single-version
- return Policy::apply(multi[seg_id.multi_index], seg_id, second, point);
- }
-};
-
-
-}} // namespace detail::copy_segments
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename MultiGeometry,
- bool Reverse,
- typename SegmentIdentifier,
- typename PointOut
->
-struct copy_segment_point
- <
- multi_polygon_tag,
- MultiGeometry,
- Reverse,
- SegmentIdentifier,
- PointOut
- >
- : detail::copy_segments::copy_segment_point_multi
- <
- MultiGeometry,
- SegmentIdentifier,
- PointOut,
- detail::copy_segments::copy_segment_point_polygon
- <
- typename boost::range_value<MultiGeometry>::type,
- Reverse,
- SegmentIdentifier,
- PointOut
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
diff --git a/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp
index f474b12fdf..54114bfae4 100644
--- a/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp
+++ b/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp
@@ -10,95 +10,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
-#include <boost/assert.hpp>
-#include <boost/range.hpp>
-
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
-#include <boost/geometry/multi/core/ring_type.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace copy_segments
-{
-
-
-template
-<
- typename MultiGeometry,
- typename SegmentIdentifier,
- typename RangeOut,
- typename Policy
->
-struct copy_segments_multi
-{
- static inline void apply(MultiGeometry const& multi_geometry,
- SegmentIdentifier const& seg_id, int to_index,
- RangeOut& current_output)
- {
-
- BOOST_ASSERT
- (
- seg_id.multi_index >= 0
- && seg_id.multi_index < int(boost::size(multi_geometry))
- );
-
- // Call the single-version
- Policy::apply(multi_geometry[seg_id.multi_index],
- seg_id, to_index, current_output);
- }
-};
-
-
-}} // namespace detail::copy_segments
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename MultiPolygon,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments
- <
- multi_polygon_tag,
- MultiPolygon,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >
- : detail::copy_segments::copy_segments_multi
- <
- MultiPolygon,
- SegmentIdentifier,
- RangeOut,
- detail::copy_segments::copy_segments_polygon
- <
- typename boost::range_value<MultiPolygon>::type,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
diff --git a/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp
index e23acf99b3..65e00d064b 100644
--- a/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp
+++ b/boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp
@@ -10,45 +10,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
-#include <boost/assert.hpp>
-#include <boost/range.hpp>
-
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
-#include <boost/geometry/multi/core/ring_type.hpp>
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace overlay
-{
-
-template<>
-struct get_ring<multi_polygon_tag>
-{
- template<typename MultiPolygon>
- static inline typename ring_type<MultiPolygon>::type const& apply(
- ring_identifier const& id,
- MultiPolygon const& multi_polygon)
- {
- BOOST_ASSERT
- (
- id.multi_index >= 0
- && id.multi_index < int(boost::size(multi_polygon))
- );
- return get_ring<polygon_tag>::apply(id,
- multi_polygon[id.multi_index]);
- }
-};
-
-
-
-}} // namespace detail::overlay
-#endif // DOXYGEN_NO_DETAIL
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
diff --git a/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp
index 1ee03cc4d0..a83fb77393 100644
--- a/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp
@@ -10,102 +10,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
-#include <boost/geometry/multi/core/ring_type.hpp>
-
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
-#include <boost/geometry/multi/algorithms/distance.hpp>
-#include <boost/geometry/multi/views/detail/range_type.hpp>
-
-#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp>
-#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace get_turns
-{
-
-template
-<
- typename Multi, typename Box,
- bool Reverse, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
->
-struct get_turns_multi_polygon_cs
-{
- static inline void apply(
- int source_id1, Multi const& multi,
- int source_id2, Box const& box,
- Turns& turns, InterruptPolicy& interrupt_policy)
- {
- typedef typename boost::range_iterator
- <
- Multi const
- >::type iterator_type;
-
- int i = 0;
- for (iterator_type it = boost::begin(multi);
- it != boost::end(multi);
- ++it, ++i)
- {
- // Call its single version
- get_turns_polygon_cs
- <
- typename boost::range_value<Multi>::type, Box,
- Reverse, ReverseBox,
- Turns, TurnPolicy, InterruptPolicy
- >::apply(source_id1, *it, source_id2, box,
- turns, interrupt_policy, i);
- }
- }
-};
-
-}} // namespace detail::get_turns
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename MultiPolygon,
- typename Box,
- bool ReverseMultiPolygon, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
->
-struct get_turns
- <
- multi_polygon_tag, box_tag,
- MultiPolygon, Box,
- ReverseMultiPolygon, ReverseBox,
- Turns,
- TurnPolicy, InterruptPolicy
- >
- : detail::get_turns::get_turns_multi_polygon_cs
- <
- MultiPolygon, Box,
- ReverseMultiPolygon, ReverseBox,
- Turns,
- TurnPolicy, InterruptPolicy
- >
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
diff --git a/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp
index 4636187880..c780c4cd9a 100644
--- a/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp
@@ -10,53 +10,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
-#include <boost/range.hpp>
-
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace overlay
-{
-
-namespace dispatch
-{
-
- template <typename Multi>
- struct select_rings<multi_polygon_tag, Multi>
- {
- template <typename Geometry, typename Map>
- static inline void apply(Multi const& multi, Geometry const& geometry,
- ring_identifier id, Map& map, bool midpoint)
- {
- typedef typename boost::range_iterator
- <
- Multi const
- >::type iterator_type;
-
- typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon;
-
- id.multi_index = 0;
- for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
- {
- id.ring_index = -1;
- per_polygon::apply(*it, geometry, id, map, midpoint);
- id.multi_index++;
- }
- }
- };
-}
-
-
-}} // namespace detail::overlay
-#endif // DOXYGEN_NO_DETAIL
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
diff --git a/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp
index 57d5ff92ca..39bfea2fb3 100644
--- a/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp
@@ -10,47 +10,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
-#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename MultiPolygon,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
->
-struct self_get_turn_points
- <
- multi_polygon_tag, MultiPolygon,
- Turns,
- TurnPolicy, InterruptPolicy
- >
- : detail::self_get_turn_points::get_turns
- <
- MultiPolygon,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
diff --git a/boost/geometry/multi/algorithms/detail/point_on_border.hpp b/boost/geometry/multi/algorithms/detail/point_on_border.hpp
index ac462ed4c5..2ee789c5da 100644
--- a/boost/geometry/multi/algorithms/detail/point_on_border.hpp
+++ b/boost/geometry/multi/algorithms/detail/point_on_border.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,82 +17,8 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
-#include <boost/range.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace point_on_border
-{
-
-
-template
-<
- typename Point,
- typename MultiGeometry,
- typename Policy
->
-struct point_on_multi
-{
- static inline bool apply(Point& point, MultiGeometry const& multi, bool midpoint)
- {
- // Take a point on the first multi-geometry
- // (i.e. the first that is not empty)
- for (typename boost::range_iterator
- <
- MultiGeometry const
- >::type it = boost::begin(multi);
- it != boost::end(multi);
- ++it)
- {
- if (Policy::apply(point, *it, midpoint))
- {
- return true;
- }
- }
- return false;
- }
-};
-
-
-
-
-}} // namespace detail::point_on_border
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template<typename Point, typename Multi>
-struct point_on_border<multi_polygon_tag, Point, Multi>
- : detail::point_on_border::point_on_multi
- <
- Point,
- Multi,
- detail::point_on_border::point_on_polygon
- <
- Point,
- typename boost::range_value<Multi>::type
- >
- >
-{};
-
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
diff --git a/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp
index 28a4805ed1..5604d9d74f 100644
--- a/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp
+++ b/boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,80 +14,13 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
-#include <boost/assert.hpp>
-#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/range_by_section.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace section
-{
-
-
-template
-<
- typename MultiGeometry,
- typename Section,
- typename Policy
->
-struct full_section_multi
-{
- static inline typename ring_return_type<MultiGeometry const>::type apply(
- MultiGeometry const& multi, Section const& section)
- {
- BOOST_ASSERT
- (
- section.ring_id.multi_index >= 0
- && section.ring_id.multi_index < int(boost::size(multi))
- );
-
- return Policy::apply(multi[section.ring_id.multi_index], section);
- }
-};
-
-
-}} // namespace detail::section
-#endif
-
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template <typename MultiPolygon, typename Section>
-struct range_by_section<multi_polygon_tag, MultiPolygon, Section>
- : detail::section::full_section_multi
- <
- MultiPolygon,
- Section,
- detail::section::full_section_polygon
- <
- typename boost::range_value<MultiPolygon>::type,
- Section
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
diff --git a/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp
index 16f70c193d..ef98021237 100644
--- a/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp
+++ b/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,82 +17,8 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
-#include <cstddef>
-#include <vector>
-
-#include <boost/concept/requires.hpp>
-#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace sectionalize
-{
-
-
-template <typename MultiGeometry, typename Sections, std::size_t DimensionCount, typename Policy>
-struct sectionalize_multi
-{
- static inline void apply(MultiGeometry const& multi, Sections& sections, ring_identifier ring_id)
- {
- ring_id.multi_index = 0;
- for (typename boost::range_iterator<MultiGeometry const>::type
- it = boost::begin(multi);
- it != boost::end(multi);
- ++it, ++ring_id.multi_index)
- {
- Policy::apply(*it, sections, ring_id);
- }
- }
-};
-
-
-}} // namespace detail::sectionalize
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename MultiPolygon,
- bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
->
-struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, Sections, DimensionCount, MaxCount>
- : detail::sectionalize::sectionalize_multi
- <
- MultiPolygon,
- Sections,
- DimensionCount,
- detail::sectionalize::sectionalize_polygon
- <
- typename boost::range_value<MultiPolygon>::type,
- Reverse,
- Sections,
- DimensionCount,
- MaxCount
- >
- >
-
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
diff --git a/boost/geometry/multi/algorithms/disjoint.hpp b/boost/geometry/multi/algorithms/disjoint.hpp
new file mode 100644
index 0000000000..55f0f01cd6
--- /dev/null
+++ b/boost/geometry/multi/algorithms/disjoint.hpp
@@ -0,0 +1,21 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2012-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2012-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DISJOINT_HPP
+#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DISJOINT_HPP
+
+#include <boost/geometry/algorithms/disjoint.hpp>
+
+#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DISJOINT_HPP
diff --git a/boost/geometry/multi/algorithms/distance.hpp b/boost/geometry/multi/algorithms/distance.hpp
index 8acb3f9006..4946b6f3e1 100644
--- a/boost/geometry/multi/algorithms/distance.hpp
+++ b/boost/geometry/multi/algorithms/distance.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,144 +19,9 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_DISTANCE_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_DISTANCE_HPP
-
-#include <boost/numeric/conversion/bounds.hpp>
-#include <boost/range.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/core/geometry_id.hpp>
-#include <boost/geometry/multi/core/point_type.hpp>
+// this file is intentionally empty (with the exception of the #include below)
+// it is used for backward compatinility and may be removed in the future
#include <boost/geometry/algorithms/distance.hpp>
-#include <boost/geometry/multi/algorithms/num_points.hpp>
-#include <boost/geometry/util/select_coordinate_type.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace distance
-{
-
-
-template<typename Geometry, typename MultiGeometry, typename Strategy>
-struct distance_single_to_multi
- : private dispatch::distance
- <
- Geometry,
- typename range_value<MultiGeometry>::type,
- Strategy
- >
-{
- typedef typename strategy::distance::services::return_type<Strategy>::type return_type;
-
- static inline return_type apply(Geometry const& geometry,
- MultiGeometry const& multi,
- Strategy const& strategy)
- {
- return_type mindist = return_type();
- bool first = true;
-
- for(typename range_iterator<MultiGeometry const>::type it = boost::begin(multi);
- it != boost::end(multi);
- ++it, first = false)
- {
- return_type dist = dispatch::distance
- <
- Geometry,
- typename range_value<MultiGeometry>::type,
- Strategy
- >::apply(geometry, *it, strategy);
-
- if (first || dist < mindist)
- {
- mindist = dist;
- }
- }
-
- return mindist;
- }
-};
-
-template<typename Multi1, typename Multi2, typename Strategy>
-struct distance_multi_to_multi
- : private distance_single_to_multi
- <
- typename range_value<Multi1>::type,
- Multi2,
- Strategy
- >
-{
- typedef typename strategy::distance::services::return_type<Strategy>::type return_type;
-
- static inline return_type apply(Multi1 const& multi1,
- Multi2 const& multi2, Strategy const& strategy)
- {
- return_type mindist = return_type();
- bool first = true;
-
- for(typename range_iterator<Multi1 const>::type it = boost::begin(multi1);
- it != boost::end(multi1);
- ++it, first = false)
- {
- return_type dist = distance_single_to_multi
- <
- typename range_value<Multi1>::type,
- Multi2,
- Strategy
- >::apply(*it, multi2, strategy);
- if (first || dist < mindist)
- {
- mindist = dist;
- }
- }
-
- return mindist;
- }
-};
-
-
-}} // namespace detail::distance
-#endif
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- typename G1,
- typename G2,
- typename Strategy,
- typename SingleGeometryTag
->
-struct distance
-<
- G1, G2, Strategy,
- SingleGeometryTag, multi_tag, strategy_tag_distance_point_point,
- false
->
- : detail::distance::distance_single_to_multi<G1, G2, Strategy>
-{};
-
-template <typename G1, typename G2, typename Strategy>
-struct distance
-<
- G1, G2, Strategy,
- multi_tag, multi_tag, strategy_tag_distance_point_point,
- false
->
- : detail::distance::distance_multi_to_multi<G1, G2, Strategy>
-{};
-
-} // namespace dispatch
-#endif
-
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_DISTANCE_HPP
diff --git a/boost/geometry/multi/algorithms/envelope.hpp b/boost/geometry/multi/algorithms/envelope.hpp
index 1876b5f91e..457dfaf3bc 100644
--- a/boost/geometry/multi/algorithms/envelope.hpp
+++ b/boost/geometry/multi/algorithms/envelope.hpp
@@ -14,104 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP
-#include <vector>
-#include <boost/range/metafunctions.hpp>
-
-
-#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
-#include <boost/geometry/multi/core/point_type.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-
-namespace detail { namespace envelope
-{
-
-
-template<typename MultiLinestring, typename Box>
-struct envelope_multi_linestring
-{
- static inline void apply(MultiLinestring const& mp, Box& mbr)
- {
- assign_inverse(mbr);
- for (typename boost::range_iterator<MultiLinestring const>::type
- it = mp.begin();
- it != mp.end();
- ++it)
- {
- envelope_range_additional(*it, mbr);
- }
- }
-};
-
-
-// version for multi_polygon: outer ring's of all polygons
-template<typename MultiPolygon, typename Box>
-struct envelope_multi_polygon
-{
- static inline void apply(MultiPolygon const& mp, Box& mbr)
- {
- assign_inverse(mbr);
- for (typename boost::range_const_iterator<MultiPolygon>::type
- it = mp.begin();
- it != mp.end();
- ++it)
- {
- envelope_range_additional(exterior_ring(*it), mbr);
- }
- }
-};
-
-
-}} // namespace detail::envelope
-
-#endif
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- typename Multi, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope<multi_point_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater>
- : detail::envelope::envelope_range<Multi, Box>
-{};
-
-template
-<
- typename Multi, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope<multi_linestring_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater>
- : detail::envelope::envelope_multi_linestring<Multi, Box>
-{};
-
-
-template
-<
- typename Multi, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope<multi_polygon_tag, box_tag, Multi, Box, StrategyLess, StrategyGreater>
- : detail::envelope::envelope_multi_polygon<Multi, Box>
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_ENVELOPE_HPP
diff --git a/boost/geometry/multi/algorithms/equals.hpp b/boost/geometry/multi/algorithms/equals.hpp
index a307ebae8b..0f045fff90 100644
--- a/boost/geometry/multi/algorithms/equals.hpp
+++ b/boost/geometry/multi/algorithms/equals.hpp
@@ -15,56 +15,8 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_EQUALS_HPP
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/core/geometry_id.hpp>
-
#include <boost/geometry/algorithms/equals.hpp>
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template <typename MultiPolygon1, typename MultiPolygon2>
-struct equals
- <
- multi_polygon_tag, multi_polygon_tag,
- MultiPolygon1, MultiPolygon2,
- 2
- >
- : detail::equals::equals_by_collection
- <
- MultiPolygon1, MultiPolygon2,
- detail::equals::area_check
- >
-{};
-
-
-template <typename Polygon, typename MultiPolygon>
-struct equals
- <
- polygon_tag, multi_polygon_tag,
- Polygon, MultiPolygon,
- 2
- >
- : detail::equals::equals_by_collection
- <
- Polygon, MultiPolygon,
- detail::equals::area_check
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_EQUALS_HPP
diff --git a/boost/geometry/multi/algorithms/for_each.hpp b/boost/geometry/multi/algorithms/for_each.hpp
index 1be38e0a7e..d8b3af1ff2 100644
--- a/boost/geometry/multi/algorithms/for_each.hpp
+++ b/boost/geometry/multi/algorithms/for_each.hpp
@@ -15,115 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_FOR_EACH_HPP
-#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/core/point_type.hpp>
-
-
#include <boost/geometry/algorithms/for_each.hpp>
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace for_each
-{
-
-// Implementation of multi, for both point and segment,
-// just calling the single version.
-template
-<
- typename MultiGeometry,
- typename Functor,
- bool IsConst,
- typename Policy
->
-struct for_each_multi
-{
- static inline Functor apply(
- typename add_const_if_c<IsConst, MultiGeometry>::type& multi,
- Functor f)
- {
- for(BOOST_AUTO_TPL(it, boost::begin(multi)); it != boost::end(multi); ++it)
- {
- f = Policy::apply(*it, f);
- }
- return f;
- }
-};
-
-
-}} // namespace detail::for_each
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- typename MultiGeometry,
- typename Functor,
- bool IsConst
->
-struct for_each_point<multi_tag, MultiGeometry, Functor, IsConst>
- : detail::for_each::for_each_multi
- <
- MultiGeometry,
- Functor,
- IsConst,
- // Specify the dispatch of the single-version as policy
- for_each_point
- <
- typename single_tag_of
- <
- typename tag<MultiGeometry>::type
- >::type,
- typename boost::range_value<MultiGeometry>::type,
- Functor,
- IsConst
- >
- >
-{};
-
-
-template
-<
- typename MultiGeometry,
- typename Functor,
- bool IsConst
->
-struct for_each_segment<multi_tag, MultiGeometry, Functor, IsConst>
- : detail::for_each::for_each_multi
- <
- MultiGeometry,
- Functor,
- IsConst,
- // Specify the dispatch of the single-version as policy
- for_each_segment
- <
- typename single_tag_of
- <
- typename tag<MultiGeometry>::type
- >::type,
- typename boost::range_value<MultiGeometry>::type,
- Functor,
- IsConst
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_FOR_EACH_HPP
diff --git a/boost/geometry/multi/algorithms/intersection.hpp b/boost/geometry/multi/algorithms/intersection.hpp
index 31e74a79ba..f434463253 100644
--- a/boost/geometry/multi/algorithms/intersection.hpp
+++ b/boost/geometry/multi/algorithms/intersection.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -10,429 +15,8 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_INTERSECTION_HPP
-#include <boost/geometry/multi/core/closure.hpp>
-#include <boost/geometry/multi/core/geometry_id.hpp>
-#include <boost/geometry/multi/core/is_areal.hpp>
-#include <boost/geometry/multi/core/point_order.hpp>
-#include <boost/geometry/multi/algorithms/covered_by.hpp>
-#include <boost/geometry/multi/algorithms/envelope.hpp>
-#include <boost/geometry/multi/algorithms/num_points.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp>
-#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/select_rings.hpp>
-#include <boost/geometry/multi/algorithms/detail/sections/range_by_section.hpp>
-#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>
-
#include <boost/geometry/algorithms/intersection.hpp>
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace intersection
-{
-
-
-template
-<
- typename MultiLinestring1, typename MultiLinestring2,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
-struct intersection_multi_linestring_multi_linestring_point
-{
- static inline OutputIterator apply(MultiLinestring1 const& ml1,
- MultiLinestring2 const& ml2, OutputIterator out,
- Strategy const& strategy)
- {
- // Note, this loop is quadratic w.r.t. number of linestrings per input.
- // Future Enhancement: first do the sections of each, then intersect.
- for (typename boost::range_iterator
- <
- MultiLinestring1 const
- >::type it1 = boost::begin(ml1);
- it1 != boost::end(ml1);
- ++it1)
- {
- for (typename boost::range_iterator
- <
- MultiLinestring2 const
- >::type it2 = boost::begin(ml2);
- it2 != boost::end(ml2);
- ++it2)
- {
- out = intersection_linestring_linestring_point
- <
- typename boost::range_value<MultiLinestring1>::type,
- typename boost::range_value<MultiLinestring2>::type,
- OutputIterator, PointOut, Strategy
- >::apply(*it1, *it2, out, strategy);
- }
- }
-
- return out;
- }
-};
-
-
-template
-<
- typename Linestring, typename MultiLinestring,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
-struct intersection_linestring_multi_linestring_point
-{
- static inline OutputIterator apply(Linestring const& linestring,
- MultiLinestring const& ml, OutputIterator out,
- Strategy const& strategy)
- {
- for (typename boost::range_iterator
- <
- MultiLinestring const
- >::type it = boost::begin(ml);
- it != boost::end(ml);
- ++it)
- {
- out = intersection_linestring_linestring_point
- <
- Linestring,
- typename boost::range_value<MultiLinestring>::type,
- OutputIterator, PointOut, Strategy
- >::apply(linestring, *it, out, strategy);
- }
-
- return out;
- }
-};
-
-
-// This loop is quite similar to the loop above, but beacuse the iterator
-// is second (above) or first (below) argument, it is not trivial to merge them.
-template
-<
- typename MultiLinestring, typename Areal,
- bool ReverseAreal,
- typename OutputIterator, typename LineStringOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_of_multi_linestring_with_areal
-{
- static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal,
- OutputIterator out,
- Strategy const& strategy)
- {
- for (typename boost::range_iterator
- <
- MultiLinestring const
- >::type it = boost::begin(ml);
- it != boost::end(ml);
- ++it)
- {
- out = intersection_of_linestring_with_areal
- <
- typename boost::range_value<MultiLinestring>::type,
- Areal, ReverseAreal,
- OutputIterator, LineStringOut, OverlayType, Strategy
- >::apply(*it, areal, out, strategy);
- }
-
- return out;
-
- }
-};
-
-// This one calls the one above with reversed arguments
-template
-<
- typename Areal, typename MultiLinestring,
- bool ReverseAreal,
- typename OutputIterator, typename LineStringOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_of_areal_with_multi_linestring
-{
- static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml,
- OutputIterator out,
- Strategy const& strategy)
- {
- return intersection_of_multi_linestring_with_areal
- <
- MultiLinestring, Areal, ReverseAreal,
- OutputIterator, LineStringOut,
- OverlayType,
- Strategy
- >::apply(ml, areal, out, strategy);
- }
-};
-
-
-
-template
-<
- typename MultiLinestring, typename Box,
- typename OutputIterator, typename LinestringOut,
- typename Strategy
->
-struct clip_multi_linestring
-{
- static inline OutputIterator apply(MultiLinestring const& multi_linestring,
- Box const& box, OutputIterator out, Strategy const& )
- {
- typedef typename point_type<LinestringOut>::type point_type;
- strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
- for (typename boost::range_iterator<MultiLinestring const>::type it
- = boost::begin(multi_linestring);
- it != boost::end(multi_linestring); ++it)
- {
- out = detail::intersection::clip_range_with_box
- <LinestringOut>(box, *it, out, lb_strategy);
- }
- return out;
- }
-};
-
-
-}} // namespace detail::intersection
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-// Linear
-template
-<
- typename MultiLinestring1, typename MultiLinestring2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- multi_linestring_tag, multi_linestring_tag, point_tag,
- false, false, false,
- MultiLinestring1, MultiLinestring2,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::intersection_multi_linestring_multi_linestring_point
- <
- MultiLinestring1, MultiLinestring2,
- OutputIterator, GeometryOut,
- Strategy
- >
-{};
-
-
-template
-<
- typename Linestring, typename MultiLinestring,
- typename OutputIterator, typename GeometryOut,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- linestring_tag, multi_linestring_tag, point_tag,
- false, false, false,
- Linestring, MultiLinestring,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::intersection_linestring_multi_linestring_point
- <
- Linestring, MultiLinestring,
- OutputIterator, GeometryOut,
- Strategy
- >
-{};
-
-
-template
-<
- typename MultiLinestring, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- multi_linestring_tag, box_tag, linestring_tag,
- false, true, false,
- MultiLinestring, Box,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::clip_multi_linestring
- <
- MultiLinestring, Box,
- OutputIterator, GeometryOut,
- Strategy
- >
-{};
-
-
-template
-<
- typename Linestring, typename MultiPolygon,
- bool ReverseLinestring, bool ReverseMultiPolygon, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- linestring_tag, multi_polygon_tag, linestring_tag,
- false, true, false,
- Linestring, MultiPolygon,
- ReverseLinestring, ReverseMultiPolygon, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::intersection_of_linestring_with_areal
- <
- Linestring, MultiPolygon,
- ReverseMultiPolygon,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
-{};
-
-
-// Derives from areal/mls because runtime arguments are in that order.
-// areal/mls reverses it itself to mls/areal
-template
-<
- typename Polygon, typename MultiLinestring,
- bool ReversePolygon, bool ReverseMultiLinestring, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- polygon_tag, multi_linestring_tag, linestring_tag,
- true, false, false,
- Polygon, MultiLinestring,
- ReversePolygon, ReverseMultiLinestring, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::intersection_of_areal_with_multi_linestring
- <
- Polygon, MultiLinestring,
- ReversePolygon,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
-{};
-
-
-template
-<
- typename MultiLinestring, typename Ring,
- bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- multi_linestring_tag, ring_tag, linestring_tag,
- false, true, false,
- MultiLinestring, Ring,
- ReverseMultiLinestring, ReverseRing, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::intersection_of_multi_linestring_with_areal
- <
- MultiLinestring, Ring,
- ReverseRing,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
-{};
-
-template
-<
- typename MultiLinestring, typename Polygon,
- bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- multi_linestring_tag, polygon_tag, linestring_tag,
- false, true, false,
- MultiLinestring, Polygon,
- ReverseMultiLinestring, ReverseRing, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::intersection_of_multi_linestring_with_areal
- <
- MultiLinestring, Polygon,
- ReverseRing,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
-{};
-
-
-
-template
-<
- typename MultiLinestring, typename MultiPolygon,
- bool ReverseMultiLinestring, bool ReverseMultiPolygon, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
->
-struct intersection_insert
- <
- multi_linestring_tag, multi_polygon_tag, linestring_tag,
- false, true, false,
- MultiLinestring, MultiPolygon,
- ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- > : detail::intersection::intersection_of_multi_linestring_with_areal
- <
- MultiLinestring, MultiPolygon,
- ReverseMultiPolygon,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
-{};
-
-
-} // namespace dispatch
-#endif
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_INTERSECTION_HPP
diff --git a/boost/geometry/multi/algorithms/length.hpp b/boost/geometry/multi/algorithms/length.hpp
index 51ff9ef3c2..168e6a732f 100644
--- a/boost/geometry/multi/algorithms/length.hpp
+++ b/boost/geometry/multi/algorithms/length.hpp
@@ -15,43 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_LENGTH_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/algorithms/length.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp>
-#include <boost/geometry/multi/algorithms/num_points.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename MultiLinestring, typename Strategy>
-struct length<multi_linestring_tag, MultiLinestring, Strategy>
- : detail::multi_sum
- <
- typename default_length_result<MultiLinestring>::type,
- MultiLinestring,
- Strategy,
- detail::length::range_length
- <
- typename boost::range_value<MultiLinestring>::type,
- Strategy,
- closed // no need to close it explicitly
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_LENGTH_HPP
diff --git a/boost/geometry/multi/algorithms/num_geometries.hpp b/boost/geometry/multi/algorithms/num_geometries.hpp
index 213339a18c..3a85f4e4bf 100644
--- a/boost/geometry/multi/algorithms/num_geometries.hpp
+++ b/boost/geometry/multi/algorithms/num_geometries.hpp
@@ -16,36 +16,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP
-#include <cstddef>
-
-#include <boost/range.hpp>
-
#include <boost/geometry/algorithms/num_geometries.hpp>
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename MultiGeometry>
-struct num_geometries<multi_tag, MultiGeometry>
-{
- static inline std::size_t apply(MultiGeometry const& multi_geometry)
- {
- return boost::size(multi_geometry);
- }
-};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_GEOMETRIES_HPP
diff --git a/boost/geometry/multi/algorithms/num_interior_rings.hpp b/boost/geometry/multi/algorithms/num_interior_rings.hpp
index 87b0bdea91..fbaa113aff 100644
--- a/boost/geometry/multi/algorithms/num_interior_rings.hpp
+++ b/boost/geometry/multi/algorithms/num_interior_rings.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,48 +19,8 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP
-#include <cstddef>
-
-#include <boost/range.hpp>
-
-#include <boost/geometry/core/tag.hpp>
-#include <boost/geometry/core/tags.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template <typename MultiPolygon>
-struct num_interior_rings<multi_polygon_tag, MultiPolygon>
-{
- static inline std::size_t apply(MultiPolygon const& multi_polygon)
- {
- std::size_t n = 0;
- for (typename boost::range_iterator<MultiPolygon const>::type
- it = boost::begin(multi_polygon);
- it != boost::end(multi_polygon);
- ++it)
- {
- n += geometry::num_interior_rings(*it);
- }
- return n;
- }
-
-};
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_INTERIOR_RINGS_HPP
diff --git a/boost/geometry/multi/algorithms/num_points.hpp b/boost/geometry/multi/algorithms/num_points.hpp
index 5ea53854eb..a736f4254b 100644
--- a/boost/geometry/multi/algorithms/num_points.hpp
+++ b/boost/geometry/multi/algorithms/num_points.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -16,66 +21,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_POINTS_HPP
-#include <boost/range.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace num_points
-{
-
-
-template <typename MultiGeometry>
-struct multi_count
-{
- 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
- <
- MultiGeometry const
- >::type iterator_type;
-
- std::size_t n = 0;
- for (iterator_type it = boost::begin(geometry);
- it != boost::end(geometry);
- ++it)
- {
- n += dispatch::num_points
- <
- typename tag<geometry_type>::type,
- geometry_type
- >::apply(*it, add_for_open);
- }
- return n;
- }
-};
-
-
-}} // namespace detail::num_points
-#endif
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template <typename Geometry>
-struct num_points<multi_tag, Geometry>
- : detail::num_points::multi_count<Geometry> {};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_NUM_POINTS_HPP
diff --git a/boost/geometry/multi/algorithms/perimeter.hpp b/boost/geometry/multi/algorithms/perimeter.hpp
index 147f6fcc30..4820111f1f 100644
--- a/boost/geometry/multi/algorithms/perimeter.hpp
+++ b/boost/geometry/multi/algorithms/perimeter.hpp
@@ -15,42 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_PERIMETER_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/algorithms/perimeter.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-#include <boost/geometry/multi/algorithms/detail/multi_sum.hpp>
-#include <boost/geometry/multi/algorithms/num_points.hpp>
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-template <typename MultiPolygon, typename Strategy>
-struct perimeter<multi_polygon_tag, MultiPolygon, Strategy>
- : detail::multi_sum
- <
- typename default_length_result<MultiPolygon>::type,
- MultiPolygon,
- Strategy,
- perimeter
- <
- polygon_tag,
- typename boost::range_value<MultiPolygon>::type,
- Strategy
- >
- >
-{};
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_PERIMETER_HPP
diff --git a/boost/geometry/multi/algorithms/remove_spikes.hpp b/boost/geometry/multi/algorithms/remove_spikes.hpp
new file mode 100644
index 0000000000..af224ec478
--- /dev/null
+++ b/boost/geometry/multi/algorithms/remove_spikes.hpp
@@ -0,0 +1,19 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_REMOVE_SPIKES_HPP
+#define BOOST_GEOMETRY_MULTI_ALGORITHMS_REMOVE_SPIKES_HPP
+
+
+#include <boost/geometry/algorithms/remove_spikes.hpp>
+
+
+#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_REMOVE_SPIKES_HPP
diff --git a/boost/geometry/multi/algorithms/reverse.hpp b/boost/geometry/multi/algorithms/reverse.hpp
index f8a9442ac0..a7872bdd2a 100644
--- a/boost/geometry/multi/algorithms/reverse.hpp
+++ b/boost/geometry/multi/algorithms/reverse.hpp
@@ -15,55 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_REVERSE_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/algorithms/reverse.hpp>
-#include <boost/geometry/multi/algorithms/detail/modify.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template <typename Geometry>
-struct reverse<multi_linestring_tag, Geometry>
- : detail::multi_modify
- <
- Geometry,
- detail::reverse::range_reverse
- <
- typename boost::range_value<Geometry>::type
- >
- >
-{};
-
-
-template <typename Geometry>
-struct reverse<multi_polygon_tag, Geometry>
- : detail::multi_modify
- <
- Geometry,
- detail::reverse::polygon_reverse
- <
- typename boost::range_value<Geometry>::type
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_REVERSE_HPP
diff --git a/boost/geometry/multi/algorithms/simplify.hpp b/boost/geometry/multi/algorithms/simplify.hpp
index dc3c7b5937..8648d366d1 100644
--- a/boost/geometry/multi/algorithms/simplify.hpp
+++ b/boost/geometry/multi/algorithms/simplify.hpp
@@ -14,104 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP
-#include <boost/range.hpp>
-#include <boost/geometry/core/mutable_range.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-#include <boost/geometry/multi/algorithms/clear.hpp>
#include <boost/geometry/algorithms/simplify.hpp>
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace simplify
-{
-
-template<typename MultiGeometry, typename Strategy, typename Policy>
-struct simplify_multi
-{
- static inline void apply(MultiGeometry const& multi, MultiGeometry& out,
- double max_distance, Strategy const& strategy)
- {
- traits::resize<MultiGeometry>::apply(out, boost::size(multi));
-
- typename boost::range_iterator<MultiGeometry>::type it_out
- = boost::begin(out);
- for (typename boost::range_iterator<MultiGeometry const>::type it_in
- = boost::begin(multi);
- it_in != boost::end(multi);
- ++it_in, ++it_out)
- {
- Policy::apply(*it_in, *it_out, max_distance, strategy);
- }
- }
-};
-
-
-
-}} // namespace detail::simplify
-#endif // DOXYGEN_NO_DETAIL
-
-
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename MultiPoint, typename Strategy>
-struct simplify<multi_point_tag, MultiPoint, Strategy>
- : detail::simplify::simplify_copy
- <
- MultiPoint,
- Strategy
- >
-
-{};
-
-
-template <typename MultiLinestring, typename Strategy>
-struct simplify<multi_linestring_tag, MultiLinestring, Strategy>
- : detail::simplify::simplify_multi
- <
- MultiLinestring,
- Strategy,
- detail::simplify::simplify_range
- <
- typename boost::range_value<MultiLinestring>::type,
- Strategy,
- 2
- >
- >
-
-{};
-
-
-template <typename MultiPolygon, typename Strategy>
-struct simplify<multi_polygon_tag, MultiPolygon, Strategy>
- : detail::simplify::simplify_multi
- <
- MultiPolygon,
- Strategy,
- detail::simplify::simplify_polygon
- <
- typename boost::range_value<MultiPolygon>::type,
- Strategy
- >
- >
-
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
-
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_SIMPLIFY_HPP
diff --git a/boost/geometry/multi/algorithms/transform.hpp b/boost/geometry/multi/algorithms/transform.hpp
index 09926778f9..7aa691ec4a 100644
--- a/boost/geometry/multi/algorithms/transform.hpp
+++ b/boost/geometry/multi/algorithms/transform.hpp
@@ -14,89 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP
-#include <boost/range.hpp>
-#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/algorithms/transform.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace transform
-{
-
-/*!
- \brief Is able to transform any multi-geometry, calling the single-version as policy
-*/
-template <typename Multi1, typename Multi2, typename Policy>
-struct transform_multi
-{
- template <typename S>
- static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy)
- {
- traits::resize<Multi2>::apply(multi2, boost::size(multi1));
-
- typename boost::range_iterator<Multi1 const>::type it1
- = boost::begin(multi1);
- typename boost::range_iterator<Multi2>::type it2
- = boost::begin(multi2);
-
- for (; it1 != boost::end(multi1); ++it1, ++it2)
- {
- if (! Policy::apply(*it1, *it2, strategy))
- {
- return false;
- }
- }
-
- return true;
- }
-};
-
-
-}} // namespace detail::transform
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename Multi1, typename Multi2, typename Strategy>
-struct transform
- <
- multi_tag, multi_tag,
- Multi1, Multi2,
- Strategy
- >
- : detail::transform::transform_multi
- <
- Multi1,
- Multi2,
- transform
- <
- typename single_tag_of
- <
- typename tag<Multi1>::type
- >::type,
- typename single_tag_of
- <
- typename tag<Multi2>::type
- >::type,
- typename boost::range_value<Multi1>::type,
- typename boost::range_value<Multi2>::type,
- Strategy
- >
- >
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_TRANSFORM_HPP
diff --git a/boost/geometry/multi/algorithms/unique.hpp b/boost/geometry/multi/algorithms/unique.hpp
index 5067e71f3f..fa063a312d 100644
--- a/boost/geometry/multi/algorithms/unique.hpp
+++ b/boost/geometry/multi/algorithms/unique.hpp
@@ -15,88 +15,7 @@
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_UNIQUE_HPP
-#include <boost/range.hpp>
-
#include <boost/geometry/algorithms/unique.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace unique
-{
-
-
-template <typename MultiGeometry, typename ComparePolicy, typename Policy>
-struct multi_unique
-{
- static inline void apply(MultiGeometry& multi, ComparePolicy const& compare)
- {
- for (typename boost::range_iterator<MultiGeometry>::type
- it = boost::begin(multi);
- it != boost::end(multi);
- ++it)
- {
- Policy::apply(*it, compare);
- }
- }
-};
-
-
-}} // namespace detail::unique
-#endif // DOXYGEN_NO_DETAIL
-
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-// For points, unique is not applicable and does nothing
-// (Note that it is not "spatially unique" but that it removes duplicate coordinates,
-// like std::unique does). Spatially unique is "dissolve" which can (or will be)
-// possible for multi-points as well, removing points at the same location.
-
-
-template <typename MultiLineString, typename ComparePolicy>
-struct unique<multi_linestring_tag, MultiLineString, ComparePolicy>
- : detail::unique::multi_unique
- <
- MultiLineString,
- ComparePolicy,
- detail::unique::range_unique
- <
- typename boost::range_value<MultiLineString>::type,
- ComparePolicy
- >
- >
-{};
-
-
-template <typename MultiPolygon, typename ComparePolicy>
-struct unique<multi_polygon_tag, MultiPolygon, ComparePolicy>
- : detail::unique::multi_unique
- <
- MultiPolygon,
- ComparePolicy,
- detail::unique::polygon_unique
- <
- typename boost::range_value<MultiPolygon>::type,
- ComparePolicy
- >
- >
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_UNIQUE_HPP
diff --git a/boost/geometry/multi/algorithms/within.hpp b/boost/geometry/multi/algorithms/within.hpp
index a3ec7514b7..9fdc5dd39a 100644
--- a/boost/geometry/multi/algorithms/within.hpp
+++ b/boost/geometry/multi/algorithms/within.hpp
@@ -3,6 +3,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,94 +15,11 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP
#define BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP
-
-#include <boost/range.hpp>
-
#include <boost/geometry/algorithms/within.hpp>
-#include <boost/geometry/multi/core/closure.hpp>
-#include <boost/geometry/multi/core/point_order.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace within
-{
-
-
-template
-<
- typename Geometry,
- typename MultiGeometry,
- typename Strategy,
- typename Policy
->
-struct geometry_multi_within_code
-{
- static inline int apply(Geometry const& geometry,
- MultiGeometry const& multi,
- Strategy const& strategy)
- {
- for (typename boost::range_iterator<MultiGeometry const>::type it
- = boost::begin(multi);
- it != boost::end(multi);
- ++it)
- {
- // Geometry coding on multi: 1 (within) if within one of them;
- // 0 (touch) if on border of one of them
- int const code = Policy::apply(geometry, *it, strategy);
- if (code != -1)
- {
- return code;
- }
- }
- return -1;
- }
-};
-
-
-}} // namespace detail::within
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename Point, typename MultiPolygon>
-struct within<Point, MultiPolygon, point_tag, multi_polygon_tag>
-{
- template <typename Strategy>
- static inline bool apply(Point const& point,
- MultiPolygon const& multi_polygon, Strategy const& strategy)
- {
- return detail::within::geometry_multi_within_code
- <
- Point,
- MultiPolygon,
- Strategy,
- detail::within::point_in_polygon
- <
- Point,
- typename boost::range_value<MultiPolygon>::type,
- order_as_direction
- <
- geometry::point_order<MultiPolygon>::value
- >::value,
- geometry::closure<MultiPolygon>::value,
- Strategy
- >
- >::apply(point, multi_polygon, strategy) == 1;
- }
-};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_ALGORITHMS_WITHIN_HPP
diff --git a/boost/geometry/multi/core/closure.hpp b/boost/geometry/multi/core/closure.hpp
index 3964db256c..9e7cf3c248 100644
--- a/boost/geometry/multi/core/closure.hpp
+++ b/boost/geometry/multi/core/closure.hpp
@@ -14,45 +14,6 @@
#ifndef BOOST_GEOMETRY_MULTI_CORE_CLOSURE_HPP
#define BOOST_GEOMETRY_MULTI_CORE_CLOSURE_HPP
-
-#include <boost/mpl/assert.hpp>
-#include <boost/range.hpp>
-#include <boost/type_traits/remove_const.hpp>
-
#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-template <typename Multi>
-struct closure<multi_point_tag, Multi> : public core_detail::closure::closed {};
-
-template <typename Multi>
-struct closure<multi_linestring_tag, Multi> : public core_detail::closure::closed {};
-
-// Specialization for polygon: the closure is the closure of its rings
-template <typename MultiPolygon>
-struct closure<multi_polygon_tag, MultiPolygon>
-{
- static const closure_selector value = core_dispatch::closure
- <
- polygon_tag,
- typename boost::range_value<MultiPolygon>::type
- >::value ;
-};
-
-
-} // namespace core_dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_CORE_CLOSURE_HPP
diff --git a/boost/geometry/multi/core/geometry_id.hpp b/boost/geometry/multi/core/geometry_id.hpp
index 9d69cb20d9..7d5e888bab 100644
--- a/boost/geometry/multi/core/geometry_id.hpp
+++ b/boost/geometry/multi/core/geometry_id.hpp
@@ -15,42 +15,6 @@
#ifndef BOOST_GEOMETRY_MULTI_CORE_GEOMETRY_ID_HPP
#define BOOST_GEOMETRY_MULTI_CORE_GEOMETRY_ID_HPP
-
-#include <boost/mpl/int.hpp>
-#include <boost/type_traits.hpp>
-
-
-#include <boost/geometry/core/tag.hpp>
-#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/geometry_id.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-template <>
-struct geometry_id<multi_point_tag> : boost::mpl::int_<4> {};
-
-
-template <>
-struct geometry_id<multi_linestring_tag> : boost::mpl::int_<5> {};
-
-
-template <>
-struct geometry_id<multi_polygon_tag> : boost::mpl::int_<6> {};
-
-
-} // namespace core_dispatch
-#endif
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_CORE_GEOMETRY_ID_HPP
diff --git a/boost/geometry/multi/core/interior_rings.hpp b/boost/geometry/multi/core/interior_rings.hpp
index 5a200d486c..deeeff81d0 100644
--- a/boost/geometry/multi/core/interior_rings.hpp
+++ b/boost/geometry/multi/core/interior_rings.hpp
@@ -16,40 +16,7 @@
#define BOOST_GEOMETRY_MULTI_CORE_INTERIOR_RINGS_HPP
-#include <cstddef>
-
-#include <boost/range.hpp>
-
#include <boost/geometry/core/interior_rings.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-
-template <typename MultiPolygon>
-struct interior_type<multi_polygon_tag, MultiPolygon>
-{
- typedef typename core_dispatch::interior_type
- <
- polygon_tag,
- typename boost::range_value<MultiPolygon>::type
- >::type type;
-};
-
-
-} // namespace core_dispatch
-#endif
-
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_CORE_INTERIOR_RINGS_HPP
diff --git a/boost/geometry/multi/core/is_areal.hpp b/boost/geometry/multi/core/is_areal.hpp
index ad8daeb497..30f98527ab 100644
--- a/boost/geometry/multi/core/is_areal.hpp
+++ b/boost/geometry/multi/core/is_areal.hpp
@@ -16,28 +16,7 @@
#define BOOST_GEOMETRY_MULTI_CORE_IS_AREAL_HPP
-#include <boost/type_traits.hpp>
-
-
#include <boost/geometry/core/is_areal.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-template <> struct is_areal<multi_polygon_tag> : boost::true_type {};
-
-} // namespace core_dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_CORE_IS_AREAL_HPP
diff --git a/boost/geometry/multi/core/point_order.hpp b/boost/geometry/multi/core/point_order.hpp
index 6b08468e8c..119e55c3ba 100644
--- a/boost/geometry/multi/core/point_order.hpp
+++ b/boost/geometry/multi/core/point_order.hpp
@@ -15,43 +15,7 @@
#define BOOST_GEOMETRY_MULTI_CORE_POINT_ORDER_HPP
-#include <boost/range.hpp>
-
#include <boost/geometry/core/point_order.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-template <typename Multi>
-struct point_order<multi_point_tag, Multi>
- : public detail::point_order::clockwise {};
-
-template <typename Multi>
-struct point_order<multi_linestring_tag, Multi>
- : public detail::point_order::clockwise {};
-
-
-// Specialization for multi_polygon: the order is the order of its polygons
-template <typename MultiPolygon>
-struct point_order<multi_polygon_tag, MultiPolygon>
-{
- static const order_selector value = core_dispatch::point_order
- <
- polygon_tag,
- typename boost::range_value<MultiPolygon>::type
- >::value ;
-};
-
-} // namespace core_dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_CORE_POINT_ORDER_HPP
diff --git a/boost/geometry/multi/core/point_type.hpp b/boost/geometry/multi/core/point_type.hpp
index 3c77e973b8..a7277d09a9 100644
--- a/boost/geometry/multi/core/point_type.hpp
+++ b/boost/geometry/multi/core/point_type.hpp
@@ -16,49 +16,7 @@
#define BOOST_GEOMETRY_MULTI_CORE_POINT_TYPE_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-template <typename MultiPoint>
-struct point_type<multi_point_tag, MultiPoint>
-{
- typedef typename boost::range_value<MultiPoint>::type type;
-};
-
-
-template <typename MultiLinestring>
-struct point_type<multi_linestring_tag, MultiLinestring>
-{
- typedef typename point_type<linestring_tag,
- typename boost::range_value<MultiLinestring>::type>::type type;
-};
-
-
-
-template <typename MultiPolygon>
-struct point_type<multi_polygon_tag, MultiPolygon>
-{
- typedef typename point_type<polygon_tag,
- typename boost::range_value<MultiPolygon>::type>::type type;
-};
-
-
-}
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_CORE_POINT_TYPE_HPP
diff --git a/boost/geometry/multi/core/ring_type.hpp b/boost/geometry/multi/core/ring_type.hpp
index faafaed021..b27b5527c2 100644
--- a/boost/geometry/multi/core/ring_type.hpp
+++ b/boost/geometry/multi/core/ring_type.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -16,51 +19,7 @@
#define BOOST_GEOMETRY_MULTI_CORE_RING_TYPE_HPP
-#include <boost/range/metafunctions.hpp>
-
#include <boost/geometry/core/ring_type.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-template <typename MultiPolygon>
-struct ring_return_type<multi_polygon_tag, MultiPolygon>
-{
- typedef typename ring_return_type
- <
- polygon_tag,
- typename mpl::if_
- <
- boost::is_const<MultiPolygon>,
- typename boost::range_value<MultiPolygon>::type const,
- typename boost::range_value<MultiPolygon>::type
- >::type
- >::type type;
-};
-
-
-template <typename MultiPolygon>
-struct ring_type<multi_polygon_tag, MultiPolygon>
-{
- typedef typename boost::remove_reference
- <
- typename ring_return_type<multi_polygon_tag, MultiPolygon>::type
- >::type type;
-};
-
-
-} // namespace core_dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_CORE_RING_TYPE_HPP
diff --git a/boost/geometry/multi/core/tags.hpp b/boost/geometry/multi/core/tags.hpp
index dcfca65b2f..fb0758d95f 100644
--- a/boost/geometry/multi/core/tags.hpp
+++ b/boost/geometry/multi/core/tags.hpp
@@ -15,57 +15,8 @@
#ifndef BOOST_GEOMETRY_MULTI_CORE_TAGS_HPP
#define BOOST_GEOMETRY_MULTI_CORE_TAGS_HPP
-#include <boost/geometry/core/tags.hpp>
-
-namespace boost { namespace geometry
-{
-
-/// OGC Multi point identifying tag
-struct multi_point_tag : multi_tag, pointlike_tag {};
-
-/// OGC Multi linestring identifying tag
-struct multi_linestring_tag : multi_tag, linear_tag {};
-
-/// OGC Multi polygon identifying tag
-struct multi_polygon_tag : multi_tag, polygonal_tag {};
-
-/// OGC Geometry Collection identifying tag
-struct geometry_collection_tag : multi_tag {};
-
-
-
-
-/*!
-\brief Meta-function to get for a tag of a multi-geometry
- the tag of the corresponding single-geometry
-*/
-template <typename Tag>
-struct single_tag_of
-{};
-
-#ifndef DOXYGEN_NO_DETAIL
-
-template <>
-struct single_tag_of<multi_point_tag>
-{
- typedef point_tag type;
-};
-
-template <>
-struct single_tag_of<multi_linestring_tag>
-{
- typedef linestring_tag type;
-};
-
-template <>
-struct single_tag_of<multi_polygon_tag>
-{
- typedef polygon_tag type;
-};
-
-#endif
+#include <boost/geometry/core/tags.hpp>
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_CORE_TAGS_HPP
diff --git a/boost/geometry/multi/core/topological_dimension.hpp b/boost/geometry/multi/core/topological_dimension.hpp
index 55118f1c73..b4f1e89ae8 100644
--- a/boost/geometry/multi/core/topological_dimension.hpp
+++ b/boost/geometry/multi/core/topological_dimension.hpp
@@ -16,37 +16,7 @@
#define BOOST_GEOMETRY_MULTI_TOPOLOGICAL_DIMENSION_HPP
-#include <boost/mpl/int.hpp>
-
-
#include <boost/geometry/core/topological_dimension.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace core_dispatch
-{
-
-template <>
-struct top_dim<multi_point_tag> : boost::mpl::int_<0> {};
-
-
-template <>
-struct top_dim<multi_linestring_tag> : boost::mpl::int_<1> {};
-
-
-template <>
-struct top_dim<multi_polygon_tag> : boost::mpl::int_<2> {};
-
-
-} // namespace core_dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif
diff --git a/boost/geometry/multi/geometries/concepts/check.hpp b/boost/geometry/multi/geometries/concepts/check.hpp
index 18f4ff0c25..c741afd794 100644
--- a/boost/geometry/multi/geometries/concepts/check.hpp
+++ b/boost/geometry/multi/geometries/concepts/check.hpp
@@ -16,68 +16,7 @@
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_CHECK_HPP
-
-#include <boost/type_traits/is_const.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
-
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/multi/geometries/concepts/multi_point_concept.hpp>
-#include <boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp>
-#include <boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template <typename Geometry>
-struct check<multi_point_tag, Geometry, true>
- : detail::concept_check::check<concept::ConstMultiPoint<Geometry> >
-{};
-
-
-template <typename Geometry>
-struct check<multi_point_tag, Geometry, false>
- : detail::concept_check::check<concept::MultiPoint<Geometry> >
-{};
-
-
-template <typename Geometry>
-struct check<multi_linestring_tag, Geometry, true>
- : detail::concept_check::check<concept::ConstMultiLinestring<Geometry> >
-{};
-
-
-template <typename Geometry>
-struct check<multi_linestring_tag, Geometry, false>
- : detail::concept_check::check<concept::MultiLinestring<Geometry> >
-{};
-
-
-template <typename Geometry>
-struct check<multi_polygon_tag, Geometry, true>
- : detail::concept_check::check<concept::ConstMultiPolygon<Geometry> >
-{};
-
-
-template <typename Geometry>
-struct check<multi_polygon_tag, Geometry, false>
- : detail::concept_check::check<concept::MultiPolygon<Geometry> >
-{};
-
-
-} // namespace dispatch
-#endif
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_CHECK_HPP
diff --git a/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp b/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp
index b0519f07ee..9a9438efcc 100644
--- a/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp
+++ b/boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp
@@ -16,71 +16,7 @@
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP
-#include <boost/concept_check.hpp>
-#include <boost/range/concepts.hpp>
-#include <boost/range/metafunctions.hpp>
-
-
-#include <boost/geometry/geometries/concepts/linestring_concept.hpp>
-
-
-namespace boost { namespace geometry { namespace concept
-{
-
-
-/*!
-\brief multi-linestring concept
-\ingroup concepts
-\par Formal definition:
-The multi linestring concept is defined as following:
-- there must be a specialization of traits::tag defining multi_linestring_tag as
- type
-- it must behave like a Boost.Range
-- its range value must fulfil the Linestring concept
-
-*/
-template <typename Geometry>
-class MultiLinestring
-{
-#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
- typedef typename boost::range_value<Geometry>::type linestring_type;
-
- BOOST_CONCEPT_ASSERT( (concept::Linestring<linestring_type>) );
- BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
-
-
-public :
-
- BOOST_CONCEPT_USAGE(MultiLinestring)
- {
- }
-#endif
-};
-
-
-/*!
-\brief concept for multi-linestring (const version)
-\ingroup const_concepts
-*/
-template <typename Geometry>
-class ConstMultiLinestring
-{
-#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
- typedef typename boost::range_value<Geometry>::type linestring_type;
-
- BOOST_CONCEPT_ASSERT( (concept::ConstLinestring<linestring_type>) );
- BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
-
-
-public :
-
- BOOST_CONCEPT_USAGE(ConstMultiLinestring)
- {
- }
-#endif
-};
-
-}}} // namespace boost::geometry::concept
+#include <boost/geometry/geometries/concepts/multi_linestring_concept.hpp>
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP
diff --git a/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp b/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp
index f5942df070..14c1d25e57 100644
--- a/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp
+++ b/boost/geometry/multi/geometries/concepts/multi_point_concept.hpp
@@ -16,70 +16,7 @@
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP
-#include <boost/concept_check.hpp>
-#include <boost/range/concepts.hpp>
-#include <boost/range/metafunctions.hpp>
-
-
-#include <boost/geometry/geometries/concepts/point_concept.hpp>
-
-
-namespace boost { namespace geometry { namespace concept
-{
-
-
-/*!
-\brief MultiPoint concept
-\ingroup concepts
-\par Formal definition:
-The multi point concept is defined as following:
-- there must be a specialization of traits::tag defining multi_point_tag as type
-- it must behave like a Boost.Range
-- its range value must fulfil the Point concept
-
-*/
-template <typename Geometry>
-class MultiPoint
-{
-#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
- typedef typename boost::range_value<Geometry>::type point_type;
-
- BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) );
- BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
-
-
-public :
-
- BOOST_CONCEPT_USAGE(MultiPoint)
- {
- }
-#endif
-};
-
-
-/*!
-\brief concept for multi-point (const version)
-\ingroup const_concepts
-*/
-template <typename Geometry>
-class ConstMultiPoint
-{
-#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
- typedef typename boost::range_value<Geometry>::type point_type;
-
- BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) );
- BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
-
-
-public :
-
- BOOST_CONCEPT_USAGE(ConstMultiPoint)
- {
- }
-#endif
-};
-
-}}} // namespace boost::geometry::concept
+#include <boost/geometry/geometries/concepts/multi_point_concept.hpp>
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP
diff --git a/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp b/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp
index ca730d4f6b..5e46fb7539 100644
--- a/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp
+++ b/boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp
@@ -16,71 +16,7 @@
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP
-#include <boost/concept_check.hpp>
-#include <boost/range/concepts.hpp>
-#include <boost/range/metafunctions.hpp>
-
-#include <boost/geometry/geometries/concepts/polygon_concept.hpp>
-
-
-namespace boost { namespace geometry { namespace concept
-{
-
-
-/*!
-\brief multi-polygon concept
-\ingroup concepts
-\par Formal definition:
-The multi polygon concept is defined as following:
-- there must be a specialization of traits::tag defining multi_polygon_tag
- as type
-- it must behave like a Boost.Range
-- its range value must fulfil the Polygon concept
-
-*/
-template <typename Geometry>
-class MultiPolygon
-{
-#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
- typedef typename boost::range_value<Geometry>::type polygon_type;
-
- BOOST_CONCEPT_ASSERT( (concept::Polygon<polygon_type>) );
- BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
-
-
-public :
-
- BOOST_CONCEPT_USAGE(MultiPolygon)
- {
- }
-#endif
-};
-
-
-/*!
-\brief concept for multi-polygon (const version)
-\ingroup const_concepts
-*/
-template <typename Geometry>
-class ConstMultiPolygon
-{
-#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
- typedef typename boost::range_value<Geometry>::type polygon_type;
-
- BOOST_CONCEPT_ASSERT( (concept::ConstPolygon<polygon_type>) );
- BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept<Geometry>) );
-
-
-public :
-
- BOOST_CONCEPT_USAGE(ConstMultiPolygon)
- {
- }
-#endif
-};
-
-
-}}} // namespace boost::geometry::concept
+#include <boost/geometry/geometries/concepts/multi_polygon_concept.hpp>
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP
diff --git a/boost/geometry/multi/geometries/multi_geometries.hpp b/boost/geometry/multi/geometries/multi_geometries.hpp
index 90cf85a0f6..53042091bd 100644
--- a/boost/geometry/multi/geometries/multi_geometries.hpp
+++ b/boost/geometry/multi/geometries/multi_geometries.hpp
@@ -14,8 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_GEOMETRIES_HPP
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_GEOMETRIES_HPP
-#include <boost/geometry/multi/geometries/multi_point.hpp>
-#include <boost/geometry/multi/geometries/multi_linestring.hpp>
-#include <boost/geometry/multi/geometries/multi_polygon.hpp>
+#include <boost/geometry/geometries/multi_point.hpp>
+#include <boost/geometry/geometries/multi_linestring.hpp>
+#include <boost/geometry/geometries/multi_polygon.hpp>
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_GEOMETRIES_HPP
diff --git a/boost/geometry/multi/geometries/multi_linestring.hpp b/boost/geometry/multi/geometries/multi_linestring.hpp
index 67d4da06b7..696d907dcc 100644
--- a/boost/geometry/multi/geometries/multi_linestring.hpp
+++ b/boost/geometry/multi/geometries/multi_linestring.hpp
@@ -11,70 +11,11 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_LINESTRING_HPP
-#define BOOST_GEOMETRY_MULTI_GEOMETRIES_LINESTRING_HPP
+#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_LINESTRING_HPP
+#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_LINESTRING_HPP
-#include <memory>
-#include <vector>
-#include <boost/concept/requires.hpp>
+#include <boost/geometry/geometries/multi_linestring.hpp>
-#include <boost/geometry/geometries/concepts/linestring_concept.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-namespace boost { namespace geometry
-{
-
-
-namespace model
-{
-
-/*!
-\brief multi_line, a collection of linestring
-\details Multi-linestring can be used to group lines belonging to each other,
- e.g. a highway (with interruptions)
-\ingroup geometries
-
-\qbk{before.synopsis,
-[heading Model of]
-[link geometry.reference.concepts.concept_multi_linestring MultiLineString Concept]
-}
-*/
-template
-<
- typename LineString,
- template<typename, typename> class Container = std::vector,
- template<typename> class Allocator = std::allocator
->
-class multi_linestring : public Container<LineString, Allocator<LineString> >
-{
- BOOST_CONCEPT_ASSERT( (concept::Linestring<LineString>) );
-};
-
-
-} // namespace model
-
-
-#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
-namespace traits
-{
-
-template
-<
- typename LineString,
- template<typename, typename> class Container,
- template<typename> class Allocator
->
-struct tag< model::multi_linestring<LineString, Container, Allocator> >
-{
- typedef multi_linestring_tag type;
-};
-
-} // namespace traits
-#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
-
-
-}} // namespace boost::geometry
-
-#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_LINESTRING_HPP
+#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_LINESTRING_HPP
diff --git a/boost/geometry/multi/geometries/multi_point.hpp b/boost/geometry/multi/geometries/multi_point.hpp
index 002d8f8a4b..750ad7802a 100644
--- a/boost/geometry/multi/geometries/multi_point.hpp
+++ b/boost/geometry/multi/geometries/multi_point.hpp
@@ -14,81 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POINT_HPP
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POINT_HPP
-#include <memory>
-#include <vector>
-#include <boost/concept/requires.hpp>
+#include <boost/geometry/geometries/multi_point.hpp>
-#include <boost/geometry/geometries/concepts/point_concept.hpp>
-
-#include <boost/geometry/multi/core/tags.hpp>
-
-namespace boost { namespace geometry
-{
-
-namespace model
-{
-
-
-/*!
-\brief multi_point, a collection of points
-\ingroup geometries
-\tparam Point \tparam_point
-\tparam Container \tparam_container
-\tparam Allocator \tparam_allocator
-\details Multipoint can be used to group points belonging to each other,
- e.g. a constellation, or the result set of an intersection
-\qbk{before.synopsis,
-[heading Model of]
-[link geometry.reference.concepts.concept_multi_point MultiPoint Concept]
-}
-*/
-template
-<
- typename Point,
- template<typename, typename> class Container = std::vector,
- template<typename> class Allocator = std::allocator
->
-class multi_point : public Container<Point, Allocator<Point> >
-{
- BOOST_CONCEPT_ASSERT( (concept::Point<Point>) );
-
- typedef Container<Point, Allocator<Point> > base_type;
-
-public :
- /// \constructor_default{multi_point}
- inline multi_point()
- : base_type()
- {}
-
- /// \constructor_begin_end{multi_point}
- template <typename Iterator>
- inline multi_point(Iterator begin, Iterator end)
- : base_type(begin, end)
- {}
-};
-
-} // namespace model
-
-
-#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
-namespace traits
-{
-
-template
-<
- typename Point,
- template<typename, typename> class Container,
- template<typename> class Allocator
->
-struct tag< model::multi_point<Point, Container, Allocator> >
-{
- typedef multi_point_tag type;
-};
-
-} // namespace traits
-#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POINT_HPP
diff --git a/boost/geometry/multi/geometries/multi_polygon.hpp b/boost/geometry/multi/geometries/multi_polygon.hpp
index af8d042873..06fefc7856 100644
--- a/boost/geometry/multi/geometries/multi_polygon.hpp
+++ b/boost/geometry/multi/geometries/multi_polygon.hpp
@@ -14,65 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POLYGON_HPP
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POLYGON_HPP
-#include <memory>
-#include <vector>
-#include <boost/concept/requires.hpp>
+#include <boost/geometry/geometries/multi_polygon.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-#include <boost/geometry/geometries/concepts/polygon_concept.hpp>
-
-namespace boost { namespace geometry
-{
-
-namespace model
-{
-
-/*!
-\brief multi_polygon, a collection of polygons
-\details Multi-polygon can be used to group polygons belonging to each other,
- e.g. Hawaii
-\ingroup geometries
-
-\qbk{before.synopsis,
-[heading Model of]
-[link geometry.reference.concepts.concept_multi_polygon MultiPolygon Concept]
-}
-*/
-template
-<
- typename Polygon,
- template<typename, typename> class Container = std::vector,
- template<typename> class Allocator = std::allocator
->
-class multi_polygon : public Container<Polygon, Allocator<Polygon> >
-{
- BOOST_CONCEPT_ASSERT( (concept::Polygon<Polygon>) );
-};
-
-
-} // namespace model
-
-
-#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
-namespace traits
-{
-
-template
-<
- typename Polygon,
- template<typename, typename> class Container,
- template<typename> class Allocator
->
-struct tag< model::multi_polygon<Polygon, Container, Allocator> >
-{
- typedef multi_polygon_tag type;
-};
-
-} // namespace traits
-#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_MULTI_POLYGON_HPP
diff --git a/boost/geometry/multi/geometries/register/multi_linestring.hpp b/boost/geometry/multi/geometries/register/multi_linestring.hpp
index 5ececdb8e8..2783a8455b 100644
--- a/boost/geometry/multi/geometries/register/multi_linestring.hpp
+++ b/boost/geometry/multi/geometries/register/multi_linestring.hpp
@@ -15,45 +15,8 @@
#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP
-#include <boost/geometry/core/tag.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-/*!
-\brief \brief_macro{multi_linestring}
-\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING, multi_linestring} The
- multi_linestring may contain template parameters, which must be specified then.
-\param MultiLineString \param_macro_type{multi_linestring}
-
-\qbk{
-[heading Example]
-[register_multi_linestring]
-[register_multi_linestring_output]
-}
-*/
-#define BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING(MultiLineString) \
-namespace boost { namespace geometry { namespace traits { \
- template<> struct tag<MultiLineString> { typedef multi_linestring_tag type; }; \
-}}}
-
-
-/*!
-\brief \brief_macro{templated multi_linestring}
-\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING_TEMPLATED, templated multi_linestring}
- \details_macro_templated{multi_linestring, linestring}
-\param MultiLineString \param_macro_type{multi_linestring (without template parameters)}
-
-\qbk{
-[heading Example]
-[register_multi_linestring_templated]
-[register_multi_linestring_templated_output]
-}
-*/
-#define BOOST_GEOMETRY_REGISTER_MULTI_LINESTRING_TEMPLATED(MultiLineString) \
-namespace boost { namespace geometry { namespace traits { \
- template<typename LineString> struct tag< MultiLineString<LineString> > { typedef multi_linestring_tag type; }; \
-}}}
+
+#include <boost/geometry/geometries/register/multi_linestring.hpp>
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_LINESTRING_HPP
diff --git a/boost/geometry/multi/geometries/register/multi_point.hpp b/boost/geometry/multi/geometries/register/multi_point.hpp
index 813f54733d..6063492c2b 100644
--- a/boost/geometry/multi/geometries/register/multi_point.hpp
+++ b/boost/geometry/multi/geometries/register/multi_point.hpp
@@ -15,45 +15,8 @@
#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POINT_HPP
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POINT_HPP
-#include <boost/geometry/core/tag.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-/*!
-\brief \brief_macro{multi_point}
-\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POINT, multi_point} The
- multi_point may contain template parameters, which must be specified then.
-\param MultiPoint \param_macro_type{multi_point}
-
-\qbk{
-[heading Example]
-[register_multi_point]
-[register_multi_point_output]
-}
-*/
-#define BOOST_GEOMETRY_REGISTER_MULTI_POINT(MultiPoint) \
-namespace boost { namespace geometry { namespace traits { \
- template<> struct tag<MultiPoint> { typedef multi_point_tag type; }; \
-}}}
-
-
-/*!
-\brief \brief_macro{templated multi_point}
-\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED, templated multi_point}
- \details_macro_templated{multi_point, point}
-\param MultiPoint \param_macro_type{multi_point (without template parameters)}
-
-\qbk{
-[heading Example]
-[register_multi_point_templated]
-[register_multi_point_templated_output]
-}
-*/
-#define BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED(MultiPoint) \
-namespace boost { namespace geometry { namespace traits { \
- template<typename Point> struct tag< MultiPoint<Point> > { typedef multi_point_tag type; }; \
-}}}
+
+#include <boost/geometry/geometries/register/multi_point.hpp>
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POINT_HPP
diff --git a/boost/geometry/multi/geometries/register/multi_polygon.hpp b/boost/geometry/multi/geometries/register/multi_polygon.hpp
index 801b98cf24..6a3e47e3da 100644
--- a/boost/geometry/multi/geometries/register/multi_polygon.hpp
+++ b/boost/geometry/multi/geometries/register/multi_polygon.hpp
@@ -15,45 +15,8 @@
#ifndef BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP
#define BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP
-#include <boost/geometry/core/tag.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-
-/*!
-\brief \brief_macro{multi_polygon}
-\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POLYGON, multi_polygon} The
- multi_polygon may contain template parameters, which must be specified then.
-\param MultiPolygon \param_macro_type{multi_polygon}
-
-\qbk{
-[heading Example]
-[register_multi_polygon]
-[register_multi_polygon_output]
-}
-*/
-#define BOOST_GEOMETRY_REGISTER_MULTI_POLYGON(MultiPolygon) \
-namespace boost { namespace geometry { namespace traits { \
- template<> struct tag<MultiPolygon> { typedef multi_polygon_tag type; }; \
-}}}
-
-
-/*!
-\brief \brief_macro{templated multi_polygon}
-\ingroup register
-\details \details_macro{BOOST_GEOMETRY_REGISTER_MULTI_POLYGON_TEMPLATED, templated multi_polygon}
- \details_macro_templated{multi_polygon, polygon}
-\param MultiPolygon \param_macro_type{multi_polygon (without template parameters)}
-
-\qbk{
-[heading Example]
-[register_multi_polygon_templated]
-[register_multi_polygon_templated_output]
-}
-*/
-#define BOOST_GEOMETRY_REGISTER_MULTI_POLYGON_TEMPLATED(MultiPolygon) \
-namespace boost { namespace geometry { namespace traits { \
- template<typename Polygon> struct tag< MultiPolygon<Polygon> > { typedef multi_polygon_tag type; }; \
-}}}
+
+#include <boost/geometry/geometries/register/multi_polygon.hpp>
#endif // BOOST_GEOMETRY_MULTI_GEOMETRIES_REGISTER_MULTI_POLYGON_HPP
diff --git a/boost/geometry/multi/io/dsv/write.hpp b/boost/geometry/multi/io/dsv/write.hpp
index be40b5da5a..092869f56c 100644
--- a/boost/geometry/multi/io/dsv/write.hpp
+++ b/boost/geometry/multi/io/dsv/write.hpp
@@ -14,70 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP
#define BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP
-#include <boost/range.hpp>
#include <boost/geometry/io/dsv/write.hpp>
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace dsv
-{
-
-template <typename MultiGeometry>
-struct dsv_multi
-{
- typedef dispatch::dsv
- <
- typename single_tag_of
- <
- typename tag<MultiGeometry>::type
- >::type,
- typename boost::range_value<MultiGeometry>::type
- > dispatch_one;
-
- typedef typename boost::range_iterator
- <
- MultiGeometry const
- >::type iterator;
-
-
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os,
- MultiGeometry const& multi,
- dsv_settings const& settings)
- {
- os << settings.list_open;
-
- bool first = true;
- for(iterator it = boost::begin(multi);
- it != boost::end(multi);
- ++it, first = false)
- {
- os << (first ? "" : settings.list_separator);
- dispatch_one::apply(os, *it, settings);
- }
- os << settings.list_close;
- }
-};
-
-}} // namespace detail::dsv
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename Geometry>
-struct dsv<multi_tag, Geometry>
- : detail::dsv::dsv_multi<Geometry>
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_DSV_WRITE_HPP
diff --git a/boost/geometry/multi/io/wkt/detail/prefix.hpp b/boost/geometry/multi/io/wkt/detail/prefix.hpp
index 37b07979ba..34e2b241d0 100644
--- a/boost/geometry/multi/io/wkt/detail/prefix.hpp
+++ b/boost/geometry/multi/io/wkt/detail/prefix.hpp
@@ -14,38 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP
-#include <boost/geometry/multi/core/tags.hpp>
-namespace boost { namespace geometry
-{
+#include <boost/geometry/io/wkt/detail/prefix.hpp>
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace wkt
-{
-
-struct prefix_null
-{
- static inline const char* apply() { return ""; }
-};
-
-struct prefix_multipoint
-{
- static inline const char* apply() { return "MULTIPOINT"; }
-};
-
-struct prefix_multilinestring
-{
- static inline const char* apply() { return "MULTILINESTRING"; }
-};
-
-struct prefix_multipolygon
-{
- static inline const char* apply() { return "MULTIPOLYGON"; }
-};
-
-}} // namespace wkt::impl
-#endif
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP
diff --git a/boost/geometry/multi/io/wkt/read.hpp b/boost/geometry/multi/io/wkt/read.hpp
index 218ddf9999..37e5f9e72e 100644
--- a/boost/geometry/multi/io/wkt/read.hpp
+++ b/boost/geometry/multi/io/wkt/read.hpp
@@ -14,154 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_IO_WKT_READ_MULTI_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKT_READ_MULTI_HPP
-#include <string>
-#include <boost/geometry/core/mutable_range.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/core/point_type.hpp>
-#include <boost/geometry/multi/io/wkt/detail/prefix.hpp>
#include <boost/geometry/io/wkt/read.hpp>
-namespace boost { namespace geometry
-{
-
-namespace detail { namespace wkt
-{
-
-template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
-struct multi_parser
-{
- static inline void apply(std::string const& wkt, MultiGeometry& geometry)
- {
- traits::clear<MultiGeometry>::apply(geometry);
-
- tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
- tokenizer::iterator it;
- if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
- {
- handle_open_parenthesis(it, tokens.end(), wkt);
-
- // Parse sub-geometries
- while(it != tokens.end() && *it != ")")
- {
- traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
- Parser
- <
- typename boost::range_value<MultiGeometry>::type
- >::apply(it, tokens.end(), wkt, geometry.back());
- if (it != tokens.end() && *it == ",")
- {
- // Skip "," after multi-element is parsed
- ++it;
- }
- }
-
- handle_close_parenthesis(it, tokens.end(), wkt);
- }
-
- check_end(it, tokens.end(), wkt);
- }
-};
-
-template <typename P>
-struct noparenthesis_point_parser
-{
- static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
- std::string const& wkt, P& point)
- {
- parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt);
- }
-};
-
-template <typename MultiGeometry, typename PrefixPolicy>
-struct multi_point_parser
-{
- static inline void apply(std::string const& wkt, MultiGeometry& geometry)
- {
- traits::clear<MultiGeometry>::apply(geometry);
-
- tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
- tokenizer::iterator it;
-
- if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
- {
- handle_open_parenthesis(it, tokens.end(), wkt);
-
- // If first point definition starts with "(" then parse points as (x y)
- // otherwise as "x y"
- bool using_brackets = (it != tokens.end() && *it == "(");
-
- while(it != tokens.end() && *it != ")")
- {
- traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
-
- if (using_brackets)
- {
- point_parser
- <
- typename boost::range_value<MultiGeometry>::type
- >::apply(it, tokens.end(), wkt, geometry.back());
- }
- else
- {
- noparenthesis_point_parser
- <
- typename boost::range_value<MultiGeometry>::type
- >::apply(it, tokens.end(), wkt, geometry.back());
- }
-
- if (it != tokens.end() && *it == ",")
- {
- // Skip "," after point is parsed
- ++it;
- }
- }
-
- handle_close_parenthesis(it, tokens.end(), wkt);
- }
-
- check_end(it, tokens.end(), wkt);
- }
-};
-
-}} // namespace detail::wkt
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename MultiGeometry>
-struct read_wkt<multi_point_tag, MultiGeometry>
- : detail::wkt::multi_point_parser
- <
- MultiGeometry,
- detail::wkt::prefix_multipoint
- >
-{};
-
-template <typename MultiGeometry>
-struct read_wkt<multi_linestring_tag, MultiGeometry>
- : detail::wkt::multi_parser
- <
- MultiGeometry,
- detail::wkt::linestring_parser,
- detail::wkt::prefix_multilinestring
- >
-{};
-
-template <typename MultiGeometry>
-struct read_wkt<multi_polygon_tag, MultiGeometry>
- : detail::wkt::multi_parser
- <
- MultiGeometry,
- detail::wkt::polygon_parser,
- detail::wkt::prefix_multipolygon
- >
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_WKT_READ_MULTI_HPP
diff --git a/boost/geometry/multi/io/wkt/wkt.hpp b/boost/geometry/multi/io/wkt/wkt.hpp
index 55f1713d4d..a6159e1409 100644
--- a/boost/geometry/multi/io/wkt/wkt.hpp
+++ b/boost/geometry/multi/io/wkt/wkt.hpp
@@ -14,7 +14,7 @@
#ifndef BOOST_GEOMETRY_MULTI_IO_WKT_WKT_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKT_WKT_HPP
-#include <boost/geometry/multi/io/wkt/read.hpp>
-#include <boost/geometry/multi/io/wkt/write.hpp>
+#include <boost/geometry/io/wkt/read.hpp>
+#include <boost/geometry/io/wkt/write.hpp>
#endif // BOOST_GEOMETRY_MULTI_IO_WKT_WKT_HPP
diff --git a/boost/geometry/multi/io/wkt/write.hpp b/boost/geometry/multi/io/wkt/write.hpp
index 374da28b53..2c26d3d2e4 100644
--- a/boost/geometry/multi/io/wkt/write.hpp
+++ b/boost/geometry/multi/io/wkt/write.hpp
@@ -14,95 +14,8 @@
#ifndef BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/io/wkt/detail/prefix.hpp>
-#include <boost/geometry/io/wkt/write.hpp>
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace wkt
-{
-
-template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
-struct wkt_multi
-{
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os,
- Multi const& geometry)
- {
- os << PrefixPolicy::apply();
- // TODO: check EMPTY here
- os << "(";
-
- for (typename boost::range_iterator<Multi const>::type
- it = boost::begin(geometry);
- it != boost::end(geometry);
- ++it)
- {
- if (it != boost::begin(geometry))
- {
- os << ",";
- }
- StreamPolicy::apply(os, *it);
- }
-
- os << ")";
- }
-};
-}} // namespace wkt::impl
-#endif
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template <typename Multi>
-struct wkt<multi_point_tag, Multi>
- : detail::wkt::wkt_multi
- <
- Multi,
- detail::wkt::wkt_point
- <
- typename boost::range_value<Multi>::type,
- detail::wkt::prefix_null
- >,
- detail::wkt::prefix_multipoint
- >
-{};
-
-template <typename Multi>
-struct wkt<multi_linestring_tag, Multi>
- : detail::wkt::wkt_multi
- <
- Multi,
- detail::wkt::wkt_sequence
- <
- typename boost::range_value<Multi>::type
- >,
- detail::wkt::prefix_multilinestring
- >
-{};
-
-template <typename Multi>
-struct wkt<multi_polygon_tag, Multi>
- : detail::wkt::wkt_multi
- <
- Multi,
- detail::wkt::wkt_poly
- <
- typename boost::range_value<Multi>::type,
- detail::wkt::prefix_null
- >,
- detail::wkt::prefix_multipolygon
- >
-{};
-
-} // namespace dispatch
-#endif
+#include <boost/geometry/io/wkt/write.hpp>
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_IO_WKT_WRITE_HPP
diff --git a/boost/geometry/multi/multi.hpp b/boost/geometry/multi/multi.hpp
index db33a9dd03..4b3063e520 100644
--- a/boost/geometry/multi/multi.hpp
+++ b/boost/geometry/multi/multi.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -15,63 +18,64 @@
#define BOOST_GEOMETRY_MULTI_HPP
-#include <boost/geometry/multi/core/closure.hpp>
-#include <boost/geometry/multi/core/geometry_id.hpp>
-#include <boost/geometry/multi/core/interior_rings.hpp>
-#include <boost/geometry/multi/core/is_areal.hpp>
-#include <boost/geometry/multi/core/point_order.hpp>
-#include <boost/geometry/multi/core/point_type.hpp>
-#include <boost/geometry/multi/core/ring_type.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
-#include <boost/geometry/multi/core/topological_dimension.hpp>
-
-#include <boost/geometry/multi/algorithms/append.hpp>
-#include <boost/geometry/multi/algorithms/area.hpp>
-#include <boost/geometry/multi/algorithms/centroid.hpp>
-#include <boost/geometry/multi/algorithms/clear.hpp>
-#include <boost/geometry/multi/algorithms/convert.hpp>
-#include <boost/geometry/multi/algorithms/correct.hpp>
-#include <boost/geometry/multi/algorithms/covered_by.hpp>
-#include <boost/geometry/multi/algorithms/distance.hpp>
-#include <boost/geometry/multi/algorithms/envelope.hpp>
-#include <boost/geometry/multi/algorithms/equals.hpp>
-#include <boost/geometry/multi/algorithms/for_each.hpp>
-#include <boost/geometry/multi/algorithms/intersection.hpp>
-#include <boost/geometry/multi/algorithms/length.hpp>
-#include <boost/geometry/multi/algorithms/num_geometries.hpp>
-#include <boost/geometry/multi/algorithms/num_interior_rings.hpp>
-#include <boost/geometry/multi/algorithms/num_points.hpp>
-#include <boost/geometry/multi/algorithms/perimeter.hpp>
-#include <boost/geometry/multi/algorithms/reverse.hpp>
-#include <boost/geometry/multi/algorithms/simplify.hpp>
-#include <boost/geometry/multi/algorithms/transform.hpp>
-#include <boost/geometry/multi/algorithms/unique.hpp>
-#include <boost/geometry/multi/algorithms/within.hpp>
-
-#include <boost/geometry/multi/algorithms/detail/for_each_range.hpp>
-#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/range_by_section.hpp>
-#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>
-
-#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/get_ring.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/select_rings.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp>
-
-#include <boost/geometry/multi/geometries/concepts/check.hpp>
-#include <boost/geometry/multi/geometries/concepts/multi_point_concept.hpp>
-#include <boost/geometry/multi/geometries/concepts/multi_linestring_concept.hpp>
-#include <boost/geometry/multi/geometries/concepts/multi_polygon_concept.hpp>
-
-#include <boost/geometry/multi/views/detail/range_type.hpp>
-#include <boost/geometry/multi/strategies/cartesian/centroid_average.hpp>
-
-#include <boost/geometry/multi/io/dsv/write.hpp>
-#include <boost/geometry/multi/io/wkt/wkt.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/geometry_id.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/is_areal.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/topological_dimension.hpp>
+
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/centroid.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/correct.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/distance.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/for_each.hpp>
+#include <boost/geometry/algorithms/intersection.hpp>
+#include <boost/geometry/algorithms/length.hpp>
+#include <boost/geometry/algorithms/num_geometries.hpp>
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/perimeter.hpp>
+#include <boost/geometry/algorithms/remove_spikes.hpp>
+#include <boost/geometry/algorithms/reverse.hpp>
+#include <boost/geometry/algorithms/simplify.hpp>
+#include <boost/geometry/algorithms/transform.hpp>
+#include <boost/geometry/algorithms/unique.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+
+#include <boost/geometry/algorithms/detail/for_each_range.hpp>
+#include <boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp>
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
+
+#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/views/detail/range_type.hpp>
+#include <boost/geometry/strategies/cartesian/centroid_average.hpp>
+
+#include <boost/geometry/io/dsv/write.hpp>
+#include <boost/geometry/io/wkt/wkt.hpp>
#endif // BOOST_GEOMETRY_MULTI_HPP
diff --git a/boost/geometry/multi/strategies/cartesian/centroid_average.hpp b/boost/geometry/multi/strategies/cartesian/centroid_average.hpp
index f28daf20bb..ce614e2e76 100644
--- a/boost/geometry/multi/strategies/cartesian/centroid_average.hpp
+++ b/boost/geometry/multi/strategies/cartesian/centroid_average.hpp
@@ -15,102 +15,7 @@
#define BOOST_GEOMETRY_MULTI_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
-#include <boost/numeric/conversion/cast.hpp>
-#include <boost/type_traits.hpp>
-
-#include <boost/geometry/core/coordinate_type.hpp>
-#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/arithmetic/arithmetic.hpp>
-#include <boost/geometry/strategies/centroid.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-namespace strategy { namespace centroid
-{
-
-
-/*!
-\brief Centroid calculation taking average of points
-\ingroup strategies
-*/
-template
-<
- typename PointCentroid,
- typename Point = PointCentroid
->
-class average
-{
-private :
-
- /*! subclass to keep state */
- class sum
- {
- friend class average;
- int count;
- PointCentroid centroid;
-
- public :
- inline sum()
- : count(0)
- {
- assign_zero(centroid);
- }
- };
-
-public :
- typedef sum state_type;
- typedef PointCentroid centroid_point_type;
- typedef Point point_type;
-
- static inline void apply(Point const& p, sum& state)
- {
- add_point(state.centroid, p);
- state.count++;
- }
-
- static inline void result(sum const& state, PointCentroid& centroid)
- {
- centroid = state.centroid;
- divide_value(centroid, state.count);
- }
-
-};
-
-
-#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
-
-
-namespace services
-{
-
-template <typename Point, std::size_t DimensionCount, typename Geometry>
-struct default_strategy
-<
- cartesian_tag,
- pointlike_tag,
- DimensionCount,
- Point,
- Geometry
->
-{
- typedef average
- <
- Point,
- typename point_type<Geometry>::type
- > type;
-};
-
-} // namespace services
-
-#endif
-
-
-}} // namespace strategy::centroid
-
-
-}} // namespace boost::geometry
+#include <boost/geometry/strategies/cartesian/centroid_average.hpp>
#endif // BOOST_GEOMETRY_MULTI_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
diff --git a/boost/geometry/multi/views/detail/range_type.hpp b/boost/geometry/multi/views/detail/range_type.hpp
index 172feb251f..f8cb0e6e53 100644
--- a/boost/geometry/multi/views/detail/range_type.hpp
+++ b/boost/geometry/multi/views/detail/range_type.hpp
@@ -15,48 +15,7 @@
#define BOOST_GEOMETRY_MULTI_VIEWS_DETAIL_RANGE_TYPE_HPP
-#include <boost/range.hpp>
-
#include <boost/geometry/views/detail/range_type.hpp>
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-// multi-point acts itself as a range
-template <typename Geometry>
-struct range_type<multi_point_tag, Geometry>
-{
- typedef Geometry type;
-};
-
-
-template <typename Geometry>
-struct range_type<multi_linestring_tag, Geometry>
-{
- typedef typename boost::range_value<Geometry>::type type;
-};
-
-
-template <typename Geometry>
-struct range_type<multi_polygon_tag, Geometry>
-{
- // Call its single-version
- typedef typename geometry::detail::range_type
- <
- typename boost::range_value<Geometry>::type
- >::type type;
-};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_MULTI_VIEWS_DETAIL_RANGE_TYPE_HPP
diff --git a/boost/geometry/policies/disjoint_interrupt_policy.hpp b/boost/geometry/policies/disjoint_interrupt_policy.hpp
new file mode 100644
index 0000000000..2a6e54b079
--- /dev/null
+++ b/boost/geometry/policies/disjoint_interrupt_policy.hpp
@@ -0,0 +1,67 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+struct disjoint_interrupt_policy
+{
+ static bool const enabled = true;
+ bool has_intersections;
+
+ inline disjoint_interrupt_policy()
+ : has_intersections(false)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // If there is any IP in the range, it is NOT disjoint
+ if (boost::size(range) > 0)
+ {
+ has_intersections = true;
+ return true;
+ }
+ return false;
+ }
+};
+
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP
diff --git a/boost/geometry/policies/predicate_based_interrupt_policy.hpp b/boost/geometry/policies/predicate_based_interrupt_policy.hpp
new file mode 100644
index 0000000000..0021b12dc6
--- /dev/null
+++ b/boost/geometry/policies/predicate_based_interrupt_policy.hpp
@@ -0,0 +1,101 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template
+<
+ typename IsAcceptableTurnPredicate,
+ bool AllowEmptyTurnRange = true // by default, allow an empty turn range
+>
+struct stateless_predicate_based_interrupt_policy
+{
+ static bool const enabled = true;
+ bool has_intersections; // set to true if there is at least one
+ // unacceptable turn
+
+ inline stateless_predicate_based_interrupt_policy()
+ : has_intersections(false)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // if there is at least one unacceptable turn in the range, return false
+ has_intersections = !detail::check_iterator_range
+ <
+ IsAcceptableTurnPredicate,
+ AllowEmptyTurnRange
+ >::apply(boost::begin(range), boost::end(range));
+
+ return has_intersections;
+ }
+};
+
+
+
+
+template
+<
+ typename IsAcceptableTurnPredicate,
+ bool AllowEmptyTurnRange = true // by default, allow an empty turn range
+>
+struct predicate_based_interrupt_policy
+{
+ static bool const enabled = true;
+ bool has_intersections; // set to true if there is at least one
+ // unacceptable turn
+ IsAcceptableTurnPredicate const& m_predicate;
+
+ inline
+ predicate_based_interrupt_policy(IsAcceptableTurnPredicate const& predicate)
+ : has_intersections(false)
+ , m_predicate(predicate)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // if there is at least one unacceptable turn in the range, return false
+ has_intersections = !detail::check_iterator_range
+ <
+ IsAcceptableTurnPredicate,
+ AllowEmptyTurnRange
+ >::apply(boost::begin(range), boost::end(range), m_predicate);
+
+ return has_intersections;
+ }
+};
+
+
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP
diff --git a/boost/geometry/policies/relate/de9im.hpp b/boost/geometry/policies/relate/de9im.hpp
index 766d80b220..e2d6b5111c 100644
--- a/boost/geometry/policies/relate/de9im.hpp
+++ b/boost/geometry/policies/relate/de9im.hpp
@@ -158,15 +158,6 @@ struct segments_de9im
false, false, false, true);
}
- static inline return_type collinear_disjoint()
- {
- return de9im_segment(0,0,
- -1, -1, 1,
- -1, -1, 0,
- 1, 0, 2,
- true);
- }
-
};
diff --git a/boost/geometry/policies/relate/direction.hpp b/boost/geometry/policies/relate/direction.hpp
index cfbaf7dd15..02fed94b10 100644
--- a/boost/geometry/policies/relate/direction.hpp
+++ b/boost/geometry/policies/relate/direction.hpp
@@ -88,7 +88,8 @@ struct direction_type
// New information
side_info sides;
- int arrival[2]; // 1=arrival, -1departure, 0=neutral; == how_a//how_b
+ // THIS IS EQUAL TO arrival_a, arrival_b - they probably can go now we have robust fractions
+ int arrival[2]; // 1=arrival, -1=departure, 0=neutral; == how_a//how_b
// About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases
@@ -110,28 +111,19 @@ struct direction_type
};
-
-template <typename S1, typename S2, typename CalculationType = void>
struct segments_direction
{
typedef direction_type return_type;
- typedef S1 segment_type1;
- typedef S2 segment_type2;
- typedef typename select_calculation_type
- <
- S1, S2, CalculationType
- >::type coordinate_type;
-
- // Get the same type, but at least a double
- typedef typename select_most_precise<coordinate_type, double>::type rtype;
-
-
- template <typename R>
- static inline return_type segments_intersect(side_info const& sides,
- R const&,
- coordinate_type const& dx1, coordinate_type const& dy1,
- coordinate_type const& dx2, coordinate_type const& dy2,
- S1 const& s1, S2 const& s2)
+
+ template
+ <
+ typename Segment1,
+ typename Segment2,
+ typename SegmentIntersectionInfo
+ >
+ static inline return_type segments_crosses(side_info const& sides,
+ SegmentIntersectionInfo const& ,
+ Segment1 const& , Segment2 const& )
{
bool const ra0 = sides.get<0,0>() == 0;
bool const ra1 = sides.get<0,1>() == 0;
@@ -140,95 +132,153 @@ struct segments_direction
return
// opposite and same starting point (FROM)
- ra0 && rb0 ? calculate_side<1>(sides, dx1, dy1, s1, s2, 'f', -1, -1)
+ ra0 && rb0 ? calculate_side<1>(sides, 'f', -1, -1)
// opposite and point to each other (TO)
- : ra1 && rb1 ? calculate_side<0>(sides, dx1, dy1, s1, s2, 't', 1, 1)
+ : ra1 && rb1 ? calculate_side<0>(sides, 't', 1, 1)
// not opposite, forming an angle, first a then b,
// directed either both left, or both right
// Check side of B2 from A. This is not calculated before
- : ra1 && rb0 ? angle<1>(sides, dx1, dy1, s1, s2, 'a', 1, -1)
+ : ra1 && rb0 ? angle<1>(sides, 'a', 1, -1)
// not opposite, forming a angle, first b then a,
// directed either both left, or both right
- : ra0 && rb1 ? angle<0>(sides, dx1, dy1, s1, s2, 'a', -1, 1)
+ : ra0 && rb1 ? angle<0>(sides, 'a', -1, 1)
// b starts from interior of a
- : rb0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'B', 0, -1)
+ : rb0 ? starts_from_middle(sides, 'B', 0, -1)
// a starts from interior of b (#39)
- : ra0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'A', -1, 0)
+ : ra0 ? starts_from_middle(sides, 'A', -1, 0)
// b ends at interior of a, calculate direction of A from IP
- : rb1 ? b_ends_at_middle(sides, dx2, dy2, s1, s2)
+ : rb1 ? b_ends_at_middle(sides)
// a ends at interior of b
- : ra1 ? a_ends_at_middle(sides, dx1, dy1, s1, s2)
+ : ra1 ? a_ends_at_middle(sides)
// normal intersection
- : calculate_side<1>(sides, dx1, dy1, s1, s2, 'i', -1, -1)
+ : calculate_side<1>(sides, 'i', -1, -1)
;
}
- static inline return_type collinear_touch(
- coordinate_type const& ,
- coordinate_type const& , int arrival_a, int arrival_b)
+ template <typename Ratio>
+ static inline int arrival_value(Ratio const& r_from, Ratio const& r_to)
{
- // Though this is 'collinear', we handle it as To/From/Angle because it is the same.
- // It only does NOT have a direction.
- side_info sides;
- //int const arrive = how == 'T' ? 1 : -1;
- bool opposite = arrival_a == arrival_b;
- return
- ! opposite
- ? return_type(sides, 'a', arrival_a, arrival_b)
- : return_type(sides, arrival_a == 0 ? 't' : 'f', arrival_a, arrival_b, 0, 0, true);
+ // a1--------->a2
+ // b1----->b2
+ // a departs: -1
+
+ // a1--------->a2
+ // b1----->b2
+ // a arrives: 1
+
+ // a1--------->a2
+ // b1----->b2
+ // both arrive there -> r-to = 1/1, or 0/1 (on_segment)
+
+ // First check the TO (for arrival), then FROM (for departure)
+ return r_to.in_segment() ? 1
+ : r_to.on_segment() ? 0
+ : r_from.on_segment() ? -1
+ : -1
+ ;
}
- template <typename S>
- static inline return_type collinear_interior_boundary_intersect(S const& , bool,
- int arrival_a, int arrival_b, bool opposite)
+ template <typename Ratio>
+ static inline void analyze(Ratio const& r,
+ int& in_segment_count,
+ int& on_end_count,
+ int& outside_segment_count)
{
- return_type r('c', opposite);
- r.arrival[0] = arrival_a;
- r.arrival[1] = arrival_b;
- return r;
+ if (r.on_end())
+ {
+ on_end_count++;
+ }
+ else if (r.in_segment())
+ {
+ in_segment_count++;
+ }
+ else
+ {
+ outside_segment_count++;
+ }
}
- static inline return_type collinear_a_in_b(S1 const& , bool opposite)
- {
- return_type r('c', opposite);
- r.arrival[0] = 1;
- r.arrival[1] = -1;
- return r;
- }
- static inline return_type collinear_b_in_a(S2 const& , bool opposite)
+ template <typename Segment1, typename Segment2, typename Ratio>
+ static inline return_type segments_collinear(
+ Segment1 const& , Segment2 const&,
+ Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b,
+ Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a)
{
- return_type r('c', opposite);
- r.arrival[0] = -1;
- r.arrival[1] = 1;
- return r;
- }
+ // If segments are opposite, the ratio of the FROM w.r.t. the other
+ // is larger than the ratio of the TO w.r.t. the other
+ bool const opposite = ra_to_wrt_b < ra_from_wrt_b;
- static inline return_type collinear_overlaps(
- coordinate_type const& , coordinate_type const& ,
- coordinate_type const& , coordinate_type const& ,
- int arrival_a, int arrival_b, bool opposite)
- {
return_type r('c', opposite);
- r.arrival[0] = arrival_a;
- r.arrival[1] = arrival_b;
+
+ // IMPORTANT: the order of conditions is different as in intersection_points.hpp
+ // We assign A in 0 and B in 1
+ r.arrival[0] = arrival_value(ra_from_wrt_b, ra_to_wrt_b);
+ r.arrival[1] = arrival_value(rb_from_wrt_a, rb_to_wrt_a);
+
+ // Analyse them
+ int a_in_segment_count = 0;
+ int a_on_end_count = 0;
+ int a_outside_segment_count = 0;
+ int b_in_segment_count = 0;
+ int b_on_end_count = 0;
+ int b_outside_segment_count = 0;
+ analyze(ra_from_wrt_b,
+ a_in_segment_count, a_on_end_count, a_outside_segment_count);
+ analyze(ra_to_wrt_b,
+ a_in_segment_count, a_on_end_count, a_outside_segment_count);
+ analyze(rb_from_wrt_a,
+ b_in_segment_count, b_on_end_count, b_outside_segment_count);
+ analyze(rb_to_wrt_a,
+ b_in_segment_count, b_on_end_count, b_outside_segment_count);
+
+ if (a_on_end_count == 1
+ && b_on_end_count == 1
+ && a_outside_segment_count == 1
+ && b_outside_segment_count == 1)
+ {
+ // This is a collinear touch
+ // --------> A (or B)
+ // <---------- B (or A)
+ // We adapt the "how"
+ // TODO: how was to be refactored anyway,
+ if (! opposite)
+ {
+ r.how = 'a';
+ }
+ else
+ {
+ r.how = r.arrival[0] == 0 ? 't' : 'f';
+ }
+ }
+ else if (a_on_end_count == 2
+ && b_on_end_count == 2)
+ {
+ r.how = 'e';
+ }
+
return r;
}
- static inline return_type segment_equal(S1 const& , bool opposite)
+ template <typename Segment>
+ static inline return_type degenerate(Segment const& , bool)
{
- return return_type('e', opposite);
+ return return_type('0', false);
}
- static inline return_type degenerate(S1 const& , bool)
+ template <typename Segment, typename Ratio>
+ static inline return_type one_degenerate(Segment const& ,
+ Ratio const& ,
+ bool)
{
+ // To be decided
return return_type('0', false);
}
@@ -237,11 +287,6 @@ struct segments_direction
return return_type('d', false);
}
- static inline return_type collinear_disjoint()
- {
- return return_type('d', false);
- }
-
static inline return_type error(std::string const&)
{
// Return "E" to denote error
@@ -252,62 +297,29 @@ struct segments_direction
private :
- static inline bool is_left
- (
- coordinate_type const& ux,
- coordinate_type const& uy,
- coordinate_type const& vx,
- coordinate_type const& vy
- )
- {
- // This is a "side calculation" as in the strategies, but here terms are precalculated
- // We might merge this with side, offering a pre-calculated term (in fact already done using cross-product)
- // Waiting for implementing spherical...
-
- rtype const zero = rtype();
- return geometry::detail::determinant<rtype>(ux, uy, vx, vy) > zero;
- }
-
template <std::size_t I>
static inline return_type calculate_side(side_info const& sides,
- coordinate_type const& dx1, coordinate_type const& dy1,
- S1 const& s1, S2 const& s2,
char how, int how_a, int how_b)
{
- coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1);
- coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1);
-
- return is_left(dx1, dy1, dpx, dpy)
- ? return_type(sides, how, how_a, how_b, -1, 1)
- : return_type(sides, how, how_a, how_b, 1, -1);
+ int const dir = sides.get<1, I>() == 1 ? 1 : -1;
+ return return_type(sides, how, how_a, how_b, -dir, dir);
}
template <std::size_t I>
static inline return_type angle(side_info const& sides,
- coordinate_type const& dx1, coordinate_type const& dy1,
- S1 const& s1, S2 const& s2,
char how, int how_a, int how_b)
{
- coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1);
- coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1);
-
- return is_left(dx1, dy1, dpx, dpy)
- ? return_type(sides, how, how_a, how_b, 1, 1)
- : return_type(sides, how, how_a, how_b, -1, -1);
+ int const dir = sides.get<1, I>() == 1 ? 1 : -1;
+ return return_type(sides, how, how_a, how_b, dir, dir);
}
static inline return_type starts_from_middle(side_info const& sides,
- coordinate_type const& dx1, coordinate_type const& dy1,
- S1 const& s1, S2 const& s2,
char which,
int how_a, int how_b)
{
// Calculate ARROW of b segment w.r.t. s1
- coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1);
- coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1);
-
- int dir = is_left(dx1, dy1, dpx, dpy) ? 1 : -1;
+ int dir = sides.get<1, 1>() == 1 ? 1 : -1;
// From other perspective, then reverse
bool const is_a = which == 'A';
@@ -326,31 +338,19 @@ private :
// To be harmonized
- static inline return_type a_ends_at_middle(side_info const& sides,
- coordinate_type const& dx, coordinate_type const& dy,
- S1 const& s1, S2 const& s2)
+ static inline return_type a_ends_at_middle(side_info const& sides)
{
- coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1);
- coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1);
-
// Ending at the middle, one ARRIVES, the other one is NEUTRAL
- // (because it both "arrives" and "departs" there
- return is_left(dx, dy, dpx, dpy)
- ? return_type(sides, 'm', 1, 0, 1, 1)
- : return_type(sides, 'm', 1, 0, -1, -1);
+ // (because it both "arrives" and "departs" there)
+ int const dir = sides.get<1, 1>() == 1 ? 1 : -1;
+ return return_type(sides, 'm', 1, 0, dir, dir);
}
- static inline return_type b_ends_at_middle(side_info const& sides,
- coordinate_type const& dx, coordinate_type const& dy,
- S1 const& s1, S2 const& s2)
+ static inline return_type b_ends_at_middle(side_info const& sides)
{
- coordinate_type dpx = get<1, 0>(s1) - get<0, 0>(s2);
- coordinate_type dpy = get<1, 1>(s1) - get<0, 1>(s2);
-
- return is_left(dx, dy, dpx, dpy)
- ? return_type(sides, 'm', 0, 1, 1, 1)
- : return_type(sides, 'm', 0, 1, -1, -1);
+ int const dir = sides.get<0, 1>() == 1 ? 1 : -1;
+ return return_type(sides, 'm', 0, 1, dir, dir);
}
};
diff --git a/boost/geometry/policies/relate/intersection_points.hpp b/boost/geometry/policies/relate/intersection_points.hpp
index d7d5199051..aa2f697a2a 100644
--- a/boost/geometry/policies/relate/intersection_points.hpp
+++ b/boost/geometry/policies/relate/intersection_points.hpp
@@ -16,12 +16,12 @@
#include <boost/concept_check.hpp>
#include <boost/numeric/conversion/cast.hpp>
-#include <boost/geometry/arithmetic/determinant.hpp>
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
-
+#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
@@ -30,106 +30,153 @@ namespace policies { namespace relate
{
-template <typename S1, typename S2, typename ReturnType, typename CalculationType = void>
+/*!
+\brief Policy calculating the intersection points themselves
+ */
+template
+<
+ typename ReturnType
+>
struct segments_intersection_points
{
typedef ReturnType return_type;
- typedef S1 segment_type1;
- typedef S2 segment_type2;
-
- typedef typename select_calculation_type
- <
- S1, S2, CalculationType
- >::type coordinate_type;
-
- template <typename R>
- static inline return_type segments_intersect(side_info const&,
- R const& r,
- coordinate_type const& dx1, coordinate_type const& dy1,
- coordinate_type const& dx2, coordinate_type const& dy2,
- S1 const& s1, S2 const& s2)
- {
- typedef typename geometry::coordinate_type
- <
- typename return_type::point_type
- >::type return_coordinate_type;
-
- coordinate_type const s1x = get<0, 0>(s1);
- coordinate_type const s1y = get<0, 1>(s1);
-
- return_type result;
- result.count = 1;
- set<0>(result.intersections[0],
- boost::numeric_cast<return_coordinate_type>(R(s1x) + r * R(dx1)));
- set<1>(result.intersections[0],
- boost::numeric_cast<return_coordinate_type>(R(s1y) + r * R(dy1)));
- return result;
- }
-
- static inline return_type collinear_touch(coordinate_type const& x,
- coordinate_type const& y, int, int)
+ template
+ <
+ typename Point,
+ typename Segment,
+ typename SegmentRatio,
+ typename T
+ >
+ static inline void assign(Point& point,
+ Segment const& segment,
+ SegmentRatio const& ratio,
+ T const& dx, T const& dy)
{
- return_type result;
- result.count = 1;
- set<0>(result.intersections[0], x);
- set<1>(result.intersections[0], y);
- return result;
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+
+ // Calculate the intersection point based on segment_ratio
+ // Up to now, division was postponed. Here we divide using numerator/
+ // denominator. In case of integer this results in an integer
+ // division.
+ BOOST_ASSERT(ratio.denominator() != 0);
+ set<0>(point, boost::numeric_cast<coordinate_type>(
+ get<0, 0>(segment)
+ + ratio.numerator() * dx / ratio.denominator()));
+ set<1>(point, boost::numeric_cast<coordinate_type>(
+ get<0, 1>(segment)
+ + ratio.numerator() * dy / ratio.denominator()));
}
- template <typename S>
- static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1)
+
+ template
+ <
+ typename Segment1,
+ typename Segment2,
+ typename SegmentIntersectionInfo
+ >
+ static inline return_type segments_crosses(side_info const&,
+ SegmentIntersectionInfo const& sinfo,
+ Segment1 const& s1, Segment2 const& s2)
{
return_type result;
- result.count = 2;
- set<0>(result.intersections[index1], get<0, 0>(s));
- set<1>(result.intersections[index1], get<0, 1>(s));
- set<0>(result.intersections[index2], get<1, 0>(s));
- set<1>(result.intersections[index2], get<1, 1>(s));
- return result;
- }
+ result.count = 1;
- template <typename S>
- static inline return_type collinear_interior_boundary_intersect(S const& s, bool a_in_b,
- int, int, bool opposite)
- {
- int index1 = opposite && ! a_in_b ? 1 : 0;
- return collinear_inside(s, index1, 1 - index1);
- }
+ if (sinfo.robust_ra < sinfo.robust_rb)
+ {
+ assign(result.intersections[0], s1, sinfo.robust_ra,
+ sinfo.dx_a, sinfo.dy_a);
+ }
+ else
+ {
+ assign(result.intersections[0], s2, sinfo.robust_rb,
+ sinfo.dx_b, sinfo.dy_b);
+ }
- static inline return_type collinear_a_in_b(S1 const& s, bool)
- {
- return collinear_inside(s);
- }
- static inline return_type collinear_b_in_a(S2 const& s, bool opposite)
- {
- int index1 = opposite ? 1 : 0;
- return collinear_inside(s, index1, 1 - index1);
- }
+ result.fractions[0].assign(sinfo);
- static inline return_type collinear_overlaps(
- coordinate_type const& x1, coordinate_type const& y1,
- coordinate_type const& x2, coordinate_type const& y2,
- int, int, bool)
- {
- return_type result;
- result.count = 2;
- set<0>(result.intersections[0], x1);
- set<1>(result.intersections[0], y1);
- set<0>(result.intersections[1], x2);
- set<1>(result.intersections[1], y2);
return result;
}
- static inline return_type segment_equal(S1 const& s, bool)
+ template <typename Segment1, typename Segment2, typename Ratio>
+ static inline return_type segments_collinear(
+ Segment1 const& a, Segment2 const& b,
+ Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b,
+ Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a)
{
return_type result;
- result.count = 2;
- // TODO: order of IP's
- set<0>(result.intersections[0], get<0, 0>(s));
- set<1>(result.intersections[0], get<0, 1>(s));
- set<0>(result.intersections[1], get<1, 0>(s));
- set<1>(result.intersections[1], get<1, 1>(s));
+ int index = 0, count_a = 0, count_b = 0;
+ Ratio on_a[2];
+
+ // The conditions "index < 2" are necessary for non-robust handling,
+ // if index would be 2 this indicate an (currently uncatched) error
+
+ // IMPORTANT: the order of conditions is different as in direction.hpp
+ if (ra_from_wrt_b.on_segment()
+ && index < 2)
+ {
+ // a1--------->a2
+ // b1----->b2
+ //
+ // ra1 (relative to b) is between 0/1:
+ // -> First point of A is intersection point
+ detail::assign_point_from_index<0>(a, result.intersections[index]);
+ result.fractions[index].assign(Ratio::zero(), ra_from_wrt_b);
+ on_a[index] = Ratio::zero();
+ index++;
+ count_a++;
+ }
+ if (rb_from_wrt_a.in_segment()
+ && index < 2)
+ {
+ // We take the first intersection point of B
+ // a1--------->a2
+ // b1----->b2
+ // But only if it is not located on A
+ // a1--------->a2
+ // b1----->b2 rb_from_wrt_a == 0/1 -> a already taken
+
+ detail::assign_point_from_index<0>(b, result.intersections[index]);
+ result.fractions[index].assign(rb_from_wrt_a, Ratio::zero());
+ on_a[index] = rb_from_wrt_a;
+ index++;
+ count_b++;
+ }
+
+ if (ra_to_wrt_b.on_segment()
+ && index < 2)
+ {
+ // Similarly, second IP (here a2)
+ // a1--------->a2
+ // b1----->b2
+ detail::assign_point_from_index<1>(a, result.intersections[index]);
+ result.fractions[index].assign(Ratio::one(), ra_to_wrt_b);
+ on_a[index] = Ratio::one();
+ index++;
+ count_a++;
+ }
+ if (rb_to_wrt_a.in_segment()
+ && index < 2)
+ {
+ detail::assign_point_from_index<1>(b, result.intersections[index]);
+ result.fractions[index].assign(rb_to_wrt_a, Ratio::one());
+ on_a[index] = rb_to_wrt_a;
+ index++;
+ count_b++;
+ }
+
+ // TEMPORARY
+ // If both are from b, and b is reversed w.r.t. a, we swap IP's
+ // to align them w.r.t. a
+ // get_turn_info still relies on some order (in some collinear cases)
+ if (index == 2 && on_a[1] < on_a[0])
+ {
+ std::swap(result.fractions[0], result.fractions[1]);
+ std::swap(result.intersections[0], result.intersections[1]);
+ }
+
+ result.count = index;
+
return result;
}
@@ -142,17 +189,35 @@ struct segments_intersection_points
return return_type();
}
- static inline return_type collinear_disjoint()
+ // Both degenerate
+ template <typename Segment>
+ static inline return_type degenerate(Segment const& segment, bool)
{
- return return_type();
+ return_type result;
+ result.count = 1;
+ set<0>(result.intersections[0], get<0, 0>(segment));
+ set<1>(result.intersections[0], get<0, 1>(segment));
+ return result;
}
- static inline return_type degenerate(S1 const& s, bool)
+ // One degenerate
+ template <typename Segment, typename Ratio>
+ static inline return_type one_degenerate(Segment const& degenerate_segment,
+ Ratio const& ratio, bool a_degenerate)
{
return_type result;
result.count = 1;
- set<0>(result.intersections[0], get<0, 0>(s));
- set<1>(result.intersections[0], get<0, 1>(s));
+ set<0>(result.intersections[0], get<0, 0>(degenerate_segment));
+ set<1>(result.intersections[0], get<0, 1>(degenerate_segment));
+ if (a_degenerate)
+ {
+ // IP lies on ratio w.r.t. segment b
+ result.fractions[0].assign(Ratio::zero(), ratio);
+ }
+ else
+ {
+ result.fractions[0].assign(ratio, Ratio::zero());
+ }
return result;
}
};
diff --git a/boost/geometry/policies/relate/intersection_ratios.hpp b/boost/geometry/policies/relate/intersection_ratios.hpp
new file mode 100644
index 0000000000..81ecba0b54
--- /dev/null
+++ b/boost/geometry/policies/relate/intersection_ratios.hpp
@@ -0,0 +1,127 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP
+#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP
+
+
+#include <algorithm>
+#include <string>
+
+#include <boost/concept_check.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/strategies/side_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace policies { namespace relate
+{
+
+
+/*!
+\brief Policy returning segment ratios
+\note Template argument FractionType should be a fraction_type<SegmentRatio>
+ */
+template
+<
+ typename FractionType
+>
+struct segments_intersection_ratios
+{
+ typedef FractionType return_type;
+
+ template
+ <
+ typename Segment1,
+ typename Segment2,
+ typename SegmentIntersectionInfo
+ >
+ static inline return_type segments_crosses(side_info const&,
+ SegmentIntersectionInfo const& sinfo,
+ Segment1 const& , Segment2 const& )
+ {
+ return_type result;
+ result.assign(sinfo);
+ return result;
+ }
+
+ template <typename Segment1, typename Segment2, typename Ratio>
+ static inline return_type segments_collinear(
+ Segment1 const& , Segment2 const& ,
+ Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b,
+ Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a)
+ {
+ // We have only one result, for (potentially) two IP's,
+ // so we take a first one
+ return_type result;
+
+ if (ra_from_wrt_b.on_segment())
+ {
+ result.assign(Ratio::zero(), ra_from_wrt_b);
+ }
+ else if (rb_from_wrt_a.in_segment())
+ {
+ result.assign(rb_from_wrt_a, Ratio::zero());
+ }
+ else if (ra_to_wrt_b.on_segment())
+ {
+ result.assign(Ratio::one(), ra_to_wrt_b);
+ }
+ else if (rb_to_wrt_a.in_segment())
+ {
+ result.assign(rb_to_wrt_a, Ratio::one());
+ }
+
+ return result;
+ }
+
+ static inline return_type disjoint()
+ {
+ return return_type();
+ }
+ static inline return_type error(std::string const&)
+ {
+ return return_type();
+ }
+
+ template <typename Segment>
+ static inline return_type degenerate(Segment const& segment, bool)
+ {
+ return return_type();
+ }
+
+ template <typename Segment, typename Ratio>
+ static inline return_type one_degenerate(Segment const& ,
+ Ratio const& ratio, bool a_degenerate)
+ {
+ return_type result;
+ if (a_degenerate)
+ {
+ // IP lies on ratio w.r.t. segment b
+ result.assign(Ratio::zero(), ratio);
+ }
+ else
+ {
+ result.assign(ratio, Ratio::zero());
+ }
+ return result;
+ }
+
+};
+
+
+}} // namespace policies::relate
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP
diff --git a/boost/geometry/policies/relate/tupled.hpp b/boost/geometry/policies/relate/tupled.hpp
index f6713c44c9..6da9095c4e 100644
--- a/boost/geometry/policies/relate/tupled.hpp
+++ b/boost/geometry/policies/relate/tupled.hpp
@@ -14,8 +14,6 @@
#include <boost/tuple/tuple.hpp>
#include <boost/geometry/strategies/side_info.hpp>
-#include <boost/geometry/util/select_calculation_type.hpp>
-#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
@@ -26,7 +24,7 @@ namespace policies { namespace relate
// "tupled" to return intersection results together.
// Now with two, with some meta-programming and derivations it can also be three (or more)
-template <typename Policy1, typename Policy2, typename CalculationType = void>
+template <typename Policy1, typename Policy2>
struct segments_tupled
{
typedef boost::tuple
@@ -35,107 +33,50 @@ struct segments_tupled
typename Policy2::return_type
> return_type;
- // Take segments of first policy, they should be equal
- typedef typename Policy1::segment_type1 segment_type1;
- typedef typename Policy1::segment_type2 segment_type2;
-
- typedef typename select_calculation_type
- <
- segment_type1,
- segment_type2,
- CalculationType
- >::type coordinate_type;
-
- // Get the same type, but at least a double
- typedef typename select_most_precise<coordinate_type, double>::type rtype;
-
- template <typename R>
- static inline return_type segments_intersect(side_info const& sides,
- R const& r,
- coordinate_type const& dx1, coordinate_type const& dy1,
- coordinate_type const& dx2, coordinate_type const& dy2,
- segment_type1 const& s1, segment_type2 const& s2)
- {
- return boost::make_tuple
- (
- Policy1::segments_intersect(sides, r,
- dx1, dy1, dx2, dy2, s1, s2),
- Policy2::segments_intersect(sides, r,
- dx1, dy1, dx2, dy2, s1, s2)
- );
- }
-
- static inline return_type collinear_touch(coordinate_type const& x,
- coordinate_type const& y, int arrival_a, int arrival_b)
- {
- return boost::make_tuple
- (
- Policy1::collinear_touch(x, y, arrival_a, arrival_b),
- Policy2::collinear_touch(x, y, arrival_a, arrival_b)
- );
- }
-
- template <typename S>
- static inline return_type collinear_interior_boundary_intersect(S const& segment,
- bool a_within_b,
- int arrival_a, int arrival_b, bool opposite)
- {
- return boost::make_tuple
- (
- Policy1::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite),
- Policy2::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite)
- );
- }
-
- static inline return_type collinear_a_in_b(segment_type1 const& segment,
- bool opposite)
- {
- return boost::make_tuple
- (
- Policy1::collinear_a_in_b(segment, opposite),
- Policy2::collinear_a_in_b(segment, opposite)
- );
- }
- static inline return_type collinear_b_in_a(segment_type2 const& segment,
- bool opposite)
+ template <typename Segment1, typename Segment2, typename SegmentIntersectionInfo>
+ static inline return_type segments_crosses(side_info const& sides,
+ SegmentIntersectionInfo const& sinfo,
+ Segment1 const& s1, Segment2 const& s2)
{
return boost::make_tuple
(
- Policy1::collinear_b_in_a(segment, opposite),
- Policy2::collinear_b_in_a(segment, opposite)
+ Policy1::segments_crosses(sides, sinfo, s1, s2),
+ Policy2::segments_crosses(sides, sinfo, s1, s2)
);
}
-
- static inline return_type collinear_overlaps(
- coordinate_type const& x1, coordinate_type const& y1,
- coordinate_type const& x2, coordinate_type const& y2,
- int arrival_a, int arrival_b, bool opposite)
+ template <typename Segment1, typename Segment2, typename Ratio>
+ static inline return_type segments_collinear(
+ Segment1 const& segment1, Segment2 const& segment2,
+ Ratio const& ra1, Ratio const& ra2, Ratio const& rb1, Ratio const& rb2)
{
return boost::make_tuple
(
- Policy1::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite),
- Policy2::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite)
+ Policy1::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2),
+ Policy2::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2)
);
}
- static inline return_type segment_equal(segment_type1 const& s,
- bool opposite)
+ template <typename Segment>
+ static inline return_type degenerate(Segment const& segment,
+ bool a_degenerate)
{
return boost::make_tuple
(
- Policy1::segment_equal(s, opposite),
- Policy2::segment_equal(s, opposite)
+ Policy1::degenerate(segment, a_degenerate),
+ Policy2::degenerate(segment, a_degenerate)
);
}
- static inline return_type degenerate(segment_type1 const& segment,
- bool a_degenerate)
+ template <typename Segment, typename Ratio>
+ static inline return_type one_degenerate(Segment const& segment,
+ Ratio const& ratio,
+ bool a_degenerate)
{
return boost::make_tuple
(
- Policy1::degenerate(segment, a_degenerate),
- Policy2::degenerate(segment, a_degenerate)
+ Policy1::one_degenerate(segment, ratio, a_degenerate),
+ Policy2::one_degenerate(segment, ratio, a_degenerate)
);
}
@@ -157,15 +98,6 @@ struct segments_tupled
);
}
- static inline return_type collinear_disjoint()
- {
- return boost::make_tuple
- (
- Policy1::collinear_disjoint(),
- Policy2::collinear_disjoint()
- );
- }
-
};
}} // namespace policies::relate
diff --git a/boost/geometry/policies/robustness/get_rescale_policy.hpp b/boost/geometry/policies/robustness/get_rescale_policy.hpp
new file mode 100644
index 0000000000..ed7c1eb94c
--- /dev/null
+++ b/boost/geometry/policies/robustness/get_rescale_policy.hpp
@@ -0,0 +1,290 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
+#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
+
+
+#include <cstddef>
+
+#include <boost/type_traits.hpp>
+#include <boost/mpl/assert.hpp>
+
+#include <boost/geometry/core/tag_cast.hpp>
+
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/algorithms/detail/get_max_size.hpp>
+#include <boost/geometry/policies/robustness/robust_type.hpp>
+
+#include <boost/geometry/geometries/point.hpp>
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/rescale_policy.hpp>
+
+#include <boost/geometry/util/promote_floating_point.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace get_rescale_policy
+{
+
+template <typename Point, typename RobustPoint, typename Geometry, typename Factor>
+static inline void init_rescale_policy(Geometry const& geometry,
+ Point& min_point,
+ RobustPoint& min_robust_point,
+ Factor& factor)
+{
+ // Get bounding boxes
+ model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry);
+
+ // Scale this to integer-range
+ typedef typename promote_floating_point
+ <
+ typename geometry::coordinate_type<Point>::type
+ >::type num_type;
+ num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env));
+ num_type const range = 10000000.0; // Define a large range to get precise integer coordinates
+ num_type const half = 0.5;
+ factor = math::equals(diff, num_type()) ? 1
+ : boost::numeric_cast<num_type>(
+ boost::numeric_cast<boost::long_long_type>(half + range / diff));
+
+ // Assign input/output minimal points
+ detail::assign_point_from_index<0>(env, min_point);
+ num_type const two = 2;
+ boost::long_long_type const min_coordinate
+ = boost::numeric_cast<boost::long_long_type>(-range / two);
+ assign_values(min_robust_point, min_coordinate, min_coordinate);
+}
+
+template <typename Point, typename RobustPoint, typename Geometry1, typename Geometry2, typename Factor>
+static inline void init_rescale_policy(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Point& min_point,
+ RobustPoint& min_robust_point,
+ Factor& factor)
+{
+ // Get bounding boxes
+ model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry1);
+ model::box<Point> env2 = geometry::return_envelope<model::box<Point> >(geometry2);
+ geometry::expand(env, env2);
+
+ // TODO: merge this with implementation above
+ // Scale this to integer-range
+ typedef typename promote_floating_point
+ <
+ typename geometry::coordinate_type<Point>::type
+ >::type num_type;
+ num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env));
+ num_type const range = 10000000.0; // Define a large range to get precise integer coordinates
+ num_type const half = 0.5;
+ factor = math::equals(diff, num_type()) ? 1
+ : boost::numeric_cast<num_type>(
+ boost::numeric_cast<boost::long_long_type>(half + range / diff));
+
+ // Assign input/output minimal points
+ detail::assign_point_from_index<0>(env, min_point);
+ num_type const two = 2;
+ boost::long_long_type const min_coordinate
+ = boost::numeric_cast<boost::long_long_type>(-range / two);
+ assign_values(min_robust_point, min_coordinate, min_coordinate);
+}
+
+
+template
+<
+ typename Point,
+ bool IsFloatingPoint
+>
+struct rescale_policy_type
+{
+ typedef no_rescale_policy type;
+};
+
+// We rescale only all FP types
+template
+<
+ typename Point
+>
+struct rescale_policy_type<Point, true>
+{
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+ typedef model::point
+ <
+ typename detail::robust_type<coordinate_type>::type,
+ geometry::dimension<Point>::value,
+ typename geometry::coordinate_system<Point>::type
+ > robust_point_type;
+ typedef typename promote_floating_point<coordinate_type>::type factor_type;
+ typedef detail::robust_policy<Point, robust_point_type, factor_type> type;
+};
+
+template <typename Policy>
+struct get_rescale_policy
+{
+ template <typename Geometry>
+ static inline Policy apply(Geometry const& geometry)
+ {
+ typedef typename point_type<Geometry>::type point_type;
+ typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
+ typedef typename promote_floating_point<coordinate_type>::type factor_type;
+ typedef model::point
+ <
+ typename detail::robust_type<coordinate_type>::type,
+ geometry::dimension<point_type>::value,
+ typename geometry::coordinate_system<point_type>::type
+ > robust_point_type;
+
+ point_type min_point;
+ robust_point_type min_robust_point;
+ factor_type factor;
+ init_rescale_policy(geometry, min_point, min_robust_point, factor);
+
+ return Policy(min_point, min_robust_point, factor);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline Policy apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ typedef typename point_type<Geometry1>::type point_type;
+ typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type;
+ typedef typename promote_floating_point<coordinate_type>::type factor_type;
+ typedef model::point
+ <
+ typename detail::robust_type<coordinate_type>::type,
+ geometry::dimension<point_type>::value,
+ typename geometry::coordinate_system<point_type>::type
+ > robust_point_type;
+
+ point_type min_point;
+ robust_point_type min_robust_point;
+ factor_type factor;
+ init_rescale_policy(geometry1, geometry2, min_point, min_robust_point, factor);
+
+ return Policy(min_point, min_robust_point, factor);
+ }
+};
+
+// Specialization for no-rescaling
+template <>
+struct get_rescale_policy<no_rescale_policy>
+{
+ template <typename Geometry>
+ static inline no_rescale_policy apply(Geometry const& )
+ {
+ return no_rescale_policy();
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline no_rescale_policy apply(Geometry1 const& , Geometry2 const& )
+ {
+ return no_rescale_policy();
+ }
+};
+
+
+}} // namespace detail::get_rescale_policy
+#endif // DOXYGEN_NO_DETAIL
+
+template<typename Point>
+struct rescale_policy_type
+ : public detail::get_rescale_policy::rescale_policy_type
+ <
+ Point,
+#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
+ false
+#else
+ boost::is_floating_point
+ <
+ typename geometry::coordinate_type<Point>::type
+ >::type::value
+#endif
+ >
+{
+ static const bool is_point
+ = boost::is_same
+ <
+ typename geometry::tag<Point>::type,
+ geometry::point_tag
+ >::type::value;
+
+ BOOST_MPL_ASSERT_MSG((is_point),
+ INVALID_INPUT_GEOMETRY,
+ (typename geometry::tag<Point>::type));
+};
+
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag_cast
+ <
+ typename tag<Geometry1>::type,
+ box_tag,
+ pointlike_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ typename Tag2 = typename tag_cast
+ <
+ typename tag<Geometry2>::type,
+ box_tag,
+ pointlike_tag,
+ linear_tag,
+ areal_tag
+ >::type
+>
+struct rescale_overlay_policy_type
+ // Default: no rescaling
+ : public detail::get_rescale_policy::rescale_policy_type
+ <
+ typename geometry::point_type<Geometry1>::type,
+ false
+ >
+{};
+
+// Areal/areal: get rescale policy based on coordinate type
+template
+<
+ typename Geometry1,
+ typename Geometry2
+>
+struct rescale_overlay_policy_type<Geometry1, Geometry2, areal_tag, areal_tag>
+ : public rescale_policy_type
+ <
+ typename geometry::point_type<Geometry1>::type
+ >
+{};
+
+
+template <typename Policy, typename Geometry>
+inline Policy get_rescale_policy(Geometry const& geometry)
+{
+ return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry);
+}
+
+template <typename Policy, typename Geometry1, typename Geometry2>
+inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry1, geometry2);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
diff --git a/boost/geometry/policies/robustness/no_rescale_policy.hpp b/boost/geometry/policies/robustness/no_rescale_policy.hpp
new file mode 100644
index 0000000000..a7899842c1
--- /dev/null
+++ b/boost/geometry/policies/robustness/no_rescale_policy.hpp
@@ -0,0 +1,66 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP
+#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP
+
+#include <stddef.h>
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+// Probably this will be moved out of namespace detail
+struct no_rescale_policy
+{
+ static bool const enabled = false;
+
+ // We don't rescale but return the reference of the input
+ template <std::size_t Dimension, typename Value>
+ inline Value const& apply(Value const& value) const
+ {
+ return value;
+ }
+};
+
+} // namespace detail
+#endif
+
+
+// Implement meta-functions for this policy
+template <typename Point>
+struct robust_point_type<Point, detail::no_rescale_policy>
+{
+ // The point itself
+ typedef Point type;
+};
+
+template <typename Point>
+struct segment_ratio_type<Point, detail::no_rescale_policy>
+{
+ // Define a segment_ratio defined on coordinate type, e.g.
+ // int/int or float/float
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+ typedef segment_ratio<coordinate_type> type;
+};
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP
diff --git a/boost/geometry/policies/robustness/rescale_policy.hpp b/boost/geometry/policies/robustness/rescale_policy.hpp
new file mode 100644
index 0000000000..5b3b566976
--- /dev/null
+++ b/boost/geometry/policies/robustness/rescale_policy.hpp
@@ -0,0 +1,83 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP
+#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP
+
+#include <cstddef>
+
+#include <boost/type_traits.hpp>
+
+#include <boost/geometry/policies/robustness/segment_ratio.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename FpPoint, typename IntPoint, typename CalculationType>
+struct robust_policy
+{
+ static bool const enabled = true;
+
+ typedef typename geometry::coordinate_type<IntPoint>::type output_ct;
+
+ robust_policy(FpPoint const& fp_min, IntPoint const& int_min, CalculationType const& the_factor)
+ : m_fp_min(fp_min)
+ , m_int_min(int_min)
+ , m_multiplier(the_factor)
+ {
+ }
+
+ template <std::size_t Dimension, typename Value>
+ inline output_ct apply(Value const& value) const
+ {
+ // a + (v-b)*f
+ CalculationType const a = static_cast<CalculationType>(get<Dimension>(m_int_min));
+ CalculationType const b = static_cast<CalculationType>(get<Dimension>(m_fp_min));
+ CalculationType const result = a + (value - b) * m_multiplier;
+ return static_cast<output_ct>(result);
+ }
+
+ FpPoint m_fp_min;
+ IntPoint m_int_min;
+ CalculationType m_multiplier;
+};
+
+} // namespace detail
+#endif
+
+
+// Implement meta-functions for this policy
+
+// Define the IntPoint as a robust-point type
+template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType>
+struct robust_point_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> >
+{
+ typedef IntPoint type;
+};
+
+// Meta function for rescaling, if rescaling is done segment_ratio is based on long long
+template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType>
+struct segment_ratio_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> >
+{
+ typedef segment_ratio<boost::long_long_type> type;
+};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP
diff --git a/boost/geometry/policies/robustness/robust_point_type.hpp b/boost/geometry/policies/robustness/robust_point_type.hpp
new file mode 100644
index 0000000000..25639227f0
--- /dev/null
+++ b/boost/geometry/policies/robustness/robust_point_type.hpp
@@ -0,0 +1,30 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP
+#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP
+
+namespace boost { namespace geometry
+{
+
+// Meta-function to typedef a robust point type for a policy
+template <typename Point, typename Policy>
+struct robust_point_type
+{
+ // By default, the point itself is the robust type
+ typedef Point type;
+};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP
diff --git a/boost/geometry/policies/robustness/robust_type.hpp b/boost/geometry/policies/robustness/robust_type.hpp
new file mode 100644
index 0000000000..4cfb2c4d91
--- /dev/null
+++ b/boost/geometry/policies/robustness/robust_type.hpp
@@ -0,0 +1,67 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP
+#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP
+
+
+#include <boost/type_traits.hpp>
+#include <boost/config.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+
+namespace detail_dispatch
+{
+
+template <typename CoordinateType, typename IsFloatingPoint>
+struct robust_type
+{
+};
+
+template <typename CoordinateType>
+struct robust_type<CoordinateType, boost::false_type>
+{
+ typedef CoordinateType type;
+};
+
+template <typename CoordinateType>
+struct robust_type<CoordinateType, boost::true_type>
+{
+ typedef boost::long_long_type type;
+};
+
+} // namespace detail_dispatch
+
+namespace detail
+{
+
+template <typename CoordinateType>
+struct robust_type
+{
+ typedef typename detail_dispatch::robust_type
+ <
+ CoordinateType,
+ typename boost::is_floating_point<CoordinateType>::type
+ >::type type;
+};
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP
diff --git a/boost/geometry/policies/robustness/segment_ratio.hpp b/boost/geometry/policies/robustness/segment_ratio.hpp
new file mode 100644
index 0000000000..8b55605c7f
--- /dev/null
+++ b/boost/geometry/policies/robustness/segment_ratio.hpp
@@ -0,0 +1,239 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
+#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/rational.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/promote_floating_point.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+namespace detail { namespace segment_ratio
+{
+
+template
+<
+ typename Type,
+ bool IsIntegral = boost::is_integral<Type>::type::value
+>
+struct less {};
+
+template <typename Type>
+struct less<Type, true>
+{
+ template <typename Ratio>
+ static inline bool apply(Ratio const& lhs, Ratio const& rhs)
+ {
+ return boost::rational<Type>(lhs.numerator(), lhs.denominator())
+ < boost::rational<Type>(rhs.numerator(), rhs.denominator());
+ }
+};
+
+template <typename Type>
+struct less<Type, false>
+{
+ template <typename Ratio>
+ static inline bool apply(Ratio const& lhs, Ratio const& rhs)
+ {
+ BOOST_ASSERT(lhs.denominator() != 0);
+ BOOST_ASSERT(rhs.denominator() != 0);
+ return lhs.numerator() * rhs.denominator()
+ < rhs.numerator() * lhs.denominator();
+ }
+};
+
+template
+<
+ typename Type,
+ bool IsIntegral = boost::is_integral<Type>::type::value
+>
+struct equal {};
+
+template <typename Type>
+struct equal<Type, true>
+{
+ template <typename Ratio>
+ static inline bool apply(Ratio const& lhs, Ratio const& rhs)
+ {
+ return boost::rational<Type>(lhs.numerator(), lhs.denominator())
+ == boost::rational<Type>(rhs.numerator(), rhs.denominator());
+ }
+};
+
+template <typename Type>
+struct equal<Type, false>
+{
+ template <typename Ratio>
+ static inline bool apply(Ratio const& lhs, Ratio const& rhs)
+ {
+ BOOST_ASSERT(lhs.denominator() != 0);
+ BOOST_ASSERT(rhs.denominator() != 0);
+ return geometry::math::equals
+ (
+ lhs.numerator() * rhs.denominator(),
+ rhs.numerator() * lhs.denominator()
+ );
+ }
+};
+
+}}
+
+//! Small class to keep a ratio (e.g. 1/4)
+//! Main purpose is intersections and checking on 0, 1, and smaller/larger
+//! The prototype used Boost.Rational. However, we also want to store FP ratios,
+//! (so numerator/denominator both in float)
+//! and Boost.Rational starts with GCD which we prefer to avoid if not necessary
+//! On a segment means: this ratio is between 0 and 1 (both inclusive)
+//!
+template <typename Type>
+class segment_ratio
+{
+public :
+ typedef Type numeric_type;
+
+ // Type-alias for the type itself
+ typedef segment_ratio<Type> thistype;
+
+ inline segment_ratio()
+ : m_numerator(0)
+ , m_denominator(1)
+ , m_approximation(0)
+ {}
+
+ inline segment_ratio(const Type& nominator, const Type& denominator)
+ : m_numerator(nominator)
+ , m_denominator(denominator)
+ {
+ initialize();
+ }
+
+ inline Type const& numerator() const { return m_numerator; }
+ inline Type const& denominator() const { return m_denominator; }
+
+ inline void assign(const Type& nominator, const Type& denominator)
+ {
+ m_numerator = nominator;
+ m_denominator = denominator;
+ initialize();
+ }
+
+ inline void initialize()
+ {
+ // Minimal normalization
+ // 1/-4 => -1/4, -1/-4 => 1/4
+ if (m_denominator < 0)
+ {
+ m_numerator = -m_numerator;
+ m_denominator = -m_denominator;
+ }
+
+ typedef typename promote_floating_point<Type>::type num_type;
+ static const num_type scale = 1000000.0;
+ m_approximation =
+ m_denominator == 0 ? 0
+ : boost::numeric_cast<double>
+ (
+ boost::numeric_cast<num_type>(m_numerator) * scale
+ / boost::numeric_cast<num_type>(m_denominator)
+ );
+ }
+
+ inline bool is_zero() const { return math::equals(m_numerator, 0); }
+ inline bool is_one() const { return math::equals(m_numerator, m_denominator); }
+ inline bool on_segment() const
+ {
+ // e.g. 0/4 or 4/4 or 2/4
+ return m_numerator >= 0 && m_numerator <= m_denominator;
+ }
+ inline bool in_segment() const
+ {
+ // e.g. 1/4
+ return m_numerator > 0 && m_numerator < m_denominator;
+ }
+ inline bool on_end() const
+ {
+ // e.g. 0/4 or 4/4
+ return is_zero() || is_one();
+ }
+ inline bool left() const
+ {
+ // e.g. -1/4
+ return m_numerator < 0;
+ }
+ inline bool right() const
+ {
+ // e.g. 5/4
+ return m_numerator > m_denominator;
+ }
+
+ inline bool close_to(thistype const& other) const
+ {
+ return geometry::math::abs(m_approximation - other.m_approximation) < 2;
+ }
+
+ inline bool operator< (thistype const& other) const
+ {
+ return close_to(other)
+ ? detail::segment_ratio::less<Type>::apply(*this, other)
+ : m_approximation < other.m_approximation;
+ }
+
+ inline bool operator== (thistype const& other) const
+ {
+ return close_to(other)
+ && detail::segment_ratio::equal<Type>::apply(*this, other);
+ }
+
+ static inline thistype zero()
+ {
+ static thistype result(0, 1);
+ return result;
+ }
+
+ static inline thistype one()
+ {
+ static thistype result(1, 1);
+ return result;
+ }
+
+#if defined(BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO)
+ friend std::ostream& operator<<(std::ostream &os, segment_ratio const& ratio)
+ {
+ os << ratio.m_numerator << "/" << ratio.m_denominator
+ << " (" << (static_cast<double>(ratio.m_numerator)
+ / static_cast<double>(ratio.m_denominator))
+ << ")";
+ return os;
+ }
+#endif
+
+
+
+private :
+ Type m_numerator;
+ Type m_denominator;
+
+ // Contains ratio on scale 0..1000000 (for 0..1)
+ // This is an approximation for fast and rough comparisons
+ // Boost.Rational is used if the approximations are close.
+ // Reason: performance, Boost.Rational does a GCD by default and also the
+ // comparisons contain while-loops.
+ double m_approximation;
+};
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
diff --git a/boost/geometry/policies/robustness/segment_ratio_type.hpp b/boost/geometry/policies/robustness/segment_ratio_type.hpp
new file mode 100644
index 0000000000..19e935bbb9
--- /dev/null
+++ b/boost/geometry/policies/robustness/segment_ratio_type.hpp
@@ -0,0 +1,28 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP
+#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+namespace boost { namespace geometry
+{
+
+// Meta-function to access segment-ratio for a policy
+template <typename Point, typename Policy>
+struct segment_ratio_type {}; // : not_implemented<> {};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP
diff --git a/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp b/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp
new file mode 100644
index 0000000000..7b7cd1890f
--- /dev/null
+++ b/boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp
@@ -0,0 +1,110 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
+#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
+
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/util/math.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace buffer
+{
+
+
+/*!
+\brief Let the buffer for linestrings be asymmetric
+\ingroup strategies
+\tparam NumericType \tparam_numeric
+\details This strategy can be used as DistanceStrategy for the buffer algorithm.
+ It can be applied for (multi)linestrings. It uses a (potentially) different
+ distances for left and for right. This means the (multi)linestrings are
+ interpreted having a direction.
+
+\qbk{
+[heading Example]
+[buffer_distance_asymmetric]
+[heading Output]
+[$img/strategies/buffer_distance_asymmetric.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_distance_symmetric distance_symmetric]
+}
+ */
+template<typename NumericType>
+class distance_asymmetric
+{
+public :
+ //! \brief Constructs the strategy, two distances must be specified
+ //! \param left The distance (or radius) of the buffer on the left side
+ //! \param right The distance on the right side
+ distance_asymmetric(NumericType const& left,
+ NumericType const& right)
+ : m_left(left)
+ , m_right(right)
+ {}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ //! Returns the distance-value for the specified side
+ template <typename Point>
+ inline NumericType apply(Point const& , Point const& ,
+ buffer_side_selector side) const
+ {
+ NumericType result = side == buffer_side_left ? m_left : m_right;
+ return negative() ? math::abs(result) : result;
+ }
+
+ //! Used internally, returns -1 for deflate, 1 for inflate
+ inline int factor() const
+ {
+ return negative() ? -1 : 1;
+ }
+
+ //! Returns true if both distances are negative
+ inline bool negative() const
+ {
+ return m_left < 0 && m_right < 0;
+ }
+
+ //! Returns the max distance distance up to the buffer will reach
+ template <typename JoinStrategy, typename EndStrategy>
+ inline NumericType max_distance(JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy) const
+ {
+ NumericType const left = geometry::math::abs(m_left);
+ NumericType const right = geometry::math::abs(m_right);
+ NumericType const dist = (std::max)(left, right);
+ return (std::max)(join_strategy.max_distance(dist),
+ end_strategy.max_distance(dist));
+ }
+
+ //! Returns the distance at which the input is simplified before the buffer process
+ inline NumericType simplify_distance() const
+ {
+ NumericType const left = geometry::math::abs(m_left);
+ NumericType const right = geometry::math::abs(m_right);
+ return (std::min)(left, right) / 1000.0;
+ }
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+private :
+ NumericType m_left;
+ NumericType m_right;
+};
+
+
+}} // namespace strategy::buffer
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
diff --git a/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp
new file mode 100644
index 0000000000..bc0c46f644
--- /dev/null
+++ b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp
@@ -0,0 +1,102 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
+#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
+
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/util/math.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace buffer
+{
+
+
+/*!
+\brief Let the buffer algorithm create buffers with same distances
+\ingroup strategies
+\tparam NumericType \tparam_numeric
+\details This strategy can be used as DistanceStrategy for the buffer algorithm.
+ It can be applied for all geometries. It uses one distance for left and
+ for right.
+ If the distance is negative and used with a (multi)polygon or ring, the
+ geometry will shrink (deflate) instead of expand (inflate).
+
+\qbk{
+[heading Example]
+[buffer_distance_symmetric]
+[heading Output]
+[$img/strategies/buffer_distance_symmetric.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_distance_asymmetric distance_asymmetric]
+}
+ */
+template<typename NumericType>
+class distance_symmetric
+{
+public :
+ //! \brief Constructs the strategy, a distance must be specified
+ //! \param distance The distance (or radius) of the buffer
+ explicit inline distance_symmetric(NumericType const& distance)
+ : m_distance(distance)
+ {}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ //! Returns the distance-value
+ template <typename Point>
+ inline NumericType apply(Point const& , Point const& ,
+ buffer_side_selector ) const
+ {
+ return negative() ? geometry::math::abs(m_distance) : m_distance;
+ }
+
+ //! Used internally, returns -1 for deflate, 1 for inflate
+ inline int factor() const
+ {
+ return negative() ? -1 : 1;
+ }
+
+ //! Returns true if distance is negative
+ inline bool negative() const
+ {
+ return m_distance < 0;
+ }
+
+ //! Returns the max distance distance up to the buffer will reach
+ template <typename JoinStrategy, typename EndStrategy>
+ inline NumericType max_distance(JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy) const
+ {
+ NumericType const dist = geometry::math::abs(m_distance);
+ return (std::max)(join_strategy.max_distance(dist),
+ end_strategy.max_distance(dist));
+ }
+
+
+ //! Returns the distance at which the input is simplified before the buffer process
+ inline NumericType simplify_distance() const
+ {
+ return geometry::math::abs(m_distance) / 1000.0;
+ }
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+private :
+ NumericType m_distance;
+};
+
+
+}} // namespace strategy::buffer
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
diff --git a/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp
index 747c140754..a960a6f1f9 100644
--- a/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp
+++ b/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -230,7 +235,7 @@ public:
// For the left boundary it is important that multiple points
// are sorted from bottom to top. Therefore the less predicate
// does not take the x-only template parameter (this fixes ticket #6019.
- // For the right boundary it is not necessary (though also not harmful),
+ // For the right boundary it is not necessary (though also not harmful),
// because points are sorted from bottom to top in a later stage.
// For symmetry and to get often more balanced lower/upper halves
// we keep it.
@@ -282,17 +287,17 @@ public:
template <typename OutputIterator>
inline void result(partitions const& state,
- OutputIterator out, bool clockwise) const
+ OutputIterator out,
+ bool clockwise,
+ bool closed) const
{
if (clockwise)
{
- output_range<iterate_forward>(state.m_upper_hull, out, false);
- output_range<iterate_reverse>(state.m_lower_hull, out, true);
+ output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed);
}
else
{
- output_range<iterate_forward>(state.m_lower_hull, out, false);
- output_range<iterate_reverse>(state.m_upper_hull, out, true);
+ output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed);
}
}
@@ -319,11 +324,11 @@ private:
typedef typename strategy::side::services::default_strategy<cs_tag>::type side;
output.push_back(p);
- register std::size_t output_size = output.size();
+ std::size_t output_size = output.size();
while (output_size >= 3)
{
rev_iterator rit = output.rbegin();
- point_type const& last = *rit++;
+ point_type const last = *rit++;
point_type const& last2 = *rit++;
if (Factor * side::apply(*rit, last, last2) <= 0)
@@ -343,28 +348,28 @@ private:
}
- template <iterate_direction Direction, typename OutputIterator>
- static inline void output_range(container_type const& range,
- OutputIterator out, bool skip_first)
+ template <typename OutputIterator>
+ static inline void output_ranges(container_type const& first, container_type const& second,
+ OutputIterator out, bool closed)
{
- typedef typename reversible_view<container_type const, Direction>::type view_type;
- view_type view(range);
- bool first = true;
- for (typename boost::range_iterator<view_type const>::type it = boost::begin(view);
- it != boost::end(view); ++it)
+ std::copy(boost::begin(first), boost::end(first), out);
+
+ BOOST_ASSERT(closed ? !boost::empty(second) : boost::size(second) > 1);
+ std::copy(++boost::rbegin(second), // skip the first Point
+ closed ? boost::rend(second) : --boost::rend(second), // skip the last Point if open
+ out);
+
+ typedef typename boost::range_size<container_type>::type size_type;
+ size_type const count = boost::size(first) + boost::size(second) - 1;
+ // count describes a closed case but comparison with min size of closed
+ // gives the result compatible also with open
+ // here core_detail::closure::minimum_ring_size<closed> could be used
+ if ( count < 4 )
{
- if (first && skip_first)
- {
- first = false;
- }
- else
- {
- *out = *it;
- ++out;
- }
+ // there should be only one missing
+ *out++ = *boost::begin(first);
}
}
-
};
}} // namespace strategy::convex_hull
diff --git a/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp b/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp
index 1398ddb687..968f9fecb9 100644
--- a/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp
+++ b/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp
@@ -22,9 +22,9 @@
#include <boost/geometry/strategies/within.hpp>
-namespace boost { namespace geometry { namespace strategy
+namespace boost { namespace geometry { namespace strategy
{
-
+
namespace within
{
@@ -71,11 +71,11 @@ struct point_in_box_by_side
boost::array<typename point_type<Box>::type, 5> bp;
geometry::detail::assign_box_corners_oriented<true>(box, bp);
bp[4] = bp[0];
-
+
bool result = true;
side_strategy_type strategy;
boost::ignore_unused_variable_warning(strategy);
-
+
for (int i = 1; i < 5; i++)
{
int const side = strategy.apply(point, bp[i - 1], bp[i]);
@@ -84,7 +84,7 @@ struct point_in_box_by_side
return result;
}
}
-
+
return result;
}
};
@@ -102,9 +102,9 @@ namespace within { namespace services
template <typename Point, typename Box>
struct default_strategy
<
- point_tag, box_tag,
- point_tag, areal_tag,
- spherical_tag, spherical_tag,
+ point_tag, box_tag,
+ point_tag, areal_tag,
+ spherical_tag, spherical_tag,
Point, Box
>
{
@@ -126,9 +126,9 @@ namespace covered_by { namespace services
template <typename Point, typename Box>
struct default_strategy
<
- point_tag, box_tag,
- point_tag, areal_tag,
- spherical_tag, spherical_tag,
+ point_tag, box_tag,
+ point_tag, areal_tag,
+ spherical_tag, spherical_tag,
Point, Box
>
{
diff --git a/boost/geometry/strategies/agnostic/point_in_point.hpp b/boost/geometry/strategies/agnostic/point_in_point.hpp
new file mode 100644
index 0000000000..e4f9bec4c6
--- /dev/null
+++ b/boost/geometry/strategies/agnostic/point_in_point.hpp
@@ -0,0 +1,136 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
+#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+#include <boost/geometry/strategies/covered_by.hpp>
+#include <boost/geometry/strategies/within.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace within
+{
+
+template
+<
+ typename Point1, typename Point2
+>
+struct point_in_point
+{
+ static inline bool apply(Point1 const& point1, Point2 const& point2)
+ {
+ return detail::equals::equals_point_point(point1, point2);
+ }
+};
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+namespace services
+{
+
+template <typename Point1, typename Point2>
+struct default_strategy<point_tag, point_tag, point_tag, point_tag, cartesian_tag, cartesian_tag, Point1, Point2>
+{
+ typedef strategy::within::point_in_point<Point1, Point2> type;
+};
+
+template <typename Point1, typename Point2>
+struct default_strategy<point_tag, point_tag, point_tag, point_tag, spherical_tag, spherical_tag, Point1, Point2>
+{
+ typedef strategy::within::point_in_point<Point1, Point2> type;
+};
+
+template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2>
+struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2>
+{
+ typedef strategy::within::point_in_point<Point1, Point2> type;
+};
+
+template <typename Point, typename MultiPoint>
+struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, cartesian_tag, cartesian_tag, Point, MultiPoint>
+{
+ typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
+};
+
+template <typename Point, typename MultiPoint>
+struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, spherical_tag, spherical_tag, Point, MultiPoint>
+{
+ typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
+};
+
+template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2>
+struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint>
+{
+ typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
+};
+
+} // namespace services
+
+#endif
+
+
+}} // namespace strategy::within
+
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace strategy { namespace covered_by { namespace services
+{
+
+template <typename Point1, typename Point2>
+struct default_strategy<point_tag, point_tag, point_tag, point_tag, cartesian_tag, cartesian_tag, Point1, Point2>
+{
+ typedef strategy::within::point_in_point<Point1, Point2> type;
+};
+
+template <typename Point1, typename Point2>
+struct default_strategy<point_tag, point_tag, point_tag, point_tag, spherical_tag, spherical_tag, Point1, Point2>
+{
+ typedef strategy::within::point_in_point<Point1, Point2> type;
+};
+
+template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2>
+struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2>
+{
+ typedef strategy::within::point_in_point<Point1, Point2> type;
+};
+
+template <typename Point, typename MultiPoint>
+struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, cartesian_tag, cartesian_tag, Point, MultiPoint>
+{
+ typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
+};
+
+template <typename Point, typename MultiPoint>
+struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, spherical_tag, spherical_tag, Point, MultiPoint>
+{
+ typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
+};
+
+template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2>
+struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint>
+{
+ typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
+};
+
+}}} // namespace strategy::covered_by::services
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
diff --git a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp
index 69188650d8..f4ed7a634f 100644
--- a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp
+++ b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp
@@ -1,6 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -9,10 +13,14 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
+#include <boost/core/ignore_unused.hpp>
+
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
@@ -27,6 +35,153 @@ namespace boost { namespace geometry
namespace strategy { namespace within
{
+
+// Fix for https://svn.boost.org/trac/boost/ticket/9628
+// For floating point coordinates, the <1> coordinate of a point is compared
+// with the segment's points using some EPS. If the coordinates are "equal"
+// the sides are calculated. Therefore we can treat a segment as a long areal
+// geometry having some width. There is a small ~triangular area somewhere
+// between the segment's effective area and a segment's line used in sides
+// calculation where the segment is on the one side of the line but on the
+// other side of a segment (due to the width).
+// For the s1 of a segment going NE the real side is RIGHT but the point may
+// be detected as LEFT, like this:
+// RIGHT
+// ___----->
+// ^ O Pt __ __
+// EPS __ __
+// v__ __ BUT DETECTED AS LEFT OF THIS LINE
+// _____7
+// _____/
+// _____/
+template <typename CSTag>
+struct winding_side_equal
+{
+ typedef typename strategy::side::services::default_strategy
+ <
+ CSTag
+ >::type strategy_side_type;
+
+ template <size_t D, typename Point, typename PointOfSegment>
+ static inline int apply(Point const& point,
+ PointOfSegment const& se,
+ int count)
+ {
+ // Create a vertical segment intersecting the original segment's endpoint
+ // equal to the point, with the derived direction (UP/DOWN).
+ // Set only the 2 first coordinates, the other ones are ignored
+ PointOfSegment ss1, ss2;
+ set<1-D>(ss1, get<1-D>(se));
+ set<1-D>(ss2, get<1-D>(se));
+ if ( count > 0 ) // UP
+ {
+ set<D>(ss1, 0);
+ set<D>(ss2, 1);
+ }
+ else // DOWN
+ {
+ set<D>(ss1, 1);
+ set<D>(ss2, 0);
+ }
+ // Check the side using this vertical segment
+ return strategy_side_type::apply(ss1, ss2, point);
+ }
+};
+
+// The optimization for cartesian
+template <>
+struct winding_side_equal<cartesian_tag>
+{
+ template <size_t D, typename Point, typename PointOfSegment>
+ static inline int apply(Point const& point,
+ PointOfSegment const& se,
+ int count)
+ {
+ return math::equals(get<1-D>(point), get<1-D>(se)) ?
+ 0 :
+ get<1-D>(point) < get<1-D>(se) ?
+ // assuming count is equal to 1 or -1
+ count : // ( count > 0 ? 1 : -1) :
+ -count; // ( count > 0 ? -1 : 1) ;
+ }
+};
+
+
+template <typename CSTag>
+struct winding_side_between
+{
+ typedef typename strategy::side::services::default_strategy
+ <
+ CSTag
+ >::type strategy_side_type;
+
+ template <size_t D, typename Point, typename PointOfSegment>
+ static inline int apply(Point const& point,
+ PointOfSegment const& s1, PointOfSegment const& s2,
+ int count)
+ {
+ // Create a vertical segment intersecting the original segment's endpoint
+ // equal to the point, with the derived direction (UP/DOWN).
+ // Set only the 2 first coordinates, the other ones are ignored
+ PointOfSegment ss1, ss2;
+ set<1-D>(ss1, get<1-D>(s1));
+ set<1-D>(ss2, get<1-D>(s1));
+
+ if ( count > 0 ) // UP
+ {
+ set<D>(ss1, 0);
+ set<D>(ss2, 1);
+ }
+ else // DOWN
+ {
+ set<D>(ss1, 1);
+ set<D>(ss2, 0);
+ }
+
+ int const seg_side = strategy_side_type::apply(ss1, ss2, s2);
+
+ if ( seg_side != 0 ) // segment not vertical
+ {
+ if ( strategy_side_type::apply(ss1, ss2, point) == -seg_side ) // point on the opposite side than s2
+ {
+ return -seg_side;
+ }
+ else
+ {
+ set<1-D>(ss1, get<1-D>(s2));
+ set<1-D>(ss2, get<1-D>(s2));
+
+ if ( strategy_side_type::apply(ss1, ss2, point) == seg_side ) // point behind s2
+ {
+ return seg_side;
+ }
+ }
+ }
+
+ // segment is vertical or point is between p1 and p2
+ return strategy_side_type::apply(s1, s2, point);
+ }
+};
+
+// The specialization for cartesian
+template <>
+struct winding_side_between<cartesian_tag>
+{
+ typedef strategy::side::services::default_strategy
+ <
+ cartesian_tag
+ >::type strategy_side_type;
+
+ template <size_t D, typename Point, typename PointOfSegment>
+ static inline int apply(Point const& point,
+ PointOfSegment const& s1, PointOfSegment const& s2,
+ int /*count*/)
+ {
+ return strategy_side_type::apply(s1, s2, point);
+ }
+};
+
+
/*!
\brief Within detection using winding rule
\ingroup strategies
@@ -106,21 +261,21 @@ class winding
template <size_t D>
static inline int check_segment(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
- counter& state)
+ counter& state, bool& eq1, bool& eq2)
{
calculation_type const p = get<D>(point);
calculation_type const s1 = get<D>(seg1);
calculation_type const s2 = get<D>(seg2);
// Check if one of segment endpoints is at same level of point
- bool eq1 = math::equals(s1, p);
- bool eq2 = math::equals(s2, p);
+ eq1 = math::equals(s1, p);
+ eq2 = math::equals(s2, p);
if (eq1 && eq2)
{
// Both equal p -> segment is horizontal (or vertical for D=0)
// The only thing which has to be done is check if point is ON segment
- return check_touch<1 - D>(point, seg1, seg2,state);
+ return check_touch<1 - D>(point, seg1, seg2, state);
}
return
@@ -132,8 +287,6 @@ class winding
}
-
-
public :
// Typedefs and static methods to fulfill the concept
@@ -145,10 +298,27 @@ public :
PointOfSegment const& s1, PointOfSegment const& s2,
counter& state)
{
- int count = check_segment<1>(point, s1, s2, state);
+ typedef typename cs_tag<Point>::type cs_t;
+
+ bool eq1 = false;
+ bool eq2 = false;
+ boost::ignore_unused(eq2);
+
+ int count = check_segment<1>(point, s1, s2, state, eq1, eq2);
if (count != 0)
{
- int side = strategy_side_type::apply(s1, s2, point);
+ int side = 0;
+ if ( count == 1 || count == -1 )
+ {
+ side = winding_side_equal<cs_t>
+ ::template apply<1>(point, eq1 ? s1 : s2, count);
+ }
+ else // count == 2 || count == -2
+ {
+ side = winding_side_between<cs_t>
+ ::template apply<1>(point, s1, s2, count);
+ }
+
if (side == 0)
{
// Point is lying on segment
@@ -194,6 +364,19 @@ struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag,
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
+// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used
+
+template <typename Point, typename Geometry, typename AnyTag>
+struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, cartesian_tag, cartesian_tag, Point, Geometry>
+{
+ typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
+};
+
+template <typename Point, typename Geometry, typename AnyTag>
+struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, spherical_tag, spherical_tag, Point, Geometry>
+{
+ typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
+};
} // namespace services
@@ -221,6 +404,19 @@ struct default_strategy<point_tag, AnyTag, point_tag, areal_tag, spherical_tag,
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
+// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used
+
+template <typename Point, typename Geometry, typename AnyTag>
+struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, cartesian_tag, cartesian_tag, Point, Geometry>
+{
+ typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
+};
+
+template <typename Point, typename Geometry, typename AnyTag>
+struct default_strategy<point_tag, AnyTag, point_tag, AnyTag, spherical_tag, spherical_tag, Point, Geometry>
+{
+ typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
+};
}}} // namespace strategy::covered_by::services
#endif
diff --git a/boost/geometry/strategies/agnostic/relate.hpp b/boost/geometry/strategies/agnostic/relate.hpp
new file mode 100644
index 0000000000..318047fadb
--- /dev/null
+++ b/boost/geometry/strategies/agnostic/relate.hpp
@@ -0,0 +1,91 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP
+#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP
+
+#include <boost/geometry/algorithms/detail/relate/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace relate
+{
+
+template <typename StaticMask>
+struct relate
+{
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ return detail::relate::relate<StaticMask>(geometry1, geometry2);
+ }
+};
+
+} // namespace relate
+
+namespace within
+{
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+namespace services
+{
+
+
+template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS>
+struct default_strategy<AnyTag1, AnyTag2, AnyTag1, AnyTag2, AnyCS, AnyCS, Geometry1, Geometry2>
+{
+ typedef strategy::relate::relate<detail::relate::static_mask_within> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS>
+struct default_strategy<AnyTag1, AnyTag2, AnyTag1, areal_tag, AnyCS, AnyCS, Geometry1, Geometry2>
+{
+ typedef strategy::relate::relate<detail::relate::static_mask_within> type;
+};
+
+
+} // namespace services
+
+#endif
+
+
+}} // namespace strategy::within
+
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace strategy { namespace covered_by { namespace services
+{
+
+
+template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS>
+struct default_strategy<AnyTag1, AnyTag2, AnyTag1, AnyTag2, AnyCS, AnyCS, Geometry1, Geometry2>
+{
+ typedef strategy::relate::relate<detail::relate::static_mask_covered_by> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2, typename AnyCS>
+struct default_strategy<AnyTag1, AnyTag2, AnyTag1, areal_tag, AnyCS, AnyCS, Geometry1, Geometry2>
+{
+ typedef strategy::relate::relate<detail::relate::static_mask_covered_by> type;
+};
+
+
+}}} // namespace strategy::covered_by::services
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP
diff --git a/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp
index 4a1a22d1cf..8ad3bbc50d 100644
--- a/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp
+++ b/boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp
@@ -65,163 +65,238 @@ namespace detail
return douglas_peucker_point<Point>(*this);
}
};
-}
-#endif // DOXYGEN_NO_DETAIL
+ template
+ <
+ typename Point,
+ typename PointDistanceStrategy,
+ typename LessCompare
+ = std::less
+ <
+ typename strategy::distance::services::return_type
+ <
+ PointDistanceStrategy,
+ Point, Point
+ >::type
+ >
+ >
+ class douglas_peucker
+ : LessCompare // for empty base optimization
+ {
+ public :
-/*!
-\brief Implements the simplify algorithm.
-\ingroup strategies
-\details The douglas_peucker strategy simplifies a linestring, ring or
- vector of points using the well-known Douglas-Peucker algorithm.
- For the algorithm, see for example:
-\see http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
-\see http://www2.dcs.hull.ac.uk/CISRG/projects/Royal-Inst/demos/dp.html
-\tparam Point the point type
-\tparam PointDistanceStrategy point-segment distance strategy to be used
-\note This strategy uses itself a point-segment-distance strategy which
- can be specified
-\author Barend and Maarten, 1995/1996
-\author Barend, revised for Generic Geometry Library, 2008
-*/
-template
-<
- typename Point,
- typename PointDistanceStrategy
->
-class douglas_peucker
-{
-public :
+ // See also ticket 5954 https://svn.boost.org/trac/boost/ticket/5954
+ // Comparable is currently not possible here because it has to be compared to the squared of max_distance, and more.
+ // For now we have to take the real distance.
+ typedef PointDistanceStrategy distance_strategy_type;
+ // typedef typename strategy::distance::services::comparable_type<PointDistanceStrategy>::type distance_strategy_type;
- // See also ticket 5954 https://svn.boost.org/trac/boost/ticket/5954
- // Comparable is currently not possible here because it has to be compared to the squared of max_distance, and more.
- // For now we have to take the real distance.
- typedef PointDistanceStrategy distance_strategy_type;
- // typedef typename strategy::distance::services::comparable_type<PointDistanceStrategy>::type distance_strategy_type;
+ typedef typename strategy::distance::services::return_type
+ <
+ distance_strategy_type,
+ Point, Point
+ >::type distance_type;
- typedef typename strategy::distance::services::return_type<distance_strategy_type>::type return_type;
+ douglas_peucker()
+ {}
-private :
- typedef detail::douglas_peucker_point<Point> dp_point_type;
- typedef typename std::vector<dp_point_type>::iterator iterator_type;
+ douglas_peucker(LessCompare const& less_compare)
+ : LessCompare(less_compare)
+ {}
+ private :
+ typedef detail::douglas_peucker_point<Point> dp_point_type;
+ typedef typename std::vector<dp_point_type>::iterator iterator_type;
- static inline void consider(iterator_type begin,
- iterator_type end,
- return_type const& max_dist, int& n,
- distance_strategy_type const& ps_distance_strategy)
- {
- std::size_t size = end - begin;
- // size must be at least 3
- // because we want to consider a candidate point in between
- if (size <= 2)
+ LessCompare const& less() const
{
-#ifdef GL_DEBUG_DOUGLAS_PEUCKER
- if (begin != end)
+ return *this;
+ }
+
+ inline void consider(iterator_type begin,
+ iterator_type end,
+ distance_type const& max_dist,
+ int& n,
+ distance_strategy_type const& ps_distance_strategy) const
+ {
+ std::size_t size = end - begin;
+
+ // size must be at least 3
+ // because we want to consider a candidate point in between
+ if (size <= 2)
{
- std::cout << "ignore between " << dsv(begin->p)
- << " and " << dsv((end - 1)->p)
- << " size=" << size << std::endl;
- }
- std::cout << "return because size=" << size << std::endl;
+#ifdef GL_DEBUG_DOUGLAS_PEUCKER
+ if (begin != end)
+ {
+ std::cout << "ignore between " << dsv(begin->p)
+ << " and " << dsv((end - 1)->p)
+ << " size=" << size << std::endl;
+ }
+ std::cout << "return because size=" << size << std::endl;
#endif
- return;
- }
+ return;
+ }
- iterator_type last = end - 1;
+ iterator_type last = end - 1;
#ifdef GL_DEBUG_DOUGLAS_PEUCKER
- std::cout << "find between " << dsv(begin->p)
- << " and " << dsv(last->p)
- << " size=" << size << std::endl;
+ std::cout << "find between " << dsv(begin->p)
+ << " and " << dsv(last->p)
+ << " size=" << size << std::endl;
#endif
- // Find most far point, compare to the current segment
- //geometry::segment<Point const> s(begin->p, last->p);
- return_type md(-1.0); // any value < 0
- iterator_type candidate;
- for(iterator_type it = begin + 1; it != last; ++it)
- {
- return_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p);
+ // Find most far point, compare to the current segment
+ //geometry::segment<Point const> s(begin->p, last->p);
+ distance_type md(-1.0); // any value < 0
+ iterator_type candidate;
+ for(iterator_type it = begin + 1; it != last; ++it)
+ {
+ distance_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p);
#ifdef GL_DEBUG_DOUGLAS_PEUCKER
- std::cout << "consider " << dsv(it->p)
- << " at " << double(dist)
- << ((dist > max_dist) ? " maybe" : " no")
- << std::endl;
+ std::cout << "consider " << dsv(it->p)
+ << " at " << double(dist)
+ << ((dist > max_dist) ? " maybe" : " no")
+ << std::endl;
#endif
- if (dist > md)
- {
- md = dist;
- candidate = it;
+ if ( less()(md, dist) )
+ {
+ md = dist;
+ candidate = it;
+ }
}
- }
- // If a point is found, set the include flag
- // and handle segments in between recursively
- if (md > max_dist)
- {
+ // If a point is found, set the include flag
+ // and handle segments in between recursively
+ if ( less()(max_dist, md) )
+ {
#ifdef GL_DEBUG_DOUGLAS_PEUCKER
- std::cout << "use " << dsv(candidate->p) << std::endl;
+ std::cout << "use " << dsv(candidate->p) << std::endl;
#endif
- candidate->included = true;
- n++;
+ candidate->included = true;
+ n++;
- consider(begin, candidate + 1, max_dist, n, ps_distance_strategy);
- consider(candidate, end, max_dist, n, ps_distance_strategy);
+ consider(begin, candidate + 1, max_dist, n, ps_distance_strategy);
+ consider(candidate, end, max_dist, n, ps_distance_strategy);
+ }
}
- }
+ public :
+
+ template <typename Range, typename OutputIterator>
+ inline OutputIterator apply(Range const& range,
+ OutputIterator out,
+ distance_type max_distance) const
+ {
+ distance_strategy_type strategy;
+
+ // Copy coordinates, a vector of references to all points
+ std::vector<dp_point_type> ref_candidates(boost::begin(range),
+ boost::end(range));
+
+ // Include first and last point of line,
+ // they are always part of the line
+ int n = 2;
+ ref_candidates.front().included = true;
+ ref_candidates.back().included = true;
+
+ // Get points, recursively, including them if they are further away
+ // than the specified distance
+ consider(boost::begin(ref_candidates), boost::end(ref_candidates), max_distance, n, strategy);
+
+ // Copy included elements to the output
+ for(typename std::vector<dp_point_type>::const_iterator it
+ = boost::begin(ref_candidates);
+ it != boost::end(ref_candidates);
+ ++it)
+ {
+ if (it->included)
+ {
+ // copy-coordinates does not work because OutputIterator
+ // does not model Point (??)
+ //geometry::convert(it->p, *out);
+ *out = it->p;
+ out++;
+ }
+ }
+ return out;
+ }
+
+ };
+
+
+}
+#endif // DOXYGEN_NO_DETAIL
+
+
+/*!
+\brief Implements the simplify algorithm.
+\ingroup strategies
+\details The douglas_peucker strategy simplifies a linestring, ring or
+ vector of points using the well-known Douglas-Peucker algorithm.
+\tparam Point the point type
+\tparam PointDistanceStrategy point-segment distance strategy to be used
+\note This strategy uses itself a point-segment-distance strategy which
+ can be specified
+\author Barend and Maarten, 1995/1996
+\author Barend, revised for Generic Geometry Library, 2008
+*/
+
+/*
+For the algorithm, see for example:
+ - http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ - http://www2.dcs.hull.ac.uk/CISRG/projects/Royal-Inst/demos/dp.html
+*/
+template
+<
+ typename Point,
+ typename PointDistanceStrategy
+>
+class douglas_peucker
+{
public :
+ typedef PointDistanceStrategy distance_strategy_type;
+
+ typedef typename detail::douglas_peucker
+ <
+ Point,
+ PointDistanceStrategy
+ >::distance_type distance_type;
+
+ typedef distance_type return_type;
+
template <typename Range, typename OutputIterator>
static inline OutputIterator apply(Range const& range,
- OutputIterator out, double max_distance)
+ OutputIterator out,
+ distance_type max_distance)
{
- distance_strategy_type strategy;
+ return detail::douglas_peucker
+ <
+ Point,
+ PointDistanceStrategy
+ >().apply(range, out, max_distance);
+ }
- // Copy coordinates, a vector of references to all points
- std::vector<dp_point_type> ref_candidates(boost::begin(range),
- boost::end(range));
+};
- // Include first and last point of line,
- // they are always part of the line
- int n = 2;
- ref_candidates.front().included = true;
- ref_candidates.back().included = true;
+}} // namespace strategy::simplify
- // Get points, recursively, including them if they are further away
- // than the specified distance
- typedef typename strategy::distance::services::return_type<distance_strategy_type>::type return_type;
- consider(boost::begin(ref_candidates), boost::end(ref_candidates), max_distance, n, strategy);
-
- // Copy included elements to the output
- for(typename std::vector<dp_point_type>::const_iterator it
- = boost::begin(ref_candidates);
- it != boost::end(ref_candidates);
- ++it)
- {
- if (it->included)
- {
- // copy-coordinates does not work because OutputIterator
- // does not model Point (??)
- //geometry::convert(it->p, *out);
- *out = it->p;
- out++;
- }
- }
- return out;
- }
+namespace traits {
+template <typename P>
+struct point_type<strategy::simplify::detail::douglas_peucker_point<P> >
+{
+ typedef P type;
};
-}} // namespace strategy::simplify
+} // namespace traits
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/buffer.hpp b/boost/geometry/strategies/buffer.hpp
new file mode 100644
index 0000000000..7dbe03b4a9
--- /dev/null
+++ b/boost/geometry/strategies/buffer.hpp
@@ -0,0 +1,91 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace buffer
+{
+
+/*
+
+ A Buffer-join strategy gets 4 input points.
+ On the two consecutive segments s1 and s2 (joining at vertex v):
+
+ The lines from parallel at s1, s2 (at buffer-distance) end/start
+ in two points perpendicular to the segments: p1 and p2.
+ These parallel lines interesct in point ip
+
+ (s2)
+ |
+ |
+ ^
+ |
+ (p2) |(v)
+ * +----<--- (s1)
+
+ x(ip) *(p1)
+
+
+ So, in clockwise order:
+ v : vertex point
+ p1: perpendicular on left side of segment1<1> (perp1)
+ ip: intersection point
+ p2: perpendicular on left side of segment2<0> (perp2)
+*/
+
+
+
+/*!
+\brief Enumerates options for side of buffer (left/right w.r.t. directed
+ segment)
+\ingroup enum
+\details Around a linestring, a buffer can be defined left or right.
+ Around a polygon, assumed clockwise internally,
+ a buffer is either on the left side (inflates the polygon), or on the
+ right side (deflates the polygon)
+*/
+enum buffer_side_selector { buffer_side_left, buffer_side_right };
+
+/*!
+\brief Enumerates types of pieces (parts of buffer) around geometries
+\ingroup enum
+*/
+enum piece_type
+{
+ buffered_segment,
+ buffered_join,
+ buffered_round_end,
+ buffered_flat_end,
+ buffered_point,
+ buffered_concave // always on the inside
+};
+
+
+/*!
+\brief Enumerates types of joins
+\ingroup enum
+*/
+enum join_selector
+{
+ join_convex,
+ join_concave,
+ join_continue, // collinear, next segment touches previous segment
+ join_spike // collinear, with overlap, next segment goes back
+};
+
+
+}} // namespace strategy::buffer
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP
diff --git a/boost/geometry/strategies/cartesian/box_in_box.hpp b/boost/geometry/strategies/cartesian/box_in_box.hpp
index 7680b8362c..9889658a13 100644
--- a/boost/geometry/strategies/cartesian/box_in_box.hpp
+++ b/boost/geometry/strategies/cartesian/box_in_box.hpp
@@ -3,6 +3,7 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -21,10 +22,10 @@
#include <boost/geometry/strategies/within.hpp>
-namespace boost { namespace geometry { namespace strategy
+namespace boost { namespace geometry { namespace strategy
{
-
-
+
+
namespace within
{
@@ -36,7 +37,8 @@ struct box_within_range
, BoxContainingValue const& bing_min
, BoxContainingValue const& bing_max)
{
- return bed_min > bing_min && bed_max < bing_max;
+ return bing_min <= bed_min && bed_max <= bing_max // contained in containing
+ && bed_min < bed_max; // interiors overlap
}
};
@@ -69,9 +71,9 @@ struct relate_box_box_loop
assert_dimension_equal<Box1, Box2>();
if (! SubStrategy::apply(
- get<min_corner, Dimension>(b_contained),
- get<max_corner, Dimension>(b_contained),
- get<min_corner, Dimension>(b_containing),
+ get<min_corner, Dimension>(b_contained),
+ get<max_corner, Dimension>(b_contained),
+ get<min_corner, Dimension>(b_containing),
get<max_corner, Dimension>(b_containing)
)
)
@@ -115,7 +117,7 @@ struct box_in_box
{
return relate_box_box_loop
<
- SubStrategy,
+ SubStrategy,
Box1, Box2, 0, dimension<Box1>::type::value
>::apply(box1, box2);
}
@@ -134,9 +136,9 @@ namespace within { namespace services
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
- box_tag, box_tag,
- box_tag, areal_tag,
- cartesian_tag, cartesian_tag,
+ box_tag, box_tag,
+ box_tag, areal_tag,
+ cartesian_tag, cartesian_tag,
BoxContained, BoxContaining
>
{
@@ -152,9 +154,9 @@ namespace covered_by { namespace services
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
- box_tag, box_tag,
- box_tag, areal_tag,
- cartesian_tag, cartesian_tag,
+ box_tag, box_tag,
+ box_tag, areal_tag,
+ cartesian_tag, cartesian_tag,
BoxContained, BoxContaining
>
{
diff --git a/boost/geometry/strategies/cartesian/buffer_end_flat.hpp b/boost/geometry/strategies/cartesian/buffer_end_flat.hpp
new file mode 100644
index 0000000000..c01cf4df85
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_end_flat.hpp
@@ -0,0 +1,112 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+#include <boost/geometry/strategies/side.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace strategy { namespace buffer
+{
+
+
+/*!
+\brief Let the buffer create flat ends
+\ingroup strategies
+\details This strategy can be used as EndStrategy for the buffer algorithm.
+ It creates a flat end for each linestring-end. It can be applied
+ for (multi)linestrings. Also it is applicable for spikes in (multi)polygons.
+ This strategy is only applicable for Cartesian coordinate systems.
+
+\qbk{
+[heading Example]
+[buffer_end_flat]
+[heading Output]
+[$img/strategies/buffer_end_flat.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_end_round end_round]
+}
+ */
+class end_flat
+{
+
+public :
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ //! Fills output_range with a flat end
+ template <typename Point, typename RangeOut, typename DistanceStrategy>
+ inline void apply(Point const& penultimate_point,
+ Point const& perp_left_point,
+ Point const& ultimate_point,
+ Point const& perp_right_point,
+ buffer_side_selector side,
+ DistanceStrategy const& distance,
+ RangeOut& range_out) const
+ {
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ typedef typename geometry::select_most_precise
+ <
+ coordinate_type,
+ double
+ >::type promoted_type;
+
+ promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
+ promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
+
+ bool reversed = (side == buffer_side_left && dist_right < 0 && -dist_right > dist_left)
+ || (side == buffer_side_right && dist_left < 0 && -dist_left > dist_right)
+ ;
+ if (reversed)
+ {
+ range_out.push_back(perp_right_point);
+ range_out.push_back(perp_left_point);
+ }
+ else
+ {
+ range_out.push_back(perp_left_point);
+ range_out.push_back(perp_right_point);
+ }
+ // Don't add the ultimate_point (endpoint of the linestring).
+ // The buffer might be generated completely at one side.
+ // In other cases it does no harm but is further useless
+ }
+
+ template <typename NumericType>
+ static inline NumericType max_distance(NumericType const& distance)
+ {
+ return distance;
+ }
+
+ //! Returns the piece_type (flat end)
+ static inline piece_type get_piece_type()
+ {
+ return buffered_flat_end;
+ }
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+};
+
+
+}} // namespace strategy::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP
diff --git a/boost/geometry/strategies/cartesian/buffer_end_round.hpp b/boost/geometry/strategies/cartesian/buffer_end_round.hpp
new file mode 100644
index 0000000000..74780d6165
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_end_round.hpp
@@ -0,0 +1,166 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+#include <boost/geometry/io/wkt/wkt.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+namespace strategy { namespace buffer
+{
+
+
+/*!
+\brief Let the buffer create rounded ends
+\ingroup strategies
+\details This strategy can be used as EndStrategy for the buffer algorithm.
+ It creates a rounded end for each linestring-end. It can be applied
+ for (multi)linestrings. Also it is applicable for spikes in (multi)polygons.
+ This strategy is only applicable for Cartesian coordinate systems.
+
+\qbk{
+[heading Example]
+[buffer_end_round]
+[heading Output]
+[$img/strategies/buffer_end_round.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_end_flat end_flat]
+}
+ */
+class end_round
+{
+private :
+ std::size_t m_points_per_circle;
+
+ template
+ <
+ typename Point,
+ typename PromotedType,
+ typename DistanceType,
+ typename RangeOut
+ >
+ inline void generate_points(Point const& point,
+ PromotedType alpha, // by value
+ DistanceType const& buffer_distance,
+ RangeOut& range_out) const
+ {
+ PromotedType const two = 2.0;
+ PromotedType const two_pi = two * geometry::math::pi<PromotedType>();
+
+ std::size_t point_buffer_count = m_points_per_circle;
+
+ PromotedType const diff = two_pi / PromotedType(point_buffer_count);
+
+ // For half circle:
+ point_buffer_count /= 2;
+ point_buffer_count++;
+
+ for (std::size_t i = 0; i < point_buffer_count; i++, alpha -= diff)
+ {
+ typename boost::range_value<RangeOut>::type p;
+ set<0>(p, get<0>(point) + buffer_distance * cos(alpha));
+ set<1>(p, get<1>(point) + buffer_distance * sin(alpha));
+ range_out.push_back(p);
+ }
+ }
+
+ template <typename T, typename P1, typename P2>
+ static inline T calculate_angle(P1 const& from_point, P2 const& to_point)
+ {
+ typedef P1 vector_type;
+ vector_type v = from_point;
+ geometry::subtract_point(v, to_point);
+ return atan2(geometry::get<1>(v), geometry::get<0>(v));
+ }
+
+public :
+
+ //! \brief Constructs the strategy
+ //! \param points_per_circle points which would be used for a full circle
+ explicit inline end_round(std::size_t points_per_circle = 90)
+ : m_points_per_circle(points_per_circle)
+ {}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+ //! Fills output_range with a flat end
+ template <typename Point, typename RangeOut, typename DistanceStrategy>
+ inline void apply(Point const& penultimate_point,
+ Point const& perp_left_point,
+ Point const& ultimate_point,
+ Point const& ,
+ buffer_side_selector side,
+ DistanceStrategy const& distance,
+ RangeOut& range_out) const
+ {
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ typedef typename geometry::select_most_precise
+ <
+ coordinate_type,
+ double
+ >::type promoted_type;
+
+ promoted_type const alpha = calculate_angle<promoted_type>(perp_left_point, ultimate_point);
+
+ promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
+ promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
+ if (geometry::math::equals(dist_left, dist_right))
+ {
+ generate_points(ultimate_point, alpha, dist_left, range_out);
+ }
+ else
+ {
+ promoted_type const two = 2.0;
+ promoted_type dist_half_diff = (dist_left - dist_right) / two;
+
+ if (side == buffer_side_right)
+ {
+ dist_half_diff = -dist_half_diff;
+ }
+
+ Point shifted_point;
+ set<0>(shifted_point, get<0>(ultimate_point) + dist_half_diff * cos(alpha));
+ set<1>(shifted_point, get<1>(ultimate_point) + dist_half_diff * sin(alpha));
+ generate_points(shifted_point, alpha, (dist_left + dist_right) / two, range_out);
+ }
+ }
+
+ template <typename NumericType>
+ static inline NumericType max_distance(NumericType const& distance)
+ {
+ return distance;
+ }
+
+ //! Returns the piece_type (flat end)
+ static inline piece_type get_piece_type()
+ {
+ return buffered_round_end;
+ }
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+};
+
+
+}} // namespace strategy::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
diff --git a/boost/geometry/strategies/cartesian/buffer_join_miter.hpp b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp
new file mode 100644
index 0000000000..8fcf3b996c
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_join_miter.hpp
@@ -0,0 +1,140 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
+
+#include <boost/assert.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace buffer
+{
+
+/*!
+\brief Let the buffer create sharp corners
+\ingroup strategies
+\details This strategy can be used as JoinStrategy for the buffer algorithm.
+ It creates a sharp corners around each convex vertex. It can be applied
+ for (multi)linestrings and (multi)polygons.
+ If corners are sharp by themselves, the miters might become very long. Therefore
+ there is a limit (miter_limit), in terms of the used distance, which limits
+ their length. The miter is not changed to a bevel form (as done in some
+ other software), it is just adapted to the specified miter_limit but keeps
+ its miter form.
+ This strategy is only applicable for Cartesian coordinate systems.
+
+\qbk{
+[heading Example]
+[buffer_join_miter]
+[heading Output]
+[$img/strategies/buffer_join_miter.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_join_round join_round]
+}
+ */
+class join_miter
+{
+public:
+
+ //! \brief Constructs the strategy
+ //! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners
+ explicit inline join_miter(double miter_limit = 5.0)
+ : m_miter_limit(valid_limit(miter_limit))
+ {}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ //! Fills output_range with a sharp shape around a vertex
+ template <typename Point, typename DistanceType, typename RangeOut>
+ inline bool apply(Point const& ip, Point const& vertex,
+ Point const& perp1, Point const& perp2,
+ DistanceType const& buffer_distance,
+ RangeOut& range_out) const
+ {
+ geometry::equal_to<Point> equals;
+ if (equals(ip, vertex))
+ {
+ return false;
+ }
+ if (equals(perp1, perp2))
+ {
+ return false;
+ }
+
+ typedef typename coordinate_type<Point>::type coordinate_type;
+ typedef typename geometry::select_most_precise
+ <
+ coordinate_type,
+ double
+ >::type promoted_type;
+
+ Point p = ip;
+
+ // Check the distance ip-vertex (= miter distance)
+ // (We calculate it manually (not using Pythagoras strategy) to reuse
+ // dx and dy)
+ coordinate_type const dx = get<0>(p) - get<0>(vertex);
+ coordinate_type const dy = get<1>(p) - get<1>(vertex);
+
+ promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy);
+
+ promoted_type const max_distance
+ = m_miter_limit * geometry::math::abs(buffer_distance);
+
+ if (distance > max_distance)
+ {
+ BOOST_ASSERT(distance != 0.0);
+
+ promoted_type const proportion = max_distance / distance;
+ set<0>(p, get<0>(vertex) + dx * proportion);
+ set<1>(p, get<1>(vertex) + dy * proportion);
+ }
+
+ range_out.push_back(perp1);
+ range_out.push_back(p);
+ range_out.push_back(perp2);
+ return true;
+ }
+
+ template <typename NumericType>
+ inline NumericType max_distance(NumericType const& distance) const
+ {
+ return distance * m_miter_limit;
+ }
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+private :
+ double valid_limit(double miter_limit) const
+ {
+ if (miter_limit < 1.0)
+ {
+ // It should always exceed the buffer distance
+ miter_limit = 1.0;
+ }
+ return miter_limit;
+ }
+
+ double m_miter_limit;
+};
+
+}} // namespace strategy::buffer
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
diff --git a/boost/geometry/strategies/cartesian/buffer_join_round.hpp b/boost/geometry/strategies/cartesian/buffer_join_round.hpp
new file mode 100644
index 0000000000..9e467c85a0
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_join_round.hpp
@@ -0,0 +1,177 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
+
+#include <boost/assert.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
+#include <boost/geometry/io/wkt/wkt.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace strategy { namespace buffer
+{
+
+/*!
+\brief Let the buffer create rounded corners
+\ingroup strategies
+\details This strategy can be used as JoinStrategy for the buffer algorithm.
+ It creates a rounded corners around each convex vertex. It can be applied
+ for (multi)linestrings and (multi)polygons.
+ This strategy is only applicable for Cartesian coordinate systems.
+
+\qbk{
+[heading Example]
+[buffer_join_round]
+[heading Output]
+[$img/strategies/buffer_join_round.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_join_miter join_miter]
+}
+ */
+class join_round
+{
+public :
+
+ //! \brief Constructs the strategy
+ //! \param points_per_circle points which would be used for a full circle
+ explicit inline join_round(std::size_t points_per_circle = 90)
+ : m_points_per_circle(points_per_circle)
+ {}
+
+private :
+ template
+ <
+ typename PromotedType,
+ typename Point,
+ typename DistanceType,
+ typename RangeOut
+ >
+ inline void generate_points(Point const& vertex,
+ Point const& perp1, Point const& perp2,
+ DistanceType const& buffer_distance,
+ RangeOut& range_out) const
+ {
+ PromotedType dx1 = get<0>(perp1) - get<0>(vertex);
+ PromotedType dy1 = get<1>(perp1) - get<1>(vertex);
+ PromotedType dx2 = get<0>(perp2) - get<0>(vertex);
+ PromotedType dy2 = get<1>(perp2) - get<1>(vertex);
+
+ BOOST_ASSERT(buffer_distance != 0);
+
+ dx1 /= buffer_distance;
+ dy1 /= buffer_distance;
+ dx2 /= buffer_distance;
+ dy2 /= buffer_distance;
+
+ PromotedType angle_diff = acos(dx1 * dx2 + dy1 * dy2);
+
+ PromotedType two = 2.0;
+ PromotedType steps = m_points_per_circle;
+ int n = boost::numeric_cast<int>(steps * angle_diff
+ / (two * geometry::math::pi<PromotedType>()));
+
+ if (n <= 1)
+ {
+ return;
+ }
+
+ PromotedType const angle1 = atan2(dy1, dx1);
+ PromotedType diff = angle_diff / PromotedType(n);
+ PromotedType a = angle1 - diff;
+
+ for (int i = 0; i < n - 1; i++, a -= diff)
+ {
+ Point p;
+ set<0>(p, get<0>(vertex) + buffer_distance * cos(a));
+ set<1>(p, get<1>(vertex) + buffer_distance * sin(a));
+ range_out.push_back(p);
+ }
+ }
+
+public :
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ //! Fills output_range with a rounded shape around a vertex
+ template <typename Point, typename DistanceType, typename RangeOut>
+ inline bool apply(Point const& ip, Point const& vertex,
+ Point const& perp1, Point const& perp2,
+ DistanceType const& buffer_distance,
+ RangeOut& range_out) const
+ {
+ typedef typename coordinate_type<Point>::type coordinate_type;
+ typedef typename boost::range_value<RangeOut>::type output_point_type;
+
+ typedef typename geometry::select_most_precise
+ <
+ typename geometry::select_most_precise
+ <
+ coordinate_type,
+ typename geometry::coordinate_type<output_point_type>::type
+ >::type,
+ double
+ >::type promoted_type;
+
+ geometry::equal_to<Point> equals;
+ if (equals(perp1, perp2))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
+ std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
+#endif
+ return false;
+ }
+
+ // Generate 'vectors'
+ coordinate_type vix = (get<0>(ip) - get<0>(vertex));
+ coordinate_type viy = (get<1>(ip) - get<1>(vertex));
+
+ promoted_type length_i = geometry::math::sqrt(vix * vix + viy * viy);
+ DistanceType const bd = geometry::math::abs(buffer_distance);
+ promoted_type prop = bd / length_i;
+
+ Point bp;
+ set<0>(bp, get<0>(vertex) + vix * prop);
+ set<1>(bp, get<1>(vertex) + viy * prop);
+
+ range_out.push_back(perp1);
+ generate_points<promoted_type>(vertex, perp1, perp2, bd, range_out);
+ range_out.push_back(perp2);
+ return true;
+ }
+
+ template <typename NumericType>
+ static inline NumericType max_distance(NumericType const& distance)
+ {
+ return distance;
+ }
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+private :
+ std::size_t m_points_per_circle;
+};
+
+
+}} // namespace strategy::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
diff --git a/boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp b/boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp
new file mode 100644
index 0000000000..1444c795af
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp
@@ -0,0 +1,155 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
+
+#include <boost/assert.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
+#include <boost/geometry/io/wkt/wkt.hpp>
+#endif
+
+namespace boost { namespace geometry
+{
+
+
+namespace strategy { namespace buffer
+{
+
+
+class join_round_by_divide
+{
+public :
+
+ inline join_round_by_divide(std::size_t max_level = 4)
+ : m_max_level(max_level)
+ {}
+
+ template
+ <
+ typename PromotedType,
+ typename Point,
+ typename DistanceType,
+ typename RangeOut
+ >
+ inline void mid_points(Point const& vertex,
+ Point const& p1, Point const& p2,
+ DistanceType const& buffer_distance,
+ RangeOut& range_out,
+ std::size_t level = 1) const
+ {
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ // Generate 'vectors'
+ coordinate_type const vp1_x = get<0>(p1) - get<0>(vertex);
+ coordinate_type const vp1_y = get<1>(p1) - get<1>(vertex);
+
+ coordinate_type const vp2_x = (get<0>(p2) - get<0>(vertex));
+ coordinate_type const vp2_y = (get<1>(p2) - get<1>(vertex));
+
+ // Average them to generate vector in between
+ coordinate_type const two = 2;
+ coordinate_type const v_x = (vp1_x + vp2_x) / two;
+ coordinate_type const v_y = (vp1_y + vp2_y) / two;
+
+ PromotedType const length2 = geometry::math::sqrt(v_x * v_x + v_y * v_y);
+
+ PromotedType prop = buffer_distance / length2;
+
+ Point mid_point;
+ set<0>(mid_point, get<0>(vertex) + v_x * prop);
+ set<1>(mid_point, get<1>(vertex) + v_y * prop);
+
+ if (level < m_max_level)
+ {
+ mid_points<PromotedType>(vertex, p1, mid_point, buffer_distance, range_out, level + 1);
+ }
+ range_out.push_back(mid_point);
+ if (level < m_max_level)
+ {
+ mid_points<PromotedType>(vertex, mid_point, p2, buffer_distance, range_out, level + 1);
+ }
+ }
+
+ template <typename Point, typename DistanceType, typename RangeOut>
+ inline bool apply(Point const& ip, Point const& vertex,
+ Point const& perp1, Point const& perp2,
+ DistanceType const& buffer_distance,
+ RangeOut& range_out) const
+ {
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ typedef typename geometry::select_most_precise
+ <
+ coordinate_type,
+ double
+ >::type promoted_type;
+
+ geometry::equal_to<Point> equals;
+
+ if (equals(perp1, perp2))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
+ std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
+#endif
+ return false;
+ }
+
+ // Generate 'vectors'
+ coordinate_type const vix = (get<0>(ip) - get<0>(vertex));
+ coordinate_type const viy = (get<1>(ip) - get<1>(vertex));
+
+ promoted_type const length_i = geometry::math::sqrt(vix * vix + viy * viy);
+
+ promoted_type const bd = geometry::math::abs(buffer_distance);
+ promoted_type prop = bd / length_i;
+
+ Point bp;
+ set<0>(bp, get<0>(vertex) + vix * prop);
+ set<1>(bp, get<1>(vertex) + viy * prop);
+
+ range_out.push_back(perp1);
+
+ if (m_max_level > 1)
+ {
+ mid_points<promoted_type>(vertex, perp1, bp, bd, range_out);
+ range_out.push_back(bp);
+ mid_points<promoted_type>(vertex, bp, perp2, bd, range_out);
+ }
+ else if (m_max_level == 1)
+ {
+ range_out.push_back(bp);
+ }
+
+ range_out.push_back(perp2);
+ return true;
+ }
+
+ template <typename NumericType>
+ static inline NumericType max_distance(NumericType const& distance)
+ {
+ return distance;
+ }
+
+private :
+ std::size_t m_max_level;
+};
+
+
+}} // namespace strategy::buffer
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
diff --git a/boost/geometry/strategies/cartesian/buffer_point_circle.hpp b/boost/geometry/strategies/cartesian/buffer_point_circle.hpp
new file mode 100644
index 0000000000..f64a82d8fc
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_point_circle.hpp
@@ -0,0 +1,108 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace buffer
+{
+
+/*!
+\brief Create a circular buffer around a point
+\ingroup strategies
+\details This strategy can be used as PointStrategy for the buffer algorithm.
+ It creates a circular buffer around a point. It can be applied
+ for points and multi_points, but also for a linestring (if it is degenerate,
+ so consisting of only one point) and for polygons (if it is degenerate).
+ This strategy is only applicable for Cartesian coordinate systems.
+
+\qbk{
+[heading Example]
+[buffer_point_circle]
+[heading Output]
+[$img/strategies/buffer_point_circle.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_point_square point_square]
+}
+ */
+class point_circle
+{
+public :
+ //! \brief Constructs the strategy
+ //! \param count number of points for the created circle
+ explicit point_circle(std::size_t count = 90)
+ : m_count(count)
+ {}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ //! Fills output_range with a circle around point using distance_strategy
+ template
+ <
+ typename Point,
+ typename OutputRange,
+ typename DistanceStrategy
+ >
+ inline void apply(Point const& point,
+ DistanceStrategy const& distance_strategy,
+ OutputRange& output_range) const
+ {
+ typedef typename boost::range_value<OutputRange>::type output_point_type;
+
+ typedef typename geometry::select_most_precise
+ <
+ typename geometry::select_most_precise
+ <
+ typename geometry::coordinate_type<Point>::type,
+ typename geometry::coordinate_type<output_point_type>::type
+ >::type,
+ double
+ >::type promoted_type;
+
+ promoted_type const buffer_distance = distance_strategy.apply(point, point,
+ strategy::buffer::buffer_side_left);
+
+ promoted_type const two = 2.0;
+ promoted_type const two_pi = two * geometry::math::pi<promoted_type>();
+
+ promoted_type const diff = two_pi / promoted_type(m_count);
+ promoted_type a = 0;
+
+ for (std::size_t i = 0; i < m_count; i++, a -= diff)
+ {
+ output_point_type p;
+ set<0>(p, get<0>(point) + buffer_distance * cos(a));
+ set<1>(p, get<1>(point) + buffer_distance * sin(a));
+ output_range.push_back(p);
+ }
+
+ // Close it:
+ output_range.push_back(output_range.front());
+ }
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+private :
+ std::size_t m_count;
+};
+
+
+}} // namespace strategy::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP
diff --git a/boost/geometry/strategies/cartesian/buffer_point_square.hpp b/boost/geometry/strategies/cartesian/buffer_point_square.hpp
new file mode 100644
index 0000000000..37a90c013f
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_point_square.hpp
@@ -0,0 +1,109 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace buffer
+{
+
+/*!
+\brief Create a squared form buffer around a point
+\ingroup strategies
+\details This strategy can be used as PointStrategy for the buffer algorithm.
+ It creates a square from each point, where the point lies in the center.
+ It can be applied for points and multi_points, but also for a linestring (if it is degenerate,
+ so consisting of only one point) and for polygons (if it is degenerate).
+ This strategy is only applicable for Cartesian coordinate systems.
+
+\qbk{
+[heading Example]
+[buffer_point_square]
+[heading Output]
+[$img/strategies/buffer_point_square.png]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+\* [link geometry.reference.strategies.strategy_buffer_point_circle point_circle]
+}
+ */
+class point_square
+{
+ template
+ <
+ typename Point,
+ typename DistanceType,
+ typename OutputRange
+ >
+ inline void add_point(Point const& point,
+ DistanceType const& distance,
+ DistanceType const& x,
+ DistanceType const& y,
+ OutputRange& output_range) const
+ {
+ typename boost::range_value<OutputRange>::type p;
+ set<0>(p, get<0>(point) + x * distance);
+ set<1>(p, get<1>(point) + y * distance);
+ output_range.push_back(p);
+ }
+
+ template
+ <
+ typename Point,
+ typename DistanceType,
+ typename OutputRange
+ >
+ inline void add_points(Point const& point,
+ DistanceType const& distance,
+ OutputRange& output_range) const
+ {
+ add_point(point, distance, -1.0, -1.0, output_range);
+ add_point(point, distance, -1.0, +1.0, output_range);
+ add_point(point, distance, +1.0, +1.0, output_range);
+ add_point(point, distance, +1.0, -1.0, output_range);
+
+ // Close it:
+ output_range.push_back(output_range.front());
+ }
+
+public :
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ //! Fills output_range with a square around point using distance_strategy
+ template
+ <
+ typename Point,
+ typename DistanceStrategy,
+ typename OutputRange
+ >
+ inline void apply(Point const& point,
+ DistanceStrategy const& distance_strategy,
+ OutputRange& output_range) const
+ {
+ add_points(point, distance_strategy.apply(point, point,
+ strategy::buffer::buffer_side_left), output_range);
+ }
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+};
+
+
+}} // namespace strategy::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP
diff --git a/boost/geometry/strategies/cartesian/buffer_side_straight.hpp b/boost/geometry/strategies/cartesian/buffer_side_straight.hpp
new file mode 100644
index 0000000000..24655ab3d7
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/buffer_side_straight.hpp
@@ -0,0 +1,105 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/strategies/side.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace buffer
+{
+
+
+
+/*!
+\brief Let the buffer use straight sides along segments (the default)
+\ingroup strategies
+\details This strategy can be used as SideStrategy for the buffer algorithm.
+ It is currently the only provided strategy for this purpose
+
+\qbk{
+[heading Example]
+See the examples for other buffer strategies\, for example
+[link geometry.reference.strategies.strategy_buffer_join_round join_round]
+[heading See also]
+\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
+}
+ */
+class side_straight
+{
+public :
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ template
+ <
+ typename Point,
+ typename OutputRange,
+ typename DistanceStrategy
+ >
+ static inline void apply(
+ Point const& input_p1, Point const& input_p2,
+ strategy::buffer::buffer_side_selector side,
+ DistanceStrategy const& distance,
+ OutputRange& output_range)
+ {
+ typedef typename coordinate_type<Point>::type coordinate_type;
+ typedef typename geometry::select_most_precise
+ <
+ coordinate_type,
+ double
+ >::type promoted_type;
+
+ // Generate a block along (left or right of) the segment
+
+ // Simulate a vector d (dx,dy)
+ coordinate_type const dx = get<0>(input_p2) - get<0>(input_p1);
+ coordinate_type const dy = get<1>(input_p2) - get<1>(input_p1);
+
+ // For normalization [0,1] (=dot product d.d, sqrt)
+ promoted_type const length = geometry::math::sqrt(dx * dx + dy * dy);
+
+ if (geometry::math::equals(length, 0))
+ {
+ // Coordinates are simplified and therefore most often not equal.
+ // But if simplify is skipped, or for lines with two
+ // equal points, length is 0 and we cannot generate output.
+ return;
+ }
+
+ // Generate the normalized perpendicular p, to the left (ccw)
+ promoted_type const px = -dy / length;
+ promoted_type const py = dx / length;
+
+ promoted_type const d = distance.apply(input_p1, input_p2, side);
+
+ output_range.resize(2);
+
+ set<0>(output_range.front(), get<0>(input_p1) + px * d);
+ set<1>(output_range.front(), get<1>(input_p1) + py * d);
+ set<0>(output_range.back(), get<0>(input_p2) + px * d);
+ set<1>(output_range.back(), get<1>(input_p2) + py * d);
+ }
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+};
+
+
+}} // namespace strategy::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP
diff --git a/boost/geometry/strategies/cartesian/cart_intersect.hpp b/boost/geometry/strategies/cartesian/cart_intersect.hpp
index ea92cf37b0..66af2d2e9c 100644
--- a/boost/geometry/strategies/cartesian/cart_intersect.hpp
+++ b/boost/geometry/strategies/cartesian/cart_intersect.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -18,6 +19,9 @@
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
@@ -27,59 +31,24 @@
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/side_info.hpp>
+#include <boost/geometry/strategies/intersection_result.hpp>
-
-namespace boost { namespace geometry
-{
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
-namespace strategy { namespace intersection
-{
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+# include <boost/geometry/io/wkt/write.hpp>
+#endif
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail
+namespace boost { namespace geometry
{
-template <std::size_t Dimension, typename Segment, typename T>
-static inline void segment_arrange(Segment const& s, T& s_1, T& s_2, bool& swapped)
-{
- s_1 = get<0, Dimension>(s);
- s_2 = get<1, Dimension>(s);
- if (s_1 > s_2)
- {
- std::swap(s_1, s_2);
- swapped = true;
- }
-}
-template <std::size_t Index, typename Segment>
-inline typename geometry::point_type<Segment>::type get_from_index(
- Segment const& segment)
+namespace strategy { namespace intersection
{
- typedef typename geometry::point_type<Segment>::type point_type;
- point_type point;
- geometry::detail::assign::assign_point_from_index
- <
- Segment, point_type, Index, 0, dimension<Segment>::type::value
- >::apply(segment, point);
- return point;
-}
-}
-#endif
-
-/***
-template <typename T>
-inline std::string rdebug(T const& value)
-{
- if (math::equals(value, 0)) return "'0'";
- if (math::equals(value, 1)) return "'1'";
- if (value < 0) return "<0";
- if (value > 1) return ">1";
- return "<0..1>";
-}
-***/
/*!
\see http://mathworld.wolfram.com/Line-LineIntersection.html
@@ -88,650 +57,307 @@ template <typename Policy, typename CalculationType = void>
struct relate_cartesian_segments
{
typedef typename Policy::return_type return_type;
- typedef typename Policy::segment_type1 segment_type1;
- typedef typename Policy::segment_type2 segment_type2;
-
- //typedef typename point_type<segment_type1>::type point_type;
- //BOOST_CONCEPT_ASSERT( (concept::Point<point_type>) );
-
- BOOST_CONCEPT_ASSERT( (concept::ConstSegment<segment_type1>) );
- BOOST_CONCEPT_ASSERT( (concept::ConstSegment<segment_type2>) );
-
- typedef typename select_calculation_type
- <segment_type1, segment_type2, CalculationType>::type coordinate_type;
- /// Relate segments a and b
- static inline return_type apply(segment_type1 const& a, segment_type2 const& b)
+ template <typename D, typename W, typename ResultType>
+ static inline void cramers_rule(D const& dx_a, D const& dy_a,
+ D const& dx_b, D const& dy_b, W const& wx, W const& wy,
+ // out:
+ ResultType& d, ResultType& da)
{
- coordinate_type const dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir
- coordinate_type const dx_b = get<1, 0>(b) - get<0, 0>(b);
- coordinate_type const dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir
- coordinate_type const dy_b = get<1, 1>(b) - get<0, 1>(b);
- return apply(a, b, dx_a, dy_a, dx_b, dy_b);
+ // Cramers rule
+ d = geometry::detail::determinant<ResultType>(dx_a, dy_a, dx_b, dy_b);
+ da = geometry::detail::determinant<ResultType>(dx_b, dy_b, wx, wy);
+ // Ratio is da/d , collinear if d == 0, intersecting if 0 <= r <= 1
+ // IntersectionPoint = (x1 + r * dx_a, y1 + r * dy_a)
}
- // Relate segments a and b using precalculated differences.
- // This can save two or four subtractions in many cases
- static inline return_type apply(segment_type1 const& a, segment_type2 const& b,
- coordinate_type const& dx_a, coordinate_type const& dy_a,
- coordinate_type const& dx_b, coordinate_type const& dy_b)
+ // Relate segments a and b
+ template <typename Segment1, typename Segment2, typename RobustPolicy>
+ static inline return_type apply(Segment1 const& a, Segment2 const& b,
+ RobustPolicy const& robust_policy)
{
- typedef side::side_by_triangle<coordinate_type> side;
- side_info sides;
-
- bool collinear_use_first = math::abs(dx_a) + math::abs(dx_b) >= math::abs(dy_a) + math::abs(dy_b);
-
- sides.set<0>
- (
- side::apply(detail::get_from_index<0>(b)
- , detail::get_from_index<1>(b)
- , detail::get_from_index<0>(a)),
- side::apply(detail::get_from_index<0>(b)
- , detail::get_from_index<1>(b)
- , detail::get_from_index<1>(a))
- );
- sides.set<1>
- (
- side::apply(detail::get_from_index<0>(a)
- , detail::get_from_index<1>(a)
- , detail::get_from_index<0>(b)),
- side::apply(detail::get_from_index<0>(a)
- , detail::get_from_index<1>(a)
- , detail::get_from_index<1>(b))
- );
+ // type them all as in Segment1 - TODO reconsider this, most precise?
+ typedef typename geometry::point_type<Segment1>::type point_type;
- bool collinear = sides.collinear();
+ typedef typename geometry::robust_point_type
+ <
+ point_type, RobustPolicy
+ >::type robust_point_type;
- robustness_verify_collinear(a, b, sides, collinear);
- robustness_verify_meeting(a, b, sides, collinear, collinear_use_first);
+ point_type a0, a1, b0, b1;
+ robust_point_type a0_rob, a1_rob, b0_rob, b1_rob;
- if (sides.same<0>() || sides.same<1>())
- {
- // Both points are at same side of other segment, we can leave
- if (robustness_verify_same_side(a, b, sides))
- {
- return Policy::disjoint();
- }
- }
+ detail::assign_point_from_index<0>(a, a0);
+ detail::assign_point_from_index<1>(a, a1);
+ detail::assign_point_from_index<0>(b, b0);
+ detail::assign_point_from_index<1>(b, b1);
- // Degenerate cases: segments of single point, lying on other segment, non disjoint
- 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, zero) && math::equals(dy_b, zero))
- {
- return Policy::degenerate(b, false);
- }
+ geometry::recalculate(a0_rob, a0, robust_policy);
+ geometry::recalculate(a1_rob, a1, robust_policy);
+ geometry::recalculate(b0_rob, b0, robust_policy);
+ geometry::recalculate(b1_rob, b1, robust_policy);
- typedef typename select_most_precise
- <
- coordinate_type, double
- >::type promoted_type;
+ return apply(a, b, robust_policy, a0_rob, a1_rob, b0_rob, b1_rob);
+ }
- // r: ratio 0-1 where intersection divides A/B
- // (only calculated for non-collinear segments)
- promoted_type r;
- if (! collinear)
- {
- // Calculate determinants - Cramers rule
- coordinate_type const wx = get<0, 0>(a) - get<0, 0>(b);
- coordinate_type const wy = get<0, 1>(a) - get<0, 1>(b);
- coordinate_type const d = geometry::detail::determinant<coordinate_type>(dx_a, dy_a, dx_b, dy_b);
- coordinate_type const da = geometry::detail::determinant<coordinate_type>(dx_b, dy_b, wx, wy);
-
- coordinate_type const zero = coordinate_type();
- if (math::equals(d, zero))
- {
- // This is still a collinear case (because of FP imprecision this can occur here)
- // sides.debug();
- sides.set<0>(0,0);
- sides.set<1>(0,0);
- collinear = true;
- }
- else
- {
- r = promoted_type(da) / promoted_type(d);
+ // The main entry-routine, calculating intersections of segments a / b
+ template <typename Segment1, typename Segment2, typename RobustPolicy, typename RobustPoint>
+ static inline return_type apply(Segment1 const& a, Segment2 const& b,
+ RobustPolicy const& robust_policy,
+ RobustPoint const& robust_a1, RobustPoint const& robust_a2,
+ RobustPoint const& robust_b1, RobustPoint const& robust_b2)
+ {
+ BOOST_CONCEPT_ASSERT( (concept::ConstSegment<Segment1>) );
+ BOOST_CONCEPT_ASSERT( (concept::ConstSegment<Segment2>) );
- if (! robustness_verify_r(a, b, r))
- {
- return Policy::disjoint();
- }
+ boost::ignore_unused_variable_warning(robust_policy);
- robustness_handle_meeting(a, b, sides, dx_a, dy_a, wx, wy, d, r);
+ typedef typename select_calculation_type
+ <Segment1, Segment2, CalculationType>::type coordinate_type;
- if (robustness_verify_disjoint_at_one_collinear(a, b, sides))
- {
- return Policy::disjoint();
- }
+ using geometry::detail::equals::equals_point_point;
+ bool const a_is_point = equals_point_point(robust_a1, robust_a2);
+ bool const b_is_point = equals_point_point(robust_b1, robust_b2);
- }
- }
+ typedef side::side_by_triangle<coordinate_type> side;
- if(collinear)
+ if(a_is_point && b_is_point)
{
- if (collinear_use_first)
- {
- return relate_collinear<0>(a, b);
- }
- else
- {
- // Y direction contains larger segments (maybe dx is zero)
- return relate_collinear<1>(a, b);
- }
+ return equals_point_point(robust_a1, robust_b2)
+ ? Policy::degenerate(a, true)
+ : Policy::disjoint()
+ ;
}
- return Policy::segments_intersect(sides, r,
- dx_a, dy_a, dx_b, dy_b,
- a, b);
- }
-
-private :
+ side_info sides;
+ sides.set<0>(side::apply(robust_b1, robust_b2, robust_a1),
+ side::apply(robust_b1, robust_b2, robust_a2));
+ sides.set<1>(side::apply(robust_a1, robust_a2, robust_b1),
+ side::apply(robust_a1, robust_a2, robust_b2));
+ bool collinear = sides.collinear();
- // Ratio should lie between 0 and 1
- // Also these three conditions might be of FP imprecision, the segments were actually (nearly) collinear
- template <typename T>
- static inline bool robustness_verify_r(
- segment_type1 const& a, segment_type2 const& b,
- T& r)
- {
- T const zero = 0;
- T const one = 1;
- if (r < zero || r > one)
+ if (sides.same<0>() || sides.same<1>())
{
- if (verify_disjoint<0>(a, b) || verify_disjoint<1>(a, b))
- {
- // Can still be disjoint (even if not one is left or right from another)
- // This is e.g. in case #snake4 of buffer test.
- return false;
- }
-
- //std::cout << "ROBUSTNESS: correction of r " << r << std::endl;
- // sides.debug();
+ // Both points are at same side of other segment, we can leave
+ return Policy::disjoint();
+ }
- // ROBUSTNESS: the r value can in epsilon-cases much larger than 1, while (with perfect arithmetic)
- // it should be one. It can be 1.14 or even 1.98049 or 2 (while still intersecting)
+ typedef typename select_most_precise
+ <
+ coordinate_type, double
+ >::type promoted_type;
- // If segments are crossing (we can see that with the sides)
- // and one is inside the other, there must be an intersection point.
- // We correct for that.
- // This is (only) in case #ggl_list_20110820_christophe in unit tests
+ typedef typename geometry::coordinate_type
+ <
+ RobustPoint
+ >::type robust_coordinate_type;
- // If segments are touching (two sides zero), of course they should intersect
- // This is (only) in case #buffer_rt_i in the unit tests)
+ typedef typename segment_ratio_type
+ <
+ typename geometry::point_type<Segment1>::type, // TODO: most precise point?
+ RobustPolicy
+ >::type ratio_type;
- // If one touches in the middle, they also should intersect (#buffer_rt_j)
+ segment_intersection_info
+ <
+ coordinate_type,
+ promoted_type,
+ ratio_type
+ > sinfo;
- // Note that even for ttmath r is occasionally > 1, e.g. 1.0000000000000000000000036191231203575
+ sinfo.dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir
+ sinfo.dx_b = get<1, 0>(b) - get<0, 0>(b);
+ sinfo.dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir
+ sinfo.dy_b = get<1, 1>(b) - get<0, 1>(b);
- if (r > one)
- {
- r = one;
- }
- else if (r < zero)
- {
- r = zero;
- }
- }
- return true;
- }
+ robust_coordinate_type const robust_dx_a = get<0>(robust_a2) - get<0>(robust_a1);
+ robust_coordinate_type const robust_dx_b = get<0>(robust_b2) - get<0>(robust_b1);
+ robust_coordinate_type const robust_dy_a = get<1>(robust_a2) - get<1>(robust_a1);
+ robust_coordinate_type const robust_dy_b = get<1>(robust_b2) - get<1>(robust_b1);
- static inline void robustness_verify_collinear(
- segment_type1 const& a, segment_type2 const& b,
- side_info& sides,
- bool& collinear)
- {
- if ((sides.zero<0>() && ! sides.zero<1>()) || (sides.zero<1>() && ! sides.zero<0>()))
+ // r: ratio 0-1 where intersection divides A/B
+ // (only calculated for non-collinear segments)
+ if (! collinear)
{
- // If one of the segments is collinear, the other must be as well.
- // So handle it as collinear.
- // (In float/double epsilon margins it can easily occur that one or two of them are -1/1)
- // sides.debug();
- sides.set<0>(0,0);
- sides.set<1>(0,0);
- collinear = true;
- }
- }
+ robust_coordinate_type robust_da0, robust_da;
+ robust_coordinate_type robust_db0, robust_db;
- static inline void robustness_verify_meeting(
- segment_type1 const& a, segment_type2 const& b,
- side_info& sides,
- bool& collinear, bool& collinear_use_first)
- {
- if (sides.meeting())
- {
- // If two segments meet each other at their segment-points, two sides are zero,
- // the other two are not (unless collinear but we don't mean those here).
- // However, in near-epsilon ranges it can happen that two sides are zero
- // but they do not meet at their segment-points.
- // In that case they are nearly collinear and handled as such.
- if (! point_equals
- (
- select(sides.zero_index<0>(), a),
- select(sides.zero_index<1>(), b)
- )
- )
+ cramers_rule(robust_dx_a, robust_dy_a, robust_dx_b, robust_dy_b,
+ get<0>(robust_a1) - get<0>(robust_b1),
+ get<1>(robust_a1) - get<1>(robust_b1),
+ robust_da0, robust_da);
+
+ cramers_rule(robust_dx_b, robust_dy_b, robust_dx_a, robust_dy_a,
+ get<0>(robust_b1) - get<0>(robust_a1),
+ get<1>(robust_b1) - get<1>(robust_a1),
+ robust_db0, robust_db);
+
+ if (robust_da0 == 0)
{
+ // If this is the case, no rescaling is done for FP precision.
+ // We set it to collinear, but it indicates a robustness issue.
sides.set<0>(0,0);
sides.set<1>(0,0);
collinear = true;
-
- if (collinear_use_first && analyse_equal<0>(a, b))
- {
- collinear_use_first = false;
- }
- else if (! collinear_use_first && analyse_equal<1>(a, b))
- {
- collinear_use_first = true;
- }
-
}
- }
- }
-
- // Verifies and if necessary correct missed touch because of robustness
- // This is the case at multi_polygon_buffer unittest #rt_m
- static inline bool robustness_verify_same_side(
- segment_type1 const& a, segment_type2 const& b,
- side_info& sides)
- {
- int corrected = 0;
- if (sides.one_touching<0>())
- {
- if (point_equals(
- select(sides.zero_index<0>(), a),
- select(0, b)
- ))
- {
- sides.correct_to_zero<1, 0>();
- corrected = 1;
- }
- if (point_equals
- (
- select(sides.zero_index<0>(), a),
- select(1, b)
- ))
+ else
{
- sides.correct_to_zero<1, 1>();
- corrected = 2;
+ sinfo.robust_ra.assign(robust_da, robust_da0);
+ sinfo.robust_rb.assign(robust_db, robust_db0);
}
}
- else if (sides.one_touching<1>())
+
+ if (collinear)
{
- if (point_equals(
- select(sides.zero_index<1>(), b),
- select(0, a)
- ))
+ bool const collinear_use_first
+ = geometry::math::abs(robust_dx_a) + geometry::math::abs(robust_dx_b)
+ >= geometry::math::abs(robust_dy_a) + geometry::math::abs(robust_dy_b);
+
+ // Degenerate cases: segments of single point, lying on other segment, are not disjoint
+ // This situation is collinear too
+
+ if (collinear_use_first)
{
- sides.correct_to_zero<0, 0>();
- corrected = 3;
+ return relate_collinear<0, ratio_type>(a, b,
+ robust_a1, robust_a2, robust_b1, robust_b2,
+ a_is_point, b_is_point);
}
- if (point_equals
- (
- select(sides.zero_index<1>(), b),
- select(1, a)
- ))
+ else
{
- sides.correct_to_zero<0, 1>();
- corrected = 4;
+ // Y direction contains larger segments (maybe dx is zero)
+ return relate_collinear<1, ratio_type>(a, b,
+ robust_a1, robust_a2, robust_b1, robust_b2,
+ a_is_point, b_is_point);
}
}
- return corrected == 0;
+ return Policy::segments_crosses(sides, sinfo, a, b);
}
- static inline bool robustness_verify_disjoint_at_one_collinear(
- segment_type1 const& a, segment_type2 const& b,
- side_info const& sides)
+private:
+ template
+ <
+ std::size_t Dimension,
+ typename RatioType,
+ typename Segment1,
+ typename Segment2,
+ typename RobustPoint
+ >
+ static inline return_type relate_collinear(Segment1 const& a,
+ Segment2 const& b,
+ RobustPoint const& robust_a1, RobustPoint const& robust_a2,
+ RobustPoint const& robust_b1, RobustPoint const& robust_b2,
+ bool a_is_point, bool b_is_point)
{
- if (sides.one_of_all_zero())
+ if (a_is_point)
{
- if (verify_disjoint<0>(a, b) || verify_disjoint<1>(a, b))
- {
- return true;
- }
+ return relate_one_degenerate<RatioType>(a,
+ get<Dimension>(robust_a1),
+ get<Dimension>(robust_b1), get<Dimension>(robust_b2),
+ true);
}
- return false;
- }
-
-
- // If r is one, or zero, segments should meet and their endpoints.
- // Robustness issue: check if this is really the case.
- // It turns out to be no problem, see buffer test #rt_s1 (and there are many cases generated)
- // It generates an "ends in the middle" situation which is correct.
- template <typename T, typename R>
- static inline void robustness_handle_meeting(segment_type1 const& a, segment_type2 const& b,
- side_info& sides,
- T const& dx_a, T const& dy_a, T const& wx, T const& wy,
- T const& d, R const& r)
- {
- return;
-
- T const db = geometry::detail::determinant<T>(dx_a, dy_a, wx, wy);
-
- R const zero = 0;
- R const one = 1;
- if (math::equals(r, zero) || math::equals(r, one))
+ if (b_is_point)
{
- R rb = db / d;
- if (rb <= 0 || rb >= 1 || math::equals(rb, 0) || math::equals(rb, 1))
- {
- if (sides.one_zero<0>() && ! sides.one_zero<1>()) // or vice versa
- {
-#if defined(BOOST_GEOMETRY_COUNT_INTERSECTION_EQUAL)
- extern int g_count_intersection_equal;
- g_count_intersection_equal++;
-#endif
- sides.debug();
- std::cout << "E r=" << r << " r.b=" << rb << " ";
- }
- }
+ return relate_one_degenerate<RatioType>(b,
+ get<Dimension>(robust_b1),
+ get<Dimension>(robust_a1), get<Dimension>(robust_a2),
+ false);
}
+ return relate_collinear<RatioType>(a, b,
+ get<Dimension>(robust_a1),
+ get<Dimension>(robust_a2),
+ get<Dimension>(robust_b1),
+ get<Dimension>(robust_b2));
}
- template <std::size_t Dimension>
- static inline bool verify_disjoint(segment_type1 const& a,
- segment_type2 const& b)
- {
- coordinate_type a_1, a_2, b_1, b_2;
- bool a_swapped = false, b_swapped = false;
- detail::segment_arrange<Dimension>(a, a_1, a_2, a_swapped);
- detail::segment_arrange<Dimension>(b, b_1, b_2, b_swapped);
- return math::smaller(a_2, b_1) || math::larger(a_1, b_2);
- }
-
- template <typename Segment>
- static inline typename point_type<Segment>::type select(int index, Segment const& segment)
- {
- return index == 0
- ? detail::get_from_index<0>(segment)
- : detail::get_from_index<1>(segment)
- ;
- }
-
- // We cannot use geometry::equals here. Besides that this will be changed
- // to compare segment-coordinate-values directly (not necessary to retrieve point first)
- template <typename Point1, typename Point2>
- static inline bool point_equals(Point1 const& point1, Point2 const& point2)
- {
- return math::equals(get<0>(point1), get<0>(point2))
- && math::equals(get<1>(point1), get<1>(point2))
- ;
- }
-
- // We cannot use geometry::equals here. Besides that this will be changed
- // to compare segment-coordinate-values directly (not necessary to retrieve point first)
- template <typename Point1, typename Point2>
- static inline bool point_equality(Point1 const& point1, Point2 const& point2,
- bool& equals_0, bool& equals_1)
- {
- equals_0 = math::equals(get<0>(point1), get<0>(point2));
- equals_1 = math::equals(get<1>(point1), get<1>(point2));
- return equals_0 && equals_1;
- }
-
- template <std::size_t Dimension>
- static inline bool analyse_equal(segment_type1 const& a, segment_type2 const& b)
- {
- coordinate_type const a_1 = geometry::get<0, Dimension>(a);
- coordinate_type const a_2 = geometry::get<1, Dimension>(a);
- coordinate_type const b_1 = geometry::get<0, Dimension>(b);
- coordinate_type const b_2 = geometry::get<1, Dimension>(b);
- return math::equals(a_1, b_1)
- || math::equals(a_2, b_1)
- || math::equals(a_1, b_2)
- || math::equals(a_2, b_2)
- ;
- }
-
- template <std::size_t Dimension>
- static inline return_type relate_collinear(segment_type1 const& a,
- segment_type2 const& b)
+ /// Relate segments known collinear
+ template
+ <
+ typename RatioType,
+ typename Segment1,
+ typename Segment2,
+ typename RobustType
+ >
+ static inline return_type relate_collinear(Segment1 const& a
+ , Segment2 const& b
+ , RobustType oa_1, RobustType oa_2
+ , RobustType ob_1, RobustType ob_2
+ )
{
- coordinate_type a_1, a_2, b_1, b_2;
- bool a_swapped = false, b_swapped = false;
- detail::segment_arrange<Dimension>(a, a_1, a_2, a_swapped);
- detail::segment_arrange<Dimension>(b, b_1, b_2, b_swapped);
- if (math::smaller(a_2, b_1) || math::larger(a_1, b_2))
- //if (a_2 < b_1 || a_1 > b_2)
+ // Calculate the ratios where a starts in b, b starts in a
+ // a1--------->a2 (2..7)
+ // b1----->b2 (5..8)
+ // length_a: 7-2=5
+ // length_b: 8-5=3
+ // b1 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a)
+ // b2 is located w.r.t. a at ratio: (8-2)/5=6/5 (right of a)
+ // a1 is located w.r.t. b at ratio: (2-5)/3=-3/3 (left of b)
+ // a2 is located w.r.t. b at ratio: (7-5)/3=2/3 (on b)
+ // A arrives (a2 on b), B departs (b1 on a)
+
+ // If both are reversed:
+ // a2<---------a1 (7..2)
+ // b2<-----b1 (8..5)
+ // length_a: 2-7=-5
+ // length_b: 5-8=-3
+ // b1 is located w.r.t. a at ratio: (8-7)/-5=-1/5 (before a starts)
+ // b2 is located w.r.t. a at ratio: (5-7)/-5=2/5 (on a)
+ // a1 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b)
+ // a2 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends)
+
+ // If both one is reversed:
+ // a1--------->a2 (2..7)
+ // b2<-----b1 (8..5)
+ // length_a: 7-2=+5
+ // length_b: 5-8=-3
+ // b1 is located w.r.t. a at ratio: (8-2)/5=6/5 (after a ends)
+ // b2 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a)
+ // a1 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends)
+ // a2 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b)
+ RobustType const length_a = oa_2 - oa_1; // no abs, see above
+ RobustType const length_b = ob_2 - ob_1;
+
+ RatioType const ra_from(oa_1 - ob_1, length_b);
+ RatioType const ra_to(oa_2 - ob_1, length_b);
+ RatioType const rb_from(ob_1 - oa_1, length_a);
+ RatioType const rb_to(ob_2 - oa_1, length_a);
+
+ if ((ra_from.left() && ra_to.left()) || (ra_from.right() && ra_to.right()))
{
return Policy::disjoint();
}
- return relate_collinear(a, b, a_1, a_2, b_1, b_2, a_swapped, b_swapped);
+
+ return Policy::segments_collinear(a, b, ra_from, ra_to, rb_from, rb_to);
}
- /// Relate segments known collinear
- static inline return_type relate_collinear(segment_type1 const& a
- , segment_type2 const& b
- , coordinate_type a_1, coordinate_type a_2
- , coordinate_type b_1, coordinate_type b_2
- , bool a_swapped, bool b_swapped)
+ /// Relate segments where one is degenerate
+ template
+ <
+ typename RatioType,
+ typename DegenerateSegment,
+ typename RobustType
+ >
+ static inline return_type relate_one_degenerate(
+ DegenerateSegment const& degenerate_segment
+ , RobustType d
+ , RobustType s1, RobustType s2
+ , bool a_degenerate
+ )
{
- // All ca. 150 lines are about collinear rays
- // The intersections, if any, are always boundary points of the segments. No need to calculate anything.
- // However we want to find out HOW they intersect, there are many cases.
- // Most sources only provide the intersection (above) or that there is a collinearity (but not the points)
- // or some spare sources give the intersection points (calculated) but not how they align.
- // This source tries to give everything and still be efficient.
- // It is therefore (and because of the extensive clarification comments) rather long...
-
- // \see http://mpa.itc.it/radim/g50history/CMP/4.2.1-CERL-beta-libes/file475.txt
- // \see http://docs.codehaus.org/display/GEOTDOC/Point+Set+Theory+and+the+DE-9IM+Matrix
- // \see http://mathworld.wolfram.com/Line-LineIntersection.html
-
- // Because of collinearity the case is now one-dimensional and can be checked using intervals
- // This function is called either horizontally or vertically
- // We get then two intervals:
- // a_1-------------a_2 where a_1 < a_2
- // b_1-------------b_2 where b_1 < b_2
- // In all figures below a_1/a_2 denotes arranged intervals, a1-a2 or a2-a1 are still unarranged
-
- // Handle "equal", in polygon neighbourhood comparisons a common case
-
- bool const opposite = a_swapped ^ b_swapped;
- bool const both_swapped = a_swapped && b_swapped;
-
- // Check if segments are equal or opposite equal...
- bool const swapped_a1_eq_b1 = math::equals(a_1, b_1);
- bool const swapped_a2_eq_b2 = math::equals(a_2, b_2);
-
- if (swapped_a1_eq_b1 && swapped_a2_eq_b2)
- {
- return Policy::segment_equal(a, opposite);
- }
-
- bool const swapped_a2_eq_b1 = math::equals(a_2, b_1);
- bool const swapped_a1_eq_b2 = math::equals(a_1, b_2);
-
- bool const a1_eq_b1 = both_swapped ? swapped_a2_eq_b2 : a_swapped ? swapped_a2_eq_b1 : b_swapped ? swapped_a1_eq_b2 : swapped_a1_eq_b1;
- bool const a2_eq_b2 = both_swapped ? swapped_a1_eq_b1 : a_swapped ? swapped_a1_eq_b2 : b_swapped ? swapped_a2_eq_b1 : swapped_a2_eq_b2;
-
- bool const a1_eq_b2 = both_swapped ? swapped_a2_eq_b1 : a_swapped ? swapped_a2_eq_b2 : b_swapped ? swapped_a1_eq_b1 : swapped_a1_eq_b2;
- bool const a2_eq_b1 = both_swapped ? swapped_a1_eq_b2 : a_swapped ? swapped_a1_eq_b1 : b_swapped ? swapped_a2_eq_b2 : swapped_a2_eq_b1;
-
-
-
-
- // The rest below will return one or two intersections.
- // The delegated class can decide which is the intersection point, or two, build the Intersection Matrix (IM)
- // For IM it is important to know which relates to which. So this information is given,
- // without performance penalties to intersection calculation
-
- bool const has_common_points = swapped_a1_eq_b1 || swapped_a1_eq_b2 || swapped_a2_eq_b1 || swapped_a2_eq_b2;
-
-
- // "Touch" -> one intersection point -> one but not two common points
- // --------> A (or B)
- // <---------- B (or A)
- // a_2==b_1 (b_2==a_1 or a_2==b1)
-
- // The check a_2/b_1 is necessary because it excludes cases like
- // ------->
- // --->
- // ... which are handled lateron
-
- // Corresponds to 4 cases, of which the equal points are determined above
- // #1: a1---->a2 b1--->b2 (a arrives at b's border)
- // #2: a2<----a1 b2<---b1 (b arrives at a's border)
- // #3: a1---->a2 b2<---b1 (both arrive at each others border)
- // #4: a2<----a1 b1--->b2 (no arrival at all)
- // Where the arranged forms have two forms:
- // a_1-----a_2/b_1-------b_2 or reverse (B left of A)
- if ((swapped_a2_eq_b1 || swapped_a1_eq_b2) && ! swapped_a1_eq_b1 && ! swapped_a2_eq_b2)
- {
- if (a2_eq_b1) return Policy::collinear_touch(get<1, 0>(a), get<1, 1>(a), 0, -1);
- if (a1_eq_b2) return Policy::collinear_touch(get<0, 0>(a), get<0, 1>(a), -1, 0);
- if (a2_eq_b2) return Policy::collinear_touch(get<1, 0>(a), get<1, 1>(a), 0, 0);
- if (a1_eq_b1) return Policy::collinear_touch(get<0, 0>(a), get<0, 1>(a), -1, -1);
- }
-
-
- // "Touch/within" -> there are common points and also an intersection of interiors:
- // Corresponds to many cases:
- // #1a: a1------->a2 #1b: a1-->a2
- // b1--->b2 b1------->b2
- // #2a: a2<-------a1 #2b: a2<--a1
- // b1--->b2 b1------->b2
- // #3a: a1------->a2 #3b: a1-->a2
- // b2<---b1 b2<-------b1
- // #4a: a2<-------a1 #4b: a2<--a1
- // b2<---b1 b2<-------b1
-
- // Note: next cases are similar and handled by the code
- // #4c: a1--->a2
- // b1-------->b2
- // #4d: a1-------->a2
- // b1-->b2
-
- // For case 1-4: a_1 < (b_1 or b_2) < a_2, two intersections are equal to segment B
- // For case 5-8: b_1 < (a_1 or a_2) < b_2, two intersections are equal to segment A
- if (has_common_points)
- {
- // Either A is in B, or B is in A, or (in case of robustness/equals)
- // both are true, see below
- bool a_in_b = (b_1 < a_1 && a_1 < b_2) || (b_1 < a_2 && a_2 < b_2);
- bool b_in_a = (a_1 < b_1 && b_1 < a_2) || (a_1 < b_2 && b_2 < a_2);
-
- if (a_in_b && b_in_a)
- {
- // testcase "ggl_list_20110306_javier"
- // In robustness it can occur that a point of A is inside B AND a point of B is inside A,
- // still while has_common_points is true (so one point equals the other).
- // If that is the case we select on length.
- coordinate_type const length_a = geometry::math::abs(a_1 - a_2);
- coordinate_type const length_b = geometry::math::abs(b_1 - b_2);
- if (length_a > length_b)
- {
- a_in_b = false;
- }
- else
- {
- b_in_a = false;
- }
- }
-
- int const arrival_a = a_in_b ? 1 : -1;
- if (a2_eq_b2) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, 0, 0, false);
- if (a1_eq_b2) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, arrival_a, 0, true);
- if (a2_eq_b1) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, 0, -arrival_a, true);
- if (a1_eq_b1) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, arrival_a, -arrival_a, false);
- }
-
-
-
- // "Inside", a completely within b or b completely within a
- // 2 cases:
- // case 1:
- // a_1---a_2 -> take A's points as intersection points
- // b_1------------b_2
- // case 2:
- // a_1------------a_2
- // b_1---b_2 -> take B's points
- if (a_1 > b_1 && a_2 < b_2)
- {
- // A within B
- return Policy::collinear_a_in_b(a, opposite);
- }
- if (b_1 > a_1 && b_2 < a_2)
- {
- // B within A
- return Policy::collinear_b_in_a(b, opposite);
- }
-
-
- /*
-
- Now that all cases with equal,touch,inside,disjoint,
- degenerate are handled the only thing left is an overlap
-
- Either a1 is between b1,b2
- or a2 is between b1,b2 (a2 arrives)
-
- Next table gives an overview.
- The IP's are ordered following the line A1->A2
-
- | |
- | a_2 in between | a_1 in between
- | |
- -----+---------------------------------+--------------------------
- | a1--------->a2 | a1--------->a2
- | b1----->b2 | b1----->b2
- | (b1,a2), a arrives | (a1,b2), b arrives
- | |
- -----+---------------------------------+--------------------------
- a sw.| a2<---------a1* | a2<---------a1*
- | b1----->b2 | b1----->b2
- | (a1,b1), no arrival | (b2,a2), a and b arrive
- | |
- -----+---------------------------------+--------------------------
- | a1--------->a2 | a1--------->a2
- b sw.| b2<-----b1 | b2<-----b1
- | (b2,a2), a and b arrive | (a1,b1), no arrival
- | |
- -----+---------------------------------+--------------------------
- a sw.| a2<---------a1* | a2<---------a1*
- b sw.| b2<-----b1 | b2<-----b1
- | (a1,b2), b arrives | (b1,a2), a arrives
- | |
- -----+---------------------------------+--------------------------
- * Note that a_1 < a_2, and a1 <> a_1; if a is swapped,
- the picture might seem wrong but it (supposed to be) is right.
- */
-
- if (b_1 < a_2 && a_2 < b_2)
- {
- // Left column, from bottom to top
- return
- both_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<1, 0>(b), get<1, 1>(b), -1, 1, opposite)
- : b_swapped ? Policy::collinear_overlaps(get<1, 0>(b), get<1, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, 1, opposite)
- : a_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<0, 0>(b), get<0, 1>(b), -1, -1, opposite)
- : Policy::collinear_overlaps(get<0, 0>(b), get<0, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, -1, opposite)
- ;
- }
- if (b_1 < a_1 && a_1 < b_2)
- {
- // Right column, from bottom to top
- return
- both_swapped ? Policy::collinear_overlaps(get<0, 0>(b), get<0, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, -1, opposite)
- : b_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<0, 0>(b), get<0, 1>(b), -1, -1, opposite)
- : a_swapped ? Policy::collinear_overlaps(get<1, 0>(b), get<1, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, 1, opposite)
- : Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<1, 0>(b), get<1, 1>(b), -1, 1, opposite)
- ;
- }
- // Nothing should goes through. If any we have made an error
- // std::cout << "Robustness issue, non-logical behaviour" << std::endl;
- return Policy::error("Robustness issue, non-logical behaviour");
+ // Calculate the ratios where ds starts in s
+ // a1--------->a2 (2..6)
+ // b1/b2 (4..4)
+ // Ratio: (4-2)/(6-2)
+ RatioType const ratio(d - s1, s2 - s1);
+ return Policy::one_degenerate(degenerate_segment, ratio, a_degenerate);
}
};
}} // namespace strategy::intersection
-
-
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/cartesian/centroid_average.hpp b/boost/geometry/strategies/cartesian/centroid_average.hpp
new file mode 100644
index 0000000000..76e2f7144c
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/centroid_average.hpp
@@ -0,0 +1,114 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
+
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/strategies/centroid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace centroid
+{
+
+
+/*!
+\brief Centroid calculation taking average of points
+\ingroup strategies
+*/
+template
+<
+ typename PointCentroid,
+ typename Point = PointCentroid
+>
+class average
+{
+private :
+
+ /*! subclass to keep state */
+ class sum
+ {
+ friend class average;
+ int count;
+ PointCentroid centroid;
+
+ public :
+ inline sum()
+ : count(0)
+ {
+ assign_zero(centroid);
+ }
+ };
+
+public :
+ typedef sum state_type;
+ typedef PointCentroid centroid_point_type;
+ typedef Point point_type;
+
+ static inline void apply(Point const& p, sum& state)
+ {
+ add_point(state.centroid, p);
+ state.count++;
+ }
+
+ static inline void result(sum const& state, PointCentroid& centroid)
+ {
+ centroid = state.centroid;
+ divide_value(centroid, state.count);
+ }
+
+};
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+namespace services
+{
+
+template <typename Point, std::size_t DimensionCount, typename Geometry>
+struct default_strategy
+<
+ cartesian_tag,
+ pointlike_tag,
+ DimensionCount,
+ Point,
+ Geometry
+>
+{
+ typedef average
+ <
+ Point,
+ typename point_type<Geometry>::type
+ > type;
+};
+
+} // namespace services
+
+#endif
+
+
+}} // namespace strategy::centroid
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
diff --git a/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp
index 8b42715e0b..f199fb80e5 100644
--- a/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp
+++ b/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp
@@ -38,17 +38,26 @@ namespace strategy { namespace centroid
/*!
-\brief Centroid calculation using algorith Bashein / Detmer
+\brief Centroid calculation using algorithm Bashein / Detmer
\ingroup strategies
\details Calculates centroid using triangulation method published by
Bashein / Detmer
\tparam Point point type of centroid to calculate
\tparam PointOfSegment point type of segments, defaults to Point
-\par Concepts for Point and PointOfSegment:
-- specialized point_traits class
+\tparam CalculationType \tparam_calculation
+
\author Adapted from "Centroid of a Polygon" by
Gerard Bashein and Paul R. Detmer<em>,
in "Graphics Gems IV", Academic Press, 1994</em>
+
+
+\qbk{
+[heading See also]
+[link geometry.reference.algorithms.centroid.centroid_3_with_strategy centroid (with strategy)]
+}
+*/
+
+/*
\par Research notes
The algorithm gives the same results as Oracle and PostGIS but
differs from MySQL
@@ -100,12 +109,6 @@ Statements:
, mdsys.sdo_dim_array(mdsys.sdo_dim_element('x',0,10,.00000005)
,mdsys.sdo_dim_element('y',0,10,.00000005)))
from dual
-
-\qbk{
-[heading See also]
-[link geometry.reference.algorithms.centroid.centroid_3_with_strategy centroid (with strategy)]
-}
-
*/
template
<
@@ -151,9 +154,7 @@ private :
, sum_a2(calculation_type())
, sum_x(calculation_type())
, sum_y(calculation_type())
- {
- typedef calculation_type ct;
- }
+ {}
};
public :
diff --git a/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp b/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp
index 48feae51df..b788738d15 100644
--- a/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp
+++ b/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp
@@ -13,7 +13,8 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP
-#include <boost/geometry/algorithms/distance.hpp>
+#include <boost/geometry/algorithms/detail/distance/interface.hpp>
+#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/centroid.hpp>
diff --git a/boost/geometry/strategies/cartesian/distance_projected_point.hpp b/boost/geometry/strategies/cartesian/distance_projected_point.hpp
index 13d4168445..dff4a77f6f 100644
--- a/boost/geometry/strategies/cartesian/distance_projected_point.hpp
+++ b/boost/geometry/strategies/cartesian/distance_projected_point.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -44,14 +49,11 @@ namespace boost { namespace geometry
namespace strategy { namespace distance
{
-
/*!
\brief Strategy for distance point to segment
\ingroup strategies
\details Calculates distance using projected-point method, and (optionally) Pythagoras
\author Adapted from: http://geometryalgorithms.com/Archive/algorithm_0102/algorithm_0102.htm
-\tparam Point \tparam_point
-\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\tparam Strategy underlying point-point distance strategy
\par Concepts for Strategy:
@@ -67,10 +69,8 @@ namespace strategy { namespace distance
*/
template
<
- typename Point,
- typename PointOfSegment = Point,
typename CalculationType = void,
- typename Strategy = pythagoras<Point, PointOfSegment, CalculationType>
+ typename Strategy = pythagoras<CalculationType>
>
class projected_point
{
@@ -81,47 +81,43 @@ public :
// Integer coordinates can still result in FP distances.
// There is a division, which must be represented in FP.
// So promote.
- typedef typename promote_floating_point
- <
- typename strategy::distance::services::return_type
- <
- Strategy
- >::type
- >::type calculation_type;
-
-private :
-
- // A projected point of points in Integer coordinates must be able to be
- // represented in FP.
- typedef model::point
- <
- calculation_type,
- dimension<PointOfSegment>::value,
- typename coordinate_system<PointOfSegment>::type
- > fp_point_type;
-
- // For convenience
- typedef fp_point_type fp_vector_type;
-
- // We have to use a strategy using FP coordinates (fp-type) which is
- // not always the same as Strategy (defined as point_strategy_type)
- // So we create a "similar" one
- typedef typename strategy::distance::services::similar_type
- <
- Strategy,
- Point,
- fp_point_type
- >::type fp_strategy_type;
+ template <typename Point, typename PointOfSegment>
+ struct calculation_type
+ : promote_floating_point
+ <
+ typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ PointOfSegment
+ >::type
+ >
+ {};
public :
- inline calculation_type apply(Point const& p,
- PointOfSegment const& p1, PointOfSegment const& p2) const
+ template <typename Point, typename PointOfSegment>
+ inline typename calculation_type<Point, PointOfSegment>::type
+ apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const
{
assert_dimension_equal<Point, PointOfSegment>();
- /*
- Algorithm [p1: (x1,y1), p2: (x2,y2), p: (px,py)]
+ typedef typename calculation_type<Point, PointOfSegment>::type calculation_type;
+
+ // A projected point of points in Integer coordinates must be able to be
+ // represented in FP.
+ typedef model::point
+ <
+ calculation_type,
+ dimension<PointOfSegment>::value,
+ typename coordinate_system<PointOfSegment>::type
+ > fp_point_type;
+
+ // For convenience
+ typedef fp_point_type fp_vector_type;
+
+ /*
+ Algorithm [p: (px,py), p1: (x1,y1), p2: (x2,y2)]
VECTOR v(x2 - x1, y2 - y1)
VECTOR w(px - x1, py - y1)
c1 = w . v
@@ -132,12 +128,13 @@ public :
// v is multiplied below with a (possibly) FP-value, so should be in FP
// For consistency we define w also in FP
- fp_vector_type v, w;
+ fp_vector_type v, w, projected;
geometry::convert(p2, v);
geometry::convert(p, w);
- subtract_point(v, p1);
- subtract_point(w, p1);
+ geometry::convert(p1, projected);
+ subtract_point(v, projected);
+ subtract_point(w, projected);
Strategy strategy;
boost::ignore_unused_variable_warning(strategy);
@@ -157,20 +154,10 @@ public :
// See above, c1 > 0 AND c2 > c1 so: c2 != 0
calculation_type const b = c1 / c2;
- fp_strategy_type fp_strategy
- = strategy::distance::services::get_similar
- <
- Strategy, Point, fp_point_type
- >::apply(strategy);
-
- fp_point_type projected;
- geometry::convert(p1, projected);
multiply_value(v, b);
add_point(projected, v);
- //std::cout << "distance " << dsv(p) << " .. " << dsv(projected) << std::endl;
-
- return fp_strategy.apply(p, projected);
+ return strategy.apply(p, projected);
}
};
@@ -178,103 +165,59 @@ public :
namespace services
{
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct tag<projected_point<Point, PointOfSegment, CalculationType, Strategy> >
+template <typename CalculationType, typename Strategy>
+struct tag<projected_point<CalculationType, Strategy> >
{
typedef strategy_tag_distance_point_segment type;
};
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct return_type<projected_point<Point, PointOfSegment, CalculationType, Strategy> >
-{
- typedef typename projected_point<Point, PointOfSegment, CalculationType, Strategy>::calculation_type type;
-};
-
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct strategy_point_point<projected_point<Point, PointOfSegment, CalculationType, Strategy> >
-{
- typedef Strategy type;
-};
-
-
-template
-<
- typename Point,
- typename PointOfSegment,
- typename CalculationType,
- typename Strategy,
- typename P1,
- typename P2
->
-struct similar_type<projected_point<Point, PointOfSegment, CalculationType, Strategy>, P1, P2>
-{
- typedef projected_point<P1, P2, CalculationType, Strategy> type;
-};
-
+template <typename CalculationType, typename Strategy, typename P, typename PS>
+struct return_type<projected_point<CalculationType, Strategy>, P, PS>
+ : projected_point<CalculationType, Strategy>::template calculation_type<P, PS>
+{};
-template
-<
- typename Point,
- typename PointOfSegment,
- typename CalculationType,
- typename Strategy,
- typename P1,
- typename P2
->
-struct get_similar<projected_point<Point, PointOfSegment, CalculationType, Strategy>, P1, P2>
-{
- static inline typename similar_type
- <
- projected_point<Point, PointOfSegment, CalculationType, Strategy>, P1, P2
- >::type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& )
- {
- return projected_point<P1, P2, CalculationType, Strategy>();
- }
-};
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct comparable_type<projected_point<Point, PointOfSegment, CalculationType, Strategy> >
+template <typename CalculationType, typename Strategy>
+struct comparable_type<projected_point<CalculationType, Strategy> >
{
// Define a projected_point strategy with its underlying point-point-strategy
// being comparable
typedef projected_point
<
- Point,
- PointOfSegment,
CalculationType,
typename comparable_type<Strategy>::type
> type;
};
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct get_comparable<projected_point<Point, PointOfSegment, CalculationType, Strategy> >
+template <typename CalculationType, typename Strategy>
+struct get_comparable<projected_point<CalculationType, Strategy> >
{
typedef typename comparable_type
<
- projected_point<Point, PointOfSegment, CalculationType, Strategy>
+ projected_point<CalculationType, Strategy>
>::type comparable_type;
public :
- static inline comparable_type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& )
+ static inline comparable_type apply(projected_point<CalculationType, Strategy> const& )
{
return comparable_type();
}
};
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct result_from_distance<projected_point<Point, PointOfSegment, CalculationType, Strategy> >
+template <typename CalculationType, typename Strategy, typename P, typename PS>
+struct result_from_distance<projected_point<CalculationType, Strategy>, P, PS>
{
private :
- typedef typename return_type<projected_point<Point, PointOfSegment, CalculationType, Strategy> >::type return_type;
+ typedef typename return_type<projected_point<CalculationType, Strategy>, P, PS>::type return_type;
public :
template <typename T>
- static inline return_type apply(projected_point<Point, PointOfSegment, CalculationType, Strategy> const& , T const& value)
+ static inline return_type apply(projected_point<CalculationType, Strategy> const& , T const& value)
{
Strategy s;
- return result_from_distance<Strategy>::apply(s, value);
+ return result_from_distance<Strategy, P, PS>::apply(s, value);
}
};
@@ -285,19 +228,21 @@ public :
// of point-to-segment or point-to-linestring.
// Convenient for geographic coordinate systems especially.
template <typename Point, typename PointOfSegment, typename Strategy>
-struct default_strategy<segment_tag, Point, PointOfSegment, cartesian_tag, cartesian_tag, Strategy>
+struct default_strategy
+ <
+ point_tag, segment_tag, Point, PointOfSegment,
+ cartesian_tag, cartesian_tag, Strategy
+ >
{
typedef strategy::distance::projected_point
<
- Point,
- PointOfSegment,
void,
typename boost::mpl::if_
<
boost::is_void<Strategy>,
typename default_strategy
<
- point_tag, Point, PointOfSegment,
+ point_tag, point_tag, Point, PointOfSegment,
cartesian_tag, cartesian_tag
>::type,
Strategy
@@ -305,6 +250,20 @@ struct default_strategy<segment_tag, Point, PointOfSegment, cartesian_tag, carte
> type;
};
+template <typename PointOfSegment, typename Point, typename Strategy>
+struct default_strategy
+ <
+ segment_tag, point_tag, PointOfSegment, Point,
+ cartesian_tag, cartesian_tag, Strategy
+ >
+{
+ typedef typename default_strategy
+ <
+ point_tag, segment_tag, Point, PointOfSegment,
+ cartesian_tag, cartesian_tag, Strategy
+ >::type type;
+};
+
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
diff --git a/boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp b/boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp
new file mode 100644
index 0000000000..c4090044f4
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp
@@ -0,0 +1,316 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP
+
+
+#include <algorithm>
+
+#include <boost/concept_check.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/arithmetic/dot_product.hpp>
+
+#include <boost/geometry/strategies/tags.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/default_distance_result.hpp>
+#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
+#include <boost/geometry/strategies/cartesian/distance_projected_point.hpp>
+
+#include <boost/geometry/util/select_coordinate_type.hpp>
+
+// Helper geometry (projected point on line)
+#include <boost/geometry/geometries/point.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace strategy { namespace distance
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename T>
+struct projected_point_ax_result
+{
+ typedef T value_type;
+
+ projected_point_ax_result(T const& c = T(0))
+ : atd(c), xtd(c)
+ {}
+
+ projected_point_ax_result(T const& a, T const& x)
+ : atd(a), xtd(x)
+ {}
+
+ friend inline bool operator<(projected_point_ax_result const& left,
+ projected_point_ax_result const& right)
+ {
+ return left.xtd < right.xtd || left.atd < right.atd;
+ }
+
+ T atd, xtd;
+};
+
+// This less-comparator may be used as a parameter of detail::douglas_peucker.
+// In this simplify strategy distances are compared in 2 places
+// 1. to choose the furthest candidate (md < dist)
+// 2. to check if the candidate is further than max_distance (max_distance < md)
+template <typename Distance>
+class projected_point_ax_less
+{
+public:
+ projected_point_ax_less(Distance const& max_distance)
+ : m_max_distance(max_distance)
+ {}
+
+ inline bool operator()(Distance const& left, Distance const& right) const
+ {
+ //return left.xtd < right.xtd && right.atd < m_max_distance.atd;
+
+ typedef typename Distance::value_type value_type;
+
+ value_type const lx = left.xtd > m_max_distance.xtd ? left.xtd - m_max_distance.xtd : 0;
+ value_type const rx = right.xtd > m_max_distance.xtd ? right.xtd - m_max_distance.xtd : 0;
+ value_type const la = left.atd > m_max_distance.atd ? left.atd - m_max_distance.atd : 0;
+ value_type const ra = right.atd > m_max_distance.atd ? right.atd - m_max_distance.atd : 0;
+
+ value_type const l = (std::max)(lx, la);
+ value_type const r = (std::max)(rx, ra);
+
+ return l < r;
+ }
+private:
+ Distance const& m_max_distance;
+};
+
+// This strategy returns 2-component Point/Segment distance.
+// The ATD (along track distance) is parallel to the Segment
+// and is a distance between Point projected into a line defined by a Segment and the nearest Segment's endpoint.
+// If the projected Point intersects the Segment the ATD is equal to 0.
+// The XTD (cross track distance) is perpendicular to the Segment
+// and is a distance between input Point and its projection.
+// If the Segment has length equal to 0, ATD and XTD has value equal
+// to the distance between the input Point and one of the Segment's endpoints.
+//
+// p3 p4
+// ^ 7
+// | /
+// p1<-----e========e----->p2
+//
+// p1: atd=D, xtd=0
+// p2: atd=D, xtd=0
+// p3: atd=0, xtd=D
+// p4: atd=D/2, xtd=D
+template
+<
+ typename CalculationType = void,
+ typename Strategy = pythagoras<CalculationType>
+>
+class projected_point_ax
+{
+public :
+ template <typename Point, typename PointOfSegment>
+ struct calculation_type
+ : public projected_point<CalculationType, Strategy>
+ ::template calculation_type<Point, PointOfSegment>
+ {};
+
+ template <typename Point, typename PointOfSegment>
+ struct result_type
+ {
+ typedef projected_point_ax_result
+ <
+ typename calculation_type<Point, PointOfSegment>::type
+ > type;
+ };
+
+public :
+
+ template <typename Point, typename PointOfSegment>
+ inline typename result_type<Point, PointOfSegment>::type
+ apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const
+ {
+ assert_dimension_equal<Point, PointOfSegment>();
+
+ typedef typename calculation_type<Point, PointOfSegment>::type calculation_type;
+
+ // A projected point of points in Integer coordinates must be able to be
+ // represented in FP.
+ typedef model::point
+ <
+ calculation_type,
+ dimension<PointOfSegment>::value,
+ typename coordinate_system<PointOfSegment>::type
+ > fp_point_type;
+
+ // For convenience
+ typedef fp_point_type fp_vector_type;
+
+ /*
+ Algorithm [p: (px,py), p1: (x1,y1), p2: (x2,y2)]
+ VECTOR v(x2 - x1, y2 - y1)
+ VECTOR w(px - x1, py - y1)
+ c1 = w . v
+ c2 = v . v
+ b = c1 / c2
+ RETURN POINT(x1 + b * vx, y1 + b * vy)
+ */
+
+ // v is multiplied below with a (possibly) FP-value, so should be in FP
+ // For consistency we define w also in FP
+ fp_vector_type v, w, projected;
+
+ geometry::convert(p2, v);
+ geometry::convert(p, w);
+ geometry::convert(p1, projected);
+ subtract_point(v, projected);
+ subtract_point(w, projected);
+
+ Strategy strategy;
+ boost::ignore_unused_variable_warning(strategy);
+
+ typename result_type<Point, PointOfSegment>::type result;
+
+ calculation_type const zero = calculation_type();
+ calculation_type const c2 = dot_product(v, v);
+ if ( math::equals(c2, zero) )
+ {
+ result.xtd = strategy.apply(p, projected);
+ // assume that the 0-length segment is perpendicular to the Pt->ProjPt vector
+ result.atd = 0;
+ return result;
+ }
+
+ calculation_type const c1 = dot_product(w, v);
+ calculation_type const b = c1 / c2;
+ multiply_value(v, b);
+ add_point(projected, v);
+
+ result.xtd = strategy.apply(p, projected);
+
+ if (c1 <= zero)
+ {
+ result.atd = strategy.apply(p1, projected);
+ }
+ else if (c2 <= c1)
+ {
+ result.atd = strategy.apply(p2, projected);
+ }
+ else
+ {
+ result.atd = 0;
+ }
+
+ return result;
+ }
+};
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace services
+{
+
+
+template <typename CalculationType, typename Strategy>
+struct tag<detail::projected_point_ax<CalculationType, Strategy> >
+{
+ typedef strategy_tag_distance_point_segment type;
+};
+
+
+template <typename CalculationType, typename Strategy, typename P, typename PS>
+struct return_type<detail::projected_point_ax<CalculationType, Strategy>, P, PS>
+{
+ typedef typename detail::projected_point_ax<CalculationType, Strategy>
+ ::template result_type<P, PS>::type type;
+};
+
+
+template <typename CalculationType, typename Strategy>
+struct comparable_type<detail::projected_point_ax<CalculationType, Strategy> >
+{
+ // Define a projected_point strategy with its underlying point-point-strategy
+ // being comparable
+ typedef detail::projected_point_ax
+ <
+ CalculationType,
+ typename comparable_type<Strategy>::type
+ > type;
+};
+
+
+template <typename CalculationType, typename Strategy>
+struct get_comparable<detail::projected_point_ax<CalculationType, Strategy> >
+{
+ typedef typename comparable_type
+ <
+ detail::projected_point_ax<CalculationType, Strategy>
+ >::type comparable_type;
+public :
+ static inline comparable_type apply(detail::projected_point_ax<CalculationType, Strategy> const& )
+ {
+ return comparable_type();
+ }
+};
+
+
+template <typename CalculationType, typename Strategy, typename P, typename PS>
+struct result_from_distance<detail::projected_point_ax<CalculationType, Strategy>, P, PS>
+{
+private :
+ typedef typename return_type<detail::projected_point_ax<CalculationType, Strategy>, P, PS>::type return_type;
+public :
+ template <typename T>
+ static inline return_type apply(detail::projected_point_ax<CalculationType, Strategy> const& , T const& value)
+ {
+ Strategy s;
+ return_type ret;
+ ret.atd = result_from_distance<Strategy, P, PS>::apply(s, value.atd);
+ ret.xtd = result_from_distance<Strategy, P, PS>::apply(s, value.xtd);
+ return ret;
+ }
+};
+
+
+} // namespace services
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+}} // namespace strategy::distance
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP
diff --git a/boost/geometry/strategies/cartesian/distance_pythagoras.hpp b/boost/geometry/strategies/cartesian/distance_pythagoras.hpp
index 51d2722663..77bdc966a6 100644
--- a/boost/geometry/strategies/cartesian/distance_pythagoras.hpp
+++ b/boost/geometry/strategies/cartesian/distance_pythagoras.hpp
@@ -22,6 +22,7 @@
#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/calculation_type.hpp>
@@ -37,21 +38,23 @@ namespace strategy { namespace distance
namespace detail
{
-template <typename Point1, typename Point2, size_t I, typename T>
+template <size_t I, typename T>
struct compute_pythagoras
{
+ template <typename Point1, typename Point2>
static inline T apply(Point1 const& p1, Point2 const& p2)
{
- T const c1 = boost::numeric_cast<T>(get<I-1>(p2));
- T const c2 = boost::numeric_cast<T>(get<I-1>(p1));
+ T const c1 = boost::numeric_cast<T>(get<I-1>(p1));
+ T const c2 = boost::numeric_cast<T>(get<I-1>(p2));
T const d = c1 - c2;
- return d * d + compute_pythagoras<Point1, Point2, I-1, T>::apply(p1, p2);
+ return d * d + compute_pythagoras<I-1, T>::apply(p1, p2);
}
};
-template <typename Point1, typename Point2, typename T>
-struct compute_pythagoras<Point1, Point2, 0, T>
+template <typename T>
+struct compute_pythagoras<0, T>
{
+ template <typename Point1, typename Point2>
static inline T apply(Point1 const&, Point2 const&)
{
return boost::numeric_cast<T>(0);
@@ -72,24 +75,26 @@ namespace comparable
\tparam Point2 \tparam_second_point
\tparam CalculationType \tparam_calculation
*/
-template
-<
- typename Point1,
- typename Point2 = Point1,
- typename CalculationType = void
->
+template <typename CalculationType = void>
class pythagoras
{
public :
- typedef typename util::calculation_type::geometric::binary
- <
- Point1,
- Point2,
- CalculationType
- >::type calculation_type;
-
- static inline calculation_type apply(Point1 const& p1, Point2 const& p2)
+ template <typename Point1, typename Point2>
+ struct calculation_type
+ : util::calculation_type::geometric::binary
+ <
+ Point1,
+ Point2,
+ CalculationType,
+ double,
+ double
+ >
+ {};
+
+ template <typename Point1, typename Point2>
+ static inline typename calculation_type<Point1, Point2>::type
+ apply(Point1 const& p1, Point2 const& p2)
{
BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point1>) );
BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point2>) );
@@ -101,9 +106,8 @@ public :
return detail::compute_pythagoras
<
- Point1, Point2,
dimension<Point1>::value,
- calculation_type
+ typename calculation_type<Point1, Point2>::type
>::apply(p1, p2);
}
};
@@ -114,8 +118,6 @@ public :
/*!
\brief Strategy to calculate the distance between two points
\ingroup strategies
-\tparam Point1 \tparam_first_point
-\tparam Point2 \tparam_second_point
\tparam CalculationType \tparam_calculation
\qbk{
@@ -128,22 +130,23 @@ public :
*/
template
<
- typename Point1,
- typename Point2 = Point1,
typename CalculationType = void
>
class pythagoras
{
- typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type;
public :
- typedef typename util::calculation_type::geometric::binary
- <
- Point1,
- Point2,
- CalculationType,
- double,
- double // promote integer to double
- >::type calculation_type;
+
+ template <typename P1, typename P2>
+ struct calculation_type
+ : util::calculation_type::geometric::binary
+ <
+ P1,
+ P2,
+ CalculationType,
+ double,
+ double // promote integer to double
+ >
+ {};
/*!
\brief applies the distance calculation using pythagoras
@@ -151,10 +154,18 @@ public :
\param p1 first point
\param p2 second point
*/
- static inline calculation_type apply(Point1 const& p1, Point2 const& p2)
+ template <typename P1, typename P2>
+ static inline typename calculation_type<P1, P2>::type
+ apply(P1 const& p1, P2 const& p2)
{
- calculation_type const t = comparable_type::apply(p1, p2);
- return sqrt(t);
+ // The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call
+ return math::sqrt
+ (
+ boost::numeric_cast<typename calculation_type<P1, P2>::type>
+ (
+ comparable::pythagoras<CalculationType>::apply(p1, p2)
+ )
+ );
}
};
@@ -163,81 +174,46 @@ public :
namespace services
{
-template <typename Point1, typename Point2, typename CalculationType>
-struct tag<pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType>
+struct tag<pythagoras<CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct return_type<pythagoras<Point1, Point2, CalculationType> >
-{
- typedef typename pythagoras<Point1, Point2, CalculationType>::calculation_type type;
-};
-
-
-template
-<
- typename Point1,
- typename Point2,
- typename CalculationType,
- typename P1,
- typename P2
->
-struct similar_type<pythagoras<Point1, Point2, CalculationType>, P1, P2>
-{
- typedef pythagoras<P1, P2, CalculationType> type;
-};
-
-
-template
-<
- typename Point1,
- typename Point2,
- typename CalculationType,
- typename P1,
- typename P2
->
-struct get_similar<pythagoras<Point1, Point2, CalculationType>, P1, P2>
-{
- static inline typename similar_type
- <
- pythagoras<Point1, Point2, CalculationType>, P1, P2
- >::type apply(pythagoras<Point1, Point2, CalculationType> const& )
- {
- return pythagoras<P1, P2, CalculationType>();
- }
-};
+template <typename CalculationType, typename P1, typename P2>
+struct return_type<distance::pythagoras<CalculationType>, P1, P2>
+ : pythagoras<CalculationType>::template calculation_type<P1, P2>
+{};
-template <typename Point1, typename Point2, typename CalculationType>
-struct comparable_type<pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType>
+struct comparable_type<pythagoras<CalculationType> >
{
- typedef comparable::pythagoras<Point1, Point2, CalculationType> type;
+ typedef comparable::pythagoras<CalculationType> type;
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct get_comparable<pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType>
+struct get_comparable<pythagoras<CalculationType> >
{
- typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type;
+ typedef comparable::pythagoras<CalculationType> comparable_type;
public :
- static inline comparable_type apply(pythagoras<Point1, Point2, CalculationType> const& )
+ static inline comparable_type apply(pythagoras<CalculationType> const& )
{
return comparable_type();
}
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct result_from_distance<pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType, typename Point1, typename Point2>
+struct result_from_distance<pythagoras<CalculationType>, Point1, Point2>
{
private :
- typedef typename return_type<pythagoras<Point1, Point2, CalculationType> >::type return_type;
+ typedef typename return_type<pythagoras<CalculationType>, Point1, Point2>::type return_type;
public :
template <typename T>
- static inline return_type apply(pythagoras<Point1, Point2, CalculationType> const& , T const& value)
+ static inline return_type apply(pythagoras<CalculationType> const& , T const& value)
{
return return_type(value);
}
@@ -245,83 +221,48 @@ public :
// Specializations for comparable::pythagoras
-template <typename Point1, typename Point2, typename CalculationType>
-struct tag<comparable::pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType>
+struct tag<comparable::pythagoras<CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct return_type<comparable::pythagoras<Point1, Point2, CalculationType> >
-{
- typedef typename comparable::pythagoras<Point1, Point2, CalculationType>::calculation_type type;
-};
-
-
+template <typename CalculationType, typename P1, typename P2>
+struct return_type<comparable::pythagoras<CalculationType>, P1, P2>
+ : comparable::pythagoras<CalculationType>::template calculation_type<P1, P2>
+{};
-template
-<
- typename Point1,
- typename Point2,
- typename CalculationType,
- typename P1,
- typename P2
->
-struct similar_type<comparable::pythagoras<Point1, Point2, CalculationType>, P1, P2>
-{
- typedef comparable::pythagoras<P1, P2, CalculationType> type;
-};
-
-
-template
-<
- typename Point1,
- typename Point2,
- typename CalculationType,
- typename P1,
- typename P2
->
-struct get_similar<comparable::pythagoras<Point1, Point2, CalculationType>, P1, P2>
-{
- static inline typename similar_type
- <
- comparable::pythagoras<Point1, Point2, CalculationType>, P1, P2
- >::type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& )
- {
- return comparable::pythagoras<P1, P2, CalculationType>();
- }
-};
-template <typename Point1, typename Point2, typename CalculationType>
-struct comparable_type<comparable::pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType>
+struct comparable_type<comparable::pythagoras<CalculationType> >
{
- typedef comparable::pythagoras<Point1, Point2, CalculationType> type;
+ typedef comparable::pythagoras<CalculationType> type;
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct get_comparable<comparable::pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType>
+struct get_comparable<comparable::pythagoras<CalculationType> >
{
- typedef comparable::pythagoras<Point1, Point2, CalculationType> comparable_type;
+ typedef comparable::pythagoras<CalculationType> comparable_type;
public :
- static inline comparable_type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& )
+ static inline comparable_type apply(comparable::pythagoras<CalculationType> const& )
{
return comparable_type();
}
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct result_from_distance<comparable::pythagoras<Point1, Point2, CalculationType> >
+template <typename CalculationType, typename Point1, typename Point2>
+struct result_from_distance<comparable::pythagoras<CalculationType>, Point1, Point2>
{
private :
- typedef typename return_type<comparable::pythagoras<Point1, Point2, CalculationType> >::type return_type;
+ typedef typename return_type<comparable::pythagoras<CalculationType>, Point1, Point2>::type return_type;
public :
template <typename T>
- static inline return_type apply(comparable::pythagoras<Point1, Point2, CalculationType> const& , T const& value)
+ static inline return_type apply(comparable::pythagoras<CalculationType> const& , T const& value)
{
return_type const v = value;
return v * v;
@@ -330,9 +271,12 @@ public :
template <typename Point1, typename Point2>
-struct default_strategy<point_tag, Point1, Point2, cartesian_tag, cartesian_tag, void>
+struct default_strategy
+ <
+ point_tag, point_tag, Point1, Point2, cartesian_tag, cartesian_tag
+ >
{
- typedef pythagoras<Point1, Point2> type;
+ typedef pythagoras<> type;
};
diff --git a/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp b/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp
new file mode 100644
index 0000000000..8a4234282e
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp
@@ -0,0 +1,338 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/calculation_type.hpp>
+
+
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace distance
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <std::size_t I>
+struct compute_pythagoras_box_box
+{
+ template <typename Box1, typename Box2, typename T>
+ static inline void apply(Box1 const& box1, Box2 const& box2, T& result)
+ {
+ T const b1_min_coord =
+ boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box1));
+ T const b1_max_coord =
+ boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box1));
+
+ T const b2_min_coord =
+ boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box2));
+ T const b2_max_coord =
+ boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box2));
+
+ if ( b1_max_coord < b2_min_coord )
+ {
+ T diff = b2_min_coord - b1_max_coord;
+ result += diff * diff;
+ }
+ if ( b1_min_coord > b2_max_coord )
+ {
+ T diff = b1_min_coord - b2_max_coord;
+ result += diff * diff;
+ }
+
+ compute_pythagoras_box_box<I-1>::apply(box1, box2, result);
+ }
+};
+
+template <>
+struct compute_pythagoras_box_box<0>
+{
+ template <typename Box1, typename Box2, typename T>
+ static inline void apply(Box1 const&, Box2 const&, T&)
+ {
+ }
+};
+
+}
+#endif // DOXYGEN_NO_DETAIL
+
+
+namespace comparable
+{
+
+/*!
+\brief Strategy to calculate comparable distance between two boxes
+\ingroup strategies
+\tparam Box1 \tparam_first_box
+\tparam Box2 \tparam_second_box
+\tparam CalculationType \tparam_calculation
+*/
+template <typename CalculationType = void>
+class pythagoras_box_box
+{
+public :
+
+ template <typename Box1, typename Box2>
+ struct calculation_type
+ {
+ typedef typename util::calculation_type::geometric::binary
+ <
+ Box1,
+ Box2,
+ CalculationType
+ >::type type;
+ };
+
+ template <typename Box1, typename Box2>
+ static inline typename calculation_type<Box1, Box2>::type
+ apply(Box1 const& box1, Box2 const& box2)
+ {
+ BOOST_CONCEPT_ASSERT
+ ( (concept::ConstPoint<typename point_type<Box1>::type>) );
+ BOOST_CONCEPT_ASSERT
+ ( (concept::ConstPoint<typename point_type<Box2>::type>) );
+
+ // Calculate distance using Pythagoras
+ // (Leave comment above for Doxygen)
+
+ assert_dimension_equal<Box1, Box2>();
+
+ typename calculation_type<Box1, Box2>::type result(0);
+
+ detail::compute_pythagoras_box_box
+ <
+ dimension<Box1>::value
+ >::apply(box1, box2, result);
+
+ return result;
+ }
+};
+
+} // namespace comparable
+
+
+/*!
+\brief Strategy to calculate the distance between two boxes
+\ingroup strategies
+\tparam CalculationType \tparam_calculation
+
+\qbk{
+[heading Notes]
+[note Can be used for boxes with two\, three or more dimensions]
+[heading See also]
+[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
+}
+
+*/
+template
+<
+ typename CalculationType = void
+>
+class pythagoras_box_box
+{
+public :
+
+ template <typename Box1, typename Box2>
+ struct calculation_type
+ : util::calculation_type::geometric::binary
+ <
+ Box1,
+ Box2,
+ CalculationType,
+ double,
+ double // promote integer to double
+ >
+ {};
+
+ /*!
+ \brief applies the distance calculation using pythagoras_box_box
+ \return the calculated distance (including taking the square root)
+ \param box1 first box
+ \param box2 second box
+ */
+ template <typename Box1, typename Box2>
+ static inline typename calculation_type<Box1, Box2>::type
+ apply(Box1 const& box1, Box2 const& box2)
+ {
+ // The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call
+ return math::sqrt
+ (
+ boost::numeric_cast<typename calculation_type
+ <
+ Box1, Box2
+ >::type>
+ (
+ comparable::pythagoras_box_box
+ <
+ CalculationType
+ >::apply(box1, box2)
+ )
+ );
+ }
+};
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace services
+{
+
+template <typename CalculationType>
+struct tag<pythagoras_box_box<CalculationType> >
+{
+ typedef strategy_tag_distance_box_box type;
+};
+
+
+template <typename CalculationType, typename Box1, typename Box2>
+struct return_type<distance::pythagoras_box_box<CalculationType>, Box1, Box2>
+ : pythagoras_box_box<CalculationType>::template calculation_type<Box1, Box2>
+{};
+
+
+template <typename CalculationType>
+struct comparable_type<pythagoras_box_box<CalculationType> >
+{
+ typedef comparable::pythagoras_box_box<CalculationType> type;
+};
+
+
+template <typename CalculationType>
+struct get_comparable<pythagoras_box_box<CalculationType> >
+{
+ typedef comparable::pythagoras_box_box<CalculationType> comparable_type;
+public :
+ static inline comparable_type
+ apply(pythagoras_box_box<CalculationType> const& )
+ {
+ return comparable_type();
+ }
+};
+
+
+template <typename CalculationType, typename Box1, typename Box2>
+struct result_from_distance<pythagoras_box_box<CalculationType>, Box1, Box2>
+{
+private:
+ typedef typename return_type
+ <
+ pythagoras_box_box<CalculationType>, Box1, Box2
+ >::type return_type;
+public:
+ template <typename T>
+ static inline return_type
+ apply(pythagoras_box_box<CalculationType> const& , T const& value)
+ {
+ return return_type(value);
+ }
+};
+
+
+// Specializations for comparable::pythagoras_box_box
+template <typename CalculationType>
+struct tag<comparable::pythagoras_box_box<CalculationType> >
+{
+ typedef strategy_tag_distance_box_box type;
+};
+
+
+template <typename CalculationType, typename Box1, typename Box2>
+struct return_type<comparable::pythagoras_box_box<CalculationType>, Box1, Box2>
+ : comparable::pythagoras_box_box
+ <
+ CalculationType
+ >::template calculation_type<Box1, Box2>
+{};
+
+
+
+
+template <typename CalculationType>
+struct comparable_type<comparable::pythagoras_box_box<CalculationType> >
+{
+ typedef comparable::pythagoras_box_box<CalculationType> type;
+};
+
+
+template <typename CalculationType>
+struct get_comparable<comparable::pythagoras_box_box<CalculationType> >
+{
+ typedef comparable::pythagoras_box_box<CalculationType> comparable_type;
+public :
+ static inline comparable_type apply(comparable_type const& )
+ {
+ return comparable_type();
+ }
+};
+
+
+template <typename CalculationType, typename Box1, typename Box2>
+struct result_from_distance
+ <
+ comparable::pythagoras_box_box<CalculationType>, Box1, Box2
+ >
+{
+private :
+ typedef typename return_type
+ <
+ comparable::pythagoras_box_box<CalculationType>, Box1, Box2
+ >::type return_type;
+public :
+ template <typename T>
+ static inline return_type
+ apply(comparable::pythagoras_box_box<CalculationType> const&,
+ T const& value)
+ {
+ return_type const v = value;
+ return v * v;
+ }
+};
+
+
+template <typename BoxPoint1, typename BoxPoint2>
+struct default_strategy
+ <
+ box_tag, box_tag, BoxPoint1, BoxPoint2, cartesian_tag, cartesian_tag
+ >
+{
+ typedef pythagoras_box_box<> type;
+};
+
+
+} // namespace services
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+}} // namespace strategy::distance
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP
diff --git a/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp b/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp
new file mode 100644
index 0000000000..0ce1d422ee
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp
@@ -0,0 +1,349 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP
+#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/calculation_type.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace distance
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <size_t I>
+struct compute_pythagoras_point_box
+{
+ template <typename Point, typename Box, typename T>
+ static inline void apply(Point const& point, Box const& box, T& result)
+ {
+ T const p_coord = boost::numeric_cast<T>(geometry::get<I-1>(point));
+ T const b_min_coord =
+ boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box));
+ T const b_max_coord =
+ boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box));
+
+ if ( p_coord < b_min_coord )
+ {
+ T diff = b_min_coord - p_coord;
+ result += diff * diff;
+ }
+ if ( p_coord > b_max_coord )
+ {
+ T diff = p_coord - b_max_coord;
+ result += diff * diff;
+ }
+
+ compute_pythagoras_point_box<I-1>::apply(point, box, result);
+ }
+};
+
+template <>
+struct compute_pythagoras_point_box<0>
+{
+ template <typename Point, typename Box, typename T>
+ static inline void apply(Point const&, Box const&, T&)
+ {
+ }
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+namespace comparable
+{
+
+/*!
+ \brief Strategy to calculate comparable distance between a point
+ and a box
+ \ingroup strategies
+ \tparam Point \tparam_first_point
+ \tparam Box \tparam_second_box
+ \tparam CalculationType \tparam_calculation
+*/
+template <typename CalculationType = void>
+class pythagoras_point_box
+{
+public :
+
+ template <typename Point, typename Box>
+ struct calculation_type
+ {
+ typedef typename util::calculation_type::geometric::binary
+ <
+ Point, Box, CalculationType
+ >::type type;
+ };
+
+ template <typename Point, typename Box>
+ static inline typename calculation_type<Point, Box>::type
+ apply(Point const& point, Box const& box)
+ {
+ BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point>) );
+ BOOST_CONCEPT_ASSERT
+ ( (concept::ConstPoint<typename point_type<Box>::type>) );
+
+ // Calculate distance using Pythagoras
+ // (Leave comment above for Doxygen)
+
+ assert_dimension_equal<Point, Box>();
+
+ typename calculation_type<Point, Box>::type result(0);
+
+ detail::compute_pythagoras_point_box
+ <
+ dimension<Point>::value
+ >::apply(point, box, result);
+
+ return result;
+ }
+};
+
+} // namespace comparable
+
+
+/*!
+\brief Strategy to calculate the distance between a point and a box
+\ingroup strategies
+\tparam CalculationType \tparam_calculation
+
+\qbk{
+[heading Notes]
+[note Can be used for points and boxes with two\, three or more dimensions]
+[heading See also]
+[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
+}
+
+*/
+template
+<
+ typename CalculationType = void
+>
+class pythagoras_point_box
+{
+public :
+
+ template <typename Point, typename Box>
+ struct calculation_type
+ : util::calculation_type::geometric::binary
+ <
+ Point,
+ Box,
+ CalculationType,
+ double,
+ double // promote integer to double
+ >
+ {};
+
+ /*!
+ \brief applies the distance calculation using pythagoras
+ \return the calculated distance (including taking the square root)
+ \param point point
+ \param box box
+ */
+ template <typename Point, typename Box>
+ static inline typename calculation_type<Point, Box>::type
+ apply(Point const& point, Box const& box)
+ {
+ // The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call
+ return math::sqrt
+ (
+ boost::numeric_cast<typename calculation_type
+ <
+ Point, Box
+ >::type>
+ (
+ comparable::pythagoras_point_box
+ <
+ CalculationType
+ >::apply(point, box)
+ )
+ );
+ }
+};
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace services
+{
+
+template <typename CalculationType>
+struct tag<pythagoras_point_box<CalculationType> >
+{
+ typedef strategy_tag_distance_point_box type;
+};
+
+
+template <typename CalculationType, typename Point, typename Box>
+struct return_type<distance::pythagoras_point_box<CalculationType>, Point, Box>
+ : pythagoras_point_box
+ <
+ CalculationType
+ >::template calculation_type<Point, Box>
+{};
+
+
+template <typename CalculationType>
+struct comparable_type<pythagoras_point_box<CalculationType> >
+{
+ typedef comparable::pythagoras_point_box<CalculationType> type;
+};
+
+
+template <typename CalculationType>
+struct get_comparable<pythagoras_point_box<CalculationType> >
+{
+ typedef comparable::pythagoras_point_box<CalculationType> comparable_type;
+public :
+ static inline comparable_type
+ apply(pythagoras_point_box<CalculationType> const& )
+ {
+ return comparable_type();
+ }
+};
+
+
+template <typename CalculationType, typename Point, typename Box>
+struct result_from_distance<pythagoras_point_box<CalculationType>, Point, Box>
+{
+private :
+ typedef typename return_type
+ <
+ pythagoras_point_box<CalculationType>, Point, Box
+ >::type return_type;
+public :
+ template <typename T>
+ static inline return_type
+ apply(pythagoras_point_box<CalculationType> const& , T const& value)
+ {
+ return return_type(value);
+ }
+};
+
+
+// Specializations for comparable::pythagoras_point_box
+template <typename CalculationType>
+struct tag<comparable::pythagoras_point_box<CalculationType> >
+{
+ typedef strategy_tag_distance_point_box type;
+};
+
+
+template <typename CalculationType, typename Point, typename Box>
+struct return_type
+ <
+ comparable::pythagoras_point_box<CalculationType>, Point, Box
+ > : comparable::pythagoras_point_box
+ <
+ CalculationType
+ >::template calculation_type<Point, Box>
+{};
+
+
+
+
+template <typename CalculationType>
+struct comparable_type<comparable::pythagoras_point_box<CalculationType> >
+{
+ typedef comparable::pythagoras_point_box<CalculationType> type;
+};
+
+
+template <typename CalculationType>
+struct get_comparable<comparable::pythagoras_point_box<CalculationType> >
+{
+ typedef comparable::pythagoras_point_box<CalculationType> comparable_type;
+public :
+ static inline comparable_type apply(comparable_type const& )
+ {
+ return comparable_type();
+ }
+};
+
+
+template <typename CalculationType, typename Point, typename Box>
+struct result_from_distance
+ <
+ comparable::pythagoras_point_box<CalculationType>, Point, Box
+ >
+{
+private :
+ typedef typename return_type
+ <
+ comparable::pythagoras_point_box<CalculationType>, Point, Box
+ >::type return_type;
+public :
+ template <typename T>
+ static inline return_type
+ apply(comparable::pythagoras_point_box<CalculationType> const& ,
+ T const& value)
+ {
+ return_type const v = value;
+ return v * v;
+ }
+};
+
+
+template <typename Point, typename BoxPoint>
+struct default_strategy
+ <
+ point_tag, box_tag, Point, BoxPoint, cartesian_tag, cartesian_tag
+ >
+{
+ typedef pythagoras_point_box<> type;
+};
+
+template <typename BoxPoint, typename Point>
+struct default_strategy
+ <
+ box_tag, point_tag, BoxPoint, Point, cartesian_tag, cartesian_tag
+ >
+{
+ typedef typename default_strategy
+ <
+ point_tag, box_tag, Point, BoxPoint, cartesian_tag, cartesian_tag
+ >::type type;
+};
+
+
+} // namespace services
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+}} // namespace strategy::distance
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP
diff --git a/boost/geometry/strategies/cartesian/point_in_box.hpp b/boost/geometry/strategies/cartesian/point_in_box.hpp
index 275f7550e4..79f094113d 100644
--- a/boost/geometry/strategies/cartesian/point_in_box.hpp
+++ b/boost/geometry/strategies/cartesian/point_in_box.hpp
@@ -21,9 +21,9 @@
#include <boost/geometry/strategies/within.hpp>
-namespace boost { namespace geometry { namespace strategy
+namespace boost { namespace geometry { namespace strategy
{
-
+
namespace within
{
@@ -60,14 +60,14 @@ struct relate_point_box_loop
{
static inline bool apply(Point const& point, Box const& box)
{
- if (! SubStrategy::apply(get<Dimension>(point),
- get<min_corner, Dimension>(box),
+ if (! SubStrategy::apply(get<Dimension>(point),
+ get<min_corner, Dimension>(box),
get<max_corner, Dimension>(box))
)
{
return false;
}
-
+
return relate_point_box_loop
<
SubStrategy,
@@ -102,12 +102,12 @@ template
>
struct point_in_box
{
- static inline bool apply(Point const& point, Box const& box)
+ static inline bool apply(Point const& point, Box const& box)
{
return relate_point_box_loop
<
SubStrategy,
- Point, Box,
+ Point, Box,
0, dimension<Point>::type::value
>::apply(point, box);
}
@@ -126,13 +126,13 @@ namespace within { namespace services
template <typename Point, typename Box>
struct default_strategy
<
- point_tag, box_tag,
- point_tag, areal_tag,
- cartesian_tag, cartesian_tag,
+ point_tag, box_tag,
+ point_tag, areal_tag,
+ cartesian_tag, cartesian_tag,
Point, Box
>
{
- typedef within::point_in_box<Point, Box> type;
+ typedef within::point_in_box<Point, Box> type;
};
@@ -146,9 +146,9 @@ namespace covered_by { namespace services
template <typename Point, typename Box>
struct default_strategy
<
- point_tag, box_tag,
- point_tag, areal_tag,
- cartesian_tag, cartesian_tag,
+ point_tag, box_tag,
+ point_tag, areal_tag,
+ cartesian_tag, cartesian_tag,
Point, Box
>
{
diff --git a/boost/geometry/strategies/cartesian/side_by_triangle.hpp b/boost/geometry/strategies/cartesian/side_by_triangle.hpp
index 967090c50a..5d589ffc86 100644
--- a/boost/geometry/strategies/cartesian/side_by_triangle.hpp
+++ b/boost/geometry/strategies/cartesian/side_by_triangle.hpp
@@ -47,6 +47,30 @@ public :
// Types can be all three different. Therefore it is
// not implemented (anymore) as "segment"
+ template <typename coordinate_type, typename promoted_type, typename P1, typename P2, typename P>
+ static inline promoted_type side_value(P1 const& p1, P2 const& p2, P const& p)
+ {
+ coordinate_type const x = get<0>(p);
+ coordinate_type const y = get<1>(p);
+
+ coordinate_type const sx1 = get<0>(p1);
+ coordinate_type const sy1 = get<1>(p1);
+ coordinate_type const sx2 = get<0>(p2);
+ coordinate_type const sy2 = get<1>(p2);
+
+ promoted_type const dx = sx2 - sx1;
+ promoted_type const dy = sy2 - sy1;
+ promoted_type const dpx = x - sx1;
+ promoted_type const dpy = y - sy1;
+
+ return geometry::detail::determinant<promoted_type>
+ (
+ dx, dy,
+ dpx, dpy
+ );
+
+ }
+
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
@@ -65,14 +89,6 @@ public :
CalculationType
>::type coordinate_type;
- coordinate_type const x = get<0>(p);
- coordinate_type const y = get<1>(p);
-
- coordinate_type const sx1 = get<0>(p1);
- coordinate_type const sy1 = get<1>(p1);
- coordinate_type const sx2 = get<0>(p2);
- coordinate_type const sy2 = get<1>(p2);
-
// Promote float->double, small int->int
typedef typename select_most_precise
<
@@ -80,23 +96,14 @@ public :
double
>::type promoted_type;
- promoted_type const dx = sx2 - sx1;
- promoted_type const dy = sy2 - sy1;
- promoted_type const dpx = x - sx1;
- promoted_type const dpy = y - sy1;
-
- promoted_type const s
- = geometry::detail::determinant<promoted_type>
- (
- dx, dy,
- dpx, dpy
- );
-
+ promoted_type const s = side_value<coordinate_type, promoted_type>(p1, p2, p);
promoted_type const zero = promoted_type();
- return math::equals(s, zero) ? 0
- : s > zero ? 1
+
+ return math::equals(s, zero) ? 0
+ : s > zero ? 1
: -1;
}
+
};
diff --git a/boost/geometry/strategies/comparable_distance_result.hpp b/boost/geometry/strategies/comparable_distance_result.hpp
new file mode 100644
index 0000000000..a258ddb9b4
--- /dev/null
+++ b/boost/geometry/strategies/comparable_distance_result.hpp
@@ -0,0 +1,196 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP
+#define BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP
+
+#include <boost/mpl/always.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/vector.hpp>
+
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/util/compress_variant.hpp>
+#include <boost/geometry/util/transform_variant.hpp>
+#include <boost/geometry/util/combine_if.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace resolve_strategy
+{
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+struct comparable_distance_result
+ : strategy::distance::services::return_type
+ <
+ typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type,
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type
+ >
+{};
+
+template <typename Geometry1, typename Geometry2>
+struct comparable_distance_result<Geometry1, Geometry2, default_strategy>
+ : comparable_distance_result
+ <
+ Geometry1,
+ Geometry2,
+ typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type
+ >
+{};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+struct comparable_distance_result
+ : resolve_strategy::comparable_distance_result
+ <
+ Geometry1,
+ Geometry2,
+ Strategy
+ >
+{};
+
+
+template
+<
+ typename Geometry1,
+ BOOST_VARIANT_ENUM_PARAMS(typename T),
+ typename Strategy
+>
+struct comparable_distance_result
+ <
+ Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
+ >
+{
+ // A set of all variant type combinations that are compatible and
+ // implemented
+ typedef typename util::combine_if<
+ typename mpl::vector1<Geometry1>,
+ typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
+ mpl::always<mpl::true_>
+ >::type possible_input_types;
+
+ // The (possibly variant) result type resulting from these combinations
+ typedef typename compress_variant<
+ typename transform_variant<
+ possible_input_types,
+ resolve_strategy::comparable_distance_result<
+ mpl::first<mpl::_>,
+ mpl::second<mpl::_>,
+ Strategy
+ >,
+ mpl::back_inserter<mpl::vector0<> >
+ >::type
+ >::type type;
+};
+
+
+// Distance arguments are commutative
+template
+<
+ BOOST_VARIANT_ENUM_PARAMS(typename T),
+ typename Geometry2,
+ typename Strategy
+>
+struct comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ > : public comparable_distance_result
+ <
+ Geometry2, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
+ >
+{};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Strategy>
+struct comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >
+{
+ // A set of all variant type combinations that are compatible and
+ // implemented
+ typedef typename util::combine_if
+ <
+ typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
+ typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
+ mpl::always<mpl::true_>
+ >::type possible_input_types;
+
+ // The (possibly variant) result type resulting from these combinations
+ typedef typename compress_variant<
+ typename transform_variant<
+ possible_input_types,
+ resolve_strategy::comparable_distance_result<
+ mpl::first<mpl::_>,
+ mpl::second<mpl::_>,
+ Strategy
+ >,
+ mpl::back_inserter<mpl::vector0<> >
+ >::type
+ >::type type;
+};
+
+} // namespace resolve_variant
+
+
+
+
+
+/*!
+\brief Meta-function defining return type of comparable_distance function
+\ingroup distance
+*/
+template
+<
+ typename Geometry1,
+ typename Geometry2 = Geometry1,
+ typename Strategy = void
+>
+struct comparable_distance_result
+ : resolve_variant::comparable_distance_result
+ <
+ Geometry1, Geometry2, Strategy
+ >
+{};
+
+template <typename Geometry1, typename Geometry2>
+struct comparable_distance_result<Geometry1, Geometry2, void>
+ : comparable_distance_result<Geometry1, Geometry2, default_strategy>
+{};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP
diff --git a/boost/geometry/strategies/concepts/convex_hull_concept.hpp b/boost/geometry/strategies/concepts/convex_hull_concept.hpp
index b31f0caa4e..d6e42e95a3 100644
--- a/boost/geometry/strategies/concepts/convex_hull_concept.hpp
+++ b/boost/geometry/strategies/concepts/convex_hull_concept.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -46,17 +51,17 @@ class ConvexHullStrategy
{
static void apply()
{
- Strategy const* str;
+ Strategy const* str = 0;
- state_type* st;
- geometry_type* sp;
- std::vector<point_type> *v;
+ state_type* st = 0;
+ geometry_type* sp = 0;
+ std::vector<point_type> *v = 0;
// 4) must implement a method apply, iterating over a range
str->apply(*sp, *st);
// 5) must implement a method result, with an output iterator
- str->result(*st, std::back_inserter(*v), true);
+ str->result(*st, std::back_inserter(*v), true, true);
}
};
diff --git a/boost/geometry/strategies/concepts/distance_concept.hpp b/boost/geometry/strategies/concepts/distance_concept.hpp
index ba347d015a..a0cbbd21ed 100644
--- a/boost/geometry/strategies/concepts/distance_concept.hpp
+++ b/boost/geometry/strategies/concepts/distance_concept.hpp
@@ -18,11 +18,13 @@
#include <iterator>
#include <boost/concept_check.hpp>
+#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/util/parameter_type_of.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/geometries/point.hpp>
namespace boost { namespace geometry { namespace concept
@@ -33,7 +35,7 @@ namespace boost { namespace geometry { namespace concept
\brief Checks strategy for point-segment-distance
\ingroup distance
*/
-template <typename Strategy>
+template <typename Strategy, typename Point1, typename Point2>
struct PointDistanceStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
@@ -42,7 +44,7 @@ private :
struct checker
{
template <typename ApplyMethod>
- static void apply(ApplyMethod const&)
+ static void apply(ApplyMethod)
{
// 1: inspect and define both arguments of apply
typedef typename parameter_type_of
@@ -55,68 +57,45 @@ private :
ApplyMethod, 1
>::type ptype2;
- // 2) check if apply-arguments fulfill point concept
- BOOST_CONCEPT_ASSERT
- (
- (concept::ConstPoint<ptype1>)
- );
-
- BOOST_CONCEPT_ASSERT
- (
- (concept::ConstPoint<ptype2>)
- );
-
-
- // 3) must define meta-function return_type
- typedef typename strategy::distance::services::return_type<Strategy>::type rtype;
-
- // 4) must define meta-function "similar_type"
- typedef typename strategy::distance::services::similar_type
+ // 2) must define meta-function return_type
+ typedef typename strategy::distance::services::return_type
<
- Strategy, ptype2, ptype1
- >::type stype;
+ Strategy, ptype1, ptype2
+ >::type rtype;
- // 5) must define meta-function "comparable_type"
+ // 3) must define meta-function "comparable_type"
typedef typename strategy::distance::services::comparable_type
<
Strategy
>::type ctype;
- // 6) must define meta-function "tag"
+ // 4) must define meta-function "tag"
typedef typename strategy::distance::services::tag
<
Strategy
>::type tag;
- // 7) must implement apply with arguments
+ // 5) must implement apply with arguments
Strategy* str = 0;
ptype1 *p1 = 0;
ptype2 *p2 = 0;
rtype r = str->apply(*p1, *p2);
- // 8) must define (meta)struct "get_similar" with apply
- stype s = strategy::distance::services::get_similar
- <
- Strategy,
- ptype2, ptype1
- >::apply(*str);
-
- // 9) must define (meta)struct "get_comparable" with apply
+ // 6) must define (meta)struct "get_comparable" with apply
ctype c = strategy::distance::services::get_comparable
<
Strategy
>::apply(*str);
- // 10) must define (meta)struct "result_from_distance" with apply
+ // 7) must define (meta)struct "result_from_distance" with apply
r = strategy::distance::services::result_from_distance
<
- Strategy
+ Strategy,
+ ptype1, ptype2
>::apply(*str, 1.0);
- boost::ignore_unused_variable_warning(str);
- boost::ignore_unused_variable_warning(s);
- boost::ignore_unused_variable_warning(c);
- boost::ignore_unused_variable_warning(r);
+ boost::ignore_unused<tag>();
+ boost::ignore_unused(str, c, r);
}
};
@@ -125,7 +104,7 @@ private :
public :
BOOST_CONCEPT_USAGE(PointDistanceStrategy)
{
- checker::apply(&Strategy::apply);
+ checker::apply(&Strategy::template apply<Point1, Point2>);
}
#endif
};
@@ -135,7 +114,7 @@ public :
\brief Checks strategy for point-segment-distance
\ingroup strategy_concepts
*/
-template <typename Strategy>
+template <typename Strategy, typename Point, typename PointOfSegment>
struct PointSegmentDistanceStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
@@ -144,7 +123,7 @@ private :
struct checker
{
template <typename ApplyMethod>
- static void apply(ApplyMethod const&)
+ static void apply(ApplyMethod)
{
typedef typename parameter_type_of
<
@@ -156,27 +135,8 @@ private :
ApplyMethod, 1
>::type sptype;
- // 2) check if apply-arguments fulfill point concept
- BOOST_CONCEPT_ASSERT
- (
- (concept::ConstPoint<ptype>)
- );
-
- BOOST_CONCEPT_ASSERT
- (
- (concept::ConstPoint<sptype>)
- );
-
-
- // 3) must define meta-function return_type
- typedef typename strategy::distance::services::return_type<Strategy>::type rtype;
-
- // 4) must define underlying point-distance-strategy
- typedef typename strategy::distance::services::strategy_point_point<Strategy>::type stype;
- BOOST_CONCEPT_ASSERT
- (
- (concept::PointDistanceStrategy<stype>)
- );
+ // must define meta-function return_type
+ typedef typename strategy::distance::services::return_type<Strategy, ptype, sptype>::type rtype;
Strategy *str = 0;
@@ -194,7 +154,7 @@ private :
public :
BOOST_CONCEPT_USAGE(PointSegmentDistanceStrategy)
{
- checker::apply(&Strategy::apply);
+ checker::apply(&Strategy::template apply<Point, PointOfSegment>);
}
#endif
};
diff --git a/boost/geometry/strategies/concepts/simplify_concept.hpp b/boost/geometry/strategies/concepts/simplify_concept.hpp
index 92e5156b5a..d7f596cfe7 100644
--- a/boost/geometry/strategies/concepts/simplify_concept.hpp
+++ b/boost/geometry/strategies/concepts/simplify_concept.hpp
@@ -18,7 +18,9 @@
#include <iterator>
#include <boost/concept_check.hpp>
+#include <boost/core/ignore_unused.hpp>
+#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/strategies/concepts/distance_concept.hpp>
@@ -30,7 +32,7 @@ namespace boost { namespace geometry { namespace concept
\brief Checks strategy for simplify
\ingroup simplify
*/
-template <typename Strategy>
+template <typename Strategy, typename Point>
struct SimplifyStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
@@ -44,7 +46,7 @@ private :
struct checker
{
template <typename ApplyMethod>
- static void apply(ApplyMethod const&)
+ static void apply(ApplyMethod)
{
namespace ft = boost::function_types;
typedef typename ft::parameter_types
@@ -59,29 +61,14 @@ private :
boost::mpl::int_<0>
>::type base_index;
- // 1: inspect and define both arguments of apply
- typedef typename boost::remove_const
- <
- typename boost::remove_reference
- <
- typename boost::mpl::at
- <
- parameter_types,
- base_index
- >::type
- >::type
- >::type point_type;
-
-
-
BOOST_CONCEPT_ASSERT
(
- (concept::PointSegmentDistanceStrategy<ds_type>)
+ (concept::PointSegmentDistanceStrategy<ds_type, Point, Point>)
);
Strategy *str = 0;
- std::vector<point_type> const* v1 = 0;
- std::vector<point_type> * v2 = 0;
+ std::vector<Point> const* v1 = 0;
+ std::vector<Point> * v2 = 0;
// 2) must implement method apply with arguments
// - Range
@@ -89,15 +76,15 @@ private :
// - floating point value
str->apply(*v1, std::back_inserter(*v2), 1.0);
- boost::ignore_unused_variable_warning(str);
+ boost::ignore_unused<parameter_types, base_index>();
+ boost::ignore_unused(str);
}
};
public :
BOOST_CONCEPT_USAGE(SimplifyStrategy)
{
- checker::apply(&ds_type::apply);
-
+ checker::apply(&ds_type::template apply<Point, Point>);
}
#endif
};
diff --git a/boost/geometry/strategies/concepts/within_concept.hpp b/boost/geometry/strategies/concepts/within_concept.hpp
index a9684b98e1..8786403712 100644
--- a/boost/geometry/strategies/concepts/within_concept.hpp
+++ b/boost/geometry/strategies/concepts/within_concept.hpp
@@ -143,7 +143,7 @@ class WithinStrategyPointBox
(
(boost::is_same
<
- bool,
+ bool,
typename boost::function_types::result_type<ApplyMethod>::type
>::type::value),
WRONG_RETURN_TYPE
@@ -207,7 +207,7 @@ class WithinStrategyBoxBox
(
(boost::is_same
<
- bool,
+ bool,
typename boost::function_types::result_type<ApplyMethod>::type
>::type::value),
WRONG_RETURN_TYPE
@@ -237,8 +237,8 @@ public :
};
// So now: boost::geometry::concept::within
-namespace within
-{
+namespace within
+{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
diff --git a/boost/geometry/strategies/covered_by.hpp b/boost/geometry/strategies/covered_by.hpp
index a878b26c86..a5aae7703b 100644
--- a/boost/geometry/strategies/covered_by.hpp
+++ b/boost/geometry/strategies/covered_by.hpp
@@ -53,7 +53,7 @@ struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
- false, NOT_IMPLEMENTED_FOR_THIS_TYPES
+ false, NOT_IMPLEMENTED_FOR_THESE_TYPES
, (types<GeometryContained, GeometryContaining>)
);
};
diff --git a/boost/geometry/strategies/default_comparable_distance_result.hpp b/boost/geometry/strategies/default_comparable_distance_result.hpp
new file mode 100644
index 0000000000..3b4229f106
--- /dev/null
+++ b/boost/geometry/strategies/default_comparable_distance_result.hpp
@@ -0,0 +1,43 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP
+#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP
+
+#include <boost/geometry/strategies/comparable_distance_result.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+/*!
+\brief Meta-function defining return type of comparable_distance function
+\ingroup distance
+\note The strategy defines the return-type (so this situation is different
+ from length, where distance is sqr/sqrt, but length always squared)
+ */
+template <typename Geometry1, typename Geometry2 = Geometry1>
+struct default_comparable_distance_result
+ : comparable_distance_result<Geometry1, Geometry2, void>
+{};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP
diff --git a/boost/geometry/strategies/default_distance_result.hpp b/boost/geometry/strategies/default_distance_result.hpp
index ea5f3ff764..e34a947727 100644
--- a/boost/geometry/strategies/default_distance_result.hpp
+++ b/boost/geometry/strategies/default_distance_result.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,10 +19,7 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP
-
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/distance_result.hpp>
namespace boost { namespace geometry
@@ -31,17 +33,8 @@ namespace boost { namespace geometry
*/
template <typename Geometry1, typename Geometry2 = Geometry1>
struct default_distance_result
-{
- typedef typename strategy::distance::services::return_type
- <
- typename strategy::distance::services::default_strategy
- <
- point_tag,
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type
- >::type
- >::type type;
-};
+ : distance_result<Geometry1, Geometry2, void>
+{};
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/default_length_result.hpp b/boost/geometry/strategies/default_length_result.hpp
index 706941b9e4..806e4284ce 100644
--- a/boost/geometry/strategies/default_length_result.hpp
+++ b/boost/geometry/strategies/default_length_result.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,22 +19,22 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
+
+#include <boost/geometry/util/compress_variant.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
+#include <boost/geometry/util/transform_variant.hpp>
namespace boost { namespace geometry
{
-/*!
- \brief Meta-function defining return type of length function
- \ingroup length
- \note Length of a line of integer coordinates can be double.
- So we take at least a double. If Big Number types are used,
- we take that type.
- */
+namespace resolve_strategy
+{
+
template <typename Geometry>
struct default_length_result
{
@@ -40,7 +45,45 @@ struct default_length_result
>::type type;
};
-}} // namespace boost::geometry
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct default_length_result
+ : resolve_strategy::default_length_result<Geometry>
+{};
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct default_length_result<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ typedef typename compress_variant<
+ typename transform_variant<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ resolve_strategy::default_length_result<boost::mpl::placeholders::_>
+ >::type
+ >::type type;
+};
+
+} // namespace resolve_variant
+
+
+/*!
+ \brief Meta-function defining return type of length function
+ \ingroup length
+ \note Length of a line of integer coordinates can be double.
+ So we take at least a double. If Big Number types are used,
+ we take that type.
+
+ */
+template <typename Geometry>
+struct default_length_result
+ : resolve_variant::default_length_result<Geometry>
+{};
+
+
+}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP
diff --git a/boost/geometry/strategies/default_strategy.hpp b/boost/geometry/strategies/default_strategy.hpp
new file mode 100644
index 0000000000..6d05970b42
--- /dev/null
+++ b/boost/geometry/strategies/default_strategy.hpp
@@ -0,0 +1,34 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP
+#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP
+
+
+namespace boost { namespace geometry
+{
+
+// This is a strategy placeholder type, which is passed by the algorithm free
+// functions to the multi-stage resolving process. It's resolved into an actual
+// strategy type during the resolve_strategy stage, possibly depending on the
+// input geometry type(s). This typically happens after the resolve_variant
+// stage, as it needs to be based on concrete geometry types - as opposed to
+// variant geometry types.
+
+struct default_strategy {};
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP
diff --git a/boost/geometry/strategies/distance.hpp b/boost/geometry/strategies/distance.hpp
index ef9a7ee10d..98ccb8202b 100644
--- a/boost/geometry/strategies/distance.hpp
+++ b/boost/geometry/strategies/distance.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -30,47 +35,16 @@ namespace strategy { namespace distance { namespace services
template <typename Strategy> struct tag {};
-template <typename Strategy> struct return_type
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy>)
- );
-};
-
-/*!
- \brief Metafunction delivering a similar strategy with other input point types
-*/
-template
-<
- typename Strategy,
- typename Point1,
- typename Point2
->
-struct similar_type
+template <typename Strategy, typename P1, typename P2>
+struct return_type
{
BOOST_MPL_ASSERT_MSG
(
- false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY
- , (types<Strategy, Point1, Point2>)
+ false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy, P1, P2>)
);
};
-template
-<
- typename Strategy,
- typename Point1,
- typename Point2
->
-struct get_similar
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY
- , (types<Strategy, Point1, Point2>)
- );
-};
template <typename Strategy> struct comparable_type
{
@@ -88,11 +62,10 @@ template <typename Strategy> struct get_comparable
);
};
-template <typename Strategy> struct result_from_distance {};
+template <typename Strategy, typename P1, typename P2>
+struct result_from_distance {};
-// For point-segment only:
-template <typename Strategy> struct strategy_point_point {};
// Default strategy
@@ -102,7 +75,8 @@ template <typename Strategy> struct strategy_point_point {};
\brief Traits class binding a default strategy for distance
to one (or possibly two) coordinate system(s)
\ingroup distance
- \tparam GeometryTag tag (point/segment) for which this strategy is the default
+ \tparam GeometryTag1 tag (point/segment/box) for which this strategy is the default
+ \tparam GeometryTag2 tag (point/segment/box) for which this strategy is the default
\tparam Point1 first point-type
\tparam Point2 second point-type
\tparam CsTag1 tag of coordinate system of first point type
@@ -110,7 +84,8 @@ template <typename Strategy> struct strategy_point_point {};
*/
template
<
- typename GeometryTag,
+ typename GeometryTag1,
+ typename GeometryTag2,
typename Point1,
typename Point2 = Point1,
typename CsTag1 = typename cs_tag<Point1>::type,
diff --git a/boost/geometry/strategies/distance_result.hpp b/boost/geometry/strategies/distance_result.hpp
new file mode 100644
index 0000000000..185a511464
--- /dev/null
+++ b/boost/geometry/strategies/distance_result.hpp
@@ -0,0 +1,213 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_DISTANCE_RESULT_HPP
+#define BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP
+
+#include <boost/mpl/always.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/vector.hpp>
+
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/util/compress_variant.hpp>
+#include <boost/geometry/util/transform_variant.hpp>
+#include <boost/geometry/util/combine_if.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace resolve_strategy
+{
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+struct distance_result
+ : strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type
+ >
+{};
+
+template <typename Geometry1, typename Geometry2>
+struct distance_result<Geometry1, Geometry2, default_strategy>
+ : distance_result
+ <
+ Geometry1,
+ Geometry2,
+ typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type
+ >
+{};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+struct distance_result
+ : resolve_strategy::distance_result
+ <
+ Geometry1,
+ Geometry2,
+ Strategy
+ >
+{};
+
+
+template
+<
+ typename Geometry1,
+ BOOST_VARIANT_ENUM_PARAMS(typename T),
+ typename Strategy
+>
+struct distance_result
+ <
+ Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
+ >
+{
+ // A set of all variant type combinations that are compatible and
+ // implemented
+ typedef typename util::combine_if<
+ typename mpl::vector1<Geometry1>,
+ typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
+ // Here we want should remove most of the combinations that
+ // are not valid, mostly to limit the size of the resulting MPL set.
+ // But is_implementedn is not ready for prime time
+ //
+ // util::is_implemented2<mpl::_1, mpl::_2, dispatch::distance<mpl::_1, mpl::_2> >
+ mpl::always<mpl::true_>
+ >::type possible_input_types;
+
+ // The (possibly variant) result type resulting from these combinations
+ typedef typename compress_variant<
+ typename transform_variant<
+ possible_input_types,
+ resolve_strategy::distance_result<
+ mpl::first<mpl::_>,
+ mpl::second<mpl::_>,
+ Strategy
+ >,
+ mpl::back_inserter<mpl::vector0<> >
+ >::type
+ >::type type;
+};
+
+
+// Distance arguments are commutative
+template
+<
+ BOOST_VARIANT_ENUM_PARAMS(typename T),
+ typename Geometry2,
+ typename Strategy
+>
+struct distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ > : public distance_result
+ <
+ Geometry2, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
+ >
+{};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Strategy>
+struct distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >
+{
+ // A set of all variant type combinations that are compatible and
+ // implemented
+ typedef typename util::combine_if
+ <
+ typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
+ typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
+ // Here we want to try to remove most of the combinations
+ // that are not valid, mostly to limit the size of the
+ // resulting MPL vector.
+ // But is_implemented is not ready for prime time
+ //
+ // util::is_implemented2<mpl::_1, mpl::_2, dispatch::distance<mpl::_1, mpl::_2> >
+ mpl::always<mpl::true_>
+ >::type possible_input_types;
+
+ // The (possibly variant) result type resulting from these combinations
+ typedef typename compress_variant<
+ typename transform_variant<
+ possible_input_types,
+ resolve_strategy::distance_result<
+ mpl::first<mpl::_>,
+ mpl::second<mpl::_>,
+ Strategy
+ >,
+ mpl::back_inserter<mpl::vector0<> >
+ >::type
+ >::type type;
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief Meta-function defining return type of distance function
+\ingroup distance
+\note The strategy defines the return-type (so this situation is different
+ from length, where distance is sqr/sqrt, but length always squared)
+ */
+template
+<
+ typename Geometry1,
+ typename Geometry2 = Geometry1,
+ typename Strategy = void
+>
+struct distance_result
+ : resolve_variant::distance_result<Geometry1, Geometry2, Strategy>
+{};
+
+
+template <typename Geometry1, typename Geometry2>
+struct distance_result<Geometry1, Geometry2, void>
+ : distance_result<Geometry1, Geometry2, default_strategy>
+{};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP
diff --git a/boost/geometry/strategies/intersection.hpp b/boost/geometry/strategies/intersection.hpp
index fc628c0635..ef1b676fda 100644
--- a/boost/geometry/strategies/intersection.hpp
+++ b/boost/geometry/strategies/intersection.hpp
@@ -17,42 +17,47 @@
#include <boost/geometry/policies/relate/tupled.hpp>
#include <boost/geometry/strategies/side.hpp>
-#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/cartesian/cart_intersect.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
namespace boost { namespace geometry
{
-// The intersection strategy is a "compound strategy",
-// it contains a segment-intersection-strategy
-// and a side-strategy
/*!
-\tparam CalculationType \tparam_calculation
-*/
+\brief "compound strategy", containing a segment-intersection-strategy
+ and a side-strategy
+ */
template
<
typename Tag,
typename Geometry1,
typename Geometry2,
typename IntersectionPoint,
+ typename RobustPolicy,
typename CalculationType = void
>
struct strategy_intersection
{
private :
+ // for development BOOST_STATIC_ASSERT((! boost::is_same<RobustPolicy, void>::type::value));
+
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
typedef typename model::referring_segment<point1_type const> segment1_type;
typedef typename model::referring_segment<point2_type const> segment2_type;
typedef segment_intersection_points
+ <
+ IntersectionPoint,
+ typename geometry::segment_ratio_type
<
- IntersectionPoint
- > ip_type;
+ IntersectionPoint, RobustPolicy
+ >::type
+ > ip_type;
public:
typedef strategy::intersection::relate_cartesian_segments
@@ -61,18 +66,9 @@ public:
<
policies::relate::segments_intersection_points
<
- segment1_type,
- segment2_type,
- ip_type,
- CalculationType
+ ip_type
> ,
policies::relate::segments_direction
- <
- segment1_type,
- segment2_type,
- CalculationType
- >,
- CalculationType
>,
CalculationType
> segment_intersection_strategy_type;
@@ -82,9 +78,12 @@ public:
Tag,
CalculationType
>::type side_strategy_type;
-};
+ typedef RobustPolicy rescale_policy_type;
+};
+// Version for box_box intersection or other detail calls not needing a strategy
+struct strategy_intersection_empty {};
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/intersection_result.hpp b/boost/geometry/strategies/intersection_result.hpp
index 15917a9eb5..b467b92a7f 100644
--- a/boost/geometry/strategies/intersection_result.hpp
+++ b/boost/geometry/strategies/intersection_result.hpp
@@ -16,6 +16,7 @@
#include <cstddef>
+
namespace boost { namespace geometry
{
@@ -89,7 +90,7 @@ struct de9im
static inline char as_char(int v)
{
- return v >= 0 && v < 10 ? ('0' + char(v)) : '-';
+ return v >= 0 && v < 10 ? static_cast<char>('0' + v) : '-';
}
#if defined(HAVE_MATRIX_AS_STRING)
@@ -153,13 +154,47 @@ struct de9im_segment : public de9im
#endif
};
+template <typename SegmentRatio>
+struct fraction_type
+{
+ SegmentRatio robust_ra; // TODO this can be renamed now to "ra"
+ SegmentRatio robust_rb;
+
+ bool initialized;
+ inline fraction_type()
+ : initialized(false)
+ {}
+
+ template <typename Info>
+ inline void assign(Info const& info)
+ {
+ initialized = true;
+ robust_ra = info.robust_ra;
+ robust_rb = info.robust_rb;
+ }
+
+ inline void assign(SegmentRatio const& a, SegmentRatio const& b)
+ {
+ initialized = true;
+ robust_ra = a;
+ robust_rb = b;
+ }
+};
-template <typename Point>
+//
+/*!
+\brief return-type for segment-intersection
+\note Set in intersection_points.hpp, from segment_intersection_info
+*/
+template <typename Point, typename SegmentRatio>
struct segment_intersection_points
{
- std::size_t count;
+ std::size_t count; // The number of intersection points
+
+ // TODO: combine intersections and fractions in one struct
Point intersections[2];
+ fraction_type<SegmentRatio> fractions[2];
typedef Point point_type;
segment_intersection_points()
@@ -167,6 +202,18 @@ struct segment_intersection_points
{}
};
+// All assigned in cart_intersect, passed to intersection_points
+template <typename CoordinateType, typename PromotedType, typename SegmentRatio>
+struct segment_intersection_info
+{
+ typedef PromotedType promoted_type;
+
+ CoordinateType dx_a, dy_a;
+ CoordinateType dx_b, dy_b; // TODO b can be removed
+ SegmentRatio robust_ra;
+ SegmentRatio robust_rb;
+};
+
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/side_info.hpp b/boost/geometry/strategies/side_info.hpp
index f3a9da0df0..d113eaa8ff 100644
--- a/boost/geometry/strategies/side_info.hpp
+++ b/boost/geometry/strategies/side_info.hpp
@@ -14,13 +14,21 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP
#define BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP
-
+#include <cmath>
#include <utility>
+#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+# include <iostream>
+#endif
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
/*!
\brief Class side_info: small class wrapping for sides (-1,0,1)
@@ -138,16 +146,16 @@ public :
return sides[Which].first == 0 ? 0 : 1;
}
-
+#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
inline void debug() const
{
std::cout << sides[0].first << " "
<< sides[0].second << " "
<< sides[1].first << " "
- << sides[1].second
- << std::endl;
+ << sides[1].second
+ << std::endl;
}
-
+#endif
inline void reverse()
{
@@ -159,6 +167,9 @@ public :
};
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/spherical/area_huiller.hpp b/boost/geometry/strategies/spherical/area_huiller.hpp
index 1bef9b5f2f..e55fdb2b0e 100644
--- a/boost/geometry/strategies/spherical/area_huiller.hpp
+++ b/boost/geometry/strategies/spherical/area_huiller.hpp
@@ -82,8 +82,7 @@ protected :
calculation_type sum;
// Distances are calculated on unit sphere here
- strategy::distance::haversine<PointOfSegment, PointOfSegment>
- distance_over_unit_sphere;
+ strategy::distance::haversine<calculation_type> distance_over_unit_sphere;
inline excess_sum()
@@ -129,7 +128,8 @@ public :
// E: spherical excess, using l'Huiller's formula
// [tg(e / 4)]2 = tg[s / 2] tg[(s-a) / 2] tg[(s-b) / 2] tg[(s-c) / 2]
- calculation_type E = four * atan(sqrt(geometry::math::abs(tan(s / two)
+ calculation_type E = four
+ * atan(geometry::math::sqrt(geometry::math::abs(tan(s / two)
* tan((s - a) / two)
* tan((s - b) / two)
* tan((s - c) / two))));
diff --git a/boost/geometry/strategies/spherical/distance_cross_track.hpp b/boost/geometry/strategies/spherical/distance_cross_track.hpp
index 7b353020eb..a40f03dbaf 100644
--- a/boost/geometry/strategies/spherical/distance_cross_track.hpp
+++ b/boost/geometry/strategies/spherical/distance_cross_track.hpp
@@ -10,6 +10,7 @@
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
+#include <boost/config.hpp>
#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits.hpp>
@@ -18,9 +19,11 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/algorithms/detail/course.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/concepts/distance_concept.hpp>
+#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/math.hpp>
@@ -40,10 +43,8 @@ namespace strategy { namespace distance
/*!
\brief Strategy functor for distance point to segment calculation
\ingroup strategies
-\details Class which calculates the distance of a point to a segment, using latlong points
+\details Class which calculates the distance of a point to a segment, for points on a sphere or globe
\see http://williams.best.vwh.net/avform.htm
-\tparam Point point type
-\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\tparam Strategy underlying point-point distance strategy, defaults to haversine
@@ -55,40 +56,35 @@ namespace strategy { namespace distance
*/
template
<
- typename Point,
- typename PointOfSegment = Point,
typename CalculationType = void,
- typename Strategy = typename services::default_strategy<point_tag, Point>::type
+ typename Strategy = haversine<double, CalculationType>
>
class cross_track
{
public :
- typedef typename promote_floating_point
- <
- typename select_calculation_type
- <
- Point,
- PointOfSegment,
- CalculationType
- >::type
- >::type return_type;
+ template <typename Point, typename PointOfSegment>
+ struct return_type
+ : promote_floating_point
+ <
+ typename select_calculation_type
+ <
+ Point,
+ PointOfSegment,
+ CalculationType
+ >::type
+ >
+ {};
inline cross_track()
- {
- m_strategy = Strategy();
- m_radius = m_strategy.radius();
- }
+ {}
- inline cross_track(return_type const& r)
- : m_radius(r)
- , m_strategy(r)
+ explicit inline cross_track(typename Strategy::radius_type const& r)
+ : m_strategy(r)
{}
inline cross_track(Strategy const& s)
: m_strategy(s)
- {
- m_radius = m_strategy.radius();
- }
+ {}
// It might be useful in the future
@@ -96,9 +92,20 @@ public :
// crosstrack(...) {}
- inline return_type apply(Point const& p,
- PointOfSegment const& sp1, PointOfSegment const& sp2) const
+ template <typename Point, typename PointOfSegment>
+ inline typename return_type<Point, PointOfSegment>::type
+ apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
{
+
+#if !defined(BOOST_MSVC)
+ BOOST_CONCEPT_ASSERT
+ (
+ (concept::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
+ );
+#endif
+
+ typedef typename return_type<Point, PointOfSegment>::type return_type;
+
// http://williams.best.vwh.net/avform.htm#XTE
return_type d1 = m_strategy.apply(sp1, p);
return_type d3 = m_strategy.apply(sp1, sp2);
@@ -111,10 +118,10 @@ public :
return_type d2 = m_strategy.apply(sp2, p);
- return_type crs_AD = course(sp1, p);
- return_type crs_AB = course(sp1, sp2);
+ return_type crs_AD = geometry::detail::course<return_type>(sp1, p);
+ return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2);
return_type crs_BA = crs_AB - geometry::math::pi<return_type>();
- return_type crs_BD = course(sp2, p);
+ return_type crs_BD = geometry::detail::course<return_type>(sp2, p);
return_type d_crs1 = crs_AD - crs_AB;
return_type d_crs2 = crs_BD - crs_BA;
@@ -132,7 +139,7 @@ public :
if(projection1 > 0.0 && projection2 > 0.0)
{
- return_type XTD = m_radius * geometry::math::abs( asin( sin( d1 / m_radius ) * sin( d_crs1 ) ));
+ return_type XTD = radius() * geometry::math::abs( asin( sin( d1 / radius() ) * sin( d_crs1 ) ));
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
std::cout << "Projection ON the segment" << std::endl;
@@ -153,33 +160,12 @@ public :
}
}
- inline return_type radius() const { return m_radius; }
+ inline typename Strategy::radius_type radius() const
+ { return m_strategy.radius(); }
private :
- BOOST_CONCEPT_ASSERT
- (
- (geometry::concept::PointDistanceStrategy<Strategy >)
- );
-
- return_type m_radius;
-
- // Point-point distances are calculated in radians, on the unit sphere
Strategy m_strategy;
-
- /// Calculate course (bearing) between two points. Might be moved to a "course formula" ...
- inline return_type course(Point const& p1, Point const& p2) const
- {
- // http://williams.best.vwh.net/avform.htm#Crs
- return_type dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1);
- return_type cos_p2lat = cos(get_as_radian<1>(p2));
-
- // "An alternative formula, not requiring the pre-computation of d"
- return atan2(sin(dlon) * cos_p2lat,
- cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2))
- - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon));
- }
-
};
@@ -188,120 +174,65 @@ private :
namespace services
{
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct tag<cross_track<Point, PointOfSegment, CalculationType, Strategy> >
+template <typename CalculationType, typename Strategy>
+struct tag<cross_track<CalculationType, Strategy> >
{
typedef strategy_tag_distance_point_segment type;
};
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct return_type<cross_track<Point, PointOfSegment, CalculationType, Strategy> >
-{
- typedef typename cross_track<Point, PointOfSegment, CalculationType, Strategy>::return_type type;
-};
+template <typename CalculationType, typename Strategy, typename P, typename PS>
+struct return_type<cross_track<CalculationType, Strategy>, P, PS>
+ : cross_track<CalculationType, Strategy>::template return_type<P, PS>
+{};
-template
-<
- typename Point,
- typename PointOfSegment,
- typename CalculationType,
- typename Strategy,
- typename P,
- typename PS
->
-struct similar_type<cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS>
+template <typename CalculationType, typename Strategy>
+struct comparable_type<cross_track<CalculationType, Strategy> >
{
- typedef cross_track<Point, PointOfSegment, CalculationType, Strategy> type;
+ // There is no shortcut, so the strategy itself is its comparable type
+ typedef cross_track<CalculationType, Strategy> type;
};
template
<
- typename Point,
- typename PointOfSegment,
typename CalculationType,
- typename Strategy,
- typename P,
- typename PS
->
-struct get_similar<cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS>
-{
- static inline typename similar_type
- <
- cross_track<Point, PointOfSegment, CalculationType, Strategy>, P, PS
- >::type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& strategy)
- {
- return cross_track<P, PS, CalculationType, Strategy>(strategy.radius());
- }
-};
-
-
-template <typename Point, typename PointOfSegment, typename CalculationType, typename Strategy>
-struct comparable_type<cross_track<Point, PointOfSegment, CalculationType, Strategy> >
-{
- // Comparable type is here just the strategy
- typedef typename similar_type
- <
- cross_track
- <
- Point, PointOfSegment, CalculationType, Strategy
- >, Point, PointOfSegment
- >::type type;
-};
-
-
-template
-<
- typename Point, typename PointOfSegment,
- typename CalculationType,
typename Strategy
>
-struct get_comparable<cross_track<Point, PointOfSegment, CalculationType, Strategy> >
+struct get_comparable<cross_track<CalculationType, Strategy> >
{
typedef typename comparable_type
<
- cross_track<Point, PointOfSegment, CalculationType, Strategy>
+ cross_track<CalculationType, Strategy>
>::type comparable_type;
public :
- static inline comparable_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& strategy)
+ static inline comparable_type apply(cross_track<CalculationType, Strategy> const& strategy)
{
return comparable_type(strategy.radius());
}
};
-template
+template
<
- typename Point, typename PointOfSegment,
- typename CalculationType,
- typename Strategy
+ typename CalculationType,
+ typename Strategy,
+ typename P, typename PS
>
-struct result_from_distance<cross_track<Point, PointOfSegment, CalculationType, Strategy> >
+struct result_from_distance<cross_track<CalculationType, Strategy>, P, PS>
{
private :
- typedef typename cross_track<Point, PointOfSegment, CalculationType, Strategy>::return_type return_type;
+ typedef typename cross_track<CalculationType, Strategy>::template return_type<P, PS> return_type;
public :
template <typename T>
- static inline return_type apply(cross_track<Point, PointOfSegment, CalculationType, Strategy> const& , T const& distance)
+ static inline return_type apply(cross_track<CalculationType, Strategy> const& , T const& distance)
{
return distance;
}
};
-template
-<
- typename Point, typename PointOfSegment,
- typename CalculationType,
- typename Strategy
->
-struct strategy_point_point<cross_track<Point, PointOfSegment, CalculationType, Strategy> >
-{
- typedef Strategy type;
-};
-
/*
@@ -311,15 +242,13 @@ TODO: spherical polar coordinate system requires "get_as_radian_equatorial<>"
template <typename Point, typename PointOfSegment, typename Strategy>
struct default_strategy
<
- segment_tag, Point, PointOfSegment,
- spherical_polar_tag, spherical_polar_tag,
+ segment_tag, Point, PointOfSegment,
+ spherical_polar_tag, spherical_polar_tag,
Strategy
>
{
typedef cross_track
<
- Point,
- PointOfSegment,
void,
typename boost::mpl::if_
<
@@ -338,22 +267,20 @@ struct default_strategy
template <typename Point, typename PointOfSegment, typename Strategy>
struct default_strategy
<
- segment_tag, Point, PointOfSegment,
- spherical_equatorial_tag, spherical_equatorial_tag,
+ point_tag, segment_tag, Point, PointOfSegment,
+ spherical_equatorial_tag, spherical_equatorial_tag,
Strategy
>
{
typedef cross_track
<
- Point,
- PointOfSegment,
void,
typename boost::mpl::if_
<
boost::is_void<Strategy>,
typename default_strategy
<
- point_tag, Point, PointOfSegment,
+ point_tag, point_tag, Point, PointOfSegment,
spherical_equatorial_tag, spherical_equatorial_tag
>::type,
Strategy
@@ -362,6 +289,22 @@ struct default_strategy
};
+template <typename PointOfSegment, typename Point, typename Strategy>
+struct default_strategy
+ <
+ segment_tag, point_tag, PointOfSegment, Point,
+ spherical_equatorial_tag, spherical_equatorial_tag,
+ Strategy
+ >
+{
+ typedef typename default_strategy
+ <
+ point_tag, segment_tag, Point, PointOfSegment,
+ spherical_equatorial_tag, spherical_equatorial_tag,
+ Strategy
+ >::type type;
+};
+
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
diff --git a/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp b/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp
new file mode 100644
index 0000000000..fe32f77236
--- /dev/null
+++ b/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp
@@ -0,0 +1,287 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
+#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/calculation_type.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace distance
+{
+
+template
+<
+ typename CalculationType = void,
+ typename Strategy = haversine<double, CalculationType>
+>
+class cross_track_point_box
+{
+public:
+ template <typename Point, typename Box>
+ struct return_type
+ : promote_floating_point
+ <
+ typename select_calculation_type
+ <
+ Point,
+ typename point_type<Box>::type,
+ CalculationType
+ >::type
+ >
+ {};
+
+ inline cross_track_point_box()
+ {}
+
+ explicit inline cross_track_point_box(typename Strategy::radius_type const& r)
+ : m_pp_strategy(r)
+ {}
+
+ inline cross_track_point_box(Strategy const& s)
+ : m_pp_strategy(s)
+ {}
+
+ template <typename Point, typename Box>
+ inline typename return_type<Point, Box>::type
+ apply(Point const& point, Box const& box) const
+ {
+
+#if !defined(BOOST_MSVC)
+ BOOST_CONCEPT_ASSERT
+ (
+ (concept::PointDistanceStrategy
+ <
+ Strategy, Point,
+ typename point_type<Box>::type
+ >)
+ );
+#endif
+
+ typedef typename return_type<Point, Box>::type return_type;
+ typedef typename point_type<Box>::type box_point_t;
+
+ // Create (counterclockwise) array of points, the fifth one closes it
+ // If every point is on the LEFT side (=1) or ON the border (=0)
+ // the distance should be equal to 0.
+
+ // TODO: This strategy as well as other cross-track strategies
+ // and therefore e.g. spherical within(Point, Box) may not work
+ // properly for a Box degenerated to a Segment or Point
+
+ boost::array<box_point_t, 5> bp;
+ geometry::detail::assign_box_corners_oriented<true>(box, bp);
+ bp[4] = bp[0];
+
+ for (int i = 1; i < 5; i++)
+ {
+ box_point_t const& p1 = bp[i - 1];
+ box_point_t const& p2 = bp[i];
+
+ return_type const crs_AD = geometry::detail::course<return_type>(p1, point);
+ return_type const crs_AB = geometry::detail::course<return_type>(p1, p2);
+ return_type const d_crs1 = crs_AD - crs_AB;
+ return_type const sin_d_crs1 = sin(d_crs1);
+
+ // this constant sin() is here to be consistent with the side strategy
+ return_type const sigXTD = asin(sin(0.001) * sin_d_crs1);
+
+ // If the point is on the right side of the edge
+ if ( sigXTD > 0 )
+ {
+ return_type const crs_BA = crs_AB - geometry::math::pi<return_type>();
+ return_type const crs_BD = geometry::detail::course<return_type>(p2, point);
+ return_type const d_crs2 = crs_BD - crs_BA;
+
+ return_type const projection1 = cos( d_crs1 );
+ return_type const projection2 = cos( d_crs2 );
+
+ if(projection1 > 0.0 && projection2 > 0.0)
+ {
+ return_type const d1 = m_pp_strategy.apply(p1, point);
+ return_type const
+ XTD = radius()
+ * geometry::math::abs(
+ asin( sin( d1 / radius() ) * sin_d_crs1 )
+ );
+
+ return return_type(XTD);
+ }
+ else
+ {
+ // OPTIMIZATION
+ // Return d1 if projection1 <= 0 and d2 if projection2 <= 0
+ // if both == 0 then return d1 or d2
+ // both shouldn't be < 0
+
+ return_type const d1 = m_pp_strategy.apply(p1, point);
+ return_type const d2 = m_pp_strategy.apply(p2, point);
+
+ return return_type((std::min)( d1 , d2 ));
+ }
+ }
+ }
+
+ // Return 0 if the point isn't on the right side of any segment
+ return return_type(0);
+ }
+
+ inline typename Strategy::radius_type radius() const
+ { return m_pp_strategy.radius(); }
+
+private :
+
+ Strategy m_pp_strategy;
+};
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace services
+{
+
+template <typename CalculationType, typename Strategy>
+struct tag<cross_track_point_box<CalculationType, Strategy> >
+{
+ typedef strategy_tag_distance_point_box type;
+};
+
+
+template <typename CalculationType, typename Strategy, typename P, typename Box>
+struct return_type<cross_track_point_box<CalculationType, Strategy>, P, Box>
+ : cross_track_point_box<CalculationType, Strategy>::template return_type<P, Box>
+{};
+
+
+template <typename CalculationType, typename Strategy>
+struct comparable_type<cross_track_point_box<CalculationType, Strategy> >
+{
+ // There is no shortcut, so the strategy itself is its comparable type
+ typedef cross_track_point_box<CalculationType, Strategy> type;
+};
+
+
+template
+<
+ typename CalculationType,
+ typename Strategy
+>
+struct get_comparable<cross_track_point_box<CalculationType, Strategy> >
+{
+ typedef typename comparable_type
+ <
+ cross_track_point_box<CalculationType, Strategy>
+ >::type comparable_type;
+public :
+ static inline comparable_type apply(
+ cross_track_point_box<CalculationType, Strategy> const& strategy)
+ {
+ return cross_track_point_box<CalculationType, Strategy>(strategy.radius());
+ }
+};
+
+
+template
+<
+ typename CalculationType,
+ typename Strategy,
+ typename P, typename Box
+>
+struct result_from_distance
+ <
+ cross_track_point_box<CalculationType, Strategy>,
+ P,
+ Box
+ >
+{
+private :
+ typedef typename cross_track_point_box
+ <
+ CalculationType, Strategy
+ >::template return_type<P, Box> return_type;
+public :
+ template <typename T>
+ static inline return_type apply(
+ cross_track_point_box<CalculationType, Strategy> const& ,
+ T const& distance)
+ {
+ return distance;
+ }
+};
+
+
+template <typename Point, typename Box, typename Strategy>
+struct default_strategy
+ <
+ point_tag, box_tag, Point, Box,
+ spherical_equatorial_tag, spherical_equatorial_tag,
+ Strategy
+ >
+{
+ typedef cross_track_point_box
+ <
+ void,
+ typename boost::mpl::if_
+ <
+ boost::is_void<Strategy>,
+ typename default_strategy
+ <
+ point_tag, point_tag,
+ Point, typename point_type<Box>::type,
+ spherical_equatorial_tag, spherical_equatorial_tag
+ >::type,
+ Strategy
+ >::type
+ > type;
+};
+
+
+template <typename Box, typename Point, typename Strategy>
+struct default_strategy
+ <
+ box_tag, point_tag, Box, Point,
+ spherical_equatorial_tag, spherical_equatorial_tag,
+ Strategy
+ >
+{
+ typedef typename default_strategy
+ <
+ point_tag, box_tag, Point, Box,
+ spherical_equatorial_tag, spherical_equatorial_tag,
+ Strategy
+ >::type type;
+};
+
+
+} // namespace services
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+}} // namespace strategy::distance
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
diff --git a/boost/geometry/strategies/spherical/distance_haversine.hpp b/boost/geometry/strategies/spherical/distance_haversine.hpp
index 59ec1c33ff..8db29c5157 100644
--- a/boost/geometry/strategies/spherical/distance_haversine.hpp
+++ b/boost/geometry/strategies/spherical/distance_haversine.hpp
@@ -14,6 +14,7 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
@@ -39,52 +40,57 @@ namespace comparable
// - applying asin (which is strictly (monotone) increasing)
template
<
- typename Point1,
- typename Point2 = Point1,
+ typename RadiusType,
typename CalculationType = void
>
class haversine
{
public :
- typedef typename promote_floating_point
- <
- typename select_calculation_type
- <
- Point1,
- Point2,
- CalculationType
- >::type
- >::type calculation_type;
-
- inline haversine(calculation_type const& r = 1.0)
+ template <typename Point1, typename Point2>
+ struct calculation_type
+ : promote_floating_point
+ <
+ typename select_calculation_type
+ <
+ Point1,
+ Point2,
+ CalculationType
+ >::type
+ >
+ {};
+
+ typedef RadiusType radius_type;
+
+ explicit inline haversine(RadiusType const& r = 1.0)
: m_radius(r)
{}
-
- static inline calculation_type apply(Point1 const& p1, Point2 const& p2)
+ template <typename Point1, typename Point2>
+ static inline typename calculation_type<Point1, Point2>::type
+ apply(Point1 const& p1, Point2 const& p2)
{
- return calculate(get_as_radian<0>(p1), get_as_radian<1>(p1),
- get_as_radian<0>(p2), get_as_radian<1>(p2));
+ return calculate<typename calculation_type<Point1, Point2>::type>(
+ get_as_radian<0>(p1), get_as_radian<1>(p1),
+ get_as_radian<0>(p2), get_as_radian<1>(p2)
+ );
}
- inline calculation_type radius() const
+ inline RadiusType radius() const
{
return m_radius;
}
private :
-
- static inline calculation_type calculate(calculation_type const& lon1,
- calculation_type const& lat1,
- calculation_type const& lon2,
- calculation_type const& lat2)
+ template <typename R, typename T1, typename T2>
+ static inline R calculate(T1 const& lon1, T1 const& lat1,
+ T2 const& lon2, T2 const& lat2)
{
return math::hav(lat2 - lat1)
+ cos(lat1) * cos(lat2) * math::hav(lon2 - lon1);
}
- calculation_type m_radius;
+ RadiusType m_radius;
};
@@ -95,19 +101,18 @@ private :
\brief Distance calculation for spherical coordinates
on a perfect sphere using haversine
\ingroup strategies
-\tparam Point1 \tparam_first_point
-\tparam Point2 \tparam_second_point
+\tparam RadiusType \tparam_radius
\tparam CalculationType \tparam_calculation
\author Adapted from: http://williams.best.vwh.net/avform.htm
\see http://en.wikipedia.org/wiki/Great-circle_distance
-\note It says: <em>The great circle distance d between two
+\note (from Wiki:) The great circle distance d between two
points with coordinates {lat1,lon1} and {lat2,lon2} is given by:
d=acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2))
A mathematically equivalent formula, which is less subject
to rounding error for short distances is:
- d=2*asin(sqrt((sin((lat1-lat2)/2))^2
- + cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))
- </em>
+ d=2*asin(sqrt((sin((lat1-lat2) / 2))^2
+ + cos(lat1)*cos(lat2)*(sin((lon1-lon2) / 2))^2))
+
\qbk{
[heading See also]
@@ -117,23 +122,26 @@ A mathematically equivalent formula, which is less subject
*/
template
<
- typename Point1,
- typename Point2 = Point1,
+ typename RadiusType,
typename CalculationType = void
>
class haversine
{
- typedef comparable::haversine<Point1, Point2, CalculationType> comparable_type;
+ typedef comparable::haversine<RadiusType, CalculationType> comparable_type;
public :
+ template <typename Point1, typename Point2>
+ struct calculation_type
+ : services::return_type<comparable_type, Point1, Point2>
+ {};
- typedef typename services::return_type<comparable_type>::type calculation_type;
+ typedef RadiusType radius_type;
/*!
\brief Constructor
\param radius radius of the sphere, defaults to 1.0 for the unit sphere
*/
- inline haversine(calculation_type const& radius = 1.0)
+ inline haversine(RadiusType const& radius = 1.0)
: m_radius(radius)
{}
@@ -143,10 +151,13 @@ public :
\param p1 first point
\param p2 second point
*/
- inline calculation_type apply(Point1 const& p1, Point2 const& p2) const
+ template <typename Point1, typename Point2>
+ inline typename calculation_type<Point1, Point2>::type
+ apply(Point1 const& p1, Point2 const& p2) const
{
+ typedef typename calculation_type<Point1, Point2>::type calculation_type;
calculation_type const a = comparable_type::apply(p1, p2);
- calculation_type const c = calculation_type(2.0) * asin(sqrt(a));
+ calculation_type const c = calculation_type(2.0) * asin(math::sqrt(a));
return m_radius * c;
}
@@ -154,13 +165,13 @@ public :
\brief access to radius value
\return the radius
*/
- inline calculation_type radius() const
+ inline RadiusType radius() const
{
return m_radius;
}
private :
- calculation_type m_radius;
+ RadiusType m_radius;
};
@@ -168,52 +179,32 @@ private :
namespace services
{
-template <typename Point1, typename Point2, typename CalculationType>
-struct tag<haversine<Point1, Point2, CalculationType> >
+template <typename RadiusType, typename CalculationType>
+struct tag<haversine<RadiusType, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct return_type<haversine<Point1, Point2, CalculationType> >
-{
- typedef typename haversine<Point1, Point2, CalculationType>::calculation_type type;
-};
+template <typename RadiusType, typename CalculationType, typename P1, typename P2>
+struct return_type<haversine<RadiusType, CalculationType>, P1, P2>
+ : haversine<RadiusType, CalculationType>::template calculation_type<P1, P2>
+{};
-template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2>
-struct similar_type<haversine<Point1, Point2, CalculationType>, P1, P2>
+template <typename RadiusType, typename CalculationType>
+struct comparable_type<haversine<RadiusType, CalculationType> >
{
- typedef haversine<P1, P2, CalculationType> type;
+ typedef comparable::haversine<RadiusType, CalculationType> type;
};
-template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2>
-struct get_similar<haversine<Point1, Point2, CalculationType>, P1, P2>
+template <typename RadiusType, typename CalculationType>
+struct get_comparable<haversine<RadiusType, CalculationType> >
{
private :
- typedef haversine<Point1, Point2, CalculationType> this_type;
-public :
- static inline typename similar_type<this_type, P1, P2>::type apply(this_type const& input)
- {
- return haversine<P1, P2, CalculationType>(input.radius());
- }
-};
-
-template <typename Point1, typename Point2, typename CalculationType>
-struct comparable_type<haversine<Point1, Point2, CalculationType> >
-{
- typedef comparable::haversine<Point1, Point2, CalculationType> type;
-};
-
-
-template <typename Point1, typename Point2, typename CalculationType>
-struct get_comparable<haversine<Point1, Point2, CalculationType> >
-{
-private :
- typedef haversine<Point1, Point2, CalculationType> this_type;
- typedef comparable::haversine<Point1, Point2, CalculationType> comparable_type;
+ typedef haversine<RadiusType, CalculationType> this_type;
+ typedef comparable::haversine<RadiusType, CalculationType> comparable_type;
public :
static inline comparable_type apply(this_type const& input)
{
@@ -221,12 +212,12 @@ public :
}
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct result_from_distance<haversine<Point1, Point2, CalculationType> >
+template <typename RadiusType, typename CalculationType, typename P1, typename P2>
+struct result_from_distance<haversine<RadiusType, CalculationType>, P1, P2>
{
private :
- typedef haversine<Point1, Point2, CalculationType> this_type;
- typedef typename return_type<this_type>::type return_type;
+ typedef haversine<RadiusType, CalculationType> this_type;
+ typedef typename return_type<this_type, P1, P2>::type return_type;
public :
template <typename T>
static inline return_type apply(this_type const& , T const& value)
@@ -237,51 +228,31 @@ public :
// Specializations for comparable::haversine
-template <typename Point1, typename Point2, typename CalculationType>
-struct tag<comparable::haversine<Point1, Point2, CalculationType> >
+template <typename RadiusType, typename CalculationType>
+struct tag<comparable::haversine<RadiusType, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct return_type<comparable::haversine<Point1, Point2, CalculationType> >
-{
- typedef typename comparable::haversine<Point1, Point2, CalculationType>::calculation_type type;
-};
-
-
-template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2>
-struct similar_type<comparable::haversine<Point1, Point2, CalculationType>, P1, P2>
-{
- typedef comparable::haversine<P1, P2, CalculationType> type;
-};
-
+template <typename RadiusType, typename CalculationType, typename P1, typename P2>
+struct return_type<comparable::haversine<RadiusType, CalculationType>, P1, P2>
+ : comparable::haversine<RadiusType, CalculationType>::template calculation_type<P1, P2>
+{};
-template <typename Point1, typename Point2, typename CalculationType, typename P1, typename P2>
-struct get_similar<comparable::haversine<Point1, Point2, CalculationType>, P1, P2>
-{
-private :
- typedef comparable::haversine<Point1, Point2, CalculationType> this_type;
-public :
- static inline typename similar_type<this_type, P1, P2>::type apply(this_type const& input)
- {
- return comparable::haversine<P1, P2, CalculationType>(input.radius());
- }
-};
-template <typename Point1, typename Point2, typename CalculationType>
-struct comparable_type<comparable::haversine<Point1, Point2, CalculationType> >
+template <typename RadiusType, typename CalculationType>
+struct comparable_type<comparable::haversine<RadiusType, CalculationType> >
{
- typedef comparable::haversine<Point1, Point2, CalculationType> type;
+ typedef comparable::haversine<RadiusType, CalculationType> type;
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct get_comparable<comparable::haversine<Point1, Point2, CalculationType> >
+template <typename RadiusType, typename CalculationType>
+struct get_comparable<comparable::haversine<RadiusType, CalculationType> >
{
private :
- typedef comparable::haversine<Point1, Point2, CalculationType> this_type;
+ typedef comparable::haversine<RadiusType, CalculationType> this_type;
public :
static inline this_type apply(this_type const& input)
{
@@ -290,12 +261,12 @@ public :
};
-template <typename Point1, typename Point2, typename CalculationType>
-struct result_from_distance<comparable::haversine<Point1, Point2, CalculationType> >
+template <typename RadiusType, typename CalculationType, typename P1, typename P2>
+struct result_from_distance<comparable::haversine<RadiusType, CalculationType>, P1, P2>
{
private :
- typedef comparable::haversine<Point1, Point2, CalculationType> strategy_type;
- typedef typename return_type<strategy_type>::type return_type;
+ typedef comparable::haversine<RadiusType, CalculationType> strategy_type;
+ typedef typename return_type<strategy_type, P1, P2>::type return_type;
public :
template <typename T>
static inline return_type apply(strategy_type const& strategy, T const& distance)
@@ -306,12 +277,16 @@ public :
};
-// Register it as the default for point-types
+// Register it as the default for point-types
// in a spherical equatorial coordinate system
template <typename Point1, typename Point2>
-struct default_strategy<point_tag, Point1, Point2, spherical_equatorial_tag, spherical_equatorial_tag>
+struct default_strategy
+ <
+ point_tag, point_tag, Point1, Point2,
+ spherical_equatorial_tag, spherical_equatorial_tag
+ >
{
- typedef strategy::distance::haversine<Point1, Point2> type;
+ typedef strategy::distance::haversine<typename select_coordinate_type<Point1, Point2>::type> type;
};
// Note: spherical polar coordinate system requires "get_as_radian_equatorial"
diff --git a/boost/geometry/strategies/spherical/side_by_cross_track.hpp b/boost/geometry/strategies/spherical/side_by_cross_track.hpp
index b7cf279d5b..c4c5f24eeb 100644
--- a/boost/geometry/strategies/spherical/side_by_cross_track.hpp
+++ b/boost/geometry/strategies/spherical/side_by_cross_track.hpp
@@ -11,11 +11,14 @@
#include <boost/mpl/if.hpp>
#include <boost/type_traits.hpp>
+#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/algorithms/detail/course.hpp>
+
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/math.hpp>
@@ -30,29 +33,6 @@ namespace boost { namespace geometry
namespace strategy { namespace side
{
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail
-{
-
-/// Calculate course (bearing) between two points. Might be moved to a "course formula" ...
-template <typename Point>
-static inline double course(Point const& p1, Point const& p2)
-{
- // http://williams.best.vwh.net/avform.htm#Crs
- double dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1);
- double cos_p2lat = cos(get_as_radian<1>(p2));
-
- // "An alternative formula, not requiring the pre-computation of d"
- return atan2(sin(dlon) * cos_p2lat,
- cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2))
- - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon));
-}
-
-}
-#endif // DOXYGEN_NO_DETAIL
-
-
-
/*!
\brief Check at which side of a Great Circle segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0)
@@ -82,9 +62,11 @@ public :
CalculationType
>::type coordinate_type;
+ boost::ignore_unused<coordinate_type>();
+
double d1 = 0.001; // m_strategy.apply(sp1, p);
- double crs_AD = detail::course(p1, p);
- double crs_AB = detail::course(p1, p2);
+ double crs_AD = geometry::detail::course<double>(p1, p);
+ double crs_AB = geometry::detail::course<double>(p1, p2);
double XTD = asin(sin(d1) * sin(crs_AD - crs_AB));
return math::equals(XTD, 0) ? 0 : XTD < 0 ? 1 : -1;
diff --git a/boost/geometry/strategies/spherical/ssf.hpp b/boost/geometry/strategies/spherical/ssf.hpp
index ab7c67559a..41562950fd 100644
--- a/boost/geometry/strategies/spherical/ssf.hpp
+++ b/boost/geometry/strategies/spherical/ssf.hpp
@@ -88,13 +88,13 @@ public :
// (Third point is converted directly)
ct const cos_delta = cos(delta);
-
+
// Apply the "Spherical Side Formula" as presented on my blog
- ct const dist
- = (c1y * c2z - c1z * c2y) * cos_delta * cos(lambda)
+ ct const dist
+ = (c1y * c2z - c1z * c2y) * cos_delta * cos(lambda)
+ (c1z * c2x - c1x * c2z) * cos_delta * sin(lambda)
+ (c1x * c2y - c1y * c2x) * sin(delta);
-
+
ct zero = ct();
return dist > zero ? 1
: dist < zero ? -1
diff --git a/boost/geometry/strategies/strategies.hpp b/boost/geometry/strategies/strategies.hpp
index 3aa9ab00f5..afc5d7046f 100644
--- a/boost/geometry/strategies/strategies.hpp
+++ b/boost/geometry/strategies/strategies.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,6 +14,8 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP
#define BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP
@@ -18,6 +23,7 @@
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/strategies/area.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
@@ -29,10 +35,22 @@
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_end_flat.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_end_round.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_join_miter.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_join_round.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_point_circle.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_point_square.hpp>
+#include <boost/geometry/strategies/cartesian/buffer_side_straight.hpp>
+#include <boost/geometry/strategies/cartesian/centroid_average.hpp>
#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
#include <boost/geometry/strategies/cartesian/centroid_weighted_length.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
+#include <boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp>
+#include <boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp>
#include <boost/geometry/strategies/cartesian/distance_projected_point.hpp>
+#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp>
@@ -41,14 +59,20 @@
#include <boost/geometry/strategies/spherical/area_huiller.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
+#include <boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp>
#include <boost/geometry/strategies/spherical/compare_circular.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
+#include <boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp>
+#include <boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp>
#include <boost/geometry/strategies/agnostic/hull_graham_andrew.hpp>
#include <boost/geometry/strategies/agnostic/point_in_box_by_side.hpp>
+#include <boost/geometry/strategies/agnostic/point_in_point.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
+#include <boost/geometry/strategies/agnostic/relate.hpp>
+
#include <boost/geometry/strategies/strategy_transform.hpp>
#include <boost/geometry/strategies/transform/matrix_transformers.hpp>
diff --git a/boost/geometry/strategies/strategy_transform.hpp b/boost/geometry/strategies/strategy_transform.hpp
index 61a408c617..9d3b1d910c 100644
--- a/boost/geometry/strategies/strategy_transform.hpp
+++ b/boost/geometry/strategies/strategy_transform.hpp
@@ -165,7 +165,7 @@ namespace detail
// http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
// https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
// http://en.citizendium.org/wiki/Spherical_polar_coordinates
-
+
// Phi = first, theta is second, r is third, see documentation on cs::spherical
// (calculations are splitted to implement ttmath)
@@ -179,7 +179,7 @@ namespace detail
set<1>(p, r_sin_theta * sin(phi));
set<2>(p, r_cos_theta);
}
-
+
/// Helper function for conversion, lambda/delta (lon lat) are in radians
template <typename P, typename T, typename R>
inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
@@ -188,7 +188,7 @@ namespace detail
// http://mathworld.wolfram.com/GreatCircle.html
// http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
-
+
T r_cos_delta = r;
T r_sin_delta = r;
r_cos_delta *= cos(delta);
@@ -198,7 +198,7 @@ namespace detail
set<1>(p, r_cos_delta * sin(lambda));
set<2>(p, r_sin_delta);
}
-
+
/// Helper function for conversion
template <typename P, typename T>
@@ -224,7 +224,7 @@ namespace detail
set_from_radian<1>(p, acos(z));
return true;
}
-
+
template <typename P, typename T>
inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
{
@@ -234,7 +234,7 @@ namespace detail
set_from_radian<1>(p, asin(z));
return true;
}
-
+
template <typename P, typename T>
inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
@@ -242,7 +242,7 @@ namespace detail
assert_dimension<P, 3>();
// http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
- T const r = sqrt(x * x + y * y + z * z);
+ T const r = math::sqrt(x * x + y * y + z * z);
set<2>(p, r);
set_from_radian<0>(p, atan2(y, x));
if (r > 0.0)
@@ -253,22 +253,22 @@ namespace detail
return false;
}
- template <typename P, typename T>
- inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
- {
- assert_dimension<P, 3>();
-
- // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
- T const r = sqrt(x * x + y * y + z * z);
- set<2>(p, r);
- set_from_radian<0>(p, atan2(y, x));
- if (r > 0.0)
- {
- set_from_radian<1>(p, asin(z / r));
- return true;
- }
- return false;
- }
+ template <typename P, typename T>
+ inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
+ {
+ assert_dimension<P, 3>();
+
+ // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
+ T const r = math::sqrt(x * x + y * y + z * z);
+ set<2>(p, r);
+ set_from_radian<0>(p, atan2(y, x));
+ if (r > 0.0)
+ {
+ set_from_radian<1>(p, asin(z / r));
+ return true;
+ }
+ return false;
+ }
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
@@ -383,11 +383,11 @@ struct from_cartesian_3_to_spherical_polar_3
template <typename P1, typename P2>
struct from_cartesian_3_to_spherical_equatorial_3
{
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
- }
+ inline bool apply(P1 const& p1, P2& p2) const
+ {
+ assert_dimension<P1, 3>();
+ return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
+ }
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
@@ -486,7 +486,7 @@ struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
{
- typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
+ typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
};
diff --git a/boost/geometry/strategies/tags.hpp b/boost/geometry/strategies/tags.hpp
index 39f2f23036..7589c21071 100644
--- a/boost/geometry/strategies/tags.hpp
+++ b/boost/geometry/strategies/tags.hpp
@@ -34,6 +34,8 @@ namespace strategy
struct strategy_tag_distance_point_point {};
struct strategy_tag_distance_point_segment {};
+struct strategy_tag_distance_point_box {};
+struct strategy_tag_distance_box_box {};
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/transform/inverse_transformer.hpp b/boost/geometry/strategies/transform/inverse_transformer.hpp
index 845a71ded3..685cf874b8 100644
--- a/boost/geometry/strategies/transform/inverse_transformer.hpp
+++ b/boost/geometry/strategies/transform/inverse_transformer.hpp
@@ -31,22 +31,23 @@ namespace strategy { namespace transform
{
/*!
-\brief Transformation strategy to do an inverse ransformation in Cartesian system
+\brief Transformation strategy to do an inverse transformation in a Cartesian coordinate system
\ingroup strategies
-\tparam P1 first point type
-\tparam P2 second point type
*/
-template <typename P1, typename P2>
+template
+<
+ typename CalculationType,
+ std::size_t Dimension1,
+ std::size_t Dimension2
+>
class inverse_transformer
- : public ublas_transformer<P1, P2, dimension<P1>::type::value, dimension<P2>::type::value>
+ : public ublas_transformer<CalculationType, Dimension1, Dimension2>
{
- typedef typename select_coordinate_type<P1, P2>::type T;
-
public :
template <typename Transformer>
inline inverse_transformer(Transformer const& input)
{
- typedef boost::numeric::ublas::matrix<T> matrix_type;
+ typedef boost::numeric::ublas::matrix<CalculationType> matrix_type;
// create a working copy of the input
matrix_type copy(input.matrix());
@@ -60,7 +61,7 @@ public :
if( res == 0 )
{
// create identity matrix
- this->m_matrix.assign(boost::numeric::ublas::identity_matrix<T>(copy.size1()));
+ this->m_matrix.assign(boost::numeric::ublas::identity_matrix<CalculationType>(copy.size1()));
// backsubstitute to get the inverse
boost::numeric::ublas::lu_substitute(copy, pm, this->m_matrix);
diff --git a/boost/geometry/strategies/transform/map_transformer.hpp b/boost/geometry/strategies/transform/map_transformer.hpp
index 150ff1de9b..1109e814b9 100644
--- a/boost/geometry/strategies/transform/map_transformer.hpp
+++ b/boost/geometry/strategies/transform/map_transformer.hpp
@@ -19,33 +19,36 @@
#include <boost/geometry/strategies/transform/matrix_transformers.hpp>
-
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
namespace strategy { namespace transform
{
/*!
-\brief Transformation strategy to do map from one to another Cartesian system
+\brief Transformation strategy to map from one to another Cartesian coordinate system
\ingroup strategies
-\tparam P1 first point type
-\tparam P2 second point type
\tparam Mirror if true map is mirrored upside-down (in most cases pixels
are from top to bottom, while map is from bottom to top)
*/
template
<
- typename P1, typename P2,
- bool Mirror = false, bool SameScale = true,
- std::size_t Dimension1 = dimension<P1>::type::value,
- std::size_t Dimension2 = dimension<P2>::type::value
+ typename CalculationType,
+ std::size_t Dimension1,
+ std::size_t Dimension2,
+ bool Mirror = false,
+ bool SameScale = true
>
class map_transformer
- : public ublas_transformer<P1, P2, Dimension1, Dimension2>
+ : public ublas_transformer<CalculationType, Dimension1, Dimension2>
{
- typedef typename select_coordinate_type<P1, P2>::type T;
- typedef boost::numeric::ublas::matrix<T> M;
+ typedef boost::numeric::ublas::matrix<CalculationType> M;
public :
template <typename B, typename D>
@@ -158,6 +161,9 @@ private :
}} // namespace strategy::transform
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/transform/matrix_transformers.hpp b/boost/geometry/strategies/transform/matrix_transformers.hpp
index 68da240934..27a3a2ae80 100644
--- a/boost/geometry/strategies/transform/matrix_transformers.hpp
+++ b/boost/geometry/strategies/transform/matrix_transformers.hpp
@@ -22,9 +22,20 @@
#define BOOST_UBLAS_TYPE_CHECK 0
#include <boost/numeric/conversion/cast.hpp>
+
+#if defined(__clang__)
+// Avoid warning about unused UBLAS function: boost_numeric_ublas_abs
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/cs.hpp>
@@ -46,14 +57,12 @@ namespace strategy { namespace transform
\see http://en.wikipedia.org/wiki/Affine_transformation
and http://www.devmaster.net/wiki/Transformation_matrices
\ingroup strategies
-\tparam P1 first point type (source)
-\tparam P2 second point type (target)
-\tparam Dimension1 number of dimensions to transform from first point
-\tparam Dimension1 number of dimensions to transform to second point
+\tparam Dimension1 number of dimensions to transform from
+\tparam Dimension2 number of dimensions to transform to
*/
template
<
- typename P1, typename P2,
+ typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
@@ -62,13 +71,12 @@ class ublas_transformer
};
-template <typename P1, typename P2>
-class ublas_transformer<P1, P2, 2, 2>
+template <typename CalculationType>
+class ublas_transformer<CalculationType, 2, 2>
{
protected :
- typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
- typedef coordinate_type ct; // Abbreviation
- typedef boost::numeric::ublas::matrix<coordinate_type> matrix_type;
+ typedef CalculationType ct;
+ typedef boost::numeric::ublas::matrix<ct> matrix_type;
matrix_type m_matrix;
public :
@@ -91,17 +99,17 @@ public :
inline ublas_transformer() : m_matrix(3, 3) {}
+ template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension_greater_equal<P1, 2>();
assert_dimension_greater_equal<P2, 2>();
- coordinate_type const& c1 = get<0>(p1);
- coordinate_type const& c2 = get<1>(p1);
+ ct const& c1 = get<0>(p1);
+ ct const& c2 = get<1>(p1);
-
- coordinate_type p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2);
- coordinate_type p2y = c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + m_matrix(1,2);
+ ct p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2);
+ ct p2y = c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + m_matrix(1,2);
typedef typename geometry::coordinate_type<P2>::type ct2;
set<0>(p2, boost::numeric_cast<ct2>(p2x));
@@ -115,38 +123,37 @@ public :
// It IS possible to go from 3 to 2 coordinates
-template <typename P1, typename P2>
-class ublas_transformer<P1, P2, 3, 2> : public ublas_transformer<P1, P2, 2, 2>
+template <typename CalculationType>
+class ublas_transformer<CalculationType, 3, 2> : public ublas_transformer<CalculationType, 2, 2>
{
- typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
- typedef coordinate_type ct; // Abbreviation
+ typedef CalculationType ct;
public :
inline ublas_transformer(
ct const& m_0_0, ct const& m_0_1, ct const& m_0_2,
ct const& m_1_0, ct const& m_1_1, ct const& m_1_2,
ct const& m_2_0, ct const& m_2_1, ct const& m_2_2)
- : ublas_transformer<P1, P2, 2, 2>(
+ : ublas_transformer<CalculationType, 2, 2>(
m_0_0, m_0_1, m_0_2,
m_1_0, m_1_1, m_1_2,
m_2_0, m_2_1, m_2_2)
{}
inline ublas_transformer()
- : ublas_transformer<P1, P2, 2, 2>()
+ : ublas_transformer<CalculationType, 2, 2>()
{}
};
-template <typename P1, typename P2>
-class ublas_transformer<P1, P2, 3, 3>
+template <typename CalculationType>
+class ublas_transformer<CalculationType, 3, 3>
{
protected :
- typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
- typedef coordinate_type ct; // Abbreviation
- typedef boost::numeric::ublas::matrix<coordinate_type> matrix_type;
+ typedef CalculationType ct;
+ typedef boost::numeric::ublas::matrix<ct> matrix_type;
matrix_type m_matrix;
+public :
inline ublas_transformer(
ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_0_3,
ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_1_3,
@@ -163,13 +170,12 @@ protected :
inline ublas_transformer() : m_matrix(4, 4) {}
-public :
-
+ template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2& p2) const
{
- coordinate_type const& c1 = get<0>(p1);
- coordinate_type const& c2 = get<1>(p1);
- coordinate_type const& c3 = get<2>(p1);
+ ct const& c1 = get<0>(p1);
+ ct const& c2 = get<1>(p1);
+ ct const& c3 = get<2>(p1);
typedef typename geometry::coordinate_type<P2>::type ct2;
@@ -192,34 +198,30 @@ public :
\details Translate moves a geometry a fixed distance in 2 or 3 dimensions.
\see http://en.wikipedia.org/wiki/Translation_%28geometry%29
\ingroup strategies
-\tparam P1 first point type
-\tparam P2 second point type
-\tparam Dimension1 number of dimensions to transform from first point
-\tparam Dimension1 number of dimensions to transform to second point
+\tparam Dimension1 number of dimensions to transform from
+\tparam Dimension2 number of dimensions to transform to
*/
template
<
- typename P1, typename P2,
- std::size_t Dimension1 = geometry::dimension<P1>::type::value,
- std::size_t Dimension2 = geometry::dimension<P2>::type::value
+ typename CalculationType,
+ std::size_t Dimension1,
+ std::size_t Dimension2
>
class translate_transformer
{
};
-template <typename P1, typename P2>
-class translate_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2>
+template<typename CalculationType>
+class translate_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 2, 2>
{
- typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
-
public :
// To have translate transformers compatible for 2/3 dimensions, the
// constructor takes an optional third argument doing nothing.
- inline translate_transformer(coordinate_type const& translate_x,
- coordinate_type const& translate_y,
- coordinate_type const& = 0)
- : ublas_transformer<P1, P2, 2, 2>(
+ inline translate_transformer(CalculationType const& translate_x,
+ CalculationType const& translate_y,
+ CalculationType const& = 0)
+ : ublas_transformer<CalculationType, 2, 2>(
1, 0, translate_x,
0, 1, translate_y,
0, 0, 1)
@@ -227,16 +229,14 @@ public :
};
-template <typename P1, typename P2>
-class translate_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3>
+template <typename CalculationType>
+class translate_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 3, 3>
{
- typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
-
public :
- inline translate_transformer(coordinate_type const& translate_x,
- coordinate_type const& translate_y,
- coordinate_type const& translate_z)
- : ublas_transformer<P1, P2, 3, 3>(
+ inline translate_transformer(CalculationType const& translate_x,
+ CalculationType const& translate_y,
+ CalculationType const& translate_z)
+ : ublas_transformer<CalculationType, 3, 3>(
1, 0, 0, translate_x,
0, 1, 0, translate_y,
0, 0, 1, translate_z,
@@ -251,40 +251,37 @@ public :
\details Scale scales a geometry up or down in all its dimensions.
\see http://en.wikipedia.org/wiki/Scaling_%28geometry%29
\ingroup strategies
-\tparam P1 first point type
-\tparam P2 second point type
-\tparam Dimension1 number of dimensions to transform from first point
-\tparam Dimension1 number of dimensions to transform to second point
+\tparam Dimension1 number of dimensions to transform from
+\tparam Dimension2 number of dimensions to transform to
*/
template
<
- typename P1, typename P2 = P1,
- std::size_t Dimension1 = geometry::dimension<P1>::type::value,
- std::size_t Dimension2 = geometry::dimension<P2>::type::value
+ typename CalculationType,
+ std::size_t Dimension1,
+ std::size_t Dimension2
>
class scale_transformer
{
};
-template <typename P1, typename P2>
-class scale_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2>
+template <typename CalculationType>
+class scale_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 2, 2>
{
- typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
public :
- inline scale_transformer(coordinate_type const& scale_x,
- coordinate_type const& scale_y,
- coordinate_type const& = 0)
- : ublas_transformer<P1, P2, 2, 2>(
+ inline scale_transformer(CalculationType const& scale_x,
+ CalculationType const& scale_y,
+ CalculationType const& = 0)
+ : ublas_transformer<CalculationType, 2, 2>(
scale_x, 0, 0,
0, scale_y, 0,
0, 0, 1)
{}
- inline scale_transformer(coordinate_type const& scale)
- : ublas_transformer<P1, P2, 2, 2>(
+ inline scale_transformer(CalculationType const& scale)
+ : ublas_transformer<CalculationType, 2, 2>(
scale, 0, 0,
0, scale, 0,
0, 0, 1)
@@ -292,15 +289,14 @@ public :
};
-template <typename P1, typename P2>
-class scale_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3>
+template <typename CalculationType>
+class scale_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 3, 3>
{
- typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
-
- inline scale_transformer(coordinate_type const& scale_x,
- coordinate_type const& scale_y,
- coordinate_type const& scale_z)
- : ublas_transformer<P1, P2, 3, 3>(
+public :
+ inline scale_transformer(CalculationType const& scale_x,
+ CalculationType const& scale_y,
+ CalculationType const& scale_z)
+ : ublas_transformer<CalculationType, 3, 3>(
scale_x, 0, 0, 0,
0, scale_y, 0, 0,
0, 0, scale_z, 0,
@@ -308,8 +304,8 @@ class scale_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3>
{}
- inline scale_transformer(coordinate_type const& scale)
- : ublas_transformer<P1, P2, 3, 3>(
+ inline scale_transformer(CalculationType const& scale)
+ : ublas_transformer<CalculationType, 3, 3>(
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, scale, 0,
@@ -352,23 +348,16 @@ struct as_radian<degree>
template
<
- typename P1, typename P2,
- std::size_t Dimension1 = geometry::dimension<P1>::type::value,
- std::size_t Dimension2 = geometry::dimension<P2>::type::value
+ typename CalculationType,
+ std::size_t Dimension1,
+ std::size_t Dimension2
>
class rad_rotate_transformer
- : public ublas_transformer<P1, P2, Dimension1, Dimension2>
+ : public ublas_transformer<CalculationType, Dimension1, Dimension2>
{
- // Angle has type of coordinate type, but at least a double
- typedef typename select_most_precise
- <
- typename select_coordinate_type<P1, P2>::type,
- double
- >::type angle_type;
-
public :
- inline rad_rotate_transformer(angle_type const& angle)
- : ublas_transformer<P1, P2, Dimension1, Dimension2>(
+ inline rad_rotate_transformer(CalculationType const& angle)
+ : ublas_transformer<CalculationType, Dimension1, Dimension2>(
cos(angle), sin(angle), 0,
-sin(angle), cos(angle), 0,
0, 0, 1)
@@ -381,33 +370,31 @@ public :
/*!
-\brief Strategy of rotate transformation in Cartesian system.
+\brief Strategy for rotate transformation in Cartesian coordinate system.
\details Rotate rotates a geometry of specified angle about a fixed point (e.g. origin).
\see http://en.wikipedia.org/wiki/Rotation_%28mathematics%29
\ingroup strategies
-\tparam P1 first point type
-\tparam P2 second point type
\tparam DegreeOrRadian degree/or/radian, type of rotation angle specification
\note A single angle is needed to specify a rotation in 2D.
Not yet in 3D, the 3D version requires special things to allow
for rotation around X, Y, Z or arbitrary axis.
\todo The 3D version will not compile.
*/
-template <typename P1, typename P2, typename DegreeOrRadian>
-class rotate_transformer : public detail::rad_rotate_transformer<P1, P2>
+template
+<
+ typename DegreeOrRadian,
+ typename CalculationType,
+ std::size_t Dimension1,
+ std::size_t Dimension2
+>
+class rotate_transformer : public detail::rad_rotate_transformer<CalculationType, Dimension1, Dimension2>
{
- // Angle has type of coordinate type, but at least a double
- typedef typename select_most_precise
- <
- typename select_coordinate_type<P1, P2>::type,
- double
- >::type angle_type;
public :
- inline rotate_transformer(angle_type const& angle)
+ inline rotate_transformer(CalculationType const& angle)
: detail::rad_rotate_transformer
<
- P1, P2
+ CalculationType, Dimension1, Dimension2
>(detail::as_radian<DegreeOrRadian>::get(angle))
{}
};
diff --git a/boost/geometry/strategies/within.hpp b/boost/geometry/strategies/within.hpp
index 0852a22d2d..d625bc40e6 100644
--- a/boost/geometry/strategies/within.hpp
+++ b/boost/geometry/strategies/within.hpp
@@ -52,7 +52,7 @@ struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
- false, NOT_IMPLEMENTED_FOR_THIS_TYPES
+ false, NOT_IMPLEMENTED_FOR_THESE_TYPES
, (types<GeometryContained, GeometryContaining>)
);
};
diff --git a/boost/geometry/util/bare_type.hpp b/boost/geometry/util/bare_type.hpp
index 1b49de6436..26dd94a8ae 100644
--- a/boost/geometry/util/bare_type.hpp
+++ b/boost/geometry/util/bare_type.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2012 Bruno Lalande, Paris, France.
// Copyright (c) 2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -11,7 +16,10 @@
#ifndef BOOST_GEOMETRY_UTIL_BARE_TYPE_HPP
#define BOOST_GEOMETRY_UTIL_BARE_TYPE_HPP
-#include <boost/type_traits.hpp>
+
+#include <boost/type_traits/remove_const.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
+#include <boost/type_traits/remove_reference.hpp>
namespace boost { namespace geometry
@@ -25,7 +33,13 @@ struct bare_type
{
typedef typename boost::remove_const
<
- typename boost::remove_pointer<T>::type
+ typename boost::remove_pointer
+ <
+ typename boost::remove_reference
+ <
+ T
+ >::type
+ >::type
>::type type;
};
diff --git a/boost/geometry/util/calculation_type.hpp b/boost/geometry/util/calculation_type.hpp
index aef58909e7..2ac0de87d9 100644
--- a/boost/geometry/util/calculation_type.hpp
+++ b/boost/geometry/util/calculation_type.hpp
@@ -34,7 +34,7 @@ struct default_integral
typedef boost::long_long_type type;
#else
typedef int type;
-#endif
+#endif
};
/*!
@@ -65,7 +65,7 @@ struct calculation_type
DefaultIntegralCalculationType
>::type::value
));
-
+
typedef typename boost::mpl::if_
<
@@ -153,12 +153,12 @@ struct ternary
<
typename select_most_precise
<
- typename coordinate_type<Geometry1>::type,
+ typename coordinate_type<Geometry1>::type,
typename select_coordinate_type
<
Geometry2,
Geometry3
- >::type
+ >::type
>::type,
CalculationType,
DefaultFloatingPointCalculationType,
diff --git a/boost/geometry/util/combine_if.hpp b/boost/geometry/util/combine_if.hpp
new file mode 100644
index 0000000000..6d8d932a1c
--- /dev/null
+++ b/boost/geometry/util/combine_if.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_UTIL_COMBINE_IF_HPP
+#define BOOST_GEOMETRY_UTIL_COMBINE_IF_HPP
+
+#include <boost/mpl/fold.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/bind.hpp>
+#include <boost/mpl/set.hpp>
+#include <boost/mpl/insert.hpp>
+#include <boost/mpl/placeholders.hpp>
+
+#include <boost/type_traits.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace util
+{
+
+
+/*!
+ \brief Meta-function to generate all the combination of pairs of types
+ from a given sequence Sequence except those that does not satisfy the
+ predicate Pred
+ \ingroup utility
+ \par Example
+ \code
+ typedef mpl::vector<mpl::int_<0>, mpl::int_<1> > types;
+ typedef combine_if<types, types, always<true_> >::type combinations;
+ typedef mpl::vector<
+ pair<mpl::int_<1>, mpl::int_<1> >,
+ pair<mpl::int_<1>, mpl::int_<0> >,
+ pair<mpl::int_<0>, mpl::int_<1> >,
+ pair<mpl::int_<0>, mpl::int_<0> >
+ > result_types;
+
+ BOOST_MPL_ASSERT(( mpl::equal<combinations, result_types> ));
+ \endcode
+*/
+template <typename Sequence1, typename Sequence2, typename Pred>
+struct combine_if
+{
+ struct combine
+ {
+ template <typename Result, typename T>
+ struct apply
+ {
+ typedef typename mpl::fold<Sequence2, Result,
+ mpl::if_
+ <
+ mpl::bind<typename mpl::lambda<Pred>::type, T, mpl::_2>,
+ mpl::insert<mpl::_1, mpl::pair<T, mpl::_2> >,
+ mpl::_1
+ >
+ >::type type;
+ };
+ };
+
+ typedef typename mpl::fold<Sequence1, mpl::set0<>, combine>::type type;
+};
+
+
+} // namespace util
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_UTIL_COMBINE_IF_HPP
diff --git a/boost/geometry/util/compress_variant.hpp b/boost/geometry/util/compress_variant.hpp
new file mode 100644
index 0000000000..a94cf28894
--- /dev/null
+++ b/boost/geometry/util/compress_variant.hpp
@@ -0,0 +1,98 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_UTIL_COMPRESS_VARIANT_HPP
+#define BOOST_GEOMETRY_UTIL_COMPRESS_VARIANT_HPP
+
+
+#include <boost/mpl/equal_to.hpp>
+#include <boost/mpl/fold.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/insert.hpp>
+#include <boost/mpl/int.hpp>
+#include <boost/mpl/set.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace detail
+{
+
+template <typename Variant>
+struct unique_types:
+ mpl::fold<
+ typename mpl::reverse_fold<
+ typename Variant::types,
+ mpl::set<>,
+ mpl::insert<
+ mpl::placeholders::_1,
+ mpl::placeholders::_2
+ >
+ >::type,
+ mpl::vector<>,
+ mpl::push_back<mpl::placeholders::_1, mpl::placeholders::_2>
+ >
+{};
+
+template <typename Types>
+struct variant_or_single:
+ mpl::if_<
+ mpl::equal_to<
+ mpl::size<Types>,
+ mpl::int_<1>
+ >,
+ typename mpl::front<Types>::type,
+ typename make_variant_over<Types>::type
+ >
+{};
+
+} // namespace detail
+
+
+/*!
+ \brief Meta-function that takes a boost::variant type and tries to minimize
+ it by doing the following:
+ - if there's any duplicate types, remove them
+ - if the result is a variant of one type, turn it into just that type
+ \ingroup utility
+ \par Example
+ \code
+ typedef variant<int, float, int, long> variant_type;
+ typedef compress_variant<variant_type>::type compressed;
+ typedef mpl::vector<int, float, long> result_types;
+ BOOST_MPL_ASSERT(( mpl::equal<compressed::types, result_types> ));
+
+ typedef variant<int, int, int> one_type_variant_type;
+ typedef compress_variant<one_type_variant_type>::type single_type;
+ BOOST_MPL_ASSERT(( boost::equals<single_type, int> ));
+ \endcode
+*/
+
+template <typename Variant>
+struct compress_variant:
+ detail::variant_or_single<
+ typename detail::unique_types<Variant>::type
+ >
+{};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_UTIL_COMPRESS_VARIANT_HPP
diff --git a/boost/geometry/util/math.hpp b/boost/geometry/util/math.hpp
index 95cbdf2ce4..22c02168ad 100644
--- a/boost/geometry/util/math.hpp
+++ b/boost/geometry/util/math.hpp
@@ -1,8 +1,14 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,6 +24,9 @@
#include <limits>
#include <boost/math/constants/constants.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/type_traits/is_fundamental.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
@@ -44,17 +53,17 @@ struct equals
template <typename Type>
struct equals<Type, true>
{
- static inline Type get_max(Type const& a, Type const& b, Type const& c)
- {
- return (std::max)((std::max)(a, b), c);
- }
+ static inline Type get_max(Type const& a, Type const& b, Type const& c)
+ {
+ return (std::max)((std::max)(a, b), c);
+ }
static inline bool apply(Type const& a, Type const& b)
{
- if (a == b)
- {
- return true;
- }
+ if (a == b)
+ {
+ return true;
+ }
// See http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17,
// FUTURE: replace by some boost tool or boost::test::close_at_tolerance
@@ -76,18 +85,81 @@ struct smaller<Type, true>
{
static inline bool apply(Type const& a, Type const& b)
{
- if (equals<Type, true>::apply(a, b))
- {
- return false;
- }
- return a < b;
+ if (equals<Type, true>::apply(a, b))
+ {
+ return false;
+ }
+ return a < b;
}
};
-template <typename Type, bool IsFloatingPoint>
+template <typename Type, bool IsFloatingPoint>
struct equals_with_epsilon : public equals<Type, IsFloatingPoint> {};
+template
+<
+ typename T,
+ bool IsFundemantal = boost::is_fundamental<T>::value /* false */
+>
+struct square_root
+{
+ typedef T return_type;
+
+ static inline T apply(T const& value)
+ {
+ // for non-fundamental number types assume that sqrt is
+ // defined either:
+ // 1) at T's scope, or
+ // 2) at global scope, or
+ // 3) in namespace std
+ using ::sqrt;
+ using std::sqrt;
+
+ return sqrt(value);
+ }
+};
+
+template <>
+struct square_root<float, true>
+{
+ typedef float return_type;
+
+ static inline float apply(float const& value)
+ {
+ // for float use std::sqrt
+ return std::sqrt(value);
+ }
+};
+
+template <>
+struct square_root<long double, true>
+{
+ typedef long double return_type;
+
+ static inline long double apply(long double const& value)
+ {
+ // for long double use std::sqrt
+ return std::sqrt(value);
+ }
+};
+
+template <typename T>
+struct square_root<T, true>
+{
+ typedef double return_type;
+
+ static inline double apply(T const& value)
+ {
+ // for all other fundamental number types use also std::sqrt
+ //
+ // Note: in C++98 the only other possibility is double;
+ // in C++11 there are also overloads for integral types;
+ // this specialization works for those as well.
+ return std::sqrt(boost::numeric_cast<double>(value));
+ }
+};
+
/*!
\brief Short construct to enable partial specialization for PI, currently not possible in Math.
@@ -102,6 +174,39 @@ struct define_pi
}
};
+template <typename T>
+struct relaxed_epsilon
+{
+ static inline T apply(const T& factor)
+ {
+ return factor * std::numeric_limits<T>::epsilon();
+ }
+};
+
+// ItoF ItoI FtoF
+template <typename Result, typename Source,
+ bool ResultIsInteger = std::numeric_limits<Result>::is_integer,
+ bool SourceIsInteger = std::numeric_limits<Source>::is_integer>
+struct round
+{
+ static inline Result apply(Source const& v)
+ {
+ return boost::numeric_cast<Result>(v);
+ }
+};
+
+// FtoI
+template <typename Result, typename Source>
+struct round<Result, Source, true, false>
+{
+ static inline Result apply(Source const& v)
+ {
+ namespace bmp = boost::math::policies;
+ // ignore rounding errors for backward compatibility
+ typedef bmp::policy< bmp::rounding_error<bmp::ignore_error> > policy;
+ return boost::numeric_cast<Result>(boost::math::round(v, policy()));
+ }
+};
} // namespace detail
#endif
@@ -110,6 +215,12 @@ struct define_pi
template <typename T>
inline T pi() { return detail::define_pi<T>::apply(); }
+template <typename T>
+inline T relaxed_epsilon(T const& factor)
+{
+ return detail::relaxed_epsilon<T>::apply(factor);
+}
+
// Maybe replace this by boost equals or boost ublas numeric equals or so
@@ -143,7 +254,7 @@ inline bool equals_with_epsilon(T1 const& a, T2 const& b)
typedef typename select_most_precise<T1, T2>::type select_type;
return detail::equals_with_epsilon
<
- select_type,
+ select_type,
boost::is_floating_point<select_type>::type::value
>::apply(a, b);
}
@@ -201,18 +312,58 @@ inline T sqr(T const& value)
return value * value;
}
+/*!
+\brief Short utility to return the square root
+\ingroup utility
+\param value Value to calculate the square root from
+\return The square root value
+*/
+template <typename T>
+inline typename detail::square_root<T>::return_type
+sqrt(T const& value)
+{
+ return detail::square_root
+ <
+ T, boost::is_fundamental<T>::value
+ >::apply(value);
+}
/*!
\brief Short utility to workaround gcc/clang problem that abs is converting to integer
+ and that older versions of MSVC does not support abs of long long...
\ingroup utility
*/
template<typename T>
-inline T abs(const T& t)
+inline T abs(T const& value)
{
- using std::abs;
- return abs(t);
+ T const zero = T();
+ return value < zero ? -value : value;
}
+/*!
+\brief Short utility to calculate the sign of a number: -1 (negative), 0 (zero), 1 (positive)
+\ingroup utility
+*/
+template <typename T>
+static inline int sign(T const& value)
+{
+ T const zero = T();
+ return value > zero ? 1 : value < zero ? -1 : 0;
+}
+
+/*!
+\brief Short utility to calculate the rounded value of a number.
+\ingroup utility
+\note If the source T is NOT an integral type and Result is an integral type
+ the value is rounded towards the closest integral value. Otherwise it's
+ just casted.
+*/
+template <typename Result, typename T>
+inline Result round(T const& v)
+{
+ // NOTE: boost::round() could be used instead but it throws in some situations
+ return detail::round<Result, T>::apply(v);
+}
} // namespace math
diff --git a/boost/geometry/util/parameter_type_of.hpp b/boost/geometry/util/parameter_type_of.hpp
index b8872d52bf..3ed09ab9bb 100644
--- a/boost/geometry/util/parameter_type_of.hpp
+++ b/boost/geometry/util/parameter_type_of.hpp
@@ -25,7 +25,7 @@
namespace boost { namespace geometry
-{
+{
/*!
@@ -46,7 +46,7 @@ struct parameter_type_of
boost::mpl::int_<1>,
boost::mpl::int_<0>
>::type base_index_type;
-
+
typedef typename boost::mpl::if_c
<
Index == 0,
diff --git a/boost/geometry/util/range.hpp b/boost/geometry/util/range.hpp
new file mode 100644
index 0000000000..fe3502f978
--- /dev/null
+++ b/boost/geometry/util/range.hpp
@@ -0,0 +1,325 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP
+#define BOOST_GEOMETRY_UTIL_RANGE_HPP
+
+#include <algorithm>
+
+#include <boost/assert.hpp>
+#include <boost/concept_check.hpp>
+#include <boost/config.hpp>
+#include <boost/range/concepts.hpp>
+#include <boost/range/begin.hpp>
+#include <boost/range/end.hpp>
+#include <boost/range/empty.hpp>
+#include <boost/range/size.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+
+#include <boost/geometry/core/mutable_range.hpp>
+
+namespace boost { namespace geometry { namespace range {
+
+// NOTE: For SinglePassRanges at could iterate over all elements until the i-th element is met.
+
+/*!
+\brief Short utility to conveniently return an element of a RandomAccessRange.
+\ingroup utility
+*/
+template <typename RandomAccessRange>
+inline typename boost::range_value<RandomAccessRange const>::type const&
+at(RandomAccessRange const& rng,
+ typename boost::range_size<RandomAccessRange const>::type i)
+{
+ BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<RandomAccessRange const> ));
+ BOOST_ASSERT(i < boost::size(rng));
+ return *(boost::begin(rng) + i);
+}
+
+/*!
+\brief Short utility to conveniently return an element of a RandomAccessRange.
+\ingroup utility
+*/
+template <typename RandomAccessRange>
+inline typename boost::range_value<RandomAccessRange>::type &
+at(RandomAccessRange & rng,
+ typename boost::range_size<RandomAccessRange>::type i)
+{
+ BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<RandomAccessRange> ));
+ BOOST_ASSERT(i < boost::size(rng));
+ return *(boost::begin(rng) + i);
+}
+
+/*!
+\brief Short utility to conveniently return the front element of a Range.
+\ingroup utility
+*/
+template <typename Range>
+inline typename boost::range_value<Range>::type const&
+front(Range const& rng)
+{
+ BOOST_ASSERT(!boost::empty(rng));
+ return *boost::begin(rng);
+}
+
+/*!
+\brief Short utility to conveniently return the front element of a Range.
+\ingroup utility
+*/
+template <typename Range>
+inline typename boost::range_value<Range>::type &
+front(Range & rng)
+{
+ BOOST_ASSERT(!boost::empty(rng));
+ return *boost::begin(rng);
+}
+
+// NOTE: For SinglePassRanges back() could iterate over all elements until the last element is met.
+
+/*!
+\brief Short utility to conveniently return the back element of a BidirectionalRange.
+\ingroup utility
+*/
+template <typename BidirectionalRange>
+inline typename boost::range_value<BidirectionalRange>::type const&
+back(BidirectionalRange const& rng)
+{
+ BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept<BidirectionalRange const> ));
+ BOOST_ASSERT(!boost::empty(rng));
+ return *(--boost::end(rng));
+}
+
+/*!
+\brief Short utility to conveniently return the back element of a BidirectionalRange.
+\ingroup utility
+*/
+template <typename BidirectionalRange>
+inline typename boost::range_value<BidirectionalRange>::type &
+back(BidirectionalRange & rng)
+{
+ BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept<BidirectionalRange> ));
+ BOOST_ASSERT(!boost::empty(rng));
+ return *(--boost::end(rng));
+}
+
+
+/*!
+\brief Short utility to conveniently clear a mutable range.
+ It uses traits::clear<>.
+\ingroup utility
+*/
+template <typename Range>
+inline void clear(Range & rng)
+{
+ // NOTE: this trait is probably not needed since it could be implemented using resize()
+ geometry::traits::clear<Range>::apply(rng);
+}
+
+/*!
+\brief Short utility to conveniently insert a new element at the end of a mutable range.
+ It uses boost::geometry::traits::push_back<>.
+\ingroup utility
+*/
+template <typename Range>
+inline void push_back(Range & rng,
+ typename boost::range_value<Range>::type const& value)
+{
+ geometry::traits::push_back<Range>::apply(rng, value);
+}
+
+/*!
+\brief Short utility to conveniently resize a mutable range.
+ It uses boost::geometry::traits::resize<>.
+\ingroup utility
+*/
+template <typename Range>
+inline void resize(Range & rng,
+ typename boost::range_size<Range>::type new_size)
+{
+ geometry::traits::resize<Range>::apply(rng, new_size);
+}
+
+
+/*!
+\brief Short utility to conveniently remove an element from the back of a mutable range.
+ It uses resize().
+\ingroup utility
+*/
+template <typename Range>
+inline void pop_back(Range & rng)
+{
+ BOOST_ASSERT(!boost::empty(rng));
+ range::resize(rng, boost::size(rng) - 1);
+}
+
+namespace detail {
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+
+template <typename It,
+ typename OutIt,
+ bool UseMove = boost::is_convertible
+ <
+ typename std::iterator_traits<It>::value_type &&,
+ typename std::iterator_traits<OutIt>::value_type
+ >::value>
+struct copy_or_move_impl
+{
+ static inline OutIt apply(It first, It last, OutIt out)
+ {
+ return std::move(first, last, out);
+ }
+};
+
+template <typename It, typename OutIt>
+struct copy_or_move_impl<It, OutIt, false>
+{
+ static inline OutIt apply(It first, It last, OutIt out)
+ {
+ return std::copy(first, last, out);
+ }
+};
+
+template <typename It, typename OutIt>
+inline OutIt copy_or_move(It first, It last, OutIt out)
+{
+ return copy_or_move_impl<It, OutIt>::apply(first, last, out);
+}
+
+#else
+
+template <typename It, typename OutIt>
+inline OutIt copy_or_move(It first, It last, OutIt out)
+{
+ return std::copy(first, last, out);
+}
+
+#endif
+
+} // namespace detail
+
+/*!
+\brief Short utility to conveniently remove an element from a mutable range.
+ It uses std::copy() and resize(). Version taking mutable iterators.
+\ingroup utility
+*/
+template <typename Range>
+inline typename boost::range_iterator<Range>::type
+erase(Range & rng,
+ typename boost::range_iterator<Range>::type it)
+{
+ BOOST_ASSERT(!boost::empty(rng));
+ BOOST_ASSERT(it != boost::end(rng));
+
+ typename boost::range_difference<Range>::type const
+ d = std::distance(boost::begin(rng), it);
+
+ typename boost::range_iterator<Range>::type
+ next = it;
+ ++next;
+
+ detail::copy_or_move(next, boost::end(rng), it);
+ range::resize(rng, boost::size(rng) - 1);
+
+ // NOTE: In general this should be sufficient:
+ // return it;
+ // But in MSVC using the returned iterator causes
+ // assertion failures when iterator debugging is enabled
+ // Furthermore the code below should work in the case if resize()
+ // invalidates iterators when the container is resized down.
+ return boost::begin(rng) + d;
+}
+
+/*!
+\brief Short utility to conveniently remove an element from a mutable range.
+ It uses std::copy() and resize(). Version taking non-mutable iterators.
+\ingroup utility
+*/
+template <typename Range>
+inline typename boost::range_iterator<Range>::type
+erase(Range & rng,
+ typename boost::range_iterator<Range const>::type cit)
+{
+ BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> ));
+
+ typename boost::range_iterator<Range>::type
+ it = boost::begin(rng)
+ + std::distance(boost::const_begin(rng), cit);
+
+ return erase(rng, it);
+}
+
+/*!
+\brief Short utility to conveniently remove a range of elements from a mutable range.
+ It uses std::copy() and resize(). Version taking mutable iterators.
+\ingroup utility
+*/
+template <typename Range>
+inline typename boost::range_iterator<Range>::type
+erase(Range & rng,
+ typename boost::range_iterator<Range>::type first,
+ typename boost::range_iterator<Range>::type last)
+{
+ typename boost::range_difference<Range>::type const
+ diff = std::distance(first, last);
+ BOOST_ASSERT(diff >= 0);
+
+ std::size_t const count = static_cast<std::size_t>(diff);
+ BOOST_ASSERT(count <= boost::size(rng));
+
+ if ( count > 0 )
+ {
+ typename boost::range_difference<Range>::type const
+ d = std::distance(boost::begin(rng), first);
+
+ detail::copy_or_move(last, boost::end(rng), first);
+ range::resize(rng, boost::size(rng) - count);
+
+ // NOTE: In general this should be sufficient:
+ // return first;
+ // But in MSVC using the returned iterator causes
+ // assertion failures when iterator debugging is enabled
+ // Furthermore the code below should work in the case if resize()
+ // invalidates iterators when the container is resized down.
+ return boost::begin(rng) + d;
+ }
+
+ return first;
+}
+
+/*!
+\brief Short utility to conveniently remove a range of elements from a mutable range.
+ It uses std::copy() and resize(). Version taking non-mutable iterators.
+\ingroup utility
+*/
+template <typename Range>
+inline typename boost::range_iterator<Range>::type
+erase(Range & rng,
+ typename boost::range_iterator<Range const>::type cfirst,
+ typename boost::range_iterator<Range const>::type clast)
+{
+ BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept<Range> ));
+
+ typename boost::range_iterator<Range>::type
+ first = boost::begin(rng)
+ + std::distance(boost::const_begin(rng), cfirst);
+ typename boost::range_iterator<Range>::type
+ last = boost::begin(rng)
+ + std::distance(boost::const_begin(rng), clast);
+
+ return erase(rng, first, last);
+}
+
+}}} // namespace boost::geometry::range
+
+#endif // BOOST_GEOMETRY_UTIL_RANGE_HPP
diff --git a/boost/geometry/util/rational.hpp b/boost/geometry/util/rational.hpp
index 45bee20460..805c85eb46 100644
--- a/boost/geometry/util/rational.hpp
+++ b/boost/geometry/util/rational.hpp
@@ -21,11 +21,11 @@
#include <boost/geometry/util/select_most_precise.hpp>
-namespace boost{ namespace geometry
-{
+namespace boost{ namespace geometry
+{
-// Specialize for Boost.Geometry's coordinate cast
+// Specialize for Boost.Geometry's coordinate cast
// (from string to coordinate type)
namespace detail
{
@@ -39,13 +39,13 @@ struct coordinate_cast<rational<T> >
std::string before_part = source.substr(0, p);
std::string const after_part = source.substr(p + 1);
- negate = false;
+ negate = false;
- if (before_part.size() > 0 && before_part[0] == '-')
- {
- negate = true;
- before_part.erase(0, 1);
- }
+ if (before_part.size() > 0 && before_part[0] == '-')
+ {
+ negate = true;
+ before_part.erase(0, 1);
+ }
before = atol(before_part.c_str());
after = atol(after_part.c_str());
len = after_part.length();
@@ -70,10 +70,10 @@ struct coordinate_cast<rational<T> >
}
split_parts(source, p, before, after, negate, len);
- return negate
- ? -rational<T>(before, after)
- : rational<T>(before, after)
- ;
+ return negate
+ ? -rational<T>(before, after)
+ : rational<T>(before, after)
+ ;
}
@@ -85,10 +85,10 @@ struct coordinate_cast<rational<T> >
den *= 10;
}
- return negate
- ? -rational<T>(before) - rational<T>(after, den)
- : rational<T>(before) + rational<T>(after, den)
- ;
+ return negate
+ ? -rational<T>(before) - rational<T>(after, den)
+ : rational<T>(before) + rational<T>(after, den)
+ ;
}
};
@@ -115,19 +115,19 @@ struct select_most_precise<boost::rational<T>, double>
// Specializes boost::rational to boost::numeric::bounds
-namespace boost { namespace numeric
+namespace boost { namespace numeric
{
template<class T>
struct bounds<rational<T> >
{
- static inline rational<T> lowest()
- {
- return rational<T>(bounds<T>::lowest(), 1);
+ static inline rational<T> lowest()
+ {
+ return rational<T>(bounds<T>::lowest(), 1);
}
- static inline rational<T> highest()
- {
- return rational<T>(bounds<T>::highest(), 1);
+ static inline rational<T> highest()
+ {
+ return rational<T>(bounds<T>::highest(), 1);
}
};
diff --git a/boost/geometry/util/transform_variant.hpp b/boost/geometry/util/transform_variant.hpp
new file mode 100644
index 0000000000..9e4a7aa152
--- /dev/null
+++ b/boost/geometry/util/transform_variant.hpp
@@ -0,0 +1,79 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_UTIL_TRANSFORM_VARIANT_HPP
+#define BOOST_GEOMETRY_UTIL_TRANSFORM_VARIANT_HPP
+
+
+#include <boost/mpl/transform.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+/*!
+ \brief Meta-function that takes a Sequence type, an MPL lambda
+ expression and an optional Inserter and returns a variant type over
+ the same types as the initial variant type, each transformed using
+ the lambda expression.
+ \ingroup utility
+ \par Example
+ \code
+ typedef mpl::vector<int, float, long> types;
+ typedef transform_variant<types, add_pointer<_> > transformed;
+ typedef variant<int*, float*, long*> result;
+ BOOST_MPL_ASSERT(( equal<result, transformed> ));
+ \endcode
+*/
+template <typename Sequence, typename Op, typename In = boost::mpl::na>
+struct transform_variant:
+ make_variant_over<
+ typename mpl::transform<
+ Sequence,
+ Op,
+ In
+ >::type
+ >
+{};
+
+
+/*!
+ \brief Meta-function that takes a boost::variant type and an MPL lambda
+ expression and returns a variant type over the same types as the
+ initial variant type, each transformed using the lambda expression.
+ \ingroup utility
+ \par Example
+ \code
+ typedef variant<int, float, long> variant_type;
+ typedef transform_variant<variant_type, add_pointer<_> > transformed;
+ typedef variant<int*, float*, long*> result;
+ BOOST_MPL_ASSERT(( equal<result, transformed> ));
+ \endcode
+*/
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Op>
+struct transform_variant<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Op, boost::mpl::na> :
+ make_variant_over<
+ typename mpl::transform<
+ typename variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
+ Op
+ >::type
+ >
+{};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_UTIL_TRANSFORM_VARIANT_HPP
diff --git a/boost/geometry/views/box_view.hpp b/boost/geometry/views/box_view.hpp
index 26608b0860..4ecb941ec9 100644
--- a/boost/geometry/views/box_view.hpp
+++ b/boost/geometry/views/box_view.hpp
@@ -43,32 +43,36 @@ namespace boost { namespace geometry
\qbk{[include reference/views/box_view.qbk]}
*/
template <typename Box, bool Clockwise = true>
-struct box_view
+struct box_view
: public detail::points_view
<
- typename geometry::point_type<Box>::type,
+ typename geometry::point_type<Box>::type,
5
>
{
typedef typename geometry::point_type<Box>::type point_type;
-
+
/// Constructor accepting the box to adapt
explicit box_view(Box const& box)
: detail::points_view<point_type, 5>(copy_policy(box))
{}
-
-private :
-
+
+private :
+
class copy_policy
{
public :
inline copy_policy(Box const& box)
: m_box(box)
{}
-
+
inline void apply(point_type* points) const
{
- detail::assign_box_corners_oriented<!Clockwise>(m_box, points);
+ // assign_box_corners_oriented requires a range
+ // an alternative for this workaround would be to pass a range here,
+ // e.g. use boost::array in points_view instead of c-array
+ std::pair<point_type*, point_type*> rng = std::make_pair(points, points + 5);
+ detail::assign_box_corners_oriented<!Clockwise>(m_box, rng);
points[4] = points[0];
}
private :
diff --git a/boost/geometry/views/closeable_view.hpp b/boost/geometry/views/closeable_view.hpp
index 376246d2dc..1f1eb2720b 100644
--- a/boost/geometry/views/closeable_view.hpp
+++ b/boost/geometry/views/closeable_view.hpp
@@ -28,6 +28,12 @@
namespace boost { namespace geometry
{
+// Silence warning C4512: assignment operator could not be generated
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4512)
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail
@@ -61,7 +67,7 @@ private :
/*!
\brief View on a range, either closing it or leaving it as it is
\details The closeable_view is used internally by the library to handle all rings,
- either closed or open, the same way. The default method is closed, all
+ either closed or open, the same way. The default method is closed, all
algorithms process rings as if they are closed. Therefore, if they are opened,
a view is created which closes them.
The closeable_view might be used by library users, but its main purpose is
@@ -93,6 +99,9 @@ struct closeable_view<Range, open>
#endif // DOXYGEN_NO_SPECIALIZATIONS
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/views/detail/indexed_point_view.hpp b/boost/geometry/views/detail/indexed_point_view.hpp
new file mode 100644
index 0000000000..88b13ec5c4
--- /dev/null
+++ b/boost/geometry/views/detail/indexed_point_view.hpp
@@ -0,0 +1,112 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_VIEWS_DETAIL_INDEXED_POINT_VIEW_HPP
+#define BOOST_GEOMETRY_VIEWS_DETAIL_INDEXED_POINT_VIEW_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/coordinate_system.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail
+{
+
+template <typename Geometry, std::size_t Index>
+class indexed_point_view
+{
+ indexed_point_view & operator=(indexed_point_view const&);
+
+public:
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
+
+ indexed_point_view(Geometry & geometry)
+ : m_geometry(geometry)
+ {}
+
+ template <std::size_t Dimension>
+ inline coordinate_type get() const
+ {
+ return geometry::get<Index, Dimension>(m_geometry);
+ }
+
+ template <std::size_t Dimension>
+ inline void set(coordinate_type const& value)
+ {
+ geometry::set<Index, Dimension>(m_geometry, value);
+ }
+
+private:
+ Geometry & m_geometry;
+};
+
+}
+
+#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+namespace traits
+{
+
+template <typename Geometry, std::size_t Index>
+struct tag< detail::indexed_point_view<Geometry, Index> >
+{
+ typedef point_tag type;
+};
+
+template <typename Geometry, std::size_t Index>
+struct coordinate_type< detail::indexed_point_view<Geometry, Index> >
+{
+ typedef typename geometry::coordinate_type<Geometry>::type type;
+};
+
+template <typename Geometry, std::size_t Index>
+struct coordinate_system< detail::indexed_point_view<Geometry, Index> >
+{
+ typedef typename geometry::coordinate_system<Geometry>::type type;
+};
+
+template <typename Geometry, std::size_t Index>
+struct dimension< detail::indexed_point_view<Geometry, Index> >
+ : geometry::dimension<Geometry>
+{};
+
+template<typename Geometry, std::size_t Index, std::size_t Dimension>
+struct access< detail::indexed_point_view<Geometry, Index>, Dimension >
+{
+ typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
+
+ static inline coordinate_type get(
+ detail::indexed_point_view<Geometry, Index> const& p)
+ {
+ return p.template get<Dimension>();
+ }
+
+ static inline void set(
+ detail::indexed_point_view<Geometry, Index> & p,
+ coordinate_type const& value)
+ {
+ p.template set<Dimension>(value);
+ }
+};
+
+} // namespace traits
+#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_VIEWS_DETAIL_INDEXED_POINT_VIEW_HPP
diff --git a/boost/geometry/views/detail/normalized_view.hpp b/boost/geometry/views/detail/normalized_view.hpp
new file mode 100644
index 0000000000..d50ffe48c8
--- /dev/null
+++ b/boost/geometry/views/detail/normalized_view.hpp
@@ -0,0 +1,116 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_VIEWS_DETAIL_NORMALIZED_VIEW_HPP
+#define BOOST_GEOMETRY_VIEWS_DETAIL_NORMALIZED_VIEW_HPP
+
+
+#include <boost/range/begin.hpp>
+#include <boost/range/end.hpp>
+#include <boost/range/iterator.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <boost/geometry/views/detail/range_type.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+
+namespace boost { namespace geometry {
+
+
+#ifndef DOXYGEN_NO_DETAIL
+
+namespace detail {
+
+template <typename Geometry>
+struct normalized_view
+{
+ static const bool is_const = boost::is_const<Geometry>::value;
+
+ //typedef typename ring_type<Geometry>::type ring_type;
+
+ typedef typename detail::range_type<Geometry>::type range_type;
+
+ typedef typename
+ boost::mpl::if_c
+ <
+ is_const,
+ range_type const,
+ range_type
+ >::type range;
+
+ typedef typename
+ reversible_view
+ <
+ range,
+ order_as_direction
+ <
+ geometry::point_order<Geometry>::value
+ >::value
+ >::type reversible_type;
+
+ typedef typename
+ boost::mpl::if_c
+ <
+ is_const,
+ reversible_type const,
+ reversible_type
+ >::type reversible;
+
+ typedef typename
+ closeable_view
+ <
+ reversible,
+ geometry::closure<Geometry>::value
+ >::type closeable_type;
+
+ typedef typename
+ boost::mpl::if_c
+ <
+ is_const,
+ closeable_type const,
+ closeable_type
+ >::type closeable;
+
+ explicit inline normalized_view(range & r)
+ : m_reversible(r)
+ , m_closeable(m_reversible)
+ {}
+
+ typedef typename boost::range_iterator<closeable>::type iterator;
+ typedef typename boost::range_const_iterator<closeable>::type const_iterator;
+
+ inline const_iterator begin() const { return boost::begin(m_closeable); }
+ inline const_iterator end() const { return boost::end(m_closeable); }
+
+ inline iterator begin() { return boost::begin(m_closeable); }
+ inline iterator end() { return boost::end(m_closeable); }
+
+private:
+ reversible_type m_reversible;
+ closeable_type m_closeable;
+};
+
+} // namespace detail
+
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_VIEWS_DETAIL_NORMALIZED_VIEW_HPP
diff --git a/boost/geometry/views/detail/points_view.hpp b/boost/geometry/views/detail/points_view.hpp
index 91fbc41c19..a06084216b 100644
--- a/boost/geometry/views/detail/points_view.hpp
+++ b/boost/geometry/views/detail/points_view.hpp
@@ -36,6 +36,7 @@ class points_view
// to have it lightweight). Probably there is already an
// equivalent of this within Boost. If so, TODO: use that one.
// This used to be "box_iterator" and "segment_iterator".
+ // ALTERNATIVE: use boost:array and its iterators
struct points_iterator
: public boost::iterator_facade
<
@@ -47,21 +48,21 @@ class points_view
// Constructor: Begin iterator
inline points_iterator(Point const* p)
: m_points(p)
- , m_index(0)
+ , m_index(0)
{}
// Constructor: End iterator
inline points_iterator(Point const* p, bool)
: m_points(p)
- , m_index(MaxSize)
+ , m_index(MaxSize)
{}
// Constructor: default (for Range Concept checking).
inline points_iterator()
: m_points(NULL)
- , m_index(MaxSize)
+ , m_index(MaxSize)
{}
-
+
typedef std::ptrdiff_t difference_type;
private:
@@ -73,7 +74,7 @@ class points_view
{
return m_points[m_index];
}
-
+
// If it index larger (or smaller) return first point
// (assuming initialized)
return m_points[0];
@@ -98,14 +99,14 @@ class points_view
{
return other.m_index - this->m_index;
}
-
+
inline void advance(difference_type n)
{
m_index += n;
}
Point const* m_points;
- int m_index;
+ difference_type m_index;
};
public :
@@ -127,8 +128,8 @@ protected :
{
copy.apply(m_points);
}
-
-private :
+
+private :
// Copy points here - box might define them otherwise
Point m_points[MaxSize];
};
diff --git a/boost/geometry/views/detail/range_type.hpp b/boost/geometry/views/detail/range_type.hpp
index a40670cf99..fff634c379 100644
--- a/boost/geometry/views/detail/range_type.hpp
+++ b/boost/geometry/views/detail/range_type.hpp
@@ -16,7 +16,7 @@
#include <boost/mpl/assert.hpp>
-#include <boost/type_traits.hpp>
+#include <boost/range/value_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tag.hpp>
@@ -33,7 +33,8 @@ namespace dispatch
{
-template <typename GeometryTag, typename Geometry>
+template <typename Geometry,
+ typename Tag = typename tag<Geometry>::type>
struct range_type
{
BOOST_MPL_ASSERT_MSG
@@ -45,31 +46,59 @@ struct range_type
template <typename Geometry>
-struct range_type<ring_tag, Geometry>
+struct range_type<Geometry, ring_tag>
{
typedef Geometry type;
};
+
template <typename Geometry>
-struct range_type<linestring_tag, Geometry>
+struct range_type<Geometry, linestring_tag>
{
typedef Geometry type;
};
template <typename Geometry>
-struct range_type<polygon_tag, Geometry>
+struct range_type<Geometry, polygon_tag>
{
typedef typename ring_type<Geometry>::type type;
};
+
template <typename Geometry>
-struct range_type<box_tag, Geometry>
+struct range_type<Geometry, box_tag>
{
typedef box_view<Geometry> type;
};
+// multi-point acts itself as a range
+template <typename Geometry>
+struct range_type<Geometry, multi_point_tag>
+{
+ typedef Geometry type;
+};
+
+
+template <typename Geometry>
+struct range_type<Geometry, multi_linestring_tag>
+{
+ typedef typename boost::range_value<Geometry>::type type;
+};
+
+
+template <typename Geometry>
+struct range_type<Geometry, multi_polygon_tag>
+{
+ // Call its single-version
+ typedef typename dispatch::range_type
+ <
+ typename boost::range_value<Geometry>::type
+ >::type type;
+};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -93,7 +122,6 @@ struct range_type
{
typedef typename dispatch::range_type
<
- typename tag<Geometry>::type,
Geometry
>::type type;
};
diff --git a/boost/geometry/views/identity_view.hpp b/boost/geometry/views/identity_view.hpp
index 5ce6e8e6d6..8947ebf6fc 100644
--- a/boost/geometry/views/identity_view.hpp
+++ b/boost/geometry/views/identity_view.hpp
@@ -21,6 +21,11 @@
namespace boost { namespace geometry
{
+// Silence warning C4512: assignment operator could not be generated
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4512)
+#endif
/*!
\brief View on a range, not modifying anything
@@ -46,6 +51,9 @@ private :
Range& m_range;
};
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/views/segment_view.hpp b/boost/geometry/views/segment_view.hpp
index 50ff617a8d..ce676fc4bf 100644
--- a/boost/geometry/views/segment_view.hpp
+++ b/boost/geometry/views/segment_view.hpp
@@ -28,7 +28,7 @@ namespace boost { namespace geometry
/*!
\brief Makes a segment behave like a linestring or a range
-\details Adapts a segment to the Boost.Range concept, enabling the user to
+\details Adapts a segment to the Boost.Range concept, enabling the user to
iterate the two segment points. The segment_view is registered as a LineString Concept
\tparam Segment \tparam_geometry{Segment}
\ingroup views
@@ -45,26 +45,26 @@ template <typename Segment>
struct segment_view
: public detail::points_view
<
- typename geometry::point_type<Segment>::type,
+ typename geometry::point_type<Segment>::type,
2
>
{
typedef typename geometry::point_type<Segment>::type point_type;
-
+
/// Constructor accepting the segment to adapt
explicit segment_view(Segment const& segment)
: detail::points_view<point_type, 2>(copy_policy(segment))
{}
-
-private :
-
+
+private :
+
class copy_policy
{
public :
inline copy_policy(Segment const& segment)
: m_segment(segment)
{}
-
+
inline void apply(point_type* points) const
{
geometry::detail::assign_point_from_index<0>(m_segment, points[0]);