/ Check-in [5a0e1541]

Many hyperlinks are disabled.

Overview
Comment: Split the three-argument version of geopoly_within() off into a separate function named geopoly_contains_point(). Tarball | ZIP archive | SQL archive family | ancestors | descendants | both | rtree-geopoly files | file ages | folders 5a0e1541037b5bbc1b4bf26a7da304c9b32ea72960aca8b9309cf2180757c8a4 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

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   }

```