]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the "circle" test geometry callback to test_rtree.c. And tests for the same.
authordan <dan@noemail.net>
Tue, 31 Aug 2010 15:02:00 +0000 (15:02 +0000)
committerdan <dan@noemail.net>
Tue, 31 Aug 2010 15:02:00 +0000 (15:02 +0000)
FossilOrigin-Name: 169b8ba4be9c3941c742eded80dbacdcd2465bc4

ext/rtree/rtree9.test
manifest
manifest.uuid
src/test_rtree.c

index ab5df40dfbee73eea3e8c34d4b3735f653a1b549..ddee277ef526a4badb726ad4956587843de791b6 100644 (file)
@@ -8,6 +8,8 @@
 #    May you share freely, never taking more than you give.
 #
 #***********************************************************************
+# This file contains tests for the r-tree module. Specifically, it tests
+# that custom r-tree queries (geometry callbacks) work.
 # 
 
 if {![info exists testdir]} {
@@ -72,7 +74,6 @@ for {set x 2} {$x<200} {incr x 2} {
     SELECT id FROM rt WHERE id MATCH randomblob($x)
   } {1 {SQL logic error or missing database}}
 }
-
 do_catchsql_test rtree9-4.3 {
   SELECT id FROM rt WHERE id MATCH CAST( 
     (cube(5.5, 5.5, 5.5, 1, 1, 1) || X'1234567812345678') AS blob 
@@ -80,4 +81,45 @@ do_catchsql_test rtree9-4.3 {
 } {1 {SQL logic error or missing database}}
 
 
+#-------------------------------------------------------------------------
+# Test the example 2d "circle" geometry callback.
+#
+register_circle_geom db
+
+breakpoint
+do_execsql_test rtree9-5.1 {
+  CREATE VIRTUAL TABLE rt2 USING rtree(id, xmin, xmax, ymin, ymax);
+
+  INSERT INTO rt2 VALUES(1,    1,   2,  1,  2);
+  INSERT INTO rt2 VALUES(2,    1,   2, -2, -1);
+  INSERT INTO rt2 VALUES(3,    -2, -1, -2, -1);
+  INSERT INTO rt2 VALUES(4,    -2, -1,  1,  2);
+
+  INSERT INTO rt2 VALUES(5,    2,   3,  2,  3);
+  INSERT INTO rt2 VALUES(6,    2,   3, -3, -2);
+  INSERT INTO rt2 VALUES(7,    -3, -2, -3, -2);
+  INSERT INTO rt2 VALUES(8,    -3, -2,  2,  3);
+
+  INSERT INTO rt2 VALUES(9,    1.8,   3,  1.8,  3);
+  INSERT INTO rt2 VALUES(10,   1.8,   3, -3, -1.8);
+  INSERT INTO rt2 VALUES(11,   -3, -1.8, -3, -1.8);
+  INSERT INTO rt2 VALUES(12,   -3, -1.8,  1.8,  3);
+
+  INSERT INTO rt2 VALUES(13,   -15, 15, 1.8, 2.2);
+  INSERT INTO rt2 VALUES(14,   -15, 15, -2.2, -1.8);
+  INSERT INTO rt2 VALUES(15,   1.8, 2.2, -15, 15);
+  INSERT INTO rt2 VALUES(16,   -2.2, -1.8, -15, 15);
+
+  INSERT INTO rt2 VALUES(17,   -100, 100, -100, 100);
+} {}
+
+do_execsql_test rtree9-5.2 {
+  SELECT id FROM rt2 WHERE id MATCH circle(0.0, 0.0, 2.0);
+} {1 2 3 4 13 14 15 16 17}
+
+do_execsql_test rtree9-5.3 {
+  UPDATE rt2 SET xmin=xmin+5, ymin=ymin+5, xmax=xmax+5, ymax=ymax+5;
+  SELECT id FROM rt2 WHERE id MATCH circle(5.0, 5.0, 2.0);
+} {1 2 3 4 13 14 15 16 17}
+
 finish_test
index e6033876791eed3ea415dca8a1b287b81236f00c..f890fe133011ed97fed24b321fd428ad81d82e6f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,8 +1,5 @@
------BEGIN PGP SIGNED MESSAGE-----
-Hash: SHA1
-
-C Remove\sunreachable\sbranches\sto\sfacilitate\stest\scoverage.
-D 2010-08-31T01:09:16
+C Add\sthe\s"circle"\stest\sgeometry\scallback\sto\stest_rtree.c.\sAnd\stests\sfor\sthe\ssame.
+D 2010-08-31T15:02:01
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in c599a15d268b1db2aeadea19df2adc3bf2eb6bee
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -91,7 +88,7 @@ F ext/rtree/rtree5.test ce3d7ccae2cfd9d2e1052b462424964c9bdcda12
 F ext/rtree/rtree6.test 1ebe0d632a7501cc80ba5a225f028fd4f0fdda08
 F ext/rtree/rtree7.test bcb647b42920b3b5d025846689147778485cc318
 F ext/rtree/rtree8.test 9772e16da71e17e02bdebf0a5188590f289ab37d
-F ext/rtree/rtree9.test c3ab7efd3617bc4d3da1d96265fdb8a28e5a3d55
+F ext/rtree/rtree9.test df9843d1a9195249c8d3b4ea6aedda2d5c73e9c2
 F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
 F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
 F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
@@ -211,7 +208,7 @@ F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
 F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
 F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
 F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
-F src/test_rtree.c 85b550f364c3694e6844bc5d41829d9c1f354e17
+F src/test_rtree.c f0476682986e7d3b04919432020b91bde4aaa925
 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
 F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
@@ -854,14 +851,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 4fead8e714c7e50a9d246467e62bc846ef6180a0
-R 2a554c21e54c6c6b8cf219133e4b794c
-U drh
-Z 1f84fd2f1fe3fdabeee2241cc9429c00
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.6 (GNU/Linux)
-
-iD8DBQFMfFY/oxKgR168RlERAmjVAJ9LLyOmGxhu/yZZZmudXyMu4QPOdQCdEH6H
-g2BR3lfdwre9DKrRofma7OY=
-=SZjz
------END PGP SIGNATURE-----
+P 86bcb9aab901713684f978479d29304cc9699e84
+R 5c25e19d785d39dcca465a202d21adcc
+U dan
+Z 0dfc99dba1561d16d8cd1c933b53fac9
index 2bd3b6f32c9c3900279d04a0276f89c72d7290d5..46510b5cb4c56fb8665ee3fb333e69a53bdfc5ba 100644 (file)
@@ -1 +1 @@
-86bcb9aab901713684f978479d29304cc9699e84
\ No newline at end of file
+169b8ba4be9c3941c742eded80dbacdcd2465bc4
\ No newline at end of file
index 4369831048950f9526e31a6e738255a6b9317cf9..800385d8f93a699fc8d15257cf68b801cf08e323 100644 (file)
 ** Code for testing all sorts of SQLite interfaces. This code
 ** is not included in the SQLite library. 
 */
-#include "sqlite3rtree.h"
+
 #include <sqlite3.h>
+
+/* 
+** Type used to cache parameter information for the "circle" r-tree geometry
+** callback.
+*/
+typedef struct Circle Circle;
+struct Circle {
+  struct Box {
+    double xmin;
+    double xmax;
+    double ymin;
+    double ymax;
+  } aBox[2];
+  double centerx;
+  double centery;
+  double radius;
+};
+
+/*
+** Destructor function for Circle objects allocated by circle_geom().
+*/
+static void circle_del(void *p){
+  sqlite3_free(p);
+}
+
+/*
+** Implementation of "circle" r-tree geometry callback.
+*/
+static int circle_geom(
+  sqlite3_rtree_geometry *p,
+  int nCoord, 
+  double *aCoord, 
+  int *pRes
+){
+  int i;                          /* Iterator variable */
+  Circle *pCircle;                /* Structure defining circular region */
+  double xmin, xmax;              /* X dimensions of box being tested */
+  double ymin, ymax;              /* X dimensions of box being tested */
+
+  if( p->pUser==0 ){
+    /* If pUser is still 0, then the parameter values have not been tested
+    ** for correctness or stored into a Circle structure yet. Do this now. */
+
+    /* This geometry callback is for use with a 2-dimensional r-tree table.
+    ** Return an error if the table does not have exactly 2 dimensions. */
+    if( nCoord!=4 ) return SQLITE_ERROR;
+
+    /* Test that the correct number of parameters (3) have been supplied,
+    ** and that the parameters are in range (that the radius of the circle 
+    ** radius is greater than zero). */
+    if( p->nParam!=3 || p->aParam[2]<0.0 ) return SQLITE_ERROR;
+
+    /* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM
+    ** if the allocation fails. */
+    pCircle = (Circle *)(p->pUser = sqlite3_malloc(sizeof(Circle)));
+    if( !pCircle ) return SQLITE_NOMEM;
+    p->xDelUser = circle_del;
+
+    /* Record the center and radius of the circular region. One way that
+    ** tested bounding boxes that intersect the circular region are detected
+    ** is by testing if each corner of the bounding box likes within radius
+    ** units of the center of the circle. */
+    pCircle->centerx = p->aParam[0];
+    pCircle->centery = p->aParam[1];
+    pCircle->radius = p->aParam[2];
+
+    /* Define two bounding box regions. The first, aBox[0], extends to
+    ** infinity in the X dimension. It covers the same range of the Y dimension
+    ** as the circular region. The second, aBox[1], extends to infinity in
+    ** the Y dimension and is constrained to the range of the circle in the
+    ** X dimension.
+    **
+    ** Then imagine each box is split in half along its short axis by a line
+    ** that intersects the center of the circular region. A bounding box
+    ** being tested can be said to intersect the circular region if it contains
+    ** points from each half of either of the two infinite bounding boxes.
+    */
+    pCircle->aBox[0].xmin = pCircle->centerx;
+    pCircle->aBox[0].xmax = pCircle->centerx;
+    pCircle->aBox[0].ymin = pCircle->centery + pCircle->radius;
+    pCircle->aBox[0].ymax = pCircle->centery - pCircle->radius;
+    pCircle->aBox[1].xmin = pCircle->centerx + pCircle->radius;
+    pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
+    pCircle->aBox[1].ymin = pCircle->centery;
+    pCircle->aBox[1].ymax = pCircle->centery;
+  }
+
+  pCircle = (Circle *)p->pUser;
+  xmin = aCoord[0];
+  xmax = aCoord[1];
+  ymin = aCoord[2];
+  ymax = aCoord[3];
+
+  /* Check if any of the 4 corners of the bounding-box being tested lie 
+  ** inside the circular region. If they do, then the bounding-box does
+  ** intersect the region of interest. Set the output variable to true and
+  ** return SQLITE_OK in this case. */
+  for(i=0; i<4; i++){
+    double x = (i&0x01) ? xmax : xmin;
+    double y = (i&0x02) ? ymax : ymin;
+    double d2;
+    
+    d2  = (x-pCircle->centerx)*(x-pCircle->centerx);
+    d2 += (y-pCircle->centery)*(y-pCircle->centery);
+    if( d2<(pCircle->radius*pCircle->radius) ){
+      *pRes = 1;
+      return SQLITE_OK;
+    }
+  }
+
+  /* Check if the bounding box covers any other part of the circular region.
+  ** See comments above for a description of how this test works. If it does
+  ** cover part of the circular region, set the output variable to true
+  ** and return SQLITE_OK. */
+  for(i=0; i<2; i++){
+    if( xmin<=pCircle->aBox[i].xmin 
+     && xmax>=pCircle->aBox[i].xmax 
+     && ymin<=pCircle->aBox[i].ymin 
+     && ymax>=pCircle->aBox[i].ymax 
+    ){
+      *pRes = 1;
+      return SQLITE_OK;
+    }
+  }
+
+  /* The specified bounding box does not intersect the circular region. Set
+  ** the output variable to zero and return SQLITE_OK. */
+  *pRes = 0;
+  return SQLITE_OK;
+}
+
+/* END of implementation of "circle" geometry callback.
+**************************************************************************
+*************************************************************************/
+
 #include <assert.h>
 #include "tcl.h"
 
@@ -111,13 +246,37 @@ static int register_cube_geom(
   }
   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
   rc = sqlite3_rtree_geometry_callback(db, "cube", cube_geom, (void *)&gHere);
-  Tcl_SetResult(interp, sqlite3TestErrorName(rc), TCL_STATIC);
+  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
+#endif
+  return TCL_OK;
+}
+
+static int register_circle_geom(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+#ifdef SQLITE_ENABLE_RTREE
+  extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
+  extern const char *sqlite3TestErrorName(int);
+  sqlite3 *db;
+  int rc;
+
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "DB");
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+  rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0);
+  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
 #endif
   return TCL_OK;
 }
 
 int Sqlitetestrtree_Init(Tcl_Interp *interp){
   Tcl_CreateObjCommand(interp, "register_cube_geom", register_cube_geom, 0, 0);
+  Tcl_CreateObjCommand(interp, "register_circle_geom",register_circle_geom,0,0);
   return TCL_OK;
 }