/ Check-in [5a0e1541]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Split the three-argument version of geopoly_within() off into a separate function named geopoly_contains_point().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | rtree-geopoly
Files: files | file ages | folders
SHA3-256:5a0e1541037b5bbc1b4bf26a7da304c9b32ea72960aca8b9309cf2180757c8a4
User & Date: drh 2018-08-27 15:55:37
Context
2018-08-27
17:05
Minor changes to the visual01.txt test script. Closed-Leaf check-in: 4bc28eed user: drh tags: rtree-geopoly
15:55
Split the three-argument version of geopoly_within() off into a separate function named geopoly_contains_point(). check-in: 5a0e1541 user: drh tags: rtree-geopoly
2018-08-25
23:03
Enhance the geopoly virtual table so that it does a better job of optimizing geopoly_within() queries. check-in: 1f717385 user: drh tags: rtree-geopoly
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/rtree/geopoly.c.

   575    575     }
   576    576     y = y1 + (y2-y1)*(x0-x1)/(x2-x1);
   577    577     if( y0==y ) return 2;
   578    578     if( y0<y ) return 1;
   579    579     return 0;
   580    580   }
   581    581   
   582         -/* Forward declaration */
   583         -static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2);
   584         -
   585    582   /*
   586         -** SQL function:    geopoly_within(P,X,Y)  -- 3-argument form
          583  +** SQL function:    geopoly_contains_point(P,X,Y)
   587    584   **
   588    585   ** Return +2 if point X,Y is within polygon P.
   589    586   ** Return +1 if point X,Y is on the polygon boundary.
   590    587   ** Return 0 if point X,Y is outside the polygon
   591         -**
   592         -** SQL function:    geopoly_within(P1,P2)  -- 2-argument form
          588  +*/
          589  +static void geopolyContainsPointFunc(
          590  +  sqlite3_context *context,
          591  +  int argc,
          592  +  sqlite3_value **argv
          593  +){
          594  +  GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
          595  +  double x0 = sqlite3_value_double(argv[1]);
          596  +  double y0 = sqlite3_value_double(argv[2]);
          597  +  int v = 0;
          598  +  int cnt = 0;
          599  +  int ii;
          600  +  if( p1==0 ) return;
          601  +  for(ii=0; ii<p1->nVertex-1; ii++){
          602  +    v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
          603  +                               p1->a[ii*2+2],p1->a[ii*2+3]);
          604  +    if( v==2 ) break;
          605  +    cnt += v;
          606  +  }
          607  +  if( v!=2 ){
          608  +    v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
          609  +                               p1->a[0],p1->a[1]);
          610  +  }
          611  +  if( v==2 ){
          612  +    sqlite3_result_int(context, 1);
          613  +  }else if( ((v+cnt)&1)==0 ){
          614  +    sqlite3_result_int(context, 0);
          615  +  }else{
          616  +    sqlite3_result_int(context, 2);
          617  +  }
          618  +  sqlite3_free(p1);
          619  +}
          620  +
          621  +/* Forward declaration */
          622  +static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2);
          623  +
          624  +/*
          625  +** SQL function:    geopoly_within(P1,P2)
   593    626   **
   594    627   ** Return +2 if P1 and P2 are the same polygon
   595    628   ** Return +1 if P2 is contained within P1
   596    629   ** Return 0 if any part of P2 is on the outside of P1
   597    630   **
   598    631   */
   599    632   static void geopolyWithinFunc(
   600    633     sqlite3_context *context,
   601    634     int argc,
   602    635     sqlite3_value **argv
   603    636   ){
   604    637     GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
   605         -  if( p1==0 ) return;
   606         -  if( argc==3 ){
   607         -    double x0 = sqlite3_value_double(argv[1]);
   608         -    double y0 = sqlite3_value_double(argv[2]);
   609         -    int v = 0;
   610         -    int cnt = 0;
   611         -    int ii;
   612         -    for(ii=0; ii<p1->nVertex-1; ii++){
   613         -      v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
   614         -                                 p1->a[ii*2+2],p1->a[ii*2+3]);
   615         -      if( v==2 ) break;
   616         -      cnt += v;
   617         -    }
   618         -    if( v!=2 ){
   619         -      v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
   620         -                                 p1->a[0],p1->a[1]);
   621         -    }
   622         -    if( v==2 ){
   623         -      sqlite3_result_int(context, 1);
   624         -    }else if( ((v+cnt)&1)==0 ){
   625         -      sqlite3_result_int(context, 0);
          638  +  GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
          639  +  if( p1 && p2 ){
          640  +    int x = geopolyOverlap(p1, p2);
          641  +    if( x<0 ){
          642  +      sqlite3_result_error_nomem(context);
   626    643       }else{
   627         -      sqlite3_result_int(context, 2);
   628         -    }
   629         -  }else{
   630         -    assert( argc==2 );
   631         -    GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
   632         -    if( p2 ){
   633         -      int x = geopolyOverlap(p1, p2);
   634         -      if( x<0 ){
   635         -        sqlite3_result_error_nomem(context);
   636         -      }else{
   637         -        sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
   638         -      }
   639         -      sqlite3_free(p2);
          644  +      sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
   640    645       }
   641    646     }
   642    647     sqlite3_free(p1);
          648  +  sqlite3_free(p2);
   643    649   }
   644    650   
   645    651   /* Objects used by the overlap algorihm. */
   646    652   typedef struct GeoEvent GeoEvent;
   647    653   typedef struct GeoSegment GeoSegment;
   648    654   typedef struct GeoOverlap GeoOverlap;
   649    655   struct GeoEvent {
................................................................................
  1482   1488     void **ppArg
  1483   1489   ){
  1484   1490     if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){
  1485   1491       *pxFunc = geopolyOverlapFunc;
  1486   1492       *ppArg = 0;
  1487   1493       return SQLITE_INDEX_CONSTRAINT_FUNCTION;
  1488   1494     }
  1489         -  if( nArg==2 && sqlite3_stricmp(zName, "geopoly_within")==0 ){
         1495  +  if( sqlite3_stricmp(zName, "geopoly_within")==0 ){
  1490   1496       *pxFunc = geopolyWithinFunc;
  1491   1497       *ppArg = 0;
  1492   1498       return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
  1493   1499     }
  1494   1500     return 0;
  1495   1501   }
  1496   1502   
................................................................................
  1524   1530   static int sqlite3_geopoly_init(sqlite3 *db){
  1525   1531     int rc = SQLITE_OK;
  1526   1532     static const struct {
  1527   1533       void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
  1528   1534       int nArg;
  1529   1535       const char *zName;
  1530   1536     } aFunc[] = {
  1531         -     { geopolyAreaFunc,          1,    "geopoly_area"     },
  1532         -     { geopolyBlobFunc,          1,    "geopoly_blob"     },
  1533         -     { geopolyJsonFunc,          1,    "geopoly_json"     },
  1534         -     { geopolySvgFunc,          -1,    "geopoly_svg"      },
  1535         -     { geopolyWithinFunc,        2,    "geopoly_within"   },
  1536         -     { geopolyWithinFunc,        3,    "geopoly_within"   },
  1537         -     { geopolyOverlapFunc,       2,    "geopoly_overlap"  },
  1538         -     { geopolyDebugFunc,         1,    "geopoly_debug"    },
  1539         -     { geopolyBBoxFunc,          1,    "geopoly_bbox"     },
  1540         -     { geopolyXformFunc,         7,    "geopoly_xform"    },
         1537  +     { geopolyAreaFunc,          1,    "geopoly_area"             },
         1538  +     { geopolyBlobFunc,          1,    "geopoly_blob"             },
         1539  +     { geopolyJsonFunc,          1,    "geopoly_json"             },
         1540  +     { geopolySvgFunc,          -1,    "geopoly_svg"              },
         1541  +     { geopolyWithinFunc,        2,    "geopoly_within"           },
         1542  +     { geopolyContainsPointFunc, 3,    "geopoly_contains_point"   },
         1543  +     { geopolyOverlapFunc,       2,    "geopoly_overlap"          },
         1544  +     { geopolyDebugFunc,         1,    "geopoly_debug"            },
         1545  +     { geopolyBBoxFunc,          1,    "geopoly_bbox"             },
         1546  +     { geopolyXformFunc,         7,    "geopoly_xform"            },
  1541   1547     };
  1542   1548     int i;
  1543   1549     for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
  1544   1550       rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
  1545   1551                                    SQLITE_UTF8, 0,
  1546   1552                                    aFunc[i].xFunc, 0, 0);
  1547   1553     }
  1548   1554     if( rc==SQLITE_OK ){
  1549   1555       rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
  1550   1556     }
  1551   1557     return rc;
  1552   1558   }