2014-09-15 22:02:33 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include <unistd.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/mman.h>
# include <string.h>
# include <fcntl.h>
# include <ctype.h>
2014-09-15 22:27:35 +00:00
# include <errno.h>
2014-09-16 18:16:51 +00:00
# include <limits.h>
2014-09-25 22:20:17 +00:00
# include <sqlite3.h>
2014-09-25 23:00:11 +00:00
# include <stdarg.h>
2014-12-02 22:17:49 +00:00
2014-09-15 22:18:08 +00:00
# include "jsonpull.h"
2014-09-22 23:06:44 +00:00
# include "tile.h"
2014-09-29 19:17:35 +00:00
# include "pool.h"
2014-09-29 19:48:58 +00:00
# include "mbtiles.h"
2014-10-25 00:22:14 +00:00
# include "projection.h"
2015-05-29 14:50:11 +00:00
# include "version.h"
2015-06-18 23:13:37 +00:00
# include "memfile.h"
2014-09-15 22:18:08 +00:00
2014-09-26 17:52:19 +00:00
int low_detail = 10 ;
2014-10-27 21:33:09 +00:00
int full_detail = - 1 ;
2015-06-01 22:01:46 +00:00
int min_detail = 7 ;
2015-07-08 22:06:21 +00:00
int quiet = 0 ;
2014-09-26 17:52:19 +00:00
2015-06-18 17:50:57 +00:00
unsigned initial_x = 0 , initial_y = 0 ;
2015-06-18 21:16:16 +00:00
int geometry_scale = 0 ;
2015-06-18 17:50:57 +00:00
int initialized = 0 ;
2015-06-03 18:21:40 +00:00
# define GEOM_POINT 0 /* array of positions */
# define GEOM_MULTIPOINT 1 /* array of arrays of positions */
# define GEOM_LINESTRING 2 /* array of arrays of positions */
# define GEOM_MULTILINESTRING 3 /* array of arrays of arrays of positions */
# define GEOM_POLYGON 4 /* array of arrays of arrays of positions */
# define GEOM_MULTIPOLYGON 5 /* array of arrays of arrays of arrays of positions */
2014-09-15 22:27:35 +00:00
# define GEOM_TYPES 6
2014-12-02 22:17:49 +00:00
const char * geometry_names [ GEOM_TYPES ] = {
2015-06-03 18:21:40 +00:00
" Point " , " MultiPoint " , " LineString " , " MultiLineString " , " Polygon " , " MultiPolygon " ,
2014-09-15 22:02:33 +00:00
} ;
2014-09-15 23:32:06 +00:00
int geometry_within [ GEOM_TYPES ] = {
2015-06-03 18:21:40 +00:00
- 1 , /* point */
GEOM_POINT , /* multipoint */
GEOM_POINT , /* linestring */
GEOM_LINESTRING , /* multilinestring */
GEOM_LINESTRING , /* polygon */
GEOM_POLYGON , /* multipolygon */
2014-09-15 22:02:33 +00:00
} ;
2014-09-16 00:33:54 +00:00
int mb_geometry [ GEOM_TYPES ] = {
2015-06-03 18:21:40 +00:00
VT_POINT , VT_POINT , VT_LINE , VT_LINE , VT_POLYGON , VT_POLYGON ,
2014-09-16 00:33:54 +00:00
} ;
2015-03-24 00:44:23 +00:00
size_t fwrite_check ( const void * ptr , size_t size , size_t nitems , FILE * stream , const char * fname ) {
2014-09-17 23:21:25 +00:00
size_t w = fwrite ( ptr , size , nitems , stream ) ;
if ( w ! = nitems ) {
2015-03-24 00:44:23 +00:00
fprintf ( stderr , " %s: Write to temporary file failed: %s \n " , fname , strerror ( errno ) ) ;
2014-09-17 23:21:25 +00:00
exit ( EXIT_FAILURE ) ;
}
return w ;
}
2015-03-24 00:44:23 +00:00
void serialize_int ( FILE * out , int n , long long * fpos , const char * fname ) {
2015-06-17 23:46:36 +00:00
serialize_long_long ( out , n , fpos , fname ) ;
2014-09-16 23:39:56 +00:00
}
2015-03-24 00:44:23 +00:00
void serialize_long_long ( FILE * out , long long n , long long * fpos , const char * fname ) {
2015-06-17 23:46:36 +00:00
unsigned long long zigzag = ( n < < 1 ) ^ ( n > > 63 ) ;
while ( 1 ) {
unsigned char b = zigzag & 0x7F ;
if ( ( zigzag > > 7 ) ! = 0 ) {
b | = 0x80 ;
2015-06-30 23:47:25 +00:00
if ( putc ( b , out ) = = EOF ) {
fprintf ( stderr , " %s: Write to temporary file failed: %s \n " , fname , strerror ( errno ) ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-17 23:46:36 +00:00
* fpos + = 1 ;
zigzag > > = 7 ;
} else {
2015-06-30 23:47:25 +00:00
if ( putc ( b , out ) = = EOF ) {
fprintf ( stderr , " %s: Write to temporary file failed: %s \n " , fname , strerror ( errno ) ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-17 23:46:36 +00:00
* fpos + = 1 ;
break ;
}
}
2014-12-04 00:18:43 +00:00
}
2015-03-24 00:44:23 +00:00
void serialize_byte ( FILE * out , signed char n , long long * fpos , const char * fname ) {
fwrite_check ( & n , sizeof ( signed char ) , 1 , out , fname ) ;
2014-11-05 22:37:54 +00:00
* fpos + = sizeof ( signed char ) ;
}
2015-03-24 00:44:23 +00:00
void serialize_uint ( FILE * out , unsigned n , long long * fpos , const char * fname ) {
fwrite_check ( & n , sizeof ( unsigned ) , 1 , out , fname ) ;
2014-09-16 23:39:56 +00:00
* fpos + = sizeof ( unsigned ) ;
}
2015-03-24 00:44:23 +00:00
void serialize_string ( FILE * out , const char * s , long long * fpos , const char * fname ) {
2014-09-16 23:39:56 +00:00
int len = strlen ( s ) ;
2015-03-24 00:44:23 +00:00
serialize_int ( out , len + 1 , fpos , fname ) ;
fwrite_check ( s , sizeof ( char ) , len , out , fname ) ;
fwrite_check ( " " , sizeof ( char ) , 1 , out , fname ) ;
2014-09-22 19:22:58 +00:00
* fpos + = len + 1 ;
2014-09-16 23:39:56 +00:00
}
2015-06-18 17:50:57 +00:00
void parse_geometry ( int t , json_object * j , unsigned * bbox , long long * fpos , FILE * out , int op , const char * fname , json_pull * source , long long * wx , long long * wy , int * initialized ) {
2014-09-15 23:32:06 +00:00
if ( j = = NULL | | j - > type ! = JSON_ARRAY ) {
2014-10-06 17:55:40 +00:00
fprintf ( stderr , " %s:%d: expected array for type %d \n " , fname , source - > line , t ) ;
2014-09-15 23:32:06 +00:00
return ;
}
int within = geometry_within [ t ] ;
2014-10-15 23:30:33 +00:00
long long began = * fpos ;
2014-09-15 23:32:06 +00:00
if ( within > = 0 ) {
int i ;
for ( i = 0 ; i < j - > length ; i + + ) {
2014-09-16 00:33:54 +00:00
if ( within = = GEOM_POINT ) {
2014-09-23 21:02:18 +00:00
if ( i = = 0 | | mb_geometry [ t ] = = GEOM_MULTIPOINT ) {
2014-09-16 21:11:50 +00:00
op = VT_MOVETO ;
2014-09-16 00:33:54 +00:00
} else {
2014-09-16 21:11:50 +00:00
op = VT_LINETO ;
2014-09-16 20:51:22 +00:00
}
2014-09-16 00:33:54 +00:00
}
2015-06-18 17:50:57 +00:00
parse_geometry ( within , j - > array [ i ] , bbox , fpos , out , op , fname , source , wx , wy , initialized ) ;
2014-09-15 23:32:06 +00:00
}
} else {
2014-12-09 23:23:22 +00:00
if ( j - > length > = 2 & & j - > array [ 0 ] - > type = = JSON_NUMBER & & j - > array [ 1 ] - > type = = JSON_NUMBER ) {
2014-09-16 23:39:56 +00:00
unsigned x , y ;
double lon = j - > array [ 0 ] - > number ;
double lat = j - > array [ 1 ] - > number ;
latlon2tile ( lat , lon , 32 , & x , & y ) ;
2014-12-09 23:23:22 +00:00
if ( j - > length > 2 ) {
static int warned = 0 ;
if ( ! warned ) {
fprintf ( stderr , " %s:%d: ignoring dimensions beyond two \n " , fname , source - > line ) ;
warned = 1 ;
}
}
2014-09-16 23:39:56 +00:00
if ( bbox ! = NULL ) {
if ( x < bbox [ 0 ] ) {
bbox [ 0 ] = x ;
}
if ( y < bbox [ 1 ] ) {
bbox [ 1 ] = y ;
2014-09-16 20:51:22 +00:00
}
2014-09-16 23:39:56 +00:00
if ( x > bbox [ 2 ] ) {
bbox [ 2 ] = x ;
2014-09-16 20:51:22 +00:00
}
2014-09-16 23:39:56 +00:00
if ( y > bbox [ 3 ] ) {
bbox [ 3 ] = y ;
2014-09-16 20:51:22 +00:00
}
2014-09-16 18:16:51 +00:00
}
2015-06-18 17:50:57 +00:00
if ( ! * initialized ) {
initial_x = x ;
initial_y = y ;
* wx = x ;
* wy = y ;
* initialized = 1 ;
}
2015-03-24 00:44:23 +00:00
serialize_byte ( out , op , fpos , fname ) ;
2015-06-18 21:16:16 +00:00
serialize_long_long ( out , ( x > > geometry_scale ) - ( * wx > > geometry_scale ) , fpos , fname ) ;
serialize_long_long ( out , ( y > > geometry_scale ) - ( * wy > > geometry_scale ) , fpos , fname ) ;
2015-06-18 00:48:29 +00:00
* wx = x ;
* wy = y ;
2014-09-15 23:32:06 +00:00
} else {
2014-12-09 23:17:20 +00:00
fprintf ( stderr , " %s:%d: malformed point \n " , fname , source - > line ) ;
2014-09-15 23:32:06 +00:00
}
}
2014-09-16 00:33:54 +00:00
2014-10-15 23:30:33 +00:00
if ( t = = GEOM_POLYGON ) {
if ( * fpos ! = began ) {
2015-03-24 00:44:23 +00:00
serialize_byte ( out , VT_CLOSEPATH , fpos , fname ) ;
2014-10-15 23:30:33 +00:00
}
2014-09-16 00:33:54 +00:00
}
2014-09-15 23:32:06 +00:00
}
2014-09-15 22:02:33 +00:00
2014-09-17 23:00:19 +00:00
void deserialize_int ( char * * f , int * n ) {
2015-06-17 23:46:36 +00:00
long long ll ;
deserialize_long_long ( f , & ll ) ;
* n = ll ;
2014-09-17 00:19:54 +00:00
}
2014-12-04 00:18:43 +00:00
void deserialize_long_long ( char * * f , long long * n ) {
2015-06-17 23:46:36 +00:00
unsigned long long zigzag = 0 ;
int shift = 0 ;
while ( 1 ) {
if ( ( * * f & 0x80 ) = = 0 ) {
zigzag | = ( ( unsigned long long ) * * f ) < < shift ;
* f + = 1 ;
shift + = 7 ;
break ;
} else {
zigzag | = ( ( unsigned long long ) ( * * f & 0x7F ) ) < < shift ;
* f + = 1 ;
shift + = 7 ;
}
}
* n = ( zigzag > > 1 ) ^ ( - ( zigzag & 1 ) ) ;
2014-12-04 00:18:43 +00:00
}
2014-12-03 02:03:07 +00:00
void deserialize_uint ( char * * f , unsigned * n ) {
memcpy ( n , * f , sizeof ( unsigned ) ) ;
* f + = sizeof ( unsigned ) ;
}
2014-11-05 22:37:54 +00:00
void deserialize_byte ( char * * f , signed char * n ) {
memcpy ( n , * f , sizeof ( signed char ) ) ;
* f + = sizeof ( signed char ) ;
}
2014-09-22 19:22:58 +00:00
struct pool_val * deserialize_string ( char * * f , struct pool * p , int type ) {
struct pool_val * ret ;
2014-09-17 00:19:54 +00:00
int len ;
2014-09-22 19:22:58 +00:00
2014-09-17 00:19:54 +00:00
deserialize_int ( f , & len ) ;
2014-09-22 19:22:58 +00:00
ret = pool ( p , * f , type ) ;
2014-09-17 23:00:19 +00:00
* f + = len ;
2014-09-22 19:22:58 +00:00
return ret ;
2014-09-17 00:19:54 +00:00
}
2015-03-05 23:15:56 +00:00
struct index {
2015-03-06 00:18:01 +00:00
long long start ;
long long end ;
2015-03-05 23:15:56 +00:00
unsigned long long index ;
} ;
int indexcmp ( const void * v1 , const void * v2 ) {
const struct index * i1 = ( const struct index * ) v1 ;
const struct index * i2 = ( const struct index * ) v2 ;
if ( i1 - > index < i2 - > index ) {
return - 1 ;
} else if ( i1 - > index > i2 - > index ) {
return 1 ;
}
return 0 ;
}
struct merge {
long long start ;
long long end ;
struct merge * next ;
} ;
static void insert ( struct merge * m , struct merge * * head , unsigned char * map , int bytes ) {
while ( * head ! = NULL & & indexcmp ( map + m - > start , map + ( * head ) - > start ) > 0 ) {
head = & ( ( * head ) - > next ) ;
}
m - > next = * head ;
* head = m ;
}
static void merge ( struct merge * merges , int nmerges , unsigned char * map , FILE * f , int bytes , long long nrec ) {
int i ;
struct merge * head = NULL ;
long long along = 0 ;
long long reported = - 1 ;
for ( i = 0 ; i < nmerges ; i + + ) {
if ( merges [ i ] . start < merges [ i ] . end ) {
insert ( & ( merges [ i ] ) , & head , map , bytes ) ;
}
}
while ( head ! = NULL ) {
2015-05-21 01:04:34 +00:00
fwrite_check ( map + head - > start , bytes , 1 , f , " merge temporary " ) ;
2015-03-05 23:15:56 +00:00
head - > start + = bytes ;
struct merge * m = head ;
head = m - > next ;
m - > next = NULL ;
if ( m - > start < m - > end ) {
insert ( m , & head , map , bytes ) ;
}
along + + ;
long long report = 100 * along / nrec ;
if ( report ! = reported ) {
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Merging: %lld%% \r " , report ) ;
}
2015-03-05 23:15:56 +00:00
reported = report ;
}
}
}
2015-06-18 00:18:08 +00:00
struct stringpool {
2015-06-18 23:13:37 +00:00
long long left ;
long long right ;
2015-06-18 00:18:08 +00:00
long long off ;
2015-06-18 23:13:37 +00:00
} ;
long long pooltree = 0 ;
2015-06-18 00:18:08 +00:00
2015-06-19 22:49:51 +00:00
static unsigned char swizzle [ 256 ] = {
2015-06-19 22:53:09 +00:00
0x00 , 0xBF , 0x18 , 0xDE , 0x93 , 0xC9 , 0xB1 , 0x5E , 0xDF , 0xBE , 0x72 , 0x5A , 0xBB , 0x42 , 0x64 , 0xC6 ,
2015-06-19 22:49:51 +00:00
0xD8 , 0xB7 , 0x15 , 0x74 , 0x1C , 0x8B , 0x91 , 0xF5 , 0x29 , 0x46 , 0xEC , 0x6F , 0xCA , 0x20 , 0xF0 , 0x06 ,
0x27 , 0x61 , 0x87 , 0xE0 , 0x6E , 0x43 , 0x50 , 0xC5 , 0x1B , 0xB4 , 0x37 , 0xC3 , 0x69 , 0xA6 , 0xEE , 0x80 ,
0xAF , 0x9B , 0xA1 , 0x76 , 0x23 , 0x24 , 0x53 , 0xF3 , 0x5B , 0x65 , 0x19 , 0xF4 , 0xFC , 0xDD , 0x26 , 0xE8 ,
0x10 , 0xF7 , 0xCE , 0x92 , 0x48 , 0xF6 , 0x94 , 0x60 , 0x07 , 0xC4 , 0xB9 , 0x97 , 0x6D , 0xA4 , 0x11 , 0x0D ,
2015-06-19 22:53:09 +00:00
0x1F , 0x4D , 0x13 , 0xB0 , 0x5D , 0xBA , 0x31 , 0xD5 , 0x8D , 0x51 , 0x36 , 0x96 , 0x7A , 0x03 , 0x7F , 0xDA ,
0x17 , 0xDB , 0xD4 , 0x83 , 0xE2 , 0x79 , 0x6A , 0xE1 , 0x95 , 0x38 , 0xFF , 0x28 , 0xB2 , 0xB3 , 0xA7 , 0xAE ,
0xF8 , 0x54 , 0xCC , 0xDC , 0x9A , 0x6B , 0xFB , 0x3F , 0xD7 , 0xBC , 0x21 , 0xC8 , 0x71 , 0x09 , 0x16 , 0xAC ,
0x3C , 0x8A , 0x62 , 0x05 , 0xC2 , 0x8C , 0x32 , 0x4E , 0x35 , 0x9C , 0x5F , 0x75 , 0xCD , 0x2E , 0xA2 , 0x3E ,
0x1A , 0xC1 , 0x8E , 0x14 , 0xA0 , 0xD3 , 0x7D , 0xD9 , 0xEB , 0x5C , 0x70 , 0xE6 , 0x9E , 0x12 , 0x3B , 0xEF ,
0x1E , 0x49 , 0xD2 , 0x98 , 0x39 , 0x7E , 0x44 , 0x4B , 0x6C , 0x88 , 0x02 , 0x2C , 0xAD , 0xE5 , 0x9F , 0x40 ,
0x7B , 0x4A , 0x3D , 0xA9 , 0xAB , 0x0B , 0xD6 , 0x2F , 0x90 , 0x2A , 0xB6 , 0x1D , 0xC7 , 0x22 , 0x55 , 0x34 ,
0x0A , 0xD0 , 0xB5 , 0x68 , 0xE3 , 0x59 , 0xFD , 0xFA , 0x57 , 0x77 , 0x25 , 0xA3 , 0x04 , 0xB8 , 0x33 , 0x89 ,
0x78 , 0x82 , 0xE4 , 0xC0 , 0x0E , 0x8F , 0x85 , 0xD1 , 0x84 , 0x08 , 0x67 , 0x47 , 0x9D , 0xCB , 0x58 , 0x4C ,
0xAA , 0xED , 0x52 , 0xF2 , 0x4F , 0xF1 , 0x66 , 0xCF , 0xA5 , 0x56 , 0xEA , 0x7C , 0xE9 , 0x63 , 0xE7 , 0x01 ,
0xF9 , 0xFE , 0x0C , 0x99 , 0x2D , 0x0F , 0x3A , 0x41 , 0x45 , 0xA8 , 0x30 , 0x2B , 0x73 , 0xBD , 0x86 , 0x81 ,
2015-06-19 22:49:51 +00:00
} ;
int swizzlecmp ( char * a , char * b ) {
while ( * a | | * b ) {
int aa = swizzle [ ( unsigned char ) * a ] ;
int bb = swizzle [ ( unsigned char ) * b ] ;
int cmp = aa - bb ;
if ( cmp ! = 0 ) {
return cmp ;
}
a + + ;
b + + ;
}
return 0 ;
}
2015-06-18 23:30:51 +00:00
long long addpool ( struct memfile * poolfile , struct memfile * treefile , char * s , char type ) {
2015-06-18 23:13:37 +00:00
long long * sp = & pooltree ;
2015-06-18 00:18:08 +00:00
2015-06-18 23:13:37 +00:00
while ( * sp ! = 0 ) {
2015-06-19 22:49:51 +00:00
int cmp = swizzlecmp ( s , poolfile - > map + ( ( struct stringpool * ) ( treefile - > map + * sp ) ) - > off + 1 ) ;
2015-06-18 19:12:20 +00:00
if ( cmp = = 0 ) {
2015-06-18 23:30:51 +00:00
cmp = type - ( poolfile - > map + ( ( struct stringpool * ) ( treefile - > map + * sp ) ) - > off ) [ 0 ] ;
2015-06-18 19:12:20 +00:00
}
2015-06-18 00:18:08 +00:00
if ( cmp < 0 ) {
2015-06-18 23:30:51 +00:00
sp = & ( ( ( struct stringpool * ) ( treefile - > map + * sp ) ) - > left ) ;
2015-06-18 00:18:08 +00:00
} else if ( cmp > 0 ) {
2015-06-18 23:30:51 +00:00
sp = & ( ( ( struct stringpool * ) ( treefile - > map + * sp ) ) - > right ) ;
2015-06-18 00:18:08 +00:00
} else {
2015-06-18 23:30:51 +00:00
return ( ( struct stringpool * ) ( treefile - > map + * sp ) ) - > off ;
2015-06-18 00:18:08 +00:00
}
}
2015-06-18 23:13:37 +00:00
// *sp is probably in the memory-mapped file, and will move if the file grows.
long long ssp ;
if ( sp = = & pooltree ) {
ssp = - 1 ;
} else {
2015-06-18 23:30:51 +00:00
ssp = ( ( char * ) sp ) - treefile - > map ;
2015-06-18 23:13:37 +00:00
}
long long off = poolfile - > off ;
if ( memfile_write ( poolfile , & type , 1 ) < 0 ) {
perror ( " memfile write " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( memfile_write ( poolfile , s , strlen ( s ) + 1 ) < 0 ) {
perror ( " memfile write " ) ;
exit ( EXIT_FAILURE ) ;
}
struct stringpool tsp ;
tsp . left = 0 ;
tsp . right = 0 ;
tsp . off = off ;
2015-06-18 23:30:51 +00:00
long long p = treefile - > off ;
if ( memfile_write ( treefile , & tsp , sizeof ( struct stringpool ) ) < 0 ) {
2015-06-18 23:13:37 +00:00
perror ( " memfile write " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-18 00:18:08 +00:00
2015-06-18 23:13:37 +00:00
if ( ssp = = - 1 ) {
pooltree = p ;
} else {
2015-06-18 23:30:51 +00:00
* ( ( long long * ) ( treefile - > map + ssp ) ) = p ;
2015-06-18 23:13:37 +00:00
}
return off ;
2015-06-18 00:18:08 +00:00
}
2015-04-10 18:36:30 +00:00
int read_json ( int argc , char * * argv , char * fname , const char * layername , int maxzoom , int minzoom , sqlite3 * outdb , struct pool * exclude , struct pool * include , int exclude_all , double droprate , int buffer , const char * tmpdir , double gamma , char * prevent ) {
2015-03-07 00:33:32 +00:00
int ret = EXIT_SUCCESS ;
2014-11-05 18:34:44 +00:00
char metaname [ strlen ( tmpdir ) + strlen ( " /meta.XXXXXXXX " ) + 1 ] ;
2015-06-18 00:18:08 +00:00
char poolname [ strlen ( tmpdir ) + strlen ( " /pool.XXXXXXXX " ) + 1 ] ;
2015-06-18 23:30:51 +00:00
char treename [ strlen ( tmpdir ) + strlen ( " /tree.XXXXXXXX " ) + 1 ] ;
2014-12-04 00:18:43 +00:00
char geomname [ strlen ( tmpdir ) + strlen ( " /geom.XXXXXXXX " ) + 1 ] ;
2015-03-05 23:15:56 +00:00
char indexname [ strlen ( tmpdir ) + strlen ( " /index.XXXXXXXX " ) + 1 ] ;
2014-11-05 18:34:44 +00:00
sprintf ( metaname , " %s%s " , tmpdir , " /meta.XXXXXXXX " ) ;
2015-06-18 00:18:08 +00:00
sprintf ( poolname , " %s%s " , tmpdir , " /pool.XXXXXXXX " ) ;
2015-06-18 23:30:51 +00:00
sprintf ( treename , " %s%s " , tmpdir , " /tree.XXXXXXXX " ) ;
2014-12-04 00:18:43 +00:00
sprintf ( geomname , " %s%s " , tmpdir , " /geom.XXXXXXXX " ) ;
2015-03-05 23:15:56 +00:00
sprintf ( indexname , " %s%s " , tmpdir , " /index.XXXXXXXX " ) ;
2014-09-18 19:11:36 +00:00
int metafd = mkstemp ( metaname ) ;
2014-11-05 18:34:44 +00:00
if ( metafd < 0 ) {
perror ( metaname ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-18 00:18:08 +00:00
int poolfd = mkstemp ( poolname ) ;
if ( poolfd < 0 ) {
perror ( poolname ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-18 23:30:51 +00:00
int treefd = mkstemp ( treename ) ;
if ( treefd < 0 ) {
perror ( treename ) ;
exit ( EXIT_FAILURE ) ;
}
2014-12-04 00:18:43 +00:00
int geomfd = mkstemp ( geomname ) ;
if ( geomfd < 0 ) {
perror ( geomname ) ;
2014-11-05 18:34:44 +00:00
exit ( EXIT_FAILURE ) ;
}
2015-03-05 23:15:56 +00:00
int indexfd = mkstemp ( indexname ) ;
if ( indexfd < 0 ) {
perror ( indexname ) ;
exit ( EXIT_FAILURE ) ;
}
2014-09-18 19:11:36 +00:00
FILE * metafile = fopen ( metaname , " wb " ) ;
2014-11-05 18:34:44 +00:00
if ( metafile = = NULL ) {
perror ( metaname ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-18 23:13:37 +00:00
struct memfile * poolfile = memfile_open ( poolfd ) ;
2015-06-18 00:18:08 +00:00
if ( poolfile = = NULL ) {
perror ( poolname ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-18 23:30:51 +00:00
struct memfile * treefile = memfile_open ( treefd ) ;
if ( treefile = = NULL ) {
perror ( treename ) ;
exit ( EXIT_FAILURE ) ;
}
2014-12-04 00:18:43 +00:00
FILE * geomfile = fopen ( geomname , " wb " ) ;
if ( geomfile = = NULL ) {
perror ( geomname ) ;
2014-11-05 18:34:44 +00:00
exit ( EXIT_FAILURE ) ;
}
2015-03-05 23:15:56 +00:00
FILE * indexfile = fopen ( indexname , " wb " ) ;
if ( indexfile = = NULL ) {
perror ( indexname ) ;
exit ( EXIT_FAILURE ) ;
}
2014-12-04 00:18:43 +00:00
long long metapos = 0 ;
long long geompos = 0 ;
2015-03-05 23:15:56 +00:00
long long indexpos = 0 ;
2014-09-16 23:39:56 +00:00
2014-09-18 21:04:52 +00:00
unlink ( metaname ) ;
2015-06-18 23:13:37 +00:00
unlink ( poolname ) ;
2015-06-18 23:30:51 +00:00
unlink ( treename ) ;
2014-12-04 00:18:43 +00:00
unlink ( geomname ) ;
2015-03-05 23:15:56 +00:00
unlink ( indexname ) ;
2014-09-18 21:04:52 +00:00
2015-06-18 23:13:37 +00:00
// To distinguish a null value
2015-06-18 23:30:51 +00:00
{
struct stringpool p ;
memfile_write ( treefile , & p , sizeof ( struct stringpool ) ) ;
}
2015-06-18 00:18:08 +00:00
2015-06-03 18:21:40 +00:00
unsigned file_bbox [ ] = { UINT_MAX , UINT_MAX , 0 , 0 } ;
2014-09-24 19:14:35 +00:00
unsigned midx = 0 , midy = 0 ;
2014-09-18 23:23:36 +00:00
long long seq = 0 ;
2015-03-24 00:44:23 +00:00
int nlayers = argc ;
if ( nlayers = = 0 ) {
nlayers = 1 ;
}
2014-09-15 22:02:33 +00:00
2015-03-24 00:44:23 +00:00
int n ;
for ( n = 0 ; n < nlayers ; n + + ) {
json_pull * jp ;
const char * reading ;
FILE * fp ;
2015-04-17 17:48:03 +00:00
long long found_hashes = 0 ;
long long found_features = 0 ;
2014-09-15 22:02:33 +00:00
2015-03-24 00:44:23 +00:00
if ( n > = argc ) {
reading = " standard input " ;
fp = stdin ;
} else {
reading = argv [ n ] ;
fp = fopen ( argv [ n ] , " r " ) ;
if ( fp = = NULL ) {
perror ( argv [ n ] ) ;
continue ;
}
2014-09-15 22:45:49 +00:00
}
2015-03-24 00:44:23 +00:00
jp = json_begin_file ( fp ) ;
2014-09-15 22:45:49 +00:00
2015-03-24 00:44:23 +00:00
while ( 1 ) {
json_object * j = json_read ( jp ) ;
if ( j = = NULL ) {
if ( jp - > error ! = NULL ) {
fprintf ( stderr , " %s:%d: %s \n " , reading , jp - > line , jp - > error ) ;
}
json_free ( jp - > root ) ;
break ;
2014-12-09 23:23:22 +00:00
}
2015-04-17 17:48:03 +00:00
if ( j - > type = = JSON_HASH ) {
found_hashes + + ;
if ( found_hashes = = 50 & & found_features = = 0 ) {
fprintf ( stderr , " %s:%d: Not finding any GeoJSON features in input. Is your file just bare geometries? \n " , reading , jp - > line ) ;
break ;
}
}
2015-03-24 00:44:23 +00:00
json_object * type = json_hash_get ( j , " type " ) ;
if ( type = = NULL | | type - > type ! = JSON_STRING | | strcmp ( type - > string , " Feature " ) ! = 0 ) {
continue ;
}
2014-12-09 23:23:22 +00:00
2015-04-17 17:48:03 +00:00
found_features + + ;
2015-03-24 00:44:23 +00:00
json_object * geometry = json_hash_get ( j , " geometry " ) ;
if ( geometry = = NULL ) {
fprintf ( stderr , " %s:%d: feature with no geometry \n " , reading , jp - > line ) ;
json_free ( j ) ;
continue ;
}
2014-09-15 22:45:49 +00:00
2015-03-24 00:44:23 +00:00
json_object * geometry_type = json_hash_get ( geometry , " type " ) ;
if ( geometry_type = = NULL ) {
static int warned = 0 ;
if ( ! warned ) {
fprintf ( stderr , " %s:%d: null geometry (additional not reported) \n " , reading , jp - > line ) ;
warned = 1 ;
}
2014-09-15 22:45:49 +00:00
2015-03-24 00:44:23 +00:00
json_free ( j ) ;
continue ;
}
2014-09-15 22:45:49 +00:00
2015-03-24 00:44:23 +00:00
if ( geometry_type - > type ! = JSON_STRING ) {
fprintf ( stderr , " %s:%d: geometry without type \n " , reading , jp - > line ) ;
json_free ( j ) ;
continue ;
}
json_object * properties = json_hash_get ( j , " properties " ) ;
if ( properties = = NULL | | ( properties - > type ! = JSON_HASH & & properties - > type ! = JSON_NULL ) ) {
fprintf ( stderr , " %s:%d: feature without properties hash \n " , reading , jp - > line ) ;
json_free ( j ) ;
continue ;
2014-09-15 22:45:49 +00:00
}
2014-09-15 22:02:33 +00:00
2015-03-24 00:44:23 +00:00
json_object * coordinates = json_hash_get ( geometry , " coordinates " ) ;
if ( coordinates = = NULL | | coordinates - > type ! = JSON_ARRAY ) {
fprintf ( stderr , " %s:%d: feature without coordinates array \n " , reading , jp - > line ) ;
json_free ( j ) ;
continue ;
}
2014-09-22 23:17:46 +00:00
2015-03-24 00:44:23 +00:00
int t ;
for ( t = 0 ; t < GEOM_TYPES ; t + + ) {
if ( strcmp ( geometry_type - > string , geometry_names [ t ] ) = = 0 ) {
break ;
}
2014-12-17 06:46:00 +00:00
}
2015-03-24 00:44:23 +00:00
if ( t > = GEOM_TYPES ) {
fprintf ( stderr , " %s:%d: Can't handle geometry type %s \n " , reading , jp - > line , geometry_type - > string ) ;
json_free ( j ) ;
continue ;
}
{
2015-06-03 18:21:40 +00:00
unsigned bbox [ ] = { UINT_MAX , UINT_MAX , 0 , 0 } ;
2015-03-24 00:44:23 +00:00
int nprop = 0 ;
if ( properties - > type = = JSON_HASH ) {
nprop = properties - > length ;
}
2014-12-17 06:46:00 +00:00
2015-03-24 00:44:23 +00:00
long long metastart = metapos ;
char * metakey [ nprop ] ;
char * metaval [ nprop ] ;
int metatype [ nprop ] ;
int m = 0 ;
int i ;
for ( i = 0 ; i < nprop ; i + + ) {
if ( properties - > keys [ i ] - > type = = JSON_STRING ) {
if ( exclude_all ) {
if ( ! is_pooled ( include , properties - > keys [ i ] - > string , VT_STRING ) ) {
continue ;
}
} else if ( is_pooled ( exclude , properties - > keys [ i ] - > string , VT_STRING ) ) {
2014-11-12 20:40:08 +00:00
continue ;
}
2014-09-29 17:49:08 +00:00
2015-03-24 00:44:23 +00:00
metakey [ m ] = properties - > keys [ i ] - > string ;
if ( properties - > values [ i ] ! = NULL & & properties - > values [ i ] - > type = = JSON_STRING ) {
metatype [ m ] = VT_STRING ;
metaval [ m ] = properties - > values [ i ] - > string ;
m + + ;
} else if ( properties - > values [ i ] ! = NULL & & properties - > values [ i ] - > type = = JSON_NUMBER ) {
metatype [ m ] = VT_NUMBER ;
metaval [ m ] = properties - > values [ i ] - > string ;
m + + ;
} else if ( properties - > values [ i ] ! = NULL & & ( properties - > values [ i ] - > type = = JSON_TRUE | | properties - > values [ i ] - > type = = JSON_FALSE ) ) {
metatype [ m ] = VT_BOOLEAN ;
2015-04-10 20:03:11 +00:00
metaval [ m ] = properties - > values [ i ] - > type = = JSON_TRUE ? " true " : " false " ;
2015-03-24 00:44:23 +00:00
m + + ;
} else if ( properties - > values [ i ] ! = NULL & & ( properties - > values [ i ] - > type = = JSON_NULL ) ) {
;
} else {
fprintf ( stderr , " %s:%d: Unsupported property type for %s \n " , reading , jp - > line , properties - > keys [ i ] - > string ) ;
continue ;
}
2014-09-15 22:02:33 +00:00
}
2014-09-15 22:45:49 +00:00
}
2015-03-24 00:44:23 +00:00
serialize_int ( metafile , m , & metapos , fname ) ;
for ( i = 0 ; i < m ; i + + ) {
2015-06-18 23:30:51 +00:00
serialize_long_long ( metafile , addpool ( poolfile , treefile , metakey [ i ] , VT_STRING ) , & metapos , fname ) ;
serialize_long_long ( metafile , addpool ( poolfile , treefile , metaval [ i ] , metatype [ i ] ) , & metapos , fname ) ;
2015-03-24 00:44:23 +00:00
}
2014-09-16 23:39:56 +00:00
2015-03-24 00:44:23 +00:00
long long geomstart = geompos ;
serialize_byte ( geomfile , mb_geometry [ t ] , & geompos , fname ) ;
2015-07-27 23:20:20 +00:00
serialize_long_long ( geomfile , n , & geompos , fname ) ;
2015-03-24 00:44:23 +00:00
serialize_long_long ( geomfile , metastart , & geompos , fname ) ;
2015-06-18 17:50:57 +00:00
long long wx = initial_x , wy = initial_y ;
parse_geometry ( t , coordinates , bbox , & geompos , geomfile , VT_MOVETO , fname , jp , & wx , & wy , & initialized ) ;
2015-03-24 00:44:23 +00:00
serialize_byte ( geomfile , VT_END , & geompos , fname ) ;
/*
* Note that minzoom for lines is the dimension
* of the geometry in world coordinates , but
* for points is the lowest zoom level ( in tiles ,
* not in pixels ) at which it should be drawn .
*
* So a line that is too small for , say , z8
* will have minzoom of 18 ( if tile detail is 10 ) ,
* not 8.
*/
int minzoom = 0 ;
if ( mb_geometry [ t ] = = VT_LINE ) {
for ( minzoom = 0 ; minzoom < 31 ; minzoom + + ) {
unsigned mask = 1 < < ( 32 - ( minzoom + 1 ) ) ;
2015-06-03 18:21:40 +00:00
if ( ( ( bbox [ 0 ] & mask ) ! = ( bbox [ 2 ] & mask ) ) | | ( ( bbox [ 1 ] & mask ) ! = ( bbox [ 3 ] & mask ) ) ) {
2015-03-24 00:44:23 +00:00
break ;
}
2014-11-12 23:57:45 +00:00
}
2015-03-24 00:44:23 +00:00
} else if ( mb_geometry [ t ] = = VT_POINT ) {
double r = ( ( double ) rand ( ) ) / RAND_MAX ;
if ( r = = 0 ) {
r = .00000001 ;
}
2015-06-03 18:21:40 +00:00
minzoom = maxzoom - floor ( log ( r ) / - log ( droprate ) ) ;
2014-11-12 23:57:45 +00:00
}
2015-03-24 00:44:23 +00:00
serialize_byte ( geomfile , minzoom , & geompos , fname ) ;
2014-12-04 00:18:43 +00:00
2015-03-24 00:44:23 +00:00
struct index index ;
index . start = geomstart ;
index . end = geompos ;
index . index = encode ( bbox [ 0 ] / 2 + bbox [ 2 ] / 2 , bbox [ 1 ] / 2 + bbox [ 3 ] / 2 ) ;
fwrite_check ( & index , sizeof ( struct index ) , 1 , indexfile , fname ) ;
indexpos + = sizeof ( struct index ) ;
2015-03-06 00:18:01 +00:00
2015-03-24 00:44:23 +00:00
for ( i = 0 ; i < 2 ; i + + ) {
if ( bbox [ i ] < file_bbox [ i ] ) {
file_bbox [ i ] = bbox [ i ] ;
}
2014-09-18 17:26:47 +00:00
}
2015-03-24 00:44:23 +00:00
for ( i = 2 ; i < 4 ; i + + ) {
if ( bbox [ i ] > file_bbox [ i ] ) {
file_bbox [ i ] = bbox [ i ] ;
}
2014-09-18 17:26:47 +00:00
}
2015-06-03 18:21:40 +00:00
2015-03-24 00:44:23 +00:00
if ( seq % 10000 = = 0 ) {
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Read %.2f million features \r " , seq / 1000000.0 ) ;
}
2015-03-24 00:44:23 +00:00
}
seq + + ;
2014-09-18 23:23:36 +00:00
}
2014-09-15 22:27:35 +00:00
2015-03-24 00:44:23 +00:00
json_free ( j ) ;
/* XXX check for any non-features in the outer object */
}
2014-09-15 22:45:49 +00:00
2015-03-24 00:44:23 +00:00
json_end ( jp ) ;
fclose ( fp ) ;
2014-09-15 22:02:33 +00:00
}
2014-09-17 22:44:07 +00:00
fclose ( metafile ) ;
2014-12-04 00:18:43 +00:00
fclose ( geomfile ) ;
2015-03-05 23:15:56 +00:00
fclose ( indexfile ) ;
2015-06-18 23:30:51 +00:00
memfile_close ( treefile ) ;
2014-09-17 22:44:07 +00:00
2014-12-04 00:18:43 +00:00
struct stat geomst ;
2014-09-18 19:11:36 +00:00
struct stat metast ;
2014-11-25 06:50:12 +00:00
2014-12-04 00:18:43 +00:00
if ( fstat ( geomfd , & geomst ) ! = 0 ) {
perror ( " stat geom \n " ) ;
2014-11-25 06:50:12 +00:00
exit ( EXIT_FAILURE ) ;
}
if ( fstat ( metafd , & metast ) ! = 0 ) {
perror ( " stat meta \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2014-12-04 00:18:43 +00:00
if ( geomst . st_size = = 0 | | metast . st_size = = 0 ) {
2015-03-24 00:44:23 +00:00
fprintf ( stderr , " did not read any valid geometries \n " ) ;
2014-11-25 06:50:12 +00:00
exit ( EXIT_FAILURE ) ;
}
2014-12-02 22:17:49 +00:00
char * meta = ( char * ) mmap ( NULL , metast . st_size , PROT_READ , MAP_PRIVATE , metafd , 0 ) ;
2014-09-17 23:00:19 +00:00
if ( meta = = MAP_FAILED ) {
perror ( " mmap meta " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-18 23:13:37 +00:00
char * stringpool = poolfile - > map ;
2015-06-18 00:18:08 +00:00
2015-03-23 20:44:35 +00:00
struct pool file_keys1 [ nlayers ] ;
struct pool * file_keys [ nlayers ] ;
int i ;
for ( i = 0 ; i < nlayers ; i + + ) {
pool_init ( & file_keys1 [ i ] , 0 ) ;
file_keys [ i ] = & file_keys1 [ i ] ;
}
2014-09-23 23:01:19 +00:00
2015-03-24 23:28:31 +00:00
char * layernames [ nlayers ] ;
for ( i = 0 ; i < nlayers ; i + + ) {
2015-03-25 21:07:34 +00:00
if ( argc < = 1 & & layername ! = NULL ) {
2015-03-24 23:28:31 +00:00
layernames [ i ] = strdup ( layername ) ;
} else {
2015-03-25 21:07:34 +00:00
char * src = argv [ i ] ;
if ( argc < 1 ) {
src = fname ;
}
2015-03-24 23:28:31 +00:00
2015-03-25 21:07:34 +00:00
char * trunc = layernames [ i ] = malloc ( strlen ( src ) + 1 ) ;
const char * ocp , * use = src ;
for ( ocp = src ; * ocp ; ocp + + ) {
2015-03-24 23:28:31 +00:00
if ( * ocp = = ' / ' & & ocp [ 1 ] ! = ' \0 ' ) {
use = ocp + 1 ;
}
2014-09-25 19:09:31 +00:00
}
2015-03-24 23:28:31 +00:00
strcpy ( trunc , use ) ;
2014-12-02 22:17:49 +00:00
2015-03-24 23:28:31 +00:00
char * cp = strstr ( trunc , " .json " ) ;
if ( cp ! = NULL ) {
* cp = ' \0 ' ;
}
cp = strstr ( trunc , " .mbtiles " ) ;
if ( cp ! = NULL ) {
* cp = ' \0 ' ;
}
layername = trunc ;
2014-09-27 16:39:20 +00:00
2015-03-24 23:28:31 +00:00
char * out = trunc ;
for ( cp = trunc ; * cp ; cp + + ) {
if ( isalpha ( * cp ) | | isdigit ( * cp ) | | * cp = = ' _ ' ) {
* out + + = * cp ;
}
2014-09-27 16:39:20 +00:00
}
2015-03-24 23:28:31 +00:00
* out = ' \0 ' ;
2014-09-27 16:39:20 +00:00
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
printf ( " using layer %d name %s \n " , i , trunc ) ;
}
2015-03-24 23:28:31 +00:00
}
2014-09-25 19:09:31 +00:00
}
2014-09-25 06:22:14 +00:00
2015-03-06 00:18:01 +00:00
/* Sort the index by geometry */
2015-03-05 23:15:56 +00:00
{
int bytes = sizeof ( struct index ) ;
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Sorting %lld features \n " , ( long long ) indexpos / bytes ) ;
}
2015-03-05 23:15:56 +00:00
int page = sysconf ( _SC_PAGESIZE ) ;
long long unit = ( 50 * 1024 * 1024 / bytes ) * bytes ;
while ( unit % page ! = 0 ) {
unit + = bytes ;
}
int nmerges = ( indexpos + unit - 1 ) / unit ;
struct merge merges [ nmerges ] ;
long long start ;
for ( start = 0 ; start < indexpos ; start + = unit ) {
long long end = start + unit ;
if ( end > indexpos ) {
end = indexpos ;
}
if ( nmerges ! = 1 ) {
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Sorting part %lld of %d \r " , start / unit + 1 , nmerges ) ;
}
2015-03-05 23:15:56 +00:00
}
merges [ start / unit ] . start = start ;
merges [ start / unit ] . end = end ;
merges [ start / unit ] . next = NULL ;
2015-06-18 23:13:37 +00:00
// MAP_PRIVATE to avoid disk writes if it fits in memory
2015-03-05 23:15:56 +00:00
void * map = mmap ( NULL , end - start , PROT_READ | PROT_WRITE , MAP_PRIVATE , indexfd , start ) ;
if ( map = = MAP_FAILED ) {
perror ( " mmap " ) ;
exit ( EXIT_FAILURE ) ;
}
qsort ( map , ( end - start ) / bytes , bytes , indexcmp ) ;
// Sorting and then copying avoids the need to
// write out intermediate stages of the sort.
void * map2 = mmap ( NULL , end - start , PROT_READ | PROT_WRITE , MAP_SHARED , indexfd , start ) ;
if ( map2 = = MAP_FAILED ) {
perror ( " mmap (write) " ) ;
exit ( EXIT_FAILURE ) ;
}
memcpy ( map2 , map , end - start ) ;
munmap ( map , end - start ) ;
munmap ( map2 , end - start ) ;
}
if ( nmerges ! = 1 ) {
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " \n " ) ;
}
2015-03-05 23:15:56 +00:00
}
void * map = mmap ( NULL , indexpos , PROT_READ , MAP_PRIVATE , indexfd , 0 ) ;
if ( map = = MAP_FAILED ) {
perror ( " mmap " ) ;
exit ( EXIT_FAILURE ) ;
}
FILE * f = fopen ( indexname , " w " ) ;
if ( f = = NULL ) {
perror ( indexname ) ;
exit ( EXIT_FAILURE ) ;
}
merge ( merges , nmerges , ( unsigned char * ) map , f , bytes , indexpos / bytes ) ;
munmap ( map , indexpos ) ;
fclose ( f ) ;
close ( indexfd ) ;
}
2015-03-06 00:18:01 +00:00
/* Copy geometries to a new file in index order */
indexfd = open ( indexname , O_RDONLY ) ;
if ( indexfd < 0 ) {
perror ( " reopen sorted index " ) ;
exit ( EXIT_FAILURE ) ;
}
struct index * index_map = mmap ( NULL , indexpos , PROT_READ , MAP_PRIVATE , indexfd , 0 ) ;
if ( index_map = = MAP_FAILED ) {
perror ( " mmap index " ) ;
exit ( EXIT_FAILURE ) ;
}
unlink ( indexname ) ;
char * geom_map = mmap ( NULL , geomst . st_size , PROT_READ , MAP_PRIVATE , geomfd , 0 ) ;
if ( geom_map = = MAP_FAILED ) {
perror ( " mmap unsorted geometry " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( close ( geomfd ) ! = 0 ) {
perror ( " close unsorted geometry " ) ;
}
sprintf ( geomname , " %s%s " , tmpdir , " /geom.XXXXXXXX " ) ;
geomfd = mkstemp ( geomname ) ;
if ( geomfd < 0 ) {
perror ( geomname ) ;
exit ( EXIT_FAILURE ) ;
}
geomfile = fopen ( geomname , " wb " ) ;
if ( geomfile = = NULL ) {
perror ( geomname ) ;
exit ( EXIT_FAILURE ) ;
}
{
geompos = 0 ;
/* initial tile is 0/0/0 */
2015-03-24 00:44:23 +00:00
serialize_int ( geomfile , 0 , & geompos , fname ) ;
serialize_uint ( geomfile , 0 , & geompos , fname ) ;
serialize_uint ( geomfile , 0 , & geompos , fname ) ;
2015-03-06 00:18:01 +00:00
long long i ;
long long sum = 0 ;
2015-03-06 23:32:52 +00:00
long long progress = 0 ;
2015-03-06 00:18:01 +00:00
for ( i = 0 ; i < indexpos / sizeof ( struct index ) ; i + + ) {
2015-03-24 00:44:23 +00:00
fwrite_check ( geom_map + index_map [ i ] . start , sizeof ( char ) , index_map [ i ] . end - index_map [ i ] . start , geomfile , fname ) ;
2015-03-06 00:18:01 +00:00
sum + = index_map [ i ] . end - index_map [ i ] . start ;
2015-03-06 23:32:52 +00:00
long long p = 1000 * i / ( indexpos / sizeof ( struct index ) ) ;
if ( p ! = progress ) {
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Reordering geometry: %3.1f%% \r " , p / 10.0 ) ;
}
2015-03-06 23:32:52 +00:00
progress = p ;
}
2015-03-06 00:18:01 +00:00
}
/* end of tile */
2015-03-24 00:44:23 +00:00
serialize_byte ( geomfile , - 2 , & geompos , fname ) ;
2015-03-06 00:18:01 +00:00
fclose ( geomfile ) ;
}
if ( munmap ( index_map , indexpos ) ! = 0 ) {
perror ( " unmap sorted index " ) ;
}
if ( munmap ( geom_map , geomst . st_size ) ! = 0 ) {
perror ( " unmap unsorted geometry " ) ;
}
if ( close ( indexfd ) ! = 0 ) {
perror ( " close sorted index " ) ;
}
/* Traverse and split the geometries for each zoom level */
geomfd = open ( geomname , O_RDONLY ) ;
if ( geomfd < 0 ) {
perror ( " reopen sorted geometry " ) ;
exit ( EXIT_FAILURE ) ;
}
unlink ( geomname ) ;
if ( fstat ( geomfd , & geomst ) ! = 0 ) {
perror ( " stat sorted geom \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-29 22:50:46 +00:00
int fd [ ( 1 < < MAX_ZOOM_INCREMENT ) * ( 1 < < MAX_ZOOM_INCREMENT ) ] ;
off_t size [ ( 1 < < MAX_ZOOM_INCREMENT ) * ( 1 < < MAX_ZOOM_INCREMENT ) ] ;
2014-12-11 23:46:54 +00:00
fd [ 0 ] = geomfd ;
size [ 0 ] = geomst . st_size ;
int j ;
2015-06-29 22:50:46 +00:00
for ( j = 1 ; j < ( 1 < < MAX_ZOOM_INCREMENT ) * ( 1 < < MAX_ZOOM_INCREMENT ) ; j + + ) {
2014-12-11 23:46:54 +00:00
fd [ j ] = - 1 ;
size [ j ] = 0 ;
}
2014-11-04 06:47:41 +00:00
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " %lld features, %lld bytes of geometry, %lld bytes of metadata, %lld bytes of string pool \n " , seq , ( long long ) geomst . st_size , ( long long ) metast . st_size , poolfile - > off ) ;
}
2014-12-12 01:59:22 +00:00
2015-06-20 00:29:56 +00:00
int written = traverse_zooms ( fd , size , meta , stringpool , file_bbox , file_keys , & midx , & midy , layernames , maxzoom , minzoom , outdb , droprate , buffer , fname , tmpdir , gamma , nlayers , prevent , full_detail , low_detail , min_detail ) ;
2015-03-07 00:33:32 +00:00
if ( maxzoom ! = written ) {
fprintf ( stderr , " \n \n \n *** NOTE TILES ONLY COMPLETE THROUGH ZOOM %d *** \n \n \n " , written ) ;
maxzoom = written ;
ret = EXIT_FAILURE ;
}
2014-09-18 19:11:36 +00:00
2014-12-18 01:41:57 +00:00
if ( munmap ( meta , metast . st_size ) ! = 0 ) {
perror ( " munmap meta " ) ;
}
2015-03-05 23:22:58 +00:00
if ( close ( metafd ) < 0 ) {
perror ( " close meta " ) ;
}
2014-09-25 22:20:17 +00:00
2015-06-18 23:13:37 +00:00
if ( memfile_close ( poolfile ) ! = 0 ) {
2015-06-18 00:18:08 +00:00
perror ( " close pool " ) ;
}
2014-09-29 19:48:58 +00:00
double minlat = 0 , minlon = 0 , maxlat = 0 , maxlon = 0 , midlat = 0 , midlon = 0 ;
2014-09-23 23:01:19 +00:00
2014-09-29 19:48:58 +00:00
tile2latlon ( midx , midy , maxzoom , & maxlat , & minlon ) ;
tile2latlon ( midx + 1 , midy + 1 , maxzoom , & minlat , & maxlon ) ;
2014-09-23 23:41:38 +00:00
2014-09-29 19:48:58 +00:00
midlat = ( maxlat + minlat ) / 2 ;
midlon = ( maxlon + minlon ) / 2 ;
2014-09-23 23:41:38 +00:00
2014-09-29 19:48:58 +00:00
tile2latlon ( file_bbox [ 0 ] , file_bbox [ 1 ] , 32 , & maxlat , & minlon ) ;
tile2latlon ( file_bbox [ 2 ] , file_bbox [ 3 ] , 32 , & minlat , & maxlon ) ;
2014-09-24 19:14:35 +00:00
2014-10-26 20:12:29 +00:00
if ( midlat < minlat ) {
midlat = minlat ;
}
if ( midlat > maxlat ) {
midlat = maxlat ;
}
if ( midlon < minlon ) {
midlon = minlon ;
}
if ( midlon > maxlon ) {
midlon = maxlon ;
}
2015-06-03 18:21:40 +00:00
mbtiles_write_metadata ( outdb , fname , layernames , minzoom , maxzoom , minlat , minlon , maxlat , maxlon , midlat , midlon , file_keys , nlayers ) ; // XXX layers
2014-10-01 17:33:22 +00:00
2015-03-23 20:44:35 +00:00
for ( i = 0 ; i < nlayers ; i + + ) {
pool_free_strings ( & file_keys1 [ i ] ) ;
2015-03-24 23:28:31 +00:00
free ( layernames [ i ] ) ;
2015-03-23 20:44:35 +00:00
}
2015-03-07 00:33:32 +00:00
return ret ;
2014-09-15 22:02:33 +00:00
}
2014-09-15 22:27:35 +00:00
int main ( int argc , char * * argv ) {
2014-09-25 19:09:31 +00:00
extern int optind ;
extern char * optarg ;
int i ;
char * name = NULL ;
char * layer = NULL ;
2014-09-25 22:20:17 +00:00
char * outdir = NULL ;
2014-09-25 19:09:31 +00:00
int maxzoom = 14 ;
int minzoom = 0 ;
2014-09-29 22:09:21 +00:00
int force = 0 ;
2014-10-07 20:54:13 +00:00
double droprate = 2.5 ;
2015-03-23 21:44:21 +00:00
double gamma = 0 ;
2014-10-27 20:20:17 +00:00
int buffer = 5 ;
2014-12-02 22:17:49 +00:00
const char * tmpdir = " /tmp " ;
2015-04-10 18:36:30 +00:00
char prevent [ 256 ] ;
2014-09-25 19:09:31 +00:00
2014-11-12 20:40:08 +00:00
struct pool exclude , include ;
2014-09-29 19:12:54 +00:00
pool_init ( & exclude , 0 ) ;
2014-11-12 20:40:08 +00:00
pool_init ( & include , 0 ) ;
2014-10-09 22:11:43 +00:00
int exclude_all = 0 ;
2014-09-29 17:49:08 +00:00
2015-04-10 18:36:30 +00:00
for ( i = 0 ; i < 256 ; i + + ) {
prevent [ i ] = 0 ;
}
2015-07-08 22:06:21 +00:00
while ( ( i = getopt ( argc , argv , " l:n:z:Z:d:D:m:o:x:y:r:b:fXt:g:p:vq " ) ) ! = - 1 ) {
2014-09-25 19:09:31 +00:00
switch ( i ) {
case ' n ' :
name = optarg ;
break ;
case ' l ' :
layer = optarg ;
break ;
case ' z ' :
maxzoom = atoi ( optarg ) ;
break ;
case ' Z ' :
2015-03-24 00:44:23 +00:00
minzoom = atoi ( optarg ) ;
2014-09-25 19:09:31 +00:00
break ;
2014-09-26 17:52:19 +00:00
case ' d ' :
full_detail = atoi ( optarg ) ;
break ;
case ' D ' :
low_detail = atoi ( optarg ) ;
break ;
2015-06-01 22:01:46 +00:00
case ' m ' :
min_detail = atoi ( optarg ) ;
break ;
2014-09-25 19:09:31 +00:00
case ' o ' :
outdir = optarg ;
break ;
2014-09-29 17:49:08 +00:00
case ' x ' :
2014-09-29 19:12:54 +00:00
pool ( & exclude , optarg , VT_STRING ) ;
2014-09-29 17:49:08 +00:00
break ;
2014-11-12 20:40:08 +00:00
case ' y ' :
exclude_all = 1 ;
pool ( & include , optarg , VT_STRING ) ;
break ;
2014-10-09 22:11:43 +00:00
case ' X ' :
exclude_all = 1 ;
break ;
2014-10-07 20:54:13 +00:00
case ' r ' :
droprate = atof ( optarg ) ;
break ;
2014-10-27 20:20:17 +00:00
case ' b ' :
buffer = atoi ( optarg ) ;
break ;
2014-09-29 22:09:21 +00:00
case ' f ' :
force = 1 ;
break ;
2014-11-05 18:34:44 +00:00
case ' t ' :
tmpdir = optarg ;
break ;
2015-03-06 21:12:32 +00:00
case ' g ' :
gamma = atof ( optarg ) ;
break ;
2015-07-08 22:06:21 +00:00
case ' q ' :
quiet = 1 ;
break ;
2015-06-03 18:21:40 +00:00
case ' p ' : {
char * cp ;
for ( cp = optarg ; * cp ! = ' \0 ' ; cp + + ) {
prevent [ * cp & 0xFF ] = 1 ;
2015-04-10 18:36:30 +00:00
}
2015-06-03 18:21:40 +00:00
} break ;
2015-04-10 18:36:30 +00:00
2015-05-29 14:50:11 +00:00
case ' v ' :
fprintf ( stderr , VERSION ) ;
exit ( EXIT_FAILURE ) ;
2014-09-25 19:09:31 +00:00
default :
2015-06-01 22:01:46 +00:00
fprintf ( stderr , " Usage: %s -o out.mbtiles [-n name] [-l layername] [-z maxzoom] [-Z minzoom] [-d detail] [-D lower-detail] [-m min-detail] [-x excluded-field ...] [-y included-field ...] [-X] [-r droprate] [-b buffer] [-t tmpdir] [-p rcfs] [file.json ...] \n " , argv [ 0 ] ) ;
2014-09-25 19:09:31 +00:00
exit ( EXIT_FAILURE ) ;
}
}
2014-09-25 22:20:17 +00:00
2015-05-29 14:33:44 +00:00
if ( minzoom > maxzoom ) {
2015-05-28 17:21:38 +00:00
fprintf ( stderr , " minimum zoom -Z cannot be greater than maxzoom -z \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2014-10-27 21:33:09 +00:00
if ( full_detail < = 0 ) {
// ~0.5m accuracy at whatever zoom
// 12 bits (4096 units) at z14
full_detail = 26 - maxzoom ;
}
2015-06-01 22:01:46 +00:00
if ( full_detail < min_detail | | low_detail < min_detail ) {
fprintf ( stderr , " %s: Full detail and low detail must be at least minimum detail \n " , argv [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-18 21:16:16 +00:00
geometry_scale = 32 - ( full_detail + maxzoom ) ;
2014-09-25 22:20:17 +00:00
if ( outdir = = NULL ) {
fprintf ( stderr , " %s: must specify -o out.mbtiles \n " , argv [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2014-09-29 22:09:21 +00:00
if ( force ) {
unlink ( outdir ) ;
}
2014-09-29 19:48:58 +00:00
sqlite3 * outdb = mbtiles_open ( outdir , argv ) ;
2015-03-07 00:33:32 +00:00
int ret = EXIT_SUCCESS ;
2015-03-24 00:44:23 +00:00
2015-04-10 18:36:30 +00:00
ret = read_json ( argc - optind , argv + optind , name ? name : outdir , layer , maxzoom , minzoom , outdb , & exclude , & include , exclude_all , droprate , buffer , tmpdir , gamma , prevent ) ;
2014-09-25 22:38:20 +00:00
2014-09-29 19:48:58 +00:00
mbtiles_close ( outdb , argv ) ;
2015-03-07 00:33:32 +00:00
return ret ;
2014-09-15 22:27:35 +00:00
}