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

Drop smallest inner rings for earcut performance #2622

Merged
merged 8 commits into from
May 26, 2016
Merged

Conversation

yhahn
Copy link
Member

@yhahn yhahn commented May 25, 2016

  • Adds unit tests for classifyRings()
  • Adds sorting of inner rings for polygons by area (desc) and truncating to EARCUT_MAX_RINGS (currently set to 100)

Next actions

cc @jakepruitt @jfirebaugh

@mourner
Copy link
Member

mourner commented May 25, 2016

If you're feeling like doing something fancy, you can replace sort here with https://github.com/mourner/quickselect, which runs in O(n) rather than O(n log n), and would also allow you to avoid some copies like concat. :)

According to my unscientific tests, I think max rings will end up being something closer to 800, but let's wait to see what @jakepruitt figures out with real benchmarks.

@jfirebaugh
Copy link
Contributor

jfirebaugh commented May 25, 2016

LGTM. Will be interested to see integration with benchmarking from @jakepruitt.

Our plan is to move classifyRings into loadGeometry for the vector-tile-js 2.0 release (mapbox/vector-tile-js#33). I think ring-dropping could move along with it, such that loadGeometry takes an optional maxRings parameter. Or it could remain a post-processing step in gl-js.

@lucaswoj
Copy link
Contributor

lucaswoj commented May 25, 2016

What went into the decision to simplify to a max # of rings rather than filter rings by area? I imagine the latter would result in

  • more predictable visual artifacts because the amount of distortion isn't a function of the complexity of the input data
  • improved rendering perf for small polygons
  • O(n) filtering perf

@mourner
Copy link
Member

mourner commented May 25, 2016

Crossposting my comment from chat, answering @lucaswoj's question:

The source issue is that Earcut is slow on polygons with tons of holes, regardless of area. If we filter by area, we can’t guarantee that we’ll filter enough if the threshold is low, and that we won't introduce unwanted visual change if the threshold is high. E.g. I had to bump the area threshold pretty high in a recent test of Streets (800 in tile coords), but this may be too high for other datasets.

So we’ll guard against the source issue with Earcut, and leave the noise filtering as responsibility of the dataset designer.

@lucaswoj lucaswoj changed the title [notready] Drop smallest inner rings for earcut performance Drop smallest inner rings for earcut performance May 25, 2016
@lucaswoj
Copy link
Contributor

Once we bump EARCUT_MAX_RINGS to 500, this is ready to 🚢!

@lucaswoj
Copy link
Contributor

I'm going to take a quick look at benchmarks using https://github.com/mourner/quickselect instead of Array#sort and then 🚢 this

@mourner
Copy link
Member

mourner commented May 26, 2016

@lucaswoj in theory, it should be about 5-7 times faster for a 500-hole polygon, but if the total sort is just a few millisecond, it probably doesn't matter much. Although worth pointing out that quickselect is already in the dep tree through supercluster->kdbush, so it won't add to the bundle size.

polygons[j] = truncated.concat(polygon.slice(0, maxRings - 1));
if (polygons[j].length <= maxRings) continue;
quickselect(polygons[j], maxRings - 1, 1, polygon.length - 1, sortByArea);
polygons[j] = polygon.slice(0, maxRings);
Copy link
Member

Choose a reason for hiding this comment

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

It seems that the 2nd arg to quickselect should be just maxRingsk is position independent of left.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it! I was a little unsure of the relationship between k and maxRings from the quickselect docs.

@lucaswoj
Copy link
Contributor

🚢 on 🍏 @mourner @yhahn @jakepruitt?

@lucaswoj lucaswoj merged commit 3d39142 into master May 26, 2016
@lucaswoj lucaswoj deleted the earcut-ringsort branch May 26, 2016 21:00
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