Update of latlon2country and use its async interface; small refactoring of simplemetagging, improvements to cacheBuilder which respects isShown and calculated tags now

This commit is contained in:
pietervdvn 2021-12-07 02:22:56 +01:00
parent e053e9f279
commit 9cfb7fbe68
14 changed files with 417 additions and 4320 deletions

View file

@ -1,3 +0,0 @@
{
"files.eol": "\n"
}

View file

@ -68,7 +68,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
const features: { feature: any; freshness: Date }[] = this.upstream.features.data;
const newFeatures = features.filter((f) => {
self.registerCallback(f.feature, layer.layerDef)
self.registerCallback(f.feature)
if (
this.state.selectedElement.data?.id === f.feature.id ||
@ -105,15 +105,18 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
this._is_dirty.setData(false)
}
private registerCallback(feature: any, layer: LayerConfig) {
const src = this.state.allElements.addOrGetElement(feature)
private registerCallback(feature: any) {
const src = this.state?.allElements?.addOrGetElement(feature)
if(src == undefined){
return
}
if (this._alreadyRegistered.has(src)) {
return
}
this._alreadyRegistered.add(src)
const self = this;
src.addCallbackAndRunD(isShown => {
src.addCallbackAndRunD(_ => {
self._is_dirty.setData(true)
})
}

View file

@ -86,6 +86,10 @@ export default class TiledFeatureSource implements Tiled, IndexedFeatureSource,
}
public static createHierarchy(features: FeatureSource, options?: TiledFeatureSourceOptions): TiledFeatureSource {
options = {
...options,
layer: features["layer"] ?? options.layer
}
const root = new TiledFeatureSource(0, 0, 0, null, options)
features.features?.addCallbackAndRunD(feats => root.addFeatures(feats))
return root;
@ -200,6 +204,6 @@ export interface TiledFeatureSourceOptions {
* Setting 'dontEnforceMinZoomLevel' will still allow bigger zoom levels for those features
*/
readonly dontEnforceMinZoom?: boolean,
readonly registerTile?: (tile: TiledFeatureSource & Tiled) => void,
readonly registerTile?: (tile: TiledFeatureSource & FeatureSourceForLayer & Tiled) => void,
readonly layer?: FilteredLayer
}

View file

@ -25,8 +25,7 @@ export class GeoOperations {
}
static centerpointCoordinates(feature: any): [number, number] {
// @ts-ignore
return turf.center(feature).geometry.coordinates;
return <[number, number]> turf.center(feature).geometry.coordinates;
}
/**
@ -35,7 +34,7 @@ export class GeoOperations {
* @param lonlat1
*/
static distanceBetween(lonlat0: [number, number], lonlat1: [number, number]) {
return turf.distance(lonlat0, lonlat1) * 1000
return turf.distance(lonlat0, lonlat1, {units: "meters"})
}
/**
@ -196,8 +195,8 @@ export class GeoOperations {
static buffer(feature: any, bufferSizeInMeter: number) {
return turf.buffer(feature, bufferSizeInMeter / 1000, {
units: 'kilometers'
})
units:'kilometers'
} )
}
static bbox(feature: any) {

View file

@ -1,4 +1,4 @@
import SimpleMetaTagger from "./SimpleMetaTagger";
import SimpleMetaTaggers from "./SimpleMetaTagger";
import {ExtraFuncParams, ExtraFunctions} from "./ExtraFunctions";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import State from "../State";
@ -33,9 +33,8 @@ export default class MetaTagging {
return;
}
const metatagsToApply: SimpleMetaTagger [] = []
for (const metatag of SimpleMetaTagger.metatags) {
const metatagsToApply: SimpleMetaTaggers[] = []
for (const metatag of SimpleMetaTaggers.metatags) {
if (metatag.includesDates) {
if (options.includeDates ?? true) {
metatagsToApply.push(metatag)
@ -59,19 +58,23 @@ export default class MetaTagging {
let somethingChanged = false
for (const metatag of metatagsToApply) {
try {
// @ts-ignore
if (!metatag.keys.some(key => feature.properties[key] === undefined)) {
// All keys are already defined, we probably already ran this one
continue
}
// @ts-ignore
if (metatag.isLazy) {
somethingChanged = true;
// @ts-ignore
metatag.applyMetaTagsOnFeature(feature, freshness, layer)
} else {
// @ts-ignore
const newValueAdded = metatag.applyMetaTagsOnFeature(feature, freshness, layer)
/* Note that the expression:
* `somethingChanged = newValueAdded || metatag.applyMetaTagsOnFeature(feature, freshness)`
@ -83,6 +86,7 @@ export default class MetaTagging {
somethingChanged = newValueAdded || somethingChanged
}
} catch (e) {
// @ts-ignore
console.error("Could not calculate metatag for ", metatag.keys.join(","), ":", e, e.stack)
}
}
@ -117,8 +121,9 @@ export default class MetaTagging {
const func = new Function("feat", "return " + code + ";");
const f = (feature: any) => {
delete feature.properties[key]
Object.defineProperty(feature.properties, key, {
configurable: true,
enumerable: false, // By setting this as not enumerable, the localTileSaver will _not_ calculate this
@ -149,7 +154,6 @@ export default class MetaTagging {
}
})
}

View file

@ -7,18 +7,92 @@ import BaseUIElement from "../UI/BaseUIElement";
import Title from "../UI/Base/Title";
import {FixedUiElement} from "../UI/Base/FixedUiElement";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import {CountryCoder} from "latlon2country"
const cardinalDirections = {
N: 0, NNE: 22.5, NE: 45, ENE: 67.5,
E: 90, ESE: 112.5, SE: 135, SSE: 157.5,
S: 180, SSW: 202.5, SW: 225, WSW: 247.5,
W: 270, WNW: 292.5, NW: 315, NNW: 337.5
export class SimpleMetaTagger {
public readonly keys: string[];
public readonly doc: string;
public readonly isLazy: boolean;
public readonly includesDates: boolean
public readonly applyMetaTagsOnFeature: (feature: any, freshness: Date, layer: LayerConfig) => boolean;
/***
* A function that adds some extra data to a feature
* @param docs: what does this extra data do?
* @param f: apply the changes. Returns true if something changed
*/
constructor(docs: { keys: string[], doc: string, includesDates?: boolean, isLazy?: boolean, cleanupRetagger?: boolean },
f: ((feature: any, freshness: Date, layer: LayerConfig) => boolean)) {
this.keys = docs.keys;
this.doc = docs.doc;
this.isLazy = docs.isLazy
this.applyMetaTagsOnFeature = f;
this.includesDates = docs.includesDates ?? false;
if (!docs.cleanupRetagger) {
for (const key of docs.keys) {
if (!key.startsWith('_') && key.toLowerCase().indexOf("theme") < 0) {
throw `Incorrect metakey ${key}: it should start with underscore (_)`
}
}
}
}
}
export class CountryTagger extends SimpleMetaTagger {
private static readonly coder = new CountryCoder("https://pietervdvn.github.io/latlon2country/");
public runningTasks: Set<any>;
constructor() {
const runningTasks= new Set<any>();
super
(
{
keys: ["_country"],
doc: "The country code of the property (with latlon2country)",
includesDates: false
},
((feature, _) => {
let centerPoint: any = GeoOperations.centerpoint(feature);
const lat = centerPoint.geometry.coordinates[1];
const lon = centerPoint.geometry.coordinates[0];
runningTasks.add(feature)
CountryTagger.coder.GetCountryCodeAsync(lon, lat).then(
countries => {
runningTasks.delete(feature)
try {
const oldCountry = feature.properties["_country"];
feature.properties["_country"] = countries[0].trim().toLowerCase();
if (oldCountry !== feature.properties["_country"]) {
const tagsSource = State.state?.allElements?.getEventSourceById(feature.properties.id);
tagsSource?.ping();
}
} catch (e) {
console.warn(e)
}
}
).catch(_ => {
runningTasks.delete(feature)
})
return false;
})
)
this.runningTasks = runningTasks;
}
}
export default class SimpleMetaTaggers {
private static readonly cardinalDirections = {
N: 0, NNE: 22.5, NE: 45, ENE: 67.5,
E: 90, ESE: 112.5, SE: 135, SSE: 157.5,
S: 180, SSW: 202.5, SW: 225, WSW: 247.5,
W: 270, WNW: 292.5, NW: 315, NNW: 337.5
}
export default class SimpleMetaTagger {
public static coder: any;
public static readonly objectMetaInfo = new SimpleMetaTagger(
{
keys: ["_last_edit:contributor",
@ -92,7 +166,7 @@ export default class SimpleMetaTagger {
return;
}
return SimpleMetaTagger.removeBothTagging(feature.properties)
return SimpleMetaTaggers.removeBothTagging(feature.properties)
})
)
private static surfaceArea = new SimpleMetaTagger(
@ -197,32 +271,7 @@ export default class SimpleMetaTagger {
return true;
})
)
private static country = new SimpleMetaTagger(
{
keys: ["_country"],
doc: "The country code of the property (with latlon2country)",
includesDates: false
},
((feature, _) => {
let centerPoint: any = GeoOperations.centerpoint(feature);
const lat = centerPoint.geometry.coordinates[1];
const lon = centerPoint.geometry.coordinates[0];
SimpleMetaTagger.coder?.GetCountryCodeFor(lon, lat, (countries: string[]) => {
try {
const oldCountry = feature.properties["_country"];
feature.properties["_country"] = countries[0].trim().toLowerCase();
if (oldCountry !== feature.properties["_country"]) {
const tagsSource = State.state.allElements.getEventSourceById(feature.properties.id);
tagsSource.ping();
}
} catch (e) {
console.warn(e)
}
})
return false;
})
)
public static country = new CountryTagger()
private static isOpen = new SimpleMetaTagger(
{
keys: ["_isOpen", "_isOpen:description"],
@ -319,7 +368,7 @@ export default class SimpleMetaTagger {
if (direction === undefined) {
return false;
}
const n = cardinalDirections[direction] ?? Number(direction);
const n = SimpleMetaTaggers.cardinalDirections[direction] ?? Number(direction);
if (isNaN(n)) {
return false;
}
@ -333,6 +382,7 @@ export default class SimpleMetaTagger {
})
)
private static currentTime = new SimpleMetaTagger(
{
keys: ["_now:date", "_now:datetime", "_loaded:date", "_loaded:_datetime"],
@ -361,49 +411,24 @@ export default class SimpleMetaTagger {
return true;
}
)
public static metatags = [
SimpleMetaTagger.latlon,
SimpleMetaTagger.layerInfo,
SimpleMetaTagger.surfaceArea,
SimpleMetaTagger.lngth,
SimpleMetaTagger.canonicalize,
SimpleMetaTagger.country,
SimpleMetaTagger.isOpen,
SimpleMetaTagger.directionSimplified,
SimpleMetaTagger.currentTime,
SimpleMetaTagger.objectMetaInfo,
SimpleMetaTagger.noBothButLeftRight
public static metatags: SimpleMetaTagger[] = [
SimpleMetaTaggers.latlon,
SimpleMetaTaggers.layerInfo,
SimpleMetaTaggers.surfaceArea,
SimpleMetaTaggers.lngth,
SimpleMetaTaggers.canonicalize,
SimpleMetaTaggers.country,
SimpleMetaTaggers.isOpen,
SimpleMetaTaggers.directionSimplified,
SimpleMetaTaggers.currentTime,
SimpleMetaTaggers.objectMetaInfo,
SimpleMetaTaggers.noBothButLeftRight
];
public readonly keys: string[];
public readonly doc: string;
public readonly isLazy: boolean;
public readonly includesDates: boolean
public readonly applyMetaTagsOnFeature: (feature: any, freshness: Date, layer: LayerConfig) => boolean;
public static readonly lazyTags: string[] = [].concat(...SimpleMetaTagger.metatags.filter(tagger => tagger.isLazy)
public static readonly lazyTags: string[] = [].concat(...SimpleMetaTaggers.metatags.filter(tagger => tagger.isLazy)
.map(tagger => tagger.keys));
/***
* A function that adds some extra data to a feature
* @param docs: what does this extra data do?
* @param f: apply the changes. Returns true if something changed
*/
constructor(docs: { keys: string[], doc: string, includesDates?: boolean, isLazy?: boolean, cleanupRetagger?: boolean },
f: ((feature: any, freshness: Date, layer: LayerConfig) => boolean)) {
this.keys = docs.keys;
this.doc = docs.doc;
this.isLazy = docs.isLazy
this.applyMetaTagsOnFeature = f;
this.includesDates = docs.includesDates ?? false;
if (!docs.cleanupRetagger) {
for (const key of docs.keys) {
if (!key.startsWith('_') && key.toLowerCase().indexOf("theme") < 0) {
throw `Incorrect metakey ${key}: it should start with underscore (_)`
}
}
}
}
/**
* Edits the given object to rewrite 'both'-tagging into a 'left-right' tagging scheme.
@ -494,7 +519,7 @@ export default class SimpleMetaTagger {
subElements.push(new Title("Metatags calculated by MapComplete", 2))
subElements.push(new FixedUiElement("The following values are always calculated, by default, by MapComplete and are available automatically on all elements in every theme"))
for (const metatag of SimpleMetaTagger.metatags) {
for (const metatag of SimpleMetaTaggers.metatags) {
subElements.push(
new Title(metatag.keys.join(", "), 3),
metatag.doc,

View file

@ -29,7 +29,7 @@
{
"id": "render_crab",
"render": {
"nl": "Volgens het CRAB ligt hier <b>{STRAATNM}</b> {HUISNR} (label: {_HNRLABEL})"
"nl": "Volgens het CRAB ligt hier <b>{STRAATNM}</b> {HUISNR} (label: {HNRLABEL})"
}
}
]

View file

@ -370,8 +370,8 @@
"_embedding_street!:={STRAATNM}"
]
},
{ "#": "Matches the embedding GRB object",
{
"#": "Matches the embedding GRB object",
"or": [
"_embedding_nr_grb!:={HUISNR}",
"_embedding_street_grb!:={STRAATNM}"
@ -453,15 +453,14 @@
"render": "{import_button(OSM-buildings,building=$building;man_made=$man_made; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref; addr:street=$addr:street; addr:housenumber=$addr:housenumber; building:min_level=$_building:min_level, Upload this building to OpenStreetMap)}",
"mappings": [
{
"if": {"and":
[
"_overlaps_with!=",
"_osm_obj:addr:street=",
"_osm_obj:addr:housenumber=",
"addr:street~*",
"addr:housenumber~*"
]
"if": {
"and": [
"_overlaps_with!=",
"_osm_obj:addr:street=",
"_osm_obj:addr:housenumber=",
"addr:street~*",
"addr:housenumber~*"
]
},
"then": "{import_button(OSM-buildings,building=$_target_building_type; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref; addr:street=$addr:street; addr:housenumber=$addr:housenumber, Replace the geometry in OpenStreetMap and add the address,,,_osm_obj:id)}"
},
@ -578,21 +577,22 @@
"centroid"
]
},
{ "width": {
"render": 5,
"mappings": [
{
"if": "_imported=yes",
"then": "1"
}
]
},
{
"width": {
"render": 5,
"mappings": [
{
"if": "_imported=yes",
"then": "1"
}
]
},
"color": {
"render": "#00a",
"mappings": [
{
"if": "_imported=yes",
"then":"#00ff00"
"then": "#00ff00"
},
{
"if": {

View file

@ -0,0 +1,146 @@
{
"id": "postal_codes",
"title": {
"en": "Postal codes"
},
"shortDescription": {
"en": "Postal codes"
},
"description": {
"en": "Postal codes"
},
"language": [
"en"
],
"maintainer": "",
"icon": "./assets/svg/bug.svg",
"version": "0",
"startLat": 0,
"startLon": 0,
"startZoom": 1,
"widenFactor": 0.05,
"socialImage": "",
"layers": [
{
"id": "postal_codes",
"name": {
"en": "postal codes"
},
"minzoom": 12,
"title": {
"render": {
"en": "Postal code {postal_code}"
}
},
"description": {},
"tagRenderings": [
{
"id": "postal_code",
"render": {
"en": "The postal code is {postal_code}"
}
}
],
"presets": [],
"source": {
"isOsmCache": true,
"geoJson": "http://127.0.0.1:8080/postal_codes_postal_codes_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 1,
"osmTags": {
"or": [
"boundary=postal_code",
{
"and": [
"bounary=administrative",
"postal_code~*"
]
}
]
}
},
"mapRendering": [
{
"icon": {
"render": "./assets/svg/bug.svg"
},
"iconSize": {
"render": "40,40,center"
},
"location": [
"point",
"centroid"
]
},
{
"color": {
"render": "#00f"
},
"width": {
"render": "8"
}
}
],
"isShown": {
"render": "yes",
"mappings": [{
"if" :"_country!=be",
"then": "no"
}]
}
},
{
"id": "town_halls",
"name": {
"en": "town halls"
},
"minzoom": 12,
"title": {
"render": {
"en": "Town halls"
}
},
"calculatedTags": [
"_postal_code=feat.overlapWith('postal_codes')[0]?.feat?.properties?.postal_code"
],
"description": {},
"tagRenderings": [
],
"presets": [],
"source": {
"isOsmCache": true,
"geoJson": "http://127.0.0.1:8080/postal_codes_town_hall_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 1,
"osmTags": "amenity=townhall"
},
"mapRendering": [
{
"icon": {
"render": "./assets/svg/bug.svg"
},
"iconSize": {
"render": "40,40,center"
},
"location": [
"point",
"centroid"
]
},
{
"color": {
"render": "#00f"
},
"width": {
"render": "8"
}
}
],
"isShown": {
"render": "yes",
"mappings": [{
"if" :"_country!=be",
"then": "no"
}]
}
}
]
}

View file

@ -3,8 +3,6 @@ import {QueryParameters} from "./Logic/Web/QueryParameters";
import Combine from "./UI/Base/Combine";
import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers";
import MinimapImplementation from "./UI/Base/MinimapImplementation";
import CountryCoder from "latlon2country/index";
import SimpleMetaTagger from "./Logic/SimpleMetaTagger";
import {Utils} from "./Utils";
import AllThemesGui from "./UI/AllThemesGui";
import DetermineLayout from "./Logic/DetermineLayout";
@ -14,12 +12,10 @@ import State from "./State";
import AvailableBaseLayersImplementation from "./Logic/Actors/AvailableBaseLayersImplementation";
import ShowOverlayLayerImplementation from "./UI/ShowDataLayer/ShowOverlayLayerImplementation";
import {DefaultGuiState} from "./UI/DefaultGuiState";
import {Browser} from "leaflet";
// Workaround for a stupid crash: inject some functions which would give stupid circular dependencies or crash the other nodejs scripts running from console
MinimapImplementation.initialize()
AvailableBaseLayers.implement(new AvailableBaseLayersImplementation())
SimpleMetaTagger.coder = new CountryCoder("https://pietervdvn.github.io/latlon2country/");
ShowOverlayLayerImplementation.Implement();
// Miscelleanous

View file

@ -1032,6 +1032,24 @@
"shortDescription": "A map with playgrounds",
"title": "Playgrounds"
},
"postal_codes": {
"description": "Postal codes",
"layers": {
"0": {
"name": "postal codes",
"tagRenderings": {
"postal_code": {
"render": "The postal code is {postal_code}"
}
},
"title": {
"render": "Postal code {postal_code}"
}
}
},
"shortDescription": "Postal codes",
"title": "Postal codes"
},
"postboxes": {
"description": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :)<br/>Spotted an error or is a post box missing? You can edit this map with a free OpenStreetMap account. ",
"layers": {

4215
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -77,7 +77,7 @@
"idb-keyval": "^6.0.3",
"jquery": "^3.6.0",
"jspdf": "^2.3.1",
"latlon2country": "^1.1.3",
"latlon2country": "^1.2.3",
"leaflet": "^1.7.1",
"leaflet-polylineoffset": "^1.1.1",
"leaflet-providers": "^1.13.0",

View file

@ -21,7 +21,9 @@ import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSou
import TiledFeatureSource from "../Logic/FeatureSource/TiledFeatureSource/TiledFeatureSource";
import Constants from "../Models/Constants";
import {GeoOperations} from "../Logic/GeoOperations";
import SimpleMetaTaggers from "../Logic/SimpleMetaTagger";
import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource";
import Loc from "../Models/Loc";
ScriptUtils.fixUtils()
@ -177,12 +179,15 @@ function loadAllTiles(targetdir: string, r: TileRange, theme: LayoutConfig, extr
* Load all the tiles into memory from disk
*/
function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relationsTracker: RelationsTracker, targetdir: string, pointsOnlyLayers: string[]) {
function handleLayer(source: FeatureSourceForLayer) {
const skippedLayers = new Set<string>()
async function handleLayer(source: FeatureSourceForLayer) {
const layer = source.layer.layerDef;
const targetZoomLevel = layer.source.geojsonZoomLevel ?? 0
const layerId = layer.id
if (layer.source.isOsmCacheLayer !== true) {
skippedLayers.add(layer.id)
return;
}
console.log("Handling layer ", layerId, "which has", source.features.data.length, "features")
@ -201,6 +206,13 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
includeDates: false,
includeNonDates: true
});
while (SimpleMetaTaggers.country.runningTasks.size > 0) {
console.log("Still waiting for ", SimpleMetaTaggers.country.runningTasks.size," features which don't have a country yet")
await ScriptUtils.sleep(1)
}
const createdTiles = []
// At this point, we have all the features of the entire area.
@ -210,23 +222,57 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
maxZoomLevel: targetZoomLevel,
maxFeatureCount: undefined,
registerTile: tile => {
const tileIndex = tile.tileIndex;
if (tile.features.data.length === 0) {
return
}
for (const feature of tile.features.data) {
const filteredTile = new FilteringFeatureSource({
locationControl: new UIEventSource<Loc>(undefined),
allElements: undefined,
selectedElement: new UIEventSource<any>(undefined)
},
tileIndex,
tile,
new UIEventSource<any>(undefined)
)
if (filteredTile.features.data.length === 0) {
return
}
let strictlyCalculated = 0
let featureCount = 0
for (const feature of filteredTile.features.data) {
// Some cleanup
delete feature.feature["bbox"]
if(tile.layer.layerDef.calculatedTags !== undefined){
// Evaluate all the calculated tags strictly
const calculatedTagKeys = tile.layer.layerDef.calculatedTags.map(ct => ct[0])
featureCount++
for (const calculatedTagKey of calculatedTagKeys) {
const strict = feature.feature.properties[calculatedTagKey]
feature.feature.properties[calculatedTagKey] =strict
strictlyCalculated ++;
if(strictlyCalculated % 100 === 0){
console.log("Strictly calculated ", strictlyCalculated, "values for tile",tileIndex,": now at ", featureCount,"/",filteredTile.features.data.length, "examle value: ", strict)
}
}
}
}
// Lets save this tile!
const [z, x, y] = Tiles.tile_from_index(tile.tileIndex)
const [z, x, y] = Tiles.tile_from_index(tileIndex)
// console.log("Writing tile ", z, x, y, layerId)
const targetPath = geoJsonName(targetdir + "_" + layerId, x, y, z)
createdTiles.push(tile.tileIndex)
createdTiles.push(tileIndex)
// This is the geojson file containing all features for this tile
writeFileSync(targetPath, JSON.stringify({
type: "FeatureCollection",
features: tile.features.data.map(f => f.feature)
features: filteredTile.features.data.map(f => f.feature)
}, null, " "))
console.log("Written tile", targetPath,"with", filteredTile.features.data.length)
}
})
@ -267,18 +313,31 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
handleLayer,
allFeatures
)
const skipped = Array.from(skippedLayers)
if (skipped.length > 0) {
console.warn("Did not save any cache files for layers " + skipped.join(", ") + " as these didn't set the flag `isOsmCache` to true")
}
}
async function main(args: string[]) {
if (args.length == 0) {
console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...]")
console.log("Cache builder started with args ", args.join(", "))
if (args.length < 6) {
console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...]\n" +
"Note: a new directory named <theme> will be created in targetdirectory")
return;
}
const themeName = args[0]
const zoomlevel = Number(args[1])
const targetdir = args[2] + "/" + themeName
if (!existsSync(args[2])) {
console.log("Directory not found")
throw "The directory " + args[2] + "does not exist"
}
const lat0 = Number(args[3])
const lon0 = Number(args[4])
const lat1 = Number(args[5])
@ -292,6 +351,11 @@ async function main(args: string[]) {
const tileRange = Tiles.TileRangeBetween(zoomlevel, lat0, lon0, lat1, lon1)
if (tileRange.total === 0) {
console.log("Tilerange has zero tiles - this is probably an error")
return
}
const theme = AllKnownLayouts.allKnownLayouts.get(themeName)
if (theme === undefined) {
const keys = []
@ -321,5 +385,9 @@ async function main(args: string[]) {
let args = [...process.argv]
args.splice(0, 2)
main(args);
try {
main(args).catch(e => console.error("Error building cache:", e));
} catch (e) {
console.error("Error building cache:", e)
}
console.log("All done!")