2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								import  Script  from  "./Script"  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  {  Tiles  }  from  "../src/Models/TileRange"  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  {  OfflineBasemapManager  }  from  "../src/service-worker/OfflineBasemapManager"  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  {  spawn  }  from  "child_process"  
						 
					
						
							
								
									
										
										
										
											2025-07-31 11:57:23 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  {  existsSync  }  from  "fs"  
						 
					
						
							
								
									
										
										
										
											2025-07-31 12:18:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  {  Utils  }  from  "../src/Utils"  
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  GeneratePmTilesExtracts  extends  Script  {  
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:11:12 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    private  targetDir : string 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 12:04:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    private  skipped : number  =  0 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    constructor ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        super ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            "Generates many pmtiles-archive from planet-latest.pmtiles. Must be started from the directory where planet-latest.pmtiles resides, archives will be created next to it" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:11:12 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    startProcess ( script : string ) :  Promise < void >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  new  Promise ( ( resolve ,  reject )  = >  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            const  child  =  spawn ( "/data/pmtiles" ,  script . split ( " " ) ,  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                stdio :  "ignore" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                cwd : this.targetDir , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:11:12 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            child . on ( "close" ,  ( code )  = >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  ( code  ===  0 )  resolve ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                else  reject ( new  Error ( ` Process exited with code  ${ code } ` ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            child . on ( "error" ,  reject ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    private  generateArchive ( z : number ,  x : number ,  y : number ,  maxzoom? : number ) :  Promise < void >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        const  [ [ max_lat ,  min_lon ] ,  [ min_lat ,  max_lon ] ]  =  Tiles . tile_bounds ( z ,  x ,  y ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        let  maxzoomflag  =  "" 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( maxzoom  !==  undefined )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            maxzoomflag  =  " --maxzoom="  +  maxzoom 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  this . startProcess ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            ` extract planet-latest.pmtiles --download-threads=1 --minzoom= ${ z } ${ maxzoomflag }  --bbox= ${ [ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                min_lon , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                min_lat  +  0.0001 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                max_lon , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                max_lat , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            ] . join ( "," ) }  $ { this . getFilename ( z ,  x ,  y ) } ` 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    private  * generateColumnIfNeeded ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        z : number , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        x : number , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        boundary : number , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        maxzoom? : number 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ) :  Generator < Promise < void > >  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 13:43:21 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        const  lastFileForColumn  =  this . getFilename ( z ,  x ,  boundary  -  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( existsSync ( this . targetDir  +  "/"  +  lastFileForColumn ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Skip this column, already exists
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            console . log ( "Skipping column " ,  x ,  "at zoom" ,  z ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            this . skipped  +=  boundary 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        console . log ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            "Starting column" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            x , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            "at zoom" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            z , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            "as" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            this . targetDir  +  "/"  +  lastFileForColumn , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            "does not exist" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 13:43:21 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( let  y  =  0 ;  y  <  boundary ;  y ++ )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            yield  this . generateArchive ( z ,  x ,  y ,  maxzoom ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    private  * generateField ( z : number ,  maxzoom? : number ) :  Generator < Promise < void > >  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:19:45 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        const  boundary  =  2  <<  ( z  -  1 ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        for  ( let  x  =  0 ;  x  <  boundary ;  x ++ )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 13:48:31 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            for  ( const  promise  of  this . generateColumnIfNeeded ( z ,  x ,  boundary ,  maxzoom ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                yield  promise 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 11:57:23 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    private  getFilename ( z : number ,  x : number ,  y : number )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 12:12:56 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  ` ${ z } - ${ x } - ${ y } .pmtiles ` 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 11:57:23 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    private  * generateAll ( ) :  Generator < Promise < void > >  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        const  zoomlevels : Record < number ,  number >  =  OfflineBasemapManager . zoomelevels 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( const  key  in  zoomlevels )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            const  minzoom : number  =  Number ( key ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            const  maxzoom : number  |  undefined  =  zoomlevels [ key ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  ( const  promise  of  this . generateField ( minzoom ,  maxzoom ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                yield  promise 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    createBatch < T > ( generator : Generator < T > ,  length : number ) :  T [ ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        const  batch  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        do  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            const  next  =  generator . next ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( next . done )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                return  batch 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            batch . push ( next . value ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        }  while  ( batch . length  <  length ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  batch 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:11:12 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    async  main ( args : string [ ] ) :  Promise < void >  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        this . targetDir  =  args [ 0 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! this . targetDir )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            console . log ( "Please specify a target directory" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 11:57:23 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        let  estimate  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( const  key  in  OfflineBasemapManager . zoomelevels )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            const  z : number  =  Number ( key ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-01 02:05:17 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            const  boundary  =  2  <<  z 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 11:57:23 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            estimate  +=  boundary  *  boundary 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:11:45 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        console . log ( "Target dir is:" ,  this . targetDir ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:22:36 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        const  numberOfThreads  =  512 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        const  generator  =  this . generateAll ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        let  batch : Promise < void > [ ]  =  [ ] 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:22:36 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        let  done  =  0 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 12:18:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        const  startDate  =  new  Date ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        do  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            batch  =  this . createBatch ( generator ,  numberOfThreads ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  Promise . all ( batch ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:22:36 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            done  +=  batch . length 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 12:18:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            const  now  =  new  Date ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            const  timeElapsed  =  ( now . getTime ( )  -  startDate . getTime ( ) )  /  1000 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-13 23:06:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            const  speed  =  ( ""  +  done  /  timeElapsed ) . substring ( 0 ,  5 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            const  perc  =  ( ""  +  ( 100  *  ( done  +  this . skipped ) )  /  estimate ) . substring ( 0 ,  5 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            const  etaSecond  =  Math . floor ( ( ( estimate  -  done  -  this . skipped )  *  timeElapsed )  /  done ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            console . log ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                "Completed" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                numberOfThreads , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                ` processes;   ${ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    done  +  this . skipped 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                }  /  $ { estimate } ,  $ { perc } % ,  $ { speed }  tile / second ,  ETA : $ { Utils . toHumanTime ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    etaSecond 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                ) } ` 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 01:03:54 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        }  while  ( batch . length  >  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								new  GeneratePmTilesExtracts ( ) . run ( )