2016-12-08 20:33:02 +00:00
# ifdef __APPLE__
# define _DARWIN_UNLIMITED_STREAMS
# endif
2014-09-22 22:41:13 +00:00
# include <iostream>
# include <fstream>
# include <string>
2014-09-24 23:51:53 +00:00
# include <stack>
2014-09-30 22:53:45 +00:00
# include <vector>
2014-10-31 23:50:28 +00:00
# include <map>
2014-11-06 19:29:11 +00:00
# include <set>
2014-09-30 22:53:45 +00:00
# include <algorithm>
2014-09-23 00:46:48 +00:00
# include <stdio.h>
2015-12-14 23:45:00 +00:00
# include <stdlib.h>
2016-04-23 00:51:35 +00:00
# include <string.h>
2014-09-23 00:46:48 +00:00
# include <unistd.h>
2015-07-10 17:26:23 +00:00
# include <limits.h>
2014-09-22 22:41:13 +00:00
# include <zlib.h>
2014-09-23 00:46:48 +00:00
# include <sys/stat.h>
# include <sys/types.h>
2015-06-20 00:29:56 +00:00
# include <sys/mman.h>
2016-04-26 23:56:24 +00:00
# include <cmath>
2014-09-25 23:34:17 +00:00
# include <sqlite3.h>
2015-10-19 19:32:40 +00:00
# include <pthread.h>
2015-12-20 23:13:33 +00:00
# include <errno.h>
2016-09-28 18:13:27 +00:00
# include <time.h>
2016-12-07 18:57:56 +00:00
# include <fcntl.h>
2016-12-09 01:22:07 +00:00
# include <sys/wait.h>
2016-04-27 19:22:47 +00:00
# include "mvt.hpp"
2016-08-30 00:42:46 +00:00
# include "mbtiles.hpp"
2016-04-27 19:22:47 +00:00
# include "geometry.hpp"
2016-04-27 21:00:14 +00:00
# include "tile.hpp"
# include "pool.hpp"
# include "projection.hpp"
2016-04-27 21:19:10 +00:00
# include "serial.hpp"
2016-04-27 22:09:06 +00:00
# include "options.hpp"
# include "main.hpp"
2016-12-01 20:04:49 +00:00
# include "plugin.hpp"
2016-12-08 23:13:38 +00:00
# include "write_json.hpp"
2014-09-22 23:06:44 +00:00
2014-09-23 00:12:38 +00:00
# define CMD_BITS 3
2015-07-10 17:26:23 +00:00
# define XSTRINGIFY(s) STRINGIFY(s)
# define STRINGIFY(s) #s
2015-10-19 19:32:40 +00:00
pthread_mutex_t db_lock = PTHREAD_MUTEX_INITIALIZER ;
2015-10-19 20:26:47 +00:00
pthread_mutex_t var_lock = PTHREAD_MUTEX_INITIALIZER ;
2015-10-19 19:32:40 +00:00
2016-04-22 22:10:16 +00:00
std : : vector < mvt_geometry > to_feature ( drawvec & geom ) {
std : : vector < mvt_geometry > out ;
2014-09-23 18:30:32 +00:00
2016-04-22 22:06:26 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2016-04-22 22:10:16 +00:00
out . push_back ( mvt_geometry ( geom [ i ] . op , geom [ i ] . x , geom [ i ] . y ) ) ;
2014-09-23 18:30:32 +00:00
}
2016-04-22 22:06:26 +00:00
return out ;
}
bool draws_something ( drawvec & geom ) {
for ( size_t i = 1 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_LINETO & & ( geom [ i ] . x ! = geom [ i - 1 ] . x | | geom [ i ] . y ! = geom [ i - 1 ] . y ) ) {
return true ;
2014-09-23 18:30:32 +00:00
}
}
2016-04-22 22:06:26 +00:00
return false ;
2014-09-23 18:30:32 +00:00
}
2016-05-10 22:30:49 +00:00
int metacmp ( int m1 , const std : : vector < long long > & keys1 , const std : : vector < long long > & values1 , char * stringpool1 , int m2 , const std : : vector < long long > & keys2 , const std : : vector < long long > & values2 , char * stringpool2 ) ;
2014-10-01 00:18:23 +00:00
int coalindexcmp ( const struct coalesce * c1 , const struct coalesce * c2 ) ;
2014-09-29 21:46:15 +00:00
struct coalesce {
2016-04-25 23:47:30 +00:00
char * stringpool ;
2016-05-23 22:57:28 +00:00
std : : vector < long long > keys ;
std : : vector < long long > values ;
2016-05-11 21:47:23 +00:00
drawvec geom ;
2014-09-29 22:38:33 +00:00
unsigned long long index ;
2014-10-22 00:52:52 +00:00
unsigned long long index2 ;
2015-09-14 22:42:06 +00:00
long long original_seq ;
2016-05-11 21:47:23 +00:00
int type ;
int m ;
bool coalesced ;
2016-05-27 23:25:40 +00:00
double spacing ;
2016-07-15 22:00:40 +00:00
bool has_id ;
unsigned long long id ;
2014-10-01 00:18:23 +00:00
2015-06-03 18:21:40 +00:00
bool operator < ( const coalesce & o ) const {
2014-10-01 00:18:23 +00:00
int cmp = coalindexcmp ( this , & o ) ;
if ( cmp < 0 ) {
return true ;
} else {
return false ;
}
}
2014-09-29 21:46:15 +00:00
} ;
2015-09-14 22:42:06 +00:00
struct preservecmp {
2015-09-15 20:23:34 +00:00
bool operator ( ) ( const struct coalesce & a , const struct coalesce & b ) {
2015-09-14 22:42:06 +00:00
return a . original_seq < b . original_seq ;
}
} preservecmp ;
2014-09-29 22:33:14 +00:00
int coalcmp ( const void * v1 , const void * v2 ) {
const struct coalesce * c1 = ( const struct coalesce * ) v1 ;
const struct coalesce * c2 = ( const struct coalesce * ) v2 ;
int cmp = c1 - > type - c2 - > type ;
if ( cmp ! = 0 ) {
return cmp ;
}
2016-05-10 22:30:49 +00:00
return metacmp ( c1 - > m , c1 - > keys , c1 - > values , c1 - > stringpool , c2 - > m , c2 - > keys , c2 - > values , c2 - > stringpool ) ;
2014-09-29 22:33:14 +00:00
}
2014-10-01 00:18:23 +00:00
int coalindexcmp ( const struct coalesce * c1 , const struct coalesce * c2 ) {
int cmp = coalcmp ( ( const void * ) c1 , ( const void * ) c2 ) ;
2014-09-29 22:38:33 +00:00
if ( cmp = = 0 ) {
if ( c1 - > index < c2 - > index ) {
return - 1 ;
} else if ( c1 - > index > c2 - > index ) {
return 1 ;
}
2014-10-22 00:52:52 +00:00
if ( c1 - > index2 > c2 - > index2 ) {
return - 1 ;
} else if ( c1 - > index2 < c2 - > index2 ) {
return 1 ;
}
2014-09-29 22:38:33 +00:00
}
return cmp ;
}
2016-05-10 22:30:49 +00:00
mvt_value retrieve_string ( long long off , char * stringpool , int * otype ) {
2016-04-25 23:19:52 +00:00
int type = stringpool [ off ] ;
char * s = stringpool + off + 1 ;
if ( otype ! = NULL ) {
* otype = type ;
}
2016-12-07 23:54:58 +00:00
return stringified_to_mvt_value ( type , s ) ;
2015-06-18 00:18:08 +00:00
}
2016-12-08 23:13:38 +00:00
void decode_meta ( int m , std : : vector < long long > const & metakeys , std : : vector < long long > const & metavals , char * stringpool , mvt_layer & layer , mvt_feature & feature ) {
2014-10-08 21:01:47 +00:00
int i ;
for ( i = 0 ; i < m ; i + + ) {
2016-04-25 23:19:52 +00:00
int otype ;
2016-05-10 22:30:49 +00:00
mvt_value key = retrieve_string ( metakeys [ i ] , stringpool , NULL ) ;
mvt_value value = retrieve_string ( metavals [ i ] , stringpool , & otype ) ;
2014-10-08 21:01:47 +00:00
2016-04-25 23:19:52 +00:00
layer . tag ( feature , key . string_value , value ) ;
2014-10-08 21:01:47 +00:00
}
}
2016-05-10 22:30:49 +00:00
int metacmp ( int m1 , const std : : vector < long long > & keys1 , const std : : vector < long long > & values1 , char * stringpool1 , int m2 , const std : : vector < long long > & keys2 , const std : : vector < long long > & values2 , char * stringpool2 ) {
2016-04-25 23:47:30 +00:00
// XXX
// Ideally this would make identical features compare the same lexically
// even if their attributes were declared in different orders in different instances.
// In practice, this is probably good enough to put "identical" features together.
int i ;
for ( i = 0 ; i < m1 & & i < m2 ; i + + ) {
2016-05-10 22:30:49 +00:00
mvt_value key1 = retrieve_string ( keys1 [ i ] , stringpool1 , NULL ) ;
mvt_value key2 = retrieve_string ( keys2 [ i ] , stringpool2 , NULL ) ;
2016-04-25 23:47:30 +00:00
if ( key1 . string_value < key2 . string_value ) {
return - 1 ;
} else if ( key1 . string_value > key2 . string_value ) {
return 1 ;
}
2016-05-10 22:30:49 +00:00
long long off1 = values1 [ i ] ;
2016-04-25 23:47:30 +00:00
int type1 = stringpool1 [ off1 ] ;
char * s1 = stringpool1 + off1 + 1 ;
2016-05-10 22:30:49 +00:00
long long off2 = values2 [ i ] ;
2016-04-25 23:47:30 +00:00
int type2 = stringpool2 [ off2 ] ;
char * s2 = stringpool2 + off2 + 1 ;
if ( type1 ! = type2 ) {
return type1 - type2 ;
}
int cmp = strcmp ( s1 , s2 ) ;
if ( s1 ! = s2 ) {
return cmp ;
}
}
if ( m1 < m2 ) {
return - 1 ;
} else if ( m1 > m2 ) {
return 1 ;
} else {
return 0 ;
}
}
2016-11-10 00:32:40 +00:00
void rewrite ( drawvec & geom , int z , int nextzoom , int maxzoom , long long * bbox , unsigned tx , unsigned ty , int buffer , int line_detail , int * within , long long * geompos , FILE * * geomfile , const char * fname , signed char t , int layer , long long metastart , signed char feature_minzoom , int child_shards , int max_zoom_increment , long long seq , int tippecanoe_minzoom , int tippecanoe_maxzoom , int segment , unsigned * initial_x , unsigned * initial_y , int m , std : : vector < long long > & metakeys , std : : vector < long long > & metavals , bool has_id , unsigned long long id , unsigned long long index , long long extent ) {
2015-12-15 20:00:05 +00:00
if ( geom . size ( ) > 0 & & nextzoom < = maxzoom ) {
2015-06-30 23:36:26 +00:00
int xo , yo ;
int span = 1 < < ( nextzoom - z ) ;
2015-07-01 22:06:12 +00:00
// Get the feature bounding box in pixel (256) coordinates at the child zoom
// in order to calculate which sub-tiles it can touch including the buffer.
long long bbox2 [ 4 ] ;
int k ;
for ( k = 0 ; k < 4 ; k + + ) {
// Division instead of right-shift because coordinates can be negative
bbox2 [ k ] = bbox [ k ] / ( 1 < < ( 32 - nextzoom - 8 ) ) ;
}
2016-01-20 21:58:17 +00:00
// Decrement the top and left edges so that any features that are
// touching the edge can potentially be included in the adjacent tiles too.
bbox2 [ 0 ] - = buffer + 1 ;
bbox2 [ 1 ] - = buffer + 1 ;
2015-07-01 22:06:12 +00:00
bbox2 [ 2 ] + = buffer ;
bbox2 [ 3 ] + = buffer ;
for ( k = 0 ; k < 4 ; k + + ) {
if ( bbox2 [ k ] < 0 ) {
bbox2 [ k ] = 0 ;
}
if ( bbox2 [ k ] > = 256 * span ) {
bbox2 [ k ] = 256 * ( span - 1 ) ;
}
bbox2 [ k ] / = 256 ;
}
2016-08-09 00:08:36 +00:00
// Offset from tile coordinates back to world coordinates
unsigned sx = 0 , sy = 0 ;
if ( z ! = 0 ) {
sx = tx < < ( 32 - z ) ;
sy = ty < < ( 32 - z ) ;
}
drawvec geom2 ;
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
geom2 . push_back ( draw ( geom [ i ] . op , ( geom [ i ] . x + sx ) > > geometry_scale , ( geom [ i ] . y + sy ) > > geometry_scale ) ) ;
}
2015-07-01 22:06:12 +00:00
for ( xo = bbox2 [ 0 ] ; xo < = bbox2 [ 2 ] ; xo + + ) {
for ( yo = bbox2 [ 1 ] ; yo < = bbox2 [ 3 ] ; yo + + ) {
2015-07-01 17:12:23 +00:00
unsigned jx = tx * span + xo ;
unsigned jy = ty * span + yo ;
// j is the shard that the child tile's data is being written to.
//
2015-07-08 23:33:22 +00:00
// Be careful: We can't jump more zoom levels than max_zoom_increment
2015-07-01 17:12:23 +00:00
// because that could break the constraint that each of the children
// of the current tile must have its own shard, because the data for
// the child tile must be contiguous within the shard.
//
// But it's OK to spread children across all the shards, not just
// the four that would normally result from splitting one tile,
// because it will go through all the shards when it does the
// next zoom.
2015-07-08 23:33:22 +00:00
//
// If child_shards is a power of 2 but not a power of 4, this will
// shard X more widely than Y. XXX Is there a better way to do this
// without causing collisions?
2015-07-01 17:12:23 +00:00
2015-07-08 23:35:02 +00:00
int j = ( ( jx < < max_zoom_increment ) |
( ( jy & ( ( 1 < < max_zoom_increment ) - 1 ) ) ) ) &
( child_shards - 1 ) ;
2015-06-30 23:36:26 +00:00
2015-07-01 22:06:12 +00:00
{
2015-06-30 23:36:26 +00:00
if ( ! within [ j ] ) {
serialize_int ( geomfile [ j ] , nextzoom , & geompos [ j ] , fname ) ;
serialize_uint ( geomfile [ j ] , tx * span + xo , & geompos [ j ] , fname ) ;
serialize_uint ( geomfile [ j ] , ty * span + yo , & geompos [ j ] , fname ) ;
within [ j ] = 1 ;
}
2016-08-09 00:08:36 +00:00
serial_feature sf ;
sf . layer = layer ;
sf . segment = segment ;
sf . seq = seq ;
sf . t = t ;
sf . has_id = has_id ;
sf . id = id ;
sf . has_tippecanoe_minzoom = tippecanoe_minzoom ! = - 1 ;
sf . tippecanoe_minzoom = tippecanoe_minzoom ;
sf . has_tippecanoe_maxzoom = tippecanoe_maxzoom ! = - 1 ;
sf . tippecanoe_maxzoom = tippecanoe_maxzoom ;
sf . metapos = metastart ;
sf . geometry = geom2 ;
2016-11-02 22:11:22 +00:00
sf . index = index ;
2016-11-10 00:32:40 +00:00
sf . extent = extent ;
2016-08-09 00:08:36 +00:00
sf . m = m ;
sf . feature_minzoom = feature_minzoom ;
2016-05-10 22:30:49 +00:00
if ( metastart < 0 ) {
for ( int i = 0 ; i < m ; i + + ) {
2016-08-09 00:08:36 +00:00
sf . keys . push_back ( metakeys [ i ] ) ;
sf . values . push_back ( metavals [ i ] ) ;
2016-05-10 22:30:49 +00:00
}
}
2016-10-10 22:31:09 +00:00
serialize_feature ( geomfile [ j ] , & sf , & geompos [ j ] , fname , initial_x [ segment ] > > geometry_scale , initial_y [ segment ] > > geometry_scale , true ) ;
2015-06-30 23:36:26 +00:00
}
}
}
}
}
2016-01-05 20:29:40 +00:00
struct partial {
2016-02-11 19:09:05 +00:00
std : : vector < drawvec > geoms ;
2016-05-23 22:57:28 +00:00
std : : vector < long long > keys ;
std : : vector < long long > values ;
2016-09-26 20:39:16 +00:00
std : : vector < ssize_t > arc_polygon ;
2016-05-11 21:47:23 +00:00
long long layer ;
2016-01-05 20:29:40 +00:00
long long original_seq ;
unsigned long long index ;
unsigned long long index2 ;
2016-05-11 21:47:23 +00:00
int m ;
int segment ;
bool reduced ;
2016-01-05 20:29:40 +00:00
int z ;
int line_detail ;
2016-01-08 19:31:10 +00:00
int maxzoom ;
2016-05-27 23:25:40 +00:00
double spacing ;
2016-07-12 23:51:56 +00:00
double simplification ;
2016-05-11 21:47:23 +00:00
signed char t ;
2016-07-15 22:00:40 +00:00
unsigned long long id ;
bool has_id ;
2016-10-25 17:01:18 +00:00
ssize_t renamed ;
2016-01-05 20:29:40 +00:00
} ;
struct partial_arg {
std : : vector < struct partial > * partials ;
int task ;
int tasks ;
} ;
2016-05-05 20:39:21 +00:00
drawvec revive_polygon ( drawvec & geom , double area , int z , int detail ) {
// From area in world coordinates to area in tile coordinates
long long divisor = 1LL < < ( 32 - detail - z ) ;
area / = divisor * divisor ;
if ( area = = 0 ) {
return drawvec ( ) ;
}
int height = ceil ( sqrt ( area ) ) ;
int width = round ( area / height ) ;
if ( width = = 0 ) {
width = 1 ;
}
long long sx = 0 , sy = 0 , n = 0 ;
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO | | geom [ i ] . op = = VT_LINETO ) {
sx + = geom [ i ] . x ;
sy + = geom [ i ] . y ;
n + + ;
}
}
if ( n > 0 ) {
sx / = n ;
sy / = n ;
drawvec out ;
out . push_back ( draw ( VT_MOVETO , sx - ( width / 2 ) , sy - ( height / 2 ) ) ) ;
out . push_back ( draw ( VT_LINETO , sx - ( width / 2 ) + width , sy - ( height / 2 ) ) ) ;
out . push_back ( draw ( VT_LINETO , sx - ( width / 2 ) + width , sy - ( height / 2 ) + height ) ) ;
out . push_back ( draw ( VT_LINETO , sx - ( width / 2 ) , sy - ( height / 2 ) + height ) ) ;
out . push_back ( draw ( VT_LINETO , sx - ( width / 2 ) , sy - ( height / 2 ) ) ) ;
return out ;
} else {
return drawvec ( ) ;
}
}
2016-01-05 20:29:40 +00:00
void * partial_feature_worker ( void * v ) {
struct partial_arg * a = ( struct partial_arg * ) v ;
std : : vector < struct partial > * partials = a - > partials ;
2016-03-25 19:20:32 +00:00
for ( size_t i = a - > task ; i < ( * partials ) . size ( ) ; i + = a - > tasks ) {
2016-02-11 20:22:22 +00:00
drawvec geom = ( * partials ) [ i ] . geoms [ 0 ] ; // XXX assumption of a single geometry at the beginning
( * partials ) [ i ] . geoms . clear ( ) ; // avoid keeping two copies in memory
2016-01-05 20:29:40 +00:00
signed char t = ( * partials ) [ i ] . t ;
int z = ( * partials ) [ i ] . z ;
int line_detail = ( * partials ) [ i ] . line_detail ;
2016-01-08 19:31:10 +00:00
int maxzoom = ( * partials ) [ i ] . maxzoom ;
2016-01-05 20:29:40 +00:00
2016-11-28 22:55:22 +00:00
if ( additional [ A_GRID_LOW_ZOOMS ] & & z < maxzoom ) {
geom = stairstep ( geom , z , line_detail ) ;
}
2016-05-05 20:39:21 +00:00
double area = 0 ;
if ( t = = VT_POLYGON ) {
area = get_area ( geom , 0 , geom . size ( ) ) ;
}
2016-11-28 22:55:22 +00:00
if ( ( t = = VT_LINE | | t = = VT_POLYGON ) & & ! ( prevent [ P_SIMPLIFY ] | | ( z = = maxzoom & & prevent [ P_SIMPLIFY_LOW ] ) | | ( z < maxzoom & & additional [ A_GRID_LOW_ZOOMS ] ) ) ) {
2016-01-07 19:35:11 +00:00
if ( 1 /* !reduced */ ) { // XXX why did this not simplify if reduced?
2016-01-05 20:29:40 +00:00
if ( t = = VT_LINE ) {
geom = remove_noop ( geom , t , 32 - z - line_detail ) ;
}
2016-09-23 20:06:37 +00:00
bool already_marked = false ;
2016-10-06 23:16:51 +00:00
if ( additional [ A_DETECT_SHARED_BORDERS ] & & t = = VT_POLYGON ) {
2016-09-23 20:06:37 +00:00
already_marked = true ;
}
2016-05-05 20:39:21 +00:00
2016-09-26 22:10:16 +00:00
if ( ! already_marked ) {
2016-11-14 19:22:21 +00:00
drawvec ngeom = simplify_lines ( geom , z , line_detail , ! ( prevent [ P_CLIPPING ] | | prevent [ P_DUPLICATION ] ) , ( * partials ) [ i ] . simplification , t = = VT_POLYGON ? 4 : 0 ) ;
2016-05-05 20:39:21 +00:00
2016-09-26 22:10:16 +00:00
if ( t ! = VT_POLYGON | | ngeom . size ( ) > = 3 ) {
geom = ngeom ;
}
2016-05-05 20:39:21 +00:00
}
2016-01-05 20:29:40 +00:00
}
}
#if 0
if ( t = = VT_LINE & & z ! = basezoom ) {
geom = shrink_lines ( geom , z , line_detail , basezoom , & along ) ;
}
# endif
2016-01-11 18:46:25 +00:00
if ( t = = VT_LINE & & additional [ A_REVERSE ] ) {
2016-01-05 20:29:40 +00:00
geom = reorder_lines ( geom ) ;
}
to_tile_scale ( geom , z , line_detail ) ;
2016-02-11 19:09:05 +00:00
std : : vector < drawvec > geoms ;
geoms . push_back ( geom ) ;
2016-02-11 20:14:32 +00:00
if ( t = = VT_POLYGON & & ! prevent [ P_POLYGON_SPLIT ] ) {
geoms = chop_polygon ( geoms ) ;
2016-02-11 19:09:05 +00:00
}
2016-01-05 20:29:40 +00:00
if ( t = = VT_POLYGON ) {
// Scaling may have made the polygon degenerate.
// Give Clipper a chance to try to fix it.
2016-05-03 22:48:42 +00:00
for ( size_t g = 0 ; g < geoms . size ( ) ; g + + ) {
2016-05-05 20:39:21 +00:00
drawvec before = geoms [ g ] ;
2016-05-03 22:48:42 +00:00
geoms [ g ] = clean_or_clip_poly ( geoms [ g ] , 0 , 0 , 0 , false ) ;
2016-03-18 23:31:56 +00:00
if ( additional [ A_DEBUG_POLYGON ] ) {
2016-05-03 22:48:42 +00:00
check_polygon ( geoms [ g ] , before ) ;
2016-03-18 23:31:56 +00:00
}
2016-05-05 20:39:21 +00:00
if ( geoms [ g ] . size ( ) < 3 ) {
2016-08-24 19:34:28 +00:00
if ( area > 0 ) {
geoms [ g ] = revive_polygon ( before , area / geoms . size ( ) , z , line_detail ) ;
} else {
geoms [ g ] . clear ( ) ;
}
2016-05-05 20:39:21 +00:00
}
2016-02-11 19:09:05 +00:00
}
2016-01-05 20:29:40 +00:00
}
// Worth skipping this if not coalescing anyway?
2016-02-11 19:09:05 +00:00
if ( geoms . size ( ) > 0 & & geoms [ 0 ] . size ( ) > 0 ) {
( * partials ) [ i ] . index = encode ( geoms [ 0 ] [ 0 ] . x , geoms [ 0 ] [ 0 ] . y ) ;
( * partials ) [ i ] . index2 = encode ( geoms [ 0 ] [ geoms [ 0 ] . size ( ) - 1 ] . x , geoms [ 0 ] [ geoms [ 0 ] . size ( ) - 1 ] . y ) ;
2016-01-05 20:29:40 +00:00
// Anything numbered below the start of the line
// can't possibly be the next feature.
// We want lowest-but-not-under.
if ( ( * partials ) [ i ] . index2 < ( * partials ) [ i ] . index ) {
( * partials ) [ i ] . index2 = ~ 0LL ;
}
} else {
( * partials ) [ i ] . index = 0 ;
( * partials ) [ i ] . index2 = 0 ;
}
2016-02-11 19:09:05 +00:00
( * partials ) [ i ] . geoms = geoms ;
2016-01-05 20:29:40 +00:00
}
return NULL ;
}
2016-02-03 23:20:45 +00:00
int manage_gap ( unsigned long long index , unsigned long long * previndex , double scale , double gamma , double * gap ) {
if ( gamma > 0 ) {
if ( * gap > 0 ) {
if ( index = = * previndex ) {
return 1 ; // Exact duplicate: can't fulfil the gap requirement
}
2016-04-27 23:41:41 +00:00
if ( index < * previndex | | std : : exp ( std : : log ( ( index - * previndex ) / scale ) * gamma ) > = * gap ) {
2016-02-03 23:20:45 +00:00
// Dot is further from the previous than the nth root of the gap,
// so produce it, and choose a new gap at the next point.
* gap = 0 ;
} else {
return 1 ;
}
2016-04-27 23:41:41 +00:00
} else if ( index > = * previndex ) {
2016-02-03 23:20:45 +00:00
* gap = ( index - * previndex ) / scale ;
if ( * gap = = 0 ) {
return 1 ; // Exact duplicate: skip
} else if ( * gap < 1 ) {
return 1 ; // Narrow dot spacing: need to stretch out
} else {
* gap = 0 ; // Wider spacing than minimum: so pass through unchanged
}
}
* previndex = index ;
}
return 0 ;
}
2016-09-26 20:39:16 +00:00
// Does not fix up moveto/lineto
static drawvec reverse_subring ( drawvec const & dv ) {
drawvec out ;
for ( size_t i = dv . size ( ) ; i > 0 ; i - - ) {
out . push_back ( dv [ i - 1 ] ) ;
}
return out ;
}
2016-09-29 21:58:38 +00:00
struct edge {
unsigned x1 ;
unsigned y1 ;
unsigned x2 ;
unsigned y2 ;
unsigned ring ;
edge ( unsigned _x1 , unsigned _y1 , unsigned _x2 , unsigned _y2 , unsigned _ring ) {
x1 = _x1 ;
y1 = _y1 ;
x2 = _x2 ;
y2 = _y2 ;
ring = _ring ;
}
bool operator < ( const edge & s ) const {
long long cmp = ( long long ) y1 - s . y1 ;
if ( cmp = = 0 ) {
cmp = ( long long ) x1 - s . x1 ;
}
if ( cmp = = 0 ) {
cmp = ( long long ) y2 - s . y2 ;
}
if ( cmp = = 0 ) {
cmp = ( long long ) x2 - s . x2 ;
}
return cmp < 0 ;
}
} ;
2016-10-14 19:27:24 +00:00
struct edgecmp_ring {
bool operator ( ) ( const edge & a , const edge & b ) {
long long cmp = ( long long ) a . y1 - b . y1 ;
if ( cmp = = 0 ) {
cmp = ( long long ) a . x1 - b . x1 ;
}
if ( cmp = = 0 ) {
cmp = ( long long ) a . y2 - b . y2 ;
}
if ( cmp = = 0 ) {
cmp = ( long long ) a . x2 - b . x2 ;
}
if ( cmp = = 0 ) {
cmp = ( long long ) a . ring - b . ring ;
}
return cmp < 0 ;
}
} edgecmp_ring ;
2016-09-29 21:58:38 +00:00
bool edges_same ( std : : pair < std : : vector < edge > : : iterator , std : : vector < edge > : : iterator > e1 , std : : pair < std : : vector < edge > : : iterator , std : : vector < edge > : : iterator > e2 ) {
if ( ( e2 . second - e2 . first ) ! = ( e1 . second - e1 . first ) ) {
return false ;
}
while ( e1 . first ! = e1 . second ) {
if ( e1 . first - > ring ! = e2 . first - > ring ) {
return false ;
}
+ + e1 . first ;
+ + e2 . first ;
}
return true ;
}
2016-10-24 23:27:00 +00:00
bool find_common_edges ( std : : vector < partial > & partials , int z , int line_detail , double simplification , int maxzoom , double merge_fraction ) {
size_t merge_count = ceil ( ( 1 - merge_fraction ) * partials . size ( ) ) ;
2016-09-24 00:52:18 +00:00
for ( size_t i = 0 ; i < partials . size ( ) ; i + + ) {
if ( partials [ i ] . t = = VT_POLYGON ) {
for ( size_t j = 0 ; j < partials [ i ] . geoms . size ( ) ; j + + ) {
drawvec & g = partials [ i ] . geoms [ j ] ;
drawvec out ;
for ( size_t k = 0 ; k < g . size ( ) ; k + + ) {
if ( g [ k ] . op = = VT_LINETO & & k > 0 & & g [ k - 1 ] = = g [ k ] ) {
;
} else {
out . push_back ( g [ k ] ) ;
}
}
partials [ i ] . geoms [ j ] = out ;
}
}
}
2016-09-23 20:06:37 +00:00
// Construct a mapping from all polygon edges to the set of rings
// that each edge appears in. (The ring number is across all polygons;
// we don't need to look it back up, just to tell where it changes.)
2016-09-29 21:58:38 +00:00
std : : vector < edge > edges ;
2016-09-23 20:06:37 +00:00
size_t ring = 0 ;
for ( size_t i = 0 ; i < partials . size ( ) ; i + + ) {
if ( partials [ i ] . t = = VT_POLYGON ) {
for ( size_t j = 0 ; j < partials [ i ] . geoms . size ( ) ; j + + ) {
for ( size_t k = 0 ; k + 1 < partials [ i ] . geoms [ j ] . size ( ) ; k + + ) {
if ( partials [ i ] . geoms [ j ] [ k ] . op = = VT_MOVETO ) {
ring + + ;
}
if ( partials [ i ] . geoms [ j ] [ k + 1 ] . op = = VT_LINETO ) {
drawvec dv ;
if ( partials [ i ] . geoms [ j ] [ k ] < partials [ i ] . geoms [ j ] [ k + 1 ] ) {
dv . push_back ( partials [ i ] . geoms [ j ] [ k ] ) ;
dv . push_back ( partials [ i ] . geoms [ j ] [ k + 1 ] ) ;
} else {
dv . push_back ( partials [ i ] . geoms [ j ] [ k + 1 ] ) ;
dv . push_back ( partials [ i ] . geoms [ j ] [ k ] ) ;
}
2016-09-29 21:58:38 +00:00
edges . push_back ( edge ( dv [ 0 ] . x , dv [ 0 ] . y , dv [ 1 ] . x , dv [ 1 ] . y , ring ) ) ;
2016-09-23 20:06:37 +00:00
}
}
}
}
}
2016-10-14 19:27:24 +00:00
std : : sort ( edges . begin ( ) , edges . end ( ) , edgecmp_ring ) ;
2016-09-26 21:00:55 +00:00
std : : set < draw > necessaries ;
2016-09-26 20:39:16 +00:00
2016-09-23 20:06:37 +00:00
// Now mark all the points where the set of rings using the edge on one side
// is not the same as the set of rings using the edge on the other side.
for ( size_t i = 0 ; i < partials . size ( ) ; i + + ) {
if ( partials [ i ] . t = = VT_POLYGON ) {
for ( size_t j = 0 ; j < partials [ i ] . geoms . size ( ) ; j + + ) {
2016-09-23 23:10:21 +00:00
drawvec & g = partials [ i ] . geoms [ j ] ;
for ( size_t k = 0 ; k < g . size ( ) ; k + + ) {
g [ k ] . necessary = 0 ;
2016-09-23 20:06:37 +00:00
}
2016-09-23 23:10:21 +00:00
for ( size_t a = 0 ; a < g . size ( ) ; a + + ) {
if ( g [ a ] . op = = VT_MOVETO ) {
size_t b ;
2016-09-23 20:06:37 +00:00
2016-09-23 23:10:21 +00:00
for ( b = a + 1 ; b < g . size ( ) ; b + + ) {
if ( g [ b ] . op ! = VT_LINETO ) {
break ;
}
2016-09-23 20:06:37 +00:00
}
2016-09-23 23:10:21 +00:00
// -1 because of duplication at the end
size_t s = b - a - 1 ;
2016-09-28 18:13:27 +00:00
if ( s > 0 ) {
drawvec left ;
if ( g [ a + ( 0 - 1 + s ) % s ] < g [ a + 0 ] ) {
left . push_back ( g [ a + ( 0 - 1 + s ) % s ] ) ;
left . push_back ( g [ a + 0 ] ) ;
2016-09-23 23:10:21 +00:00
} else {
2016-09-28 18:13:27 +00:00
left . push_back ( g [ a + 0 ] ) ;
left . push_back ( g [ a + ( 0 - 1 + s ) % s ] ) ;
2016-09-23 23:10:21 +00:00
}
if ( left [ 1 ] < left [ 0 ] ) {
fprintf ( stderr , " left misordered \n " ) ;
}
2016-09-29 21:58:38 +00:00
std : : pair < std : : vector < edge > : : iterator , std : : vector < edge > : : iterator > e1 = std : : equal_range ( edges . begin ( ) , edges . end ( ) , edge ( left [ 0 ] . x , left [ 0 ] . y , left [ 1 ] . x , left [ 1 ] . y , 0 ) ) ;
2016-09-28 18:13:27 +00:00
for ( size_t k = 0 ; k < s ; k + + ) {
drawvec right ;
if ( g [ a + k ] < g [ a + k + 1 ] ) {
right . push_back ( g [ a + k ] ) ;
right . push_back ( g [ a + k + 1 ] ) ;
} else {
right . push_back ( g [ a + k + 1 ] ) ;
right . push_back ( g [ a + k ] ) ;
}
2016-09-23 20:06:37 +00:00
2016-09-29 21:58:38 +00:00
std : : pair < std : : vector < edge > : : iterator , std : : vector < edge > : : iterator > e2 = std : : equal_range ( edges . begin ( ) , edges . end ( ) , edge ( right [ 0 ] . x , right [ 0 ] . y , right [ 1 ] . x , right [ 1 ] . y , 0 ) ) ;
2016-09-23 20:06:37 +00:00
2016-09-28 18:13:27 +00:00
if ( right [ 1 ] < right [ 0 ] ) {
fprintf ( stderr , " left misordered \n " ) ;
}
2016-09-29 21:58:38 +00:00
if ( e1 . first = = e1 . second | | e2 . first = = e2 . second ) {
2016-09-28 18:13:27 +00:00
fprintf ( stderr , " Internal error: polygon edge lookup failed for %lld,%lld to %lld,%lld or %lld,%lld to %lld,%lld \n " , left [ 0 ] . x , left [ 0 ] . y , left [ 1 ] . x , left [ 1 ] . y , right [ 0 ] . x , right [ 0 ] . y , right [ 1 ] . x , right [ 1 ] . y ) ;
exit ( EXIT_FAILURE ) ;
2016-09-23 20:06:37 +00:00
}
2016-09-23 23:10:21 +00:00
2016-09-29 21:58:38 +00:00
if ( ! edges_same ( e1 , e2 ) ) {
2016-09-28 18:13:27 +00:00
g [ a + k ] . necessary = 1 ;
necessaries . insert ( g [ a + k ] ) ;
}
2016-09-23 20:06:37 +00:00
2016-09-28 18:13:27 +00:00
e1 = e2 ;
2016-09-23 23:10:21 +00:00
}
2016-09-23 20:06:37 +00:00
}
2016-09-23 23:10:21 +00:00
a = b - 1 ;
2016-09-23 20:06:37 +00:00
}
}
2016-09-26 21:00:55 +00:00
}
}
}
2016-10-14 19:15:23 +00:00
edges . clear ( ) ;
std : : map < drawvec , size_t > arcs ;
2016-10-22 00:33:46 +00:00
std : : multimap < ssize_t , size_t > merge_candidates ; // from arc to partial
2016-09-28 18:13:27 +00:00
2016-09-26 21:00:55 +00:00
// Roll rings that include a necessary point around so they start at one
for ( size_t i = 0 ; i < partials . size ( ) ; i + + ) {
if ( partials [ i ] . t = = VT_POLYGON ) {
for ( size_t j = 0 ; j < partials [ i ] . geoms . size ( ) ; j + + ) {
drawvec & g = partials [ i ] . geoms [ j ] ;
2016-09-23 22:39:19 +00:00
2016-09-26 21:00:55 +00:00
for ( size_t k = 0 ; k < g . size ( ) ; k + + ) {
if ( necessaries . count ( g [ k ] ) ! = 0 ) {
g [ k ] . necessary = 1 ;
}
}
2016-09-23 22:39:19 +00:00
2016-09-23 23:10:21 +00:00
for ( size_t k = 0 ; k < g . size ( ) ; k + + ) {
if ( g [ k ] . op = = VT_MOVETO ) {
2016-09-23 22:39:19 +00:00
ssize_t necessary = - 1 ;
2016-09-24 01:03:57 +00:00
ssize_t lowest = k ;
2016-09-23 22:39:19 +00:00
size_t l ;
2016-09-23 23:10:21 +00:00
for ( l = k + 1 ; l < g . size ( ) ; l + + ) {
if ( g [ l ] . op ! = VT_LINETO ) {
2016-09-23 22:39:19 +00:00
break ;
}
2016-09-23 23:10:21 +00:00
if ( g [ l ] . necessary ) {
2016-09-23 22:39:19 +00:00
necessary = l ;
}
2016-09-24 01:03:57 +00:00
if ( g [ l ] < g [ lowest ] ) {
lowest = l ;
}
}
if ( necessary < 0 ) {
necessary = lowest ;
2016-09-26 20:39:16 +00:00
// Add a necessary marker if there was none in the ring,
// so the arc code below can find it.
g [ lowest ] . necessary = 1 ;
2016-09-23 22:39:19 +00:00
}
2016-09-26 20:39:16 +00:00
{
2016-09-23 22:39:19 +00:00
drawvec tmp ;
// l - 1 because the endpoint is duplicated
for ( size_t m = necessary ; m < l - 1 ; m + + ) {
2016-09-23 23:10:21 +00:00
tmp . push_back ( g [ m ] ) ;
2016-09-23 22:39:19 +00:00
}
2016-10-15 00:11:57 +00:00
for ( ssize_t m = k ; m < necessary ; m + + ) {
2016-09-23 23:10:21 +00:00
tmp . push_back ( g [ m ] ) ;
2016-09-23 22:39:19 +00:00
}
// replace the endpoint
2016-09-23 23:10:21 +00:00
tmp . push_back ( g [ necessary ] ) ;
2016-09-23 22:39:19 +00:00
if ( tmp . size ( ) ! = l - k ) {
fprintf ( stderr , " internal error shifting ring \n " ) ;
exit ( EXIT_FAILURE ) ;
}
for ( size_t m = 0 ; m < tmp . size ( ) ; m + + ) {
if ( m = = 0 ) {
tmp [ m ] . op = VT_MOVETO ;
} else {
tmp [ m ] . op = VT_LINETO ;
}
2016-09-23 23:10:21 +00:00
g [ k + m ] = tmp [ m ] ;
2016-09-23 22:39:19 +00:00
}
}
2016-09-26 20:39:16 +00:00
// Now peel off each set of segments from one necessary point to the next
// into an "arc" as in TopoJSON
for ( size_t m = k ; m < l ; m + + ) {
if ( ! g [ m ] . necessary ) {
fprintf ( stderr , " internal error in arc building \n " ) ;
exit ( EXIT_FAILURE ) ;
}
drawvec arc ;
size_t n ;
for ( n = m ; n < l ; n + + ) {
arc . push_back ( g [ n ] ) ;
if ( n > m & & g [ n ] . necessary ) {
break ;
}
}
auto f = arcs . find ( arc ) ;
if ( f = = arcs . end ( ) ) {
drawvec arc2 = reverse_subring ( arc ) ;
auto f2 = arcs . find ( arc2 ) ;
if ( f2 = = arcs . end ( ) ) {
// Add new arc
size_t added = arcs . size ( ) + 1 ;
arcs . insert ( std : : pair < drawvec , size_t > ( arc , added ) ) ;
partials [ i ] . arc_polygon . push_back ( added ) ;
2016-10-22 00:33:46 +00:00
merge_candidates . insert ( std : : pair < ssize_t , size_t > ( added , i ) ) ;
2016-09-26 20:39:16 +00:00
} else {
2016-09-27 05:45:44 +00:00
partials [ i ] . arc_polygon . push_back ( - f2 - > second ) ;
2016-10-22 00:33:46 +00:00
merge_candidates . insert ( std : : pair < ssize_t , size_t > ( - f2 - > second , i ) ) ;
2016-09-26 20:39:16 +00:00
}
} else {
partials [ i ] . arc_polygon . push_back ( f - > second ) ;
2016-10-22 00:33:46 +00:00
merge_candidates . insert ( std : : pair < ssize_t , size_t > ( f - > second , i ) ) ;
2016-09-26 20:39:16 +00:00
}
m = n - 1 ;
}
partials [ i ] . arc_polygon . push_back ( 0 ) ;
2016-09-23 22:39:19 +00:00
k = l - 1 ;
}
}
2016-09-23 20:06:37 +00:00
}
}
}
2016-09-26 22:10:16 +00:00
2016-10-24 22:33:14 +00:00
// Simplify each arc
2016-10-22 01:00:46 +00:00
std : : vector < drawvec > simplified_arcs ;
size_t count = 0 ;
for ( auto ai = arcs . begin ( ) ; ai ! = arcs . end ( ) ; + + ai ) {
if ( simplified_arcs . size ( ) < ai - > second + 1 ) {
simplified_arcs . resize ( ai - > second + 1 ) ;
}
drawvec dv = ai - > first ;
for ( size_t i = 0 ; i < dv . size ( ) ; i + + ) {
if ( i = = 0 ) {
dv [ i ] . op = VT_MOVETO ;
} else {
dv [ i ] . op = VT_LINETO ;
}
}
2016-11-28 22:55:22 +00:00
if ( ! ( prevent [ P_SIMPLIFY ] | | ( z = = maxzoom & & prevent [ P_SIMPLIFY_LOW ] ) | | ( z < maxzoom & & additional [ A_GRID_LOW_ZOOMS ] ) ) ) {
2016-11-14 19:22:21 +00:00
simplified_arcs [ ai - > second ] = simplify_lines ( dv , z , line_detail , ! ( prevent [ P_CLIPPING ] | | prevent [ P_DUPLICATION ] ) , simplification , 3 ) ;
2016-10-22 01:00:46 +00:00
} else {
simplified_arcs [ ai - > second ] = dv ;
}
count + + ;
}
2016-10-24 22:33:14 +00:00
// If necessary, merge some adjacent polygons into some other polygons
2016-10-25 00:58:26 +00:00
struct merge_order {
2016-10-25 21:13:55 +00:00
ssize_t edge ;
2016-10-25 00:58:26 +00:00
unsigned long long gap ;
size_t p1 ;
size_t p2 ;
bool operator < ( const merge_order & m ) const {
return gap < m . gap ;
}
} ;
std : : vector < merge_order > order ;
2016-10-25 21:13:55 +00:00
for ( ssize_t i = 0 ; i < ( ssize_t ) simplified_arcs . size ( ) ; i + + ) {
2016-10-25 00:58:26 +00:00
auto r1 = merge_candidates . equal_range ( i ) ;
for ( auto r1i = r1 . first ; r1i ! = r1 . second ; + + r1i ) {
auto r2 = merge_candidates . equal_range ( - i ) ;
for ( auto r2i = r2 . first ; r2i ! = r2 . second ; + + r2i ) {
if ( r1i - > second ! = r2i - > second ) {
merge_order mo ;
mo . edge = i ;
if ( partials [ r1i - > second ] . index > partials [ r2i - > second ] . index ) {
mo . gap = partials [ r1i - > second ] . index - partials [ r2i - > second ] . index ;
} else {
mo . gap = partials [ r2i - > second ] . index - partials [ r1i - > second ] . index ;
}
mo . p1 = r1i - > second ;
mo . p2 = r2i - > second ;
order . push_back ( mo ) ;
}
}
}
2016-10-24 23:27:00 +00:00
}
2016-10-25 00:58:26 +00:00
std : : sort ( order . begin ( ) , order . end ( ) ) ;
size_t merged = 0 ;
for ( size_t o = 0 ; o < order . size ( ) ; o + + ) {
2016-10-24 23:27:00 +00:00
if ( merged > = merge_count ) {
break ;
}
2016-10-25 00:58:26 +00:00
size_t i = order [ o ] . p1 ;
2016-10-25 17:01:18 +00:00
while ( partials [ i ] . renamed > = 0 ) {
i = partials [ i ] . renamed ;
}
size_t i2 = order [ o ] . p2 ;
while ( partials [ i2 ] . renamed > = 0 ) {
i2 = partials [ i2 ] . renamed ;
}
2016-10-25 00:58:26 +00:00
2016-10-24 23:27:00 +00:00
for ( size_t j = 0 ; j < partials [ i ] . arc_polygon . size ( ) & & merged < merge_count ; j + + ) {
2016-10-25 00:58:26 +00:00
if ( partials [ i ] . arc_polygon [ j ] = = order [ o ] . edge ) {
{
// XXX snap links
if ( partials [ order [ o ] . p2 ] . arc_polygon . size ( ) > 0 ) {
2016-10-22 00:33:46 +00:00
// This has to merge the ring that contains the anti-arc to this arc
// into the current ring, and then add whatever other rings were in
// that feature on to the end.
//
// This can't be good for keeping parent-child relationships among
// the rings in order, but Wagyu should sort that out later
std : : vector < ssize_t > additions ;
std : : vector < ssize_t > & here = partials [ i ] . arc_polygon ;
2016-10-25 17:01:18 +00:00
std : : vector < ssize_t > & other = partials [ i2 ] . arc_polygon ;
2016-10-22 01:00:46 +00:00
#if 0
printf ( " seeking %zd \n " , partials [ i ] . arc_polygon [ j ] ) ;
printf ( " before: " ) ;
for ( size_t k = 0 ; k < here . size ( ) ; k + + ) {
printf ( " %zd " , here [ k ] ) ;
}
printf ( " \n " ) ;
printf ( " other: " ) ;
for ( size_t k = 0 ; k < other . size ( ) ; k + + ) {
printf ( " %zd " , other [ k ] ) ;
}
printf ( " \n " ) ;
# endif
2016-10-22 00:33:46 +00:00
for ( size_t k = 0 ; k < other . size ( ) ; k + + ) {
size_t l ;
for ( l = k ; l < other . size ( ) ; l + + ) {
if ( other [ l ] = = 0 ) {
break ;
}
}
2016-10-22 01:00:46 +00:00
if ( l > = other . size ( ) ) {
l - - ;
}
#if 0
for ( size_t m = k ; m < = l ; m + + ) {
printf ( " %zd " , other [ m ] ) ;
}
printf ( " \n " ) ;
# endif
2016-10-22 00:33:46 +00:00
size_t m ;
for ( m = k ; m < = l ; m + + ) {
if ( other [ m ] = = - partials [ i ] . arc_polygon [ j ] ) {
break ;
}
}
2016-10-22 01:00:46 +00:00
if ( m < = l ) {
2016-10-22 00:33:46 +00:00
// Found the shared arc
here . erase ( here . begin ( ) + j ) ;
2016-10-22 01:00:46 +00:00
size_t off = 0 ;
2016-10-22 00:33:46 +00:00
for ( size_t n = m + 1 ; n < l ; n + + ) {
2016-10-22 01:00:46 +00:00
here . insert ( here . begin ( ) + j + off , other [ n ] ) ;
off + + ;
2016-10-22 00:33:46 +00:00
}
for ( size_t n = k ; n < m ; n + + ) {
2016-10-22 01:00:46 +00:00
here . insert ( here . begin ( ) + j + off , other [ n ] ) ;
off + + ;
2016-10-22 00:33:46 +00:00
}
} else {
// Looking at some other ring
for ( size_t n = k ; n < = l ; n + + ) {
additions . push_back ( other [ n ] ) ;
}
}
k = l ;
}
2016-10-25 17:01:18 +00:00
partials [ i2 ] . arc_polygon . clear ( ) ;
partials [ i2 ] . renamed = i ;
2016-10-24 23:27:00 +00:00
merged + + ;
2016-10-22 00:33:46 +00:00
for ( size_t k = 0 ; k < additions . size ( ) ; k + + ) {
partials [ i ] . arc_polygon . push_back ( additions [ k ] ) ;
}
2016-10-22 01:00:46 +00:00
#if 0
printf ( " after: " ) ;
for ( size_t k = 0 ; k < here . size ( ) ; k + + ) {
printf ( " %zd " , here [ k ] ) ;
}
printf ( " \n " ) ;
# endif
#if 0
for ( size_t k = 0 ; k + 1 < here . size ( ) ; k + + ) {
if ( here [ k ] ! = 0 & & here [ k + 1 ] ! = 0 ) {
if ( simplified_arcs [ here [ k + 1 ] ] [ 0 ] ! = simplified_arcs [ here [ k ] ] [ simplified_arcs [ here [ k ] ] . size ( ) - 1 ] ) {
printf ( " error from %zd to %zd \n " , here [ k ] , here [ k + 1 ] ) ;
}
}
}
# endif
2016-10-22 00:33:46 +00:00
}
}
}
}
}
2016-10-24 22:33:14 +00:00
// Turn the arc representations of the polygons back into standard polygon geometries
2016-09-26 22:10:16 +00:00
for ( size_t i = 0 ; i < partials . size ( ) ; i + + ) {
if ( partials [ i ] . t = = VT_POLYGON ) {
partials [ i ] . geoms . resize ( 0 ) ;
partials [ i ] . geoms . push_back ( drawvec ( ) ) ;
bool at_start = true ;
2016-09-27 17:55:53 +00:00
draw first ( - 1 , 0 , 0 ) ;
2016-09-26 22:10:16 +00:00
for ( size_t j = 0 ; j < partials [ i ] . arc_polygon . size ( ) ; j + + ) {
ssize_t p = partials [ i ] . arc_polygon [ j ] ;
if ( p = = 0 ) {
2016-09-27 17:55:53 +00:00
if ( first . op > = 0 ) {
partials [ i ] . geoms [ 0 ] . push_back ( first ) ;
first = draw ( - 1 , 0 , 0 ) ;
}
2016-09-26 22:10:16 +00:00
at_start = true ;
} else if ( p > 0 ) {
for ( size_t k = 0 ; k + 1 < simplified_arcs [ p ] . size ( ) ; k + + ) {
if ( at_start ) {
partials [ i ] . geoms [ 0 ] . push_back ( draw ( VT_MOVETO , simplified_arcs [ p ] [ k ] . x , simplified_arcs [ p ] [ k ] . y ) ) ;
2016-09-27 17:55:53 +00:00
first = draw ( VT_LINETO , simplified_arcs [ p ] [ k ] . x , simplified_arcs [ p ] [ k ] . y ) ;
2016-09-26 22:10:16 +00:00
} else {
partials [ i ] . geoms [ 0 ] . push_back ( draw ( VT_LINETO , simplified_arcs [ p ] [ k ] . x , simplified_arcs [ p ] [ k ] . y ) ) ;
}
at_start = 0 ;
}
} else { /* p < 0 */
for ( ssize_t k = simplified_arcs [ - p ] . size ( ) - 1 ; k > 0 ; k - - ) {
if ( at_start ) {
partials [ i ] . geoms [ 0 ] . push_back ( draw ( VT_MOVETO , simplified_arcs [ - p ] [ k ] . x , simplified_arcs [ - p ] [ k ] . y ) ) ;
2016-09-27 17:55:53 +00:00
first = draw ( VT_LINETO , simplified_arcs [ - p ] [ k ] . x , simplified_arcs [ - p ] [ k ] . y ) ;
2016-09-26 22:10:16 +00:00
} else {
partials [ i ] . geoms [ 0 ] . push_back ( draw ( VT_LINETO , simplified_arcs [ - p ] [ k ] . x , simplified_arcs [ - p ] [ k ] . y ) ) ;
}
at_start = 0 ;
}
}
}
}
}
2016-10-24 23:27:00 +00:00
if ( merged > = merge_count ) {
return true ;
} else {
return false ;
}
2016-09-23 20:06:37 +00:00
}
2016-11-02 19:49:31 +00:00
unsigned long long choose_mingap ( std : : vector < unsigned long long > const & indices , double f ) {
unsigned long long bot = ULLONG_MAX ;
unsigned long long top = 0 ;
for ( size_t i = 0 ; i < indices . size ( ) ; i + + ) {
if ( i > 0 & & indices [ i ] > = indices [ i - 1 ] ) {
if ( indices [ i ] - indices [ i - 1 ] > top ) {
top = indices [ i ] - indices [ i - 1 ] ;
}
if ( indices [ i ] - indices [ i - 1 ] < bot ) {
bot = indices [ i ] - indices [ i - 1 ] ;
}
}
}
size_t want = indices . size ( ) * f ;
while ( top - bot > 2 ) {
2016-11-02 23:57:35 +00:00
unsigned long long guess = bot / 2 + top / 2 ;
2016-11-02 19:49:31 +00:00
size_t count = 0 ;
2016-11-02 23:57:35 +00:00
unsigned long long prev = 0 ;
2016-11-02 19:49:31 +00:00
for ( size_t i = 0 ; i < indices . size ( ) ; i + + ) {
2016-11-02 23:57:35 +00:00
if ( indices [ i ] - prev > = guess ) {
2016-11-02 19:49:31 +00:00
count + + ;
2016-11-02 23:57:35 +00:00
prev = indices [ i ] ;
2016-11-02 19:49:31 +00:00
}
}
if ( count > want ) {
bot = guess ;
} else if ( count < want ) {
top = guess ;
} else {
return guess ;
}
}
return top ;
}
2016-11-10 00:32:40 +00:00
long long choose_minextent ( std : : vector < long long > & extents , double f ) {
std : : sort ( extents . begin ( ) , extents . end ( ) ) ;
return extents [ ( extents . size ( ) - 1 ) * ( 1 - f ) ] ;
}
2016-10-25 21:13:55 +00:00
struct write_tile_args {
struct task * tasks ;
char * metabase ;
char * stringpool ;
int min_detail ;
int basezoom ;
sqlite3 * outdb ;
double droprate ;
int buffer ;
const char * fname ;
FILE * * geomfile ;
double todo ;
volatile long long * along ;
double gamma ;
2016-10-26 17:40:53 +00:00
double gamma_out ;
2016-10-25 21:13:55 +00:00
int child_shards ;
int * geomfd ;
off_t * geom_size ;
volatile unsigned * midx ;
volatile unsigned * midy ;
int maxzoom ;
int minzoom ;
int full_detail ;
int low_detail ;
double simplification ;
volatile long long * most ;
long long * meta_off ;
long long * pool_off ;
unsigned * initial_x ;
unsigned * initial_y ;
volatile int * running ;
int err ;
std : : vector < std : : map < std : : string , layermap_entry > > * layermaps ;
std : : vector < std : : vector < std : : string > > * layer_unmaps ;
size_t pass ;
2016-11-04 00:13:11 +00:00
size_t passes ;
2016-10-25 23:28:32 +00:00
unsigned long long mingap ;
2016-10-26 17:40:53 +00:00
unsigned long long mingap_out ;
2016-11-10 00:32:40 +00:00
long long minextent ;
long long minextent_out ;
2016-11-04 19:26:13 +00:00
double fraction ;
double fraction_out ;
2016-12-08 23:13:38 +00:00
const char * prefilter ;
const char * postfilter ;
2016-10-25 21:13:55 +00:00
} ;
2016-12-08 23:13:38 +00:00
long long write_tile ( FILE * geoms , long long * geompos_in , char * metabase , char * stringpool , int z , unsigned tx , unsigned ty , int detail , int min_detail , int basezoom , sqlite3 * outdb , double droprate , int buffer , const char * fname , FILE * * geomfile , int minzoom , int maxzoom , double todo , volatile long long * along , long long alongminus , double gamma , int child_shards , long long * meta_off , long long * pool_off , unsigned * initial_x , unsigned * initial_y , volatile int * running , double simplification , std : : vector < std : : map < std : : string , layermap_entry > > * layermaps , std : : vector < std : : vector < std : : string > > * layer_unmaps , size_t pass , size_t passes , unsigned long long mingap , long long minextent , double fraction , const char * prefilter , const char * postfilter , write_tile_args * arg ) {
2014-10-07 17:27:17 +00:00
int line_detail ;
2016-10-24 23:27:00 +00:00
double merge_fraction = 1 ;
2016-10-25 23:28:32 +00:00
double mingap_fraction = 1 ;
2016-11-10 00:32:40 +00:00
double minextent_fraction = 1 ;
2014-09-22 22:41:13 +00:00
2016-04-11 22:59:02 +00:00
long long og = * geompos_in ;
2014-12-04 00:18:43 +00:00
2015-07-08 23:33:22 +00:00
// XXX is there a way to do this without floating point?
2016-04-26 23:56:24 +00:00
int max_zoom_increment = std : : log ( child_shards ) / std : : log ( 4 ) ;
2015-07-08 23:33:22 +00:00
if ( child_shards < 4 | | max_zoom_increment < 1 ) {
fprintf ( stderr , " Internal error: %d shards, max zoom increment %d \n " , child_shards , max_zoom_increment ) ;
exit ( EXIT_FAILURE ) ;
}
if ( ( ( ( child_shards - 1 ) < < 1 ) & child_shards ) ! = child_shards ) {
fprintf ( stderr , " Internal error: %d shards not a power of 2 \n " , child_shards ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-29 23:42:26 +00:00
int nextzoom = z + 1 ;
2015-12-15 20:00:05 +00:00
if ( nextzoom < minzoom ) {
if ( z + max_zoom_increment > minzoom ) {
nextzoom = minzoom ;
2015-06-29 23:42:26 +00:00
} else {
2015-07-08 23:33:22 +00:00
nextzoom = z + max_zoom_increment ;
2015-06-29 23:42:26 +00:00
}
}
2016-01-11 21:09:10 +00:00
static volatile double oprogress = 0 ;
2016-10-25 22:21:00 +00:00
bool has_polygons = false ;
2016-01-11 21:09:10 +00:00
2016-10-24 19:29:36 +00:00
bool first_time = true ;
2016-01-11 21:09:10 +00:00
// This only loops if the tile data didn't fit, in which case the detail
// goes down and the progress indicator goes backward for the next try.
for ( line_detail = detail ; line_detail > = min_detail | | line_detail = = detail ; line_detail - - , oprogress = 0 ) {
2014-10-07 17:27:17 +00:00
long long count = 0 ;
2014-10-07 22:37:55 +00:00
double accum_area = 0 ;
2014-09-23 21:42:17 +00:00
2015-03-06 18:56:02 +00:00
double interval = 0 ;
if ( z < basezoom ) {
2016-04-26 23:56:24 +00:00
interval = std : : exp ( std : : log ( droprate ) * ( basezoom - z ) ) ;
2015-03-06 18:56:02 +00:00
}
2015-05-20 21:57:00 +00:00
double fraction_accum = 0 ;
2016-10-24 23:27:00 +00:00
unsigned long long previndex = 0 , density_previndex = 0 , merge_previndex = 0 ;
2015-03-06 21:12:32 +00:00
double scale = ( double ) ( 1LL < < ( 64 - 2 * ( z + 8 ) ) ) ;
2016-05-27 23:25:40 +00:00
double gap = 0 , density_gap = 0 ;
double spacing = 0 ;
2015-03-06 21:12:32 +00:00
2015-06-05 17:23:25 +00:00
long long original_features = 0 ;
long long unclipped_features = 0 ;
2016-01-05 20:29:40 +00:00
std : : vector < struct partial > partials ;
2016-08-30 22:05:33 +00:00
std : : map < std : : string , std : : vector < coalesce > > layers ;
2016-10-25 23:28:32 +00:00
std : : vector < unsigned long long > indices ;
2016-11-10 00:32:40 +00:00
std : : vector < long long > extents ;
2014-09-22 23:27:10 +00:00
2015-07-08 23:33:22 +00:00
int within [ child_shards ] ;
long long geompos [ child_shards ] ;
memset ( within , ' \0 ' , sizeof ( within ) ) ;
memset ( geompos , ' \0 ' , sizeof ( geompos ) ) ;
2014-11-14 20:42:50 +00:00
2016-04-11 22:59:02 +00:00
if ( * geompos_in ! = og ) {
if ( fseek ( geoms , og , SEEK_SET ) ! = 0 ) {
perror ( " fseek geom " ) ;
exit ( EXIT_FAILURE ) ;
}
* geompos_in = og ;
}
2014-12-04 00:18:43 +00:00
2016-12-09 00:09:20 +00:00
int prefilter_write = - 1 , prefilter_read = - 1 ;
pid_t prefilter_pid = 0 ;
FILE * prefilter_fd = NULL ;
if ( prefilter ! = NULL ) {
setup_filter ( prefilter , & prefilter_write , & prefilter_read , & prefilter_pid , z , tx , ty ) ;
prefilter_fd = fdopen ( prefilter_write , " w " ) ;
if ( prefilter_fd = = NULL ) {
perror ( " freopen prefilter " ) ;
exit ( EXIT_FAILURE ) ;
}
}
2014-12-04 00:18:43 +00:00
while ( 1 ) {
2016-12-09 00:28:57 +00:00
serial_feature sf = deserialize_feature ( geoms , geompos_in , metabase , meta_off , z , tx , ty , initial_x , initial_y ) ;
if ( sf . t < 0 ) {
2014-12-04 00:18:43 +00:00
break ;
2014-11-12 23:57:45 +00:00
}
2014-10-27 19:56:51 +00:00
2016-11-04 00:13:11 +00:00
double progress = floor ( ( ( ( ( * geompos_in + * along - alongminus ) / ( double ) todo ) + ( pass - ( 2 - passes ) ) ) / passes + z ) / ( maxzoom + 1 ) * 1000 ) / 10 ;
2015-10-19 20:39:44 +00:00
if ( progress > = oprogress + 0.1 ) {
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " %3.1f%% %d/%u/%u \r " , progress , z , tx , ty ) ;
}
2014-12-18 01:08:04 +00:00
oprogress = progress ;
2014-12-18 00:01:33 +00:00
}
2015-06-05 17:23:25 +00:00
original_features + + ;
2016-12-09 00:28:57 +00:00
int quick = quick_check ( sf . bbox , z , line_detail , buffer ) ;
2014-12-11 21:34:50 +00:00
if ( quick = = 0 ) {
continue ;
}
2015-12-03 21:12:34 +00:00
if ( z = = 0 ) {
2016-12-09 00:28:57 +00:00
if ( sf . bbox [ 0 ] < 0 | | sf . bbox [ 2 ] > 1LL < < 32 ) {
2015-12-03 21:12:34 +00:00
// If the geometry extends off the edge of the world, concatenate on another copy
// shifted by 360 degrees, and then make sure both copies get clipped down to size.
2016-12-09 00:28:57 +00:00
size_t n = sf . geometry . size ( ) ;
2015-12-09 00:57:04 +00:00
2016-12-09 00:28:57 +00:00
if ( sf . bbox [ 0 ] < 0 ) {
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < n ; i + + ) {
2016-12-09 00:28:57 +00:00
sf . geometry . push_back ( draw ( sf . geometry [ i ] . op , sf . geometry [ i ] . x + ( 1LL < < 32 ) , sf . geometry [ i ] . y ) ) ;
2015-12-09 00:57:04 +00:00
}
2015-12-03 21:12:34 +00:00
}
2015-12-09 00:57:04 +00:00
2016-12-09 00:28:57 +00:00
if ( sf . bbox [ 2 ] > 1LL < < 32 ) {
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < n ; i + + ) {
2016-12-09 00:28:57 +00:00
sf . geometry . push_back ( draw ( sf . geometry [ i ] . op , sf . geometry [ i ] . x - ( 1LL < < 32 ) , sf . geometry [ i ] . y ) ) ;
2015-12-09 00:57:04 +00:00
}
2015-12-03 21:12:34 +00:00
}
2016-12-09 00:28:57 +00:00
sf . bbox [ 0 ] = 0 ;
sf . bbox [ 2 ] = 1LL < < 32 ;
2015-12-03 21:12:34 +00:00
quick = - 1 ;
}
}
2016-04-20 22:00:32 +00:00
// Can't accept the quick check if guaranteeing no duplication, since the
// overlap might have been in the buffer.
if ( quick ! = 1 | | prevent [ P_DUPLICATION ] ) {
2016-04-19 22:32:58 +00:00
drawvec clipped ;
// Do the clipping, even if we are going to include the whole feature,
// so that we can know whether the feature itself, or only the feature's
// bounding box, touches the tile.
2016-12-09 00:28:57 +00:00
if ( sf . t = = VT_LINE ) {
clipped = clip_lines ( sf . geometry , z , line_detail , buffer ) ;
2014-12-11 21:34:50 +00:00
}
2016-12-09 00:28:57 +00:00
if ( sf . t = = VT_POLYGON ) {
clipped = simple_clip_poly ( sf . geometry , z , line_detail , buffer ) ;
2014-12-11 21:34:50 +00:00
}
2016-12-09 00:28:57 +00:00
if ( sf . t = = VT_POINT ) {
clipped = clip_point ( sf . geometry , z , line_detail , buffer ) ;
2014-12-11 21:34:50 +00:00
}
2014-12-04 00:18:43 +00:00
2016-12-09 00:28:57 +00:00
clipped = remove_noop ( clipped , sf . t , 0 ) ;
2016-04-19 22:32:58 +00:00
// Must clip at z0 even if we don't want clipping, to handle features
// that are duplicated across the date line
2016-04-20 22:00:32 +00:00
if ( prevent [ P_DUPLICATION ] & & z ! = 0 ) {
2016-12-09 00:28:57 +00:00
if ( point_within_tile ( ( sf . bbox [ 0 ] + sf . bbox [ 2 ] ) / 2 , ( sf . bbox [ 1 ] + sf . bbox [ 3 ] ) / 2 , z , line_detail , buffer ) ) {
// sf.geometry is unchanged
2016-04-20 22:00:32 +00:00
} else {
2016-12-09 00:28:57 +00:00
sf . geometry . clear ( ) ;
2016-04-20 22:00:32 +00:00
}
} else if ( prevent [ P_CLIPPING ] & & z ! = 0 ) {
2016-04-19 22:32:58 +00:00
if ( clipped . size ( ) = = 0 ) {
2016-12-09 00:28:57 +00:00
sf . geometry . clear ( ) ;
2016-04-19 22:32:58 +00:00
} else {
2016-12-09 00:28:57 +00:00
// sf.geometry is unchanged
2016-04-19 22:32:58 +00:00
}
} else {
2016-12-09 00:28:57 +00:00
sf . geometry = clipped ;
2016-04-19 22:32:58 +00:00
}
2014-12-12 00:08:53 +00:00
}
2014-12-04 00:18:43 +00:00
2016-12-09 00:28:57 +00:00
if ( sf . geometry . size ( ) > 0 ) {
2015-06-05 17:23:25 +00:00
unclipped_features + + ;
}
2016-10-25 21:13:55 +00:00
if ( first_time & & pass = = 1 ) { /* only write out the next zoom once, even if we retry */
2016-12-09 00:28:57 +00:00
rewrite ( sf . geometry , z , nextzoom , maxzoom , sf . bbox , tx , ty , buffer , line_detail , within , geompos , geomfile , fname , sf . t , sf . layer , sf . metapos , sf . feature_minzoom , child_shards , max_zoom_increment , sf . seq , sf . tippecanoe_minzoom , sf . tippecanoe_maxzoom , sf . segment , initial_x , initial_y , sf . m , sf . keys , sf . values , sf . has_id , sf . id , sf . index , sf . extent ) ;
2014-12-04 00:18:43 +00:00
}
2015-12-15 20:00:05 +00:00
if ( z < minzoom ) {
2014-12-17 19:05:14 +00:00
continue ;
}
2016-12-09 00:28:57 +00:00
if ( sf . tippecanoe_minzoom ! = - 1 & & z < sf . tippecanoe_minzoom ) {
2015-10-06 23:51:23 +00:00
continue ;
}
2016-12-09 00:28:57 +00:00
if ( sf . tippecanoe_maxzoom ! = - 1 & & z > sf . tippecanoe_maxzoom ) {
2015-10-06 23:51:23 +00:00
continue ;
}
2016-12-09 00:28:57 +00:00
if ( sf . tippecanoe_minzoom = = - 1 & & z < sf . feature_minzoom ) {
2014-12-04 00:18:43 +00:00
continue ;
}
2016-12-08 23:13:38 +00:00
if ( prefilter ! = NULL ) {
mvt_layer tmp_layer ;
tmp_layer . extent = 1LL < < 32 ;
2016-12-09 00:28:57 +00:00
tmp_layer . name = ( * layer_unmaps ) [ sf . segment ] [ sf . layer ] ;
2016-12-08 23:13:38 +00:00
mvt_feature tmp_feature ;
2016-12-09 00:28:57 +00:00
tmp_feature . type = sf . t ;
tmp_feature . geometry = to_feature ( sf . geometry ) ;
tmp_feature . id = sf . id ;
tmp_feature . has_id = sf . has_id ;
2016-12-08 23:13:38 +00:00
// Offset from tile coordinates back to world coordinates
unsigned sx = 0 , sy = 0 ;
if ( z ! = 0 ) {
sx = tx < < ( 32 - z ) ;
sy = ty < < ( 32 - z ) ;
}
for ( size_t i = 0 ; i < tmp_feature . geometry . size ( ) ; i + + ) {
tmp_feature . geometry [ i ] . x + = sx ;
tmp_feature . geometry [ i ] . y + = sy ;
}
2016-12-09 00:28:57 +00:00
decode_meta ( sf . m , sf . keys , sf . values , stringpool + pool_off [ sf . segment ] , tmp_layer , tmp_feature ) ;
2016-12-08 23:13:38 +00:00
tmp_layer . features . push_back ( tmp_feature ) ;
2016-12-09 00:09:20 +00:00
layer_to_geojson ( prefilter_fd , tmp_layer , 0 , 0 , 0 , false , true ) ;
2016-12-08 23:13:38 +00:00
}
2016-10-11 00:15:33 +00:00
if ( gamma > 0 ) {
2016-12-09 00:28:57 +00:00
if ( manage_gap ( sf . index , & previndex , scale , gamma , & gap ) ) {
2015-03-06 18:56:02 +00:00
continue ;
}
}
2016-11-17 20:40:11 +00:00
if ( additional [ A_DROP_DENSEST_AS_NEEDED ] ) {
2016-12-09 00:28:57 +00:00
indices . push_back ( sf . index ) ;
if ( sf . index - merge_previndex < mingap ) {
2016-10-25 23:28:32 +00:00
continue ;
}
}
2016-11-10 00:32:40 +00:00
if ( additional [ A_DROP_SMALLEST_AS_NEEDED ] ) {
2016-12-09 00:28:57 +00:00
extents . push_back ( sf . extent ) ;
if ( sf . extent < = minextent & & sf . t ! = VT_POINT ) {
2016-11-10 00:32:40 +00:00
continue ;
}
}
2016-10-25 23:28:32 +00:00
2016-05-27 23:25:40 +00:00
if ( additional [ A_CALCULATE_FEATURE_DENSITY ] ) {
// Gamma is always 1 for this calculation so there is a reasonable
// interpretation when no features are being dropped.
// The spacing is only calculated if a feature would be retained by
// that standard, so that duplicates aren't reported as infinitely dense.
double o_density_previndex = density_previndex ;
2016-12-09 00:28:57 +00:00
if ( ! manage_gap ( sf . index , & density_previndex , scale , 1 , & density_gap ) ) {
spacing = ( sf . index - o_density_previndex ) / scale ;
2016-05-27 23:25:40 +00:00
}
}
2015-05-20 21:57:00 +00:00
fraction_accum + = fraction ;
if ( fraction_accum < 1 ) {
continue ;
}
fraction_accum - = 1 ;
2014-12-04 00:18:43 +00:00
bool reduced = false ;
2016-12-09 00:28:57 +00:00
if ( sf . t = = VT_POLYGON ) {
2016-11-28 22:55:22 +00:00
if ( ! prevent [ P_TINY_POLYGON_REDUCTION ] & & ! additional [ A_GRID_LOW_ZOOMS ] ) {
2016-12-09 00:28:57 +00:00
sf . geometry = reduce_tiny_poly ( sf . geometry , z , line_detail , & reduced , & accum_area ) ;
2016-11-21 19:26:37 +00:00
}
2016-10-25 22:21:00 +00:00
has_polygons = true ;
2014-12-04 00:18:43 +00:00
}
2014-10-03 23:33:22 +00:00
2016-12-09 00:28:57 +00:00
if ( sf . geometry . size ( ) > 0 ) {
2016-01-05 20:29:40 +00:00
partial p ;
2016-12-09 00:28:57 +00:00
p . geoms . push_back ( sf . geometry ) ;
p . layer = sf . layer ;
p . m = sf . m ;
p . t = sf . t ;
p . segment = sf . segment ;
p . original_seq = sf . seq ;
2016-01-05 20:29:40 +00:00
p . reduced = reduced ;
p . z = z ;
p . line_detail = line_detail ;
2016-01-08 19:31:10 +00:00
p . maxzoom = maxzoom ;
2016-12-09 00:28:57 +00:00
p . keys = sf . keys ;
p . values = sf . values ;
2016-05-27 23:25:40 +00:00
p . spacing = spacing ;
2016-07-12 23:51:56 +00:00
p . simplification = simplification ;
2016-12-09 00:28:57 +00:00
p . id = sf . id ;
p . has_id = sf . has_id ;
2016-10-24 23:27:00 +00:00
p . index2 = merge_previndex ;
2016-12-09 00:28:57 +00:00
p . index = sf . index ;
2016-10-25 17:01:18 +00:00
p . renamed = - 1 ;
2016-01-05 20:29:40 +00:00
partials . push_back ( p ) ;
2014-10-07 17:27:17 +00:00
}
2016-10-24 23:27:00 +00:00
2016-12-09 00:28:57 +00:00
merge_previndex = sf . index ;
2016-01-05 20:29:40 +00:00
}
2014-09-24 23:51:53 +00:00
2016-12-09 00:09:20 +00:00
if ( prefilter ! = NULL ) {
if ( fclose ( prefilter_fd ) ! = 0 ) {
perror ( " fclose output to prefilter " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( close ( prefilter_read ) ! = 0 ) {
perror ( " close output from prefilter " ) ;
exit ( EXIT_FAILURE ) ;
}
while ( 1 ) {
int stat_loc ;
if ( waitpid ( prefilter_pid , & stat_loc , 0 ) < 0 ) {
perror ( " waitpid for prefilter \n " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( WIFEXITED ( stat_loc ) | | WIFSIGNALED ( stat_loc ) ) {
break ;
}
}
}
2016-10-24 19:29:36 +00:00
first_time = false ;
2016-10-24 23:27:00 +00:00
bool merge_successful = true ;
2016-10-24 19:29:36 +00:00
2016-10-24 23:27:00 +00:00
if ( additional [ A_DETECT_SHARED_BORDERS ] | | ( additional [ A_MERGE_POLYGONS_AS_NEEDED ] & & merge_fraction < 1 ) ) {
merge_successful = find_common_edges ( partials , z , line_detail , simplification , maxzoom , merge_fraction ) ;
2016-09-23 20:06:37 +00:00
}
2016-01-05 21:56:36 +00:00
int tasks = ceil ( ( double ) CPUS / * running ) ;
2016-01-05 20:29:40 +00:00
if ( tasks < 1 ) {
tasks = 1 ;
}
2014-09-24 21:58:26 +00:00
2016-01-05 20:29:40 +00:00
pthread_t pthreads [ tasks ] ;
partial_arg args [ tasks ] ;
for ( int i = 0 ; i < tasks ; i + + ) {
args [ i ] . task = i ;
args [ i ] . tasks = tasks ;
args [ i ] . partials = & partials ;
if ( tasks > 1 ) {
if ( pthread_create ( & pthreads [ i ] , NULL , partial_feature_worker , & args [ i ] ) ! = 0 ) {
perror ( " pthread_create " ) ;
exit ( EXIT_FAILURE ) ;
}
} else {
partial_feature_worker ( & args [ i ] ) ;
2014-10-21 23:09:51 +00:00
}
2016-01-05 20:29:40 +00:00
}
2014-10-21 23:09:51 +00:00
2016-01-05 20:29:40 +00:00
if ( tasks > 1 ) {
for ( int i = 0 ; i < tasks ; i + + ) {
void * retval ;
2014-09-24 21:14:43 +00:00
2016-01-05 20:29:40 +00:00
if ( pthread_join ( pthreads [ i ] , & retval ) ! = 0 ) {
perror ( " pthread_join " ) ;
}
2015-10-16 00:11:29 +00:00
}
2016-01-05 20:29:40 +00:00
}
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < partials . size ( ) ; i + + ) {
2016-05-11 21:23:39 +00:00
std : : vector < drawvec > & pgeoms = partials [ i ] . geoms ;
2016-01-05 20:29:40 +00:00
signed char t = partials [ i ] . t ;
long long original_seq = partials [ i ] . original_seq ;
2015-10-16 00:11:29 +00:00
2016-02-11 19:09:05 +00:00
// A complex polygon may have been split up into multiple geometries.
// Break them out into multiple features if necessary.
2016-05-03 22:48:42 +00:00
for ( size_t j = 0 ; j < pgeoms . size ( ) ; j + + ) {
if ( t = = VT_POINT | | draws_something ( pgeoms [ j ] ) ) {
2016-02-11 19:09:05 +00:00
struct coalesce c ;
c . type = t ;
c . index = partials [ i ] . index ;
c . index2 = partials [ i ] . index2 ;
2016-05-03 22:48:42 +00:00
c . geom = pgeoms [ j ] ;
2016-05-11 21:23:39 +00:00
pgeoms [ j ] . clear ( ) ;
2016-02-11 19:09:05 +00:00
c . coalesced = false ;
c . original_seq = original_seq ;
2016-04-25 23:19:52 +00:00
c . m = partials [ i ] . m ;
2016-04-25 23:52:20 +00:00
c . stringpool = stringpool + pool_off [ partials [ i ] . segment ] ;
2016-05-10 22:30:49 +00:00
c . keys = partials [ i ] . keys ;
c . values = partials [ i ] . values ;
2016-05-27 23:25:40 +00:00
c . spacing = partials [ i ] . spacing ;
2016-07-15 22:00:40 +00:00
c . id = partials [ i ] . id ;
c . has_id = partials [ i ] . has_id ;
2016-02-11 19:09:05 +00:00
2016-08-30 21:38:30 +00:00
// printf("segment %d layer %lld is %s\n", partials[i].segment, partials[i].layer, (*layer_unmaps)[partials[i].segment][partials[i].layer].c_str());
2016-08-30 21:59:53 +00:00
std : : string layername = ( * layer_unmaps ) [ partials [ i ] . segment ] [ partials [ i ] . layer ] ;
2016-08-30 22:05:33 +00:00
if ( layers . count ( layername ) = = 0 ) {
layers . insert ( std : : pair < std : : string , std : : vector < coalesce > > ( layername , std : : vector < coalesce > ( ) ) ) ;
2016-08-30 21:59:53 +00:00
}
2016-08-30 22:05:33 +00:00
auto l = layers . find ( layername ) ;
l - > second . push_back ( c ) ;
2016-02-11 19:09:05 +00:00
}
2014-10-07 17:27:17 +00:00
}
2014-09-22 23:27:10 +00:00
}
2016-05-11 21:23:39 +00:00
partials . clear ( ) ;
2014-12-11 23:46:54 +00:00
int j ;
2015-07-08 23:33:22 +00:00
for ( j = 0 ; j < child_shards ; j + + ) {
2014-12-11 23:46:54 +00:00
if ( within [ j ] ) {
2015-03-24 00:44:23 +00:00
serialize_byte ( geomfile [ j ] , - 2 , & geompos [ j ] , fname ) ;
2014-12-11 23:46:54 +00:00
within [ j ] = 0 ;
}
2014-12-04 00:18:43 +00:00
}
2016-08-30 22:05:33 +00:00
for ( auto layer_iterator = layers . begin ( ) ; layer_iterator ! = layers . end ( ) ; + + layer_iterator ) {
std : : vector < coalesce > & layer_features = layer_iterator - > second ;
2016-08-30 21:59:53 +00:00
2016-01-11 18:46:25 +00:00
if ( additional [ A_REORDER ] ) {
2016-08-30 22:05:33 +00:00
std : : sort ( layer_features . begin ( ) , layer_features . end ( ) ) ;
2015-04-21 15:19:51 +00:00
}
2015-03-23 18:36:35 +00:00
std : : vector < coalesce > out ;
2016-08-30 22:05:33 +00:00
if ( layer_features . size ( ) > 0 ) {
out . push_back ( layer_features [ 0 ] ) ;
2016-04-27 18:13:15 +00:00
}
2016-08-30 22:05:33 +00:00
for ( size_t x = 1 ; x < layer_features . size ( ) ; x + + ) {
2016-03-25 19:20:32 +00:00
size_t y = out . size ( ) - 1 ;
2014-09-29 22:33:14 +00:00
2015-04-21 15:19:51 +00:00
#if 0
2016-08-30 22:05:33 +00:00
if ( out . size ( ) > 0 & & coalcmp ( & layer_features [ x ] , & out [ y ] ) < 0 ) {
2015-03-23 18:36:35 +00:00
fprintf ( stderr , " \n feature out of order \n " ) ;
}
2015-04-21 15:19:51 +00:00
# endif
2014-09-30 22:53:45 +00:00
2016-08-30 22:05:33 +00:00
if ( additional [ A_COALESCE ] & & out . size ( ) > 0 & & out [ y ] . geom . size ( ) + layer_features [ x ] . geom . size ( ) < 700 & & coalcmp ( & layer_features [ x ] , & out [ y ] ) = = 0 & & layer_features [ x ] . type ! = VT_POINT ) {
for ( size_t g = 0 ; g < layer_features [ x ] . geom . size ( ) ; g + + ) {
out [ y ] . geom . push_back ( layer_features [ x ] . geom [ g ] ) ;
2015-03-23 18:36:35 +00:00
}
out [ y ] . coalesced = true ;
} else {
2016-08-30 22:05:33 +00:00
out . push_back ( layer_features [ x ] ) ;
2015-03-23 18:36:35 +00:00
}
2014-10-07 17:27:17 +00:00
}
2016-02-11 19:09:05 +00:00
2016-08-30 22:05:33 +00:00
layer_features = out ;
2014-10-01 00:18:23 +00:00
2015-12-11 20:31:10 +00:00
out . clear ( ) ;
2016-08-30 22:05:33 +00:00
for ( size_t x = 0 ; x < layer_features . size ( ) ; x + + ) {
if ( layer_features [ x ] . coalesced & & layer_features [ x ] . type = = VT_LINE ) {
layer_features [ x ] . geom = remove_noop ( layer_features [ x ] . geom , layer_features [ x ] . type , 0 ) ;
layer_features [ x ] . geom = simplify_lines ( layer_features [ x ] . geom , 32 , 0 ,
2016-11-14 19:22:21 +00:00
! ( prevent [ P_CLIPPING ] | | prevent [ P_DUPLICATION ] ) , simplification , layer_features [ x ] . type = = VT_POLYGON ? 4 : 0 ) ;
2014-10-07 17:27:17 +00:00
}
2015-12-11 20:31:10 +00:00
2016-08-30 22:05:33 +00:00
if ( layer_features [ x ] . type = = VT_POLYGON ) {
if ( layer_features [ x ] . coalesced ) {
layer_features [ x ] . geom = clean_or_clip_poly ( layer_features [ x ] . geom , 0 , 0 , 0 , false ) ;
2016-04-18 22:46:07 +00:00
}
2016-08-30 22:05:33 +00:00
layer_features [ x ] . geom = close_poly ( layer_features [ x ] . geom ) ;
2014-10-07 17:27:17 +00:00
}
2015-12-11 20:31:10 +00:00
2016-08-30 22:05:33 +00:00
if ( layer_features [ x ] . geom . size ( ) > 0 ) {
out . push_back ( layer_features [ x ] ) ;
2015-12-11 20:31:10 +00:00
}
2014-09-30 22:53:45 +00:00
}
2016-08-30 22:05:33 +00:00
layer_features = out ;
2015-09-14 22:42:06 +00:00
2016-01-11 18:46:25 +00:00
if ( prevent [ P_INPUT_ORDER ] ) {
2016-08-30 22:05:33 +00:00
std : : sort ( layer_features . begin ( ) , layer_features . end ( ) , preservecmp ) ;
2015-09-14 22:42:06 +00:00
}
2014-09-29 22:33:14 +00:00
}
2014-09-30 00:32:01 +00:00
2016-04-25 23:19:52 +00:00
mvt_tile tile ;
2016-08-30 22:05:33 +00:00
for ( auto layer_iterator = layers . begin ( ) ; layer_iterator ! = layers . end ( ) ; + + layer_iterator ) {
std : : vector < coalesce > & layer_features = layer_iterator - > second ;
2016-04-25 23:19:52 +00:00
2016-08-30 21:59:53 +00:00
mvt_layer layer ;
2016-08-30 22:05:33 +00:00
layer . name = layer_iterator - > first ;
2016-04-25 23:52:20 +00:00
layer . version = 2 ;
layer . extent = 1 < < line_detail ;
2016-04-25 23:19:52 +00:00
2016-08-30 22:05:33 +00:00
for ( size_t x = 0 ; x < layer_features . size ( ) ; x + + ) {
2016-04-25 23:52:20 +00:00
mvt_feature feature ;
2016-04-25 23:19:52 +00:00
2016-08-30 22:05:33 +00:00
if ( layer_features [ x ] . type = = VT_LINE | | layer_features [ x ] . type = = VT_POLYGON ) {
layer_features [ x ] . geom = remove_noop ( layer_features [ x ] . geom , layer_features [ x ] . type , 0 ) ;
2016-04-25 23:19:52 +00:00
}
2016-08-30 22:05:33 +00:00
if ( layer_features [ x ] . geom . size ( ) = = 0 ) {
2016-07-12 00:45:12 +00:00
continue ;
}
2016-08-30 22:05:33 +00:00
feature . type = layer_features [ x ] . type ;
feature . geometry = to_feature ( layer_features [ x ] . geom ) ;
count + = layer_features [ x ] . geom . size ( ) ;
layer_features [ x ] . geom . clear ( ) ;
2016-04-25 23:19:52 +00:00
2016-08-30 22:05:33 +00:00
feature . id = layer_features [ x ] . id ;
feature . has_id = layer_features [ x ] . has_id ;
2016-07-15 22:00:40 +00:00
2016-08-30 22:05:33 +00:00
decode_meta ( layer_features [ x ] . m , layer_features [ x ] . keys , layer_features [ x ] . values , layer_features [ x ] . stringpool , layer , feature ) ;
2016-05-27 23:25:40 +00:00
if ( additional [ A_CALCULATE_FEATURE_DENSITY ] ) {
int glow = 255 ;
2016-08-30 22:05:33 +00:00
if ( layer_features [ x ] . spacing > 0 ) {
glow = ( 1 / layer_features [ x ] . spacing ) ;
2016-05-27 23:25:40 +00:00
if ( glow > 255 ) {
glow = 255 ;
}
}
mvt_value v ;
v . type = mvt_sint ;
v . numeric_value . sint_value = glow ;
layer . tag ( feature , " tippecanoe_feature_density " , v ) ;
}
2016-04-25 23:52:20 +00:00
layer . features . push_back ( feature ) ;
2016-04-25 23:19:52 +00:00
}
2016-12-08 23:13:38 +00:00
if ( postfilter ! = NULL ) {
layer = filter_layer ( postfilter , layer , z , tx , ty ) ;
2016-12-07 20:15:57 +00:00
}
2016-04-25 23:52:20 +00:00
if ( layer . features . size ( ) > 0 ) {
tile . layers . push_back ( layer ) ;
2016-04-25 23:19:52 +00:00
}
}
2015-06-05 17:23:25 +00:00
if ( z = = 0 & & unclipped_features < original_features / 2 ) {
fprintf ( stderr , " \n \n More than half the features were clipped away at zoom level 0. \n " ) ;
2015-06-05 17:34:19 +00:00
fprintf ( stderr , " Is your data in the wrong projection? It should be in WGS84/EPSG:4326. \n " ) ;
2015-06-05 17:23:25 +00:00
}
2015-03-23 18:36:35 +00:00
long long totalsize = 0 ;
2016-08-30 22:05:33 +00:00
for ( auto layer_iterator = layers . begin ( ) ; layer_iterator ! = layers . end ( ) ; + + layer_iterator ) {
std : : vector < coalesce > & layer_features = layer_iterator - > second ;
totalsize + = layer_features . size ( ) ;
2014-10-18 18:40:09 +00:00
}
2016-11-04 00:13:11 +00:00
double progress = floor ( ( ( ( ( * geompos_in + * along - alongminus ) / ( double ) todo ) + ( pass - ( 2 - passes ) ) ) / passes + z ) / ( maxzoom + 1 ) * 1000 ) / 10 ;
2016-07-08 22:49:59 +00:00
if ( progress > = oprogress + 0.1 ) {
if ( ! quiet ) {
fprintf ( stderr , " %3.1f%% %d/%u/%u \r " , progress , z , tx , ty ) ;
}
oprogress = progress ;
}
2016-07-12 22:56:57 +00:00
if ( totalsize > 0 & & tile . layers . size ( ) > 0 ) {
2016-01-11 18:46:25 +00:00
if ( totalsize > 200000 & & ! prevent [ P_FEATURE_LIMIT ] ) {
2015-03-23 18:36:35 +00:00
fprintf ( stderr , " tile %d/%u/%u has %lld features, >200000 \n " , z , tx , ty , totalsize ) ;
2016-10-24 19:29:36 +00:00
2016-10-25 22:21:00 +00:00
if ( has_polygons & & additional [ A_MERGE_POLYGONS_AS_NEEDED ] & & merge_fraction > .05 & & merge_successful ) {
merge_fraction = merge_fraction * 200000 / tile . layers . size ( ) * 0.95 ;
2016-10-24 19:29:36 +00:00
if ( ! quiet ) {
2016-10-25 22:21:00 +00:00
fprintf ( stderr , " Going to try merging %0.2f%% of the polygons to make it fit \n " , 100 - merge_fraction * 100 ) ;
2016-10-24 19:29:36 +00:00
}
line_detail + + ; // to keep it the same when the loop decrements it
continue ;
2016-10-24 22:33:14 +00:00
} else if ( additional [ A_INCREASE_GAMMA_AS_NEEDED ] & & gamma < 10 ) {
2016-10-24 19:29:36 +00:00
if ( gamma < 1 ) {
gamma = 1 ;
} else {
gamma = gamma * 1.25 ;
}
2016-10-26 17:40:53 +00:00
if ( gamma > arg - > gamma_out ) {
arg - > gamma_out = gamma ;
}
2016-10-25 21:13:55 +00:00
2016-10-24 19:29:36 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Going to try gamma of %0.3f to make it fit \n " , gamma ) ;
}
line_detail + + ; // to keep it the same when the loop decrements it
continue ;
2016-11-17 20:40:11 +00:00
} else if ( additional [ A_DROP_DENSEST_AS_NEEDED ] ) {
2016-11-02 23:57:35 +00:00
mingap_fraction = mingap_fraction * 200000.0 / totalsize * 0.90 ;
2016-11-04 00:49:32 +00:00
mingap = choose_mingap ( indices , mingap_fraction ) ;
if ( mingap > arg - > mingap_out ) {
arg - > mingap_out = mingap ;
}
2016-11-02 19:49:31 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Going to try keeping the sparsest %0.2f%% of the features to make it fit \n " , mingap_fraction * 100.0 ) ;
2016-10-25 23:28:32 +00:00
}
2016-11-02 19:49:31 +00:00
line_detail + + ;
continue ;
2016-11-10 00:32:40 +00:00
} else if ( additional [ A_DROP_SMALLEST_AS_NEEDED ] ) {
minextent_fraction = minextent_fraction * 200000.0 / totalsize * 0.90 ;
2016-11-23 21:57:32 +00:00
long long m = choose_minextent ( extents , minextent_fraction ) ;
if ( m ! = minextent ) {
minextent = m ;
if ( minextent > arg - > minextent_out ) {
arg - > minextent_out = minextent ;
}
if ( ! quiet ) {
fprintf ( stderr , " Going to try keeping the biggest %0.2f%% of the features to make it fit \n " , minextent_fraction * 100.0 ) ;
}
line_detail + + ;
continue ;
2016-11-10 00:32:40 +00:00
}
2016-11-04 19:26:13 +00:00
} else if ( prevent [ P_DYNAMIC_DROP ] | | additional [ A_DROP_FRACTION_AS_NEEDED ] ) {
2016-10-25 22:21:00 +00:00
fraction = fraction * 200000 / totalsize * 0.95 ;
if ( ! quiet ) {
fprintf ( stderr , " Going to try keeping %0.2f%% of the features to make it fit \n " , fraction * 100 ) ;
}
2016-11-04 19:26:13 +00:00
if ( additional [ A_DROP_FRACTION_AS_NEEDED ] & & fraction < arg - > fraction_out ) {
arg - > fraction_out = fraction ;
}
2016-10-25 22:21:00 +00:00
line_detail + + ; // to keep it the same when the loop decrements it
continue ;
2016-10-24 19:29:36 +00:00
} else {
fprintf ( stderr , " Try using -B (and --drop-lines or --drop-polygons if needed) to set a higher base zoom level. \n " ) ;
return - 1 ;
}
2014-12-19 22:33:39 +00:00
}
2016-04-25 19:13:52 +00:00
std : : string compressed = tile . encode ( ) ;
2014-09-23 19:17:18 +00:00
2016-10-24 22:33:14 +00:00
if ( compressed . size ( ) > max_tile_size & & ! prevent [ P_KILOBYTE_LIMIT ] ) {
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
2016-10-24 22:33:14 +00:00
fprintf ( stderr , " tile %d/%u/%u size is %lld with detail %d, >%zu \n " , z , tx , ty , ( long long ) compressed . size ( ) , line_detail , max_tile_size ) ;
2015-07-08 22:06:21 +00:00
}
2014-10-08 23:39:44 +00:00
2016-10-25 22:21:00 +00:00
if ( has_polygons & & additional [ A_MERGE_POLYGONS_AS_NEEDED ] & & merge_fraction > .05 & & merge_successful ) {
merge_fraction = merge_fraction * max_tile_size / compressed . size ( ) * 0.95 ;
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
2016-10-25 22:21:00 +00:00
fprintf ( stderr , " Going to try merging %0.2f%% of the polygons to make it fit \n " , 100 - merge_fraction * 100 ) ;
2015-07-08 22:06:21 +00:00
}
2015-06-03 18:21:40 +00:00
line_detail + + ; // to keep it the same when the loop decrements it
2016-10-24 22:33:14 +00:00
} else if ( additional [ A_INCREASE_GAMMA_AS_NEEDED ] & & gamma < 10 ) {
2016-10-24 19:29:36 +00:00
if ( gamma < 1 ) {
gamma = 1 ;
} else {
gamma = gamma * 1.25 ;
}
2016-10-26 17:40:53 +00:00
if ( gamma > arg - > gamma_out ) {
arg - > gamma_out = gamma ;
}
2016-10-25 21:13:55 +00:00
2016-10-24 19:29:36 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Going to try gamma of %0.3f to make it fit \n " , gamma ) ;
}
line_detail + + ; // to keep it the same when the loop decrements it
2016-11-17 20:40:11 +00:00
} else if ( additional [ A_DROP_DENSEST_AS_NEEDED ] ) {
2016-11-02 23:57:35 +00:00
mingap_fraction = mingap_fraction * max_tile_size / compressed . size ( ) * 0.90 ;
2016-11-04 00:49:32 +00:00
mingap = choose_mingap ( indices , mingap_fraction ) ;
if ( mingap > arg - > mingap_out ) {
arg - > mingap_out = mingap ;
}
2016-11-02 19:49:31 +00:00
if ( ! quiet ) {
fprintf ( stderr , " Going to try keeping the sparsest %0.2f%% of the features to make it fit \n " , mingap_fraction * 100.0 ) ;
2016-10-25 23:28:32 +00:00
}
2016-11-02 19:49:31 +00:00
line_detail + + ;
2016-11-10 00:32:40 +00:00
} else if ( additional [ A_DROP_SMALLEST_AS_NEEDED ] ) {
minextent_fraction = minextent_fraction * max_tile_size / compressed . size ( ) * 0.90 ;
2016-11-23 21:57:32 +00:00
long long m = choose_minextent ( extents , minextent_fraction ) ;
if ( m ! = minextent ) {
minextent = m ;
if ( minextent > arg - > minextent_out ) {
arg - > minextent_out = minextent ;
}
if ( ! quiet ) {
fprintf ( stderr , " Going to try keeping the biggest %0.2f%% of the features to make it fit \n " , minextent_fraction * 100.0 ) ;
}
line_detail + + ;
continue ;
2016-11-10 00:32:40 +00:00
}
2016-11-04 19:26:13 +00:00
} else if ( prevent [ P_DYNAMIC_DROP ] | | additional [ A_DROP_FRACTION_AS_NEEDED ] ) {
2016-10-25 22:21:00 +00:00
// The 95% is a guess to avoid too many retries
// and probably actually varies based on how much duplicated metadata there is
fraction = fraction * max_tile_size / compressed . size ( ) * 0.95 ;
2016-10-24 23:27:00 +00:00
if ( ! quiet ) {
2016-10-25 22:21:00 +00:00
fprintf ( stderr , " Going to try keeping %0.2f%% of the features to make it fit \n " , fraction * 100 ) ;
2016-10-24 23:27:00 +00:00
}
2016-11-04 19:26:13 +00:00
if ( additional [ A_DROP_FRACTION_AS_NEEDED ] & & fraction < arg - > fraction_out ) {
arg - > fraction_out = fraction ;
}
2016-10-24 23:27:00 +00:00
line_detail + + ; // to keep it the same when the loop decrements it
2015-05-20 21:57:00 +00:00
}
2014-11-20 22:31:50 +00:00
} else {
2016-10-25 21:13:55 +00:00
if ( pass = = 1 ) {
if ( pthread_mutex_lock ( & db_lock ) ! = 0 ) {
perror ( " pthread_mutex_lock " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-10-19 19:32:40 +00:00
2016-10-25 21:13:55 +00:00
mbtiles_write_tile ( outdb , z , tx , ty , compressed . data ( ) , compressed . size ( ) ) ;
2015-10-19 19:32:40 +00:00
2016-10-25 21:13:55 +00:00
if ( pthread_mutex_unlock ( & db_lock ) ! = 0 ) {
perror ( " pthread_mutex_unlock " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-10-19 19:32:40 +00:00
}
2014-11-20 22:31:50 +00:00
return count ;
2014-10-08 23:59:00 +00:00
}
2014-10-07 17:27:17 +00:00
} else {
return count ;
}
2014-09-23 19:17:18 +00:00
}
2014-09-23 00:46:48 +00:00
2014-10-07 17:27:17 +00:00
fprintf ( stderr , " could not make tile %d/%u/%u small enough \n " , z , tx , ty ) ;
2015-03-07 00:33:32 +00:00
return - 1 ;
2014-09-22 23:27:10 +00:00
}
2015-06-20 00:29:56 +00:00
2015-07-23 23:17:23 +00:00
struct task {
int fileno ;
struct task * next ;
2015-11-12 00:10:39 +00:00
} ;
2015-07-23 23:17:23 +00:00
2015-10-19 19:32:40 +00:00
void * run_thread ( void * vargs ) {
write_tile_args * arg = ( write_tile_args * ) vargs ;
2015-07-23 23:17:23 +00:00
struct task * task ;
for ( task = arg - > tasks ; task ! = NULL ; task = task - > next ) {
int j = task - > fileno ;
if ( arg - > geomfd [ j ] < 0 ) {
// only one source file for zoom level 0
continue ;
}
if ( arg - > geom_size [ j ] = = 0 ) {
continue ;
}
// printf("%lld of geom_size\n", (long long) geom_size[j]);
2016-04-11 22:59:02 +00:00
FILE * geom = fdopen ( arg - > geomfd [ j ] , " rb " ) ;
if ( geom = = NULL ) {
2015-07-23 23:17:23 +00:00
perror ( " mmap geom " ) ;
exit ( EXIT_FAILURE ) ;
}
2016-04-11 22:59:02 +00:00
long long geompos = 0 ;
long long prevgeom = 0 ;
2015-07-23 23:17:23 +00:00
2016-04-11 22:59:02 +00:00
while ( 1 ) {
2015-07-23 23:17:23 +00:00
int z ;
unsigned x , y ;
2016-04-11 22:59:02 +00:00
if ( ! deserialize_int_io ( geom , & z , & geompos ) ) {
break ;
}
deserialize_uint_io ( geom , & x , & geompos ) ;
deserialize_uint_io ( geom , & y , & geompos ) ;
2015-07-23 23:17:23 +00:00
// fprintf(stderr, "%d/%u/%u\n", z, x, y);
2016-12-08 23:13:38 +00:00
long long len = write_tile ( geom , & geompos , arg - > metabase , arg - > stringpool , z , x , y , z = = arg - > maxzoom ? arg - > full_detail : arg - > low_detail , arg - > min_detail , arg - > basezoom , arg - > outdb , arg - > droprate , arg - > buffer , arg - > fname , arg - > geomfile , arg - > minzoom , arg - > maxzoom , arg - > todo , arg - > along , geompos , arg - > gamma , arg - > child_shards , arg - > meta_off , arg - > pool_off , arg - > initial_x , arg - > initial_y , arg - > running , arg - > simplification , arg - > layermaps , arg - > layer_unmaps , arg - > pass , arg - > passes , arg - > mingap , arg - > minextent , arg - > fraction , arg - > prefilter , arg - > postfilter , arg ) ;
2015-07-23 23:17:23 +00:00
if ( len < 0 ) {
2016-05-03 17:52:49 +00:00
int * err = & arg - > err ;
2015-10-19 20:39:44 +00:00
* err = z - 1 ;
return err ;
2015-07-23 23:17:23 +00:00
}
2015-10-19 21:17:04 +00:00
if ( pthread_mutex_lock ( & var_lock ) ! = 0 ) {
2015-10-19 20:32:02 +00:00
perror ( " pthread_mutex_lock " ) ;
exit ( EXIT_FAILURE ) ;
}
2016-01-28 22:38:10 +00:00
if ( z = = arg - > maxzoom ) {
if ( len > * arg - > most ) {
* arg - > midx = x ;
* arg - > midy = y ;
* arg - > most = len ;
} else if ( len = = * arg - > most ) {
2016-01-28 23:35:22 +00:00
unsigned long long a = ( ( ( unsigned long long ) x ) < < 32 ) | y ;
2016-01-28 22:38:10 +00:00
unsigned long long b = ( ( ( unsigned long long ) * arg - > midx ) < < 32 ) | * arg - > midy ;
if ( a < b ) {
* arg - > midx = x ;
* arg - > midy = y ;
* arg - > most = len ;
}
}
2015-07-23 23:17:23 +00:00
}
2015-10-19 20:32:02 +00:00
2016-04-11 22:59:02 +00:00
* arg - > along + = geompos - prevgeom ;
prevgeom = geompos ;
2015-10-19 21:17:04 +00:00
if ( pthread_mutex_unlock ( & var_lock ) ! = 0 ) {
2015-10-19 20:32:02 +00:00
perror ( " pthread_mutex_unlock " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-07-23 23:17:23 +00:00
}
2016-10-25 21:13:55 +00:00
if ( arg - > pass = = 1 ) {
// Since the fclose() has closed the underlying file descriptor
arg - > geomfd [ j ] = - 1 ;
} else {
int newfd = dup ( arg - > geomfd [ j ] ) ;
if ( newfd < 0 ) {
perror ( " dup geometry " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( lseek ( newfd , 0 , SEEK_SET ) < 0 ) {
perror ( " lseek geometry " ) ;
exit ( EXIT_FAILURE ) ;
}
arg - > geomfd [ j ] = newfd ;
}
2016-04-11 22:59:02 +00:00
if ( fclose ( geom ) ! = 0 ) {
perror ( " close geom " ) ;
exit ( EXIT_FAILURE ) ;
2015-07-23 23:17:23 +00:00
}
}
2015-10-19 19:32:40 +00:00
2016-01-05 21:56:36 +00:00
arg - > running - - ;
2015-10-19 19:32:40 +00:00
return NULL ;
2015-07-23 23:17:23 +00:00
}
2016-12-08 23:13:38 +00:00
int traverse_zooms ( int * geomfd , off_t * geom_size , char * metabase , char * stringpool , unsigned * midx , unsigned * midy , int maxzoom , int minzoom , int basezoom , sqlite3 * outdb , double droprate , int buffer , const char * fname , const char * tmpdir , double gamma , int full_detail , int low_detail , int min_detail , long long * meta_off , long long * pool_off , unsigned * initial_x , unsigned * initial_y , double simplification , std : : vector < std : : map < std : : string , layermap_entry > > & layermaps , const char * prefilter , const char * postfilter ) {
2016-08-30 21:38:30 +00:00
// Table to map segment and layer number back to layer name
std : : vector < std : : vector < std : : string > > layer_unmaps ;
for ( size_t seg = 0 ; seg < layermaps . size ( ) ; seg + + ) {
layer_unmaps . push_back ( std : : vector < std : : string > ( ) ) ;
for ( auto a = layermaps [ seg ] . begin ( ) ; a ! = layermaps [ seg ] . end ( ) ; + + a ) {
if ( a - > second . id > = layer_unmaps [ seg ] . size ( ) ) {
layer_unmaps [ seg ] . resize ( a - > second . id + 1 ) ;
}
layer_unmaps [ seg ] [ a - > second . id ] = a - > first ;
}
}
2015-06-20 00:29:56 +00:00
int i ;
for ( i = 0 ; i < = maxzoom ; i + + ) {
long long most = 0 ;
2015-07-08 23:33:22 +00:00
FILE * sub [ TEMP_FILES ] ;
int subfd [ TEMP_FILES ] ;
2016-10-15 00:11:57 +00:00
for ( size_t j = 0 ; j < TEMP_FILES ; j + + ) {
2015-07-10 17:26:23 +00:00
char geomname [ strlen ( tmpdir ) + strlen ( " /geom.XXXXXXXX " XSTRINGIFY ( INT_MAX ) ) + 1 ] ;
2016-10-15 00:11:57 +00:00
sprintf ( geomname , " %s/geom%zu.XXXXXXXX " , tmpdir , j ) ;
2016-12-07 19:19:29 +00:00
subfd [ j ] = mkstemp_cloexec ( geomname ) ;
2015-06-20 00:29:56 +00:00
// printf("%s\n", geomname);
if ( subfd [ j ] < 0 ) {
perror ( geomname ) ;
exit ( EXIT_FAILURE ) ;
}
2016-12-07 18:57:56 +00:00
sub [ j ] = fopen_oflag ( geomname , " wb " , O_WRONLY | O_CLOEXEC ) ;
2015-06-20 00:29:56 +00:00
if ( sub [ j ] = = NULL ) {
perror ( geomname ) ;
exit ( EXIT_FAILURE ) ;
}
unlink ( geomname ) ;
}
2016-10-15 00:11:57 +00:00
size_t useful_threads = 0 ;
2015-06-20 00:29:56 +00:00
long long todo = 0 ;
2016-10-15 00:11:57 +00:00
for ( size_t j = 0 ; j < TEMP_FILES ; j + + ) {
2015-06-20 00:29:56 +00:00
todo + = geom_size [ j ] ;
2015-07-09 22:24:47 +00:00
if ( geom_size [ j ] > 0 ) {
useful_threads + + ;
}
2015-06-20 00:29:56 +00:00
}
2015-07-08 23:33:22 +00:00
2016-10-15 00:11:57 +00:00
size_t threads = CPUS ;
2015-07-09 22:24:47 +00:00
if ( threads > TEMP_FILES / 4 ) {
threads = TEMP_FILES / 4 ;
}
// XXX is it useful to divide further if we know we are skipping
// some zoom levels? Is it faster to have fewer CPUs working on
// sharding, but more deeply, or fewer CPUs, less deeply?
if ( threads > useful_threads ) {
threads = useful_threads ;
}
2016-04-27 23:41:41 +00:00
2015-07-09 22:24:47 +00:00
// Round down to a power of 2
2016-04-27 23:41:41 +00:00
for ( int e = 0 ; e < 30 ; e + + ) {
if ( threads > = ( 1 < < e ) & & threads < ( 1 < < ( e + 1 ) ) ) {
threads = 1 < < e ;
break ;
}
}
if ( threads > = ( 1 < < 30 ) ) {
threads = 1 < < 30 ;
}
2015-07-08 23:33:22 +00:00
2015-07-09 23:09:40 +00:00
// Assign temporary files to threads
2015-11-12 00:10:39 +00:00
struct task tasks [ TEMP_FILES ] ;
2015-07-09 23:09:40 +00:00
struct dispatch {
struct task * tasks ;
long long todo ;
struct dispatch * next ;
} dispatches [ threads ] ;
struct dispatch * dispatch_head = & dispatches [ 0 ] ;
2016-10-15 00:11:57 +00:00
for ( size_t j = 0 ; j < threads ; j + + ) {
2015-07-09 23:09:40 +00:00
dispatches [ j ] . tasks = NULL ;
dispatches [ j ] . todo = 0 ;
if ( j + 1 < threads ) {
dispatches [ j ] . next = & dispatches [ j + 1 ] ;
} else {
dispatches [ j ] . next = NULL ;
}
}
2016-10-15 00:11:57 +00:00
for ( size_t j = 0 ; j < TEMP_FILES ; j + + ) {
2015-07-09 23:09:40 +00:00
if ( geom_size [ j ] = = 0 ) {
continue ;
}
tasks [ j ] . fileno = j ;
tasks [ j ] . next = dispatch_head - > tasks ;
dispatch_head - > tasks = & tasks [ j ] ;
dispatch_head - > todo + = geom_size [ j ] ;
struct dispatch * here = dispatch_head ;
dispatch_head = dispatch_head - > next ;
dispatch * * d ;
for ( d = & dispatch_head ; * d ! = NULL ; d = & ( ( * d ) - > next ) ) {
if ( here - > todo < ( * d ) - > todo ) {
break ;
}
}
here - > next = * d ;
* d = here ;
2015-07-09 23:14:24 +00:00
}
2015-07-09 23:09:40 +00:00
2016-10-25 21:13:55 +00:00
int err = INT_MAX ;
size_t start = 1 ;
2016-11-17 20:40:11 +00:00
if ( additional [ A_INCREASE_GAMMA_AS_NEEDED ] | | additional [ A_DROP_DENSEST_AS_NEEDED ] | | additional [ A_DROP_FRACTION_AS_NEEDED ] | | additional [ A_DROP_SMALLEST_AS_NEEDED ] ) {
2016-10-25 21:13:55 +00:00
start = 0 ;
}
double zoom_gamma = gamma ;
2016-11-02 19:49:31 +00:00
unsigned long long zoom_mingap = 0 ;
2016-11-10 00:32:40 +00:00
long long zoom_minextent = 0 ;
2016-11-04 19:26:13 +00:00
double zoom_fraction = 1 ;
2016-10-25 21:13:55 +00:00
for ( size_t pass = start ; pass < 2 ; pass + + ) {
pthread_t pthreads [ threads ] ;
write_tile_args args [ threads ] ;
int running = threads ;
2016-11-04 00:13:11 +00:00
long long along = 0 ;
2016-10-25 21:13:55 +00:00
for ( size_t thread = 0 ; thread < threads ; thread + + ) {
args [ thread ] . metabase = metabase ;
args [ thread ] . stringpool = stringpool ;
args [ thread ] . min_detail = min_detail ;
args [ thread ] . basezoom = basezoom ;
args [ thread ] . outdb = outdb ; // locked with db_lock
args [ thread ] . droprate = droprate ;
args [ thread ] . buffer = buffer ;
args [ thread ] . fname = fname ;
args [ thread ] . geomfile = sub + thread * ( TEMP_FILES / threads ) ;
args [ thread ] . todo = todo ;
args [ thread ] . along = & along ; // locked with var_lock
args [ thread ] . gamma = zoom_gamma ;
2016-10-26 17:40:53 +00:00
args [ thread ] . gamma_out = zoom_gamma ;
2016-10-25 23:28:32 +00:00
args [ thread ] . mingap = zoom_mingap ;
2016-10-26 17:40:53 +00:00
args [ thread ] . mingap_out = zoom_mingap ;
2016-11-10 00:32:40 +00:00
args [ thread ] . minextent = zoom_minextent ;
args [ thread ] . minextent_out = zoom_minextent ;
2016-11-04 19:26:13 +00:00
args [ thread ] . fraction = zoom_fraction ;
args [ thread ] . fraction_out = zoom_fraction ;
2016-10-25 21:13:55 +00:00
args [ thread ] . child_shards = TEMP_FILES / threads ;
args [ thread ] . simplification = simplification ;
args [ thread ] . geomfd = geomfd ;
args [ thread ] . geom_size = geom_size ;
args [ thread ] . midx = midx ; // locked with var_lock
args [ thread ] . midy = midy ; // locked with var_lock
args [ thread ] . maxzoom = maxzoom ;
args [ thread ] . minzoom = minzoom ;
args [ thread ] . full_detail = full_detail ;
args [ thread ] . low_detail = low_detail ;
args [ thread ] . most = & most ; // locked with var_lock
args [ thread ] . meta_off = meta_off ;
args [ thread ] . pool_off = pool_off ;
args [ thread ] . initial_x = initial_x ;
args [ thread ] . initial_y = initial_y ;
args [ thread ] . layermaps = & layermaps ;
args [ thread ] . layer_unmaps = & layer_unmaps ;
2016-12-08 23:13:38 +00:00
args [ thread ] . prefilter = prefilter ;
args [ thread ] . postfilter = postfilter ;
2016-10-25 21:13:55 +00:00
args [ thread ] . tasks = dispatches [ thread ] . tasks ;
args [ thread ] . running = & running ;
args [ thread ] . pass = pass ;
2016-11-04 00:13:11 +00:00
args [ thread ] . passes = 2 - start ;
2016-10-25 21:13:55 +00:00
if ( pthread_create ( & pthreads [ thread ] , NULL , run_thread , & args [ thread ] ) ! = 0 ) {
perror ( " pthread_create " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-10-19 19:32:40 +00:00
}
2016-10-25 21:13:55 +00:00
for ( size_t thread = 0 ; thread < threads ; thread + + ) {
void * retval ;
2015-10-19 20:39:44 +00:00
2016-10-25 21:13:55 +00:00
if ( pthread_join ( pthreads [ thread ] , & retval ) ! = 0 ) {
perror ( " pthread_join " ) ;
}
2015-10-19 19:32:40 +00:00
2016-10-25 21:13:55 +00:00
if ( retval ! = NULL ) {
err = * ( ( int * ) retval ) ;
}
2015-10-19 20:39:44 +00:00
2016-10-26 17:40:53 +00:00
if ( args [ thread ] . gamma_out > zoom_gamma ) {
zoom_gamma = args [ thread ] . gamma_out ;
2016-10-25 21:13:55 +00:00
}
2016-10-26 17:40:53 +00:00
if ( args [ thread ] . mingap_out > zoom_mingap ) {
zoom_mingap = args [ thread ] . mingap_out ;
2016-10-25 23:28:32 +00:00
}
2016-11-10 00:32:40 +00:00
if ( args [ thread ] . minextent_out > zoom_minextent ) {
zoom_minextent = args [ thread ] . minextent_out ;
}
2016-11-04 19:26:13 +00:00
if ( args [ thread ] . fraction_out < zoom_fraction ) {
zoom_fraction = args [ thread ] . fraction_out ;
}
2015-10-19 20:39:44 +00:00
}
2015-06-20 00:29:56 +00:00
}
2016-10-15 00:11:57 +00:00
for ( size_t j = 0 ; j < TEMP_FILES ; j + + ) {
2016-04-05 18:13:31 +00:00
// Can be < 0 if there is only one source file, at z0
if ( geomfd [ j ] > = 0 ) {
if ( close ( geomfd [ j ] ) ! = 0 ) {
perror ( " close geom " ) ;
exit ( EXIT_FAILURE ) ;
}
}
if ( fclose ( sub [ j ] ) ! = 0 ) {
perror ( " close subfile " ) ;
exit ( EXIT_FAILURE ) ;
}
2015-06-20 00:29:56 +00:00
struct stat geomst ;
if ( fstat ( subfd [ j ] , & geomst ) ! = 0 ) {
perror ( " stat geom \n " ) ;
exit ( EXIT_FAILURE ) ;
}
geomfd [ j ] = subfd [ j ] ;
geom_size [ j ] = geomst . st_size ;
}
2015-10-19 20:39:44 +00:00
if ( err ! = INT_MAX ) {
return err ;
}
2015-06-20 00:29:56 +00:00
}
2016-10-15 00:11:57 +00:00
for ( size_t j = 0 ; j < TEMP_FILES ; j + + ) {
2016-04-05 21:07:24 +00:00
// Can be < 0 if there is only one source file, at z0
if ( geomfd [ j ] > = 0 ) {
if ( close ( geomfd [ j ] ) ! = 0 ) {
perror ( " close geom " ) ;
exit ( EXIT_FAILURE ) ;
}
}
}
2015-07-08 22:06:21 +00:00
if ( ! quiet ) {
fprintf ( stderr , " \n " ) ;
}
2015-06-20 00:29:56 +00:00
return maxzoom ;
}