Skip to content
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

Uncrossing polygon functions. #269

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Uncrossing polygon functions. #269

wants to merge 1 commit into from

Conversation

manthey
Copy link
Member

@manthey manthey commented Mar 12, 2018

This adds some utility functions, the most significant of which is uncrossPolygon. This can handle polygons with or without holes. Without holes, it takes a polygon in the form of a list of vertices with each vertex a list or tuple of at least two elements. For a polygon with holes, it takes a list of such polygons, where the first element in the list is the outside polygon and all other elements are the holes.

If a polygon self-crosses, additional vertices will be added and part of the sequence of vertices will be reversed to uncross the polygon. If the polygon contains holes, each hole is checked to make sure it doesn't cross other holes or the outline polygon.

The resultant polygon will have consistently clockwise vertices (though if the original polygon has multiple loops that only have a vertex in common, not all of the polygon may be consistently oriented).

Examples:

  • uncrossPolygon([[0, 4], [0, 2], [2, 2], [2, 0], [0, 0], [2, 4]]) results in [[0, 4], [2, 4], [1, 2], [2, 2], [2, 0], [0, 0], [1, 2], [0, 2]]

  • uncrossPolygon([[[0, 0], [0, 2], [2, 2], [2, 0]], [[1, 1], [1, 3], [3, 3], [3, 1]]]) results in [[[0, 0], [0, 2], [1, 2], [1, 1], [2, 1], [2, 2], [1, 2], [1, 3], [3, 3], [3, 1], [2, 1], [2, 0]]]

@manthey
Copy link
Member Author

manthey commented Mar 12, 2018

This addresses issue DigitalSlideArchive/HistomicsTK#481. When we eventually separate annotations from image routines, this code will be in the annotations repository.

@cooperlab
Copy link

@kheffah could provide some good testing

@manthey
Copy link
Member Author

manthey commented Mar 12, 2018

@cooperlab I still need to write CI tests. If @kheffah has a chance to test with real-world data, that would be better (especially if it turns up any issues that can be incorporated into the CI tests).

@manthey manthey changed the title [WIP] Uncrossing polygon functions. Uncrossing polygon functions. Mar 15, 2018
@manthey
Copy link
Member Author

manthey commented Mar 15, 2018

@cooperlab, @kheffah I've added tests which uncovered a few edge cases (when a polygon had edges the were colinear and partly overlapping). I think this is ready for real use now.

@rwtam121
Copy link

rwtam121 commented Jun 25, 2018

This is interesting to me because without the support of hole generation in large_image annotations at the moment, I have been trying to merge interior polygons together using the shapely library, then take the difference with the exterior polygon create a single polygon that can visualize hole regions. The holes can be seen in the middle but the tradeoff is we get all these intersecting lines.

I'm hoping that the uncrossPolygon could uncross the lines of that polygon.

Is uncrossPolygon a command that can be invoked in python code, ie
value=uncrossPolygon([[0, 4], [0, 2], [2, 2], [2, 0], [0, 0], [2, 4]])

and that variable can be put within largeAnnotations as seen below?

{
"type": "polyline", # Exact string. Required
<id, label, lineColor, lineWidth> # Optional general shape properties
"points": [ # At least two points must be specified
value
],
"closed": true, # Boolean. Default is false. Optional
"fillColor": "rgba(0, 255, 0, 1)" # String. See note about colors. Optional
}

Thanks!

@kheffah
Copy link
Collaborator

kheffah commented Oct 18, 2019

@manthey I'm curious if this has been integrated yet? When this becomes enough of a priority, I think it would be ideal if this function is automatically called as soon as the user creates a polygon annotation that crosses itself, so that it gets automatically uncrossed before it is displayed.

I'm also assuming this is dependent on integration on "polygons with holes" functionality first.

@manthey
Copy link
Member Author

manthey commented Oct 18, 2019

No, this hasn't been merged. It was awaiting someone trying it out or reviewing it.

Separate from this, we could uncross polygons on the client side as they are being drawn. This is slightly complex, as the client doesn't expect the number of vertices in a polygon to change dynamically, and, ideally, you'd add two vertices at the crossing point.

@kheffah
Copy link
Collaborator

kheffah commented Oct 18, 2019

@manthey I see. I'll try to find time to try this on some real data when I get the chance. I don't think necessarily that dynamic uncrossing is necessary while the polygon is drawn, but certainly it would be great if the final displayed polygon (when the user releases the mouse) is uncrossed, with two vertices at the crossing point like you mentioned.

@kheffah
Copy link
Collaborator

kheffah commented Jan 20, 2020

@manthey I tested the uncross polygon on real data from a user who frequently had self-crossing polygons, see the gist below:

https://gist.github.com/kheffah/6ff203132391d194021525c2faf0b15d

Unfortunately, it seems that the uncrossing method somehow drops self-crossing polygons as opposed to actually uncrossing them. This may have to do with the specific nature of the polygons in the test examples used. If you have time and would like to check the issue, you may access the examples used here since they are public.

@kheffah
Copy link
Collaborator

kheffah commented Jan 21, 2020

Close-up on self-crossing region that is not handled in one slide (http://candygram.neurology.emory.edu:8080/histomicstk#?image=5e24c0dfddda5f8398695571&bounds=47157%2C24090%2C47870%2C24431%2C0):

image

This adds some utility functions, the most significant of which is
uncrossPolygon. This can handle polygons with or without holes. Without
holes, it takes a polygon in the form of a list of vertices with each
vertex a list or tuple of at least two elements. For a polygon with
holes, it takes a list of such polygons, where the first element in the
list is the outside polygon and all other elements are the holes.

If a polygon self-crosses, additional vertices will be added and part of
the sequence of vertices will be reversed to uncross the polygon. If the
polygon contains holes, each hole is checked to make sure it doesn't
cross other holes or the outline polygon.

The resultant polygon will have consistently clockwise vertices (though
if the original polygon has multiple loops that only have a vertex in
common, not all of the polygon may be consistently oriented).

Examples:

- `uncrossPolygon([[0, 4], [0, 2], [2, 2], [2, 0], [0, 0], [2, 4]])`
  results in `[[0, 4], [2, 4], [1, 2], [2, 2], [2, 0], [0, 0], [1, 2],
  [0, 2]]`

- `uncrossPolygon([[[0, 0], [0, 2], [2, 2], [2, 0]], [[1, 1], [1, 3],
  [3, 3], [3, 1]]])` results in `[[[0, 0], [0, 2], [1, 2], [1, 1], [2,
  1], [2, 2], [1, 2], [1, 3], [3, 3], [3, 1], [2, 1], [2, 0]]]`
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.

4 participants