-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for 'linestring being readded' bug #974
Conversation
Can you add a test case that demonstrates the problem? |
da60a5d
to
8ea1df1
Compare
8ea1df1
to
7a75ca9
Compare
I've changed the fix to a cleaner implementation. The basic idea now is to only consider 'first' points when looking for new points to add to the current linestring. The justification for this is that, assuming the exterior linestring of a polygon has the opposite orientation (clockwise or counter-clockwise) to all interior linestrings, then when traversing the boundary looking for the end point of the next line to add to the current linestring, we should only encounter 'first' points; if we encounter a 'last' point then it can only be that it is at the same location as a 'first' point. As to whether the above assumption is justified, the algorithm already implicitly assumes this: when beginning to process a new linestring in the first iteration of the loop at line 455 it chooses to process the line from 'first' to 'last'. This is only valid if the above assumption is true. It turns out that the root cause of the bug doesn't always result in an error. It can simply result in the polygon encompassing the whole map. I've added two tests which demonstrates the two cases. The test
Notice that the end points of linestrings enumerated 0 and 4 are interleaved. Because of this interleaving, when processing linestring 0, the algorithm 'jumps over' point (0, 'first') via linestring 4. It then goes all around the boundary and re-encounters linestring 3, which results in the error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Thanks @djkirkham.
P.S. I tested this with the code @djkirkham provided:
|
@@ -429,6 +429,11 @@ def boundary_distance(xy): | |||
ax.text(coords[-1, 0], coords[-1, 1], | |||
'{}.'.format(thing.data[0])) | |||
|
|||
def filter_last(t): | |||
return t.kind or t.data[1] == 'first' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do wonder whether this should be != 'last'
.
Actually, I wasn't quite done with this... |
Please feel free to use the reviewing / assignment functionality. I actually believe the testing is sufficient, though you may be correct about some of this making subsequent code obsolete. Happy to review a PR from yourself / @djkirkham to clear that bit up. |
No its okay, I checked it through again and I was wrong ! |
When attaching lines to the boundary, the points where the lines meet the boundary, plus the boundary points, are put into a list and sorted by their distance along the boundary. If two lines happen to have an end-point at the same location then there is a risk that the end-points of the two lines will be interleaved, which causes the algorithm to fail later on with the 'linestring being re-added' error. This PR adds extra elements to the key used for the sort to prevent this happening.