-
Notifications
You must be signed in to change notification settings - Fork 97
/
Profile.java
271 lines (245 loc) · 11 KB
/
Profile.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
package com.onthegomap.planetiler;
import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.geo.TileCoord;
import com.onthegomap.planetiler.mbtiles.Mbtiles;
import com.onthegomap.planetiler.reader.SourceFeature;
import com.onthegomap.planetiler.reader.osm.OsmElement;
import com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
import com.onthegomap.planetiler.util.Wikidata;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* Provides methods for implementations to control how maps are generated.
* <p>
* This includes:
* <ul>
* <li>How source features (OSM elements, shapefile elements, etc.) map to output features and their tags</li>
* <li>How vector tile features in an output tile should be post-processed (see {@link FeatureMerge})</li>
* <li>What attributes to include in the mbtiles metadata output (see {@link Mbtiles})</li>
* <li>Whether {@link Wikidata} class should fetch wikidata translations for an OSM element</li>
* </ul>
* <p>
* {@link Profile#processFeature(SourceFeature, FeatureCollector)} only handles a single element at a time. To "join"
* elements across or within sources, implementations can store data in instance fields and wait to process them until
* an element is encountered in a later source, or the
* {@link Profile#finish(String, FeatureCollector.Factory, Consumer)} method is called for a source. All methods may be
* called concurrently by multiple threads, so implementations must be careful to ensure access to instance fields is
* thread-safe.
* <p>
* For complex profiles, {@link ForwardingProfile} provides a framework for splitting the logic up into several handlers
* (i.e. one per layer) and forwarding each element/event to the handlers that care about it.
*/
public interface Profile {
// TODO might want to break this apart into sub-interfaces that ForwardingProfile (and TileArchiveMetadata) can use too
/**
* Allows profile to extract any information it needs from a {@link OsmElement.Node} during the first pass through OSM
* elements.
* <p>
* The default implementation does nothing.
*
* @param node the OSM node
*/
default void preprocessOsmNode(OsmElement.Node node) {}
/**
* Allows profile to extract any information it needs from a {@link OsmElement.Way} during the first pass through OSM
* elements.
* <p>
* The default implementation does nothing.
*
* @param way the OSM way
*/
default void preprocessOsmWay(OsmElement.Way way) {}
/**
* Extracts information from <a href="https://wiki.openstreetmap.org/wiki/Relation">OSM relations</a> that will be
* passed along to {@link #processFeature(SourceFeature, FeatureCollector)} for any OSM element in that relation.
* <p>
* The result of this method is stored in memory.
* <p>
* The default implementation returns {@code null} to ignore all relations
*
* @param relation the OSM relation
* @return a list of relation info instances with information extracted from the relation to pass to
* {@link #processFeature(SourceFeature, FeatureCollector)}, or {@code null} to ignore.
*/
default List<OsmRelationInfo> preprocessOsmRelation(OsmElement.Relation relation) {
return null;
}
/**
* Generates output features for any input feature that should appear in the map.
* <p>
* Multiple threads may invoke this method concurrently for a single data source so implementations should ensure
* thread-safe access to any shared data structures. Separate data sources are processed sequentially.
* <p>
* All OSM nodes are processed first, then ways, then relations.
*
* @param sourceFeature the input feature from a source dataset (OSM element, shapefile element, etc.)
* @param features a collector for generating output map features to emit
*/
void processFeature(SourceFeature sourceFeature, FeatureCollector features);
/** Free any resources associated with this profile (i.e. shared data structures) */
default void release() {}
/**
* Apply any post-processing to features in an output layer of a tile before writing it to the output file
* <p>
* These transformations may add, remove, or change the tags, geometry, or ordering of output features based on other
* features present in this tile. See {@link FeatureMerge} class for a set of common transformations that merge
* linestrings/polygons.
* <p>
* Many threads invoke this method concurrently so ensure thread-safe access to any shared data structures.
* <p>
* The default implementation passes through input features unaltered
*
* @param layer the output layer name
* @param zoom zoom level of the tile
* @param items all the output features in this layer in this tile
* @return the new list of output features or {@code null} to not change anything. Set any elements of the list to
* {@code null} if they should be ignored.
* @throws GeometryException for any recoverable geometric operation failures - the framework will log the error, emit
* the original input features, and continue processing other layers
*/
default List<VectorTile.Feature> postProcessLayerFeatures(String layer, int zoom,
List<VectorTile.Feature> items) throws GeometryException {
return items;
}
/**
* Apply any post-processing to layers in an output tile before writing it to the output.
* <p>
* This is called before {@link #postProcessLayerFeatures(String, int, List)} gets called for each layer. Use this
* method if features in one layer should influence features in another layer, to create new layers from existing
* ones, or if you need to remove a layer entirely from the output.
* <p>
* These transformations may add, remove, or change the tags, geometry, or ordering of output features based on other
* features present in this tile. See {@link FeatureMerge} class for a set of common transformations that merge
* linestrings/polygons.
* <p>
* Many threads invoke this method concurrently so ensure thread-safe access to any shared data structures.
* <p>
* The default implementation passes through input features unaltered
*
* @param tileCoord the tile being post-processed
* @param layers all the output features in each layer on this tile
* @return the new map from layer to features or {@code null} to not change anything. Set any elements of the lists to
* {@code null} if they should be ignored.
* @throws GeometryException for any recoverable geometric operation failures - the framework will log the error, emit
* the original input features, and continue processing other tiles
*/
default Map<String, List<VectorTile.Feature>> postProcessTileFeatures(TileCoord tileCoord,
Map<String, List<VectorTile.Feature>> layers) throws GeometryException {
return layers;
}
/**
* Returns the name of the generated tileset to put into {@link Mbtiles} metadata
*
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#metadata">MBTiles specification</a>
*/
String name();
/**
* Returns the description of the generated tileset to put into {@link Mbtiles} metadata
*
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#metadata">MBTiles specification</a>
*/
default String description() {
return null;
}
/**
* Returns the attribution of the generated tileset to put into {@link Mbtiles} metadata
*
* @see <a href="https://www.openstreetmap.org/copyright">https://www.openstreetmap.org/copyright</a> for attribution
* requirements of any map using OpenStreetMap data
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#metadata">MBTiles specification</a>
*/
default String attribution() {
return null;
}
/**
* Returns the version of the generated tileset to put into {@link Mbtiles} metadata
*
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#metadata">MBTiles specification</a>
*/
default String version() {
return null;
}
/**
* Returns {@code true} to set {@code type="overlay"} in {@link Mbtiles} metadata otherwise sets {@code
* type="baselayer"}
* <p>
* The default implementation sets {@code type="baselayer"}
*
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#metadata">MBTiles specification</a>
*/
default boolean isOverlay() {
return false;
}
default Map<String, String> extraArchiveMetadata() {
return Map.of();
}
/**
* Defines whether {@link Wikidata} should fetch wikidata translations for the input element.
* <p>
* The default implementation returns {@code true} for all elements
*
* @param elem the input OSM element
* @return {@code true} to fetch wikidata translations for {@code elem}, {@code false} to ignore
*/
default boolean caresAboutWikidataTranslation(OsmElement elem) {
return true;
}
/**
* Invoked once for each source after all elements for that source have been processed.
*
* @param sourceName the name of the source that just finished
* @param featureCollectors a supplier for new {@link FeatureCollector} instances for a {@link SourceFeature}.
* @param next a consumer to pass finished map features to
*/
default void finish(String sourceName, FeatureCollector.Factory featureCollectors,
Consumer<FeatureCollector.Feature> next) {}
/**
* Returns true if this profile will use any of the elements from an input source.
* <p>
* The default implementation returns true.
*
* @param name the input source name
* @return {@code true} if this profile uses that source, {@code false} if it is safe to ignore
*/
default boolean caresAboutSource(String name) {
return true;
}
/**
* Returns an estimate for how many bytes of disk this profile will use for intermediate feature storage to warn when
* running with insufficient disk space.
*/
default long estimateIntermediateDiskBytes(long osmFileSize) {
return 0L;
}
/**
* Returns an estimate for how many bytes the output file will be to warn when running with insufficient disk space.
*/
default long estimateOutputBytes(long osmFileSize) {
return 0L;
}
/**
* Returns an estimate for how many bytes of RAM this will use to warn when running with insufficient memory.
* <p>
* This should include memory for things the profile stores in memory, as well as relations and multipolygons.
*/
default long estimateRamRequired(long osmFileSize) {
return 0L;
}
/**
* A default implementation of {@link Profile} that emits no output elements.
*/
class NullProfile implements Profile {
@Override
public void processFeature(SourceFeature sourceFeature, FeatureCollector features) {}
@Override
public List<VectorTile.Feature> postProcessLayerFeatures(String layer, int zoom,
List<VectorTile.Feature> items) {
return items;
}
@Override
public String name() {
return "Null";
}
}
}