2014-10-24 22:12:02 +00:00
# include <iostream>
# include <fstream>
# include <string>
# include <stack>
# include <vector>
2016-12-09 23:35:57 +00:00
# include <map>
2014-10-24 22:12:02 +00:00
# include <algorithm>
2016-04-26 23:51:12 +00:00
# include <cstdio>
2014-10-24 22:12:02 +00:00
# include <unistd.h>
2016-04-26 23:51:12 +00:00
# include <cmath>
2016-04-26 23:56:24 +00:00
# include <limits.h>
2016-04-27 21:00:14 +00:00
# include <sqlite3.h>
2017-01-26 21:25:06 +00:00
# include <mapbox/geometry/point.hpp>
# include <mapbox/geometry/multi_polygon.hpp>
2016-12-07 22:29:09 +00:00
# include <mapbox/geometry/wagyu/wagyu.hpp>
2017-01-07 00:24:09 +00:00
# include <mapbox/geometry/wagyu/quick_clip.hpp>
2017-02-17 21:25:56 +00:00
# include <mapbox/geometry/snap_rounding.hpp>
2016-04-27 19:22:47 +00:00
# include "geometry.hpp"
2016-04-27 21:00:14 +00:00
# include "projection.hpp"
2016-04-27 21:19:10 +00:00
# include "serial.hpp"
2016-04-27 22:09:06 +00:00
# include "main.hpp"
2014-10-24 22:12:02 +00:00
2016-03-29 18:05:39 +00:00
static int pnpoly ( drawvec & vert , size_t start , size_t nvert , long long testx , long long testy ) ;
2016-04-27 19:25:03 +00:00
static int clip ( double * x0 , double * y0 , double * x1 , double * y1 , double xmin , double ymin , double xmax , double ymax ) ;
2016-03-29 18:05:39 +00:00
2016-12-09 00:28:57 +00:00
drawvec decode_geometry ( FILE * meta , long long * geompos , int z , unsigned tx , unsigned ty , long long * bbox , unsigned initial_x , unsigned initial_y ) {
2014-10-24 22:12:02 +00:00
drawvec out ;
2016-03-21 23:13:47 +00:00
bbox [ 0 ] = LLONG_MAX ;
bbox [ 1 ] = LLONG_MAX ;
bbox [ 2 ] = LLONG_MIN ;
bbox [ 3 ] = LLONG_MIN ;
2014-12-11 21:34:50 +00:00
2015-06-18 17:50:57 +00:00
long long wx = initial_x , wy = initial_y ;
2015-06-18 00:48:29 +00:00
2014-10-24 22:12:02 +00:00
while ( 1 ) {
draw d ;
2016-08-09 00:08:36 +00:00
if ( ! deserialize_byte_io ( meta , & d . op , geompos ) ) {
fprintf ( stderr , " Internal error: Unexpected end of file in geometry \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2014-10-24 22:12:02 +00:00
if ( d . op = = VT_END ) {
break ;
}
if ( d . op = = VT_MOVETO | | d . op = = VT_LINETO ) {
2015-06-18 00:48:29 +00:00
long long dx , dy ;
2016-04-11 22:59:02 +00:00
deserialize_long_long_io ( meta , & dx , geompos ) ;
deserialize_long_long_io ( meta , & dy , geompos ) ;
2015-06-18 00:48:29 +00:00
2016-04-27 18:13:15 +00:00
wx + = dx * ( 1 < < geometry_scale ) ;
wy + = dy * ( 1 < < geometry_scale ) ;
2014-10-24 22:12:02 +00:00
2015-06-18 00:48:29 +00:00
long long wwx = wx ;
long long wwy = wy ;
2014-10-24 22:12:02 +00:00
if ( z ! = 0 ) {
wwx - = tx < < ( 32 - z ) ;
wwy - = ty < < ( 32 - z ) ;
}
2014-12-11 21:34:50 +00:00
if ( wwx < bbox [ 0 ] ) {
bbox [ 0 ] = wwx ;
}
if ( wwy < bbox [ 1 ] ) {
bbox [ 1 ] = wwy ;
}
if ( wwx > bbox [ 2 ] ) {
bbox [ 2 ] = wwx ;
}
if ( wwy > bbox [ 3 ] ) {
bbox [ 3 ] = wwy ;
}
2014-10-24 22:12:02 +00:00
d . x = wwx ;
d . y = wwy ;
}
out . push_back ( d ) ;
}
return out ;
}
void to_tile_scale ( drawvec & geom , int z , int detail ) {
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
geom [ i ] . x > > = ( 32 - detail - z ) ;
geom [ i ] . y > > = ( 32 - detail - z ) ;
}
}
2015-07-01 19:16:50 +00:00
drawvec remove_noop ( drawvec geom , int type , int shift ) {
2014-10-24 22:12:02 +00:00
// first pass: remove empty linetos
long long x = 0 , y = 0 ;
drawvec out ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2015-07-01 19:16:50 +00:00
if ( geom [ i ] . op = = VT_LINETO & & ( geom [ i ] . x > > shift ) = = x & & ( geom [ i ] . y > > shift ) = = y ) {
2014-10-24 22:12:02 +00:00
continue ;
}
if ( geom [ i ] . op = = VT_CLOSEPATH ) {
out . push_back ( geom [ i ] ) ;
} else { /* moveto or lineto */
out . push_back ( geom [ i ] ) ;
2015-07-01 19:16:50 +00:00
x = geom [ i ] . x > > shift ;
y = geom [ i ] . y > > shift ;
2014-10-24 22:12:02 +00:00
}
}
// second pass: remove unused movetos
2015-12-11 20:31:10 +00:00
if ( type ! = VT_POINT ) {
geom = out ;
out . resize ( 0 ) ;
2014-10-24 22:12:02 +00:00
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2015-12-11 20:31:10 +00:00
if ( geom [ i ] . op = = VT_MOVETO ) {
if ( i + 1 > = geom . size ( ) ) {
continue ;
}
if ( geom [ i + 1 ] . op = = VT_MOVETO ) {
continue ;
}
if ( geom [ i + 1 ] . op = = VT_CLOSEPATH ) {
fprintf ( stderr , " Shouldn't happen \n " ) ;
i + + ; // also remove unused closepath
continue ;
}
2014-10-24 22:12:02 +00:00
}
2015-12-11 20:31:10 +00:00
out . push_back ( geom [ i ] ) ;
2014-10-24 22:12:02 +00:00
}
}
// second pass: remove empty movetos
if ( type = = VT_LINE ) {
geom = out ;
out . resize ( 0 ) ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
if ( geom [ i ] . op = = VT_MOVETO ) {
2015-07-01 19:16:50 +00:00
if ( i > 0 & & geom [ i - 1 ] . op = = VT_LINETO & & ( geom [ i - 1 ] . x > > shift ) = = ( geom [ i ] . x > > shift ) & & ( geom [ i - 1 ] . y > > shift ) = = ( geom [ i ] . y > > shift ) ) {
2014-10-24 22:12:02 +00:00
continue ;
}
}
out . push_back ( geom [ i ] ) ;
}
}
return out ;
}
2016-05-03 23:39:26 +00:00
double get_area ( drawvec & geom , size_t i , size_t j ) {
2016-03-24 00:10:10 +00:00
double area = 0 ;
2016-05-03 23:39:26 +00:00
for ( size_t k = i ; k < j ; k + + ) {
2016-03-24 00:10:10 +00:00
area + = ( long double ) geom [ k ] . x * ( long double ) geom [ i + ( ( k - i + 1 ) % ( j - i ) ) ] . y ;
area - = ( long double ) geom [ k ] . y * ( long double ) geom [ i + ( ( k - i + 1 ) % ( j - i ) ) ] . x ;
}
area / = 2 ;
return area ;
}
2017-02-06 22:14:34 +00:00
double get_mp_area ( drawvec & geom ) {
double ret = 0 ;
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO ) {
size_t j ;
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
}
}
ret + = get_area ( geom , i , j ) ;
i = j - 1 ;
}
}
return ret ;
}
2016-12-07 22:29:09 +00:00
static void decode_clipped ( mapbox : : geometry : : multi_polygon < long long > & t , drawvec & out ) {
out . clear ( ) ;
2016-03-24 00:10:10 +00:00
2016-12-07 22:29:09 +00:00
for ( size_t i = 0 ; i < t . size ( ) ; i + + ) {
for ( size_t j = 0 ; j < t [ i ] . size ( ) ; j + + ) {
drawvec ring ;
2016-03-29 18:05:39 +00:00
2016-12-07 22:29:09 +00:00
for ( size_t k = 0 ; k < t [ i ] [ j ] . size ( ) ; k + + ) {
ring . push_back ( draw ( ( k = = 0 ) ? VT_MOVETO : VT_LINETO , t [ i ] [ j ] [ k ] . x , t [ i ] [ j ] [ k ] . y ) ) ;
2016-03-29 18:05:39 +00:00
}
2016-04-27 17:47:21 +00:00
2016-12-07 22:29:09 +00:00
if ( ring . size ( ) > 0 & & ring [ ring . size ( ) - 1 ] ! = ring [ 0 ] ) {
fprintf ( stderr , " Had to close ring \n " ) ;
ring . push_back ( draw ( VT_LINETO , ring [ 0 ] . x , ring [ 0 ] . y ) ) ;
2016-03-29 18:05:39 +00:00
}
2016-04-27 17:47:21 +00:00
2016-12-07 22:29:09 +00:00
double area = get_area ( ring , 0 , ring . size ( ) ) ;
2016-03-29 18:05:39 +00:00
2016-12-07 22:29:09 +00:00
if ( ( j = = 0 & & area < 0 ) | | ( j ! = 0 & & area > 0 ) ) {
fprintf ( stderr , " Ring area has wrong sign: %f for %zu \n " , area , j ) ;
exit ( EXIT_FAILURE ) ;
2016-03-29 18:05:39 +00:00
}
2016-12-07 22:29:09 +00:00
for ( size_t k = 0 ; k < ring . size ( ) ; k + + ) {
out . push_back ( ring [ k ] ) ;
2016-03-29 18:05:39 +00:00
}
2015-10-14 00:25:01 +00:00
}
}
}
2016-12-07 22:29:09 +00:00
drawvec clean_or_clip_poly ( drawvec & geom , int z , int detail , int buffer , bool clip ) {
mapbox : : geometry : : wagyu : : wagyu < long long > wagyu ;
2016-04-12 23:40:03 +00:00
2016-12-14 00:55:33 +00:00
geom = remove_noop ( geom , VT_POLYGON , 0 ) ;
2016-04-12 23:40:03 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO ) {
size_t j ;
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
}
}
2016-12-07 22:29:09 +00:00
if ( j > = i + 4 ) {
mapbox : : geometry : : linear_ring < long long > lr ;
2016-04-12 23:40:03 +00:00
2016-12-07 22:29:09 +00:00
for ( size_t k = i ; k < j ; k + + ) {
lr . push_back ( mapbox : : geometry : : point < long long > ( geom [ k ] . x , geom [ k ] . y ) ) ;
}
2016-04-12 23:40:03 +00:00
2016-12-07 22:29:09 +00:00
if ( lr . size ( ) > = 3 ) {
wagyu . add_ring ( lr ) ;
}
2016-04-12 23:40:03 +00:00
}
i = j - 1 ;
}
}
2016-12-07 22:29:09 +00:00
if ( clip ) {
long long area = 0xFFFFFFFF ;
if ( z ! = 0 ) {
area = 1LL < < ( 32 - z ) ;
}
long long clip_buffer = buffer * area / 256 ;
2014-10-24 22:12:02 +00:00
2016-12-07 22:29:09 +00:00
mapbox : : geometry : : linear_ring < long long > lr ;
2016-03-11 00:03:02 +00:00
2016-12-07 22:29:09 +00:00
lr . push_back ( mapbox : : geometry : : point < long long > ( - clip_buffer , - clip_buffer ) ) ;
lr . push_back ( mapbox : : geometry : : point < long long > ( - clip_buffer , area + clip_buffer ) ) ;
lr . push_back ( mapbox : : geometry : : point < long long > ( area + clip_buffer , area + clip_buffer ) ) ;
lr . push_back ( mapbox : : geometry : : point < long long > ( area + clip_buffer , - clip_buffer ) ) ;
lr . push_back ( mapbox : : geometry : : point < long long > ( - clip_buffer , - clip_buffer ) ) ;
2016-03-11 00:03:02 +00:00
2016-12-07 22:29:09 +00:00
wagyu . add_ring ( lr , mapbox : : geometry : : wagyu : : polygon_type_clip ) ;
}
2015-10-14 00:25:01 +00:00
2016-12-07 22:29:09 +00:00
mapbox : : geometry : : multi_polygon < long long > result ;
try {
wagyu . execute ( mapbox : : geometry : : wagyu : : clip_type_union , result , mapbox : : geometry : : wagyu : : fill_type_positive , mapbox : : geometry : : wagyu : : fill_type_positive ) ;
} catch ( std : : runtime_error e ) {
FILE * f = fopen ( " /tmp/wagyu.log " , " w " ) ;
fprintf ( f , " %s \n " , e . what ( ) ) ;
fprintf ( stderr , " %s \n " , e . what ( ) ) ;
fprintf ( f , " [ " ) ;
2015-10-14 00:25:01 +00:00
2016-12-07 22:29:09 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO ) {
size_t j ;
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
}
2015-10-07 23:52:52 +00:00
}
2014-10-24 22:12:02 +00:00
2016-12-07 22:29:09 +00:00
if ( j > = i + 4 ) {
mapbox : : geometry : : linear_ring < long long > lr ;
2015-10-14 00:25:01 +00:00
2016-12-07 22:29:09 +00:00
if ( i ! = 0 ) {
fprintf ( f , " , " ) ;
}
fprintf ( f , " [ " ) ;
2015-10-14 00:25:01 +00:00
2016-12-07 22:29:09 +00:00
for ( size_t k = i ; k < j ; k + + ) {
lr . push_back ( mapbox : : geometry : : point < long long > ( geom [ k ] . x , geom [ k ] . y ) ) ;
if ( k ! = i ) {
fprintf ( f , " , " ) ;
}
fprintf ( f , " [%lld,%lld] " , geom [ k ] . x , geom [ k ] . y ) ;
}
2015-10-14 00:25:01 +00:00
2016-12-07 22:29:09 +00:00
fprintf ( f , " ] " ) ;
2016-03-11 00:03:02 +00:00
2016-12-07 22:29:09 +00:00
if ( lr . size ( ) > = 3 ) {
}
}
2016-04-06 21:17:44 +00:00
2016-12-07 22:29:09 +00:00
i = j - 1 ;
2016-04-06 21:17:44 +00:00
}
2015-10-16 00:11:29 +00:00
}
2015-10-14 00:25:01 +00:00
2016-12-07 22:29:09 +00:00
fprintf ( f , " ] " ) ;
fprintf ( f , " \n \n \n \n \n " ) ;
2015-10-14 00:25:01 +00:00
2016-12-07 22:29:09 +00:00
fclose ( f ) ;
fprintf ( stderr , " Internal error: Polygon cleaning failed. Log in /tmp/wagyu.log \n " ) ;
exit ( EXIT_FAILURE ) ;
2015-10-14 00:25:01 +00:00
}
2016-12-07 22:29:09 +00:00
drawvec ret ;
decode_clipped ( result , ret ) ;
return ret ;
2014-10-24 22:12:02 +00:00
}
2016-03-28 23:52:33 +00:00
/* pnpoly:
Copyright ( c ) 1970 - 2003 , Wm . Randolph Franklin
Permission is hereby granted , free of charge , to any person obtaining a copy of this software and associated documentation files ( the " Software " ) , to deal in the Software without restriction , including without limitation the rights to use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of the Software , and to permit persons to whom the Software is furnished to do so , subject to the following conditions :
Redistributions of source code must retain the above copyright notice , this list of conditions and the following disclaimers .
Redistributions in binary form must reproduce the above copyright notice in the documentation and / or other materials provided with the distribution .
The name of W . Randolph Franklin may not be used to endorse or promote products derived from this Software without specific prior written permission .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*/
2016-03-29 18:05:39 +00:00
static int pnpoly ( drawvec & vert , size_t start , size_t nvert , long long testx , long long testy ) {
2016-05-03 23:39:26 +00:00
size_t i , j ;
bool c = false ;
2016-03-28 23:52:33 +00:00
for ( i = 0 , j = nvert - 1 ; i < nvert ; j = i + + ) {
if ( ( ( vert [ i + start ] . y > testy ) ! = ( vert [ j + start ] . y > testy ) ) & &
2016-04-19 19:28:49 +00:00
( testx < ( vert [ j + start ] . x - vert [ i + start ] . x ) * ( testy - vert [ i + start ] . y ) / ( double ) ( vert [ j + start ] . y - vert [ i + start ] . y ) + vert [ i + start ] . x ) )
2016-03-28 23:52:33 +00:00
c = ! c ;
}
return c ;
}
2016-04-12 23:40:03 +00:00
void check_polygon ( drawvec & geom , drawvec & before ) {
2017-02-17 21:25:56 +00:00
geom = remove_noop ( geom , VT_POLYGON , 0 ) ;
mapbox : : geometry : : multi_polygon < long long > mp ;
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO ) {
size_t j ;
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
2016-03-18 23:31:56 +00:00
}
}
2017-02-17 21:25:56 +00:00
if ( j > = i + 4 ) {
mapbox : : geometry : : linear_ring < long long > lr ;
for ( size_t k = i ; k < j ; k + + ) {
lr . push_back ( mapbox : : geometry : : point < long long > ( geom [ k ] . x , geom [ k ] . y ) ) ;
}
if ( lr . size ( ) > = 3 ) {
mapbox : : geometry : : polygon < long long > p ;
p . push_back ( lr ) ;
mp . push_back ( p ) ;
2016-03-18 23:31:56 +00:00
}
}
2017-02-17 21:25:56 +00:00
i = j - 1 ;
2016-03-18 23:31:56 +00:00
}
}
2016-03-28 23:52:33 +00:00
2017-02-17 21:25:56 +00:00
mapbox : : geometry : : multi_polygon < long long > mp2 = mapbox : : geometry : : snap_round ( mp , true , true ) ;
if ( mp ! = mp2 ) {
fprintf ( stderr , " Internal error: self-intersecting polygon \n " ) ;
}
2016-03-28 23:52:33 +00:00
size_t outer_start = - 1 ;
size_t outer_len = 0 ;
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO ) {
size_t j ;
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
}
}
2016-03-29 00:01:17 +00:00
double area = get_area ( geom , i , j ) ;
2016-03-28 23:52:33 +00:00
2016-03-29 18:05:39 +00:00
#if 0
fprintf ( stderr , " looking at %lld to %lld, area %f \n " , ( long long ) i , ( long long ) j , area ) ;
# endif
2016-03-28 23:52:33 +00:00
if ( area > 0 ) {
outer_start = i ;
outer_len = j - i ;
} else {
2016-03-29 18:05:39 +00:00
for ( size_t k = i ; k < j ; k + + ) {
2016-03-28 23:52:33 +00:00
if ( ! pnpoly ( geom , outer_start , outer_len , geom [ k ] . x , geom [ k ] . y ) ) {
bool on_edge = false ;
for ( size_t l = outer_start ; l < outer_start + outer_len ; l + + ) {
if ( geom [ k ] . x = = geom [ l ] . x | | geom [ k ] . y = = geom [ l ] . y ) {
on_edge = true ;
break ;
}
}
if ( ! on_edge ) {
2016-04-12 23:40:03 +00:00
printf ( " %lld,%lld at %lld not in outer ring (%lld to %lld) \n " , geom [ k ] . x , geom [ k ] . y , ( long long ) k , ( long long ) outer_start , ( long long ) ( outer_start + outer_len ) ) ;
2016-03-28 23:52:33 +00:00
2016-03-29 18:05:39 +00:00
#if 0
2016-03-28 23:52:33 +00:00
for ( size_t l = outer_start ; l < outer_start + outer_len ; l + + ) {
fprintf ( stderr , " %lld,%lld " , geom [ l ] . x , geom [ l ] . y ) ;
}
2016-03-29 18:05:39 +00:00
# endif
2016-03-28 23:52:33 +00:00
}
}
}
}
}
}
2016-03-18 23:31:56 +00:00
}
2015-10-28 21:34:57 +00:00
drawvec close_poly ( drawvec & geom ) {
drawvec out ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2015-10-28 21:34:57 +00:00
if ( geom [ i ] . op = = VT_MOVETO ) {
2016-03-25 19:20:32 +00:00
size_t j ;
2015-10-28 21:34:57 +00:00
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
}
}
if ( j - 1 > i ) {
if ( geom [ j - 1 ] . x ! = geom [ i ] . x | | geom [ j - 1 ] . y ! = geom [ i ] . y ) {
fprintf ( stderr , " Internal error: polygon not closed \n " ) ;
}
}
2016-03-25 19:20:32 +00:00
for ( size_t n = i ; n < j - 1 ; n + + ) {
2015-10-28 21:34:57 +00:00
out . push_back ( geom [ n ] ) ;
}
out . push_back ( draw ( VT_CLOSEPATH , 0 , 0 ) ) ;
i = j - 1 ;
}
}
return out ;
}
2016-02-11 19:31:53 +00:00
drawvec simple_clip_poly ( drawvec & geom , long long minx , long long miny , long long maxx , long long maxy ) {
2015-12-21 23:56:21 +00:00
drawvec out ;
2017-01-07 00:24:09 +00:00
mapbox : : geometry : : point < long long > min ( minx , miny ) ;
mapbox : : geometry : : point < long long > max ( maxx , maxy ) ;
mapbox : : geometry : : box < long long > bbox ( min , max ) ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2015-12-21 23:56:21 +00:00
if ( geom [ i ] . op = = VT_MOVETO ) {
2016-03-25 19:20:32 +00:00
size_t j ;
2015-12-21 23:56:21 +00:00
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
}
}
2017-01-07 00:24:09 +00:00
mapbox : : geometry : : linear_ring < long long > ring ;
2016-03-25 19:20:32 +00:00
for ( size_t k = i ; k < j ; k + + ) {
2017-01-07 00:24:09 +00:00
ring . push_back ( mapbox : : geometry : : point < long long > ( geom [ k ] . x , geom [ k ] . y ) ) ;
2015-12-21 23:56:21 +00:00
}
2017-01-07 00:24:09 +00:00
2017-01-26 21:25:06 +00:00
mapbox : : geometry : : linear_ring < long long > lr = mapbox : : geometry : : wagyu : : quick_clip : : quick_lr_clip ( ring , bbox ) ;
2017-01-07 00:24:09 +00:00
2017-01-26 21:25:06 +00:00
if ( lr . size ( ) > 0 ) {
for ( size_t k = 0 ; k < lr . size ( ) ; k + + ) {
2017-01-07 00:24:09 +00:00
if ( k = = 0 ) {
2017-01-26 21:25:06 +00:00
out . push_back ( draw ( VT_MOVETO , lr [ k ] . x , lr [ k ] . y ) ) ;
2017-01-07 00:24:09 +00:00
} else {
2017-01-26 21:25:06 +00:00
out . push_back ( draw ( VT_LINETO , lr [ k ] . x , lr [ k ] . y ) ) ;
2017-01-07 00:24:09 +00:00
}
}
2017-01-26 21:25:06 +00:00
if ( lr . size ( ) > 0 & & lr [ 0 ] ! = lr [ lr . size ( ) - 1 ] ) {
out . push_back ( draw ( VT_LINETO , lr [ 0 ] . x , lr [ 0 ] . y ) ) ;
2015-12-21 23:56:21 +00:00
}
}
i = j - 1 ;
} else {
fprintf ( stderr , " Unexpected operation in polygon %d \n " , ( int ) geom [ i ] . op ) ;
exit ( EXIT_FAILURE ) ;
}
}
return out ;
}
2016-12-09 18:47:03 +00:00
drawvec simple_clip_poly ( drawvec & geom , int z , int buffer ) {
2016-05-11 21:23:39 +00:00
long long area = 1LL < < ( 32 - z ) ;
2016-02-11 19:31:53 +00:00
long long clip_buffer = buffer * area / 256 ;
return simple_clip_poly ( geom , - clip_buffer , - clip_buffer , area + clip_buffer , area + clip_buffer ) ;
}
2014-10-24 22:12:02 +00:00
drawvec reduce_tiny_poly ( drawvec & geom , int z , int detail , bool * reduced , double * accum_area ) {
drawvec out ;
2015-10-14 22:50:40 +00:00
long long pixel = ( 1 < < ( 32 - detail - z ) ) * 2 ;
2014-10-24 22:12:02 +00:00
* reduced = true ;
2015-11-02 19:43:44 +00:00
bool included_last_outer = false ;
2014-10-24 22:12:02 +00:00
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
if ( geom [ i ] . op = = VT_MOVETO ) {
2016-03-25 19:20:32 +00:00
size_t j ;
2014-10-24 22:12:02 +00:00
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
2015-10-08 00:11:58 +00:00
if ( geom [ j ] . op ! = VT_LINETO ) {
2014-10-24 22:12:02 +00:00
break ;
}
}
2016-03-29 00:01:17 +00:00
double area = get_area ( geom , i , j ) ;
2014-10-24 22:12:02 +00:00
2015-12-09 23:02:59 +00:00
// XXX There is an ambiguity here: If the area of a ring is 0 and it is followed by holes,
// we don't know whether the area-0 ring was a hole too or whether it was the outer ring
// that these subsequent holes are somehow being subtracted from. I hope that if a polygon
// was simplified down to nothing, its holes also became nothing.
2014-10-24 22:12:02 +00:00
2015-12-09 23:02:59 +00:00
if ( area ! = 0 ) {
// These are pixel coordinates, so area > 0 for the outer ring.
// If the outer ring of a polygon was reduced to a pixel, its
// inner rings must just have their area de-accumulated rather
// than being drawn since we don't really know where they are.
2014-10-24 22:12:02 +00:00
2016-04-26 23:51:12 +00:00
if ( std : : fabs ( area ) < = pixel * pixel | | ( area < 0 & & ! included_last_outer ) ) {
2015-12-09 23:02:59 +00:00
// printf("area is only %f vs %lld so using square\n", area, pixel * pixel);
2014-10-24 22:12:02 +00:00
2015-12-09 23:02:59 +00:00
* accum_area + = area ;
if ( area > 0 & & * accum_area > pixel * pixel ) {
// XXX use centroid;
2015-11-02 19:43:44 +00:00
2015-12-09 23:02:59 +00:00
out . push_back ( draw ( VT_MOVETO , geom [ i ] . x - pixel / 2 , geom [ i ] . y - pixel / 2 ) ) ;
out . push_back ( draw ( VT_LINETO , geom [ i ] . x + pixel / 2 , geom [ i ] . y - pixel / 2 ) ) ;
out . push_back ( draw ( VT_LINETO , geom [ i ] . x + pixel / 2 , geom [ i ] . y + pixel / 2 ) ) ;
out . push_back ( draw ( VT_LINETO , geom [ i ] . x - pixel / 2 , geom [ i ] . y + pixel / 2 ) ) ;
out . push_back ( draw ( VT_LINETO , geom [ i ] . x - pixel / 2 , geom [ i ] . y - pixel / 2 ) ) ;
2014-10-24 22:12:02 +00:00
2015-12-09 23:02:59 +00:00
* accum_area - = pixel * pixel ;
}
if ( area > 0 ) {
included_last_outer = false ;
}
} else {
// printf("area is %f so keeping instead of %lld\n", area, pixel * pixel);
2016-03-25 19:20:32 +00:00
for ( size_t k = i ; k < = j & & k < geom . size ( ) ; k + + ) {
2015-12-09 23:02:59 +00:00
out . push_back ( geom [ k ] ) ;
}
2014-10-24 22:12:02 +00:00
2015-12-09 23:02:59 +00:00
* reduced = false ;
2015-11-02 19:43:44 +00:00
2015-12-09 23:02:59 +00:00
if ( area > 0 ) {
included_last_outer = true ;
}
2015-11-02 19:43:44 +00:00
}
2014-10-24 22:12:02 +00:00
}
2015-10-08 00:11:58 +00:00
i = j - 1 ;
2014-10-24 22:12:02 +00:00
} else {
2014-12-04 22:54:11 +00:00
fprintf ( stderr , " how did we get here with %d in %d? \n " , geom [ i ] . op , ( int ) geom . size ( ) ) ;
2016-03-25 19:20:32 +00:00
for ( size_t n = 0 ; n < geom . size ( ) ; n + + ) {
2014-12-04 22:54:11 +00:00
fprintf ( stderr , " %d/%lld/%lld " , geom [ n ] . op , geom [ n ] . x , geom [ n ] . y ) ;
}
fprintf ( stderr , " \n " ) ;
2014-10-24 22:12:02 +00:00
out . push_back ( geom [ i ] ) ;
}
}
return out ;
}
2016-12-09 18:47:03 +00:00
drawvec clip_point ( drawvec & geom , int z , long long buffer ) {
2014-12-04 00:18:43 +00:00
drawvec out ;
long long min = 0 ;
2016-05-09 23:01:10 +00:00
long long area = 1LL < < ( 32 - z ) ;
2014-12-04 00:18:43 +00:00
2016-05-09 23:01:10 +00:00
min - = buffer * area / 256 ;
area + = buffer * area / 256 ;
2014-12-04 00:18:43 +00:00
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-12-04 00:18:43 +00:00
if ( geom [ i ] . x > = min & & geom [ i ] . y > = min & & geom [ i ] . x < = area & & geom [ i ] . y < = area ) {
out . push_back ( geom [ i ] ) ;
}
}
return out ;
}
2014-10-24 22:12:02 +00:00
2016-12-09 18:47:03 +00:00
int quick_check ( long long * bbox , int z , long long buffer ) {
2014-12-11 21:34:50 +00:00
long long min = 0 ;
2016-05-09 23:01:10 +00:00
long long area = 1LL < < ( 32 - z ) ;
2014-12-11 21:34:50 +00:00
2016-05-09 23:01:10 +00:00
min - = buffer * area / 256 ;
area + = buffer * area / 256 ;
2014-12-11 21:34:50 +00:00
// bbox entirely outside the tile
if ( bbox [ 0 ] > area | | bbox [ 1 ] > area ) {
return 0 ;
}
if ( bbox [ 2 ] < min | | bbox [ 3 ] < min ) {
return 0 ;
}
// bbox entirely within the tile
if ( bbox [ 0 ] > min & & bbox [ 1 ] > min & & bbox [ 2 ] < area & & bbox [ 3 ] < area ) {
return 1 ;
}
// some overlap of edge
return 2 ;
}
2016-12-09 18:47:03 +00:00
bool point_within_tile ( long long x , long long y , int z , long long buffer ) {
2016-04-20 22:00:32 +00:00
// No adjustment for buffer, because the point must be
// strictly within the tile to appear exactly once
long long area = 1LL < < ( 32 - z ) ;
return x > = 0 & & y > = 0 & & x < area & & y < area ;
}
2016-12-09 18:47:03 +00:00
drawvec clip_lines ( drawvec & geom , int z , long long buffer ) {
2014-10-24 22:12:02 +00:00
drawvec out ;
2014-12-04 00:18:43 +00:00
long long min = 0 ;
2016-05-09 23:01:10 +00:00
long long area = 1LL < < ( 32 - z ) ;
min - = buffer * area / 256 ;
area + = buffer * area / 256 ;
2014-12-04 00:18:43 +00:00
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
if ( i > 0 & & ( geom [ i - 1 ] . op = = VT_MOVETO | | geom [ i - 1 ] . op = = VT_LINETO ) & & geom [ i ] . op = = VT_LINETO ) {
double x1 = geom [ i - 1 ] . x ;
double y1 = geom [ i - 1 ] . y ;
double x2 = geom [ i - 0 ] . x ;
double y2 = geom [ i - 0 ] . y ;
2014-10-27 20:20:17 +00:00
int c = clip ( & x1 , & y1 , & x2 , & y2 , min , min , area , area ) ;
2014-10-24 22:12:02 +00:00
2015-06-03 18:21:40 +00:00
if ( c > 1 ) { // clipped
2014-10-24 22:12:02 +00:00
out . push_back ( draw ( VT_MOVETO , x1 , y1 ) ) ;
out . push_back ( draw ( VT_LINETO , x2 , y2 ) ) ;
out . push_back ( draw ( VT_MOVETO , geom [ i ] . x , geom [ i ] . y ) ) ;
2015-06-03 18:21:40 +00:00
} else if ( c = = 1 ) { // unchanged
2014-10-24 22:12:02 +00:00
out . push_back ( geom [ i ] ) ;
2015-06-03 18:21:40 +00:00
} else { // clipped away entirely
2014-10-24 22:12:02 +00:00
out . push_back ( draw ( VT_MOVETO , geom [ i ] . x , geom [ i ] . y ) ) ;
}
} else {
out . push_back ( geom [ i ] ) ;
}
}
return out ;
}
static double square_distance_from_line ( long long point_x , long long point_y , long long segA_x , long long segA_y , long long segB_x , long long segB_y ) {
double p2x = segB_x - segA_x ;
double p2y = segB_y - segA_y ;
double something = p2x * p2x + p2y * p2y ;
double u = 0 = = something ? 0 : ( ( point_x - segA_x ) * p2x + ( point_y - segA_y ) * p2y ) / something ;
if ( u > 1 ) {
u = 1 ;
} else if ( u < 0 ) {
u = 0 ;
}
double x = segA_x + u * p2x ;
double y = segA_y + u * p2y ;
double dx = x - point_x ;
double dy = y - point_y ;
return dx * dx + dy * dy ;
}
// https://github.com/Project-OSRM/osrm-backend/blob/733d1384a40f/Algorithms/DouglasePeucker.cpp
2016-11-14 19:22:21 +00:00
static void douglas_peucker ( drawvec & geom , int start , int n , double e , size_t kept , size_t retain ) {
2014-10-24 22:12:02 +00:00
e = e * e ;
std : : stack < int > recursion_stack ;
{
int left_border = 0 ;
int right_border = 1 ;
// Sweep linerarily over array and identify those ranges that need to be checked
do {
if ( geom [ start + right_border ] . necessary ) {
recursion_stack . push ( left_border ) ;
recursion_stack . push ( right_border ) ;
left_border = right_border ;
}
+ + right_border ;
} while ( right_border < n ) ;
}
while ( ! recursion_stack . empty ( ) ) {
// pop next element
int second = recursion_stack . top ( ) ;
recursion_stack . pop ( ) ;
int first = recursion_stack . top ( ) ;
recursion_stack . pop ( ) ;
double max_distance = - 1 ;
int farthest_element_index = second ;
// find index idx of element with max_distance
int i ;
for ( i = first + 1 ; i < second ; i + + ) {
2015-06-03 18:21:40 +00:00
double temp_dist = square_distance_from_line ( geom [ start + i ] . x , geom [ start + i ] . y , geom [ start + first ] . x , geom [ start + first ] . y , geom [ start + second ] . x , geom [ start + second ] . y ) ;
2014-10-24 22:12:02 +00:00
2016-04-26 23:51:12 +00:00
double distance = std : : fabs ( temp_dist ) ;
2014-10-24 22:12:02 +00:00
2016-11-14 19:22:21 +00:00
if ( ( distance > e | | kept < retain ) & & distance > max_distance ) {
2014-10-24 22:12:02 +00:00
farthest_element_index = i ;
max_distance = distance ;
}
}
2016-11-14 19:22:21 +00:00
if ( max_distance > = 0 ) {
2014-10-24 22:12:02 +00:00
// mark idx as necessary
geom [ start + farthest_element_index ] . necessary = 1 ;
2016-11-14 19:22:21 +00:00
kept + + ;
2014-10-24 22:12:02 +00:00
if ( 1 < farthest_element_index - first ) {
recursion_stack . push ( first ) ;
recursion_stack . push ( farthest_element_index ) ;
}
if ( 1 < second - farthest_element_index ) {
recursion_stack . push ( farthest_element_index ) ;
recursion_stack . push ( second ) ;
}
}
}
}
2016-01-07 19:35:11 +00:00
// If any line segment crosses a tile boundary, add a node there
// that cannot be simplified away, to prevent the edge of any
// feature from jumping abruptly at the tile boundary.
drawvec impose_tile_boundaries ( drawvec & geom , long long extent ) {
drawvec out ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2016-01-07 19:35:11 +00:00
if ( i > 0 & & geom [ i ] . op = = VT_LINETO & & ( geom [ i - 1 ] . op = = VT_MOVETO | | geom [ i - 1 ] . op = = VT_LINETO ) ) {
double x1 = geom [ i - 1 ] . x ;
double y1 = geom [ i - 1 ] . y ;
double x2 = geom [ i - 0 ] . x ;
double y2 = geom [ i - 0 ] . y ;
int c = clip ( & x1 , & y1 , & x2 , & y2 , 0 , 0 , extent , extent ) ;
if ( c > 1 ) { // clipped
if ( x1 ! = geom [ i - 1 ] . x | | y1 ! = geom [ i - 1 ] . y ) {
out . push_back ( draw ( VT_LINETO , x1 , y1 ) ) ;
out [ out . size ( ) - 1 ] . necessary = 1 ;
}
if ( x2 ! = geom [ i - 0 ] . x | | y2 ! = geom [ i - 0 ] . y ) {
out . push_back ( draw ( VT_LINETO , x2 , y2 ) ) ;
out [ out . size ( ) - 1 ] . necessary = 1 ;
}
}
}
out . push_back ( geom [ i ] ) ;
}
return out ;
}
2016-11-14 19:22:21 +00:00
drawvec simplify_lines ( drawvec & geom , int z , int detail , bool mark_tile_bounds , double simplification , size_t retain ) {
2014-10-24 22:12:02 +00:00
int res = 1 < < ( 32 - detail - z ) ;
2016-05-09 23:01:10 +00:00
long long area = 1LL < < ( 32 - z ) ;
2014-10-24 22:12:02 +00:00
2016-10-26 22:47:26 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO ) {
geom [ i ] . necessary = 1 ;
} else if ( geom [ i ] . op = = VT_LINETO ) {
geom [ i ] . necessary = 0 ;
} else {
geom [ i ] . necessary = 1 ;
2014-10-24 22:12:02 +00:00
}
}
2016-04-19 23:13:02 +00:00
if ( mark_tile_bounds ) {
geom = impose_tile_boundaries ( geom , area ) ;
}
2016-01-07 19:35:11 +00:00
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
if ( geom [ i ] . op = = VT_MOVETO ) {
2016-03-25 19:20:32 +00:00
size_t j ;
2014-10-24 22:12:02 +00:00
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
2015-10-08 00:11:58 +00:00
if ( geom [ j ] . op ! = VT_LINETO ) {
2014-10-24 22:12:02 +00:00
break ;
}
}
geom [ i ] . necessary = 1 ;
geom [ j - 1 ] . necessary = 1 ;
2016-04-07 23:45:45 +00:00
if ( j - i > 1 ) {
2016-11-14 19:22:21 +00:00
douglas_peucker ( geom , i , j - i , res * simplification , 2 , retain ) ;
2016-04-07 23:45:45 +00:00
}
2014-10-24 22:12:02 +00:00
i = j - 1 ;
}
}
drawvec out ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
if ( geom [ i ] . necessary ) {
out . push_back ( geom [ i ] ) ;
}
}
return out ;
}
drawvec reorder_lines ( drawvec & geom ) {
// Only reorder simple linestrings with a single moveto
2014-12-04 00:30:35 +00:00
if ( geom . size ( ) = = 0 ) {
return geom ;
}
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
if ( geom [ i ] . op = = VT_MOVETO ) {
if ( i ! = 0 ) {
return geom ;
}
} else if ( geom [ i ] . op = = VT_LINETO ) {
if ( i = = 0 ) {
return geom ;
}
} else {
return geom ;
}
}
// Reorder anything that goes up and to the left
// instead of down and to the right
// so that it will coalesce better
unsigned long long l1 = encode ( geom [ 0 ] . x , geom [ 0 ] . y ) ;
unsigned long long l2 = encode ( geom [ geom . size ( ) - 1 ] . x , geom [ geom . size ( ) - 1 ] . y ) ;
if ( l1 > l2 ) {
drawvec out ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2014-10-24 22:12:02 +00:00
out . push_back ( geom [ geom . size ( ) - 1 - i ] ) ;
}
out [ 0 ] . op = VT_MOVETO ;
out [ out . size ( ) - 1 ] . op = VT_LINETO ;
return out ;
}
return geom ;
}
2015-10-07 23:52:52 +00:00
drawvec fix_polygon ( drawvec & geom ) {
int outer = 1 ;
drawvec out ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2015-10-07 23:52:52 +00:00
if ( geom [ i ] . op = = VT_CLOSEPATH ) {
outer = 1 ;
} else if ( geom [ i ] . op = = VT_MOVETO ) {
// Find the end of the ring
2016-03-25 19:20:32 +00:00
size_t j ;
2015-10-07 23:52:52 +00:00
for ( j = i + 1 ; j < geom . size ( ) ; j + + ) {
if ( geom [ j ] . op ! = VT_LINETO ) {
break ;
}
}
// Make a temporary copy of the ring.
// Close it if it isn't closed.
drawvec ring ;
2016-03-25 19:20:32 +00:00
for ( size_t a = i ; a < j ; a + + ) {
2015-10-07 23:52:52 +00:00
ring . push_back ( geom [ a ] ) ;
}
if ( j - i ! = 0 & & ( ring [ 0 ] . x ! = ring [ j - i - 1 ] . x | | ring [ 0 ] . y ! = ring [ j - i - 1 ] . y ) ) {
ring . push_back ( ring [ 0 ] ) ;
}
// Reverse ring if winding order doesn't match
// inner/outer expectation
2016-03-29 00:01:17 +00:00
double area = get_area ( ring , 0 , ring . size ( ) ) ;
2015-10-07 23:52:52 +00:00
if ( ( area > 0 ) ! = outer ) {
drawvec tmp ;
for ( int a = ring . size ( ) - 1 ; a > = 0 ; a - - ) {
tmp . push_back ( ring [ a ] ) ;
}
ring = tmp ;
}
// Copy ring into output, fixing the moveto/lineto ops if necessary because of
// reversal or closing
2016-03-25 19:20:32 +00:00
for ( size_t a = 0 ; a < ring . size ( ) ; a + + ) {
2015-10-07 23:52:52 +00:00
if ( a = = 0 ) {
out . push_back ( draw ( VT_MOVETO , ring [ a ] . x , ring [ a ] . y ) ) ;
} else {
out . push_back ( draw ( VT_LINETO , ring [ a ] . x , ring [ a ] . y ) ) ;
}
}
// Next ring or polygon begins on the non-lineto that ended this one
// and is not an outer ring unless there is a terminator first
i = j - 1 ;
outer = 0 ;
} else {
fprintf ( stderr , " Internal error: polygon ring begins with %d, not moveto \n " , geom [ i ] . op ) ;
exit ( EXIT_FAILURE ) ;
}
}
return out ;
}
2016-02-11 19:31:53 +00:00
std : : vector < drawvec > chop_polygon ( std : : vector < drawvec > & geoms ) {
while ( 1 ) {
bool again = false ;
std : : vector < drawvec > out ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < geoms . size ( ) ; i + + ) {
2016-02-11 19:31:53 +00:00
if ( geoms [ i ] . size ( ) > 700 ) {
2016-03-24 00:35:19 +00:00
static bool warned = false ;
if ( ! warned ) {
fprintf ( stderr , " Warning: splitting up polygon with more than 700 sides \n " ) ;
warned = true ;
}
2016-02-11 19:31:53 +00:00
long long midx = 0 , midy = 0 , count = 0 ;
2016-03-21 23:13:47 +00:00
long long maxx = LLONG_MIN , maxy = LLONG_MIN , minx = LLONG_MAX , miny = LLONG_MAX ;
2016-02-11 19:31:53 +00:00
2016-03-25 19:20:32 +00:00
for ( size_t j = 0 ; j < geoms [ i ] . size ( ) ; j + + ) {
2016-02-11 19:31:53 +00:00
if ( geoms [ i ] [ j ] . op = = VT_MOVETO | | geoms [ i ] [ j ] . op = = VT_LINETO ) {
midx + = geoms [ i ] [ j ] . x ;
midy + = geoms [ i ] [ j ] . y ;
count + + ;
if ( geoms [ i ] [ j ] . x > maxx ) {
maxx = geoms [ i ] [ j ] . x ;
}
if ( geoms [ i ] [ j ] . y > maxy ) {
maxy = geoms [ i ] [ j ] . y ;
}
if ( geoms [ i ] [ j ] . x < minx ) {
minx = geoms [ i ] [ j ] . x ;
}
if ( geoms [ i ] [ j ] . y < miny ) {
miny = geoms [ i ] [ j ] . y ;
}
}
}
2016-02-11 20:14:32 +00:00
midx / = count ;
midy / = count ;
2016-03-11 01:07:22 +00:00
drawvec c1 , c2 ;
2016-02-11 20:14:32 +00:00
if ( maxy - miny > maxx - minx ) {
// printf("clipping y to %lld %lld %lld %lld\n", minx, miny, maxx, midy);
2016-03-11 01:07:22 +00:00
c1 = simple_clip_poly ( geoms [ i ] , minx , miny , maxx , midy ) ;
2016-02-11 20:14:32 +00:00
// printf(" and %lld %lld %lld %lld\n", minx, midy, maxx, maxy);
2016-03-11 01:07:22 +00:00
c2 = simple_clip_poly ( geoms [ i ] , minx , midy , maxx , maxy ) ;
2016-02-11 20:14:32 +00:00
} else {
// printf("clipping x to %lld %lld %lld %lld\n", minx, miny, midx, maxy);
2016-03-11 01:07:22 +00:00
c1 = simple_clip_poly ( geoms [ i ] , minx , miny , midx , maxy ) ;
2016-02-11 20:14:32 +00:00
// printf(" and %lld %lld %lld %lld\n", midx, midy, maxx, maxy);
2016-03-11 01:07:22 +00:00
c2 = simple_clip_poly ( geoms [ i ] , midx , miny , maxx , maxy ) ;
}
if ( c1 . size ( ) > = geoms [ i ] . size ( ) ) {
fprintf ( stderr , " Subdividing complex polygon failed \n " ) ;
} else {
out . push_back ( c1 ) ;
}
if ( c2 . size ( ) > = geoms [ i ] . size ( ) ) {
fprintf ( stderr , " Subdividing complex polygon failed \n " ) ;
} else {
out . push_back ( c2 ) ;
2016-02-11 20:14:32 +00:00
}
again = true ;
2016-02-11 19:31:53 +00:00
} else {
out . push_back ( geoms [ i ] ) ;
}
}
if ( ! again ) {
return out ;
}
geoms = out ;
}
}
2016-04-27 19:25:03 +00:00
# define INSIDE 0
# define LEFT 1
# define RIGHT 2
# define BOTTOM 4
# define TOP 8
static int computeOutCode ( double x , double y , double xmin , double ymin , double xmax , double ymax ) {
int code = INSIDE ;
if ( x < xmin ) {
code | = LEFT ;
} else if ( x > xmax ) {
code | = RIGHT ;
}
if ( y < ymin ) {
code | = BOTTOM ;
} else if ( y > ymax ) {
code | = TOP ;
}
return code ;
}
static int clip ( double * x0 , double * y0 , double * x1 , double * y1 , double xmin , double ymin , double xmax , double ymax ) {
int outcode0 = computeOutCode ( * x0 , * y0 , xmin , ymin , xmax , ymax ) ;
int outcode1 = computeOutCode ( * x1 , * y1 , xmin , ymin , xmax , ymax ) ;
int accept = 0 ;
int changed = 0 ;
while ( 1 ) {
if ( ! ( outcode0 | outcode1 ) ) { // Bitwise OR is 0. Trivially accept and get out of loop
accept = 1 ;
break ;
} else if ( outcode0 & outcode1 ) { // Bitwise AND is not 0. Trivially reject and get out of loop
break ;
} else {
// failed both tests, so calculate the line segment to clip
// from an outside point to an intersection with clip edge
double x = * x0 , y = * y0 ;
// At least one endpoint is outside the clip rectangle; pick it.
int outcodeOut = outcode0 ? outcode0 : outcode1 ;
// Now find the intersection point;
// use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
if ( outcodeOut & TOP ) { // point is above the clip rectangle
x = * x0 + ( * x1 - * x0 ) * ( ymax - * y0 ) / ( * y1 - * y0 ) ;
y = ymax ;
} else if ( outcodeOut & BOTTOM ) { // point is below the clip rectangle
x = * x0 + ( * x1 - * x0 ) * ( ymin - * y0 ) / ( * y1 - * y0 ) ;
y = ymin ;
} else if ( outcodeOut & RIGHT ) { // point is to the right of clip rectangle
y = * y0 + ( * y1 - * y0 ) * ( xmax - * x0 ) / ( * x1 - * x0 ) ;
x = xmax ;
} else if ( outcodeOut & LEFT ) { // point is to the left of clip rectangle
y = * y0 + ( * y1 - * y0 ) * ( xmin - * x0 ) / ( * x1 - * x0 ) ;
x = xmin ;
}
// Now we move outside point to intersection point to clip
// and get ready for next pass.
if ( outcodeOut = = outcode0 ) {
* x0 = x ;
* y0 = y ;
outcode0 = computeOutCode ( * x0 , * y0 , xmin , ymin , xmax , ymax ) ;
changed = 1 ;
} else {
* x1 = x ;
* y1 = y ;
outcode1 = computeOutCode ( * x1 , * y1 , xmin , ymin , xmax , ymax ) ;
changed = 1 ;
}
}
}
if ( accept = = 0 ) {
return 0 ;
} else {
return changed + 1 ;
}
}
2016-11-28 22:55:22 +00:00
drawvec stairstep ( drawvec & geom , int z , int detail ) {
drawvec out ;
2016-11-29 23:18:44 +00:00
double scale = 1 < < ( 32 - detail - z ) ;
2016-11-28 22:55:22 +00:00
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
2016-11-29 23:18:44 +00:00
geom [ i ] . x = std : : round ( geom [ i ] . x / scale ) ;
geom [ i ] . y = std : : round ( geom [ i ] . y / scale ) ;
2016-11-28 22:55:22 +00:00
}
for ( size_t i = 0 ; i < geom . size ( ) ; i + + ) {
if ( geom [ i ] . op = = VT_MOVETO ) {
out . push_back ( geom [ i ] ) ;
} else {
long long x0 = out [ out . size ( ) - 1 ] . x ;
long long y0 = out [ out . size ( ) - 1 ] . y ;
long long x1 = geom [ i ] . x ;
long long y1 = geom [ i ] . y ;
bool swap = false ;
if ( y0 < y1 ) {
swap = true ;
std : : swap ( x0 , x1 ) ;
std : : swap ( y0 , y1 ) ;
}
long long xx = x0 , yy = y0 ;
long long dx = std : : abs ( x1 - x0 ) ;
long long sx = ( x0 < x1 ) ? 1 : - 1 ;
long long dy = std : : abs ( y1 - y0 ) ;
long long sy = ( y0 < y1 ) ? 1 : - 1 ;
long long err = ( ( dx > dy ) ? dx : - dy ) / 2 ;
int last = - 1 ;
drawvec tmp ;
tmp . push_back ( draw ( VT_LINETO , xx , yy ) ) ;
while ( xx ! = x1 | | yy ! = y1 ) {
long long e2 = err ;
if ( e2 > - dx ) {
err - = dy ;
xx + = sx ;
if ( last = = 1 ) {
tmp [ tmp . size ( ) - 1 ] = draw ( VT_LINETO , xx , yy ) ;
} else {
tmp . push_back ( draw ( VT_LINETO , xx , yy ) ) ;
}
last = 1 ;
}
if ( e2 < dy ) {
err + = dx ;
yy + = sy ;
if ( last = = 2 ) {
tmp [ tmp . size ( ) - 1 ] = draw ( VT_LINETO , xx , yy ) ;
} else {
tmp . push_back ( draw ( VT_LINETO , xx , yy ) ) ;
}
last = 2 ;
}
}
if ( swap ) {
for ( size_t j = tmp . size ( ) ; j > 0 ; j - - ) {
out . push_back ( tmp [ j - 1 ] ) ;
}
} else {
for ( size_t j = 0 ; j < tmp . size ( ) ; j + + ) {
out . push_back ( tmp [ j ] ) ;
}
}
// out.push_back(draw(VT_LINETO, xx, yy));
}
}
for ( size_t i = 0 ; i < out . size ( ) ; i + + ) {
2016-12-14 00:19:38 +00:00
out [ i ] . x * = 1 < < ( 32 - detail - z ) ;
out [ i ] . y * = 1 < < ( 32 - detail - z ) ;
2016-11-28 22:55:22 +00:00
}
return out ;
}