diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 229c399c7b..1ebca66259 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -579,34 +579,45 @@ static int pointBeneathLine( return 0; } +/* Forward declaration */ +static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2); + /* -** SQL function: geopoly_within(P,X,Y) +** SQL function: geopoly_within(P,X,Y) -- 3-argument form ** ** Return +2 if point X,Y is within polygon P. ** Return +1 if point X,Y is on the polygon boundary. ** Return 0 if point X,Y is outside the polygon +** +** SQL function: geopoly_within(P1,P2) -- 2-argument form +** +** Return +2 if P1 and P2 are the same polygon +** Return +1 if P2 is contained within P1 +** Return 0 if any part of P2 is on the outside of P1 +** */ static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - GeoPoly *p = geopolyFuncParam(context, argv[0], 0); - double x0 = sqlite3_value_double(argv[1]); - double y0 = sqlite3_value_double(argv[2]); - if( p ){ + GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); + if( p1==0 ) return; + if( argc==3 ){ + double x0 = sqlite3_value_double(argv[1]); + double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; - for(ii=0; iinVertex-1; ii++){ - v = pointBeneathLine(x0,y0,p->a[ii*2],p->a[ii*2+1], - p->a[ii*2+2],p->a[ii*2+3]); + for(ii=0; iinVertex-1; ii++){ + v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], + p1->a[ii*2+2],p1->a[ii*2+3]); if( v==2 ) break; cnt += v; } if( v!=2 ){ - v = pointBeneathLine(x0,y0,p->a[ii*2],p->a[ii*2+1], - p->a[0],p->a[1]); + v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], + p1->a[0],p1->a[1]); } if( v==2 ){ sqlite3_result_int(context, 1); @@ -615,8 +626,20 @@ static void geopolyWithinFunc( }else{ sqlite3_result_int(context, 2); } - sqlite3_free(p); - } + }else{ + assert( argc==2 ); + GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); + if( p2 ){ + int x = geopolyOverlap(p1, p2); + if( x<0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); + } + sqlite3_free(p2); + } + } + sqlite3_free(p1); } /* Objects used by the overlap algorihm. */ @@ -1219,6 +1242,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ if( iRowidTerm>=0 ){ pIdxInfo->idxNum = 1; + pIdxInfo->idxStr = "rowid"; pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; pIdxInfo->estimatedCost = 30.0; @@ -1228,6 +1252,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ } if( iFuncTerm>=0 ){ pIdxInfo->idxNum = 2; + pIdxInfo->idxStr = "rtree"; pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0; pIdxInfo->estimatedCost = 300.0; @@ -1235,6 +1260,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ return SQLITE_OK; } pIdxInfo->idxNum = 3; + pIdxInfo->idxStr = "fullscan"; pIdxInfo->estimatedCost = 3000000.0; pIdxInfo->estimatedRows = 100000; return SQLITE_OK; @@ -1432,6 +1458,11 @@ static int geopolyFindFunction( *ppArg = 0; return SQLITE_INDEX_CONSTRAINT_FUNCTION; } + if( nArg==2 && sqlite3_stricmp(zName, "geopoly_within")==0 ){ + *pxFunc = geopolyWithinFunc; + *ppArg = 0; + return SQLITE_INDEX_CONSTRAINT_FUNCTION; + } return 0; } @@ -1473,6 +1504,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){ { geopolyBlobFunc, 1, "geopoly_blob" }, { geopolyJsonFunc, 1, "geopoly_json" }, { geopolySvgFunc, -1, "geopoly_svg" }, + { geopolyWithinFunc, 2, "geopoly_within" }, { geopolyWithinFunc, 3, "geopoly_within" }, { geopolyOverlapFunc, 2, "geopoly_overlap" }, { geopolyDebugFunc, 1, "geopoly_debug" }, diff --git a/ext/rtree/visual01.txt b/ext/rtree/visual01.txt index bb3e4af5b5..9aafb14dc3 100644 --- a/ext/rtree/visual01.txt +++ b/ext/rtree/visual01.txt @@ -374,7 +374,16 @@ SELECT geopoly_svg(poly, ) FROM querypoly; .print '' -.print '

Query

' + +.print '

Overlap Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_overlap(_shape, poly);
+.print '
' .print '' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) @@ -386,4 +395,67 @@ SELECT geopoly_svg(poly, ) FROM querypoly; .print '' + +.print '

Within Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_within(_shape, poly);
+.print '
' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE geopoly_within(_shape, poly); +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' + +.print '

Not Overlap Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE NOT geopoly_overlap(_shape, poly);
+.print '
' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE NOT geopoly_overlap(_shape, poly); +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' + +.print '

Not Within Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE NOT geopoly_within(_shape, poly);
+.print '
' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE NOT geopoly_within(_shape, poly); +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' .print '' diff --git a/manifest b/manifest index a150ebe81f..4be8e181d6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sharmless\scompiler\swarning. -D 2018-08-25T18:57:12.922 +C Provide\sthe\stwo-argument\sgeopoly_within(P1,P2)\sroutine\sthat\sdetermines\sif\npolygon\sP2\sis\scontained\swithin\spolygon\sP1.\s\sMake\sthis\sfunction\savailable\sto\nthe\squery\splanner\sfor\soptimized\srtree\slookups.\s\sUpdate\sthe\svisual01.txt\nscript\sto\sverify\sthat\sthe\snew\sfunctionality\sactually\sworks. +D 2018-08-25T19:51:49.457 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -359,7 +359,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782 F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/geopoly.c 9d4f90cdb08bc46de463c5ee1ab7cf114f33f7d512165a9b60eb710a5801777a +F ext/rtree/geopoly.c b495718226257fe7a69df3367ae9a440a81f99e63013177cb327fbc8a12a1d92 F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 @@ -386,7 +386,7 @@ F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae926833 F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 -F ext/rtree/visual01.txt ce5473774986a7fde188de9cbfc554f9c0f07109c61a5169019bd0c514776c11 +F ext/rtree/visual01.txt c5cceddea30ab74099365a54ee8850f085d01503050353240eda48b6062ad3f4 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0 @@ -1757,7 +1757,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c446c8841192054c97ba5003fb6185b135a687b36c10fe0986e627282955520a -R a41568f93760504ebb09f57d0f907e04 +P d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e +R d6a6a8b236c31c3e94eaf646cbba5241 U drh -Z e5256e66a995508165b2fa785b46beee +Z 150d6fa9f487a014f94bf1a66214204f diff --git a/manifest.uuid b/manifest.uuid index b99708861f..c25d834242 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e \ No newline at end of file +6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7 \ No newline at end of file