wdtinc / mapbox-vector-tile-java

Java Mapbox Vector Tile Library for Encoding/Decoding
Apache License 2.0
148 stars 73 forks source link

Add support for optionally avoiding simplification of geometries #4

Closed justinlewis closed 7 years ago

justinlewis commented 7 years ago

Simplification is useful for a variety of reasons but there are situations where simplification is not desired. For example, at lower zoom levels or if wanting to edit features where maximum precision and accuracy is necessary. I'm happy to help with this but could use some help as the simplification seems to occur in the Affine Transform.

ShibaBandit commented 7 years ago

Are you referring to JtsAdapter#createTileGeom() ?

justinlewis commented 7 years ago

Yes sir that method. However I think the simplification occurs outside of that specific simplify method: TopologyPreservingSimplifier.simplify(nextTransformGeom, .1d);

I have already branched the project to add a flag to avoid that simplify method but polygon topology is still compromised.

I think it actually happens as part of the AffineTransform in the lines prior to that method.

nextTransformGeom = t.transform(nextInterGeom); // Floating --> Integer, still contained within doubles nextTransformGeom.apply(RoundingFilter.INSTANCE);

I debugged into those methods but before trying to understand the inner workings of how the AffineTransform is implemented I thought you might be able to shed some light as to whether I'm on the right track.

Thanks for responding!

ShibaBandit commented 7 years ago

Gotcha. Quick recap of this method, sorry if I'm repeating information you already know:

  1. The AffineTransformation converts global coordinates to local MVT coordinates. These coordinates are still floating point.
  2. The RoundingFilter does as you might expect, it just rounds all floating point coordinates in the geometry to the nearest integer, since MVTs are no longer floating point and have fixed precision defined by the extent.
  3. TopologyPreservingSimplifier#simplify() does some quick and dirty simplification that needs to occur after using the RoundingFilter.

Going to MVT (integer) coordinates has the risk that your geometry may be altered, although it will be more or less severe depending on the extent size. In our pipeline, we generally write MVTs as our final step after all other pre-processing.

It sound like in your application's case it needs to edit vector tiles without step 2+3? There's a couple of options that come to mind at first:

  1. Used the intersected geometry output in the TileGeomResult, these will be in your world coordinates though.
  2. You need local tile coordinates, but don't round to the MVT extent. Can be handled with a processing flag like you suggested
  3. You need local tile coordinates, but don't round to the MVT extent. Can alternatively be handled by exposing the functionality within that method as smaller pieces... Ex. Expose the method to generate the AffineTransformation and Flat Intersected Geometry.

If you need to edit geometries in local tile coordinates, how will you handle edges/boundaries?

justinlewis commented 7 years ago

Thanks for this response... I haven't had time to try this yet since I got pulled off on another issue. I'll get back to you soon.

ShibaBandit commented 7 years ago

Closing this out for now. Feel free to re-open if you have more feedback.

justinlewis commented 7 years ago

Thanks @ShibaBandit. Sounds good. We ended up loading the features that need editing ability (no simplification) as geojson. This works for now. However, we will be submitting a small pull request to you soon for some other things. I'd be happy to work with you more on that to make sure you understand what we are trying to achieve and how we did it. Thanks!