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

Explode MultiPolygons when loading #6

Open
mojodna opened this issue Feb 8, 2018 · 4 comments
Open

Explode MultiPolygons when loading #6

mojodna opened this issue Feb 8, 2018 · 4 comments

Comments

@mojodna
Copy link

mojodna commented Feb 8, 2018

I'm using martinez to intersect features w/ candidates from rbush in order to do strict intersections:

COUNTRY_INDEX.search(feature)
    .features.filter(x => {
      try {
        const i = martinez.intersection(
          x.geometry.coordinates,
          feature.geometry.coordinates
        );

        return i != null && i.length > 0;
      } catch (err) {
        // buffer to convert to a Polygon
        const i = martinez.intersection(
          x.geometry.coordinates,
          buffer(feature, 0.000001, { units: "degrees" }).geometry.coordinates
        );

        return i != null && i.length > 0;
      }
    })
    .map(x => x.properties.ADM0_A3);

COUNTRY_INDEX is Natural Earth admin 0 boundaries, many of which are MultiPolygons that include territories. As a result, the bboxes produced for the USA, Canada, and Russia cover much of the world. By splitting the MultiPolygons into multiple Polygon features, I get a substantial speed-up because fewer indexed features match:

const { featureCollection, polygon } = require("@turf/helpers");
const geojsonRbush = require("geojson-rbush");

const countries = require("./countries.json");

// explode multipolygons for smaller bounding boxes within the rtree
const polys = countries.features.filter(f => f.geometry.type === "Polygon");
const mps = countries.features.filter(f => f.geometry.type === "MultiPolygon");

const features = mps.reduce(
  (acc, mp) =>
    acc.concat(
      mp.geometry.coordinates.map(rings => polygon(rings, mp.properties))
    ),
  polys
);

const COUNTRY_INDEX = geojsonRbush();

COUNTRY_INDEX.load(featureCollection(features));

Doing this automatically within geojson-rbush seems like it would provide a transparent speed-up for those using MultiPolygons.

@DenisCarriere
Copy link
Owner

👍 Agreed, we can include flattenEach from @turf/meta when using the search method.

By splitting the MultiPolygon

This shouldn't be applied to the initial loading of the FeatureCollection since MultiPolygon is treated as a single feature and not multiple features.

@mojodna If you feel like doing a PR, I can definitely help review it 👍

@mojodna
Copy link
Author

mojodna commented Feb 8, 2018

we can include flattenEach from @turf/meta when using the search method.

Can you elaborate a bit on this? It sounds like I can simplify the second block of code ☝️ by using that in the absence of a patch to search.

This shouldn't be applied to the initial loading of the FeatureCollection since MultiPolygon is treated as a single feature and not multiple features.

Yup, that makes sense. I was realizing after I opened this issue that a side-effect is that the features that come out of the index aren't necessarily the ones expected.

I will try to find time to do a PR (🙏 for the review offer), but I'm not sure I'll have time before disappearing again.

@DenisCarriere
Copy link
Owner

Sounds like a plan! 👍

@mojodna
Copy link
Author

mojodna commented Feb 9, 2018

I was thinking about this a bit more; I think the bulk of the performance improvement I'm seeing is actually related to intersecting against Polygons rather than MultiPolygons w/ martinez. In other words, reducing the number of candidates is less helpful than considerations outside of this module's scope.

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

No branches or pull requests

2 participants