Skip to content

Flow maps: implement second sweep#19

Merged
Willem3141 merged 57 commits intomasterfrom
flowmap-second-sweep
Aug 18, 2023
Merged

Flow maps: implement second sweep#19
Willem3141 merged 57 commits intomasterfrom
flowmap-second-sweep

Conversation

@Willem3141
Copy link
Contributor

@Willem3141 Willem3141 commented Oct 28, 2022

Implements the second (inwards) sweep in the flow map algorithm. See #16.

For this we first need to extend the first (outward) sweep, now called
ReachableRegionAlgorithm, to actually produce a list of vertices on the
boundary of the unreachable regions.
Pruning a sweep edge can just slightly change its φ value for a given r,
due to rounding errors. This presents various problems.

Firstly, if I prune an edge, I may not be able to find that edge anymore
in the sweep circle. Namely, I changed the edge's shape, but the edge is
still indexed with the old shape as key in the std::multimap that stores
the sweep circle edges. If these yield different φ values, I've lost the
edge. This commit solves this problem by using an std::multiset to store
the sweep circle instead. This way, the φ comparisons are done using the
shapes stored in the edges themselves, rather than the shape stored as a
key separately.

Secondly, pruning edges before their join event is nice because then for
sure the endpoints of the edges have the same φ, hence erasing them from
the sweep circle always works without problems. On the other hand, doing
it this way also presents a new problem, namely that if we prune, we may
move the endpoint over φ = π, and now the sweep circle's order is messed
up. So we don't actually want to do it this way: we now first remove the
edges from the sweep circle, and then we prune. This seems to just work,
at least under g++/clang, but on MSVC it seems that the removal may miss
the edges. This commit solves this problem by adding an additional check
to the edge comparator used by the sweep circle: if the edge that we are
checking actually has a lower φ than its previous neighbor edge (that we
luckily already store as a pointer), then we sneakily compare not to the
edge's own φ but the previous edge's φ. To make this work, some annoying
special cases have to be handled (e.g., if the edge hasn't been inserted
yet it doesn't yet have a previous edge, and if it has been inserted but
it is the first edge on the sweep circle, we shouldn't change its φ, and
so on).
The check if an edge is the first edge in the sweep circle is incorrect,
probably because it's a bad idea to query the first edge in the multiset
while we're inserting something into the multiset.
This already used to work because the std::shared_ptr<SweepEdge>
carrying the join event's sweep edges would become stale. However, now
we keep references to these shared_ptrs because we need them for the
second sweep. Hence, we need to explicitly maintain if a SweepEdge is
still on the circle. This commit implements just that.
There is a bug in how the ReachableRegionAlgorithm sets the adjacent
edges of the vertices it passes to the second sweep. The aim of this
commit is to make it easier to distinguish visually what exactly it sets
as the edges for each vertex.
Now it should actually be fixed, as opposed to before.
Far events belonging to concave obstacle corners are on the boundary of
the reachable region only if they border a reachable interval.
The file data/flow-map-test.spt contains the same configuration for the
old FlowTrees tool, for testing purposes.
@Willem3141 Willem3141 marked this pull request as draft April 5, 2023 08:57
@Willem3141 Willem3141 changed the title WIP: Flow maps: implement second sweep Flow maps: implement second sweep Apr 5, 2023
In the SpiralTreeObstructedAlgorithm there were quite a lot of
statements to copy node pointers to the new intervals after an event is
handled. It is easier to just copy these node pointers by default in the
SweepCircle.
Using these pointers we'll be able to remove all reachable regions that
have the same active descendant, as soon as a join event happens.
When joining two reachable regions, mark all reachable intervals that
have the same active descendant as the merged regions as free.

The implementation now generates a correct spiral tree with obstacles on
the test instance.
The same fix as commit f89ef1d, but now for the renderer.
The old code didn't handle a large number of corner cases correctly.
This commit implements a more robust way and documents how it works.
See commit a51da5e (the "secondly" part of the commit message, more
specifically the "sneaky" comparisons).

This turns out to be not a good idea as it breaks the std::multiset when
inserting into it (see commit 08a168b).
Using std::ranges::views::reverse breaks when compiling with clang and
libstdc++ as per llvm/llvm-project#44178.
@Willem3141 Willem3141 marked this pull request as ready for review August 11, 2023 09:29
To find out if a sweep edge departs to the left or right of another
sweep edge, we used to just evaluate both at radius + ε, but that is not
very robust. This commit makes it so that instead the tangent angle of
both sweep edges is evaluated.
This commit adds node events for the ReachableRegionAlgorithm so that we
can track which nodes are reachable. This way, we now ignore unreachable
nodes when constructing the spiral tree.
@Willem3141
Copy link
Contributor Author

The spiral tree generation is not correct yet (creates unnecessary nodes and edges) but let's fix / reimplement that later.

@Willem3141 Willem3141 merged commit 0ba56fe into master Aug 18, 2023
@Willem3141 Willem3141 deleted the flowmap-second-sweep branch August 18, 2023 11:43
@Willem3141 Willem3141 mentioned this pull request Aug 24, 2023
51 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant