SQLite

Check-in [927d52a93c]
Login

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

Overview
Comment:Add the geopoly_within() SQL function.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | geojson
Files: files | file ages | folders
SHA3-256: 927d52a93c82ae408cb1651fd1326772f0be7442b6673e89f20567e633d39af3
User & Date: drh 2018-05-11 16:50:57.975
Context
2018-05-12
16:05
An initial attempt at an overlap function in the geopoly extension. (check-in: c857976efb user: drh tags: geojson)
2018-05-11
16:50
Add the geopoly_within() SQL function. (check-in: 927d52a93c user: drh tags: geojson)
15:38
Add the geopoly_read() SQL function to the geopoly.c extension. (check-in: b37625e8e4 user: drh tags: geojson)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/misc/geopoly.c.
363
364
365
366
367
368
369














































































370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

388
389
390
391
392
393
394
395
396
397
398
             * (p->a[ii*2+1] + p->a[1])              /* (yN + y0) */
             * 0.5;
    sqlite3_result_double(context, rArea);
    sqlite3_free(p);
  }            
}
















































































#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_geopoly_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  static const struct {
    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
    int nArg;
    const char *zName;
  } aFunc[] = {
     { geopolyAreaFunc,          1,    "geopoly_area"  },
     { geopolyBlobFunc,          1,    "geopoly_blob"  },
     { geopolyJsonFunc,          1,    "geopoly_json"  },

  };
  int i;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
                                 SQLITE_UTF8, 0,
                                 aFunc[i].xFunc, 0, 0);
  }
  return rc;
}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>















|
|
|
>











363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
             * (p->a[ii*2+1] + p->a[1])              /* (yN + y0) */
             * 0.5;
    sqlite3_result_double(context, rArea);
    sqlite3_free(p);
  }            
}

/*
** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
** Returns:
**
**    +2  x0,y0 is on the line segement
**
**    +1  x0,y0 is beneath line segment
**
**    0   x0,y0 is not on or beneath the line segment or the line segment
**        is vertical and x0,y0 is not on the line segment
**
** The left-most coordinate min(x1,x2) is not considered to be part of
** the line segment for the purposes of this analysis.
*/
static int pointBeneathLine(
  double x0, double y0,
  double x1, double y1,
  double x2, double y2
){
  double y;
  if( x0==x1 && y0==y1 ) return 2;
  if( x1<x2 ){
    if( x0<=x1 || x0>x2 ) return 0;
  }else if( x1>x2 ){
    if( x0<=x2 || x0>x1 ) return 0;
  }else{
    /* Vertical line segment */
    if( x0!=x1 ) return 0;
    if( y0<y1 && y0<y2 ) return 0;
    if( y0>y1 && y0>y2 ) return 0;
    return 2;
  }
  y = y1 + (y2-y1)*(x0-x1)/(x2-x1);
  if( y0==y ) return 2;
  if( y0<y ) return 1;
  return 0;
}

/*
** SQL function:    geopoly_within(P,X,Y)
**
** 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
*/
static void geopolyWithinFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  GeoPoly *p = geopolyFuncParam(context, argv[0]);
  double x0 = sqlite3_value_double(argv[1]);
  double y0 = sqlite3_value_double(argv[2]);
  if( p ){
    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]);
      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]);
    }
    if( v==2 ){
      sqlite3_result_int(context, 1);
    }else if( ((v+cnt)&1)==0 ){
      sqlite3_result_int(context, 0);
    }else{
      sqlite3_result_int(context, 2);
    }
    sqlite3_free(p);
  }            
}


#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_geopoly_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  static const struct {
    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
    int nArg;
    const char *zName;
  } aFunc[] = {
     { geopolyAreaFunc,          1,    "geopoly_area"   },
     { geopolyBlobFunc,          1,    "geopoly_blob"   },
     { geopolyJsonFunc,          1,    "geopoly_json"   },
     { geopolyWithinFunc,        3,    "geopoly_within" },
  };
  int i;
  SQLITE_EXTENSION_INIT2(pApi);
  (void)pzErrMsg;  /* Unused parameter */
  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
                                 SQLITE_UTF8, 0,
                                 aFunc[i].xFunc, 0, 0);
  }
  return rc;
}