]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Provide the two-argument geopoly_within(P1,P2) routine that determines if
authordrh <drh@noemail.net>
Sat, 25 Aug 2018 19:51:49 +0000 (19:51 +0000)
committerdrh <drh@noemail.net>
Sat, 25 Aug 2018 19:51:49 +0000 (19:51 +0000)
polygon P2 is contained within polygon P1.  Make this function available to
the query planner for optimized rtree lookups.  Update the visual01.txt
script to verify that the new functionality actually works.

FossilOrigin-Name: 6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7

ext/rtree/geopoly.c
ext/rtree/visual01.txt
manifest
manifest.uuid

index 229c399c7b38c11d4fac0e13511940dfa85ce9b7..1ebca66259d9675dea41c11ae6fcc75bcf1b59c4 100644 (file)
@@ -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; ii<p->nVertex-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; ii<p1->nVertex-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"    },
index bb3e4af5b54787c3ef28cd842832ed37f2d9e9f7..9aafb14dc36f4391d5056bf685a0c851316c5fb8 100644 (file)
@@ -374,7 +374,16 @@ SELECT geopoly_svg(poly,
        )
   FROM querypoly;
 .print '</svg>'
-.print '<h1>Query</h1>'
+
+.print '<h1>Overlap Query</h1>'
+.print '<pre>'
+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 '</pre>'
 .print '<svg width="1000" height="800" style="border:1px solid black">'
 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 '</svg>'
+
+.print '<h1>Within Query</h1>'
+.print '<pre>'
+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 '</pre>'
+.print '<svg width="1000" height="800" style="border:1px solid black">'
+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 '</svg>'
+
+.print '<h1>Not Overlap Query</h1>'
+.print '<pre>'
+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 '</pre>'
+.print '<svg width="1000" height="800" style="border:1px solid black">'
+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 '</svg>'
+
+.print '<h1>Not Within Query</h1>'
+.print '<pre>'
+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 '</pre>'
+.print '<svg width="1000" height="800" style="border:1px solid black">'
+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 '</svg>'
 .print '</html>'
index a150ebe81f67185439871c7bb04aa1f94b248e62..4be8e181d68ff7d3b6752394692b2d738ba3a410 100644 (file)
--- 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
index b99708861f727db7611172cf9eb41e824db69a31..c25d834242823dfb1c6bd6d4aefb6b7ae8f5c6c6 100644 (file)
@@ -1 +1 @@
-d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e
\ No newline at end of file
+6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7
\ No newline at end of file