iterator() {
return output.iterator();
}
/**
* Starts building a new map feature with an explicit JTS {@code geometry} that overrides the source geometry.
*
* @param layer the output vector tile layer this feature will be written to
* @param geometry the explicit geometry to use instead of what is present in source data
* @return a feature that can be configured further.
*/
public Feature geometry(String layer, Geometry geometry) {
Feature feature = new Feature(layer, geometry, source.id());
output.add(feature);
return feature;
}
/**
* Starts building a new point map feature that expects the source feature to be a point.
*
* If the source feature is not a point, logs an error and returns a feature that can be configured, but won't
* actually emit anything to the map.
*
* @param layer the output vector tile layer this feature will be written to
* @return a feature that can be configured further.
*/
public Feature point(String layer) {
try {
if (!source.isPoint()) {
throw new GeometryException("feature_not_point", "not a point");
}
return geometry(layer, source.worldGeometry());
} catch (GeometryException e) {
e.log(stats, "feature_point", "Error getting point geometry for " + source.id());
return new Feature(layer, EMPTY_GEOM, source.id());
}
}
/**
* Starts building a new line map feature that expects the source feature to be a line.
*
* If the source feature cannot be a line, logs an error and returns a feature that can be configured, but won't
* actually emit anything to the map.
*
* Some OSM closed OSM ways can be both a polygon and a line
*
* @param layer the output vector tile layer this feature will be written to
* @return a feature that can be configured further.
*/
public Feature line(String layer) {
try {
return geometry(layer, source.line());
} catch (GeometryException e) {
e.log(stats, "feature_line", "Error constructing line for " + source.id());
return new Feature(layer, EMPTY_GEOM, source.id());
}
}
/**
* Starts building a new polygon map feature that expects the source feature to be a polygon.
*
* If the source feature cannot be a polygon, logs an error and returns a feature that can be configured, but won't
* actually emit anything to the map.
*
* Some OSM closed OSM ways can be both a polygon and a line
*
* @param layer the output vector tile layer this feature will be written to
* @return a feature that can be configured further.
*/
public Feature polygon(String layer) {
try {
return geometry(layer, source.polygon());
} catch (GeometryException e) {
e.log(stats, "feature_polygon", "Error constructing polygon for " + source.id());
return new Feature(layer, EMPTY_GEOM, source.id());
}
}
/**
* Starts building a new point map feature with geometry from {@link Geometry#getCentroid()} of the source feature.
*
* @param layer the output vector tile layer this feature will be written to
* @return a feature that can be configured further.
*/
public Feature centroid(String layer) {
try {
return geometry(layer, source.centroid());
} catch (GeometryException e) {
e.log(stats, "feature_centroid", "Error getting centroid for " + source.id());
return new Feature(layer, EMPTY_GEOM, source.id());
}
}
/**
* Starts building a new point map feature with geometry from {@link Geometry#getCentroid()} if the source feature is
* a point, line, or simple convex polygon, or {@link Geometry#getInteriorPoint()} if it is a multipolygon, polygon
* with holes, or concave simple polygon.
*
* @param layer the output vector tile layer this feature will be written to
* @return a feature that can be configured further.
*/
public Feature centroidIfConvex(String layer) {
try {
return geometry(layer, source.centroidIfConvex());
} catch (GeometryException e) {
e.log(stats, "feature_centroid_if_convex", "Error constructing centroid if convex for " + source.id());
return new Feature(layer, EMPTY_GEOM, source.id());
}
}
/**
* Starts building a new point map feature with geometry from {@link Geometry#getInteriorPoint()} of the source
* feature.
*
* @param layer the output vector tile layer this feature will be written to
* @return a feature that can be configured further.
*/
public Feature pointOnSurface(String layer) {
try {
return geometry(layer, source.pointOnSurface());
} catch (GeometryException e) {
e.log(stats, "feature_point_on_surface", "Error constructing point on surface for " + source.id());
return new Feature(layer, EMPTY_GEOM, source.id());
}
}
/**
* Creates new feature collector instances for each source feature that we encounter.
*/
public record Factory(PlanetilerConfig config, Stats stats) {
public FeatureCollector get(SourceFeature source) {
return new FeatureCollector(source, config, stats);
}
}
/**
* A builder for an output map feature that contains all the information that will be needed to render vector tile
* features from the input element.
*
* Some feature attributes are set globally (like sort key), and some allow the value to change by zoom-level (like
* tags).
*/
public final class Feature {
private static final double DEFAULT_LABEL_GRID_SIZE = 0;
private static final int DEFAULT_LABEL_GRID_LIMIT = 0;
private final String layer;
private final Geometry geom;
private final Map attrs = new TreeMap<>();
private final GeometryType geometryType;
private final long sourceId;
private int sortKey = 0;
private int minzoom = config.minzoom();
private int maxzoom = config.maxzoom();
private ZoomFunction labelGridPixelSize = null;
private ZoomFunction labelGridLimit = null;
private boolean attrsChangeByZoom = false;
private CacheByZoom