2021-08-02 00:26:22 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors.
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Code license: BSD 3-Clause License
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
|
|
list of conditions and the following disclaimer.
|
|
|
|
|
|
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
this list of conditions and the following disclaimer in the documentation
|
|
|
|
and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
* Neither the name of the copyright holder nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived from
|
|
|
|
this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
Design license: CC-BY 4.0
|
|
|
|
|
|
|
|
See https://github.com/openmaptiles/openmaptiles/blob/master/LICENSE.md for details on usage
|
|
|
|
*/
|
2021-12-23 10:42:24 +00:00
|
|
|
package com.onthegomap.planetiler.basemap.layers;
|
2021-06-14 11:04:03 +00:00
|
|
|
|
2021-12-23 10:42:24 +00:00
|
|
|
import static com.onthegomap.planetiler.basemap.util.Utils.elevationTags;
|
|
|
|
import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty;
|
2021-06-14 11:04:03 +00:00
|
|
|
|
2021-06-17 01:05:42 +00:00
|
|
|
import com.carrotsearch.hppc.LongIntHashMap;
|
|
|
|
import com.carrotsearch.hppc.LongIntMap;
|
2021-12-23 10:42:24 +00:00
|
|
|
import com.onthegomap.planetiler.FeatureCollector;
|
|
|
|
import com.onthegomap.planetiler.VectorTile;
|
|
|
|
import com.onthegomap.planetiler.basemap.BasemapProfile;
|
|
|
|
import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema;
|
|
|
|
import com.onthegomap.planetiler.basemap.generated.Tables;
|
|
|
|
import com.onthegomap.planetiler.basemap.util.LanguageUtils;
|
|
|
|
import com.onthegomap.planetiler.config.PlanetilerConfig;
|
|
|
|
import com.onthegomap.planetiler.geo.GeometryException;
|
|
|
|
import com.onthegomap.planetiler.stats.Stats;
|
|
|
|
import com.onthegomap.planetiler.util.Parse;
|
|
|
|
import com.onthegomap.planetiler.util.Translations;
|
2021-06-16 10:01:39 +00:00
|
|
|
import java.util.List;
|
2021-09-10 00:46:20 +00:00
|
|
|
import org.locationtech.jts.geom.Geometry;
|
|
|
|
import org.locationtech.jts.geom.Point;
|
2021-06-14 11:04:03 +00:00
|
|
|
|
2021-08-02 00:26:22 +00:00
|
|
|
/**
|
2021-09-16 09:15:43 +00:00
|
|
|
* Defines the logic for generating map elements for mountain peak label points in the {@code mountain_peak} layer from
|
|
|
|
* source features.
|
|
|
|
* <p>
|
|
|
|
* This class is ported to Java from <a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers/mountain_peak">OpenMapTiles
|
|
|
|
* mountain_peak sql files</a>.
|
2021-08-02 00:26:22 +00:00
|
|
|
*/
|
2021-06-14 11:04:03 +00:00
|
|
|
public class MountainPeak implements
|
2021-06-19 09:35:57 +00:00
|
|
|
OpenMapTilesSchema.MountainPeak,
|
2021-06-16 10:01:39 +00:00
|
|
|
Tables.OsmPeakPoint.Handler,
|
2021-10-20 01:57:47 +00:00
|
|
|
BasemapProfile.FeaturePostProcessor {
|
2021-06-16 10:01:39 +00:00
|
|
|
|
2021-09-16 09:15:43 +00:00
|
|
|
/*
|
|
|
|
* Mountain peaks come from OpenStreetMap data and are ranked by importance (based on if they
|
|
|
|
* have a name or wikipedia page) then by elevation. Uses the "label grid" feature to limit
|
|
|
|
* label density by only taking the top 5 most important mountain peaks within each 100x100px
|
|
|
|
* square.
|
|
|
|
*/
|
|
|
|
|
2021-06-16 10:01:39 +00:00
|
|
|
private final Translations translations;
|
2021-09-10 00:46:20 +00:00
|
|
|
private final Stats stats;
|
2021-06-16 10:01:39 +00:00
|
|
|
|
2021-12-23 10:42:24 +00:00
|
|
|
public MountainPeak(Translations translations, PlanetilerConfig config, Stats stats) {
|
2021-06-16 10:01:39 +00:00
|
|
|
this.translations = translations;
|
2021-09-10 00:46:20 +00:00
|
|
|
this.stats = stats;
|
2021-06-16 10:01:39 +00:00
|
|
|
}
|
2021-06-14 11:04:03 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void process(Tables.OsmPeakPoint element, FeatureCollector features) {
|
|
|
|
Integer meters = Parse.parseIntSubstring(element.ele());
|
2021-06-16 10:01:39 +00:00
|
|
|
if (meters != null && Math.abs(meters) < 10_000) {
|
2021-06-14 11:04:03 +00:00
|
|
|
features.point(LAYER_NAME)
|
|
|
|
.setAttr(Fields.CLASS, element.source().getTag("natural"))
|
2021-09-10 00:46:20 +00:00
|
|
|
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations))
|
|
|
|
.putAttrs(elevationTags(meters))
|
2021-09-18 00:18:06 +00:00
|
|
|
.setSortKeyDescending(
|
2021-06-16 10:01:39 +00:00
|
|
|
meters +
|
2021-06-17 01:05:42 +00:00
|
|
|
(nullIfEmpty(element.wikipedia()) != null ? 10_000 : 0) +
|
|
|
|
(nullIfEmpty(element.name()) != null ? 10_000 : 0)
|
2021-06-16 10:01:39 +00:00
|
|
|
)
|
2021-09-16 09:15:43 +00:00
|
|
|
.setMinZoom(7)
|
|
|
|
// need to use a larger buffer size to allow enough points through to not cut off
|
|
|
|
// any label grid squares which could lead to inconsistent label ranks for a feature
|
|
|
|
// in adjacent tiles. postProcess() will remove anything outside the desired buffer.
|
2021-09-10 00:46:20 +00:00
|
|
|
.setBufferPixels(100)
|
2022-01-10 11:41:15 +00:00
|
|
|
.setPointLabelGridSizeAndLimit(13, 100, 5);
|
2021-06-14 11:04:03 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-16 10:01:39 +00:00
|
|
|
|
|
|
|
@Override
|
2021-09-10 00:46:20 +00:00
|
|
|
public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) {
|
2021-06-17 01:05:42 +00:00
|
|
|
LongIntMap groupCounts = new LongIntHashMap();
|
2021-09-18 00:18:06 +00:00
|
|
|
for (int i = 0; i < items.size(); i++) {
|
2021-09-10 00:46:20 +00:00
|
|
|
VectorTile.Feature feature = items.get(i);
|
2021-06-17 01:05:42 +00:00
|
|
|
int gridrank = groupCounts.getOrDefault(feature.group(), 1);
|
|
|
|
groupCounts.put(feature.group(), gridrank + 1);
|
2021-09-16 09:15:43 +00:00
|
|
|
// now that we have accurate ranks, remove anything outside the desired buffer
|
2021-09-10 00:46:20 +00:00
|
|
|
if (!insideTileBuffer(feature)) {
|
|
|
|
items.set(i, null);
|
|
|
|
} else if (!feature.attrs().containsKey(Fields.RANK)) {
|
2021-06-17 01:05:42 +00:00
|
|
|
feature.attrs().put(Fields.RANK, gridrank);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return items;
|
2021-06-16 10:01:39 +00:00
|
|
|
}
|
2021-09-10 00:46:20 +00:00
|
|
|
|
2021-09-16 09:15:43 +00:00
|
|
|
private static boolean insideTileBuffer(double xOrY) {
|
2021-09-10 00:46:20 +00:00
|
|
|
return xOrY >= -BUFFER_SIZE && xOrY <= 256 + BUFFER_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean insideTileBuffer(VectorTile.Feature feature) {
|
|
|
|
try {
|
|
|
|
Geometry geom = feature.geometry().decode();
|
|
|
|
return !(geom instanceof Point point) || (insideTileBuffer(point.getX()) && insideTileBuffer(point.getY()));
|
|
|
|
} catch (GeometryException e) {
|
|
|
|
e.log(stats, "mountain_peak_decode_point", "Error decoding mountain peak point: " + feature.attrs());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-06-14 11:04:03 +00:00
|
|
|
}
|