xref: /sqlite-3.40.0/ext/rtree/geopoly.c (revision f98109e7)
1 /*
2 ** 2018-05-25
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 ** This file implements an alternative R-Tree virtual table that
14 ** uses polygons to express the boundaries of 2-dimensional objects.
15 **
16 ** This file is #include-ed onto the end of "rtree.c" so that it has
17 ** access to all of the R-Tree internals.
18 */
19 #include <stdlib.h>
20 
21 /* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */
22 #ifdef GEOPOLY_ENABLE_DEBUG
23   static int geo_debug = 0;
24 # define GEODEBUG(X) if(geo_debug)printf X
25 #else
26 # define GEODEBUG(X)
27 #endif
28 
29 /* Character class routines */
30 #ifdef sqlite3Isdigit
31    /* Use the SQLite core versions if this routine is part of the
32    ** SQLite amalgamation */
33 #  define safe_isdigit(x)  sqlite3Isdigit(x)
34 #  define safe_isalnum(x)  sqlite3Isalnum(x)
35 #  define safe_isxdigit(x) sqlite3Isxdigit(x)
36 #else
37    /* Use the standard library for separate compilation */
38 #include <ctype.h>  /* amalgamator: keep */
39 #  define safe_isdigit(x)  isdigit((unsigned char)(x))
40 #  define safe_isalnum(x)  isalnum((unsigned char)(x))
41 #  define safe_isxdigit(x) isxdigit((unsigned char)(x))
42 #endif
43 
44 #ifndef JSON_NULL   /* The following stuff repeats things found in json1 */
45 /*
46 ** Growing our own isspace() routine this way is twice as fast as
47 ** the library isspace() function.
48 */
49 static const char geopolyIsSpace[] = {
50   0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
51   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
52   1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
53   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
54   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
55   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
56   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
57   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
58   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
59   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
60   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
61   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
62   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
63   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
64   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
65   0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
66 };
67 #define fast_isspace(x) (geopolyIsSpace[(unsigned char)x])
68 #endif /* JSON NULL - back to original code */
69 
70 /* Compiler and version */
71 #ifndef GCC_VERSION
72 #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
73 # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
74 #else
75 # define GCC_VERSION 0
76 #endif
77 #endif
78 #ifndef MSVC_VERSION
79 #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
80 # define MSVC_VERSION _MSC_VER
81 #else
82 # define MSVC_VERSION 0
83 #endif
84 #endif
85 
86 /* Datatype for coordinates
87 */
88 typedef float GeoCoord;
89 
90 /*
91 ** Internal representation of a polygon.
92 **
93 ** The polygon consists of a sequence of vertexes.  There is a line
94 ** segment between each pair of vertexes, and one final segment from
95 ** the last vertex back to the first.  (This differs from the GeoJSON
96 ** standard in which the final vertex is a repeat of the first.)
97 **
98 ** The polygon follows the right-hand rule.  The area to the right of
99 ** each segment is "outside" and the area to the left is "inside".
100 **
101 ** The on-disk representation consists of a 4-byte header followed by
102 ** the values.  The 4-byte header is:
103 **
104 **      encoding    (1 byte)   0=big-endian, 1=little-endian
105 **      nvertex     (3 bytes)  Number of vertexes as a big-endian integer
106 **
107 ** Enough space is allocated for 4 coordinates, to work around over-zealous
108 ** warnings coming from some compiler (notably, clang). In reality, the size
109 ** of each GeoPoly memory allocate is adjusted as necessary so that the
110 ** GeoPoly.a[] array at the end is the appropriate size.
111 */
112 typedef struct GeoPoly GeoPoly;
113 struct GeoPoly {
114   int nVertex;          /* Number of vertexes */
115   unsigned char hdr[4]; /* Header for on-disk representation */
116   GeoCoord a[8];        /* 2*nVertex values. X (longitude) first, then Y */
117 };
118 
119 /* The size of a memory allocation needed for a GeoPoly object sufficient
120 ** to hold N coordinate pairs.
121 */
122 #define GEOPOLY_SZ(N)  (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4))
123 
124 /* Macros to access coordinates of a GeoPoly.
125 ** We have to use these macros, rather than just say p->a[i] in order
126 ** to silence (incorrect) UBSAN warnings if the array index is too large.
127 */
128 #define GeoX(P,I)  (((GeoCoord*)(P)->a)[(I)*2])
129 #define GeoY(P,I)  (((GeoCoord*)(P)->a)[(I)*2+1])
130 
131 
132 /*
133 ** State of a parse of a GeoJSON input.
134 */
135 typedef struct GeoParse GeoParse;
136 struct GeoParse {
137   const unsigned char *z;   /* Unparsed input */
138   int nVertex;              /* Number of vertexes in a[] */
139   int nAlloc;               /* Space allocated to a[] */
140   int nErr;                 /* Number of errors encountered */
141   GeoCoord *a;          /* Array of vertexes.  From sqlite3_malloc64() */
142 };
143 
144 /* Do a 4-byte byte swap */
geopolySwab32(unsigned char * a)145 static void geopolySwab32(unsigned char *a){
146   unsigned char t = a[0];
147   a[0] = a[3];
148   a[3] = t;
149   t = a[1];
150   a[1] = a[2];
151   a[2] = t;
152 }
153 
154 /* Skip whitespace.  Return the next non-whitespace character. */
geopolySkipSpace(GeoParse * p)155 static char geopolySkipSpace(GeoParse *p){
156   while( fast_isspace(p->z[0]) ) p->z++;
157   return p->z[0];
158 }
159 
160 /* Parse out a number.  Write the value into *pVal if pVal!=0.
161 ** return non-zero on success and zero if the next token is not a number.
162 */
geopolyParseNumber(GeoParse * p,GeoCoord * pVal)163 static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
164   char c = geopolySkipSpace(p);
165   const unsigned char *z = p->z;
166   int j = 0;
167   int seenDP = 0;
168   int seenE = 0;
169   if( c=='-' ){
170     j = 1;
171     c = z[j];
172   }
173   if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0;
174   for(;; j++){
175     c = z[j];
176     if( safe_isdigit(c) ) continue;
177     if( c=='.' ){
178       if( z[j-1]=='-' ) return 0;
179       if( seenDP ) return 0;
180       seenDP = 1;
181       continue;
182     }
183     if( c=='e' || c=='E' ){
184       if( z[j-1]<'0' ) return 0;
185       if( seenE ) return -1;
186       seenDP = seenE = 1;
187       c = z[j+1];
188       if( c=='+' || c=='-' ){
189         j++;
190         c = z[j+1];
191       }
192       if( c<'0' || c>'9' ) return 0;
193       continue;
194     }
195     break;
196   }
197   if( z[j-1]<'0' ) return 0;
198   if( pVal ){
199 #ifdef SQLITE_AMALGAMATION
200      /* The sqlite3AtoF() routine is much much faster than atof(), if it
201      ** is available */
202      double r;
203      (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8);
204      *pVal = r;
205 #else
206      *pVal = (GeoCoord)atof((const char*)p->z);
207 #endif
208   }
209   p->z += j;
210   return 1;
211 }
212 
213 /*
214 ** If the input is a well-formed JSON array of coordinates with at least
215 ** four coordinates and where each coordinate is itself a two-value array,
216 ** then convert the JSON into a GeoPoly object and return a pointer to
217 ** that object.
218 **
219 ** If any error occurs, return NULL.
220 */
geopolyParseJson(const unsigned char * z,int * pRc)221 static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
222   GeoParse s;
223   int rc = SQLITE_OK;
224   memset(&s, 0, sizeof(s));
225   s.z = z;
226   if( geopolySkipSpace(&s)=='[' ){
227     s.z++;
228     while( geopolySkipSpace(&s)=='[' ){
229       int ii = 0;
230       char c;
231       s.z++;
232       if( s.nVertex>=s.nAlloc ){
233         GeoCoord *aNew;
234         s.nAlloc = s.nAlloc*2 + 16;
235         aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 );
236         if( aNew==0 ){
237           rc = SQLITE_NOMEM;
238           s.nErr++;
239           break;
240         }
241         s.a = aNew;
242       }
243       while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){
244         ii++;
245         if( ii==2 ) s.nVertex++;
246         c = geopolySkipSpace(&s);
247         s.z++;
248         if( c==',' ) continue;
249         if( c==']' && ii>=2 ) break;
250         s.nErr++;
251         rc = SQLITE_ERROR;
252         goto parse_json_err;
253       }
254       if( geopolySkipSpace(&s)==',' ){
255         s.z++;
256         continue;
257       }
258       break;
259     }
260     if( geopolySkipSpace(&s)==']'
261      && s.nVertex>=4
262      && s.a[0]==s.a[s.nVertex*2-2]
263      && s.a[1]==s.a[s.nVertex*2-1]
264      && (s.z++, geopolySkipSpace(&s)==0)
265     ){
266       GeoPoly *pOut;
267       int x = 1;
268       s.nVertex--;  /* Remove the redundant vertex at the end */
269       pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) );
270       x = 1;
271       if( pOut==0 ) goto parse_json_err;
272       pOut->nVertex = s.nVertex;
273       memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord));
274       pOut->hdr[0] = *(unsigned char*)&x;
275       pOut->hdr[1] = (s.nVertex>>16)&0xff;
276       pOut->hdr[2] = (s.nVertex>>8)&0xff;
277       pOut->hdr[3] = s.nVertex&0xff;
278       sqlite3_free(s.a);
279       if( pRc ) *pRc = SQLITE_OK;
280       return pOut;
281     }else{
282       s.nErr++;
283       rc = SQLITE_ERROR;
284     }
285   }
286 parse_json_err:
287   if( pRc ) *pRc = rc;
288   sqlite3_free(s.a);
289   return 0;
290 }
291 
292 /*
293 ** Given a function parameter, try to interpret it as a polygon, either
294 ** in the binary format or JSON text.  Compute a GeoPoly object and
295 ** return a pointer to that object.  Or if the input is not a well-formed
296 ** polygon, put an error message in sqlite3_context and return NULL.
297 */
geopolyFuncParam(sqlite3_context * pCtx,sqlite3_value * pVal,int * pRc)298 static GeoPoly *geopolyFuncParam(
299   sqlite3_context *pCtx,      /* Context for error messages */
300   sqlite3_value *pVal,        /* The value to decode */
301   int *pRc                    /* Write error here */
302 ){
303   GeoPoly *p = 0;
304   int nByte;
305   testcase( pCtx==0 );
306   if( sqlite3_value_type(pVal)==SQLITE_BLOB
307    && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
308   ){
309     const unsigned char *a = sqlite3_value_blob(pVal);
310     int nVertex;
311     if( a==0 ){
312       if( pCtx ) sqlite3_result_error_nomem(pCtx);
313       return 0;
314     }
315     nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
316     if( (a[0]==0 || a[0]==1)
317      && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
318     ){
319       p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
320       if( p==0 ){
321         if( pRc ) *pRc = SQLITE_NOMEM;
322         if( pCtx ) sqlite3_result_error_nomem(pCtx);
323       }else{
324         int x = 1;
325         p->nVertex = nVertex;
326         memcpy(p->hdr, a, nByte);
327         if( a[0] != *(unsigned char*)&x ){
328           int ii;
329           for(ii=0; ii<nVertex; ii++){
330             geopolySwab32((unsigned char*)&GeoX(p,ii));
331             geopolySwab32((unsigned char*)&GeoY(p,ii));
332           }
333           p->hdr[0] ^= 1;
334         }
335       }
336     }
337     if( pRc ) *pRc = SQLITE_OK;
338     return p;
339   }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){
340     const unsigned char *zJson = sqlite3_value_text(pVal);
341     if( zJson==0 ){
342       if( pRc ) *pRc = SQLITE_NOMEM;
343       return 0;
344     }
345     return geopolyParseJson(zJson, pRc);
346   }else{
347     if( pRc ) *pRc = SQLITE_ERROR;
348     return 0;
349   }
350 }
351 
352 /*
353 ** Implementation of the geopoly_blob(X) function.
354 **
355 ** If the input is a well-formed Geopoly BLOB or JSON string
356 ** then return the BLOB representation of the polygon.  Otherwise
357 ** return NULL.
358 */
geopolyBlobFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)359 static void geopolyBlobFunc(
360   sqlite3_context *context,
361   int argc,
362   sqlite3_value **argv
363 ){
364   GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
365   if( p ){
366     sqlite3_result_blob(context, p->hdr,
367        4+8*p->nVertex, SQLITE_TRANSIENT);
368     sqlite3_free(p);
369   }
370 }
371 
372 /*
373 ** SQL function:     geopoly_json(X)
374 **
375 ** Interpret X as a polygon and render it as a JSON array
376 ** of coordinates.  Or, if X is not a valid polygon, return NULL.
377 */
geopolyJsonFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)378 static void geopolyJsonFunc(
379   sqlite3_context *context,
380   int argc,
381   sqlite3_value **argv
382 ){
383   GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
384   if( p ){
385     sqlite3 *db = sqlite3_context_db_handle(context);
386     sqlite3_str *x = sqlite3_str_new(db);
387     int i;
388     sqlite3_str_append(x, "[", 1);
389     for(i=0; i<p->nVertex; i++){
390       sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i));
391     }
392     sqlite3_str_appendf(x, "[%!g,%!g]]", GeoX(p,0), GeoY(p,0));
393     sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free);
394     sqlite3_free(p);
395   }
396 }
397 
398 /*
399 ** SQL function:     geopoly_svg(X, ....)
400 **
401 ** Interpret X as a polygon and render it as a SVG <polyline>.
402 ** Additional arguments are added as attributes to the <polyline>.
403 */
geopolySvgFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)404 static void geopolySvgFunc(
405   sqlite3_context *context,
406   int argc,
407   sqlite3_value **argv
408 ){
409   GeoPoly *p;
410   if( argc<1 ) return;
411   p = geopolyFuncParam(context, argv[0], 0);
412   if( p ){
413     sqlite3 *db = sqlite3_context_db_handle(context);
414     sqlite3_str *x = sqlite3_str_new(db);
415     int i;
416     char cSep = '\'';
417     sqlite3_str_appendf(x, "<polyline points=");
418     for(i=0; i<p->nVertex; i++){
419       sqlite3_str_appendf(x, "%c%g,%g", cSep, GeoX(p,i), GeoY(p,i));
420       cSep = ' ';
421     }
422     sqlite3_str_appendf(x, " %g,%g'", GeoX(p,0), GeoY(p,0));
423     for(i=1; i<argc; i++){
424       const char *z = (const char*)sqlite3_value_text(argv[i]);
425       if( z && z[0] ){
426         sqlite3_str_appendf(x, " %s", z);
427       }
428     }
429     sqlite3_str_appendf(x, "></polyline>");
430     sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free);
431     sqlite3_free(p);
432   }
433 }
434 
435 /*
436 ** SQL Function:      geopoly_xform(poly, A, B, C, D, E, F)
437 **
438 ** Transform and/or translate a polygon as follows:
439 **
440 **      x1 = A*x0 + B*y0 + E
441 **      y1 = C*x0 + D*y0 + F
442 **
443 ** For a translation:
444 **
445 **      geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset)
446 **
447 ** Rotate by R around the point (0,0):
448 **
449 **      geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0)
450 */
geopolyXformFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)451 static void geopolyXformFunc(
452   sqlite3_context *context,
453   int argc,
454   sqlite3_value **argv
455 ){
456   GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
457   double A = sqlite3_value_double(argv[1]);
458   double B = sqlite3_value_double(argv[2]);
459   double C = sqlite3_value_double(argv[3]);
460   double D = sqlite3_value_double(argv[4]);
461   double E = sqlite3_value_double(argv[5]);
462   double F = sqlite3_value_double(argv[6]);
463   GeoCoord x1, y1, x0, y0;
464   int ii;
465   if( p ){
466     for(ii=0; ii<p->nVertex; ii++){
467       x0 = GeoX(p,ii);
468       y0 = GeoY(p,ii);
469       x1 = (GeoCoord)(A*x0 + B*y0 + E);
470       y1 = (GeoCoord)(C*x0 + D*y0 + F);
471       GeoX(p,ii) = x1;
472       GeoY(p,ii) = y1;
473     }
474     sqlite3_result_blob(context, p->hdr,
475        4+8*p->nVertex, SQLITE_TRANSIENT);
476     sqlite3_free(p);
477   }
478 }
479 
480 /*
481 ** Compute the area enclosed by the polygon.
482 **
483 ** This routine can also be used to detect polygons that rotate in
484 ** the wrong direction.  Polygons are suppose to be counter-clockwise (CCW).
485 ** This routine returns a negative value for clockwise (CW) polygons.
486 */
geopolyArea(GeoPoly * p)487 static double geopolyArea(GeoPoly *p){
488   double rArea = 0.0;
489   int ii;
490   for(ii=0; ii<p->nVertex-1; ii++){
491     rArea += (GeoX(p,ii) - GeoX(p,ii+1))           /* (x0 - x1) */
492               * (GeoY(p,ii) + GeoY(p,ii+1))        /* (y0 + y1) */
493               * 0.5;
494   }
495   rArea += (GeoX(p,ii) - GeoX(p,0))                /* (xN - x0) */
496            * (GeoY(p,ii) + GeoY(p,0))              /* (yN + y0) */
497            * 0.5;
498   return rArea;
499 }
500 
501 /*
502 ** Implementation of the geopoly_area(X) function.
503 **
504 ** If the input is a well-formed Geopoly BLOB then return the area
505 ** enclosed by the polygon.  If the polygon circulates clockwise instead
506 ** of counterclockwise (as it should) then return the negative of the
507 ** enclosed area.  Otherwise return NULL.
508 */
geopolyAreaFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)509 static void geopolyAreaFunc(
510   sqlite3_context *context,
511   int argc,
512   sqlite3_value **argv
513 ){
514   GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
515   if( p ){
516     sqlite3_result_double(context, geopolyArea(p));
517     sqlite3_free(p);
518   }
519 }
520 
521 /*
522 ** Implementation of the geopoly_ccw(X) function.
523 **
524 ** If the rotation of polygon X is clockwise (incorrect) instead of
525 ** counter-clockwise (the correct winding order according to RFC7946)
526 ** then reverse the order of the vertexes in polygon X.
527 **
528 ** In other words, this routine returns a CCW polygon regardless of the
529 ** winding order of its input.
530 **
531 ** Use this routine to sanitize historical inputs that that sometimes
532 ** contain polygons that wind in the wrong direction.
533 */
geopolyCcwFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)534 static void geopolyCcwFunc(
535   sqlite3_context *context,
536   int argc,
537   sqlite3_value **argv
538 ){
539   GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
540   if( p ){
541     if( geopolyArea(p)<0.0 ){
542       int ii, jj;
543       for(ii=1, jj=p->nVertex-1; ii<jj; ii++, jj--){
544         GeoCoord t = GeoX(p,ii);
545         GeoX(p,ii) = GeoX(p,jj);
546         GeoX(p,jj) = t;
547         t = GeoY(p,ii);
548         GeoY(p,ii) = GeoY(p,jj);
549         GeoY(p,jj) = t;
550       }
551     }
552     sqlite3_result_blob(context, p->hdr,
553        4+8*p->nVertex, SQLITE_TRANSIENT);
554     sqlite3_free(p);
555   }
556 }
557 
558 #define GEOPOLY_PI 3.1415926535897932385
559 
560 /* Fast approximation for sine(X) for X between -0.5*pi and 2*pi
561 */
geopolySine(double r)562 static double geopolySine(double r){
563   assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI );
564   if( r>=1.5*GEOPOLY_PI ){
565     r -= 2.0*GEOPOLY_PI;
566   }
567   if( r>=0.5*GEOPOLY_PI ){
568     return -geopolySine(r-GEOPOLY_PI);
569   }else{
570     double r2 = r*r;
571     double r3 = r2*r;
572     double r5 = r3*r2;
573     return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5;
574   }
575 }
576 
577 /*
578 ** Function:   geopoly_regular(X,Y,R,N)
579 **
580 ** Construct a simple, convex, regular polygon centered at X, Y
581 ** with circumradius R and with N sides.
582 */
geopolyRegularFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)583 static void geopolyRegularFunc(
584   sqlite3_context *context,
585   int argc,
586   sqlite3_value **argv
587 ){
588   double x = sqlite3_value_double(argv[0]);
589   double y = sqlite3_value_double(argv[1]);
590   double r = sqlite3_value_double(argv[2]);
591   int n = sqlite3_value_int(argv[3]);
592   int i;
593   GeoPoly *p;
594 
595   if( n<3 || r<=0.0 ) return;
596   if( n>1000 ) n = 1000;
597   p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) );
598   if( p==0 ){
599     sqlite3_result_error_nomem(context);
600     return;
601   }
602   i = 1;
603   p->hdr[0] = *(unsigned char*)&i;
604   p->hdr[1] = 0;
605   p->hdr[2] = (n>>8)&0xff;
606   p->hdr[3] = n&0xff;
607   for(i=0; i<n; i++){
608     double rAngle = 2.0*GEOPOLY_PI*i/n;
609     GeoX(p,i) = x - r*geopolySine(rAngle-0.5*GEOPOLY_PI);
610     GeoY(p,i) = y + r*geopolySine(rAngle);
611   }
612   sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT);
613   sqlite3_free(p);
614 }
615 
616 /*
617 ** If pPoly is a polygon, compute its bounding box. Then:
618 **
619 **    (1) if aCoord!=0 store the bounding box in aCoord, returning NULL
620 **    (2) otherwise, compute a GeoPoly for the bounding box and return the
621 **        new GeoPoly
622 **
623 ** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from
624 ** the bounding box in aCoord and return a pointer to that GeoPoly.
625 */
geopolyBBox(sqlite3_context * context,sqlite3_value * pPoly,RtreeCoord * aCoord,int * pRc)626 static GeoPoly *geopolyBBox(
627   sqlite3_context *context,   /* For recording the error */
628   sqlite3_value *pPoly,       /* The polygon */
629   RtreeCoord *aCoord,         /* Results here */
630   int *pRc                    /* Error code here */
631 ){
632   GeoPoly *pOut = 0;
633   GeoPoly *p;
634   float mnX, mxX, mnY, mxY;
635   if( pPoly==0 && aCoord!=0 ){
636     p = 0;
637     mnX = aCoord[0].f;
638     mxX = aCoord[1].f;
639     mnY = aCoord[2].f;
640     mxY = aCoord[3].f;
641     goto geopolyBboxFill;
642   }else{
643     p = geopolyFuncParam(context, pPoly, pRc);
644   }
645   if( p ){
646     int ii;
647     mnX = mxX = GeoX(p,0);
648     mnY = mxY = GeoY(p,0);
649     for(ii=1; ii<p->nVertex; ii++){
650       double r = GeoX(p,ii);
651       if( r<mnX ) mnX = (float)r;
652       else if( r>mxX ) mxX = (float)r;
653       r = GeoY(p,ii);
654       if( r<mnY ) mnY = (float)r;
655       else if( r>mxY ) mxY = (float)r;
656     }
657     if( pRc ) *pRc = SQLITE_OK;
658     if( aCoord==0 ){
659       geopolyBboxFill:
660       pOut = sqlite3_realloc64(p, GEOPOLY_SZ(4));
661       if( pOut==0 ){
662         sqlite3_free(p);
663         if( context ) sqlite3_result_error_nomem(context);
664         if( pRc ) *pRc = SQLITE_NOMEM;
665         return 0;
666       }
667       pOut->nVertex = 4;
668       ii = 1;
669       pOut->hdr[0] = *(unsigned char*)&ii;
670       pOut->hdr[1] = 0;
671       pOut->hdr[2] = 0;
672       pOut->hdr[3] = 4;
673       GeoX(pOut,0) = mnX;
674       GeoY(pOut,0) = mnY;
675       GeoX(pOut,1) = mxX;
676       GeoY(pOut,1) = mnY;
677       GeoX(pOut,2) = mxX;
678       GeoY(pOut,2) = mxY;
679       GeoX(pOut,3) = mnX;
680       GeoY(pOut,3) = mxY;
681     }else{
682       sqlite3_free(p);
683       aCoord[0].f = mnX;
684       aCoord[1].f = mxX;
685       aCoord[2].f = mnY;
686       aCoord[3].f = mxY;
687     }
688   }else if( aCoord ){
689     memset(aCoord, 0, sizeof(RtreeCoord)*4);
690   }
691   return pOut;
692 }
693 
694 /*
695 ** Implementation of the geopoly_bbox(X) SQL function.
696 */
geopolyBBoxFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)697 static void geopolyBBoxFunc(
698   sqlite3_context *context,
699   int argc,
700   sqlite3_value **argv
701 ){
702   GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
703   if( p ){
704     sqlite3_result_blob(context, p->hdr,
705        4+8*p->nVertex, SQLITE_TRANSIENT);
706     sqlite3_free(p);
707   }
708 }
709 
710 /*
711 ** State vector for the geopoly_group_bbox() aggregate function.
712 */
713 typedef struct GeoBBox GeoBBox;
714 struct GeoBBox {
715   int isInit;
716   RtreeCoord a[4];
717 };
718 
719 
720 /*
721 ** Implementation of the geopoly_group_bbox(X) aggregate SQL function.
722 */
geopolyBBoxStep(sqlite3_context * context,int argc,sqlite3_value ** argv)723 static void geopolyBBoxStep(
724   sqlite3_context *context,
725   int argc,
726   sqlite3_value **argv
727 ){
728   RtreeCoord a[4];
729   int rc = SQLITE_OK;
730   (void)geopolyBBox(context, argv[0], a, &rc);
731   if( rc==SQLITE_OK ){
732     GeoBBox *pBBox;
733     pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox));
734     if( pBBox==0 ) return;
735     if( pBBox->isInit==0 ){
736       pBBox->isInit = 1;
737       memcpy(pBBox->a, a, sizeof(RtreeCoord)*4);
738     }else{
739       if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0];
740       if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1];
741       if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2];
742       if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3];
743     }
744   }
745 }
geopolyBBoxFinal(sqlite3_context * context)746 static void geopolyBBoxFinal(
747   sqlite3_context *context
748 ){
749   GeoPoly *p;
750   GeoBBox *pBBox;
751   pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0);
752   if( pBBox==0 ) return;
753   p = geopolyBBox(context, 0, pBBox->a, 0);
754   if( p ){
755     sqlite3_result_blob(context, p->hdr,
756        4+8*p->nVertex, SQLITE_TRANSIENT);
757     sqlite3_free(p);
758   }
759 }
760 
761 
762 /*
763 ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
764 ** Returns:
765 **
766 **    +2  x0,y0 is on the line segement
767 **
768 **    +1  x0,y0 is beneath line segment
769 **
770 **    0   x0,y0 is not on or beneath the line segment or the line segment
771 **        is vertical and x0,y0 is not on the line segment
772 **
773 ** The left-most coordinate min(x1,x2) is not considered to be part of
774 ** the line segment for the purposes of this analysis.
775 */
pointBeneathLine(double x0,double y0,double x1,double y1,double x2,double y2)776 static int pointBeneathLine(
777   double x0, double y0,
778   double x1, double y1,
779   double x2, double y2
780 ){
781   double y;
782   if( x0==x1 && y0==y1 ) return 2;
783   if( x1<x2 ){
784     if( x0<=x1 || x0>x2 ) return 0;
785   }else if( x1>x2 ){
786     if( x0<=x2 || x0>x1 ) return 0;
787   }else{
788     /* Vertical line segment */
789     if( x0!=x1 ) return 0;
790     if( y0<y1 && y0<y2 ) return 0;
791     if( y0>y1 && y0>y2 ) return 0;
792     return 2;
793   }
794   y = y1 + (y2-y1)*(x0-x1)/(x2-x1);
795   if( y0==y ) return 2;
796   if( y0<y ) return 1;
797   return 0;
798 }
799 
800 /*
801 ** SQL function:    geopoly_contains_point(P,X,Y)
802 **
803 ** Return +2 if point X,Y is within polygon P.
804 ** Return +1 if point X,Y is on the polygon boundary.
805 ** Return 0 if point X,Y is outside the polygon
806 */
geopolyContainsPointFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)807 static void geopolyContainsPointFunc(
808   sqlite3_context *context,
809   int argc,
810   sqlite3_value **argv
811 ){
812   GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
813   double x0 = sqlite3_value_double(argv[1]);
814   double y0 = sqlite3_value_double(argv[2]);
815   int v = 0;
816   int cnt = 0;
817   int ii;
818   if( p1==0 ) return;
819   for(ii=0; ii<p1->nVertex-1; ii++){
820     v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
821                                GeoX(p1,ii+1),GeoY(p1,ii+1));
822     if( v==2 ) break;
823     cnt += v;
824   }
825   if( v!=2 ){
826     v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
827                                GeoX(p1,0),  GeoY(p1,0));
828   }
829   if( v==2 ){
830     sqlite3_result_int(context, 1);
831   }else if( ((v+cnt)&1)==0 ){
832     sqlite3_result_int(context, 0);
833   }else{
834     sqlite3_result_int(context, 2);
835   }
836   sqlite3_free(p1);
837 }
838 
839 /* Forward declaration */
840 static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2);
841 
842 /*
843 ** SQL function:    geopoly_within(P1,P2)
844 **
845 ** Return +2 if P1 and P2 are the same polygon
846 ** Return +1 if P2 is contained within P1
847 ** Return 0 if any part of P2 is on the outside of P1
848 **
849 */
geopolyWithinFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)850 static void geopolyWithinFunc(
851   sqlite3_context *context,
852   int argc,
853   sqlite3_value **argv
854 ){
855   GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
856   GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
857   if( p1 && p2 ){
858     int x = geopolyOverlap(p1, p2);
859     if( x<0 ){
860       sqlite3_result_error_nomem(context);
861     }else{
862       sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
863     }
864   }
865   sqlite3_free(p1);
866   sqlite3_free(p2);
867 }
868 
869 /* Objects used by the overlap algorihm. */
870 typedef struct GeoEvent GeoEvent;
871 typedef struct GeoSegment GeoSegment;
872 typedef struct GeoOverlap GeoOverlap;
873 struct GeoEvent {
874   double x;              /* X coordinate at which event occurs */
875   int eType;             /* 0 for ADD, 1 for REMOVE */
876   GeoSegment *pSeg;      /* The segment to be added or removed */
877   GeoEvent *pNext;       /* Next event in the sorted list */
878 };
879 struct GeoSegment {
880   double C, B;           /* y = C*x + B */
881   double y;              /* Current y value */
882   float y0;              /* Initial y value */
883   unsigned char side;    /* 1 for p1, 2 for p2 */
884   unsigned int idx;      /* Which segment within the side */
885   GeoSegment *pNext;     /* Next segment in a list sorted by y */
886 };
887 struct GeoOverlap {
888   GeoEvent *aEvent;          /* Array of all events */
889   GeoSegment *aSegment;      /* Array of all segments */
890   int nEvent;                /* Number of events */
891   int nSegment;              /* Number of segments */
892 };
893 
894 /*
895 ** Add a single segment and its associated events.
896 */
geopolyAddOneSegment(GeoOverlap * p,GeoCoord x0,GeoCoord y0,GeoCoord x1,GeoCoord y1,unsigned char side,unsigned int idx)897 static void geopolyAddOneSegment(
898   GeoOverlap *p,
899   GeoCoord x0,
900   GeoCoord y0,
901   GeoCoord x1,
902   GeoCoord y1,
903   unsigned char side,
904   unsigned int idx
905 ){
906   GeoSegment *pSeg;
907   GeoEvent *pEvent;
908   if( x0==x1 ) return;  /* Ignore vertical segments */
909   if( x0>x1 ){
910     GeoCoord t = x0;
911     x0 = x1;
912     x1 = t;
913     t = y0;
914     y0 = y1;
915     y1 = t;
916   }
917   pSeg = p->aSegment + p->nSegment;
918   p->nSegment++;
919   pSeg->C = (y1-y0)/(x1-x0);
920   pSeg->B = y1 - x1*pSeg->C;
921   pSeg->y0 = y0;
922   pSeg->side = side;
923   pSeg->idx = idx;
924   pEvent = p->aEvent + p->nEvent;
925   p->nEvent++;
926   pEvent->x = x0;
927   pEvent->eType = 0;
928   pEvent->pSeg = pSeg;
929   pEvent = p->aEvent + p->nEvent;
930   p->nEvent++;
931   pEvent->x = x1;
932   pEvent->eType = 1;
933   pEvent->pSeg = pSeg;
934 }
935 
936 
937 
938 /*
939 ** Insert all segments and events for polygon pPoly.
940 */
geopolyAddSegments(GeoOverlap * p,GeoPoly * pPoly,unsigned char side)941 static void geopolyAddSegments(
942   GeoOverlap *p,          /* Add segments to this Overlap object */
943   GeoPoly *pPoly,         /* Take all segments from this polygon */
944   unsigned char side      /* The side of pPoly */
945 ){
946   unsigned int i;
947   GeoCoord *x;
948   for(i=0; i<(unsigned)pPoly->nVertex-1; i++){
949     x = &GeoX(pPoly,i);
950     geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i);
951   }
952   x = &GeoX(pPoly,i);
953   geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i);
954 }
955 
956 /*
957 ** Merge two lists of sorted events by X coordinate
958 */
geopolyEventMerge(GeoEvent * pLeft,GeoEvent * pRight)959 static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){
960   GeoEvent head, *pLast;
961   head.pNext = 0;
962   pLast = &head;
963   while( pRight && pLeft ){
964     if( pRight->x <= pLeft->x ){
965       pLast->pNext = pRight;
966       pLast = pRight;
967       pRight = pRight->pNext;
968     }else{
969       pLast->pNext = pLeft;
970       pLast = pLeft;
971       pLeft = pLeft->pNext;
972     }
973   }
974   pLast->pNext = pRight ? pRight : pLeft;
975   return head.pNext;
976 }
977 
978 /*
979 ** Sort an array of nEvent event objects into a list.
980 */
geopolySortEventsByX(GeoEvent * aEvent,int nEvent)981 static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){
982   int mx = 0;
983   int i, j;
984   GeoEvent *p;
985   GeoEvent *a[50];
986   for(i=0; i<nEvent; i++){
987     p = &aEvent[i];
988     p->pNext = 0;
989     for(j=0; j<mx && a[j]; j++){
990       p = geopolyEventMerge(a[j], p);
991       a[j] = 0;
992     }
993     a[j] = p;
994     if( j>=mx ) mx = j+1;
995   }
996   p = 0;
997   for(i=0; i<mx; i++){
998     p = geopolyEventMerge(a[i], p);
999   }
1000   return p;
1001 }
1002 
1003 /*
1004 ** Merge two lists of sorted segments by Y, and then by C.
1005 */
geopolySegmentMerge(GeoSegment * pLeft,GeoSegment * pRight)1006 static GeoSegment *geopolySegmentMerge(GeoSegment *pLeft, GeoSegment *pRight){
1007   GeoSegment head, *pLast;
1008   head.pNext = 0;
1009   pLast = &head;
1010   while( pRight && pLeft ){
1011     double r = pRight->y - pLeft->y;
1012     if( r==0.0 ) r = pRight->C - pLeft->C;
1013     if( r<0.0 ){
1014       pLast->pNext = pRight;
1015       pLast = pRight;
1016       pRight = pRight->pNext;
1017     }else{
1018       pLast->pNext = pLeft;
1019       pLast = pLeft;
1020       pLeft = pLeft->pNext;
1021     }
1022   }
1023   pLast->pNext = pRight ? pRight : pLeft;
1024   return head.pNext;
1025 }
1026 
1027 /*
1028 ** Sort a list of GeoSegments in order of increasing Y and in the event of
1029 ** a tie, increasing C (slope).
1030 */
geopolySortSegmentsByYAndC(GeoSegment * pList)1031 static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){
1032   int mx = 0;
1033   int i;
1034   GeoSegment *p;
1035   GeoSegment *a[50];
1036   while( pList ){
1037     p = pList;
1038     pList = pList->pNext;
1039     p->pNext = 0;
1040     for(i=0; i<mx && a[i]; i++){
1041       p = geopolySegmentMerge(a[i], p);
1042       a[i] = 0;
1043     }
1044     a[i] = p;
1045     if( i>=mx ) mx = i+1;
1046   }
1047   p = 0;
1048   for(i=0; i<mx; i++){
1049     p = geopolySegmentMerge(a[i], p);
1050   }
1051   return p;
1052 }
1053 
1054 /*
1055 ** Determine the overlap between two polygons
1056 */
geopolyOverlap(GeoPoly * p1,GeoPoly * p2)1057 static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
1058   sqlite3_int64 nVertex = p1->nVertex + p2->nVertex + 2;
1059   GeoOverlap *p;
1060   sqlite3_int64 nByte;
1061   GeoEvent *pThisEvent;
1062   double rX;
1063   int rc = 0;
1064   int needSort = 0;
1065   GeoSegment *pActive = 0;
1066   GeoSegment *pSeg;
1067   unsigned char aOverlap[4];
1068 
1069   nByte = sizeof(GeoEvent)*nVertex*2
1070            + sizeof(GeoSegment)*nVertex
1071            + sizeof(GeoOverlap);
1072   p = sqlite3_malloc64( nByte );
1073   if( p==0 ) return -1;
1074   p->aEvent = (GeoEvent*)&p[1];
1075   p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2];
1076   p->nEvent = p->nSegment = 0;
1077   geopolyAddSegments(p, p1, 1);
1078   geopolyAddSegments(p, p2, 2);
1079   pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
1080   rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0;
1081   memset(aOverlap, 0, sizeof(aOverlap));
1082   while( pThisEvent ){
1083     if( pThisEvent->x!=rX ){
1084       GeoSegment *pPrev = 0;
1085       int iMask = 0;
1086       GEODEBUG(("Distinct X: %g\n", pThisEvent->x));
1087       rX = pThisEvent->x;
1088       if( needSort ){
1089         GEODEBUG(("SORT\n"));
1090         pActive = geopolySortSegmentsByYAndC(pActive);
1091         needSort = 0;
1092       }
1093       for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
1094         if( pPrev ){
1095           if( pPrev->y!=pSeg->y ){
1096             GEODEBUG(("MASK: %d\n", iMask));
1097             aOverlap[iMask] = 1;
1098           }
1099         }
1100         iMask ^= pSeg->side;
1101         pPrev = pSeg;
1102       }
1103       pPrev = 0;
1104       for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
1105         double y = pSeg->C*rX + pSeg->B;
1106         GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y));
1107         pSeg->y = y;
1108         if( pPrev ){
1109           if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){
1110             rc = 1;
1111             GEODEBUG(("Crossing: %d.%d and %d.%d\n",
1112                     pPrev->side, pPrev->idx,
1113                     pSeg->side, pSeg->idx));
1114             goto geopolyOverlapDone;
1115           }else if( pPrev->y!=pSeg->y ){
1116             GEODEBUG(("MASK: %d\n", iMask));
1117             aOverlap[iMask] = 1;
1118           }
1119         }
1120         iMask ^= pSeg->side;
1121         pPrev = pSeg;
1122       }
1123     }
1124     GEODEBUG(("%s %d.%d C=%g B=%g\n",
1125       pThisEvent->eType ? "RM " : "ADD",
1126       pThisEvent->pSeg->side, pThisEvent->pSeg->idx,
1127       pThisEvent->pSeg->C,
1128       pThisEvent->pSeg->B));
1129     if( pThisEvent->eType==0 ){
1130       /* Add a segment */
1131       pSeg = pThisEvent->pSeg;
1132       pSeg->y = pSeg->y0;
1133       pSeg->pNext = pActive;
1134       pActive = pSeg;
1135       needSort = 1;
1136     }else{
1137       /* Remove a segment */
1138       if( pActive==pThisEvent->pSeg ){
1139         pActive = ALWAYS(pActive) ? pActive->pNext : 0;
1140       }else{
1141         for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
1142           if( pSeg->pNext==pThisEvent->pSeg ){
1143             pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0;
1144             break;
1145           }
1146         }
1147       }
1148     }
1149     pThisEvent = pThisEvent->pNext;
1150   }
1151   if( aOverlap[3]==0 ){
1152     rc = 0;
1153   }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){
1154     rc = 3;
1155   }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){
1156     rc = 2;
1157   }else if( aOverlap[1]==0 && aOverlap[2]==0 ){
1158     rc = 4;
1159   }else{
1160     rc = 1;
1161   }
1162 
1163 geopolyOverlapDone:
1164   sqlite3_free(p);
1165   return rc;
1166 }
1167 
1168 /*
1169 ** SQL function:    geopoly_overlap(P1,P2)
1170 **
1171 ** Determine whether or not P1 and P2 overlap. Return value:
1172 **
1173 **   0     The two polygons are disjoint
1174 **   1     They overlap
1175 **   2     P1 is completely contained within P2
1176 **   3     P2 is completely contained within P1
1177 **   4     P1 and P2 are the same polygon
1178 **   NULL  Either P1 or P2 or both are not valid polygons
1179 */
geopolyOverlapFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)1180 static void geopolyOverlapFunc(
1181   sqlite3_context *context,
1182   int argc,
1183   sqlite3_value **argv
1184 ){
1185   GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
1186   GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
1187   if( p1 && p2 ){
1188     int x = geopolyOverlap(p1, p2);
1189     if( x<0 ){
1190       sqlite3_result_error_nomem(context);
1191     }else{
1192       sqlite3_result_int(context, x);
1193     }
1194   }
1195   sqlite3_free(p1);
1196   sqlite3_free(p2);
1197 }
1198 
1199 /*
1200 ** Enable or disable debugging output
1201 */
geopolyDebugFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)1202 static void geopolyDebugFunc(
1203   sqlite3_context *context,
1204   int argc,
1205   sqlite3_value **argv
1206 ){
1207 #ifdef GEOPOLY_ENABLE_DEBUG
1208   geo_debug = sqlite3_value_int(argv[0]);
1209 #endif
1210 }
1211 
1212 /*
1213 ** This function is the implementation of both the xConnect and xCreate
1214 ** methods of the geopoly virtual table.
1215 **
1216 **   argv[0]   -> module name
1217 **   argv[1]   -> database name
1218 **   argv[2]   -> table name
1219 **   argv[...] -> column names...
1220 */
geopolyInit(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr,int isCreate)1221 static int geopolyInit(
1222   sqlite3 *db,                        /* Database connection */
1223   void *pAux,                         /* One of the RTREE_COORD_* constants */
1224   int argc, const char *const*argv,   /* Parameters to CREATE TABLE statement */
1225   sqlite3_vtab **ppVtab,              /* OUT: New virtual table */
1226   char **pzErr,                       /* OUT: Error message, if any */
1227   int isCreate                        /* True for xCreate, false for xConnect */
1228 ){
1229   int rc = SQLITE_OK;
1230   Rtree *pRtree;
1231   sqlite3_int64 nDb;              /* Length of string argv[1] */
1232   sqlite3_int64 nName;            /* Length of string argv[2] */
1233   sqlite3_str *pSql;
1234   char *zSql;
1235   int ii;
1236 
1237   sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
1238 
1239   /* Allocate the sqlite3_vtab structure */
1240   nDb = strlen(argv[1]);
1241   nName = strlen(argv[2]);
1242   pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
1243   if( !pRtree ){
1244     return SQLITE_NOMEM;
1245   }
1246   memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
1247   pRtree->nBusy = 1;
1248   pRtree->base.pModule = &rtreeModule;
1249   pRtree->zDb = (char *)&pRtree[1];
1250   pRtree->zName = &pRtree->zDb[nDb+1];
1251   pRtree->eCoordType = RTREE_COORD_REAL32;
1252   pRtree->nDim = 2;
1253   pRtree->nDim2 = 4;
1254   memcpy(pRtree->zDb, argv[1], nDb);
1255   memcpy(pRtree->zName, argv[2], nName);
1256 
1257 
1258   /* Create/Connect to the underlying relational database schema. If
1259   ** that is successful, call sqlite3_declare_vtab() to configure
1260   ** the r-tree table schema.
1261   */
1262   pSql = sqlite3_str_new(db);
1263   sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape");
1264   pRtree->nAux = 1;         /* Add one for _shape */
1265   pRtree->nAuxNotNull = 1;  /* The _shape column is always not-null */
1266   for(ii=3; ii<argc; ii++){
1267     pRtree->nAux++;
1268     sqlite3_str_appendf(pSql, ",%s", argv[ii]);
1269   }
1270   sqlite3_str_appendf(pSql, ");");
1271   zSql = sqlite3_str_finish(pSql);
1272   if( !zSql ){
1273     rc = SQLITE_NOMEM;
1274   }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
1275     *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
1276   }
1277   sqlite3_free(zSql);
1278   if( rc ) goto geopolyInit_fail;
1279   pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
1280 
1281   /* Figure out the node size to use. */
1282   rc = getNodeSize(db, pRtree, isCreate, pzErr);
1283   if( rc ) goto geopolyInit_fail;
1284   rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
1285   if( rc ){
1286     *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
1287     goto geopolyInit_fail;
1288   }
1289 
1290   *ppVtab = (sqlite3_vtab *)pRtree;
1291   return SQLITE_OK;
1292 
1293 geopolyInit_fail:
1294   if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
1295   assert( *ppVtab==0 );
1296   assert( pRtree->nBusy==1 );
1297   rtreeRelease(pRtree);
1298   return rc;
1299 }
1300 
1301 
1302 /*
1303 ** GEOPOLY virtual table module xCreate method.
1304 */
geopolyCreate(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)1305 static int geopolyCreate(
1306   sqlite3 *db,
1307   void *pAux,
1308   int argc, const char *const*argv,
1309   sqlite3_vtab **ppVtab,
1310   char **pzErr
1311 ){
1312   return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
1313 }
1314 
1315 /*
1316 ** GEOPOLY virtual table module xConnect method.
1317 */
geopolyConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)1318 static int geopolyConnect(
1319   sqlite3 *db,
1320   void *pAux,
1321   int argc, const char *const*argv,
1322   sqlite3_vtab **ppVtab,
1323   char **pzErr
1324 ){
1325   return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0);
1326 }
1327 
1328 
1329 /*
1330 ** GEOPOLY virtual table module xFilter method.
1331 **
1332 ** Query plans:
1333 **
1334 **      1         rowid lookup
1335 **      2         search for objects overlapping the same bounding box
1336 **                that contains polygon argv[0]
1337 **      3         search for objects overlapping the same bounding box
1338 **                that contains polygon argv[0]
1339 **      4         full table scan
1340 */
geopolyFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)1341 static int geopolyFilter(
1342   sqlite3_vtab_cursor *pVtabCursor,     /* The cursor to initialize */
1343   int idxNum,                           /* Query plan */
1344   const char *idxStr,                   /* Not Used */
1345   int argc, sqlite3_value **argv        /* Parameters to the query plan */
1346 ){
1347   Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
1348   RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
1349   RtreeNode *pRoot = 0;
1350   int rc = SQLITE_OK;
1351   int iCell = 0;
1352 
1353   rtreeReference(pRtree);
1354 
1355   /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
1356   resetCursor(pCsr);
1357 
1358   pCsr->iStrategy = idxNum;
1359   if( idxNum==1 ){
1360     /* Special case - lookup by rowid. */
1361     RtreeNode *pLeaf;        /* Leaf on which the required cell resides */
1362     RtreeSearchPoint *p;     /* Search point for the leaf */
1363     i64 iRowid = sqlite3_value_int64(argv[0]);
1364     i64 iNode = 0;
1365     rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
1366     if( rc==SQLITE_OK && pLeaf!=0 ){
1367       p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0);
1368       assert( p!=0 );  /* Always returns pCsr->sPoint */
1369       pCsr->aNode[0] = pLeaf;
1370       p->id = iNode;
1371       p->eWithin = PARTLY_WITHIN;
1372       rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);
1373       p->iCell = (u8)iCell;
1374       RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:");
1375     }else{
1376       pCsr->atEOF = 1;
1377     }
1378   }else{
1379     /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
1380     ** with the configured constraints.
1381     */
1382     rc = nodeAcquire(pRtree, 1, 0, &pRoot);
1383     if( rc==SQLITE_OK && idxNum<=3 ){
1384       RtreeCoord bbox[4];
1385       RtreeConstraint *p;
1386       assert( argc==1 );
1387       assert( argv[0]!=0 );
1388       geopolyBBox(0, argv[0], bbox, &rc);
1389       if( rc ){
1390         goto geopoly_filter_end;
1391       }
1392       pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4);
1393       pCsr->nConstraint = 4;
1394       if( p==0 ){
1395         rc = SQLITE_NOMEM;
1396       }else{
1397         memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4);
1398         memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1));
1399         if( idxNum==2 ){
1400           /* Overlap query */
1401           p->op = 'B';
1402           p->iCoord = 0;
1403           p->u.rValue = bbox[1].f;
1404           p++;
1405           p->op = 'D';
1406           p->iCoord = 1;
1407           p->u.rValue = bbox[0].f;
1408           p++;
1409           p->op = 'B';
1410           p->iCoord = 2;
1411           p->u.rValue = bbox[3].f;
1412           p++;
1413           p->op = 'D';
1414           p->iCoord = 3;
1415           p->u.rValue = bbox[2].f;
1416         }else{
1417           /* Within query */
1418           p->op = 'D';
1419           p->iCoord = 0;
1420           p->u.rValue = bbox[0].f;
1421           p++;
1422           p->op = 'B';
1423           p->iCoord = 1;
1424           p->u.rValue = bbox[1].f;
1425           p++;
1426           p->op = 'D';
1427           p->iCoord = 2;
1428           p->u.rValue = bbox[2].f;
1429           p++;
1430           p->op = 'B';
1431           p->iCoord = 3;
1432           p->u.rValue = bbox[3].f;
1433         }
1434       }
1435     }
1436     if( rc==SQLITE_OK ){
1437       RtreeSearchPoint *pNew;
1438       pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
1439       if( pNew==0 ){
1440         rc = SQLITE_NOMEM;
1441         goto geopoly_filter_end;
1442       }
1443       pNew->id = 1;
1444       pNew->iCell = 0;
1445       pNew->eWithin = PARTLY_WITHIN;
1446       assert( pCsr->bPoint==1 );
1447       pCsr->aNode[0] = pRoot;
1448       pRoot = 0;
1449       RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:");
1450       rc = rtreeStepToLeaf(pCsr);
1451     }
1452   }
1453 
1454 geopoly_filter_end:
1455   nodeRelease(pRtree, pRoot);
1456   rtreeRelease(pRtree);
1457   return rc;
1458 }
1459 
1460 /*
1461 ** Rtree virtual table module xBestIndex method. There are three
1462 ** table scan strategies to choose from (in order from most to
1463 ** least desirable):
1464 **
1465 **   idxNum     idxStr        Strategy
1466 **   ------------------------------------------------
1467 **     1        "rowid"       Direct lookup by rowid.
1468 **     2        "rtree"       R-tree overlap query using geopoly_overlap()
1469 **     3        "rtree"       R-tree within query using geopoly_within()
1470 **     4        "fullscan"    full-table scan.
1471 **   ------------------------------------------------
1472 */
geopolyBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)1473 static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
1474   int ii;
1475   int iRowidTerm = -1;
1476   int iFuncTerm = -1;
1477   int idxNum = 0;
1478 
1479   for(ii=0; ii<pIdxInfo->nConstraint; ii++){
1480     struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
1481     if( !p->usable ) continue;
1482     if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ  ){
1483       iRowidTerm = ii;
1484       break;
1485     }
1486     if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
1487       /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap()
1488       ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within().
1489       ** See geopolyFindFunction() */
1490       iFuncTerm = ii;
1491       idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2;
1492     }
1493   }
1494 
1495   if( iRowidTerm>=0 ){
1496     pIdxInfo->idxNum = 1;
1497     pIdxInfo->idxStr = "rowid";
1498     pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
1499     pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
1500     pIdxInfo->estimatedCost = 30.0;
1501     pIdxInfo->estimatedRows = 1;
1502     pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
1503     return SQLITE_OK;
1504   }
1505   if( iFuncTerm>=0 ){
1506     pIdxInfo->idxNum = idxNum;
1507     pIdxInfo->idxStr = "rtree";
1508     pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1;
1509     pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0;
1510     pIdxInfo->estimatedCost = 300.0;
1511     pIdxInfo->estimatedRows = 10;
1512     return SQLITE_OK;
1513   }
1514   pIdxInfo->idxNum = 4;
1515   pIdxInfo->idxStr = "fullscan";
1516   pIdxInfo->estimatedCost = 3000000.0;
1517   pIdxInfo->estimatedRows = 100000;
1518   return SQLITE_OK;
1519 }
1520 
1521 
1522 /*
1523 ** GEOPOLY virtual table module xColumn method.
1524 */
geopolyColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)1525 static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
1526   Rtree *pRtree = (Rtree *)cur->pVtab;
1527   RtreeCursor *pCsr = (RtreeCursor *)cur;
1528   RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
1529   int rc = SQLITE_OK;
1530   RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
1531 
1532   if( rc ) return rc;
1533   if( p==0 ) return SQLITE_OK;
1534   if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK;
1535   if( i<=pRtree->nAux ){
1536     if( !pCsr->bAuxValid ){
1537       if( pCsr->pReadAux==0 ){
1538         rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
1539                                 &pCsr->pReadAux, 0);
1540         if( rc ) return rc;
1541       }
1542       sqlite3_bind_int64(pCsr->pReadAux, 1,
1543           nodeGetRowid(pRtree, pNode, p->iCell));
1544       rc = sqlite3_step(pCsr->pReadAux);
1545       if( rc==SQLITE_ROW ){
1546         pCsr->bAuxValid = 1;
1547       }else{
1548         sqlite3_reset(pCsr->pReadAux);
1549         if( rc==SQLITE_DONE ) rc = SQLITE_OK;
1550         return rc;
1551       }
1552     }
1553     sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2));
1554   }
1555   return SQLITE_OK;
1556 }
1557 
1558 
1559 /*
1560 ** The xUpdate method for GEOPOLY module virtual tables.
1561 **
1562 ** For DELETE:
1563 **
1564 **     argv[0] = the rowid to be deleted
1565 **
1566 ** For INSERT:
1567 **
1568 **     argv[0] = SQL NULL
1569 **     argv[1] = rowid to insert, or an SQL NULL to select automatically
1570 **     argv[2] = _shape column
1571 **     argv[3] = first application-defined column....
1572 **
1573 ** For UPDATE:
1574 **
1575 **     argv[0] = rowid to modify.  Never NULL
1576 **     argv[1] = rowid after the change.  Never NULL
1577 **     argv[2] = new value for _shape
1578 **     argv[3] = new value for first application-defined column....
1579 */
geopolyUpdate(sqlite3_vtab * pVtab,int nData,sqlite3_value ** aData,sqlite_int64 * pRowid)1580 static int geopolyUpdate(
1581   sqlite3_vtab *pVtab,
1582   int nData,
1583   sqlite3_value **aData,
1584   sqlite_int64 *pRowid
1585 ){
1586   Rtree *pRtree = (Rtree *)pVtab;
1587   int rc = SQLITE_OK;
1588   RtreeCell cell;                 /* New cell to insert if nData>1 */
1589   i64 oldRowid;                   /* The old rowid */
1590   int oldRowidValid;              /* True if oldRowid is valid */
1591   i64 newRowid;                   /* The new rowid */
1592   int newRowidValid;              /* True if newRowid is valid */
1593   int coordChange = 0;            /* Change in coordinates */
1594 
1595   if( pRtree->nNodeRef ){
1596     /* Unable to write to the btree while another cursor is reading from it,
1597     ** since the write might do a rebalance which would disrupt the read
1598     ** cursor. */
1599     return SQLITE_LOCKED_VTAB;
1600   }
1601   rtreeReference(pRtree);
1602   assert(nData>=1);
1603 
1604   oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;;
1605   oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0;
1606   newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL;
1607   newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0;
1608   cell.iRowid = newRowid;
1609 
1610   if( nData>1                                 /* not a DELETE */
1611    && (!oldRowidValid                         /* INSERT */
1612         || !sqlite3_value_nochange(aData[2])  /* UPDATE _shape */
1613         || oldRowid!=newRowid)                /* Rowid change */
1614   ){
1615     assert( aData[2]!=0 );
1616     geopolyBBox(0, aData[2], cell.aCoord, &rc);
1617     if( rc ){
1618       if( rc==SQLITE_ERROR ){
1619         pVtab->zErrMsg =
1620           sqlite3_mprintf("_shape does not contain a valid polygon");
1621       }
1622       goto geopoly_update_end;
1623     }
1624     coordChange = 1;
1625 
1626     /* If a rowid value was supplied, check if it is already present in
1627     ** the table. If so, the constraint has failed. */
1628     if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){
1629       int steprc;
1630       sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
1631       steprc = sqlite3_step(pRtree->pReadRowid);
1632       rc = sqlite3_reset(pRtree->pReadRowid);
1633       if( SQLITE_ROW==steprc ){
1634         if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
1635           rc = rtreeDeleteRowid(pRtree, cell.iRowid);
1636         }else{
1637           rc = rtreeConstraintError(pRtree, 0);
1638         }
1639       }
1640     }
1641   }
1642 
1643   /* If aData[0] is not an SQL NULL value, it is the rowid of a
1644   ** record to delete from the r-tree table. The following block does
1645   ** just that.
1646   */
1647   if( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){
1648     rc = rtreeDeleteRowid(pRtree, oldRowid);
1649   }
1650 
1651   /* If the aData[] array contains more than one element, elements
1652   ** (aData[2]..aData[argc-1]) contain a new record to insert into
1653   ** the r-tree structure.
1654   */
1655   if( rc==SQLITE_OK && nData>1 && coordChange ){
1656     /* Insert the new record into the r-tree */
1657     RtreeNode *pLeaf = 0;
1658     if( !newRowidValid ){
1659       rc = rtreeNewRowid(pRtree, &cell.iRowid);
1660     }
1661     *pRowid = cell.iRowid;
1662     if( rc==SQLITE_OK ){
1663       rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
1664     }
1665     if( rc==SQLITE_OK ){
1666       int rc2;
1667       pRtree->iReinsertHeight = -1;
1668       rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
1669       rc2 = nodeRelease(pRtree, pLeaf);
1670       if( rc==SQLITE_OK ){
1671         rc = rc2;
1672       }
1673     }
1674   }
1675 
1676   /* Change the data */
1677   if( rc==SQLITE_OK && nData>1 ){
1678     sqlite3_stmt *pUp = pRtree->pWriteAux;
1679     int jj;
1680     int nChange = 0;
1681     sqlite3_bind_int64(pUp, 1, cell.iRowid);
1682     assert( pRtree->nAux>=1 );
1683     if( sqlite3_value_nochange(aData[2]) ){
1684       sqlite3_bind_null(pUp, 2);
1685     }else{
1686       GeoPoly *p = 0;
1687       if( sqlite3_value_type(aData[2])==SQLITE_TEXT
1688        && (p = geopolyFuncParam(0, aData[2], &rc))!=0
1689        && rc==SQLITE_OK
1690       ){
1691         sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT);
1692       }else{
1693         sqlite3_bind_value(pUp, 2, aData[2]);
1694       }
1695       sqlite3_free(p);
1696       nChange = 1;
1697     }
1698     for(jj=1; jj<nData-2; jj++){
1699       nChange++;
1700       sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
1701     }
1702     if( nChange ){
1703       sqlite3_step(pUp);
1704       rc = sqlite3_reset(pUp);
1705     }
1706   }
1707 
1708 geopoly_update_end:
1709   rtreeRelease(pRtree);
1710   return rc;
1711 }
1712 
1713 /*
1714 ** Report that geopoly_overlap() is an overloaded function suitable
1715 ** for use in xBestIndex.
1716 */
geopolyFindFunction(sqlite3_vtab * pVtab,int nArg,const char * zName,void (** pxFunc)(sqlite3_context *,int,sqlite3_value **),void ** ppArg)1717 static int geopolyFindFunction(
1718   sqlite3_vtab *pVtab,
1719   int nArg,
1720   const char *zName,
1721   void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
1722   void **ppArg
1723 ){
1724   if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){
1725     *pxFunc = geopolyOverlapFunc;
1726     *ppArg = 0;
1727     return SQLITE_INDEX_CONSTRAINT_FUNCTION;
1728   }
1729   if( sqlite3_stricmp(zName, "geopoly_within")==0 ){
1730     *pxFunc = geopolyWithinFunc;
1731     *ppArg = 0;
1732     return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
1733   }
1734   return 0;
1735 }
1736 
1737 
1738 static sqlite3_module geopolyModule = {
1739   3,                          /* iVersion */
1740   geopolyCreate,              /* xCreate - create a table */
1741   geopolyConnect,             /* xConnect - connect to an existing table */
1742   geopolyBestIndex,           /* xBestIndex - Determine search strategy */
1743   rtreeDisconnect,            /* xDisconnect - Disconnect from a table */
1744   rtreeDestroy,               /* xDestroy - Drop a table */
1745   rtreeOpen,                  /* xOpen - open a cursor */
1746   rtreeClose,                 /* xClose - close a cursor */
1747   geopolyFilter,              /* xFilter - configure scan constraints */
1748   rtreeNext,                  /* xNext - advance a cursor */
1749   rtreeEof,                   /* xEof */
1750   geopolyColumn,              /* xColumn - read data */
1751   rtreeRowid,                 /* xRowid - read data */
1752   geopolyUpdate,              /* xUpdate - write data */
1753   rtreeBeginTransaction,      /* xBegin - begin transaction */
1754   rtreeEndTransaction,        /* xSync - sync transaction */
1755   rtreeEndTransaction,        /* xCommit - commit transaction */
1756   rtreeEndTransaction,        /* xRollback - rollback transaction */
1757   geopolyFindFunction,        /* xFindFunction - function overloading */
1758   rtreeRename,                /* xRename - rename the table */
1759   rtreeSavepoint,             /* xSavepoint */
1760   0,                          /* xRelease */
1761   0,                          /* xRollbackTo */
1762   rtreeShadowName             /* xShadowName */
1763 };
1764 
sqlite3_geopoly_init(sqlite3 * db)1765 static int sqlite3_geopoly_init(sqlite3 *db){
1766   int rc = SQLITE_OK;
1767   static const struct {
1768     void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
1769     signed char nArg;
1770     unsigned char bPure;
1771     const char *zName;
1772   } aFunc[] = {
1773      { geopolyAreaFunc,          1, 1,    "geopoly_area"             },
1774      { geopolyBlobFunc,          1, 1,    "geopoly_blob"             },
1775      { geopolyJsonFunc,          1, 1,    "geopoly_json"             },
1776      { geopolySvgFunc,          -1, 1,    "geopoly_svg"              },
1777      { geopolyWithinFunc,        2, 1,    "geopoly_within"           },
1778      { geopolyContainsPointFunc, 3, 1,    "geopoly_contains_point"   },
1779      { geopolyOverlapFunc,       2, 1,    "geopoly_overlap"          },
1780      { geopolyDebugFunc,         1, 0,    "geopoly_debug"            },
1781      { geopolyBBoxFunc,          1, 1,    "geopoly_bbox"             },
1782      { geopolyXformFunc,         7, 1,    "geopoly_xform"            },
1783      { geopolyRegularFunc,       4, 1,    "geopoly_regular"          },
1784      { geopolyCcwFunc,           1, 1,    "geopoly_ccw"              },
1785   };
1786   static const struct {
1787     void (*xStep)(sqlite3_context*,int,sqlite3_value**);
1788     void (*xFinal)(sqlite3_context*);
1789     const char *zName;
1790   } aAgg[] = {
1791      { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox"    },
1792   };
1793   int i;
1794   for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
1795     int enc;
1796     if( aFunc[i].bPure ){
1797       enc = SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS;
1798     }else{
1799       enc = SQLITE_UTF8|SQLITE_DIRECTONLY;
1800     }
1801     rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
1802                                  enc, 0,
1803                                  aFunc[i].xFunc, 0, 0);
1804   }
1805   for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
1806     rc = sqlite3_create_function(db, aAgg[i].zName, 1,
1807               SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, 0,
1808               0, aAgg[i].xStep, aAgg[i].xFinal);
1809   }
1810   if( rc==SQLITE_OK ){
1811     rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
1812   }
1813   return rc;
1814 }
1815