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

Concave hull #427

Closed

Conversation

FObermaier
Copy link
Contributor

I hijacked @dr-jts ConcaveHull stub in jts-lab and replaced it with an implementation inspired by
@mourner 's concaveman algorithm.

It is based on ideas from the paper A New Concave Hull Algorithm and Concaveness Measure for n-dimensional Datasets, 2012 by Jin-Seo Park and Se-Jong Oh.

* Add Distance.segmentToEnvelope function
* Minor javadoc fixes to BoundablePair and
  GeometryItemDistance
* Complete unit tests and test data

Signed-off-by: Felix Obermaier <[email protected]>
Signed-off-by: Felix Obermaier <[email protected]>
* Use SquaredDistance in ConcaveHull computation

Signed-off-by: Felix Obermaier <[email protected]>
Signed-off-by: Felix Obermaier <[email protected]>
Copy link
Contributor

@dr-jts dr-jts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Further to my comment about needing a more precise name for this algorithm, note that for this algorithm larger tolerance values produce shapes closer to the convex hull (less concave).

In most other algorithms I've seen (such as Duckhams - implementation here) larger tolerance produce a more concave hull.

This is an important distinction. For one thing, it means that this algorithm has a different signature, so cannot be "plug-compatible" with other algorithms. It also requires a different understanding of how to choose appropriate tolerance values.

This relates to something I find problematic about current concave hull algorithms, which is that it's hard to predict a priori what a "good" tolerance distance is. Actually this algorithm might work better in this respect, since the tolerance is a ratio rather than an absolute distance.

* @since 1.17
* @author Felix Obermaier
*/
@SuppressWarnings({"ForLoopReplaceableByForEach", "ManualArrayToCollectionCopy"})
public class ConcaveHull {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few Concave Hull algorithms around. It would be good to distinguish them by name, to leave namespace room for other implementations. Is there a more specific name for this algorithm?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatives:

  • ConcaveHullDigger (sounds like an arcade game)
  • ParkOhConcaveHull (giving credit to the inventors)

Anyone?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer a name based on the algorithm concept (unless this becomes known by the names of the inventors). I agree Digger is an awkward term, but that's the one they use. Perhaps DiggingConcaveHull ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps NearestPointConcaveHull ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using to excavate as a synonyme of to dig gives a less awkward so how about ConcaveHullExcavator?

* @param bounds the bounds
* @return the distance between AB and the envelope.
*/
public static double segmentToEnvelope(Coordinate A, Coordinate B, Envelope bounds) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be placed in the Envelope class, since it requires an envelope to be present anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this seems to be a left-over from the first attempts using real distances.
But yes, I can move it to Envelope class

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not used then just delete it.

@dr-jts
Copy link
Contributor

dr-jts commented May 8, 2019

Can this algorithm produce invalid topology for extreme tolerance values?

This is possibly one advantage of the triangulation-based approaches, which can be easily limited to ensure that only valid topology is produced. And it's also easy to enforce fully connected output.

@FObermaier
Copy link
Contributor Author

FObermaier commented May 9, 2019

In most other algorithms I've seen (such as Duckhams - implementation here) larger tolerance produce a more concave hull.

I have no idea how to change that for the lengthThreshold parameter. It prevents looking for further candidates when a segment's length goes below that value. The concavity value could be handled as a reciprocal value thus having greater concaveness for larger values.

Can this algorithm produce invalid topology for extreme tolerance values?

According to the short paper:

Our proposed algorithm satisfies Galton’s evaluation criteria, with the exception of
question (5). The question has no relationship to the robustness of the proposed algorithm.

Question 5 asks if the concave hull should be polygonal, or its boundary can be curved.

As the starting solution is a convex hull, I see no way of producing a not fully connected result, regardless of the input parameters.

@FObermaier
Copy link
Contributor Author

FObermaier commented May 9, 2019

An idea to improve the expected output for non-puntal input is to mark segments of the starting solution (convex-hull) that are part of the input geometry as immutable. The other concave hull implementation you mentioned proposes to densify the input geometry in such cases.

@dr-jts
Copy link
Contributor

dr-jts commented May 9, 2019

In most other algorithms I've seen (such as Duckhams - implementation here) larger tolerance produce a more concave hull.

I have no idea how to change that for the lengthThreshold parameter. It prevents looking for further candidates when a segment's length goes below that value.

Yes, this seems more like a quality control rather than a core parameter to the algorithm. Was this in the original paper?

The concavity value could be handled as a reciprocal value thus having greater concaveness for larger values.

Yes, I thought of that too. Best to leave it as per original paper, though.

@dr-jts
Copy link
Contributor

dr-jts commented May 9, 2019

As the starting solution is a convex hull, I see no way of producing a not fully connected result, regardless of the input parameters.

Another possible issue is whether the algorithm can produce edges which cross one another. My evaluation is that this is not possible, due to the closest edge-point pair always being chosen for processing. Would have been nice if they'd proved this (it's not part of the Galton criteria, but probably should be).

@dr-jts
Copy link
Contributor

dr-jts commented May 9, 2019

This is possibly one advantage of the triangulation-based approaches, which can be easily limited to ensure that only valid topology is produced. And it's also easy to enforce fully connected output.

Triangulation-based approaches can also produce holes - which may or may not be desirable (but obviously can be removed if not).

@dr-jts
Copy link
Contributor

dr-jts commented May 9, 2019

This relates to something I find problematic about current concave hull algorithms, which is that it's hard to predict a priori what a "good" tolerance distance is. Actually this algorithm might work better in this respect, since the tolerance is a ratio rather than an absolute distance.

Another comment on the intuitiveness of the concavity parameter is that (if I understand it) it's based on purely local information (a ratio of the edges of the triangle being considered for removal).

It's interesting that they propose a Concaveness Measure equation which is based on global values (perimeter length). But there doesn't seem to be any way to decide a priori on a concavity value that will produce a target concaveness measure value.

@FObermaier
Copy link
Contributor Author

Another possible issue is whether the algorithm can produce edges which cross one another.

That is taken care of:
https://github.com/FObermaier/jts/blob/3a8e9f4459c2deb76b3db6f32f98a691e3dd6b7b/modules/lab/src/main/java/org/locationtech/jts/hull/ConcaveHull.java#L341-L344

@FObermaier
Copy link
Contributor Author

Triangulation-based approaches can also produce holes - which may or may not be desirable (but obviously can be removed if not).

In my understanding hulls don't have holes.

@FObermaier
Copy link
Contributor Author

I think the concavity parameter does not directly relate to the Concaveness Measure.

The concavity value has its representation in the smoothness parameter N introduced in 2.1.
If I understand the paper correctly, the smoothness parameter N is understood as application specific which could be addressed by adding a static property DefaultConcavity. For the concaveman algorithm that value was chosen to be 2.

* Remove Distance.segmentToEnvelope function (not-used)
* Add static defaultConcavity to ConcaveHullExcavator and setter
  function
* Rename SquaredDistance to DistanceSquared
* Rename ConcaveHullTest to ConcaveHullExcavatorTest

Signed-off-by: Felix Obermaier <[email protected]>
@FObermaier
Copy link
Contributor Author

I'm wondering if there is an interest in this convex hull implemenation?

FObermaier added a commit to FObermaier/jts-ex that referenced this pull request Mar 19, 2021
Imported and adapted code from /locationtech/jts/pull/427

Signed-off-by: Felix Obermaier <[email protected]>
FObermaier added a commit to FObermaier/jts-ex that referenced this pull request Mar 19, 2021
Imported and adapted code from /locationtech/jts/pull/427

Signed-off-by: Felix Obermaier <[email protected]>
FObermaier added a commit to FObermaier/jts-ex that referenced this pull request Mar 19, 2021
Imported and adapted code from /locationtech/jts/pull/427

Signed-off-by: Felix Obermaier <[email protected]>
@FObermaier
Copy link
Contributor Author

The code can be found here: https://github.com/FObermaier/jts-ex

@FObermaier FObermaier closed this Jul 6, 2021
@dr-jts
Copy link
Contributor

dr-jts commented Dec 20, 2021

I haven't forgotten about this, but need to do #823 as a drop-in replacement for the PostGIS one.

It would be interesting to compare the results and performance of the two algorithms.

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.

2 participants