4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 ******************************************************************************
13 ** This file implements an alternative R-Tree virtual table that
14 ** uses polygons to express the boundaries of 2-dimensional objects.
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.
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
29 /* Character class routines */
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)
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))
44 #ifndef JSON_NULL /* The following stuff repeats things found in json1 */
46 ** Growing our own isspace() routine this way is twice as fast as
47 ** the library isspace() function.
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,
67 #define fast_isspace(x) (geopolyIsSpace[(unsigned char)x])
68 #endif /* JSON NULL - back to original code */
70 /* Compiler and version */
72 #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
73 # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
75 # define GCC_VERSION 0
79 #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
80 # define MSVC_VERSION _MSC_VER
82 # define MSVC_VERSION 0
86 /* Datatype for coordinates
88 typedef float GeoCoord
;
91 ** Internal representation of a polygon.
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.)
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".
101 ** The on-disk representation consists of a 4-byte header followed by
102 ** the values. The 4-byte header is:
104 ** encoding (1 byte) 0=big-endian, 1=little-endian
105 ** nvertex (3 bytes) Number of vertexes as a big-endian integer
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.
112 typedef struct GeoPoly 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 */
119 /* The size of a memory allocation needed for a GeoPoly object sufficient
120 ** to hold N coordinate pairs.
122 #define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4))
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.
128 #define GeoX(P,I) (((GeoCoord*)(P)->a)[(I)*2])
129 #define GeoY(P,I) (((GeoCoord*)(P)->a)[(I)*2+1])
133 ** State of a parse of a GeoJSON input.
135 typedef struct GeoParse 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() */
144 /* Do a 4-byte byte swap */
145 static void geopolySwab32(unsigned char *a
){
146 unsigned char t
= a
[0];
154 /* Skip whitespace. Return the next non-whitespace character. */
155 static char geopolySkipSpace(GeoParse
*p
){
156 while( fast_isspace(p
->z
[0]) ) p
->z
++;
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.
163 static int geopolyParseNumber(GeoParse
*p
, GeoCoord
*pVal
){
164 char c
= geopolySkipSpace(p
);
165 const unsigned char *z
= p
->z
;
173 if( c
=='0' && z
[j
+1]>='0' && z
[j
+1]<='9' ) return 0;
176 if( safe_isdigit(c
) ) continue;
178 if( z
[j
-1]=='-' ) return 0;
179 if( seenDP
) return 0;
183 if( c
=='e' || c
=='E' ){
184 if( z
[j
-1]<'0' ) return 0;
185 if( seenE
) return -1;
188 if( c
=='+' || c
=='-' ){
192 if( c
<'0' || c
>'9' ) return 0;
197 if( z
[j
-1]<'0' ) return 0;
199 #ifdef SQLITE_AMALGAMATION
200 /* The sqlite3AtoF() routine is much much faster than atof(), if it
203 (void)sqlite3AtoF((const char*)p
->z
, &r
, j
, SQLITE_UTF8
);
206 *pVal
= (GeoCoord
)atof((const char*)p
->z
);
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
219 ** If any error occurs, return NULL.
221 static GeoPoly
*geopolyParseJson(const unsigned char *z
, int *pRc
){
224 memset(&s
, 0, sizeof(s
));
226 if( geopolySkipSpace(&s
)=='[' ){
228 while( geopolySkipSpace(&s
)=='[' ){
232 if( s
.nVertex
>=s
.nAlloc
){
234 s
.nAlloc
= s
.nAlloc
*2 + 16;
235 aNew
= sqlite3_realloc64(s
.a
, s
.nAlloc
*sizeof(GeoCoord
)*2 );
243 while( geopolyParseNumber(&s
, ii
<=1 ? &s
.a
[s
.nVertex
*2+ii
] : 0) ){
245 if( ii
==2 ) s
.nVertex
++;
246 c
= geopolySkipSpace(&s
);
248 if( c
==',' ) continue;
249 if( c
==']' && ii
>=2 ) break;
254 if( geopolySkipSpace(&s
)==',' ){
260 if( geopolySkipSpace(&s
)==']'
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)
268 s
.nVertex
--; /* Remove the redundant vertex at the end */
269 pOut
= sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64
)s
.nVertex
) );
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;
279 if( pRc
) *pRc
= SQLITE_OK
;
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.
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 */
306 if( sqlite3_value_type(pVal
)==SQLITE_BLOB
307 && (nByte
= sqlite3_value_bytes(pVal
))>=(int)(4+6*sizeof(GeoCoord
))
309 const unsigned char *a
= sqlite3_value_blob(pVal
);
312 if( pCtx
) sqlite3_result_error_nomem(pCtx
);
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
319 p
= sqlite3_malloc64( sizeof(*p
) + (nVertex
-1)*2*sizeof(GeoCoord
) );
321 if( pRc
) *pRc
= SQLITE_NOMEM
;
322 if( pCtx
) sqlite3_result_error_nomem(pCtx
);
325 p
->nVertex
= nVertex
;
326 memcpy(p
->hdr
, a
, nByte
);
327 if( a
[0] != *(unsigned char*)&x
){
329 for(ii
=0; ii
<nVertex
; ii
++){
330 geopolySwab32((unsigned char*)&GeoX(p
,ii
));
331 geopolySwab32((unsigned char*)&GeoY(p
,ii
));
337 if( pRc
) *pRc
= SQLITE_OK
;
339 }else if( sqlite3_value_type(pVal
)==SQLITE_TEXT
){
340 const unsigned char *zJson
= sqlite3_value_text(pVal
);
342 if( pRc
) *pRc
= SQLITE_NOMEM
;
345 return geopolyParseJson(zJson
, pRc
);
347 if( pRc
) *pRc
= SQLITE_ERROR
;
353 ** Implementation of the geopoly_blob(X) function.
355 ** If the input is a well-formed Geopoly BLOB or JSON string
356 ** then return the BLOB representation of the polygon. Otherwise
359 static void geopolyBlobFunc(
360 sqlite3_context
*context
,
364 GeoPoly
*p
= geopolyFuncParam(context
, argv
[0], 0);
367 sqlite3_result_blob(context
, p
->hdr
,
368 4+8*p
->nVertex
, SQLITE_TRANSIENT
);
374 ** SQL function: geopoly_json(X)
376 ** Interpret X as a polygon and render it as a JSON array
377 ** of coordinates. Or, if X is not a valid polygon, return NULL.
379 static void geopolyJsonFunc(
380 sqlite3_context
*context
,
384 GeoPoly
*p
= geopolyFuncParam(context
, argv
[0], 0);
387 sqlite3
*db
= sqlite3_context_db_handle(context
);
388 sqlite3_str
*x
= sqlite3_str_new(db
);
390 sqlite3_str_append(x
, "[", 1);
391 for(i
=0; i
<p
->nVertex
; i
++){
392 sqlite3_str_appendf(x
, "[%!g,%!g],", GeoX(p
,i
), GeoY(p
,i
));
394 sqlite3_str_appendf(x
, "[%!g,%!g]]", GeoX(p
,0), GeoY(p
,0));
395 sqlite3_result_text(context
, sqlite3_str_finish(x
), -1, sqlite3_free
);
401 ** SQL function: geopoly_svg(X, ....)
403 ** Interpret X as a polygon and render it as a SVG <polyline>.
404 ** Additional arguments are added as attributes to the <polyline>.
406 static void geopolySvgFunc(
407 sqlite3_context
*context
,
413 p
= geopolyFuncParam(context
, argv
[0], 0);
415 sqlite3
*db
= sqlite3_context_db_handle(context
);
416 sqlite3_str
*x
= sqlite3_str_new(db
);
419 sqlite3_str_appendf(x
, "<polyline points=");
420 for(i
=0; i
<p
->nVertex
; i
++){
421 sqlite3_str_appendf(x
, "%c%g,%g", cSep
, GeoX(p
,i
), GeoY(p
,i
));
424 sqlite3_str_appendf(x
, " %g,%g'", GeoX(p
,0), GeoY(p
,0));
425 for(i
=1; i
<argc
; i
++){
426 const char *z
= (const char*)sqlite3_value_text(argv
[i
]);
428 sqlite3_str_appendf(x
, " %s", z
);
431 sqlite3_str_appendf(x
, "></polyline>");
432 sqlite3_result_text(context
, sqlite3_str_finish(x
), -1, sqlite3_free
);
438 ** SQL Function: geopoly_xform(poly, A, B, C, D, E, F)
440 ** Transform and/or translate a polygon as follows:
442 ** x1 = A*x0 + B*y0 + E
443 ** y1 = C*x0 + D*y0 + F
445 ** For a translation:
447 ** geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset)
449 ** Rotate by R around the point (0,0):
451 ** geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0)
453 static void geopolyXformFunc(
454 sqlite3_context
*context
,
458 GeoPoly
*p
= geopolyFuncParam(context
, argv
[0], 0);
459 double A
= sqlite3_value_double(argv
[1]);
460 double B
= sqlite3_value_double(argv
[2]);
461 double C
= sqlite3_value_double(argv
[3]);
462 double D
= sqlite3_value_double(argv
[4]);
463 double E
= sqlite3_value_double(argv
[5]);
464 double F
= sqlite3_value_double(argv
[6]);
465 GeoCoord x1
, y1
, x0
, y0
;
469 for(ii
=0; ii
<p
->nVertex
; ii
++){
472 x1
= (GeoCoord
)(A
*x0
+ B
*y0
+ E
);
473 y1
= (GeoCoord
)(C
*x0
+ D
*y0
+ F
);
477 sqlite3_result_blob(context
, p
->hdr
,
478 4+8*p
->nVertex
, SQLITE_TRANSIENT
);
484 ** Compute the area enclosed by the polygon.
486 ** This routine can also be used to detect polygons that rotate in
487 ** the wrong direction. Polygons are suppose to be counter-clockwise (CCW).
488 ** This routine returns a negative value for clockwise (CW) polygons.
490 static double geopolyArea(GeoPoly
*p
){
493 for(ii
=0; ii
<p
->nVertex
-1; ii
++){
494 rArea
+= (GeoX(p
,ii
) - GeoX(p
,ii
+1)) /* (x0 - x1) */
495 * (GeoY(p
,ii
) + GeoY(p
,ii
+1)) /* (y0 + y1) */
498 rArea
+= (GeoX(p
,ii
) - GeoX(p
,0)) /* (xN - x0) */
499 * (GeoY(p
,ii
) + GeoY(p
,0)) /* (yN + y0) */
505 ** Implementation of the geopoly_area(X) function.
507 ** If the input is a well-formed Geopoly BLOB then return the area
508 ** enclosed by the polygon. If the polygon circulates clockwise instead
509 ** of counterclockwise (as it should) then return the negative of the
510 ** enclosed area. Otherwise return NULL.
512 static void geopolyAreaFunc(
513 sqlite3_context
*context
,
517 GeoPoly
*p
= geopolyFuncParam(context
, argv
[0], 0);
520 sqlite3_result_double(context
, geopolyArea(p
));
526 ** Implementation of the geopoly_ccw(X) function.
528 ** If the rotation of polygon X is clockwise (incorrect) instead of
529 ** counter-clockwise (the correct winding order according to RFC7946)
530 ** then reverse the order of the vertexes in polygon X.
532 ** In other words, this routine returns a CCW polygon regardless of the
533 ** winding order of its input.
535 ** Use this routine to sanitize historical inputs that that sometimes
536 ** contain polygons that wind in the wrong direction.
538 static void geopolyCcwFunc(
539 sqlite3_context
*context
,
543 GeoPoly
*p
= geopolyFuncParam(context
, argv
[0], 0);
546 if( geopolyArea(p
)<0.0 ){
548 for(ii
=1, jj
=p
->nVertex
-1; ii
<jj
; ii
++, jj
--){
549 GeoCoord t
= GeoX(p
,ii
);
550 GeoX(p
,ii
) = GeoX(p
,jj
);
553 GeoY(p
,ii
) = GeoY(p
,jj
);
557 sqlite3_result_blob(context
, p
->hdr
,
558 4+8*p
->nVertex
, SQLITE_TRANSIENT
);
563 #define GEOPOLY_PI 3.1415926535897932385
565 /* Fast approximation for sine(X) for X between -0.5*pi and 2*pi
567 static double geopolySine(double r
){
568 assert( r
>=-0.5*GEOPOLY_PI
&& r
<=2.0*GEOPOLY_PI
);
569 if( r
>=1.5*GEOPOLY_PI
){
572 if( r
>=0.5*GEOPOLY_PI
){
573 return -geopolySine(r
-GEOPOLY_PI
);
578 return 0.9996949*r
- 0.1656700*r3
+ 0.0075134*r5
;
583 ** Function: geopoly_regular(X,Y,R,N)
585 ** Construct a simple, convex, regular polygon centered at X, Y
586 ** with circumradius R and with N sides.
588 static void geopolyRegularFunc(
589 sqlite3_context
*context
,
593 double x
= sqlite3_value_double(argv
[0]);
594 double y
= sqlite3_value_double(argv
[1]);
595 double r
= sqlite3_value_double(argv
[2]);
596 int n
= sqlite3_value_int(argv
[3]);
601 if( n
<3 || r
<=0.0 ) return;
602 if( n
>1000 ) n
= 1000;
603 p
= sqlite3_malloc64( sizeof(*p
) + (n
-1)*2*sizeof(GeoCoord
) );
605 sqlite3_result_error_nomem(context
);
609 p
->hdr
[0] = *(unsigned char*)&i
;
611 p
->hdr
[2] = (n
>>8)&0xff;
614 double rAngle
= 2.0*GEOPOLY_PI
*i
/n
;
615 GeoX(p
,i
) = x
- r
*geopolySine(rAngle
-0.5*GEOPOLY_PI
);
616 GeoY(p
,i
) = y
+ r
*geopolySine(rAngle
);
618 sqlite3_result_blob(context
, p
->hdr
, 4+8*n
, SQLITE_TRANSIENT
);
623 ** If pPoly is a polygon, compute its bounding box. Then:
625 ** (1) if aCoord!=0 store the bounding box in aCoord, returning NULL
626 ** (2) otherwise, compute a GeoPoly for the bounding box and return the
629 ** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from
630 ** the bounding box in aCoord and return a pointer to that GeoPoly.
632 static GeoPoly
*geopolyBBox(
633 sqlite3_context
*context
, /* For recording the error */
634 sqlite3_value
*pPoly
, /* The polygon */
635 RtreeCoord
*aCoord
, /* Results here */
636 int *pRc
/* Error code here */
640 float mnX
, mxX
, mnY
, mxY
;
641 if( pPoly
==0 && aCoord
!=0 ){
647 goto geopolyBboxFill
;
649 p
= geopolyFuncParam(context
, pPoly
, pRc
);
653 mnX
= mxX
= GeoX(p
,0);
654 mnY
= mxY
= GeoY(p
,0);
655 for(ii
=1; ii
<p
->nVertex
; ii
++){
656 double r
= GeoX(p
,ii
);
657 if( r
<mnX
) mnX
= (float)r
;
658 else if( r
>mxX
) mxX
= (float)r
;
660 if( r
<mnY
) mnY
= (float)r
;
661 else if( r
>mxY
) mxY
= (float)r
;
663 if( pRc
) *pRc
= SQLITE_OK
;
666 pOut
= sqlite3_realloc64(p
, GEOPOLY_SZ(4));
669 if( context
) sqlite3_result_error_nomem(context
);
670 if( pRc
) *pRc
= SQLITE_NOMEM
;
675 pOut
->hdr
[0] = *(unsigned char*)&ii
;
695 memset(aCoord
, 0, sizeof(RtreeCoord
)*4);
701 ** Implementation of the geopoly_bbox(X) SQL function.
703 static void geopolyBBoxFunc(
704 sqlite3_context
*context
,
708 GeoPoly
*p
= geopolyBBox(context
, argv
[0], 0, 0);
711 sqlite3_result_blob(context
, p
->hdr
,
712 4+8*p
->nVertex
, SQLITE_TRANSIENT
);
718 ** State vector for the geopoly_group_bbox() aggregate function.
720 typedef struct GeoBBox GeoBBox
;
728 ** Implementation of the geopoly_group_bbox(X) aggregate SQL function.
730 static void geopolyBBoxStep(
731 sqlite3_context
*context
,
738 (void)geopolyBBox(context
, argv
[0], a
, &rc
);
741 pBBox
= (GeoBBox
*)sqlite3_aggregate_context(context
, sizeof(*pBBox
));
742 if( pBBox
==0 ) return;
743 if( pBBox
->isInit
==0 ){
745 memcpy(pBBox
->a
, a
, sizeof(RtreeCoord
)*4);
747 if( a
[0].f
< pBBox
->a
[0].f
) pBBox
->a
[0] = a
[0];
748 if( a
[1].f
> pBBox
->a
[1].f
) pBBox
->a
[1] = a
[1];
749 if( a
[2].f
< pBBox
->a
[2].f
) pBBox
->a
[2] = a
[2];
750 if( a
[3].f
> pBBox
->a
[3].f
) pBBox
->a
[3] = a
[3];
754 static void geopolyBBoxFinal(
755 sqlite3_context
*context
759 pBBox
= (GeoBBox
*)sqlite3_aggregate_context(context
, 0);
760 if( pBBox
==0 ) return;
761 p
= geopolyBBox(context
, 0, pBBox
->a
, 0);
763 sqlite3_result_blob(context
, p
->hdr
,
764 4+8*p
->nVertex
, SQLITE_TRANSIENT
);
771 ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
774 ** +2 x0,y0 is on the line segement
776 ** +1 x0,y0 is beneath line segment
778 ** 0 x0,y0 is not on or beneath the line segment or the line segment
779 ** is vertical and x0,y0 is not on the line segment
781 ** The left-most coordinate min(x1,x2) is not considered to be part of
782 ** the line segment for the purposes of this analysis.
784 static int pointBeneathLine(
785 double x0
, double y0
,
786 double x1
, double y1
,
790 if( x0
==x1
&& y0
==y1
) return 2;
792 if( x0
<=x1
|| x0
>x2
) return 0;
794 if( x0
<=x2
|| x0
>x1
) return 0;
796 /* Vertical line segment */
797 if( x0
!=x1
) return 0;
798 if( y0
<y1
&& y0
<y2
) return 0;
799 if( y0
>y1
&& y0
>y2
) return 0;
802 y
= y1
+ (y2
-y1
)*(x0
-x1
)/(x2
-x1
);
803 if( y0
==y
) return 2;
809 ** SQL function: geopoly_contains_point(P,X,Y)
811 ** Return +2 if point X,Y is within polygon P.
812 ** Return +1 if point X,Y is on the polygon boundary.
813 ** Return 0 if point X,Y is outside the polygon
815 static void geopolyContainsPointFunc(
816 sqlite3_context
*context
,
820 GeoPoly
*p1
= geopolyFuncParam(context
, argv
[0], 0);
821 double x0
= sqlite3_value_double(argv
[1]);
822 double y0
= sqlite3_value_double(argv
[2]);
829 for(ii
=0; ii
<p1
->nVertex
-1; ii
++){
830 v
= pointBeneathLine(x0
,y0
,GeoX(p1
,ii
), GeoY(p1
,ii
),
831 GeoX(p1
,ii
+1),GeoY(p1
,ii
+1));
836 v
= pointBeneathLine(x0
,y0
,GeoX(p1
,ii
), GeoY(p1
,ii
),
837 GeoX(p1
,0), GeoY(p1
,0));
840 sqlite3_result_int(context
, 1);
841 }else if( ((v
+cnt
)&1)==0 ){
842 sqlite3_result_int(context
, 0);
844 sqlite3_result_int(context
, 2);
849 /* Forward declaration */
850 static int geopolyOverlap(GeoPoly
*p1
, GeoPoly
*p2
);
853 ** SQL function: geopoly_within(P1,P2)
855 ** Return +2 if P1 and P2 are the same polygon
856 ** Return +1 if P2 is contained within P1
857 ** Return 0 if any part of P2 is on the outside of P1
860 static void geopolyWithinFunc(
861 sqlite3_context
*context
,
865 GeoPoly
*p1
= geopolyFuncParam(context
, argv
[0], 0);
866 GeoPoly
*p2
= geopolyFuncParam(context
, argv
[1], 0);
869 int x
= geopolyOverlap(p1
, p2
);
871 sqlite3_result_error_nomem(context
);
873 sqlite3_result_int(context
, x
==2 ? 1 : x
==4 ? 2 : 0);
880 /* Objects used by the overlap algorihm. */
881 typedef struct GeoEvent GeoEvent
;
882 typedef struct GeoSegment GeoSegment
;
883 typedef struct GeoOverlap GeoOverlap
;
885 double x
; /* X coordinate at which event occurs */
886 int eType
; /* 0 for ADD, 1 for REMOVE */
887 GeoSegment
*pSeg
; /* The segment to be added or removed */
888 GeoEvent
*pNext
; /* Next event in the sorted list */
891 double C
, B
; /* y = C*x + B */
892 double y
; /* Current y value */
893 float y0
; /* Initial y value */
894 unsigned char side
; /* 1 for p1, 2 for p2 */
895 unsigned int idx
; /* Which segment within the side */
896 GeoSegment
*pNext
; /* Next segment in a list sorted by y */
899 GeoEvent
*aEvent
; /* Array of all events */
900 GeoSegment
*aSegment
; /* Array of all segments */
901 int nEvent
; /* Number of events */
902 int nSegment
; /* Number of segments */
906 ** Add a single segment and its associated events.
908 static void geopolyAddOneSegment(
919 if( x0
==x1
) return; /* Ignore vertical segments */
928 pSeg
= p
->aSegment
+ p
->nSegment
;
930 pSeg
->C
= (y1
-y0
)/(x1
-x0
);
931 pSeg
->B
= y1
- x1
*pSeg
->C
;
935 pEvent
= p
->aEvent
+ p
->nEvent
;
940 pEvent
= p
->aEvent
+ p
->nEvent
;
950 ** Insert all segments and events for polygon pPoly.
952 static void geopolyAddSegments(
953 GeoOverlap
*p
, /* Add segments to this Overlap object */
954 GeoPoly
*pPoly
, /* Take all segments from this polygon */
955 unsigned char side
/* The side of pPoly */
959 for(i
=0; i
<(unsigned)pPoly
->nVertex
-1; i
++){
961 geopolyAddOneSegment(p
, x
[0], x
[1], x
[2], x
[3], side
, i
);
964 geopolyAddOneSegment(p
, x
[0], x
[1], pPoly
->a
[0], pPoly
->a
[1], side
, i
);
968 ** Merge two lists of sorted events by X coordinate
970 static GeoEvent
*geopolyEventMerge(GeoEvent
*pLeft
, GeoEvent
*pRight
){
971 GeoEvent head
, *pLast
;
974 while( pRight
&& pLeft
){
975 if( pRight
->x
<= pLeft
->x
){
976 pLast
->pNext
= pRight
;
978 pRight
= pRight
->pNext
;
980 pLast
->pNext
= pLeft
;
982 pLeft
= pLeft
->pNext
;
985 pLast
->pNext
= pRight
? pRight
: pLeft
;
990 ** Sort an array of nEvent event objects into a list.
992 static GeoEvent
*geopolySortEventsByX(GeoEvent
*aEvent
, int nEvent
){
997 for(i
=0; i
<nEvent
; i
++){
1000 for(j
=0; j
<mx
&& a
[j
]; j
++){
1001 p
= geopolyEventMerge(a
[j
], p
);
1005 if( j
>=mx
) mx
= j
+1;
1008 for(i
=0; i
<mx
; i
++){
1009 p
= geopolyEventMerge(a
[i
], p
);
1015 ** Merge two lists of sorted segments by Y, and then by C.
1017 static GeoSegment
*geopolySegmentMerge(GeoSegment
*pLeft
, GeoSegment
*pRight
){
1018 GeoSegment head
, *pLast
;
1021 while( pRight
&& pLeft
){
1022 double r
= pRight
->y
- pLeft
->y
;
1023 if( r
==0.0 ) r
= pRight
->C
- pLeft
->C
;
1025 pLast
->pNext
= pRight
;
1027 pRight
= pRight
->pNext
;
1029 pLast
->pNext
= pLeft
;
1031 pLeft
= pLeft
->pNext
;
1034 pLast
->pNext
= pRight
? pRight
: pLeft
;
1039 ** Sort a list of GeoSegments in order of increasing Y and in the event of
1040 ** a tie, increasing C (slope).
1042 static GeoSegment
*geopolySortSegmentsByYAndC(GeoSegment
*pList
){
1049 pList
= pList
->pNext
;
1051 for(i
=0; i
<mx
&& a
[i
]; i
++){
1052 p
= geopolySegmentMerge(a
[i
], p
);
1056 if( i
>=mx
) mx
= i
+1;
1059 for(i
=0; i
<mx
; i
++){
1060 p
= geopolySegmentMerge(a
[i
], p
);
1066 ** Determine the overlap between two polygons
1068 static int geopolyOverlap(GeoPoly
*p1
, GeoPoly
*p2
){
1069 sqlite3_int64 nVertex
= p1
->nVertex
+ p2
->nVertex
+ 2;
1071 sqlite3_int64 nByte
;
1072 GeoEvent
*pThisEvent
;
1076 GeoSegment
*pActive
= 0;
1078 unsigned char aOverlap
[4];
1080 nByte
= sizeof(GeoEvent
)*nVertex
*2
1081 + sizeof(GeoSegment
)*nVertex
1082 + sizeof(GeoOverlap
);
1083 p
= sqlite3_malloc64( nByte
);
1084 if( p
==0 ) return -1;
1085 p
->aEvent
= (GeoEvent
*)&p
[1];
1086 p
->aSegment
= (GeoSegment
*)&p
->aEvent
[nVertex
*2];
1087 p
->nEvent
= p
->nSegment
= 0;
1088 geopolyAddSegments(p
, p1
, 1);
1089 geopolyAddSegments(p
, p2
, 2);
1090 pThisEvent
= geopolySortEventsByX(p
->aEvent
, p
->nEvent
);
1091 rX
= pThisEvent
&& pThisEvent
->x
==0.0 ? -1.0 : 0.0;
1092 memset(aOverlap
, 0, sizeof(aOverlap
));
1093 while( pThisEvent
){
1094 if( pThisEvent
->x
!=rX
){
1095 GeoSegment
*pPrev
= 0;
1097 GEODEBUG(("Distinct X: %g\n", pThisEvent
->x
));
1100 GEODEBUG(("SORT\n"));
1101 pActive
= geopolySortSegmentsByYAndC(pActive
);
1104 for(pSeg
=pActive
; pSeg
; pSeg
=pSeg
->pNext
){
1106 if( pPrev
->y
!=pSeg
->y
){
1107 GEODEBUG(("MASK: %d\n", iMask
));
1108 aOverlap
[iMask
] = 1;
1111 iMask
^= pSeg
->side
;
1115 for(pSeg
=pActive
; pSeg
; pSeg
=pSeg
->pNext
){
1116 double y
= pSeg
->C
*rX
+ pSeg
->B
;
1117 GEODEBUG(("Segment %d.%d %g->%g\n", pSeg
->side
, pSeg
->idx
, pSeg
->y
, y
));
1120 if( pPrev
->y
>pSeg
->y
&& pPrev
->side
!=pSeg
->side
){
1122 GEODEBUG(("Crossing: %d.%d and %d.%d\n",
1123 pPrev
->side
, pPrev
->idx
,
1124 pSeg
->side
, pSeg
->idx
));
1125 goto geopolyOverlapDone
;
1126 }else if( pPrev
->y
!=pSeg
->y
){
1127 GEODEBUG(("MASK: %d\n", iMask
));
1128 aOverlap
[iMask
] = 1;
1131 iMask
^= pSeg
->side
;
1135 GEODEBUG(("%s %d.%d C=%g B=%g\n",
1136 pThisEvent
->eType
? "RM " : "ADD",
1137 pThisEvent
->pSeg
->side
, pThisEvent
->pSeg
->idx
,
1138 pThisEvent
->pSeg
->C
,
1139 pThisEvent
->pSeg
->B
));
1140 if( pThisEvent
->eType
==0 ){
1142 pSeg
= pThisEvent
->pSeg
;
1144 pSeg
->pNext
= pActive
;
1148 /* Remove a segment */
1149 if( pActive
==pThisEvent
->pSeg
){
1150 pActive
= ALWAYS(pActive
) ? pActive
->pNext
: 0;
1152 for(pSeg
=pActive
; pSeg
; pSeg
=pSeg
->pNext
){
1153 if( pSeg
->pNext
==pThisEvent
->pSeg
){
1154 pSeg
->pNext
= ALWAYS(pSeg
->pNext
) ? pSeg
->pNext
->pNext
: 0;
1160 pThisEvent
= pThisEvent
->pNext
;
1162 if( aOverlap
[3]==0 ){
1164 }else if( aOverlap
[1]!=0 && aOverlap
[2]==0 ){
1166 }else if( aOverlap
[1]==0 && aOverlap
[2]!=0 ){
1168 }else if( aOverlap
[1]==0 && aOverlap
[2]==0 ){
1180 ** SQL function: geopoly_overlap(P1,P2)
1182 ** Determine whether or not P1 and P2 overlap. Return value:
1184 ** 0 The two polygons are disjoint
1186 ** 2 P1 is completely contained within P2
1187 ** 3 P2 is completely contained within P1
1188 ** 4 P1 and P2 are the same polygon
1189 ** NULL Either P1 or P2 or both are not valid polygons
1191 static void geopolyOverlapFunc(
1192 sqlite3_context
*context
,
1194 sqlite3_value
**argv
1196 GeoPoly
*p1
= geopolyFuncParam(context
, argv
[0], 0);
1197 GeoPoly
*p2
= geopolyFuncParam(context
, argv
[1], 0);
1200 int x
= geopolyOverlap(p1
, p2
);
1202 sqlite3_result_error_nomem(context
);
1204 sqlite3_result_int(context
, x
);
1212 ** Enable or disable debugging output
1214 static void geopolyDebugFunc(
1215 sqlite3_context
*context
,
1217 sqlite3_value
**argv
1221 #ifdef GEOPOLY_ENABLE_DEBUG
1222 geo_debug
= sqlite3_value_int(argv
[0]);
1229 ** This function is the implementation of both the xConnect and xCreate
1230 ** methods of the geopoly virtual table.
1232 ** argv[0] -> module name
1233 ** argv[1] -> database name
1234 ** argv[2] -> table name
1235 ** argv[...] -> column names...
1237 static int geopolyInit(
1238 sqlite3
*db
, /* Database connection */
1239 void *pAux
, /* One of the RTREE_COORD_* constants */
1240 int argc
, const char *const*argv
, /* Parameters to CREATE TABLE statement */
1241 sqlite3_vtab
**ppVtab
, /* OUT: New virtual table */
1242 char **pzErr
, /* OUT: Error message, if any */
1243 int isCreate
/* True for xCreate, false for xConnect */
1247 sqlite3_int64 nDb
; /* Length of string argv[1] */
1248 sqlite3_int64 nName
; /* Length of string argv[2] */
1254 sqlite3_vtab_config(db
, SQLITE_VTAB_CONSTRAINT_SUPPORT
, 1);
1255 sqlite3_vtab_config(db
, SQLITE_VTAB_INNOCUOUS
);
1257 /* Allocate the sqlite3_vtab structure */
1258 nDb
= strlen(argv
[1]);
1259 nName
= strlen(argv
[2]);
1260 pRtree
= (Rtree
*)sqlite3_malloc64(sizeof(Rtree
)+nDb
+nName
*2+8);
1262 return SQLITE_NOMEM
;
1264 memset(pRtree
, 0, sizeof(Rtree
)+nDb
+nName
*2+8);
1266 pRtree
->base
.pModule
= &rtreeModule
;
1267 pRtree
->zDb
= (char *)&pRtree
[1];
1268 pRtree
->zName
= &pRtree
->zDb
[nDb
+1];
1269 pRtree
->zNodeName
= &pRtree
->zName
[nName
+1];
1270 pRtree
->eCoordType
= RTREE_COORD_REAL32
;
1273 memcpy(pRtree
->zDb
, argv
[1], nDb
);
1274 memcpy(pRtree
->zName
, argv
[2], nName
);
1275 memcpy(pRtree
->zNodeName
, argv
[2], nName
);
1276 memcpy(&pRtree
->zNodeName
[nName
], "_node", 6);
1279 /* Create/Connect to the underlying relational database schema. If
1280 ** that is successful, call sqlite3_declare_vtab() to configure
1281 ** the r-tree table schema.
1283 pSql
= sqlite3_str_new(db
);
1284 sqlite3_str_appendf(pSql
, "CREATE TABLE x(_shape");
1285 pRtree
->nAux
= 1; /* Add one for _shape */
1286 pRtree
->nAuxNotNull
= 1; /* The _shape column is always not-null */
1287 for(ii
=3; ii
<argc
; ii
++){
1289 sqlite3_str_appendf(pSql
, ",%s", argv
[ii
]);
1291 sqlite3_str_appendf(pSql
, ");");
1292 zSql
= sqlite3_str_finish(pSql
);
1295 }else if( SQLITE_OK
!=(rc
= sqlite3_declare_vtab(db
, zSql
)) ){
1296 *pzErr
= sqlite3_mprintf("%s", sqlite3_errmsg(db
));
1299 if( rc
) goto geopolyInit_fail
;
1300 pRtree
->nBytesPerCell
= 8 + pRtree
->nDim2
*4;
1302 /* Figure out the node size to use. */
1303 rc
= getNodeSize(db
, pRtree
, isCreate
, pzErr
);
1304 if( rc
) goto geopolyInit_fail
;
1305 rc
= rtreeSqlInit(pRtree
, db
, argv
[1], argv
[2], isCreate
);
1307 *pzErr
= sqlite3_mprintf("%s", sqlite3_errmsg(db
));
1308 goto geopolyInit_fail
;
1311 *ppVtab
= (sqlite3_vtab
*)pRtree
;
1315 if( rc
==SQLITE_OK
) rc
= SQLITE_ERROR
;
1316 assert( *ppVtab
==0 );
1317 assert( pRtree
->nBusy
==1 );
1318 rtreeRelease(pRtree
);
1324 ** GEOPOLY virtual table module xCreate method.
1326 static int geopolyCreate(
1329 int argc
, const char *const*argv
,
1330 sqlite3_vtab
**ppVtab
,
1333 return geopolyInit(db
, pAux
, argc
, argv
, ppVtab
, pzErr
, 1);
1337 ** GEOPOLY virtual table module xConnect method.
1339 static int geopolyConnect(
1342 int argc
, const char *const*argv
,
1343 sqlite3_vtab
**ppVtab
,
1346 return geopolyInit(db
, pAux
, argc
, argv
, ppVtab
, pzErr
, 0);
1351 ** GEOPOLY virtual table module xFilter method.
1356 ** 2 search for objects overlapping the same bounding box
1357 ** that contains polygon argv[0]
1358 ** 3 search for objects overlapping the same bounding box
1359 ** that contains polygon argv[0]
1360 ** 4 full table scan
1362 static int geopolyFilter(
1363 sqlite3_vtab_cursor
*pVtabCursor
, /* The cursor to initialize */
1364 int idxNum
, /* Query plan */
1365 const char *idxStr
, /* Not Used */
1366 int argc
, sqlite3_value
**argv
/* Parameters to the query plan */
1368 Rtree
*pRtree
= (Rtree
*)pVtabCursor
->pVtab
;
1369 RtreeCursor
*pCsr
= (RtreeCursor
*)pVtabCursor
;
1370 RtreeNode
*pRoot
= 0;
1375 rtreeReference(pRtree
);
1377 /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
1380 pCsr
->iStrategy
= idxNum
;
1382 /* Special case - lookup by rowid. */
1383 RtreeNode
*pLeaf
; /* Leaf on which the required cell resides */
1384 RtreeSearchPoint
*p
; /* Search point for the leaf */
1385 i64 iRowid
= sqlite3_value_int64(argv
[0]);
1387 rc
= findLeafNode(pRtree
, iRowid
, &pLeaf
, &iNode
);
1388 if( rc
==SQLITE_OK
&& pLeaf
!=0 ){
1389 p
= rtreeSearchPointNew(pCsr
, RTREE_ZERO
, 0);
1390 assert( p
!=0 ); /* Always returns pCsr->sPoint */
1391 pCsr
->aNode
[0] = pLeaf
;
1393 p
->eWithin
= PARTLY_WITHIN
;
1394 rc
= nodeRowidIndex(pRtree
, pLeaf
, iRowid
, &iCell
);
1395 p
->iCell
= (u8
)iCell
;
1396 RTREE_QUEUE_TRACE(pCsr
, "PUSH-F1:");
1401 /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
1402 ** with the configured constraints.
1404 rc
= nodeAcquire(pRtree
, 1, 0, &pRoot
);
1405 if( rc
==SQLITE_OK
&& idxNum
<=3 ){
1409 assert( argv
[0]!=0 );
1410 geopolyBBox(0, argv
[0], bbox
, &rc
);
1412 goto geopoly_filter_end
;
1414 pCsr
->aConstraint
= p
= sqlite3_malloc(sizeof(RtreeConstraint
)*4);
1415 pCsr
->nConstraint
= 4;
1419 memset(pCsr
->aConstraint
, 0, sizeof(RtreeConstraint
)*4);
1420 memset(pCsr
->anQueue
, 0, sizeof(u32
)*(pRtree
->iDepth
+ 1));
1425 p
->u
.rValue
= bbox
[1].f
;
1429 p
->u
.rValue
= bbox
[0].f
;
1433 p
->u
.rValue
= bbox
[3].f
;
1437 p
->u
.rValue
= bbox
[2].f
;
1442 p
->u
.rValue
= bbox
[0].f
;
1446 p
->u
.rValue
= bbox
[1].f
;
1450 p
->u
.rValue
= bbox
[2].f
;
1454 p
->u
.rValue
= bbox
[3].f
;
1458 if( rc
==SQLITE_OK
){
1459 RtreeSearchPoint
*pNew
;
1460 pNew
= rtreeSearchPointNew(pCsr
, RTREE_ZERO
, (u8
)(pRtree
->iDepth
+1));
1463 goto geopoly_filter_end
;
1467 pNew
->eWithin
= PARTLY_WITHIN
;
1468 assert( pCsr
->bPoint
==1 );
1469 pCsr
->aNode
[0] = pRoot
;
1471 RTREE_QUEUE_TRACE(pCsr
, "PUSH-Fm:");
1472 rc
= rtreeStepToLeaf(pCsr
);
1477 nodeRelease(pRtree
, pRoot
);
1478 rtreeRelease(pRtree
);
1483 ** Rtree virtual table module xBestIndex method. There are three
1484 ** table scan strategies to choose from (in order from most to
1485 ** least desirable):
1487 ** idxNum idxStr Strategy
1488 ** ------------------------------------------------
1489 ** 1 "rowid" Direct lookup by rowid.
1490 ** 2 "rtree" R-tree overlap query using geopoly_overlap()
1491 ** 3 "rtree" R-tree within query using geopoly_within()
1492 ** 4 "fullscan" full-table scan.
1493 ** ------------------------------------------------
1495 static int geopolyBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
1497 int iRowidTerm
= -1;
1502 for(ii
=0; ii
<pIdxInfo
->nConstraint
; ii
++){
1503 struct sqlite3_index_constraint
*p
= &pIdxInfo
->aConstraint
[ii
];
1504 if( !p
->usable
) continue;
1505 if( p
->iColumn
<0 && p
->op
==SQLITE_INDEX_CONSTRAINT_EQ
){
1509 if( p
->iColumn
==0 && p
->op
>=SQLITE_INDEX_CONSTRAINT_FUNCTION
){
1510 /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap()
1511 ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within().
1512 ** See geopolyFindFunction() */
1514 idxNum
= p
->op
- SQLITE_INDEX_CONSTRAINT_FUNCTION
+ 2;
1518 if( iRowidTerm
>=0 ){
1519 pIdxInfo
->idxNum
= 1;
1520 pIdxInfo
->idxStr
= "rowid";
1521 pIdxInfo
->aConstraintUsage
[iRowidTerm
].argvIndex
= 1;
1522 pIdxInfo
->aConstraintUsage
[iRowidTerm
].omit
= 1;
1523 pIdxInfo
->estimatedCost
= 30.0;
1524 pIdxInfo
->estimatedRows
= 1;
1525 pIdxInfo
->idxFlags
= SQLITE_INDEX_SCAN_UNIQUE
;
1529 pIdxInfo
->idxNum
= idxNum
;
1530 pIdxInfo
->idxStr
= "rtree";
1531 pIdxInfo
->aConstraintUsage
[iFuncTerm
].argvIndex
= 1;
1532 pIdxInfo
->aConstraintUsage
[iFuncTerm
].omit
= 0;
1533 pIdxInfo
->estimatedCost
= 300.0;
1534 pIdxInfo
->estimatedRows
= 10;
1537 pIdxInfo
->idxNum
= 4;
1538 pIdxInfo
->idxStr
= "fullscan";
1539 pIdxInfo
->estimatedCost
= 3000000.0;
1540 pIdxInfo
->estimatedRows
= 100000;
1546 ** GEOPOLY virtual table module xColumn method.
1548 static int geopolyColumn(sqlite3_vtab_cursor
*cur
, sqlite3_context
*ctx
, int i
){
1549 Rtree
*pRtree
= (Rtree
*)cur
->pVtab
;
1550 RtreeCursor
*pCsr
= (RtreeCursor
*)cur
;
1551 RtreeSearchPoint
*p
= rtreeSearchPointFirst(pCsr
);
1553 RtreeNode
*pNode
= rtreeNodeOfFirstSearchPoint(pCsr
, &rc
);
1556 if( p
==0 ) return SQLITE_OK
;
1557 if( i
==0 && sqlite3_vtab_nochange(ctx
) ) return SQLITE_OK
;
1558 if( i
<=pRtree
->nAux
){
1559 if( !pCsr
->bAuxValid
){
1560 if( pCsr
->pReadAux
==0 ){
1561 rc
= sqlite3_prepare_v3(pRtree
->db
, pRtree
->zReadAuxSql
, -1, 0,
1562 &pCsr
->pReadAux
, 0);
1565 sqlite3_bind_int64(pCsr
->pReadAux
, 1,
1566 nodeGetRowid(pRtree
, pNode
, p
->iCell
));
1567 rc
= sqlite3_step(pCsr
->pReadAux
);
1568 if( rc
==SQLITE_ROW
){
1569 pCsr
->bAuxValid
= 1;
1571 sqlite3_reset(pCsr
->pReadAux
);
1572 if( rc
==SQLITE_DONE
) rc
= SQLITE_OK
;
1576 sqlite3_result_value(ctx
, sqlite3_column_value(pCsr
->pReadAux
, i
+2));
1583 ** The xUpdate method for GEOPOLY module virtual tables.
1587 ** argv[0] = the rowid to be deleted
1591 ** argv[0] = SQL NULL
1592 ** argv[1] = rowid to insert, or an SQL NULL to select automatically
1593 ** argv[2] = _shape column
1594 ** argv[3] = first application-defined column....
1598 ** argv[0] = rowid to modify. Never NULL
1599 ** argv[1] = rowid after the change. Never NULL
1600 ** argv[2] = new value for _shape
1601 ** argv[3] = new value for first application-defined column....
1603 static int geopolyUpdate(
1604 sqlite3_vtab
*pVtab
,
1606 sqlite3_value
**aData
,
1607 sqlite_int64
*pRowid
1609 Rtree
*pRtree
= (Rtree
*)pVtab
;
1611 RtreeCell cell
; /* New cell to insert if nData>1 */
1612 i64 oldRowid
; /* The old rowid */
1613 int oldRowidValid
; /* True if oldRowid is valid */
1614 i64 newRowid
; /* The new rowid */
1615 int newRowidValid
; /* True if newRowid is valid */
1616 int coordChange
= 0; /* Change in coordinates */
1618 if( pRtree
->nNodeRef
){
1619 /* Unable to write to the btree while another cursor is reading from it,
1620 ** since the write might do a rebalance which would disrupt the read
1622 return SQLITE_LOCKED_VTAB
;
1624 rtreeReference(pRtree
);
1627 oldRowidValid
= sqlite3_value_type(aData
[0])!=SQLITE_NULL
;;
1628 oldRowid
= oldRowidValid
? sqlite3_value_int64(aData
[0]) : 0;
1629 newRowidValid
= nData
>1 && sqlite3_value_type(aData
[1])!=SQLITE_NULL
;
1630 newRowid
= newRowidValid
? sqlite3_value_int64(aData
[1]) : 0;
1631 cell
.iRowid
= newRowid
;
1633 if( nData
>1 /* not a DELETE */
1634 && (!oldRowidValid
/* INSERT */
1635 || !sqlite3_value_nochange(aData
[2]) /* UPDATE _shape */
1636 || oldRowid
!=newRowid
) /* Rowid change */
1638 assert( aData
[2]!=0 );
1639 geopolyBBox(0, aData
[2], cell
.aCoord
, &rc
);
1641 if( rc
==SQLITE_ERROR
){
1643 sqlite3_mprintf("_shape does not contain a valid polygon");
1645 goto geopoly_update_end
;
1649 /* If a rowid value was supplied, check if it is already present in
1650 ** the table. If so, the constraint has failed. */
1651 if( newRowidValid
&& (!oldRowidValid
|| oldRowid
!=newRowid
) ){
1653 sqlite3_bind_int64(pRtree
->pReadRowid
, 1, cell
.iRowid
);
1654 steprc
= sqlite3_step(pRtree
->pReadRowid
);
1655 rc
= sqlite3_reset(pRtree
->pReadRowid
);
1656 if( SQLITE_ROW
==steprc
){
1657 if( sqlite3_vtab_on_conflict(pRtree
->db
)==SQLITE_REPLACE
){
1658 rc
= rtreeDeleteRowid(pRtree
, cell
.iRowid
);
1660 rc
= rtreeConstraintError(pRtree
, 0);
1666 /* If aData[0] is not an SQL NULL value, it is the rowid of a
1667 ** record to delete from the r-tree table. The following block does
1670 if( rc
==SQLITE_OK
&& (nData
==1 || (coordChange
&& oldRowidValid
)) ){
1671 rc
= rtreeDeleteRowid(pRtree
, oldRowid
);
1674 /* If the aData[] array contains more than one element, elements
1675 ** (aData[2]..aData[argc-1]) contain a new record to insert into
1676 ** the r-tree structure.
1678 if( rc
==SQLITE_OK
&& nData
>1 && coordChange
){
1679 /* Insert the new record into the r-tree */
1680 RtreeNode
*pLeaf
= 0;
1681 if( !newRowidValid
){
1682 rc
= rtreeNewRowid(pRtree
, &cell
.iRowid
);
1684 *pRowid
= cell
.iRowid
;
1685 if( rc
==SQLITE_OK
){
1686 rc
= ChooseLeaf(pRtree
, &cell
, 0, &pLeaf
);
1688 if( rc
==SQLITE_OK
){
1690 rc
= rtreeInsertCell(pRtree
, pLeaf
, &cell
, 0);
1691 rc2
= nodeRelease(pRtree
, pLeaf
);
1692 if( rc
==SQLITE_OK
){
1698 /* Change the data */
1699 if( rc
==SQLITE_OK
&& nData
>1 ){
1700 sqlite3_stmt
*pUp
= pRtree
->pWriteAux
;
1703 sqlite3_bind_int64(pUp
, 1, cell
.iRowid
);
1704 assert( pRtree
->nAux
>=1 );
1705 if( sqlite3_value_nochange(aData
[2]) ){
1706 sqlite3_bind_null(pUp
, 2);
1709 if( sqlite3_value_type(aData
[2])==SQLITE_TEXT
1710 && (p
= geopolyFuncParam(0, aData
[2], &rc
))!=0
1713 sqlite3_bind_blob(pUp
, 2, p
->hdr
, 4+8*p
->nVertex
, SQLITE_TRANSIENT
);
1715 sqlite3_bind_value(pUp
, 2, aData
[2]);
1720 for(jj
=1; jj
<nData
-2; jj
++){
1722 sqlite3_bind_value(pUp
, jj
+2, aData
[jj
+2]);
1726 rc
= sqlite3_reset(pUp
);
1731 rtreeRelease(pRtree
);
1736 ** Report that geopoly_overlap() is an overloaded function suitable
1737 ** for use in xBestIndex.
1739 static int geopolyFindFunction(
1740 sqlite3_vtab
*pVtab
,
1743 void (**pxFunc
)(sqlite3_context
*,int,sqlite3_value
**),
1748 if( sqlite3_stricmp(zName
, "geopoly_overlap")==0 ){
1749 *pxFunc
= geopolyOverlapFunc
;
1751 return SQLITE_INDEX_CONSTRAINT_FUNCTION
;
1753 if( sqlite3_stricmp(zName
, "geopoly_within")==0 ){
1754 *pxFunc
= geopolyWithinFunc
;
1756 return SQLITE_INDEX_CONSTRAINT_FUNCTION
+1;
1762 static sqlite3_module geopolyModule
= {
1764 geopolyCreate
, /* xCreate - create a table */
1765 geopolyConnect
, /* xConnect - connect to an existing table */
1766 geopolyBestIndex
, /* xBestIndex - Determine search strategy */
1767 rtreeDisconnect
, /* xDisconnect - Disconnect from a table */
1768 rtreeDestroy
, /* xDestroy - Drop a table */
1769 rtreeOpen
, /* xOpen - open a cursor */
1770 rtreeClose
, /* xClose - close a cursor */
1771 geopolyFilter
, /* xFilter - configure scan constraints */
1772 rtreeNext
, /* xNext - advance a cursor */
1773 rtreeEof
, /* xEof */
1774 geopolyColumn
, /* xColumn - read data */
1775 rtreeRowid
, /* xRowid - read data */
1776 geopolyUpdate
, /* xUpdate - write data */
1777 rtreeBeginTransaction
, /* xBegin - begin transaction */
1778 rtreeEndTransaction
, /* xSync - sync transaction */
1779 rtreeEndTransaction
, /* xCommit - commit transaction */
1780 rtreeEndTransaction
, /* xRollback - rollback transaction */
1781 geopolyFindFunction
, /* xFindFunction - function overloading */
1782 rtreeRename
, /* xRename - rename the table */
1783 rtreeSavepoint
, /* xSavepoint */
1785 0, /* xRollbackTo */
1786 rtreeShadowName
, /* xShadowName */
1787 rtreeIntegrity
/* xIntegrity */
1790 static int sqlite3_geopoly_init(sqlite3
*db
){
1792 static const struct {
1793 void (*xFunc
)(sqlite3_context
*,int,sqlite3_value
**);
1795 unsigned char bPure
;
1798 { geopolyAreaFunc
, 1, 1, "geopoly_area" },
1799 { geopolyBlobFunc
, 1, 1, "geopoly_blob" },
1800 { geopolyJsonFunc
, 1, 1, "geopoly_json" },
1801 { geopolySvgFunc
, -1, 1, "geopoly_svg" },
1802 { geopolyWithinFunc
, 2, 1, "geopoly_within" },
1803 { geopolyContainsPointFunc
, 3, 1, "geopoly_contains_point" },
1804 { geopolyOverlapFunc
, 2, 1, "geopoly_overlap" },
1805 { geopolyDebugFunc
, 1, 0, "geopoly_debug" },
1806 { geopolyBBoxFunc
, 1, 1, "geopoly_bbox" },
1807 { geopolyXformFunc
, 7, 1, "geopoly_xform" },
1808 { geopolyRegularFunc
, 4, 1, "geopoly_regular" },
1809 { geopolyCcwFunc
, 1, 1, "geopoly_ccw" },
1811 static const struct {
1812 void (*xStep
)(sqlite3_context
*,int,sqlite3_value
**);
1813 void (*xFinal
)(sqlite3_context
*);
1816 { geopolyBBoxStep
, geopolyBBoxFinal
, "geopoly_group_bbox" },
1819 for(i
=0; i
<sizeof(aFunc
)/sizeof(aFunc
[0]) && rc
==SQLITE_OK
; i
++){
1821 if( aFunc
[i
].bPure
){
1822 enc
= SQLITE_UTF8
|SQLITE_DETERMINISTIC
|SQLITE_INNOCUOUS
;
1824 enc
= SQLITE_UTF8
|SQLITE_DIRECTONLY
;
1826 rc
= sqlite3_create_function(db
, aFunc
[i
].zName
, aFunc
[i
].nArg
,
1828 aFunc
[i
].xFunc
, 0, 0);
1830 for(i
=0; i
<sizeof(aAgg
)/sizeof(aAgg
[0]) && rc
==SQLITE_OK
; i
++){
1831 rc
= sqlite3_create_function(db
, aAgg
[i
].zName
, 1,
1832 SQLITE_UTF8
|SQLITE_DETERMINISTIC
|SQLITE_INNOCUOUS
, 0,
1833 0, aAgg
[i
].xStep
, aAgg
[i
].xFinal
);
1835 if( rc
==SQLITE_OK
){
1836 rc
= sqlite3_create_module_v2(db
, "geopoly", &geopolyModule
, 0, 0);