From: dan Date: Tue, 31 Aug 2010 15:02:00 +0000 (+0000) Subject: Add the "circle" test geometry callback to test_rtree.c. And tests for the same. X-Git-Tag: experimental~95 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=18ec96b3a3a138c8e54f4fcc56102f246004ade4;p=thirdparty%2Fsqlite.git Add the "circle" test geometry callback to test_rtree.c. And tests for the same. FossilOrigin-Name: 169b8ba4be9c3941c742eded80dbacdcd2465bc4 --- diff --git a/ext/rtree/rtree9.test b/ext/rtree/rtree9.test index ab5df40dfb..ddee277ef5 100644 --- a/ext/rtree/rtree9.test +++ b/ext/rtree/rtree9.test @@ -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 diff --git a/manifest b/manifest index e603387679..f890fe1330 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 2bd3b6f32c..46510b5cb4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -86bcb9aab901713684f978479d29304cc9699e84 \ No newline at end of file +169b8ba4be9c3941c742eded80dbacdcd2465bc4 \ No newline at end of file diff --git a/src/test_rtree.c b/src/test_rtree.c index 4369831048..800385d8f9 100644 --- a/src/test_rtree.c +++ b/src/test_rtree.c @@ -12,8 +12,143 @@ ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. */ -#include "sqlite3rtree.h" + #include + +/* +** 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 #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; }