diff --git a/OsmAnd-java/libs/jts-core-1.14.0.jar b/OsmAnd-java/libs/jts-core-1.14.0.jar new file mode 100644 index 0000000000..a690bed698 Binary files /dev/null and b/OsmAnd-java/libs/jts-core-1.14.0.jar differ diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/GeomMinSizeFilter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/GeomMinSizeFilter.java new file mode 100644 index 0000000000..f690728aa9 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/GeomMinSizeFilter.java @@ -0,0 +1,50 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.vividsolutions.jts.geom.*; + +/** + * Filter {@link Polygon} and {@link MultiPolygon} by area or + * {@link LineString} and {@link MultiLineString} by length. + * + * @see IGeometryFilter + */ +public final class GeomMinSizeFilter implements IGeometryFilter { + + /** Minimum area */ + private final double minArea; + + /** Minimum length */ + private final double minLength; + + /** + * @param minArea minimum area required for a {@link Polygon} or {@link MultiPolygon} + * @param minLength minimum length required for a {@link LineString} or {@link MultiLineString} + */ + public GeomMinSizeFilter(double minArea, double minLength) { + if(minArea < 0.0d) { + throw new IllegalArgumentException("minArea must be >= 0"); + } + if(minLength < 0.0d) { + throw new IllegalArgumentException("minLength must be >= 0"); + } + + this.minArea = minArea; + this.minLength = minLength; + } + + @Override + public boolean accept(Geometry geometry) { + boolean accept = true; + + if((geometry instanceof Polygon || geometry instanceof MultiPolygon) + && geometry.getArea() < minArea) { + accept = false; + + } else if((geometry instanceof LineString || geometry instanceof MultiLineString) + && geometry.getLength() < minLength) { + accept = false; + } + + return accept; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/IGeometryFilter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/IGeometryFilter.java new file mode 100644 index 0000000000..d9da6a4b3d --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/IGeometryFilter.java @@ -0,0 +1,15 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.vividsolutions.jts.geom.Geometry; + +public interface IGeometryFilter { + + /** + * Return true if the value should be accepted (pass), or false if the value should be rejected (fail). + * + * @param geometry input to test + * @return true if the value should be accepted (pass), or false if the value should be rejected (fail) + * @see Geometry + */ + boolean accept(Geometry geometry); +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/ITagConverter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/ITagConverter.java new file mode 100644 index 0000000000..4c62781167 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/ITagConverter.java @@ -0,0 +1,26 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import net.osmand.binary.VectorTile; + +import java.util.List; + +/** + * Process MVT tags and feature id, convert to user data object. The returned user data + * object may be null. + */ +public interface ITagConverter { + + /** + * Convert MVT user data to JTS user data object or null. + * + * @param id feature id, may be {@code null} + * @param tags MVT feature tags, may be invalid + * @param keysList layer key list + * @param valuesList layer value list + * @return user data object or null + */ + Object toUserData(Long id, + List tags, + List keysList, + List valuesList); +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/IUserDataConverter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/IUserDataConverter.java new file mode 100644 index 0000000000..6631208baf --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/IUserDataConverter.java @@ -0,0 +1,23 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.wdtinc.mapbox_vector_tile.build.MvtLayerProps; + +import net.osmand.binary.VectorTile; + +/** + * Processes a user data object, converts to MVT feature tags. + */ +public interface IUserDataConverter { + + /** + *

Convert user data to MVT tags. The supplied user data may be null. Implementation + * should update layerProps and optionally set the feature id.

+ * + *

SIDE EFFECT: The implementation may add tags to featureBuilder, modify layerProps, modify userData.

+ * + * @param userData user object may contain values in any format; may be null + * @param layerProps properties global to the layer the feature belongs to + * @param featureBuilder may be modified to contain additional tags + */ + void addTags(Object userData, MvtLayerProps layerProps, VectorTile.Tile.Feature.Builder featureBuilder); +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/JtsAdapter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/JtsAdapter.java new file mode 100644 index 0000000000..e82213cfff --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/JtsAdapter.java @@ -0,0 +1,655 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.vividsolutions.jts.algorithm.CGAlgorithms; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateArrays; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.TopologyException; +import com.vividsolutions.jts.geom.util.AffineTransformation; +import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier; +import com.wdtinc.mapbox_vector_tile.build.MvtLayerParams; +import com.wdtinc.mapbox_vector_tile.build.MvtLayerProps; +import com.wdtinc.mapbox_vector_tile.encoding.GeomCmd; +import com.wdtinc.mapbox_vector_tile.encoding.GeomCmdHdr; +import com.wdtinc.mapbox_vector_tile.encoding.MvtUtil; +import com.wdtinc.mapbox_vector_tile.encoding.ZigZag; +import com.wdtinc.mapbox_vector_tile.util.Vec2d; + +import net.osmand.binary.VectorTile; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +/** + * Adapt JTS {@link Geometry} to 'Mapbox Vector Tile' objects. + */ +public final class JtsAdapter { + + /** + * Create geometry clipped and then converted to MVT 'extent' coordinates. Result + * contains both clipped geometry (intersection) and transformed geometry for encoding to MVT. + * + * @param g original 'source' geometry + * @param tileEnvelope world coordinate bounds for tile + * @param geomFactory creates a geometry for the tile envelope + * @param mvtLayerParams specifies vector tile properties + * @param filter geometry values that fail filter after transforms are removed + * @return tile geometry result + * @see TileGeomResult + */ + public static TileGeomResult createTileGeom(Geometry g, + Envelope tileEnvelope, + GeometryFactory geomFactory, + MvtLayerParams mvtLayerParams, + IGeometryFilter filter) { + return createTileGeom(flatFeatureList(g), tileEnvelope, geomFactory, + mvtLayerParams, filter); + } + + /** + * Create geometry clipped and then converted to MVT 'extent' coordinates. Result + * contains both clipped geometry (intersection) and transformed geometry for encoding to MVT. + * + * @param g original 'source' geometry, passed through {@link #flatFeatureList(Geometry)} + * @param tileEnvelope world coordinate bounds for tile + * @param geomFactory creates a geometry for the tile envelope + * @param mvtLayerParams specifies vector tile properties + * @param filter geometry values that fail filter after transforms are removed + * @return tile geometry result + * @see TileGeomResult + */ + public static TileGeomResult createTileGeom(List g, + Envelope tileEnvelope, + GeometryFactory geomFactory, + MvtLayerParams mvtLayerParams, + IGeometryFilter filter) { + + final Geometry tileEnvelopeGeom = geomFactory.toGeometry(tileEnvelope); + + final AffineTransformation t = new AffineTransformation(); + final double xDiff = tileEnvelope.getWidth(); + final double yDiff = tileEnvelope.getHeight(); + + final double xOffset = -tileEnvelope.getMinX(); + final double yOffset = -tileEnvelope.getMinY(); + + // Transform Setup: Shift to 0 as minimum value + t.translate(xOffset, yOffset); + + // Transform Setup: Scale X and Y to tile extent values, flip Y values + t.scale(1d / (xDiff / (double) mvtLayerParams.extent), + -1d / (yDiff / (double) mvtLayerParams.extent)); + + // Transform Setup: Bump Y values to positive quadrant + t.translate(0d, (double) mvtLayerParams.extent); + + + // The area contained in BOTH the 'original geometry', g, AND the 'tile envelope geometry' is the 'tile geometry' + final List intersectedGeoms = flatIntersection(tileEnvelopeGeom, g); + final List transformedGeoms = new ArrayList<>(intersectedGeoms.size()); + + // Transform intersected geometry + Geometry nextTransformGeom; + Object nextUserData; + for(Geometry nextInterGeom : intersectedGeoms) { + nextUserData = nextInterGeom.getUserData(); + + nextTransformGeom = t.transform(nextInterGeom); + + // Floating --> Integer, still contained within doubles + nextTransformGeom.apply(RoundingFilter.INSTANCE); + + // TODO: Refactor line simplification + nextTransformGeom = TopologyPreservingSimplifier.simplify(nextTransformGeom, .1d); // Can't use 0d, specify value < .5d + + nextTransformGeom.setUserData(nextUserData); + + // Apply filter on transformed geometry + if(filter.accept(nextTransformGeom)) { + transformedGeoms.add(nextTransformGeom); + } + } + + return new TileGeomResult(intersectedGeoms, transformedGeoms); + } + + /** + * @param envelope non-list geometry defines bounding area + * @param data geometry passed to {@link #flatFeatureList(Geometry)} + * @return list of geometry from {@code data} intersecting with {@code envelope}. + * @see #flatIntersection(Geometry, List) + */ + private static List flatIntersection(Geometry envelope, Geometry data) { + return flatIntersection(envelope, flatFeatureList(data)); + } + + /** + * JTS 1.14 does not support intersection on a {@link GeometryCollection}. This function works around this + * by performing intersection on a flat list of geometry. The resulting list is pre-filtered for invalid + * or empty geometry (outside of bounds). Invalid geometry are logged as errors. + * + * @param envelope non-list geometry defines bounding area + * @param dataGeoms geometry pre-passed through {@link #flatFeatureList(Geometry)} + * @return list of geometry from {@code data} intersecting with {@code envelope}. + */ + private static List flatIntersection(Geometry envelope, List dataGeoms) { + final List intersectedGeoms = new ArrayList<>(dataGeoms.size()); + + Geometry nextIntersected; + for(Geometry nextGeom : dataGeoms) { + try { + + // AABB intersection culling + if(envelope.getEnvelopeInternal().intersects(nextGeom.getEnvelopeInternal())) { + + nextIntersected = envelope.intersection(nextGeom); + if(!nextIntersected.isEmpty()) { + nextIntersected.setUserData(nextGeom.getUserData()); + intersectedGeoms.add(nextIntersected); + } + } + + } catch (TopologyException e) { + //LoggerFactory.getLogger(JtsAdapter.class).error(e.getMessage(), e); + } + } + + return intersectedGeoms; + } + + /** + * Get the MVT type mapping for the provided JTS Geometry. + * + * @param geometry JTS Geometry to get MVT type for + * @return MVT type for the given JTS Geometry, may return + * {@link com.wdtinc.mapbox_vector_tile.VectorTile.Tile.GeomType#UNKNOWN} + */ + public static VectorTile.Tile.GeomType toGeomType(Geometry geometry) { + VectorTile.Tile.GeomType result = VectorTile.Tile.GeomType.UNKNOWN; + + if(geometry instanceof Point + || geometry instanceof MultiPoint) { + result = VectorTile.Tile.GeomType.POINT; + + } else if(geometry instanceof LineString + || geometry instanceof MultiLineString) { + result = VectorTile.Tile.GeomType.LINESTRING; + + } else if(geometry instanceof Polygon + || geometry instanceof MultiPolygon) { + result = VectorTile.Tile.GeomType.POLYGON; + } + + return result; + } + + /** + *

Recursively convert a {@link Geometry}, which may be an instance of {@link GeometryCollection} with mixed + * element types, into a flat list containing only the following {@link Geometry} types:

+ *
    + *
  • {@link Point}
  • + *
  • {@link LineString}
  • + *
  • {@link Polygon}
  • + *
  • {@link MultiPoint}
  • + *
  • {@link MultiLineString}
  • + *
  • {@link MultiPolygon}
  • + *
+ *

WARNING: Any other Geometry types that were not mentioned in the list above will be discarded!

+ *

Useful for converting a generic geometry into a list of simple MVT-feature-ready geometries.

+ * + * @param geom geometry to flatten + * @return list of MVT-feature-ready geometries + */ + public static List flatFeatureList(Geometry geom) { + final List singleGeoms = new ArrayList<>(); + final Stack geomStack = new Stack<>(); + + Geometry nextGeom; + int nextGeomCount; + + geomStack.push(geom); + while(!geomStack.isEmpty()) { + nextGeom = geomStack.pop(); + + if(nextGeom instanceof Point + || nextGeom instanceof MultiPoint + || nextGeom instanceof LineString + || nextGeom instanceof MultiLineString + || nextGeom instanceof Polygon + || nextGeom instanceof MultiPolygon) { + + singleGeoms.add(nextGeom); + + } else if(nextGeom instanceof GeometryCollection) { + + // Push all child geometries + nextGeomCount = nextGeom.getNumGeometries(); + for(int i = 0; i < nextGeomCount; ++i) { + geomStack.push(nextGeom.getGeometryN(i)); + } + + } + } + + return singleGeoms; + } + + /** + *

Convert JTS {@link Geometry} to a list of vector tile features. + * The Geometry should be in MVT coordinates.

+ * + *

Each geometry will have its own ID.

+ * + * @param geometry JTS geometry to convert + * @param layerProps layer properties for tagging features + * @param userDataConverter convert {@link Geometry#userData} to MVT feature tags + * @see #flatFeatureList(Geometry) + * @see #createTileGeom(Geometry, Envelope, GeometryFactory, MvtLayerParams, IGeometryFilter) + */ + public static List toFeatures(Geometry geometry, + MvtLayerProps layerProps, + IUserDataConverter userDataConverter) { + return toFeatures(flatFeatureList(geometry), layerProps, userDataConverter); + } + + /** + *

Convert a flat list of JTS {@link Geometry} to a list of vector tile features. + * The Geometry should be in MVT coordinates.

+ * + *

Each geometry will have its own ID.

+ * + * @param flatGeoms flat list of JTS geometry to convert + * @param layerProps layer properties for tagging features + * @param userDataConverter convert {@link Geometry#userData} to MVT feature tags + * @see #flatFeatureList(Geometry) + * @see #createTileGeom(Geometry, Envelope, GeometryFactory, MvtLayerParams, IGeometryFilter) + */ + public static List toFeatures(Collection flatGeoms, + MvtLayerProps layerProps, + IUserDataConverter userDataConverter) { + + // Guard: empty geometry + if(flatGeoms.isEmpty()) { + return Collections.emptyList(); + } + + final List features = new ArrayList<>(); + final Vec2d cursor = new Vec2d(); + + VectorTile.Tile.Feature nextFeature; + + for(Geometry nextGeom : flatGeoms) { + cursor.set(0d, 0d); + nextFeature = toFeature(nextGeom, cursor, layerProps, userDataConverter); + if(nextFeature != null) { + features.add(nextFeature); + } + } + + return features; + } + + /** + * Create and return a feature from a geometry. Returns null on failure. + * + * @param geom flat geometry via {@link #flatFeatureList(Geometry)} that can be translated to a feature + * @param cursor vector tile cursor position + * @param layerProps layer properties for tagging features + * @return new tile feature instance, or null on failure + */ + private static VectorTile.Tile.Feature toFeature(Geometry geom, + Vec2d cursor, + MvtLayerProps layerProps, + IUserDataConverter userDataConverter) { + + // Guard: UNKNOWN Geometry + final VectorTile.Tile.GeomType mvtGeomType = JtsAdapter.toGeomType(geom); + if(mvtGeomType == VectorTile.Tile.GeomType.UNKNOWN) { + return null; + } + + + final VectorTile.Tile.Feature.Builder featureBuilder = VectorTile.Tile.Feature.newBuilder(); + final boolean mvtClosePath = MvtUtil.shouldClosePath(mvtGeomType); + final List mvtGeom = new ArrayList<>(); + + featureBuilder.setType(mvtGeomType); + + if(geom instanceof Point || geom instanceof MultiPoint) { + + // Encode as MVT point or multipoint + mvtGeom.addAll(ptsToGeomCmds(geom, cursor)); + + } else if(geom instanceof LineString || geom instanceof MultiLineString) { + + // Encode as MVT linestring or multi-linestring + for (int i = 0; i < geom.getNumGeometries(); ++i) { + mvtGeom.addAll(linesToGeomCmds(geom.getGeometryN(i), mvtClosePath, cursor, 1)); + } + + } else if(geom instanceof MultiPolygon || geom instanceof Polygon) { + + // Encode as MVT polygon or multi-polygon + for(int i = 0; i < geom.getNumGeometries(); ++i) { + + final Polygon nextPoly = (Polygon) geom.getGeometryN(i); + final List nextPolyGeom = new ArrayList<>(); + boolean valid = true; + + // Add exterior ring + final LineString exteriorRing = nextPoly.getExteriorRing(); + + // Area must be non-zero + final double exteriorArea = CGAlgorithms.signedArea(exteriorRing.getCoordinates()); + if(((int) Math.round(exteriorArea)) == 0) { + continue; + } + + // Check CCW Winding (must be positive area) + if(exteriorArea < 0d) { + CoordinateArrays.reverse(exteriorRing.getCoordinates()); + } + + nextPolyGeom.addAll(linesToGeomCmds(exteriorRing, mvtClosePath, cursor, 2)); + + + // Add interior rings + for(int ringIndex = 0; ringIndex < nextPoly.getNumInteriorRing(); ++ringIndex) { + + final LineString nextInteriorRing = nextPoly.getInteriorRingN(ringIndex); + + // Area must be non-zero + final double interiorArea = CGAlgorithms.signedArea(nextInteriorRing.getCoordinates()); + if(((int)Math.round(interiorArea)) == 0) { + continue; + } + + // Check CW Winding (must be negative area) + if(interiorArea > 0d) { + CoordinateArrays.reverse(nextInteriorRing.getCoordinates()); + } + + // Interior ring area must be < exterior ring area, or entire geometry is invalid + if(Math.abs(exteriorArea) <= Math.abs(interiorArea)) { + valid = false; + break; + } + + nextPolyGeom.addAll(linesToGeomCmds(nextInteriorRing, mvtClosePath, cursor, 2)); + } + + + if(valid) { + mvtGeom.addAll(nextPolyGeom); + } + } + } + + + if(mvtGeom.size() < 1) { + return null; + } + + featureBuilder.addAllGeometry(mvtGeom); + + + // Feature Properties + userDataConverter.addTags(geom.getUserData(), layerProps, featureBuilder); + + return featureBuilder.build(); + } + + /** + *

Convert a {@link Point} or {@link MultiPoint} geometry to a list of MVT geometry drawing commands. See + * vector-tile-spec + * for details.

+ * + *

WARNING: The value of the {@code cursor} parameter is modified as a result of calling this method.

+ * + * @param geom input of type {@link Point} or {@link MultiPoint}. Type is NOT checked and expected to be correct. + * @param cursor modified during processing to contain next MVT cursor position + * @return list of commands + */ + private static List ptsToGeomCmds(final Geometry geom, final Vec2d cursor) { + + // Guard: empty geometry coordinates + final Coordinate[] geomCoords = geom.getCoordinates(); + if(geomCoords.length <= 0) { + Collections.emptyList(); + } + + + /** Tile commands and parameters */ + final List geomCmds = new ArrayList<>(geomCmdBuffLenPts(geomCoords.length)); + + /** Holds next MVT coordinate */ + final Vec2d mvtPos = new Vec2d(); + + /** Length of 'MoveTo' draw command */ + int moveCmdLen = 0; + + // Insert placeholder for 'MoveTo' command header + geomCmds.add(0); + + Coordinate nextCoord; + + for(int i = 0; i < geomCoords.length; ++i) { + nextCoord = geomCoords[i]; + mvtPos.set(nextCoord.x, nextCoord.y); + + // Ignore duplicate MVT points + if(i == 0 || !equalAsInts(cursor, mvtPos)) { + ++moveCmdLen; + moveCursor(cursor, geomCmds, mvtPos); + } + } + + + if(moveCmdLen <= GeomCmdHdr.CMD_HDR_LEN_MAX) { + + // Write 'MoveTo' command header to first index + geomCmds.set(0, GeomCmdHdr.cmdHdr(GeomCmd.MoveTo, moveCmdLen)); + + return geomCmds; + + } else { + + // Invalid geometry, need at least 1 'MoveTo' value to make points + return Collections.emptyList(); + } + } + + /** + *

Convert a {@link LineString} or {@link Polygon} to a list of MVT geometry drawing commands. + * A {@link MultiLineString} or {@link MultiPolygon} can be encoded by calling this method multiple times.

+ * + *

See vector-tile-spec for details.

+ * + *

WARNING: The value of the {@code cursor} parameter is modified as a result of calling this method.

+ * + * @param geom input of type {@link LineString} or {@link Polygon}. Type is NOT checked and expected to be correct. + * @param closeEnabled whether a 'ClosePath' command should terminate the command list + * @param cursor modified during processing to contain next MVT cursor position + * @param minLineToLen minimum allowed length for LineTo command. + * @return list of commands + */ + private static List linesToGeomCmds( + final Geometry geom, + final boolean closeEnabled, + final Vec2d cursor, + final int minLineToLen) { + + final Coordinate[] geomCoords = geom.getCoordinates(); + + // Check geometry for repeated end points + final int repeatEndCoordCount = countCoordRepeatReverse(geomCoords); + final int minExpGeomCoords = geomCoords.length - repeatEndCoordCount; + + // Guard/Optimization: Not enough geometry coordinates for a line + if(minExpGeomCoords < 2) { + Collections.emptyList(); + } + + + /** Tile commands and parameters */ + final List geomCmds = new ArrayList<>(geomCmdBuffLenLines(minExpGeomCoords, closeEnabled)); + + /** Holds next MVT coordinate */ + final Vec2d mvtPos = new Vec2d(); + + // Initial coordinate + Coordinate nextCoord = geomCoords[0]; + mvtPos.set(nextCoord.x, nextCoord.y); + + // Encode initial 'MoveTo' command + geomCmds.add(GeomCmdHdr.cmdHdr(GeomCmd.MoveTo, 1)); + + moveCursor(cursor, geomCmds, mvtPos); + + + /** Index of 'LineTo' 'command header' */ + final int lineToCmdHdrIndex = geomCmds.size(); + + // Insert placeholder for 'LineTo' command header + geomCmds.add(0); + + + /** Length of 'LineTo' draw command */ + int lineToLength = 0; + + for(int i = 1; i < minExpGeomCoords; ++i) { + nextCoord = geomCoords[i]; + mvtPos.set(nextCoord.x, nextCoord.y); + + // Ignore duplicate MVT points in sequence + if(!equalAsInts(cursor, mvtPos)) { + ++lineToLength; + moveCursor(cursor, geomCmds, mvtPos); + } + } + + if(lineToLength >= minLineToLen && lineToLength <= GeomCmdHdr.CMD_HDR_LEN_MAX) { + + // Write 'LineTo' 'command header' + geomCmds.set(lineToCmdHdrIndex, GeomCmdHdr.cmdHdr(GeomCmd.LineTo, lineToLength)); + + if(closeEnabled) { + geomCmds.add(GeomCmdHdr.closePathCmdHdr()); + } + + return geomCmds; + + } else { + + // Invalid geometry, need at least 1 'LineTo' value to make a Multiline or Polygon + return Collections.emptyList(); + } + } + + /** + *

Count number of coordinates starting from the end of the coordinate array backwards + * that match the first coordinate value.

+ * + *

Useful for ensuring self-closing line strings do not repeat the first coordinate.

+ * + * @param coords coordinates to check for duplicate points + * @return number of duplicate points at the rear of the list + */ + private static int countCoordRepeatReverse(Coordinate[] coords) { + int repeatCoords = 0; + + final Coordinate firstCoord = coords[0]; + Coordinate nextCoord; + + for(int i = coords.length - 1; i > 0; --i) { + nextCoord = coords[i]; + if(equalAsInts2d(firstCoord, nextCoord)) { + ++repeatCoords; + } else { + break; + } + } + + return repeatCoords; + } + + /** + *

Appends {@link ZigZag#encode(int)} of delta in x,y from {@code cursor} to {@code mvtPos} into the {@code geomCmds} buffer.

+ * + *

Afterwards, the {@code cursor} values are changed to match the {@code mvtPos} values.

+ * + * @param cursor MVT cursor position + * @param geomCmds geometry command list + * @param mvtPos next MVT cursor position + */ + private static void moveCursor(Vec2d cursor, List geomCmds, Vec2d mvtPos) { + + // Delta, then zigzag + geomCmds.add(ZigZag.encode((int)mvtPos.x - (int)cursor.x)); + geomCmds.add(ZigZag.encode((int)mvtPos.y - (int)cursor.y)); + + cursor.set(mvtPos); + } + + /** + * Return true if the values of the two {@link Coordinate} are equal when their + * first and second ordinates are cast as ints. Ignores 3rd ordinate. + * + * @param a first coordinate to compare + * @param b second coordinate to compare + * @return true if the values of the two {@link Coordinate} are equal when their + * first and second ordinates are cast as ints + */ + private static boolean equalAsInts2d(Coordinate a, Coordinate b) { + return ((int)a.getOrdinate(0)) == ((int)b.getOrdinate(0)) + && ((int)a.getOrdinate(1)) == ((int)b.getOrdinate(1)); + } + + /** + * Return true if the values of the two vectors are equal when cast as ints. + * + * @param a first vector to compare + * @param b second vector to compare + * @return true if the values of the two vectors are equal when cast as ints + */ + private static boolean equalAsInts(Vec2d a, Vec2d b) { + return ((int) a.x) == ((int) b.x) && ((int) a.y) == ((int) b.y); + } + + /** + * Get required geometry buffer size for a {@link Point} or {@link MultiPoint} geometry. + * + * @param coordCount coordinate count for the geometry + * @return required geometry buffer length + */ + private static int geomCmdBuffLenPts(int coordCount) { + + // 1 MoveTo Header, 2 parameters * coordCount + return 1 + (coordCount * 2); + } + + /** + * Get required geometry buffer size for a {@link LineString} or {@link Polygon} geometry. + * + * @param coordCount coordinate count for the geometry + * @param closeEnabled whether a 'ClosePath' command should terminate the command list + * @return required geometry buffer length + */ + private static int geomCmdBuffLenLines(int coordCount, boolean closeEnabled) { + + // MoveTo Header, LineTo Header, Optional ClosePath Header, 2 parameters * coordCount + return 2 + (closeEnabled ? 1 : 0) + (coordCount * 2); + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/MvtReader.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/MvtReader.java new file mode 100644 index 0000000000..6083ca980e --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/MvtReader.java @@ -0,0 +1,599 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.vividsolutions.jts.algorithm.CGAlgorithms; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.wdtinc.mapbox_vector_tile.encoding.GeomCmd; +import com.wdtinc.mapbox_vector_tile.encoding.GeomCmdHdr; +import com.wdtinc.mapbox_vector_tile.encoding.ZigZag; +import com.wdtinc.mapbox_vector_tile.util.Vec2d; + +import net.osmand.binary.VectorTile; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * Load Mapbox Vector Tiles (MVT) to JTS {@link Geometry}. Feature tags may be converted + * to user data via {@link ITagConverter}. + */ +public final class MvtReader { + private static final int MIN_LINE_STRING_LEN = 6; // MoveTo,1 + LineTo,1 + private static final int MIN_POLYGON_LEN = 9; // MoveTo,1 + LineTo,2 + ClosePath + + /** + * Convenience method for loading MVT from file. + * See {@link #loadMvt(InputStream, GeometryFactory, ITagConverter, RingClassifier)}. + * Uses {@link #RING_CLASSIFIER_V2_1} for forming Polygons and MultiPolygons. + * + * @param f MVT file + * @param geomFactory allows for JTS geometry creation + * @param tagConverter converts MVT feature tags to JTS user data object + * @return JTS geometries in using MVT coordinates + * @throws IOException failure reading MVT from path + * @see #loadMvt(InputStream, GeometryFactory, ITagConverter, RingClassifier) + * @see Geometry + * @see Geometry#getUserData() + * @see RingClassifier + */ + public static List loadMvt(File f, + GeometryFactory geomFactory, + ITagConverter tagConverter) throws IOException { + return loadMvt(f, geomFactory, tagConverter, RING_CLASSIFIER_V2_1); + } + + /** + * Convenience method for loading MVT from file. + * See {@link #loadMvt(InputStream, GeometryFactory, ITagConverter, RingClassifier)}. + * + * @param f MVT file + * @param geomFactory allows for JTS geometry creation + * @param tagConverter converts MVT feature tags to JTS user data object + * @param ringClassifier determines how rings are parsed into Polygons and MultiPolygons + * @return JTS geometries in using MVT coordinates + * @throws IOException failure reading MVT from path + * @see #loadMvt(InputStream, GeometryFactory, ITagConverter, RingClassifier) + * @see Geometry + * @see Geometry#getUserData() + * @see RingClassifier + */ + public static List loadMvt(File f, + GeometryFactory geomFactory, + ITagConverter tagConverter, + RingClassifier ringClassifier) throws IOException { + final InputStream is = new FileInputStream(f); + return loadMvt(is, geomFactory, tagConverter, ringClassifier); + } + + /** + * Load an MVT to JTS geometries using coordinates. Uses {@code tagConverter} to create user data + * from feature properties. Uses {@link #RING_CLASSIFIER_V2_1} for forming Polygons and MultiPolygons. + * + * @param is stream with MVT data + * @param geomFactory allows for JTS geometry creation + * @param tagConverter converts MVT feature tags to JTS user data object. + * @return JTS geometries in using MVT coordinates + * @throws IOException failure reading MVT from stream + * @see Geometry + * @see Geometry#getUserData() + * @see RingClassifier + */ + public static List loadMvt(InputStream is, + GeometryFactory geomFactory, + ITagConverter tagConverter) throws IOException { + return loadMvt(is, geomFactory, tagConverter, RING_CLASSIFIER_V2_1); + } + + + /** + * Load an MVT to JTS geometries using coordinates. Uses {@code tagConverter} to create user data + * from feature properties. + * + * @param is stream with MVT data + * @param geomFactory allows for JTS geometry creation + * @param tagConverter converts MVT feature tags to JTS user data object. + * @param ringClassifier determines how rings are parsed into Polygons and MultiPolygons + * @return JTS geometries in using MVT coordinates + * @throws IOException failure reading MVT from stream + * @see Geometry + * @see Geometry#getUserData() + * @see RingClassifier + */ + public static List loadMvt(InputStream is, + GeometryFactory geomFactory, + ITagConverter tagConverter, + RingClassifier ringClassifier) throws IOException { + + final List tileGeoms = new ArrayList<>(); + final VectorTile.Tile mvt = VectorTile.Tile.parseFrom(is); + final Vec2d cursor = new Vec2d(); + + for (VectorTile.Tile.Layer nextLayer : mvt.getLayersList()) { + + final List keysList = nextLayer.getKeysList(); + final List valuesList = nextLayer.getValuesList(); + + for (VectorTile.Tile.Feature nextFeature : nextLayer.getFeaturesList()) { + + final Long id = nextFeature.hasId() ? nextFeature.getId() : null; + + final VectorTile.Tile.GeomType geomType = nextFeature.getType(); + + if (geomType == VectorTile.Tile.GeomType.UNKNOWN) { + continue; + } + + final List geomCmds = nextFeature.getGeometryList(); + cursor.set(0d, 0d); + final Geometry nextGeom = readGeometry(geomCmds, geomType, geomFactory, cursor, ringClassifier); + if (nextGeom != null) { + tileGeoms.add(nextGeom); + nextGeom.setUserData(tagConverter.toUserData(id, nextFeature.getTagsList(), keysList, valuesList)); + } + } + } + + return tileGeoms; + } + + private static Geometry readGeometry(List geomCmds, + VectorTile.Tile.GeomType geomType, + GeometryFactory geomFactory, + Vec2d cursor, + RingClassifier ringClassifier) { + Geometry result = null; + + switch (geomType) { + case POINT: + result = readPoints(geomFactory, geomCmds, cursor); + break; + case LINESTRING: + result = readLines(geomFactory, geomCmds, cursor); + break; + case POLYGON: + result = readPolys(geomFactory, geomCmds, cursor, ringClassifier); + break; + default: + //LoggerFactory.getLogger(MvtReader.class).error("readGeometry(): Unhandled geometry type [{}]", geomType); + } + + return result; + } + + /** + * Create {@link Point} or {@link MultiPoint} from MVT geometry drawing commands. + * + * @param geomFactory creates JTS geometry + * @param geomCmds contains MVT geometry commands + * @param cursor contains current MVT extent position + * @return JTS geometry or null on failure + */ + private static Geometry readPoints(GeometryFactory geomFactory, List geomCmds, Vec2d cursor) { + + // Guard: must have header + if (geomCmds.isEmpty()) { + return null; + } + + /** Geometry command index */ + int i = 0; + + // Read command header + final int cmdHdr = geomCmds.get(i++); + final int cmdLength = GeomCmdHdr.getCmdLength(cmdHdr); + final GeomCmd cmd = GeomCmdHdr.getCmd(cmdHdr); + + // Guard: command type + if (cmd != GeomCmd.MoveTo) { + return null; + } + + // Guard: minimum command length + if (cmdLength < 1) { + return null; + } + + // Guard: header data unsupported by geometry command buffer + // (require header and at least 1 value * 2 params) + if (cmdLength * GeomCmd.MoveTo.getParamCount() + 1 > geomCmds.size()) { + return null; + } + + final CoordinateSequence coordSeq = geomFactory.getCoordinateSequenceFactory().create(cmdLength, 2); + int coordIndex = 0; + Coordinate nextCoord; + + while (i < geomCmds.size() - 1) { + cursor.add( + ZigZag.decode(geomCmds.get(i++)), + ZigZag.decode(geomCmds.get(i++)) + ); + + nextCoord = coordSeq.getCoordinate(coordIndex++); + nextCoord.setOrdinate(0, cursor.x); + nextCoord.setOrdinate(1, cursor.y); + } + + return coordSeq.size() == 1 ? geomFactory.createPoint(coordSeq) : geomFactory.createMultiPoint(coordSeq); + } + + /** + * Create {@link LineString} or {@link MultiLineString} from MVT geometry drawing commands. + * + * @param geomFactory creates JTS geometry + * @param geomCmds contains MVT geometry commands + * @param cursor contains current MVT extent position + * @return JTS geometry or null on failure + */ + private static Geometry readLines(GeometryFactory geomFactory, List geomCmds, Vec2d cursor) { + + // Guard: must have header + if (geomCmds.isEmpty()) { + return null; + } + + /** Geometry command index */ + int i = 0; + + int cmdHdr; + int cmdLength; + GeomCmd cmd; + List geoms = new ArrayList<>(1); + CoordinateSequence nextCoordSeq; + Coordinate nextCoord; + + while (i <= geomCmds.size() - MIN_LINE_STRING_LEN) { + + // -------------------------------------------- + // Expected: MoveTo command of length 1 + // -------------------------------------------- + + // Read command header + cmdHdr = geomCmds.get(i++); + cmdLength = GeomCmdHdr.getCmdLength(cmdHdr); + cmd = GeomCmdHdr.getCmd(cmdHdr); + + // Guard: command type and length + if (cmd != GeomCmd.MoveTo || cmdLength != 1) { + break; + } + + // Update cursor position with relative move + cursor.add( + ZigZag.decode(geomCmds.get(i++)), + ZigZag.decode(geomCmds.get(i++)) + ); + + + // -------------------------------------------- + // Expected: LineTo command of length > 0 + // -------------------------------------------- + + // Read command header + cmdHdr = geomCmds.get(i++); + cmdLength = GeomCmdHdr.getCmdLength(cmdHdr); + cmd = GeomCmdHdr.getCmd(cmdHdr); + + // Guard: command type and length + if (cmd != GeomCmd.LineTo || cmdLength < 1) { + break; + } + + // Guard: header data length unsupported by geometry command buffer + // (require at least (1 value * 2 params) + current_index) + if ((cmdLength * GeomCmd.LineTo.getParamCount()) + i > geomCmds.size()) { + break; + } + + nextCoordSeq = geomFactory.getCoordinateSequenceFactory().create(1 + cmdLength, 2); + + // Set first point from MoveTo command + nextCoord = nextCoordSeq.getCoordinate(0); + nextCoord.setOrdinate(0, cursor.x); + nextCoord.setOrdinate(1, cursor.y); + + // Set remaining points from LineTo command + for (int lineToIndex = 0; lineToIndex < cmdLength; ++lineToIndex) { + + // Update cursor position with relative line delta + cursor.add( + ZigZag.decode(geomCmds.get(i++)), + ZigZag.decode(geomCmds.get(i++)) + ); + + nextCoord = nextCoordSeq.getCoordinate(lineToIndex + 1); + nextCoord.setOrdinate(0, cursor.x); + nextCoord.setOrdinate(1, cursor.y); + } + + geoms.add(geomFactory.createLineString(nextCoordSeq)); + } + + return geoms.size() == 1 ? geoms.get(0) : geomFactory.createMultiLineString(geoms.toArray(new LineString[geoms.size()])); + } + + /** + * Create {@link Polygon} or {@link MultiPolygon} from MVT geometry drawing commands. + * + * @param geomFactory creates JTS geometry + * @param geomCmds contains MVT geometry commands + * @param cursor contains current MVT extent position + * @param ringClassifier + * @return JTS geometry or null on failure + */ + private static Geometry readPolys(GeometryFactory geomFactory, + List geomCmds, + Vec2d cursor, + RingClassifier ringClassifier) { + + // Guard: must have header + if (geomCmds.isEmpty()) { + return null; + } + + /** Geometry command index */ + int i = 0; + + int cmdHdr; + int cmdLength; + GeomCmd cmd; + List rings = new ArrayList<>(1); + CoordinateSequence nextCoordSeq; + Coordinate nextCoord; + + while (i <= geomCmds.size() - MIN_POLYGON_LEN) { + + // -------------------------------------------- + // Expected: MoveTo command of length 1 + // -------------------------------------------- + + // Read command header + cmdHdr = geomCmds.get(i++); + cmdLength = GeomCmdHdr.getCmdLength(cmdHdr); + cmd = GeomCmdHdr.getCmd(cmdHdr); + + // Guard: command type and length + if (cmd != GeomCmd.MoveTo || cmdLength != 1) { + break; + } + + // Update cursor position with relative move + cursor.add( + ZigZag.decode(geomCmds.get(i++)), + ZigZag.decode(geomCmds.get(i++)) + ); + + + // -------------------------------------------- + // Expected: LineTo command of length > 1 + // -------------------------------------------- + + // Read command header + cmdHdr = geomCmds.get(i++); + cmdLength = GeomCmdHdr.getCmdLength(cmdHdr); + cmd = GeomCmdHdr.getCmd(cmdHdr); + + // Guard: command type and length + if (cmd != GeomCmd.LineTo || cmdLength < 2) { + break; + } + + // Guard: header data length unsupported by geometry command buffer + // (require at least (2 values * 2 params) + (current index 'i') + (1 for ClosePath)) + if ((cmdLength * GeomCmd.LineTo.getParamCount()) + i + 1 > geomCmds.size()) { + break; + } + + nextCoordSeq = geomFactory.getCoordinateSequenceFactory().create(2 + cmdLength, 2); + + // Set first point from MoveTo command + nextCoord = nextCoordSeq.getCoordinate(0); + nextCoord.setOrdinate(0, cursor.x); + nextCoord.setOrdinate(1, cursor.y); + + // Set remaining points from LineTo command + for (int lineToIndex = 0; lineToIndex < cmdLength; ++lineToIndex) { + + // Update cursor position with relative line delta + cursor.add( + ZigZag.decode(geomCmds.get(i++)), + ZigZag.decode(geomCmds.get(i++)) + ); + + nextCoord = nextCoordSeq.getCoordinate(lineToIndex + 1); + nextCoord.setOrdinate(0, cursor.x); + nextCoord.setOrdinate(1, cursor.y); + } + + + // -------------------------------------------- + // Expected: ClosePath command of length 1 + // -------------------------------------------- + + // Read command header + cmdHdr = geomCmds.get(i++); + cmdLength = GeomCmdHdr.getCmdLength(cmdHdr); + cmd = GeomCmdHdr.getCmd(cmdHdr); + + if (cmd != GeomCmd.ClosePath || cmdLength != 1) { + break; + } + + // Set last point from ClosePath command + nextCoord = nextCoordSeq.getCoordinate(nextCoordSeq.size() - 1); + nextCoord.setOrdinate(0, nextCoordSeq.getOrdinate(0, 0)); + nextCoord.setOrdinate(1, nextCoordSeq.getOrdinate(0, 1)); + + rings.add(geomFactory.createLinearRing(nextCoordSeq)); + } + + + // Classify rings + final List polygons = ringClassifier.classifyRings(rings, geomFactory); + if (polygons.size() < 1) { + return null; + + } else if (polygons.size() == 1) { + return polygons.get(0); + + } else { + return geomFactory.createMultiPolygon(polygons.toArray(new Polygon[polygons.size()])); + } + } + + + /** + * Classifies Polygon and MultiPolygon rings. + */ + public interface RingClassifier { + + /** + *

Classify a list of rings into polygons using surveyor formula.

+ *

+ *

Zero-area polygons are removed.

+ * + * @param rings linear rings to classify into polygons + * @param geomFactory creates JTS geometry + * @return polygons from classified rings + */ + List classifyRings(List rings, GeometryFactory geomFactory); + } + + + /** + * Area for surveyor formula may be positive or negative for exterior rings. Mimics Mapbox parsers supporting V1. + */ + public static final RingClassifier RING_CLASSIFIER_V1 = new PolyRingClassifierV1(); + + /** + * Area from surveyor formula must be positive for exterior rings. Obeys V2.1 spec. + */ + public static final RingClassifier RING_CLASSIFIER_V2_1 = new PolyRingClassifierV2_1(); + + + /** + * Area from surveyor formula must be positive for exterior rings. Obeys V2.1 spec. + * + * @see CGAlgorithms#signedArea(Coordinate[]) + */ + private static final class PolyRingClassifierV2_1 implements RingClassifier { + + @Override + public List classifyRings(List rings, GeometryFactory geomFactory) { + final List polygons = new ArrayList<>(); + final List holes = new ArrayList<>(); + + double outerArea = 0d; + LinearRing outerPoly = null; + + for (LinearRing r : rings) { + double area = CGAlgorithms.signedArea(r.getCoordinates()); + + if (!r.isRing()) { + continue; // sanity check, could probably be handled in a isSimple() check + } + + if (area == 0d) { + continue; // zero-area + } + + if (area > 0d) { + if (outerPoly != null) { + polygons.add(geomFactory.createPolygon(outerPoly, holes.toArray(new LinearRing[holes.size()]))); + holes.clear(); + } + + // Pos --> CCW, Outer + outerPoly = r; + outerArea = area; + + } else { + + if (Math.abs(outerArea) < Math.abs(area)) { + continue; // Holes must have less area, could probably be handled in a isSimple() check + } + + // Neg --> CW, Hole + holes.add(r); + } + } + + if (outerPoly != null) { + holes.toArray(); + polygons.add(geomFactory.createPolygon(outerPoly, holes.toArray(new LinearRing[holes.size()]))); + } + + return polygons; + } + } + + + /** + * Area for surveyor formula may be positive or negative for exterior rings. Mimics Mapbox parsers supporting V1. + * + * @see CGAlgorithms#signedArea(Coordinate[]) + */ + private static final class PolyRingClassifierV1 implements RingClassifier { + + @Override + public List classifyRings(List rings, GeometryFactory geomFactory) { + final List polygons = new ArrayList<>(); + final List holes = new ArrayList<>(); + + double outerArea = 0d; + LinearRing outerPoly = null; + + for (LinearRing r : rings) { + double area = CGAlgorithms.signedArea(r.getCoordinates()); + + if (!r.isRing()) { + continue; // sanity check, could probably be handled in a isSimple() check + } + + if (area == 0d) { + continue; // zero-area + } + + if (outerPoly == null || (outerArea < 0 == area < 0)) { + if (outerPoly != null) { + polygons.add(geomFactory.createPolygon(outerPoly, holes.toArray(new LinearRing[holes.size()]))); + holes.clear(); + } + + // Pos --> CCW, Outer + outerPoly = r; + outerArea = area; + + } else { + + if (Math.abs(outerArea) < Math.abs(area)) { + continue; // Holes must have less area, could probably be handled in a isSimple() check + } + + // Neg --> CW, Hole + holes.add(r); + } + } + + if (outerPoly != null) { + holes.toArray(); + polygons.add(geomFactory.createPolygon(outerPoly, holes.toArray(new LinearRing[holes.size()]))); + } + + return polygons; + } + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/RoundingFilter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/RoundingFilter.java new file mode 100644 index 0000000000..0cbb6994c6 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/RoundingFilter.java @@ -0,0 +1,33 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.CoordinateSequenceFilter; + +/** + *

Round each coordinate value to an integer.

+ * + *

Mapbox vector tiles have fixed precision. This filter can be useful for reducing precision to + * the extent of a MVT.

+ */ +public final class RoundingFilter implements CoordinateSequenceFilter { + + public static final RoundingFilter INSTANCE = new RoundingFilter(); + + private RoundingFilter() {} + + @Override + public void filter(CoordinateSequence seq, int i) { + seq.setOrdinate(i, 0, Math.round(seq.getOrdinate(i, 0))); + seq.setOrdinate(i, 1, Math.round(seq.getOrdinate(i, 1))); + } + + @Override + public boolean isDone() { + return false; + } + + @Override + public boolean isGeometryChanged() { + return true; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TagIgnoreConverter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TagIgnoreConverter.java new file mode 100644 index 0000000000..bc648b8742 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TagIgnoreConverter.java @@ -0,0 +1,18 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import net.osmand.binary.VectorTile; + +import java.util.List; + +/** + * Ignores tags, always returns null. + * + * @see ITagConverter + */ +public final class TagIgnoreConverter implements ITagConverter { + @Override + public Object toUserData(Long id, List tags, List keysList, + List valuesList) { + return null; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TagKeyValueMapConverter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TagKeyValueMapConverter.java new file mode 100644 index 0000000000..59d24ba8c9 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TagKeyValueMapConverter.java @@ -0,0 +1,99 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.wdtinc.mapbox_vector_tile.encoding.MvtValue; + +import net.osmand.binary.VectorTile; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Convert MVT tags list to a {@link Map} of {@link String} to {@link Object}. Tags indices that are out + * of range of the key or value list are ignored. + * + * @see ITagConverter + */ +public final class TagKeyValueMapConverter implements ITagConverter { + + /** If true, return null user data when tags are empty */ + private final boolean nullIfEmpty; + + /** If true, add id to user data object */ + private final boolean addId; + + /** The {@link Map} key for the feature id. */ + private final String idKey; + + /** + * Always created user data object, even with empty tags. Ignore feature ids. + */ + public TagKeyValueMapConverter() { + this(false); + } + + /** + * Ignore feature ids. + * + * @param nullIfEmpty if true, return null user data when tags are empty + */ + public TagKeyValueMapConverter(boolean nullIfEmpty) { + this.nullIfEmpty = nullIfEmpty; + this.addId = false; + this.idKey = null; + } + + /** + * Store feature ids using idKey. Id value may be null if not present. + * + * @param nullIfEmpty if true, return null user data when tags are empty + * @param idKey key name to use for feature id value + */ + public TagKeyValueMapConverter(boolean nullIfEmpty, String idKey) { + if (idKey == null) { + throw new NullPointerException(); + } + + this.nullIfEmpty = nullIfEmpty; + this.addId = true; + this.idKey = idKey; + } + + @Override + public Object toUserData(Long id, List tags, List keysList, + List valuesList) { + + // Guard: empty + if(nullIfEmpty && tags.size() < 1 && (!addId || id == null)) { + return null; + } + + + final Map userData = new HashMap<>(((tags.size() + 1) / 2)); + + // Add feature properties + int keyIndex; + int valIndex; + boolean valid; + + for(int i = 0; i < tags.size() - 1; i += 2) { + keyIndex = tags.get(i); + valIndex = tags.get(i + 1); + + valid = keyIndex >= 0 && keyIndex < keysList.size() + && valIndex >= 0 && valIndex < valuesList.size(); + + if(valid) { + userData.put(keysList.get(keyIndex), MvtValue.toObject(valuesList.get(valIndex))); + } + } + + // Add ID, value may be null + if(addId) { + userData.put(idKey, id); + } + + return userData; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TileGeomResult.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TileGeomResult.java new file mode 100644 index 0000000000..f74ca25392 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/TileGeomResult.java @@ -0,0 +1,35 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.wdtinc.mapbox_vector_tile.build.MvtLayerParams; + +import java.util.List; + +/** + * Processing result containing intersection geometry and MVT geometry. + * + * @see JtsAdapter#createTileGeom(Geometry, Envelope, GeometryFactory, MvtLayerParams, IGeometryFilter) + */ +public final class TileGeomResult { + + /** Intersection geometry (projection units and coordinates) */ + public final List intGeoms; + + /** Geometry in MVT coordinates (tile extent units, screen coordinates) */ + public final List mvtGeoms; + + /** + * @param intGeoms geometry intersecting tile + * @param mvtGeoms geometry for MVT + * @throws NullPointerException if intGeoms or mvtGeoms are null + */ + public TileGeomResult(List intGeoms, List mvtGeoms) { + if(intGeoms == null || mvtGeoms == null) { + throw new NullPointerException(); + } + this.intGeoms = intGeoms; + this.mvtGeoms = mvtGeoms; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/UserDataIgnoreConverter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/UserDataIgnoreConverter.java new file mode 100644 index 0000000000..c61f13855e --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/UserDataIgnoreConverter.java @@ -0,0 +1,15 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.wdtinc.mapbox_vector_tile.build.MvtLayerProps; + +import net.osmand.binary.VectorTile; + +/** + * Ignores user data, does not take any action. + * + * @see IUserDataConverter + */ +public final class UserDataIgnoreConverter implements IUserDataConverter { + @Override + public void addTags(Object userData, MvtLayerProps layerProps, VectorTile.Tile.Feature.Builder featureBuilder) {} +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/UserDataKeyValueMapConverter.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/UserDataKeyValueMapConverter.java new file mode 100644 index 0000000000..2325251c2c --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/adapt/jts/UserDataKeyValueMapConverter.java @@ -0,0 +1,88 @@ +package com.wdtinc.mapbox_vector_tile.adapt.jts; + +import com.wdtinc.mapbox_vector_tile.build.MvtLayerProps; + +import net.osmand.binary.VectorTile; + +import java.util.Map; +import java.util.Objects; + +/** + * Convert simple user data {@link Map} where the keys are {@link String} and values are {@link Object}. Supports + * converting a specific map key to a user id. If the key to user id conversion fails, the error occurs silently + * and the id is discarded. + * + * @see IUserDataConverter + */ +public final class UserDataKeyValueMapConverter implements IUserDataConverter { + + /** If true, set feature id from user data */ + private final boolean setId; + + /** The {@link Map} key for the feature id. */ + private final String idKey; + + /** + * Does not set feature id. + */ + public UserDataKeyValueMapConverter() { + this.setId = false; + this.idKey = null; + } + + /** + * Tries to set feature id using provided user data {@link Map} key. + * + * @param idKey user data {@link Map} key for getting id value. + */ + public UserDataKeyValueMapConverter(String idKey) { + if (idKey == null) { + throw new NullPointerException(); + } + this.setId = true; + this.idKey = idKey; + } + + @Override + public void addTags(Object userData, MvtLayerProps layerProps, VectorTile.Tile.Feature.Builder featureBuilder) { + if(userData != null) { + try { + @SuppressWarnings("unchecked") + final Map userDataMap = (Map)userData; + + for(Map.Entry e :userDataMap.entrySet()){ + final String key = e.getKey(); + final Object value = e.getValue(); + + if(key != null && value != null) { + final int valueIndex = layerProps.addValue(value); + + if(valueIndex >= 0) { + featureBuilder.addTags(layerProps.addKey(key)); + featureBuilder.addTags(valueIndex); + } + } + } + + // Set feature id value + if(setId) { + final Object idValue = userDataMap.get(idKey); + if (idValue != null) { + if(idValue instanceof Long || idValue instanceof Integer + || idValue instanceof Float || idValue instanceof Double + || idValue instanceof Byte || idValue instanceof Short) { + featureBuilder.setId((long)idValue); + } else if(idValue instanceof String) { + try { + featureBuilder.setId(Long.valueOf((String)idValue)); + } catch (NumberFormatException ignored) {} + } + } + } + + } catch (ClassCastException e) { + //LoggerFactory.getLogger(UserDataKeyValueMapConverter.class).error(e.getMessage(), e); + } + } + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/GeomCmd.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/GeomCmd.java new file mode 100644 index 0000000000..3cfdacf354 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/GeomCmd.java @@ -0,0 +1,63 @@ +package com.wdtinc.mapbox_vector_tile.encoding; + +/** + * MVT draw command types. + * + * @see GeomCmdHdr + */ +public enum GeomCmd { + MoveTo(1, 2), + LineTo(2, 2), + ClosePath(7, 0); + + /** Unique command ID */ + private final int cmdId; + + /** Amount of parameters that follow the command */ + private final int paramCount; + + GeomCmd(int cmdId, int paramCount) { + this.cmdId = cmdId; + this.paramCount = paramCount; + } + + /** + * @return unique command ID + */ + public int getCmdId() { + return cmdId; + } + + /** + * @return amount of parameters that follow the command + */ + public int getParamCount() { + return paramCount; + } + + + /** + * Return matching {@link GeomCmd} for the provided cmdId, or null if there is not + * a matching command. + * + * @param cmdId command id to find match for + * @return command with matching id, or null if there is not a matching command + */ + public static GeomCmd fromId(int cmdId) { + final GeomCmd geomCmd; + switch (cmdId) { + case 1: + geomCmd = MoveTo; + break; + case 2: + geomCmd = LineTo; + break; + case 7: + geomCmd = ClosePath; + break; + default: + geomCmd = null; + } + return geomCmd; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/GeomCmdHdr.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/GeomCmdHdr.java new file mode 100644 index 0000000000..776d57a295 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/GeomCmdHdr.java @@ -0,0 +1,68 @@ +package com.wdtinc.mapbox_vector_tile.encoding; + + +/** + * Utilities for working with geometry command headers. + * + * @see GeomCmd + */ +public final class GeomCmdHdr { + + private static int CLOSE_PATH_HDR = cmdHdr(GeomCmd.ClosePath, 1); + + /** + *

Encodes a 'command header' with the first 3 LSB as the command id, the remaining bits + * as the command length. See the vector-tile-spec for details.

+ * + * @param cmd command to execute + * @param length how many times the command is repeated + * @return encoded 'command header' integer + */ + public static int cmdHdr(GeomCmd cmd, int length) { + return (cmd.getCmdId() & 0x7) | (length << 3); + } + + /** + * Get the length component from the 'command header' integer. + * + * @param cmdHdr encoded 'command header' integer + * @return command length + */ + public static int getCmdLength(int cmdHdr) { + return cmdHdr >> 3; + } + + /** + * Get the id component from the 'command header' integer. + * + * @param cmdHdr encoded 'command header' integer + * @return command id + */ + public static int getCmdId(int cmdHdr) { + return cmdHdr & 0x7; + } + + /** + * Get the id component from the 'command header' integer, then find the + * {@link GeomCmd} with a matching id. + * + * @param cmdHdr encoded 'command header' integer + * @return command with matching id, or null if a match could not be made + */ + public static GeomCmd getCmd(int cmdHdr) { + final int cmdId = getCmdId(cmdHdr); + return GeomCmd.fromId(cmdId); + } + + /** + * @return encoded 'command header' integer for {@link GeomCmd#ClosePath}. + */ + public static int closePathCmdHdr() { + return CLOSE_PATH_HDR; + } + + /** + * Maximum allowed 'command header' length value. + */ + public static final int CMD_HDR_LEN_MAX = (int) (Math.pow(2, 29) - 1); +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/MvtUtil.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/MvtUtil.java new file mode 100644 index 0000000000..d1ac1be819 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/MvtUtil.java @@ -0,0 +1,33 @@ +package com.wdtinc.mapbox_vector_tile.encoding; + + +import net.osmand.binary.VectorTile; + +/** + *

Useful misc operations for encoding 'Mapbox Vector Tiles'.

+ * + *

See: https://github.com/mapbox/vector-tile-spec

+ */ +public final class MvtUtil { + + /** + * Return whether the MVT geometry type should be closed with a {@link GeomCmd#ClosePath}. + * + * @param geomType the type of MVT geometry + * @return true if the geometry should be closed, false if it should not be closed + */ + public static boolean shouldClosePath(VectorTile.Tile.GeomType geomType) { + final boolean closeReq; + + switch(geomType) { + case POLYGON: + closeReq = true; + break; + default: + closeReq = false; + break; + } + + return closeReq; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/MvtValue.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/MvtValue.java new file mode 100644 index 0000000000..566ea1d6d5 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/MvtValue.java @@ -0,0 +1,94 @@ +package com.wdtinc.mapbox_vector_tile.encoding; + + +import net.osmand.binary.VectorTile; + +/** + * Utility class for working with {@link VectorTile.Tile.Value} instances. + * + * @see VectorTile.Tile.Value + */ +public final class MvtValue { + + /** + * Covert an {@link Object} to a new {@link VectorTile.Tile.Value} instance. + * + * @param value target for conversion + * @return new instance with String or primitive value set + */ + public static VectorTile.Tile.Value toValue(Object value) { + final VectorTile.Tile.Value.Builder tileValue = VectorTile.Tile.Value.newBuilder(); + + if(value instanceof Boolean) { + tileValue.setBoolValue((Boolean) value); + + } else if(value instanceof Integer) { + tileValue.setSintValue((Integer) value); + + } else if(value instanceof Long) { + tileValue.setSintValue((Long) value); + + } else if(value instanceof Float) { + tileValue.setFloatValue((Float) value); + + } else if(value instanceof Double) { + tileValue.setDoubleValue((Double) value); + + } else if(value instanceof String) { + tileValue.setStringValue((String) value); + } + + return tileValue.build(); + } + + /** + * Convert {@link VectorTile.Tile.Value} to String or boxed primitive object. + * + * @param value target for conversion + * @return String or boxed primitive + */ + public static Object toObject(VectorTile.Tile.Value value) { + Object result = null; + + if(value.hasDoubleValue()) { + result = value.getDoubleValue(); + + } else if(value.hasFloatValue()) { + result = value.getFloatValue(); + + } else if(value.hasIntValue()) { + result = value.getIntValue(); + + } else if(value.hasBoolValue()) { + result = value.getBoolValue(); + + } else if(value.hasStringValue()) { + result = value.getStringValue(); + + } else if(value.hasSintValue()) { + result = value.getSintValue(); + + } else if(value.hasUintValue()) { + result = value.getUintValue(); + } + + return result; + } + + /** + * Check if {@code value} is valid for encoding as a MVT layer property value. + * + * @param value target to check + * @return true is the object is a type that is supported by MVT + */ + public static boolean isValidPropValue(Object value) { + boolean isValid = false; + + if(value instanceof Boolean || value instanceof Integer || value instanceof Long + || value instanceof Float || value instanceof Double || value instanceof String) { + isValid = true; + } + + return isValid; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/ZigZag.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/ZigZag.java new file mode 100644 index 0000000000..ca82192129 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/encoding/ZigZag.java @@ -0,0 +1,27 @@ +package com.wdtinc.mapbox_vector_tile.encoding; + +/** + * See: Google Protocol Buffers Docs + */ +public final class ZigZag { + + /** + * See: Google Protocol Buffers Docs + * + * @param n integer to encode + * @return zig-zag encoded integer + */ + public static int encode(int n) { + return (n << 1) ^ (n >> 31); + } + + /** + * See: Google Protocol Buffers Docs + * + * @param n zig-zag encoded integer to decode + * @return decoded integer + */ + public static int decode(int n) { + return (n >> 1) ^ (-(n & 1)); + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/util/JtsGeomStats.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/util/JtsGeomStats.java new file mode 100644 index 0000000000..52618e3878 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/util/JtsGeomStats.java @@ -0,0 +1,151 @@ +package com.wdtinc.mapbox_vector_tile.util; + +import com.vividsolutions.jts.geom.*; +import com.wdtinc.mapbox_vector_tile.adapt.jts.JtsAdapter; + +import net.osmand.binary.VectorTile; + +import java.util.*; + +public final class JtsGeomStats { + + public static final class FeatureStats { + public int totalPts; + public int repeatedPts; + + @Override + public String toString() { + return "FeatureStats{" + + "totalPts=" + totalPts + + ", repeatedPts=" + repeatedPts + + '}'; + } + } + + public Map featureCounts; + public List featureStats; + + private JtsGeomStats() { + final VectorTile.Tile.GeomType[] geomTypes = VectorTile.Tile.GeomType.values(); + featureCounts = new HashMap<>(geomTypes.length); + + for(VectorTile.Tile.GeomType nextGeomType : geomTypes) { + featureCounts.put(nextGeomType, 0); + } + + this.featureStats = new ArrayList<>(); + } + + @Override + public String toString() { + return "JtsGeomStats{" + + "featureCounts=" + featureCounts + + ", featureStats=" + featureStats + + '}'; + } + + public static JtsGeomStats getStats(List flatGeomList) { + final JtsGeomStats stats = new JtsGeomStats(); + + for(Geometry nextGeom : flatGeomList) { + final VectorTile.Tile.GeomType geomType = JtsAdapter.toGeomType(nextGeom); + + // Count features by type + Integer oldValue = stats.featureCounts.get(geomType); + if(oldValue!=null){ + oldValue+=1; + stats.featureCounts.put(geomType, oldValue); + } + + // Get stats per feature + stats.featureStats.add(getStats(nextGeom, geomType)); + } + + return stats; + } + + private static FeatureStats getStats(Geometry geom, VectorTile.Tile.GeomType type) { + FeatureStats featureStats; + + switch (type) { + case POINT: + featureStats = pointStats(geom); + break; + case LINESTRING: + featureStats = lineStats(geom); + break; + case POLYGON: + featureStats = polyStats(geom); + break; + default: + featureStats = new FeatureStats(); + } + + return featureStats; + } + + private static FeatureStats pointStats(Geometry geom) { + final FeatureStats featureStats = new FeatureStats(); + + final HashSet pointSet = new HashSet<>(geom.getNumPoints()); + featureStats.totalPts = geom.getNumPoints(); + + for(int i = 0; i < geom.getNumGeometries(); ++i) { + final Point p = (Point) geom.getGeometryN(i); + featureStats.repeatedPts += pointSet.add(p) ? 0 : 1; + } + + return featureStats; + } + + private static FeatureStats lineStats(Geometry geom) { + final FeatureStats featureStats = new FeatureStats(); + + for(int i = 0; i < geom.getNumGeometries(); ++i) { + final LineString lineString = (LineString) geom.getGeometryN(i); + featureStats.totalPts += lineString.getNumPoints(); + featureStats.repeatedPts += checkRepeatedPoints2d(lineString); + } + + return featureStats; + } + + private static FeatureStats polyStats(Geometry geom) { + final FeatureStats featureStats = new FeatureStats(); + + for(int i = 0; i < geom.getNumGeometries(); ++i) { + final Polygon nextPoly = (Polygon) geom.getGeometryN(i); + + // Stats: exterior ring + final LineString exteriorRing = nextPoly.getExteriorRing(); + featureStats.totalPts += exteriorRing.getNumPoints(); + featureStats.repeatedPts += checkRepeatedPoints2d(exteriorRing); + + // Stats: interior rings + for(int ringIndex = 0; ringIndex < nextPoly.getNumInteriorRing(); ++ringIndex) { + + final LineString nextInteriorRing = nextPoly.getInteriorRingN(ringIndex); + featureStats.totalPts += nextInteriorRing.getNumPoints(); + featureStats.repeatedPts += checkRepeatedPoints2d(nextInteriorRing); + } + } + + return featureStats; + } + + private static int checkRepeatedPoints2d(LineString lineString) { + int repeatedPoints = 0; + + final CoordinateSequence coordSeq = lineString.getCoordinateSequence(); + Coordinate nextCoord = null, prevCoord; + for(int i = 0; i < coordSeq.size(); ++i) { + prevCoord = nextCoord; + nextCoord = coordSeq.getCoordinate(i); + if(nextCoord.equals(prevCoord)) { + ++repeatedPoints; + } + } + + return repeatedPoints; + } +} diff --git a/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/util/Vec2d.java b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/util/Vec2d.java new file mode 100644 index 0000000000..0e1e7e1c68 --- /dev/null +++ b/OsmAnd-java/src/com/wdtinc/mapbox_vector_tile/util/Vec2d.java @@ -0,0 +1,126 @@ + +package com.wdtinc.mapbox_vector_tile.util; + +/** + * Mutable Vector with double-valued x and y dimensions. + */ +public final class Vec2d { + + public double x, y; + + /** + * Construct instance with x = 0, y = 0. + */ + public Vec2d() { + set(0d, 0d); + } + + /** + * Construct instance with (x, y) values set to passed parameters + * + * @param x value in x + * @param y value in y + */ + public Vec2d(double x, double y) { + set(x, y); + } + + /** + * Constructs instance with values from the input vector 'v'. + * + * @param v The vector + */ + public Vec2d(Vec2d v) { + set(v); + } + + /** + * Set the x and y values of this vector. Return this vector for chaining. + * + * @param x value in x + * @param y value in y + * @return this vector for chaining + */ + public Vec2d set(double x, double y) { + this.x = x; + this.y = y; + + return this; + } + + /** + * Set the x and y values of this vector to match input vector 'v'. Return this vector for chaining. + * + * @param v contains values to copy + * @return this vector for chaining + */ + public Vec2d set(Vec2d v) { + return set(v.x, v.y); + } + + /** + * Adds the given values to this vector. Return this vector for chaining. + * + * @param x value in x + * @param y value in y + * @return this vector for chaining + */ + public Vec2d add(double x, double y) { + this.x += x; + this.y += y; + + return this; + } + + /** + * Adds the given vector 'v' to this vector. Return this vector for chaining. + * + * @param v vector to add + * @return this vector for chaining + */ + public Vec2d add(Vec2d v) { + return add(v.x, v.y); + } + + /** + * Subtracts the given values from this vector. Return this vector for chaining. + * + * @param x value in x to subtract + * @param y value in y to subtract + * @return this vector for chaining + */ + public Vec2d sub(double x, double y) { + this.x -= x; + this.y -= y; + + return this; + } + + /** + * Subtracts the given vector 'v' from this vector. Return this vector for chaining. + * + * @param v vector to subtract + * @return this vector for chaining + */ + public Vec2d sub(Vec2d v) { + return sub(v.x, v.y); + } + + /** + * Scales this vector's values by a constant. + * + * @param scalar constant to scale this vector's values by + * @return this vector for chaining + */ + public Vec2d scale(double scalar) { + this.x *= scalar; + this.y *= scalar; + + return this; + } + + @Override + public String toString () { + return "(" + x + "," + y + ")"; + } +} \ No newline at end of file diff --git a/OsmAnd-java/src/net/osmand/binary/BinaryVectorTileReader.java b/OsmAnd-java/src/net/osmand/binary/BinaryVectorTileReader.java new file mode 100644 index 0000000000..18fe14ea4b --- /dev/null +++ b/OsmAnd-java/src/net/osmand/binary/BinaryVectorTileReader.java @@ -0,0 +1,22 @@ +package net.osmand.binary; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.wdtinc.mapbox_vector_tile.adapt.jts.MvtReader; +import com.wdtinc.mapbox_vector_tile.adapt.jts.TagKeyValueMapConverter; + +import net.osmand.data.GeometryTile; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; + +public class BinaryVectorTileReader { + + public static GeometryTile readTile(File file) throws IOException { + GeometryFactory geomFactory = new GeometryFactory(); + return new GeometryTile( + MvtReader.loadMvt(new FileInputStream(file), geomFactory, new TagKeyValueMapConverter())); + } +} diff --git a/OsmAnd-java/src/net/osmand/binary/VectorTile.java b/OsmAnd-java/src/net/osmand/binary/VectorTile.java new file mode 100644 index 0000000000..c487bd4585 --- /dev/null +++ b/OsmAnd-java/src/net/osmand/binary/VectorTile.java @@ -0,0 +1,4942 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: vector_tile.proto + +package net.osmand.binary; + +public final class VectorTile { + private VectorTile() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public interface TileOrBuilder extends + com.google.protobuf.GeneratedMessage. + ExtendableMessageOrBuilder { + + // repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + java.util.List + getLayersList(); + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + net.osmand.binary.VectorTile.Tile.Layer getLayers(int index); + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + int getLayersCount(); + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + java.util.List + getLayersOrBuilderList(); + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + net.osmand.binary.VectorTile.Tile.LayerOrBuilder getLayersOrBuilder( + int index); + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile} + */ + public static final class Tile extends + com.google.protobuf.GeneratedMessage.ExtendableMessage< + Tile> implements TileOrBuilder { + // Use Tile.newBuilder() to construct. + private Tile(com.google.protobuf.GeneratedMessage.ExtendableBuilder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Tile(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Tile defaultInstance; + public static Tile getDefaultInstance() { + return defaultInstance; + } + + public Tile getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Tile( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 26: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + layers_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + layers_.add(input.readMessage(net.osmand.binary.VectorTile.Tile.Layer.PARSER, extensionRegistry)); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + layers_ = java.util.Collections.unmodifiableList(layers_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.class, net.osmand.binary.VectorTile.Tile.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Tile parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Tile(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + /** + * Protobuf enum {@code OsmAnd.VectorTile.Tile.GeomType} + * + *
+     * GeomType is described in section 4.3.4 of the specification
+     * 
+ */ + public enum GeomType + implements com.google.protobuf.ProtocolMessageEnum { + /** + * UNKNOWN = 0; + */ + UNKNOWN(0, 0), + /** + * POINT = 1; + */ + POINT(1, 1), + /** + * LINESTRING = 2; + */ + LINESTRING(2, 2), + /** + * POLYGON = 3; + */ + POLYGON(3, 3), + ; + + /** + * UNKNOWN = 0; + */ + public static final int UNKNOWN_VALUE = 0; + /** + * POINT = 1; + */ + public static final int POINT_VALUE = 1; + /** + * LINESTRING = 2; + */ + public static final int LINESTRING_VALUE = 2; + /** + * POLYGON = 3; + */ + public static final int POLYGON_VALUE = 3; + + + public final int getNumber() { return value; } + + public static GeomType valueOf(int value) { + switch (value) { + case 0: return UNKNOWN; + case 1: return POINT; + case 2: return LINESTRING; + case 3: return POLYGON; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public GeomType findValueByNumber(int number) { + return GeomType.valueOf(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(index); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return net.osmand.binary.VectorTile.Tile.getDescriptor().getEnumTypes().get(0); + } + + private static final GeomType[] VALUES = values(); + + public static GeomType valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int index; + private final int value; + + private GeomType(int index, int value) { + this.index = index; + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:OsmAnd.VectorTile.Tile.GeomType) + } + + public interface ValueOrBuilder extends + com.google.protobuf.GeneratedMessage. + ExtendableMessageOrBuilder { + + // optional string string_value = 1; + /** + * optional string string_value = 1; + * + *
+       * Exactly one of these values must be present in a valid message
+       * 
+ */ + boolean hasStringValue(); + /** + * optional string string_value = 1; + * + *
+       * Exactly one of these values must be present in a valid message
+       * 
+ */ + java.lang.String getStringValue(); + /** + * optional string string_value = 1; + * + *
+       * Exactly one of these values must be present in a valid message
+       * 
+ */ + com.google.protobuf.ByteString + getStringValueBytes(); + + // optional float float_value = 2; + /** + * optional float float_value = 2; + */ + boolean hasFloatValue(); + /** + * optional float float_value = 2; + */ + float getFloatValue(); + + // optional double double_value = 3; + /** + * optional double double_value = 3; + */ + boolean hasDoubleValue(); + /** + * optional double double_value = 3; + */ + double getDoubleValue(); + + // optional int64 int_value = 4; + /** + * optional int64 int_value = 4; + */ + boolean hasIntValue(); + /** + * optional int64 int_value = 4; + */ + long getIntValue(); + + // optional uint64 uint_value = 5; + /** + * optional uint64 uint_value = 5; + */ + boolean hasUintValue(); + /** + * optional uint64 uint_value = 5; + */ + long getUintValue(); + + // optional sint64 sint_value = 6; + /** + * optional sint64 sint_value = 6; + */ + boolean hasSintValue(); + /** + * optional sint64 sint_value = 6; + */ + long getSintValue(); + + // optional bool bool_value = 7; + /** + * optional bool bool_value = 7; + */ + boolean hasBoolValue(); + /** + * optional bool bool_value = 7; + */ + boolean getBoolValue(); + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile.Value} + * + *
+     * Variant type encoding
+     * The use of values is described in section 4.1 of the specification
+     * 
+ */ + public static final class Value extends + com.google.protobuf.GeneratedMessage.ExtendableMessage< + Value> implements ValueOrBuilder { + // Use Value.newBuilder() to construct. + private Value(com.google.protobuf.GeneratedMessage.ExtendableBuilder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Value(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Value defaultInstance; + public static Value getDefaultInstance() { + return defaultInstance; + } + + public Value getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Value( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + stringValue_ = input.readBytes(); + break; + } + case 21: { + bitField0_ |= 0x00000002; + floatValue_ = input.readFloat(); + break; + } + case 25: { + bitField0_ |= 0x00000004; + doubleValue_ = input.readDouble(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + intValue_ = input.readInt64(); + break; + } + case 40: { + bitField0_ |= 0x00000010; + uintValue_ = input.readUInt64(); + break; + } + case 48: { + bitField0_ |= 0x00000020; + sintValue_ = input.readSInt64(); + break; + } + case 56: { + bitField0_ |= 0x00000040; + boolValue_ = input.readBool(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Value_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Value_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.Value.class, net.osmand.binary.VectorTile.Tile.Value.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Value parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Value(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional string string_value = 1; + public static final int STRING_VALUE_FIELD_NUMBER = 1; + private java.lang.Object stringValue_; + /** + * optional string string_value = 1; + * + *
+       * Exactly one of these values must be present in a valid message
+       * 
+ */ + public boolean hasStringValue() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional string string_value = 1; + * + *
+       * Exactly one of these values must be present in a valid message
+       * 
+ */ + public java.lang.String getStringValue() { + java.lang.Object ref = stringValue_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + stringValue_ = s; + } + return s; + } + } + /** + * optional string string_value = 1; + * + *
+       * Exactly one of these values must be present in a valid message
+       * 
+ */ + public com.google.protobuf.ByteString + getStringValueBytes() { + java.lang.Object ref = stringValue_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + stringValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // optional float float_value = 2; + public static final int FLOAT_VALUE_FIELD_NUMBER = 2; + private float floatValue_; + /** + * optional float float_value = 2; + */ + public boolean hasFloatValue() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional float float_value = 2; + */ + public float getFloatValue() { + return floatValue_; + } + + // optional double double_value = 3; + public static final int DOUBLE_VALUE_FIELD_NUMBER = 3; + private double doubleValue_; + /** + * optional double double_value = 3; + */ + public boolean hasDoubleValue() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional double double_value = 3; + */ + public double getDoubleValue() { + return doubleValue_; + } + + // optional int64 int_value = 4; + public static final int INT_VALUE_FIELD_NUMBER = 4; + private long intValue_; + /** + * optional int64 int_value = 4; + */ + public boolean hasIntValue() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional int64 int_value = 4; + */ + public long getIntValue() { + return intValue_; + } + + // optional uint64 uint_value = 5; + public static final int UINT_VALUE_FIELD_NUMBER = 5; + private long uintValue_; + /** + * optional uint64 uint_value = 5; + */ + public boolean hasUintValue() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional uint64 uint_value = 5; + */ + public long getUintValue() { + return uintValue_; + } + + // optional sint64 sint_value = 6; + public static final int SINT_VALUE_FIELD_NUMBER = 6; + private long sintValue_; + /** + * optional sint64 sint_value = 6; + */ + public boolean hasSintValue() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional sint64 sint_value = 6; + */ + public long getSintValue() { + return sintValue_; + } + + // optional bool bool_value = 7; + public static final int BOOL_VALUE_FIELD_NUMBER = 7; + private boolean boolValue_; + /** + * optional bool bool_value = 7; + */ + public boolean hasBoolValue() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional bool bool_value = 7; + */ + public boolean getBoolValue() { + return boolValue_; + } + + private void initFields() { + stringValue_ = ""; + floatValue_ = 0F; + doubleValue_ = 0D; + intValue_ = 0L; + uintValue_ = 0L; + sintValue_ = 0L; + boolValue_ = false; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!extensionsAreInitialized()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + com.google.protobuf.GeneratedMessage + .ExtendableMessage.ExtensionWriter extensionWriter = + newExtensionWriter(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getStringValueBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeFloat(2, floatValue_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeDouble(3, doubleValue_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeInt64(4, intValue_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt64(5, uintValue_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeSInt64(6, sintValue_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeBool(7, boolValue_); + } + extensionWriter.writeUntil(536870912, output); + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getStringValueBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeFloatSize(2, floatValue_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeDoubleSize(3, doubleValue_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(4, intValue_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(5, uintValue_); + } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeSInt64Size(6, sintValue_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(7, boolValue_); + } + size += extensionsSerializedSize(); + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static net.osmand.binary.VectorTile.Tile.Value parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile.Value parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Value parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile.Value parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Value parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Value parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Value parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Value parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Value parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Value parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.VectorTile.Tile.Value prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile.Value} + * + *
+       * Variant type encoding
+       * The use of values is described in section 4.1 of the specification
+       * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.ExtendableBuilder< + net.osmand.binary.VectorTile.Tile.Value, Builder> implements net.osmand.binary.VectorTile.Tile.ValueOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Value_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Value_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.Value.class, net.osmand.binary.VectorTile.Tile.Value.Builder.class); + } + + // Construct using net.osmand.binary.VectorTile.Tile.Value.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + stringValue_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + floatValue_ = 0F; + bitField0_ = (bitField0_ & ~0x00000002); + doubleValue_ = 0D; + bitField0_ = (bitField0_ & ~0x00000004); + intValue_ = 0L; + bitField0_ = (bitField0_ & ~0x00000008); + uintValue_ = 0L; + bitField0_ = (bitField0_ & ~0x00000010); + sintValue_ = 0L; + bitField0_ = (bitField0_ & ~0x00000020); + boolValue_ = false; + bitField0_ = (bitField0_ & ~0x00000040); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Value_descriptor; + } + + public net.osmand.binary.VectorTile.Tile.Value getDefaultInstanceForType() { + return net.osmand.binary.VectorTile.Tile.Value.getDefaultInstance(); + } + + public net.osmand.binary.VectorTile.Tile.Value build() { + net.osmand.binary.VectorTile.Tile.Value result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public net.osmand.binary.VectorTile.Tile.Value buildPartial() { + net.osmand.binary.VectorTile.Tile.Value result = new net.osmand.binary.VectorTile.Tile.Value(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.stringValue_ = stringValue_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.floatValue_ = floatValue_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.doubleValue_ = doubleValue_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.intValue_ = intValue_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.uintValue_ = uintValue_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.sintValue_ = sintValue_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + result.boolValue_ = boolValue_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.VectorTile.Tile.Value) { + return mergeFrom((net.osmand.binary.VectorTile.Tile.Value)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.VectorTile.Tile.Value other) { + if (other == net.osmand.binary.VectorTile.Tile.Value.getDefaultInstance()) return this; + if (other.hasStringValue()) { + bitField0_ |= 0x00000001; + stringValue_ = other.stringValue_; + onChanged(); + } + if (other.hasFloatValue()) { + setFloatValue(other.getFloatValue()); + } + if (other.hasDoubleValue()) { + setDoubleValue(other.getDoubleValue()); + } + if (other.hasIntValue()) { + setIntValue(other.getIntValue()); + } + if (other.hasUintValue()) { + setUintValue(other.getUintValue()); + } + if (other.hasSintValue()) { + setSintValue(other.getSintValue()); + } + if (other.hasBoolValue()) { + setBoolValue(other.getBoolValue()); + } + this.mergeExtensionFields(other); + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!extensionsAreInitialized()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + net.osmand.binary.VectorTile.Tile.Value parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (net.osmand.binary.VectorTile.Tile.Value) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional string string_value = 1; + private java.lang.Object stringValue_ = ""; + /** + * optional string string_value = 1; + * + *
+         * Exactly one of these values must be present in a valid message
+         * 
+ */ + public boolean hasStringValue() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional string string_value = 1; + * + *
+         * Exactly one of these values must be present in a valid message
+         * 
+ */ + public java.lang.String getStringValue() { + java.lang.Object ref = stringValue_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + stringValue_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string string_value = 1; + * + *
+         * Exactly one of these values must be present in a valid message
+         * 
+ */ + public com.google.protobuf.ByteString + getStringValueBytes() { + java.lang.Object ref = stringValue_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + stringValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string string_value = 1; + * + *
+         * Exactly one of these values must be present in a valid message
+         * 
+ */ + public Builder setStringValue( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + stringValue_ = value; + onChanged(); + return this; + } + /** + * optional string string_value = 1; + * + *
+         * Exactly one of these values must be present in a valid message
+         * 
+ */ + public Builder clearStringValue() { + bitField0_ = (bitField0_ & ~0x00000001); + stringValue_ = getDefaultInstance().getStringValue(); + onChanged(); + return this; + } + /** + * optional string string_value = 1; + * + *
+         * Exactly one of these values must be present in a valid message
+         * 
+ */ + public Builder setStringValueBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + stringValue_ = value; + onChanged(); + return this; + } + + // optional float float_value = 2; + private float floatValue_ ; + /** + * optional float float_value = 2; + */ + public boolean hasFloatValue() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional float float_value = 2; + */ + public float getFloatValue() { + return floatValue_; + } + /** + * optional float float_value = 2; + */ + public Builder setFloatValue(float value) { + bitField0_ |= 0x00000002; + floatValue_ = value; + onChanged(); + return this; + } + /** + * optional float float_value = 2; + */ + public Builder clearFloatValue() { + bitField0_ = (bitField0_ & ~0x00000002); + floatValue_ = 0F; + onChanged(); + return this; + } + + // optional double double_value = 3; + private double doubleValue_ ; + /** + * optional double double_value = 3; + */ + public boolean hasDoubleValue() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional double double_value = 3; + */ + public double getDoubleValue() { + return doubleValue_; + } + /** + * optional double double_value = 3; + */ + public Builder setDoubleValue(double value) { + bitField0_ |= 0x00000004; + doubleValue_ = value; + onChanged(); + return this; + } + /** + * optional double double_value = 3; + */ + public Builder clearDoubleValue() { + bitField0_ = (bitField0_ & ~0x00000004); + doubleValue_ = 0D; + onChanged(); + return this; + } + + // optional int64 int_value = 4; + private long intValue_ ; + /** + * optional int64 int_value = 4; + */ + public boolean hasIntValue() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional int64 int_value = 4; + */ + public long getIntValue() { + return intValue_; + } + /** + * optional int64 int_value = 4; + */ + public Builder setIntValue(long value) { + bitField0_ |= 0x00000008; + intValue_ = value; + onChanged(); + return this; + } + /** + * optional int64 int_value = 4; + */ + public Builder clearIntValue() { + bitField0_ = (bitField0_ & ~0x00000008); + intValue_ = 0L; + onChanged(); + return this; + } + + // optional uint64 uint_value = 5; + private long uintValue_ ; + /** + * optional uint64 uint_value = 5; + */ + public boolean hasUintValue() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional uint64 uint_value = 5; + */ + public long getUintValue() { + return uintValue_; + } + /** + * optional uint64 uint_value = 5; + */ + public Builder setUintValue(long value) { + bitField0_ |= 0x00000010; + uintValue_ = value; + onChanged(); + return this; + } + /** + * optional uint64 uint_value = 5; + */ + public Builder clearUintValue() { + bitField0_ = (bitField0_ & ~0x00000010); + uintValue_ = 0L; + onChanged(); + return this; + } + + // optional sint64 sint_value = 6; + private long sintValue_ ; + /** + * optional sint64 sint_value = 6; + */ + public boolean hasSintValue() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional sint64 sint_value = 6; + */ + public long getSintValue() { + return sintValue_; + } + /** + * optional sint64 sint_value = 6; + */ + public Builder setSintValue(long value) { + bitField0_ |= 0x00000020; + sintValue_ = value; + onChanged(); + return this; + } + /** + * optional sint64 sint_value = 6; + */ + public Builder clearSintValue() { + bitField0_ = (bitField0_ & ~0x00000020); + sintValue_ = 0L; + onChanged(); + return this; + } + + // optional bool bool_value = 7; + private boolean boolValue_ ; + /** + * optional bool bool_value = 7; + */ + public boolean hasBoolValue() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional bool bool_value = 7; + */ + public boolean getBoolValue() { + return boolValue_; + } + /** + * optional bool bool_value = 7; + */ + public Builder setBoolValue(boolean value) { + bitField0_ |= 0x00000040; + boolValue_ = value; + onChanged(); + return this; + } + /** + * optional bool bool_value = 7; + */ + public Builder clearBoolValue() { + bitField0_ = (bitField0_ & ~0x00000040); + boolValue_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:OsmAnd.VectorTile.Tile.Value) + } + + static { + defaultInstance = new Value(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:OsmAnd.VectorTile.Tile.Value) + } + + public interface FeatureOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional uint64 id = 1 [default = 0]; + /** + * optional uint64 id = 1 [default = 0]; + */ + boolean hasId(); + /** + * optional uint64 id = 1 [default = 0]; + */ + long getId(); + + // repeated uint32 tags = 2 [packed = true]; + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+       * Tags of this feature are encoded as repeated pairs of
+       * integers.
+       * A detailed description of tags is located in sections
+       * 4.2 and 4.4 of the specification
+       * 
+ */ + java.util.List getTagsList(); + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+       * Tags of this feature are encoded as repeated pairs of
+       * integers.
+       * A detailed description of tags is located in sections
+       * 4.2 and 4.4 of the specification
+       * 
+ */ + int getTagsCount(); + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+       * Tags of this feature are encoded as repeated pairs of
+       * integers.
+       * A detailed description of tags is located in sections
+       * 4.2 and 4.4 of the specification
+       * 
+ */ + int getTags(int index); + + // optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+       * The type of geometry stored in this feature.
+       * 
+ */ + boolean hasType(); + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+       * The type of geometry stored in this feature.
+       * 
+ */ + net.osmand.binary.VectorTile.Tile.GeomType getType(); + + // repeated uint32 geometry = 4 [packed = true]; + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+       * Contains a stream of commands and parameters (vertices).
+       * A detailed description on geometry encoding is located in
+       * section 4.3 of the specification.
+       * 
+ */ + java.util.List getGeometryList(); + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+       * Contains a stream of commands and parameters (vertices).
+       * A detailed description on geometry encoding is located in
+       * section 4.3 of the specification.
+       * 
+ */ + int getGeometryCount(); + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+       * Contains a stream of commands and parameters (vertices).
+       * A detailed description on geometry encoding is located in
+       * section 4.3 of the specification.
+       * 
+ */ + int getGeometry(int index); + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile.Feature} + * + *
+     * Features are described in section 4.2 of the specification
+     * 
+ */ + public static final class Feature extends + com.google.protobuf.GeneratedMessage + implements FeatureOrBuilder { + // Use Feature.newBuilder() to construct. + private Feature(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Feature(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Feature defaultInstance; + public static Feature getDefaultInstance() { + return defaultInstance; + } + + public Feature getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Feature( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + id_ = input.readUInt64(); + break; + } + case 16: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + tags_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + tags_.add(input.readUInt32()); + break; + } + case 18: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002) && input.getBytesUntilLimit() > 0) { + tags_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000002; + } + while (input.getBytesUntilLimit() > 0) { + tags_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + case 24: { + int rawValue = input.readEnum(); + net.osmand.binary.VectorTile.Tile.GeomType value = net.osmand.binary.VectorTile.Tile.GeomType.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(3, rawValue); + } else { + bitField0_ |= 0x00000002; + type_ = value; + } + break; + } + case 32: { + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + geometry_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + geometry_.add(input.readUInt32()); + break; + } + case 34: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008) && input.getBytesUntilLimit() > 0) { + geometry_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + while (input.getBytesUntilLimit() > 0) { + geometry_.add(input.readUInt32()); + } + input.popLimit(limit); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + tags_ = java.util.Collections.unmodifiableList(tags_); + } + if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + geometry_ = java.util.Collections.unmodifiableList(geometry_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Feature_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Feature_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.Feature.class, net.osmand.binary.VectorTile.Tile.Feature.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Feature parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Feature(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional uint64 id = 1 [default = 0]; + public static final int ID_FIELD_NUMBER = 1; + private long id_; + /** + * optional uint64 id = 1 [default = 0]; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1 [default = 0]; + */ + public long getId() { + return id_; + } + + // repeated uint32 tags = 2 [packed = true]; + public static final int TAGS_FIELD_NUMBER = 2; + private java.util.List tags_; + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+       * Tags of this feature are encoded as repeated pairs of
+       * integers.
+       * A detailed description of tags is located in sections
+       * 4.2 and 4.4 of the specification
+       * 
+ */ + public java.util.List + getTagsList() { + return tags_; + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+       * Tags of this feature are encoded as repeated pairs of
+       * integers.
+       * A detailed description of tags is located in sections
+       * 4.2 and 4.4 of the specification
+       * 
+ */ + public int getTagsCount() { + return tags_.size(); + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+       * Tags of this feature are encoded as repeated pairs of
+       * integers.
+       * A detailed description of tags is located in sections
+       * 4.2 and 4.4 of the specification
+       * 
+ */ + public int getTags(int index) { + return tags_.get(index); + } + private int tagsMemoizedSerializedSize = -1; + + // optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + public static final int TYPE_FIELD_NUMBER = 3; + private net.osmand.binary.VectorTile.Tile.GeomType type_; + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+       * The type of geometry stored in this feature.
+       * 
+ */ + public boolean hasType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+       * The type of geometry stored in this feature.
+       * 
+ */ + public net.osmand.binary.VectorTile.Tile.GeomType getType() { + return type_; + } + + // repeated uint32 geometry = 4 [packed = true]; + public static final int GEOMETRY_FIELD_NUMBER = 4; + private java.util.List geometry_; + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+       * Contains a stream of commands and parameters (vertices).
+       * A detailed description on geometry encoding is located in
+       * section 4.3 of the specification.
+       * 
+ */ + public java.util.List + getGeometryList() { + return geometry_; + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+       * Contains a stream of commands and parameters (vertices).
+       * A detailed description on geometry encoding is located in
+       * section 4.3 of the specification.
+       * 
+ */ + public int getGeometryCount() { + return geometry_.size(); + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+       * Contains a stream of commands and parameters (vertices).
+       * A detailed description on geometry encoding is located in
+       * section 4.3 of the specification.
+       * 
+ */ + public int getGeometry(int index) { + return geometry_.get(index); + } + private int geometryMemoizedSerializedSize = -1; + + private void initFields() { + id_ = 0L; + tags_ = java.util.Collections.emptyList(); + type_ = net.osmand.binary.VectorTile.Tile.GeomType.UNKNOWN; + geometry_ = java.util.Collections.emptyList(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt64(1, id_); + } + if (getTagsList().size() > 0) { + output.writeRawVarint32(18); + output.writeRawVarint32(tagsMemoizedSerializedSize); + } + for (int i = 0; i < tags_.size(); i++) { + output.writeUInt32NoTag(tags_.get(i)); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(3, type_.getNumber()); + } + if (getGeometryList().size() > 0) { + output.writeRawVarint32(34); + output.writeRawVarint32(geometryMemoizedSerializedSize); + } + for (int i = 0; i < geometry_.size(); i++) { + output.writeUInt32NoTag(geometry_.get(i)); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(1, id_); + } + { + int dataSize = 0; + for (int i = 0; i < tags_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(tags_.get(i)); + } + size += dataSize; + if (!getTagsList().isEmpty()) { + size += 1; + size += com.google.protobuf.CodedOutputStream + .computeInt32SizeNoTag(dataSize); + } + tagsMemoizedSerializedSize = dataSize; + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, type_.getNumber()); + } + { + int dataSize = 0; + for (int i = 0; i < geometry_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeUInt32SizeNoTag(geometry_.get(i)); + } + size += dataSize; + if (!getGeometryList().isEmpty()) { + size += 1; + size += com.google.protobuf.CodedOutputStream + .computeInt32SizeNoTag(dataSize); + } + geometryMemoizedSerializedSize = dataSize; + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Feature parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.VectorTile.Tile.Feature prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile.Feature} + * + *
+       * Features are described in section 4.2 of the specification
+       * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements net.osmand.binary.VectorTile.Tile.FeatureOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Feature_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Feature_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.Feature.class, net.osmand.binary.VectorTile.Tile.Feature.Builder.class); + } + + // Construct using net.osmand.binary.VectorTile.Tile.Feature.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + id_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + tags_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + type_ = net.osmand.binary.VectorTile.Tile.GeomType.UNKNOWN; + bitField0_ = (bitField0_ & ~0x00000004); + geometry_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Feature_descriptor; + } + + public net.osmand.binary.VectorTile.Tile.Feature getDefaultInstanceForType() { + return net.osmand.binary.VectorTile.Tile.Feature.getDefaultInstance(); + } + + public net.osmand.binary.VectorTile.Tile.Feature build() { + net.osmand.binary.VectorTile.Tile.Feature result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public net.osmand.binary.VectorTile.Tile.Feature buildPartial() { + net.osmand.binary.VectorTile.Tile.Feature result = new net.osmand.binary.VectorTile.Tile.Feature(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.id_ = id_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + tags_ = java.util.Collections.unmodifiableList(tags_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.tags_ = tags_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000002; + } + result.type_ = type_; + if (((bitField0_ & 0x00000008) == 0x00000008)) { + geometry_ = java.util.Collections.unmodifiableList(geometry_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.geometry_ = geometry_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.VectorTile.Tile.Feature) { + return mergeFrom((net.osmand.binary.VectorTile.Tile.Feature)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.VectorTile.Tile.Feature other) { + if (other == net.osmand.binary.VectorTile.Tile.Feature.getDefaultInstance()) return this; + if (other.hasId()) { + setId(other.getId()); + } + if (!other.tags_.isEmpty()) { + if (tags_.isEmpty()) { + tags_ = other.tags_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureTagsIsMutable(); + tags_.addAll(other.tags_); + } + onChanged(); + } + if (other.hasType()) { + setType(other.getType()); + } + if (!other.geometry_.isEmpty()) { + if (geometry_.isEmpty()) { + geometry_ = other.geometry_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureGeometryIsMutable(); + geometry_.addAll(other.geometry_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + net.osmand.binary.VectorTile.Tile.Feature parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (net.osmand.binary.VectorTile.Tile.Feature) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional uint64 id = 1 [default = 0]; + private long id_ ; + /** + * optional uint64 id = 1 [default = 0]; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1 [default = 0]; + */ + public long getId() { + return id_; + } + /** + * optional uint64 id = 1 [default = 0]; + */ + public Builder setId(long value) { + bitField0_ |= 0x00000001; + id_ = value; + onChanged(); + return this; + } + /** + * optional uint64 id = 1 [default = 0]; + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0L; + onChanged(); + return this; + } + + // repeated uint32 tags = 2 [packed = true]; + private java.util.List tags_ = java.util.Collections.emptyList(); + private void ensureTagsIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + tags_ = new java.util.ArrayList(tags_); + bitField0_ |= 0x00000002; + } + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+         * Tags of this feature are encoded as repeated pairs of
+         * integers.
+         * A detailed description of tags is located in sections
+         * 4.2 and 4.4 of the specification
+         * 
+ */ + public java.util.List + getTagsList() { + return java.util.Collections.unmodifiableList(tags_); + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+         * Tags of this feature are encoded as repeated pairs of
+         * integers.
+         * A detailed description of tags is located in sections
+         * 4.2 and 4.4 of the specification
+         * 
+ */ + public int getTagsCount() { + return tags_.size(); + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+         * Tags of this feature are encoded as repeated pairs of
+         * integers.
+         * A detailed description of tags is located in sections
+         * 4.2 and 4.4 of the specification
+         * 
+ */ + public int getTags(int index) { + return tags_.get(index); + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+         * Tags of this feature are encoded as repeated pairs of
+         * integers.
+         * A detailed description of tags is located in sections
+         * 4.2 and 4.4 of the specification
+         * 
+ */ + public Builder setTags( + int index, int value) { + ensureTagsIsMutable(); + tags_.set(index, value); + onChanged(); + return this; + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+         * Tags of this feature are encoded as repeated pairs of
+         * integers.
+         * A detailed description of tags is located in sections
+         * 4.2 and 4.4 of the specification
+         * 
+ */ + public Builder addTags(int value) { + ensureTagsIsMutable(); + tags_.add(value); + onChanged(); + return this; + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+         * Tags of this feature are encoded as repeated pairs of
+         * integers.
+         * A detailed description of tags is located in sections
+         * 4.2 and 4.4 of the specification
+         * 
+ */ + public Builder addAllTags( + java.lang.Iterable values) { + ensureTagsIsMutable(); + super.addAll(values, tags_); + onChanged(); + return this; + } + /** + * repeated uint32 tags = 2 [packed = true]; + * + *
+         * Tags of this feature are encoded as repeated pairs of
+         * integers.
+         * A detailed description of tags is located in sections
+         * 4.2 and 4.4 of the specification
+         * 
+ */ + public Builder clearTags() { + tags_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + + // optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + private net.osmand.binary.VectorTile.Tile.GeomType type_ = net.osmand.binary.VectorTile.Tile.GeomType.UNKNOWN; + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+         * The type of geometry stored in this feature.
+         * 
+ */ + public boolean hasType() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+         * The type of geometry stored in this feature.
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.GeomType getType() { + return type_; + } + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+         * The type of geometry stored in this feature.
+         * 
+ */ + public Builder setType(net.osmand.binary.VectorTile.Tile.GeomType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + type_ = value; + onChanged(); + return this; + } + /** + * optional .OsmAnd.VectorTile.Tile.GeomType type = 3 [default = UNKNOWN]; + * + *
+         * The type of geometry stored in this feature.
+         * 
+ */ + public Builder clearType() { + bitField0_ = (bitField0_ & ~0x00000004); + type_ = net.osmand.binary.VectorTile.Tile.GeomType.UNKNOWN; + onChanged(); + return this; + } + + // repeated uint32 geometry = 4 [packed = true]; + private java.util.List geometry_ = java.util.Collections.emptyList(); + private void ensureGeometryIsMutable() { + if (!((bitField0_ & 0x00000008) == 0x00000008)) { + geometry_ = new java.util.ArrayList(geometry_); + bitField0_ |= 0x00000008; + } + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+         * Contains a stream of commands and parameters (vertices).
+         * A detailed description on geometry encoding is located in
+         * section 4.3 of the specification.
+         * 
+ */ + public java.util.List + getGeometryList() { + return java.util.Collections.unmodifiableList(geometry_); + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+         * Contains a stream of commands and parameters (vertices).
+         * A detailed description on geometry encoding is located in
+         * section 4.3 of the specification.
+         * 
+ */ + public int getGeometryCount() { + return geometry_.size(); + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+         * Contains a stream of commands and parameters (vertices).
+         * A detailed description on geometry encoding is located in
+         * section 4.3 of the specification.
+         * 
+ */ + public int getGeometry(int index) { + return geometry_.get(index); + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+         * Contains a stream of commands and parameters (vertices).
+         * A detailed description on geometry encoding is located in
+         * section 4.3 of the specification.
+         * 
+ */ + public Builder setGeometry( + int index, int value) { + ensureGeometryIsMutable(); + geometry_.set(index, value); + onChanged(); + return this; + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+         * Contains a stream of commands and parameters (vertices).
+         * A detailed description on geometry encoding is located in
+         * section 4.3 of the specification.
+         * 
+ */ + public Builder addGeometry(int value) { + ensureGeometryIsMutable(); + geometry_.add(value); + onChanged(); + return this; + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+         * Contains a stream of commands and parameters (vertices).
+         * A detailed description on geometry encoding is located in
+         * section 4.3 of the specification.
+         * 
+ */ + public Builder addAllGeometry( + java.lang.Iterable values) { + ensureGeometryIsMutable(); + super.addAll(values, geometry_); + onChanged(); + return this; + } + /** + * repeated uint32 geometry = 4 [packed = true]; + * + *
+         * Contains a stream of commands and parameters (vertices).
+         * A detailed description on geometry encoding is located in
+         * section 4.3 of the specification.
+         * 
+ */ + public Builder clearGeometry() { + geometry_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:OsmAnd.VectorTile.Tile.Feature) + } + + static { + defaultInstance = new Feature(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:OsmAnd.VectorTile.Tile.Feature) + } + + public interface LayerOrBuilder extends + com.google.protobuf.GeneratedMessage. + ExtendableMessageOrBuilder { + + // required uint32 version = 15 [default = 1]; + /** + * required uint32 version = 15 [default = 1]; + * + *
+       * Any compliant implementation must first read the version
+       * number encoded in this message and choose the correct
+       * implementation for this version number before proceeding to
+       * decode other parts of this message.
+       * 
+ */ + boolean hasVersion(); + /** + * required uint32 version = 15 [default = 1]; + * + *
+       * Any compliant implementation must first read the version
+       * number encoded in this message and choose the correct
+       * implementation for this version number before proceeding to
+       * decode other parts of this message.
+       * 
+ */ + int getVersion(); + + // required string name = 1; + /** + * required string name = 1; + */ + boolean hasName(); + /** + * required string name = 1; + */ + java.lang.String getName(); + /** + * required string name = 1; + */ + com.google.protobuf.ByteString + getNameBytes(); + + // repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + java.util.List + getFeaturesList(); + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + net.osmand.binary.VectorTile.Tile.Feature getFeatures(int index); + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + int getFeaturesCount(); + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + java.util.List + getFeaturesOrBuilderList(); + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + net.osmand.binary.VectorTile.Tile.FeatureOrBuilder getFeaturesOrBuilder( + int index); + + // repeated string keys = 3; + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + java.util.List + getKeysList(); + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + int getKeysCount(); + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + java.lang.String getKeys(int index); + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + com.google.protobuf.ByteString + getKeysBytes(int index); + + // repeated .OsmAnd.VectorTile.Tile.Value values = 4; + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + java.util.List + getValuesList(); + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + net.osmand.binary.VectorTile.Tile.Value getValues(int index); + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + int getValuesCount(); + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + java.util.List + getValuesOrBuilderList(); + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + net.osmand.binary.VectorTile.Tile.ValueOrBuilder getValuesOrBuilder( + int index); + + // optional uint32 extent = 5 [default = 4096]; + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+       * Although this is an "optional" field it is required by the specification.
+       * See https://github.com/mapbox/vector-tile-spec/issues/47
+       * 
+ */ + boolean hasExtent(); + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+       * Although this is an "optional" field it is required by the specification.
+       * See https://github.com/mapbox/vector-tile-spec/issues/47
+       * 
+ */ + int getExtent(); + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile.Layer} + * + *
+     * Layers are described in section 4.1 of the specification
+     * 
+ */ + public static final class Layer extends + com.google.protobuf.GeneratedMessage.ExtendableMessage< + Layer> implements LayerOrBuilder { + // Use Layer.newBuilder() to construct. + private Layer(com.google.protobuf.GeneratedMessage.ExtendableBuilder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Layer(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Layer defaultInstance; + public static Layer getDefaultInstance() { + return defaultInstance; + } + + public Layer getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Layer( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + bitField0_ |= 0x00000002; + name_ = input.readBytes(); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + features_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000004; + } + features_.add(input.readMessage(net.osmand.binary.VectorTile.Tile.Feature.PARSER, extensionRegistry)); + break; + } + case 26: { + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + keys_ = new com.google.protobuf.LazyStringArrayList(); + mutable_bitField0_ |= 0x00000008; + } + keys_.add(input.readBytes()); + break; + } + case 34: { + if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + values_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000010; + } + values_.add(input.readMessage(net.osmand.binary.VectorTile.Tile.Value.PARSER, extensionRegistry)); + break; + } + case 40: { + bitField0_ |= 0x00000004; + extent_ = input.readUInt32(); + break; + } + case 120: { + bitField0_ |= 0x00000001; + version_ = input.readUInt32(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) { + features_ = java.util.Collections.unmodifiableList(features_); + } + if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + keys_ = new com.google.protobuf.UnmodifiableLazyStringList(keys_); + } + if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) { + values_ = java.util.Collections.unmodifiableList(values_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Layer_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Layer_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.Layer.class, net.osmand.binary.VectorTile.Tile.Layer.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Layer parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Layer(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // required uint32 version = 15 [default = 1]; + public static final int VERSION_FIELD_NUMBER = 15; + private int version_; + /** + * required uint32 version = 15 [default = 1]; + * + *
+       * Any compliant implementation must first read the version
+       * number encoded in this message and choose the correct
+       * implementation for this version number before proceeding to
+       * decode other parts of this message.
+       * 
+ */ + public boolean hasVersion() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 version = 15 [default = 1]; + * + *
+       * Any compliant implementation must first read the version
+       * number encoded in this message and choose the correct
+       * implementation for this version number before proceeding to
+       * decode other parts of this message.
+       * 
+ */ + public int getVersion() { + return version_; + } + + // required string name = 1; + public static final int NAME_FIELD_NUMBER = 1; + private java.lang.Object name_; + /** + * required string name = 1; + */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string name = 1; + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + name_ = s; + } + return s; + } + } + /** + * required string name = 1; + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + public static final int FEATURES_FIELD_NUMBER = 2; + private java.util.List features_; + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + public java.util.List getFeaturesList() { + return features_; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + public java.util.List + getFeaturesOrBuilderList() { + return features_; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + public int getFeaturesCount() { + return features_.size(); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + public net.osmand.binary.VectorTile.Tile.Feature getFeatures(int index) { + return features_.get(index); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+       * The actual features in this tile.
+       * 
+ */ + public net.osmand.binary.VectorTile.Tile.FeatureOrBuilder getFeaturesOrBuilder( + int index) { + return features_.get(index); + } + + // repeated string keys = 3; + public static final int KEYS_FIELD_NUMBER = 3; + private com.google.protobuf.LazyStringList keys_; + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + public java.util.List + getKeysList() { + return keys_; + } + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + public int getKeysCount() { + return keys_.size(); + } + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + public java.lang.String getKeys(int index) { + return keys_.get(index); + } + /** + * repeated string keys = 3; + * + *
+       * Dictionary encoding for keys
+       * 
+ */ + public com.google.protobuf.ByteString + getKeysBytes(int index) { + return keys_.getByteString(index); + } + + // repeated .OsmAnd.VectorTile.Tile.Value values = 4; + public static final int VALUES_FIELD_NUMBER = 4; + private java.util.List values_; + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + public java.util.List getValuesList() { + return values_; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + public java.util.List + getValuesOrBuilderList() { + return values_; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + public int getValuesCount() { + return values_.size(); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + public net.osmand.binary.VectorTile.Tile.Value getValues(int index) { + return values_.get(index); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+       * Dictionary encoding for values
+       * 
+ */ + public net.osmand.binary.VectorTile.Tile.ValueOrBuilder getValuesOrBuilder( + int index) { + return values_.get(index); + } + + // optional uint32 extent = 5 [default = 4096]; + public static final int EXTENT_FIELD_NUMBER = 5; + private int extent_; + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+       * Although this is an "optional" field it is required by the specification.
+       * See https://github.com/mapbox/vector-tile-spec/issues/47
+       * 
+ */ + public boolean hasExtent() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+       * Although this is an "optional" field it is required by the specification.
+       * See https://github.com/mapbox/vector-tile-spec/issues/47
+       * 
+ */ + public int getExtent() { + return extent_; + } + + private void initFields() { + version_ = 1; + name_ = ""; + features_ = java.util.Collections.emptyList(); + keys_ = com.google.protobuf.LazyStringArrayList.EMPTY; + values_ = java.util.Collections.emptyList(); + extent_ = 4096; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasVersion()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasName()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getValuesCount(); i++) { + if (!getValues(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + if (!extensionsAreInitialized()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + com.google.protobuf.GeneratedMessage + .ExtendableMessage.ExtensionWriter extensionWriter = + newExtensionWriter(); + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(1, getNameBytes()); + } + for (int i = 0; i < features_.size(); i++) { + output.writeMessage(2, features_.get(i)); + } + for (int i = 0; i < keys_.size(); i++) { + output.writeBytes(3, keys_.getByteString(i)); + } + for (int i = 0; i < values_.size(); i++) { + output.writeMessage(4, values_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeUInt32(5, extent_); + } + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt32(15, version_); + } + extensionWriter.writeUntil(536870912, output); + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getNameBytes()); + } + for (int i = 0; i < features_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, features_.get(i)); + } + { + int dataSize = 0; + for (int i = 0; i < keys_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeBytesSizeNoTag(keys_.getByteString(i)); + } + size += dataSize; + size += 1 * getKeysList().size(); + } + for (int i = 0; i < values_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, values_.get(i)); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(5, extent_); + } + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(15, version_); + } + size += extensionsSerializedSize(); + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile.Layer parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.VectorTile.Tile.Layer prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile.Layer} + * + *
+       * Layers are described in section 4.1 of the specification
+       * 
+ */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.ExtendableBuilder< + net.osmand.binary.VectorTile.Tile.Layer, Builder> implements net.osmand.binary.VectorTile.Tile.LayerOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Layer_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Layer_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.Layer.class, net.osmand.binary.VectorTile.Tile.Layer.Builder.class); + } + + // Construct using net.osmand.binary.VectorTile.Tile.Layer.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getFeaturesFieldBuilder(); + getValuesFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + version_ = 1; + bitField0_ = (bitField0_ & ~0x00000001); + name_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + if (featuresBuilder_ == null) { + features_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + } else { + featuresBuilder_.clear(); + } + keys_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + if (valuesBuilder_ == null) { + values_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + } else { + valuesBuilder_.clear(); + } + extent_ = 4096; + bitField0_ = (bitField0_ & ~0x00000020); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_Layer_descriptor; + } + + public net.osmand.binary.VectorTile.Tile.Layer getDefaultInstanceForType() { + return net.osmand.binary.VectorTile.Tile.Layer.getDefaultInstance(); + } + + public net.osmand.binary.VectorTile.Tile.Layer build() { + net.osmand.binary.VectorTile.Tile.Layer result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public net.osmand.binary.VectorTile.Tile.Layer buildPartial() { + net.osmand.binary.VectorTile.Tile.Layer result = new net.osmand.binary.VectorTile.Tile.Layer(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.version_ = version_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.name_ = name_; + if (featuresBuilder_ == null) { + if (((bitField0_ & 0x00000004) == 0x00000004)) { + features_ = java.util.Collections.unmodifiableList(features_); + bitField0_ = (bitField0_ & ~0x00000004); + } + result.features_ = features_; + } else { + result.features_ = featuresBuilder_.build(); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + keys_ = new com.google.protobuf.UnmodifiableLazyStringList( + keys_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.keys_ = keys_; + if (valuesBuilder_ == null) { + if (((bitField0_ & 0x00000010) == 0x00000010)) { + values_ = java.util.Collections.unmodifiableList(values_); + bitField0_ = (bitField0_ & ~0x00000010); + } + result.values_ = values_; + } else { + result.values_ = valuesBuilder_.build(); + } + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000004; + } + result.extent_ = extent_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.VectorTile.Tile.Layer) { + return mergeFrom((net.osmand.binary.VectorTile.Tile.Layer)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.VectorTile.Tile.Layer other) { + if (other == net.osmand.binary.VectorTile.Tile.Layer.getDefaultInstance()) return this; + if (other.hasVersion()) { + setVersion(other.getVersion()); + } + if (other.hasName()) { + bitField0_ |= 0x00000002; + name_ = other.name_; + onChanged(); + } + if (featuresBuilder_ == null) { + if (!other.features_.isEmpty()) { + if (features_.isEmpty()) { + features_ = other.features_; + bitField0_ = (bitField0_ & ~0x00000004); + } else { + ensureFeaturesIsMutable(); + features_.addAll(other.features_); + } + onChanged(); + } + } else { + if (!other.features_.isEmpty()) { + if (featuresBuilder_.isEmpty()) { + featuresBuilder_.dispose(); + featuresBuilder_ = null; + features_ = other.features_; + bitField0_ = (bitField0_ & ~0x00000004); + featuresBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getFeaturesFieldBuilder() : null; + } else { + featuresBuilder_.addAllMessages(other.features_); + } + } + } + if (!other.keys_.isEmpty()) { + if (keys_.isEmpty()) { + keys_ = other.keys_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureKeysIsMutable(); + keys_.addAll(other.keys_); + } + onChanged(); + } + if (valuesBuilder_ == null) { + if (!other.values_.isEmpty()) { + if (values_.isEmpty()) { + values_ = other.values_; + bitField0_ = (bitField0_ & ~0x00000010); + } else { + ensureValuesIsMutable(); + values_.addAll(other.values_); + } + onChanged(); + } + } else { + if (!other.values_.isEmpty()) { + if (valuesBuilder_.isEmpty()) { + valuesBuilder_.dispose(); + valuesBuilder_ = null; + values_ = other.values_; + bitField0_ = (bitField0_ & ~0x00000010); + valuesBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getValuesFieldBuilder() : null; + } else { + valuesBuilder_.addAllMessages(other.values_); + } + } + } + if (other.hasExtent()) { + setExtent(other.getExtent()); + } + this.mergeExtensionFields(other); + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasVersion()) { + + return false; + } + if (!hasName()) { + + return false; + } + for (int i = 0; i < getValuesCount(); i++) { + if (!getValues(i).isInitialized()) { + + return false; + } + } + if (!extensionsAreInitialized()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + net.osmand.binary.VectorTile.Tile.Layer parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (net.osmand.binary.VectorTile.Tile.Layer) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // required uint32 version = 15 [default = 1]; + private int version_ = 1; + /** + * required uint32 version = 15 [default = 1]; + * + *
+         * Any compliant implementation must first read the version
+         * number encoded in this message and choose the correct
+         * implementation for this version number before proceeding to
+         * decode other parts of this message.
+         * 
+ */ + public boolean hasVersion() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required uint32 version = 15 [default = 1]; + * + *
+         * Any compliant implementation must first read the version
+         * number encoded in this message and choose the correct
+         * implementation for this version number before proceeding to
+         * decode other parts of this message.
+         * 
+ */ + public int getVersion() { + return version_; + } + /** + * required uint32 version = 15 [default = 1]; + * + *
+         * Any compliant implementation must first read the version
+         * number encoded in this message and choose the correct
+         * implementation for this version number before proceeding to
+         * decode other parts of this message.
+         * 
+ */ + public Builder setVersion(int value) { + bitField0_ |= 0x00000001; + version_ = value; + onChanged(); + return this; + } + /** + * required uint32 version = 15 [default = 1]; + * + *
+         * Any compliant implementation must first read the version
+         * number encoded in this message and choose the correct
+         * implementation for this version number before proceeding to
+         * decode other parts of this message.
+         * 
+ */ + public Builder clearVersion() { + bitField0_ = (bitField0_ & ~0x00000001); + version_ = 1; + onChanged(); + return this; + } + + // required string name = 1; + private java.lang.Object name_ = ""; + /** + * required string name = 1; + */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string name = 1; + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string name = 1; + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string name = 1; + */ + public Builder setName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + name_ = value; + onChanged(); + return this; + } + /** + * required string name = 1; + */ + public Builder clearName() { + bitField0_ = (bitField0_ & ~0x00000002); + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + /** + * required string name = 1; + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + name_ = value; + onChanged(); + return this; + } + + // repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + private java.util.List features_ = + java.util.Collections.emptyList(); + private void ensureFeaturesIsMutable() { + if (!((bitField0_ & 0x00000004) == 0x00000004)) { + features_ = new java.util.ArrayList(features_); + bitField0_ |= 0x00000004; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Feature, net.osmand.binary.VectorTile.Tile.Feature.Builder, net.osmand.binary.VectorTile.Tile.FeatureOrBuilder> featuresBuilder_; + + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public java.util.List getFeaturesList() { + if (featuresBuilder_ == null) { + return java.util.Collections.unmodifiableList(features_); + } else { + return featuresBuilder_.getMessageList(); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public int getFeaturesCount() { + if (featuresBuilder_ == null) { + return features_.size(); + } else { + return featuresBuilder_.getCount(); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Feature getFeatures(int index) { + if (featuresBuilder_ == null) { + return features_.get(index); + } else { + return featuresBuilder_.getMessage(index); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder setFeatures( + int index, net.osmand.binary.VectorTile.Tile.Feature value) { + if (featuresBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureFeaturesIsMutable(); + features_.set(index, value); + onChanged(); + } else { + featuresBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder setFeatures( + int index, net.osmand.binary.VectorTile.Tile.Feature.Builder builderForValue) { + if (featuresBuilder_ == null) { + ensureFeaturesIsMutable(); + features_.set(index, builderForValue.build()); + onChanged(); + } else { + featuresBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder addFeatures(net.osmand.binary.VectorTile.Tile.Feature value) { + if (featuresBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureFeaturesIsMutable(); + features_.add(value); + onChanged(); + } else { + featuresBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder addFeatures( + int index, net.osmand.binary.VectorTile.Tile.Feature value) { + if (featuresBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureFeaturesIsMutable(); + features_.add(index, value); + onChanged(); + } else { + featuresBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder addFeatures( + net.osmand.binary.VectorTile.Tile.Feature.Builder builderForValue) { + if (featuresBuilder_ == null) { + ensureFeaturesIsMutable(); + features_.add(builderForValue.build()); + onChanged(); + } else { + featuresBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder addFeatures( + int index, net.osmand.binary.VectorTile.Tile.Feature.Builder builderForValue) { + if (featuresBuilder_ == null) { + ensureFeaturesIsMutable(); + features_.add(index, builderForValue.build()); + onChanged(); + } else { + featuresBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder addAllFeatures( + java.lang.Iterable values) { + if (featuresBuilder_ == null) { + ensureFeaturesIsMutable(); + super.addAll(values, features_); + onChanged(); + } else { + featuresBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder clearFeatures() { + if (featuresBuilder_ == null) { + features_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + } else { + featuresBuilder_.clear(); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public Builder removeFeatures(int index) { + if (featuresBuilder_ == null) { + ensureFeaturesIsMutable(); + features_.remove(index); + onChanged(); + } else { + featuresBuilder_.remove(index); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Feature.Builder getFeaturesBuilder( + int index) { + return getFeaturesFieldBuilder().getBuilder(index); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.FeatureOrBuilder getFeaturesOrBuilder( + int index) { + if (featuresBuilder_ == null) { + return features_.get(index); } else { + return featuresBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public java.util.List + getFeaturesOrBuilderList() { + if (featuresBuilder_ != null) { + return featuresBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(features_); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Feature.Builder addFeaturesBuilder() { + return getFeaturesFieldBuilder().addBuilder( + net.osmand.binary.VectorTile.Tile.Feature.getDefaultInstance()); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Feature.Builder addFeaturesBuilder( + int index) { + return getFeaturesFieldBuilder().addBuilder( + index, net.osmand.binary.VectorTile.Tile.Feature.getDefaultInstance()); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Feature features = 2; + * + *
+         * The actual features in this tile.
+         * 
+ */ + public java.util.List + getFeaturesBuilderList() { + return getFeaturesFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Feature, net.osmand.binary.VectorTile.Tile.Feature.Builder, net.osmand.binary.VectorTile.Tile.FeatureOrBuilder> + getFeaturesFieldBuilder() { + if (featuresBuilder_ == null) { + featuresBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Feature, net.osmand.binary.VectorTile.Tile.Feature.Builder, net.osmand.binary.VectorTile.Tile.FeatureOrBuilder>( + features_, + ((bitField0_ & 0x00000004) == 0x00000004), + getParentForChildren(), + isClean()); + features_ = null; + } + return featuresBuilder_; + } + + // repeated string keys = 3; + private com.google.protobuf.LazyStringList keys_ = com.google.protobuf.LazyStringArrayList.EMPTY; + private void ensureKeysIsMutable() { + if (!((bitField0_ & 0x00000008) == 0x00000008)) { + keys_ = new com.google.protobuf.LazyStringArrayList(keys_); + bitField0_ |= 0x00000008; + } + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public java.util.List + getKeysList() { + return java.util.Collections.unmodifiableList(keys_); + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public int getKeysCount() { + return keys_.size(); + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public java.lang.String getKeys(int index) { + return keys_.get(index); + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public com.google.protobuf.ByteString + getKeysBytes(int index) { + return keys_.getByteString(index); + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public Builder setKeys( + int index, java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureKeysIsMutable(); + keys_.set(index, value); + onChanged(); + return this; + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public Builder addKeys( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureKeysIsMutable(); + keys_.add(value); + onChanged(); + return this; + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public Builder addAllKeys( + java.lang.Iterable values) { + ensureKeysIsMutable(); + super.addAll(values, keys_); + onChanged(); + return this; + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public Builder clearKeys() { + keys_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + * repeated string keys = 3; + * + *
+         * Dictionary encoding for keys
+         * 
+ */ + public Builder addKeysBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureKeysIsMutable(); + keys_.add(value); + onChanged(); + return this; + } + + // repeated .OsmAnd.VectorTile.Tile.Value values = 4; + private java.util.List values_ = + java.util.Collections.emptyList(); + private void ensureValuesIsMutable() { + if (!((bitField0_ & 0x00000010) == 0x00000010)) { + values_ = new java.util.ArrayList(values_); + bitField0_ |= 0x00000010; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Value, net.osmand.binary.VectorTile.Tile.Value.Builder, net.osmand.binary.VectorTile.Tile.ValueOrBuilder> valuesBuilder_; + + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public java.util.List getValuesList() { + if (valuesBuilder_ == null) { + return java.util.Collections.unmodifiableList(values_); + } else { + return valuesBuilder_.getMessageList(); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public int getValuesCount() { + if (valuesBuilder_ == null) { + return values_.size(); + } else { + return valuesBuilder_.getCount(); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Value getValues(int index) { + if (valuesBuilder_ == null) { + return values_.get(index); + } else { + return valuesBuilder_.getMessage(index); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder setValues( + int index, net.osmand.binary.VectorTile.Tile.Value value) { + if (valuesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureValuesIsMutable(); + values_.set(index, value); + onChanged(); + } else { + valuesBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder setValues( + int index, net.osmand.binary.VectorTile.Tile.Value.Builder builderForValue) { + if (valuesBuilder_ == null) { + ensureValuesIsMutable(); + values_.set(index, builderForValue.build()); + onChanged(); + } else { + valuesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder addValues(net.osmand.binary.VectorTile.Tile.Value value) { + if (valuesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureValuesIsMutable(); + values_.add(value); + onChanged(); + } else { + valuesBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder addValues( + int index, net.osmand.binary.VectorTile.Tile.Value value) { + if (valuesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureValuesIsMutable(); + values_.add(index, value); + onChanged(); + } else { + valuesBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder addValues( + net.osmand.binary.VectorTile.Tile.Value.Builder builderForValue) { + if (valuesBuilder_ == null) { + ensureValuesIsMutable(); + values_.add(builderForValue.build()); + onChanged(); + } else { + valuesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder addValues( + int index, net.osmand.binary.VectorTile.Tile.Value.Builder builderForValue) { + if (valuesBuilder_ == null) { + ensureValuesIsMutable(); + values_.add(index, builderForValue.build()); + onChanged(); + } else { + valuesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder addAllValues( + java.lang.Iterable values) { + if (valuesBuilder_ == null) { + ensureValuesIsMutable(); + super.addAll(values, values_); + onChanged(); + } else { + valuesBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder clearValues() { + if (valuesBuilder_ == null) { + values_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + } else { + valuesBuilder_.clear(); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public Builder removeValues(int index) { + if (valuesBuilder_ == null) { + ensureValuesIsMutable(); + values_.remove(index); + onChanged(); + } else { + valuesBuilder_.remove(index); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Value.Builder getValuesBuilder( + int index) { + return getValuesFieldBuilder().getBuilder(index); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.ValueOrBuilder getValuesOrBuilder( + int index) { + if (valuesBuilder_ == null) { + return values_.get(index); } else { + return valuesBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public java.util.List + getValuesOrBuilderList() { + if (valuesBuilder_ != null) { + return valuesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(values_); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Value.Builder addValuesBuilder() { + return getValuesFieldBuilder().addBuilder( + net.osmand.binary.VectorTile.Tile.Value.getDefaultInstance()); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public net.osmand.binary.VectorTile.Tile.Value.Builder addValuesBuilder( + int index) { + return getValuesFieldBuilder().addBuilder( + index, net.osmand.binary.VectorTile.Tile.Value.getDefaultInstance()); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Value values = 4; + * + *
+         * Dictionary encoding for values
+         * 
+ */ + public java.util.List + getValuesBuilderList() { + return getValuesFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Value, net.osmand.binary.VectorTile.Tile.Value.Builder, net.osmand.binary.VectorTile.Tile.ValueOrBuilder> + getValuesFieldBuilder() { + if (valuesBuilder_ == null) { + valuesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Value, net.osmand.binary.VectorTile.Tile.Value.Builder, net.osmand.binary.VectorTile.Tile.ValueOrBuilder>( + values_, + ((bitField0_ & 0x00000010) == 0x00000010), + getParentForChildren(), + isClean()); + values_ = null; + } + return valuesBuilder_; + } + + // optional uint32 extent = 5 [default = 4096]; + private int extent_ = 4096; + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+         * Although this is an "optional" field it is required by the specification.
+         * See https://github.com/mapbox/vector-tile-spec/issues/47
+         * 
+ */ + public boolean hasExtent() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+         * Although this is an "optional" field it is required by the specification.
+         * See https://github.com/mapbox/vector-tile-spec/issues/47
+         * 
+ */ + public int getExtent() { + return extent_; + } + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+         * Although this is an "optional" field it is required by the specification.
+         * See https://github.com/mapbox/vector-tile-spec/issues/47
+         * 
+ */ + public Builder setExtent(int value) { + bitField0_ |= 0x00000020; + extent_ = value; + onChanged(); + return this; + } + /** + * optional uint32 extent = 5 [default = 4096]; + * + *
+         * Although this is an "optional" field it is required by the specification.
+         * See https://github.com/mapbox/vector-tile-spec/issues/47
+         * 
+ */ + public Builder clearExtent() { + bitField0_ = (bitField0_ & ~0x00000020); + extent_ = 4096; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:OsmAnd.VectorTile.Tile.Layer) + } + + static { + defaultInstance = new Layer(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:OsmAnd.VectorTile.Tile.Layer) + } + + // repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + public static final int LAYERS_FIELD_NUMBER = 3; + private java.util.List layers_; + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public java.util.List getLayersList() { + return layers_; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public java.util.List + getLayersOrBuilderList() { + return layers_; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public int getLayersCount() { + return layers_.size(); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public net.osmand.binary.VectorTile.Tile.Layer getLayers(int index) { + return layers_.get(index); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public net.osmand.binary.VectorTile.Tile.LayerOrBuilder getLayersOrBuilder( + int index) { + return layers_.get(index); + } + + private void initFields() { + layers_ = java.util.Collections.emptyList(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + for (int i = 0; i < getLayersCount(); i++) { + if (!getLayers(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + if (!extensionsAreInitialized()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + com.google.protobuf.GeneratedMessage + .ExtendableMessage.ExtensionWriter extensionWriter = + newExtensionWriter(); + for (int i = 0; i < layers_.size(); i++) { + output.writeMessage(3, layers_.get(i)); + } + extensionWriter.writeUntil(8192, output); + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < layers_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, layers_.get(i)); + } + size += extensionsSerializedSize(); + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static net.osmand.binary.VectorTile.Tile parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static net.osmand.binary.VectorTile.Tile parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static net.osmand.binary.VectorTile.Tile parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static net.osmand.binary.VectorTile.Tile parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static net.osmand.binary.VectorTile.Tile parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.VectorTile.Tile prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code OsmAnd.VectorTile.Tile} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.ExtendableBuilder< + net.osmand.binary.VectorTile.Tile, Builder> implements net.osmand.binary.VectorTile.TileOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_fieldAccessorTable + .ensureFieldAccessorsInitialized( + net.osmand.binary.VectorTile.Tile.class, net.osmand.binary.VectorTile.Tile.Builder.class); + } + + // Construct using net.osmand.binary.VectorTile.Tile.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getLayersFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + if (layersBuilder_ == null) { + layers_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + layersBuilder_.clear(); + } + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.VectorTile.internal_static_OsmAnd_VectorTile_Tile_descriptor; + } + + public net.osmand.binary.VectorTile.Tile getDefaultInstanceForType() { + return net.osmand.binary.VectorTile.Tile.getDefaultInstance(); + } + + public net.osmand.binary.VectorTile.Tile build() { + net.osmand.binary.VectorTile.Tile result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public net.osmand.binary.VectorTile.Tile buildPartial() { + net.osmand.binary.VectorTile.Tile result = new net.osmand.binary.VectorTile.Tile(this); + int from_bitField0_ = bitField0_; + if (layersBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + layers_ = java.util.Collections.unmodifiableList(layers_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.layers_ = layers_; + } else { + result.layers_ = layersBuilder_.build(); + } + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.VectorTile.Tile) { + return mergeFrom((net.osmand.binary.VectorTile.Tile)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.VectorTile.Tile other) { + if (other == net.osmand.binary.VectorTile.Tile.getDefaultInstance()) return this; + if (layersBuilder_ == null) { + if (!other.layers_.isEmpty()) { + if (layers_.isEmpty()) { + layers_ = other.layers_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureLayersIsMutable(); + layers_.addAll(other.layers_); + } + onChanged(); + } + } else { + if (!other.layers_.isEmpty()) { + if (layersBuilder_.isEmpty()) { + layersBuilder_.dispose(); + layersBuilder_ = null; + layers_ = other.layers_; + bitField0_ = (bitField0_ & ~0x00000001); + layersBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getLayersFieldBuilder() : null; + } else { + layersBuilder_.addAllMessages(other.layers_); + } + } + } + this.mergeExtensionFields(other); + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + for (int i = 0; i < getLayersCount(); i++) { + if (!getLayers(i).isInitialized()) { + + return false; + } + } + if (!extensionsAreInitialized()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + net.osmand.binary.VectorTile.Tile parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (net.osmand.binary.VectorTile.Tile) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + private java.util.List layers_ = + java.util.Collections.emptyList(); + private void ensureLayersIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + layers_ = new java.util.ArrayList(layers_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Layer, net.osmand.binary.VectorTile.Tile.Layer.Builder, net.osmand.binary.VectorTile.Tile.LayerOrBuilder> layersBuilder_; + + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public java.util.List getLayersList() { + if (layersBuilder_ == null) { + return java.util.Collections.unmodifiableList(layers_); + } else { + return layersBuilder_.getMessageList(); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public int getLayersCount() { + if (layersBuilder_ == null) { + return layers_.size(); + } else { + return layersBuilder_.getCount(); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public net.osmand.binary.VectorTile.Tile.Layer getLayers(int index) { + if (layersBuilder_ == null) { + return layers_.get(index); + } else { + return layersBuilder_.getMessage(index); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder setLayers( + int index, net.osmand.binary.VectorTile.Tile.Layer value) { + if (layersBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureLayersIsMutable(); + layers_.set(index, value); + onChanged(); + } else { + layersBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder setLayers( + int index, net.osmand.binary.VectorTile.Tile.Layer.Builder builderForValue) { + if (layersBuilder_ == null) { + ensureLayersIsMutable(); + layers_.set(index, builderForValue.build()); + onChanged(); + } else { + layersBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder addLayers(net.osmand.binary.VectorTile.Tile.Layer value) { + if (layersBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureLayersIsMutable(); + layers_.add(value); + onChanged(); + } else { + layersBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder addLayers( + int index, net.osmand.binary.VectorTile.Tile.Layer value) { + if (layersBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureLayersIsMutable(); + layers_.add(index, value); + onChanged(); + } else { + layersBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder addLayers( + net.osmand.binary.VectorTile.Tile.Layer.Builder builderForValue) { + if (layersBuilder_ == null) { + ensureLayersIsMutable(); + layers_.add(builderForValue.build()); + onChanged(); + } else { + layersBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder addLayers( + int index, net.osmand.binary.VectorTile.Tile.Layer.Builder builderForValue) { + if (layersBuilder_ == null) { + ensureLayersIsMutable(); + layers_.add(index, builderForValue.build()); + onChanged(); + } else { + layersBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder addAllLayers( + java.lang.Iterable values) { + if (layersBuilder_ == null) { + ensureLayersIsMutable(); + super.addAll(values, layers_); + onChanged(); + } else { + layersBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder clearLayers() { + if (layersBuilder_ == null) { + layers_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + layersBuilder_.clear(); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public Builder removeLayers(int index) { + if (layersBuilder_ == null) { + ensureLayersIsMutable(); + layers_.remove(index); + onChanged(); + } else { + layersBuilder_.remove(index); + } + return this; + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public net.osmand.binary.VectorTile.Tile.Layer.Builder getLayersBuilder( + int index) { + return getLayersFieldBuilder().getBuilder(index); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public net.osmand.binary.VectorTile.Tile.LayerOrBuilder getLayersOrBuilder( + int index) { + if (layersBuilder_ == null) { + return layers_.get(index); } else { + return layersBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public java.util.List + getLayersOrBuilderList() { + if (layersBuilder_ != null) { + return layersBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(layers_); + } + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public net.osmand.binary.VectorTile.Tile.Layer.Builder addLayersBuilder() { + return getLayersFieldBuilder().addBuilder( + net.osmand.binary.VectorTile.Tile.Layer.getDefaultInstance()); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public net.osmand.binary.VectorTile.Tile.Layer.Builder addLayersBuilder( + int index) { + return getLayersFieldBuilder().addBuilder( + index, net.osmand.binary.VectorTile.Tile.Layer.getDefaultInstance()); + } + /** + * repeated .OsmAnd.VectorTile.Tile.Layer layers = 3; + */ + public java.util.List + getLayersBuilderList() { + return getLayersFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Layer, net.osmand.binary.VectorTile.Tile.Layer.Builder, net.osmand.binary.VectorTile.Tile.LayerOrBuilder> + getLayersFieldBuilder() { + if (layersBuilder_ == null) { + layersBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + net.osmand.binary.VectorTile.Tile.Layer, net.osmand.binary.VectorTile.Tile.Layer.Builder, net.osmand.binary.VectorTile.Tile.LayerOrBuilder>( + layers_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + layers_ = null; + } + return layersBuilder_; + } + + // @@protoc_insertion_point(builder_scope:OsmAnd.VectorTile.Tile) + } + + static { + defaultInstance = new Tile(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:OsmAnd.VectorTile.Tile) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_OsmAnd_VectorTile_Tile_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_OsmAnd_VectorTile_Tile_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_OsmAnd_VectorTile_Tile_Value_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_OsmAnd_VectorTile_Tile_Value_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_OsmAnd_VectorTile_Tile_Feature_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_OsmAnd_VectorTile_Tile_Feature_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_OsmAnd_VectorTile_Tile_Layer_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_OsmAnd_VectorTile_Tile_Layer_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\021vector_tile.proto\022\021OsmAnd.VectorTile\"\330" + + "\004\n\004Tile\022-\n\006layers\030\003 \003(\0132\035.OsmAnd.VectorT" + + "ile.Tile.Layer\032\241\001\n\005Value\022\024\n\014string_value" + + "\030\001 \001(\t\022\023\n\013float_value\030\002 \001(\002\022\024\n\014double_va" + + "lue\030\003 \001(\001\022\021\n\tint_value\030\004 \001(\003\022\022\n\nuint_val" + + "ue\030\005 \001(\004\022\022\n\nsint_value\030\006 \001(\022\022\022\n\nbool_val" + + "ue\030\007 \001(\010*\010\010\010\020\200\200\200\200\002\032y\n\007Feature\022\r\n\002id\030\001 \001(" + + "\004:\0010\022\020\n\004tags\030\002 \003(\rB\002\020\001\0227\n\004type\030\003 \001(\0162 .O" + + "smAnd.VectorTile.Tile.GeomType:\007UNKNOWN\022" + + "\024\n\010geometry\030\004 \003(\rB\002\020\001\032\271\001\n\005Layer\022\022\n\007versi", + "on\030\017 \002(\r:\0011\022\014\n\004name\030\001 \002(\t\0221\n\010features\030\002 " + + "\003(\0132\037.OsmAnd.VectorTile.Tile.Feature\022\014\n\004" + + "keys\030\003 \003(\t\022-\n\006values\030\004 \003(\0132\035.OsmAnd.Vect" + + "orTile.Tile.Value\022\024\n\006extent\030\005 \001(\r:\0044096*" + + "\010\010\020\020\200\200\200\200\002\"?\n\010GeomType\022\013\n\007UNKNOWN\020\000\022\t\n\005PO" + + "INT\020\001\022\016\n\nLINESTRING\020\002\022\013\n\007POLYGON\020\003*\005\010\020\020\200" + + "@B\037\n\021net.osmand.binaryB\nVectorTile" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + internal_static_OsmAnd_VectorTile_Tile_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_OsmAnd_VectorTile_Tile_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_OsmAnd_VectorTile_Tile_descriptor, + new java.lang.String[] { "Layers", }); + internal_static_OsmAnd_VectorTile_Tile_Value_descriptor = + internal_static_OsmAnd_VectorTile_Tile_descriptor.getNestedTypes().get(0); + internal_static_OsmAnd_VectorTile_Tile_Value_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_OsmAnd_VectorTile_Tile_Value_descriptor, + new java.lang.String[] { "StringValue", "FloatValue", "DoubleValue", "IntValue", "UintValue", "SintValue", "BoolValue", }); + internal_static_OsmAnd_VectorTile_Tile_Feature_descriptor = + internal_static_OsmAnd_VectorTile_Tile_descriptor.getNestedTypes().get(1); + internal_static_OsmAnd_VectorTile_Tile_Feature_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_OsmAnd_VectorTile_Tile_Feature_descriptor, + new java.lang.String[] { "Id", "Tags", "Type", "Geometry", }); + internal_static_OsmAnd_VectorTile_Tile_Layer_descriptor = + internal_static_OsmAnd_VectorTile_Tile_descriptor.getNestedTypes().get(2); + internal_static_OsmAnd_VectorTile_Tile_Layer_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_OsmAnd_VectorTile_Tile_Layer_descriptor, + new java.lang.String[] { "Version", "Name", "Features", "Keys", "Values", "Extent", }); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/OsmAnd-java/src/net/osmand/data/GeometryTile.java b/OsmAnd-java/src/net/osmand/data/GeometryTile.java new file mode 100644 index 0000000000..39be28ee62 --- /dev/null +++ b/OsmAnd-java/src/net/osmand/data/GeometryTile.java @@ -0,0 +1,18 @@ +package net.osmand.data; + +import com.vividsolutions.jts.geom.Geometry; + +import java.util.List; + +public class GeometryTile { + + private List data; + + public GeometryTile(List data) { + this.data = data; + } + + public List getData() { + return data; + } +} diff --git a/OsmAnd-java/src/net/osmand/map/TileSourceManager.java b/OsmAnd-java/src/net/osmand/map/TileSourceManager.java index 1d296911df..9211caada8 100644 --- a/OsmAnd-java/src/net/osmand/map/TileSourceManager.java +++ b/OsmAnd-java/src/net/osmand/map/TileSourceManager.java @@ -40,11 +40,14 @@ public class TileSourceManager { new TileSourceTemplate("OsmAnd (online tiles)", "http://tile.osmand.net/hd/{0}/{1}/{2}.png", ".png", 19, 1, 512, 8, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ private static final TileSourceTemplate CYCLE_MAP_SOURCE = new TileSourceTemplate("CycleMap", "http://b.tile.opencyclemap.org/cycle/{0}/{1}/{2}.png", ".png", 16, 1, 256, 32, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - private static final TileSourceTemplate MAPILLARY_SOURCE = - new TileSourceTemplate("Mapillary (raster tiles)", "https://d6a1v2w10ny40.cloudfront.net/v0.1/{0}/{1}/{2}.png", ".png", 17, 0, 256, 16, 32000); + private static final TileSourceTemplate MAPILLARY_RASTER_SOURCE = + new TileSourceTemplate("Mapillary (raster tiles)", "https://d6a1v2w10ny40.cloudfront.net/v0.1/{0}/{1}/{2}.png", ".png", 14, 0, 256, 16, 32000); + private static final TileSourceTemplate MAPILLARY_VECTOR_SOURCE = + new TileSourceTemplate("Mapillary (vector tiles)", "https://d25uarhxywzl1j.cloudfront.net/v0.1/{0}/{1}/{2}.mvt", ".mvt", 21, 15, 256, 16, 3200); static { - MAPILLARY_SOURCE.setExpirationTimeMinutes(60 * 24); + MAPILLARY_RASTER_SOURCE.setExpirationTimeMinutes(60 * 24); + MAPILLARY_VECTOR_SOURCE.setExpirationTimeMinutes(60 * 24); } public static class TileSourceTemplate implements ITileSource, Cloneable { @@ -424,7 +427,8 @@ public class TileSourceManager { java.util.List list = new ArrayList(); list.add(getMapnikSource()); list.add(getCycleMapSource()); - list.add(getMapillarySource()); + list.add(getMapillaryRasterSource()); + list.add(getMapillaryVectorSource()); return list; } @@ -437,8 +441,12 @@ public class TileSourceManager { return CYCLE_MAP_SOURCE; } - public static TileSourceTemplate getMapillarySource() { - return MAPILLARY_SOURCE; + public static TileSourceTemplate getMapillaryRasterSource() { + return MAPILLARY_RASTER_SOURCE; + } + + public static TileSourceTemplate getMapillaryVectorSource() { + return MAPILLARY_VECTOR_SOURCE; } public static List downloadTileSourceTemplates(String versionAsUrl) { diff --git a/OsmAnd/libs/jts-core-1.14.0.jar b/OsmAnd/libs/jts-core-1.14.0.jar new file mode 100644 index 0000000000..a690bed698 Binary files /dev/null and b/OsmAnd/libs/jts-core-1.14.0.jar differ diff --git a/OsmAnd/src/net/osmand/core/android/TileSourceProxyProvider.java b/OsmAnd/src/net/osmand/core/android/TileSourceProxyProvider.java index 2145ddbfd6..6bdf80f67f 100644 --- a/OsmAnd/src/net/osmand/core/android/TileSourceProxyProvider.java +++ b/OsmAnd/src/net/osmand/core/android/TileSourceProxyProvider.java @@ -1,26 +1,22 @@ package net.osmand.core.android; -import android.graphics.Bitmap; - -import java.io.IOException; - import net.osmand.IndexConstants; import net.osmand.core.jni.AlphaChannelPresence; -import net.osmand.core.jni.IMapDataProvider; +import net.osmand.core.jni.IMapTiledDataProvider; +import net.osmand.core.jni.ImageMapLayerProvider; import net.osmand.core.jni.MapStubStyle; import net.osmand.core.jni.SWIGTYPE_p_QByteArray; import net.osmand.core.jni.SwigUtilities; -import net.osmand.core.jni.TileId; import net.osmand.core.jni.ZoomLevel; import net.osmand.core.jni.interface_ImageMapLayerProvider; -import net.osmand.core.jni.IMapTiledDataProvider; -import net.osmand.core.jni.ImageMapLayerProvider; import net.osmand.map.ITileSource; import net.osmand.map.MapTileDownloader; import net.osmand.plus.OsmandApplication; import net.osmand.plus.resources.AsyncLoadingThread; import net.osmand.plus.resources.ResourceManager; +import java.io.IOException; + public class TileSourceProxyProvider extends interface_ImageMapLayerProvider { private final OsmandApplication app; @@ -62,7 +58,7 @@ public class TileSourceProxyProvider extends interface_ImageMapLayerProvider { final TileReadyCallback tileReadyCallback = new TileReadyCallback(tileSource, request.getTileId().getX(), request.getTileId().getY(), request.getZoom().swigValue()); rm.getMapTileDownloader().addDownloaderCallback(tileReadyCallback); - while (rm.getTileImageForMapAsync(tileFilename, tileSource, request.getTileId().getX(), request.getTileId().getY(), + while (rm.getBitmapTilesCache().getTileForMapAsync(tileFilename, tileSource, request.getTileId().getX(), request.getTileId().getY(), request.getZoom().swigValue(), true) == null) { synchronized (tileReadyCallback.getSync()) { if (tileReadyCallback.isReady()) { diff --git a/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java b/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java index 914d840d67..89035e5255 100644 --- a/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java +++ b/OsmAnd/src/net/osmand/plus/activities/DownloadTilesDialog.java @@ -166,7 +166,7 @@ public class DownloadTilesDialog { if (rm.tileExistOnFileSystem(tileId, map, x, y, z)) { progressDlg.setProgress(progressDlg.getProgress() + 1); } else { - rm.getTileImageForMapSync(tileId, map, x, y, z, true); + rm.hasTileForMapSync(tileId, map, x, y, z, true); requests++; } if (!cancel) { diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index a190b2a893..385fa477fe 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -540,7 +540,7 @@ public class MapActivityActions implements DialogProvider { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { ((OsmandApplication) mapActivity.getApplication()).getResourceManager(). - clearTileImageForMap(null, mapSource, i + left, j + top, zoom); + clearTileForMap(null, mapSource, i + left, j + top, zoom); } } diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImage.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImage.java new file mode 100644 index 0000000000..28a6a0fb1a --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImage.java @@ -0,0 +1,15 @@ +package net.osmand.plus.mapillary; + +public class MapillaryImage { + + /* + * ca number Camera heading. -1 if not found. + * captured_at number When the image was captured, expressed as UTC epoch time in milliseconds. Must be non-negative integer; 0 if not found. + * key Key Image key. + * pano number Whether the image is panorama ( 1 ), or not ( 0 ). + * skey Key Sequence key. + * userkey Key User key. Empty if not found. + */ + + private double ca = Double.NaN; +} diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageDialog.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageDialog.java index d4fca11c33..414873655f 100644 --- a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageDialog.java +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageDialog.java @@ -119,15 +119,8 @@ public class MapillaryImageDialog extends ContextMenuCardDialog { private void setImageLocation(LatLon latLon, double ca, boolean animated) { OsmandMapTileView mapView = getMapActivity().getMapView(); - MapillaryLayer layer = mapView.getLayerByClass(MapillaryLayer.class); - if (layer != null) { - layer.setSelectedImageLocation(latLon); - if (!Double.isNaN(ca)) { - layer.setSelectedImageCameraAngle((float) ca); - } else { - layer.setSelectedImageCameraAngle(null); - } - } + updateLayer(mapView.getLayerByClass(MapillaryRasterLayer.class), latLon, ca); + updateLayer(mapView.getLayerByClass(MapillaryVectorLayer.class), latLon, ca); if (latLon != null) { if (animated) { mapView.getAnimatedDraggingThread().startMoving( @@ -140,6 +133,17 @@ public class MapillaryImageDialog extends ContextMenuCardDialog { } } + private void updateLayer(MapillaryLayer layer, LatLon latLon, double ca) { + if (layer != null) { + layer.setSelectedImageLocation(latLon); + if (!Double.isNaN(ca)) { + layer.setSelectedImageCameraAngle((float) ca); + } else { + layer.setSelectedImageCameraAngle(null); + } + } + } + public View getContentView() { if (getMapActivity().getMyApplication().getSettings().WEBGL_SUPPORTED.get()) { return getWebView(); diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryLayer.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryLayer.java index e7d452b498..30a9203b74 100644 --- a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryLayer.java +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryLayer.java @@ -1,69 +1,10 @@ package net.osmand.plus.mapillary; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; - import net.osmand.data.LatLon; -import net.osmand.data.RotatedTileBox; -import net.osmand.plus.R; -import net.osmand.plus.views.MapTileLayer; -import net.osmand.plus.views.OsmandMapLayer; -import net.osmand.plus.views.OsmandMapTileView; -public class MapillaryLayer extends MapTileLayer { +interface MapillaryLayer { - private LatLon selectedImageLocation; - private Float selectedImageCameraAngle; - private Bitmap selectedImage; - private Bitmap headingImage; - private Paint paintIcon; + void setSelectedImageLocation(LatLon selectedImageLocation); - public MapillaryLayer() { - super(false); - } - - @Override - public void initLayer(OsmandMapTileView view) { - super.initLayer(view); - paintIcon = new Paint(); - selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_default_location); - headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pedestrian_location_view_angle); - } - - public LatLon getSelectedImageLocation() { - return selectedImageLocation; - } - - public void setSelectedImageLocation(LatLon selectedImageLocation) { - this.selectedImageLocation = selectedImageLocation; - } - - public Float getSelectedImageCameraAngle() { - return selectedImageCameraAngle; - } - - public void setSelectedImageCameraAngle(Float selectedImageCameraAngle) { - this.selectedImageCameraAngle = selectedImageCameraAngle; - } - - @Override - public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings drawSettings) { - super.onPrepareBufferImage(canvas, tileBox, drawSettings); - if (selectedImageLocation != null) { - float x = tileBox.getPixXFromLatLon(selectedImageLocation.getLatitude(), selectedImageLocation.getLongitude()); - float y = tileBox.getPixYFromLatLon(selectedImageLocation.getLatitude(), selectedImageLocation.getLongitude()); - if (selectedImageCameraAngle != null) { - canvas.save(); - canvas.rotate(selectedImageCameraAngle - 180, x, y); - canvas.drawBitmap(headingImage, x - headingImage.getWidth() / 2, - y - headingImage.getHeight() / 2, paintIcon); - canvas.restore(); - } - canvas.drawBitmap(selectedImage, x - selectedImage.getWidth() / 2, y - selectedImage.getHeight() / 2, paintIcon); - } - } + void setSelectedImageCameraAngle(Float selectedImageCameraAngle); } diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java index f717e08d4b..3ae59ab7c4 100644 --- a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java @@ -41,7 +41,8 @@ public class MapillaryPlugin extends OsmandPlugin { private OsmandSettings settings; private OsmandApplication app; - private MapillaryLayer rasterLayer; + private MapillaryRasterLayer rasterLayer; + private MapillaryVectorLayer vectorLayer; private TextInfoWidget mapillaryControl; private MapWidgetRegInfo mapillaryWidgetRegInfo; @@ -82,7 +83,8 @@ public class MapillaryPlugin extends OsmandPlugin { } private void createLayers() { - rasterLayer = new MapillaryLayer(); + rasterLayer = new MapillaryRasterLayer(); + vectorLayer = new MapillaryVectorLayer(); } @Override @@ -91,23 +93,28 @@ public class MapillaryPlugin extends OsmandPlugin { } private void updateMapLayers(OsmandMapTileView mapView, final MapActivityLayers layers) { - if (rasterLayer == null) { + if (rasterLayer == null || vectorLayer == null) { createLayers(); } if (isActive()) { - updateLayer(mapView, rasterLayer, 0.6f); + ITileSource rasterSource = null; + ITileSource vectorSource = null; + if (settings.SHOW_MAPILLARY.get()) { + rasterSource = settings.getTileSourceByName(TileSourceManager.getMapillaryRasterSource().getName(), false); + vectorSource = settings.getTileSourceByName(TileSourceManager.getMapillaryVectorSource().getName(), false); + } + updateLayer(mapView, rasterSource, rasterLayer, 0.6f); + updateLayer(mapView, vectorSource, vectorLayer, 0.61f); } else { mapView.removeLayer(rasterLayer); rasterLayer.setMap(null); + mapView.removeLayer(vectorLayer); + vectorLayer.setMap(null); } layers.updateMapSource(mapView, null); } - private void updateLayer(OsmandMapTileView mapView, MapTileLayer layer, float layerOrder) { - ITileSource mapillarySource = null; - if (settings.SHOW_MAPILLARY.get()) { - mapillarySource = settings.getTileSourceByName(TileSourceManager.getMapillarySource().getName(), false); - } + private void updateLayer(OsmandMapTileView mapView, ITileSource mapillarySource, MapTileLayer layer, float layerOrder) { if (!Algorithms.objectEquals(mapillarySource, layer.getMap()) || !mapView.isLayerVisible(layer)) { if (mapView.getMapRenderer() == null && !mapView.isLayerVisible(layer)) { mapView.addLayer(layer, layerOrder); diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryRasterLayer.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryRasterLayer.java new file mode 100644 index 0000000000..2efdf7e194 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryRasterLayer.java @@ -0,0 +1,74 @@ +package net.osmand.plus.mapillary; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; + +import net.osmand.data.LatLon; +import net.osmand.data.RotatedTileBox; +import net.osmand.map.ITileSource; +import net.osmand.plus.R; +import net.osmand.plus.views.MapTileLayer; +import net.osmand.plus.views.OsmandMapTileView; + +class MapillaryRasterLayer extends MapTileLayer implements MapillaryLayer { + + private LatLon selectedImageLocation; + private Float selectedImageCameraAngle; + private Bitmap selectedImage; + private Bitmap headingImage; + private Paint paintIcon; + + MapillaryRasterLayer() { + super(false); + } + + @Override + public void initLayer(OsmandMapTileView view) { + super.initLayer(view); + paintIcon = new Paint(); + selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_default_location); + headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pedestrian_location_view_angle); + } + + @Override + public void setSelectedImageLocation(LatLon selectedImageLocation) { + this.selectedImageLocation = selectedImageLocation; + } + + @Override + public void setSelectedImageCameraAngle(Float selectedImageCameraAngle) { + this.selectedImageCameraAngle = selectedImageCameraAngle; + } + + @Override + public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings drawSettings) { + super.onPrepareBufferImage(canvas, tileBox, drawSettings); + if (selectedImageLocation != null) { + float x = tileBox.getPixXFromLatLon(selectedImageLocation.getLatitude(), selectedImageLocation.getLongitude()); + float y = tileBox.getPixYFromLatLon(selectedImageLocation.getLatitude(), selectedImageLocation.getLongitude()); + if (selectedImageCameraAngle != null) { + canvas.save(); + canvas.rotate(selectedImageCameraAngle - 180, x, y); + canvas.drawBitmap(headingImage, x - headingImage.getWidth() / 2, + y - headingImage.getHeight() / 2, paintIcon); + canvas.restore(); + } + canvas.drawBitmap(selectedImage, x - selectedImage.getWidth() / 2, y - selectedImage.getHeight() / 2, paintIcon); + } + } + + @Override + public void drawTileMap(Canvas canvas, RotatedTileBox tileBox) { + ITileSource map = this.map; + if (map == null) { + return; + } + int maxZoom = map.getMaximumZoomSupported(); + if (tileBox.getZoom() > maxZoom) { + return; + } + super.drawTileMap(canvas, tileBox); + } +} diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryVectorLayer.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryVectorLayer.java new file mode 100644 index 0000000000..cc5f8d91a7 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryVectorLayer.java @@ -0,0 +1,160 @@ +package net.osmand.plus.mapillary; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Point; + +import net.osmand.data.GeometryTile; +import net.osmand.data.LatLon; +import net.osmand.data.QuadRect; +import net.osmand.data.RotatedTileBox; +import net.osmand.map.ITileSource; +import net.osmand.plus.OsmandPlugin; +import net.osmand.plus.R; +import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin; +import net.osmand.plus.resources.ResourceManager; +import net.osmand.plus.views.MapTileLayer; +import net.osmand.plus.views.OsmandMapTileView; +import net.osmand.util.MapUtils; + +import java.util.LinkedHashMap; +import java.util.Map; + +class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer { + + private static final int TILE_ZOOM = 14; + + private LatLon selectedImageLocation; + private Float selectedImageCameraAngle; + private Bitmap selectedImage; + private Bitmap headingImage; + private Paint paintIcon; + private Bitmap point; + + MapillaryVectorLayer() { + super(false); + } + + @Override + public void initLayer(OsmandMapTileView view) { + super.initLayer(view); + paintIcon = new Paint(); + selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_default_location); + headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pedestrian_location_view_angle); + point = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_note_small); + } + + @Override + public void setSelectedImageLocation(LatLon selectedImageLocation) { + this.selectedImageLocation = selectedImageLocation; + } + + @Override + public void setSelectedImageCameraAngle(Float selectedImageCameraAngle) { + this.selectedImageCameraAngle = selectedImageCameraAngle; + } + + @Override + public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings drawSettings) { + super.onPrepareBufferImage(canvas, tileBox, drawSettings); + if (selectedImageLocation != null) { + float x = tileBox.getPixXFromLatLon(selectedImageLocation.getLatitude(), selectedImageLocation.getLongitude()); + float y = tileBox.getPixYFromLatLon(selectedImageLocation.getLatitude(), selectedImageLocation.getLongitude()); + if (selectedImageCameraAngle != null) { + canvas.save(); + canvas.rotate(selectedImageCameraAngle - 180, x, y); + canvas.drawBitmap(headingImage, x - headingImage.getWidth() / 2, + y - headingImage.getHeight() / 2, paintIcon); + canvas.restore(); + } + canvas.drawBitmap(selectedImage, x - selectedImage.getWidth() / 2, y - selectedImage.getHeight() / 2, paintIcon); + } + } + + @Override + public void drawTileMap(Canvas canvas, RotatedTileBox tileBox) { + ITileSource map = this.map; + if (map == null) { + return; + } + int nzoom = tileBox.getZoom(); + if (nzoom < map.getMinimumZoomSupported()) { + return; + } + ResourceManager mgr = resourceManager; + final QuadRect tilesRect = tileBox.getTileBounds(); + + // recalculate for ellipsoid coordinates + float ellipticTileCorrection = 0; + if (map.isEllipticYTile()) { + ellipticTileCorrection = (float) (MapUtils.getTileEllipsoidNumberY(nzoom, tileBox.getLatitude()) - tileBox.getCenterTileY()); + } + + int left = (int) Math.floor(tilesRect.left); + int top = (int) Math.floor(tilesRect.top + ellipticTileCorrection); + int width = (int) Math.ceil(tilesRect.right - left); + int height = (int) Math.ceil(tilesRect.bottom + ellipticTileCorrection - top); + + boolean useInternet = (OsmandPlugin.getEnabledPlugin(OsmandRasterMapsPlugin.class) != null || OsmandPlugin.getEnabledPlugin(MapillaryPlugin.class) != null) && + settings.USE_INTERNET_TO_DOWNLOAD_TILES.get() && settings.isInternetConnectionAvailable() && map.couldBeDownloadedFromInternet(); + + Map tiles = new LinkedHashMap<>(); + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + int leftPlusI = left + i; + int topPlusJ = top + j; + + int x1 = tileBox.getPixXFromTileXNoRot(leftPlusI); + int x2 = tileBox.getPixXFromTileXNoRot(leftPlusI + 1); + + int y1 = tileBox.getPixYFromTileYNoRot(topPlusJ - ellipticTileCorrection); + int y2 = tileBox.getPixYFromTileYNoRot(topPlusJ + 1 - ellipticTileCorrection); + bitmapToDraw.set(x1, y1, x2, y2); + + int tileX = leftPlusI; + int tileY = topPlusJ; + + //String tileId = mgr.calculateTileId(map, tileX, tileY, nzoom); + int dzoom = nzoom - TILE_ZOOM; + int div = (int) Math.pow(2.0, dzoom); + tileX /= div; + tileY /= div; + String tileId = mgr.calculateTileId(map, tileX, tileY, TILE_ZOOM); + GeometryTile tile = tiles.get(tileId); + if (tile == null) { + // asking tile image async + boolean imgExist = mgr.tileExistOnFileSystem(tileId, map, tileX, tileY, TILE_ZOOM); + if (imgExist || useInternet) { + tile = mgr.getGeometryTilesCache().getTileForMapAsync(tileId, map, tileX, tileY, TILE_ZOOM, useInternet); + } + if (tile != null) { + tiles.put(tileId, tile); + if (tile.getData() != null) { + drawPoints(canvas, tileBox, tileX, tileY, tile); + } + } + } + } + } + } + + private void drawPoints(Canvas canvas, RotatedTileBox tileBox, int tileX, int tileY, GeometryTile tile) { + for (Geometry g : tile.getData()) { + if (g instanceof Point && g.getCoordinate() != null) { + int x = (int) g.getCoordinate().x; + int y = (int) g.getCoordinate().y; + double lat = MapUtils.getLatitudeFromTile(TILE_ZOOM, tileY + y / 4096f); + double lon = MapUtils.getLongitudeFromTile(TILE_ZOOM, tileX + x / 4096f); + if (tileBox.containsLatLon(lat, lon)) { + float px = tileBox.getPixXFromLatLon(lat, lon); + float py = tileBox.getPixYFromLatLon(lat, lon); + canvas.drawBitmap(point, px - point.getWidth() / 2, py - point.getHeight() / 2, paintIcon); + } + } + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/resources/AsyncLoadingThread.java b/OsmAnd/src/net/osmand/plus/resources/AsyncLoadingThread.java index a75c5b35b3..27559ee966 100644 --- a/OsmAnd/src/net/osmand/plus/resources/AsyncLoadingThread.java +++ b/OsmAnd/src/net/osmand/plus/resources/AsyncLoadingThread.java @@ -1,12 +1,6 @@ package net.osmand.plus.resources; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Stack; - import net.osmand.PlatformUtil; import net.osmand.ResultMatcher; import net.osmand.data.RotatedTileBox; @@ -17,6 +11,12 @@ import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Stack; + /** * Thread to load map objects (POI, transport stops )async */ @@ -44,7 +44,7 @@ public class AsyncLoadingThread extends Thread { Object req = requests.pop(); if (req instanceof TileLoadDownloadRequest) { TileLoadDownloadRequest r = (TileLoadDownloadRequest) req; - tileLoaded |= resourceManger.getRequestedImageTile(r) != null; + tileLoaded |= resourceManger.hasRequestedTile(r); } else if (req instanceof MapLoadRequest) { if (!mapLoaded) { MapLoadRequest r = (MapLoadRequest) req; @@ -69,7 +69,7 @@ public class AsyncLoadingThread extends Thread { } } - public void requestToLoadImage(TileLoadDownloadRequest req) { + public void requestToLoadTile(TileLoadDownloadRequest req) { requests.push(req); } diff --git a/OsmAnd/src/net/osmand/plus/resources/BitmapTilesCache.java b/OsmAnd/src/net/osmand/plus/resources/BitmapTilesCache.java new file mode 100644 index 0000000000..52fb6b2138 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/resources/BitmapTilesCache.java @@ -0,0 +1,55 @@ +package net.osmand.plus.resources; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import net.osmand.map.ITileSource; +import net.osmand.plus.SQLiteTileSource; +import net.osmand.plus.resources.AsyncLoadingThread.TileLoadDownloadRequest; + +import java.io.File; + +public class BitmapTilesCache extends TilesCache { + + public BitmapTilesCache(AsyncLoadingThread asyncLoadingThread) { + super(asyncLoadingThread); + // it is not good investigated but no more than 64 (satellite images) + // Only 8 MB (from 16 Mb whole mem) available for images : image 64K * 128 = 8 MB (8 bit), 64 - 16 bit, 32 - 32 bit + // at least 3*9? + maxCacheSize = 28; + } + + @Override + public boolean isTileSourceSupported(ITileSource tileSource) { + return !".mvt".equals(tileSource.getTileFormat()); + } + + @Override + protected Bitmap getTileObject(TileLoadDownloadRequest req) { + Bitmap bmp = null; + if (req.tileSource instanceof SQLiteTileSource) { + try { + long[] tm = new long[1]; + bmp = ((SQLiteTileSource) req.tileSource).getImage(req.xTile, req.yTile, req.zoom, tm); + if (tm[0] != 0) { + downloadIfExpired(req, tm[0]); + } + } catch (OutOfMemoryError e) { + log.error("Out of memory error", e); //$NON-NLS-1$ + clearTiles(); + } + } else { + File en = new File(req.dirWithTiles, req.tileId); + if (en.exists()) { + try { + bmp = BitmapFactory.decodeFile(en.getAbsolutePath()); + downloadIfExpired(req, en.lastModified()); + } catch (OutOfMemoryError e) { + log.error("Out of memory error", e); //$NON-NLS-1$ + clearTiles(); + } + } + } + return bmp; + } +} diff --git a/OsmAnd/src/net/osmand/plus/resources/GeometryTilesCache.java b/OsmAnd/src/net/osmand/plus/resources/GeometryTilesCache.java new file mode 100644 index 0000000000..1a6a738662 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/resources/GeometryTilesCache.java @@ -0,0 +1,40 @@ +package net.osmand.plus.resources; + +import net.osmand.binary.BinaryVectorTileReader; +import net.osmand.data.GeometryTile; +import net.osmand.map.ITileSource; +import net.osmand.plus.resources.AsyncLoadingThread.TileLoadDownloadRequest; + +import java.io.File; +import java.io.IOException; + +public class GeometryTilesCache extends TilesCache { + + public GeometryTilesCache(AsyncLoadingThread asyncLoadingThread) { + super(asyncLoadingThread); + maxCacheSize = 50; + } + + @Override + public boolean isTileSourceSupported(ITileSource tileSource) { + return ".mvt".equals(tileSource.getTileFormat()); + } + + @Override + protected GeometryTile getTileObject(TileLoadDownloadRequest req) { + GeometryTile tile = null; + File en = new File(req.dirWithTiles, req.tileId); + if (en.exists()) { + try { + tile = BinaryVectorTileReader.readTile(en); + downloadIfExpired(req, en.lastModified()); + } catch (IOException e) { + log.error("Cannot read tile", e); + } catch (OutOfMemoryError e) { + log.error("Out of memory error", e); + clearTiles(); + } + } + return tile; + } +} diff --git a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java index e3fd8f7b2d..1b4219ab0b 100644 --- a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java +++ b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java @@ -4,8 +4,6 @@ package net.osmand.plus.resources; import android.content.Context; import android.content.res.AssetManager; import android.database.sqlite.SQLiteException; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.os.HandlerThread; import android.text.format.DateFormat; import android.util.DisplayMetrics; @@ -35,7 +33,6 @@ import net.osmand.plus.AppInitializer.InitEvents; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; -import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.Version; import net.osmand.plus.render.MapRenderRepositories; import net.osmand.plus.render.NativeOsmandLibrary; @@ -79,25 +76,18 @@ public class ResourceManager { public static final String VECTOR_MAP = "#vector_map"; //$NON-NLS-1$ private static final String INDEXES_CACHE = "ind.cache"; - - + private static final Log log = PlatformUtil.getLog(ResourceManager.class); - protected static ResourceManager manager = null; - - // it is not good investigated but no more than 64 (satellite images) - // Only 8 MB (from 16 Mb whole mem) available for images : image 64K * 128 = 8 MB (8 bit), 64 - 16 bit, 32 - 32 bit - // at least 3*9? - protected int maxImgCacheSize = 28; - - protected Map cacheOfImages = new LinkedHashMap(); - protected Map imagesOnFS = new LinkedHashMap() ; - - protected File dirWithTiles ; - - private final OsmandApplication context; + protected File dirWithTiles ; + + private List tilesCacheList = new ArrayList<>(); + private BitmapTilesCache bitmapTilesCache; + private GeometryTilesCache geometryTilesCache; + + private final OsmandApplication context; private List resourceListeners = new ArrayList<>(); public interface ResourceListener { @@ -105,7 +95,6 @@ public class ResourceManager { void onMapsIndexed(); } - // Indexes public enum BinaryMapReaderResourceType { POI, @@ -217,6 +206,12 @@ public class ResourceManager { this.context = context; this.renderer = new MapRenderRepositories(context); + + bitmapTilesCache = new BitmapTilesCache(asyncLoadingThread); + geometryTilesCache = new GeometryTilesCache(asyncLoadingThread); + tilesCacheList.add(bitmapTilesCache); + tilesCacheList.add(geometryTilesCache); + asyncLoadingThread.start(); renderingBufferImageThread = new HandlerThread("RenderingBaseImage"); renderingBufferImageThread.start(); @@ -224,16 +219,25 @@ public class ResourceManager { tileDownloader = MapTileDownloader.getInstance(Version.getFullVersion(context)); dateFormat = DateFormat.getDateFormat(context); resetStoreDirectory(); + WindowManager mgr = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); mgr.getDefaultDisplay().getMetrics(dm); // Only 8 MB (from 16 Mb whole mem) available for images : image 64K * 128 = 8 MB (8 bit), 64 - 16 bit, 32 - 32 bit // at least 3*9? float tiles = (dm.widthPixels / 256 + 2) * (dm.heightPixels / 256 + 2) * 3; - log.info("Tiles to load in memory : " + tiles); - maxImgCacheSize = (int) (tiles) ; + log.info("Bitmap tiles to load in memory : " + tiles); + bitmapTilesCache.setMaxCacheSize((int) (tiles)); } - + + public BitmapTilesCache getBitmapTilesCache() { + return bitmapTilesCache; + } + + public GeometryTilesCache getGeometryTilesCache() { + return geometryTilesCache; + } + public MapTileDownloader getMapTileDownloader() { return tileDownloader; } @@ -261,6 +265,9 @@ public class ResourceManager { context.getAppPath(".nomedia").createNewFile(); //$NON-NLS-1$ } catch( Exception e ) { } + for (TilesCache tilesCache : tilesCacheList) { + tilesCache.setDirWithTiles(dirWithTiles); + } } public java.text.DateFormat getDateFormat() { @@ -276,224 +283,62 @@ public class ResourceManager { } ////////////////////////////////////////////// Working with tiles //////////////////////////////////////////////// - - public Bitmap getTileImageForMapAsync(String file, ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) { - return getTileImageForMap(file, map, x, y, zoom, loadFromInternetIfNeeded, false, true); - } - - - public synchronized Bitmap getTileImageFromCache(String file){ - return cacheOfImages.get(file); - } - - public synchronized void putTileInTheCache(String file, Bitmap bmp) { - cacheOfImages.put(file, bmp); - } - - - public Bitmap getTileImageForMapSync(String file, ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) { - return getTileImageForMap(file, map, x, y, zoom, loadFromInternetIfNeeded, true, true); - } - - public synchronized void tileDownloaded(DownloadRequest request){ - if(request instanceof TileLoadDownloadRequest){ - TileLoadDownloadRequest req = ((TileLoadDownloadRequest) request); - imagesOnFS.put(req.tileId, Boolean.TRUE); -/* if(req.fileToSave != null && req.tileSource instanceof SQLiteTileSource){ - try { - ((SQLiteTileSource) req.tileSource).insertImage(req.xTile, req.yTile, req.zoom, req.fileToSave); - } catch (IOException e) { - log.warn("File "+req.fileToSave.getName() + " couldn't be read", e); //$NON-NLS-1$//$NON-NLS-2$ - } - req.fileToSave.delete(); - String[] l = req.fileToSave.getParentFile().list(); - if(l == null || l.length == 0){ - req.fileToSave.getParentFile().delete(); - l = req.fileToSave.getParentFile().getParentFile().list(); - if(l == null || l.length == 0){ - req.fileToSave.getParentFile().getParentFile().delete(); - } - } - }*/ - } - - } - - public synchronized boolean tileExistOnFileSystem(String file, ITileSource map, int x, int y, int zoom){ - if(!imagesOnFS.containsKey(file)){ - boolean ex = false; - if(map instanceof SQLiteTileSource){ - if(((SQLiteTileSource) map).isLocked()){ - return false; - } - ex = ((SQLiteTileSource) map).exists(x, y, zoom); - } else { - if(file == null){ - file = calculateTileId(map, x, y, zoom); - } - ex = new File(dirWithTiles, file).exists(); - } - if (ex) { - imagesOnFS.put(file, Boolean.TRUE); - } else { - imagesOnFS.put(file, null); + + private TilesCache getTilesCache(ITileSource map) { + for (TilesCache tc : tilesCacheList) { + if (tc.isTileSourceSupported(map)) { + return tc; } } - return imagesOnFS.get(file) != null || cacheOfImages.get(file) != null; - } - - public void clearTileImageForMap(String file, ITileSource map, int x, int y, int zoom){ - getTileImageForMap(file, map, x, y, zoom, true, false, true, true); - } - - /** - * @param file - null could be passed if you do not call very often with that param - */ - protected Bitmap getTileImageForMap(String file, ITileSource map, int x, int y, int zoom, - boolean loadFromInternetIfNeeded, boolean sync, boolean loadFromFs) { - return getTileImageForMap(file, map, x, y, zoom, loadFromInternetIfNeeded, sync, loadFromFs, false); + return null; } - // introduce cache in order save memory + public synchronized void tileDownloaded(DownloadRequest request){ + if (request instanceof TileLoadDownloadRequest) { + TileLoadDownloadRequest req = ((TileLoadDownloadRequest) request); + TilesCache cache = getTilesCache(req.tileSource); + if (cache != null) { + cache.tilesOnFS.put(req.tileId, Boolean.TRUE); + } + } + } - protected StringBuilder builder = new StringBuilder(40); - protected char[] tileId = new char[120]; + public synchronized boolean tileExistOnFileSystem(String file, ITileSource map, int x, int y, int zoom) { + TilesCache cache = getTilesCache(map); + return cache != null && !cache.tilesOnFS.containsKey(file) + && cache.tileExistOnFileSystem(file, map, x, y, zoom); + } + + public void clearTileForMap(String file, ITileSource map, int x, int y, int zoom){ + TilesCache cache = getTilesCache(map); + if (cache != null) { + cache.getTileForMap(file, map, x, y, zoom, true, false, true, true); + } + } + private GeoidAltitudeCorrection geoidAltitudeCorrection; private boolean searchAmenitiesInProgress; public synchronized String calculateTileId(ITileSource map, int x, int y, int zoom) { - builder.setLength(0); - if (map == null) { - builder.append(IndexConstants.TEMP_SOURCE_TO_LOAD); - } else { - builder.append(map.getName()); + TilesCache cache = getTilesCache(map); + if (cache != null) { + return cache.calculateTileId(map, x, y, zoom); } - - if (map instanceof SQLiteTileSource) { - builder.append('@'); - } else { - builder.append('/'); - } - builder.append(zoom).append('/').append(x).append('/').append(y). - append(map == null ? ".jpg" : map.getTileFormat()).append(".tile"); //$NON-NLS-1$ //$NON-NLS-2$ - return builder.toString(); + return null; } - - protected synchronized Bitmap getTileImageForMap(String tileId, ITileSource map, int x, int y, int zoom, - boolean loadFromInternetIfNeeded, boolean sync, boolean loadFromFs, boolean deleteBefore) { - if (tileId == null) { - tileId = calculateTileId(map, x, y, zoom); - if(tileId == null){ - return null; - } - } - - if(deleteBefore){ - cacheOfImages.remove(tileId); - if (map instanceof SQLiteTileSource) { - ((SQLiteTileSource) map).deleteImage(x, y, zoom); - } else { - File f = new File(dirWithTiles, tileId); - if (f.exists()) { - f.delete(); - } - } - imagesOnFS.put(tileId, null); - } - - if (loadFromFs && cacheOfImages.get(tileId) == null && map != null) { - boolean locked = map instanceof SQLiteTileSource && ((SQLiteTileSource) map).isLocked(); - if(!loadFromInternetIfNeeded && !locked && !tileExistOnFileSystem(tileId, map, x, y, zoom)){ - return null; - } - String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null; - File toSave = null; - if (url != null) { - if (map instanceof SQLiteTileSource) { - toSave = new File(dirWithTiles, calculateTileId(((SQLiteTileSource) map).getBase(), x, y, zoom)); - } else { - toSave = new File(dirWithTiles, tileId); - } - } - TileLoadDownloadRequest req = new TileLoadDownloadRequest(dirWithTiles, url, toSave, - tileId, map, x, y, zoom, map.getReferer()); - if(sync){ - return getRequestedImageTile(req); - } else { - asyncLoadingThread.requestToLoadImage(req); - } - } - return cacheOfImages.get(tileId); + protected boolean hasRequestedTile(TileLoadDownloadRequest req) { + TilesCache cache = getTilesCache(req.tileSource); + return cache != null && cache.getRequestedTile(req) != null; } - - - - protected Bitmap getRequestedImageTile(TileLoadDownloadRequest req){ - if(req.tileId == null || req.dirWithTiles == null){ - return null; - } - Bitmap cacheBmp = cacheOfImages.get(req.tileId); - if (cacheBmp != null) { - return cacheBmp; - } - if (cacheOfImages.size() > maxImgCacheSize) { - clearTiles(); - } - if (req.dirWithTiles.canRead() && !asyncLoadingThread.isFileCurrentlyDownloaded(req.fileToSave) - && !asyncLoadingThread.isFilePendingToDownload(req.fileToSave)) { - long time = System.currentTimeMillis(); - if (log.isDebugEnabled()) { - log.debug("Start loaded file : " + req.tileId + " " + Thread.currentThread().getName()); //$NON-NLS-1$ //$NON-NLS-2$ - } - Bitmap bmp = null; - if (req.tileSource instanceof SQLiteTileSource) { - try { - long[] tm = new long[1]; - bmp = ((SQLiteTileSource) req.tileSource).getImage(req.xTile, req.yTile, req.zoom, tm); - if (tm[0] != 0) { - int ts = req.tileSource.getExpirationTimeMillis(); - if (ts != -1 && req.url != null && time - tm[0] > ts) { - asyncLoadingThread.requestToDownload(req); - } - } - } catch (OutOfMemoryError e) { - log.error("Out of memory error", e); //$NON-NLS-1$ - clearTiles(); - } - } else { - File en = new File(req.dirWithTiles, req.tileId); - if (en.exists()) { - try { - bmp = BitmapFactory.decodeFile(en.getAbsolutePath()); - int ts = req.tileSource.getExpirationTimeMillis(); - if(ts != -1 && req.url != null && time - en.lastModified() > ts) { - asyncLoadingThread.requestToDownload(req); - } - } catch (OutOfMemoryError e) { - log.error("Out of memory error", e); //$NON-NLS-1$ - clearTiles(); - } - } - } - if (bmp != null) { - cacheOfImages.put(req.tileId, bmp); - if (log.isDebugEnabled()) { - log.debug("Loaded file : " + req.tileId + " " + -(time - System.currentTimeMillis()) + " ms " + cacheOfImages.size()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - } - - if (cacheOfImages.get(req.tileId) == null && req.url != null) { - asyncLoadingThread.requestToDownload(req); - } - - } - return cacheOfImages.get(req.tileId); + public boolean hasTileForMapSync(String file, ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) { + TilesCache cache = getTilesCache(map); + return cache != null && cache.getTileForMapSync(file, map, x, y, zoom, loadFromInternetIfNeeded) != null; } - ////////////////////////////////////////////// Working with indexes //////////////////////////////////////////////// + ////////////////////////////////////////////// Working with indexes //////////////////////////////////////////////// public List reloadIndexesOnStart(AppInitializer progress, List warnings){ close(); @@ -1077,7 +922,9 @@ public class ResourceManager { } public synchronized void close(){ - imagesOnFS.clear(); + for (TilesCache tc : tilesCacheList) { + tc.close(); + } indexFileNames.clear(); basemapFileNames.clear(); renderer.clearAllResources(); @@ -1140,7 +987,7 @@ public class ResourceManager { if (lf != null) { for (File f : lf) { if (f != null && f.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) { - map.put(f.getName(), AndroidUtils.formatDate(context, f.lastModified())); //$NON-NLS-1$ + map.put(f.getName(), AndroidUtils.formatDate(context, f.lastModified())); } } } @@ -1148,15 +995,17 @@ public class ResourceManager { return map; } - public synchronized void reloadTilesFromFS(){ - imagesOnFS.clear(); + public synchronized void reloadTilesFromFS() { + for (TilesCache tc : tilesCacheList) { + tc.tilesOnFS.clear(); + } } /// On low memory method /// public void onLowMemory() { - log.info("On low memory : cleaning tiles - size = " + cacheOfImages.size()); //$NON-NLS-1$ + log.info("On low memory"); clearTiles(); - for(RegionAddressRepository r : addressMap.values()){ + for (RegionAddressRepository r : addressMap.values()) { r.clearCache(); } renderer.clearCache(); @@ -1171,14 +1020,11 @@ public class ResourceManager { public OsmandRegions getOsmandRegions() { return context.getRegions(); } - - + protected synchronized void clearTiles() { - log.info("Cleaning tiles - size = " + cacheOfImages.size()); //$NON-NLS-1$ - ArrayList list = new ArrayList(cacheOfImages.keySet()); - // remove first images (as we think they are older) - for (int i = 0; i < list.size() / 2; i++) { - cacheOfImages.remove(list.get(i)); + log.info("Cleaning tiles..."); + for (TilesCache tc : tilesCacheList) { + tc.clearTiles(); } } diff --git a/OsmAnd/src/net/osmand/plus/resources/TilesCache.java b/OsmAnd/src/net/osmand/plus/resources/TilesCache.java new file mode 100644 index 0000000000..0ce19b1736 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/resources/TilesCache.java @@ -0,0 +1,234 @@ +package net.osmand.plus.resources; + +import net.osmand.IndexConstants; +import net.osmand.PlatformUtil; +import net.osmand.map.ITileSource; +import net.osmand.plus.SQLiteTileSource; +import net.osmand.plus.resources.AsyncLoadingThread.TileLoadDownloadRequest; + +import org.apache.commons.logging.Log; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public abstract class TilesCache { + private AsyncLoadingThread asyncLoadingThread; + protected static final Log log = PlatformUtil.getLog(TilesCache.class); + + Map cache = new LinkedHashMap<>(); + Map tilesOnFS = new LinkedHashMap<>(); + + protected File dirWithTiles; + protected int maxCacheSize = 30; + + public TilesCache(AsyncLoadingThread asyncLoadingThread) { + this.asyncLoadingThread = asyncLoadingThread; + } + + protected StringBuilder builder = new StringBuilder(40); + + public int getMaxCacheSize() { + return maxCacheSize; + } + + public void setMaxCacheSize(int maxCacheSize) { + this.maxCacheSize = maxCacheSize; + } + + public File getDirWithTiles() { + return dirWithTiles; + } + + public void setDirWithTiles(File dirWithTiles) { + this.dirWithTiles = dirWithTiles; + } + + public abstract boolean isTileSourceSupported(ITileSource tileSource); + + public synchronized String calculateTileId(ITileSource map, int x, int y, int zoom) { + builder.setLength(0); + if (map == null) { + builder.append(IndexConstants.TEMP_SOURCE_TO_LOAD); + } else { + builder.append(map.getName()); + } + + if (map instanceof SQLiteTileSource) { + builder.append('@'); + } else { + builder.append('/'); + } + builder.append(zoom).append('/').append(x).append('/').append(y). + append(map == null ? ".jpg" : map.getTileFormat()).append(".tile"); //$NON-NLS-1$ //$NON-NLS-2$ + return builder.toString(); + } + + public synchronized boolean tileExistOnFileSystem(String file, ITileSource map, int x, int y, int zoom) { + if (!tilesOnFS.containsKey(file)) { + boolean ex = false; + if (map instanceof SQLiteTileSource){ + if (((SQLiteTileSource) map).isLocked()){ + return false; + } + ex = ((SQLiteTileSource) map).exists(x, y, zoom); + } else { + if(file == null){ + file = calculateTileId(map, x, y, zoom); + } + ex = new File(dirWithTiles, file).exists(); + } + if (ex) { + tilesOnFS.put(file, Boolean.TRUE); + } else { + tilesOnFS.put(file, null); + } + } + return tilesOnFS.get(file) != null || cache.get(file) != null; + } + + public T getTileForMapAsync(String file, ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) { + return getTileForMap(file, map, x, y, zoom, loadFromInternetIfNeeded, false, true); + } + + public T getTileForMapSync(String file, ITileSource map, int x, int y, int zoom, boolean loadFromInternetIfNeeded) { + return getTileForMap(file, map, x, y, zoom, loadFromInternetIfNeeded, true, true); + } + + /** + * @param file - null could be passed if you do not call very often with that param + */ + protected T getTileForMap(String file, ITileSource map, int x, int y, int zoom, + boolean loadFromInternetIfNeeded, boolean sync, boolean loadFromFs) { + return getTileForMap(file, map, x, y, zoom, loadFromInternetIfNeeded, sync, loadFromFs, false); + } + + protected synchronized T getTileForMap(String tileId, ITileSource map, int x, int y, int zoom, + boolean loadFromInternetIfNeeded, boolean sync, + boolean loadFromFs, boolean deleteBefore) { + if (tileId == null) { + tileId = calculateTileId(map, x, y, zoom); + if(tileId == null){ + return null; + } + } + + if (deleteBefore){ + cache.remove(tileId); + if (map instanceof SQLiteTileSource) { + ((SQLiteTileSource) map).deleteImage(x, y, zoom); + } else { + File f = new File(dirWithTiles, tileId); + if (f.exists()) { + f.delete(); + } + } + tilesOnFS.put(tileId, null); + } + + if (loadFromFs && cache.get(tileId) == null && map != null) { + boolean locked = map instanceof SQLiteTileSource && ((SQLiteTileSource) map).isLocked(); + if (!loadFromInternetIfNeeded && !locked && !tileExistOnFileSystem(tileId, map, x, y, zoom)){ + return null; + } + String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null; + File toSave = null; + if (url != null) { + if (map instanceof SQLiteTileSource) { + toSave = new File(dirWithTiles, calculateTileId(((SQLiteTileSource) map).getBase(), x, y, zoom)); + } else { + toSave = new File(dirWithTiles, tileId); + } + } + TileLoadDownloadRequest req = new TileLoadDownloadRequest(dirWithTiles, url, toSave, + tileId, map, x, y, zoom, map.getReferer()); + if (sync) { + return getRequestedTile(req); + } else { + asyncLoadingThread.requestToLoadTile(req); + } + } + return cache.get(tileId); + } + + protected T getRequestedTile(TileLoadDownloadRequest req) { + if (req.tileId == null || req.dirWithTiles == null) { + return null; + } + T cacheObject = cache.get(req.tileId); + if (cacheObject != null) { + return cacheObject; + } + if (cache.size() > maxCacheSize) { + clearTiles(); + } + if (req.dirWithTiles.canRead() && !asyncLoadingThread.isFileCurrentlyDownloaded(req.fileToSave) + && !asyncLoadingThread.isFilePendingToDownload(req.fileToSave)) { + long time = System.currentTimeMillis(); + if (log.isDebugEnabled()) { + log.debug("Start loaded file : " + req.tileId + " " + Thread.currentThread().getName()); + } + + T tileObject = getTileObject(req); + + if (tileObject != null) { + cache.put(req.tileId, tileObject); + if (log.isDebugEnabled()) { + log.debug("Loaded file : " + req.tileId + " " + -(time - System.currentTimeMillis()) + " ms " + cache.size()); + } + } + + if (cache.get(req.tileId) == null && req.url != null) { + asyncLoadingThread.requestToDownload(req); + } + + } + return cache.get(req.tileId); + } + + protected abstract T getTileObject(TileLoadDownloadRequest req); + + protected void downloadIfExpired(TileLoadDownloadRequest req, long lastModified) { + long time = System.currentTimeMillis(); + int ts = req.tileSource.getExpirationTimeMillis(); + if(ts != -1 && req.url != null && time - lastModified > ts) { + asyncLoadingThread.requestToDownload(req); + } + } + + protected synchronized void clearTiles() { + log.info("Cleaning tiles - size = " + cache.size()); + List list = new ArrayList<>(cache.keySet()); + // remove first images (as we think they are older) + for (int i = 0; i < list.size() / 2; i++) { + cache.remove(list.get(i)); + } + } + + public synchronized T get(String key) { + return cache.get(key); + } + + public synchronized void put(String key, T value) { + cache.put(key, value); + } + + public synchronized T remove(String key) { + return cache.remove(key); + } + + public synchronized int size() { + return cache.size(); + } + + public synchronized Set keySet() { + return cache.keySet(); + } + + public void close() { + tilesOnFS.clear(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java b/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java index eebe9ba458..210502d48b 100644 --- a/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/MapTileLayer.java @@ -1,5 +1,14 @@ package net.osmand.plus.views; +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.widget.Toast; + import net.osmand.data.QuadRect; import net.osmand.data.RotatedTileBox; import net.osmand.map.ITileSource; @@ -12,32 +21,24 @@ import net.osmand.plus.mapillary.MapillaryPlugin; import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin; import net.osmand.plus.resources.ResourceManager; import net.osmand.util.MapUtils; -import android.annotation.SuppressLint; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.RectF; -import android.widget.Toast; public class MapTileLayer extends BaseMapLayer { protected static final int emptyTileDivisor = 16; public static final int OVERZOOM_IN = 2; - private final boolean mainMap; + protected final boolean mainMap; protected ITileSource map = null; protected MapTileAdapter mapTileAdapter = null; - Paint paintBitmap; + protected Paint paintBitmap; protected RectF bitmapToDraw = new RectF(); protected Rect bitmapToZoom = new Rect(); protected OsmandMapTileView view; protected ResourceManager resourceManager; - private OsmandSettings settings; + protected OsmandSettings settings; private boolean visible = true; @@ -175,7 +176,7 @@ public class MapTileLayer extends BaseMapLayer { boolean imgExist = mgr.tileExistOnFileSystem(ordImgTile, map, tileX, tileY, nzoom); boolean originalWillBeLoaded = useInternet && nzoom <= maxLevel; if (imgExist || originalWillBeLoaded) { - bmp = mgr.getTileImageForMapAsync(ordImgTile, map, tileX, tileY, nzoom, useInternet); + bmp = mgr.getBitmapTilesCache().getTileForMapAsync(ordImgTile, map, tileX, tileY, nzoom, useInternet); } if (bmp == null) { int div = 1; @@ -188,14 +189,14 @@ public class MapTileLayer extends BaseMapLayer { div *= 2; String imgTileId = mgr.calculateTileId(map, tileX / div, tileY / div, nzoom - kzoom); if (readFromCache) { - bmp = mgr.getTileImageFromCache(imgTileId); + bmp = mgr.getBitmapTilesCache().get(imgTileId); if (bmp != null) { break; } } else if (loadIfExists) { if (mgr.tileExistOnFileSystem(imgTileId, map, tileX / div, tileY / div, nzoom - kzoom) || (useInternet && nzoom - kzoom <= maxLevel)) { - bmp = mgr.getTileImageForMapAsync(imgTileId, map, tileX / div, tileY / div, nzoom + bmp = mgr.getBitmapTilesCache().getTileForMapAsync(imgTileId, map, tileX / div, tileY / div, nzoom - kzoom, useInternet); break; } @@ -243,7 +244,7 @@ public class MapTileLayer extends BaseMapLayer { bitmapToZoom.width(), bitmapToZoom.height(), m, true); bitmapToZoom.set(0, 0, tileSize, tileSize); // very expensive that's why put in the cache - mgr.putTileInTheCache(ordImgTile, sampled); + mgr.getBitmapTilesCache().put(ordImgTile, sampled); canvas.drawBitmap(sampled, bitmapToZoom, bitmapToDraw, paintBitmap); } }