2021-04-22 03:30:46 +02:00
/ * *
* Generates a collection of geojson files based on an overpass query for a given theme
* /
2021-07-10 21:03:41 +02:00
import { Utils } from "../Utils" ;
2021-04-22 03:30:46 +02:00
import { Overpass } from "../Logic/Osm/Overpass" ;
2021-04-23 12:58:49 +02:00
import { existsSync , readFileSync , writeFileSync } from "fs" ;
2021-04-22 03:30:46 +02:00
import { TagsFilter } from "../Logic/Tags/TagsFilter" ;
import { Or } from "../Logic/Tags/Or" ;
import { AllKnownLayouts } from "../Customizations/AllKnownLayouts" ;
2021-09-21 02:10:42 +02:00
import RelationsTracker from "../Logic/Osm/RelationsTracker" ;
2021-04-22 03:30:46 +02:00
import * as OsmToGeoJson from "osmtogeojson" ;
2021-04-22 13:30:00 +02:00
import MetaTagging from "../Logic/MetaTagging" ;
2022-07-22 11:50:25 +02:00
import { ImmutableStore , UIEventSource } from "../Logic/UIEventSource" ;
2021-09-26 17:36:39 +02:00
import { TileRange , Tiles } from "../Models/TileRange" ;
2021-08-07 23:11:34 +02:00
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" ;
2021-09-10 00:00:48 +02:00
import ScriptUtils from "./ScriptUtils" ;
2021-09-21 02:10:42 +02:00
import PerLayerFeatureSourceSplitter from "../Logic/FeatureSource/PerLayerFeatureSourceSplitter" ;
import FilteredLayer from "../Models/FilteredLayer" ;
import FeatureSource , { FeatureSourceForLayer } from "../Logic/FeatureSource/FeatureSource" ;
import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource" ;
import TiledFeatureSource from "../Logic/FeatureSource/TiledFeatureSource/TiledFeatureSource" ;
2021-10-03 01:38:57 +02:00
import Constants from "../Models/Constants" ;
2021-10-13 00:08:41 +02:00
import { GeoOperations } from "../Logic/GeoOperations" ;
2021-12-07 02:22:56 +01:00
import SimpleMetaTaggers from "../Logic/SimpleMetaTagger" ;
import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource" ;
import Loc from "../Models/Loc" ;
2022-01-16 01:59:06 +01:00
2021-09-10 00:00:48 +02:00
ScriptUtils . fixUtils ( )
2021-09-09 00:05:51 +02:00
2021-10-03 01:38:57 +02:00
function createOverpassObject ( theme : LayoutConfig , relationTracker : RelationsTracker , backend : string ) {
2021-04-22 03:30:46 +02:00
let filters : TagsFilter [ ] = [ ] ;
let extraScripts : string [ ] = [ ] ;
for ( const layer of theme . layers ) {
if ( typeof ( layer ) === "string" ) {
throw "A layer was not expanded!"
}
if ( layer . doNotDownload ) {
continue ;
}
if ( layer . source . geojsonSource !== undefined ) {
2021-05-14 02:25:30 +02:00
// This layer defines a geoJson-source
// SHould it be cached?
2021-07-27 15:06:36 +02:00
if ( layer . source . isOsmCacheLayer !== true ) {
2021-05-14 02:25:30 +02:00
continue ;
}
2021-04-22 03:30:46 +02:00
}
// Check if data for this layer has already been loaded
if ( layer . source . overpassScript !== undefined ) {
extraScripts . push ( layer . source . overpassScript )
} else {
filters . push ( layer . source . osmTags ) ;
}
}
filters = Utils . NoNull ( filters )
extraScripts = Utils . NoNull ( extraScripts )
if ( filters . length + extraScripts . length === 0 ) {
throw "Nothing to download! The theme doesn't declare anything to download"
}
2021-10-03 01:38:57 +02:00
return new Overpass ( new Or ( filters ) , extraScripts , backend ,
2021-09-21 02:10:42 +02:00
new UIEventSource < number > ( 60 ) , relationTracker ) ;
2021-04-22 03:30:46 +02:00
}
function rawJsonName ( targetDir : string , x : number , y : number , z : number ) : string {
return targetDir + "_" + z + "_" + x + "_" + y + ".json"
}
function geoJsonName ( targetDir : string , x : number , y : number , z : number ) : string {
return targetDir + "_" + z + "_" + x + "_" + y + ".geojson"
}
2021-05-14 02:25:30 +02:00
/// Downloads the given feature and saves them to disk
2021-10-03 01:38:57 +02:00
async function downloadRaw ( targetdir : string , r : TileRange , theme : LayoutConfig , relationTracker : RelationsTracker ) /* : {failed: number, skipped :number} */ {
2021-04-22 03:30:46 +02:00
let downloaded = 0
2021-04-22 16:01:43 +02:00
let failed = 0
let skipped = 0
2021-10-13 01:28:20 +02:00
const startTime = new Date ( ) . getTime ( )
2021-04-22 03:30:46 +02:00
for ( let x = r . xstart ; x <= r . xend ; x ++ ) {
for ( let y = r . ystart ; y <= r . yend ; y ++ ) {
downloaded ++ ;
const filename = rawJsonName ( targetdir , x , y , r . zoomlevel )
if ( existsSync ( filename ) ) {
2021-09-21 02:10:42 +02:00
console . log ( "Already exists (not downloading again): " , filename )
2021-04-22 16:01:43 +02:00
skipped ++
2021-04-22 03:30:46 +02:00
continue ;
}
2021-10-13 01:28:20 +02:00
const runningSeconds = ( new Date ( ) . getTime ( ) - startTime ) / 1000
const resting = failed + ( r . total - downloaded )
2021-11-07 16:34:51 +01:00
const perTile = ( runningSeconds / ( downloaded - skipped ) )
const estimated = Math . floor ( resting * perTile )
console . log ( "total: " , downloaded , "/" , r . total , "failed: " , failed , "skipped: " , skipped , "running time: " , Utils . toHumanTime ( runningSeconds ) + "s" , "estimated left: " , Utils . toHumanTime ( estimated ) , "(" + Math . floor ( perTile ) + "s/tile)" )
2021-04-22 03:30:46 +02:00
2021-09-26 17:36:39 +02:00
const boundsArr = Tiles . tile_bounds ( r . zoomlevel , x , y )
2021-04-22 03:30:46 +02:00
const bounds = {
north : Math.max ( boundsArr [ 0 ] [ 0 ] , boundsArr [ 1 ] [ 0 ] ) ,
south : Math.min ( boundsArr [ 0 ] [ 0 ] , boundsArr [ 1 ] [ 0 ] ) ,
east : Math.max ( boundsArr [ 0 ] [ 1 ] , boundsArr [ 1 ] [ 1 ] ) ,
west : Math.min ( boundsArr [ 0 ] [ 1 ] , boundsArr [ 1 ] [ 1 ] )
}
2021-10-13 01:28:20 +02:00
const overpass = createOverpassObject ( theme , relationTracker , Constants . defaultOverpassUrls [ ( failed ) % Constants . defaultOverpassUrls . length ] )
2021-04-22 03:30:46 +02:00
const url = overpass . buildQuery ( "[bbox:" + bounds . south + "," + bounds . west + "," + bounds . north + "," + bounds . east + "]" )
2021-10-03 01:38:57 +02:00
try {
2021-07-18 19:08:14 +02:00
2022-02-14 01:15:20 +01:00
const json = await Utils . downloadJson ( url )
2021-10-03 02:11:06 +02:00
if ( ( < string > json . remark ? ? "" ) . startsWith ( "runtime error" ) ) {
console . error ( "Got a runtime error: " , json . remark )
failed ++ ;
2021-11-07 16:34:51 +01:00
} else if ( json . elements . length === 0 ) {
2021-10-03 02:11:06 +02:00
console . log ( "Got an empty response! Writing anyway" )
}
2021-10-03 01:38:57 +02:00
2021-11-07 16:34:51 +01:00
2022-06-05 02:24:14 +02:00
console . log ( "Got the response - writing " , json . elements . length , " elements to " , filename )
2021-11-07 16:34:51 +01:00
writeFileSync ( filename , JSON . stringify ( json , null , " " ) ) ;
2021-10-03 01:38:57 +02:00
} catch ( err ) {
console . log ( url )
console . log ( "Could not download - probably hit the rate limit; waiting a bit. (" + err + ")" )
failed ++ ;
await ScriptUtils . sleep ( 1000 )
2021-09-10 00:00:48 +02:00
}
2021-04-22 03:30:46 +02:00
}
}
2021-04-22 16:01:43 +02:00
return { failed : failed , skipped : skipped }
2021-04-22 03:30:46 +02:00
}
2021-05-14 02:25:30 +02:00
/ *
* Downloads extra geojson sources and returns the features .
* Extra geojson layers should not be tiled
* /
async function downloadExtraData ( theme : LayoutConfig ) /* : any[] */ {
const allFeatures : any [ ] = [ ]
for ( const layer of theme . layers ) {
const source = layer . source . geojsonSource ;
if ( source === undefined ) {
continue ;
}
2021-09-10 00:00:48 +02:00
if ( layer . source . isOsmCacheLayer !== undefined && layer . source . isOsmCacheLayer !== false ) {
2021-05-14 02:25:30 +02:00
// Cached layers are not considered here
continue ;
}
console . log ( "Downloading extra data: " , source )
2022-02-14 01:15:20 +01:00
await Utils . downloadJson ( source ) . then ( json = > allFeatures . push ( . . . json . features ) )
2021-05-14 02:25:30 +02:00
}
return allFeatures ;
}
2021-09-21 02:10:42 +02:00
function loadAllTiles ( targetdir : string , r : TileRange , theme : LayoutConfig , extraFeatures : any [ ] ) : FeatureSource {
let allFeatures = [ . . . extraFeatures ]
2021-04-22 03:30:46 +02:00
let processed = 0 ;
for ( let x = r . xstart ; x <= r . xend ; x ++ ) {
for ( let y = r . ystart ; y <= r . yend ; y ++ ) {
processed ++ ;
const filename = rawJsonName ( targetdir , x , y , r . zoomlevel )
2021-09-21 02:10:42 +02:00
console . log ( " Loading and processing" , processed , "/" , r . total , filename )
2021-04-22 03:30:46 +02:00
if ( ! existsSync ( filename ) ) {
2021-05-14 02:25:30 +02:00
console . error ( "Not found - and not downloaded. Run this script again!: " + filename )
continue ;
2021-04-22 03:30:46 +02:00
}
// We read the raw OSM-file and convert it to a geojson
const rawOsm = JSON . parse ( readFileSync ( filename , "UTF8" ) )
2021-07-18 19:08:14 +02:00
2021-04-22 03:30:46 +02:00
// Create and save the geojson file - which is the main chunk of the data
const geojson = OsmToGeoJson . default ( rawOsm ) ;
2022-01-16 01:59:06 +01:00
console . log ( " which as" , geojson . features . length , "features" )
2021-04-23 20:09:27 +02:00
2021-09-21 02:10:42 +02:00
allFeatures . push ( . . . geojson . features )
2021-04-22 03:30:46 +02:00
}
}
2022-06-05 02:24:14 +02:00
return StaticFeatureSource . fromGeojson ( allFeatures )
2021-04-22 03:30:46 +02:00
}
2021-09-21 02:10:42 +02:00
/ * *
* Load all the tiles into memory from disk
* /
2021-10-13 00:08:41 +02:00
function sliceToTiles ( allFeatures : FeatureSource , theme : LayoutConfig , relationsTracker : RelationsTracker , targetdir : string , pointsOnlyLayers : string [ ] ) {
2021-12-07 02:22:56 +01:00
const skippedLayers = new Set < string > ( )
2022-01-16 01:59:06 +01:00
const indexedFeatures : Map < string , any > = new Map < string , any > ( )
2021-12-07 17:46:57 +01:00
let indexisBuilt = false ;
2022-01-16 01:59:06 +01:00
function buildIndex() {
2021-12-07 17:46:57 +01:00
for ( const ff of allFeatures . features . data ) {
const f = ff . feature
indexedFeatures . set ( f . properties . id , f )
}
indexisBuilt = true ;
}
2022-01-16 01:59:06 +01:00
function getFeatureById ( id ) {
if ( ! indexisBuilt ) {
2021-12-07 17:46:57 +01:00
buildIndex ( )
}
return indexedFeatures . get ( id )
}
2022-01-16 01:59:06 +01:00
2021-12-07 02:22:56 +01:00
async function handleLayer ( source : FeatureSourceForLayer ) {
2021-09-21 02:10:42 +02:00
const layer = source . layer . layerDef ;
2021-10-13 00:08:41 +02:00
const targetZoomLevel = layer . source . geojsonZoomLevel ? ? 0
2021-11-07 16:34:51 +01:00
2021-09-21 02:10:42 +02:00
const layerId = layer . id
if ( layer . source . isOsmCacheLayer !== true ) {
2021-12-13 20:50:03 +01:00
console . log ( "Skipping layer " , layerId , ": not a caching layer" )
2021-12-07 02:22:56 +01:00
skippedLayers . add ( layer . id )
2021-09-21 02:10:42 +02:00
return ;
}
console . log ( "Handling layer " , layerId , "which has" , source . features . data . length , "features" )
if ( source . features . data . length === 0 ) {
return ;
}
MetaTagging . addMetatags ( source . features . data ,
{
memberships : relationsTracker ,
getFeaturesWithin : _ = > {
return [ allFeatures . features . data . map ( f = > f . feature ) ]
2021-12-07 17:46:57 +01:00
} ,
getFeatureById : getFeatureById
2021-09-21 02:10:42 +02:00
} ,
layer ,
2021-12-13 13:22:23 +01:00
{ } ,
2021-09-22 05:02:09 +02:00
{
includeDates : false ,
2022-02-02 02:36:49 +01:00
includeNonDates : true ,
evaluateStrict : true
2021-09-22 05:02:09 +02:00
} ) ;
2022-01-16 01:59:06 +01:00
2021-12-07 02:22:56 +01:00
while ( SimpleMetaTaggers . country . runningTasks . size > 0 ) {
2022-01-16 01:59:06 +01:00
console . log ( "Still waiting for " , SimpleMetaTaggers . country . runningTasks . size , " features which don't have a country yet" )
2021-12-07 02:22:56 +01:00
await ScriptUtils . sleep ( 1 )
}
2021-09-21 02:10:42 +02:00
const createdTiles = [ ]
// At this point, we have all the features of the entire area.
// However, we want to export them per tile of a fixed size, so we use a dynamicTileSOurce to split it up
TiledFeatureSource . createHierarchy ( source , {
2021-10-13 00:08:41 +02:00
minZoomLevel : targetZoomLevel ,
maxZoomLevel : targetZoomLevel ,
2021-09-21 02:10:42 +02:00
maxFeatureCount : undefined ,
registerTile : tile = > {
2021-12-07 02:22:56 +01:00
const tileIndex = tile . tileIndex ;
2021-12-13 20:50:03 +01:00
console . log ( "Got tile:" , tileIndex , tile . layer . layerDef . id )
2021-09-21 02:10:42 +02:00
if ( tile . features . data . length === 0 ) {
return
2021-07-23 17:28:36 +02:00
}
2022-01-16 01:59:06 +01:00
2021-12-07 02:22:56 +01:00
const filteredTile = new FilteringFeatureSource ( {
2022-07-22 11:50:25 +02:00
locationControl : new ImmutableStore < Loc > ( undefined ) ,
2022-01-16 01:59:06 +01:00
allElements : undefined ,
2022-07-22 11:50:25 +02:00
selectedElement : new ImmutableStore < any > ( undefined ) ,
globalFilters : new ImmutableStore ( [ ] )
2022-01-16 01:59:06 +01:00
} ,
2021-12-07 02:22:56 +01:00
tileIndex ,
tile ,
new UIEventSource < any > ( undefined )
2022-01-16 01:59:06 +01:00
)
2021-12-07 02:22:56 +01:00
2022-01-16 01:59:06 +01:00
console . log ( "Tile " + layer . id + "." + tileIndex + " contains " + filteredTile . features . data . length + " features after filtering (" + tile . features . data . length + ") features before" )
2021-12-07 02:22:56 +01:00
if ( filteredTile . features . data . length === 0 ) {
return
}
let strictlyCalculated = 0
let featureCount = 0
for ( const feature of filteredTile . features . data ) {
2021-09-21 02:10:42 +02:00
// Some cleanup
delete feature . feature [ "bbox" ]
2022-01-16 01:59:06 +01:00
if ( tile . layer . layerDef . calculatedTags !== undefined ) {
// Evaluate all the calculated tags strictly
const calculatedTagKeys = tile . layer . layerDef . calculatedTags . map ( ct = > ct [ 0 ] )
featureCount ++
2022-03-18 13:08:04 +01:00
const props = feature . feature . properties
2022-01-16 01:59:06 +01:00
for ( const calculatedTagKey of calculatedTagKeys ) {
2022-03-18 13:08:04 +01:00
const strict = props [ calculatedTagKey ]
if ( props . hasOwnProperty ( calculatedTagKey ) ) {
delete props [ calculatedTagKey ]
}
props [ calculatedTagKey ] = strict
2022-01-16 01:59:06 +01:00
strictlyCalculated ++ ;
if ( strictlyCalculated % 100 === 0 ) {
console . log ( "Strictly calculated " , strictlyCalculated , "values for tile" , tileIndex , ": now at " , featureCount , "/" , filteredTile . features . data . length , "examle value: " , strict )
}
2021-12-07 02:22:56 +01:00
}
}
2022-01-16 01:59:06 +01:00
2021-07-23 17:28:36 +02:00
}
2021-09-21 02:10:42 +02:00
// Lets save this tile!
2021-12-07 02:22:56 +01:00
const [ z , x , y ] = Tiles . tile_from_index ( tileIndex )
2021-10-13 03:10:46 +02:00
// console.log("Writing tile ", z, x, y, layerId)
2021-09-21 02:10:42 +02:00
const targetPath = geoJsonName ( targetdir + "_" + layerId , x , y , z )
2021-12-07 02:22:56 +01:00
createdTiles . push ( tileIndex )
2021-09-21 02:10:42 +02:00
// This is the geojson file containing all features for this tile
writeFileSync ( targetPath , JSON . stringify ( {
type : "FeatureCollection" ,
2021-12-07 02:22:56 +01:00
features : filteredTile.features.data.map ( f = > f . feature )
2021-09-21 02:10:42 +02:00
} , null , " " ) )
2022-01-16 01:59:06 +01:00
console . log ( "Written tile" , targetPath , "with" , filteredTile . features . data . length )
2021-07-23 17:28:36 +02:00
}
2021-09-21 02:10:42 +02:00
} )
2021-04-23 20:09:27 +02:00
2021-09-21 02:10:42 +02:00
// All the tiles are written at this point
// Only thing left to do is to create the index
2021-10-13 00:08:41 +02:00
const path = targetdir + "_" + layerId + "_" + targetZoomLevel + "_overview.json"
2021-09-21 02:10:42 +02:00
const perX = { }
2021-09-26 17:36:39 +02:00
createdTiles . map ( i = > Tiles . tile_from_index ( i ) ) . forEach ( ( [ z , x , y ] ) = > {
2021-09-21 02:10:42 +02:00
const key = "" + x
if ( perX [ key ] === undefined ) {
perX [ key ] = [ ]
2021-07-23 17:28:36 +02:00
}
2021-09-21 02:10:42 +02:00
perX [ key ] . push ( y )
} )
2021-10-13 03:10:46 +02:00
console . log ( "Written overview: " , path , "with " , createdTiles . length , "tiles" )
2021-09-21 02:10:42 +02:00
writeFileSync ( path , JSON . stringify ( perX ) )
2021-09-09 00:05:51 +02:00
2021-10-13 00:08:41 +02:00
// And, if needed, to create a points-only layer
2021-11-07 16:34:51 +01:00
if ( pointsOnlyLayers . indexOf ( layer . id ) >= 0 ) {
2021-12-07 17:46:57 +01:00
const filtered = new FilteringFeatureSource ( {
2022-07-22 11:50:25 +02:00
locationControl : new ImmutableStore < Loc > ( undefined ) ,
2021-12-07 17:46:57 +01:00
allElements : undefined ,
2022-07-22 11:50:25 +02:00
selectedElement : new ImmutableStore < any > ( undefined ) ,
globalFilters : new ImmutableStore ( [ ] )
2021-12-07 17:46:57 +01:00
} ,
2022-01-16 01:59:06 +01:00
Tiles . tile_index ( 0 , 0 , 0 ) ,
2021-12-07 17:46:57 +01:00
source ,
new UIEventSource < any > ( undefined )
)
const features = filtered . features . data . map ( f = > f . feature )
2022-01-16 01:59:06 +01:00
2021-10-13 00:08:41 +02:00
const points = features . map ( feature = > GeoOperations . centerpoint ( feature ) )
console . log ( "Writing points overview for " , layerId )
2021-11-07 16:34:51 +01:00
const targetPath = targetdir + "_" + layerId + "_points.geojson"
2021-10-13 00:08:41 +02:00
// This is the geojson file containing all features for this tile
writeFileSync ( targetPath , JSON . stringify ( {
type : "FeatureCollection" ,
features : points
} , null , " " ) )
}
2021-07-23 17:28:36 +02:00
}
2021-09-21 02:10:42 +02:00
new PerLayerFeatureSourceSplitter (
new UIEventSource < FilteredLayer [ ] > ( theme . layers . map ( l = > ( {
layerDef : l ,
isDisplayed : new UIEventSource < boolean > ( true ) ,
appliedFilters : new UIEventSource ( undefined )
} ) ) ) ,
handleLayer ,
allFeatures
)
2021-12-07 02:22:56 +01:00
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" )
}
2021-07-23 17:28:36 +02:00
}
2021-04-23 20:09:27 +02:00
2021-09-21 02:10:42 +02:00
2022-02-14 01:15:20 +01:00
export async function main ( args : string [ ] ) {
2021-04-22 03:30:46 +02:00
2021-12-07 02:22:56 +01:00
console . log ( "Cache builder started with args " , args . join ( ", " ) )
if ( args . length < 6 ) {
2021-12-07 17:46:57 +01:00
console . error ( "Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...] [--force-zoom-level z] \n" +
2021-12-07 02:22:56 +01:00
"Note: a new directory named <theme> will be created in targetdirectory" )
2021-04-22 03:30:46 +02:00
return ;
}
const themeName = args [ 0 ]
const zoomlevel = Number ( args [ 1 ] )
2021-12-07 02:22:56 +01:00
2021-04-22 13:30:00 +02:00
const targetdir = args [ 2 ] + "/" + themeName
2021-12-07 02:22:56 +01:00
if ( ! existsSync ( args [ 2 ] ) ) {
console . log ( "Directory not found" )
2021-12-13 20:50:03 +01:00
throw ` The directory ${ args [ 2 ] } does not exist `
2021-12-07 02:22:56 +01:00
}
2021-04-22 03:30:46 +02:00
const lat0 = Number ( args [ 3 ] )
const lon0 = Number ( args [ 4 ] )
const lat1 = Number ( args [ 5 ] )
const lon1 = Number ( args [ 6 ] )
2021-11-07 16:34:51 +01:00
2022-01-26 21:40:38 +01:00
if ( isNaN ( lat0 ) ) {
2022-01-25 18:20:15 +01:00
throw "The first number (a latitude) is not a valid number"
}
2022-01-26 21:40:38 +01:00
if ( isNaN ( lon0 ) ) {
2022-01-25 18:20:15 +01:00
throw "The second number (a longitude) is not a valid number"
}
2022-01-26 21:40:38 +01:00
if ( isNaN ( lat1 ) ) {
2022-01-25 18:20:15 +01:00
throw "The third number (a latitude) is not a valid number"
}
2022-01-26 21:40:38 +01:00
if ( isNaN ( lon1 ) ) {
2022-02-14 01:15:20 +01:00
throw "The fourth number (a longitude) is not a valid number"
2022-01-25 18:20:15 +01:00
}
2022-01-26 21:40:38 +01:00
2021-04-22 03:30:46 +02:00
2021-09-26 17:36:39 +02:00
const tileRange = Tiles . TileRangeBetween ( zoomlevel , lat0 , lon0 , lat1 , lon1 )
2021-04-22 03:30:46 +02:00
2022-01-26 21:40:38 +01:00
if ( isNaN ( tileRange . total ) ) {
2022-01-25 18:20:15 +01:00
throw "Something has gone wrong: tilerange is NAN"
}
2022-01-26 21:40:38 +01:00
2021-12-07 02:22:56 +01:00
if ( tileRange . total === 0 ) {
console . log ( "Tilerange has zero tiles - this is probably an error" )
return
}
2021-04-22 03:30:46 +02:00
const theme = AllKnownLayouts . allKnownLayouts . get ( themeName )
if ( theme === undefined ) {
const keys = [ ]
AllKnownLayouts . allKnownLayouts . forEach ( ( _ , key ) = > {
keys . push ( key )
} )
console . error ( "The theme " + theme + " was not found; try one of " , keys ) ;
return
}
2021-12-07 17:46:57 +01:00
let generatePointLayersFor = [ ]
if ( args [ 7 ] == "--generate-point-overview" ) {
2022-01-16 01:59:06 +01:00
if ( args [ 8 ] === undefined ) {
2021-12-07 17:46:57 +01:00
throw "--generate-point-overview needs a list of layers to generate the overview for (or * for all)"
2022-01-16 01:59:06 +01:00
} else if ( args [ 8 ] === '*' ) {
2021-12-07 17:46:57 +01:00
generatePointLayersFor = theme . layers . map ( l = > l . id )
2022-01-16 01:59:06 +01:00
} else {
2021-12-07 17:46:57 +01:00
generatePointLayersFor = args [ 8 ] . split ( "," )
}
console . log ( "Also generating a point overview for layers " , generatePointLayersFor . join ( "," ) )
}
{
2022-01-16 01:59:06 +01:00
const index = args . indexOf ( "--force-zoom-level" )
if ( index >= 0 ) {
const forcedZoomLevel = Number ( args [ index + 1 ] )
for ( const layer of theme . layers ) {
layer . source . geojsonSource = "https://127.0.0.1/cache_{layer}_{z}_{x}_{y}.geojson"
layer . source . isOsmCacheLayer = true
layer . source . geojsonZoomLevel = forcedZoomLevel
}
2021-12-07 17:46:57 +01:00
}
}
2022-01-16 01:59:06 +01:00
2021-09-21 02:10:42 +02:00
const relationTracker = new RelationsTracker ( )
2021-04-22 03:30:46 +02:00
2021-04-22 16:01:43 +02:00
let failed = 0 ;
do {
2021-10-03 01:38:57 +02:00
const cachingResult = await downloadRaw ( targetdir , tileRange , theme , relationTracker )
2021-04-22 16:01:43 +02:00
failed = cachingResult . failed
if ( failed > 0 ) {
2021-05-14 02:25:30 +02:00
await ScriptUtils . sleep ( 30000 )
2021-04-22 16:01:43 +02:00
}
} while ( failed > 0 )
2021-04-22 03:30:46 +02:00
2021-05-14 02:25:30 +02:00
const extraFeatures = await downloadExtraData ( theme ) ;
2021-09-21 02:10:42 +02:00
const allFeaturesSource = loadAllTiles ( targetdir , tileRange , theme , extraFeatures )
2021-10-13 00:08:41 +02:00
sliceToTiles ( allFeaturesSource , theme , relationTracker , targetdir , generatePointLayersFor )
2021-09-21 02:10:42 +02:00
2021-04-22 03:30:46 +02:00
}
let args = [ . . . process . argv ]
2022-02-14 02:26:03 +01:00
if ( ! args [ 1 ] ? . endsWith ( "test/TestAll.ts" ) ) {
args . splice ( 0 , 2 )
try {
main ( args )
. then ( ( ) = > console . log ( "All done!" ) )
. catch ( e = > console . error ( "Error building cache:" , e ) ) ;
} catch ( e ) {
console . error ( "Error building cache:" , e )
}
}