Skip to content

Commit 96f8d93

Browse files
committed
feat: prepare fix of dissolve
1 parent 787c1af commit 96f8d93

File tree

6 files changed

+120
-93
lines changed

6 files changed

+120
-93
lines changed

include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -202,70 +202,6 @@ inline void enrich_assign(Operations& operations, Turns& turns)
202202
#endif
203203
}
204204

205-
template <typename Operations, typename Turns>
206-
inline void enrich_adapt(Operations& operations, Turns& turns)
207-
{
208-
// Operations is a vector of indexed_turn_operation<>
209-
// If it is empty, or contains one or two items, it makes no sense
210-
if (operations.size() < 3)
211-
{
212-
return;
213-
}
214-
215-
bool next_phase = false;
216-
std::size_t previous_index = operations.size() - 1;
217-
218-
for (auto const& item : util::enumerate(operations))
219-
{
220-
auto const& index = item.index;
221-
auto const& indexed = item.value;
222-
auto& turn = turns[indexed.turn_index];
223-
auto& op = turn.operations[indexed.operation_index];
224-
225-
std::size_t const next_index = (index + 1) % operations.size();
226-
auto const& next_turn = turns[operations[next_index].turn_index];
227-
auto const& next_op = next_turn.operations[operations[next_index].operation_index];
228-
229-
if (op.seg_id.segment_index == next_op.seg_id.segment_index)
230-
{
231-
auto const& prev_turn = turns[operations[previous_index].turn_index];
232-
auto const& prev_op = prev_turn.operations[operations[previous_index].operation_index];
233-
if (op.seg_id.segment_index == prev_op.seg_id.segment_index)
234-
{
235-
op.enriched.startable = false;
236-
next_phase = true;
237-
}
238-
}
239-
previous_index = index;
240-
}
241-
242-
if (! next_phase)
243-
{
244-
return;
245-
}
246-
247-
// Discard turns which are both non-startable
248-
next_phase = false;
249-
for (auto& turn : turns)
250-
{
251-
if (! turn.operations[0].enriched.startable
252-
&& ! turn.operations[1].enriched.startable)
253-
{
254-
turn.discarded = true;
255-
next_phase = true;
256-
}
257-
}
258-
259-
if (! next_phase)
260-
{
261-
return;
262-
}
263-
264-
// Remove discarded turns from operations to avoid having them as next turn
265-
discarded_indexed_turn<Turns> const predicate(turns);
266-
operations.erase(std::remove_if(std::begin(operations),
267-
std::end(operations), predicate), std::end(operations));
268-
}
269205

270206
struct enriched_map_default_include_policy
271207
{
@@ -420,11 +356,6 @@ inline void enrich_turns(Turns& turns,
420356
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
421357
std::cout << "ENRICH-assign Ring " << pair.first << std::endl;
422358
#endif
423-
if BOOST_GEOMETRY_CONSTEXPR (OverlayType == overlay_dissolve)
424-
{
425-
enrich_adapt(pair.second, turns);
426-
}
427-
428359
enrich_assign(pair.second, turns);
429360
}
430361

include/boost/geometry/algorithms/detail/overlay/graph/get_tois.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ set_of_tois get_tois(Turns const& turns, Clusters const& clusters,
111111
}
112112

113113
// Variant with multiple target nodes
114-
template <operation_type TargetOperation, typename Turns, typename Clusters>
114+
template <operation_type TargetOperation, typename Turns, typename Clusters, typename TargetNodeIds>
115115
set_of_tois get_tois(Turns const& turns, Clusters const& clusters,
116-
signed_size_type source_node_id, std::set<signed_size_type> const& target_node_ids)
116+
signed_size_type source_node_id, TargetNodeIds const& target_node_ids)
117117
{
118118
set_of_tois result;
119119
for (auto const& target : target_node_ids)

include/boost/geometry/algorithms/detail/overlay/graph/node_util.hpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
1717
#include <boost/geometry/algorithms/detail/overlay/turn_operation_id.hpp>
1818

19+
#include <algorithm>
1920
#include <set>
21+
#include <vector>
2022
#include <tuple>
2123

2224
namespace boost { namespace geometry
@@ -121,14 +123,15 @@ void get_target_operations(Turns const& turns,
121123

122124

123125
// Get the target nodes of a specific component_id only.
126+
// Target nodes are sorted on preference index.
124127
template <operation_type TargetOperation, typename Turns, typename Clusters, typename Set>
125128
auto get_target_nodes(Turns const& turns, Clusters const& clusters,
126129
Set const& turn_indices,
127130
signed_size_type component_id)
128131
{
129132
using is_included = is_operation_included<TargetOperation>;
130133

131-
std::set<signed_size_type> result;
134+
std::vector<std::pair<signed_size_type, std::size_t>> selected;
132135
for (auto turn_index : turn_indices)
133136
{
134137
auto const& turn = turns[turn_index];
@@ -144,10 +147,19 @@ auto get_target_nodes(Turns const& turns, Clusters const& clusters,
144147
&& is_included::apply(op)
145148
&& is_target_operation<TargetOperation>(turns, {turn_index, j}))
146149
{
147-
result.insert(get_node_id(turns, op.enriched.travels_to_ip_index));
150+
selected.push_back({get_node_id(turns, op.enriched.travels_to_ip_index), op.preference_index});
148151
}
149152
}
150153
}
154+
155+
std::sort(selected.begin(), selected.end(),
156+
[](auto const& a, auto const& b) { return a.second < b.second; });
157+
158+
std::vector<signed_size_type> result;
159+
for (auto const& item : selected)
160+
{
161+
result.push_back(item.first);
162+
}
151163
return result;
152164
}
153165

include/boost/geometry/algorithms/detail/overlay/graph/select_edge.hpp

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,28 @@ struct edge_and_side
3737
int side{0};
3838
};
3939

40+
// Sort by side and always take the right (smaller) side (for intersection, union, buffer).
41+
template <overlay_type OverlayType>
42+
struct compare_edges_by_side
43+
{
44+
template <typename Edge1, typename Edge2>
45+
bool operator()(Edge1 const& a, Edge2 const& b) const
46+
{
47+
return a.side < b.side;
48+
}
49+
};
50+
51+
// For dissolve, the left (larger) side is taken.
52+
template <>
53+
struct compare_edges_by_side<overlay_dissolve>
54+
{
55+
template <typename Edge1, typename Edge2>
56+
bool operator()(Edge1 const& a, Edge2 const& b) const
57+
{
58+
return a.side > b.side;
59+
}
60+
};
61+
4062
template
4163
<
4264
bool Reverse1,
@@ -154,14 +176,8 @@ struct edge_selector
154176
edge.side = side_strategy.apply(p1, p2, edge.point);
155177
}
156178

157-
// Sort by side (with respect to segment [p1..p2]) (TEMPORARY: and then by toi)
158-
// Right = -1 will come first. Left = 1 will come last.
159-
// This works for both union and intersection operations, because it should always
160-
// take the right turn (even in uu in buffer/union).
161-
std::sort(edges.begin(), edges.end(), [](auto const& a, auto const& b)
162-
{
163-
return std::tie(a.side, a.toi) < std::tie(b.side, b.toi);
164-
});
179+
// Sort by side, with respect to segment [p1..p2]
180+
std::sort(edges.begin(), edges.end(), compare_edges_by_side<OverlayType>());
165181

166182
report("by side", edges, p1, p2);
167183

@@ -274,6 +290,16 @@ struct edge_selector
274290
return edges.front().toi;
275291
}
276292

293+
if (target_operation == operation_union
294+
&& op0.operation == operation_union
295+
&& op1.operation == operation_union
296+
&& op0.preference_index != op1.preference_index)
297+
{
298+
return op0.preference_index < op1.preference_index
299+
? edges[0].toi
300+
: edges[1].toi;
301+
}
302+
277303
if (target_operation == operation_union
278304
&& turn0.is_clustered()
279305
&& op0.operation == operation_union

include/boost/geometry/algorithms/detail/overlay/graph/traverse_graph.hpp

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ struct traverse_graph
256256
// Select the first toi which is not yet visited and has the requested component.
257257
// If all tois are visited, not having the same component, it is not possible to continue,
258258
// and it returns an invalid toi.
259-
auto select_first_toi = [&](auto const& tois)
259+
auto select_first_toi_other = [&](auto const& tois)
260260
{
261261
for (auto const& toi : tois)
262262
{
@@ -276,6 +276,40 @@ struct traverse_graph
276276
return turn_operation_id{0, -1};
277277
};
278278

279+
auto select_first_toi_of_two_in_union = [&](auto const& tois)
280+
{
281+
const auto& toi0 = *tois.begin();
282+
const auto& toi1 = *(++tois.begin());
283+
284+
if (m_finished_tois.count(toi0) == 0
285+
&& m_finished_tois.count(toi1) == 0)
286+
{
287+
auto const& turn0 = m_turns[toi0.turn_index];
288+
auto const& turn1 = m_turns[toi1.turn_index];
289+
auto const& op0 = turn0.operations[toi0.operation_index];
290+
auto const& op1 = turn1.operations[toi1.operation_index];
291+
292+
if (op0.preference_index != op1.preference_index)
293+
{
294+
return op0.preference_index < op1.preference_index
295+
? toi0
296+
: toi1;
297+
}
298+
}
299+
return select_first_toi_other(tois);
300+
};
301+
302+
auto select_first_toi = [&](auto const& tois)
303+
{
304+
if (tois.size() == 2
305+
&& target_operation == operation_union)
306+
{
307+
return select_first_toi_of_two_in_union(tois);
308+
}
309+
310+
return select_first_toi_other(tois);
311+
};
312+
279313
auto const toi = select_first_toi(get_tois<target_operation>(m_turns, m_clusters,
280314
start_node_id, target_node_id));
281315
if (toi.operation_index < 0)
@@ -349,25 +383,44 @@ struct traverse_graph
349383
{
350384
return;
351385
}
352-
auto const source_node_id = get_node_id(m_turns, turn_index);
353-
auto const turn_indices = get_turn_indices_by_node_id(m_turns, m_clusters,
354-
source_node_id, allow_closed);
355386

387+
// Iterate through the turns operations which are sorted by preference.
388+
std::vector<turn_operation_id> start_operations;
356389
for (int j = 0; j < 2; j++)
357390
{
358391
auto const& op = turn.operations[j];
359-
if (! op.enriched.startable || ! is_included::apply(op))
360-
{
361-
continue;
362-
}
363-
364392
turn_operation_id const toi{turn_index, j};
365-
if (m_finished_tois.count(toi) > 0
366-
|| ! is_target_operation<target_operation>(m_turns, toi))
393+
if (op.enriched.startable
394+
&& m_finished_tois.count(toi) == 0
395+
&& is_target_operation<target_operation>(m_turns, toi)
396+
&& is_included::apply(op))
367397
{
368-
continue;
398+
start_operations.push_back(toi);
369399
}
400+
}
401+
402+
if (start_operations.empty())
403+
{
404+
return;
405+
}
370406

407+
std::sort(start_operations.begin(), start_operations.end(),
408+
[&](auto const& a, auto const& b)
409+
{
410+
auto const& op_a = m_turns[a.turn_index].operations[a.operation_index];
411+
auto const& op_b = m_turns[b.turn_index].operations[b.operation_index];
412+
// Sort by preference index, then by operation index
413+
return std::tie(op_a.preference_index, a.operation_index)
414+
< std::tie(op_b.preference_index, b.operation_index);
415+
});
416+
417+
auto const source_node_id = get_node_id(m_turns, turn_index);
418+
auto const turn_indices = get_turn_indices_by_node_id(m_turns, m_clusters,
419+
source_node_id, allow_closed);
420+
421+
for (const auto& toi : start_operations)
422+
{
423+
auto const& op = turn.operations[toi.operation_index];
371424
auto const component_id = op.enriched.component_id;
372425
auto const target_nodes = get_target_nodes<target_operation>(m_turns, m_clusters,
373426
turn_indices, component_id);

include/boost/geometry/algorithms/detail/overlay/turn_info.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ struct turn_operation
5656
operation_type operation{operation_none};
5757
segment_identifier seg_id;
5858
segment_ratio_type fraction;
59+
60+
// Preference index can be used to sort operations which are otherwise equivalent.
61+
// It is used by dissolve overlays, where operation is often set to operation_union
62+
// but the preference index is used to determine which operation to use first.
63+
std::size_t preference_index{0};
5964
};
6065

6166

0 commit comments

Comments
 (0)