Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Existing utils to cut geometry to certain bounds? #1316

Answered by wipfli
adjourn asked this question in Q&A
Discussion options

Problem:
I want to generate a limited area, it could be a country, county, city, etc. However, limited extracts are always messy since extraction works based on cells and not exact bounds geometry. There are always lines, polygons and points extending over the intended area.

I need crisp cut-off on exact geometry, for example a county border which I have as a geoJSON.
In other words: geometry outside gets omitted, any geometry extending over bounds is cut to bounds (lines, polygons).

What I've done:
I've been playing around with this for few days now, so my steps taken are the first ideas. I'm manually converting the geoJSON coordinates to double[]. Then, at the start of the program, before any processors run, I convert it to Geometry like this:

public static Geometry createPolygonFromCoordArray(double[] c) {
 Coordinate[] coords = new Coordinate[c.length / 2];
 for (int i = 0; i < coords.length; i++) {
 int ii = i * 2;
 coords[i] = new Coordinate(c[ii], c[ii + 1]);
 }
 return GeoUtils.latLonToWorldCoords(GeoUtils.JTS_FACTORY.createPolygon(coords));
}

I then pass the bounds geometry to all layer processors as an argument:

var landuse = new Landuse(bounds);
registerHandler(landuse);
registerSourceHandler("osm", landuse::processOsm);

When features are processed, I check if they are in bounds and omit if necessary:

if (!this.bounds.covers(feat.getGeometry())) {
 // only omitting at the moment, nothing is cut into bounds
 feat.omit();
 return;
}

Questions:

  1. Is there an utility or few to load geoJSON from file and convert it to Geometry?
  2. Since planetiler already has bounds feature.. How to detect geometry is partially outside the bounds and how to cut it?
  3. Is there a more intelligent/convenient way to cut all features in a layer to certain bounds or is my idea the way to go?

Thanks!

You must be logged in to vote

Replies: 1 comment 5 replies

Comment options

You must be logged in to vote
5 replies
Comment options

Yeah this utility should do exactly what you want by post-processing tiles on the border of your polygon to remove any data outside. If it turns out to be generally useful maybe we could upstream it into planetiler?

Comment options

That's very useful, thanks! I'll definitely find some inspiration from that and it seems to contain all the answers.

How ever I plan to use it more granually while processing the features, I won't benefit from global post-processing. Random example: a county contains all the details while rest of the country/world has borders, county/country names and very high-level landuse.

--clip option would definitely be useful for general use. I would personally love to see some one-liner planetiler API to have this functionality but it might be too specific use case, not use, I can make my own in any case..

Example:

// GeoJSON Geometry hopefully cached for repeated use
feat = ClipUtils.clip(feat, "path/to/bounds.geojson");
Comment options

I did hit one roadblock, I can't seem to figure out how to update existing FeatureCollector.Feature geometry.
@msbarry Is there a way?

If not, my alternative is to do the clipping on SourceFeature.worldGeometry() and use collector.geometry(name, clipped) instead of collector.line(), collector.point() etc.

collector.geometry(name, clipped) unfortunately has one side effect, for example with roads. Since I'm not telling that it's collector.line(), unnecessary polygons end up in output with closed loop road lines. Looks like I need to start using line(), polygon(), etc on SourceFeature instead of just worldGeometry().

Comment options

I still think your best bet would be to modify Clip.java. This method does the post-processing: https://github.com/protomaps/basemaps/blob/main/tiles/src/main/java/com/protomaps/basemap/postprocess/Clip.java#L120-L157 - you could modify it to only clip certain layers or even give it a Predicate that tells it which features to clip and if you have multiple geometries for different features you could stack them, each with a different geojson/layer/feature predicate.

If you want to do it in process step then the only way to provide a custom geometry is features.geometry(layer, geometry). You could check sourceFeature.isPoint() or canBeLine or canBePolygon first too.

Comment options

I appreciate all the tips and help, learned a lot.

Answer selected by adjourn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /